Building NumPy requires the following installed software:
-1) Python__ 3.6.x or newer.
+1) Python__ 3.7.x or newer.
Please note that the Python development headers also need to be installed,
e.g., on Debian/Ubuntu one needs to install both `python3` and
This is required for testing NumPy, but not for using it.
-Python__ http://www.python.org
-pytest__ http://pytest.readthedocs.io
+Python__ https://www.python.org/
+pytest__ https://docs.pytest.org/en/stable/
Hypothesis__ https://hypothesis.readthedocs.io/en/latest/
If you want to build NumPy in order to work on NumPy itself, use
``runtests.py``. For more details, see
- https://docs.scipy.org/doc/numpy/dev/development_environment.html
+ https://numpy.org/devdocs/dev/development_environment.html
.. note::
- More extensive information on building NumPy (and SciPy) is maintained at
- https://scipy.github.io/devdocs/building/
+ More extensive information on building NumPy is maintained at
+ https://numpy.org/devdocs/user/building.html#building-from-source
Basic Installation
Choosing compilers
==================
-NumPy needs a C compiler, and for development versions also Cython. A Fortran
+NumPy needs a C compiler, and for development versions also needs Cython. A Fortran
compiler isn't needed to build NumPy itself; the ``numpy.f2py`` tests will be
skipped when running the test suite if no Fortran compiler is available. For
building Scipy a Fortran compiler is needed though, so we include some details
-------
On Windows, building from source can be difficult (in particular if you need to
-build SciPy as well, because that requires a Fortran compiler). Currently, the
+build SciPy as well, because that requires a Fortran compiler). Currently, the
most robust option is to use MSVC (for NumPy only). If you also need SciPy,
you can either use MSVC + Intel Fortran or the Intel compiler suite.
Intel itself maintains a good `application note
Build issues
============
-If you run into build issues and need help, the NumPy
+If you run into build issues and need help, the NumPy and SciPy
`mailing list <https://scipy.org/scipylib/mailing-lists.html>`_ is the best
-place to ask. If the issue is clearly a bug in NumPy, please file an issue (or
+place to ask. If the issue is clearly a bug in NumPy, please file an issue (or
even better, a pull request) at https://github.com/numpy/numpy.
The NumPy repository and source distributions bundle several libraries that are
compatibly licensed. We list these here.
-Name: Numpydoc
-Files: doc/sphinxext/numpydoc/*
-License: BSD-2-Clause
- For details, see doc/sphinxext/LICENSE.txt
-
-Name: scipy-sphinx-theme
-Files: doc/scipy-sphinx-theme/*
-License: BSD-3-Clause AND PSF-2.0 AND Apache-2.0
- For details, see doc/scipy-sphinx-theme/LICENSE.txt
-
Name: lapack-lite
Files: numpy/linalg/lapack_lite/*
License: BSD-3-Clause
include .coveragerc
include test_requirements.txt
recursive-include numpy/random *.pyx *.pxd *.pyx.in *.pxd.in
+include numpy/py.typed
include numpy/random/include/*
include numpy/*.pxd
# Add build support that should go in sdist, but not go in bdist/be installed
# Note that sub-directories that don't have __init__ are apparently not
# included by 'recursive-include', so list those separately
recursive-include numpy *
-recursive-include numpy/_build_utils *
recursive-include numpy/linalg/lapack_lite *
recursive-include tools *
# Add sdist files whose use depends on local configuration.
Metadata-Version: 1.2
Name: numpy
-Version: 1.19.5
+Version: 1.20.0
Summary: NumPy is the fundamental package for array computing with Python.
Home-page: https://www.numpy.org
Author: Travis E. Oliphant et al.
License: BSD
Download-URL: https://pypi.python.org/pypi/numpy
Project-URL: Bug Tracker, https://github.com/numpy/numpy/issues
-Project-URL: Documentation, https://numpy.org/doc/1.19
+Project-URL: Documentation, https://numpy.org/doc/1.20
Project-URL: Source Code, https://github.com/numpy/numpy
Description: It provides:
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved
+Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: C
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Software Development
Classifier: Topic :: Scientific/Engineering
+Classifier: Typing :: Typed
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Operating System :: Unix
Classifier: Operating System :: MacOS
-Requires-Python: >=3.6
+Requires-Python: >=3.7
-# <img alt="NumPy" src="https://cdn.rawgit.com/numpy/numpy/master/branding/icons/numpylogo.svg" height="60">
+# <img alt="NumPy" src="https://ghcdn.rawgit.org/numpy/numpy/master/branding/icons/primary/numpylogo.svg" height="60">
-[](
- https://travis-ci.org/numpy/numpy)
+[](
+ https://travis-ci.com/github/numpy/numpy)
[](
https://dev.azure.com/numpy/numpy/_build/latest?definitionId=5)
[](
--- /dev/null
+// This config file is almost similar to 'asv.conf.json' except it contains
+// custom tokens that can be substituted by 'runtests.py' and ASV,
+// due to the necessity to add custom build options when `--bench-compare`
+// is used.
+{
+ // The version of the config file format. Do not change, unless
+ // you know what you are doing.
+ "version": 1,
+
+ // The name of the project being benchmarked
+ "project": "numpy",
+
+ // The project's homepage
+ "project_url": "https://www.numpy.org/",
+
+ // The URL or local path of the source code repository for the
+ // project being benchmarked
+ "repo": "..",
+
+ // List of branches to benchmark. If not provided, defaults to "master"
+ // (for git) or "tip" (for mercurial).
+ "branches": ["HEAD"],
+
+ // The DVCS being used. If not set, it will be automatically
+ // determined from "repo" by looking at the protocol in the URL
+ // (if remote), or by looking for special directories, such as
+ // ".git" (if local).
+ "dvcs": "git",
+
+ // The tool to use to create environments. May be "conda",
+ // "virtualenv" or other value depending on the plugins in use.
+ // If missing or the empty string, the tool will be automatically
+ // determined by looking for tools on the PATH environment
+ // variable.
+ "environment_type": "virtualenv",
+
+ // the base URL to show a commit for the project.
+ "show_commit_url": "https://github.com/numpy/numpy/commit/",
+
+ // The Pythons you'd like to test against. If not provided, defaults
+ // to the current version of Python used to run `asv`.
+ "pythons": ["3.7"],
+
+ // The matrix of dependencies to test. Each key is the name of a
+ // package (in PyPI) and the values are version numbers. An empty
+ // list indicates to just test against the default (latest)
+ // version.
+ "matrix": {
+ "Cython": [],
+ },
+
+ // The directory (relative to the current directory) that benchmarks are
+ // stored in. If not provided, defaults to "benchmarks"
+ "benchmark_dir": "benchmarks",
+
+ // The directory (relative to the current directory) to cache the Python
+ // environments in. If not provided, defaults to "env"
+ // NOTE: changes dir name will requires update `generate_asv_config()` in
+ // runtests.py
+ "env_dir": "env",
+
+
+ // The directory (relative to the current directory) that raw benchmark
+ // results are stored in. If not provided, defaults to "results".
+ "results_dir": "results",
+
+ // The directory (relative to the current directory) that the html tree
+ // should be written to. If not provided, defaults to "html".
+ "html_dir": "html",
+
+ // The number of characters to retain in the commit hashes.
+ // "hash_length": 8,
+
+ // `asv` will cache wheels of the recent builds in each
+ // environment, making them faster to install next time. This is
+ // number of builds to keep, per environment.
+ "build_cache_size": 8,
+
+ "build_command" : [
+ "python setup.py build {numpy_build_options}",
+ "PIP_NO_BUILD_ISOLATION=false python -mpip wheel --no-deps --no-index -w {build_cache_dir} {build_dir}"
+ ],
+ // The commits after which the regression search in `asv publish`
+ // should start looking for regressions. Dictionary whose keys are
+ // regexps matching to benchmark names, and values corresponding to
+ // the commit (exclusive) after which to start looking for
+ // regressions. The default is to start from the first commit
+ // with results. If the commit is `null`, regression detection is
+ // skipped for the matching benchmark.
+ //
+ // "regressions_first_commits": {
+ // "some_benchmark": "352cdf", // Consider regressions only after this commit
+ // "another_benchmark": null, // Skip regression detection altogether
+ // }
+}
'rint',
'floor',
'ceil' ,
- 'trunc']
+ 'trunc',
+ 'frexp',
+ 'isnan',
+ 'isfinite',
+ 'isinf',
+ 'signbit']
stride = [1, 2, 4]
dtype = ['f', 'd']
def time_ufunc(self, ufuncname, stride, dtype):
self.f(self.arr[::stride])
+class AVX_UFunc_log(Benchmark):
+ params = [stride, dtype]
+ param_names = ['stride', 'dtype']
+ timeout = 10
+
+ def setup(self, stride, dtype):
+ np.seterr(all='ignore')
+ N = 10000
+ self.arr = np.array(np.random.random_sample(stride*N), dtype=dtype)
+
+ def time_log(self, stride, dtype):
+ np.log(self.arr[::stride])
+
avx_bfuncs = ['maximum',
'minimum']
def time_ufunc(self, ufuncname, dtype, stride):
self.f(self.arr1[::stride], self.arr2[::stride])
+class AVX_ldexp(Benchmark):
+
+ params = [dtype, stride]
+ param_names = ['dtype', 'stride']
+ timeout = 10
+
+ def setup(self, dtype, stride):
+ np.seterr(all='ignore')
+ self.f = getattr(np, 'ldexp')
+ N = 10000
+ self.arr1 = np.array(np.random.rand(stride*N), dtype=dtype)
+ self.arr2 = np.array(np.random.rand(stride*N), dtype='i')
+
+ def time_ufunc(self, dtype, stride):
+ self.f(self.arr1[::stride], self.arr2[::stride])
+
cmplx_bfuncs = ['add',
'subtract',
'multiply',
def setup(self):
self.l100 = range(100)
self.l50 = range(50)
+ self.float_l1000 = [float(i) for i in range(1000)]
+ self.float64_l1000 = [np.float64(i) for i in range(1000)]
+ self.int_l1000 = list(range(1000))
self.l = [np.arange(1000), np.arange(1000)]
self.l_view = [memoryview(a) for a in self.l]
self.l10x10 = np.ones((10, 10))
+ self.float64_dtype = np.dtype(np.float64)
def time_array_1(self):
np.array(1)
def time_array_l100(self):
np.array(self.l100)
+ def time_array_float_l1000(self):
+ np.array(self.float_l1000)
+
+ def time_array_float_l1000_dtype(self):
+ np.array(self.float_l1000, dtype=self.float64_dtype)
+
+ def time_array_float64_l1000(self):
+ np.array(self.float64_l1000)
+
+ def time_array_int_l1000(self):
+ np.array(self.int_l1000)
+
def time_array_l(self):
np.array(self.l)
self.func()
+class ScalarIndexing(Benchmark):
+ params = [[0, 1, 2]]
+ param_names = ["ndim"]
+
+ def setup(self, ndim):
+ self.array = np.ones((5,) * ndim)
+
+ def time_index(self, ndim):
+ # time indexing.
+ arr = self.array
+ indx = (1,) * ndim
+ for i in range(100):
+ arr[indx]
+
+ def time_assign(self, ndim):
+ # time assignment from a python scalar
+ arr = self.array
+ indx = (1,) * ndim
+ for i in range(100):
+ arr[indx] = 5.
+
+ def time_assign_cast(self, ndim):
+ # time an assignment which may use a cast operation
+ arr = self.array
+ indx = (1,) * ndim
+ val = np.int16(43)
+ for i in range(100):
+ arr[indx] = val
+
+
class IndexingSeparate(Benchmark):
def setup(self):
self.tmp_dir = mkdtemp()
def time_numpy_linalg_lstsq_a__b_float64(self):
np.linalg.lstsq(self.a, self.b, rcond=-1)
+
+class Einsum(Benchmark):
+ param_names = ['dtype']
+ params = [[np.float32, np.float64]]
+ def setup(self, dtype):
+ self.one_dim_small = np.arange(600, dtype=dtype)
+ self.one_dim = np.arange(3000, dtype=dtype)
+ self.one_dim_big = np.arange(480000, dtype=dtype)
+ self.two_dim_small = np.arange(1200, dtype=dtype).reshape(30, 40)
+ self.two_dim = np.arange(240000, dtype=dtype).reshape(400, 600)
+ self.three_dim_small = np.arange(10000, dtype=dtype).reshape(10,100,10)
+ self.three_dim = np.arange(24000, dtype=dtype).reshape(20, 30, 40)
+ # non_contigous arrays
+ self.non_contigous_dim1_small = np.arange(1, 80, 2, dtype=dtype)
+ self.non_contigous_dim1 = np.arange(1, 4000, 2, dtype=dtype)
+ self.non_contigous_dim2 = np.arange(1, 2400, 2, dtype=dtype).reshape(30, 40)
+ self.non_contigous_dim3 = np.arange(1, 48000, 2, dtype=dtype).reshape(20, 30, 40)
+
+ # outer(a,b): trigger sum_of_products_contig_stride0_outcontig_two
+ def time_einsum_outer(self, dtype):
+ np.einsum("i,j", self.one_dim, self.one_dim, optimize=True)
+
+ # multiply(a, b):trigger sum_of_products_contig_two
+ def time_einsum_multiply(self, dtype):
+ np.einsum("..., ...", self.two_dim_small, self.three_dim , optimize=True)
+
+ # sum and multiply:trigger sum_of_products_contig_stride0_outstride0_two
+ def time_einsum_sum_mul(self, dtype):
+ np.einsum(",i...->", 300, self.three_dim_small, optimize=True)
+
+ # sum and multiply:trigger sum_of_products_stride0_contig_outstride0_two
+ def time_einsum_sum_mul2(self, dtype):
+ np.einsum("i...,->", self.three_dim_small, 300, optimize=True)
+
+ # scalar mul: trigger sum_of_products_stride0_contig_outcontig_two
+ def time_einsum_mul(self, dtype):
+ np.einsum("i,->i", self.one_dim_big, 300, optimize=True)
+
+ # trigger contig_contig_outstride0_two
+ def time_einsum_contig_contig(self, dtype):
+ np.einsum("ji,i->", self.two_dim, self.one_dim_small, optimize=True)
+
+ # trigger sum_of_products_contig_outstride0_one
+ def time_einsum_contig_outstride0(self, dtype):
+ np.einsum("i->", self.one_dim_big, optimize=True)
+
+ # outer(a,b): non_contigous arrays
+ def time_einsum_noncon_outer(self, dtype):
+ np.einsum("i,j", self.non_contigous_dim1, self.non_contigous_dim1, optimize=True)
+
+ # multiply(a, b):non_contigous arrays
+ def time_einsum_noncon_multiply(self, dtype):
+ np.einsum("..., ...", self.non_contigous_dim2, self.non_contigous_dim3 , optimize=True)
+
+ # sum and multiply:non_contigous arrays
+ def time_einsum_noncon_sum_mul(self, dtype):
+ np.einsum(",i...->", 300, self.non_contigous_dim3, optimize=True)
+
+ # sum and multiply:non_contigous arrays
+ def time_einsum_noncon_sum_mul2(self, dtype):
+ np.einsum("i...,->", self.non_contigous_dim3, 300, optimize=True)
+
+ # scalar mul: non_contigous arrays
+ def time_einsum_noncon_mul(self, dtype):
+ np.einsum("i,->i", self.non_contigous_dim1, 300, optimize=True)
+
+ # contig_contig_outstride0_two: non_contigous arrays
+ def time_einsum_noncon_contig_contig(self, dtype):
+ np.einsum("ji,i->", self.non_contigous_dim2, self.non_contigous_dim1_small, optimize=True)
+
+ # sum_of_products_contig_outstride0_one:non_contigous arrays
+ def time_einsum_noncon_contig_outstride0(self, dtype):
+ np.einsum("i->", self.non_contigous_dim1, optimize=True)
def time_max(self, dtype):
np.max(self.d)
+class ArgMax(Benchmark):
+ params = [np.float32, bool]
+ param_names = ['dtype']
+
+ def setup(self, dtype):
+ self.d = np.zeros(200000, dtype=dtype)
+
+ def time_argmax(self, dtype):
+ np.argmax(self.d)
class SmallReduction(Benchmark):
def setup(self):
--- /dev/null
+from .common import Benchmark, TYPES1
+
+import numpy as np
+
+
+class ScalarMath(Benchmark):
+ # Test scalar math, note that each of these is run repeatedly to offset
+ # the function call overhead to some degree.
+ params = [TYPES1]
+ param_names = ["type"]
+ def setup(self, typename):
+ self.num = np.dtype(typename).type(2)
+
+ def time_addition(self, typename):
+ n = self.num
+ res = n + n + n + n + n + n + n + n + n + n
+
+ def time_addition_pyint(self, typename):
+ n = self.num
+ res = n + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
+
+ def time_multiplication(self, typename):
+ n = self.num
+ res = n * n * n * n * n * n * n * n * n * n
+
+ def time_power_of_two(self, typename):
+ n = self.num
+ res = n**2, n**2, n**2, n**2, n**2, n**2, n**2, n**2, n**2, n**2
+
+ def time_abs(self, typename):
+ n = self.num
+ res = abs(abs(abs(abs(abs(abs(abs(abs(abs(abs(n))))))))))
+
--- /dev/null
+from .common import Benchmark
+
+import numpy as np
+
+_FLOAT = np.dtype('float64')
+_COMPLEX = np.dtype('complex128')
+_INT = np.dtype('int64')
+_BOOL = np.dtype('bool')
+
+
+class TrimZeros(Benchmark):
+ param_names = ["dtype", "size"]
+ params = [
+ [_INT, _FLOAT, _COMPLEX, _BOOL],
+ [3000, 30_000, 300_000]
+ ]
+
+ def setup(self, dtype, size):
+ n = size // 3
+ self.array = np.hstack([
+ np.zeros(n),
+ np.random.uniform(size=n),
+ np.zeros(n),
+ ]).astype(dtype)
+
+ def time_trim_zeros(self, dtype, size):
+ np.trim_zeros(self.array)
class Benchmark:
- goal_time = 0.25
+ pass
-===================
-NumPy C Style Guide
-===================
-The NumPy C coding conventions are based on Python PEP-0007 by Guido van
-Rossum with a few added strictures. There are many C coding conventions and
-it must be emphasized that the primary goal of the NumPy conventions isn't
-to choose the 'best', about which there is certain to be disagreement, but
-to achieve uniformity. Because the NumPy conventions are very close to
-those in PEP-0007, that PEP is used as a template below with the NumPy
-additions and variations in the appropriate spots.
-
-Introduction
-------------
-
-This document gives coding conventions for the C code comprising
-the C implementation of NumPy. Note, rules are there to be broken.
-Two good reasons to break a particular rule:
-
-1. When applying the rule would make the code less readable, even
- for someone who is used to reading code that follows the rules.
-
-2. To be consistent with surrounding code that also breaks it
- (maybe for historic reasons) -- although this is also an
- opportunity to clean up someone else's mess.
-
-
-C dialect
----------
-
-* Use C99 (that is, the standard defined by ISO/IEC 9899:1999).
-
-* Don't use GCC extensions (e.g. don't write multi-line strings
- without trailing backslashes). Preferably break long strings
- up onto separate lines like so::
-
- "blah blah"
- "blah blah"
-
- This will work with MSVC, which otherwise chokes on very long
- strings.
-
-* All function declarations and definitions must use full
- prototypes (i.e. specify the types of all arguments).
-
-* No compiler warnings with major compilers (gcc, VC++, a few others).
- Note: NumPy still produces compiler warnings that need to be addressed.
-
-
-Code lay-out
-------------
-
-* Use 4-space indents and no tabs at all.
-
-* No line should be longer than 80 characters. If this and the
- previous rule together don't give you enough room to code, your code is
- too complicated, consider using subroutines.
-
-* No line should end in whitespace. If you think you need
- significant trailing whitespace, think again, somebody's editor might
- delete it as a matter of routine.
-
-* Function definition style: function name in column 1, outermost
- curly braces in column 1, blank line after local variable declarations::
-
- static int
- extra_ivars(PyTypeObject *type, PyTypeObject *base)
- {
- int t_size = PyType_BASICSIZE(type);
- int b_size = PyType_BASICSIZE(base);
-
- assert(t_size >= b_size); /* type smaller than base! */
- ...
- return 1;
- }
-
- If the transition to C++ goes through it is possible that this form will
- be relaxed so that short class methods meant to be inlined can have the
- return type on the same line as the function name. However, that is yet to
- be determined.
-
-* Code structure: one space between keywords like ``if``, ``for`` and
- the following left parenthesis; no spaces inside the parenthesis; braces
- around all ``if`` branches and no statements on the same line as the
- ``if``. They should be formatted as shown::
-
- if (mro != NULL) {
- one_line_statement;
- }
- else {
- ...
- }
-
-
- for (i = 0; i < n; i++) {
- one_line_statement;
- }
-
-
- while (isstuff) {
- dostuff;
- }
-
-
- do {
- stuff;
- } while (isstuff);
-
-
- switch (kind) {
- /* Boolean kind */
- case 'b':
- return 0;
- /* Unsigned int kind */
- case 'u':
- ...
- /* Anything else */
- default:
- return 3;
- }
-
-
-* The return statement should *not* get redundant parentheses::
-
- return Py_None; /* correct */
- return(Py_None); /* incorrect */
-
-* Function and macro call style: ``foo(a, b, c)``, no space before
- the open paren, no spaces inside the parens, no spaces before
- commas, one space after each comma.
-
-* Always put spaces around the assignment, Boolean and comparison
- operators. In expressions using a lot of operators, add spaces
- around the outermost (lowest priority) operators.
-
-* Breaking long lines: if you can, break after commas in the
- outermost argument list. Always indent continuation lines
- appropriately, e.g., ::
-
- PyErr_SetString(PyExc_TypeError,
- "Oh dear, you messed up.");
-
- Here appropriately means at least two tabs. It isn't necessary to
- line everything up with the opening parenthesis of the function
- call.
-
-* When you break a long expression at a binary operator, the
- operator goes at the end of the previous line, e.g., ::
-
- if (type > tp_dictoffset != 0 &&
- base > tp_dictoffset == 0 &&
- type > tp_dictoffset == b_size &&
- (size_t)t_size == b_size + sizeof(PyObject *)) {
- return 0;
- }
-
- Note that the terms in the multi-line Boolean expression are indented so
- as to make the beginning of the code block clearly visible.
-
-* Put blank lines around functions, structure definitions, and
- major sections inside functions.
-
-* Comments go before the code they describe. Multi-line comments should
- be like so::
-
- /*
- * This would be a long
- * explanatory comment.
- */
-
- Trailing comments should be used sparingly. Instead of ::
-
- if (yes) { // Success!
-
- do ::
-
- if (yes) {
- // Success!
-
-* All functions and global variables should be declared static
- when they aren't needed outside the current compilation unit.
-
-* Declare external functions and variables in a header file.
-
-
-Naming conventions
-------------------
-
-* There has been no consistent prefix for NumPy public functions, but
- they all begin with a prefix of some sort, followed by an underscore, and
- are in camel case: ``PyArray_DescrAlignConverter``, ``NpyIter_GetIterNext``.
- In the future the names should be of the form ``Npy*_PublicFunction``,
- where the star is something appropriate.
-
-* Public Macros should have a ``NPY_`` prefix and then use upper case,
- for example, ``NPY_DOUBLE``.
-
-* Private functions should be lower case with underscores, for example:
- ``array_real_get``. Single leading underscores should not be used, but
- some current function names violate that rule due to historical accident.
- Those functions should be renamed at some point.
-
-
-Function documentation
-----------------------
-
-NumPy doesn't have a C function documentation standard at this time, but
-needs one. Most numpy functions are not documented in the code and that
-should change. One possibility is Doxygen with a plugin so that the same
-NumPy style used for Python functions can also be used for documenting
-C functions, see the files in doc/cdoc/.
+The "NumPy C Style Guide" at this page has been supserseded by
+"NEP 45 — C Style Guide" at https://numpy.org/neps/nep-0045-c_style_guide.html
named repeat rules of the Fortran-specific repeats.
NumPy Distutils preprocesses C source files (extension: :file:`.c.src`) written
-in a custom templating language to generate C code. The :c:data:`@` symbol is
+in a custom templating language to generate C code. The ``@`` symbol is
used to wrap macro-style variables to empower a string substitution mechanism
that might describe (for instance) a set of data types.
-The template language blocks are delimited by :c:data:`/**begin repeat`
-and :c:data:`/**end repeat**/` lines, which may also be nested using
-consecutively numbered delimiting lines such as :c:data:`/**begin repeat1`
-and :c:data:`/**end repeat1**/`:
+The template language blocks are delimited by ``/**begin repeat``
+and ``/**end repeat**/`` lines, which may also be nested using
+consecutively numbered delimiting lines such as ``/**begin repeat1``
+and ``/**end repeat1**/``:
-1. "/\**begin repeat "on a line by itself marks the beginning of
-a segment that should be repeated.
+1. ``/**begin repeat`` on a line by itself marks the beginning of
+ a segment that should be repeated.
2. Named variable expansions are defined using ``#name=item1, item2, item3,
-..., itemN#`` and placed on successive lines. These variables are
-replaced in each repeat block with corresponding word. All named
-variables in the same repeat block must define the same number of
-words.
+ ..., itemN#`` and placed on successive lines. These variables are
+ replaced in each repeat block with corresponding word. All named
+ variables in the same repeat block must define the same number of
+ words.
3. In specifying the repeat rule for a named variable, ``item*N`` is short-
-hand for ``item, item, ..., item`` repeated N times. In addition,
-parenthesis in combination with \*N can be used for grouping several
-items that should be repeated. Thus, #name=(item1, item2)*4# is
-equivalent to #name=item1, item2, item1, item2, item1, item2, item1,
-item2#
+ hand for ``item, item, ..., item`` repeated N times. In addition,
+ parenthesis in combination with ``*N`` can be used for grouping several
+ items that should be repeated. Thus, ``#name=(item1, item2)*4#`` is
+ equivalent to ``#name=item1, item2, item1, item2, item1, item2, item1,
+ item2#``.
-4. "\*/ "on a line by itself marks the end of the variable expansion
-naming. The next line is the first line that will be repeated using
-the named rules.
+4. ``*/`` on a line by itself marks the end of the variable expansion
+ naming. The next line is the first line that will be repeated using
+ the named rules.
5. Inside the block to be repeated, the variables that should be expanded
-are specified as ``@name@``
+ are specified as ``@name@``.
-6. "/\**end repeat**/ "on a line by itself marks the previous line
-as the last line of the block to be repeated.
+6. ``/**end repeat**/`` on a line by itself marks the previous line
+ as the last line of the block to be repeated.
7. A loop in the NumPy C source code may have a ``@TYPE@`` variable, targeted
-for string substitution, which is preprocessed to a number of otherwise
-identical loops with several strings such as INT, LONG, UINT, ULONG. The
-``@TYPE@`` style syntax thus reduces code duplication and maintenance burden by
-mimicking languages that have generic type support.
+ for string substitution, which is preprocessed to a number of otherwise
+ identical loops with several strings such as ``INT``, ``LONG``, ``UINT``,
+ ``ULONG``. The ``@TYPE@`` style syntax thus reduces code duplication and
+ maintenance burden by mimicking languages that have generic type support.
The above rules may be clearer in the following template source example:
/**end repeat**/
-The preprocessing of generically typed C source files (whether in NumPy
+The preprocessing of generically-typed C source files (whether in NumPy
proper or in any third party package using NumPy Distutils) is performed
by `conv_template.py`_.
-The type specific C files generated (extension: .c)
+The type-specific C files generated (extension: ``.c``)
by these modules during the build process are ready to be compiled. This
form of generic typing is also supported for C header files (preprocessed
-to produce .h files).
+to produce ``.h`` files).
.. _conv_template.py: https://github.com/numpy/numpy/blob/master/numpy/distutils/conv_template.py
test = Tester().test
bench = Tester().bench
-Note that NumPy submodules still use a file named ``info.py`` in which the
-module docstring and ``__all__`` dict are defined. These files will be removed
-at some point.
-
Extra features in NumPy Distutils
'''''''''''''''''''''''''''''''''
NumPy Docs
----------
- https://github.com/numpy/numpy/blob/master/doc/HOWTO_RELEASE.rst.txt
-- http://projects.scipy.org/numpy/wiki/MicrosoftToolchainSupport (dead link)
SciPy.org wiki
--------------
- https://www.scipy.org/Installing_SciPy and links on that page.
-- http://new.scipy.org/building/windows.html (dead link)
-
-
-Doc wiki
---------
-- http://docs.scipy.org/numpy/docs/numpy-docs/user/install.rst/ (dead link)
Release Scripts
Supported platforms and versions
================================
-`NEP 29`_ outlines which Python versions are supported; For the first half of
-2020, this will be Python >= 3.6. We test NumPy against all these versions
-every time we merge code to master. Binary installers may be available for a
-subset of these versions (see below).
+:ref:`NEP 29 <NEP29>` outlines which Python versions
+are supported; For the first half of 2020, this will be Python >= 3.6. We test
+NumPy against all these versions every time we merge code to master. Binary
+installers may be available for a subset of these versions (see below).
OS X
----
-OS X versions >= 10.9 are supported, for Python version support see `NEP 29`_.
-We build binary wheels for OSX that are compatible with Python.org Python,
-system Python, homebrew and macports - see this `OSX wheel building summary
+OS X versions >= 10.9 are supported, for Python version support see
+:ref:`NEP 29 <NEP29>`. We build binary wheels for
+OSX that are compatible with Python.org Python, system Python, homebrew and
+macports - see this `OSX wheel building summary
<https://github.com/MacPython/wiki/wiki/Spinning-wheels>`_ for details.
files in the NumPy distribution to ``.c`` files.
.. _mingw-w64 toolchain : https://mingwpy.github.io
-.. _NEP 29 : https://numpy.org/neps/nep-0029-deprecation_policy.html
OpenBLAS
------------
# This checks out github.com/numpy/doc and adds (``git add``) the
# documentation to the checked out repo.
make merge-doc
- # Now edit the ``index.html`` file in the repo to reflect the new content,
- # and commit the changes
+ # Now edit the ``index.html`` file in the repo to reflect the new content.
+ # If the documentation is for a non-patch release (e.g. 1.19 -> 1.20),
+ # make sure to update the ``stable`` symlink to point to the new directory.
+ ln -sfn <latest_stable_directory> stable
+ # Commit the changes
git -C build/merge commit -am "Add documentation for <version>"
# Push to numpy/doc repo
git -C build/merge push
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck \
dist dist-build gitwash-update version-check html-build latex-build \
- merge-doc
+ merge-doc show
#------------------------------------------------------------------------------
@echo " gitwash-update GITWASH=path/to/gitwash update gitwash developer docs"
@echo " upload USERNAME=... RELEASE=... to upload built docs to docs.scipy.org"
@echo " merge-doc TAG=... to clone numpy/doc and archive documentation into it"
+ @echo " show to show the html output in a browser"
clean:
-rm -rf build/*
mkdir -p build/html build/doctrees
$(SPHINXBUILD) -t scipyorg -b html $(ALLSPHINXOPTS) build/html-scipyorg $(FILES)
@echo
- @echo "Build finished. The HTML pages are in build/html."
+ @echo "Build finished. The HTML pages are in build/html-scipyorg."
pickle: generate version-check
mkdir -p build/pickle build/doctrees
@echo "Running Texinfo files through makeinfo..."
make -C build/texinfo info
@echo "makeinfo finished; the Info files are in build/texinfo."
+
+show:
+ @python -c "import webbrowser; webbrowser.open_new_tab('file://$(PWD)/build/html/index.html')"
+
-This file contains a walkthrough of the NumPy 1.14.5 release on Linux, modified
+This file contains a walkthrough of the NumPy 1.19.0 release on Linux, modified
for building on azure and uploading to anaconda.org
The commands can be copied into the command line, but be sure to
-replace 1.14.5 by the correct version.
+replace 1.19.0 by the correct version.
This should be read together with the general directions in `releasing`.
-Release Walkthrough
-====================
-
-Note that in the code snippets below, ``upstream`` refers to the root repository on
-github and ``origin`` to a fork in your personal account. You may need to make adjustments
-if you have not forked the repository but simply cloned it locally. You can
-also edit ``.git/config`` and add ``upstream`` if it isn't already present.
-
+Release Preparation
+===================
Backport Pull Requests
----------------------
Changes that have been marked for this release must be backported to the
-maintenance/1.14.x branch.
+maintenance/1.19.x branch.
Update Release documentation
----------------------------
-The file ``doc/changelog/1.14.5-changelog.rst`` should be updated to reflect
+The file ``doc/changelog/1.19.0-changelog.rst`` should be updated to reflect
the final list of changes and contributors. This text can be generated by::
- $ python tools/changelog.py $GITHUB v1.14.4..maintenance/1.14.x > doc/changelog/1.14.5-changelog.rst
+ $ python tools/changelog.py $GITHUB v1.18.0..maintenance/1.19.x > doc/changelog/1.19.0-changelog.rst
where ``GITHUB`` contains your github access token. This text may also be
-appended to ``doc/release/1.14.5-notes.rst`` for release updates, though not
-for new releases like ``1.14.0``, as the changelogs for ``*.0`` releases tend to be
-excessively long. The ``doc/source/release.rst`` file should also be
-updated with a link to the new release notes. These changes should be committed
-to the maintenance branch, and later will be forward ported to master.
+appended to ``doc/release/1.19.0-notes.rst`` for patch release, though not for
+new releases like ``1.19.0``, as the changelogs for ``*.0`` releases tend to be
+excessively long. The ``doc/source/release.rst`` file should also be updated
+with a link to the new release notes. These changes should be committed to the
+maintenance branch, and later will be forward ported to master. The changelog
+should be reviewed for name duplicates or short names and the ``.mailmap`` file
+updated if needed.
Finish the Release Note
This has changed now that we use ``towncrier``. See the instructions for
creating the release note in ``doc/release/upcoming_changes/README.rst``.
-Fill out the release note ``doc/release/1.14.5-notes.rst`` calling out
+Fill out the release note ``doc/release/1.19.0-notes.rst`` calling out
significant changes.
+Release Walkthrough
+====================
+
+Note that in the code snippets below, ``upstream`` refers to the root repository on
+github and ``origin`` to a fork in your personal account. You may need to make adjustments
+if you have not forked the repository but simply cloned it locally. You can
+also edit ``.git/config`` and add ``upstream`` if it isn't already present.
+
Prepare the release commit
--------------------------
Checkout the branch for the release, make sure it is up to date, and clean the
repository::
- $ git checkout maintenance/1.14.x
- $ git pull upstream maintenance/1.14.x
+ $ git checkout maintenance/1.19.x
+ $ git pull upstream maintenance/1.19.x
$ git submodule update
$ git clean -xdfq
Edit pavement.py and setup.py as detailed in HOWTO_RELEASE::
- $ gvim pavement.py setup.py
- $ git commit -a -m"REL: NumPy 1.14.5 release."
+ $ gvim pavement.py setup.py # Generally only setup.py needs updating
+ $ git commit -a -m"REL: NumPy 1.19.0 release."
Sanity check::
Push this release directly onto the end of the maintenance branch. This
requires write permission to the numpy repository::
- $ git push upstream maintenance/1.14.x
-
-As an example, see the 1.14.3 REL commit: `<https://github.com/numpy/numpy/commit/73299826729be58cec179b52c656adfcaefada93>`_.
+ $ git push upstream HEAD
Build source releases
source releases in the latter. ::
$ python3 -m cython --version # check for correct cython version
- $ paver sdist # sdist will do a git clean -xdf, so we omit that
+ $ paver sdist # sdist will do a git clean -xdfq, so we omit that
Build wheels
Trigger the wheels build by pointing the numpy-wheels repository at this
commit. This can take up to an hour. The numpy-wheels repository is cloned from
-`<https://github.com/MacPython/numpy-wheels>`_. Start with a pull as the repo
-may have been accessed and changed by someone else and a push will fail::
+`<https://github.com/MacPython/numpy-wheels>`_. If this is the first release in
+a series, start with a pull as the repo may have been accessed and changed by
+someone else, then create a new branch for the series. If the branch already
+exists skip this::
$ cd ../numpy-wheels
+ $ git co master
$ git pull upstream master
- $ git branch <new version> # only when starting new numpy version
- $ git checkout v1.14.x # v1.14.x already existed for the 1.14.4 release
+ $ git branch v1.19.x
-Edit the ``azure/posix.yml`` and ``azure/windows.yml`` files to make sure they
-have the correct version, and put in the commit hash for the ``REL`` commit
-created above for ``BUILD_COMMIT``, see an _example::
+Checkout the new branch and edit the ``azure-pipelines.yml`` and
+``.travis.yml`` files to make sure they have the correct version, and put in
+the commit hash for the ``REL`` commit created above for ``BUILD_COMMIT``. The
+``azure/posix.yml`` and ``.travis.yml`` files may also need the Cython versions
+updated to keep up with Python releases, but generally just do::
- $ gvim azure/posix.yml azure/windows.yml
- $ git commit -a
+ $ git checkout v1.19.x
+ $ gvim azure-pipelines .travis.yml
+ $ git commit -a -m"NumPy 1.19.0 release."
$ git push upstream HEAD
Now wait. If you get nervous at the amount of time taken -- the builds can take
a while -- you can check the build progress by following the links
-provided at `<https://github.com/MacPython/numpy-wheels>`_ to check the
+provided at `<https://github.com/MacPython/numpy-wheels>`_ to check the
build status. Check if all the needed wheels have been built and
-uploaded before proceeding. There should currently be 21 of them at
-`<https://anaconda.org/multibuild-wheels-staging/numpy/files>`_, 3 for Mac, 6
-for Windows, and 12 for Linux.
+uploaded to the staging repository before proceeding.
-.. example_: https://github.com/MacPython/numpy-wheels/pull/80/commits/cbf4af4
-
-Note that sometimes builds, like tests, fail for unrelated reasons and
-you will need to restart them.
+Note that sometimes builds, like tests, fail for unrelated reasons and you will
+need to rerun them. You will need to be logged in under 'numpy' to do this
+on azure.
Download wheels
---------------
-When the wheels have all been successfully built, download them using the ``wheel-uploader``
-in the ``terryfy`` repository. The terryfy repository may be cloned from
-`<https://github.com/MacPython/terryfy>`_ if you don't already have it. The
-wheels can also be uploaded using the ``wheel-uploader``, but we prefer to
-download all the wheels to the ``../numpy/release/installers`` directory and
-upload later using ``twine``::
+When the wheels have all been successfully built and staged, download them from the
+Anaconda staging directory using the ``tools/download-wheels.py`` script::
- $ cd ../terryfy
- $ git pull upstream master
- $ CDN_URL=https://anaconda.org/multibuild-wheels-staging/numpy/files
- $ NPY_WHLS=../numpy/release/installers
- $ ./wheel-uploader -u $CDN_URL -n -v -w $NPY_WHLS -t win numpy 1.14.5
- $ ./wheel-uploader -u $CDN_URL -n -v -w $NPY_WHLS -t manylinux1 numpy 1.14.5
- $ ./wheel-uploader -u $CDN_URL -n -v -w $NPY_WHLS -t macosx numpy 1.14.5
+ $ cd ../numpy
+ $ python3 tools/download-wheels.py 1.19.0
-If you do this often, consider making CDN_URL and NPY_WHLS part of your default
-environment.
Generate the README files
-------------------------
This needs to be done after all installers are downloaded, but before the pavement
file is updated for continued development::
- $ cd ../numpy
$ paver write_release
Tag the release
---------------
-Once the wheels have been built and downloaded without errors, go back to your
-numpy repository in the maintenance branch and tag the ``REL`` commit, signing
+Once the wheels have been built and downloaded without errors tag the ``REL`` commit, signing
it with your gpg key::
- $ git tag -s v1.14.5
+ $ git tag -s -m"NumPy 1.19.0 release" v1.19.0
You should upload your public gpg key to github, so that the tag will appear
"verified" there.
Check that the files in ``release/installers`` have the correct versions, then
push the tag upstream::
- $ git push upstream v1.14.5
+ $ git push upstream v1.19.0
We wait until this point to push the tag because it is public and should not
be changed after it has been pushed.
Create release notes for next release and edit them to set the version::
- $ cp doc/source/release/template.rst doc/source/release/1.14.6-notes.rst
- $ gvim doc/source/release/1.14.6-notes.rst
- $ git add doc/source/release/1.14.6-notes.rst
+ $ cp doc/source/release/template.rst doc/source/release/1.19.1-notes.rst
+ $ gvim doc/source/release/1.19.1-notes.rst
+ $ git add doc/source/release/1.19.1-notes.rst
Add new release notes to the documentation release list::
Commit the result::
- $ git commit -a -m"REL: prepare 1.14.x for further development"
- $ git push upstream maintenance/1.14.x
+ $ git commit -a -m"REL: prepare 1.19.x for further development"
+ $ git push upstream HEAD
Upload to PyPI
--------------
Upload to PyPI using ``twine``. A recent version of ``twine`` of is needed
-after recent PyPI changes, version ``1.11.0`` was used here.
-
-.. code-block:: sh
+after recent PyPI changes, version ``3.1.1`` was used here::
$ cd ../numpy
$ twine upload release/installers/*.whl
- $ twine upload release/installers/numpy-1.14.5.zip # Upload last.
+ $ twine upload release/installers/numpy-1.19.0.zip # Upload last.
-If one of the commands breaks in the middle, which is not uncommon, you may
-need to selectively upload the remaining files because PyPI does not allow the
-same file to be uploaded twice. The source file should be uploaded last to
-avoid synchronization problems if pip users access the files while this is in
+If one of the commands breaks in the middle, you may need to selectively upload
+the remaining files because PyPI does not allow the same file to be uploaded
+twice. The source file should be uploaded last to avoid synchronization
+problems that might occur if pip users access the files while this is in
process. Note that PyPI only allows a single source distribution, here we have
chosen the zip archive.
Upload files to github
----------------------
-Go to `<https://github.com/numpy/numpy/releases>`_, there should be a ``v1.14.5
+Go to `<https://github.com/numpy/numpy/releases>`_, there should be a ``v1.19.0
tag``, click on it and hit the edit button for that tag. There are two ways to
-add files, using an editable text window and as binary uploads.
+add files, using an editable text window and as binary uploads. Cut and paste
+the ``release/README.md`` file contents into the text window. You will probably
+need to make some edits to get it to look right. Then
-- Cut and paste the ``release/README.md`` file contents into the text window.
-- Upload ``release/installers/numpy-1.14.5.tar.gz`` as a binary file.
-- Upload ``release/installers/numpy-1.14.5.zip`` as a binary file.
+- Upload ``release/installers/numpy-1.19.0.tar.gz`` as a binary file.
+- Upload ``release/installers/numpy-1.19.0.zip`` as a binary file.
- Upload ``release/README.rst`` as a binary file.
-- Upload ``doc/changelog/1.14.5-changelog.rst`` as a binary file.
+- Upload ``doc/changelog/1.19.0-changelog.rst`` as a binary file.
- Check the pre-release button if this is a pre-releases.
- Hit the ``{Publish,Update} release`` button at the bottom.
Otherwise, only the ``zip`` and ``pdf`` links should be updated with the
new tag name::
- $ gvim doc/build/merge/index.html +/'tag v1.14'
+ $ gvim doc/build/merge/index.html +/'tag v1.19'
You can "test run" the new documentation in a browser to make sure the links
work::
Once everything seems satisfactory, commit and upload the changes::
$ pushd doc/build/merge
- $ git commit -am"Add documentation for v1.14.5"
+ $ git commit -am"Add documentation for v1.19.0"
$ git push
$ popd
$ cd ../scipy.org
$ git checkout master
$ git pull upstream master
- $ git checkout -b numpy-1.14.5
+ $ git checkout -b numpy-1.19.0
$ gvim www/index.rst # edit the News section
$ git commit -a
$ git push origin HEAD
Checkout master and forward port the documentation changes::
- $ git checkout -b update-after-1.14.5-release
- $ git checkout maintenance/1.14.x doc/source/release/1.14.5-notes.rst
- $ git checkout maintenance/1.14.x doc/changelog/1.14.5-changelog.rst
+ $ git checkout -b post-1.19.0-release-update
+ $ git checkout maintenance/1.19.x doc/source/release/1.19.0-notes.rst
+ $ git checkout maintenance/1.19.x doc/changelog/1.19.0-changelog.rst
+ $ git checkout maintenance/1.19.x .mailmap # only if updated for release.
$ gvim doc/source/release.rst # Add link to new notes
- $ git add doc/changelog/1.14.5-changelog.rst doc/source/release/1.14.5-notes.rst
+ $ git add doc/changelog/1.19.0-changelog.rst doc/source/release/1.19.0-notes.rst
$ git status # check status before commit
- $ git commit -a -m"REL: Update master after 1.14.5 release."
+ $ git commit -a -m"REL: Update master after 1.19.0 release."
$ git push origin HEAD
Go to github and make a PR.
Labeling tests
--------------
-As an alternative to ``pytest.mark.<label>``, there are a number of labels you
-can use.
-
Unlabeled tests like the ones above are run in the default
``numpy.test()`` run. If you want to label your test as slow - and
therefore reserved for a full ``numpy.test(label='full')`` run, you
-can label it with a decorator::
+can label it with ``pytest.mark.slow``::
- # numpy.testing module includes 'import decorators as dec'
- from numpy.testing import dec, assert_
+ import pytest
- @dec.slow
+ @pytest.mark.slow
def test_big(self):
print 'Big, slow test'
Similarly for methods::
class test_zzz:
- @dec.slow
+ @pytest.mark.slow
def test_simple(self):
assert_(zzz() == 'Hello from zzz')
-Available labels are:
-
-- ``slow``: marks a test as taking a long time
-- ``setastest(tf)``: work-around for test discovery when the test name is
- non conformant
-- ``skipif(condition, msg=None)``: skips the test when ``eval(condition)`` is
- ``True``
-- ``knownfailureif(fail_cond, msg=None)``: will avoid running the test if
- ``eval(fail_cond)`` is ``True``, useful for tests that conditionally segfault
-- ``deprecated(conditional=True)``: filters deprecation warnings emitted in the
- test
-- ``paramaterize(var, input)``: an alternative to
- `pytest.mark.paramaterized
- <https://docs.pytest.org/en/latest/parametrize.html>`_
-
Easier setup and teardown functions / methods
---------------------------------------------
Contributors
============
-A total of 125 people contributed to this release. People with a "+" by their
+A total of 126 people contributed to this release. People with a "+" by their
names contributed a patch for the first time.
* Alex Henrie
* Chris Barker
* Chris Holland +
* Christian Kastner +
+* Chunlin +
* Chunlin Fang +
* Damien Caliste +
* Dan Allan
--- /dev/null
+
+Contributors
+============
+
+A total of 184 people contributed to this release. People with a "+" by their
+names contributed a patch for the first time.
+
+* Aaron Meurer +
+* Abhilash Barigidad +
+* Abhinav Reddy +
+* Abhishek Singh +
+* Al-Baraa El-Hag +
+* Albert Villanova del Moral +
+* Alex Leontiev +
+* Alex Rockhill +
+* Alex Rogozhnikov
+* Alexander Belopolsky
+* Alexander Kuhn-Regnier +
+* Allen Downey +
+* Andras Deak
+* Andrea Olivo +
+* Andrew Eckart +
+* Anirudh Subramanian
+* Anthony Byuraev +
+* Antonio Larrosa +
+* Ashutosh Singh +
+* Bangcheng Yang +
+* Bas van Beek +
+* Ben Derrett +
+* Ben Elliston +
+* Ben Nathanson +
+* Bernie Gray +
+* Bharat Medasani +
+* Bharat Raghunathan
+* Bijesh Mohan +
+* Bradley Dice +
+* Brandon David +
+* Brandt Bucher
+* Brian Soto +
+* Brigitta Sipocz
+* Cameron Blocker +
+* Carl Leake +
+* Charles Harris
+* Chris Brown +
+* Chris Vavaliaris +
+* Christoph Gohlke
+* Chunlin Fang
+* CloseChoice +
+* Daniel G. A. Smith +
+* Daniel Hrisca
+* Daniel Vanzo +
+* David Pitchford +
+* Davide Dal Bosco +
+* Derek Homeier
+* Dima Kogan +
+* Dmitry Kutlenkov +
+* Douglas Fenstermacher +
+* Dustin Spicuzza +
+* E. Madison Bray +
+* Elia Franzella +
+* Enrique Matías Sánchez +
+* Erfan Nariman | Veneficus +
+* Eric Larson
+* Eric Moore
+* Eric Wieser
+* Erik M. Bray
+* EthanCJ-git +
+* Etienne Guesnet +
+* FX Coudert +
+* Felix Divo
+* Frankie Robertson +
+* Ganesh Kathiresan
+* Gengxin Xie
+* Gerry Manoim +
+* Guilherme Leobas
+* Hassan Kibirige
+* Hugo Mendes +
+* Hugo van Kemenade
+* Ian Thomas +
+* InessaPawson +
+* Isabela Presedo-Floyd +
+* Isuru Fernando
+* Jakob Jakobson +
+* Jakub Wilk
+* James Myatt +
+* Jesse Li +
+* John Hagen +
+* John Zwinck
+* Joseph Fox-Rabinovitz
+* Josh Wilson
+* Jovial Joe Jayarson +
+* Julia Signell +
+* Jun Kudo +
+* Karan Dhir +
+* Kaspar Thommen +
+* Kerem Hallaç
+* Kevin Moore +
+* Kevin Sheppard
+* Klaus Zimmermann +
+* LSchroefl +
+* Laurie +
+* Laurie Stephey +
+* Levi Stovall +
+* Lisa Schwetlick +
+* Lukas Geiger +
+* Madhulika Jain Chambers +
+* Matthias Bussonnier
+* Matti Picus
+* Melissa Weber Mendonça
+* Michael Hirsch
+* Nick R. Papior
+* Nikola Forró
+* Noman Arshad +
+* Paul YS Lee +
+* Pauli Virtanen
+* Paweł Redzyński +
+* Peter Andreas Entschev
+* Peter Bell
+* Philippe Ombredanne +
+* Phoenix Meadowlark +
+* Piotr Gaiński
+* Raghav Khanna +
+* Raghuveer Devulapalli
+* Rajas Rade +
+* Rakesh Vasudevan
+* Ralf Gommers
+* Raphael Kruse +
+* Rashmi K A +
+* Robert Kern
+* Rohit Sanjay +
+* Roman Yurchak
+* Ross Barnowski
+* Royston E Tauro +
+* Ryan C Cooper +
+* Ryan Soklaski
+* Safouane Chergui +
+* Sahil Siddiq +
+* Sarthak Vineet Kumar +
+* Sayed Adel
+* Sebastian Berg
+* Sergei Vorfolomeev +
+* Seth Troisi
+* Sidhant Bansal +
+* Simon Gasse
+* Simon Graham +
+* Stefan Appelhoff +
+* Stefan Behnel +
+* Stefan van der Walt
+* Steve Dower
+* Steve Joachim +
+* Steven Pitman +
+* Stuart Archibald
+* Sturla Molden
+* Susan Chang +
+* Takanori H +
+* Tapajyoti Bose +
+* Thomas A Caswell
+* Tina Oberoi
+* Tirth Patel
+* Tobias Pitters +
+* Tomoki, Karatsu +
+* Tyler Reddy
+* Veniamin Petrenko +
+* Wansoo Kim +
+* Warren Weckesser
+* Wei Yang +
+* Wojciech Rzadkowski
+* Yang Hau +
+* Yogesh Raisinghani +
+* Yu Feng
+* Yuya Unno +
+* Zac Hatfield-Dodds
+* Zuhair Ali-Khan +
+* @abhilash42 +
+* @danbeibei +
+* @dojafrat
+* @dpitch40 +
+* @forfun +
+* @iamsoto +
+* @jbrockmendel +
+* @leeyspaul +
+* @mitch +
+* @prateek arora +
+* @serge-sans-paille +
+* @skywalker +
+* @stphnlyd +
+* @xoviat
+* @谭九鼎 +
+* @JMFT +
+* @Jack +
+* @Neal C +
+
+Pull requests merged
+====================
+
+A total of 684 pull requests were merged for this release.
+
+* `#13516 <https://github.com/numpy/numpy/pull/13516>`__: ENH: enable multi-platform SIMD compiler optimizations
+* `#14779 <https://github.com/numpy/numpy/pull/14779>`__: NEP 36 (fair play)
+* `#14882 <https://github.com/numpy/numpy/pull/14882>`__: DEP: Deprecate aliases of builtin types in python 3.7+
+* `#15037 <https://github.com/numpy/numpy/pull/15037>`__: BUG: `np.resize` negative shape and subclasses edge case fixes
+* `#15121 <https://github.com/numpy/numpy/pull/15121>`__: ENH: random: Add the method `permuted` to Generator.
+* `#15162 <https://github.com/numpy/numpy/pull/15162>`__: BUG,MAINT: Fix issues with non-reduce broadcasting axes
+* `#15471 <https://github.com/numpy/numpy/pull/15471>`__: BUG: Ensure PyArray_FromScalar always returns the requested dtype
+* `#15507 <https://github.com/numpy/numpy/pull/15507>`__: NEP 42: Technical decisions for new DTypes
+* `#15508 <https://github.com/numpy/numpy/pull/15508>`__: API: Create Preliminary DTypeMeta class and np.dtype subclasses
+* `#15604 <https://github.com/numpy/numpy/pull/15604>`__: MAINT: Avoid exception in NpzFile destructor if constructor raises...
+* `#15666 <https://github.com/numpy/numpy/pull/15666>`__: ENH: Improved `__str__` for polynomials
+* `#15759 <https://github.com/numpy/numpy/pull/15759>`__: BUILD: Remove Accelerate support
+* `#15791 <https://github.com/numpy/numpy/pull/15791>`__: [DOC] Added tutorial about the numpy.ma module.
+* `#15852 <https://github.com/numpy/numpy/pull/15852>`__: ENH: Add where argument to np.mean
+* `#15886 <https://github.com/numpy/numpy/pull/15886>`__: DEP: Deprecate passing shape=None to mean shape=()
+* `#15900 <https://github.com/numpy/numpy/pull/15900>`__: DEP: Ensure indexing errors will be raised even on empty results
+* `#15997 <https://github.com/numpy/numpy/pull/15997>`__: ENH: improve printing of arrays with multi-line reprs
+* `#16130 <https://github.com/numpy/numpy/pull/16130>`__: DOC: Correct documentation of ``__array__`` when used as output...
+* `#16134 <https://github.com/numpy/numpy/pull/16134>`__: ENH: Implement concatenate dtype and casting keyword arguments
+* `#16156 <https://github.com/numpy/numpy/pull/16156>`__: DEP: Deprecate `numpy.dual`.
+* `#16161 <https://github.com/numpy/numpy/pull/16161>`__: BUG: Potential fix for divmod(1.0, 0.0) to raise divbyzero and...
+* `#16167 <https://github.com/numpy/numpy/pull/16167>`__: DOC: Increase guidance and detail of np.polynomial docstring
+* `#16174 <https://github.com/numpy/numpy/pull/16174>`__: DOC: Add transition note to all lib/poly functions
+* `#16200 <https://github.com/numpy/numpy/pull/16200>`__: ENH: Rewrite of array-coercion to support new dtypes
+* `#16205 <https://github.com/numpy/numpy/pull/16205>`__: ENH: Add ``full_output`` argument to ``f2py.compile``.
+* `#16232 <https://github.com/numpy/numpy/pull/16232>`__: DEP: Deprecate ufunc.outer with matrix inputs
+* `#16238 <https://github.com/numpy/numpy/pull/16238>`__: MAINT: Unify cached (C-level static) imports
+* `#16239 <https://github.com/numpy/numpy/pull/16239>`__: BUG,DOC: Allow attach docs twice but error if wrong
+* `#16242 <https://github.com/numpy/numpy/pull/16242>`__: BUG: Fix default fallback in genfromtxt
+* `#16247 <https://github.com/numpy/numpy/pull/16247>`__: ENH:Umath Replace raw SIMD of unary float point(32-64) with NPYV...
+* `#16248 <https://github.com/numpy/numpy/pull/16248>`__: MRG, ENH: added edge keyword argument to digitize
+* `#16257 <https://github.com/numpy/numpy/pull/16257>`__: DOC: Update the f2py section of the "Using Python as Glue" page.
+* `#16260 <https://github.com/numpy/numpy/pull/16260>`__: DOC: Improve `rec.array` function documentation (#15853)
+* `#16266 <https://github.com/numpy/numpy/pull/16266>`__: ENH: include dt64/td64 isinstance checks in ``__init__.pxd``
+* `#16267 <https://github.com/numpy/numpy/pull/16267>`__: DOC: Clarifications for np.std
+* `#16273 <https://github.com/numpy/numpy/pull/16273>`__: BUG: Order percentile monotonically
+* `#16274 <https://github.com/numpy/numpy/pull/16274>`__: MAINT: cleanups to quantile
+* `#16275 <https://github.com/numpy/numpy/pull/16275>`__: REL: Update master after 1.19.x branch.
+* `#16276 <https://github.com/numpy/numpy/pull/16276>`__: BUG: Ensure out argument is returned by identity for 0d arrays
+* `#16278 <https://github.com/numpy/numpy/pull/16278>`__: DOC: Clarifications for ``np.var``.
+* `#16283 <https://github.com/numpy/numpy/pull/16283>`__: DOC: Add a note about performance of isclose compared to math.isclose
+* `#16284 <https://github.com/numpy/numpy/pull/16284>`__: MAINT: Clean up the implementation of quantile
+* `#16285 <https://github.com/numpy/numpy/pull/16285>`__: MAINT: Bump hypothesis from 5.12.0 to 5.14.0
+* `#16291 <https://github.com/numpy/numpy/pull/16291>`__: DOC: Improve "tobytes" docstring.
+* `#16292 <https://github.com/numpy/numpy/pull/16292>`__: BUG: Fix tools/download-wheels.py.
+* `#16295 <https://github.com/numpy/numpy/pull/16295>`__: BUG: Require Python >= 3.6 in setup.py
+* `#16296 <https://github.com/numpy/numpy/pull/16296>`__: DOC: Fix malformed docstrings in ma.
+* `#16297 <https://github.com/numpy/numpy/pull/16297>`__: ENH: Optimize Cpu feature detect in X86, fix for GCC on macOS
+* `#16298 <https://github.com/numpy/numpy/pull/16298>`__: BUG: np.info does not show keyword-only arguments
+* `#16300 <https://github.com/numpy/numpy/pull/16300>`__: DOC: Fix bad reference in ``numpy.ma``
+* `#16304 <https://github.com/numpy/numpy/pull/16304>`__: TST, MAINT: Fix detecting and testing armhf features
+* `#16305 <https://github.com/numpy/numpy/pull/16305>`__: DOC: Fix packbits documentation rendering,
+* `#16306 <https://github.com/numpy/numpy/pull/16306>`__: DOC: Fix troubleshooting code snippet when env vars are empty
+* `#16308 <https://github.com/numpy/numpy/pull/16308>`__: BUG: relpath fails for different drives on windows
+* `#16311 <https://github.com/numpy/numpy/pull/16311>`__: DOC: Fix ``np.ma.core.doc_note``
+* `#16316 <https://github.com/numpy/numpy/pull/16316>`__: MAINT: Bump numpydoc version
+* `#16318 <https://github.com/numpy/numpy/pull/16318>`__: MAINT: Stop Using PyEval_Call* and simplify some uses
+* `#16321 <https://github.com/numpy/numpy/pull/16321>`__: ENH: Improve the ARM cpu feature detection by parsing /proc/cpuinfo
+* `#16323 <https://github.com/numpy/numpy/pull/16323>`__: DOC: Reconstruct Testing Guideline.
+* `#16329 <https://github.com/numpy/numpy/pull/16329>`__: MAINT: Cleanup 'tools/download-wheels.py'
+* `#16332 <https://github.com/numpy/numpy/pull/16332>`__: DOC: link np.interp to SciPy's interpolation functions (closes...
+* `#16333 <https://github.com/numpy/numpy/pull/16333>`__: DOC: Fix spelling typo - homogenous to homogeneous. (#16324)
+* `#16334 <https://github.com/numpy/numpy/pull/16334>`__: ENH: Use AVX-512 for np.isnan, np.infinite, np.isinf and np.signbit
+* `#16336 <https://github.com/numpy/numpy/pull/16336>`__: BUG: Fix refcounting in add_newdoc
+* `#16337 <https://github.com/numpy/numpy/pull/16337>`__: CI: Create a link for the circleCI artifact
+* `#16348 <https://github.com/numpy/numpy/pull/16348>`__: BUG: Fix dtype leak in `PyArray_FromAny` error path
+* `#16349 <https://github.com/numpy/numpy/pull/16349>`__: BUG: Indentation for docstrings
+* `#16351 <https://github.com/numpy/numpy/pull/16351>`__: BUG: Fix small leaks in error path and ``empty_like`` with shape
+* `#16362 <https://github.com/numpy/numpy/pull/16362>`__: MAINT: Streamline download-wheels.
+* `#16365 <https://github.com/numpy/numpy/pull/16365>`__: DOC: Fix an obvious mistake in a message printed in doc/Makefile.
+* `#16367 <https://github.com/numpy/numpy/pull/16367>`__: MAINT: Bump cython from 0.29.17 to 0.29.19
+* `#16368 <https://github.com/numpy/numpy/pull/16368>`__: MAINT: Bump hypothesis from 5.14.0 to 5.15.1
+* `#16369 <https://github.com/numpy/numpy/pull/16369>`__: MAINT: Bump pytest-cov from 2.8.1 to 2.9.0
+* `#16371 <https://github.com/numpy/numpy/pull/16371>`__: ENH: Use AVX-512 for np.frexp and np.ldexp
+* `#16373 <https://github.com/numpy/numpy/pull/16373>`__: MAINT, DOC: add index for user docs.
+* `#16375 <https://github.com/numpy/numpy/pull/16375>`__: ENH: ARM Neon implementation with intrinsic for np.argmax.
+* `#16385 <https://github.com/numpy/numpy/pull/16385>`__: DOC: Tighten howto-docs guide #16259
+* `#16387 <https://github.com/numpy/numpy/pull/16387>`__: MAINT: Make ctypes optional on Windows
+* `#16389 <https://github.com/numpy/numpy/pull/16389>`__: ENH: Hardcode buffer handling for simple scalars
+* `#16392 <https://github.com/numpy/numpy/pull/16392>`__: MAINT: Stop uploading wheels to Rackspace.
+* `#16393 <https://github.com/numpy/numpy/pull/16393>`__: MAINT: Use a raw string for the fromstring docstring.
+* `#16395 <https://github.com/numpy/numpy/pull/16395>`__: ENH: Validate and disable CPU features in runtime
+* `#16397 <https://github.com/numpy/numpy/pull/16397>`__: ENH: Implement the NumPy C SIMD vectorization interface
+* `#16404 <https://github.com/numpy/numpy/pull/16404>`__: DOC,BLD: Update make dist html target.
+* `#16408 <https://github.com/numpy/numpy/pull/16408>`__: DOC,BLD: Update sphinx conf to use xelatex.
+* `#16409 <https://github.com/numpy/numpy/pull/16409>`__: TST, CI: turn on codecov patch diffs
+* `#16411 <https://github.com/numpy/numpy/pull/16411>`__: BUG: endpoints of array returned by geomspace() should match...
+* `#16417 <https://github.com/numpy/numpy/pull/16417>`__: MAINT: support python 3.10
+* `#16418 <https://github.com/numpy/numpy/pull/16418>`__: MAINT: Chain some exceptions.
+* `#16420 <https://github.com/numpy/numpy/pull/16420>`__: DOC: Improve intersect1d docstring
+* `#16422 <https://github.com/numpy/numpy/pull/16422>`__: DOC: Update assert_warns parameter list
+* `#16423 <https://github.com/numpy/numpy/pull/16423>`__: TST: Simplify assert_warns in test_io.py
+* `#16427 <https://github.com/numpy/numpy/pull/16427>`__: DOC: make NEP 18 status Final
+* `#16428 <https://github.com/numpy/numpy/pull/16428>`__: DOC: Add style guide to howto_document
+* `#16430 <https://github.com/numpy/numpy/pull/16430>`__: DOC: NEP for C style guide
+* `#16433 <https://github.com/numpy/numpy/pull/16433>`__: DOC: Fix description of dtype default in linspace
+* `#16435 <https://github.com/numpy/numpy/pull/16435>`__: BUG: Add extern to PyArrayDTypeMeta_Type declaration
+* `#16436 <https://github.com/numpy/numpy/pull/16436>`__: DOC: Add a reference into NEP 29,
+* `#16438 <https://github.com/numpy/numpy/pull/16438>`__: MAINT: Catch remaining cases of Py_SIZE and Py_TYPE as lvalues
+* `#16442 <https://github.com/numpy/numpy/pull/16442>`__: ENH: Fix deprecated warn for Intel/Apple/Clang Compiler
+* `#16444 <https://github.com/numpy/numpy/pull/16444>`__: DOC: make clearer that sinc is normalized by a factor pi
+* `#16445 <https://github.com/numpy/numpy/pull/16445>`__: DOC: update roadmap
+* `#16446 <https://github.com/numpy/numpy/pull/16446>`__: BUG: fixes einsum output order with optimization (#14615)
+* `#16447 <https://github.com/numpy/numpy/pull/16447>`__: DOC: add a "make show" command to doc/Makefile
+* `#16450 <https://github.com/numpy/numpy/pull/16450>`__: DOC: Add a NEP link to all neps.
+* `#16452 <https://github.com/numpy/numpy/pull/16452>`__: DOC,ENH: extend error message when Accelerate is detected
+* `#16463 <https://github.com/numpy/numpy/pull/16463>`__: DOC: Improve assert_warns docstring with example
+* `#16464 <https://github.com/numpy/numpy/pull/16464>`__: MAINT: Bump hypothesis from 5.15.1 to 5.16.0
+* `#16465 <https://github.com/numpy/numpy/pull/16465>`__: DOC: Fix development_workflow links
+* `#16468 <https://github.com/numpy/numpy/pull/16468>`__: BUG: fix GCC 10 major version comparison
+* `#16471 <https://github.com/numpy/numpy/pull/16471>`__: BLD: install mingw32 v7.3.0 for win32
+* `#16472 <https://github.com/numpy/numpy/pull/16472>`__: DOC: Fixes for 18 broken links
+* `#16474 <https://github.com/numpy/numpy/pull/16474>`__: MAINT: use zip instead of range in piecewise
+* `#16476 <https://github.com/numpy/numpy/pull/16476>`__: ENH: add `norm=forward,backward` to numpy.fft functions
+* `#16482 <https://github.com/numpy/numpy/pull/16482>`__: SIMD: Optimize the performace of np.packbits in ARM-based machine.
+* `#16485 <https://github.com/numpy/numpy/pull/16485>`__: BUG: Fix result when a gufunc output broadcasts the inputs.
+* `#16500 <https://github.com/numpy/numpy/pull/16500>`__: DOC: Point Contributing page to new NEP 45
+* `#16501 <https://github.com/numpy/numpy/pull/16501>`__: MAINT: make Py_SET_SIZE and Py_SET_TYPE macros a bit safer
+* `#16503 <https://github.com/numpy/numpy/pull/16503>`__: BUG:random: Error when ``size`` is smaller than broadcast input...
+* `#16504 <https://github.com/numpy/numpy/pull/16504>`__: DOC: Correct MV Normal sig
+* `#16505 <https://github.com/numpy/numpy/pull/16505>`__: BUG: raise IEEE exception on AIX
+* `#16506 <https://github.com/numpy/numpy/pull/16506>`__: DOC: only single-polynomial fitting in np.polynomial.Polynomial.fit()
+* `#16510 <https://github.com/numpy/numpy/pull/16510>`__: DOC: Minor rounding correction in Generator.binomial
+* `#16514 <https://github.com/numpy/numpy/pull/16514>`__: STY: trivial doc style fix in NEP 45.
+* `#16515 <https://github.com/numpy/numpy/pull/16515>`__: ENH: add type stubs from numpy-stubs
+* `#16519 <https://github.com/numpy/numpy/pull/16519>`__: BUG: f2py: make callbacks threadsafe
+* `#16520 <https://github.com/numpy/numpy/pull/16520>`__: STY: f2py: replace \t by whitespace for readability
+* `#16522 <https://github.com/numpy/numpy/pull/16522>`__: MAINT:ARMHF Fix detecting feature groups NEON_HALF and NEON_VFPV4
+* `#16523 <https://github.com/numpy/numpy/pull/16523>`__: MAINT: Improve buffer speed
+* `#16524 <https://github.com/numpy/numpy/pull/16524>`__: MAINT: f2py: move thread-local declaration definition to common...
+* `#16529 <https://github.com/numpy/numpy/pull/16529>`__: BUG: Fix cython warning in random/_common.pyx.
+* `#16530 <https://github.com/numpy/numpy/pull/16530>`__: MAINT: Bump pytest from 5.4.2 to 5.4.3
+* `#16532 <https://github.com/numpy/numpy/pull/16532>`__: BUG: Remove non-threadsafe sigint handling from fft calculation
+* `#16540 <https://github.com/numpy/numpy/pull/16540>`__: SIMD: SSE2 intrinsic implementation for float64 input of np.enisum
+* `#16551 <https://github.com/numpy/numpy/pull/16551>`__: BUG: Ensure SeedSequence 0-padding does not collide with spawn...
+* `#16554 <https://github.com/numpy/numpy/pull/16554>`__: DEP: Remove deprecated numeric types and deprecate remaining
+* `#16555 <https://github.com/numpy/numpy/pull/16555>`__: CI: drop win32 3.7, 3.6 builds
+* `#16556 <https://github.com/numpy/numpy/pull/16556>`__: MAINT: simplifying annotations for np.core.from_numeric
+* `#16558 <https://github.com/numpy/numpy/pull/16558>`__: ENH: make typing module available at runtime
+* `#16570 <https://github.com/numpy/numpy/pull/16570>`__: ENH: Throw TypeError on operator concat on Numpy Arrays
+* `#16571 <https://github.com/numpy/numpy/pull/16571>`__: TST: Add new tests for array coercion
+* `#16572 <https://github.com/numpy/numpy/pull/16572>`__: BUG: fix sin/cos bug when input is strided array
+* `#16574 <https://github.com/numpy/numpy/pull/16574>`__: MAINT: fix name of first parameter to dtype constructor in type...
+* `#16581 <https://github.com/numpy/numpy/pull/16581>`__: DOC: Added an example for np.transpose(4d_array)
+* `#16583 <https://github.com/numpy/numpy/pull/16583>`__: MAINT: changed np.generic arguments to positional-only
+* `#16590 <https://github.com/numpy/numpy/pull/16590>`__: DOC: Clarify dtype default for logspace and geomspace
+* `#16591 <https://github.com/numpy/numpy/pull/16591>`__: DOC: Disallow complex args in arange
+* `#16592 <https://github.com/numpy/numpy/pull/16592>`__: BUG: Raise TypeError for float->timedelta promotion
+* `#16594 <https://github.com/numpy/numpy/pull/16594>`__: ENH: Add ``__f2py_numpy_version__`` attribute to Fortran modules.
+* `#16596 <https://github.com/numpy/numpy/pull/16596>`__: BUG: Fix reference count leak in mapping.c
+* `#16601 <https://github.com/numpy/numpy/pull/16601>`__: MAINT: Move and improve ``test_ignore_nan_ulperror``.
+* `#16603 <https://github.com/numpy/numpy/pull/16603>`__: DOC: make addition of types a "new feature" in release notes
+* `#16605 <https://github.com/numpy/numpy/pull/16605>`__: MAINT: Avx512 intrinsics implementation for float64 input np.log
+* `#16606 <https://github.com/numpy/numpy/pull/16606>`__: MAINT: Bump pytest-cov from 2.9.0 to 2.10.0
+* `#16607 <https://github.com/numpy/numpy/pull/16607>`__: MAINT: Bump hypothesis from 5.16.0 to 5.16.1
+* `#16613 <https://github.com/numpy/numpy/pull/16613>`__: MAINT: bump mypy version to 0.780
+* `#16617 <https://github.com/numpy/numpy/pull/16617>`__: BLD: Openblas 0.3.10
+* `#16618 <https://github.com/numpy/numpy/pull/16618>`__: ENH: add annotation for abs
+* `#16619 <https://github.com/numpy/numpy/pull/16619>`__: BLD: check if std=c99 is really required
+* `#16620 <https://github.com/numpy/numpy/pull/16620>`__: MAINT, CI: disable Shippable cache
+* `#16621 <https://github.com/numpy/numpy/pull/16621>`__: BENCH: Expand array-creation benchmarks
+* `#16622 <https://github.com/numpy/numpy/pull/16622>`__: MAINT: Implemented two dtype-related TODO's
+* `#16623 <https://github.com/numpy/numpy/pull/16623>`__: BUG: Initialize stop-reading in array_from_text
+* `#16627 <https://github.com/numpy/numpy/pull/16627>`__: DOC: Updated documentation for numpy.squeeze
+* `#16629 <https://github.com/numpy/numpy/pull/16629>`__: ENH: add tool to find functions missing types
+* `#16630 <https://github.com/numpy/numpy/pull/16630>`__: ENH,BUG:distutils Remove the origins from the implied features
+* `#16633 <https://github.com/numpy/numpy/pull/16633>`__: MAINT: lib: Some code clean up in loadtxt
+* `#16635 <https://github.com/numpy/numpy/pull/16635>`__: BENCH: remove obsolete goal_time param
+* `#16639 <https://github.com/numpy/numpy/pull/16639>`__: BUG: Fix uint->timedelta promotion to raise TypeError
+* `#16642 <https://github.com/numpy/numpy/pull/16642>`__: MAINT: Replace `PyUString_GET_SIZE` with `PyUnicode_GetLength`.
+* `#16643 <https://github.com/numpy/numpy/pull/16643>`__: REL: Fix outdated docs link
+* `#16646 <https://github.com/numpy/numpy/pull/16646>`__: TST: add a static typing test for memoryviews as ArrayLikes
+* `#16647 <https://github.com/numpy/numpy/pull/16647>`__: ENH: Added annotations to 8 functions from np.core.fromnumeric
+* `#16648 <https://github.com/numpy/numpy/pull/16648>`__: REL: Update master after 1.19.0 release.
+* `#16650 <https://github.com/numpy/numpy/pull/16650>`__: ENH: Allow genfromtxt to unpack structured arrays
+* `#16651 <https://github.com/numpy/numpy/pull/16651>`__: MAINT: Prefer generator expressions over list comprehensions...
+* `#16653 <https://github.com/numpy/numpy/pull/16653>`__: DOC: cross-reference numpy.dot and numpy.linalg.multi_dot
+* `#16658 <https://github.com/numpy/numpy/pull/16658>`__: MAINT: Bump hypothesis from 5.16.1 to 5.16.3
+* `#16659 <https://github.com/numpy/numpy/pull/16659>`__: MAINT: Bump mypy from 0.780 to 0.781
+* `#16664 <https://github.com/numpy/numpy/pull/16664>`__: DOC: Add lib.format.open_memmap to autosummary.
+* `#16666 <https://github.com/numpy/numpy/pull/16666>`__: BUG: Fix bug in AVX complex absolute while processing array of...
+* `#16669 <https://github.com/numpy/numpy/pull/16669>`__: MAINT: remove blacklist/whitelist terms
+* `#16674 <https://github.com/numpy/numpy/pull/16674>`__: TST: Add extra debugging information to CPU features detection
+* `#16675 <https://github.com/numpy/numpy/pull/16675>`__: ENH: Add support for file like objects to np.core.records.fromfile
+* `#16683 <https://github.com/numpy/numpy/pull/16683>`__: DOC: updated gcc minimum recommend version to build from source
+* `#16684 <https://github.com/numpy/numpy/pull/16684>`__: MAINT: Allow `None` to be passed to certain `generic` subclasses
+* `#16690 <https://github.com/numpy/numpy/pull/16690>`__: DOC: fixed docstring for descr_to_dtype
+* `#16691 <https://github.com/numpy/numpy/pull/16691>`__: DOC: Remove "matrix" from `triu` docstring.
+* `#16696 <https://github.com/numpy/numpy/pull/16696>`__: MAINT: add py.typed sentinel to package manifest
+* `#16699 <https://github.com/numpy/numpy/pull/16699>`__: MAINT: Fixup quantile tests to not use `np.float`
+* `#16702 <https://github.com/numpy/numpy/pull/16702>`__: BLD: Add CPU entry for Emscripten / WebAssembly
+* `#16704 <https://github.com/numpy/numpy/pull/16704>`__: TST: Disable Python 3.9-dev testing.
+* `#16706 <https://github.com/numpy/numpy/pull/16706>`__: DOC: Add instruction about stable symlink
+* `#16708 <https://github.com/numpy/numpy/pull/16708>`__: MAINT: Disable use_hugepages in case of ValueError
+* `#16709 <https://github.com/numpy/numpy/pull/16709>`__: DOC: Add dep directive to alen docstring.
+* `#16710 <https://github.com/numpy/numpy/pull/16710>`__: ENH, BLD: Add RPATH support for AIX
+* `#16718 <https://github.com/numpy/numpy/pull/16718>`__: DOC: fix typo
+* `#16720 <https://github.com/numpy/numpy/pull/16720>`__: BUG: Fix PyArray_SearchSorted signature.
+* `#16729 <https://github.com/numpy/numpy/pull/16729>`__: ENH: Add annotations to the last 8 functions in numpy.core.fromnumeric
+* `#16730 <https://github.com/numpy/numpy/pull/16730>`__: ENH: Use f90 compiler specified in f2py command line args for...
+* `#16731 <https://github.com/numpy/numpy/pull/16731>`__: DOC: reword random c-api introduction, cython is documented in...
+* `#16735 <https://github.com/numpy/numpy/pull/16735>`__: DOC: Tweak a sentence about broadcasting.
+* `#16736 <https://github.com/numpy/numpy/pull/16736>`__: DOC: Prepend `ma.` to references in ``numpy.ma``
+* `#16738 <https://github.com/numpy/numpy/pull/16738>`__: DOC: Remove redundant word
+* `#16742 <https://github.com/numpy/numpy/pull/16742>`__: DOC: add unique() to See Also of repeat()
+* `#16743 <https://github.com/numpy/numpy/pull/16743>`__: DOC: add example to unique() and make connection to repeat()
+* `#16747 <https://github.com/numpy/numpy/pull/16747>`__: MAINT: Chaining exceptions in numpy/core/_internal.py
+* `#16752 <https://github.com/numpy/numpy/pull/16752>`__: BLD: add manylinux1 OpenBlAS 0.3.10 hashes and test for them
+* `#16757 <https://github.com/numpy/numpy/pull/16757>`__: DOC: Add Matti Picus to steering council page
+* `#16759 <https://github.com/numpy/numpy/pull/16759>`__: ENH: make dtype generic over scalar type
+* `#16760 <https://github.com/numpy/numpy/pull/16760>`__: DOC: Added a section in the 'Iterating over arrays' doc page...
+* `#16761 <https://github.com/numpy/numpy/pull/16761>`__: MAINT: Tidy exception chaining in _datasource.py
+* `#16762 <https://github.com/numpy/numpy/pull/16762>`__: MAINT: Fixes for deprecated functions in scalartypes.c.src
+* `#16764 <https://github.com/numpy/numpy/pull/16764>`__: MAINT: Bump mypy from 0.781 to 0.782
+* `#16765 <https://github.com/numpy/numpy/pull/16765>`__: MAINT: Bump hypothesis from 5.16.3 to 5.19.0
+* `#16767 <https://github.com/numpy/numpy/pull/16767>`__: ENH: Update NumPy logos
+* `#16770 <https://github.com/numpy/numpy/pull/16770>`__: MAINT: Remove unneeded call to PyUnicode_READY
+* `#16771 <https://github.com/numpy/numpy/pull/16771>`__: MAINT: Fix deprecated functions in scalarapi.c
+* `#16775 <https://github.com/numpy/numpy/pull/16775>`__: DOC: switch to logo with text
+* `#16782 <https://github.com/numpy/numpy/pull/16782>`__: ENH, TST: Bring the NumPy C SIMD vectorization interface "NPYV"...
+* `#16786 <https://github.com/numpy/numpy/pull/16786>`__: BENCH: Add basic benchmarks for scalar indexing and assignment
+* `#16789 <https://github.com/numpy/numpy/pull/16789>`__: BUG: fix decode error when building and get rid of warn
+* `#16792 <https://github.com/numpy/numpy/pull/16792>`__: DOC: Minor RST formatting.
+* `#16793 <https://github.com/numpy/numpy/pull/16793>`__: BLD, MAINT: update cython to 0.29.21
+* `#16794 <https://github.com/numpy/numpy/pull/16794>`__: TST: Upgrade to Python 3.8 for DEBUG testing.
+* `#16798 <https://github.com/numpy/numpy/pull/16798>`__: DOC: Fix RST/numpydoc standard.
+* `#16800 <https://github.com/numpy/numpy/pull/16800>`__: MAINT: Move typing tests
+* `#16802 <https://github.com/numpy/numpy/pull/16802>`__: MAINT: Explicitly disallow object user dtypes
+* `#16805 <https://github.com/numpy/numpy/pull/16805>`__: DOC: add example to corrcoef function
+* `#16806 <https://github.com/numpy/numpy/pull/16806>`__: DOC: adding docs on passing dimensions as tuple to ndindex
+* `#16807 <https://github.com/numpy/numpy/pull/16807>`__: BUG, MAINT: Remove overzealous automatic RST link
+* `#16811 <https://github.com/numpy/numpy/pull/16811>`__: DOC: Add explanation of 'K' and 'A' layout options to 'asarray*'...
+* `#16814 <https://github.com/numpy/numpy/pull/16814>`__: DOC: Add a reST label to /user/building.rst
+* `#16815 <https://github.com/numpy/numpy/pull/16815>`__: BUG: fix mgrid output for lower precision float inputs
+* `#16816 <https://github.com/numpy/numpy/pull/16816>`__: BLD: temporarily disable OpenBLAS hash checks
+* `#16817 <https://github.com/numpy/numpy/pull/16817>`__: BUG: Do not inherit flags from the structured part of a union...
+* `#16819 <https://github.com/numpy/numpy/pull/16819>`__: DOC: replace dec.slow with pytest.mark.slow
+* `#16820 <https://github.com/numpy/numpy/pull/16820>`__: MAINT: Make void scalar to array creation copy when dtype is...
+* `#16821 <https://github.com/numpy/numpy/pull/16821>`__: DOC: fix inconsistent parameter name in np.ndindex docstring
+* `#16822 <https://github.com/numpy/numpy/pull/16822>`__: MAINT: setuptools 49.2.0 emits a warning, avoid it
+* `#16824 <https://github.com/numpy/numpy/pull/16824>`__: DOC: add examples to random number generator pages
+* `#16826 <https://github.com/numpy/numpy/pull/16826>`__: DOC: describe ufunc copy behavior when input and output overlap
+* `#16827 <https://github.com/numpy/numpy/pull/16827>`__: MAINT: Fix ``runtest.py`` warning.
+* `#16829 <https://github.com/numpy/numpy/pull/16829>`__: DOC,BLD: Add pandas to doc_requirements.txt
+* `#16831 <https://github.com/numpy/numpy/pull/16831>`__: MAINT: fix sphinx deprecation
+* `#16834 <https://github.com/numpy/numpy/pull/16834>`__: Avoid using uninitialized bytes in getlimits.py.
+* `#16835 <https://github.com/numpy/numpy/pull/16835>`__: DOC: Explaining why datetime64 doesn't work for allclose + isclose
+* `#16836 <https://github.com/numpy/numpy/pull/16836>`__: DOC: improve SIMD features tables
+* `#16837 <https://github.com/numpy/numpy/pull/16837>`__: BLD: update openblas hashes, re-enable check
+* `#16838 <https://github.com/numpy/numpy/pull/16838>`__: MAINT: Remove code that will never run
+* `#16840 <https://github.com/numpy/numpy/pull/16840>`__: MAINT: Bump hypothesis from 5.19.0 to 5.19.1
+* `#16841 <https://github.com/numpy/numpy/pull/16841>`__: BUG: linspace should round towards -infinity
+* `#16845 <https://github.com/numpy/numpy/pull/16845>`__: TST: Disable shippable until we can fix it.
+* `#16847 <https://github.com/numpy/numpy/pull/16847>`__: MAINT: Remove Duplicated Code (function extract rmap)
+* `#16848 <https://github.com/numpy/numpy/pull/16848>`__: MAINT: Remove Duplicated Code
+* `#16849 <https://github.com/numpy/numpy/pull/16849>`__: MAINT: Change for loop (range -> for each)
+* `#16850 <https://github.com/numpy/numpy/pull/16850>`__: DEP: Deprecate NumPy object scalars
+* `#16854 <https://github.com/numpy/numpy/pull/16854>`__: DOC: clarify whats required for new features see #13924
+* `#16857 <https://github.com/numpy/numpy/pull/16857>`__: MAINT: fix new compiler warnings on clang
+* `#16858 <https://github.com/numpy/numpy/pull/16858>`__: BUG: fix the search dir of dispatch-able sources
+* `#16860 <https://github.com/numpy/numpy/pull/16860>`__: MAINT: Remove deprecated python function 'file()'
+* `#16868 <https://github.com/numpy/numpy/pull/16868>`__: BUG: Validate output size in bin- and multinomial
+* `#16870 <https://github.com/numpy/numpy/pull/16870>`__: BLD, MAINT: Pin setuptools
+* `#16871 <https://github.com/numpy/numpy/pull/16871>`__: BUG: Update compiler check for AVX-512F
+* `#16874 <https://github.com/numpy/numpy/pull/16874>`__: TST, MAINT: fix the test for ``np.ones``
+* `#16878 <https://github.com/numpy/numpy/pull/16878>`__: DOC: edit to the documentation of lib/polynomial.py/polyfit
+* `#16879 <https://github.com/numpy/numpy/pull/16879>`__: MAINT: Configure hypothesis in ``np.test()`` for determinism,...
+* `#16882 <https://github.com/numpy/numpy/pull/16882>`__: BLD: Remove unused pip install
+* `#16883 <https://github.com/numpy/numpy/pull/16883>`__: BUG,DOC: Fix bad MPL kwarg in docs
+* `#16886 <https://github.com/numpy/numpy/pull/16886>`__: DOC: Fix types including curly braces
+* `#16887 <https://github.com/numpy/numpy/pull/16887>`__: DOC: Remove the links for ``True`` and ``False``
+* `#16888 <https://github.com/numpy/numpy/pull/16888>`__: ENH: Integrate the new CPU dispatcher with umath generator
+* `#16894 <https://github.com/numpy/numpy/pull/16894>`__: DOC: Fix wrong markups in `arrays.dtypes`
+* `#16896 <https://github.com/numpy/numpy/pull/16896>`__: DOC: Remove links for C codes
+* `#16897 <https://github.com/numpy/numpy/pull/16897>`__: DOC: Fix the declarations of C fuctions
+* `#16899 <https://github.com/numpy/numpy/pull/16899>`__: MNT: also use Py_SET_REFCNT instead of Py_REFCNT
+* `#16900 <https://github.com/numpy/numpy/pull/16900>`__: MAINT: Chaining exceptions in numpy/__init__.py
+* `#16907 <https://github.com/numpy/numpy/pull/16907>`__: DOC: update val to be scalar or array like optional closes #16901
+* `#16910 <https://github.com/numpy/numpy/pull/16910>`__: MAINT: Bump hypothesis from 5.19.1 to 5.20.2
+* `#16911 <https://github.com/numpy/numpy/pull/16911>`__: ENH: Speed up trim_zeros
+* `#16914 <https://github.com/numpy/numpy/pull/16914>`__: BUG: Fix string/bytes to complex assignment
+* `#16917 <https://github.com/numpy/numpy/pull/16917>`__: DOC: Add correctness vs strictness consideration for np.dtype
+* `#16919 <https://github.com/numpy/numpy/pull/16919>`__: DOC: Add ufunc docstring to generated docs.
+* `#16925 <https://github.com/numpy/numpy/pull/16925>`__: REL: Update master after 1.19.1 release.
+* `#16931 <https://github.com/numpy/numpy/pull/16931>`__: Revert "Merge pull request #16248 from alexrockhill/edge"
+* `#16936 <https://github.com/numpy/numpy/pull/16936>`__: BUG: Fix memory leak of buffer-info cache due to relaxed strides
+* `#16938 <https://github.com/numpy/numpy/pull/16938>`__: ENH,API: Store exported buffer info on the array
+* `#16940 <https://github.com/numpy/numpy/pull/16940>`__: BLD: update OpenBLAS build
+* `#16941 <https://github.com/numpy/numpy/pull/16941>`__: BUG: Allow array-like types to be coerced as object array elements
+* `#16943 <https://github.com/numpy/numpy/pull/16943>`__: DEP: Deprecate size-one ragged array coercion
+* `#16944 <https://github.com/numpy/numpy/pull/16944>`__: Change the name of the folder "icons" to "logo".
+* `#16949 <https://github.com/numpy/numpy/pull/16949>`__: ENH: enable colors for `runtests.py --ipython`
+* `#16950 <https://github.com/numpy/numpy/pull/16950>`__: DOC: Clarify input to irfft/irfft2/irfftn
+* `#16952 <https://github.com/numpy/numpy/pull/16952>`__: MAINT: Bump hypothesis from 5.20.2 to 5.23.2
+* `#16953 <https://github.com/numpy/numpy/pull/16953>`__: update numpy/lib/arraypad.py with appropriate chain exception
+* `#16957 <https://github.com/numpy/numpy/pull/16957>`__: MAINT: Use arm64 instead of aarch64 on travisCI.
+* `#16962 <https://github.com/numpy/numpy/pull/16962>`__: MAINT: Chain exception in ``distutils/fcompiler/environment.py``.
+* `#16966 <https://github.com/numpy/numpy/pull/16966>`__: MAINT: Added the `order` parameter to `np.array()`
+* `#16969 <https://github.com/numpy/numpy/pull/16969>`__: ENH: Add Neon SIMD implementations for add, sub, mul, and div
+* `#16973 <https://github.com/numpy/numpy/pull/16973>`__: DOC: Fixed typo in lib/recfunctions.py
+* `#16974 <https://github.com/numpy/numpy/pull/16974>`__: TST: Add pypy win32 CI testing.
+* `#16982 <https://github.com/numpy/numpy/pull/16982>`__: ENH: Increase the use of `Literal` types
+* `#16986 <https://github.com/numpy/numpy/pull/16986>`__: ENH: Add NumPy declarations to be used by Cython 3.0+
+* `#16988 <https://github.com/numpy/numpy/pull/16988>`__: DOC: Add the new NumPy logo to Sphinx pages
+* `#16991 <https://github.com/numpy/numpy/pull/16991>`__: MAINT: Bump hypothesis from 5.23.2 to 5.23.9
+* `#16992 <https://github.com/numpy/numpy/pull/16992>`__: MAINT: Bump pytest from 5.4.3 to 6.0.1
+* `#16993 <https://github.com/numpy/numpy/pull/16993>`__: BLD: pin setuptools < 49.2.0
+* `#16996 <https://github.com/numpy/numpy/pull/16996>`__: DOC: Revise glossary page
+* `#17002 <https://github.com/numpy/numpy/pull/17002>`__: DOC: clip() allows arguments.
+* `#17009 <https://github.com/numpy/numpy/pull/17009>`__: NEP: Updated NEP-35 with keyword-only instruction
+* `#17013 <https://github.com/numpy/numpy/pull/17013>`__: MAINT: Simplify scalar power
+* `#17014 <https://github.com/numpy/numpy/pull/17014>`__: MAINT: Improve error handling in umathmodule setup
+* `#17028 <https://github.com/numpy/numpy/pull/17028>`__: DOC: Disclaimer for FFT library
+* `#17029 <https://github.com/numpy/numpy/pull/17029>`__: MAINT: Add error return to all casting functionality and NpyIter
+* `#17033 <https://github.com/numpy/numpy/pull/17033>`__: BUG: fix a compile and a test warning
+* `#17036 <https://github.com/numpy/numpy/pull/17036>`__: DOC: Clarify that `np.char` comparison functions always return...
+* `#17039 <https://github.com/numpy/numpy/pull/17039>`__: DOC: Use a less ambiguous example for array_split
+* `#17041 <https://github.com/numpy/numpy/pull/17041>`__: MAINT: Bump hypothesis from 5.23.9 to 5.23.12
+* `#17048 <https://github.com/numpy/numpy/pull/17048>`__: STY: core._internal style fixups
+* `#17050 <https://github.com/numpy/numpy/pull/17050>`__: MAINT: Remove _EXTRAFLAGS variable
+* `#17053 <https://github.com/numpy/numpy/pull/17053>`__: BUG: fix typo in polydiv that prevented promotion to poly1d
+* `#17058 <https://github.com/numpy/numpy/pull/17058>`__: MAINT: Revert boolean casting back to elementwise comparisons...
+* `#17062 <https://github.com/numpy/numpy/pull/17062>`__: API, BUG: Raise error on complex input to i0
+* `#17063 <https://github.com/numpy/numpy/pull/17063>`__: MAINT: Remove obsolete conversion to set
+* `#17067 <https://github.com/numpy/numpy/pull/17067>`__: DEP: lib: Remove the deprecated financial functions.
+* `#17068 <https://github.com/numpy/numpy/pull/17068>`__: MAINT, BUG: Remove uses of PyString_FromString.
+* `#17074 <https://github.com/numpy/numpy/pull/17074>`__: DOC: use the pydata_sphinx_theme
+* `#17078 <https://github.com/numpy/numpy/pull/17078>`__: DOC: Fixes duplication of toctree content (Closes #17077)
+* `#17091 <https://github.com/numpy/numpy/pull/17091>`__: MAINT: Bump pytest-cov from 2.10.0 to 2.10.1
+* `#17092 <https://github.com/numpy/numpy/pull/17092>`__: MAINT: Bump hypothesis from 5.23.12 to 5.26.0
+* `#17093 <https://github.com/numpy/numpy/pull/17093>`__: NEP: Adjust NEP-35 to make it more user-accessible
+* `#17104 <https://github.com/numpy/numpy/pull/17104>`__: ENH: Add placeholder stubs for all sub-modules
+* `#17109 <https://github.com/numpy/numpy/pull/17109>`__: MAINT: Split einsum into multiple files
+* `#17112 <https://github.com/numpy/numpy/pull/17112>`__: BUG: Handle errors from the PyCapsule API
+* `#17115 <https://github.com/numpy/numpy/pull/17115>`__: DOC: Fix spacing in vectorize doc
+* `#17116 <https://github.com/numpy/numpy/pull/17116>`__: API: Remove `np.ctypeslib.ctypes_load_library`
+* `#17119 <https://github.com/numpy/numpy/pull/17119>`__: DOC: make spacing consistent in NEP 41 bullet points
+* `#17121 <https://github.com/numpy/numpy/pull/17121>`__: BUG: core: fix ilp64 blas dot/vdot/... for strides > int32 max
+* `#17123 <https://github.com/numpy/numpy/pull/17123>`__: ENH: allow running mypy through runtests.py
+* `#17127 <https://github.com/numpy/numpy/pull/17127>`__: MAINT: Remove duplicated symbols from link step
+* `#17129 <https://github.com/numpy/numpy/pull/17129>`__: BLD: Check for reduce intrinsics and AVX512BW mask operations
+* `#17132 <https://github.com/numpy/numpy/pull/17132>`__: MAINT: Chain some exceptions in arraysetops.
+* `#17133 <https://github.com/numpy/numpy/pull/17133>`__: MAINT: Chain ValueError in ma.timer_comparison
+* `#17137 <https://github.com/numpy/numpy/pull/17137>`__: API,MAINT: Rewrite promotion using common DType and common instance
+* `#17141 <https://github.com/numpy/numpy/pull/17141>`__: MAINT: Make arrayprint str and repr the ndarray defaults.
+* `#17142 <https://github.com/numpy/numpy/pull/17142>`__: DOC: NEP-42: Fix a few typos.
+* `#17143 <https://github.com/numpy/numpy/pull/17143>`__: MAINT: Change handling of the expired financial functions.
+* `#17144 <https://github.com/numpy/numpy/pull/17144>`__: ENH: Add annotations to 3 functions in `np.core.function_base`
+* `#17145 <https://github.com/numpy/numpy/pull/17145>`__: MAINT, BUG: Replace uses of PyString_AsString.
+* `#17146 <https://github.com/numpy/numpy/pull/17146>`__: MAINT: ``Replace PyUString_*`` by ``PyUnicode_*`` equivalents.
+* `#17149 <https://github.com/numpy/numpy/pull/17149>`__: MAINT: Replace PyInt macros with their PyLong replacement
+* `#17150 <https://github.com/numpy/numpy/pull/17150>`__: ENH: Add support for the abstract scalars to cython code
+* `#17151 <https://github.com/numpy/numpy/pull/17151>`__: BUG: Fix incorrect cython definition of npy_cfloat
+* `#17152 <https://github.com/numpy/numpy/pull/17152>`__: MAINT: Clean up some Npy_ vs Py_ macro usage
+* `#17154 <https://github.com/numpy/numpy/pull/17154>`__: DOC: Remove references to PyCObject
+* `#17159 <https://github.com/numpy/numpy/pull/17159>`__: DOC: Update numpy4matlab
+* `#17160 <https://github.com/numpy/numpy/pull/17160>`__: Clean up some more bytes vs unicode handling
+* `#17161 <https://github.com/numpy/numpy/pull/17161>`__: BUG: Remove Void special case for "safe casting"
+* `#17163 <https://github.com/numpy/numpy/pull/17163>`__: MAINT: Remove redundant headers
+* `#17164 <https://github.com/numpy/numpy/pull/17164>`__: MAINT: Remove NPY_COPY_PYOBJECT_PTR
+* `#17167 <https://github.com/numpy/numpy/pull/17167>`__: BLD: Merge the npysort library into multiarray
+* `#17168 <https://github.com/numpy/numpy/pull/17168>`__: TST: Add tests mapping out the rules for metadata in promotion
+* `#17171 <https://github.com/numpy/numpy/pull/17171>`__: BUG: revert trim_zeros changes from gh-16911
+* `#17172 <https://github.com/numpy/numpy/pull/17172>`__: ENH: Make `np.complexfloating` generic w.r.t. `np.floating`
+* `#17176 <https://github.com/numpy/numpy/pull/17176>`__: MAINT/ENH: datetime: remove calls to PyUnicode_AsASCIIString,...
+* `#17180 <https://github.com/numpy/numpy/pull/17180>`__: ENH: Added missing methods to `np.flatiter`
+* `#17181 <https://github.com/numpy/numpy/pull/17181>`__: DOC: Correct error in description of ndarray.base
+* `#17182 <https://github.com/numpy/numpy/pull/17182>`__: DOC: Document `dtype.metadata`
+* `#17186 <https://github.com/numpy/numpy/pull/17186>`__: MAINT: Use utf8 strings in more of datetime
+* `#17188 <https://github.com/numpy/numpy/pull/17188>`__: MAINT: Add placeholder stubs for `ndarray` and `generic`
+* `#17191 <https://github.com/numpy/numpy/pull/17191>`__: MAINT: Bump hypothesis from 5.26.0 to 5.30.0
+* `#17193 <https://github.com/numpy/numpy/pull/17193>`__: MAINT: Remove some callers of functions in numpy.compat
+* `#17195 <https://github.com/numpy/numpy/pull/17195>`__: ENH: Make the window functions exactly symmetric
+* `#17197 <https://github.com/numpy/numpy/pull/17197>`__: MAINT: Improve error handling in npy_cpu_init
+* `#17199 <https://github.com/numpy/numpy/pull/17199>`__: DOC: Fix the documented signatures of four `ufunc` methods
+* `#17201 <https://github.com/numpy/numpy/pull/17201>`__: MAINT: Make the `NPY_CPU_DISPATCH_CALL` macros expressions not...
+* `#17204 <https://github.com/numpy/numpy/pull/17204>`__: DOC: Fixed headings for tutorials so they appear at new theme...
+* `#17210 <https://github.com/numpy/numpy/pull/17210>`__: DOC: Canonical_urls
+* `#17214 <https://github.com/numpy/numpy/pull/17214>`__: MAINT: Fix various issues with the `np.generic` annotations
+* `#17219 <https://github.com/numpy/numpy/pull/17219>`__: BLD: enabled negation of library choices in NPY_*_ORDER
+* `#17220 <https://github.com/numpy/numpy/pull/17220>`__: BUG, DOC: comment out metadata added via javascript
+* `#17222 <https://github.com/numpy/numpy/pull/17222>`__: MAINT, DOC: move informational files from numpy.doc.*.py to their...
+* `#17223 <https://github.com/numpy/numpy/pull/17223>`__: MAINT: use sysconfig not distutils.sysconfig where possible
+* `#17225 <https://github.com/numpy/numpy/pull/17225>`__: BUG: Fix dimension discovery of within array ragged cases
+* `#17227 <https://github.com/numpy/numpy/pull/17227>`__: DOC: Added templates for different types of issues.
+* `#17233 <https://github.com/numpy/numpy/pull/17233>`__: DEP: Deprecated ndindex.ndincr
+* `#17235 <https://github.com/numpy/numpy/pull/17235>`__: MAINT: Remove old PY_VERSION_HEX and sys.version_info code
+* `#17237 <https://github.com/numpy/numpy/pull/17237>`__: BUG: Avoid using ``np.random`` in typing tests.
+* `#17239 <https://github.com/numpy/numpy/pull/17239>`__: DOC: Fix link quick-start in old random API functions
+* `#17241 <https://github.com/numpy/numpy/pull/17241>`__: MAINT: ``__array_interface__`` data address cannot be bytes
+* `#17242 <https://github.com/numpy/numpy/pull/17242>`__: MAINT: Run slow CI jobs earlier so builds finishes sooner
+* `#17247 <https://github.com/numpy/numpy/pull/17247>`__: ENH: Add tool to help speed up Travis CI
+* `#17250 <https://github.com/numpy/numpy/pull/17250>`__: DOC: Fix docstring cross-referencing
+* `#17252 <https://github.com/numpy/numpy/pull/17252>`__: DOC: Added a PR "Reviewer guidelines" document.
+* `#17257 <https://github.com/numpy/numpy/pull/17257>`__: DOC: work around a bug in the new theme
+* `#17258 <https://github.com/numpy/numpy/pull/17258>`__: SIMD: add fused multiply subtract/add intrinics for all supported...
+* `#17259 <https://github.com/numpy/numpy/pull/17259>`__: MAINT: Bump hypothesis from 5.30.0 to 5.33.0
+* `#17260 <https://github.com/numpy/numpy/pull/17260>`__: MAINT: Bump pydata-sphinx-theme from 0.3.2 to 0.4.0
+* `#17263 <https://github.com/numpy/numpy/pull/17263>`__: DOC: add new glossary terms
+* `#17264 <https://github.com/numpy/numpy/pull/17264>`__: DOC: remove some glosssary terms
+* `#17267 <https://github.com/numpy/numpy/pull/17267>`__: TST: Fix the path to `mypy.ini` in `runtests.py`
+* `#17268 <https://github.com/numpy/numpy/pull/17268>`__: BUG: sysconfig attributes/distutils issue
+* `#17273 <https://github.com/numpy/numpy/pull/17273>`__: ENH: Annotate the arithmetic operations of `ndarray` and `generic`
+* `#17278 <https://github.com/numpy/numpy/pull/17278>`__: MAINT: Merge together index page content into a single file
+* `#17279 <https://github.com/numpy/numpy/pull/17279>`__: DOC: Fix a typo in shape_base.
+* `#17284 <https://github.com/numpy/numpy/pull/17284>`__: ENH: Pass optimizations arguments to asv build
+* `#17285 <https://github.com/numpy/numpy/pull/17285>`__: DEP: Change the financial name access warning to DeprecationWarning
+* `#17288 <https://github.com/numpy/numpy/pull/17288>`__: REL: Update master after 1.19.2 release.
+* `#17289 <https://github.com/numpy/numpy/pull/17289>`__: MAINT: Simplify ufunc pickling
+* `#17290 <https://github.com/numpy/numpy/pull/17290>`__: MAINT: Cleanup some pystring macros
+* `#17292 <https://github.com/numpy/numpy/pull/17292>`__: MAINT: Replace remaining PyString macros.
+* `#17293 <https://github.com/numpy/numpy/pull/17293>`__: MAINT: Replace PyUString_Check by PyUnicode_Check.
+* `#17295 <https://github.com/numpy/numpy/pull/17295>`__: BUG,ENH: fix pickling user-scalars by allowing non-format buffer...
+* `#17296 <https://github.com/numpy/numpy/pull/17296>`__: MAINT: Replace some ``pyint_*`` macros defined in ``npy_3kcompat``.
+* `#17297 <https://github.com/numpy/numpy/pull/17297>`__: BLD: set upper versions for build dependencies
+* `#17299 <https://github.com/numpy/numpy/pull/17299>`__: MAINT: (dtype-transfer) make copyswapn and legacy cast wrapper...
+* `#17300 <https://github.com/numpy/numpy/pull/17300>`__: MAINT: Replace PyBaseString_Check by PyUnicode_Check
+* `#17302 <https://github.com/numpy/numpy/pull/17302>`__: MAINT: Replace a couple of missed npy_3kcompat macros
+* `#17304 <https://github.com/numpy/numpy/pull/17304>`__: BUILD: pin pygments to 2.6.1, 2.7.0 breaks custom NumPyC lexer
+* `#17307 <https://github.com/numpy/numpy/pull/17307>`__: MAINT: Bump hypothesis from 5.33.0 to 5.35.1
+* `#17308 <https://github.com/numpy/numpy/pull/17308>`__: MAINT: Bump pytest from 6.0.1 to 6.0.2
+* `#17309 <https://github.com/numpy/numpy/pull/17309>`__: MAINT: Move the `fromnumeric` annotations to their own stub file
+* `#17312 <https://github.com/numpy/numpy/pull/17312>`__: MAINT: Syntax-highlight .src files on github
+* `#17313 <https://github.com/numpy/numpy/pull/17313>`__: MAINT: Mark vendored/generated files in .gitattributes
+* `#17315 <https://github.com/numpy/numpy/pull/17315>`__: MAINT: Cleanup f2py/cfuncs.py
+* `#17319 <https://github.com/numpy/numpy/pull/17319>`__: BUG: Set deprecated fields to null in PyArray_InitArrFuncs
+* `#17320 <https://github.com/numpy/numpy/pull/17320>`__: BUG: allow registration of hard-coded structured dtypes
+* `#17326 <https://github.com/numpy/numpy/pull/17326>`__: ENH: Add annotations for five array construction functions
+* `#17329 <https://github.com/numpy/numpy/pull/17329>`__: DOC: Fix incorrect `.. deprecated::` syntax that led to this...
+* `#17330 <https://github.com/numpy/numpy/pull/17330>`__: DOC: improve `issubdtype` and scalar type docs
+* `#17331 <https://github.com/numpy/numpy/pull/17331>`__: DOC: Remove the tables of scalar types, and use `..autoclass`...
+* `#17332 <https://github.com/numpy/numpy/pull/17332>`__: DOC, BLD: update lexer highlighting and make numpydocs a regular...
+* `#17334 <https://github.com/numpy/numpy/pull/17334>`__: MAINT: Chaining exceptions in npyio.py
+* `#17337 <https://github.com/numpy/numpy/pull/17337>`__: NEP: Regenerate table in NEP 29 (add numpy 1.18 and 1.19 to list)
+* `#17338 <https://github.com/numpy/numpy/pull/17338>`__: DOC: Fix syntax errors in docstrings for versionchanged, versionadded
+* `#17340 <https://github.com/numpy/numpy/pull/17340>`__: SIMD: Add partial/non-contig load and store intrinsics for 32/64-bit
+* `#17344 <https://github.com/numpy/numpy/pull/17344>`__: ENH, BLD: Support for the NVIDIA HPC SDK nvfortran compiler
+* `#17346 <https://github.com/numpy/numpy/pull/17346>`__: BLD,BUG: Fix a macOS build failure when `NPY_BLAS_ORDER=""`
+* `#17350 <https://github.com/numpy/numpy/pull/17350>`__: DEV: Add PR prefix labeler and numpy prefix mapping
+* `#17352 <https://github.com/numpy/numpy/pull/17352>`__: DOC: Guide to writing how-tos
+* `#17353 <https://github.com/numpy/numpy/pull/17353>`__: DOC: How-to guide for I/O
+* `#17354 <https://github.com/numpy/numpy/pull/17354>`__: DOC: clarify residuals return param
+* `#17356 <https://github.com/numpy/numpy/pull/17356>`__: ENH: Add Npy__PyLong_AsInt function.
+* `#17357 <https://github.com/numpy/numpy/pull/17357>`__: MAINT: Bump hypothesis from 5.35.1 to 5.35.3
+* `#17364 <https://github.com/numpy/numpy/pull/17364>`__: MAINT: Finish replacing PyInt_Check
+* `#17369 <https://github.com/numpy/numpy/pull/17369>`__: DOC: distutils: Remove an obsolete paragraph.
+* `#17370 <https://github.com/numpy/numpy/pull/17370>`__: NEP: Edit nep-0042 for more clarity
+* `#17372 <https://github.com/numpy/numpy/pull/17372>`__: ENH: Add annotations for remaining `ndarray` / `generic` non-magic...
+* `#17373 <https://github.com/numpy/numpy/pull/17373>`__: BUG: Fixes module data docstrings.
+* `#17375 <https://github.com/numpy/numpy/pull/17375>`__: DOC: Fix default_rng docstring
+* `#17377 <https://github.com/numpy/numpy/pull/17377>`__: BUG: ensure _UFuncNoLoopError can be pickled
+* `#17380 <https://github.com/numpy/numpy/pull/17380>`__: Minor grammatical correction in quickstart doc.
+* `#17382 <https://github.com/numpy/numpy/pull/17382>`__: DOC: NumPy restyling for pydata theme
+* `#17383 <https://github.com/numpy/numpy/pull/17383>`__: MAINT: Fix docstring for np.matmul
+* `#17386 <https://github.com/numpy/numpy/pull/17386>`__: MAINT: Bump hypothesis from 5.35.3 to 5.36.1
+* `#17388 <https://github.com/numpy/numpy/pull/17388>`__: MAINT: Remove old debug print statement.
+* `#17391 <https://github.com/numpy/numpy/pull/17391>`__: DOC: Replace "About NumPy" with "Document conventions"
+* `#17392 <https://github.com/numpy/numpy/pull/17392>`__: DOC: Update info on doc style rules
+* `#17393 <https://github.com/numpy/numpy/pull/17393>`__: BUG: Fix default void, datetime, and timedelta in array coercion
+* `#17396 <https://github.com/numpy/numpy/pull/17396>`__: MAINT: Replace append_metastr_to_string function.
+* `#17399 <https://github.com/numpy/numpy/pull/17399>`__: BLD: Fixed ARGOUTVIEWM memory deallocation. Closes #17398.
+* `#17400 <https://github.com/numpy/numpy/pull/17400>`__: DOC: rm incorrect alias from recarray user article.
+* `#17401 <https://github.com/numpy/numpy/pull/17401>`__: MAINT: Rewrite can-cast logic in terms of NEP 42
+* `#17402 <https://github.com/numpy/numpy/pull/17402>`__: DOC: Add arraysetops to an autosummary
+* `#17404 <https://github.com/numpy/numpy/pull/17404>`__: MAINT: Replace PyUString_ConcatAndDel in nditer_constr.c.
+* `#17405 <https://github.com/numpy/numpy/pull/17405>`__: MAINT: Replace PyUString_ConcatAndDel in mapping.c.
+* `#17406 <https://github.com/numpy/numpy/pull/17406>`__: ENH: Replace the module-level `__getattr__` with explicit type...
+* `#17407 <https://github.com/numpy/numpy/pull/17407>`__: DOC: in PR template, set expectations for PR review timeline
+* `#17409 <https://github.com/numpy/numpy/pull/17409>`__: MAINT: Cleanup remaining PyUString_ConcatAndDel use.
+* `#17410 <https://github.com/numpy/numpy/pull/17410>`__: API: Special case how numpy scalars are coerced to signed integer
+* `#17411 <https://github.com/numpy/numpy/pull/17411>`__: TST: Mark the typing tests as slow
+* `#17412 <https://github.com/numpy/numpy/pull/17412>`__: DOC: Fix a parameter type in the `putmask` docs
+* `#17418 <https://github.com/numpy/numpy/pull/17418>`__: DOC: adding operational form documentation for array ops
+* `#17419 <https://github.com/numpy/numpy/pull/17419>`__: DEP: Deprecate coercion to subarray dtypes
+* `#17421 <https://github.com/numpy/numpy/pull/17421>`__: BUG: Fix memory leak in array-coercion error paths
+* `#17422 <https://github.com/numpy/numpy/pull/17422>`__: MAINT: chains nested try-except in numpy/ma/core.py
+* `#17423 <https://github.com/numpy/numpy/pull/17423>`__: DOC: Remove bogus reference to _a_
+* `#17424 <https://github.com/numpy/numpy/pull/17424>`__: DOC: Fix formatting issues in description of .c.src files
+* `#17427 <https://github.com/numpy/numpy/pull/17427>`__: NEP: nep-0029 typo correction
+* `#17429 <https://github.com/numpy/numpy/pull/17429>`__: MAINT: Move aliases for common scalar unions to `numpy.typing`
+* `#17430 <https://github.com/numpy/numpy/pull/17430>`__: BUG: Fix memoryleaks related to NEP 37 function overrides
+* `#17431 <https://github.com/numpy/numpy/pull/17431>`__: DOC: Fix the links for ``Ellipsis``
+* `#17432 <https://github.com/numpy/numpy/pull/17432>`__: DOC: add references to einops and opt_einsum
+* `#17433 <https://github.com/numpy/numpy/pull/17433>`__: MAINT : Disable 32 bit PyPy CI testing on Windows.
+* `#17435 <https://github.com/numpy/numpy/pull/17435>`__: DOC: Security warning for issues template
+* `#17436 <https://github.com/numpy/numpy/pull/17436>`__: DOC: Fix "Feature request" spelling in issue templates
+* `#17438 <https://github.com/numpy/numpy/pull/17438>`__: MAINT: Chaining exception in numpy\numpy\ma\mrecords.py
+* `#17440 <https://github.com/numpy/numpy/pull/17440>`__: DOC: Cleaner template for PRs
+* `#17442 <https://github.com/numpy/numpy/pull/17442>`__: MAINT: fix exception chaining in format.py
+* `#17443 <https://github.com/numpy/numpy/pull/17443>`__: ENH: Warn on unsupported Python 3.10+
+* `#17444 <https://github.com/numpy/numpy/pull/17444>`__: ENH: Add `Typing :: Typed` to the PyPi classifier
+* `#17445 <https://github.com/numpy/numpy/pull/17445>`__: DOC: Fix the references for macros
+* `#17447 <https://github.com/numpy/numpy/pull/17447>`__: NEP: update NEP 42 with discussion of type hinting applications
+* `#17448 <https://github.com/numpy/numpy/pull/17448>`__: DOC: Remove CoC pages from Sphinx
+* `#17453 <https://github.com/numpy/numpy/pull/17453>`__: MAINT: Chain exceptions in "_polybase.py"
+* `#17455 <https://github.com/numpy/numpy/pull/17455>`__: MAINT: Bump hypothesis from 5.36.1 to 5.37.0
+* `#17456 <https://github.com/numpy/numpy/pull/17456>`__: ENH: add dtype option to numpy.lib.function_base.cov and corrcoef
+* `#17457 <https://github.com/numpy/numpy/pull/17457>`__: BUG: Fixes incorrect error message in numpy.ediff1d
+* `#17459 <https://github.com/numpy/numpy/pull/17459>`__: DOC: update code of conduct URL
+* `#17464 <https://github.com/numpy/numpy/pull/17464>`__: DOC: Add some entries for C types and macros
+* `#17465 <https://github.com/numpy/numpy/pull/17465>`__: ENH: Add annotations for bitwise operations
+* `#17468 <https://github.com/numpy/numpy/pull/17468>`__: DOC: add some missing scalar aliases
+* `#17472 <https://github.com/numpy/numpy/pull/17472>`__: TST: Fix doctest for full_like
+* `#17473 <https://github.com/numpy/numpy/pull/17473>`__: MAINT: py3k: remove os.fspath and os.PathLike backports
+* `#17474 <https://github.com/numpy/numpy/pull/17474>`__: MAINT: Move the `np.core.numeric` annotations to their own stub...
+* `#17479 <https://github.com/numpy/numpy/pull/17479>`__: ENH: type np.unicode_ as np.str_
+* `#17481 <https://github.com/numpy/numpy/pull/17481>`__: DOC: Fix the entries for members of structures
+* `#17483 <https://github.com/numpy/numpy/pull/17483>`__: DOC: Fix the references for `random.*`
+* `#17485 <https://github.com/numpy/numpy/pull/17485>`__: BLD: circleCI- merge before build, add -n to sphinx
+* `#17487 <https://github.com/numpy/numpy/pull/17487>`__: MAINT: Remove duplicate placeholder annotations
+* `#17497 <https://github.com/numpy/numpy/pull/17497>`__: DOC: Use consistent lowercase on docs landing page
+* `#17498 <https://github.com/numpy/numpy/pull/17498>`__: MAINT: fix incompatible type comparison in numpy.lib.utils.info
+* `#17501 <https://github.com/numpy/numpy/pull/17501>`__: BUG: Fix failures in master related to userdtype registeration
+* `#17502 <https://github.com/numpy/numpy/pull/17502>`__: BUG: remove `sys` from the type stubs
+* `#17503 <https://github.com/numpy/numpy/pull/17503>`__: DOC: Fix empty 'C style guide' page
+* `#17504 <https://github.com/numpy/numpy/pull/17504>`__: DOC: Rename 'Quickstart tutorial'
+* `#17508 <https://github.com/numpy/numpy/pull/17508>`__: ENH: Added the Final feature for all constants
+* `#17510 <https://github.com/numpy/numpy/pull/17510>`__: DOC: Fewer blank lines in PR template
+* `#17520 <https://github.com/numpy/numpy/pull/17520>`__: DOC: Display real license on license page
+* `#17521 <https://github.com/numpy/numpy/pull/17521>`__: DOC: Add docstrings for some scalar types
+* `#17523 <https://github.com/numpy/numpy/pull/17523>`__: DOC: Update top links in landing page
+* `#17525 <https://github.com/numpy/numpy/pull/17525>`__: CI: Make merge ref grabbing conditional on the PR being active
+* `#17527 <https://github.com/numpy/numpy/pull/17527>`__: DOC: Fix Bool types in C functions
+* `#17528 <https://github.com/numpy/numpy/pull/17528>`__: Doc: Fix some links and typos
+* `#17529 <https://github.com/numpy/numpy/pull/17529>`__: MAINT: Cleanup compatibility code for pathlib
+* `#17534 <https://github.com/numpy/numpy/pull/17534>`__: DOC: Fix a typo
+* `#17535 <https://github.com/numpy/numpy/pull/17535>`__: ENH: add function to get broadcast shape from a given set of...
+* `#17536 <https://github.com/numpy/numpy/pull/17536>`__: BUG: Fixed crash on self-referential dtypes
+* `#17537 <https://github.com/numpy/numpy/pull/17537>`__: MAINT: Bump hypothesis from 5.37.0 to 5.37.1
+* `#17538 <https://github.com/numpy/numpy/pull/17538>`__: MAINT: Bump pydata-sphinx-theme from 0.4.0 to 0.4.1
+* `#17539 <https://github.com/numpy/numpy/pull/17539>`__: MAINT: Bump mypy from 0.782 to 0.790
+* `#17540 <https://github.com/numpy/numpy/pull/17540>`__: ENH: Make `np.number` generic with respect to its precision
+* `#17541 <https://github.com/numpy/numpy/pull/17541>`__: CI: fix conditional for PR merge command
+* `#17546 <https://github.com/numpy/numpy/pull/17546>`__: MAINT: explicit disabling `CCompilerOpt` in F2PY
+* `#17548 <https://github.com/numpy/numpy/pull/17548>`__: BUG: Cygwin Workaround for #14787 on affected platforms
+* `#17549 <https://github.com/numpy/numpy/pull/17549>`__: DOC: Fix the entries of C functions
+* `#17555 <https://github.com/numpy/numpy/pull/17555>`__: DOC: Fix wrong blockquotes
+* `#17558 <https://github.com/numpy/numpy/pull/17558>`__: DOC: MAINT: Add NEP 43 links to NEP 42
+* `#17559 <https://github.com/numpy/numpy/pull/17559>`__: DOC: Remove directives for some constants
+* `#17564 <https://github.com/numpy/numpy/pull/17564>`__: MAINT: Update the annotations in `np.core.numeric`
+* `#17570 <https://github.com/numpy/numpy/pull/17570>`__: DOC: Add the entry for ``NPY_FEATURE_VERSION``
+* `#17571 <https://github.com/numpy/numpy/pull/17571>`__: DOC: Fix typos
+* `#17572 <https://github.com/numpy/numpy/pull/17572>`__: ENH: Add annotations for three new constants
+* `#17576 <https://github.com/numpy/numpy/pull/17576>`__: DOC: Fix Boolean array indexing typo
+* `#17577 <https://github.com/numpy/numpy/pull/17577>`__: BUG: Respect dtype of all-zero argument to poly1d
+* `#17578 <https://github.com/numpy/numpy/pull/17578>`__: NEP36: include additional feedback
+* `#17580 <https://github.com/numpy/numpy/pull/17580>`__: MAINT: Cleanup swig for Python 3.
+* `#17581 <https://github.com/numpy/numpy/pull/17581>`__: MAINT: Move the `np.core.numerictypes` annotations to their own...
+* `#17583 <https://github.com/numpy/numpy/pull/17583>`__: MAINT: Bump hypothesis from 5.37.1 to 5.37.3
+* `#17584 <https://github.com/numpy/numpy/pull/17584>`__: ENH: Add annotations for `np.core._type_aliases`
+* `#17594 <https://github.com/numpy/numpy/pull/17594>`__: DOC: Typo in lexsort docstring
+* `#17596 <https://github.com/numpy/numpy/pull/17596>`__: DEP,BUG: Coercion/cast of array to a subarray dtype will be fixed
+* `#17597 <https://github.com/numpy/numpy/pull/17597>`__: TST: Clean up the errors of the typing tests
+* `#17598 <https://github.com/numpy/numpy/pull/17598>`__: BUG: Fixed file handle leak in array_tofile.
+* `#17601 <https://github.com/numpy/numpy/pull/17601>`__: TST: Fix a broken `np.core.numeric` test
+* `#17603 <https://github.com/numpy/numpy/pull/17603>`__: MAINT: Mark dead code as intentional for clang.
+* `#17607 <https://github.com/numpy/numpy/pull/17607>`__: DOC: removed old references to submodule licenses
+* `#17608 <https://github.com/numpy/numpy/pull/17608>`__: DOC: Fix typos (general documentation)
+* `#17610 <https://github.com/numpy/numpy/pull/17610>`__: Fully qualify license trove classifier
+* `#17611 <https://github.com/numpy/numpy/pull/17611>`__: BUG: mac dylib treated as part of extra objects by f2py
+* `#17613 <https://github.com/numpy/numpy/pull/17613>`__: ENH: Add annotations for 9 `ndarray`/`generic` magic methods
+* `#17614 <https://github.com/numpy/numpy/pull/17614>`__: DOC: Fix the document for arrays interface
+* `#17618 <https://github.com/numpy/numpy/pull/17618>`__: MAINT: Conversion of some strings to f-strings
+* `#17619 <https://github.com/numpy/numpy/pull/17619>`__: DOC: Fix some references
+* `#17621 <https://github.com/numpy/numpy/pull/17621>`__: TST: Valid docstring for config_py function show()
+* `#17622 <https://github.com/numpy/numpy/pull/17622>`__: MAINT: Conversion of some strings to fstrings, part II
+* `#17623 <https://github.com/numpy/numpy/pull/17623>`__: MAINT: Conversion of some strings to fstrings, part III
+* `#17624 <https://github.com/numpy/numpy/pull/17624>`__: DOC: Tidy up references to str_ / bytes_
+* `#17625 <https://github.com/numpy/numpy/pull/17625>`__: MAINT: Conversion of some strings to fstrings, part iv
+* `#17627 <https://github.com/numpy/numpy/pull/17627>`__: DOC: Fix the references for ``__array_*__``
+* `#17628 <https://github.com/numpy/numpy/pull/17628>`__: DOC: Add entries for macros
+* `#17629 <https://github.com/numpy/numpy/pull/17629>`__: DOC: Add ``identity_value`` to ``PyUFuncObject``
+* `#17630 <https://github.com/numpy/numpy/pull/17630>`__: DOC: Replace ``PyCObject`` with ``PyCapsule``
+* `#17633 <https://github.com/numpy/numpy/pull/17633>`__: DOC: Don't use Python highlighting for non-python code
+* `#17638 <https://github.com/numpy/numpy/pull/17638>`__: DOC: Fix some references
+* `#17639 <https://github.com/numpy/numpy/pull/17639>`__: MAINT: Bump hypothesis from 5.37.3 to 5.38.0
+* `#17641 <https://github.com/numpy/numpy/pull/17641>`__: MAINT, BLD: update to OpenBLAS v0.3.12
+* `#17642 <https://github.com/numpy/numpy/pull/17642>`__: DOC: Fix reference to atleast_1d
+* `#17643 <https://github.com/numpy/numpy/pull/17643>`__: ENH: Add annotations for `np.core._ufunc_config`
+* `#17644 <https://github.com/numpy/numpy/pull/17644>`__: ENH: Add annotations for `np.core.shape_base`
+* `#17645 <https://github.com/numpy/numpy/pull/17645>`__: BUG: fix np.timedelta64('nat').__format__ throwing an exception
+* `#17654 <https://github.com/numpy/numpy/pull/17654>`__: BUG: f2py incorrectly translates dimension declarations.
+* `#17655 <https://github.com/numpy/numpy/pull/17655>`__: BLD: Fix installing Numpy on z/OS
+* `#17657 <https://github.com/numpy/numpy/pull/17657>`__: NEP: Ensure inner loop signature is complete everywhere
+* `#17658 <https://github.com/numpy/numpy/pull/17658>`__: TST: simplify source path names in compilation test
+* `#17662 <https://github.com/numpy/numpy/pull/17662>`__: TST: f2py: Add a doctest for ``getlincoef``
+* `#17666 <https://github.com/numpy/numpy/pull/17666>`__: REL: Update master after 1.19.3 release.
+* `#17668 <https://github.com/numpy/numpy/pull/17668>`__: TST: Make test suite work in FIPS (140-2) Mode
+* `#17670 <https://github.com/numpy/numpy/pull/17670>`__: DOC: f2py: Add a docstring for getarrlen
+* `#17672 <https://github.com/numpy/numpy/pull/17672>`__: DOC: Update README badge for travis-ci.com
+* `#17673 <https://github.com/numpy/numpy/pull/17673>`__: MAINT: Refine a number of ``np.generic`` annotations
+* `#17675 <https://github.com/numpy/numpy/pull/17675>`__: MAINT: Update release documentation and software
+* `#17681 <https://github.com/numpy/numpy/pull/17681>`__: SIMD: Add sum intrinsics for float/double.
+* `#17682 <https://github.com/numpy/numpy/pull/17682>`__: BUG: (nditer_impl.h) Use ``intp`` instead of ``char *`` for offset...
+* `#17689 <https://github.com/numpy/numpy/pull/17689>`__: BUG: Fix small bug in ``make_lite.py``.
+* `#17691 <https://github.com/numpy/numpy/pull/17691>`__: DOC: Modify Templates
+* `#17692 <https://github.com/numpy/numpy/pull/17692>`__: MAINT: Bump hypothesis from 5.38.0 to 5.41.0
+* `#17693 <https://github.com/numpy/numpy/pull/17693>`__: MAINT: Bump pytz from 2020.1 to 2020.4
+* `#17695 <https://github.com/numpy/numpy/pull/17695>`__: TST: use a more standard workflow for PyPy
+* `#17696 <https://github.com/numpy/numpy/pull/17696>`__: REL: Update master after 1.19.4 release.
+* `#17699 <https://github.com/numpy/numpy/pull/17699>`__: MAINT: Rename ``DtypeLike`` to ``DTypeLike``
+* `#17700 <https://github.com/numpy/numpy/pull/17700>`__: Fix small typos.
+* `#17701 <https://github.com/numpy/numpy/pull/17701>`__: BUG: Fixed an issue where ``.pyi`` files were ignored by numpy...
+* `#17703 <https://github.com/numpy/numpy/pull/17703>`__: Fix Doc Typos & Added Example
+* `#17708 <https://github.com/numpy/numpy/pull/17708>`__: Improve the einsum bench by adding new bench cases and variable...
+* `#17715 <https://github.com/numpy/numpy/pull/17715>`__: REV: Revert gh-17654 - f2py incorrectly translates dimension...
+* `#17717 <https://github.com/numpy/numpy/pull/17717>`__: MAINT: Add more files to ``.gitgnore``
+* `#17720 <https://github.com/numpy/numpy/pull/17720>`__: API: Do not import sliding_window_view to main namespace
+* `#17723 <https://github.com/numpy/numpy/pull/17723>`__: MAINT: Do not override ``sliding_window_view`` module to ``numpy``
+* `#17725 <https://github.com/numpy/numpy/pull/17725>`__: NEP: Add NEP-35 instructions on reading like= downstream
+* `#17729 <https://github.com/numpy/numpy/pull/17729>`__: BLD: Use importlib to find numpy root directory in distutils
+* `#17733 <https://github.com/numpy/numpy/pull/17733>`__: MAINT: ma: Remove unused ``**options`` from MaskedArray ``__new__``...
+* `#17735 <https://github.com/numpy/numpy/pull/17735>`__: TST: Remove Python 3.6 CI testing.
+* `#17738 <https://github.com/numpy/numpy/pull/17738>`__: BLD, TST: move linux jobs to github actions
+* `#17740 <https://github.com/numpy/numpy/pull/17740>`__: MAINT: Bump hypothesis from 5.41.0 to 5.41.2
+* `#17743 <https://github.com/numpy/numpy/pull/17743>`__: BLD, BUG: Fix cblas detection on windows
+* `#17745 <https://github.com/numpy/numpy/pull/17745>`__: TST: add pypy3.7
+* `#17748 <https://github.com/numpy/numpy/pull/17748>`__: BLD: compare platform.architecture() correctly
+* `#17749 <https://github.com/numpy/numpy/pull/17749>`__: DOC: Add "performance" category to the release notes
+* `#17751 <https://github.com/numpy/numpy/pull/17751>`__: BUG: Fix segfault due to out of bound pointer in floatstatus...
+* `#17753 <https://github.com/numpy/numpy/pull/17753>`__: BUG: Fix buffer export dtype references
+* `#17755 <https://github.com/numpy/numpy/pull/17755>`__: BUG: Fix memory leaks found using valgrind
+* `#17758 <https://github.com/numpy/numpy/pull/17758>`__: BLD: Lazy load f2py test utilities
+* `#17759 <https://github.com/numpy/numpy/pull/17759>`__: BLD: use BUFFERSIZE=20 in OpenBLAS
+* `#17763 <https://github.com/numpy/numpy/pull/17763>`__: SIMD, BUG: fix reuses the previous values during the fallback...
+* `#17768 <https://github.com/numpy/numpy/pull/17768>`__: MAINT: update link to website in FUNDING.yml
+* `#17773 <https://github.com/numpy/numpy/pull/17773>`__: MAINT: Add BLD and STY to labeler prefixes.
+* `#17776 <https://github.com/numpy/numpy/pull/17776>`__: MAINT: Simplify Hypothesis configuration
+* `#17787 <https://github.com/numpy/numpy/pull/17787>`__: NEP: Make like= argument added in NEP-35 strict
+* `#17788 <https://github.com/numpy/numpy/pull/17788>`__: DOC: Fix up links, code blocks of release note fragments
+* `#17796 <https://github.com/numpy/numpy/pull/17796>`__: MAINT: Minor touchups in npyio
+* `#17802 <https://github.com/numpy/numpy/pull/17802>`__: MAINT: Update mailmap.
+* `#17805 <https://github.com/numpy/numpy/pull/17805>`__: MAINT: Set the ufunc and ndarray ops return type to ``Any``
+* `#17812 <https://github.com/numpy/numpy/pull/17812>`__: Update linalg.py
+* `#17815 <https://github.com/numpy/numpy/pull/17815>`__: DOC: Fix empty_like docstring
+* `#17823 <https://github.com/numpy/numpy/pull/17823>`__: DOC: Add missing release fragments to ``upcoming_changes``.
+* `#17828 <https://github.com/numpy/numpy/pull/17828>`__: BUG: Fix incorrectly passed size in masked processing
+* `#17829 <https://github.com/numpy/numpy/pull/17829>`__: MAINT: Bump hypothesis from 5.41.2 to 5.41.3
+* `#17830 <https://github.com/numpy/numpy/pull/17830>`__: TST: Add back durations flag for DEBUG builds.
+* `#17832 <https://github.com/numpy/numpy/pull/17832>`__: BUG: Fix subarray dtype used with too large count in fromfile
+* `#17833 <https://github.com/numpy/numpy/pull/17833>`__: BUG: Fix pickling of scalars with NPY_LISTPICKLE
+* `#17838 <https://github.com/numpy/numpy/pull/17838>`__: DOC: Update the `numpy.typing` documentation
+* `#17841 <https://github.com/numpy/numpy/pull/17841>`__: DOC: Fixing boilerplate code example
+* `#17844 <https://github.com/numpy/numpy/pull/17844>`__: MAINT: Add ``__all__`` to `numpy.typing`
+* `#17848 <https://github.com/numpy/numpy/pull/17848>`__: DOC: Add release note for gh-16161.
+* `#17855 <https://github.com/numpy/numpy/pull/17855>`__: BUG: Fix incorrect C function prototypes/declarations.
+* `#17857 <https://github.com/numpy/numpy/pull/17857>`__: MAINT: Prepare for the NumPy 1.20.x branch.
+* `#17869 <https://github.com/numpy/numpy/pull/17869>`__: BUG, TST: use python-version not PYTHON_VERSION
+* `#17879 <https://github.com/numpy/numpy/pull/17879>`__: BUG: Fix buffer readflag errors and small leaks
+* `#17893 <https://github.com/numpy/numpy/pull/17893>`__: DOC: Prepare for 1.20.0 release
+* `#17898 <https://github.com/numpy/numpy/pull/17898>`__: MAINT: Remove remaining uses of Python 3.6.
+* `#17899 <https://github.com/numpy/numpy/pull/17899>`__: TST: use latest pypy37 not pypy36
+* `#17901 <https://github.com/numpy/numpy/pull/17901>`__: MAINT: clean up a spurious warning in numpy/typing/setup.py
+* `#17904 <https://github.com/numpy/numpy/pull/17904>`__: ENH: Speed up default ``where`` in the reduce-like method
+* `#17915 <https://github.com/numpy/numpy/pull/17915>`__: TST: remove stray '+' from f-string upgrade
+* `#17916 <https://github.com/numpy/numpy/pull/17916>`__: ENH: add support for fujitsu compiler to numpy.
+* `#17922 <https://github.com/numpy/numpy/pull/17922>`__: BUG: 'bool' object has no attribute 'ndim'
+* `#17931 <https://github.com/numpy/numpy/pull/17931>`__: DOC: Update release notes to mention ``type(dtype) is not np.dtype``
+* `#17990 <https://github.com/numpy/numpy/pull/17990>`__: BUG: Replace f-string in setup.py
+* `#18015 <https://github.com/numpy/numpy/pull/18015>`__: BUG: Ignore fewer errors during array-coercion
+* `#18016 <https://github.com/numpy/numpy/pull/18016>`__: BUG: Fix a MacOS build failure
+* `#18017 <https://github.com/numpy/numpy/pull/18017>`__: TST: Fix crosstalk issues with polynomial str tests.
+* `#18018 <https://github.com/numpy/numpy/pull/18018>`__: TST: Ensure tests are not sensitive to execution order
+* `#18019 <https://github.com/numpy/numpy/pull/18019>`__: BLD: update to OpenBLAS 0.3.13
+* `#18024 <https://github.com/numpy/numpy/pull/18024>`__: DEP: Futurewarn on requiring __len__ on array-likes
+* `#18035 <https://github.com/numpy/numpy/pull/18035>`__: BUG: make a variable volatile to work around clang compiler bug
+* `#18049 <https://github.com/numpy/numpy/pull/18049>`__: TST: add back sdist test run
+* `#18063 <https://github.com/numpy/numpy/pull/18063>`__: BUG: Fix concatenation when the output is "S" or "U"
+* `#18064 <https://github.com/numpy/numpy/pull/18064>`__: BLD, BUG: Fix detecting aarch64 on macOS
+* `#18068 <https://github.com/numpy/numpy/pull/18068>`__: REL: Prepare for 1.20.0rc2 release.
+* `#18108 <https://github.com/numpy/numpy/pull/18108>`__: BUG, BLD: Generate the main dispatcher config header into the...
+* `#18120 <https://github.com/numpy/numpy/pull/18120>`__: BUG, SIMD: Fix _simd module build for 64bit ARM/NEON clang
+* `#18127 <https://github.com/numpy/numpy/pull/18127>`__: REL: Update 1.20.x after 1.19.5 release.
+* `#18130 <https://github.com/numpy/numpy/pull/18130>`__: BUG: Fix promotion of half and string
+* `#18146 <https://github.com/numpy/numpy/pull/18146>`__: BUG, MAINT: improve avx512 mask logical operations
+* `#18154 <https://github.com/numpy/numpy/pull/18154>`__: BUG: Promotion between strings and objects was assymetric
+* `#18192 <https://github.com/numpy/numpy/pull/18192>`__: MAINT: Use explicit reexports for numpy.typing objects
+* `#18201 <https://github.com/numpy/numpy/pull/18201>`__: BUG: Keep ignoring most errors during array-protocol lookup
+* `#18219 <https://github.com/numpy/numpy/pull/18219>`__: MAINT: random shuffle: warn on unrecognized objects, fix empty...
+* `#18231 <https://github.com/numpy/numpy/pull/18231>`__: BLD: update OpenBLAS to af2b0d02
+* `#18237 <https://github.com/numpy/numpy/pull/18237>`__: DOC: Clarify the type alias deprecation message
+* `#18257 <https://github.com/numpy/numpy/pull/18257>`__: BUG: Ensure too many advanced indices raises an exception
+* `#18258 <https://github.com/numpy/numpy/pull/18258>`__: MAINT: add an 'apt update'
+* `#18259 <https://github.com/numpy/numpy/pull/18259>`__: DOC: Prepare for the NumPy 1.20.0 release.
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="908pt"
+ height="444pt"
+ viewBox="0 0 908 444"
+ version="1.1"
+ id="svg2577"
+ sodipodi:docname="casting_flow.svg"
+ inkscape:version="1.0rc1 (09960d6f05, 2020-04-09)">
+ <metadata
+ id="metadata2581">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:document-rotation="0"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="2560"
+ inkscape:window-height="1376"
+ id="namedview2579"
+ showgrid="false"
+ inkscape:zoom="1.1348363"
+ inkscape:cx="754.6365"
+ inkscape:cy="382.73477"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="surface392452" />
+ <defs
+ id="defs1910">
+ <g
+ id="g1908">
+ <symbol
+ overflow="visible"
+ id="glyph0-0">
+ <path
+ style="stroke:none;"
+ d="M 0.640625 2.265625 L 0.640625 -9.015625 L 7.03125 -9.015625 L 7.03125 2.265625 Z M 1.359375 1.546875 L 6.328125 1.546875 L 6.328125 -8.296875 L 1.359375 -8.296875 Z M 1.359375 1.546875 "
+ id="path1734" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-1">
+ <path
+ style="stroke:none;"
+ d="M 8.234375 -8.609375 L 8.234375 -7.28125 C 7.816406 -7.675781 7.363281 -7.96875 6.875 -8.15625 C 6.394531 -8.351562 5.882812 -8.453125 5.34375 -8.453125 C 4.28125 -8.453125 3.460938 -8.125 2.890625 -7.46875 C 2.328125 -6.820312 2.046875 -5.882812 2.046875 -4.65625 C 2.046875 -3.425781 2.328125 -2.484375 2.890625 -1.828125 C 3.460938 -1.179688 4.28125 -0.859375 5.34375 -0.859375 C 5.882812 -0.859375 6.394531 -0.953125 6.875 -1.140625 C 7.363281 -1.335938 7.816406 -1.632812 8.234375 -2.03125 L 8.234375 -0.71875 C 7.796875 -0.414062 7.328125 -0.1875 6.828125 -0.03125 C 6.335938 0.113281 5.820312 0.1875 5.28125 0.1875 C 3.863281 0.1875 2.75 -0.242188 1.9375 -1.109375 C 1.125 -1.972656 0.71875 -3.15625 0.71875 -4.65625 C 0.71875 -6.15625 1.125 -7.335938 1.9375 -8.203125 C 2.75 -9.066406 3.863281 -9.5 5.28125 -9.5 C 5.832031 -9.5 6.351562 -9.421875 6.84375 -9.265625 C 7.34375 -9.117188 7.804688 -8.898438 8.234375 -8.609375 Z M 8.234375 -8.609375 "
+ id="path1737" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-2">
+ <path
+ style="stroke:none;"
+ d="M 4.390625 -3.515625 C 3.460938 -3.515625 2.816406 -3.40625 2.453125 -3.1875 C 2.097656 -2.976562 1.921875 -2.617188 1.921875 -2.109375 C 1.921875 -1.703125 2.050781 -1.378906 2.3125 -1.140625 C 2.582031 -0.898438 2.953125 -0.78125 3.421875 -0.78125 C 4.054688 -0.78125 4.566406 -1.003906 4.953125 -1.453125 C 5.335938 -1.910156 5.53125 -2.515625 5.53125 -3.265625 L 5.53125 -3.515625 Z M 6.671875 -4 L 6.671875 0 L 5.53125 0 L 5.53125 -1.0625 C 5.269531 -0.632812 4.941406 -0.316406 4.546875 -0.109375 C 4.160156 0.0859375 3.679688 0.1875 3.109375 0.1875 C 2.390625 0.1875 1.816406 -0.015625 1.390625 -0.421875 C 0.972656 -0.828125 0.765625 -1.363281 0.765625 -2.03125 C 0.765625 -2.820312 1.023438 -3.414062 1.546875 -3.8125 C 2.078125 -4.21875 2.867188 -4.421875 3.921875 -4.421875 L 5.53125 -4.421875 L 5.53125 -4.53125 C 5.53125 -5.0625 5.351562 -5.46875 5 -5.75 C 4.65625 -6.039062 4.171875 -6.1875 3.546875 -6.1875 C 3.140625 -6.1875 2.75 -6.140625 2.375 -6.046875 C 2 -5.953125 1.632812 -5.8125 1.28125 -5.625 L 1.28125 -6.671875 C 1.695312 -6.835938 2.101562 -6.960938 2.5 -7.046875 C 2.894531 -7.128906 3.28125 -7.171875 3.65625 -7.171875 C 4.675781 -7.171875 5.429688 -6.90625 5.921875 -6.375 C 6.421875 -5.851562 6.671875 -5.0625 6.671875 -4 Z M 6.671875 -4 "
+ id="path1740" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-3">
+ <path
+ style="stroke:none;"
+ d="M 5.671875 -6.796875 L 5.671875 -5.703125 C 5.347656 -5.867188 5.007812 -5.992188 4.65625 -6.078125 C 4.300781 -6.160156 3.9375 -6.203125 3.5625 -6.203125 C 3 -6.203125 2.570312 -6.113281 2.28125 -5.9375 C 2 -5.769531 1.859375 -5.507812 1.859375 -5.15625 C 1.859375 -4.882812 1.957031 -4.671875 2.15625 -4.515625 C 2.363281 -4.367188 2.773438 -4.226562 3.390625 -4.09375 L 3.78125 -4 C 4.601562 -3.832031 5.1875 -3.585938 5.53125 -3.265625 C 5.875 -2.941406 6.046875 -2.5 6.046875 -1.9375 C 6.046875 -1.28125 5.785156 -0.757812 5.265625 -0.375 C 4.753906 0 4.050781 0.1875 3.15625 0.1875 C 2.78125 0.1875 2.390625 0.148438 1.984375 0.078125 C 1.578125 0.00390625 1.144531 -0.101562 0.6875 -0.25 L 0.6875 -1.4375 C 1.113281 -1.21875 1.53125 -1.050781 1.9375 -0.9375 C 2.351562 -0.832031 2.765625 -0.78125 3.171875 -0.78125 C 3.710938 -0.78125 4.128906 -0.875 4.421875 -1.0625 C 4.710938 -1.25 4.859375 -1.507812 4.859375 -1.84375 C 4.859375 -2.15625 4.753906 -2.394531 4.546875 -2.5625 C 4.335938 -2.726562 3.875 -2.890625 3.15625 -3.046875 L 2.765625 -3.140625 C 2.046875 -3.285156 1.53125 -3.515625 1.21875 -3.828125 C 0.90625 -4.140625 0.75 -4.566406 0.75 -5.109375 C 0.75 -5.765625 0.976562 -6.269531 1.4375 -6.625 C 1.90625 -6.988281 2.570312 -7.171875 3.4375 -7.171875 C 3.851562 -7.171875 4.25 -7.140625 4.625 -7.078125 C 5 -7.015625 5.347656 -6.921875 5.671875 -6.796875 Z M 5.671875 -6.796875 "
+ id="path1743" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-4">
+ <path
+ style="stroke:none;"
+ d="M 2.34375 -8.984375 L 2.34375 -7 L 4.71875 -7 L 4.71875 -6.109375 L 2.34375 -6.109375 L 2.34375 -2.3125 C 2.34375 -1.738281 2.421875 -1.367188 2.578125 -1.203125 C 2.734375 -1.046875 3.050781 -0.96875 3.53125 -0.96875 L 4.71875 -0.96875 L 4.71875 0 L 3.53125 0 C 2.644531 0 2.03125 -0.164062 1.6875 -0.5 C 1.351562 -0.832031 1.1875 -1.4375 1.1875 -2.3125 L 1.1875 -6.109375 L 0.34375 -6.109375 L 0.34375 -7 L 1.1875 -7 L 1.1875 -8.984375 Z M 2.34375 -8.984375 "
+ id="path1746" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-5">
+ <path
+ style="stroke:none;"
+ d="M 1.203125 -7 L 2.359375 -7 L 2.359375 0 L 1.203125 0 Z M 1.203125 -9.71875 L 2.359375 -9.71875 L 2.359375 -8.265625 L 1.203125 -8.265625 Z M 1.203125 -9.71875 "
+ id="path1749" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-6">
+ <path
+ style="stroke:none;"
+ d="M 7.015625 -4.21875 L 7.015625 0 L 5.875 0 L 5.875 -4.1875 C 5.875 -4.851562 5.742188 -5.347656 5.484375 -5.671875 C 5.222656 -6.003906 4.835938 -6.171875 4.328125 -6.171875 C 3.703125 -6.171875 3.207031 -5.972656 2.84375 -5.578125 C 2.488281 -5.179688 2.3125 -4.640625 2.3125 -3.953125 L 2.3125 0 L 1.15625 0 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.90625 C 2.59375 -6.332031 2.914062 -6.648438 3.28125 -6.859375 C 3.65625 -7.066406 4.085938 -7.171875 4.578125 -7.171875 C 5.378906 -7.171875 5.984375 -6.921875 6.390625 -6.421875 C 6.804688 -5.921875 7.015625 -5.1875 7.015625 -4.21875 Z M 7.015625 -4.21875 "
+ id="path1752" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-7">
+ <path
+ style="stroke:none;"
+ d="M 5.8125 -3.578125 C 5.8125 -4.410156 5.640625 -5.054688 5.296875 -5.515625 C 4.953125 -5.972656 4.46875 -6.203125 3.84375 -6.203125 C 3.226562 -6.203125 2.75 -5.972656 2.40625 -5.515625 C 2.0625 -5.054688 1.890625 -4.410156 1.890625 -3.578125 C 1.890625 -2.753906 2.0625 -2.113281 2.40625 -1.65625 C 2.75 -1.195312 3.226562 -0.96875 3.84375 -0.96875 C 4.46875 -0.96875 4.953125 -1.195312 5.296875 -1.65625 C 5.640625 -2.113281 5.8125 -2.753906 5.8125 -3.578125 Z M 6.953125 -0.875 C 6.953125 0.320312 6.6875 1.207031 6.15625 1.78125 C 5.632812 2.363281 4.828125 2.65625 3.734375 2.65625 C 3.328125 2.65625 2.945312 2.625 2.59375 2.5625 C 2.238281 2.507812 1.890625 2.421875 1.546875 2.296875 L 1.546875 1.171875 C 1.890625 1.359375 2.222656 1.492188 2.546875 1.578125 C 2.878906 1.671875 3.21875 1.71875 3.5625 1.71875 C 4.3125 1.71875 4.875 1.519531 5.25 1.125 C 5.625 0.726562 5.8125 0.132812 5.8125 -0.65625 L 5.8125 -1.234375 C 5.570312 -0.816406 5.265625 -0.503906 4.890625 -0.296875 C 4.523438 -0.0976562 4.082031 0 3.5625 0 C 2.707031 0 2.015625 -0.328125 1.484375 -0.984375 C 0.960938 -1.640625 0.703125 -2.503906 0.703125 -3.578125 C 0.703125 -4.660156 0.960938 -5.53125 1.484375 -6.1875 C 2.015625 -6.84375 2.707031 -7.171875 3.5625 -7.171875 C 4.082031 -7.171875 4.523438 -7.066406 4.890625 -6.859375 C 5.265625 -6.648438 5.570312 -6.34375 5.8125 -5.9375 L 5.8125 -7 L 6.953125 -7 Z M 6.953125 -0.875 "
+ id="path1755" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-8">
+ <path
+ style="stroke:none;"
+ d="M 1.25 -9.328125 L 2.515625 -9.328125 L 2.515625 0 L 1.25 0 Z M 1.25 -9.328125 "
+ id="path1758" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-9">
+ <path
+ style="stroke:none;"
+ d="M 6.65625 -5.65625 C 6.9375 -6.164062 7.273438 -6.546875 7.671875 -6.796875 C 8.078125 -7.046875 8.550781 -7.171875 9.09375 -7.171875 C 9.820312 -7.171875 10.382812 -6.914062 10.78125 -6.40625 C 11.175781 -5.894531 11.375 -5.164062 11.375 -4.21875 L 11.375 0 L 10.21875 0 L 10.21875 -4.1875 C 10.21875 -4.851562 10.097656 -5.347656 9.859375 -5.671875 C 9.628906 -6.003906 9.269531 -6.171875 8.78125 -6.171875 C 8.1875 -6.171875 7.710938 -5.972656 7.359375 -5.578125 C 7.015625 -5.179688 6.84375 -4.640625 6.84375 -3.953125 L 6.84375 0 L 5.6875 0 L 5.6875 -4.1875 C 5.6875 -4.863281 5.566406 -5.363281 5.328125 -5.6875 C 5.097656 -6.007812 4.734375 -6.171875 4.234375 -6.171875 C 3.648438 -6.171875 3.179688 -5.96875 2.828125 -5.5625 C 2.484375 -5.164062 2.3125 -4.628906 2.3125 -3.953125 L 2.3125 0 L 1.15625 0 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.90625 C 2.582031 -6.332031 2.898438 -6.648438 3.265625 -6.859375 C 3.628906 -7.066406 4.0625 -7.171875 4.5625 -7.171875 C 5.070312 -7.171875 5.503906 -7.039062 5.859375 -6.78125 C 6.222656 -6.519531 6.488281 -6.144531 6.65625 -5.65625 Z M 6.65625 -5.65625 "
+ id="path1761" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-10">
+ <path
+ style="stroke:none;"
+ d="M 2.3125 -1.046875 L 2.3125 2.65625 L 1.15625 2.65625 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.9375 C 2.5625 -6.351562 2.867188 -6.660156 3.234375 -6.859375 C 3.597656 -7.066406 4.039062 -7.171875 4.5625 -7.171875 C 5.40625 -7.171875 6.09375 -6.832031 6.625 -6.15625 C 7.15625 -5.476562 7.421875 -4.59375 7.421875 -3.5 C 7.421875 -2.394531 7.15625 -1.503906 6.625 -0.828125 C 6.09375 -0.148438 5.40625 0.1875 4.5625 0.1875 C 4.039062 0.1875 3.597656 0.0859375 3.234375 -0.109375 C 2.867188 -0.316406 2.5625 -0.628906 2.3125 -1.046875 Z M 6.234375 -3.5 C 6.234375 -4.34375 6.054688 -5.003906 5.703125 -5.484375 C 5.359375 -5.960938 4.882812 -6.203125 4.28125 -6.203125 C 3.664062 -6.203125 3.179688 -5.960938 2.828125 -5.484375 C 2.484375 -5.003906 2.3125 -4.34375 2.3125 -3.5 C 2.3125 -2.644531 2.484375 -1.976562 2.828125 -1.5 C 3.179688 -1.019531 3.664062 -0.78125 4.28125 -0.78125 C 4.882812 -0.78125 5.359375 -1.019531 5.703125 -1.5 C 6.054688 -1.976562 6.234375 -2.644531 6.234375 -3.5 Z M 6.234375 -3.5 "
+ id="path1764" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-11">
+ <path
+ style="stroke:none;"
+ d="M 1.203125 -9.71875 L 2.359375 -9.71875 L 2.359375 0 L 1.203125 0 Z M 1.203125 -9.71875 "
+ id="path1767" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-12">
+ <path
+ style="stroke:none;"
+ d="M 1.09375 -9.71875 L 3.75 -9.71875 L 3.75 -8.828125 L 2.25 -8.828125 L 2.25 0.796875 L 3.75 0.796875 L 3.75 1.6875 L 1.09375 1.6875 Z M 1.09375 -9.71875 "
+ id="path1770" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-13">
+ <path
+ style="stroke:none;"
+ d="M 2.453125 -1.0625 L 6.859375 -1.0625 L 6.859375 0 L 0.9375 0 L 0.9375 -1.0625 C 1.414062 -1.5625 2.066406 -2.226562 2.890625 -3.0625 C 3.722656 -3.894531 4.242188 -4.429688 4.453125 -4.671875 C 4.859375 -5.128906 5.140625 -5.515625 5.296875 -5.828125 C 5.460938 -6.140625 5.546875 -6.445312 5.546875 -6.75 C 5.546875 -7.25 5.367188 -7.65625 5.015625 -7.96875 C 4.671875 -8.28125 4.21875 -8.4375 3.65625 -8.4375 C 3.257812 -8.4375 2.84375 -8.363281 2.40625 -8.21875 C 1.96875 -8.082031 1.5 -7.878906 1 -7.609375 L 1 -8.875 C 1.507812 -9.082031 1.984375 -9.238281 2.421875 -9.34375 C 2.867188 -9.445312 3.273438 -9.5 3.640625 -9.5 C 4.609375 -9.5 5.378906 -9.253906 5.953125 -8.765625 C 6.523438 -8.285156 6.8125 -7.640625 6.8125 -6.828125 C 6.8125 -6.453125 6.738281 -6.09375 6.59375 -5.75 C 6.445312 -5.40625 6.1875 -5 5.8125 -4.53125 C 5.707031 -4.40625 5.375 -4.054688 4.8125 -3.484375 C 4.257812 -2.910156 3.472656 -2.101562 2.453125 -1.0625 Z M 2.453125 -1.0625 "
+ id="path1773" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-14">
+ <path
+ style="stroke:none;"
+ d="M 4.84375 -8.234375 L 1.65625 -3.25 L 4.84375 -3.25 Z M 4.5 -9.328125 L 6.09375 -9.328125 L 6.09375 -3.25 L 7.421875 -3.25 L 7.421875 -2.203125 L 6.09375 -2.203125 L 6.09375 0 L 4.84375 0 L 4.84375 -2.203125 L 0.625 -2.203125 L 0.625 -3.421875 Z M 4.5 -9.328125 "
+ id="path1776" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-15">
+ <path
+ style="stroke:none;"
+ d="M 1.5 -1.59375 L 2.8125 -1.59375 L 2.8125 -0.515625 L 1.796875 1.484375 L 0.984375 1.484375 L 1.5 -0.515625 Z M 1.5 -1.59375 "
+ id="path1779" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-16">
+ <path
+ style="stroke:none;"
+ d=""
+ id="path1782" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-17">
+ <path
+ style="stroke:none;"
+ d="M 6.84375 -9.015625 L 6.84375 -7.796875 C 6.363281 -8.023438 5.910156 -8.191406 5.484375 -8.296875 C 5.066406 -8.410156 4.660156 -8.46875 4.265625 -8.46875 C 3.578125 -8.46875 3.046875 -8.332031 2.671875 -8.0625 C 2.296875 -7.800781 2.109375 -7.425781 2.109375 -6.9375 C 2.109375 -6.519531 2.234375 -6.207031 2.484375 -6 C 2.734375 -5.789062 3.203125 -5.625 3.890625 -5.5 L 4.65625 -5.34375 C 5.59375 -5.15625 6.285156 -4.835938 6.734375 -4.390625 C 7.179688 -3.941406 7.40625 -3.335938 7.40625 -2.578125 C 7.40625 -1.671875 7.101562 -0.984375 6.5 -0.515625 C 5.894531 -0.046875 5.007812 0.1875 3.84375 0.1875 C 3.394531 0.1875 2.921875 0.132812 2.421875 0.03125 C 1.929688 -0.0703125 1.414062 -0.21875 0.875 -0.40625 L 0.875 -1.71875 C 1.394531 -1.425781 1.898438 -1.207031 2.390625 -1.0625 C 2.878906 -0.914062 3.363281 -0.84375 3.84375 -0.84375 C 4.5625 -0.84375 5.113281 -0.984375 5.5 -1.265625 C 5.894531 -1.546875 6.09375 -1.953125 6.09375 -2.484375 C 6.09375 -2.941406 5.953125 -3.296875 5.671875 -3.546875 C 5.390625 -3.804688 4.925781 -4.003906 4.28125 -4.140625 L 3.515625 -4.28125 C 2.578125 -4.46875 1.894531 -4.757812 1.46875 -5.15625 C 1.050781 -5.5625 0.84375 -6.117188 0.84375 -6.828125 C 0.84375 -7.660156 1.132812 -8.3125 1.71875 -8.78125 C 2.300781 -9.257812 3.101562 -9.5 4.125 -9.5 C 4.5625 -9.5 5.003906 -9.457031 5.453125 -9.375 C 5.910156 -9.300781 6.375 -9.179688 6.84375 -9.015625 Z M 6.84375 -9.015625 "
+ id="path1785" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-18">
+ <path
+ style="stroke:none;"
+ d="M 5.265625 -5.921875 C 5.128906 -5.992188 4.984375 -6.046875 4.828125 -6.078125 C 4.679688 -6.117188 4.519531 -6.140625 4.34375 -6.140625 C 3.6875 -6.140625 3.179688 -5.925781 2.828125 -5.5 C 2.484375 -5.082031 2.3125 -4.476562 2.3125 -3.6875 L 2.3125 0 L 1.15625 0 L 1.15625 -7 L 2.3125 -7 L 2.3125 -5.90625 C 2.5625 -6.332031 2.878906 -6.648438 3.265625 -6.859375 C 3.648438 -7.066406 4.117188 -7.171875 4.671875 -7.171875 C 4.753906 -7.171875 4.84375 -7.164062 4.9375 -7.15625 C 5.03125 -7.144531 5.132812 -7.128906 5.25 -7.109375 Z M 5.265625 -5.921875 "
+ id="path1788" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-19">
+ <path
+ style="stroke:none;"
+ d="M 3.890625 -9.71875 L 3.890625 1.6875 L 1.25 1.6875 L 1.25 0.796875 L 2.734375 0.796875 L 2.734375 -8.828125 L 1.25 -8.828125 L 1.25 -9.71875 Z M 3.890625 -9.71875 "
+ id="path1791" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-20">
+ <path
+ style="stroke:none;"
+ d="M 4.0625 -8.5 C 3.414062 -8.5 2.925781 -8.175781 2.59375 -7.53125 C 2.269531 -6.894531 2.109375 -5.9375 2.109375 -4.65625 C 2.109375 -3.375 2.269531 -2.410156 2.59375 -1.765625 C 2.925781 -1.128906 3.414062 -0.8125 4.0625 -0.8125 C 4.71875 -0.8125 5.207031 -1.128906 5.53125 -1.765625 C 5.863281 -2.410156 6.03125 -3.375 6.03125 -4.65625 C 6.03125 -5.9375 5.863281 -6.894531 5.53125 -7.53125 C 5.207031 -8.175781 4.71875 -8.5 4.0625 -8.5 Z M 4.0625 -9.5 C 5.113281 -9.5 5.914062 -9.082031 6.46875 -8.25 C 7.019531 -7.425781 7.296875 -6.226562 7.296875 -4.65625 C 7.296875 -3.082031 7.019531 -1.878906 6.46875 -1.046875 C 5.914062 -0.222656 5.113281 0.1875 4.0625 0.1875 C 3.019531 0.1875 2.222656 -0.222656 1.671875 -1.046875 C 1.117188 -1.878906 0.84375 -3.082031 0.84375 -4.65625 C 0.84375 -6.226562 1.117188 -7.425781 1.671875 -8.25 C 2.222656 -9.082031 3.019531 -9.5 4.0625 -9.5 Z M 4.0625 -9.5 "
+ id="path1794" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-21">
+ <path
+ style="stroke:none;"
+ d="M 5.8125 -5.9375 L 5.8125 -9.71875 L 6.953125 -9.71875 L 6.953125 0 L 5.8125 0 L 5.8125 -1.046875 C 5.570312 -0.628906 5.265625 -0.316406 4.890625 -0.109375 C 4.523438 0.0859375 4.082031 0.1875 3.5625 0.1875 C 2.71875 0.1875 2.03125 -0.148438 1.5 -0.828125 C 0.96875 -1.503906 0.703125 -2.394531 0.703125 -3.5 C 0.703125 -4.59375 0.96875 -5.476562 1.5 -6.15625 C 2.03125 -6.832031 2.71875 -7.171875 3.5625 -7.171875 C 4.082031 -7.171875 4.523438 -7.066406 4.890625 -6.859375 C 5.265625 -6.660156 5.570312 -6.351562 5.8125 -5.9375 Z M 1.890625 -3.5 C 1.890625 -2.644531 2.0625 -1.976562 2.40625 -1.5 C 2.757812 -1.019531 3.238281 -0.78125 3.84375 -0.78125 C 4.457031 -0.78125 4.9375 -1.019531 5.28125 -1.5 C 5.632812 -1.976562 5.8125 -2.644531 5.8125 -3.5 C 5.8125 -4.34375 5.632812 -5.003906 5.28125 -5.484375 C 4.9375 -5.960938 4.457031 -6.203125 3.84375 -6.203125 C 3.238281 -6.203125 2.757812 -5.960938 2.40625 -5.484375 C 2.0625 -5.003906 1.890625 -4.34375 1.890625 -3.5 Z M 1.890625 -3.5 "
+ id="path1797" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-22">
+ <path
+ style="stroke:none;"
+ d="M 1.203125 -7 L 2.359375 -7 L 2.359375 0.125 C 2.359375 1.019531 2.1875 1.664062 1.84375 2.0625 C 1.507812 2.457031 0.960938 2.65625 0.203125 2.65625 L -0.234375 2.65625 L -0.234375 1.6875 L 0.078125 1.6875 C 0.515625 1.6875 0.8125 1.582031 0.96875 1.375 C 1.125 1.175781 1.203125 0.757812 1.203125 0.125 Z M 1.203125 -9.71875 L 2.359375 -9.71875 L 2.359375 -8.265625 L 1.203125 -8.265625 Z M 1.203125 -9.71875 "
+ id="path1800" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-23">
+ <path
+ style="stroke:none;"
+ d="M 1.09375 -2.765625 L 1.09375 -7 L 2.234375 -7 L 2.234375 -2.8125 C 2.234375 -2.144531 2.363281 -1.644531 2.625 -1.3125 C 2.882812 -0.976562 3.269531 -0.8125 3.78125 -0.8125 C 4.40625 -0.8125 4.894531 -1.007812 5.25 -1.40625 C 5.613281 -1.800781 5.796875 -2.34375 5.796875 -3.03125 L 5.796875 -7 L 6.953125 -7 L 6.953125 0 L 5.796875 0 L 5.796875 -1.078125 C 5.515625 -0.648438 5.191406 -0.332031 4.828125 -0.125 C 4.460938 0.0820312 4.035156 0.1875 3.546875 0.1875 C 2.742188 0.1875 2.132812 -0.0625 1.71875 -0.5625 C 1.300781 -1.0625 1.09375 -1.796875 1.09375 -2.765625 Z M 3.984375 -7.171875 Z M 3.984375 -7.171875 "
+ id="path1803" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-24">
+ <path
+ style="stroke:none;"
+ d="M 6.515625 2.125 L 6.515625 3.015625 L -0.125 3.015625 L -0.125 2.125 Z M 6.515625 2.125 "
+ id="path1806" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-25">
+ <path
+ style="stroke:none;"
+ d="M 7.1875 -3.78125 L 7.1875 -3.21875 L 1.90625 -3.21875 C 1.957031 -2.425781 2.195312 -1.820312 2.625 -1.40625 C 3.050781 -1 3.644531 -0.796875 4.40625 -0.796875 C 4.84375 -0.796875 5.269531 -0.847656 5.6875 -0.953125 C 6.101562 -1.066406 6.515625 -1.226562 6.921875 -1.4375 L 6.921875 -0.359375 C 6.515625 -0.179688 6.09375 -0.046875 5.65625 0.046875 C 5.21875 0.140625 4.78125 0.1875 4.34375 0.1875 C 3.21875 0.1875 2.328125 -0.132812 1.671875 -0.78125 C 1.023438 -1.4375 0.703125 -2.320312 0.703125 -3.4375 C 0.703125 -4.582031 1.007812 -5.488281 1.625 -6.15625 C 2.25 -6.832031 3.085938 -7.171875 4.140625 -7.171875 C 5.078125 -7.171875 5.816406 -6.863281 6.359375 -6.25 C 6.910156 -5.644531 7.1875 -4.820312 7.1875 -3.78125 Z M 6.046875 -4.125 C 6.035156 -4.75 5.859375 -5.25 5.515625 -5.625 C 5.171875 -6 4.71875 -6.1875 4.15625 -6.1875 C 3.507812 -6.1875 2.992188 -6.003906 2.609375 -5.640625 C 2.222656 -5.285156 2 -4.78125 1.9375 -4.125 Z M 6.046875 -4.125 "
+ id="path1809" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-26">
+ <path
+ style="stroke:none;"
+ d="M 6.25 -6.734375 L 6.25 -5.65625 C 5.914062 -5.832031 5.585938 -5.960938 5.265625 -6.046875 C 4.941406 -6.140625 4.613281 -6.1875 4.28125 -6.1875 C 3.53125 -6.1875 2.945312 -5.953125 2.53125 -5.484375 C 2.125 -5.015625 1.921875 -4.351562 1.921875 -3.5 C 1.921875 -2.644531 2.125 -1.976562 2.53125 -1.5 C 2.945312 -1.03125 3.53125 -0.796875 4.28125 -0.796875 C 4.613281 -0.796875 4.941406 -0.835938 5.265625 -0.921875 C 5.585938 -1.015625 5.914062 -1.148438 6.25 -1.328125 L 6.25 -0.265625 C 5.925781 -0.117188 5.59375 -0.0078125 5.25 0.0625 C 4.90625 0.144531 4.539062 0.1875 4.15625 0.1875 C 3.09375 0.1875 2.25 -0.144531 1.625 -0.8125 C 1.007812 -1.476562 0.703125 -2.375 0.703125 -3.5 C 0.703125 -4.632812 1.015625 -5.53125 1.640625 -6.1875 C 2.273438 -6.84375 3.132812 -7.171875 4.21875 -7.171875 C 4.570312 -7.171875 4.914062 -7.132812 5.25 -7.0625 C 5.59375 -6.988281 5.925781 -6.878906 6.25 -6.734375 Z M 6.25 -6.734375 "
+ id="path1812" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-27">
+ <path
+ style="stroke:none;"
+ d="M 3.921875 -6.1875 C 3.304688 -6.1875 2.816406 -5.945312 2.453125 -5.46875 C 2.097656 -4.988281 1.921875 -4.332031 1.921875 -3.5 C 1.921875 -2.65625 2.097656 -1.992188 2.453125 -1.515625 C 2.804688 -1.035156 3.296875 -0.796875 3.921875 -0.796875 C 4.535156 -0.796875 5.019531 -1.035156 5.375 -1.515625 C 5.726562 -2.003906 5.90625 -2.664062 5.90625 -3.5 C 5.90625 -4.320312 5.726562 -4.972656 5.375 -5.453125 C 5.019531 -5.941406 4.535156 -6.1875 3.921875 -6.1875 Z M 3.921875 -7.171875 C 4.921875 -7.171875 5.703125 -6.84375 6.265625 -6.1875 C 6.835938 -5.539062 7.125 -4.644531 7.125 -3.5 C 7.125 -2.351562 6.835938 -1.453125 6.265625 -0.796875 C 5.703125 -0.140625 4.921875 0.1875 3.921875 0.1875 C 2.910156 0.1875 2.117188 -0.140625 1.546875 -0.796875 C 0.984375 -1.453125 0.703125 -2.351562 0.703125 -3.5 C 0.703125 -4.644531 0.984375 -5.539062 1.546875 -6.1875 C 2.117188 -6.84375 2.910156 -7.171875 3.921875 -7.171875 Z M 3.921875 -7.171875 "
+ id="path1815" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-28">
+ <path
+ style="stroke:none;"
+ d="M 3.96875 -9.703125 C 3.40625 -8.742188 2.988281 -7.796875 2.71875 -6.859375 C 2.445312 -5.929688 2.3125 -4.984375 2.3125 -4.015625 C 2.3125 -3.054688 2.445312 -2.101562 2.71875 -1.15625 C 3 -0.21875 3.414062 0.726562 3.96875 1.6875 L 2.96875 1.6875 C 2.34375 0.707031 1.875 -0.253906 1.5625 -1.203125 C 1.25 -2.148438 1.09375 -3.085938 1.09375 -4.015625 C 1.09375 -4.941406 1.25 -5.875 1.5625 -6.8125 C 1.875 -7.757812 2.34375 -8.722656 2.96875 -9.703125 Z M 3.96875 -9.703125 "
+ id="path1818" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-29">
+ <path
+ style="stroke:none;"
+ d="M 1.03125 -9.703125 L 2.03125 -9.703125 C 2.65625 -8.722656 3.117188 -7.757812 3.421875 -6.8125 C 3.734375 -5.875 3.890625 -4.941406 3.890625 -4.015625 C 3.890625 -3.085938 3.734375 -2.148438 3.421875 -1.203125 C 3.117188 -0.253906 2.65625 0.707031 2.03125 1.6875 L 1.03125 1.6875 C 1.582031 0.726562 1.992188 -0.21875 2.265625 -1.15625 C 2.535156 -2.101562 2.671875 -3.054688 2.671875 -4.015625 C 2.671875 -4.984375 2.535156 -5.929688 2.265625 -6.859375 C 1.992188 -7.796875 1.582031 -8.742188 1.03125 -9.703125 Z M 1.03125 -9.703125 "
+ id="path1821" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-30">
+ <path
+ style="stroke:none;"
+ d="M 4.0625 -4.4375 C 3.46875 -4.4375 3 -4.273438 2.65625 -3.953125 C 2.3125 -3.628906 2.140625 -3.1875 2.140625 -2.625 C 2.140625 -2.0625 2.3125 -1.617188 2.65625 -1.296875 C 3 -0.972656 3.46875 -0.8125 4.0625 -0.8125 C 4.664062 -0.8125 5.140625 -0.972656 5.484375 -1.296875 C 5.828125 -1.617188 6 -2.0625 6 -2.625 C 6 -3.1875 5.828125 -3.628906 5.484375 -3.953125 C 5.140625 -4.273438 4.664062 -4.4375 4.0625 -4.4375 Z M 2.8125 -4.96875 C 2.269531 -5.101562 1.847656 -5.351562 1.546875 -5.71875 C 1.242188 -6.09375 1.09375 -6.546875 1.09375 -7.078125 C 1.09375 -7.828125 1.359375 -8.414062 1.890625 -8.84375 C 2.421875 -9.28125 3.144531 -9.5 4.0625 -9.5 C 5 -9.5 5.726562 -9.28125 6.25 -8.84375 C 6.78125 -8.414062 7.046875 -7.828125 7.046875 -7.078125 C 7.046875 -6.546875 6.894531 -6.09375 6.59375 -5.71875 C 6.289062 -5.351562 5.875 -5.101562 5.34375 -4.96875 C 5.945312 -4.820312 6.414062 -4.539062 6.75 -4.125 C 7.09375 -3.71875 7.265625 -3.21875 7.265625 -2.625 C 7.265625 -1.71875 6.988281 -1.019531 6.4375 -0.53125 C 5.882812 -0.0507812 5.09375 0.1875 4.0625 0.1875 C 3.039062 0.1875 2.253906 -0.0507812 1.703125 -0.53125 C 1.148438 -1.019531 0.875 -1.71875 0.875 -2.625 C 0.875 -3.21875 1.039062 -3.71875 1.375 -4.125 C 1.71875 -4.539062 2.195312 -4.820312 2.8125 -4.96875 Z M 2.34375 -6.953125 C 2.34375 -6.472656 2.492188 -6.097656 2.796875 -5.828125 C 3.097656 -5.554688 3.519531 -5.421875 4.0625 -5.421875 C 4.601562 -5.421875 5.023438 -5.554688 5.328125 -5.828125 C 5.640625 -6.097656 5.796875 -6.472656 5.796875 -6.953125 C 5.796875 -7.441406 5.640625 -7.820312 5.328125 -8.09375 C 5.023438 -8.363281 4.601562 -8.5 4.0625 -8.5 C 3.519531 -8.5 3.097656 -8.363281 2.796875 -8.09375 C 2.492188 -7.820312 2.34375 -7.441406 2.34375 -6.953125 Z M 2.34375 -6.953125 "
+ id="path1824" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-31">
+ <path
+ style="stroke:none;"
+ d="M 1.9375 -1.59375 L 3.203125 -1.59375 L 3.203125 0 L 1.9375 0 Z M 1.9375 -9.328125 L 3.203125 -9.328125 L 3.203125 -5.234375 L 3.078125 -3 L 2.0625 -3 L 1.9375 -5.234375 Z M 1.9375 -9.328125 "
+ id="path1827" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-32">
+ <path
+ style="stroke:none;"
+ d="M 1.359375 -5.8125 L 9.359375 -5.8125 L 9.359375 -4.765625 L 1.359375 -4.765625 Z M 1.359375 -3.265625 L 9.359375 -3.265625 L 9.359375 -2.203125 L 1.359375 -2.203125 Z M 1.359375 -3.265625 "
+ id="path1830" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-33">
+ <path
+ style="stroke:none;"
+ d="M 4.75 -9.71875 L 4.75 -8.765625 L 3.65625 -8.765625 C 3.238281 -8.765625 2.945312 -8.679688 2.78125 -8.515625 C 2.625 -8.347656 2.546875 -8.046875 2.546875 -7.609375 L 2.546875 -7 L 4.4375 -7 L 4.4375 -6.109375 L 2.546875 -6.109375 L 2.546875 0 L 1.390625 0 L 1.390625 -6.109375 L 0.296875 -6.109375 L 0.296875 -7 L 1.390625 -7 L 1.390625 -7.484375 C 1.390625 -8.265625 1.570312 -8.832031 1.9375 -9.1875 C 2.300781 -9.539062 2.875 -9.71875 3.65625 -9.71875 Z M 4.75 -9.71875 "
+ id="path1833" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph0-34">
+ <path
+ style="stroke:none;"
+ d="M 2.296875 -9.328125 L 2.296875 -5.859375 L 1.234375 -5.859375 L 1.234375 -9.328125 Z M 4.65625 -9.328125 L 4.65625 -5.859375 L 3.59375 -5.859375 L 3.59375 -9.328125 Z M 4.65625 -9.328125 "
+ id="path1836" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-0">
+ <path
+ style="stroke:none;"
+ d="M 0.984375 3.484375 L 0.984375 -13.921875 L 10.859375 -13.921875 L 10.859375 3.484375 Z M 2.09375 2.390625 L 9.765625 2.390625 L 9.765625 -12.8125 L 2.09375 -12.8125 Z M 2.09375 2.390625 "
+ id="path1839" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-1">
+ <path
+ style="stroke:none;"
+ d="M 12.515625 -6.578125 L 12.515625 0 L 9.046875 0 L 9.046875 -5.03125 C 9.046875 -5.96875 9.023438 -6.613281 8.984375 -6.96875 C 8.941406 -7.320312 8.867188 -7.582031 8.765625 -7.75 C 8.628906 -7.96875 8.445312 -8.140625 8.21875 -8.265625 C 7.988281 -8.390625 7.722656 -8.453125 7.421875 -8.453125 C 6.703125 -8.453125 6.132812 -8.175781 5.71875 -7.625 C 5.3125 -7.070312 5.109375 -6.300781 5.109375 -5.3125 L 5.109375 0 L 1.65625 0 L 1.65625 -10.796875 L 5.109375 -10.796875 L 5.109375 -9.21875 C 5.628906 -9.851562 6.179688 -10.316406 6.765625 -10.609375 C 7.347656 -10.910156 7.992188 -11.0625 8.703125 -11.0625 C 9.953125 -11.0625 10.898438 -10.675781 11.546875 -9.90625 C 12.191406 -9.144531 12.515625 -8.035156 12.515625 -6.578125 Z M 12.515625 -6.578125 "
+ id="path1842" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-2">
+ <path
+ style="stroke:none;"
+ d="M 5.109375 -1.5625 L 5.109375 4.109375 L 1.65625 4.109375 L 1.65625 -10.796875 L 5.109375 -10.796875 L 5.109375 -9.21875 C 5.585938 -9.851562 6.113281 -10.316406 6.6875 -10.609375 C 7.269531 -10.910156 7.9375 -11.0625 8.6875 -11.0625 C 10.019531 -11.0625 11.113281 -10.53125 11.96875 -9.46875 C 12.820312 -8.414062 13.25 -7.054688 13.25 -5.390625 C 13.25 -3.722656 12.820312 -2.359375 11.96875 -1.296875 C 11.113281 -0.242188 10.019531 0.28125 8.6875 0.28125 C 7.9375 0.28125 7.269531 0.128906 6.6875 -0.171875 C 6.113281 -0.472656 5.585938 -0.9375 5.109375 -1.5625 Z M 7.40625 -8.546875 C 6.664062 -8.546875 6.097656 -8.273438 5.703125 -7.734375 C 5.304688 -7.191406 5.109375 -6.410156 5.109375 -5.390625 C 5.109375 -4.367188 5.304688 -3.585938 5.703125 -3.046875 C 6.097656 -2.503906 6.664062 -2.234375 7.40625 -2.234375 C 8.144531 -2.234375 8.707031 -2.5 9.09375 -3.03125 C 9.488281 -3.570312 9.6875 -4.359375 9.6875 -5.390625 C 9.6875 -6.421875 9.488281 -7.203125 9.09375 -7.734375 C 8.707031 -8.273438 8.144531 -8.546875 7.40625 -8.546875 Z M 7.40625 -8.546875 "
+ id="path1845" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-3">
+ <path
+ style="stroke:none;"
+ d="M 2.015625 -3.734375 L 5.484375 -3.734375 L 5.484375 0 L 2.015625 0 Z M 2.015625 -3.734375 "
+ id="path1848" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-4">
+ <path
+ style="stroke:none;"
+ d="M 6.5 -4.859375 C 5.78125 -4.859375 5.238281 -4.734375 4.875 -4.484375 C 4.507812 -4.242188 4.328125 -3.882812 4.328125 -3.40625 C 4.328125 -2.976562 4.472656 -2.640625 4.765625 -2.390625 C 5.054688 -2.140625 5.460938 -2.015625 5.984375 -2.015625 C 6.640625 -2.015625 7.1875 -2.242188 7.625 -2.703125 C 8.070312 -3.171875 8.296875 -3.757812 8.296875 -4.46875 L 8.296875 -4.859375 Z M 11.78125 -6.15625 L 11.78125 0 L 8.296875 0 L 8.296875 -1.59375 C 7.828125 -0.945312 7.300781 -0.472656 6.71875 -0.171875 C 6.144531 0.128906 5.445312 0.28125 4.625 0.28125 C 3.5 0.28125 2.585938 -0.0390625 1.890625 -0.6875 C 1.191406 -1.34375 0.84375 -2.191406 0.84375 -3.234375 C 0.84375 -4.503906 1.28125 -5.4375 2.15625 -6.03125 C 3.03125 -6.625 4.398438 -6.921875 6.265625 -6.921875 L 8.296875 -6.921875 L 8.296875 -7.1875 C 8.296875 -7.726562 8.078125 -8.125 7.640625 -8.375 C 7.210938 -8.632812 6.539062 -8.765625 5.625 -8.765625 C 4.882812 -8.765625 4.195312 -8.691406 3.5625 -8.546875 C 2.925781 -8.398438 2.335938 -8.175781 1.796875 -7.875 L 1.796875 -10.515625 C 2.535156 -10.691406 3.273438 -10.828125 4.015625 -10.921875 C 4.765625 -11.015625 5.515625 -11.0625 6.265625 -11.0625 C 8.210938 -11.0625 9.617188 -10.675781 10.484375 -9.90625 C 11.347656 -9.132812 11.78125 -7.882812 11.78125 -6.15625 Z M 11.78125 -6.15625 "
+ id="path1851" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-5">
+ <path
+ style="stroke:none;"
+ d="M 9.6875 -7.859375 C 9.382812 -8.003906 9.082031 -8.109375 8.78125 -8.171875 C 8.476562 -8.242188 8.175781 -8.28125 7.875 -8.28125 C 6.988281 -8.28125 6.304688 -7.992188 5.828125 -7.421875 C 5.347656 -6.847656 5.109375 -6.03125 5.109375 -4.96875 L 5.109375 0 L 1.65625 0 L 1.65625 -10.796875 L 5.109375 -10.796875 L 5.109375 -9.03125 C 5.554688 -9.738281 6.066406 -10.253906 6.640625 -10.578125 C 7.210938 -10.898438 7.898438 -11.0625 8.703125 -11.0625 C 8.816406 -11.0625 8.941406 -11.054688 9.078125 -11.046875 C 9.210938 -11.035156 9.410156 -11.015625 9.671875 -10.984375 Z M 9.6875 -7.859375 "
+ id="path1854" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-6">
+ <path
+ style="stroke:none;"
+ d="M 0.234375 -10.796875 L 3.6875 -10.796875 L 6.59375 -3.46875 L 9.0625 -10.796875 L 12.515625 -10.796875 L 7.96875 1.015625 C 7.519531 2.222656 6.988281 3.066406 6.375 3.546875 C 5.769531 4.023438 4.96875 4.265625 3.96875 4.265625 L 1.984375 4.265625 L 1.984375 2 L 3.0625 2 C 3.644531 2 4.066406 1.90625 4.328125 1.71875 C 4.597656 1.53125 4.804688 1.195312 4.953125 0.71875 L 5.046875 0.421875 Z M 0.234375 -10.796875 "
+ id="path1857" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-7">
+ <path
+ style="stroke:none;"
+ d="M 7.4375 2.609375 L 4.578125 2.609375 C 3.597656 1.015625 2.875 -0.492188 2.40625 -1.921875 C 1.9375 -3.347656 1.703125 -4.769531 1.703125 -6.1875 C 1.703125 -7.59375 1.9375 -9.015625 2.40625 -10.453125 C 2.875 -11.898438 3.597656 -13.410156 4.578125 -14.984375 L 7.4375 -14.984375 C 6.613281 -13.460938 5.992188 -11.972656 5.578125 -10.515625 C 5.171875 -9.054688 4.96875 -7.617188 4.96875 -6.203125 C 4.96875 -4.773438 5.171875 -3.332031 5.578125 -1.875 C 5.992188 -0.414062 6.613281 1.078125 7.4375 2.609375 Z M 7.4375 2.609375 "
+ id="path1860" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-8">
+ <path
+ style="stroke:none;"
+ d="M 7.265625 -11.34375 L 3.203125 -5.3125 L 7.265625 -5.3125 Z M 6.65625 -14.390625 L 10.78125 -14.390625 L 10.78125 -5.3125 L 12.828125 -5.3125 L 12.828125 -2.625 L 10.78125 -2.625 L 10.78125 0 L 7.265625 0 L 7.265625 -2.625 L 0.890625 -2.625 L 0.890625 -5.8125 Z M 6.65625 -14.390625 "
+ id="path1863" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-9">
+ <path
+ style="stroke:none;"
+ d="M 5.6875 -2.734375 L 12.03125 -2.734375 L 12.03125 0 L 1.5625 0 L 1.5625 -2.734375 L 6.8125 -7.375 C 7.28125 -7.789062 7.628906 -8.203125 7.859375 -8.609375 C 8.085938 -9.015625 8.203125 -9.4375 8.203125 -9.875 C 8.203125 -10.550781 7.972656 -11.09375 7.515625 -11.5 C 7.066406 -11.914062 6.460938 -12.125 5.703125 -12.125 C 5.128906 -12.125 4.5 -12 3.8125 -11.75 C 3.125 -11.5 2.382812 -11.128906 1.59375 -10.640625 L 1.59375 -13.8125 C 2.4375 -14.082031 3.265625 -14.289062 4.078125 -14.4375 C 4.890625 -14.582031 5.691406 -14.65625 6.484375 -14.65625 C 8.203125 -14.65625 9.535156 -14.273438 10.484375 -13.515625 C 11.441406 -12.753906 11.921875 -11.695312 11.921875 -10.34375 C 11.921875 -9.5625 11.71875 -8.832031 11.3125 -8.15625 C 10.914062 -7.476562 10.066406 -6.566406 8.765625 -5.421875 Z M 5.6875 -2.734375 "
+ id="path1866" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-10">
+ <path
+ style="stroke:none;"
+ d="M 2.015625 -3.734375 L 5.484375 -3.734375 L 5.484375 -0.796875 L 3.109375 2.8125 L 1.046875 2.8125 L 2.015625 -0.796875 Z M 2.015625 -3.734375 "
+ id="path1869" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-11">
+ <path
+ style="stroke:none;"
+ d=""
+ id="path1872" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-12">
+ <path
+ style="stroke:none;"
+ d="M 9 -9.21875 L 9 -15 L 12.484375 -15 L 12.484375 0 L 9 0 L 9 -1.5625 C 8.53125 -0.925781 8.007812 -0.457031 7.4375 -0.15625 C 6.863281 0.132812 6.203125 0.28125 5.453125 0.28125 C 4.117188 0.28125 3.023438 -0.242188 2.171875 -1.296875 C 1.316406 -2.359375 0.890625 -3.722656 0.890625 -5.390625 C 0.890625 -7.054688 1.316406 -8.414062 2.171875 -9.46875 C 3.023438 -10.53125 4.117188 -11.0625 5.453125 -11.0625 C 6.191406 -11.0625 6.847656 -10.910156 7.421875 -10.609375 C 8.003906 -10.316406 8.53125 -9.851562 9 -9.21875 Z M 6.734375 -2.234375 C 7.472656 -2.234375 8.035156 -2.5 8.421875 -3.03125 C 8.804688 -3.570312 9 -4.359375 9 -5.390625 C 9 -6.421875 8.804688 -7.203125 8.421875 -7.734375 C 8.035156 -8.273438 7.472656 -8.546875 6.734375 -8.546875 C 5.992188 -8.546875 5.429688 -8.273438 5.046875 -7.734375 C 4.660156 -7.203125 4.46875 -6.421875 4.46875 -5.390625 C 4.46875 -4.359375 4.660156 -3.570312 5.046875 -3.03125 C 5.429688 -2.5 5.992188 -2.234375 6.734375 -2.234375 Z M 6.734375 -2.234375 "
+ id="path1875" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-13">
+ <path
+ style="stroke:none;"
+ d="M 5.421875 -13.875 L 5.421875 -10.796875 L 8.984375 -10.796875 L 8.984375 -8.328125 L 5.421875 -8.328125 L 5.421875 -3.75 C 5.421875 -3.25 5.519531 -2.910156 5.71875 -2.734375 C 5.925781 -2.554688 6.328125 -2.46875 6.921875 -2.46875 L 8.6875 -2.46875 L 8.6875 0 L 5.734375 0 C 4.367188 0 3.398438 -0.28125 2.828125 -0.84375 C 2.265625 -1.414062 1.984375 -2.382812 1.984375 -3.75 L 1.984375 -8.328125 L 0.265625 -8.328125 L 0.265625 -10.796875 L 1.984375 -10.796875 L 1.984375 -13.875 Z M 5.421875 -13.875 "
+ id="path1878" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-14">
+ <path
+ style="stroke:none;"
+ d="M 12.4375 -5.421875 L 12.4375 -4.453125 L 4.375 -4.453125 C 4.457031 -3.640625 4.75 -3.03125 5.25 -2.625 C 5.75 -2.21875 6.445312 -2.015625 7.34375 -2.015625 C 8.070312 -2.015625 8.816406 -2.117188 9.578125 -2.328125 C 10.335938 -2.546875 11.117188 -2.875 11.921875 -3.3125 L 11.921875 -0.65625 C 11.109375 -0.34375 10.289062 -0.109375 9.46875 0.046875 C 8.65625 0.203125 7.84375 0.28125 7.03125 0.28125 C 5.070312 0.28125 3.550781 -0.210938 2.46875 -1.203125 C 1.382812 -2.203125 0.84375 -3.597656 0.84375 -5.390625 C 0.84375 -7.148438 1.375 -8.535156 2.4375 -9.546875 C 3.507812 -10.554688 4.976562 -11.0625 6.84375 -11.0625 C 8.539062 -11.0625 9.894531 -10.550781 10.90625 -9.53125 C 11.925781 -8.507812 12.4375 -7.140625 12.4375 -5.421875 Z M 8.890625 -6.578125 C 8.890625 -7.234375 8.695312 -7.757812 8.3125 -8.15625 C 7.9375 -8.5625 7.4375 -8.765625 6.8125 -8.765625 C 6.144531 -8.765625 5.601562 -8.578125 5.1875 -8.203125 C 4.769531 -7.828125 4.507812 -7.285156 4.40625 -6.578125 Z M 8.890625 -6.578125 "
+ id="path1881" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-15">
+ <path
+ style="stroke:none;"
+ d="M 2.09375 -9.515625 L 14.453125 -9.515625 L 14.453125 -7.25 L 2.09375 -7.25 Z M 2.09375 -5.125 L 14.453125 -5.125 L 14.453125 -2.84375 L 2.09375 -2.84375 Z M 2.09375 -5.125 "
+ id="path1884" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-16">
+ <path
+ style="stroke:none;"
+ d="M 1.65625 -10.796875 L 5.109375 -10.796875 L 5.109375 0 L 1.65625 0 Z M 1.65625 -15 L 5.109375 -15 L 5.109375 -12.1875 L 1.65625 -12.1875 Z M 1.65625 -15 "
+ id="path1887" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-17">
+ <path
+ style="stroke:none;"
+ d="M 1.578125 2.609375 C 2.398438 1.078125 3.015625 -0.414062 3.421875 -1.875 C 3.835938 -3.332031 4.046875 -4.773438 4.046875 -6.203125 C 4.046875 -7.617188 3.835938 -9.054688 3.421875 -10.515625 C 3.015625 -11.972656 2.398438 -13.460938 1.578125 -14.984375 L 4.453125 -14.984375 C 5.421875 -13.410156 6.140625 -11.898438 6.609375 -10.453125 C 7.085938 -9.015625 7.328125 -7.59375 7.328125 -6.1875 C 7.328125 -4.769531 7.09375 -3.347656 6.625 -1.921875 C 6.15625 -0.492188 5.429688 1.015625 4.453125 2.609375 Z M 1.578125 2.609375 "
+ id="path1890" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-18">
+ <path
+ style="stroke:none;"
+ d="M 10.09375 -10.46875 L 10.09375 -7.84375 C 9.351562 -8.144531 8.640625 -8.375 7.953125 -8.53125 C 7.265625 -8.6875 6.617188 -8.765625 6.015625 -8.765625 C 5.359375 -8.765625 4.867188 -8.679688 4.546875 -8.515625 C 4.222656 -8.359375 4.0625 -8.109375 4.0625 -7.765625 C 4.0625 -7.484375 4.179688 -7.269531 4.421875 -7.125 C 4.671875 -6.976562 5.109375 -6.867188 5.734375 -6.796875 L 6.328125 -6.71875 C 8.097656 -6.488281 9.285156 -6.113281 9.890625 -5.59375 C 10.503906 -5.082031 10.8125 -4.28125 10.8125 -3.1875 C 10.8125 -2.03125 10.390625 -1.160156 9.546875 -0.578125 C 8.703125 -0.00390625 7.4375 0.28125 5.75 0.28125 C 5.03125 0.28125 4.289062 0.222656 3.53125 0.109375 C 2.769531 -0.00390625 1.988281 -0.171875 1.1875 -0.390625 L 1.1875 -3.015625 C 1.875 -2.679688 2.578125 -2.429688 3.296875 -2.265625 C 4.023438 -2.097656 4.757812 -2.015625 5.5 -2.015625 C 6.175781 -2.015625 6.6875 -2.109375 7.03125 -2.296875 C 7.375 -2.484375 7.546875 -2.757812 7.546875 -3.125 C 7.546875 -3.4375 7.425781 -3.664062 7.1875 -3.8125 C 6.957031 -3.96875 6.488281 -4.085938 5.78125 -4.171875 L 5.171875 -4.25 C 3.640625 -4.4375 2.5625 -4.789062 1.9375 -5.3125 C 1.320312 -5.832031 1.015625 -6.625 1.015625 -7.6875 C 1.015625 -8.832031 1.40625 -9.679688 2.1875 -10.234375 C 2.976562 -10.785156 4.1875 -11.0625 5.8125 -11.0625 C 6.445312 -11.0625 7.113281 -11.007812 7.8125 -10.90625 C 8.507812 -10.8125 9.269531 -10.664062 10.09375 -10.46875 Z M 10.09375 -10.46875 "
+ id="path1893" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-19">
+ <path
+ style="stroke:none;"
+ d="M 8.40625 -14.390625 L 8.40625 -9.046875 L 6.125 -9.046875 L 6.125 -14.390625 Z M 4.171875 -14.390625 L 4.171875 -9.046875 L 1.875 -9.046875 L 1.875 -14.390625 Z M 4.171875 -14.390625 "
+ id="path1896" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-20">
+ <path
+ style="stroke:none;"
+ d="M 11.828125 -13.9375 L 11.828125 -10.890625 C 11.035156 -11.242188 10.265625 -11.507812 9.515625 -11.6875 C 8.765625 -11.875 8.054688 -11.96875 7.390625 -11.96875 C 6.503906 -11.96875 5.847656 -11.84375 5.421875 -11.59375 C 4.992188 -11.351562 4.78125 -10.976562 4.78125 -10.46875 C 4.78125 -10.082031 4.921875 -9.78125 5.203125 -9.5625 C 5.492188 -9.34375 6.015625 -9.15625 6.765625 -9 L 8.34375 -8.6875 C 9.945312 -8.363281 11.085938 -7.875 11.765625 -7.21875 C 12.441406 -6.5625 12.78125 -5.628906 12.78125 -4.421875 C 12.78125 -2.835938 12.304688 -1.65625 11.359375 -0.875 C 10.421875 -0.101562 8.984375 0.28125 7.046875 0.28125 C 6.140625 0.28125 5.222656 0.191406 4.296875 0.015625 C 3.378906 -0.148438 2.460938 -0.40625 1.546875 -0.75 L 1.546875 -3.890625 C 2.460938 -3.398438 3.347656 -3.03125 4.203125 -2.78125 C 5.066406 -2.53125 5.894531 -2.40625 6.6875 -2.40625 C 7.5 -2.40625 8.117188 -2.539062 8.546875 -2.8125 C 8.984375 -3.082031 9.203125 -3.46875 9.203125 -3.96875 C 9.203125 -4.414062 9.054688 -4.757812 8.765625 -5 C 8.472656 -5.25 7.890625 -5.472656 7.015625 -5.671875 L 5.578125 -5.984375 C 4.128906 -6.296875 3.070312 -6.789062 2.40625 -7.46875 C 1.75 -8.144531 1.421875 -9.050781 1.421875 -10.1875 C 1.421875 -11.625 1.878906 -12.726562 2.796875 -13.5 C 3.722656 -14.269531 5.054688 -14.65625 6.796875 -14.65625 C 7.585938 -14.65625 8.398438 -14.59375 9.234375 -14.46875 C 10.078125 -14.351562 10.941406 -14.175781 11.828125 -13.9375 Z M 11.828125 -13.9375 "
+ id="path1899" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-21">
+ <path
+ style="stroke:none;"
+ d="M 9.078125 -7.21875 C 9.078125 -9.007812 8.910156 -10.273438 8.578125 -11.015625 C 8.242188 -11.753906 7.675781 -12.125 6.875 -12.125 C 6.082031 -12.125 5.515625 -11.753906 5.171875 -11.015625 C 4.828125 -10.273438 4.65625 -9.007812 4.65625 -7.21875 C 4.65625 -5.394531 4.828125 -4.109375 5.171875 -3.359375 C 5.515625 -2.617188 6.082031 -2.25 6.875 -2.25 C 7.664062 -2.25 8.226562 -2.617188 8.5625 -3.359375 C 8.90625 -4.109375 9.078125 -5.394531 9.078125 -7.21875 Z M 12.796875 -7.1875 C 12.796875 -4.800781 12.28125 -2.957031 11.25 -1.65625 C 10.226562 -0.363281 8.769531 0.28125 6.875 0.28125 C 4.976562 0.28125 3.515625 -0.363281 2.484375 -1.65625 C 1.453125 -2.957031 0.9375 -4.800781 0.9375 -7.1875 C 0.9375 -9.570312 1.453125 -11.410156 2.484375 -12.703125 C 3.515625 -14.003906 4.976562 -14.65625 6.875 -14.65625 C 8.769531 -14.65625 10.226562 -14.003906 11.25 -12.703125 C 12.28125 -11.410156 12.796875 -9.570312 12.796875 -7.1875 Z M 12.796875 -7.1875 "
+ id="path1902" />
+ </symbol>
+ <symbol
+ overflow="visible"
+ id="glyph1-22">
+ <path
+ style="stroke:none;"
+ d="M 15.578125 -6.859375 L 15.578125 -5.515625 L 11.796875 -1.71875 L 10.390625 -3.125 L 12.3125 -5.03125 L 1.125 -5.03125 L 1.125 -7.34375 L 12.3125 -7.34375 L 10.390625 -9.265625 L 11.796875 -10.65625 Z M 15.578125 -6.859375 "
+ id="path1905" />
+ </symbol>
+ </g>
+ </defs>
+ <g
+ id="surface392452">
+ <rect
+ x="0"
+ y="0"
+ width="908"
+ height="444"
+ style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"
+ id="rect1912" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(41.176471%,77.254903%,47.058824%);fill-opacity:0.592157;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 37.690003 18.712741 L 47.059925 18.712741 L 47.059925 20.612741 L 37.690003 20.612741 Z M 37.690003 18.712741 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1914" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g1968">
+ <use
+ xlink:href="#glyph0-1"
+ x="273.335938"
+ y="24.88878"
+ id="use1916" />
+ <use
+ xlink:href="#glyph0-2"
+ x="282.224826"
+ y="24.88878"
+ id="use1918" />
+ <use
+ xlink:href="#glyph0-3"
+ x="290.002604"
+ y="24.88878"
+ id="use1920" />
+ <use
+ xlink:href="#glyph0-4"
+ x="296.669271"
+ y="24.88878"
+ id="use1922" />
+ <use
+ xlink:href="#glyph0-5"
+ x="301.669271"
+ y="24.88878"
+ id="use1924" />
+ <use
+ xlink:href="#glyph0-6"
+ x="305.280382"
+ y="24.88878"
+ id="use1926" />
+ <use
+ xlink:href="#glyph0-7"
+ x="313.335938"
+ y="24.88878"
+ id="use1928" />
+ <use
+ xlink:href="#glyph0-8"
+ x="321.391493"
+ y="24.88878"
+ id="use1930" />
+ <use
+ xlink:href="#glyph0-9"
+ x="325.280382"
+ y="24.88878"
+ id="use1932" />
+ <use
+ xlink:href="#glyph0-10"
+ x="337.780382"
+ y="24.88878"
+ id="use1934" />
+ <use
+ xlink:href="#glyph0-11"
+ x="345.835938"
+ y="24.88878"
+ id="use1936" />
+ <use
+ xlink:href="#glyph0-12"
+ x="349.447049"
+ y="24.88878"
+ id="use1938" />
+ <use
+ xlink:href="#glyph0-8"
+ x="354.447049"
+ y="24.88878"
+ id="use1940" />
+ <use
+ xlink:href="#glyph0-6"
+ x="358.335938"
+ y="24.88878"
+ id="use1942" />
+ <use
+ xlink:href="#glyph0-4"
+ x="366.391493"
+ y="24.88878"
+ id="use1944" />
+ <use
+ xlink:href="#glyph0-13"
+ x="371.391493"
+ y="24.88878"
+ id="use1946" />
+ <use
+ xlink:href="#glyph0-14"
+ x="379.447049"
+ y="24.88878"
+ id="use1948" />
+ <use
+ xlink:href="#glyph0-15"
+ x="387.502604"
+ y="24.88878"
+ id="use1950" />
+ <use
+ xlink:href="#glyph0-16"
+ x="391.669271"
+ y="24.88878"
+ id="use1952" />
+ <use
+ xlink:href="#glyph0-17"
+ x="395.835938"
+ y="24.88878"
+ id="use1954" />
+ <use
+ xlink:href="#glyph0-4"
+ x="403.891493"
+ y="24.88878"
+ id="use1956" />
+ <use
+ xlink:href="#glyph0-18"
+ x="408.891493"
+ y="24.88878"
+ id="use1958" />
+ <use
+ xlink:href="#glyph0-5"
+ x="414.169271"
+ y="24.88878"
+ id="use1960" />
+ <use
+ xlink:href="#glyph0-6"
+ x="417.780382"
+ y="24.88878"
+ id="use1962" />
+ <use
+ xlink:href="#glyph0-7"
+ x="425.835938"
+ y="24.88878"
+ id="use1964" />
+ <use
+ xlink:href="#glyph0-19"
+ x="433.891493"
+ y="24.88878"
+ id="use1966" />
+ </g>
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.2,0.2;stroke-miterlimit:10;"
+ d="M 42.374964 20.662937 L 42.374964 21.218991 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1970" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 42.124964 21.218991 L 42.374964 21.718991 L 42.624964 21.218991 Z M 42.124964 21.218991 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1972" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 32.07594 22.801609 L 36.211292 22.813327 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1974" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 36.586292 22.814499 L 36.085706 23.063132 L 36.211292 22.813327 L 36.087073 22.563132 Z M 36.586292 22.814499 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1976" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 56.489612 22.817429 L 48.53844 22.825046 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1978" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 48.16344 22.825437 L 48.66305 22.574851 L 48.53844 22.825046 L 48.663636 23.074851 Z M 48.16344 22.825437 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1980" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 41.592932 23.830124 L 40.322034 25.453757 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1982" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 40.090979 25.748874 L 40.202307 25.201218 L 40.322034 25.453757 L 40.596057 25.509421 Z M 40.090979 25.748874 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1984" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 43.056604 23.830124 L 44.151331 25.434812 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1986" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 44.362659 25.744577 L 43.874378 25.472507 L 44.151331 25.434812 L 44.287464 25.190671 Z M 44.362659 25.744577 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1988" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(61.176473%,63.921571%,97.647059%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 29.543714 22.614499 L 32.026331 21.881296 L 32.026331 23.714499 L 29.543714 23.714499 Z M 29.543714 22.614499 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path1990" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2002">
+ <use
+ xlink:href="#glyph0-5"
+ x="107.921875"
+ y="94.923937"
+ id="use1992" />
+ <use
+ xlink:href="#glyph0-6"
+ x="111.532986"
+ y="94.923937"
+ id="use1994" />
+ <use
+ xlink:href="#glyph0-4"
+ x="119.588542"
+ y="94.923937"
+ id="use1996" />
+ <use
+ xlink:href="#glyph0-13"
+ x="124.588542"
+ y="94.923937"
+ id="use1998" />
+ <use
+ xlink:href="#glyph0-14"
+ x="132.644097"
+ y="94.923937"
+ id="use2000" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,70.19608%,14.509805%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 56.539612 22.616257 L 58.539612 21.816257 L 58.539612 23.816257 L 56.539612 23.816257 Z M 56.539612 22.616257 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2004" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2012">
+ <use
+ xlink:href="#glyph0-17"
+ x="647.332031"
+ y="95.959093"
+ id="use2006" />
+ <use
+ xlink:href="#glyph0-13"
+ x="655.387587"
+ y="95.959093"
+ id="use2008" />
+ <use
+ xlink:href="#glyph0-20"
+ x="663.443142"
+ y="95.959093"
+ id="use2010" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(41.176471%,77.254903%,47.058824%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 36.747425 21.881101 L 48.002503 21.881101 L 48.002503 23.781101 L 36.747425 23.781101 Z M 36.747425 21.881101 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2014" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2076">
+ <use
+ xlink:href="#glyph0-2"
+ x="260.152344"
+ y="88.252062"
+ id="use2016" />
+ <use
+ xlink:href="#glyph0-21"
+ x="267.930122"
+ y="88.252062"
+ id="use2018" />
+ <use
+ xlink:href="#glyph0-22"
+ x="275.985677"
+ y="88.252062"
+ id="use2020" />
+ <use
+ xlink:href="#glyph0-23"
+ x="279.596788"
+ y="88.252062"
+ id="use2022" />
+ <use
+ xlink:href="#glyph0-3"
+ x="287.652344"
+ y="88.252062"
+ id="use2024" />
+ <use
+ xlink:href="#glyph0-4"
+ x="294.31901"
+ y="88.252062"
+ id="use2026" />
+ <use
+ xlink:href="#glyph0-24"
+ x="299.31901"
+ y="88.252062"
+ id="use2028" />
+ <use
+ xlink:href="#glyph0-21"
+ x="305.707899"
+ y="88.252062"
+ id="use2030" />
+ <use
+ xlink:href="#glyph0-25"
+ x="313.763455"
+ y="88.252062"
+ id="use2032" />
+ <use
+ xlink:href="#glyph0-3"
+ x="321.541233"
+ y="88.252062"
+ id="use2034" />
+ <use
+ xlink:href="#glyph0-26"
+ x="328.207899"
+ y="88.252062"
+ id="use2036" />
+ <use
+ xlink:href="#glyph0-18"
+ x="335.152344"
+ y="88.252062"
+ id="use2038" />
+ <use
+ xlink:href="#glyph0-5"
+ x="340.430122"
+ y="88.252062"
+ id="use2040" />
+ <use
+ xlink:href="#glyph0-10"
+ x="344.041233"
+ y="88.252062"
+ id="use2042" />
+ <use
+ xlink:href="#glyph0-4"
+ x="352.096788"
+ y="88.252062"
+ id="use2044" />
+ <use
+ xlink:href="#glyph0-27"
+ x="357.096788"
+ y="88.252062"
+ id="use2046" />
+ <use
+ xlink:href="#glyph0-18"
+ x="364.874566"
+ y="88.252062"
+ id="use2048" />
+ <use
+ xlink:href="#glyph0-3"
+ x="370.152344"
+ y="88.252062"
+ id="use2050" />
+ <use
+ xlink:href="#glyph0-28"
+ x="376.81901"
+ y="88.252062"
+ id="use2052" />
+ <use
+ xlink:href="#glyph0-5"
+ x="381.81901"
+ y="88.252062"
+ id="use2054" />
+ <use
+ xlink:href="#glyph0-6"
+ x="385.430122"
+ y="88.252062"
+ id="use2056" />
+ <use
+ xlink:href="#glyph0-4"
+ x="393.485677"
+ y="88.252062"
+ id="use2058" />
+ <use
+ xlink:href="#glyph0-13"
+ x="398.485677"
+ y="88.252062"
+ id="use2060" />
+ <use
+ xlink:href="#glyph0-14"
+ x="406.541233"
+ y="88.252062"
+ id="use2062" />
+ <use
+ xlink:href="#glyph0-15"
+ x="414.596788"
+ y="88.252062"
+ id="use2064" />
+ <use
+ xlink:href="#glyph0-16"
+ x="418.763455"
+ y="88.252062"
+ id="use2066" />
+ <use
+ xlink:href="#glyph0-17"
+ x="422.930122"
+ y="88.252062"
+ id="use2068" />
+ <use
+ xlink:href="#glyph0-13"
+ x="430.985677"
+ y="88.252062"
+ id="use2070" />
+ <use
+ xlink:href="#glyph0-20"
+ x="439.041233"
+ y="88.252062"
+ id="use2072" />
+ <use
+ xlink:href="#glyph0-29"
+ x="447.096788"
+ y="88.252062"
+ id="use2074" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 37.777112 25.887156 L 41.350745 25.887156 L 40.622815 27.887156 L 37.049182 27.887156 Z M 37.777112 25.887156 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2078" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2090">
+ <use
+ xlink:href="#glyph0-5"
+ x="276.222656"
+ y="169.377062"
+ id="use2080" />
+ <use
+ xlink:href="#glyph0-6"
+ x="279.833767"
+ y="169.377062"
+ id="use2082" />
+ <use
+ xlink:href="#glyph0-4"
+ x="287.889323"
+ y="169.377062"
+ id="use2084" />
+ <use
+ xlink:href="#glyph0-13"
+ x="292.889323"
+ y="169.377062"
+ id="use2086" />
+ <use
+ xlink:href="#glyph0-14"
+ x="300.944878"
+ y="169.377062"
+ id="use2088" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 44.26344 25.887156 L 46.748792 25.887156 L 46.020862 27.887156 L 43.535511 27.887156 Z M 44.26344 25.887156 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2092" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2098">
+ <use
+ xlink:href="#glyph0-17"
+ x="403.40625"
+ y="169.377062"
+ id="use2094" />
+ <use
+ xlink:href="#glyph0-30"
+ x="411.461806"
+ y="169.377062"
+ id="use2096" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 57.539612 25.68364 L 59.946643 26.887156 L 57.539612 28.090671 L 55.132776 26.887156 Z M 57.539612 25.68364 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2100" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2106">
+ <use
+ xlink:href="#glyph0-31"
+ x="651.492188"
+ y="169.377062"
+ id="use2102" />
+ <use
+ xlink:href="#glyph0-32"
+ x="656.492188"
+ y="169.377062"
+ id="use2104" />
+ </g>
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 46.416761 26.887156 L 54.596057 26.887156 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2108" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 54.971057 26.887156 L 54.471057 27.137156 L 54.596057 26.887156 L 54.471057 26.637156 Z M 54.971057 26.887156 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2110" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 57.539612 23.866257 L 57.539612 25.146921 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2112" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 57.539612 25.521921 L 57.289612 25.021921 L 57.539612 25.146921 L 57.789612 25.021921 Z M 57.539612 25.521921 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2114" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(41.176471%,77.254903%,47.058824%);fill-opacity:0.592157;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 60.273401 28.318015 L 69.890979 28.318015 L 69.890979 30.218015 L 60.273401 30.218015 Z M 60.273401 28.318015 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2116" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2172">
+ <use
+ xlink:href="#glyph0-1"
+ x="724.980469"
+ y="216.994249"
+ id="use2118" />
+ <use
+ xlink:href="#glyph0-2"
+ x="733.869358"
+ y="216.994249"
+ id="use2120" />
+ <use
+ xlink:href="#glyph0-3"
+ x="741.647135"
+ y="216.994249"
+ id="use2122" />
+ <use
+ xlink:href="#glyph0-4"
+ x="748.313802"
+ y="216.994249"
+ id="use2124" />
+ <use
+ xlink:href="#glyph0-5"
+ x="753.313802"
+ y="216.994249"
+ id="use2126" />
+ <use
+ xlink:href="#glyph0-6"
+ x="756.924913"
+ y="216.994249"
+ id="use2128" />
+ <use
+ xlink:href="#glyph0-7"
+ x="764.980469"
+ y="216.994249"
+ id="use2130" />
+ <use
+ xlink:href="#glyph0-8"
+ x="773.036024"
+ y="216.994249"
+ id="use2132" />
+ <use
+ xlink:href="#glyph0-9"
+ x="776.924913"
+ y="216.994249"
+ id="use2134" />
+ <use
+ xlink:href="#glyph0-10"
+ x="789.424913"
+ y="216.994249"
+ id="use2136" />
+ <use
+ xlink:href="#glyph0-11"
+ x="797.480469"
+ y="216.994249"
+ id="use2138" />
+ <use
+ xlink:href="#glyph0-12"
+ x="801.09158"
+ y="216.994249"
+ id="use2140" />
+ <use
+ xlink:href="#glyph0-17"
+ x="806.09158"
+ y="216.994249"
+ id="use2142" />
+ <use
+ xlink:href="#glyph0-4"
+ x="814.147135"
+ y="216.994249"
+ id="use2144" />
+ <use
+ xlink:href="#glyph0-18"
+ x="819.147135"
+ y="216.994249"
+ id="use2146" />
+ <use
+ xlink:href="#glyph0-5"
+ x="824.424913"
+ y="216.994249"
+ id="use2148" />
+ <use
+ xlink:href="#glyph0-6"
+ x="828.036024"
+ y="216.994249"
+ id="use2150" />
+ <use
+ xlink:href="#glyph0-7"
+ x="836.09158"
+ y="216.994249"
+ id="use2152" />
+ <use
+ xlink:href="#glyph0-15"
+ x="844.147135"
+ y="216.994249"
+ id="use2154" />
+ <use
+ xlink:href="#glyph0-16"
+ x="848.313802"
+ y="216.994249"
+ id="use2156" />
+ <use
+ xlink:href="#glyph0-17"
+ x="852.480469"
+ y="216.994249"
+ id="use2158" />
+ <use
+ xlink:href="#glyph0-4"
+ x="860.536024"
+ y="216.994249"
+ id="use2160" />
+ <use
+ xlink:href="#glyph0-18"
+ x="865.536024"
+ y="216.994249"
+ id="use2162" />
+ <use
+ xlink:href="#glyph0-5"
+ x="870.813802"
+ y="216.994249"
+ id="use2164" />
+ <use
+ xlink:href="#glyph0-6"
+ x="874.424913"
+ y="216.994249"
+ id="use2166" />
+ <use
+ xlink:href="#glyph0-7"
+ x="882.480469"
+ y="216.994249"
+ id="use2168" />
+ <use
+ xlink:href="#glyph0-19"
+ x="890.536024"
+ y="216.994249"
+ id="use2170" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(41.176471%,77.254903%,47.058824%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 51.584729 31.317234 L 63.49469 31.317234 L 63.49469 33.217234 L 51.584729 33.217234 Z M 51.584729 31.317234 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2174" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2234">
+ <use
+ xlink:href="#glyph0-7"
+ x="565.378906"
+ y="276.978624"
+ id="use2176" />
+ <use
+ xlink:href="#glyph0-25"
+ x="573.434462"
+ y="276.978624"
+ id="use2178" />
+ <use
+ xlink:href="#glyph0-4"
+ x="581.21224"
+ y="276.978624"
+ id="use2180" />
+ <use
+ xlink:href="#glyph0-24"
+ x="586.21224"
+ y="276.978624"
+ id="use2182" />
+ <use
+ xlink:href="#glyph0-4"
+ x="592.601128"
+ y="276.978624"
+ id="use2184" />
+ <use
+ xlink:href="#glyph0-18"
+ x="597.601128"
+ y="276.978624"
+ id="use2186" />
+ <use
+ xlink:href="#glyph0-2"
+ x="602.878906"
+ y="276.978624"
+ id="use2188" />
+ <use
+ xlink:href="#glyph0-6"
+ x="610.656684"
+ y="276.978624"
+ id="use2190" />
+ <use
+ xlink:href="#glyph0-3"
+ x="618.71224"
+ y="276.978624"
+ id="use2192" />
+ <use
+ xlink:href="#glyph0-33"
+ x="625.378906"
+ y="276.978624"
+ id="use2194" />
+ <use
+ xlink:href="#glyph0-25"
+ x="629.823351"
+ y="276.978624"
+ id="use2196" />
+ <use
+ xlink:href="#glyph0-18"
+ x="637.601128"
+ y="276.978624"
+ id="use2198" />
+ <use
+ xlink:href="#glyph0-33"
+ x="642.878906"
+ y="276.978624"
+ id="use2200" />
+ <use
+ xlink:href="#glyph0-23"
+ x="647.323351"
+ y="276.978624"
+ id="use2202" />
+ <use
+ xlink:href="#glyph0-6"
+ x="655.378906"
+ y="276.978624"
+ id="use2204" />
+ <use
+ xlink:href="#glyph0-26"
+ x="663.434462"
+ y="276.978624"
+ id="use2206" />
+ <use
+ xlink:href="#glyph0-4"
+ x="670.378906"
+ y="276.978624"
+ id="use2208" />
+ <use
+ xlink:href="#glyph0-5"
+ x="675.378906"
+ y="276.978624"
+ id="use2210" />
+ <use
+ xlink:href="#glyph0-27"
+ x="678.990017"
+ y="276.978624"
+ id="use2212" />
+ <use
+ xlink:href="#glyph0-6"
+ x="686.767795"
+ y="276.978624"
+ id="use2214" />
+ <use
+ xlink:href="#glyph0-28"
+ x="694.823351"
+ y="276.978624"
+ id="use2216" />
+ <use
+ xlink:href="#glyph0-17"
+ x="699.823351"
+ y="276.978624"
+ id="use2218" />
+ <use
+ xlink:href="#glyph0-30"
+ x="707.878906"
+ y="276.978624"
+ id="use2220" />
+ <use
+ xlink:href="#glyph0-15"
+ x="715.934462"
+ y="276.978624"
+ id="use2222" />
+ <use
+ xlink:href="#glyph0-16"
+ x="720.101128"
+ y="276.978624"
+ id="use2224" />
+ <use
+ xlink:href="#glyph0-17"
+ x="724.267795"
+ y="276.978624"
+ id="use2226" />
+ <use
+ xlink:href="#glyph0-13"
+ x="732.323351"
+ y="276.978624"
+ id="use2228" />
+ <use
+ xlink:href="#glyph0-20"
+ x="740.378906"
+ y="276.978624"
+ id="use2230" />
+ <use
+ xlink:href="#glyph0-29"
+ x="748.434462"
+ y="276.978624"
+ id="use2232" />
+ </g>
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.2,0.2;stroke-miterlimit:10;"
+ d="M 62.568518 30.267624 L 60.621643 31.041648 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2236" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 60.529456 30.809421 L 60.15719 31.226413 L 60.714026 31.27407 Z M 60.529456 30.809421 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2238" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 57.539612 28.140671 L 57.539612 30.780906 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2240" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 57.539612 31.155906 L 57.289612 30.655906 L 57.539612 30.780906 L 57.789612 30.655906 Z M 57.539612 31.155906 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2242" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(41.176471%,77.254903%,47.058824%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 36.420081 31.317234 L 48.330042 31.317234 L 48.330042 33.217234 L 36.420081 33.217234 Z M 36.420081 31.317234 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2244" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2308">
+ <use
+ xlink:href="#glyph0-7"
+ x="257.789062"
+ y="276.978624"
+ id="use2246" />
+ <use
+ xlink:href="#glyph0-25"
+ x="265.844618"
+ y="276.978624"
+ id="use2248" />
+ <use
+ xlink:href="#glyph0-4"
+ x="273.622396"
+ y="276.978624"
+ id="use2250" />
+ <use
+ xlink:href="#glyph0-24"
+ x="278.622396"
+ y="276.978624"
+ id="use2252" />
+ <use
+ xlink:href="#glyph0-4"
+ x="285.011285"
+ y="276.978624"
+ id="use2254" />
+ <use
+ xlink:href="#glyph0-18"
+ x="290.011285"
+ y="276.978624"
+ id="use2256" />
+ <use
+ xlink:href="#glyph0-2"
+ x="295.289062"
+ y="276.978624"
+ id="use2258" />
+ <use
+ xlink:href="#glyph0-6"
+ x="303.06684"
+ y="276.978624"
+ id="use2260" />
+ <use
+ xlink:href="#glyph0-3"
+ x="311.122396"
+ y="276.978624"
+ id="use2262" />
+ <use
+ xlink:href="#glyph0-33"
+ x="317.789062"
+ y="276.978624"
+ id="use2264" />
+ <use
+ xlink:href="#glyph0-25"
+ x="322.233507"
+ y="276.978624"
+ id="use2266" />
+ <use
+ xlink:href="#glyph0-18"
+ x="330.011285"
+ y="276.978624"
+ id="use2268" />
+ <use
+ xlink:href="#glyph0-33"
+ x="335.289062"
+ y="276.978624"
+ id="use2270" />
+ <use
+ xlink:href="#glyph0-23"
+ x="339.733507"
+ y="276.978624"
+ id="use2272" />
+ <use
+ xlink:href="#glyph0-6"
+ x="347.789062"
+ y="276.978624"
+ id="use2274" />
+ <use
+ xlink:href="#glyph0-26"
+ x="355.844618"
+ y="276.978624"
+ id="use2276" />
+ <use
+ xlink:href="#glyph0-4"
+ x="362.789062"
+ y="276.978624"
+ id="use2278" />
+ <use
+ xlink:href="#glyph0-5"
+ x="367.789062"
+ y="276.978624"
+ id="use2280" />
+ <use
+ xlink:href="#glyph0-27"
+ x="371.400174"
+ y="276.978624"
+ id="use2282" />
+ <use
+ xlink:href="#glyph0-6"
+ x="379.177951"
+ y="276.978624"
+ id="use2284" />
+ <use
+ xlink:href="#glyph0-28"
+ x="387.233507"
+ y="276.978624"
+ id="use2286" />
+ <use
+ xlink:href="#glyph0-5"
+ x="392.233507"
+ y="276.978624"
+ id="use2288" />
+ <use
+ xlink:href="#glyph0-6"
+ x="395.844618"
+ y="276.978624"
+ id="use2290" />
+ <use
+ xlink:href="#glyph0-4"
+ x="403.900174"
+ y="276.978624"
+ id="use2292" />
+ <use
+ xlink:href="#glyph0-13"
+ x="408.900174"
+ y="276.978624"
+ id="use2294" />
+ <use
+ xlink:href="#glyph0-14"
+ x="416.955729"
+ y="276.978624"
+ id="use2296" />
+ <use
+ xlink:href="#glyph0-15"
+ x="425.011285"
+ y="276.978624"
+ id="use2298" />
+ <use
+ xlink:href="#glyph0-16"
+ x="429.177951"
+ y="276.978624"
+ id="use2300" />
+ <use
+ xlink:href="#glyph0-17"
+ x="433.344618"
+ y="276.978624"
+ id="use2302" />
+ <use
+ xlink:href="#glyph0-30"
+ x="441.400174"
+ y="276.978624"
+ id="use2304" />
+ <use
+ xlink:href="#glyph0-29"
+ x="449.455729"
+ y="276.978624"
+ id="use2306" />
+ </g>
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 39.807776 27.917038 L 41.537659 30.848484 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2310" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 41.728284 31.171335 L 41.258948 30.86782 L 41.537659 30.848484 L 41.689417 30.613718 Z M 41.728284 31.171335 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2312" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 44.612464 27.917038 L 43.111682 30.834812 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2314" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 42.940198 31.16821 L 42.946643 30.609226 L 43.111682 30.834812 L 43.391175 30.837937 Z M 42.940198 31.16821 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2316" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.2,0.2;stroke-miterlimit:10;"
+ d="M 42.374964 23.831491 L 42.374964 30.654929 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2318" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 42.124964 30.654929 L 42.374964 31.154929 L 42.624964 30.654929 Z M 42.124964 30.654929 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2320" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 30.784925 25.633054 L 33.293128 26.887156 L 30.784925 28.141257 L 28.276917 26.887156 Z M 30.784925 25.633054 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2322" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2330">
+ <use
+ xlink:href="#glyph0-31"
+ x="114.308594"
+ y="169.377062"
+ id="use2324" />
+ <use
+ xlink:href="#glyph0-32"
+ x="119.308594"
+ y="169.377062"
+ id="use2326" />
+ <use
+ xlink:href="#glyph0-16"
+ x="130.141927"
+ y="169.377062"
+ id="use2328" />
+ </g>
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 30.784925 23.76489 L 30.784925 25.096335 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2332" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 30.784925 25.471335 L 30.534925 24.971335 L 30.784925 25.096335 L 31.034925 24.971335 Z M 30.784925 25.471335 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2334" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 37.381214 26.887156 L 33.830042 26.887156 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2336" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 33.455042 26.887156 L 33.955042 26.637156 L 33.830042 26.887156 L 33.955042 27.137156 Z M 33.455042 26.887156 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2338" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(61.176473%,63.921571%,97.647059%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 28.660706 35.381882 L 32.909339 34.542038 L 32.909339 36.642038 L 28.660706 36.642038 Z M 28.660706 35.381882 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2340" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2360">
+ <use
+ xlink:href="#glyph0-5"
+ x="94.875"
+ y="351.869249"
+ id="use2342" />
+ <use
+ xlink:href="#glyph0-6"
+ x="98.486111"
+ y="351.869249"
+ id="use2344" />
+ <use
+ xlink:href="#glyph0-4"
+ x="106.541667"
+ y="351.869249"
+ id="use2346" />
+ <use
+ xlink:href="#glyph0-13"
+ x="111.541667"
+ y="351.869249"
+ id="use2348" />
+ <use
+ xlink:href="#glyph0-14"
+ x="119.597222"
+ y="351.869249"
+ id="use2350" />
+ <use
+ xlink:href="#glyph0-28"
+ x="127.652778"
+ y="351.869249"
+ id="use2352" />
+ <use
+ xlink:href="#glyph0-14"
+ x="132.652778"
+ y="351.869249"
+ id="use2354" />
+ <use
+ xlink:href="#glyph0-13"
+ x="140.708333"
+ y="351.869249"
+ id="use2356" />
+ <use
+ xlink:href="#glyph0-29"
+ x="148.763889"
+ y="351.869249"
+ id="use2358" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 37.764612 35.581101 C 37.764612 36.05239 37.000354 36.434421 36.057776 36.434421 C 35.115198 36.434421 34.351136 36.05239 34.351136 35.581101 C 34.351136 35.109812 35.115198 34.727781 36.057776 34.727781 C 37.000354 34.727781 37.764612 35.109812 37.764612 35.581101 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2362" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.2,0.2;stroke-miterlimit:10;"
+ d="M 40.467932 33.267624 L 37.821448 34.655906 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2364" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 37.705237 34.434616 L 37.378675 34.888132 L 37.937659 34.87739 Z M 37.705237 34.434616 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2366" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 32.959534 35.587546 L 33.814417 35.585788 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2368" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 34.189417 35.585007 L 33.690003 35.835984 L 33.814417 35.585788 L 33.689026 35.335984 Z M 34.189417 35.585007 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2370" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 37.812268 35.570554 L 39.839807 35.558249 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2372" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 40.214807 35.555906 L 39.71637 35.808835 L 39.839807 35.558249 L 39.713245 35.308835 Z M 40.214807 35.555906 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2374" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 40.726721 34.542624 L 44.835315 34.542624 L 44.107386 36.542624 L 39.998792 36.542624 Z M 40.726721 34.542624 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2376" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2394">
+ <use
+ xlink:href="#glyph0-17"
+ x="330.019531"
+ y="342.48253"
+ id="use2378" />
+ <use
+ xlink:href="#glyph0-30"
+ x="338.075087"
+ y="342.48253"
+ id="use2380" />
+ <use
+ xlink:href="#glyph0-28"
+ x="346.130642"
+ y="342.48253"
+ id="use2382" />
+ <use
+ xlink:href="#glyph0-34"
+ x="351.130642"
+ y="342.48253"
+ id="use2384" />
+ <use
+ xlink:href="#glyph0-14"
+ x="356.963976"
+ y="342.48253"
+ id="use2386" />
+ <use
+ xlink:href="#glyph0-13"
+ x="365.019531"
+ y="342.48253"
+ id="use2388" />
+ <use
+ xlink:href="#glyph0-34"
+ x="373.075087"
+ y="342.48253"
+ id="use2390" />
+ <use
+ xlink:href="#glyph0-29"
+ x="378.90842"
+ y="342.48253"
+ id="use2392" />
+ </g>
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 50.59469 35.581101 C 50.59469 36.05239 49.830432 36.434421 48.887854 36.434421 C 47.945276 36.434421 47.181214 36.05239 47.181214 35.581101 C 47.181214 35.109812 47.945276 34.727781 48.887854 34.727781 C 49.830432 34.727781 50.59469 35.109812 50.59469 35.581101 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2396" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.2,0.2;stroke-miterlimit:10;"
+ d="M 54.927893 33.267624 L 50.860901 34.825437 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2398" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 50.771643 34.591843 L 50.394104 35.004148 L 50.950354 35.058835 Z M 50.771643 34.591843 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2400" />
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 44.49762 35.554929 L 46.650745 35.56782 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2402" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 47.025745 35.569968 L 46.524182 35.817038 L 46.650745 35.56782 L 46.527307 35.317038 Z M 47.025745 35.569968 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2404" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%,70.19608%,14.509805%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 54.63805 34.542624 L 61.1693 34.542624 L 60.44137 36.542624 L 53.91012 36.542624 Z M 54.63805 34.542624 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2406" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2426">
+ <use
+ xlink:href="#glyph0-17"
+ x="628.445313"
+ y="342.48253"
+ id="use2408" />
+ <use
+ xlink:href="#glyph0-13"
+ x="636.500868"
+ y="342.48253"
+ id="use2410" />
+ <use
+ xlink:href="#glyph0-20"
+ x="644.556424"
+ y="342.48253"
+ id="use2412" />
+ <use
+ xlink:href="#glyph0-28"
+ x="652.611979"
+ y="342.48253"
+ id="use2414" />
+ <use
+ xlink:href="#glyph0-34"
+ x="657.611979"
+ y="342.48253"
+ id="use2416" />
+ <use
+ xlink:href="#glyph0-14"
+ x="663.445313"
+ y="342.48253"
+ id="use2418" />
+ <use
+ xlink:href="#glyph0-13"
+ x="671.500868"
+ y="342.48253"
+ id="use2420" />
+ <use
+ xlink:href="#glyph0-34"
+ x="679.556424"
+ y="342.48253"
+ id="use2422" />
+ <use
+ xlink:href="#glyph0-29"
+ x="685.389757"
+ y="342.48253"
+ id="use2424" />
+ </g>
+ <path
+ style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 50.577698 35.573484 L 53.753479 35.559421 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2428" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;"
+ d="M 54.128479 35.557663 L 53.629651 35.810007 L 53.753479 35.559421 L 53.627503 35.310007 Z M 54.128479 35.557663 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2430" />
+ <path
+ style="fill-rule:evenodd;fill:rgb(100%, 100%, 100%);fill-opacity:1;stroke-width:0.20012599;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%, 0%, 0%);stroke-opacity:1;stroke-miterlimit:10;stroke-dasharray:none"
+ d="M 24.669495 38.169382 L 66.289417 38.169382 L 66.289417 40.751023 L 24.669495 40.751023 Z M 24.669495 38.169382 "
+ transform="matrix(20,0,0,20,-491.389899,-372.25483)"
+ id="path2432" />
+ <g
+ style="fill:rgb(0%,0%,0%);fill-opacity:1;"
+ id="g2574">
+ <use
+ xlink:href="#glyph1-1"
+ x="13.492188"
+ y="422.957954"
+ id="use2434" />
+ <use
+ xlink:href="#glyph1-2"
+ x="27.658854"
+ y="422.957954"
+ id="use2436" />
+ <use
+ xlink:href="#glyph1-3"
+ x="41.825521"
+ y="422.957954"
+ id="use2438" />
+ <use
+ xlink:href="#glyph1-4"
+ x="49.325521"
+ y="422.957954"
+ id="use2440" />
+ <use
+ xlink:href="#glyph1-5"
+ x="62.658854"
+ y="422.957954"
+ id="use2442" />
+ <use
+ xlink:href="#glyph1-5"
+ x="72.381076"
+ y="422.957954"
+ id="use2444" />
+ <use
+ xlink:href="#glyph1-4"
+ x="82.103299"
+ y="422.957954"
+ id="use2446" />
+ <use
+ xlink:href="#glyph1-6"
+ x="94.881076"
+ y="422.957954"
+ id="use2448" />
+ <use
+ xlink:href="#glyph1-7"
+ x="107.658854"
+ y="422.957954"
+ id="use2450" />
+ <use
+ xlink:href="#glyph1-8"
+ x="116.825521"
+ y="422.957954"
+ id="use2452"
+ style="fill:#9ca1f8;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-9"
+ x="130.436632"
+ y="422.957954"
+ id="use2454"
+ style="fill:#9ca1f8;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-10"
+ x="144.047743"
+ y="422.957954"
+ id="use2456" />
+ <use
+ xlink:href="#glyph1-11"
+ x="151.547743"
+ y="422.957954"
+ id="use2458" />
+ <use
+ xlink:href="#glyph1-12"
+ x="158.492188"
+ y="422.957954"
+ id="use2460" />
+ <use
+ xlink:href="#glyph1-13"
+ x="172.658854"
+ y="422.957954"
+ id="use2462" />
+ <use
+ xlink:href="#glyph1-6"
+ x="182.103299"
+ y="422.957954"
+ id="use2464" />
+ <use
+ xlink:href="#glyph1-2"
+ x="194.881076"
+ y="422.957954"
+ id="use2466" />
+ <use
+ xlink:href="#glyph1-14"
+ x="209.047743"
+ y="422.957954"
+ id="use2468" />
+ <use
+ xlink:href="#glyph1-15"
+ x="222.381076"
+ y="422.957954"
+ id="use2470" />
+ <use
+ xlink:href="#glyph1-16"
+ x="239.047743"
+ y="422.957954"
+ id="use2472"
+ style="fill:#9ca1f8;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-1"
+ x="245.71441"
+ y="422.957954"
+ id="use2474"
+ style="fill:#9ca1f8;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-13"
+ x="259.881076"
+ y="422.957954"
+ id="use2476"
+ style="fill:#9ca1f8;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-9"
+ x="269.325521"
+ y="422.957954"
+ id="use2478"
+ style="fill:#9ca1f8;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-8"
+ x="282.936632"
+ y="422.957954"
+ id="use2480"
+ style="fill:#9ca1f8;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-17"
+ x="296.547743"
+ y="422.957954"
+ id="use2482" />
+ <use
+ xlink:href="#glyph1-3"
+ x="305.71441"
+ y="422.957954"
+ id="use2484" />
+ <use
+ xlink:href="#glyph1-4"
+ x="313.21441"
+ y="422.957954"
+ id="use2486" />
+ <use
+ xlink:href="#glyph1-18"
+ x="326.547743"
+ y="422.957954"
+ id="use2488" />
+ <use
+ xlink:href="#glyph1-13"
+ x="338.21441"
+ y="422.957954"
+ id="use2490" />
+ <use
+ xlink:href="#glyph1-6"
+ x="347.658854"
+ y="422.957954"
+ id="use2492" />
+ <use
+ xlink:href="#glyph1-2"
+ x="360.436632"
+ y="422.957954"
+ id="use2494" />
+ <use
+ xlink:href="#glyph1-14"
+ x="374.603299"
+ y="422.957954"
+ id="use2496" />
+ <use
+ xlink:href="#glyph1-7"
+ x="387.936632"
+ y="422.957954"
+ id="use2498" />
+ <use
+ xlink:href="#glyph1-19"
+ x="397.103299"
+ y="422.957954"
+ id="use2500"
+ style="fill:#000000;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-20"
+ x="407.381076"
+ y="422.957954"
+ id="use2502"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-9"
+ x="421.547743"
+ y="422.957954"
+ id="use2504"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-21"
+ x="435.158854"
+ y="422.957954"
+ id="use2506"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-19"
+ x="448.769965"
+ y="422.957954"
+ id="use2508"
+ style="fill:#000000;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-17"
+ x="459.047743"
+ y="422.957954"
+ id="use2510" />
+ <use
+ xlink:href="#glyph1-11"
+ x="468.21441"
+ y="422.957954"
+ id="use2512" />
+ <use
+ xlink:href="#glyph1-11"
+ x="475.158854"
+ y="422.957954"
+ id="use2514" />
+ <use
+ xlink:href="#glyph1-22"
+ x="482.103299"
+ y="422.957954"
+ id="use2516" />
+ <use
+ xlink:href="#glyph1-11"
+ x="498.769965"
+ y="422.957954"
+ id="use2518" />
+ <use
+ xlink:href="#glyph1-1"
+ x="505.71441"
+ y="422.957954"
+ id="use2520" />
+ <use
+ xlink:href="#glyph1-2"
+ x="519.881076"
+ y="422.957954"
+ id="use2522" />
+ <use
+ xlink:href="#glyph1-3"
+ x="534.047743"
+ y="422.957954"
+ id="use2524" />
+ <use
+ xlink:href="#glyph1-4"
+ x="541.547743"
+ y="422.957954"
+ id="use2526" />
+ <use
+ xlink:href="#glyph1-5"
+ x="554.881076"
+ y="422.957954"
+ id="use2528" />
+ <use
+ xlink:href="#glyph1-5"
+ x="564.603299"
+ y="422.957954"
+ id="use2530" />
+ <use
+ xlink:href="#glyph1-4"
+ x="574.325521"
+ y="422.957954"
+ id="use2532" />
+ <use
+ xlink:href="#glyph1-6"
+ x="587.103299"
+ y="422.957954"
+ id="use2534" />
+ <use
+ xlink:href="#glyph1-7"
+ x="599.881076"
+ y="422.957954"
+ id="use2536" />
+ <use
+ xlink:href="#glyph1-19"
+ x="609.047743"
+ y="422.957954"
+ id="use2538"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-8"
+ x="619.325521"
+ y="422.957954"
+ id="use2540"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-9"
+ x="632.936632"
+ y="422.957954"
+ id="use2542"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-19"
+ x="646.547743"
+ y="422.957954"
+ id="use2544"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-10"
+ x="656.825521"
+ y="422.957954"
+ id="use2546" />
+ <use
+ xlink:href="#glyph1-11"
+ x="664.325521"
+ y="422.957954"
+ id="use2548" />
+ <use
+ xlink:href="#glyph1-12"
+ x="671.269965"
+ y="422.957954"
+ id="use2550" />
+ <use
+ xlink:href="#glyph1-13"
+ x="685.436632"
+ y="422.957954"
+ id="use2552" />
+ <use
+ xlink:href="#glyph1-6"
+ x="694.881076"
+ y="422.957954"
+ id="use2554" />
+ <use
+ xlink:href="#glyph1-2"
+ x="707.658854"
+ y="422.957954"
+ id="use2556" />
+ <use
+ xlink:href="#glyph1-14"
+ x="721.825521"
+ y="422.957954"
+ id="use2558" />
+ <use
+ xlink:href="#glyph1-15"
+ x="735.158854"
+ y="422.957954"
+ id="use2560" />
+ <use
+ xlink:href="#glyph1-19"
+ x="751.825521"
+ y="422.957954"
+ id="use2562" />
+ <use
+ xlink:href="#glyph1-20"
+ x="762.103299"
+ y="422.957954"
+ id="use2564"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-9"
+ x="776.269965"
+ y="422.957954"
+ id="use2566"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-21"
+ x="789.881076"
+ y="422.957954"
+ id="use2568"
+ style="fill:#ffb323;fill-opacity:1" />
+ <use
+ xlink:href="#glyph1-19"
+ x="803.492188"
+ y="422.957954"
+ id="use2570" />
+ <use
+ xlink:href="#glyph1-17"
+ x="813.769965"
+ y="422.957954"
+ id="use2572" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:14.6266px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke:#cccccc;stroke-width:0.483685"
+ x="61.029861"
+ y="206.28314"
+ id="text2605"><tspan
+ sodipodi:role="line"
+ id="tspan2603"
+ x="61.029861"
+ y="206.28314"
+ style="stroke:#cccccc;stroke-width:0.483685">cast not required</tspan></text>
+ <text
+ id="text2609"
+ y="127.66325"
+ x="395.55035"
+ style="font-size:14.6266px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke:#cccccc;stroke-width:0.483685"
+ xml:space="preserve"><tspan
+ style="stroke:#cccccc;stroke-width:0.483685"
+ y="127.66325"
+ x="395.55035"
+ id="tspan2607"
+ sodipodi:role="line">only implements S8</tspan></text>
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="432.64694mm"
+ height="374.31384mm"
+ viewBox="0 0 432.64693 374.31384"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+ sodipodi:docname="dtype_hierarchy.svg"
+ inkscape:export-filename="/home/sebastian/BIDS/dtypes/dtype_hierarchy.png"
+ inkscape:export-xdpi="43.502129"
+ inkscape:export-ydpi="43.502129">
+ <defs
+ id="defs2">
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker1380"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow2Mend">
+ <path
+ transform="scale(-0.6)"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+ id="path1378"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mstart"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path835"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="matrix(0.4,0,0,0.4,4,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Mend"
+ style="overflow:visible"
+ inkscape:isstock="true"
+ inkscape:collect="always">
+ <path
+ id="path856"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="scale(-0.6)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Send"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path844"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lend"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path832"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="matrix(-0.8,0,0,-0.8,-10,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.49497475"
+ inkscape:cx="-261.18562"
+ inkscape:cy="440.75659"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="3440"
+ inkscape:window-height="1376"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ fit-margin-top="10"
+ fit-margin-left="10"
+ fit-margin-right="10"
+ fit-margin-bottom="10" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(1.2604327,40.771063)">
+ <rect
+ style="opacity:1;fill:#ff9000;fill-opacity:1;stroke:none;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2120"
+ width="44.63401"
+ height="17.105249"
+ x="23.573442"
+ y="161.07759"
+ rx="2.843874"
+ ry="2.5766025" />
+ <text
+ id="text2124"
+ y="172.67239"
+ x="30.910395"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
+ xml:space="preserve"><tspan
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
+ y="172.67239"
+ x="30.910395"
+ id="tspan2122"
+ sodipodi:role="line">DType</tspan></text>
+ <g
+ id="g1288">
+ <rect
+ style="opacity:1;fill:#4dabcf;fill-opacity:1;stroke:none;stroke-width:1.37016749;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2146"
+ width="61.739262"
+ height="17.105249"
+ x="42.09428"
+ y="203.41173"
+ rx="2.843874"
+ ry="2.5766025" />
+ <text
+ id="text2150"
+ y="215.00667"
+ x="56.400177"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="215.00667"
+ x="56.400177"
+ id="tspan2148"
+ sodipodi:role="line">Float64</tspan></text>
+ </g>
+ <g
+ id="g1283">
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="182.24493"
+ x="42.09428"
+ height="17.105249"
+ width="61.739262"
+ id="rect2154"
+ style="opacity:1;fill:#4dabcf;fill-opacity:1;stroke:none;stroke-width:1.37016749;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="61.425056"
+ y="194.36903"
+ id="text2158"><tspan
+ sodipodi:role="line"
+ id="tspan2156"
+ x="61.425056"
+ y="194.36903"
+ style="stroke-width:0.26458332">Int64</tspan></text>
+ </g>
+ <g
+ id="g1334"
+ transform="translate(46.037524,104.2459)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path827"
+ d="m 58.264755,86.658881 h 10.69078"
+ style="fill:none;stroke:#000000;stroke-width:1.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ transform="translate(25.819071,143.16003)"
+ id="g2205">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2199"
+ width="44.63401"
+ height="17.105249"
+ x="92.475258"
+ y="39.0849"
+ rx="0"
+ ry="0" />
+ <text
+ id="text2203"
+ y="50.67984"
+ x="99.81221"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="50.67984"
+ x="99.81221"
+ id="tspan2201"
+ sodipodi:role="line">>int64</tspan></text>
+ </g>
+ <g
+ id="g2213"
+ transform="translate(75.560923,143.16003)">
+ <rect
+ ry="0"
+ rx="0"
+ y="39.0849"
+ x="92.475258"
+ height="17.105249"
+ width="44.63401"
+ id="rect2207"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="99.81221"
+ y="50.67984"
+ id="text2211"><tspan
+ sodipodi:role="line"
+ id="tspan2209"
+ x="99.81221"
+ y="50.67984"
+ style="stroke-width:0.26458332"><int64</tspan></text>
+ </g>
+ <g
+ id="g2663"
+ transform="translate(-50.910137,157.97679)">
+ <g
+ id="g2645"
+ transform="translate(96.947661,-32.563904)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path2643"
+ d="m 58.264755,86.658881 h 10.69078"
+ style="fill:none;stroke:#000000;stroke-width:1.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <g
+ transform="translate(76.729209,6.3500001)"
+ id="g2653">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2647"
+ width="44.63401"
+ height="17.105249"
+ x="92.475258"
+ y="39.0849"
+ rx="0"
+ ry="0" />
+ <text
+ id="text2651"
+ y="50.67984"
+ x="97.166374"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="50.67984"
+ x="97.166374"
+ id="tspan2649"
+ sodipodi:role="line">>float64</tspan></text>
+ </g>
+ <g
+ id="g2661"
+ transform="translate(126.47106,6.3500001)">
+ <rect
+ ry="0"
+ rx="0"
+ y="39.0849"
+ x="92.475258"
+ height="17.105249"
+ width="44.63401"
+ id="rect2655"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="96.637207"
+ y="50.67984"
+ id="text2659"><tspan
+ sodipodi:role="line"
+ id="tspan2657"
+ x="96.637207"
+ y="50.67984"
+ style="stroke-width:0.26458332"><float64</tspan></text>
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.51278019px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="146.93526"
+ y="178.48193"
+ id="text2737"><tspan
+ sodipodi:role="line"
+ id="tspan2735"
+ x="146.93526"
+ y="178.48193"
+ style="fill:#9866cf;fill-opacity:1;stroke-width:0.26458332">Instances</tspan></text>
+ <text
+ id="text2675-3"
+ y="153.10063"
+ x="8.1723146"
+ style="font-style:normal;font-weight:normal;font-size:11.38954353px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458329"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.26458329"
+ y="153.10063"
+ x="8.1723146"
+ id="tspan2673-6"
+ sodipodi:role="line">Concrete Types:</tspan></text>
+ <text
+ id="text3215"
+ y="72.108665"
+ x="243.3298"
+ style="font-style:normal;font-weight:normal;font-size:8.51278019px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="fill:#9866cf;fill-opacity:1;stroke-width:0.26458332"
+ y="72.108665"
+ x="243.3298"
+ id="tspan3213"
+ sodipodi:role="line">Instances</tspan></text>
+ <g
+ id="g1293">
+ <rect
+ style="opacity:1;fill:#4dabcf;fill-opacity:1;stroke:none;stroke-width:1.37016749;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2146-6"
+ width="61.739262"
+ height="17.105249"
+ x="42.297195"
+ y="224.75034"
+ rx="2.843874"
+ ry="2.5766025" />
+ <text
+ id="text2150-7"
+ y="236.34528"
+ x="47.843731"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="236.34528"
+ x="47.843731"
+ id="tspan2148-5"
+ sodipodi:role="line">datetime64</tspan></text>
+ </g>
+ <g
+ transform="translate(-50.910137,179.14359)"
+ id="g1057">
+ <g
+ transform="translate(96.947661,-32.563904)"
+ id="g1039">
+ <path
+ sodipodi:nodetypes="cc"
+ style="fill:none;stroke:#000000;stroke-width:1.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
+ d="m 58.264755,86.658881 h 10.69078"
+ id="path1037"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g1047"
+ transform="translate(76.729209,6.3500001)">
+ <rect
+ ry="0"
+ rx="0"
+ y="39.0849"
+ x="92.475258"
+ height="17.105249"
+ width="44.63401"
+ id="rect1041"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="98.777588"
+ y="50.67984"
+ id="text1045"><tspan
+ sodipodi:role="line"
+ id="tspan1043"
+ x="98.777588"
+ y="50.67984"
+ style="stroke-width:0.26458332"><M8[s]</tspan></text>
+ </g>
+ <g
+ transform="translate(126.47106,6.3500001)"
+ id="g1055">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1049"
+ width="44.63401"
+ height="17.105249"
+ x="92.475258"
+ y="39.0849"
+ rx="0"
+ ry="0" />
+ <text
+ id="text1053"
+ y="50.67984"
+ x="96.000237"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="50.67984"
+ x="96.000237"
+ id="tspan1051"
+ sodipodi:role="line">>M8[ns]</tspan></text>
+ <rect
+ ry="0"
+ rx="0"
+ y="39.0849"
+ x="92.475258"
+ height="17.105249"
+ width="44.63401"
+ id="rect1207"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <g
+ id="g1265"
+ style="fill:#9866cf;fill-opacity:1"
+ transform="matrix(2.2707534,0,0,2.2707534,-177.4572,-60.535544)">
+ <circle
+ r="1.1358955"
+ cy="47.637524"
+ cx="141.20377"
+ id="path1256"
+ style="opacity:1;fill:#9866cf;fill-opacity:1;stroke:none;stroke-width:1.71979165;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <circle
+ style="opacity:1;fill:#9866cf;fill-opacity:1;stroke:none;stroke-width:1.71979165;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="circle1258"
+ cx="144.21054"
+ cy="47.637524"
+ r="1.1358955" />
+ <circle
+ r="1.1358955"
+ cy="47.637524"
+ cx="147.21733"
+ id="circle1260"
+ style="opacity:1;fill:#9866cf;fill-opacity:1;stroke:none;stroke-width:1.71979165;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:11.38954353px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458329"
+ x="8.1723146"
+ y="-22.317886"
+ id="text2802"><tspan
+ sodipodi:role="line"
+ id="tspan2800"
+ x="8.1723146"
+ y="-22.317886"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.26458329">Concept:</tspan></text>
+ <ellipse
+ ry="11.626225"
+ rx="29.800554"
+ cy="-4.7734947"
+ cx="53.874973"
+ id="path2804"
+ style="opacity:1;fill:#ffc553;fill-opacity:1;stroke:none;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
+ x="28.792381"
+ y="-2.5054595"
+ id="text2808"><tspan
+ sodipodi:role="line"
+ id="tspan2806"
+ x="28.792381"
+ y="-2.5054595"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1">DTypeMeta</tspan></text>
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="-14.100398"
+ x="96.558197"
+ height="17.105249"
+ width="44.63401"
+ id="rect2810"
+ style="opacity:1;fill:#ff9000;fill-opacity:1;stroke:none;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
+ x="104.69695"
+ y="-3.0399978"
+ id="text2814"><tspan
+ sodipodi:role="line"
+ id="tspan2812"
+ x="104.69695"
+ y="-3.0399978"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;stroke-opacity:1">DType</tspan></text>
+ <g
+ transform="translate(25.655198,-91.784983)"
+ id="g2818">
+ <path
+ sodipodi:nodetypes="cc"
+ style="fill:none;stroke:#000000;stroke-width:1.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
+ d="m 58.264755,86.658881 h 10.69078"
+ id="path2816"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g2846"
+ transform="translate(4.3286934,-30.623148)">
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="39.0849"
+ x="108.87944"
+ height="52.384823"
+ width="90.871613"
+ id="rect2840"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#ff9153;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:9.03164291px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="112.0525"
+ y="50.851093"
+ id="text2844"><tspan
+ id="tspan2842"
+ sodipodi:role="line"
+ x="112.0525"
+ y="50.851093"
+ style="stroke-width:0.26458332">AbstractDtypes:</tspan><tspan
+ sodipodi:role="line"
+ x="112.0525"
+ y="62.140648"
+ style="stroke-width:0.26458332"
+ id="tspan3068">• type hierarchy</tspan><tspan
+ sodipodi:role="line"
+ x="112.0525"
+ y="73.430199"
+ style="stroke-width:0.26458332"
+ id="tspan3078">• UFunc resolution</tspan><tspan
+ sodipodi:role="line"
+ x="112.0525"
+ y="84.719757"
+ style="stroke-width:0.26458332"
+ id="tspan3072">• may promote</tspan><tspan
+ sodipodi:role="line"
+ x="112.0525"
+ y="96.009308"
+ style="stroke-width:0.26458332"
+ id="tspan3066" /></text>
+ </g>
+ <g
+ transform="translate(20.732865,35.976636)"
+ id="g2854">
+ <rect
+ style="opacity:1;fill:#4dabcf;fill-opacity:1;stroke:none;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2848"
+ width="91.940727"
+ height="47.306705"
+ x="92.475258"
+ y="39.0849"
+ rx="2.843874"
+ ry="2.5766025" />
+ <text
+ id="text2852"
+ y="49.872658"
+ x="96.583473"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="49.872658"
+ x="96.583473"
+ id="tspan2850"
+ sodipodi:role="line">Concrete DTypes:</tspan><tspan
+ style="stroke-width:0.26458332"
+ y="60.811176"
+ x="96.583473"
+ sodipodi:role="line"
+ id="tspan3086">• casting/promotion</tspan><tspan
+ style="stroke-width:0.26458332"
+ y="71.749695"
+ x="96.583473"
+ sodipodi:role="line"
+ id="tspan3088">• UFunc signature</tspan></text>
+ </g>
+ <g
+ transform="translate(148.727,10.030009)"
+ id="g2858">
+ <path
+ sodipodi:nodetypes="cc"
+ style="fill:none;stroke:#000000;stroke-width:1.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
+ d="m 58.264755,86.658881 h 10.69078"
+ id="path2856"
+ inkscape:connector-curvature="0" />
+ </g>
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#9866cf;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2860"
+ width="84.724449"
+ height="45.435818"
+ x="220.98373"
+ y="75.328812"
+ rx="0"
+ ry="0" />
+ <text
+ id="text2864"
+ y="86.923752"
+ x="228.32069"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="86.923752"
+ x="228.32069"
+ id="tspan2862"
+ sodipodi:role="line">DType Instances</tspan><tspan
+ id="tspan3074"
+ style="stroke-width:0.26458332"
+ y="97.862267"
+ x="228.32069"
+ sodipodi:role="line">• Describe data</tspan><tspan
+ id="tspan3076"
+ style="stroke-width:0.26458332"
+ y="108.80079"
+ x="228.32069"
+ sodipodi:role="line">• `arr.dtype`</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="228.32069"
+ y="38.240372"
+ id="text3096"><tspan
+ sodipodi:role="line"
+ x="228.32069"
+ y="38.240372"
+ style="stroke-width:0.26458332"
+ id="tspan3094">(Cannot be instantiated)</tspan></text>
+ <text
+ id="text3223"
+ y="277.53149"
+ x="163.20908"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ id="tspan3221"
+ style="stroke-width:0.26458332"
+ y="277.53149"
+ x="163.20908"
+ sodipodi:role="line">Concrete Types form</tspan><tspan
+ style="stroke-width:0.26458332"
+ y="288.47"
+ x="163.20908"
+ sodipodi:role="line"
+ id="tspan3225">leaves of the tree;</tspan><tspan
+ id="tspan3248"
+ style="stroke-width:0.26458332"
+ y="299.40854"
+ x="163.20908"
+ sodipodi:role="line">the inheritance is abstract</tspan><tspan
+ id="tspan3270"
+ style="stroke-width:0.26458332"
+ y="310.34705"
+ x="163.20908"
+ sodipodi:role="line">similar to Python's abc.ABC. </tspan></text>
+ <g
+ id="g3084"
+ transform="translate(35.454183,8.4666671)">
+ <g
+ transform="translate(111.41246,-60.58556)"
+ id="g3058">
+ <path
+ sodipodi:nodetypes="cc"
+ style="fill:none;stroke:#000000;stroke-width:1.16499996;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
+ d="m 58.264755,86.658881 h 10.69078"
+ id="path3056"
+ inkscape:connector-curvature="0" />
+ </g>
+ <text
+ id="text3062"
+ y="33.375549"
+ x="177.81163"
+ style="font-style:normal;font-weight:normal;font-size:25.73707581px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="33.375549"
+ x="177.81163"
+ id="tspan3060"
+ sodipodi:role="line">x</tspan></text>
+ </g>
+ <path
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0"
+ id="path3217"
+ d="m 240.37519,140.22719 v 115.49978 l -21.73363,-0.0959"
+ style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 373.75879,132.43914 H 41.810036"
+ id="path3219"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g1383"
+ transform="translate(1.5875)">
+ <g
+ transform="translate(282.50926,124.19261)"
+ id="g1309">
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="182.24493"
+ x="42.09428"
+ height="17.105249"
+ width="61.739262"
+ id="rect1303"
+ style="opacity:1;fill:#4dabcf;fill-opacity:1;stroke:none;stroke-width:1.37016749;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="61.425056"
+ y="194.36903"
+ id="text1307"><tspan
+ sodipodi:role="line"
+ id="tspan1305"
+ x="61.425056"
+ y="194.36903"
+ style="stroke-width:0.26458332">Int64</tspan></text>
+ </g>
+ <g
+ transform="translate(283.57834,60.501707)"
+ id="g1301">
+ <rect
+ style="opacity:1;fill:#4dabcf;fill-opacity:1;stroke:none;stroke-width:1.37016749;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1295"
+ width="61.739262"
+ height="17.105249"
+ x="42.09428"
+ y="203.41173"
+ rx="2.843874"
+ ry="2.5766025" />
+ <text
+ id="text1299"
+ y="215.00667"
+ x="56.400177"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="215.00667"
+ x="56.400177"
+ id="tspan1297"
+ sodipodi:role="line">Float64</tspan></text>
+ </g>
+ <g
+ transform="translate(185.91751,182.30441)"
+ id="g2195">
+ <rect
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#ff9153;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2187"
+ width="44.63401"
+ height="17.105249"
+ x="108.87944"
+ y="39.0849"
+ rx="2.843874"
+ ry="2.5766025" />
+ <text
+ id="text2193"
+ y="50.321926"
+ x="113.11084"
+ style="font-style:normal;font-weight:normal;font-size:9.03164291px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="50.321926"
+ x="113.11084"
+ sodipodi:role="line"
+ id="tspan2191">Inexact</tspan></text>
+ </g>
+ <g
+ id="g2671"
+ transform="translate(172.15917,161.04236)">
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="39.0849"
+ x="108.87944"
+ height="17.105249"
+ width="44.63401"
+ id="rect2665"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#ff9153;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:9.03164291px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="112.0525"
+ y="50.851093"
+ id="text2669"><tspan
+ id="tspan2667"
+ sodipodi:role="line"
+ x="112.0525"
+ y="50.851093"
+ style="stroke-width:0.26458332">Numeric</tspan></text>
+ </g>
+ <g
+ id="g2701"
+ transform="translate(170.57168,118.51826)">
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="39.0849"
+ x="92.475258"
+ height="17.105249"
+ width="44.63401"
+ id="rect2695"
+ style="opacity:1;fill:#ff9153;fill-opacity:1;stroke:none;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="99.81221"
+ y="50.67984"
+ id="text2699"><tspan
+ sodipodi:role="line"
+ id="tspan2697"
+ x="99.81221"
+ y="50.67984"
+ style="stroke-width:0.26458332">DType</tspan></text>
+ </g>
+ <g
+ id="g2709"
+ transform="translate(201.26335,203.56648)">
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="39.0849"
+ x="108.87944"
+ height="17.105249"
+ width="44.63401"
+ id="rect2703"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#ff9153;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:9.03164291px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="112.0525"
+ y="50.321926"
+ id="text2707"><tspan
+ id="tspan2705"
+ sodipodi:role="line"
+ x="112.0525"
+ y="50.321926"
+ style="stroke-width:0.26458332">Floating</tspan></text>
+ </g>
+ <g
+ id="g2717"
+ transform="translate(185.38297,221.7489)">
+ <rect
+ ry="2.5766025"
+ rx="2.843874"
+ y="63.42659"
+ x="108.87944"
+ height="17.105249"
+ width="44.63401"
+ id="rect2711"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#ff9153;stroke-width:1.16499996;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:9.03164291px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="113.11084"
+ y="74.663612"
+ id="text2715"><tspan
+ id="tspan2713"
+ sodipodi:role="line"
+ x="113.11084"
+ y="74.663612"
+ style="stroke-width:0.26458332">Integral</tspan></text>
+ </g>
+ <text
+ id="text2774"
+ y="149.89339"
+ x="244.4957"
+ style="font-style:normal;font-weight:normal;font-size:11.38954258px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458329"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.26458329"
+ y="149.89339"
+ x="244.4957"
+ id="tspan2772"
+ sodipodi:role="line">Abstract Types (Hierarchy):</tspan></text>
+ <g
+ transform="translate(238.74141,-45.88513)"
+ id="g1317">
+ <rect
+ style="opacity:1;fill:#4dabcf;fill-opacity:1;stroke:none;stroke-width:1.37016749;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1311"
+ width="61.739262"
+ height="17.105249"
+ x="42.297195"
+ y="224.75034"
+ rx="2.843874"
+ ry="2.5766025" />
+ <text
+ id="text1315"
+ y="236.34528"
+ x="47.843731"
+ style="font-style:normal;font-weight:normal;font-size:8.75081348px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.26458332"
+ y="236.34528"
+ x="47.843731"
+ id="tspan1313"
+ sodipodi:role="line">datetime64</tspan></text>
+ </g>
+ </g>
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0rc1 (09960d6f05, 2020-04-09)"
+ sodipodi:docname="nep-0041-type-sketch-no-fonts.svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 390.05549 139.7222"
+ height="139.7222mm"
+ width="390.05548mm">
+ <defs
+ id="defs2">
+ <rect
+ x="-108.43283"
+ y="116.0488"
+ width="38.824516"
+ height="5.9122801"
+ id="rect3054" />
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker7096"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path7094"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5628"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5626"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5618"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Sstart">
+ <path
+ transform="matrix(0.2,0,0,0.2,1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5616"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4826"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#206120;fill-opacity:1;fill-rule:evenodd;stroke:#206120;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4824"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker4400"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4398"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4390"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#b7943d;fill-opacity:1;fill-rule:evenodd;stroke:#b7943d;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4388"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker2037"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#f4ae00;fill-opacity:1;fill-rule:evenodd;stroke:#ffc433;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path2035"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <rect
+ id="rect1296"
+ height="8.8755655"
+ width="16.467854"
+ y="100.87298"
+ x="-2.9674385" />
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lend"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="matrix(-0.8,0,0,-0.8,-10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path915"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path912"
+ inkscape:connector-curvature="0" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ inkscape:guide-bbox="true"
+ showguides="true"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:window-height="1376"
+ inkscape:window-width="2560"
+ showgrid="false"
+ inkscape:document-rotation="0"
+ inkscape:current-layer="layer1"
+ inkscape:document-units="mm"
+ inkscape:cy="290.82008"
+ inkscape:cx="134.87089"
+ inkscape:zoom="0.98994949"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ lock-margins="true"
+ fit-margin-top="2"
+ fit-margin-left="2"
+ fit-margin-right="2"
+ fit-margin-bottom="2"
+ objecttolerance="29.7"
+ gridtolerance="20.4"
+ guidetolerance="19.1"
+ inkscape:snap-perpendicular="true"
+ inkscape:snap-tangential="true" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="Layer 1"
+ transform="translate(143.44857,-67.864137)">
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path1976"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796078;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 175.57699,126.11316 h 65.38081 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -65.38081 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path3044"
+ d="M 172.89254,70.114137 V 205.33633"
+ style="fill:none;stroke:#808080;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ d="M 55.143494,98.892926 H 240.95778 c 1.14406,0 2.06509,0.921034 2.06509,2.065094 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 55.143494 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.065094 2.06509,-2.065094 z"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796609;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="rect5208"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ d="M -60.569299,98.727824 H 50.002364 c 1.14406,0 2.06509,0.92103 2.06509,2.065086 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H -60.569299 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.144056 0.92103,-2.065086 2.06509,-2.065086 z"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="rect4618"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <g
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ id="text4368" />
+ <g
+ style="font-size:3.52778px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1296)"
+ id="text1294" />
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.76111px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ id="text1931"
+ aria-label="Value Storage">
+ <path
+ id="path1309"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 177.73074,82.757808 h 1.46657 l 1.50069,4.176144 1.49689,-4.176144 h 1.46658 l -2.09565,5.65788 h -1.73943 z" />
+ <path
+ id="path1311"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 185.82912,86.505727 q -0.42443,0 -0.64044,0.144005 -0.21222,0.144005 -0.21222,0.424436 0,0.257693 0.17053,0.405487 0.17432,0.144005 0.48128,0.144005 0.38275,0 0.64424,-0.272851 0.26148,-0.276641 0.26148,-0.689708 v -0.155374 z m 2.07292,-0.511597 v 2.421558 h -1.36805 v -0.629075 q -0.27285,0.38654 -0.61392,0.564651 -0.34106,0.174322 -0.82992,0.174322 -0.65939,0 -1.07246,-0.38275 -0.40928,-0.38654 -0.40928,-1.000456 0,-0.746552 0.5116,-1.095195 0.51539,-0.348644 1.61437,-0.348644 h 0.79961 v -0.106109 q 0,-0.322116 -0.25391,-0.469911 -0.2539,-0.151584 -0.79202,-0.151584 -0.43581,0 -0.81098,0.08716 -0.37517,0.08716 -0.69729,0.261483 v -1.034562 q 0.43581,-0.106109 0.8754,-0.159164 0.4396,-0.05684 0.87919,-0.05684 1.14825,0 1.65606,0.454753 0.5116,0.450963 0.5116,1.470366 z" />
+ <path
+ id="path1313"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 189.16397,82.519063 h 1.35668 v 5.896625 h -1.35668 z" />
+ <path
+ id="path1315"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 191.7788,86.76342 v -2.592089 h 1.36426 v 0.424435 q 0,0.344854 -0.004,0.86782 -0.004,0.519176 -0.004,0.693497 0,0.511597 0.0265,0.738973 0.0265,0.223587 0.0909,0.325906 0.0834,0.132636 0.216,0.204639 0.13643,0.072 0.31075,0.072 0.42444,0 0.66697,-0.325906 0.24254,-0.325906 0.24254,-0.905715 v -2.095651 h 1.35667 v 4.244357 h -1.35667 v -0.613916 q -0.30696,0.371381 -0.65182,0.549492 -0.34106,0.174322 -0.75413,0.174322 -0.73518,0 -1.12172,-0.450963 -0.38275,-0.450963 -0.38275,-1.311203 z" />
+ <path
+ id="path1317"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 201.5863,86.28214 v 0.38654 h -3.1719 q 0.0493,0.47749 0.34485,0.716235 0.29559,0.238745 0.82613,0.238745 0.42823,0 0.8754,-0.125057 0.45097,-0.128846 0.92467,-0.386539 v 1.04593 q -0.48128,0.181901 -0.96256,0.272852 -0.48128,0.09474 -0.96256,0.09474 -1.15204,0 -1.79249,-0.583599 -0.63665,-0.587389 -0.63665,-1.644688 0,-1.038352 0.62529,-1.63332 0.62907,-0.594968 1.72806,-0.594968 1.00045,0 1.59921,0.602547 0.60255,0.602548 0.60255,1.610582 z m -1.39458,-0.450963 q 0,-0.386539 -0.22737,-0.621495 -0.22359,-0.238745 -0.58739,-0.238745 -0.39412,0 -0.64045,0.223587 -0.24632,0.219797 -0.30695,0.636653 z" />
+ <path
+ id="path1319"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 209.3133,82.93592 v 1.197515 q -0.46612,-0.208429 -0.9095,-0.314538 -0.44339,-0.106109 -0.83751,-0.106109 -0.52296,0 -0.77308,0.144005 -0.25011,0.144005 -0.25011,0.447174 0,0.227376 0.16674,0.356223 0.17053,0.125057 0.61392,0.216007 l 0.62149,0.125057 q 0.94361,0.18948 1.34152,0.57602 0.39791,0.38654 0.39791,1.098985 0,0.936032 -0.55707,1.394575 -0.55328,0.454752 -1.69395,0.454752 -0.53813,0 -1.08004,-0.102319 -0.54191,-0.10232 -1.08383,-0.303169 v -1.231621 q 0.54192,0.28801 1.04593,0.435804 0.50781,0.144005 0.97772,0.144005 0.47749,0 0.7314,-0.159163 0.2539,-0.159163 0.2539,-0.454752 0,-0.265273 -0.17432,-0.409278 -0.17054,-0.144005 -0.68592,-0.257693 l -0.56465,-0.125057 q -0.84887,-0.181901 -1.24299,-0.579809 -0.39033,-0.397909 -0.39033,-1.072458 0,-0.845082 0.5457,-1.299835 0.5457,-0.454752 1.5689,-0.454752 0.46612,0 0.95877,0.072 0.49265,0.06821 1.0194,0.208429 z" />
+ <path
+ id="path1321"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 212.38667,82.966236 v 1.205095 h 1.39836 v 0.970138 h -1.39836 v 1.800062 q 0,0.29559 0.11748,0.401699 0.11747,0.102319 0.46612,0.102319 h 0.69728 v 0.970139 h -1.1634 q -0.8034,0 -1.14068,-0.333486 -0.33348,-0.337274 -0.33348,-1.140671 v -1.800062 h -0.67455 v -0.970138 h 0.67455 v -1.205095 z" />
+ <path
+ id="path1323"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 216.63482,85.03915 q -0.45097,0 -0.68971,0.325906 -0.23496,0.322116 -0.23496,0.932243 0,0.610126 0.23496,0.936032 0.23874,0.322116 0.68971,0.322116 0.44338,0 0.67834,-0.322116 0.23495,-0.325906 0.23495,-0.936032 0,-0.610127 -0.23495,-0.932243 -0.23496,-0.325906 -0.67834,-0.325906 z m 0,-0.970139 q 1.09519,0 1.70911,0.591179 0.6177,0.591178 0.6177,1.637109 0,1.045931 -0.6177,1.637109 -0.61392,0.591178 -1.70911,0.591178 -1.09899,0 -1.72048,-0.591178 -0.61771,-0.591178 -0.61771,-1.637109 0,-1.045931 0.61771,-1.637109 0.62149,-0.591179 1.72048,-0.591179 z" />
+ <path
+ id="path1325"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 223.09988,85.32716 q -0.17811,-0.08337 -0.35622,-0.121267 -0.17433,-0.04169 -0.35244,-0.04169 -0.52296,0 -0.80718,0.337275 -0.28043,0.333485 -0.28043,0.95877 v 1.955436 h -1.35668 v -4.244357 h 1.35668 v 0.697287 q 0.26148,-0.416857 0.59875,-0.606337 0.34107,-0.19327 0.81477,-0.19327 0.0682,0 0.14779,0.0076 0.0796,0.0038 0.23117,0.02274 z" />
+ <path
+ id="path1327"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 225.67681,86.505727 q -0.42443,0 -0.64044,0.144005 -0.21222,0.144005 -0.21222,0.424436 0,0.257693 0.17053,0.405487 0.17433,0.144005 0.48128,0.144005 0.38275,0 0.64424,-0.272851 0.26148,-0.276641 0.26148,-0.689708 v -0.155374 z m 2.07292,-0.511597 v 2.421558 h -1.36805 v -0.629075 q -0.27285,0.38654 -0.61392,0.564651 -0.34106,0.174322 -0.82992,0.174322 -0.65939,0 -1.07246,-0.38275 -0.40928,-0.38654 -0.40928,-1.000456 0,-0.746552 0.5116,-1.095195 0.51539,-0.348644 1.61437,-0.348644 h 0.79961 v -0.106109 q 0,-0.322116 -0.2539,-0.469911 -0.25391,-0.151584 -0.79203,-0.151584 -0.43581,0 -0.81098,0.08716 -0.37517,0.08716 -0.69728,0.261483 v -1.034562 q 0.4358,-0.106109 0.87539,-0.159164 0.4396,-0.05684 0.87919,-0.05684 1.14825,0 1.65606,0.454753 0.5116,0.450963 0.5116,1.470366 z" />
+ <path
+ id="path1329"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 231.89934,87.695663 q -0.28043,0.371381 -0.6177,0.545703 -0.33728,0.174322 -0.78066,0.174322 -0.77687,0 -1.28468,-0.610127 -0.5078,-0.613916 -0.5078,-1.561317 0,-0.95119 0.5078,-1.557527 0.50781,-0.610126 1.28468,-0.610126 0.44338,0 0.78066,0.174321 0.33727,0.174322 0.6177,0.549493 v -0.629074 h 1.36426 v 3.816131 q 0,1.023193 -0.64802,1.561317 -0.64424,0.541914 -1.87207,0.541914 -0.39791,0 -0.76929,-0.06063 -0.37138,-0.06063 -0.74655,-0.185691 v -1.057299 q 0.35622,0.204638 0.69729,0.303168 0.34106,0.102319 0.68592,0.102319 0.66697,0 0.97771,-0.291799 0.31075,-0.2918 0.31075,-0.913295 z M 231.005,85.054308 q -0.42065,0 -0.65561,0.310748 -0.23495,0.310748 -0.23495,0.879188 0,0.583599 0.22737,0.886768 0.22738,0.299378 0.66319,0.299378 0.42443,0 0.65939,-0.310747 0.23495,-0.310748 0.23495,-0.875399 0,-0.56844 -0.23495,-0.879188 -0.23496,-0.310748 -0.65939,-0.310748 z" />
+ <path
+ id="path1331"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 238.804,86.28214 v 0.38654 h -3.1719 q 0.0493,0.47749 0.34486,0.716235 0.29559,0.238745 0.82613,0.238745 0.42823,0 0.8754,-0.125057 0.45096,-0.128846 0.92466,-0.386539 v 1.04593 q -0.48128,0.181901 -0.96256,0.272852 -0.48128,0.09474 -0.96256,0.09474 -1.15204,0 -1.79248,-0.583599 -0.63665,-0.587389 -0.63665,-1.644688 0,-1.038352 0.62528,-1.63332 0.62908,-0.594968 1.72806,-0.594968 1.00046,0 1.59922,0.602547 0.60254,0.602548 0.60254,1.610582 z m -1.39457,-0.450963 q 0,-0.386539 -0.22738,-0.621495 -0.22358,-0.238745 -0.58739,-0.238745 -0.39412,0 -0.64044,0.223587 -0.24632,0.219797 -0.30696,0.636653 z" />
+ </g>
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.76111px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ id="text1935"
+ aria-label="Parameters and
+Storage options">
+ <path
+ id="path1254"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 78.339383,73.092678 h 2.421558 q 1.080037,0 1.656057,0.481279 0.579809,0.47749 0.579809,1.364258 0,0.890557 -0.579809,1.371837 -0.57602,0.47749 -1.656057,0.47749 h -0.96256 v 1.963015 h -1.458998 z m 1.458998,1.057299 v 1.580265 h 0.807186 q 0.424436,0 0.655601,-0.204638 0.231166,-0.208429 0.231166,-0.587389 0,-0.378961 -0.231166,-0.583599 -0.231165,-0.204639 -0.655601,-0.204639 z" />
+ <path
+ id="path1256"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 85.660899,76.840596 q -0.424436,0 -0.640443,0.144005 -0.212218,0.144005 -0.212218,0.424436 0,0.257693 0.170532,0.405488 0.174322,0.144005 0.48128,0.144005 0.38275,0 0.644233,-0.272852 0.261482,-0.276641 0.261482,-0.689708 V 76.840596 Z M 87.733813,76.329 v 2.421557 h -1.368048 v -0.629074 q -0.272851,0.386539 -0.613915,0.564651 -0.341065,0.174321 -0.829924,0.174321 -0.659391,0 -1.072458,-0.38275 -0.409277,-0.386539 -0.409277,-1.000455 0,-0.746552 0.511596,-1.095196 0.515387,-0.348643 1.614372,-0.348643 h 0.799606 v -0.106109 q 0,-0.322117 -0.253903,-0.469911 -0.253904,-0.151584 -0.792027,-0.151584 -0.435805,0 -0.810976,0.08716 -0.375171,0.08716 -0.697287,0.261483 v -1.034562 q 0.435805,-0.106109 0.875399,-0.159163 0.439594,-0.05684 0.879188,-0.05684 1.14825,0 1.656057,0.454752 0.511597,0.450963 0.511597,1.470367 z" />
+ <path
+ id="path1258"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 92.148702,75.662029 q -0.178112,-0.08337 -0.356223,-0.121267 -0.174322,-0.04169 -0.352433,-0.04169 -0.522966,0 -0.807186,0.337275 -0.280431,0.333485 -0.280431,0.95877 v 1.955436 H 88.995751 V 74.5062 h 1.356678 v 0.697287 q 0.261483,-0.416856 0.598758,-0.606336 0.341064,-0.19327 0.814765,-0.19327 0.06821,0 0.147794,0.0076 0.07958,0.0038 0.231166,0.02274 z" />
+ <path
+ id="path1260"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 94.725633,76.840596 q -0.424436,0 -0.640444,0.144005 -0.212217,0.144005 -0.212217,0.424436 0,0.257693 0.170532,0.405488 0.174322,0.144005 0.48128,0.144005 0.38275,0 0.644232,-0.272852 0.261483,-0.276641 0.261483,-0.689708 V 76.840596 Z M 96.798546,76.329 v 2.421557 h -1.368047 v -0.629074 q -0.272852,0.386539 -0.613916,0.564651 -0.341064,0.174321 -0.829923,0.174321 -0.659391,0 -1.072458,-0.38275 -0.409278,-0.386539 -0.409278,-1.000455 0,-0.746552 0.511597,-1.095196 0.515386,-0.348643 1.614371,-0.348643 h 0.799607 v -0.106109 q 0,-0.322117 -0.253904,-0.469911 -0.253903,-0.151584 -0.792027,-0.151584 -0.435804,0 -0.810975,0.08716 -0.375171,0.08716 -0.697287,0.261483 v -1.034562 q 0.435804,-0.106109 0.875398,-0.159163 0.439594,-0.05684 0.879188,-0.05684 1.148251,0 1.656058,0.454752 0.511596,0.450963 0.511596,1.470367 z" />
+ <path
+ id="path1262"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 101.99409,75.211066 q 0.2577,-0.394118 0.61013,-0.598757 0.35622,-0.208428 0.78066,-0.208428 0.73139,0 1.11414,0.450963 0.38275,0.450963 0.38275,1.311203 v 2.58451 h -1.36426 v -2.213129 q 0.004,-0.04927 0.004,-0.102319 0.004,-0.05306 0.004,-0.151585 0,-0.450962 -0.13263,-0.651811 -0.13264,-0.204639 -0.42823,-0.204639 -0.38654,0 -0.59876,0.318327 -0.20842,0.318326 -0.216,0.920874 v 2.084282 h -1.36426 v -2.213129 q 0,-0.704866 -0.12127,-0.905715 -0.12126,-0.204639 -0.43201,-0.204639 -0.390332,0 -0.602549,0.322116 -0.212218,0.318327 -0.212218,0.913295 v 2.088072 H 98.052905 V 74.5062 h 1.364258 v 0.621495 q 0.250114,-0.360012 0.57223,-0.541913 0.325907,-0.181901 0.716237,-0.181901 0.43959,0 0.77687,0.212218 0.33727,0.212217 0.51159,0.594967 z" />
+ <path
+ id="path1264"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 110.38428,76.61701 v 0.386539 h -3.1719 q 0.0493,0.47749 0.34485,0.716236 0.29559,0.238745 0.82614,0.238745 0.42822,0 0.8754,-0.125057 0.45096,-0.128847 0.92466,-0.38654 v 1.045931 q -0.48128,0.181901 -0.96256,0.272851 -0.48128,0.09474 -0.96256,0.09474 -1.15204,0 -1.79248,-0.583599 -0.63666,-0.587388 -0.63666,-1.644688 0,-1.038352 0.62529,-1.633319 0.62907,-0.594968 1.72806,-0.594968 1.00045,0 1.59921,0.602547 0.60255,0.602547 0.60255,1.610582 z m -1.39458,-0.450963 q 0,-0.38654 -0.22737,-0.621495 -0.22359,-0.238745 -0.58739,-0.238745 -0.39412,0 -0.64044,0.223586 -0.24633,0.219797 -0.30696,0.636654 z" />
+ <path
+ id="path1266"
+ style="fill:#000000;stroke-width:0.105503"
+ d="M 112.893,73.301106 V 74.5062 h 1.39836 v 0.970139 H 112.893 v 1.800062 q 0,0.295589 0.11747,0.401698 0.11748,0.102319 0.46613,0.102319 h 0.69728 v 0.970139 h -1.16341 q -0.80339,0 -1.14067,-0.333485 -0.33348,-0.337275 -0.33348,-1.140671 v -1.800062 h -0.67455 V 74.5062 h 0.67455 v -1.205094 z" />
+ <path
+ id="path1268"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 119.35806,76.61701 v 0.386539 h -3.1719 q 0.0493,0.47749 0.34486,0.716236 0.29558,0.238745 0.82613,0.238745 0.42822,0 0.8754,-0.125057 0.45096,-0.128847 0.92466,-0.38654 v 1.045931 q -0.48128,0.181901 -0.96256,0.272851 -0.48128,0.09474 -0.96256,0.09474 -1.15204,0 -1.79248,-0.583599 -0.63665,-0.587388 -0.63665,-1.644688 0,-1.038352 0.62528,-1.633319 0.62908,-0.594968 1.72806,-0.594968 1.00046,0 1.59921,0.602547 0.60255,0.602547 0.60255,1.610582 z m -1.39457,-0.450963 q 0,-0.38654 -0.22738,-0.621495 -0.22359,-0.238745 -0.58739,-0.238745 -0.39412,0 -0.64044,0.223586 -0.24633,0.219797 -0.30696,0.636654 z" />
+ <path
+ id="path1270"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 123.53799,75.662029 q -0.17811,-0.08337 -0.35622,-0.121267 -0.17432,-0.04169 -0.35243,-0.04169 -0.52297,0 -0.80719,0.337275 -0.28043,0.333485 -0.28043,0.95877 v 1.955436 h -1.35668 V 74.5062 h 1.35668 v 0.697287 q 0.26148,-0.416856 0.59876,-0.606336 0.34106,-0.19327 0.81476,-0.19327 0.0682,0 0.1478,0.0076 0.0796,0.0038 0.23116,0.02274 z" />
+ <path
+ id="path1272"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 127.52845,74.638836 v 1.030773 q -0.4358,-0.181901 -0.84129,-0.272852 -0.40549,-0.09095 -0.7655,-0.09095 -0.38654,0 -0.57602,0.09853 -0.18569,0.09474 -0.18569,0.295589 0,0.162953 0.14021,0.250114 0.14401,0.08716 0.5116,0.128847 l 0.23874,0.03411 q 1.04215,0.132636 1.40216,0.435805 0.36001,0.303168 0.36001,0.95119 0,0.67834 -0.50023,1.019404 -0.50023,0.341064 -1.4931,0.341064 -0.42065,0 -0.87161,-0.06821 -0.44717,-0.06442 -0.92087,-0.19706 v -1.030772 q 0.40548,0.197059 0.82992,0.295589 0.42822,0.09853 0.86782,0.09853 0.39791,0 0.59876,-0.109899 0.20084,-0.109898 0.20084,-0.325906 0,-0.181901 -0.14021,-0.269062 -0.13643,-0.09095 -0.54949,-0.140215 l -0.23875,-0.03032 q -0.90571,-0.113688 -1.26952,-0.420646 -0.3638,-0.306958 -0.3638,-0.932243 0,-0.674549 0.46233,-1.000455 0.46234,-0.325906 1.41732,-0.325906 0.37517,0 0.78823,0.05684 0.41307,0.05684 0.89814,0.178111 z" />
+ <path
+ id="path1274"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 133.43644,76.840596 q -0.42443,0 -0.64044,0.144005 -0.21222,0.144005 -0.21222,0.424436 0,0.257693 0.17053,0.405488 0.17432,0.144005 0.48128,0.144005 0.38275,0 0.64424,-0.272852 0.26148,-0.276641 0.26148,-0.689708 V 76.840596 Z M 135.50935,76.329 v 2.421557 h -1.36804 v -0.629074 q -0.27285,0.386539 -0.61392,0.564651 -0.34106,0.174321 -0.82992,0.174321 -0.65939,0 -1.07246,-0.38275 -0.40928,-0.386539 -0.40928,-1.000455 0,-0.746552 0.5116,-1.095196 0.51539,-0.348643 1.61437,-0.348643 h 0.79961 v -0.106109 q 0,-0.322117 -0.25391,-0.469911 -0.2539,-0.151584 -0.79202,-0.151584 -0.43581,0 -0.81098,0.08716 -0.37517,0.08716 -0.69729,0.261483 v -1.034562 q 0.43581,-0.106109 0.8754,-0.159163 0.4396,-0.05684 0.87919,-0.05684 1.14825,0 1.65606,0.454752 0.51159,0.450963 0.51159,1.470367 z" />
+ <path
+ id="path1276"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 141.03839,76.166047 v 2.58451 h -1.36426 v -0.420646 -1.557528 q 0,-0.549492 -0.0265,-0.75792 -0.0227,-0.208429 -0.0834,-0.306958 -0.0796,-0.132637 -0.21601,-0.204639 -0.13642,-0.07579 -0.31074,-0.07579 -0.42444,0 -0.66697,0.329695 -0.24254,0.325906 -0.24254,0.905716 v 2.088072 h -1.35668 V 74.5062 h 1.35668 v 0.621495 q 0.30696,-0.371381 0.65181,-0.545703 0.34486,-0.178111 0.76171,-0.178111 0.73519,0 1.11415,0.450963 0.38275,0.450963 0.38275,1.311203 z" />
+ <path
+ id="path1278"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 145.18421,75.127695 v -2.273763 h 1.36426 v 5.896625 h -1.36426 v -0.613916 q -0.28043,0.375171 -0.6177,0.549493 -0.33728,0.174321 -0.78066,0.174321 -0.78445,0 -1.28847,-0.621495 -0.50401,-0.625284 -0.50401,-1.606792 0,-0.981507 0.50401,-1.603003 0.50402,-0.625284 1.28847,-0.625284 0.43959,0 0.77687,0.178111 0.34106,0.174322 0.62149,0.545703 z m -0.89434,2.747463 q 0.4358,0 0.66318,-0.318326 0.23116,-0.318327 0.23116,-0.924664 0,-0.606337 -0.23116,-0.924663 -0.22738,-0.318327 -0.66318,-0.318327 -0.43202,0 -0.66318,0.318327 -0.22738,0.318326 -0.22738,0.924663 0,0.606337 0.22738,0.924664 0.23116,0.318326 0.66318,0.318326 z" />
+ <path
+ id="path1280"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 82.276782,82.972176 v 1.197515 q -0.466121,-0.208428 -0.909505,-0.314537 -0.443383,-0.106109 -0.837502,-0.106109 -0.522966,0 -0.773079,0.144005 -0.250114,0.144005 -0.250114,0.447173 0,0.227377 0.166742,0.356223 0.170532,0.125057 0.613916,0.216008 l 0.621495,0.125057 q 0.943612,0.18948 1.34152,0.57602 0.397909,0.386539 0.397909,1.098985 0,0.936032 -0.557072,1.394574 -0.553282,0.454753 -1.693953,0.454753 -0.538124,0 -1.080038,-0.10232 -0.541913,-0.102319 -1.083826,-0.303168 v -1.231621 q 0.541913,0.28801 1.04593,0.435804 0.507807,0.144005 0.977718,0.144005 0.47749,0 0.731394,-0.159163 0.253903,-0.159164 0.253903,-0.454753 0,-0.265272 -0.174321,-0.409277 -0.170533,-0.144005 -0.685919,-0.257693 L 79.817329,86.0986 q -0.848871,-0.181901 -1.24299,-0.57981 -0.390329,-0.397908 -0.390329,-1.072458 0,-0.845081 0.545703,-1.299834 0.545703,-0.454752 1.568896,-0.454752 0.466121,0 0.95877,0.072 0.492648,0.06821 1.019403,0.208428 z" />
+ <path
+ id="path1282"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 85.350152,83.002493 v 1.205094 h 1.398364 v 0.970139 h -1.398364 v 1.800062 q 0,0.295589 0.117477,0.401698 0.117478,0.10232 0.466122,0.10232 h 0.697287 v 0.970138 h -1.163409 q -0.803396,0 -1.140671,-0.333485 -0.333485,-0.337275 -0.333485,-1.140671 v -1.800062 h -0.674549 v -0.970139 h 0.674549 v -1.205094 z" />
+ <path
+ id="path1284"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 89.598298,85.075407 q -0.450963,0 -0.689708,0.325906 -0.234955,0.322116 -0.234955,0.932242 0,0.610127 0.234955,0.936033 0.238745,0.322116 0.689708,0.322116 0.443384,0 0.678339,-0.322116 0.234956,-0.325906 0.234956,-0.936033 0,-0.610126 -0.234956,-0.932242 -0.234955,-0.325906 -0.678339,-0.325906 z m 0,-0.970139 q 1.095196,0 1.709112,0.591178 0.617705,0.591179 0.617705,1.637109 0,1.045931 -0.617705,1.637109 -0.613916,0.591179 -1.709112,0.591179 -1.098985,0 -1.72048,-0.591179 -0.617706,-0.591178 -0.617706,-1.637109 0,-1.04593 0.617706,-1.637109 0.621495,-0.591178 1.72048,-0.591178 z" />
+ <path
+ id="path1286"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 96.063363,85.363417 q -0.178111,-0.08337 -0.356223,-0.121268 -0.174322,-0.04169 -0.352433,-0.04169 -0.522965,0 -0.807186,0.337274 -0.28043,0.333486 -0.28043,0.95877 v 1.955436 h -1.356679 v -4.244357 h 1.356679 v 0.697288 q 0.261482,-0.416857 0.598757,-0.606337 0.341064,-0.19327 0.814765,-0.19327 0.06821,0 0.147795,0.0076 0.07958,0.0038 0.231165,0.02274 z" />
+ <path
+ id="path1288"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 98.640295,86.541984 q -0.424436,0 -0.640443,0.144005 -0.212218,0.144005 -0.212218,0.424435 0,0.257693 0.170532,0.405488 0.174322,0.144005 0.48128,0.144005 0.38275,0 0.644233,-0.272852 0.261482,-0.276641 0.261482,-0.689708 v -0.155373 z m 2.072915,-0.511597 v 2.421557 H 99.345161 V 87.82287 q -0.272851,0.38654 -0.613916,0.564651 -0.341064,0.174322 -0.829923,0.174322 -0.659391,0 -1.072458,-0.38275 -0.409277,-0.38654 -0.409277,-1.000456 0,-0.746552 0.511596,-1.095196 0.515387,-0.348643 1.614372,-0.348643 h 0.799606 v -0.106109 q 0,-0.322116 -0.253903,-0.469911 -0.253904,-0.151584 -0.792027,-0.151584 -0.435805,0 -0.810976,0.08716 -0.375171,0.08716 -0.697287,0.261482 v -1.034562 q 0.435804,-0.106108 0.875399,-0.159163 0.439594,-0.05684 0.879188,-0.05684 1.14825,0 1.656055,0.454753 0.5116,0.450962 0.5116,1.470366 z" />
+ <path
+ id="path1290"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 104.86282,87.731919 q -0.28043,0.371382 -0.6177,0.545703 -0.33728,0.174322 -0.78066,0.174322 -0.77687,0 -1.28468,-0.610126 -0.5078,-0.613916 -0.5078,-1.561317 0,-0.951191 0.5078,-1.557528 0.50781,-0.610126 1.28468,-0.610126 0.44338,0 0.78066,0.174322 0.33727,0.174322 0.6177,0.549493 v -0.629075 h 1.36426 v 3.816132 q 0,1.023193 -0.64802,1.561317 -0.64423,0.541913 -1.87207,0.541913 -0.3979,0 -0.76928,-0.06063 -0.37139,-0.06063 -0.74656,-0.185691 v -1.0573 q 0.35623,0.204639 0.69729,0.303169 0.34106,0.102319 0.68592,0.102319 0.66697,0 0.97772,-0.291799 0.31074,-0.2918 0.31074,-0.913295 z m -0.89434,-2.641354 q -0.42065,0 -0.6556,0.310748 -0.23496,0.310747 -0.23496,0.879188 0,0.583599 0.22738,0.886767 0.22737,0.299379 0.66318,0.299379 0.42443,0 0.65939,-0.310747 0.23495,-0.310748 0.23495,-0.875399 0,-0.568441 -0.23495,-0.879188 -0.23496,-0.310748 -0.65939,-0.310748 z" />
+ <path
+ id="path1292"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 111.76748,86.318397 v 0.38654 h -3.17189 q 0.0493,0.47749 0.34485,0.716235 0.29559,0.238745 0.82613,0.238745 0.42823,0 0.8754,-0.125057 0.45096,-0.128847 0.92467,-0.38654 v 1.045931 q -0.48128,0.181901 -0.96256,0.272852 -0.48128,0.09474 -0.96256,0.09474 -1.15204,0 -1.79249,-0.583599 -0.63665,-0.587389 -0.63665,-1.644689 0,-1.038351 0.62528,-1.633319 0.62908,-0.594968 1.72806,-0.594968 1.00046,0 1.59922,0.602547 0.60254,0.602547 0.60254,1.610582 z m -1.39457,-0.450963 q 0,-0.38654 -0.22738,-0.621495 -0.22358,-0.238745 -0.58738,-0.238745 -0.39412,0 -0.64045,0.223586 -0.24632,0.219798 -0.30696,0.636654 z" />
+ <path
+ id="path1294"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 117.51631,85.075407 q -0.45096,0 -0.6897,0.325906 -0.23496,0.322116 -0.23496,0.932242 0,0.610127 0.23496,0.936033 0.23874,0.322116 0.6897,0.322116 0.44339,0 0.67834,-0.322116 0.23496,-0.325906 0.23496,-0.936033 0,-0.610126 -0.23496,-0.932242 -0.23495,-0.325906 -0.67834,-0.325906 z m 0,-0.970139 q 1.0952,0 1.70912,0.591178 0.6177,0.591179 0.6177,1.637109 0,1.045931 -0.6177,1.637109 -0.61392,0.591179 -1.70912,0.591179 -1.09898,0 -1.72048,-0.591179 -0.6177,-0.591178 -0.6177,-1.637109 0,-1.04593 0.6177,-1.637109 0.6215,-0.591178 1.72048,-0.591178 z" />
+ <path
+ id="path1296"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 122.18511,87.838028 v 2.228288 h -1.35668 v -5.858729 h 1.35668 v 0.621495 q 0.28043,-0.371381 0.62149,-0.545703 0.34107,-0.178111 0.78445,-0.178111 0.78445,0 1.28847,0.625285 0.50401,0.621495 0.50401,1.603002 0,0.981508 -0.50401,1.606793 -0.50402,0.621495 -1.28847,0.621495 -0.44338,0 -0.78445,-0.174322 -0.34106,-0.178111 -0.62149,-0.549493 z m 0.90192,-2.747463 q -0.4358,0 -0.67076,0.322116 -0.23116,0.318327 -0.23116,0.920874 0,0.602547 0.23116,0.924664 0.23496,0.318327 0.67076,0.318327 0.43581,0 0.66318,-0.318327 0.23117,-0.318327 0.23117,-0.924664 0,-0.606336 -0.23117,-0.924663 -0.22737,-0.318327 -0.66318,-0.318327 z" />
+ <path
+ id="path1298"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 127.86573,83.002493 v 1.205094 h 1.39836 v 0.970139 h -1.39836 v 1.800062 q 0,0.295589 0.11747,0.401698 0.11748,0.10232 0.46612,0.10232 h 0.69729 v 0.970138 h -1.16341 q -0.80339,0 -1.14067,-0.333485 -0.33348,-0.337275 -0.33348,-1.140671 v -1.800062 h -0.67455 v -0.970139 h 0.67455 v -1.205094 z" />
+ <path
+ id="path1300"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 130.09401,84.207587 h 1.35668 v 4.244357 h -1.35668 z m 0,-1.652267 h 1.35668 v 1.106564 h -1.35668 z" />
+ <path
+ id="path1302"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 134.77417,85.075407 q -0.45096,0 -0.68971,0.325906 -0.23495,0.322116 -0.23495,0.932242 0,0.610127 0.23495,0.936033 0.23875,0.322116 0.68971,0.322116 0.44339,0 0.67834,-0.322116 0.23496,-0.325906 0.23496,-0.936033 0,-0.610126 -0.23496,-0.932242 -0.23495,-0.325906 -0.67834,-0.325906 z m 0,-0.970139 q 1.0952,0 1.70911,0.591178 0.61771,0.591179 0.61771,1.637109 0,1.045931 -0.61771,1.637109 -0.61391,0.591179 -1.70911,0.591179 -1.09898,0 -1.72048,-0.591179 -0.6177,-0.591178 -0.6177,-1.637109 0,-1.04593 0.6177,-1.637109 0.6215,-0.591178 1.72048,-0.591178 z" />
+ <path
+ id="path1304"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 142.35338,85.867434 v 2.58451 h -1.36426 v -0.420646 -1.557527 q 0,-0.549493 -0.0265,-0.757921 -0.0227,-0.208428 -0.0834,-0.306958 -0.0796,-0.132636 -0.21601,-0.204639 -0.13643,-0.07579 -0.31075,-0.07579 -0.42444,0 -0.66697,0.329696 -0.24253,0.325906 -0.24253,0.905715 v 2.088072 h -1.35668 v -4.244357 h 1.35668 v 0.621495 q 0.30695,-0.371381 0.65181,-0.545703 0.34485,-0.178111 0.76171,-0.178111 0.73518,0 1.11414,0.450963 0.38275,0.450963 0.38275,1.311203 z" />
+ <path
+ id="path1306"
+ style="fill:#000000;stroke-width:0.105503"
+ d="m 146.92743,84.340223 v 1.030773 q -0.4358,-0.181901 -0.84129,-0.272852 -0.40549,-0.09095 -0.7655,-0.09095 -0.38654,0 -0.57602,0.09853 -0.18569,0.09474 -0.18569,0.295589 0,0.162953 0.14022,0.250114 0.144,0.08716 0.51159,0.128846 l 0.23875,0.03411 q 1.04214,0.132636 1.40215,0.435804 0.36001,0.303168 0.36001,0.951191 0,0.678339 -0.50022,1.019403 -0.50023,0.341065 -1.49311,0.341065 -0.42065,0 -0.87161,-0.06821 -0.44717,-0.06442 -0.92087,-0.19706 v -1.030772 q 0.40549,0.197059 0.82992,0.295589 0.42823,0.09853 0.86782,0.09853 0.39791,0 0.59876,-0.109899 0.20085,-0.109898 0.20085,-0.325906 0,-0.181901 -0.14022,-0.269062 -0.13642,-0.09095 -0.54949,-0.140215 l -0.23875,-0.03032 q -0.90571,-0.113688 -1.26951,-0.420646 -0.36381,-0.306958 -0.36381,-0.932242 0,-0.67455 0.46234,-1.000456 0.46233,-0.325906 1.41731,-0.325906 0.37517,0 0.78824,0.05684 0.41306,0.05684 0.89813,0.178111 z" />
+ </g>
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ id="text1939"
+ aria-label="Value Space and
+Behaviour">
+ <path
+ id="path1209"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -41.05733,73.092678 h 1.466577 l 1.500683,4.176144 1.496894,-4.176144 h 1.466577 l -2.095652,5.657879 h -1.739428 z" />
+ <path
+ id="path1211"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -32.958945,76.840596 q -0.424436,0 -0.640444,0.144005 -0.212217,0.144005 -0.212217,0.424436 0,0.257693 0.170532,0.405488 0.174322,0.144005 0.48128,0.144005 0.38275,0 0.644232,-0.272852 0.261483,-0.276641 0.261483,-0.689708 V 76.840596 Z M -30.886032,76.329 v 2.421557 h -1.368047 v -0.629074 q -0.272851,0.386539 -0.613916,0.564651 -0.341064,0.174321 -0.829923,0.174321 -0.659391,0 -1.072458,-0.38275 -0.409278,-0.386539 -0.409278,-1.000455 0,-0.746552 0.511597,-1.095196 0.515386,-0.348643 1.614371,-0.348643 h 0.799607 v -0.106109 q 0,-0.322117 -0.253903,-0.469911 -0.253904,-0.151584 -0.792028,-0.151584 -0.435804,0 -0.810975,0.08716 -0.375171,0.08716 -0.697287,0.261483 v -1.034562 q 0.435804,-0.106109 0.875398,-0.159163 0.439594,-0.05684 0.879188,-0.05684 1.148251,0 1.656058,0.454752 0.511596,0.450963 0.511596,1.470367 z" />
+ <path
+ id="path1213"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -29.624094,72.853932 h 1.356679 v 5.896625 h -1.356679 z" />
+ <path
+ id="path1215"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="M -27.009267,77.098289 V 74.5062 h 1.364258 v 0.424436 q 0,0.344854 -0.0038,0.867819 -0.0038,0.519176 -0.0038,0.693498 0,0.511596 0.02653,0.738973 0.02653,0.223586 0.09095,0.325906 0.08337,0.132636 0.216008,0.204638 0.136426,0.072 0.310747,0.072 0.424436,0 0.666971,-0.325906 0.242534,-0.325906 0.242534,-0.905716 V 74.5062 h 1.356679 v 4.244357 h -1.356679 v -0.613916 q -0.306958,0.371381 -0.651812,0.549493 -0.341064,0.174321 -0.754131,0.174321 -0.735183,0 -1.121723,-0.450962 -0.38275,-0.450963 -0.38275,-1.311204 z" />
+ <path
+ id="path1217"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -17.201771,76.61701 v 0.386539 h -3.171899 q 0.04927,0.47749 0.344854,0.716236 0.295589,0.238745 0.826134,0.238745 0.428225,0 0.875399,-0.125057 0.450962,-0.128847 0.924663,-0.38654 v 1.045931 q -0.48128,0.181901 -0.96256,0.272851 -0.481279,0.09474 -0.962559,0.09474 -1.15204,0 -1.792483,-0.583599 -0.636653,-0.587388 -0.636653,-1.644688 0,-1.038352 0.625284,-1.633319 0.629075,-0.594968 1.72806,-0.594968 1.000455,0 1.599213,0.602547 0.602547,0.602547 0.602547,1.610582 z m -1.394574,-0.450963 q 0,-0.38654 -0.227377,-0.621495 -0.223586,-0.238745 -0.587388,-0.238745 -0.394119,0 -0.640443,0.223586 -0.246325,0.219797 -0.306958,0.636654 z" />
+ <path
+ id="path1219"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -9.4747663,73.270789 v 1.197515 q -0.4661213,-0.208428 -0.9095047,-0.314537 -0.443384,-0.106109 -0.837503,-0.106109 -0.522965,0 -0.773079,0.144005 -0.250114,0.144005 -0.250114,0.447173 0,0.227376 0.166742,0.356223 0.170533,0.125057 0.613916,0.216007 l 0.621496,0.125057 q 0.943611,0.189481 1.3415195,0.57602 0.3979084,0.38654 0.3979084,1.098986 0,0.936032 -0.5570718,1.394574 -0.5532821,0.454752 -1.6939531,0.454752 -0.538124,0 -1.080037,-0.102319 -0.541914,-0.102319 -1.083827,-0.303168 v -1.231622 q 0.541913,0.28801 1.045931,0.435805 0.507807,0.144005 0.977718,0.144005 0.47749,0 0.731393,-0.159164 0.253904,-0.159163 0.253904,-0.454752 0,-0.265272 -0.174322,-0.409277 -0.170532,-0.144005 -0.685918,-0.257693 l -0.564652,-0.125057 q -0.848871,-0.181901 -1.24299,-0.57981 -0.390329,-0.397908 -0.390329,-1.072458 0,-0.845082 0.545703,-1.299834 0.545703,-0.454753 1.568896,-0.454753 0.466122,0 0.95877,0.072 0.492649,0.06821 1.0194037,0.208428 z" />
+ <path
+ id="path1221"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -6.5264561,78.136641 v 2.228287 H -7.8831345 V 74.5062 h 1.3566784 v 0.621495 q 0.2804307,-0.371381 0.6214951,-0.545703 0.3410644,-0.178111 0.7844481,-0.178111 0.7844481,0 1.2884655,0.625284 0.5040174,0.621496 0.5040174,1.603003 0,0.981508 -0.5040174,1.606792 -0.5040174,0.621495 -1.2884655,0.621495 -0.4433837,0 -0.7844481,-0.174321 -0.3410644,-0.178112 -0.6214951,-0.549493 z m 0.9019258,-2.747463 q -0.4358045,0 -0.6707599,0.322116 -0.2311659,0.318327 -0.2311659,0.920874 0,0.602547 0.2311659,0.924664 0.2349554,0.318326 0.6707599,0.318326 0.4358046,0 0.6631808,-0.318326 0.2311659,-0.318327 0.2311659,-0.924664 0,-0.606337 -0.2311659,-0.924663 -0.2273762,-0.318327 -0.6631808,-0.318327 z" />
+ <path
+ id="path1223"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -0.425192,76.840596 q -0.4244357,0 -0.6404431,0.144005 -0.2122179,0.144005 -0.2122179,0.424436 0,0.257693 0.1705322,0.405488 0.1743218,0.144005 0.48127976,0.144005 0.38275005,0 0.64423275,-0.272852 0.26148271,-0.276641 0.26148271,-0.689708 V 76.840596 Z M 1.6477216,76.329 v 2.421557 H 0.27967442 v -0.629074 q -0.27285152,0.386539 -0.61391592,0.564651 -0.3410644,0.174321 -0.8299234,0.174321 -0.6593911,0 -1.072458,-0.38275 -0.4092773,-0.386539 -0.4092773,-1.000455 0,-0.746552 0.5115966,-1.095196 0.5153862,-0.348643 1.61437149,-0.348643 h 0.79960653 v -0.106109 q 0,-0.322117 -0.2539035,-0.469911 -0.2539035,-0.151584 -0.79202732,-0.151584 -0.4358045,0 -0.8109753,0.08716 -0.3751709,0.08716 -0.6972873,0.261483 v -1.034562 q 0.4358046,-0.106109 0.8753987,-0.159163 0.43959407,-0.05684 0.87918819,-0.05684 1.14825013,0 1.65605711,0.454752 0.5115966,0.450963 0.5115966,1.470367 z" />
+ <path
+ id="path1225"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m 6.3392508,74.638836 v 1.106565 Q 6.0626097,75.55592 5.7821789,75.46497 q -0.2766411,-0.09095 -0.5760198,-0.09095 -0.5684407,0 -0.8867675,0.333486 -0.3145371,0.329695 -0.3145371,0.924663 0,0.594968 0.3145371,0.928453 0.3183268,0.329696 0.8867675,0.329696 0.3183267,0 0.6025471,-0.09474 0.2880099,-0.09474 0.5305446,-0.280431 V 78.6255 q -0.3183268,0.117478 -0.6480224,0.174322 -0.325906,0.06063 -0.6556015,0.06063 -1.1482502,0 -1.7962725,-0.587388 -0.6480224,-0.591178 -0.6480224,-1.640899 0,-1.04972 0.6480224,-1.637109 0.6480223,-0.591178 1.7962725,-0.591178 0.3334852,0 0.6556015,0.06063 0.325906,0.05684 0.6480224,0.174322 z" />
+ <path
+ id="path1227"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m 11.747019,76.61701 v 0.386539 H 8.5751198 q 0.049265,0.47749 0.344854,0.716236 0.2955891,0.238745 0.8261337,0.238745 0.4282255,0 0.8753985,-0.125057 0.450963,-0.128847 0.924664,-0.38654 v 1.045931 q -0.48128,0.181901 -0.96256,0.272851 -0.48128,0.09474 -0.9625594,0.09474 -1.1520398,0 -1.7924829,-0.583599 -0.6366536,-0.587388 -0.6366536,-1.644688 0,-1.038352 0.6252848,-1.633319 0.6290743,-0.594968 1.7280596,-0.594968 1.0004555,0 1.5992135,0.602547 0.602547,0.602547 0.602547,1.610582 z m -1.394575,-0.450963 q 0,-0.38654 -0.227376,-0.621495 -0.2235867,-0.238745 -0.5873887,-0.238745 -0.3941189,0 -0.6404432,0.223586 -0.2463243,0.219797 -0.3069579,0.636654 z" />
+ <path
+ id="path1229"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m 17.37837,76.840596 q -0.424436,0 -0.640443,0.144005 -0.212218,0.144005 -0.212218,0.424436 0,0.257693 0.170532,0.405488 0.174322,0.144005 0.48128,0.144005 0.38275,0 0.644233,-0.272852 0.261483,-0.276641 0.261483,-0.689708 V 76.840596 Z M 19.451284,76.329 v 2.421557 h -1.368047 v -0.629074 q -0.272852,0.386539 -0.613916,0.564651 -0.341065,0.174321 -0.829924,0.174321 -0.659391,0 -1.072458,-0.38275 -0.409277,-0.386539 -0.409277,-1.000455 0,-0.746552 0.511597,-1.095196 0.515386,-0.348643 1.614371,-0.348643 h 0.799607 v -0.106109 q 0,-0.322117 -0.253904,-0.469911 -0.253903,-0.151584 -0.792027,-0.151584 -0.435805,0 -0.810976,0.08716 -0.37517,0.08716 -0.697287,0.261483 v -1.034562 q 0.435805,-0.106109 0.875399,-0.159163 0.439594,-0.05684 0.879188,-0.05684 1.14825,0 1.656057,0.454752 0.511597,0.450963 0.511597,1.470367 z" />
+ <path
+ id="path1231"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m 24.980316,76.166047 v 2.58451 h -1.364258 v -0.420646 -1.557528 q 0,-0.549492 -0.02653,-0.75792 -0.02274,-0.208429 -0.08337,-0.306958 -0.07958,-0.132637 -0.216007,-0.204639 -0.136426,-0.07579 -0.310748,-0.07579 -0.424435,0 -0.66697,0.329695 -0.242535,0.325906 -0.242535,0.905716 v 2.088072 H 20.713221 V 74.5062 h 1.356678 v 0.621495 q 0.306958,-0.371381 0.651812,-0.545703 0.344854,-0.178111 0.761711,-0.178111 0.735183,0 1.114143,0.450963 0.382751,0.450963 0.382751,1.311203 z" />
+ <path
+ id="path1233"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m 29.126141,75.127695 v -2.273763 h 1.364258 v 5.896625 h -1.364258 v -0.613916 q -0.28043,0.375171 -0.617705,0.549493 -0.337275,0.174321 -0.780659,0.174321 -0.784448,0 -1.288465,-0.621495 -0.504018,-0.625284 -0.504018,-1.606792 0,-0.981507 0.504018,-1.603003 0.504017,-0.625284 1.288465,-0.625284 0.439594,0 0.776869,0.178111 0.341065,0.174322 0.621495,0.545703 z m -0.894346,2.747463 q 0.435804,0 0.66318,-0.318326 0.231166,-0.318327 0.231166,-0.924664 0,-0.606337 -0.231166,-0.924663 -0.227376,-0.318327 -0.66318,-0.318327 -0.432015,0 -0.663181,0.318327 -0.227376,0.318326 -0.227376,0.924663 0,0.606337 0.227376,0.924664 0.231166,0.318326 0.663181,0.318326 z" />
+ <path
+ id="path1235"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -38.116597,84.984456 q 0.344854,0 0.522965,-0.151584 0.178112,-0.151584 0.178112,-0.447173 0,-0.2918 -0.178112,-0.443384 -0.178111,-0.155374 -0.522965,-0.155374 h -0.807186 v 1.197515 z m 0.04926,2.474612 q 0.439594,0 0.659391,-0.185691 0.223586,-0.18569 0.223586,-0.560861 0,-0.367592 -0.219797,-0.549493 -0.219797,-0.18569 -0.66318,-0.18569 h -0.856451 v 1.481735 z m 1.356678,-2.035018 q 0.469911,0.136426 0.727604,0.504018 0.257693,0.367591 0.257693,0.901926 0,0.818554 -0.553282,1.220252 -0.553282,0.401698 -1.682584,0.401698 h -2.421558 v -5.657879 h 2.190392 q 1.178567,0 1.705322,0.356223 0.530544,0.356222 0.530544,1.140671 0,0.413066 -0.19327,0.704866 -0.193269,0.28801 -0.560861,0.428225 z" />
+ <path
+ id="path1237"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -30.291064,86.318397 v 0.38654 h -3.171899 q 0.04927,0.47749 0.344854,0.716235 0.295589,0.238745 0.826134,0.238745 0.428225,0 0.875399,-0.125057 0.450962,-0.128847 0.924663,-0.38654 v 1.045931 q -0.48128,0.181901 -0.96256,0.272852 -0.481279,0.09474 -0.962559,0.09474 -1.15204,0 -1.792483,-0.583599 -0.636653,-0.587389 -0.636653,-1.644689 0,-1.038351 0.625284,-1.633319 0.629075,-0.594968 1.72806,-0.594968 1.000455,0 1.599213,0.602547 0.602547,0.602547 0.602547,1.610582 z m -1.394574,-0.450963 q 0,-0.38654 -0.227377,-0.621495 -0.223586,-0.238745 -0.587388,-0.238745 -0.394119,0 -0.640443,0.223586 -0.246325,0.219798 -0.306958,0.636654 z" />
+ <path
+ id="path1239"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -24.996987,85.867434 v 2.58451 h -1.364258 V 88.031298 86.48135 q 0,-0.557072 -0.02653,-0.7655 -0.02274,-0.208428 -0.08337,-0.306958 -0.07958,-0.132636 -0.216008,-0.204639 -0.136425,-0.07579 -0.310747,-0.07579 -0.424436,0 -0.666971,0.329696 -0.242534,0.325906 -0.242534,0.905715 v 2.088072 h -1.356679 V 82.55532 h 1.356679 v 2.273762 q 0.306958,-0.371381 0.651812,-0.545703 0.344854,-0.178111 0.76171,-0.178111 0.735183,0 1.114144,0.450963 0.38275,0.450963 0.38275,1.311203 z" />
+ <path
+ id="path1241"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -21.836456,86.541984 q -0.424436,0 -0.640444,0.144005 -0.212217,0.144005 -0.212217,0.424435 0,0.257693 0.170532,0.405488 0.174322,0.144005 0.48128,0.144005 0.38275,0 0.644232,-0.272852 0.261483,-0.276641 0.261483,-0.689708 v -0.155373 z m 2.072913,-0.511597 v 2.421557 H -21.13159 V 87.82287 q -0.272852,0.38654 -0.613916,0.564651 -0.341064,0.174322 -0.829923,0.174322 -0.659391,0 -1.072458,-0.38275 -0.409278,-0.38654 -0.409278,-1.000456 0,-0.746552 0.511597,-1.095196 0.515386,-0.348643 1.614371,-0.348643 h 0.799607 v -0.106109 q 0,-0.322116 -0.253903,-0.469911 -0.253904,-0.151584 -0.792028,-0.151584 -0.435804,0 -0.810975,0.08716 -0.375171,0.08716 -0.697287,0.261482 v -1.034562 q 0.435804,-0.106108 0.875398,-0.159163 0.439594,-0.05684 0.879188,-0.05684 1.148251,0 1.656058,0.454753 0.511596,0.450962 0.511596,1.470366 z" />
+ <path
+ id="path1243"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -19.035938,84.207587 h 1.356678 l 1.0573,2.933154 1.05351,-2.933154 h 1.360468 l -1.671215,4.244357 h -1.489315 z" />
+ <path
+ id="path1245"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -13.442484,84.207587 h 1.356679 v 4.244357 h -1.356679 z m 0,-1.652267 h 1.356679 v 1.106564 h -1.356679 z" />
+ <path
+ id="path1247"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -8.7623213,85.075407 q -0.4509629,0 -0.689708,0.325906 -0.2349555,0.322116 -0.2349555,0.932242 0,0.610127 0.2349555,0.936033 0.2387451,0.322116 0.689708,0.322116 0.4433837,0 0.6783392,-0.322116 0.2349555,-0.325906 0.2349555,-0.936033 0,-0.610126 -0.2349555,-0.932242 -0.2349555,-0.325906 -0.6783392,-0.325906 z m 0,-0.970139 q 1.0951957,0 1.7091116,0.591178 0.6177055,0.591179 0.6177055,1.637109 0,1.045931 -0.6177055,1.637109 -0.6139159,0.591179 -1.7091116,0.591179 -1.0989853,0 -1.7204807,-0.591179 -0.617705,-0.591178 -0.617705,-1.637109 0,-1.04593 0.617705,-1.637109 0.6214954,-0.591178 1.7204807,-0.591178 z" />
+ <path
+ id="path1249"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -5.4956836,86.799677 v -2.59209 h 1.3642576 v 0.424436 q 0,0.344854 -0.00379,0.867819 -0.00379,0.519176 -0.00379,0.693498 0,0.511597 0.026527,0.738973 0.026527,0.223587 0.09095,0.325906 0.083371,0.132636 0.2160074,0.204638 0.1364258,0.072 0.3107476,0.072 0.4244357,0 0.6669703,-0.325906 0.2425347,-0.325906 0.2425347,-0.905715 v -2.095652 h 1.3566784 v 4.244357 h -1.3566784 v -0.613916 q -0.3069579,0.371382 -0.6518119,0.549493 -0.3410644,0.174322 -0.7541313,0.174322 -0.7351833,0 -1.1217229,-0.450963 -0.3827501,-0.450963 -0.3827501,-1.311203 z" />
+ <path
+ id="path1251"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m 3.2279882,85.363417 q -0.1781114,-0.08337 -0.3562228,-0.121268 -0.1743218,-0.04169 -0.3524332,-0.04169 -0.5229654,0 -0.8071857,0.337274 -0.2804308,0.333486 -0.2804308,0.95877 v 1.955436 H 0.07503736 V 84.207587 H 1.4317157 v 0.697288 q 0.2614827,-0.416857 0.5987575,-0.606337 0.3410644,-0.19327 0.814765,-0.19327 0.068213,0 0.1477946,0.0076 0.079582,0.0038 0.2311658,0.02274 z" />
+ </g>
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ id="text1968"
+ aria-label="type">
+ <path
+ id="path1200"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -12.982713,110.86802 q -0.340778,0.22526 -0.825954,0.36965 -0.485175,0.1444 -1.051213,0.1444 -1.120524,0 -1.686562,-0.57759 -0.566038,-0.58336 -0.566038,-1.54794 v -3.08433 h -1.328456 v -1.08009 h 1.328456 v -1.34579 l 1.524837,-0.18482 v 1.53061 h 2.021564 l -0.155949,1.08009 h -1.865615 v 3.07855 q 0,0.47363 0.231036,0.69311 0.231036,0.21949 0.74509,0.21949 0.329227,0 0.600694,-0.0751 0.277243,-0.0809 0.502503,-0.20216 z" />
+ <path
+ id="path1202"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -5.7917378,105.09212 -2.0735471,6.12823 q -0.3754333,1.12052 -1.1147482,1.76742 -0.7393148,0.65268 -2.0677709,0.74509 l -0.190605,-1.1032 q 0.612245,-0.0866 0.981903,-0.25991 0.375433,-0.17328 0.5949171,-0.4563 0.22526,-0.28302 0.3869851,-0.70466 h -0.5198308 l -2.0042364,-6.11667 h 1.611475 l 1.3862158,5.10012 1.4439743,-5.10012 z" />
+ <path
+ id="path1204"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -1.2403471,104.91884 q 0.80284968,0 1.29380094,0.39854 0.49095126,0.39276 0.71043535,1.12052 0.22525999,0.72199 0.22525999,1.69812 0,0.94147 -0.27146716,1.67501 -0.27146717,0.73354 -0.79707382,1.15518 -0.51983075,0.41586 -1.2822492,0.41586 -0.9356953,0 -1.513285,-0.66423 v 2.84752 l -1.5248369,0.16172 v -8.63496 h 1.3400081 l 0.080863,0.74509 q 0.3581056,-0.47362 0.8086256,-0.69311 0.4562959,-0.22526 0.9299195,-0.22526 z m -0.4447441,1.14363 q -0.3869851,0 -0.6815559,0.23104 -0.2887948,0.23103 -0.5082789,0.57181 v 2.73777 q 0.4216405,0.6238 1.0743168,0.6238 0.5833657,0 0.88948821,-0.48517 0.31189844,-0.49096 0.31189844,-1.58838 0,-1.16095 -0.27724306,-1.62302 -0.27724309,-0.46785 -0.80862559,-0.46785 z" />
+ <path
+ id="path1206"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 3.8308738,108.61542 q 0.069311,0.8606 0.508279,1.24181 0.4389681,0.38121 1.0685409,0.38121 0.4389682,0 0.8259533,-0.13862 0.3869852,-0.13862 0.7624185,-0.38698 l 0.6353487,0.87216 q -0.4274164,0.3581 -1.0223338,0.57759 -0.5891416,0.21948 -1.2995769,0.21948 -0.9934543,0 -1.6750102,-0.41009 -0.67578,-0.41009 -1.0223338,-1.13785 -0.3465538,-0.72776 -0.3465538,-1.67501 0,-0.91259 0.335002,-1.64613 0.3407779,-0.73354 0.9819025,-1.16096 0.6469005,-0.43319 1.5537164,-0.43319 1.2591456,0 1.9984604,0.82018 0.7393148,0.82018 0.7393148,2.26993 0,0.335 -0.028879,0.60647 z m 1.3111287,-2.62226 q -0.5544862,0 -0.9125918,0.39854 -0.3523297,0.39853 -0.4158646,1.24759 h 2.5760502 q -0.011552,-0.77397 -0.3176744,-1.20716 -0.3061225,-0.43897 -0.9299194,-0.43897 z" />
+ </g>
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ id="text1972"
+ aria-label="instance">
+ <path
+ id="path1183"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 123.54934,104.04259 q 0.41586,0 0.68156,0.25991 0.26569,0.25992 0.26569,0.6469 0,0.38699 -0.26569,0.65268 -0.2657,0.25991 -0.68156,0.25991 -0.42164,0 -0.68733,-0.25991 -0.26569,-0.26569 -0.26569,-0.65268 0,-0.38698 0.26569,-0.6469 0.26569,-0.25991 0.68733,-0.25991 z m 0.98768,3.08433 v 5.03658 h 1.61147 v 1.08009 h -4.92684 v -1.08009 h 1.79053 v -3.95649 h -1.73277 v -1.08009 z" />
+ <path
+ id="path1185"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 127.95056,113.24359 v -6.11667 h 1.32845 l 0.10974,0.75664 q 0.7913,-0.92992 1.94071,-0.92992 0.82017,0 1.25337,0.4794 0.43896,0.47362 0.43896,1.33423 v 4.47632 h -1.52483 v -3.8814 q 0,-0.69311 -0.1444,-0.9819 -0.13862,-0.2888 -0.60069,-0.2888 -0.37544,0 -0.69889,0.23681 -0.32345,0.23681 -0.57759,0.57759 v 4.3377 z" />
+ <path
+ id="path1187"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 137.2093,112.29057 q 0.53716,0 0.86061,-0.18483 0.32923,-0.18483 0.32923,-0.53138 0,-0.21949 -0.10974,-0.37544 -0.10397,-0.16172 -0.41587,-0.29457 -0.3119,-0.13862 -0.93569,-0.30612 -0.58915,-0.15017 -1.03389,-0.36966 -0.43897,-0.22526 -0.68733,-0.57759 -0.24259,-0.35233 -0.24259,-0.88948 0,-0.79708 0.67001,-1.29958 0.67,-0.50828 1.87139,-0.50828 0.78552,0 1.37466,0.20793 0.58914,0.20216 1.01078,0.50828 l -0.6238,0.92992 q -0.36965,-0.23681 -0.80285,-0.38121 -0.42741,-0.15017 -0.92414,-0.15017 -0.53716,0 -0.78552,0.15595 -0.24259,0.15595 -0.24259,0.43319 0,0.19638 0.1213,0.335 0.12707,0.13285 0.45052,0.25992 0.32922,0.12129 0.93569,0.29457 0.59492,0.1675 1.03389,0.38698 0.44474,0.21949 0.68733,0.58337 0.24259,0.3581 0.24259,0.94724 0,0.66423 -0.38699,1.09743 -0.38698,0.43319 -1.02233,0.6469 -0.63535,0.20793 -1.36889,0.20793 -0.86639,0 -1.51329,-0.24837 -0.6469,-0.24836 -1.09742,-0.64112 l 0.7913,-0.88949 q 0.35811,0.28302 0.8144,0.46785 0.46207,0.18483 0.99923,0.18483 z" />
+ <path
+ id="path1189"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 147.09185,112.90281 q -0.34078,0.22526 -0.82596,0.36966 -0.48517,0.1444 -1.05121,0.1444 -1.12052,0 -1.68656,-0.57759 -0.56604,-0.58337 -0.56604,-1.54794 v -3.08433 h -1.32846 v -1.08009 h 1.32846 v -1.34579 l 1.52484,-0.18483 v 1.53062 h 2.02156 l -0.15595,1.08009 h -1.86561 v 3.07855 q 0,0.47363 0.23103,0.69311 0.23104,0.21948 0.74509,0.21948 0.32923,0 0.6007,-0.0751 0.27724,-0.0809 0.5025,-0.20216 z" />
+ <path
+ id="path1191"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 153.62437,111.63212 q 0,0.35233 0.10397,0.51405 0.10396,0.16173 0.335,0.23681 l -0.32923,1.02234 q -0.48517,-0.052 -0.83173,-0.24259 -0.34655,-0.19638 -0.53138,-0.58337 -0.34655,0.42164 -0.87794,0.62958 -0.5256,0.20793 -1.10319,0.20793 -0.9357,0 -1.48441,-0.53138 -0.54871,-0.53139 -0.54871,-1.38044 0,-0.97613 0.76242,-1.50174 0.7682,-0.53138 2.17174,-0.53138 h 0.85483 v -0.32923 q 0,-0.54293 -0.34078,-0.78552 -0.335,-0.24836 -0.9588,-0.24836 -0.29457,0 -0.73931,0.0809 -0.44474,0.0751 -0.90682,0.23681 l -0.36388,-1.04543 q 0.58337,-0.21949 1.17251,-0.32345 0.59492,-0.10397 1.08009,-0.10397 1.28803,0 1.91182,0.54871 0.6238,0.54293 0.6238,1.54216 z m -2.73777,0.68155 q 0.34655,0 0.69888,-0.1906 0.35233,-0.19638 0.56026,-0.55449 v -1.18983 h -0.60069 q -0.84906,0 -1.23027,0.27146 -0.37543,0.27147 -0.37543,0.7682 0,0.89526 0.94725,0.89526 z" />
+ <path
+ id="path1193"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 155.6748,113.24359 v -6.11667 h 1.32845 l 0.10974,0.75664 q 0.7913,-0.92992 1.94071,-0.92992 0.82017,0 1.25337,0.4794 0.43896,0.47362 0.43896,1.33423 v 4.47632 h -1.52483 v -3.8814 q 0,-0.69311 -0.1444,-0.9819 -0.13862,-0.2888 -0.60069,-0.2888 -0.37544,0 -0.69889,0.23681 -0.32345,0.23681 -0.57759,0.57759 v 4.3377 z" />
+ <path
+ id="path1195"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 165.68441,112.19238 q 0.40431,0 0.75664,-0.15018 0.35233,-0.15017 0.68733,-0.3812 l 0.69311,0.97612 q -0.40431,0.34078 -0.97612,0.56026 -0.57182,0.21949 -1.22449,0.21949 -0.96458,0 -1.65191,-0.39854 -0.68156,-0.39854 -1.04544,-1.12052 -0.36388,-0.72199 -0.36388,-1.67501 0,-0.94147 0.36966,-1.68079 0.37543,-0.73931 1.06276,-1.16095 0.69311,-0.42742 1.65191,-0.42742 0.65845,0 1.18983,0.1906 0.53716,0.18483 0.98191,0.55449 l -0.67578,0.9357 q -0.34078,-0.23104 -0.70466,-0.35811 -0.36388,-0.12707 -0.74509,-0.12707 -0.67578,0 -1.1032,0.49095 -0.42164,0.48518 -0.42164,1.5826 0,1.08587 0.43319,1.53061 0.43319,0.43897 1.08587,0.43897 z" />
+ <path
+ id="path1197"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 170.83649,110.65021 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76242,-0.38699 l 0.63535,0.87216 q -0.42742,0.35811 -1.02234,0.57759 -0.58914,0.21949 -1.29958,0.21949 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34655,-0.72777 -0.34655,-1.67501 0,-0.91259 0.335,-1.64613 0.34078,-0.73354 0.9819,-1.16096 0.6469,-0.43319 1.55372,-0.43319 1.25914,0 1.99846,0.82018 0.73931,0.82017 0.73931,2.26992 0,0.33501 -0.0289,0.60647 z m 1.31113,-2.62225 q -0.55448,0 -0.91259,0.39853 -0.35233,0.39854 -0.41586,1.2476 h 2.57605 q -0.0115,-0.77397 -0.31768,-1.20717 -0.30612,-0.43896 -0.92992,-0.43896 z" />
+ </g>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path1974"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m -60.569299,125.94806 h 72.698771 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -72.698771 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z" />
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ id="text1980"
+ aria-label="ABC">
+ <path
+ id="path1176"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -29.753207,138.03049 h -2.628033 l -0.496728,1.83096 h -1.634579 l 2.500964,-7.98807 h 1.940701 l 2.495188,7.98807 h -1.680786 z m -2.345015,-1.18406 h 2.050444 l -1.022334,-3.78899 z" />
+ <path
+ id="path1178"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -21.112481,137.54532 q 0,0.67578 -0.265692,1.1263 -0.259915,0.44474 -0.710435,0.71043 -0.45052,0.25992 -1.022334,0.36966 -0.571814,0.10974 -1.184059,0.10974 h -2.47786 v -7.98807 h 2.333463 q 0.779746,0 1.455526,0.18483 0.681556,0.18483 1.103196,0.62958 0.421641,0.43896 0.421641,1.21871 0,0.49095 -0.207932,0.84328 -0.202157,0.34656 -0.542935,0.56604 -0.335002,0.21948 -0.721987,0.31767 0.433192,0.0693 0.849057,0.27147 0.42164,0.19638 0.693108,0.59492 0.277243,0.39276 0.277243,1.04544 z m -1.946478,-3.5002 q 0,-0.54293 -0.340778,-0.77974 -0.340778,-0.23682 -0.993454,-0.23682 h -0.797074 v 2.10821 h 0.866385 q 0.641124,0 0.953023,-0.25414 0.311898,-0.25992 0.311898,-0.83751 z m 0.306123,3.45976 q 0,-0.72776 -0.415865,-0.98767 -0.410088,-0.2657 -1.039661,-0.2657 h -0.981903 v 2.42588 h 0.912592 q 0.381209,0 0.727763,-0.0866 0.35233,-0.0924 0.571814,-0.34078 0.22526,-0.25413 0.22526,-0.74509 z" />
+ <path
+ id="path1180"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -16.514884,131.70011 q 0.83173,0 1.409319,0.21948 0.57759,0.21371 1.068541,0.61802 l -0.802849,0.95303 q -0.346554,-0.28302 -0.750867,-0.4332 -0.404313,-0.15595 -0.866385,-0.15595 -0.560262,0 -1.028109,0.29457 -0.462072,0.29458 -0.739315,0.94725 -0.277243,0.6469 -0.277243,1.70967 0,1.04543 0.265691,1.69234 0.271467,0.64112 0.733539,0.94147 0.467848,0.30034 1.056989,0.30034 0.623797,0 1.033886,-0.2137 0.415864,-0.21949 0.739315,-0.48518 l 0.74509,0.94147 q -0.42164,0.41587 -1.056989,0.71044 -0.629573,0.29457 -1.530613,0.29457 -1.045437,0 -1.865614,-0.47363 -0.820178,-0.4794 -1.288025,-1.40932 -0.467848,-0.93569 -0.467848,-2.2988 0,-1.34001 0.479399,-2.26415 0.485176,-0.92992 1.305353,-1.40932 0.825953,-0.4794 1.836735,-0.4794 z" />
+ </g>
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ id="text1984"
+ aria-label="instance">
+ <path
+ id="path1159"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 183.76608,131.26282 q 0.41587,0 0.68156,0.25991 0.26569,0.25992 0.26569,0.6469 0,0.38699 -0.26569,0.65268 -0.26569,0.25991 -0.68156,0.25991 -0.42164,0 -0.68733,-0.25991 -0.26569,-0.26569 -0.26569,-0.65268 0,-0.38698 0.26569,-0.6469 0.26569,-0.25991 0.68733,-0.25991 z m 0.98768,3.08433 v 5.03658 h 1.61148 v 1.08009 h -4.92684 v -1.08009 h 1.79052 v -3.95649 h -1.73276 v -1.08009 z" />
+ <path
+ id="path1161"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 188.1673,140.46382 v -6.11667 h 1.32846 l 0.10974,0.75664 q 0.7913,-0.92992 1.9407,-0.92992 0.82018,0 1.25337,0.4794 0.43897,0.47362 0.43897,1.33423 v 4.47632 h -1.52484 v -3.8814 q 0,-0.69311 -0.1444,-0.9819 -0.13862,-0.2888 -0.60069,-0.2888 -0.37543,0 -0.69888,0.23681 -0.32345,0.23681 -0.57759,0.57759 v 4.3377 z" />
+ <path
+ id="path1163"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 197.42605,139.5108 q 0.53716,0 0.86061,-0.18483 0.32922,-0.18483 0.32922,-0.53138 0,-0.21949 -0.10974,-0.37544 -0.10397,-0.16172 -0.41586,-0.29457 -0.3119,-0.13862 -0.9357,-0.30612 -0.58914,-0.15017 -1.03389,-0.36966 -0.43896,-0.22526 -0.68733,-0.57759 -0.24259,-0.35233 -0.24259,-0.88948 0,-0.79708 0.67001,-1.29958 0.67,-0.50828 1.87139,-0.50828 0.78552,0 1.37466,0.20793 0.58914,0.20216 1.01078,0.50828 l -0.62379,0.92992 q -0.36966,-0.23681 -0.80285,-0.38121 -0.42742,-0.15017 -0.92415,-0.15017 -0.53715,0 -0.78552,0.15595 -0.24258,0.15595 -0.24258,0.43319 0,0.19638 0.12129,0.335 0.12707,0.13285 0.45052,0.25992 0.32923,0.12129 0.93569,0.29457 0.59492,0.1675 1.03389,0.38698 0.44474,0.21949 0.68733,0.58337 0.24259,0.3581 0.24259,0.94725 0,0.66422 -0.38699,1.09742 -0.38698,0.43319 -1.02233,0.6469 -0.63535,0.20793 -1.36889,0.20793 -0.86638,0 -1.51328,-0.24837 -0.6469,-0.24836 -1.09742,-0.64112 l 0.7913,-0.88949 q 0.3581,0.28302 0.8144,0.46785 0.46207,0.18483 0.99923,0.18483 z" />
+ <path
+ id="path1165"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 207.30859,140.12304 q -0.34078,0.22526 -0.82595,0.36966 -0.48518,0.1444 -1.05122,0.1444 -1.12052,0 -1.68656,-0.57759 -0.56604,-0.58337 -0.56604,-1.54794 v -3.08433 h -1.32845 v -1.08009 h 1.32845 v -1.34579 l 1.52484,-0.18483 v 1.53062 h 2.02156 l -0.15594,1.08009 h -1.86562 v 3.07855 q 0,0.47363 0.23104,0.69311 0.23103,0.21948 0.74509,0.21948 0.32922,0 0.60069,-0.0751 0.27724,-0.0809 0.5025,-0.20216 z" />
+ <path
+ id="path1167"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 213.84111,138.85235 q 0,0.35233 0.10397,0.51405 0.10397,0.16173 0.335,0.23681 l -0.32922,1.02234 q -0.48518,-0.052 -0.83173,-0.24259 -0.34656,-0.19638 -0.53139,-0.58337 -0.34655,0.42164 -0.87793,0.62958 -0.52561,0.20793 -1.1032,0.20793 -0.93569,0 -1.4844,-0.53138 -0.54871,-0.53139 -0.54871,-1.38044 0,-0.97613 0.76241,-1.50174 0.7682,-0.53138 2.17174,-0.53138 h 0.85483 v -0.32923 q 0,-0.54293 -0.34077,-0.78552 -0.33501,-0.24836 -0.9588,-0.24836 -0.29457,0 -0.73932,0.0809 -0.44474,0.0751 -0.90681,0.23681 l -0.36388,-1.04543 q 0.58336,-0.21949 1.1725,-0.32345 0.59492,-0.10397 1.0801,-0.10397 1.28802,0 1.91182,0.54871 0.62379,0.54293 0.62379,1.54216 z m -2.73777,0.68155 q 0.34655,0 0.69888,-0.1906 0.35233,-0.19638 0.56026,-0.55449 v -1.18983 h -0.60069 q -0.84906,0 -1.23027,0.27146 -0.37543,0.27147 -0.37543,0.7682 0,0.89526 0.94725,0.89526 z" />
+ <path
+ id="path1169"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 215.89154,140.46382 v -6.11667 H 217.22 l 0.10974,0.75664 q 0.7913,-0.92992 1.9407,-0.92992 0.82018,0 1.25337,0.4794 0.43897,0.47362 0.43897,1.33423 v 4.47632 h -1.52484 v -3.8814 q 0,-0.69311 -0.1444,-0.9819 -0.13862,-0.2888 -0.60069,-0.2888 -0.37543,0 -0.69888,0.23681 -0.32345,0.23681 -0.57759,0.57759 v 4.3377 z" />
+ <path
+ id="path1171"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 225.90115,139.41261 q 0.40432,0 0.75665,-0.15018 0.35233,-0.15017 0.68733,-0.3812 l 0.69311,0.97612 q -0.40432,0.34078 -0.97613,0.56026 -0.57181,0.21949 -1.22449,0.21949 -0.96458,0 -1.65191,-0.39854 -0.68155,-0.39854 -1.04544,-1.12052 -0.36388,-0.72199 -0.36388,-1.67501 0,-0.94147 0.36966,-1.68079 0.37543,-0.73931 1.06277,-1.16095 0.6931,-0.42742 1.6519,-0.42742 0.65845,0 1.18984,0.1906 0.53716,0.18483 0.9819,0.55449 l -0.67578,0.9357 q -0.34078,-0.23104 -0.70466,-0.35811 -0.36388,-0.12707 -0.74509,-0.12707 -0.67578,0 -1.1032,0.49095 -0.42164,0.48518 -0.42164,1.5826 0,1.08587 0.4332,1.53061 0.43319,0.43897 1.08586,0.43897 z" />
+ <path
+ id="path1173"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ d="m 231.05324,137.87044 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82595,-0.13862 0.38699,-0.13862 0.76242,-0.38699 l 0.63535,0.87216 q -0.42742,0.35811 -1.02234,0.57759 -0.58914,0.21949 -1.29957,0.21949 -0.99346,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02234,-1.13785 -0.34655,-0.72777 -0.34655,-1.67501 0,-0.91259 0.335,-1.64613 0.34078,-0.73354 0.9819,-1.16096 0.64691,-0.43319 1.55372,-0.43319 1.25915,0 1.99846,0.82018 0.73932,0.82017 0.73932,2.26992 0,0.33501 -0.0289,0.60647 z m 1.31113,-2.62225 q -0.55449,0 -0.91259,0.39853 -0.35233,0.39854 -0.41587,1.2476 h 2.57605 q -0.0115,-0.77397 -0.31767,-1.20717 -0.30613,-0.43896 -0.92992,-0.43896 z" />
+ </g>
+ <path
+ d="M 17.347598,126.00309 H 170.2081 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 17.347598 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path1986"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ id="text1990"
+ aria-label="type">
+ <path
+ id="path1150"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 86.078604,138.14328 q -0.340778,0.22526 -0.825953,0.36965 -0.485176,0.1444 -1.051214,0.1444 -1.120524,0 -1.686562,-0.57759 -0.566038,-0.58336 -0.566038,-1.54794 v -3.08433 h -1.328456 v -1.08009 h 1.328456 v -1.34578 l 1.524837,-0.18483 v 1.53061 h 2.021564 l -0.155949,1.08009 h -1.865615 v 3.07856 q 0,0.47362 0.231036,0.6931 0.231036,0.21949 0.745091,0.21949 0.329226,0 0.600693,-0.0751 0.277243,-0.0809 0.502503,-0.20216 z" />
+ <path
+ id="path1152"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 93.26958,132.36738 -2.073547,6.12823 q -0.375434,1.12052 -1.114749,1.76742 -0.739314,0.65268 -2.067771,0.74509 l -0.190604,-1.10319 q 0.612245,-0.0866 0.981902,-0.25992 0.375433,-0.17328 0.594918,-0.4563 0.22526,-0.28301 0.386985,-0.70466 h -0.519831 l -2.004236,-6.11667 h 1.611475 l 1.386215,5.10012 1.443974,-5.10012 z" />
+ <path
+ id="path1154"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 97.82097,132.1941 q 0.80285,0 1.293801,0.39854 0.490952,0.39276 0.710436,1.12052 0.225263,0.72199 0.225263,1.69812 0,0.94147 -0.271471,1.67501 -0.271467,0.73354 -0.797073,1.15518 -0.519831,0.41586 -1.28225,0.41586 -0.935695,0 -1.513285,-0.66423 v 2.84752 l -1.524836,0.16173 v -8.63497 h 1.340008 l 0.08086,0.74509 q 0.358106,-0.47362 0.808626,-0.69311 0.456296,-0.22526 0.929919,-0.22526 z m -0.444744,1.14363 q -0.386985,0 -0.681556,0.23104 -0.288795,0.23103 -0.508279,0.57181 v 2.73778 q 0.421641,0.62379 1.074317,0.62379 0.583366,0 0.889488,-0.48517 0.311899,-0.49095 0.311899,-1.58838 0,-1.16095 -0.277243,-1.62302 -0.277243,-0.46785 -0.808626,-0.46785 z" />
+ <path
+ id="path1156"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 102.89219,135.89068 q 0.0693,0.86061 0.50828,1.24181 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82595,-0.13862 0.38699,-0.13862 0.76242,-0.38698 l 0.63535,0.87216 q -0.42741,0.3581 -1.02233,0.57759 -0.58914,0.21948 -1.29958,0.21948 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34656,-0.72776 -0.34656,-1.67501 0,-0.91259 0.33501,-1.64613 0.34077,-0.73354 0.9819,-1.16096 0.6469,-0.43319 1.55371,-0.43319 1.25915,0 1.99846,0.82018 0.73932,0.82018 0.73932,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55449,0 -0.91259,0.39854 -0.35233,0.39853 -0.41587,1.24759 h 2.57605 q -0.0115,-0.77397 -0.31767,-1.20716 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ </g>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path1992"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="M -60.569299,153.16829 H 49.987465 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H -60.569299 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z" />
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ id="text1998"
+ aria-label="DType">
+ <path
+ id="path1139"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -16.103363,161.78806 q 0,1.23027 -0.32345,2.02157 -0.323451,0.78552 -0.866385,1.22449 -0.542934,0.43897 -1.218714,0.61224 -0.670004,0.17328 -1.368888,0.17328 h -2.044668 v -7.98806 h 1.906046 q 0.745091,0 1.443975,0.16172 0.698883,0.15595 1.253369,0.57759 0.560262,0.42164 0.889489,1.20139 0.329226,0.77397 0.329226,2.01578 z m -1.651907,0 q 0,-0.88948 -0.167501,-1.43819 -0.161725,-0.54871 -0.444744,-0.83751 -0.283019,-0.29457 -0.641125,-0.39854 -0.358105,-0.10396 -0.74509,-0.10396 h -0.589142 v 5.63727 h 0.594918 q 0.542934,0 0.993454,-0.23681 0.45052,-0.23681 0.721987,-0.85483 0.277243,-0.6238 0.277243,-1.76743 z" />
+ <path
+ id="path1141"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -11.482662,159.07339 v 6.74625 h -1.57682 v -6.74625 h -2.333462 v -1.24181 h 6.3130554 l -0.1617251,1.24181 z" />
+ <path
+ id="path1143"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -2.3221052,159.70297 -2.0735471,6.12822 q -0.3754333,1.12053 -1.1147481,1.76743 -0.7393149,0.65267 -2.0677712,0.74509 l -0.1906046,-1.1032 q 0.6122451,-0.0866 0.9819025,-0.25991 0.3754333,-0.17328 0.5949174,-0.4563 0.22526,-0.28302 0.3869851,-0.70466 h -0.5198307 l -2.0042364,-6.11667 h 1.6114754 l 1.3862153,5.10011 1.4439743,-5.10011 z" />
+ <path
+ id="path1145"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 2.229285,159.52969 q 0.8028497,0 1.293801,0.39854 0.4909512,0.39276 0.7104353,1.12052 0.22526,0.72199 0.22526,1.69811 0,0.94148 -0.2714671,1.67501 -0.2714672,0.73354 -0.7970738,1.15518 -0.5198308,0.41587 -1.2822492,0.41587 -0.9356954,0 -1.51328509,-0.66423 v 2.84752 l -1.52483686,0.16172 v -8.63496 H 0.4098774 l 0.0808626,0.74509 q 0.35810562,-0.47363 0.80862564,-0.69311 0.4562958,-0.22526 0.9299194,-0.22526 z m -0.4447441,1.14363 q -0.3869851,0 -0.6815558,0.23103 -0.2887949,0.23104 -0.50827899,0.57182 v 2.73777 q 0.42164049,0.6238 1.07431689,0.6238 0.5833656,0 0.8894882,-0.48518 0.3118984,-0.49095 0.3118984,-1.58837 0,-1.16095 -0.2772431,-1.62303 -0.277243,-0.46784 -0.8086256,-0.46784 z" />
+ <path
+ id="path1147"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 7.3005069,163.22626 q 0.069311,0.86061 0.508279,1.24182 0.4389681,0.38121 1.0685409,0.38121 0.4389682,0 0.8259533,-0.13862 0.3869849,-0.13862 0.7624189,-0.38699 l 0.635348,0.87216 q -0.427416,0.35811 -1.022334,0.57759 -0.5891411,0.21949 -1.2995764,0.21949 -0.9934543,0 -1.6750102,-0.41009 -0.67578,-0.41009 -1.0223338,-1.13785 -0.3465538,-0.72777 -0.3465538,-1.67501 0,-0.91259 0.335002,-1.64613 0.3407779,-0.73354 0.9819025,-1.16096 0.6469005,-0.43319 1.5537164,-0.43319 1.2591456,0 1.9984603,0.82018 0.739315,0.82017 0.739315,2.26992 0,0.33501 -0.02888,0.60647 z m 1.3111287,-2.62225 q -0.5544862,0 -0.9125918,0.39853 -0.3523297,0.39854 -0.4158646,1.2476 h 2.5760502 q -0.011552,-0.77397 -0.3176744,-1.20717 -0.3061225,-0.43896 -0.9299194,-0.43896 z" />
+ </g>
+ <path
+ d="m -60.569299,180.38852 h 72.698771 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -72.698771 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 V 182.4536 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path2004"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ d="m 175.57697,180.55362 h 65.38081 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -65.38081 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796078;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path2006"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ id="text2010"
+ aria-label="base dtype">
+ <path
+ id="path1120"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -56.5562,187.97729 q 0.306123,-0.39854 0.721988,-0.62957 0.42164,-0.23104 0.906816,-0.23104 1.19561,0 1.732769,0.87794 0.537158,0.87216 0.537158,2.33923 0,0.94148 -0.277243,1.67501 -0.277243,0.73354 -0.825953,1.15518 -0.542935,0.41587 -1.334233,0.41587 -0.99923,0 -1.565268,-0.75664 l -0.06931,0.58336 h -1.35156 v -8.55988 l 1.524836,-0.16172 z m 1.068541,4.46477 q 0.583366,0 0.912592,-0.49673 0.329226,-0.49673 0.329226,-1.59415 0,-1.16095 -0.300346,-1.62303 -0.300347,-0.46784 -0.825954,-0.46784 -0.381209,0 -0.67578,0.23103 -0.288794,0.23104 -0.508279,0.57182 v 2.73777 q 0.196381,0.30612 0.462072,0.47363 0.265692,0.1675 0.606469,0.1675 z" />
+ <path
+ id="path1122"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -46.269343,191.79516 q 0,0.35233 0.103966,0.51405 0.103966,0.16173 0.335002,0.23681 l -0.329226,1.02234 q -0.485175,-0.052 -0.831729,-0.24259 -0.346554,-0.19638 -0.531383,-0.58337 -0.346553,0.42164 -0.877936,0.62958 -0.525607,0.20793 -1.103196,0.20793 -0.935696,0 -1.484406,-0.53138 -0.54871,-0.53139 -0.54871,-1.38044 0,-0.97613 0.762418,-1.50174 0.768195,-0.53138 2.171738,-0.53138 h 0.854832 v -0.32923 q 0,-0.54293 -0.340778,-0.78552 -0.335002,-0.24836 -0.958798,-0.24836 -0.294571,0 -0.739315,0.0809 -0.444744,0.0751 -0.906816,0.23681 l -0.363882,-1.04543 q 0.583366,-0.21949 1.172507,-0.32345 0.594918,-0.10397 1.080093,-0.10397 1.288025,0 1.911822,0.54871 0.623797,0.54293 0.623797,1.54216 z m -2.737775,0.68155 q 0.346554,0 0.698883,-0.1906 0.35233,-0.19638 0.560262,-0.55449 v -1.18983 h -0.600693 q -0.849057,0 -1.230266,0.27146 -0.375433,0.27147 -0.375433,0.7682 0,0.89526 0.947247,0.89526 z" />
+ <path
+ id="path1124"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -41.891229,192.45361 q 0.537158,0 0.860609,-0.18483 0.329226,-0.18483 0.329226,-0.53138 0,-0.21949 -0.109742,-0.37544 -0.103967,-0.16172 -0.415865,-0.29457 -0.311898,-0.13862 -0.935695,-0.30612 -0.589142,-0.15017 -1.033886,-0.36966 -0.438968,-0.22526 -0.687332,-0.57759 -0.242587,-0.35233 -0.242587,-0.88948 0,-0.79708 0.670004,-1.29958 0.670004,-0.50828 1.87139,-0.50828 0.785522,0 1.374664,0.20793 0.589141,0.20216 1.010782,0.50828 l -0.623797,0.92992 q -0.369657,-0.23681 -0.80285,-0.38121 -0.427416,-0.15017 -0.924143,-0.15017 -0.537159,0 -0.785522,0.15595 -0.242588,0.15595 -0.242588,0.43319 0,0.19638 0.121294,0.335 0.12707,0.13285 0.45052,0.25992 0.329226,0.12129 0.935695,0.29457 0.594918,0.1675 1.033886,0.38698 0.444744,0.21949 0.687332,0.58337 0.242587,0.3581 0.242587,0.94725 0,0.66422 -0.386985,1.09742 -0.386985,0.43319 -1.022334,0.6469 -0.635348,0.20793 -1.368887,0.20793 -0.866385,0 -1.513285,-0.24837 -0.646901,-0.24836 -1.097421,-0.64112 l 0.791298,-0.88949 q 0.358106,0.28302 0.814402,0.46785 0.462071,0.18483 0.99923,0.18483 z" />
+ <path
+ id="path1126"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -35.988279,190.81325 q 0.06931,0.86061 0.508279,1.24182 0.438968,0.38121 1.068541,0.38121 0.438968,0 0.825953,-0.13862 0.386985,-0.13862 0.762419,-0.38699 l 0.635348,0.87216 q -0.427416,0.35811 -1.022333,0.57759 -0.589142,0.21949 -1.299577,0.21949 -0.993455,0 -1.675011,-0.41009 -0.67578,-0.41009 -1.022333,-1.13785 -0.346554,-0.72777 -0.346554,-1.67501 0,-0.91259 0.335002,-1.64613 0.340778,-0.73354 0.981902,-1.16096 0.646901,-0.43319 1.553717,-0.43319 1.259145,0 1.99846,0.82018 0.739315,0.82017 0.739315,2.26992 0,0.33501 -0.02888,0.60647 z m 1.311129,-2.62225 q -0.554486,0 -0.912592,0.39853 -0.35233,0.39854 -0.415865,1.2476 h 2.57605 q -0.01155,-0.77397 -0.317674,-1.20717 -0.306122,-0.43896 -0.929919,-0.43896 z" />
+ <path
+ id="path1128"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -19.879335,184.68503 1.524837,0.16172 v 8.55988 h -1.35156 l -0.09242,-0.72199 q -0.283019,0.40432 -0.710435,0.65268 -0.427417,0.24259 -0.993454,0.24259 -0.773971,0 -1.28225,-0.40431 -0.502503,-0.40432 -0.750866,-1.13208 -0.242588,-0.73354 -0.242588,-1.70389 0,-0.92992 0.288795,-1.65768 0.294571,-0.73354 0.837505,-1.14941 0.542934,-0.41586 1.293801,-0.41586 0.895264,0 1.47863,0.61802 z m -1.068541,3.5695 q -0.57759,0 -0.912592,0.5025 -0.329226,0.49673 -0.329226,1.58838 0,1.15518 0.306122,1.62302 0.306123,0.46785 0.825954,0.46785 0.381209,0 0.670004,-0.22526 0.288795,-0.23104 0.508279,-0.57181 v -2.78399 q -0.213709,-0.28301 -0.4794,-0.43896 -0.259915,-0.16173 -0.589141,-0.16173 z" />
+ <path
+ id="path1130"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -11.215505,193.06585 q -0.340778,0.22526 -0.825954,0.36966 -0.485175,0.1444 -1.051213,0.1444 -1.120524,0 -1.686562,-0.57759 -0.566038,-0.58337 -0.566038,-1.54794 v -3.08433 h -1.328456 v -1.08009 h 1.328456 v -1.34579 l 1.524837,-0.18483 v 1.53062 h 2.021564 l -0.155949,1.08009 h -1.865615 v 3.07855 q 0,0.47363 0.231036,0.69311 0.231036,0.21948 0.745091,0.21948 0.329226,0 0.600693,-0.0751 0.277243,-0.0809 0.502503,-0.20216 z" />
+ <path
+ id="path1132"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m -4.0245292,187.28996 -2.0735471,6.12822 q -0.3754333,1.12053 -1.1147482,1.76743 -0.7393148,0.65267 -2.0677712,0.74509 l -0.1906046,-1.1032 q 0.6122451,-0.0866 0.9819025,-0.25991 0.3754334,-0.17328 0.5949175,-0.4563 0.2252599,-0.28302 0.3869851,-0.70466 H -8.027226 l -2.004236,-6.11667 h 1.611475 l 1.3862153,5.10011 1.4439743,-5.10011 z" />
+ <path
+ id="path1134"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 0.52686192,187.11668 q 0.80284968,0 1.29380098,0.39854 0.4909513,0.39276 0.7104353,1.12052 0.22526,0.72199 0.22526,1.69811 0,0.94148 -0.2714671,1.67501 -0.2714672,0.73354 -0.7970738,1.15518 -0.5198308,0.41587 -1.28224922,0.41587 -0.93569535,0 -1.51328508,-0.66423 v 2.84752 l -1.5248368,0.16172 v -8.63496 h 1.3400081 l 0.080863,0.74509 q 0.35810559,-0.47363 0.80862557,-0.69311 0.45629588,-0.22526 0.92991945,-0.22526 z m -0.44474409,1.14363 q -0.38698511,0 -0.68155586,0.23103 -0.28879486,0.23104 -0.50827897,0.57182 v 2.73777 q 0.42164051,0.6238 1.07431689,0.6238 0.58336562,0 0.88948817,-0.48518 0.31189844,-0.49095 0.31189844,-1.58837 0,-1.16095 -0.27724306,-1.62303 -0.27724306,-0.46784 -0.80862561,-0.46784 z" />
+ <path
+ id="path1136"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 5.5980838,190.81325 q 0.069311,0.86061 0.508279,1.24182 0.4389682,0.38121 1.0685409,0.38121 0.4389682,0 0.8259533,-0.13862 0.3869852,-0.13862 0.7624185,-0.38699 l 0.6353487,0.87216 q -0.4274164,0.35811 -1.0223338,0.57759 -0.5891416,0.21949 -1.2995769,0.21949 -0.9934543,0 -1.6750102,-0.41009 -0.67578,-0.41009 -1.0223338,-1.13785 -0.3465538,-0.72777 -0.3465538,-1.67501 0,-0.91259 0.335002,-1.64613 0.3407779,-0.73354 0.9819025,-1.16096 0.6469005,-0.43319 1.5537164,-0.43319 1.2591456,0 1.9984604,0.82018 0.7393149,0.82017 0.7393149,2.26992 0,0.33501 -0.02888,0.60647 z M 6.9092125,188.191 q -0.5544862,0 -0.9125918,0.39853 -0.3523297,0.39854 -0.4158646,1.2476 H 8.1568063 Q 8.1452545,189.06316 7.8391319,188.62996 7.5330094,188.191 6.9092125,188.191 Z" />
+ </g>
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ id="text2014"
+ aria-label="element">
+ <path
+ id="path1105"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 186.26703,191.99035 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.3812 1.06854,0.3812 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76241,-0.38698 l 0.63535,0.87216 q -0.42741,0.3581 -1.02233,0.57759 -0.58914,0.21948 -1.29958,0.21948 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34656,-0.72776 -0.34656,-1.67501 0,-0.91259 0.33501,-1.64613 0.34077,-0.73354 0.9819,-1.16095 0.6469,-0.4332 1.55372,-0.4332 1.25914,0 1.99846,0.82018 0.73931,0.82018 0.73931,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55448,0 -0.91259,0.39854 -0.35233,0.39853 -0.41586,1.24759 h 2.57605 q -0.0116,-0.77397 -0.31768,-1.20716 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ <path
+ id="path1107"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 194.80957,186.02385 v 6.7809 q 0,0.39854 0.23681,0.56604 0.23681,0.1675 0.62957,0.1675 0.24837,0 0.4794,-0.052 0.23104,-0.0577 0.43897,-0.13862 l 0.37543,1.03966 q -0.28879,0.15018 -0.70466,0.25992 -0.41008,0.10974 -0.95302,0.10974 -0.99923,0 -1.51328,-0.57181 -0.51406,-0.57182 -0.51406,-1.54217 v -5.53908 h -1.83096 v -1.08009 z" />
+ <path
+ id="path1109"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 200.12915,191.99035 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.3812 1.06854,0.3812 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76242,-0.38698 l 0.63534,0.87216 q -0.42741,0.3581 -1.02233,0.57759 -0.58914,0.21948 -1.29958,0.21948 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34655,-0.72776 -0.34655,-1.67501 0,-0.91259 0.335,-1.64613 0.34078,-0.73354 0.9819,-1.16095 0.6469,-0.4332 1.55372,-0.4332 1.25914,0 1.99846,0.82018 0.73931,0.82018 0.73931,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55448,0 -0.91259,0.39854 -0.35233,0.39853 -0.41586,1.24759 h 2.57605 q -0.0116,-0.77397 -0.31768,-1.20716 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ <path
+ id="path1111"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 210.10989,188.29377 q 0.57759,0 0.91259,0.38699 0.335,0.38121 0.335,1.36889 v 4.53407 h -1.32846 v -4.34347 q 0,-0.41009 -0.0635,-0.58337 -0.0635,-0.17905 -0.30035,-0.17905 -0.1906,0 -0.38698,0.11552 -0.19638,0.10974 -0.39854,0.39854 v 4.59183 h -1.1494 v -4.34347 q 0,-0.41009 -0.0635,-0.58337 -0.0635,-0.17905 -0.30034,-0.17905 -0.19061,0 -0.38699,0.11552 -0.19638,0.10974 -0.39854,0.39854 v 4.59183 h -1.34578 v -6.11667 h 1.13785 l 0.0982,0.63535 q 0.27147,-0.37543 0.57182,-0.58914 0.30034,-0.21949 0.72198,-0.21949 0.34656,0 0.61225,0.17328 0.27147,0.1675 0.38698,0.57759 0.26569,-0.335 0.58914,-0.54293 0.32923,-0.20794 0.75665,-0.20794 z" />
+ <path
+ id="path1113"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 213.99127,191.99035 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.3812 1.06854,0.3812 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76242,-0.38698 l 0.63534,0.87216 q -0.42741,0.3581 -1.02233,0.57759 -0.58914,0.21948 -1.29958,0.21948 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34655,-0.72776 -0.34655,-1.67501 0,-0.91259 0.335,-1.64613 0.34078,-0.73354 0.9819,-1.16095 0.6469,-0.4332 1.55372,-0.4332 1.25914,0 1.99846,0.82018 0.73931,0.82018 0.73931,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55448,0 -0.91259,0.39854 -0.35233,0.39853 -0.41586,1.24759 H 216.55 q -0.0116,-0.77397 -0.31768,-1.20716 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ <path
+ id="path1115"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 219.62276,194.58372 v -6.11667 h 1.32845 l 0.10974,0.75664 q 0.7913,-0.92992 1.94071,-0.92992 0.82017,0 1.25337,0.4794 0.43896,0.47363 0.43896,1.33423 v 4.47632 h -1.52483 v -3.8814 q 0,-0.69311 -0.1444,-0.9819 -0.13862,-0.2888 -0.60069,-0.2888 -0.37544,0 -0.69889,0.23682 -0.32345,0.23681 -0.57759,0.57759 v 4.33769 z" />
+ <path
+ id="path1117"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 231.83299,194.24295 q -0.34078,0.22526 -0.82596,0.36965 -0.48517,0.1444 -1.05121,0.1444 -1.12052,0 -1.68656,-0.57759 -0.56604,-0.58336 -0.56604,-1.54794 v -3.08433 h -1.32846 v -1.08009 h 1.32846 v -1.34578 l 1.52484,-0.18483 v 1.53061 h 2.02156 l -0.15595,1.08009 h -1.86561 v 3.07856 q 0,0.47362 0.23103,0.6931 0.23104,0.21949 0.74509,0.21949 0.32923,0 0.6007,-0.0751 0.27724,-0.0809 0.5025,-0.20216 z" />
+ </g>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path2016"
+ style="opacity:0.25;fill:#000081;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="M 17.463123,180.38852 H 170.32495 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 17.463123 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 V 182.4536 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z" />
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ id="text2020"
+ aria-label="dtype">
+ <path
+ id="path1094"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 81.083132,184.68503 1.524837,0.16172 v 8.55988 h -1.35156 l -0.09242,-0.72199 q -0.283019,0.40432 -0.710435,0.65268 -0.427416,0.24259 -0.993454,0.24259 -0.77397,0 -1.282249,-0.40431 -0.502503,-0.40432 -0.750867,-1.13208 -0.242588,-0.73354 -0.242588,-1.70389 0,-0.92992 0.288795,-1.65768 0.294571,-0.73354 0.837505,-1.14941 0.542935,-0.41586 1.293801,-0.41586 0.895264,0 1.47863,0.61802 z m -1.068541,3.5695 q -0.57759,0 -0.912592,0.5025 -0.329226,0.49673 -0.329226,1.58838 0,1.15518 0.306123,1.62302 0.306122,0.46785 0.825953,0.46785 0.381209,0 0.670004,-0.22526 0.288795,-0.23104 0.508279,-0.57181 v -2.78399 q -0.213708,-0.28301 -0.4794,-0.43896 -0.259915,-0.16173 -0.589141,-0.16173 z" />
+ <path
+ id="path1096"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 89.746961,193.06585 q -0.340778,0.22526 -0.825953,0.36966 -0.485175,0.1444 -1.051213,0.1444 -1.120524,0 -1.686562,-0.57759 -0.566038,-0.58337 -0.566038,-1.54794 v -3.08433 h -1.328457 v -1.08009 h 1.328457 v -1.34579 l 1.524837,-0.18483 v 1.53062 h 2.021564 l -0.15595,1.08009 h -1.865614 v 3.07855 q 0,0.47363 0.231036,0.69311 0.231035,0.21948 0.74509,0.21948 0.329226,0 0.600694,-0.0751 0.277243,-0.0809 0.502503,-0.20216 z" />
+ <path
+ id="path1098"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 96.937937,187.28996 -2.073547,6.12822 q -0.375433,1.12053 -1.114748,1.76743 -0.739315,0.65267 -2.067771,0.74509 l -0.190605,-1.1032 q 0.612245,-0.0866 0.981902,-0.25991 0.375434,-0.17328 0.594918,-0.4563 0.22526,-0.28302 0.386985,-0.70466 H 92.93524 l -2.004236,-6.11667 h 1.611475 l 1.386216,5.10011 1.443974,-5.10011 z" />
+ <path
+ id="path1100"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 101.48933,187.11668 q 0.80285,0 1.2938,0.39854 0.49095,0.39276 0.71043,1.12052 0.22526,0.72199 0.22526,1.69811 0,0.94148 -0.27146,1.67501 -0.27147,0.73354 -0.79708,1.15518 -0.51983,0.41587 -1.28225,0.41587 -0.93569,0 -1.513282,-0.66423 v 2.84752 l -1.524837,0.16172 v -8.63496 h 1.340009 l 0.08086,0.74509 q 0.358108,-0.47363 0.808628,-0.69311 0.45629,-0.22526 0.92992,-0.22526 z m -0.44475,1.14363 q -0.38698,0 -0.68155,0.23103 -0.2888,0.23104 -0.508282,0.57182 v 2.73777 q 0.421642,0.6238 1.074322,0.6238 0.58336,0 0.88948,-0.48518 0.3119,-0.49095 0.3119,-1.58837 0,-1.16095 -0.27724,-1.62303 -0.27724,-0.46784 -0.80863,-0.46784 z" />
+ <path
+ id="path1102"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ d="m 106.56055,190.81325 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82595,-0.13862 0.38699,-0.13862 0.76242,-0.38699 l 0.63535,0.87216 q -0.42742,0.35811 -1.02233,0.57759 -0.58915,0.21949 -1.29958,0.21949 -0.99346,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02234,-1.13785 -0.34655,-0.72777 -0.34655,-1.67501 0,-0.91259 0.335,-1.64613 0.34078,-0.73354 0.98191,-1.16096 0.6469,-0.43319 1.55371,-0.43319 1.25915,0 1.99846,0.82018 0.73932,0.82017 0.73932,2.26992 0,0.33501 -0.0289,0.60647 z m 1.31113,-2.62225 q -0.55449,0 -0.91259,0.39853 -0.35233,0.39854 -0.41587,1.2476 h 2.57605 q -0.0115,-0.77397 -0.31767,-1.20717 -0.30613,-0.43896 -0.92992,-0.43896 z" />
+ </g>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path2022"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796078;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 175.57697,153.33338 h 65.38081 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -65.38081 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z" />
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ id="text2026"
+ aria-label="element">
+ <path
+ id="path1079"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 186.26703,164.7701 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76241,-0.38699 l 0.63535,0.87216 q -0.42741,0.35811 -1.02233,0.57759 -0.58914,0.21949 -1.29958,0.21949 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34656,-0.72777 -0.34656,-1.67501 0,-0.9126 0.33501,-1.64613 0.34077,-0.73354 0.9819,-1.16096 0.6469,-0.43319 1.55372,-0.43319 1.25914,0 1.99846,0.82017 0.73931,0.82018 0.73931,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55448,0 -0.91259,0.39854 -0.35233,0.39854 -0.41586,1.2476 h 2.57605 q -0.0116,-0.77398 -0.31768,-1.20717 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ <path
+ id="path1081"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 194.80957,158.8036 v 6.7809 q 0,0.39854 0.23681,0.56604 0.23681,0.1675 0.62957,0.1675 0.24837,0 0.4794,-0.052 0.23104,-0.0578 0.43897,-0.13862 l 0.37543,1.03966 q -0.28879,0.15017 -0.70466,0.25991 -0.41008,0.10975 -0.95302,0.10975 -0.99923,0 -1.51328,-0.57182 -0.51406,-0.57181 -0.51406,-1.54216 v -5.53909 h -1.83096 v -1.08009 z" />
+ <path
+ id="path1083"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 200.12915,164.7701 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76242,-0.38699 l 0.63534,0.87216 q -0.42741,0.35811 -1.02233,0.57759 -0.58914,0.21949 -1.29958,0.21949 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34655,-0.72777 -0.34655,-1.67501 0,-0.9126 0.335,-1.64613 0.34078,-0.73354 0.9819,-1.16096 0.6469,-0.43319 1.55372,-0.43319 1.25914,0 1.99846,0.82017 0.73931,0.82018 0.73931,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55448,0 -0.91259,0.39854 -0.35233,0.39854 -0.41586,1.2476 h 2.57605 q -0.0116,-0.77398 -0.31768,-1.20717 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ <path
+ id="path1085"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 210.10989,161.07353 q 0.57759,0 0.91259,0.38698 0.335,0.38121 0.335,1.36889 v 4.53408 h -1.32846 V 163.02 q 0,-0.41008 -0.0635,-0.58336 -0.0635,-0.17905 -0.30035,-0.17905 -0.1906,0 -0.38698,0.11551 -0.19638,0.10975 -0.39854,0.39854 v 4.59184 h -1.1494 V 163.02 q 0,-0.41008 -0.0635,-0.58336 -0.0635,-0.17905 -0.30034,-0.17905 -0.19061,0 -0.38699,0.11551 -0.19638,0.10975 -0.39854,0.39854 v 4.59184 h -1.34578 v -6.11668 h 1.13785 l 0.0982,0.63535 q 0.27147,-0.37543 0.57182,-0.58914 0.30034,-0.21948 0.72198,-0.21948 0.34656,0 0.61225,0.17327 0.27147,0.16751 0.38698,0.57759 0.26569,-0.335 0.58914,-0.54293 0.32923,-0.20793 0.75665,-0.20793 z" />
+ <path
+ id="path1087"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 213.99127,164.7701 q 0.0693,0.86061 0.50828,1.24182 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76242,-0.38699 l 0.63534,0.87216 q -0.42741,0.35811 -1.02233,0.57759 -0.58914,0.21949 -1.29958,0.21949 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34655,-0.72777 -0.34655,-1.67501 0,-0.9126 0.335,-1.64613 0.34078,-0.73354 0.9819,-1.16096 0.6469,-0.43319 1.55372,-0.43319 1.25914,0 1.99846,0.82017 0.73931,0.82018 0.73931,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55448,0 -0.91259,0.39854 -0.35233,0.39854 -0.41586,1.2476 H 216.55 q -0.0116,-0.77398 -0.31768,-1.20717 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ <path
+ id="path1089"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 219.62276,167.36348 v -6.11668 h 1.32845 l 0.10974,0.75665 q 0.7913,-0.92992 1.94071,-0.92992 0.82017,0 1.25337,0.4794 0.43896,0.47362 0.43896,1.33423 v 4.47632 h -1.52483 v -3.8814 q 0,-0.69311 -0.1444,-0.98191 -0.13862,-0.28879 -0.60069,-0.28879 -0.37544,0 -0.69889,0.23681 -0.32345,0.23681 -0.57759,0.57759 v 4.3377 z" />
+ <path
+ id="path1091"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ d="m 231.83299,167.0227 q -0.34078,0.22526 -0.82596,0.36966 -0.48517,0.1444 -1.05121,0.1444 -1.12052,0 -1.68656,-0.57759 -0.56604,-0.58337 -0.56604,-1.54794 v -3.08433 h -1.32846 v -1.0801 h 1.32846 v -1.34578 l 1.52484,-0.18483 v 1.53061 h 2.02156 l -0.15595,1.0801 h -1.86561 v 3.07855 q 0,0.47362 0.23103,0.69311 0.23104,0.21948 0.74509,0.21948 0.32923,0 0.6007,-0.0751 0.27724,-0.0809 0.5025,-0.20216 z" />
+ </g>
+ <path
+ d="M 55.175507,153.27835 H 170.22016 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 55.175507 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z"
+ style="opacity:0.25;fill:#d99b00;fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path2031"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <g
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ id="text2035"
+ aria-label="dtype">
+ <path
+ id="path1068"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ d="m 99.886927,157.49231 1.524833,0.16172 v 8.55988 h -1.35156 l -0.09241,-0.72198 q -0.283019,0.40431 -0.710435,0.65267 -0.427416,0.24259 -0.993454,0.24259 -0.773971,0 -1.28225,-0.40431 -0.502503,-0.40432 -0.750866,-1.13208 -0.242588,-0.73354 -0.242588,-1.70389 0,-0.92992 0.288795,-1.65768 0.294571,-0.73354 0.837505,-1.1494 0.542934,-0.41587 1.293801,-0.41587 0.895264,0 1.47863,0.61802 z m -1.068541,3.5695 q -0.57759,0 -0.912592,0.50251 -0.329226,0.49672 -0.329226,1.58837 0,1.15518 0.306122,1.62302 0.306123,0.46785 0.825954,0.46785 0.381209,0 0.670004,-0.22526 0.288795,-0.23103 0.508279,-0.57181 v -2.78398 q -0.213708,-0.28302 -0.4794,-0.43897 -0.259915,-0.16173 -0.589141,-0.16173 z" />
+ <path
+ id="path1070"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ d="m 108.55076,165.87314 q -0.34078,0.22526 -0.82596,0.36965 -0.48517,0.1444 -1.05121,0.1444 -1.12052,0 -1.68656,-0.57759 -0.56604,-0.58337 -0.56604,-1.54794 v -3.08433 h -1.32846 v -1.08009 h 1.32846 v -1.34579 l 1.52484,-0.18482 v 1.53061 h 2.02156 l -0.15595,1.08009 h -1.86561 v 3.07855 q 0,0.47363 0.23103,0.69311 0.23104,0.21949 0.74509,0.21949 0.32923,0 0.6007,-0.0751 0.27724,-0.0809 0.5025,-0.20216 z" />
+ <path
+ id="path1072"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ d="m 115.74173,160.09724 -2.07355,6.12822 q -0.37543,1.12053 -1.11474,1.76743 -0.73932,0.65268 -2.06777,0.74509 l -0.19061,-1.1032 q 0.61225,-0.0866 0.9819,-0.25991 0.37544,-0.17328 0.59492,-0.4563 0.22526,-0.28302 0.38699,-0.70466 h -0.51983 l -2.00424,-6.11667 h 1.61147 l 1.38622,5.10012 1.44397,-5.10012 z" />
+ <path
+ id="path1074"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ d="m 120.29312,159.92396 q 0.80285,0 1.2938,0.39854 0.49095,0.39276 0.71044,1.12052 0.22526,0.72199 0.22526,1.69812 0,0.94147 -0.27147,1.67501 -0.27147,0.73353 -0.79707,1.15518 -0.51983,0.41586 -1.28225,0.41586 -0.9357,0 -1.51329,-0.66423 v 2.84752 l -1.52483,0.16172 v -8.63496 h 1.34 l 0.0809,0.74509 q 0.3581,-0.47362 0.80862,-0.69311 0.4563,-0.22526 0.92992,-0.22526 z m -0.44474,1.14363 q -0.38699,0 -0.68156,0.23103 -0.28879,0.23104 -0.50828,0.57182 v 2.73777 q 0.42164,0.6238 1.07432,0.6238 0.58337,0 0.88949,-0.48517 0.3119,-0.49096 0.3119,-1.58838 0,-1.16095 -0.27725,-1.62302 -0.27724,-0.46785 -0.80862,-0.46785 z" />
+ <path
+ id="path1076"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ d="m 125.36434,163.62054 q 0.0693,0.8606 0.50828,1.24181 0.43897,0.38121 1.06854,0.38121 0.43897,0 0.82596,-0.13862 0.38698,-0.13862 0.76242,-0.38698 l 0.63534,0.87216 q -0.42741,0.3581 -1.02233,0.57759 -0.58914,0.21948 -1.29958,0.21948 -0.99345,0 -1.67501,-0.41009 -0.67578,-0.41009 -1.02233,-1.13785 -0.34655,-0.72776 -0.34655,-1.67501 0,-0.91259 0.335,-1.64613 0.34078,-0.73354 0.9819,-1.16096 0.6469,-0.43319 1.55372,-0.43319 1.25914,0 1.99846,0.82018 0.73931,0.82018 0.73931,2.26993 0,0.335 -0.0289,0.60647 z m 1.31113,-2.62226 q -0.55448,0 -0.91259,0.39853 -0.35233,0.39854 -0.41586,1.2476 h 2.57605 q -0.0116,-0.77397 -0.31768,-1.20716 -0.30612,-0.43897 -0.92992,-0.43897 z" />
+ </g>
+ <path
+ style="fill:none;stroke:#808080;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 52.572927,70.114137 V 205.33633"
+ id="path3042"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ id="text3050"
+ aria-label="Python type">
+ <path
+ id="path1047"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -121.47364,105.10011 h 2.42156 q 1.08004,0 1.65606,0.48128 0.57981,0.47749 0.57981,1.36426 0,0.89055 -0.57981,1.37183 -0.57602,0.47749 -1.65606,0.47749 h -0.96256 v 1.96302 h -1.459 z m 1.459,1.0573 v 1.58026 h 0.80719 q 0.42443,0 0.6556,-0.20464 0.23117,-0.20842 0.23117,-0.58738 0,-0.37896 -0.23117,-0.5836 -0.23117,-0.20464 -0.6556,-0.20464 z" />
+ <path
+ id="path1049"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -116.25914,106.51363 h 1.35668 l 1.14067,2.8801 0.97014,-2.8801 h 1.35668 l -1.78491,4.64606 q -0.26906,0.70865 -0.62907,0.98908 -0.35622,0.28422 -0.94361,0.28422 h -0.78445 v -0.89055 h 0.42443 q 0.34486,0 0.50023,-0.1099 0.15917,-0.1099 0.24633,-0.39412 l 0.0379,-0.11748 z" />
+ <path
+ id="path1051"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -109.16121,105.30854 v 1.20509 h 1.39836 v 0.97014 h -1.39836 v 1.80006 q 0,0.29559 0.11748,0.4017 0.11747,0.10232 0.46612,0.10232 h 0.69729 v 0.97014 h -1.16341 q -0.8034,0 -1.14067,-0.33349 -0.33349,-0.33727 -0.33349,-1.14067 v -1.80006 h -0.67455 v -0.97014 h 0.67455 v -1.20509 z" />
+ <path
+ id="path1053"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -102.66583,108.17348 v 2.58451 h -1.36426 v -0.42065 -1.54995 q 0,-0.55707 -0.0265,-0.7655 -0.0227,-0.20842 -0.0834,-0.30695 -0.0796,-0.13264 -0.21601,-0.20464 -0.13643,-0.0758 -0.31075,-0.0758 -0.42444,0 -0.66697,0.3297 -0.24253,0.32591 -0.24253,0.90572 v 2.08807 h -1.35668 v -5.89663 h 1.35668 v 2.27377 q 0.30695,-0.37139 0.65181,-0.54571 0.34485,-0.17811 0.76171,-0.17811 0.73518,0 1.11414,0.45096 0.38275,0.45097 0.38275,1.31121 z" />
+ <path
+ id="path1055"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -99.387821,107.38145 q -0.450963,0 -0.689709,0.32591 -0.23495,0.32211 -0.23495,0.93224 0,0.61013 0.23495,0.93603 0.238746,0.32212 0.689709,0.32212 0.443384,0 0.678339,-0.32212 0.234956,-0.3259 0.234956,-0.93603 0,-0.61013 -0.234956,-0.93224 -0.234955,-0.32591 -0.678339,-0.32591 z m 0,-0.97014 q 1.095196,0 1.709112,0.59118 0.617705,0.59118 0.617705,1.63711 0,1.04593 -0.617705,1.63711 -0.613916,0.59118 -1.709112,0.59118 -1.098989,0 -1.720479,-0.59118 -0.61771,-0.59118 -0.61771,-1.63711 0,-1.04593 0.61771,-1.63711 0.62149,-0.59118 1.720479,-0.59118 z" />
+ <path
+ id="path1057"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -91.808612,108.17348 v 2.58451 h -1.364257 v -0.42065 -1.55753 q 0,-0.54949 -0.02653,-0.75792 -0.02274,-0.20842 -0.08337,-0.30695 -0.07958,-0.13264 -0.216007,-0.20464 -0.136426,-0.0758 -0.310748,-0.0758 -0.424435,0 -0.66697,0.3297 -0.242535,0.32591 -0.242535,0.90572 v 2.08807 h -1.356678 v -4.24436 h 1.356678 v 0.6215 q 0.306958,-0.37139 0.651812,-0.54571 0.344854,-0.17811 0.761711,-0.17811 0.735183,0 1.114143,0.45096 0.38275,0.45097 0.38275,1.31121 z" />
+ <path
+ id="path1059"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -86.366739,105.30854 v 1.20509 h 1.398364 v 0.97014 h -1.398364 v 1.80006 q 0,0.29559 0.117478,0.4017 0.117478,0.10232 0.466121,0.10232 h 0.697287 v 0.97014 h -1.163408 q -0.803396,0 -1.140671,-0.33349 -0.333485,-0.33727 -0.333485,-1.14067 v -1.80006 h -0.67455 v -0.97014 h 0.67455 v -1.20509 z" />
+ <path
+ id="path1061"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -84.695524,106.51363 h 1.356678 l 1.140671,2.8801 0.970139,-2.8801 h 1.356678 l -1.784903,4.64606 q -0.269062,0.70865 -0.629075,0.98908 -0.356222,0.28422 -0.943611,0.28422 h -0.784448 v -0.89055 h 0.424435 q 0.344854,0 0.500228,-0.1099 0.159164,-0.1099 0.246325,-0.39412 l 0.0379,-0.11748 z" />
+ <path
+ id="path1063"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -77.722654,110.14407 v 2.22829 h -1.356678 v -5.85873 h 1.356678 v 0.6215 q 0.280431,-0.37139 0.621496,-0.54571 0.341064,-0.17811 0.784448,-0.17811 0.784448,0 1.288465,0.62529 0.504018,0.62149 0.504018,1.603 0,0.98151 -0.504018,1.60679 -0.504017,0.6215 -1.288465,0.6215 -0.443384,0 -0.784448,-0.17433 -0.341065,-0.17811 -0.621496,-0.54949 z m 0.901926,-2.74746 q -0.435804,0 -0.67076,0.32212 -0.231166,0.31832 -0.231166,0.92087 0,0.60255 0.231166,0.92466 0.234956,0.31833 0.67076,0.31833 0.435805,0 0.663181,-0.31833 0.231166,-0.31832 0.231166,-0.92466 0,-0.60634 -0.231166,-0.92466 -0.227376,-0.31833 -0.663181,-0.31833 z" />
+ <path
+ id="path1065"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -69.286993,108.62444 v 0.38654 h -3.171899 q 0.04927,0.47749 0.344854,0.71624 0.295589,0.23874 0.826134,0.23874 0.428225,0 0.875398,-0.12506 0.450963,-0.12884 0.924664,-0.38654 v 1.04593 q -0.48128,0.18191 -0.96256,0.27286 -0.48128,0.0947 -0.962559,0.0947 -1.15204,0 -1.792483,-0.5836 -0.636654,-0.58739 -0.636654,-1.64469 0,-1.03835 0.625285,-1.63332 0.629074,-0.59497 1.72806,-0.59497 1.000455,0 1.599213,0.60255 0.602547,0.60255 0.602547,1.61058 z m -1.394575,-0.45096 q 0,-0.38654 -0.227376,-0.6215 -0.223587,-0.23874 -0.587389,-0.23874 -0.394118,0 -0.640443,0.22358 -0.246324,0.2198 -0.306958,0.63666 z" />
+ </g>
+ <g
+ style="font-size:3.52778px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect3054)"
+ id="text3052" />
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ id="text3062"
+ aria-label="Python type
+with ABC">
+ <path
+ id="path1011"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -121.47364,128.2522 h 2.42156 q 1.08004,0 1.65606,0.48128 0.57981,0.47749 0.57981,1.36426 0,0.89055 -0.57981,1.37183 -0.57602,0.47749 -1.65606,0.47749 h -0.96256 v 1.96302 h -1.459 z m 1.459,1.0573 v 1.58027 h 0.80719 q 0.42443,0 0.6556,-0.20464 0.23117,-0.20843 0.23117,-0.58739 0,-0.37896 -0.23117,-0.5836 -0.23117,-0.20464 -0.6556,-0.20464 z" />
+ <path
+ id="path1013"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -116.25914,129.66572 h 1.35668 l 1.14067,2.8801 0.97014,-2.8801 h 1.35668 l -1.78491,4.64606 q -0.26906,0.70865 -0.62907,0.98908 -0.35622,0.28423 -0.94361,0.28423 h -0.78445 v -0.89056 h 0.42443 q 0.34486,0 0.50023,-0.1099 0.15917,-0.1099 0.24633,-0.39412 l 0.0379,-0.11748 z" />
+ <path
+ id="path1015"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -109.16121,128.46063 v 1.20509 h 1.39836 v 0.97014 h -1.39836 v 1.80006 q 0,0.29559 0.11748,0.4017 0.11747,0.10232 0.46612,0.10232 h 0.69729 v 0.97014 h -1.16341 q -0.8034,0 -1.14067,-0.33349 -0.33349,-0.33727 -0.33349,-1.14067 v -1.80006 h -0.67455 v -0.97014 h 0.67455 v -1.20509 z" />
+ <path
+ id="path1017"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -102.66583,131.32557 v 2.58451 h -1.36426 v -0.42065 -1.54994 q 0,-0.55708 -0.0265,-0.7655 -0.0227,-0.20843 -0.0834,-0.30696 -0.0796,-0.13264 -0.21601,-0.20464 -0.13643,-0.0758 -0.31075,-0.0758 -0.42444,0 -0.66697,0.32969 -0.24253,0.32591 -0.24253,0.90572 v 2.08807 h -1.35668 v -5.89662 h 1.35668 v 2.27376 q 0.30695,-0.37138 0.65181,-0.5457 0.34485,-0.17812 0.76171,-0.17812 0.73518,0 1.11414,0.45097 0.38275,0.45096 0.38275,1.3112 z" />
+ <path
+ id="path1019"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -99.387821,130.53354 q -0.450963,0 -0.689709,0.32591 -0.23495,0.32211 -0.23495,0.93224 0,0.61013 0.23495,0.93603 0.238746,0.32212 0.689709,0.32212 0.443384,0 0.678339,-0.32212 0.234956,-0.3259 0.234956,-0.93603 0,-0.61013 -0.234956,-0.93224 -0.234955,-0.32591 -0.678339,-0.32591 z m 0,-0.97014 q 1.095196,0 1.709112,0.59118 0.617705,0.59118 0.617705,1.63711 0,1.04593 -0.617705,1.63711 -0.613916,0.59118 -1.709112,0.59118 -1.098989,0 -1.720479,-0.59118 -0.61771,-0.59118 -0.61771,-1.63711 0,-1.04593 0.61771,-1.63711 0.62149,-0.59118 1.720479,-0.59118 z" />
+ <path
+ id="path1021"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -91.808612,131.32557 v 2.58451 h -1.364257 v -0.42065 -1.55752 q 0,-0.5495 -0.02653,-0.75792 -0.02274,-0.20843 -0.08337,-0.30696 -0.07958,-0.13264 -0.216007,-0.20464 -0.136426,-0.0758 -0.310748,-0.0758 -0.424435,0 -0.66697,0.32969 -0.242535,0.32591 -0.242535,0.90572 v 2.08807 h -1.356678 v -4.24436 h 1.356678 v 0.6215 q 0.306958,-0.37138 0.651812,-0.5457 0.344854,-0.17812 0.761711,-0.17812 0.735183,0 1.114143,0.45097 0.38275,0.45096 0.38275,1.3112 z" />
+ <path
+ id="path1023"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -86.366739,128.46063 v 1.20509 h 1.398364 v 0.97014 h -1.398364 v 1.80006 q 0,0.29559 0.117478,0.4017 0.117478,0.10232 0.466121,0.10232 h 0.697287 v 0.97014 h -1.163408 q -0.803396,0 -1.140671,-0.33349 -0.333485,-0.33727 -0.333485,-1.14067 v -1.80006 h -0.67455 v -0.97014 h 0.67455 v -1.20509 z" />
+ <path
+ id="path1025"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -84.695524,129.66572 h 1.356678 l 1.140671,2.8801 0.970139,-2.8801 h 1.356678 l -1.784903,4.64606 q -0.269062,0.70865 -0.629075,0.98908 -0.356222,0.28423 -0.943611,0.28423 h -0.784448 v -0.89056 h 0.424435 q 0.344854,0 0.500228,-0.1099 0.159164,-0.1099 0.246325,-0.39412 l 0.0379,-0.11748 z" />
+ <path
+ id="path1027"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -77.722654,133.29616 v 2.22829 h -1.356678 v -5.85873 h 1.356678 v 0.6215 q 0.280431,-0.37138 0.621496,-0.5457 0.341064,-0.17812 0.784448,-0.17812 0.784448,0 1.288465,0.62529 0.504018,0.62149 0.504018,1.603 0,0.98151 -0.504018,1.60679 -0.504017,0.6215 -1.288465,0.6215 -0.443384,0 -0.784448,-0.17432 -0.341065,-0.17811 -0.621496,-0.5495 z m 0.901926,-2.74746 q -0.435804,0 -0.67076,0.32212 -0.231166,0.31832 -0.231166,0.92087 0,0.60255 0.231166,0.92466 0.234956,0.31833 0.67076,0.31833 0.435805,0 0.663181,-0.31833 0.231166,-0.31832 0.231166,-0.92466 0,-0.60634 -0.231166,-0.92466 -0.227376,-0.31833 -0.663181,-0.31833 z" />
+ <path
+ id="path1029"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -69.286993,131.77653 v 0.38654 h -3.171899 q 0.04927,0.47749 0.344854,0.71624 0.295589,0.23874 0.826134,0.23874 0.428225,0 0.875398,-0.12505 0.450963,-0.12885 0.924664,-0.38654 v 1.04593 q -0.48128,0.1819 -0.96256,0.27285 -0.48128,0.0947 -0.962559,0.0947 -1.15204,0 -1.792483,-0.5836 -0.636654,-0.58739 -0.636654,-1.64469 0,-1.03835 0.625285,-1.63332 0.629074,-0.59497 1.72806,-0.59497 1.000455,0 1.599213,0.60255 0.602547,0.60255 0.602547,1.61058 z m -1.394575,-0.45096 q 0,-0.38654 -0.227376,-0.6215 -0.223587,-0.23874 -0.587389,-0.23874 -0.394118,0 -0.640443,0.22359 -0.246324,0.21979 -0.306958,0.63665 z" />
+ <path
+ id="path1031"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -121.91323,139.36711 h 1.31878 l 0.71245,2.92557 0.71623,-2.92557 h 1.1331 l 0.71244,2.89526 0.71624,-2.89526 h 1.31878 l -1.11793,4.24436 h -1.48174 l -0.71624,-2.918 -0.71244,2.918 h -1.48174 z" />
+ <path
+ id="path1033"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -114.36434,139.36711 h 1.35668 v 4.24436 h -1.35668 z m 0,-1.65227 h 1.35668 v 1.10657 h -1.35668 z" />
+ <path
+ id="path1035"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -110.2223,138.16202 v 1.20509 h 1.39836 v 0.97014 h -1.39836 v 1.80006 q 0,0.29559 0.11748,0.4017 0.11748,0.10232 0.46612,0.10232 h 0.69729 v 0.97014 h -1.16341 q -0.8034,0 -1.14067,-0.33349 -0.33349,-0.33727 -0.33349,-1.14067 v -1.80006 h -0.67455 v -0.97014 h 0.67455 v -1.20509 z" />
+ <path
+ id="path1037"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -103.72692,141.02696 v 2.58451 h -1.36426 v -0.42065 -1.54995 q 0,-0.55707 -0.0265,-0.7655 -0.0227,-0.20843 -0.0834,-0.30696 -0.0796,-0.13263 -0.21601,-0.20463 -0.13643,-0.0758 -0.31075,-0.0758 -0.42443,0 -0.66697,0.3297 -0.24253,0.32591 -0.24253,0.90572 v 2.08807 h -1.35668 v -5.89663 h 1.35668 v 2.27377 q 0.30695,-0.37139 0.65181,-0.54571 0.34485,-0.17811 0.76171,-0.17811 0.73518,0 1.11414,0.45096 0.38275,0.45097 0.38275,1.31121 z" />
+ <path
+ id="path1039"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -96.272765,142.58069 h -2.281342 l -0.360013,1.03078 h -1.46658 l 2.095655,-5.65788 h 1.739428 l 2.095651,5.65788 h -1.466576 z m -1.91754,-1.04972 h 1.549948 l -0.773079,-2.25102 z" />
+ <path
+ id="path1041"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -91.43344,140.14398 q 0.344854,0 0.522965,-0.15158 0.178112,-0.15159 0.178112,-0.44718 0,-0.2918 -0.178112,-0.44338 -0.178111,-0.15538 -0.522965,-0.15538 h -0.807186 v 1.19752 z m 0.04927,2.47461 q 0.439594,0 0.659391,-0.18569 0.223586,-0.18569 0.223586,-0.56086 0,-0.36759 -0.219797,-0.54949 -0.219797,-0.18569 -0.66318,-0.18569 h -0.856451 v 1.48173 z m 1.356678,-2.03502 q 0.469911,0.13643 0.727604,0.50402 0.257693,0.36759 0.257693,0.90193 0,0.81855 -0.553282,1.22025 -0.553282,0.4017 -1.682584,0.4017 h -2.421558 v -5.65788 h 2.190392 q 1.178567,0 1.705322,0.35622 0.530544,0.35622 0.530544,1.14067 0,0.41307 -0.19327,0.70487 -0.193269,0.28801 -0.560861,0.42822 z" />
+ <path
+ id="path1043"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -83.297161,143.30072 q -0.401698,0.20843 -0.837502,0.31454 -0.435805,0.10611 -0.909505,0.10611 -1.413523,0 -2.239657,-0.78824 -0.826133,-0.79203 -0.826133,-2.14492 0,-1.35668 0.826133,-2.14491 0.826134,-0.79203 2.239657,-0.79203 0.4737,0 0.909505,0.10611 0.435804,0.10611 0.837502,0.31453 v 1.17099 q -0.405488,-0.27664 -0.799606,-0.40549 -0.394119,-0.12884 -0.829924,-0.12884 -0.780658,0 -1.227832,0.50023 -0.447173,0.50022 -0.447173,1.37941 0,0.8754 0.447173,1.37563 0.447174,0.50023 1.227832,0.50023 0.435805,0 0.829924,-0.12885 0.394118,-0.12885 0.799606,-0.40549 z" />
+ </g>
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ id="text3070"
+ aria-label="NEP 41 Proposal">
+ <path
+ id="path984"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -139.86458,159.57088 h 1.62953 l 2.05775,3.88056 v -3.88056 h 1.38321 v 5.65788 h -1.62953 l -2.05776,-3.88056 v 3.88056 h -1.3832 z" />
+ <path
+ id="path986"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -133.3692,159.57088 h 3.9374 v 1.10278 h -2.4784 v 1.05351 h 2.33061 v 1.10277 h -2.33061 v 1.29604 h 2.56177 v 1.10278 h -4.02077 z" />
+ <path
+ id="path988"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -128.06754,159.57088 h 2.42156 q 1.08003,0 1.65605,0.48128 0.57981,0.47749 0.57981,1.36426 0,0.89055 -0.57981,1.37183 -0.57602,0.47749 -1.65605,0.47749 h -0.96256 v 1.96302 h -1.459 z m 1.459,1.0573 v 1.58027 h 0.80718 q 0.42444,0 0.6556,-0.20464 0.23117,-0.20843 0.23117,-0.58739 0,-0.37896 -0.23117,-0.5836 -0.23116,-0.20464 -0.6556,-0.20464 z" />
+ <path
+ id="path990"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -117.53244,160.77218 -1.59921,2.36851 h 1.59921 z m -0.24254,-1.2013 h 1.62195 v 3.56981 h 0.80719 v 1.0573 h -0.80719 v 1.03077 h -1.37941 v -1.03077 h -2.50872 v -1.25057 z" />
+ <path
+ id="path992"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -114.08011,164.22072 h 1.28846 v -3.65696 l -1.32257,0.27285 v -0.99288 l 1.31499,-0.27285 h 1.387 v 4.64984 h 1.28846 v 1.00804 h -3.95634 z" />
+ <path
+ id="path994"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -106.175,159.57088 h 2.42156 q 1.08004,0 1.65606,0.48128 0.57981,0.47749 0.57981,1.36426 0,0.89055 -0.57981,1.37183 -0.57602,0.47749 -1.65606,0.47749 h -0.96256 v 1.96302 h -1.459 z m 1.459,1.0573 v 1.58027 h 0.80719 q 0.42443,0 0.6556,-0.20464 0.23116,-0.20843 0.23116,-0.58739 0,-0.37896 -0.23116,-0.5836 -0.23117,-0.20464 -0.6556,-0.20464 z" />
+ <path
+ id="path996"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -97.394486,162.14023 q -0.178112,-0.0834 -0.356223,-0.12127 -0.174322,-0.0417 -0.352433,-0.0417 -0.522966,0 -0.807186,0.33727 -0.280431,0.33349 -0.280431,0.95877 v 1.95544 h -1.356681 v -4.24436 h 1.356681 v 0.69729 q 0.261483,-0.41686 0.598758,-0.60634 0.341064,-0.19327 0.814765,-0.19327 0.06821,0 0.147794,0.008 0.07958,0.004 0.231166,0.0227 z" />
+ <path
+ id="path998"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -94.700075,161.85222 q -0.450963,0 -0.689708,0.32591 -0.234955,0.32211 -0.234955,0.93224 0,0.61013 0.234955,0.93603 0.238745,0.32212 0.689708,0.32212 0.443384,0 0.678339,-0.32212 0.234956,-0.3259 0.234956,-0.93603 0,-0.61013 -0.234956,-0.93224 -0.234955,-0.32591 -0.678339,-0.32591 z m 0,-0.97014 q 1.095196,0 1.709112,0.59118 0.617705,0.59118 0.617705,1.63711 0,1.04593 -0.617705,1.63711 -0.613916,0.59118 -1.709112,0.59118 -1.098985,0 -1.72048,-0.59118 -0.617706,-0.59118 -0.617706,-1.63711 0,-1.04593 0.617706,-1.63711 0.621495,-0.59118 1.72048,-0.59118 z" />
+ <path
+ id="path1000"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -90.031282,164.61484 v 2.22829 h -1.356678 v -5.85873 h 1.356678 v 0.6215 q 0.280431,-0.37138 0.621495,-0.54571 0.341065,-0.17811 0.784449,-0.17811 0.784448,0 1.288465,0.62529 0.504017,0.62149 0.504017,1.603 0,0.98151 -0.504017,1.60679 -0.504017,0.6215 -1.288465,0.6215 -0.443384,0 -0.784449,-0.17432 -0.341064,-0.17811 -0.621495,-0.5495 z m 0.901926,-2.74746 q -0.435804,0 -0.67076,0.32212 -0.231166,0.31832 -0.231166,0.92087 0,0.60255 0.231166,0.92466 0.234956,0.31833 0.67076,0.31833 0.435805,0 0.663181,-0.31833 0.231166,-0.31832 0.231166,-0.92466 0,-0.60634 -0.231166,-0.92466 -0.227376,-0.31833 -0.663181,-0.31833 z" />
+ <path
+ id="path1002"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -83.812544,161.85222 q -0.450963,0 -0.689708,0.32591 -0.234955,0.32211 -0.234955,0.93224 0,0.61013 0.234955,0.93603 0.238745,0.32212 0.689708,0.32212 0.443384,0 0.67834,-0.32212 0.234955,-0.3259 0.234955,-0.93603 0,-0.61013 -0.234955,-0.93224 -0.234956,-0.32591 -0.67834,-0.32591 z m 0,-0.97014 q 1.095196,0 1.709112,0.59118 0.617705,0.59118 0.617705,1.63711 0,1.04593 -0.617705,1.63711 -0.613916,0.59118 -1.709112,0.59118 -1.098985,0 -1.72048,-0.59118 -0.617706,-0.59118 -0.617706,-1.63711 0,-1.04593 0.617706,-1.63711 0.621495,-0.59118 1.72048,-0.59118 z" />
+ <path
+ id="path1004"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -77.184525,161.11704 v 1.03077 q -0.435804,-0.1819 -0.841292,-0.27285 -0.405488,-0.0909 -0.7655,-0.0909 -0.38654,0 -0.57602,0.0985 -0.185691,0.0947 -0.185691,0.29559 0,0.16295 0.140216,0.25011 0.144005,0.0872 0.511596,0.12885 l 0.238745,0.0341 q 1.042142,0.13263 1.402154,0.4358 0.360012,0.30317 0.360012,0.95119 0,0.67834 -0.500227,1.0194 -0.500228,0.34107 -1.493105,0.34107 -0.420646,0 -0.871609,-0.0682 -0.447173,-0.0644 -0.920873,-0.19706 v -1.03078 q 0.405487,0.19706 0.829923,0.29559 0.428225,0.0985 0.867819,0.0985 0.397909,0 0.598758,-0.1099 0.200849,-0.10989 0.200849,-0.3259 0,-0.1819 -0.140215,-0.26906 -0.136426,-0.0909 -0.549493,-0.14022 l -0.238745,-0.0303 q -0.905716,-0.11368 -1.269518,-0.42064 -0.363802,-0.30696 -0.363802,-0.93224 0,-0.67455 0.462332,-1.00046 0.462332,-0.32591 1.417312,-0.32591 0.375171,0 0.788238,0.0568 0.413067,0.0568 0.898136,0.17811 z" />
+ <path
+ id="path1006"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -73.978521,163.3188 q -0.424436,0 -0.640444,0.144 -0.212217,0.14401 -0.212217,0.42444 0,0.25769 0.170532,0.40549 0.174322,0.144 0.481279,0.144 0.382751,0 0.644233,-0.27285 0.261483,-0.27664 0.261483,-0.68971 v -0.15537 z m 2.072913,-0.5116 v 2.42156 h -1.368047 v -0.62907 q -0.272852,0.38654 -0.613916,0.56465 -0.341064,0.17432 -0.829923,0.17432 -0.659391,0 -1.072458,-0.38275 -0.409278,-0.38654 -0.409278,-1.00046 0,-0.74655 0.511597,-1.09519 0.515386,-0.34865 1.614371,-0.34865 h 0.799607 v -0.10611 q 0,-0.32211 -0.253904,-0.46991 -0.253903,-0.15158 -0.792027,-0.15158 -0.435804,0 -0.810975,0.0872 -0.375171,0.0872 -0.697287,0.26148 v -1.03456 q 0.435804,-0.10611 0.875398,-0.15916 0.439594,-0.0568 0.879188,-0.0568 1.148251,0 1.656058,0.45476 0.511596,0.45096 0.511596,1.47036 z" />
+ <path
+ id="path1008"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -70.643667,159.33214 h 1.356679 v 5.89662 h -1.356679 z" />
+ </g>
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ id="text3076"
+ aria-label="Alternative">
+ <path
+ id="path961"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -113.68979,192.17046 h -2.28134 l -0.36001,1.03077 h -1.46658 l 2.09565,-5.65788 h 1.73943 l 2.09565,5.65788 h -1.46658 z m -1.91754,-1.04972 h 1.54995 l -0.77308,-2.25102 z" />
+ <path
+ id="path963"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -111.17728,187.30461 h 1.35668 v 5.89662 h -1.35668 z" />
+ <path
+ id="path965"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -107.03524,187.75178 v 1.2051 h 1.39836 v 0.97013 h -1.39836 v 1.80007 q 0,0.29559 0.11747,0.40169 0.11748,0.10232 0.46612,0.10232 h 0.69729 v 0.97014 h -1.16341 q -0.80339,0 -1.14067,-0.33348 -0.33348,-0.33728 -0.33348,-1.14067 v -1.80007 h -0.67455 v -0.97013 h 0.67455 v -1.2051 z" />
+ <path
+ id="path967"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -100.57018,191.06769 v 0.38654 h -3.1719 q 0.0493,0.47749 0.34486,0.71623 0.29559,0.23875 0.82613,0.23875 0.42823,0 0.8754,-0.12506 0.45096,-0.12885 0.92466,-0.38654 v 1.04593 q -0.48128,0.1819 -0.96256,0.27285 -0.48128,0.0947 -0.96256,0.0947 -1.15204,0 -1.79248,-0.5836 -0.63665,-0.58739 -0.63665,-1.64469 0,-1.03835 0.62528,-1.63332 0.62908,-0.59496 1.72806,-0.59496 1.00046,0 1.59921,0.60254 0.60255,0.60255 0.60255,1.61059 z m -1.39457,-0.45097 q 0,-0.38654 -0.22738,-0.62149 -0.22359,-0.23875 -0.58739,-0.23875 -0.39412,0 -0.64044,0.22359 -0.24633,0.2198 -0.30696,0.63665 z" />
+ <path
+ id="path969"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -96.390244,190.11271 q -0.178112,-0.0834 -0.356223,-0.12127 -0.174322,-0.0417 -0.352434,-0.0417 -0.522965,0 -0.807185,0.33728 -0.280431,0.33348 -0.280431,0.95877 v 1.95543 h -1.356678 v -4.24435 h 1.356678 v 0.69728 q 0.261483,-0.41685 0.598758,-0.60633 0.341064,-0.19327 0.814764,-0.19327 0.06821,0 0.147795,0.008 0.07958,0.004 0.231166,0.0227 z" />
+ <path
+ id="path971"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -91.448601,190.61672 v 2.58451 h -1.364258 v -0.42064 -1.55753 q 0,-0.54949 -0.02653,-0.75792 -0.02274,-0.20843 -0.08337,-0.30696 -0.07958,-0.13264 -0.216007,-0.20464 -0.136426,-0.0758 -0.310748,-0.0758 -0.424435,0 -0.66697,0.3297 -0.242535,0.3259 -0.242535,0.90571 v 2.08807 h -1.356678 v -4.24435 h 1.356678 v 0.62149 q 0.306958,-0.37138 0.651812,-0.5457 0.344854,-0.17811 0.761711,-0.17811 0.735183,0 1.114144,0.45096 0.38275,0.45096 0.38275,1.3112 z" />
+ <path
+ id="path973"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -88.288071,191.29127 q -0.424435,0 -0.640443,0.14401 -0.212218,0.144 -0.212218,0.42443 0,0.2577 0.170532,0.40549 0.174322,0.14401 0.48128,0.14401 0.38275,0 0.644233,-0.27286 0.261483,-0.27664 0.261483,-0.6897 v -0.15538 z m 2.072914,-0.51159 v 2.42155 h -1.368047 v -0.62907 q -0.272852,0.38654 -0.613916,0.56465 -0.341065,0.17432 -0.829924,0.17432 -0.659391,0 -1.072458,-0.38275 -0.409277,-0.38654 -0.409277,-1.00045 0,-0.74656 0.511597,-1.0952 0.515386,-0.34864 1.614371,-0.34864 h 0.799607 v -0.10611 q 0,-0.32212 -0.253904,-0.46991 -0.253903,-0.15159 -0.792027,-0.15159 -0.435805,0 -0.810976,0.0872 -0.37517,0.0872 -0.697287,0.26149 v -1.03457 q 0.435805,-0.1061 0.875399,-0.15916 0.439594,-0.0568 0.879188,-0.0568 1.14825,0 1.656057,0.45475 0.511597,0.45096 0.511597,1.47037 z" />
+ <path
+ id="path975"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -83.471483,187.75178 v 1.2051 h 1.398364 v 0.97013 h -1.398364 v 1.80007 q 0,0.29559 0.117478,0.40169 0.117478,0.10232 0.466121,0.10232 h 0.697288 v 0.97014 h -1.163409 q -0.803396,0 -1.140671,-0.33348 -0.333485,-0.33728 -0.333485,-1.14067 v -1.80007 h -0.67455 v -0.97013 h 0.67455 v -1.2051 z" />
+ <path
+ id="path977"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -81.243196,188.95688 h 1.356678 v 4.24435 h -1.356678 z m 0,-1.65227 h 1.356678 v 1.10656 h -1.356678 z" />
+ <path
+ id="path979"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -79.117229,188.95688 h 1.356678 l 1.0573,2.93315 1.05351,-2.93315 h 1.360468 l -1.671216,4.24435 h -1.489314 z" />
+ <path
+ id="path981"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ d="m -69.286993,191.06769 v 0.38654 h -3.171899 q 0.04927,0.47749 0.344854,0.71623 0.295589,0.23875 0.826134,0.23875 0.428225,0 0.875398,-0.12506 0.450963,-0.12885 0.924664,-0.38654 v 1.04593 q -0.48128,0.1819 -0.96256,0.27285 -0.48128,0.0947 -0.962559,0.0947 -1.15204,0 -1.792483,-0.5836 -0.636654,-0.58739 -0.636654,-1.64469 0,-1.03835 0.625285,-1.63332 0.629074,-0.59496 1.72806,-0.59496 1.000455,0 1.599213,0.60254 0.602547,0.60255 0.602547,1.61059 z m -1.394575,-0.45097 q 0,-0.38654 -0.227376,-0.62149 -0.223587,-0.23875 -0.587389,-0.23875 -0.394118,0 -0.640443,0.22359 -0.246324,0.2198 -0.306958,0.63665 z" />
+ </g>
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path960"
+ d="M 244.3569,149.56007 H -141.19857"
+ style="fill:none;stroke:#808080;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0rc1 (09960d6f05, 2020-04-09)"
+ sodipodi:docname="nep-0041-type-sketch.svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 390.05549 139.7222"
+ height="139.7222mm"
+ width="390.05548mm">
+ <defs
+ id="defs2">
+ <rect
+ x="-108.43283"
+ y="116.0488"
+ width="38.824516"
+ height="5.9122801"
+ id="rect3054" />
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker7096"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path7094"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5628"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5626"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5618"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Sstart">
+ <path
+ transform="matrix(0.2,0,0,0.2,1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5616"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4826"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#206120;fill-opacity:1;fill-rule:evenodd;stroke:#206120;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4824"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker4400"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4398"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4390"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#b7943d;fill-opacity:1;fill-rule:evenodd;stroke:#b7943d;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4388"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker2037"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#f4ae00;fill-opacity:1;fill-rule:evenodd;stroke:#ffc433;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path2035"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <rect
+ id="rect1296"
+ height="8.8755655"
+ width="16.467854"
+ y="100.87298"
+ x="-2.9674385" />
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lend"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="matrix(-0.8,0,0,-0.8,-10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path915"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path912"
+ inkscape:connector-curvature="0" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ inkscape:guide-bbox="true"
+ showguides="true"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:window-height="1376"
+ inkscape:window-width="2560"
+ showgrid="false"
+ inkscape:document-rotation="0"
+ inkscape:current-layer="layer1"
+ inkscape:document-units="mm"
+ inkscape:cy="290.82008"
+ inkscape:cx="134.87089"
+ inkscape:zoom="0.98994949"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ lock-margins="true"
+ fit-margin-top="2"
+ fit-margin-left="2"
+ fit-margin-right="2"
+ fit-margin-bottom="2"
+ objecttolerance="29.7"
+ gridtolerance="20.4"
+ guidetolerance="19.1"
+ inkscape:snap-perpendicular="true"
+ inkscape:snap-tangential="true" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="Layer 1"
+ transform="translate(143.44857,-67.864137)">
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path1976"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796078;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 175.57699,126.11316 h 65.38081 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -65.38081 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path3044"
+ d="M 172.89254,70.114137 V 205.33633"
+ style="fill:none;stroke:#808080;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ d="M 55.143494,98.892926 H 240.95778 c 1.14406,0 2.06509,0.921034 2.06509,2.065094 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 55.143494 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.065094 2.06509,-2.065094 z"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796609;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="rect5208"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ d="M -60.569299,98.727824 H 50.002364 c 1.14406,0 2.06509,0.92103 2.06509,2.065086 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H -60.569299 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.144056 0.92103,-2.065086 2.06509,-2.065086 z"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="rect4618"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <g
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ id="text4368" />
+ <g
+ style="font-size:3.52778px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1296)"
+ id="text1294" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.76111px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ x="177.69284"
+ y="88.415688"
+ id="text1931"><tspan
+ sodipodi:role="line"
+ id="tspan1929"
+ x="177.69284"
+ y="88.415688"
+ style="fill:#000000;stroke-width:0.105503">Value Storage</tspan></text>
+ <text
+ id="text1935"
+ y="78.750557"
+ x="77.626938"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.76111px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ xml:space="preserve"><tspan
+ style="fill:#000000;stroke-width:0.105503"
+ y="78.750557"
+ x="77.626938"
+ id="tspan1933"
+ sodipodi:role="line">Parameters and</tspan><tspan
+ style="fill:#000000;stroke-width:0.105503"
+ y="88.451942"
+ x="77.626938"
+ sodipodi:role="line"
+ id="tspan3040">Storage options</tspan></text>
+ <text
+ id="text1939"
+ y="78.750557"
+ x="-41.095226"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ xml:space="preserve"><tspan
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ y="78.750557"
+ x="-41.095226"
+ sodipodi:role="line"
+ id="tspan3034">Value Space and</tspan><tspan
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ y="88.451942"
+ x="-41.095226"
+ sodipodi:role="line"
+ id="tspan3038">Behaviour</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ x="-19.191803"
+ y="111.20879"
+ id="text1968"><tspan
+ sodipodi:role="line"
+ id="tspan1965"
+ x="-19.191803"
+ y="111.20879"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583">type</tspan></text>
+ <text
+ id="text1972"
+ y="113.24359"
+ x="120.08958"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.976587;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
+ y="113.24359"
+ x="120.08958"
+ id="tspan1970"
+ sodipodi:role="line">instance</tspan></text>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path1974"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m -60.569299,125.94806 h 72.698771 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -72.698771 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z" />
+ <text
+ id="text1980"
+ y="139.86145"
+ x="-34.512547"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ y="139.86145"
+ x="-34.512547"
+ id="tspan1978"
+ sodipodi:role="line">ABC</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#830000;fill-opacity:1;stroke-width:0.264583"
+ x="180.30632"
+ y="140.46382"
+ id="text1984"><tspan
+ sodipodi:role="line"
+ id="tspan1982"
+ x="180.30632"
+ y="140.46382"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#830000;fill-opacity:1;stroke-width:0.264583">instance</tspan></text>
+ <path
+ d="M 17.347598,126.00309 H 170.2081 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 17.347598 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path1986"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ x="79.869514"
+ y="138.48405"
+ id="text1990"><tspan
+ sodipodi:role="line"
+ id="tspan1988"
+ x="79.869514"
+ y="138.48405"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583">type</tspan></text>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path1992"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="M -60.569299,153.16829 H 49.987465 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H -60.569299 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.70853 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z" />
+ <text
+ id="text1998"
+ y="165.81964"
+ x="-22.653231"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ y="165.81964"
+ x="-22.653231"
+ id="tspan1996"
+ sodipodi:role="line">DType</tspan></text>
+ <path
+ d="m -60.569299,180.38852 h 72.698771 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -72.698771 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 V 182.4536 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path2004"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <path
+ d="m 175.57697,180.55362 h 65.38081 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -65.38081 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796078;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path2006"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ x="-59.010956"
+ y="193.40663"
+ id="text2010"><tspan
+ sodipodi:role="line"
+ id="tspan2008"
+ x="-59.010956"
+ y="193.40663"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583">base dtype</tspan></text>
+ <text
+ id="text2014"
+ y="194.58372"
+ x="184.03754"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ y="194.58372"
+ x="184.03754"
+ id="tspan2012"
+ sodipodi:role="line">element</tspan></text>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path2016"
+ style="opacity:0.25;fill:#000081;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="M 17.463123,180.38852 H 170.32495 c 1.14406,0 2.06509,0.92103 2.06509,2.06508 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 17.463123 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 V 182.4536 c 0,-1.14405 0.92103,-2.06508 2.06509,-2.06508 z" />
+ <text
+ id="text2020"
+ y="193.40663"
+ x="76.606812"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000081;fill-opacity:1;stroke-width:0.264583"
+ y="193.40663"
+ x="76.606812"
+ id="tspan2018"
+ sodipodi:role="line">dtype</tspan></text>
+ <path
+ sodipodi:nodetypes="sssssssss"
+ inkscape:connector-curvature="0"
+ id="path2022"
+ style="opacity:1;fill:#ddb9b9;fill-opacity:0.796078;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 175.57697,153.33338 h 65.38081 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -65.38081 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:0.8;stroke-width:0.264583"
+ x="184.03754"
+ y="167.36348"
+ id="text2026"><tspan
+ sodipodi:role="line"
+ id="tspan2024"
+ x="184.03754"
+ y="167.36348"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#800000;fill-opacity:0.8;stroke-width:0.264583">element</tspan></text>
+ <path
+ d="M 55.175507,153.27835 H 170.22016 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 55.175507 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z"
+ style="opacity:0.25;fill:#d99b00;fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="path2031"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ <text
+ id="text2035"
+ y="166.21391"
+ x="95.410606"
+ style="font-size:11.263px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#b27d00;fill-opacity:1;stroke-width:0.264583"
+ y="166.21391"
+ x="95.410606"
+ id="tspan2033"
+ sodipodi:role="line">dtype</tspan></text>
+ <path
+ style="fill:none;stroke:#808080;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 52.572927,70.114137 V 205.33633"
+ id="path3042"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ x="-122.18608"
+ y="110.75799"
+ id="text3050"><tspan
+ id="tspan3048"
+ sodipodi:role="line"
+ x="-122.18608"
+ y="110.75799"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503">Python type</tspan></text>
+ <text
+ xml:space="preserve"
+ id="text3052"
+ style="font-size:3.52778px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect3054);" />
+ <text
+ id="text3062"
+ y="133.91008"
+ x="-122.18608"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ xml:space="preserve"><tspan
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ y="133.91008"
+ x="-122.18608"
+ sodipodi:role="line"
+ id="tspan3060">Python type</tspan><tspan
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ y="143.61147"
+ x="-122.18608"
+ sodipodi:role="line"
+ id="tspan3064">with ABC</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ x="-140.57703"
+ y="165.22876"
+ id="text3070"><tspan
+ id="tspan3068"
+ sodipodi:role="line"
+ x="-140.57703"
+ y="165.22876"
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503">NEP 41 Proposal</tspan></text>
+ <text
+ id="text3076"
+ y="193.20123"
+ x="-117.83562"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:7.72103px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.105503"
+ xml:space="preserve"><tspan
+ style="font-size:7.76111px;fill:#000000;stroke-width:0.105503"
+ y="193.20123"
+ x="-117.83562"
+ sodipodi:role="line"
+ id="tspan3074">Alternative</tspan></text>
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path960"
+ d="M 244.3569,149.56007 H -141.19857"
+ style="fill:none;stroke:#808080;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ sodipodi:docname="nep43-sketch-with-text.svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 289.35355 238.13675"
+ height="238.13675mm"
+ width="289.35355mm">
+ <defs
+ id="defs2">
+ <linearGradient
+ id="linearGradient5092"
+ inkscape:collect="always">
+ <stop
+ id="stop5088"
+ offset="0"
+ style="stop-color:#800000;stop-opacity:1;" />
+ <stop
+ id="stop5090"
+ offset="1"
+ style="stop-color:#800000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5078"
+ inkscape:collect="always">
+ <stop
+ id="stop5074"
+ offset="0"
+ style="stop-color:#000080;stop-opacity:1;" />
+ <stop
+ id="stop5076"
+ offset="1"
+ style="stop-color:#000080;stop-opacity:0;" />
+ </linearGradient>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker7096"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path7094"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker6260"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path6258"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5628"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5626"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5618"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Sstart">
+ <path
+ transform="matrix(0.2,0,0,0.2,1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5616"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker5002"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path5000"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4826"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#206120;fill-opacity:1;fill-rule:evenodd;stroke:#206120;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4824"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Sstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Sstart">
+ <path
+ transform="matrix(0.2,0,0,0.2,1.2,0)"
+ style="fill:#800000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path924"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker4400"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4398"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4390"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#b7943d;fill-opacity:1;fill-rule:evenodd;stroke:#b7943d;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4388"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker3453"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#800000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path3451"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker2179"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#206120;fill-opacity:1;fill-rule:evenodd;stroke:#206120;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path2177"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker2037"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#f4ae00;fill-opacity:1;fill-rule:evenodd;stroke:#ffc433;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path2035"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker1480"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path1478"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#ffc433;fill-opacity:1;fill-rule:evenodd;stroke:#ffc433;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <rect
+ id="rect1296"
+ height="8.8755655"
+ width="16.467854"
+ y="100.87298"
+ x="-2.9674385" />
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Send"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path927"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lend"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="matrix(-0.8,0,0,-0.8,-10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path915"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path912"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Send-5"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path927-6"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <linearGradient
+ gradientTransform="translate(0.29900013,18.755984)"
+ gradientUnits="userSpaceOnUse"
+ y2="220.58623"
+ x2="-9.5455313"
+ y1="221.22202"
+ x1="-44.254147"
+ id="linearGradient5080"
+ xlink:href="#linearGradient5078"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="translate(0.29900013,18.755984)"
+ gradientUnits="userSpaceOnUse"
+ y2="161.24438"
+ x2="216.83401"
+ y1="161.02299"
+ x1="248.04567"
+ id="linearGradient5094"
+ xlink:href="#linearGradient5092"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="translate(0.29900013,18.755984)"
+ y2="221.80334"
+ x2="4.2398605"
+ y1="221.22202"
+ x1="-44.254147"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5200"
+ xlink:href="#linearGradient5078"
+ inkscape:collect="always" />
+ </defs>
+ <sodipodi:namedview
+ inkscape:guide-bbox="true"
+ showguides="true"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:window-height="1376"
+ inkscape:window-width="2560"
+ showgrid="false"
+ inkscape:document-rotation="0"
+ inkscape:current-layer="g4988"
+ inkscape:document-units="mm"
+ inkscape:cy="408.92855"
+ inkscape:cx="490.09169"
+ inkscape:zoom="0.7"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ lock-margins="true"
+ fit-margin-top="2"
+ fit-margin-left="2"
+ fit-margin-right="2"
+ fit-margin-bottom="2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="Layer 1"
+ transform="translate(46.254147,-52.135225)">
+ <rect
+ style="opacity:0.25;fill:url(#linearGradient5094);fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="rect5086"
+ width="53.12854"
+ height="221.86719"
+ x="187.97086"
+ y="66.404785"
+ ry="2.065089"
+ rx="2.065089" />
+ <rect
+ style="opacity:0.25;fill:url(#linearGradient5200);fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="rect5198"
+ width="71.246887"
+ height="16.547533"
+ x="-44.254147"
+ y="133.66225"
+ ry="2.065089"
+ rx="2.065089" />
+ <rect
+ rx="2.065089"
+ ry="2.065089"
+ y="157.51857"
+ x="-44.254147"
+ height="130.7534"
+ width="65.95256"
+ id="rect5064"
+ style="opacity:0.25;fill:url(#linearGradient5080);fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957" />
+ <rect
+ rx="2.065089"
+ ry="2.065089"
+ y="181.42923"
+ x="28.783215"
+ height="16.350454"
+ width="55.675358"
+ id="rect4614"
+ style="opacity:0.25;fill:#800000;fill-opacity:0.639216;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957" />
+ <rect
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ id="rect4618"
+ width="72.423012"
+ height="19.838709"
+ x="28.783215"
+ y="134.54594"
+ ry="2.065089"
+ rx="2.065089" />
+ <rect
+ rx="2.065089"
+ ry="2.065089"
+ y="224.65892"
+ x="36.191555"
+ height="16.652536"
+ width="116.8335"
+ id="rect4620"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957" />
+ <path
+ style="fill:none;stroke:#ffc433;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker1480)"
+ d="M 162.39696,87.706466 V 102.33478"
+ id="path1476"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4822"
+ d="m 87.064551,181.16793 v 56.58639"
+ style="fill:none;stroke:#206120;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4826)" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path2033"
+ d="M 162.39696,243.19694 V 134.06539"
+ style="fill:#f4ae00;fill-opacity:1;stroke:#ffc433;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker2037)" />
+ <path
+ style="fill:none;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4400)"
+ d="m 82.917295,224.24439 v 13.50993"
+ id="path4310"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4312"
+ d="m 149.89381,181.16793 v 56.58639"
+ style="opacity:0.5;fill:none;fill-opacity:0.501961;stroke:#b7943d;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4390)" />
+ <rect
+ style="fill:none;stroke:#000080;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:1"
+ id="rect4314"
+ width="158.89915"
+ height="24.343685"
+ x="28.543333"
+ y="241.1985" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ x="22.815491"
+ y="252.4229"
+ id="text4320"><tspan
+ sodipodi:role="line"
+ id="tspan4316"
+ x="22.815491"
+ y="252.4229"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0">Loop</tspan><tspan
+ sodipodi:role="line"
+ x="22.815493"
+ y="260.36038"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="tspan4318">descriptors</tspan></text>
+ <rect
+ y="197.56255"
+ x="28.168863"
+ height="24.343685"
+ width="158.89915"
+ id="rect4322"
+ style="opacity:0.6;fill:#ffffff;stroke:#800000;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:0.8" />
+ <text
+ id="text4328"
+ y="208.32829"
+ x="22.815491"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ y="208.32829"
+ x="22.815489"
+ sodipodi:role="line"
+ id="tspan4326">Resolver</tspan><tspan
+ id="tspan4554"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ y="216.26579"
+ x="22.815489"
+ sodipodi:role="line">Input</tspan></text>
+ <rect
+ y="200.65752"
+ x="142.70969"
+ height="17.717829"
+ width="39.227802"
+ id="rect4330"
+ style="opacity:0.5;fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10" />
+ <rect
+ y="201.09155"
+ x="89.303658"
+ height="17.131346"
+ width="39.31385"
+ id="rect4332"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ x="77.700294"
+ y="213.4348"
+ id="text4336"><tspan
+ sodipodi:role="line"
+ id="tspan4334"
+ x="77.700294"
+ y="213.4348"
+ style="stroke-width:0.933951">+</tspan></text>
+ <text
+ id="text4340"
+ y="214.15385"
+ x="130.39491"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.933951"
+ xml:space="preserve"><tspan
+ style="fill:#000000;fill-opacity:1;stroke-width:0.933951"
+ y="214.15385"
+ x="130.39491"
+ id="tspan4338"
+ sodipodi:role="line">→</tspan></text>
+ <rect
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect4342"
+ width="39.31385"
+ height="17.131346"
+ x="37.217079"
+ y="200.69289" />
+ <rect
+ style="fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect4344"
+ width="39.227802"
+ height="17.717829"
+ x="142.70969"
+ y="244.04799" />
+ <rect
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect4346"
+ width="39.31385"
+ height="17.131346"
+ x="89.303658"
+ y="244.48203" />
+ <text
+ id="text4350"
+ y="256.82526"
+ x="77.700294"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.933951"
+ y="256.82526"
+ x="77.700294"
+ id="tspan4348"
+ sodipodi:role="line">+</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ x="130.39491"
+ y="257.54431"
+ id="text4354"><tspan
+ sodipodi:role="line"
+ id="tspan4352"
+ x="130.39491"
+ y="257.54431"
+ style="stroke-width:0.933951">→</tspan></text>
+ <rect
+ y="244.08336"
+ x="37.217079"
+ height="17.131346"
+ width="39.31385"
+ id="rect4356"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10" />
+ <text
+ id="text4360"
+ y="211.66945"
+ x="49.371288"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ y="211.66945"
+ x="49.371288"
+ id="tspan4358"
+ sodipodi:role="line">>U5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ x="100.25864"
+ y="212.11256"
+ id="text4364"><tspan
+ sodipodi:role="line"
+ id="tspan4362"
+ x="100.25864"
+ y="212.11256"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"><U8</tspan></text>
+ <text
+ id="text4368"
+ y="212.01785"
+ x="150.35503"
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.505891"
+ y="212.01785"
+ x="150.35503"
+ id="tspan4366"
+ sodipodi:role="line" /></text>
+ <text
+ id="text4374"
+ y="230.71275"
+ x="38.610909"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;stroke-width:0.398751"
+ xml:space="preserve"><tspan
+ style="fill:#000080;stroke-width:0.398751"
+ y="230.71275"
+ x="38.610909"
+ sodipodi:role="line"
+ id="tspan4372">set descriptors</tspan><tspan
+ id="tspan1803"
+ style="fill:#000080;stroke-width:0.398751"
+ y="237.35863"
+ x="38.610909"
+ sodipodi:role="line">for inner-loop…</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ x="49.371288"
+ y="255.05992"
+ id="text4378"><tspan
+ sodipodi:role="line"
+ id="tspan4376"
+ x="49.371288"
+ y="255.05992"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"><U5</tspan></text>
+ <text
+ id="text4382"
+ y="255.50304"
+ x="100.25864"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ y="255.50304"
+ x="100.25864"
+ id="tspan4380"
+ sodipodi:role="line"><U8</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ x="152.65042"
+ y="255.36224"
+ id="text4386"><tspan
+ sodipodi:role="line"
+ id="tspan4384"
+ x="152.65042"
+ y="255.36224"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"><U13</tspan></text>
+ <rect
+ y="65.16613"
+ x="29.071695"
+ height="24.343685"
+ width="158.89915"
+ id="rect833"
+ style="fill:none;stroke:#cccccc;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10" />
+ <text
+ id="text841"
+ y="79.000191"
+ x="22.683092"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ y="79.000191"
+ x="22.68309"
+ id="tspan839"
+ sodipodi:role="line">User Input</tspan></text>
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path910"
+ d="M 31.352669,92.208912 V 194.08332"
+ style="fill:none;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send)" />
+ <path
+ id="path1730"
+ style="fill:none;fill-opacity:0.483526;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7096)"
+ d="m 31.352669,146.65942 h 51.793437 v 4.50227"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:none;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-5)"
+ d="M 83.488644,92.208912 V 102.42617"
+ id="path910-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path2175"
+ d="m 35.539436,181.16793 v 12.91539"
+ style="fill:none;stroke:#206120;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2179)" />
+ <rect
+ style="opacity:0.8;fill:#ffffff;stroke:#800000;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:1"
+ id="rect833-3"
+ width="158.89915"
+ height="24.343685"
+ x="28.977177"
+ y="106.27831" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ x="22.815489"
+ y="117.5332"
+ id="text841-6"><tspan
+ sodipodi:role="line"
+ id="tspan839-7"
+ x="22.815487"
+ y="117.5332"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751">Input/Output</tspan><tspan
+ id="tspan3693"
+ sodipodi:role="line"
+ x="22.815491"
+ y="125.4707"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751">Operands</tspan></text>
+ <rect
+ y="68.992058"
+ x="37.217079"
+ height="17.131346"
+ width="39.31385"
+ id="rect874"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10" />
+ <rect
+ style="opacity:0.5;fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect876"
+ width="39.227802"
+ height="17.717829"
+ x="142.70969"
+ y="68.95668" />
+ <rect
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect878"
+ width="39.31385"
+ height="17.131346"
+ x="89.303658"
+ y="69.390724" />
+ <text
+ id="text882"
+ y="81.733971"
+ x="77.700294"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.933951"
+ y="81.733971"
+ x="77.700294"
+ id="tspan880"
+ sodipodi:role="line">+</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ x="130.39491"
+ y="82.453018"
+ id="text886"><tspan
+ sodipodi:role="line"
+ id="tspan884"
+ x="130.39491"
+ y="82.453018"
+ style="stroke-width:0.933951">→</tspan></text>
+ <rect
+ style="opacity:0.6;fill:#ffffff;stroke:#000080;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:0.5"
+ id="rect888"
+ width="158.89915"
+ height="24.343685"
+ x="28.168863"
+ y="154.17207" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ x="22.815491"
+ y="156.80496"
+ id="text892"><tspan
+ sodipodi:role="line"
+ id="tspan890"
+ x="22.815491"
+ y="156.80496"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751" /><tspan
+ id="tspan894"
+ sodipodi:role="line"
+ x="22.815489"
+ y="164.74246"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751">DType classes</tspan><tspan
+ id="tspan5908"
+ sodipodi:role="line"
+ x="22.815491"
+ y="172.67996"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751">of the <tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="tspan1154">ArrayMethod</tspan></tspan><tspan
+ id="tspan5906"
+ sodipodi:role="line"
+ x="22.815491"
+ y="180.67947"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751" /></text>
+ <rect
+ y="109.79432"
+ x="142.70969"
+ height="17.717829"
+ width="39.227802"
+ id="rect1272"
+ style="opacity:0.5;fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10" />
+ <rect
+ y="110.22836"
+ x="89.303658"
+ height="17.131346"
+ width="39.31385"
+ id="rect1274"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ x="77.700294"
+ y="122.57161"
+ id="text1278"><tspan
+ sodipodi:role="line"
+ id="tspan1276"
+ x="77.700294"
+ y="122.57161"
+ style="stroke-width:0.933951">+</tspan></text>
+ <text
+ id="text1282"
+ y="123.29066"
+ x="130.39491"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.933951"
+ y="123.29066"
+ x="130.39491"
+ id="tspan1280"
+ sodipodi:role="line">→</tspan></text>
+ <text
+ id="text1292"
+ y="142.74757"
+ x="35.332455"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;stroke-width:0.398751"
+ xml:space="preserve"><tspan
+ id="tspan1300"
+ style="fill:#000080;stroke-width:0.398751"
+ y="142.74757"
+ x="35.332455"
+ sodipodi:role="line">Promotion (if necessary)</tspan></text>
+ <text
+ style="font-size:3.52778px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1296);"
+ id="text1294"
+ xml:space="preserve" />
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ x="164.28925"
+ y="99.407722"
+ id="text1292-5"><tspan
+ sodipodi:role="line"
+ x="164.28925"
+ y="99.407722"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="tspan1300-3">If provided</tspan></text>
+ <rect
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect1270"
+ width="39.31385"
+ height="17.131346"
+ x="37.217079"
+ y="109.8297" />
+ <rect
+ style="fill:#9f8a56;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect1907"
+ width="39.227802"
+ height="17.717829"
+ x="142.70969"
+ y="157.26704" />
+ <rect
+ style="fill:#206020;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ id="rect1909"
+ width="39.31385"
+ height="17.131346"
+ x="89.303658"
+ y="157.70108" />
+ <text
+ id="text1913"
+ y="170.04433"
+ x="77.700294"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.933951"
+ y="170.04433"
+ x="77.700294"
+ id="tspan1911"
+ sodipodi:role="line">+</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.933951"
+ x="130.39491"
+ y="170.76338"
+ id="text1917"><tspan
+ sodipodi:role="line"
+ id="tspan1915"
+ x="130.39491"
+ y="170.76338"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.933951">→</tspan></text>
+ <rect
+ y="157.30241"
+ x="37.217079"
+ height="17.131346"
+ width="39.31385"
+ id="rect1919"
+ style="fill:#206020;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10" />
+ <text
+ id="text1937"
+ y="79.968613"
+ x="49.371288"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ y="79.968613"
+ x="49.371288"
+ id="tspan1935"
+ sodipodi:role="line">>U5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ x="103.54726"
+ y="80.411743"
+ id="text1941"><tspan
+ sodipodi:role="line"
+ id="tspan1939"
+ x="103.54726"
+ y="80.411743"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891">S8</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ x="49.371288"
+ y="120.80625"
+ id="text1949"><tspan
+ sodipodi:role="line"
+ id="tspan1947"
+ x="49.371288"
+ y="120.80625"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891">>U5</tspan></text>
+ <text
+ id="text1953"
+ y="121.24938"
+ x="100.58635"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ y="121.24938"
+ x="100.58635"
+ id="tspan1951"
+ sodipodi:role="line"><S8</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ x="43.083893"
+ y="168.38272"
+ id="text1967"><tspan
+ sodipodi:role="line"
+ id="tspan1965"
+ x="43.083893"
+ y="168.38272"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891">Unicode</tspan></text>
+ <text
+ id="text1971"
+ y="168.78139"
+ x="94.035469"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ y="168.78139"
+ x="94.035469"
+ id="tspan1969"
+ sodipodi:role="line">Unicode</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ x="148.53348"
+ y="168.64059"
+ id="text1989"><tspan
+ sodipodi:role="line"
+ id="tspan1987"
+ x="148.53348"
+ y="168.64059"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891">Unicode</tspan></text>
+ <text
+ id="text2113"
+ y="144.74529"
+ x="164.28925"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ xml:space="preserve"><tspan
+ id="tspan2111"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ y="144.74529"
+ x="164.28925"
+ sodipodi:role="line">If not provided</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ x="39.131157"
+ y="187.32767"
+ id="text2441"><tspan
+ id="tspan2767"
+ sodipodi:role="line"
+ x="39.131157"
+ y="187.32767"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751">Cast descriptors</tspan><tspan
+ id="tspan4558"
+ sodipodi:role="line"
+ x="39.131157"
+ y="193.97354"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751">to Loop DTypes</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;opacity:0.5;stroke-width:0.505891"
+ x="152.65042"
+ y="121.10858"
+ id="text3113"><tspan
+ sodipodi:role="line"
+ id="tspan3111"
+ x="152.65042"
+ y="121.10858"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"><U13</tspan></text>
+ <g
+ transform="translate(232.48255,-0.55871913)"
+ id="g4067">
+ <g
+ transform="translate(-7.4083337)"
+ id="g4102">
+ <path
+ id="path3217"
+ style="fill:none;fill-opacity:0.483526;stroke:#800000;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Sstart);marker-end:url(#marker3453)"
+ d="m -33.43701,119.33194 h 18.789774 v 41.58775 93.14908 H -33.43701"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ </g>
+ <g
+ id="g4988"
+ transform="rotate(180,-31.440594,176.71768)">
+ <path
+ id="path4980"
+ style="fill:none;fill-opacity:0.483526;stroke:#000081;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker5002)"
+ d="M -21.573873,211.51421 H -87.252914"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ x="21.68927"
+ y="-291.25931"
+ id="text4984"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ x="21.68927"
+ y="-291.25931"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan4982">Registered</tspan></text>
+ <path
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0"
+ d="m -94.24417,121.2914 64.203629,-0.52916 V 83.191271"
+ style="fill:none;fill-opacity:0.483526;stroke:#000081;stroke-width:1.2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker5618)"
+ id="path6082" />
+ <text
+ transform="scale(-1)"
+ id="text6086"
+ y="-123.67085"
+ x="28.974308"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.3167px;line-height:1.25;font-family:fira;-inkscape-font-specification:fira;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ xml:space="preserve"><tspan
+ id="tspan6084"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ y="-123.67085"
+ x="28.974308"
+ sodipodi:role="line">resolve_descriptors</tspan></text>
+ <path
+ id="path6252"
+ style="fill:none;fill-opacity:0.483526;stroke:#000081;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6260)"
+ d="M -30.040541,83.191271 H -85.328359"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ x="91.053413"
+ y="-80.689705"
+ id="text6256"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ x="91.053413"
+ y="-80.689705"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan6254" /><tspan
+ sodipodi:role="line"
+ x="91.053413"
+ y="-74.043831"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan7420" /></text>
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ x="89.791664"
+ y="-80.862366"
+ id="text7434"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ x="89.791664"
+ y="-80.862366"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan4836">Perform operation with these descriptors</tspan><tspan
+ sodipodi:role="line"
+ x="89.791664"
+ y="-74.216492"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan5896">(setup, inner-loop function, teardown)</tspan><tspan
+ sodipodi:role="line"
+ x="89.791664"
+ y="-67.570618"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan4840" /></text>
+ <text
+ transform="scale(-1)"
+ id="text7580"
+ y="-291.25931"
+ x="255.89056"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ y="-291.25931"
+ x="255.89056"
+ sodipodi:role="line"
+ id="tspan7582">NumPy</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.65;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ x="20.452068"
+ y="-214.1572"
+ id="text1141"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ x="20.452068"
+ y="-214.1572"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan1143">Registered or default</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.45542px;line-height:1.25;font-family:fira;-inkscape-font-specification:fira;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ x="113.16111"
+ y="25.668264"
+ id="text4678"
+ transform="rotate(90)"><tspan
+ sodipodi:role="line"
+ x="113.16111"
+ y="25.668264"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan4676">ArrayMethod</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:3.52777px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
+ x="92.373795"
+ y="-75.619186"
+ id="text4844"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ id="tspan4842"
+ x="92.373795"
+ y="-75.619186"
+ style="stroke-width:0.264583" /></text>
+ <text
+ transform="rotate(-90)"
+ id="text4856"
+ y="-282.71359"
+ x="-235.48586"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ xml:space="preserve"><tspan
+ id="tspan4852"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ y="-282.71359"
+ x="-235.48586"
+ sodipodi:role="line">Casting, Result Allocation and Outer Iteration</tspan><tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ y="-276.06772"
+ x="-235.48586"
+ sodipodi:role="line"
+ id="tspan4918">done by UFunc Machinery (within <tspan
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="tspan1182">ArrayMethod)</tspan></tspan><tspan
+ id="tspan4854"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ y="-269.36993"
+ x="-235.48586"
+ sodipodi:role="line" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.3167px;line-height:1.25;font-family:fira;-inkscape-font-specification:fira;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ x="20.532179"
+ y="-205.57103"
+ id="text5366"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ x="20.532179"
+ y="-205.57103"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan5364">Promoter</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#008100;fill-opacity:1;stroke-width:0.505891"
+ x="72.261002"
+ y="61.442417"
+ id="text1097"><tspan
+ sodipodi:role="line"
+ id="tspan1095"
+ x="72.261002"
+ y="61.442417"
+ style="fill:#008100;fill-opacity:1;stroke-width:0.505891">Inputs</tspan></text>
+ <text
+ id="text1101"
+ y="61.442417"
+ x="150.49973"
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ y="61.442417"
+ x="150.49973"
+ id="tspan1099"
+ sodipodi:role="line">Output</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ x="144.32066"
+ y="230.83656"
+ id="text1791"><tspan
+ id="tspan1795"
+ sodipodi:role="line"
+ x="144.32066"
+ y="230.83656"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751">… including correct</tspan><tspan
+ id="tspan1807"
+ sodipodi:role="line"
+ x="144.32066"
+ y="237.48244"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751">output descriptor</tspan></text>
+ <rect
+ rx="2.065089"
+ ry="2.065089"
+ y="134.54594"
+ x="101.20623"
+ height="19.673599"
+ width="46.424511"
+ id="rect5208"
+ style="opacity:0.25;fill:#830000;fill-opacity:0.64;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957" />
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ x="103.66331"
+ y="142.74757"
+ id="text5218"><tspan
+ sodipodi:role="line"
+ x="103.66331"
+ y="142.74757"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="tspan5216">+ <tspan
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="tspan1156">ArrayMethod</tspan></tspan><tspan
+ id="tspan5904"
+ sodipodi:role="line"
+ x="103.66331"
+ y="149.44537"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"> lookup</tspan></text>
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ sodipodi:docname="nep43-sketch.svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 289.35355 238.13675"
+ height="238.13675mm"
+ width="289.35355mm">
+ <defs
+ id="defs2">
+ <linearGradient
+ id="linearGradient5092"
+ inkscape:collect="always">
+ <stop
+ id="stop5088"
+ offset="0"
+ style="stop-color:#800000;stop-opacity:1;" />
+ <stop
+ id="stop5090"
+ offset="1"
+ style="stop-color:#800000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5078"
+ inkscape:collect="always">
+ <stop
+ id="stop5074"
+ offset="0"
+ style="stop-color:#000080;stop-opacity:1;" />
+ <stop
+ id="stop5076"
+ offset="1"
+ style="stop-color:#000080;stop-opacity:0;" />
+ </linearGradient>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker7096"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path7094"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker6260"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path6258"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5628"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5626"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker5618"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Sstart">
+ <path
+ transform="matrix(0.2,0,0,0.2,1.2,0)"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path5616"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker5002"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path5000"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000081;fill-opacity:1;fill-rule:evenodd;stroke:#000081;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4826"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#206120;fill-opacity:1;fill-rule:evenodd;stroke:#206120;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4824"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Sstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Sstart">
+ <path
+ transform="matrix(0.2,0,0,0.2,1.2,0)"
+ style="fill:#800000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path924"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker4400"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4398"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker4390"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#b7943d;fill-opacity:1;fill-rule:evenodd;stroke:#b7943d;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path4388"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker3453"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#800000;fill-opacity:1;fill-rule:evenodd;stroke:#800000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path3451"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker2179"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#206120;fill-opacity:1;fill-rule:evenodd;stroke:#206120;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path2177"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="marker2037"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#f4ae00;fill-opacity:1;fill-rule:evenodd;stroke:#ffc433;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path2035"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="marker1480"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path1478"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#ffc433;fill-opacity:1;fill-rule:evenodd;stroke:#ffc433;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <rect
+ id="rect1296"
+ height="8.8755655"
+ width="16.467854"
+ y="100.87298"
+ x="-2.9674385" />
+ <marker
+ inkscape:collect="always"
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Send"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Send">
+ <path
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path927"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lend"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lend">
+ <path
+ transform="matrix(-0.8,0,0,-0.8,-10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path915"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:isstock="true"
+ style="overflow:visible"
+ id="Arrow1Lstart"
+ refX="0"
+ refY="0"
+ orient="auto"
+ inkscape:stockid="Arrow1Lstart">
+ <path
+ transform="matrix(0.8,0,0,0.8,10,0)"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ id="path912"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:collect="always"
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Send-5"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path927-6"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#00b200;fill-opacity:1;fill-rule:evenodd;stroke:#00b200;stroke-width:1pt;stroke-opacity:1"
+ transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+ </marker>
+ <linearGradient
+ gradientTransform="translate(0.29900013,18.755984)"
+ gradientUnits="userSpaceOnUse"
+ y2="220.58623"
+ x2="-9.5455313"
+ y1="221.22202"
+ x1="-44.254147"
+ id="linearGradient5080"
+ xlink:href="#linearGradient5078"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="translate(0.29900013,18.755984)"
+ gradientUnits="userSpaceOnUse"
+ y2="161.24438"
+ x2="216.83401"
+ y1="161.02299"
+ x1="248.04567"
+ id="linearGradient5094"
+ xlink:href="#linearGradient5092"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="translate(0.29900013,18.755984)"
+ y2="221.80334"
+ x2="4.2398605"
+ y1="221.22202"
+ x1="-44.254147"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5200"
+ xlink:href="#linearGradient5078"
+ inkscape:collect="always" />
+ </defs>
+ <sodipodi:namedview
+ inkscape:guide-bbox="true"
+ showguides="true"
+ inkscape:window-maximized="1"
+ inkscape:window-y="27"
+ inkscape:window-x="0"
+ inkscape:window-height="1376"
+ inkscape:window-width="2560"
+ showgrid="false"
+ inkscape:document-rotation="0"
+ inkscape:current-layer="text892"
+ inkscape:document-units="mm"
+ inkscape:cy="408.92855"
+ inkscape:cx="490.09169"
+ inkscape:zoom="0.7"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ lock-margins="true"
+ fit-margin-top="2"
+ fit-margin-left="2"
+ fit-margin-right="2"
+ fit-margin-bottom="2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="Layer 1"
+ transform="translate(46.254147,-52.135225)">
+ <path
+ id="rect5086"
+ style="opacity:0.25;fill:url(#linearGradient5094);fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 190.03594,66.404785 h 48.99837 c 1.14406,0 2.06509,0.92103 2.06509,2.065089 V 286.20688 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -48.99837 c -1.14405,0 -2.06508,-0.92103 -2.06508,-2.06509 V 68.469874 c 0,-1.144059 0.92103,-2.065089 2.06508,-2.065089 z" />
+ <path
+ id="rect5198"
+ style="opacity:0.25;fill:url(#linearGradient5200);fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m -42.189058,133.66225 h 67.11671 c 1.144059,0 2.065089,0.92103 2.065089,2.06509 v 12.41735 c 0,1.14406 -0.92103,2.06509 -2.065089,2.06509 h -67.11671 c -1.144059,0 -2.065089,-0.92103 -2.065089,-2.06509 v -12.41735 c 0,-1.14406 0.92103,-2.06509 2.065089,-2.06509 z" />
+ <path
+ id="rect5064"
+ style="opacity:0.25;fill:url(#linearGradient5080);fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m -42.189058,157.51857 h 61.822383 c 1.144059,0 2.065089,0.92103 2.065089,2.06509 v 126.62322 c 0,1.14406 -0.92103,2.06509 -2.065089,2.06509 h -61.822383 c -1.144059,0 -2.065089,-0.92103 -2.065089,-2.06509 V 159.58366 c 0,-1.14406 0.92103,-2.06509 2.065089,-2.06509 z" />
+ <path
+ id="rect4614"
+ style="opacity:0.25;fill:#800000;fill-opacity:0.639216;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 30.848304,181.42923 h 51.545179 c 1.14406,0 2.065089,0.92103 2.065089,2.06509 v 12.22028 c 0,1.14405 -0.921029,2.06508 -2.065089,2.06508 H 30.848304 c -1.14406,0 -2.065089,-0.92103 -2.065089,-2.06508 v -12.22028 c 0,-1.14406 0.921029,-2.06509 2.065089,-2.06509 z" />
+ <path
+ id="rect4618"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 30.848304,134.54594 h 68.292833 c 1.144063,0 2.065093,0.92103 2.065093,2.06509 v 15.70853 c 0,1.14406 -0.92103,2.06509 -2.065093,2.06509 H 30.848304 c -1.14406,0 -2.065089,-0.92103 -2.065089,-2.06509 v -15.70853 c 0,-1.14406 0.921029,-2.06509 2.065089,-2.06509 z" />
+ <path
+ id="rect4620"
+ style="opacity:0.25;fill:#000080;fill-opacity:0.4;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="M 38.256644,224.65892 H 150.95997 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 12.52236 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 H 38.256644 c -1.144059,0 -2.065089,-0.92103 -2.065089,-2.06509 v -12.52236 c 0,-1.14406 0.92103,-2.06509 2.065089,-2.06509 z" />
+ <path
+ style="fill:none;stroke:#ffc433;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker1480)"
+ d="M 162.39696,87.706466 V 102.33478"
+ id="path1476"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4822"
+ d="m 87.064551,181.16793 v 56.58639"
+ style="fill:none;stroke:#206120;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4826)" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path2033"
+ d="M 162.39696,243.19694 V 134.06539"
+ style="fill:#f4ae00;fill-opacity:1;stroke:#ffc433;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker2037)" />
+ <path
+ style="fill:none;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4400)"
+ d="m 82.917295,224.24439 v 13.50993"
+ id="path4310"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4312"
+ d="m 149.89381,181.16793 v 56.58639"
+ style="opacity:0.5;fill:none;fill-opacity:0.501961;stroke:#b7943d;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4390)" />
+ <path
+ id="rect4314"
+ style="fill:none;stroke:#000080;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:1"
+ d="M 28.543333,241.1985 H 187.44249 v 24.34369 H 28.543333 Z" />
+ <g
+ aria-label="Loop
+descriptors"
+ id="text4320"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0">
+ <path
+ d="m 6.0816287,247.79372 h 1.1937255 v 3.72691 h 2.0959961 v 0.90227 H 6.0816287 Z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2125" />
+ <path
+ d="m 11.730896,249.66028 q -0.368969,0 -0.564306,0.26665 -0.192237,0.26355 -0.192237,0.76274 0,0.49919 0.192237,0.76584 0.195337,0.26355 0.564306,0.26355 0.362769,0 0.555005,-0.26355 0.192236,-0.26665 0.192236,-0.76584 0,-0.49919 -0.192236,-0.76274 -0.192236,-0.26665 -0.555005,-0.26665 z m 0,-0.79375 q 0.89607,0 1.398364,0.48369 0.505396,0.48369 0.505396,1.33945 0,0.85576 -0.505396,1.33945 -0.502294,0.48369 -1.398364,0.48369 -0.89917,0 -1.407666,-0.48369 -0.5053953,-0.48369 -0.5053953,-1.33945 0,-0.85576 0.5053953,-1.33945 0.508496,-0.48369 1.407666,-0.48369 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2127" />
+ <path
+ d="m 16.09342,249.66028 q -0.368969,0 -0.564306,0.26665 -0.192237,0.26355 -0.192237,0.76274 0,0.49919 0.192237,0.76584 0.195337,0.26355 0.564306,0.26355 0.362769,0 0.555005,-0.26355 0.192236,-0.26665 0.192236,-0.76584 0,-0.49919 -0.192236,-0.76274 -0.192236,-0.26665 -0.555005,-0.26665 z m 0,-0.79375 q 0.89607,0 1.398364,0.48369 0.505396,0.48369 0.505396,1.33945 0,0.85576 -0.505396,1.33945 -0.502294,0.48369 -1.398364,0.48369 -0.89917,0 -1.407666,-0.48369 -0.505395,-0.48369 -0.505395,-1.33945 0,-0.85576 0.505395,-1.33945 0.508496,-0.48369 1.407666,-0.48369 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2129" />
+ <path
+ d="m 19.913343,251.9206 v 1.82315 h -1.11001 v -4.79351 h 1.11001 v 0.5085 q 0.229443,-0.30386 0.508496,-0.44649 0.279053,-0.14572 0.641821,-0.14572 0.641821,0 1.054199,0.51159 0.412378,0.5085 0.412378,1.31155 0,0.80305 -0.412378,1.31465 -0.412378,0.50849 -1.054199,0.50849 -0.362768,0 -0.641821,-0.14262 -0.279053,-0.14573 -0.508496,-0.44959 z m 0.737939,-2.24792 q -0.356567,0 -0.548804,0.26355 -0.189135,0.26045 -0.189135,0.75344 0,0.49299 0.189135,0.75654 0.192237,0.26045 0.548804,0.26045 0.356568,0 0.542603,-0.26045 0.189135,-0.26045 0.189135,-0.75654 0,-0.49609 -0.189135,-0.75654 -0.186035,-0.26045 -0.542603,-0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2131" />
+ <path
+ d="m -14.847326,257.39624 v -1.86035 h 1.116211 v 4.82451 h -1.116211 v -0.5023 q -0.229443,0.30696 -0.505396,0.44959 -0.275952,0.14262 -0.63872,0.14262 -0.641822,0 -1.054199,-0.50849 -0.412378,-0.5116 -0.412378,-1.31465 0,-0.80305 0.412378,-1.31155 0.412377,-0.51159 1.054199,-0.51159 0.359668,0 0.63562,0.14572 0.279053,0.14263 0.508496,0.44649 z m -0.731738,2.24792 q 0.356567,0 0.542602,-0.26045 0.189136,-0.26045 0.189136,-0.75654 0,-0.49609 -0.189136,-0.75654 -0.186035,-0.26045 -0.542602,-0.26045 -0.353467,0 -0.542603,0.26045 -0.186035,0.26045 -0.186035,0.75654 0,0.49609 0.186035,0.75654 0.189136,0.26045 0.542603,0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2133" />
+ <path
+ d="m -9.1980587,258.61477 v 0.31626 h -2.5951903 q 0.04031,0.39067 0.282153,0.58601 0.241846,0.19533 0.675928,0.19533 0.350366,0 0.716235,-0.10231 0.36897,-0.10542 0.7565432,-0.31626 v 0.85576 q -0.3937744,0.14883 -0.7875492,0.22324 -0.393774,0.0775 -0.787548,0.0775 -0.942579,0 -1.466578,-0.47749 -0.520898,-0.48059 -0.520898,-1.34565 0,-0.84956 0.511597,-1.33635 0.514697,-0.48679 1.413867,-0.48679 0.818555,0 1.3084471,0.49299 0.4929932,0.49299 0.4929932,1.31775 z m -1.1410153,-0.36897 q 0,-0.31626 -0.186035,-0.5085 -0.182935,-0.19534 -0.480591,-0.19534 -0.322461,0 -0.523999,0.18294 -0.201538,0.17983 -0.251148,0.5209 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2135" />
+ <path
+ d="m -5.644787,256.99626 v 0.84336 q -0.3565674,-0.14883 -0.6883301,-0.22324 -0.3317627,-0.0744 -0.6263184,-0.0744 -0.3162597,0 -0.471289,0.0806 -0.1519287,0.0775 -0.1519287,0.24185 0,0.13332 0.1147217,0.20463 0.1178222,0.0713 0.4185791,0.10542 l 0.1953369,0.0279 q 0.8526611,0.10852 1.1472167,0.35657 0.2945557,0.24804 0.2945557,0.77824 0,0.55501 -0.4092773,0.83406 -0.4092774,0.27905 -1.2216309,0.27905 -0.344165,0 -0.7131347,-0.0558 -0.3658692,-0.0527 -0.7534424,-0.16123 v -0.84336 q 0.3317627,0.16123 0.6790283,0.24185 0.3503662,0.0806 0.7100342,0.0806 0.3255615,0 0.4898925,-0.0899 0.1643311,-0.0899 0.1643311,-0.26665 0,-0.14883 -0.1147217,-0.22014 -0.1116211,-0.0744 -0.4495849,-0.11473 l -0.1953369,-0.0248 q -0.7410401,-0.093 -1.0386963,-0.34417 -0.2976563,-0.25114 -0.2976563,-0.76274 0,-0.5519 0.3782715,-0.81855 0.3782715,-0.26665 1.1596191,-0.26665 0.306958,0 0.6449219,0.0465 0.3379639,0.0465 0.7348389,0.14573 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2137" />
+ <path
+ d="m -1.772156,256.99626 v 0.90537 q -0.2263427,-0.15503 -0.4557861,-0.22944 -0.2263428,-0.0744 -0.471289,-0.0744 -0.4650879,0 -0.7255371,0.27285 -0.2573487,0.26975 -0.2573487,0.75654 0,0.48679 0.2573487,0.75964 0.2604492,0.26975 0.7255371,0.26975 0.2604492,0 0.4929931,-0.0775 0.2356445,-0.0775 0.434082,-0.22944 v 0.90847 q -0.2604492,0.0961 -0.5302002,0.14262 -0.2666503,0.0496 -0.5364013,0.0496 -0.9394775,0 -1.4696777,-0.48059 -0.5302002,-0.48369 -0.5302002,-1.34255 0,-0.85886 0.5302002,-1.33945 0.5302002,-0.48369 1.4696777,-0.48369 0.2728515,0 0.5364013,0.0496 0.2666504,0.0465 0.5302002,0.14263 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2139" />
+ <path
+ d="m 1.7656118,257.83342 q -0.1457275,-0.0682 -0.291455,-0.0992 -0.142627,-0.0341 -0.2883545,-0.0341 -0.42788089,0 -0.66042483,0.27596 -0.22944335,0.27285 -0.22944335,0.78444 v 1.59991 h -1.11000975 v -3.47266 h 1.11000975 v 0.57051 q 0.21394042,-0.34107 0.48989257,-0.49609 0.27905271,-0.15813 0.66662601,-0.15813 0.05581,0 0.1209228,0.006 0.065112,0.003 0.1891357,0.0186 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2141" />
+ <path
+ d="m 2.3175162,256.88774 h 1.1100097 v 3.47266 H 2.3175162 Z m 0,-1.35185 h 1.1100097 v 0.90537 H 2.3175162 Z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2143" />
+ <path
+ d="m 5.6041388,259.8581 v 1.82315 H 4.494129 v -4.79351 h 1.1100098 v 0.5085 q 0.2294433,-0.30386 0.5084961,-0.44649 0.2790527,-0.14572 0.6418212,-0.14572 0.6418213,0 1.0541992,0.51159 0.412378,0.5085 0.412378,1.31155 0,0.80305 -0.412378,1.31465 -0.4123779,0.50849 -1.0541992,0.50849 -0.3627685,0 -0.6418212,-0.14262 -0.2790528,-0.14573 -0.5084961,-0.44959 z m 0.7379394,-2.24792 q -0.3565674,0 -0.5488037,0.26355 -0.1891357,0.26045 -0.1891357,0.75344 0,0.49299 0.1891357,0.75654 0.1922363,0.26045 0.5488037,0.26045 0.3565674,0 0.5426025,-0.26045 0.1891358,-0.26045 0.1891358,-0.75654 0,-0.49609 -0.1891358,-0.75654 -0.1860351,-0.26045 -0.5426025,-0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2145" />
+ <path
+ d="m 10.251916,255.90175 v 0.98599 h 1.144116 v 0.79375 h -1.144116 v 1.47278 q 0,0.24185 0.09612,0.32866 0.09612,0.0837 0.381372,0.0837 h 0.570508 v 0.79375 h -0.95188 q -0.6573241,0 -0.9332762,-0.27285 -0.2728516,-0.27596 -0.2728516,-0.93328 v -1.47278 H 8.5900019 v -0.79375 h 0.5519043 v -0.98599 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2147" />
+ <path
+ d="m 13.727674,257.59778 q -0.36897,0 -0.564307,0.26665 -0.192236,0.26355 -0.192236,0.76274 0,0.49919 0.192236,0.76584 0.195337,0.26355 0.564307,0.26355 0.362768,0 0.555005,-0.26355 0.192236,-0.26665 0.192236,-0.76584 0,-0.49919 -0.192236,-0.76274 -0.192237,-0.26665 -0.555005,-0.26665 z m 0,-0.79375 q 0.896069,0 1.398364,0.48369 0.505396,0.48369 0.505396,1.33945 0,0.85576 -0.505396,1.33945 -0.502295,0.48369 -1.398364,0.48369 -0.89917,0 -1.407666,-0.48369 -0.505396,-0.48369 -0.505396,-1.33945 0,-0.85576 0.505396,-1.33945 0.508496,-0.48369 1.407666,-0.48369 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2149" />
+ <path
+ d="m 19.017271,257.83342 q -0.145727,-0.0682 -0.291455,-0.0992 -0.142627,-0.0341 -0.288354,-0.0341 -0.427881,0 -0.660425,0.27596 -0.229443,0.27285 -0.229443,0.78444 v 1.59991 h -1.11001 v -3.47266 h 1.11001 v 0.57051 q 0.21394,-0.34107 0.489892,-0.49609 0.279053,-0.15813 0.666626,-0.15813 0.05581,0 0.120923,0.006 0.06511,0.003 0.189136,0.0186 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2151" />
+ <path
+ d="m 22.282188,256.99626 v 0.84336 q -0.356567,-0.14883 -0.68833,-0.22324 -0.331763,-0.0744 -0.626318,-0.0744 -0.31626,0 -0.471289,0.0806 -0.151929,0.0775 -0.151929,0.24185 0,0.13332 0.114722,0.20463 0.117822,0.0713 0.418579,0.10542 l 0.195337,0.0279 q 0.852661,0.10852 1.147216,0.35657 0.294556,0.24804 0.294556,0.77824 0,0.55501 -0.409277,0.83406 -0.409278,0.27905 -1.221631,0.27905 -0.344165,0 -0.713135,-0.0558 -0.365869,-0.0527 -0.753442,-0.16123 v -0.84336 q 0.331763,0.16123 0.679028,0.24185 0.350366,0.0806 0.710034,0.0806 0.325562,0 0.489893,-0.0899 0.164331,-0.0899 0.164331,-0.26665 0,-0.14883 -0.114722,-0.22014 -0.111621,-0.0744 -0.449585,-0.11473 l -0.195337,-0.0248 q -0.74104,-0.093 -1.038696,-0.34417 -0.297656,-0.25114 -0.297656,-0.76274 0,-0.5519 0.378271,-0.81855 0.378272,-0.26665 1.159619,-0.26665 0.306958,0 0.644922,0.0465 0.337964,0.0465 0.734839,0.14573 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000080;fill-opacity:1;stroke:#000000;stroke-width:0.398751;stroke-opacity:0"
+ id="path2153" />
+ </g>
+ <path
+ id="rect4322"
+ style="opacity:0.6;fill:#ffffff;stroke:#800000;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:0.8"
+ d="M 28.168863,197.56255 H 187.06802 v 24.34368 H 28.168863 Z" />
+ <g
+ aria-label="Resolver
+Input"
+ id="text4328"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751">
+ <path
+ d="m -5.998254,205.75171 q 0.3751709,0 0.5364014,-0.13953 0.164331,-0.13953 0.164331,-0.45889 0,-0.31626 -0.164331,-0.45268 -0.1612305,-0.13643 -0.5364014,-0.13643 h -0.5022949 v 1.18753 z m -0.5022949,0.82475 v 1.75183 h -1.1937255 v -4.62917 h 1.8231445 q 0.9146728,0 1.3394531,0.30696 0.4278808,0.30695 0.4278808,0.97048 0,0.45889 -0.2232422,0.75344 -0.2201416,0.29456 -0.6666259,0.43408 0.2449463,0.0558 0.4371826,0.25425 0.1953369,0.19534 0.3937744,0.59531 l 0.6480224,1.31465 h -1.2712402 l -0.5643066,-1.15031 q -0.1705322,-0.34727 -0.3472656,-0.47439 -0.1736328,-0.12713 -0.4650879,-0.12713 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2325" />
+ <path
+ d="m 0.61219533,206.58266 v 0.31626 H -1.9829951 q 0.040308,0.39068 0.2821534,0.58601 0.2418457,0.19534 0.6759277,0.19534 0.35036618,0 0.71623532,-0.10232 0.36896972,-0.10542 0.75654295,-0.31626 v 0.85576 q -0.3937744,0.14883 -0.78754881,0.22325 -0.39377441,0.0775 -0.78754886,0.0775 -0.9425781,0 -1.4665771,-0.47749 -0.5208984,-0.48059 -0.5208984,-1.34565 0,-0.84957 0.5115967,-1.33636 0.5146972,-0.48679 1.4138671,-0.48679 0.8185547,0 1.30844727,0.49299 0.49299316,0.493 0.49299316,1.31775 z m -1.14101561,-0.36897 q 0,-0.31626 -0.18603515,-0.50849 -0.18293457,-0.19534 -0.48059077,-0.19534 -0.322461,0 -0.5239991,0.18293 -0.201538,0.17984 -0.2511474,0.5209 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2327" />
+ <path
+ d="m 4.1654665,204.96416 v 0.84336 q -0.3565673,-0.14883 -0.68833,-0.22325 -0.3317627,-0.0744 -0.6263184,-0.0744 -0.3162597,0 -0.471289,0.0806 -0.1519287,0.0775 -0.1519287,0.24184 0,0.13333 0.1147216,0.20464 0.1178223,0.0713 0.4185791,0.10542 l 0.1953369,0.0279 q 0.8526612,0.10852 1.1472168,0.35656 0.2945557,0.24805 0.2945557,0.77825 0,0.555 -0.4092774,0.83406 -0.4092773,0.27905 -1.2216308,0.27905 -0.344165,0 -0.7131348,-0.0558 -0.3658691,-0.0527 -0.7534423,-0.16123 v -0.84336 q 0.3317627,0.16123 0.6790283,0.24185 0.3503662,0.0806 0.7100342,0.0806 0.3255615,0 0.4898925,-0.0899 0.1643311,-0.0899 0.1643311,-0.26665 0,-0.14883 -0.1147217,-0.22014 -0.1116211,-0.0744 -0.449585,-0.11472 l -0.1953369,-0.0248 q -0.74104,-0.093 -1.0386962,-0.34417 -0.2976563,-0.25115 -0.2976563,-0.76274 0,-0.55191 0.3782715,-0.81856 0.3782715,-0.26665 1.1596191,-0.26665 0.306958,0 0.6449219,0.0465 0.3379638,0.0465 0.7348388,0.14573 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2329" />
+ <path
+ d="m 6.8846806,205.56567 q -0.3689697,0 -0.5643066,0.26665 -0.1922363,0.26355 -0.1922363,0.76275 0,0.49919 0.1922363,0.76584 0.1953369,0.26355 0.5643066,0.26355 0.3627686,0 0.5550049,-0.26355 0.1922363,-0.26665 0.1922363,-0.76584 0,-0.4992 -0.1922363,-0.76275 -0.1922363,-0.26665 -0.5550049,-0.26665 z m 0,-0.79375 q 0.8960693,0 1.3983642,0.48369 0.5053955,0.48369 0.5053955,1.33946 0,0.85576 -0.5053955,1.33945 -0.5022949,0.48369 -1.3983642,0.48369 -0.8991699,0 -1.407666,-0.48369 -0.5053955,-0.48369 -0.5053955,-1.33945 0,-0.85577 0.5053955,-1.33946 0.5084961,-0.48369 1.407666,-0.48369 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2331" />
+ <path
+ d="m 9.5945924,203.50378 h 1.1100096 v 4.82451 H 9.5945924 Z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2333" />
+ <path
+ d="m 11.334021,204.85564 h 1.110009 l 0.865064,2.39985 0.861963,-2.39985 h 1.11311 l -1.367358,3.47265 h -1.218531 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2335" />
+ <path
+ d="m 19.376941,206.58266 v 0.31626 H 16.78175 q 0.04031,0.39068 0.282153,0.58601 0.241846,0.19534 0.675928,0.19534 0.350366,0 0.716236,-0.10232 0.368969,-0.10542 0.756543,-0.31626 v 0.85576 q -0.393775,0.14883 -0.787549,0.22325 -0.393775,0.0775 -0.787549,0.0775 -0.942578,0 -1.466577,-0.47749 -0.520899,-0.48059 -0.520899,-1.34565 0,-0.84957 0.511597,-1.33636 0.514697,-0.48679 1.413867,-0.48679 0.818555,0 1.308447,0.49299 0.492994,0.493 0.492994,1.31775 z m -1.141016,-0.36897 q 0,-0.31626 -0.186035,-0.50849 -0.182935,-0.19534 -0.480591,-0.19534 -0.322461,0 -0.523999,0.18293 -0.201538,0.17984 -0.251147,0.5209 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2337" />
+ <path
+ d="m 22.796886,205.80132 q -0.145727,-0.0682 -0.291455,-0.0992 -0.142627,-0.0341 -0.288354,-0.0341 -0.427881,0 -0.660425,0.27595 -0.229444,0.27285 -0.229444,0.78445 v 1.5999 h -1.110009 v -3.47265 h 1.110009 v 0.5705 q 0.213941,-0.34106 0.489893,-0.49609 0.279053,-0.15813 0.666626,-0.15813 0.05581,0 0.120923,0.006 0.06511,0.003 0.189136,0.0186 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2339" />
+ <path
+ d="M 4.4135135,211.63662 H 5.607239 v 4.62917 H 4.4135135 Z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2341" />
+ <path
+ d="m 10.21781,214.15119 v 2.1146 H 9.1015992 v -0.34416 -1.27434 q 0,-0.44959 -0.021704,-0.62012 -0.018603,-0.17053 -0.068213,-0.25115 -0.065112,-0.10852 -0.1767334,-0.16743 -0.1116211,-0.062 -0.254248,-0.062 -0.3472656,0 -0.5457031,0.26975 -0.1984375,0.26665 -0.1984375,0.74104 v 1.70842 H 6.7265504 v -3.47265 h 1.1100098 v 0.50849 q 0.2511474,-0.30385 0.5333007,-0.44648 0.2821534,-0.14573 0.6232178,-0.14573 0.6015137,0 0.9115723,0.36897 0.313159,0.36897 0.313159,1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2343" />
+ <path
+ d="m 12.357215,215.7635 v 1.82314 h -1.11001 v -4.7935 h 1.11001 v 0.50849 q 0.229443,-0.30385 0.508496,-0.44648 0.279052,-0.14573 0.641821,-0.14573 0.641821,0 1.054199,0.5116 0.412378,0.50849 0.412378,1.31155 0,0.80305 -0.412378,1.31464 -0.412378,0.5085 -1.054199,0.5085 -0.362769,0 -0.641821,-0.14263 -0.279053,-0.14572 -0.508496,-0.44958 z m 0.737939,-2.24793 q -0.356567,0 -0.548804,0.26355 -0.189135,0.26045 -0.189135,0.75345 0,0.49299 0.189135,0.75654 0.192237,0.26045 0.548804,0.26045 0.356567,0 0.542603,-0.26045 0.189135,-0.26045 0.189135,-0.75654 0,-0.4961 -0.189135,-0.75655 -0.186036,-0.26045 -0.542603,-0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2345" />
+ <path
+ d="m 15.755457,214.91394 v -2.1208 h 1.116211 v 0.34726 q 0,0.28216 -0.0031,0.71004 -0.0031,0.42478 -0.0031,0.5674 0,0.41858 0.0217,0.60462 0.0217,0.18293 0.07441,0.26665 0.06821,0.10852 0.176733,0.16743 0.111621,0.0589 0.254248,0.0589 0.347266,0 0.545703,-0.26665 0.198438,-0.26665 0.198438,-0.74104 v -1.71462 h 1.110009 v 3.47265 h -1.110009 v -0.50229 q -0.251148,0.30386 -0.533301,0.44958 -0.279053,0.14263 -0.617017,0.14263 -0.601513,0 -0.917773,-0.36897 -0.313159,-0.36897 -0.313159,-1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2347" />
+ <path
+ d="m 21.525646,211.80715 v 0.98599 h 1.144117 v 0.79375 h -1.144117 v 1.47277 q 0,0.24185 0.09612,0.32867 0.09612,0.0837 0.381372,0.0837 h 0.570507 v 0.79375 h -0.951879 q -0.657325,0 -0.933277,-0.27285 -0.272851,-0.27595 -0.272851,-0.93328 v -1.47277 h -0.551905 v -0.79375 h 0.551905 v -0.98599 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path2349" />
+ </g>
+ <path
+ id="rect4330"
+ style="opacity:0.5;fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 142.70969,200.65752 h 39.2278 v 17.71783 h -39.2278 z" />
+ <path
+ id="rect4332"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 89.303658,201.09155 H 128.61751 V 218.2229 H 89.303658 Z" />
+ <g
+ aria-label="+"
+ id="text4336"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 83.42805,205.62754 v 3.38679 h 3.386794 v 1.03368 H 83.42805 v 3.38679 h -1.021511 v -3.38679 h -3.386793 v -1.03368 h 3.386793 v -3.38679 z"
+ style="stroke-width:0.933951"
+ id="path2606" />
+ </g>
+ <g
+ aria-label="→"
+ id="text4340"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.933951">
+ <path
+ d="m 140.22087,209.97661 v 0.54723 l -2.3896,2.38961 -0.72965,-0.72965 1.41673,-1.41674 h -7.41203 v -1.03367 h 7.41203 l -1.41673,-1.41674 0.72965,-0.72965 z"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.933951"
+ id="path2693" />
+ </g>
+ <path
+ id="rect4342"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 37.217079,200.69289 H 76.53093 v 17.13134 H 37.217079 Z" />
+ <path
+ id="rect4344"
+ style="fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 142.70969,244.04799 h 39.2278 v 17.71783 h -39.2278 z" />
+ <path
+ id="rect4346"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 89.303658,244.48203 h 39.313852 v 17.13134 H 89.303658 Z" />
+ <g
+ aria-label="+"
+ id="text4350"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 83.42805,249.018 v 3.38679 h 3.386794 v 1.03367 H 83.42805 v 3.3868 h -1.021511 v -3.3868 h -3.386793 v -1.03367 h 3.386793 V 249.018 Z"
+ style="stroke-width:0.933951"
+ id="path3035" />
+ </g>
+ <g
+ aria-label="→"
+ id="text4354"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 140.22087,253.36706 v 0.54724 l -2.3896,2.38961 -0.72965,-0.72965 1.41673,-1.41674 h -7.41203 v -1.03367 h 7.41203 l -1.41673,-1.41674 0.72965,-0.72965 z"
+ style="stroke-width:0.933951"
+ id="path3122" />
+ </g>
+ <path
+ id="rect4356"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 37.217079,244.08336 H 76.53093 V 261.2147 H 37.217079 Z" />
+ <g
+ aria-label=">U5"
+ id="text4360"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 50.308698,207.47705 2.691162,1.66381 v 0.71603 l -2.670407,1.66382 -0.432385,-0.63301 2.317582,-1.38709 -2.317582,-1.35942 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3294" />
+ <path
+ d="m 57.30986,206.88555 v 3.19964 q 0,0.48773 -0.197167,0.87169 -0.197167,0.3805 -0.581125,0.59842 -0.380498,0.21792 -0.93741,0.21792 -0.56037,0 -0.940869,-0.211 -0.380498,-0.21447 -0.574207,-0.59496 -0.193708,-0.3805 -0.193708,-0.88207 v -3.19964 h 0.947787 v 2.93329 q 0,0.61226 0.166036,0.92012 0.166036,0.3044 0.594961,0.3044 0.432385,0 0.59842,-0.3044 0.166036,-0.30786 0.166036,-0.92012 v -2.93329 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3296" />
+ <path
+ d="m 61.166722,206.88555 -0.107232,0.67106 h -1.79872 v 1.19684 q 0.190249,-0.0934 0.380499,-0.13145 0.190249,-0.0381 0.366662,-0.0381 0.377039,0 0.677979,0.18333 0.30094,0.18333 0.477352,0.52924 0.176413,0.34245 0.176413,0.82326 0,0.48081 -0.22484,0.85439 -0.221381,0.37358 -0.622634,0.58805 -0.401252,0.211 -0.940868,0.211 -0.48773,0 -0.868229,-0.17987 -0.377039,-0.17987 -0.646847,-0.48427 l 0.532698,-0.49465 q 0.377039,0.44622 0.930491,0.44622 0.411631,0 0.653766,-0.24905 0.242135,-0.24906 0.242135,-0.68836 0,-0.48773 -0.204085,-0.68835 -0.204086,-0.20063 -0.518862,-0.20063 -0.311317,0 -0.643388,0.15912 h -0.639929 v -2.50783 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3298" />
+ </g>
+ <g
+ aria-label="<U8"
+ id="text4364"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 103.47904,207.92016 0.40817,0.64685 -2.31412,1.37671 2.31412,1.36634 -0.43239,0.65376 -2.6704,-1.66381 v -0.71257 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3385" />
+ <path
+ d="m 108.19721,207.32866 v 3.19965 q 0,0.48773 -0.19717,0.87168 -0.19717,0.3805 -0.58112,0.59842 -0.3805,0.21793 -0.93741,0.21793 -0.56037,0 -0.94087,-0.21101 -0.3805,-0.21446 -0.57421,-0.59496 -0.19371,-0.3805 -0.19371,-0.88206 v -3.19965 h 0.94779 v 2.9333 q 0,0.61225 0.16604,0.92011 0.16603,0.3044 0.59496,0.3044 0.43238,0 0.59842,-0.3044 0.16603,-0.30786 0.16603,-0.92011 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3387" />
+ <path
+ d="m 112.17168,208.47362 q 0,0.33898 -0.19371,0.58458 -0.19025,0.24559 -0.57767,0.46352 0.96163,0.45659 0.96163,1.29715 0,0.37704 -0.20063,0.69527 -0.20063,0.31824 -0.5915,0.51195 -0.38742,0.19025 -0.95125,0.19025 -0.56037,0 -0.94087,-0.18679 -0.38049,-0.19025 -0.5742,-0.50157 -0.19371,-0.31132 -0.19371,-0.6849 0,-0.422 0.24559,-0.7264 0.24906,-0.3044 0.66415,-0.48773 -0.37358,-0.21447 -0.54654,-0.46006 -0.17295,-0.24905 -0.17295,-0.65031 0,-0.41855 0.21446,-0.70565 0.21792,-0.29056 0.56729,-0.4393 0.35283,-0.14874 0.75754,-0.14874 0.42546,0 0.77137,0.14528 0.34937,0.14182 0.55345,0.42201 0.20755,0.28018 0.20755,0.68144 z m -2.19652,0.0484 q 0,0.31132 0.20755,0.4739 0.211,0.15911 0.61571,0.30439 0.26981,-0.17987 0.38396,-0.35628 0.11415,-0.17987 0.11415,-0.42201 0,-0.29402 -0.16949,-0.47389 -0.16604,-0.18333 -0.48773,-0.18333 -0.31478,0 -0.49119,0.16949 -0.17296,0.1695 -0.17296,0.48773 z m 1.46319,2.29683 q 0,-0.26635 -0.12106,-0.42893 -0.11761,-0.16257 -0.34937,-0.27672 -0.23176,-0.11415 -0.57421,-0.23522 -0.23867,0.1349 -0.40125,0.35629 -0.15912,0.22138 -0.15912,0.56728 0,0.33553 0.20063,0.53962 0.20063,0.20409 0.60188,0.20409 0.40471,0 0.60188,-0.21101 0.20062,-0.21446 0.20062,-0.5154 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3389" />
+ </g>
+ <text
+ id="text4368"
+ y="212.01785"
+ x="150.35503"
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.505891"
+ xml:space="preserve"><tspan
+ style="stroke-width:0.505891"
+ y="212.01785"
+ x="150.35503"
+ id="tspan4366"
+ sodipodi:role="line" /></text>
+ <g
+ aria-label="set descriptors
+for inner-loop…"
+ id="text4374"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;stroke-width:0.398751">
+ <path
+ d="m 40.965521,227.89085 v 0.45171 q -0.202491,-0.10384 -0.420559,-0.15576 -0.218068,-0.0519 -0.451712,-0.0519 -0.355658,0 -0.534785,0.10903 -0.176531,0.10904 -0.176531,0.32711 0,0.16614 0.127206,0.2622 0.127206,0.0934 0.511421,0.17912 l 0.163551,0.0363 q 0.508825,0.10903 0.7217,0.30893 0.215472,0.1973 0.215472,0.55296 0,0.40498 -0.32191,0.64122 -0.319313,0.23624 -0.880059,0.23624 -0.233644,0 -0.488056,-0.0467 -0.251817,-0.0441 -0.53219,-0.13499 v -0.49325 q 0.264797,0.13759 0.521806,0.20768 0.257008,0.0675 0.508824,0.0675 0.337486,0 0.519209,-0.11423 0.181723,-0.11682 0.181723,-0.3271 0,-0.1947 -0.132398,-0.29855 -0.129802,-0.10384 -0.573726,-0.19989 l -0.166147,-0.0389 q -0.443923,-0.0935 -0.641223,-0.28557 -0.197299,-0.1947 -0.197299,-0.53219 0,-0.41017 0.290757,-0.63343 0.290757,-0.22326 0.825542,-0.22326 0.264797,0 0.498441,0.0389 0.233644,0.0389 0.430943,0.11682 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3476" />
+ <path
+ d="m 44.368936,229.13955 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267393,0.25701 0.742469,0.25701 0.275181,0 0.532189,-0.0675 0.259605,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257008,0.10903 -0.526997,0.16615 -0.269989,0.0571 -0.547765,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40499 -0.404983,-1.09554 0,-0.71391 0.384214,-1.13187 0.386811,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477672,-0.14019 q -0.0052,-0.392 -0.220664,-0.62564 -0.212876,-0.23365 -0.565938,-0.23365 -0.399791,0 -0.641223,0.22586 -0.238836,0.22585 -0.275181,0.63603 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3478" />
+ <path
+ d="m 45.625422,226.97964 v 0.82554 h 0.983901 v 0.37124 h -0.983901 v 1.57839 q 0,0.35566 0.09605,0.45691 0.09865,0.10124 0.397194,0.10124 h 0.490653 v 0.39979 H 46.11867 q -0.552957,0 -0.763237,-0.20508 -0.210279,-0.20769 -0.210279,-0.75286 v -1.57839 h -0.350466 v -0.37124 h 0.350466 v -0.82554 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3480" />
+ <path
+ d="m 50.840876,228.24651 v -1.5732 h 0.477673 v 4.03944 h -0.477673 v -0.43613 q -0.15057,0.2596 -0.381618,0.38681 -0.228452,0.12461 -0.550362,0.12461 -0.526997,0 -0.859291,-0.42056 -0.329697,-0.42056 -0.329697,-1.10592 0,-0.68535 0.329697,-1.10591 0.332294,-0.42056 0.859291,-0.42056 0.32191,0 0.550362,0.12721 0.231048,0.12461 0.381618,0.38421 z m -1.62772,1.01505 q 0,0.527 0.215472,0.82814 0.218068,0.29855 0.59709,0.29855 0.379023,0 0.597091,-0.29855 0.218067,-0.30114 0.218067,-0.82814 0,-0.52699 -0.218067,-0.82554 -0.218068,-0.30114 -0.597091,-0.30114 -0.379022,0 -0.59709,0.30114 -0.215472,0.29855 -0.215472,0.82554 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3482" />
+ <path
+ d="m 54.78946,229.13955 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267393,0.25701 0.742469,0.25701 0.275181,0 0.532189,-0.0675 0.259605,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257008,0.10903 -0.526997,0.16615 -0.269988,0.0571 -0.547765,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40499 -0.404983,-1.09554 0,-0.71391 0.384214,-1.13187 0.386811,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477672,-0.14019 q -0.0052,-0.392 -0.220664,-0.62564 -0.212875,-0.23365 -0.565938,-0.23365 -0.399791,0 -0.641223,0.22586 -0.238836,0.22585 -0.27518,0.63603 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3484" />
+ <path
+ d="m 57.427042,227.89085 v 0.45171 q -0.202491,-0.10384 -0.420559,-0.15576 -0.218068,-0.0519 -0.451712,-0.0519 -0.355658,0 -0.534785,0.10903 -0.176531,0.10904 -0.176531,0.32711 0,0.16614 0.127206,0.2622 0.127206,0.0934 0.511421,0.17912 l 0.163551,0.0363 q 0.508825,0.10903 0.7217,0.30893 0.215472,0.1973 0.215472,0.55296 0,0.40498 -0.321909,0.64122 -0.319314,0.23624 -0.88006,0.23624 -0.233644,0 -0.488056,-0.0467 -0.251817,-0.0441 -0.532189,-0.13499 v -0.49325 q 0.264796,0.13759 0.521805,0.20768 0.257008,0.0675 0.508824,0.0675 0.337486,0 0.519209,-0.11423 0.181724,-0.11682 0.181724,-0.3271 0,-0.1947 -0.132399,-0.29855 -0.129802,-0.10384 -0.573726,-0.19989 l -0.166146,-0.0389 q -0.443924,-0.0935 -0.641224,-0.28557 -0.197299,-0.1947 -0.197299,-0.53219 0,-0.41017 0.290757,-0.63343 0.290757,-0.22326 0.825542,-0.22326 0.264797,0 0.498441,0.0389 0.233644,0.0389 0.430943,0.11682 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3486" />
+ <path
+ d="m 60.435858,227.91681 v 0.44652 q -0.202492,-0.11163 -0.407579,-0.16614 -0.202492,-0.0571 -0.410175,-0.0571 -0.464692,0 -0.721701,0.29595 -0.257008,0.29335 -0.257008,0.82554 0,0.53219 0.257008,0.82814 0.257009,0.29336 0.721701,0.29336 0.207683,0 0.410175,-0.0545 0.205087,-0.0571 0.407579,-0.16874 v 0.44132 q -0.199895,0.0935 -0.415367,0.14019 -0.212876,0.0467 -0.454308,0.0467 -0.656799,0 -1.04361,-0.41277 -0.386811,-0.41277 -0.386811,-1.11371 0,-0.71131 0.389407,-1.11889 0.392003,-0.40758 1.072166,-0.40758 0.220664,0 0.430944,0.0467 0.21028,0.0441 0.407579,0.13499 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3488" />
+ <path
+ d="m 62.951426,228.2517 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207683,-0.0234 -0.404984,0 -0.623051,0.2648 -0.215472,0.2622 -0.215472,0.75545 v 1.53166 h -0.480268 v -2.90757 h 0.480268 v 0.45171 q 0.150571,-0.26479 0.392003,-0.392 0.241432,-0.1298 0.586706,-0.1298 0.04933,0 0.109034,0.008 0.05971,0.005 0.132398,0.0182 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3490" />
+ <path
+ d="m 63.452462,227.80518 h 0.477672 v 2.90757 h -0.477672 z m 0,-1.13187 h 0.477672 v 0.60488 h -0.477672 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3492" />
+ <path
+ d="m 65.391708,230.27662 v 1.54205 H 64.91144 v -4.01349 h 0.480268 v 0.44133 q 0.150571,-0.2596 0.379023,-0.38421 0.231048,-0.12721 0.550361,-0.12721 0.529593,0 0.859291,0.42056 0.332294,0.42056 0.332294,1.10591 0,0.68536 -0.332294,1.10592 -0.329698,0.42056 -0.859291,0.42056 -0.319313,0 -0.550361,-0.12461 -0.228452,-0.12721 -0.379023,-0.38681 z m 1.625124,-1.01506 q 0,-0.52699 -0.218067,-0.82554 -0.215472,-0.30114 -0.594495,-0.30114 -0.379022,0 -0.59709,0.30114 -0.215472,0.29855 -0.215472,0.82554 0,0.527 0.215472,0.82814 0.218068,0.29855 0.59709,0.29855 0.379023,0 0.594495,-0.29855 0.218067,-0.30114 0.218067,-0.82814 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3494" />
+ <path
+ d="m 68.776951,226.97964 v 0.82554 h 0.983901 v 0.37124 h -0.983901 v 1.57839 q 0,0.35566 0.09605,0.45691 0.09865,0.10124 0.397195,0.10124 h 0.490652 v 0.39979 H 69.2702 q -0.552958,0 -0.763237,-0.20508 -0.21028,-0.20769 -0.21028,-0.75286 v -1.57839 h -0.350466 v -0.37124 h 0.350466 v -0.82554 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3496" />
+ <path
+ d="m 71.515778,228.14007 q -0.384215,0 -0.607475,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220664,0.82295 0.22326,0.29855 0.610071,0.29855 0.381618,0 0.604878,-0.30115 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.604878,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40499 0.355658,1.12149 0,0.71392 -0.355658,1.1215 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.1215 0,-0.7165 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3498" />
+ <path
+ d="m 75.326773,228.2517 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207683,-0.0234 -0.404983,0 -0.623051,0.2648 -0.215472,0.2622 -0.215472,0.75545 v 1.53166 h -0.480268 v -2.90757 h 0.480268 v 0.45171 q 0.150571,-0.26479 0.392003,-0.392 0.241432,-0.1298 0.586706,-0.1298 0.04932,0 0.109034,0.008 0.05971,0.005 0.132398,0.0182 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3500" />
+ <path
+ d="m 77.681384,227.89085 v 0.45171 q -0.202492,-0.10384 -0.42056,-0.15576 -0.218068,-0.0519 -0.451712,-0.0519 -0.355658,0 -0.534785,0.10903 -0.176531,0.10904 -0.176531,0.32711 0,0.16614 0.127206,0.2622 0.127207,0.0934 0.511421,0.17912 l 0.163551,0.0363 q 0.508825,0.10903 0.7217,0.30893 0.215472,0.1973 0.215472,0.55296 0,0.40498 -0.321909,0.64122 -0.319314,0.23624 -0.88006,0.23624 -0.233644,0 -0.488056,-0.0467 -0.251816,-0.0441 -0.532189,-0.13499 v -0.49325 q 0.264796,0.13759 0.521805,0.20768 0.257008,0.0675 0.508825,0.0675 0.337485,0 0.519209,-0.11423 0.181723,-0.11682 0.181723,-0.3271 0,-0.1947 -0.132399,-0.29855 -0.129802,-0.10384 -0.573725,-0.19989 l -0.166147,-0.0389 q -0.443924,-0.0935 -0.641223,-0.28557 -0.1973,-0.1947 -0.1973,-0.53219 0,-0.41017 0.290757,-0.63343 0.290757,-0.22326 0.825542,-0.22326 0.264797,0 0.498441,0.0389 0.233644,0.0389 0.430944,0.11682 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3502" />
+ <path
+ d="m 40.583903,233.31918 v 0.3972 h -0.456904 q -0.257009,0 -0.358254,0.10384 -0.09865,0.10384 -0.09865,0.37383 v 0.25701 h 0.786601 v 0.37123 h -0.786601 v 2.53634 h -0.480268 v -2.53634 h -0.456904 v -0.37123 h 0.456904 v -0.20249 q 0,-0.48546 0.225855,-0.70613 0.225856,-0.22326 0.716509,-0.22326 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3504" />
+ <path
+ d="m 42.110377,234.78595 q -0.384215,0 -0.607475,0.30114 -0.223259,0.29854 -0.223259,0.82035 0,0.5218 0.220663,0.82295 0.22326,0.29854 0.610071,0.29854 0.381619,0 0.604878,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.223259,-0.30374 -0.604878,-0.30374 z m 0,-0.40499 q 0.623051,0 0.978709,0.40499 0.355658,0.40498 0.355658,1.12149 0,0.71391 -0.355658,1.12149 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 0.355658,-0.40499 0.981305,-0.40499 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3506" />
+ <path
+ d="m 45.921371,234.89758 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207684,-0.0234 -0.404983,0 -0.62305,0.26479 -0.215472,0.2622 -0.215472,0.75545 v 1.53167 h -0.480268 v -2.90757 h 0.480268 v 0.45171 q 0.150571,-0.2648 0.392003,-0.392 0.241432,-0.12981 0.586706,-0.12981 0.04932,0 0.109034,0.008 0.05971,0.005 0.132398,0.0182 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3508" />
+ <path
+ d="m 48.112433,234.45106 h 0.477673 v 2.90757 h -0.477673 z m 0,-1.13188 h 0.477673 v 0.60488 h -0.477673 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3510" />
+ <path
+ d="m 52.0065,235.6037 v 1.75493 h -0.477672 v -1.73935 q 0,-0.41277 -0.160955,-0.61786 -0.160955,-0.20509 -0.482864,-0.20509 -0.386811,0 -0.610071,0.24663 -0.22326,0.24662 -0.22326,0.67237 v 1.6433 H 49.57141 v -2.90757 h 0.480268 v 0.45171 q 0.171339,-0.2622 0.402387,-0.392 0.233644,-0.12981 0.537382,-0.12981 0.501036,0 0.758045,0.31153 0.257008,0.30893 0.257008,0.91121 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3512" />
+ <path
+ d="m 55.376166,235.6037 v 1.75493 h -0.477672 v -1.73935 q 0,-0.41277 -0.160955,-0.61786 -0.160954,-0.20509 -0.482864,-0.20509 -0.386811,0 -0.610071,0.24663 -0.223259,0.24662 -0.223259,0.67237 v 1.6433 h -0.480269 v -2.90757 h 0.480269 v 0.45171 q 0.171339,-0.2622 0.402387,-0.392 0.233644,-0.12981 0.537381,-0.12981 0.501036,0 0.758045,0.31153 0.257008,0.30893 0.257008,0.91121 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3514" />
+ <path
+ d="m 58.815927,235.78543 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75285 0.267392,0.25701 0.742469,0.25701 0.27518,0 0.532189,-0.0675 0.259604,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257009,0.10904 -0.526997,0.16615 -0.269989,0.0571 -0.547766,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40498 -0.404983,-1.09553 0,-0.71391 0.384215,-1.13188 0.38681,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37903 0.342678,0.37642 0.342678,1.02544 z m -0.477673,-0.14019 q -0.0052,-0.392 -0.220663,-0.62565 -0.212876,-0.23364 -0.565938,-0.23364 -0.399791,0 -0.641223,0.22585 -0.238836,0.22586 -0.275181,0.63603 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3516" />
+ <path
+ d="m 61.284766,234.89758 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207684,-0.0234 -0.404983,0 -0.623051,0.26479 -0.215471,0.2622 -0.215471,0.75545 v 1.53167 H 59.58176 v -2.90757 h 0.480269 v 0.45171 q 0.15057,-0.2648 0.392002,-0.392 0.241433,-0.12981 0.586707,-0.12981 0.04932,0 0.109034,0.008 0.05971,0.005 0.132398,0.0182 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3518" />
+ <path
+ d="m 61.204288,235.68937 h 1.399268 v 0.42575 h -1.399268 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3520" />
+ <path
+ d="m 63.364198,233.31918 h 0.477672 v 4.03945 h -0.477672 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3522" />
+ <path
+ d="m 65.968029,234.78595 q -0.384214,0 -0.607474,0.30114 -0.22326,0.29854 -0.22326,0.82035 0,0.5218 0.220664,0.82295 0.22326,0.29854 0.61007,0.29854 0.381619,0 0.604879,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.604879,-0.30374 z m 0,-0.40499 q 0.623051,0 0.978709,0.40499 0.355658,0.40498 0.355658,1.12149 0,0.71391 -0.355658,1.12149 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 0.355658,-0.40499 0.981305,-0.40499 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3524" />
+ <path
+ d="m 69.220875,234.78595 q -0.384215,0 -0.607474,0.30114 -0.22326,0.29854 -0.22326,0.82035 0,0.5218 0.220664,0.82295 0.223259,0.29854 0.61007,0.29854 0.381619,0 0.604879,-0.30114 0.223259,-0.30114 0.223259,-0.82035 0,-0.51661 -0.223259,-0.81775 -0.22326,-0.30374 -0.604879,-0.30374 z m 0,-0.40499 q 0.623051,0 0.978709,0.40499 0.355658,0.40498 0.355658,1.12149 0,0.71391 -0.355658,1.12149 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 0.355658,-0.40499 0.981305,-0.40499 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3526" />
+ <path
+ d="m 71.80913,236.92249 v 1.54205 h -0.480269 v -4.01348 h 0.480269 v 0.44133 q 0.15057,-0.25961 0.379022,-0.38422 0.231048,-0.12721 0.550362,-0.12721 0.529593,0 0.85929,0.42056 0.332294,0.42056 0.332294,1.10592 0,0.68536 -0.332294,1.10591 -0.329697,0.42056 -0.85929,0.42056 -0.319314,0 -0.550362,-0.12461 -0.228452,-0.1272 -0.379022,-0.38681 z m 1.625124,-1.01505 q 0,-0.527 -0.218068,-0.82554 -0.215472,-0.30114 -0.594494,-0.30114 -0.379023,0 -0.597091,0.30114 -0.215471,0.29854 -0.215471,0.82554 0,0.527 0.215471,0.82814 0.218068,0.29854 0.597091,0.29854 0.379022,0 0.594494,-0.29854 0.218068,-0.30114 0.218068,-0.82814 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3528" />
+ <path
+ d="m 76.604025,236.69923 h 0.550361 v 0.6594 h -0.550361 z m 1.767907,0 h 0.552957 v 0.6594 h -0.552957 z m -3.53841,0 h 0.552958 v 0.6594 h -0.552958 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path3530" />
+ </g>
+ <g
+ aria-label="<U5"
+ id="text4378"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 52.591689,250.86752 0.408171,0.64685 -2.314122,1.37671 2.314122,1.36634 -0.432385,0.65376 -2.670407,-1.66382 v -0.71256 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3617" />
+ <path
+ d="m 57.30986,250.27602 v 3.19964 q 0,0.48773 -0.197167,0.87169 -0.197167,0.3805 -0.581125,0.59842 -0.380498,0.21792 -0.93741,0.21792 -0.56037,0 -0.940869,-0.211 -0.380498,-0.21446 -0.574207,-0.59496 -0.193708,-0.3805 -0.193708,-0.88207 v -3.19964 h 0.947787 v 2.9333 q 0,0.61225 0.166036,0.92011 0.166036,0.3044 0.594961,0.3044 0.432385,0 0.59842,-0.3044 0.166036,-0.30786 0.166036,-0.92011 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3619" />
+ <path
+ d="m 61.166722,250.27602 -0.107232,0.67106 h -1.79872 v 1.19684 q 0.190249,-0.0934 0.380499,-0.13145 0.190249,-0.038 0.366662,-0.038 0.377039,0 0.677979,0.18334 0.30094,0.18333 0.477352,0.52923 0.176413,0.34245 0.176413,0.82326 0,0.48082 -0.22484,0.8544 -0.221381,0.37358 -0.622634,0.58804 -0.401252,0.211 -0.940868,0.211 -0.48773,0 -0.868229,-0.17987 -0.377039,-0.17987 -0.646847,-0.48427 l 0.532698,-0.49465 q 0.377039,0.44622 0.930491,0.44622 0.411631,0 0.653766,-0.24905 0.242135,-0.24905 0.242135,-0.68836 0,-0.48773 -0.204085,-0.68835 -0.204086,-0.20063 -0.518862,-0.20063 -0.311317,0 -0.643388,0.15912 h -0.639929 v -2.50783 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3621" />
+ </g>
+ <g
+ aria-label="<U8"
+ id="text4382"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 103.47904,251.31064 0.40817,0.64684 -2.31412,1.37672 2.31412,1.36633 -0.43239,0.65377 -2.6704,-1.66382 v -0.71257 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3708" />
+ <path
+ d="m 108.19721,250.71913 v 3.19965 q 0,0.48773 -0.19717,0.87169 -0.19717,0.3805 -0.58112,0.59842 -0.3805,0.21792 -0.93741,0.21792 -0.56037,0 -0.94087,-0.211 -0.3805,-0.21447 -0.57421,-0.59497 -0.19371,-0.38049 -0.19371,-0.88206 v -3.19965 h 0.94779 v 2.9333 q 0,0.61226 0.16604,0.92011 0.16603,0.3044 0.59496,0.3044 0.43238,0 0.59842,-0.3044 0.16603,-0.30785 0.16603,-0.92011 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3710" />
+ <path
+ d="m 112.17168,251.86409 q 0,0.33899 -0.19371,0.58458 -0.19025,0.2456 -0.57767,0.46352 0.96163,0.4566 0.96163,1.29715 0,0.37704 -0.20063,0.69528 -0.20063,0.31823 -0.5915,0.51194 -0.38742,0.19025 -0.95125,0.19025 -0.56037,0 -0.94087,-0.18679 -0.38049,-0.19025 -0.5742,-0.50157 -0.19371,-0.31131 -0.19371,-0.68489 0,-0.42201 0.24559,-0.72641 0.24906,-0.3044 0.66415,-0.48773 -0.37358,-0.21446 -0.54654,-0.46006 -0.17295,-0.24905 -0.17295,-0.6503 0,-0.41855 0.21446,-0.70566 0.21792,-0.29056 0.56729,-0.4393 0.35283,-0.14874 0.75754,-0.14874 0.42546,0 0.77137,0.14528 0.34937,0.14182 0.55345,0.42201 0.20755,0.28018 0.20755,0.68144 z m -2.19652,0.0484 q 0,0.31132 0.20755,0.4739 0.211,0.15912 0.61571,0.3044 0.26981,-0.17988 0.38396,-0.35629 0.11415,-0.17987 0.11415,-0.42201 0,-0.29402 -0.16949,-0.47389 -0.16604,-0.18333 -0.48773,-0.18333 -0.31478,0 -0.49119,0.16949 -0.17296,0.1695 -0.17296,0.48773 z m 1.46319,2.29683 q 0,-0.26635 -0.12106,-0.42892 -0.11761,-0.16258 -0.34937,-0.27673 -0.23176,-0.11415 -0.57421,-0.23522 -0.23867,0.13491 -0.40125,0.35629 -0.15912,0.22138 -0.15912,0.56729 0,0.33553 0.20063,0.53961 0.20063,0.20409 0.60188,0.20409 0.40471,0 0.60188,-0.21101 0.20062,-0.21446 0.20062,-0.5154 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3712" />
+ </g>
+ <g
+ aria-label="<U13"
+ id="text4386"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 155.87082,251.16984 0.40817,0.64685 -2.31412,1.37671 2.31412,1.36634 -0.43238,0.65376 -2.67041,-1.66381 v -0.71257 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3799" />
+ <path
+ d="m 160.58899,250.57834 v 3.19965 q 0,0.48773 -0.19716,0.87168 -0.19717,0.3805 -0.58113,0.59842 -0.3805,0.21793 -0.93741,0.21793 -0.56037,0 -0.94087,-0.21101 -0.3805,-0.21446 -0.5742,-0.59496 -0.19371,-0.3805 -0.19371,-0.88206 v -3.19965 h 0.94778 v 2.9333 q 0,0.61225 0.16604,0.92011 0.16604,0.3044 0.59496,0.3044 0.43239,0 0.59842,-0.3044 0.16604,-0.30786 0.16604,-0.92011 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3801" />
+ <path
+ d="m 164.68107,254.66005 v 0.70219 h -2.98518 v -0.70219 h 1.15879 v -3.1616 l -1.02043,0.63302 -0.39087,-0.63302 1.50123,-0.92011 h 0.80597 v 4.08171 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3803" />
+ <path
+ d="m 166.97789,250.47457 q 0.49119,0 0.84401,0.16603 0.35283,0.16258 0.53962,0.43931 0.18679,0.27672 0.18679,0.60879 0,0.44968 -0.26981,0.74025 -0.26981,0.2871 -0.69181,0.39433 0.31477,0.038 0.56383,0.17295 0.25251,0.13145 0.40125,0.3805 0.14874,0.24906 0.14874,0.62956 0,0.40471 -0.21792,0.73678 -0.21792,0.33207 -0.61918,0.52924 -0.39779,0.19371 -0.94433,0.19371 -0.49118,0 -0.90627,-0.17296 -0.41163,-0.17641 -0.7022,-0.5154 l 0.53616,-0.48427 q 0.20409,0.23868 0.46698,0.34937 0.26635,0.11069 0.55345,0.11069 0.40471,0 0.64685,-0.20755 0.24559,-0.211 0.24559,-0.5915 0,-0.42547 -0.23868,-0.60188 -0.23521,-0.17987 -0.63301,-0.17987 h -0.42546 l 0.10723,-0.65031 h 0.30094 q 0.32515,0 0.55345,-0.16949 0.23176,-0.17296 0.23176,-0.52924 0,-0.31132 -0.21792,-0.48427 -0.21793,-0.17642 -0.54654,-0.17642 -0.29748,0 -0.52924,0.11069 -0.23175,0.1107 -0.44968,0.31478 l -0.47389,-0.50157 q 0.63647,-0.61225 1.53929,-0.61225 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path3805" />
+ </g>
+ <path
+ id="rect833"
+ style="fill:none;stroke:#cccccc;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 29.071695,65.16613 H 187.97085 V 89.509815 H 29.071695 Z" />
+ <g
+ aria-label="User Input"
+ id="text841"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752">
+ <path
+ d="m -14.303797,74.371016 h 1.193726 v 2.775024 q 0,0.573609 0.186035,0.821656 0.189135,0.244946 0.613916,0.244946 0.427881,0 0.613916,-0.244946 0.189135,-0.248047 0.189135,-0.821656 v -2.775024 h 1.193726 v 2.775024 q 0,0.982886 -0.492993,1.463477 -0.492993,0.480591 -1.503784,0.480591 -1.007691,0 -1.500684,-0.480591 -0.492993,-0.480591 -0.492993,-1.463477 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3977" />
+ <path
+ d="m -6.4841194,75.636055 v 0.843359 q -0.3565674,-0.148828 -0.68833,-0.223242 -0.3317627,-0.07441 -0.6263184,-0.07441 -0.3162598,0 -0.471289,0.08061 -0.1519288,0.07752 -0.1519288,0.241846 0,0.133325 0.1147217,0.204639 0.1178223,0.07131 0.4185791,0.10542 l 0.1953369,0.02791 q 0.8526611,0.10852 1.1472168,0.356567 0.2945557,0.248047 0.2945557,0.778247 0,0.555005 -0.4092774,0.834058 -0.4092773,0.279053 -1.2216308,0.279053 -0.344165,0 -0.7131348,-0.05581 -0.3658691,-0.05271 -0.7534423,-0.16123 v -0.84336 q 0.3317627,0.161231 0.6790283,0.241846 0.3503662,0.08062 0.7100341,0.08062 0.3255616,0 0.4898926,-0.08992 0.1643311,-0.08992 0.1643311,-0.26665 0,-0.148828 -0.1147217,-0.220142 -0.1116211,-0.07441 -0.449585,-0.114721 l -0.1953369,-0.02481 q -0.74104,-0.09302 -1.0386963,-0.344165 -0.2976562,-0.251148 -0.2976562,-0.762744 0,-0.551905 0.3782715,-0.818555 0.3782715,-0.26665 1.1596191,-0.26665 0.306958,0 0.6449219,0.04651 0.3379638,0.04651 0.7348388,0.145727 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3979" />
+ <path
+ d="m -1.951063,77.254561 v 0.31626 h -2.5951904 q 0.040308,0.390673 0.2821533,0.58601 0.2418457,0.195337 0.6759277,0.195337 0.3503662,0 0.7162354,-0.102319 0.3689697,-0.10542 0.7565429,-0.31626 v 0.855762 q -0.3937744,0.148828 -0.7875488,0.223242 -0.3937744,0.07752 -0.7875488,0.07752 -0.9425781,0 -1.4665771,-0.477491 -0.5208985,-0.48059 -0.5208985,-1.345654 0,-0.84956 0.5115967,-1.336352 0.5146973,-0.486792 1.4138672,-0.486792 0.8185546,0 1.3084472,0.492993 0.4929932,0.492993 0.4929932,1.317749 z m -1.1410156,-0.36897 q 0,-0.31626 -0.1860352,-0.508496 -0.1829346,-0.195337 -0.4805908,-0.195337 -0.3224609,0 -0.523999,0.182935 -0.2015381,0.179834 -0.2511475,0.520898 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3981" />
+ <path
+ d="M 1.4688835,76.473213 Q 1.3231559,76.405 1.1774284,76.373994 q -0.142627,-0.03411 -0.2883545,-0.03411 -0.42788085,0 -0.6604248,0.275952 -0.22944335261,0.272852 -0.22944335261,0.784448 v 1.599903 H -1.110804 v -3.472656 h 1.11000974739 v 0.570507 Q 0.21314617,75.756978 0.48909832,75.601949 q 0.27905273,-0.15813 0.66662598,-0.15813 0.05581,0 0.1209228,0.0062 0.065112,0.0031 0.1891358,0.0186 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3983" />
+ <path
+ d="m 4.2811144,74.371016 h 1.1937255 v 4.629175 H 4.2811144 Z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3985" />
+ <path
+ d="m 10.085411,76.885591 v 2.1146 H 8.9691999 v -0.344165 -1.274341 q 0,-0.449585 -0.021704,-0.620117 -0.018604,-0.170533 -0.068213,-0.251148 -0.065112,-0.10852 -0.1767334,-0.167431 -0.1116211,-0.06201 -0.254248,-0.06201 -0.3472657,0 -0.5457032,0.269751 -0.1984375,0.26665 -0.1984375,0.74104 v 1.708423 H 6.5941511 v -3.472656 h 1.1100097 v 0.508496 q 0.2511475,-0.303858 0.5333008,-0.446485 0.2821533,-0.145727 0.6232178,-0.145727 0.6015136,0 0.9115722,0.368969 0.3131594,0.36897 0.3131594,1.072803 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3987" />
+ <path
+ d="m 12.224816,78.497896 v 1.823144 h -1.11001 v -4.793505 h 1.11001 v 0.508496 q 0.229443,-0.303858 0.508496,-0.446485 0.279052,-0.145727 0.641821,-0.145727 0.641821,0 1.054199,0.511596 0.412378,0.508496 0.412378,1.311548 0,0.803052 -0.412378,1.314649 -0.412378,0.508496 -1.054199,0.508496 -0.362769,0 -0.641821,-0.142627 -0.279053,-0.145728 -0.508496,-0.449585 z m 0.737939,-2.247925 q -0.356567,0 -0.548804,0.26355 -0.189135,0.260449 -0.189135,0.753442 0,0.492993 0.189135,0.756543 0.192237,0.260449 0.548804,0.260449 0.356567,0 0.542602,-0.260449 0.189136,-0.260449 0.189136,-0.756543 0,-0.496094 -0.189136,-0.756543 -0.186035,-0.260449 -0.542602,-0.260449 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3989" />
+ <path
+ d="m 15.623058,77.648335 v -2.1208 h 1.116211 V 75.8748 q 0,0.282153 -0.0031,0.710034 -0.0031,0.424781 -0.0031,0.567408 0,0.418579 0.0217,0.604614 0.0217,0.182934 0.07441,0.26665 0.06821,0.108521 0.176734,0.167432 0.111621,0.05891 0.254248,0.05891 0.347265,0 0.545703,-0.26665 0.198437,-0.266651 0.198437,-0.74104 v -1.714624 h 1.11001 v 3.472656 h -1.11001 v -0.502295 q -0.251147,0.303857 -0.5333,0.449585 -0.279053,0.142627 -0.617017,0.142627 -0.601514,0 -0.917773,-0.36897 -0.31316,-0.36897 -0.31316,-1.072803 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3991" />
+ <path
+ d="m 21.393247,74.541548 v 0.985987 h 1.144117 v 0.79375 h -1.144117 v 1.472778 q 0,0.241846 0.09612,0.328662 0.09612,0.08372 0.381372,0.08372 h 0.570507 v 0.79375 h -0.951879 q -0.657325,0 -0.933277,-0.272852 -0.272851,-0.275952 -0.272851,-0.933276 v -1.472778 h -0.551905 v -0.79375 h 0.551905 v -0.985987 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#8f8f8f;fill-opacity:1;stroke-width:0.398752"
+ id="path3993" />
+ </g>
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path910"
+ d="M 31.352669,92.208912 V 194.08332"
+ style="fill:none;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send)" />
+ <path
+ id="path1730"
+ style="fill:none;fill-opacity:0.483526;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker7096)"
+ d="m 31.352669,146.65942 h 51.793437 v 4.50227"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:none;stroke:#00b200;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Send-5)"
+ d="M 83.488644,92.208912 V 102.42617"
+ id="path910-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path2175"
+ d="m 35.539436,181.16793 v 12.91539"
+ style="fill:none;stroke:#206120;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker2179)" />
+ <path
+ id="rect833-3"
+ style="opacity:0.8;fill:#ffffff;stroke:#800000;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:1"
+ d="M 28.977177,106.27831 H 187.87633 V 130.622 H 28.977177 Z" />
+ <g
+ aria-label="Input/Output
+Operands"
+ id="text841-6"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751">
+ <path
+ d="m -22.961561,112.90403 h 1.193725 v 4.62917 h -1.193725 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4165" />
+ <path
+ d="m -17.157265,115.4186 v 2.1146 h -1.116211 v -0.34416 -1.27434 q 0,-0.44959 -0.0217,-0.62012 -0.0186,-0.17053 -0.06821,-0.25115 -0.06511,-0.10852 -0.176733,-0.16743 -0.111621,-0.062 -0.254248,-0.062 -0.347266,0 -0.545703,0.26975 -0.198438,0.26665 -0.198438,0.74104 v 1.70842 h -1.110009 v -3.47265 h 1.110009 v 0.50849 q 0.251148,-0.30385 0.533301,-0.44648 0.282154,-0.14573 0.623218,-0.14573 0.601514,0 0.911572,0.36897 0.313159,0.36897 0.313159,1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4167" />
+ <path
+ d="m -15.01786,117.03091 v 1.82314 h -1.11001 v -4.7935 h 1.11001 v 0.50849 q 0.229443,-0.30385 0.508496,-0.44648 0.279053,-0.14573 0.641821,-0.14573 0.641822,0 1.054199,0.5116 0.412378,0.50849 0.412378,1.31155 0,0.80305 -0.412378,1.31464 -0.412377,0.5085 -1.054199,0.5085 -0.362768,0 -0.641821,-0.14263 -0.279053,-0.14572 -0.508496,-0.44958 z m 0.737939,-2.24793 q -0.356567,0 -0.548803,0.26355 -0.189136,0.26045 -0.189136,0.75345 0,0.49299 0.189136,0.75654 0.192236,0.26045 0.548803,0.26045 0.356568,0 0.542603,-0.26045 0.189136,-0.26045 0.189136,-0.75654 0,-0.4961 -0.189136,-0.75655 -0.186035,-0.26045 -0.542603,-0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4169" />
+ <path
+ d="m -11.619618,116.18135 v -2.1208 h 1.116211 v 0.34726 q 0,0.28216 -0.0031,0.71004 -0.0031,0.42478 -0.0031,0.5674 0,0.41858 0.0217,0.60462 0.0217,0.18293 0.07441,0.26665 0.06821,0.10852 0.176733,0.16743 0.111621,0.0589 0.2542482,0.0589 0.3472657,0 0.5457032,-0.26665 0.1984375,-0.26665 0.1984375,-0.74104 v -1.71462 h 1.1100097 v 3.47265 h -1.1100097 v -0.50229 q -0.2511475,0.30386 -0.5333008,0.44958 -0.2790531,0.14263 -0.6170171,0.14263 -0.601513,0 -0.917773,-0.36897 -0.313159,-0.36897 -0.313159,-1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4171" />
+ <path
+ d="m -5.8494283,113.07456 v 0.98599 h 1.1441162 v 0.79375 h -1.1441162 v 1.47278 q 0,0.24184 0.096118,0.32866 0.096118,0.0837 0.3813721,0.0837 h 0.5705078 v 0.79375 h -0.9518799 q -0.6573242,0 -0.9332764,-0.27285 -0.2728515,-0.27595 -0.2728515,-0.93327 v -1.47278 h -0.5519043 v -0.79375 h 0.5519043 v -0.98599 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4173" />
+ <path
+ d="m -2.9286771,112.90403 h 0.6883301 l -1.6340088,5.21828 h -0.6852295 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4175" />
+ <path
+ d="m 0.45716313,113.68538 q -0.54570312,0 -0.84645995,0.40307 -0.30075683,0.40308 -0.30075683,1.13482 0,0.72863 0.30075683,1.13171 0.30075683,0.40308 0.84645995,0.40308 0.54880367,0 0.84956057,-0.40308 0.3007568,-0.40308 0.3007568,-1.13171 0,-0.73174 -0.3007568,-1.13482 -0.3007569,-0.40307 -0.84956057,-0.40307 z m 0,-0.86507 q 1.11621097,0 1.74873047,0.63872 0.6325195,0.63872 0.6325195,1.76424 0,1.12241 -0.6325195,1.76113 -0.6325195,0.63872 -1.74873047,0.63872 -1.11311033,0 -1.74873043,-0.63872 -0.6325195,-0.63872 -0.6325195,-1.76113 0,-1.12552 0.6325195,-1.76424 0.6356201,-0.63872 1.74873043,-0.63872 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4177" />
+ <path
+ d="m 3.653868,116.18135 v -2.1208 h 1.1162109 v 0.34726 q 0,0.28216 -0.0031,0.71004 -0.0031,0.42478 -0.0031,0.5674 0,0.41858 0.021704,0.60462 0.021704,0.18293 0.074414,0.26665 0.068213,0.10852 0.1767334,0.16743 0.1116211,0.0589 0.2542481,0.0589 0.3472656,0 0.5457031,-0.26665 0.1984375,-0.26665 0.1984375,-0.74104 v -1.71462 h 1.1100097 v 3.47265 H 6.035118 v -0.50229 q -0.2511475,0.30386 -0.5333008,0.44958 -0.2790527,0.14263 -0.6170166,0.14263 -0.6015136,0 -0.9177734,-0.36897 -0.3131592,-0.36897 -0.3131592,-1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4179" />
+ <path
+ d="m 9.4240588,113.07456 v 0.98599 h 1.1441162 v 0.79375 H 9.4240588 v 1.47278 q 0,0.24184 0.096118,0.32866 0.096118,0.0837 0.381372,0.0837 h 0.570508 v 0.79375 h -0.95188 q -0.6573242,0 -0.9332764,-0.27285 -0.2728515,-0.27595 -0.2728515,-0.93327 V 114.8543 H 7.7621448 v -0.79375 h 0.5519043 v -0.98599 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4181" />
+ <path
+ d="m 12.357212,117.03091 v 1.82314 h -1.110009 v -4.7935 h 1.110009 v 0.50849 q 0.229444,-0.30385 0.508496,-0.44648 0.279053,-0.14573 0.641822,-0.14573 0.641821,0 1.054199,0.5116 0.412378,0.50849 0.412378,1.31155 0,0.80305 -0.412378,1.31464 -0.412378,0.5085 -1.054199,0.5085 -0.362769,0 -0.641822,-0.14263 -0.279052,-0.14572 -0.508496,-0.44958 z m 0.73794,-2.24793 q -0.356568,0 -0.548804,0.26355 -0.189136,0.26045 -0.189136,0.75345 0,0.49299 0.189136,0.75654 0.192236,0.26045 0.548804,0.26045 0.356567,0 0.542602,-0.26045 0.189136,-0.26045 0.189136,-0.75654 0,-0.4961 -0.189136,-0.75655 -0.186035,-0.26045 -0.542602,-0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4183" />
+ <path
+ d="m 15.755455,116.18135 v -2.1208 h 1.116211 v 0.34726 q 0,0.28216 -0.0031,0.71004 -0.0031,0.42478 -0.0031,0.5674 0,0.41858 0.0217,0.60462 0.0217,0.18293 0.07441,0.26665 0.06821,0.10852 0.176734,0.16743 0.111621,0.0589 0.254248,0.0589 0.347265,0 0.545703,-0.26665 0.198437,-0.26665 0.198437,-0.74104 v -1.71462 h 1.11001 v 3.47265 h -1.11001 v -0.50229 q -0.251147,0.30386 -0.5333,0.44958 -0.279053,0.14263 -0.617017,0.14263 -0.601514,0 -0.917774,-0.36897 -0.313159,-0.36897 -0.313159,-1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4185" />
+ <path
+ d="m 21.525644,113.07456 v 0.98599 h 1.144116 v 0.79375 h -1.144116 v 1.47278 q 0,0.24184 0.09612,0.32866 0.09612,0.0837 0.381372,0.0837 h 0.570508 v 0.79375 h -0.95188 q -0.657324,0 -0.933276,-0.27285 -0.272852,-0.27595 -0.272852,-0.93327 V 114.8543 H 19.86373 v -0.79375 h 0.551904 v -0.98599 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4187" />
+ <path
+ d="m -8.999623,121.62288 q -0.5457031,0 -0.84646,0.40307 -0.300757,0.40308 -0.300757,1.13482 0,0.72863 0.300757,1.13171 0.3007569,0.40308 0.84646,0.40308 0.5488037,0 0.8495605,-0.40308 0.3007569,-0.40308 0.3007569,-1.13171 0,-0.73174 -0.3007569,-1.13482 -0.3007568,-0.40307 -0.8495605,-0.40307 z m 0,-0.86507 q 1.1162109,0 1.7487304,0.63872 0.6325196,0.63872 0.6325196,1.76424 0,1.12241 -0.6325196,1.76113 -0.6325195,0.63872 -1.7487304,0.63872 -1.11311,0 -1.74873,-0.63872 -0.63252,-0.63872 -0.63252,-1.76113 0,-1.12552 0.63252,-1.76424 0.63562,-0.63872 1.74873,-0.63872 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4189" />
+ <path
+ d="m -4.6557023,124.96841 v 1.82314 H -5.765712 v -4.7935 h 1.1100097 v 0.50849 q 0.2294434,-0.30385 0.5084961,-0.44648 0.2790527,-0.14573 0.6418213,-0.14573 0.6418213,0 1.0541992,0.5116 0.4123779,0.50849 0.4123779,1.31155 0,0.80305 -0.4123779,1.31464 -0.4123779,0.5085 -1.0541992,0.5085 -0.3627686,0 -0.6418213,-0.14263 -0.2790527,-0.14572 -0.5084961,-0.44958 z m 0.7379395,-2.24793 q -0.3565674,0 -0.5488037,0.26355 -0.1891358,0.26045 -0.1891358,0.75345 0,0.49299 0.1891358,0.75654 0.1922363,0.26045 0.5488037,0.26045 0.3565673,0 0.5426025,-0.26045 0.1891357,-0.26045 0.1891357,-0.75654 0,-0.4961 -0.1891357,-0.75655 -0.1860352,-0.26045 -0.5426025,-0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4191" />
+ <path
+ d="m 2.2462018,123.72507 v 0.31626 h -2.59519041 q 0.0403076,0.39068 0.28215332,0.58601 0.2418457,0.19534 0.67592772,0.19534 0.35036621,0 0.71623537,-0.10232 0.3689697,-0.10542 0.7565429,-0.31626 v 0.85576 q -0.3937744,0.14883 -0.7875488,0.22325 -0.39377439,0.0775 -0.7875488,0.0775 -0.94257811,0 -1.46657713,-0.47749 -0.52089847,-0.48059 -0.52089847,-1.34565 0,-0.84957 0.51159671,-1.33636 0.51469726,-0.48679 1.41386717,-0.48679 0.81855472,0 1.30844722,0.49299 0.4929932,0.493 0.4929932,1.31775 z M 1.1051862,123.3561 q 0,-0.31626 -0.18603518,-0.50849 -0.18293457,-0.19534 -0.48059081,-0.19534 -0.32246093,0 -0.52399902,0.18293 -0.20153808,0.17984 -0.25114745,0.5209 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4193" />
+ <path
+ d="m 5.6661473,122.94373 q -0.1457275,-0.0682 -0.2914551,-0.0992 -0.1426269,-0.0341 -0.2883544,-0.0341 -0.4278809,0 -0.6604248,0.27595 -0.2294434,0.27285 -0.2294434,0.78445 v 1.5999 H 3.0864599 v -3.47265 h 1.1100097 v 0.5705 q 0.2139404,-0.34106 0.4898926,-0.49609 0.2790527,-0.15813 0.6666259,-0.15813 0.055811,0 0.1209229,0.006 0.065112,0.003 0.1891357,0.0186 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4195" />
+ <path
+ d="m 7.7745458,123.90801 q -0.3472656,0 -0.523999,0.11782 -0.1736329,0.11782 -0.1736329,0.34727 0,0.21084 0.1395264,0.33176 0.142627,0.11782 0.3937744,0.11782 0.3131592,0 0.5270996,-0.22324 0.2139405,-0.22634 0.2139405,-0.56431 v -0.12712 z m 1.6960205,-0.41858 v 1.98127 H 8.3512548 v -0.51469 q -0.2232422,0.31626 -0.502295,0.46198 -0.2790527,0.14263 -0.6790283,0.14263 -0.5395019,0 -0.8774658,-0.31316 -0.3348633,-0.31626 -0.3348633,-0.81855 0,-0.61082 0.4185791,-0.89607 0.4216797,-0.28526 1.3208496,-0.28526 h 0.6542237 v -0.0868 q 0,-0.26355 -0.2077393,-0.38448 -0.2077393,-0.12402 -0.6480225,-0.12402 -0.3565673,0 -0.6635253,0.0713 -0.306958,0.0713 -0.5705078,0.21394 v -0.84646 q 0.3565673,-0.0868 0.7162353,-0.13022 0.359668,-0.0465 0.7193359,-0.0465 0.9394776,0 1.3549561,0.37207 0.4185791,0.36897 0.4185791,1.20303 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4197" />
+ <path
+ d="m 13.994321,123.3561 v 2.1146 H 12.87811 v -0.34416 -1.27434 q 0,-0.44959 -0.0217,-0.62012 -0.0186,-0.17053 -0.06821,-0.25115 -0.06511,-0.10852 -0.176734,-0.16743 -0.111621,-0.062 -0.254248,-0.062 -0.347265,0 -0.545703,0.26975 -0.198437,0.26665 -0.198437,0.74104 v 1.70842 h -1.11001 v -3.47265 h 1.11001 v 0.50849 q 0.251147,-0.30385 0.533301,-0.44648 0.282153,-0.14573 0.623217,-0.14573 0.601514,0 0.911573,0.36897 0.313159,0.36897 0.313159,1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4199" />
+ <path
+ d="m 17.386362,122.50654 v -1.86035 h 1.116211 v 4.82451 h -1.116211 v -0.50229 q -0.229443,0.30696 -0.505395,0.44958 -0.275952,0.14263 -0.638721,0.14263 -0.641821,0 -1.054199,-0.5085 -0.412378,-0.51159 -0.412378,-1.31464 0,-0.80306 0.412378,-1.31155 0.412378,-0.5116 1.054199,-0.5116 0.359668,0 0.63562,0.14573 0.279053,0.14263 0.508496,0.44648 z m -0.731738,2.24793 q 0.356567,0 0.542602,-0.26045 0.189136,-0.26045 0.189136,-0.75654 0,-0.4961 -0.189136,-0.75655 -0.186035,-0.26045 -0.542602,-0.26045 -0.353467,0 -0.542603,0.26045 -0.186035,0.26045 -0.186035,0.75655 0,0.49609 0.186035,0.75654 0.189136,0.26045 0.542603,0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4201" />
+ <path
+ d="m 22.282188,122.10657 v 0.84336 q -0.356567,-0.14883 -0.68833,-0.22325 -0.331763,-0.0744 -0.626318,-0.0744 -0.31626,0 -0.471289,0.0806 -0.151929,0.0775 -0.151929,0.24184 0,0.13333 0.114722,0.20464 0.117822,0.0713 0.418579,0.10542 l 0.195337,0.0279 q 0.852661,0.10852 1.147216,0.35656 0.294556,0.24805 0.294556,0.77825 0,0.555 -0.409277,0.83406 -0.409278,0.27905 -1.221631,0.27905 -0.344165,0 -0.713135,-0.0558 -0.365869,-0.0527 -0.753442,-0.16123 v -0.84336 q 0.331762,0.16123 0.679028,0.24185 0.350366,0.0806 0.710034,0.0806 0.325562,0 0.489893,-0.0899 0.164331,-0.0899 0.164331,-0.26665 0,-0.14882 -0.114722,-0.22014 -0.111621,-0.0744 -0.449585,-0.11472 l -0.195337,-0.0248 q -0.74104,-0.093 -1.038696,-0.34417 -0.297656,-0.25115 -0.297656,-0.76274 0,-0.55191 0.378271,-0.81856 0.378272,-0.26665 1.159619,-0.26665 0.306958,0 0.644922,0.0465 0.337964,0.0465 0.734839,0.14573 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#800000;fill-opacity:0.8;stroke-width:0.398751"
+ id="path4203" />
+ </g>
+ <path
+ id="rect874"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 37.217079,68.992058 H 76.53093 V 86.123404 H 37.217079 Z" />
+ <path
+ id="rect876"
+ style="opacity:0.5;fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 142.70969,68.95668 h 39.2278 v 17.717829 h -39.2278 z" />
+ <path
+ id="rect878"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 89.303658,69.390724 H 128.61751 V 86.52207 H 89.303658 Z" />
+ <g
+ aria-label="+"
+ id="text882"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 83.42805,73.926712 v 3.386793 h 3.386794 v 1.033672 H 83.42805 v 3.386794 h -1.021511 v -3.386794 h -3.386793 v -1.033672 h 3.386793 v -3.386793 z"
+ style="stroke-width:0.933951"
+ id="path4545" />
+ </g>
+ <g
+ aria-label="→"
+ id="text886"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 140.22087,78.27577 v 0.547238 l -2.3896,2.389605 -0.72965,-0.729651 1.41673,-1.416738 h -7.41203 v -1.033671 h 7.41203 l -1.41673,-1.416738 0.72965,-0.72965 z"
+ style="stroke-width:0.933951"
+ id="path4632" />
+ </g>
+ <path
+ id="rect888"
+ style="opacity:0.6;fill:#ffffff;stroke:#000080;stroke-width:1.412;stroke-linecap:round;stroke-miterlimit:10;stroke-opacity:0.5"
+ d="M 28.168863,154.17207 H 187.06802 v 24.34369 H 28.168863 Z" />
+ <g
+ aria-label="
+DType classes
+of the ArrayMethod
+"
+ id="text892"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.35px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m -25.330407,161.01556 v 2.82463 h 0.427881 q 0.731738,0 1.116211,-0.36277 0.387573,-0.36277 0.387573,-1.0542 0,-0.68833 -0.384473,-1.04799 -0.384472,-0.35967 -1.119311,-0.35967 z m -1.193726,-0.90227 h 1.258838 q 1.0542,0 1.568897,0.15193 0.517798,0.14882 0.886767,0.50849 0.325562,0.31316 0.483692,0.72244 0.15813,0.40928 0.15813,0.92707 0,0.524 -0.15813,0.93638 -0.15813,0.40928 -0.483692,0.72244 -0.37207,0.35967 -0.892968,0.51159 -0.520899,0.14883 -1.562696,0.14883 h -1.258838 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4804" />
+ <path
+ d="m -21.805041,160.11329 h 4.266406 v 0.90227 h -1.53479 v 3.7269 h -1.193725 v -3.7269 h -1.537891 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4806" />
+ <path
+ d="m -18.180456,161.26981 h 1.11001 l 0.933276,2.35644 0.79375,-2.35644 h 1.11001 l -1.460376,3.80131 q -0.220141,0.57981 -0.514697,0.80926 -0.291455,0.23254 -0.772046,0.23254 h -0.641821 v -0.72864 h 0.347265 q 0.282154,0 0.409278,-0.0899 0.130224,-0.0899 0.201538,-0.32246 l 0.03101,-0.0961 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4808" />
+ <path
+ d="m -12.475378,164.24017 v 1.82314 h -1.110009 v -4.7935 h 1.110009 v 0.50849 q 0.229444,-0.30386 0.508497,-0.44648 0.279052,-0.14573 0.641821,-0.14573 0.641821,0 1.054199,0.5116 0.412378,0.50849 0.412378,1.31154 0,0.80306 -0.412378,1.31465 -0.412378,0.5085 -1.054199,0.5085 -0.362769,0 -0.641821,-0.14263 -0.279053,-0.14573 -0.508497,-0.44958 z m 0.73794,-2.24793 q -0.356567,0 -0.548804,0.26355 -0.189136,0.26045 -0.189136,0.75344 0,0.493 0.189136,0.75655 0.192237,0.26045 0.548804,0.26045 0.356567,0 0.542602,-0.26045 0.189136,-0.26045 0.189136,-0.75655 0,-0.49609 -0.189136,-0.75654 -0.186035,-0.26045 -0.542602,-0.26045 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4810" />
+ <path
+ d="m -5.5734734,162.99683 v 0.31626 h -2.5951904 q 0.040308,0.39068 0.2821533,0.58601 0.2418457,0.19534 0.6759277,0.19534 0.3503662,0 0.7162354,-0.10232 0.3689697,-0.10542 0.7565429,-0.31626 v 0.85576 q -0.3937744,0.14883 -0.7875488,0.22324 -0.3937744,0.0775 -0.7875488,0.0775 -0.9425781,0 -1.4665771,-0.47749 -0.5208985,-0.48059 -0.5208985,-1.34566 0,-0.84956 0.5115967,-1.33635 0.5146973,-0.48679 1.4138672,-0.48679 0.8185546,0 1.3084472,0.49299 0.4929932,0.493 0.4929932,1.31775 z m -1.1410156,-0.36897 q 0,-0.31626 -0.1860352,-0.50849 -0.1829346,-0.19534 -0.4805908,-0.19534 -0.3224609,0 -0.523999,0.18293 -0.2015381,0.17984 -0.2511475,0.5209 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4812" />
+ <path
+ d="m 0.28353303,161.37833 v 0.90537 q -0.22634277,-0.15503 -0.45578612,-0.22945 -0.22634277,-0.0744 -0.47128906,-0.0744 -0.46508785,0 -0.72553705,0.27285 -0.2573487,0.26975 -0.2573487,0.75654 0,0.4868 0.2573487,0.75965 0.2604492,0.26975 0.72553705,0.26975 0.26044922,0 0.49299316,-0.0775 0.23564453,-0.0775 0.43408202,-0.22944 v 0.90847 q -0.26044921,0.0961 -0.53020018,0.14263 -0.26665039,0.0496 -0.53640136,0.0496 -0.93947749,0 -1.46967769,-0.48059 -0.5302002,-0.48369 -0.5302002,-1.34256 0,-0.85886 0.5302002,-1.33945 0.5302002,-0.48369 1.46967769,-0.48369 0.27285155,0 0.53640136,0.0496 0.26665038,0.0465 0.53020018,0.14263 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4814" />
+ <path
+ d="m 1.2416134,159.91795 h 1.1100097 v 4.82451 H 1.2416134 Z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4816" />
+ <path
+ d="m 4.9747184,163.17977 q -0.3472656,0 -0.523999,0.11782 -0.1736328,0.11782 -0.1736328,0.34726 0,0.21084 0.1395264,0.33177 0.1426269,0.11782 0.3937744,0.11782 0.3131592,0 0.5270996,-0.22324 0.2139404,-0.22635 0.2139404,-0.56431 v -0.12712 z m 1.6960205,-0.41858 v 1.98127 H 5.5514274 v -0.5147 q -0.2232422,0.31626 -0.5022949,0.46199 -0.2790527,0.14263 -0.6790283,0.14263 -0.539502,0 -0.8774658,-0.31316 -0.3348633,-0.31626 -0.3348633,-0.81855 0,-0.61082 0.4185791,-0.89607 0.4216797,-0.28526 1.3208496,-0.28526 h 0.6542236 v -0.0868 q 0,-0.26355 -0.2077392,-0.38448 -0.2077393,-0.12402 -0.6480225,-0.12402 -0.3565674,0 -0.6635254,0.0713 -0.306958,0.0713 -0.5705078,0.21394 v -0.84646 q 0.3565674,-0.0868 0.7162354,-0.13022 0.3596679,-0.0465 0.7193359,-0.0465 0.9394775,0 1.354956,0.37207 0.4185791,0.36897 0.4185791,1.20303 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4818" />
+ <path
+ d="m 10.416248,161.37833 v 0.84336 q -0.356567,-0.14883 -0.6883298,-0.22325 -0.3317627,-0.0744 -0.6263184,-0.0744 -0.3162597,0 -0.471289,0.0806 -0.1519287,0.0775 -0.1519287,0.24185 0,0.13333 0.1147217,0.20464 0.1178222,0.0713 0.4185791,0.10542 l 0.1953369,0.0279 q 0.8526612,0.10852 1.1472172,0.35657 0.294555,0.24805 0.294555,0.77825 0,0.555 -0.409277,0.83406 -0.4092775,0.27905 -1.221631,0.27905 -0.344165,0 -0.7131347,-0.0558 -0.3658692,-0.0527 -0.7534424,-0.16123 v -0.84336 q 0.3317627,0.16123 0.6790283,0.24184 0.3503662,0.0806 0.7100342,0.0806 0.3255615,0 0.4898925,-0.0899 0.1643311,-0.0899 0.1643311,-0.26665 0,-0.14883 -0.1147217,-0.22014 -0.1116211,-0.0744 -0.4495849,-0.11472 l -0.1953369,-0.0248 q -0.7410401,-0.093 -1.0386963,-0.34416 -0.2976563,-0.25115 -0.2976563,-0.76274 0,-0.55191 0.3782715,-0.81856 0.3782715,-0.26665 1.1596191,-0.26665 0.306958,0 0.6449219,0.0465 0.3379636,0.0465 0.7348386,0.14573 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4820" />
+ <path
+ d="m 14.195862,161.37833 v 0.84336 q -0.356568,-0.14883 -0.68833,-0.22325 -0.331763,-0.0744 -0.626319,-0.0744 -0.316259,0 -0.471289,0.0806 -0.151928,0.0775 -0.151928,0.24185 0,0.13333 0.114721,0.20464 0.117823,0.0713 0.418579,0.10542 l 0.195337,0.0279 q 0.852661,0.10852 1.147217,0.35657 0.294556,0.24805 0.294556,0.77825 0,0.555 -0.409278,0.83406 -0.409277,0.27905 -1.22163,0.27905 -0.344166,0 -0.713135,-0.0558 -0.365869,-0.0527 -0.753443,-0.16123 v -0.84336 q 0.331763,0.16123 0.679029,0.24184 0.350366,0.0806 0.710034,0.0806 0.325561,0 0.489892,-0.0899 0.164331,-0.0899 0.164331,-0.26665 0,-0.14883 -0.114721,-0.22014 -0.111621,-0.0744 -0.449585,-0.11472 l -0.195337,-0.0248 q -0.74104,-0.093 -1.038696,-0.34416 -0.297657,-0.25115 -0.297657,-0.76274 0,-0.55191 0.378272,-0.81856 0.378271,-0.26665 1.159619,-0.26665 0.306958,0 0.644922,0.0465 0.337964,0.0465 0.734839,0.14573 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4823" />
+ <path
+ d="m 18.728918,162.99683 v 0.31626 h -2.595191 q 0.04031,0.39068 0.282154,0.58601 0.241845,0.19534 0.675927,0.19534 0.350366,0 0.716236,-0.10232 0.368969,-0.10542 0.756543,-0.31626 v 0.85576 q -0.393775,0.14883 -0.787549,0.22324 -0.393775,0.0775 -0.787549,0.0775 -0.942578,0 -1.466577,-0.47749 -0.520899,-0.48059 -0.520899,-1.34566 0,-0.84956 0.511597,-1.33635 0.514697,-0.48679 1.413867,-0.48679 0.818555,0 1.308447,0.49299 0.492994,0.493 0.492994,1.31775 z m -1.141016,-0.36897 q 0,-0.31626 -0.186035,-0.50849 -0.182935,-0.19534 -0.480591,-0.19534 -0.322461,0 -0.523999,0.18293 -0.201538,0.17984 -0.251147,0.5209 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4825" />
+ <path
+ d="m 22.282188,161.37833 v 0.84336 q -0.356567,-0.14883 -0.68833,-0.22325 -0.331762,-0.0744 -0.626318,-0.0744 -0.31626,0 -0.471289,0.0806 -0.151929,0.0775 -0.151929,0.24185 0,0.13333 0.114722,0.20464 0.117822,0.0713 0.418579,0.10542 l 0.195337,0.0279 q 0.852661,0.10852 1.147217,0.35657 0.294555,0.24805 0.294555,0.77825 0,0.555 -0.409277,0.83406 -0.409277,0.27905 -1.221631,0.27905 -0.344165,0 -0.713135,-0.0558 -0.365869,-0.0527 -0.753442,-0.16123 v -0.84336 q 0.331763,0.16123 0.679028,0.24184 0.350367,0.0806 0.710034,0.0806 0.325562,0 0.489893,-0.0899 0.164331,-0.0899 0.164331,-0.26665 0,-0.14883 -0.114722,-0.22014 -0.111621,-0.0744 -0.449585,-0.11472 l -0.195336,-0.0248 q -0.74104,-0.093 -1.038697,-0.34416 -0.297656,-0.25115 -0.297656,-0.76274 0,-0.55191 0.378272,-0.81856 0.378271,-0.26665 1.159619,-0.26665 0.306958,0 0.644921,0.0465 0.337964,0.0465 0.734839,0.14573 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4827" />
+ <path
+ d="m -41.392532,169.91734 q -0.36897,0 -0.564307,0.26665 -0.192236,0.26355 -0.192236,0.76274 0,0.4992 0.192236,0.76585 0.195337,0.26355 0.564307,0.26355 0.362769,0 0.555005,-0.26355 0.192236,-0.26665 0.192236,-0.76585 0,-0.49919 -0.192236,-0.76274 -0.192236,-0.26665 -0.555005,-0.26665 z m 0,-0.79375 q 0.896069,0 1.398364,0.48369 0.505396,0.48369 0.505396,1.33945 0,0.85577 -0.505396,1.33946 -0.502295,0.48369 -1.398364,0.48369 -0.89917,0 -1.407666,-0.48369 -0.505395,-0.48369 -0.505395,-1.33946 0,-0.85576 0.505395,-1.33945 0.508496,-0.48369 1.407666,-0.48369 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4829" />
+ <path
+ d="m -36.397488,167.85545 v 0.72864 h -0.613916 q -0.235644,0 -0.328662,0.0868 -0.09302,0.0837 -0.09302,0.29456 v 0.24185 h 0.94878 v 0.79375 h -0.94878 v 2.6789 h -1.110009 v -2.6789 h -0.551905 v -0.79375 h 0.551905 v -0.24185 q 0,-0.56741 0.316259,-0.83716 0.31626,-0.27285 0.979786,-0.27285 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4831" />
+ <path
+ d="m -32.496951,168.22132 v 0.98599 h 1.144116 v 0.79375 h -1.144116 v 1.47277 q 0,0.24185 0.09612,0.32867 0.09612,0.0837 0.381372,0.0837 h 0.570508 v 0.79375 h -0.95188 q -0.657324,0 -0.933276,-0.27285 -0.272852,-0.27595 -0.272852,-0.93328 v -1.47277 h -0.551904 v -0.79375 h 0.551904 v -0.98599 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4833" />
+ <path
+ d="m -27.182547,170.56536 v 2.1146 h -1.116211 v -0.34416 -1.26814 q 0,-0.45579 -0.0217,-0.62632 -0.0186,-0.17053 -0.06821,-0.25115 -0.06511,-0.10852 -0.176733,-0.16743 -0.111621,-0.062 -0.254248,-0.062 -0.347266,0 -0.545703,0.26975 -0.198438,0.26665 -0.198438,0.74104 v 1.70842 h -1.110009 v -4.82451 h 1.110009 v 1.86035 q 0.251148,-0.30386 0.533301,-0.44648 0.282153,-0.14573 0.623218,-0.14573 0.601514,0 0.911572,0.36897 0.313159,0.36897 0.313159,1.0728 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4835" />
+ <path
+ d="m -22.686697,170.93433 v 0.31626 h -2.59519 q 0.04031,0.39068 0.282153,0.58601 0.241846,0.19534 0.675928,0.19534 0.350366,0 0.716235,-0.10232 0.36897,-0.10542 0.756543,-0.31626 v 0.85576 q -0.393774,0.14883 -0.787549,0.22324 -0.393774,0.0775 -0.787548,0.0775 -0.942578,0 -1.466577,-0.47749 -0.520899,-0.48059 -0.520899,-1.34566 0,-0.84956 0.511597,-1.33635 0.514697,-0.48679 1.413867,-0.48679 0.818555,0 1.308447,0.49299 0.492993,0.493 0.492993,1.31775 z m -1.141015,-0.36897 q 0,-0.31626 -0.186035,-0.50849 -0.182935,-0.19534 -0.480591,-0.19534 -0.322461,0 -0.523999,0.18293 -0.201538,0.17984 -0.251148,0.5209 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:end;text-anchor:end;fill:#000081;fill-opacity:1;stroke-width:0.398751"
+ id="path4837" />
+ <path
+ d="m -17.563893,171.7063 h -1.322103 l -0.237718,0.97366 h -1.116948 l 1.380718,-4.51338 h 1.296051 l 1.380718,4.51338 h -1.143 z m -1.152769,-0.77503 h 0.976923 l -0.488462,-1.99618 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4839" />
+ <path
+ d="m -15.772877,172.67996 v -0.69036 h 0.455897 v -2.0841 h -0.455897 v -0.68385 h 1.240692 l 0.188872,0.77829 q 0.185615,-0.44613 0.472179,-0.66431 0.289821,-0.21818 0.706641,-0.21818 0.175846,0 0.312616,0.0293 0.136769,0.026 0.257256,0.0749 l -0.192128,1.44585 h -0.644769 v -0.63826 q -0.293077,0.0521 -0.514513,0.31913 -0.221436,0.26377 -0.341923,0.65128 v 0.98995 h 0.683846 v 0.69036 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4841" />
+ <path
+ d="m -11.865195,172.67996 v -0.69036 h 0.455898 v -2.0841 h -0.455898 v -0.68385 h 1.240692 l 0.188872,0.77829 q 0.185616,-0.44613 0.4721797,-0.66431 0.2898206,-0.21818 0.7066411,-0.21818 0.1758461,0 0.3126153,0.0293 0.1367693,0.026 0.2572564,0.0749 l -0.1921282,1.44585 h -0.6447692 v -0.63826 q -0.2930769,0.0521 -0.5145131,0.31913 -0.221436,0.26377 -0.341923,0.65128 v 0.98995 h 0.6838464 v 0.69036 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4843" />
+ <path
+ d="m -5.0788439,171.6835 q 0,0.19539 0.052103,0.28331 0.055359,0.0879 0.1758462,0.13351 l -0.2116667,0.67733 q -0.3061026,-0.0293 -0.5177692,-0.13351 -0.2084103,-0.10746 -0.3288975,-0.32238 -0.198641,0.23771 -0.508,0.35495 -0.3093589,0.11397 -0.6317435,0.11397 -0.5340513,0 -0.8531795,-0.30285 -0.3158718,-0.3061 -0.3158718,-0.78479 0,-0.56336 0.4396154,-0.86946 0.4428718,-0.30611 1.2439487,-0.30611 h 0.4656666 v -0.13025 q 0,-0.5308 -0.6838461,-0.5308 -0.1660769,0 -0.4265897,0.0488 -0.2605129,0.0456 -0.5210257,0.13351 l -0.2377179,-0.68384 q 0.3354102,-0.127 0.6968718,-0.19213 0.3647179,-0.0651 0.651282,-0.0651 0.7717692,0 1.1397436,0.31587 0.3712307,0.31262 0.3712307,0.90528 z m -1.6151794,0.37123 q 0.1660769,0 0.3484359,-0.0977 0.1823589,-0.10095 0.2767948,-0.28331 v -0.5601 h -0.254 q -0.4298461,0 -0.6317435,0.13351 -0.2018975,0.13026 -0.2018975,0.38426 0,0.19864 0.1204872,0.31261 0.1237436,0.11072 0.3419231,0.11072 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4845" />
+ <path
+ d="m -0.81295823,169.22165 -1.15276917,3.45831 q -0.2279488,0.6871 -0.690359,1.04531 -0.4591538,0.3582 -1.2472051,0.40379 l -0.1172308,-0.72618 q 0.3419231,-0.0423 0.5503333,-0.127 0.2116667,-0.0847 0.3386667,-0.2312 0.1302564,-0.14328 0.2246923,-0.36472 h -0.3516923 l -1.0974102,-3.45831 h 1.087641 l 0.6708205,2.80052 0.7294359,-2.80052 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4847" />
+ <path
+ d="m 2.9091107,168.16658 0.254,4.51338 H 2.2317774 l -0.055359,-1.93105 q -0.00977,-0.3582 -0.00651,-0.62197 0.00651,-0.26377 0.022795,-0.50475 0.016282,-0.24423 0.039077,-0.54707 l -0.508,2.83633 H 0.91618767 l -0.54707692,-2.83633 q 0.0260513,0.2833 0.0423333,0.53405 0.016282,0.24748 0.0195385,0.52102 0.006513,0.27354 0,0.635 l -0.0325641,1.91477 h -0.91505127 l 0.25399999,-4.51338 h 1.09741024 l 0.50148719,2.91774 0.4754359,-2.91774 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4849" />
+ <path
+ d="m 4.625231,171.2504 q 0.052102,0.42333 0.2767948,0.60895 0.2246923,0.18236 0.5535898,0.18236 0.2377179,0 0.4591538,-0.0782 0.2214359,-0.0781 0.4265898,-0.20841 l 0.413564,0.5601 q -0.2442307,0.20841 -0.5926666,0.34193 -0.3451795,0.13351 -0.7880513,0.13351 -0.5926666,0 -0.9932051,-0.23446 -0.4005384,-0.23772 -0.6024359,-0.65128 -0.2018974,-0.41357 -0.2018974,-0.95088 0,-0.51125 0.1953846,-0.92807 0.1953846,-0.42008 0.5698718,-0.66757 0.3777436,-0.25074 0.9215641,-0.25074 0.4949743,0 0.8564359,0.21167 0.3647179,0.21166 0.5633589,0.60895 0.2018975,0.39728 0.2018975,0.95412 0,0.0879 -0.00651,0.18888 -0.00326,0.10094 -0.013026,0.1791 z m 0.6382564,-1.45236 q -0.2767949,0 -0.4461282,0.19864 -0.1693334,0.19864 -0.2051539,0.635 h 1.27 q -0.00326,-0.37774 -0.1465384,-0.60569 -0.1432821,-0.22795 -0.4721795,-0.22795 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4851" />
+ <path
+ d="m 10.753783,172.47806 q -0.201897,0.13026 -0.488461,0.22144 -0.2865644,0.0912 -0.6447695,0.0912 -0.6773333,0 -1.0062308,-0.34518 -0.3288974,-0.34844 -0.3288974,-0.94436 v -1.56959 H 7.5592448 v -0.7099 h 0.7261795 v -0.74897 l 1.0290256,-0.12374 v 0.87271 h 1.1136921 l -0.100948,0.7099 H 9.3144499 v 1.56959 q 0,0.25726 0.1172308,0.36798 0.1172308,0.11071 0.3744872,0.11071 0.1823589,0 0.3321541,-0.0423 0.153051,-0.0456 0.273538,-0.11397 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4853" />
+ <path
+ d="m 12.577365,167.7465 v 1.81708 q 0.433103,-0.4559 1.016,-0.4559 0.46241,0 0.706641,0.27028 0.244231,0.27028 0.244231,0.762 v 2.54 h -1.029026 v -2.25343 q 0,-0.31262 -0.07164,-0.43636 -0.06838,-0.12375 -0.260513,-0.12375 -0.16282,0 -0.312615,0.11398 -0.146539,0.11072 -0.293077,0.3061 v 2.39346 h -1.029026 v -4.83251 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4855" />
+ <path
+ d="m 16.953969,169.10768 q 0.534051,0 0.908538,0.22795 0.374487,0.22795 0.573128,0.64151 0.198641,0.41031 0.198641,0.9639 0,0.8662 -0.442872,1.35792 -0.442871,0.49172 -1.237435,0.49172 -0.794564,0 -1.237436,-0.48521 -0.442872,-0.4852 -0.442872,-1.35792 0,-0.55033 0.198641,-0.9639 0.201897,-0.41356 0.576385,-0.64476 0.377743,-0.23121 0.905282,-0.23121 z m 0,0.75874 q -0.315872,0 -0.468923,0.26052 -0.149795,0.25725 -0.149795,0.82061 0,0.57313 0.149795,0.83039 0.153051,0.25725 0.468923,0.25725 0.315871,0 0.465666,-0.25725 0.153052,-0.25726 0.153052,-0.8369 0,-0.5601 -0.153052,-0.81736 -0.149795,-0.25726 -0.465666,-0.25726 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4857" />
+ <path
+ d="m 21.330576,167.73999 1.029026,0.10746 v 4.83251 h -0.911795 l -0.0521,-0.381 q -0.143282,0.2019 -0.381,0.34844 -0.237718,0.14328 -0.576384,0.14328 -0.429847,0 -0.713154,-0.23121 -0.280051,-0.2312 -0.420077,-0.64476 -0.136769,-0.41682 -0.136769,-0.97367 0,-0.53405 0.166077,-0.94762 0.166076,-0.41356 0.475435,-0.64802 0.309359,-0.23772 0.735949,-0.23772 0.465667,0 0.784795,0.31913 z m -0.508,2.11992 q -0.267026,0 -0.429846,0.254 -0.162821,0.25074 -0.162821,0.83364 0,0.42659 0.06838,0.66431 0.06839,0.23446 0.188872,0.3289 0.120487,0.0944 0.276795,0.0944 0.172589,0 0.312615,-0.10746 0.143282,-0.10746 0.254,-0.29308 v -1.49143 q -0.107462,-0.13351 -0.227949,-0.20841 -0.120487,-0.0749 -0.280051,-0.0749 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path4859" />
+ </g>
+ <path
+ id="rect1272"
+ style="opacity:0.5;fill:#ffc333;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 142.70969,109.79432 h 39.2278 v 17.71783 h -39.2278 z" />
+ <path
+ id="rect1274"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 89.303658,110.22836 h 39.313852 v 17.13135 H 89.303658 Z" />
+ <g
+ aria-label="+"
+ id="text1278"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 83.42805,114.76435 v 3.38679 h 3.386794 v 1.03368 H 83.42805 v 3.38679 h -1.021511 v -3.38679 h -3.386793 v -1.03368 h 3.386793 v -3.38679 z"
+ style="stroke-width:0.933951"
+ id="path5116" />
+ </g>
+ <g
+ aria-label="→"
+ id="text1282"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 140.22087,119.11341 v 0.54724 l -2.3896,2.3896 -0.72965,-0.72965 1.41673,-1.41674 h -7.41203 v -1.03367 h 7.41203 l -1.41673,-1.41674 0.72965,-0.72965 z"
+ style="stroke-width:0.933951"
+ id="path5203" />
+ </g>
+ <g
+ aria-label="Promotion (if necessary)"
+ id="text1292"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;stroke-width:0.398751">
+ <path
+ d="m 36.378661,139.30262 v 1.45638 h 0.659395 q 0.366043,0 0.565938,-0.18951 0.199895,-0.18951 0.199895,-0.53998 0,-0.34787 -0.199895,-0.53738 -0.199895,-0.18951 -0.565938,-0.18951 z m -0.524401,-0.43094 h 1.183796 q 0.651607,0 0.983901,0.29595 0.33489,0.29335 0.33489,0.86188 0,0.57373 -0.33489,0.86708 -0.332294,0.29336 -0.983901,0.29336 h -0.659395 v 1.55762 H 35.85426 Z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5290" />
+ <path
+ d="m 40.630982,140.28652 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207683,-0.0234 -0.404983,0 -0.623051,0.2648 -0.215472,0.2622 -0.215472,0.75545 v 1.53166 H 38.927977 V 139.84 h 0.480268 v 0.45172 q 0.150571,-0.2648 0.392003,-0.39201 0.241432,-0.1298 0.586706,-0.1298 0.04932,0 0.109034,0.008 0.05971,0.005 0.132398,0.0182 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5292" />
+ <path
+ d="m 42.14188,140.17489 q -0.384214,0 -0.607474,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220664,0.82295 0.22326,0.29855 0.61007,0.29855 0.381619,0 0.604879,-0.30115 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.604879,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40499 0.355658,1.12149 0,0.71392 -0.355658,1.1215 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.1215 0,-0.7165 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5294" />
+ <path
+ d="m 46.531792,140.39815 q 0.179127,-0.32191 0.428347,-0.47507 0.249221,-0.15317 0.586706,-0.15317 0.454308,0 0.700933,0.31931 0.246624,0.31672 0.246624,0.90343 v 1.75492 h -0.480269 v -1.73935 q 0,-0.41796 -0.147974,-0.62045 -0.147975,-0.20249 -0.451712,-0.20249 -0.371234,0 -0.586706,0.24662 -0.215472,0.24663 -0.215472,0.67238 v 1.64329 h -0.480268 v -1.73935 q 0,-0.42056 -0.147975,-0.62045 -0.147974,-0.20249 -0.456904,-0.20249 -0.366042,0 -0.581514,0.24922 -0.215471,0.24662 -0.215471,0.66978 v 1.64329 H 44.249868 V 139.84 h 0.480269 v 0.45172 q 0.163551,-0.2674 0.392002,-0.3946 0.228452,-0.12721 0.542574,-0.12721 0.316717,0 0.537381,0.16096 0.22326,0.16095 0.329698,0.46728 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5296" />
+ <path
+ d="m 50.573834,140.17489 q -0.384215,0 -0.607475,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220664,0.82295 0.22326,0.29855 0.610071,0.29855 0.381618,0 0.604878,-0.30115 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.604878,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40499 0.355658,1.12149 0,0.71392 -0.355658,1.1215 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.1215 0,-0.7165 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5298" />
+ <path
+ d="M 53.172476,139.01446 V 139.84 h 0.983901 v 0.37124 h -0.983901 v 1.57839 q 0,0.35566 0.09605,0.45691 0.09865,0.10124 0.397195,0.10124 h 0.490652 v 0.39979 h -0.490652 q -0.552958,0 -0.763237,-0.20508 -0.21028,-0.20769 -0.21028,-0.75286 v -1.57839 H 52.341742 V 139.84 h 0.350466 v -0.82554 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5300" />
+ <path
+ d="m 54.784619,139.84 h 0.477673 v 2.90757 h -0.477673 z m 0,-1.13187 h 0.477673 v 0.60488 h -0.477673 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5302" />
+ <path
+ d="m 57.388453,140.17489 q -0.384215,0 -0.607475,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220664,0.82295 0.22326,0.29855 0.610071,0.29855 0.381618,0 0.604878,-0.30115 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.604878,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40499 0.355658,1.12149 0,0.71392 -0.355658,1.1215 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.1215 0,-0.7165 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5304" />
+ <path
+ d="m 61.931531,140.99265 v 1.75492 h -0.477672 v -1.73935 q 0,-0.41277 -0.160955,-0.61785 -0.160955,-0.20509 -0.482864,-0.20509 -0.386811,0 -0.610071,0.24662 -0.22326,0.24663 -0.22326,0.67238 v 1.64329 H 59.496441 V 139.84 h 0.480268 v 0.45172 q 0.171339,-0.26221 0.402387,-0.39201 0.233644,-0.1298 0.537381,-0.1298 0.501037,0 0.758046,0.31153 0.257008,0.30893 0.257008,0.91121 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5306" />
+ <path
+ d="m 65.721757,138.71332 q -0.34787,0.59709 -0.516613,1.1812 -0.168742,0.58411 -0.168742,1.1838 0,0.59968 0.168742,1.18899 0.171339,0.5867 0.516613,1.1812 H 65.30639 q -0.389407,-0.61007 -0.58411,-1.19938 -0.192107,-0.5893 -0.192107,-1.17081 0,-0.57892 0.192107,-1.16563 0.192107,-0.5867 0.58411,-1.19937 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5308" />
+ <path
+ d="m 66.648545,139.84 h 0.477673 v 2.90757 h -0.477673 z m 0,-1.13187 h 0.477673 v 0.60488 h -0.477673 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5310" />
+ <path
+ d="m 69.597651,138.70813 v 0.39719 h -0.456904 q -0.257009,0 -0.358254,0.10384 -0.09865,0.10385 -0.09865,0.37384 v 0.257 h 0.786602 v 0.37124 h -0.786602 v 2.53633 h -0.480268 v -2.53633 H 67.746671 V 139.84 h 0.456904 v -0.20249 q 0,-0.48546 0.225856,-0.70612 0.225856,-0.22326 0.716508,-0.22326 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5312" />
+ <path
+ d="m 74.104386,140.99265 v 1.75492 h -0.477672 v -1.73935 q 0,-0.41277 -0.160955,-0.61785 -0.160954,-0.20509 -0.482864,-0.20509 -0.386811,0 -0.610071,0.24662 -0.223259,0.24663 -0.223259,0.67238 v 1.64329 H 71.669296 V 139.84 h 0.480269 v 0.45172 q 0.171339,-0.26221 0.402387,-0.39201 0.233644,-0.1298 0.537381,-0.1298 0.501036,0 0.758045,0.31153 0.257008,0.30893 0.257008,0.91121 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5314" />
+ <path
+ d="m 77.544147,141.17437 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267392,0.25701 0.742469,0.25701 0.27518,0 0.532189,-0.0675 0.259604,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257009,0.10903 -0.526997,0.16615 -0.269989,0.0571 -0.547766,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40499 -0.404983,-1.09553 0,-0.71392 0.384215,-1.13188 0.38681,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477673,-0.14019 q -0.0052,-0.392 -0.220663,-0.62564 -0.212876,-0.23365 -0.565938,-0.23365 -0.399791,0 -0.641223,0.22586 -0.238836,0.22586 -0.275181,0.63603 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5316" />
+ <path
+ d="m 80.420563,139.95163 v 0.44652 q -0.202492,-0.11163 -0.407579,-0.16614 -0.202492,-0.0571 -0.410175,-0.0571 -0.464692,0 -0.721701,0.29595 -0.257008,0.29336 -0.257008,0.82554 0,0.53219 0.257008,0.82814 0.257009,0.29336 0.721701,0.29336 0.207683,0 0.410175,-0.0545 0.205087,-0.0571 0.407579,-0.16874 v 0.44132 q -0.199895,0.0935 -0.415367,0.14019 -0.212876,0.0467 -0.454308,0.0467 -0.656799,0 -1.04361,-0.41277 -0.386811,-0.41277 -0.386811,-1.11371 0,-0.71131 0.389407,-1.11889 0.392003,-0.40758 1.072166,-0.40758 0.220664,0 0.430944,0.0467 0.21028,0.0441 0.407579,0.13499 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5318" />
+ <path
+ d="m 83.738307,141.17437 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267393,0.25701 0.742469,0.25701 0.275181,0 0.532189,-0.0675 0.259605,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257008,0.10903 -0.526997,0.16615 -0.269989,0.0571 -0.547765,0.0571 -0.69574,0 -1.10332,-0.40498 -0.404983,-0.40499 -0.404983,-1.09553 0,-0.71392 0.384215,-1.13188 0.386811,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477672,-0.14019 q -0.0052,-0.392 -0.220664,-0.62564 -0.212876,-0.23365 -0.565938,-0.23365 -0.399791,0 -0.641223,0.22586 -0.238836,0.22586 -0.275181,0.63603 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5320" />
+ <path
+ d="m 86.375891,139.92567 v 0.45171 q -0.202491,-0.10384 -0.420559,-0.15576 -0.218068,-0.0519 -0.451712,-0.0519 -0.355658,0 -0.534785,0.10904 -0.176531,0.10903 -0.176531,0.3271 0,0.16614 0.127206,0.2622 0.127206,0.0934 0.511421,0.17912 l 0.163551,0.0363 q 0.508824,0.10903 0.7217,0.30893 0.215472,0.1973 0.215472,0.55296 0,0.40498 -0.32191,0.64122 -0.319313,0.23624 -0.880059,0.23624 -0.233644,0 -0.488056,-0.0467 -0.251817,-0.0441 -0.53219,-0.13499 v -0.49325 q 0.264797,0.13759 0.521805,0.20768 0.257009,0.0675 0.508825,0.0675 0.337486,0 0.519209,-0.11423 0.181723,-0.11682 0.181723,-0.3271 0,-0.1947 -0.132398,-0.29854 -0.129802,-0.10385 -0.573726,-0.1999 l -0.166147,-0.0389 q -0.443923,-0.0935 -0.641223,-0.28557 -0.197299,-0.1947 -0.197299,-0.53218 0,-0.41018 0.290757,-0.63344 0.290757,-0.22326 0.825542,-0.22326 0.264797,0 0.498441,0.0389 0.233644,0.0389 0.430943,0.11682 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5322" />
+ <path
+ d="m 89.145869,139.92567 v 0.45171 q -0.202492,-0.10384 -0.42056,-0.15576 -0.218067,-0.0519 -0.451711,-0.0519 -0.355659,0 -0.534786,0.10904 -0.176531,0.10903 -0.176531,0.3271 0,0.16614 0.127206,0.2622 0.127207,0.0934 0.511421,0.17912 l 0.163551,0.0363 q 0.508825,0.10903 0.721701,0.30893 0.215471,0.1973 0.215471,0.55296 0,0.40498 -0.321909,0.64122 -0.319314,0.23624 -0.880059,0.23624 -0.233644,0 -0.488057,-0.0467 -0.251816,-0.0441 -0.532189,-0.13499 v -0.49325 q 0.264797,0.13759 0.521805,0.20768 0.257008,0.0675 0.508825,0.0675 0.337486,0 0.519209,-0.11423 0.181723,-0.11682 0.181723,-0.3271 0,-0.1947 -0.132398,-0.29854 -0.129803,-0.10385 -0.573726,-0.1999 l -0.166147,-0.0389 q -0.443924,-0.0935 -0.641223,-0.28557 -0.1973,-0.1947 -0.1973,-0.53218 0,-0.41018 0.290757,-0.63344 0.290757,-0.22326 0.825543,-0.22326 0.264796,0 0.49844,0.0389 0.233644,0.0389 0.430944,0.11682 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5324" />
+ <path
+ d="m 91.383661,141.286 q -0.578918,0 -0.802178,0.1324 -0.22326,0.1324 -0.22326,0.45171 0,0.25441 0.166147,0.40498 0.168743,0.14798 0.456904,0.14798 0.397195,0 0.636031,-0.28037 0.241432,-0.28297 0.241432,-0.75026 V 141.286 Z m 0.952748,-0.1973 v 1.65887 h -0.477672 v -0.44132 q -0.163551,0.26479 -0.407579,0.392 -0.244028,0.12461 -0.59709,0.12461 -0.44652,0 -0.711317,-0.24922 -0.2622,-0.25182 -0.2622,-0.67238 0,-0.49065 0.327102,-0.73987 0.329697,-0.24922 0.981304,-0.24922 h 0.66978 v -0.0467 q 0,-0.3297 -0.218068,-0.50882 -0.215471,-0.18173 -0.607474,-0.18173 -0.249221,0 -0.485461,0.0597 -0.23624,0.0597 -0.454307,0.17913 v -0.44133 q 0.2622,-0.10124 0.508824,-0.15057 0.246625,-0.0519 0.480269,-0.0519 0.630839,0 0.942364,0.3271 0.311525,0.3271 0.311525,0.99169 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5326" />
+ <path
+ d="m 95.005145,140.28652 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207684,-0.0234 -0.404983,0 -0.623051,0.2648 -0.215471,0.2622 -0.215471,0.75545 v 1.53166 H 93.302139 V 139.84 h 0.480269 v 0.45172 q 0.15057,-0.2648 0.392002,-0.39201 0.241433,-0.1298 0.586706,-0.1298 0.04932,0 0.109034,0.008 0.05971,0.005 0.132399,0.0182 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5328" />
+ <path
+ d="m 96.715936,143.01756 q -0.202492,0.51921 -0.394599,0.67757 -0.192107,0.15836 -0.514017,0.15836 h -0.381619 v -0.39979 h 0.280373 q 0.1973,0 0.306334,-0.0935 0.109034,-0.0935 0.241432,-0.44133 l 0.08567,-0.21806 -1.176008,-2.86085 h 0.506229 l 0.908615,2.27414 0.908616,-2.27414 h 0.506229 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5330" />
+ <path
+ d="m 98.577302,138.71332 h 0.415367 q 0.389407,0.61267 0.581514,1.19937 0.194703,0.58671 0.194703,1.16563 0,0.58151 -0.194703,1.17081 -0.192107,0.58931 -0.581514,1.19938 h -0.415367 q 0.345274,-0.5945 0.514017,-1.1812 0.171339,-0.58931 0.171339,-1.18899 0,-0.59969 -0.171339,-1.1838 -0.168743,-0.58411 -0.514017,-1.1812 z"
+ style="fill:#000080;stroke-width:0.398751"
+ id="path5332" />
+ </g>
+ <text
+ style="font-size:3.52778px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1296);"
+ id="text1294"
+ xml:space="preserve" />
+ <g
+ aria-label="If provided"
+ id="text1292-5"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 164.81105,95.531827 h 0.5244 v 3.875895 h -0.5244 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5419" />
+ <path
+ d="m 167.83025,95.368277 v 0.397194 h -0.4569 q -0.25701,0 -0.35826,0.103842 -0.0986,0.103842 -0.0986,0.373831 v 0.257008 h 0.7866 v 0.371235 h -0.7866 v 2.536335 h -0.48027 v -2.536335 h -0.4569 v -0.371235 h 0.4569 v -0.202491 q 0,-0.485461 0.22586,-0.706125 0.22586,-0.223259 0.71651,-0.223259 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5421" />
+ <path
+ d="m 170.38216,98.971587 v 1.542053 h -0.48027 v -4.013488 h 0.48027 v 0.441328 q 0.15057,-0.259605 0.37903,-0.384215 0.23104,-0.127206 0.55036,-0.127206 0.52959,0 0.85929,0.420559 0.33229,0.42056 0.33229,1.105915 0,0.685356 -0.33229,1.105915 -0.3297,0.42056 -0.85929,0.42056 -0.31932,0 -0.55036,-0.12461 -0.22846,-0.127207 -0.37903,-0.386811 z m 1.62513,-1.015054 q 0,-0.526997 -0.21807,-0.825542 -0.21547,-0.301141 -0.5945,-0.301141 -0.37902,0 -0.59709,0.301141 -0.21547,0.298545 -0.21547,0.825542 0,0.526997 0.21547,0.828139 0.21807,0.298545 0.59709,0.298545 0.37903,0 0.5945,-0.298545 0.21807,-0.301142 0.21807,-0.828139 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5423" />
+ <path
+ d="m 174.97976,96.946672 q -0.0805,-0.04673 -0.17653,-0.0675 -0.0935,-0.02336 -0.20769,-0.02336 -0.40498,0 -0.62305,0.264797 -0.21547,0.2622 -0.21547,0.755449 v 1.531666 h -0.48027 v -2.90757 h 0.48027 v 0.451712 q 0.15057,-0.264797 0.392,-0.392003 0.24144,-0.129802 0.58671,-0.129802 0.0493,0 0.10903,0.0078 0.0597,0.0052 0.1324,0.01817 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5425" />
+ <path
+ d="m 176.49066,96.835042 q -0.38422,0 -0.60748,0.301141 -0.22326,0.298545 -0.22326,0.82035 0,0.521805 0.22067,0.822947 0.22326,0.298545 0.61007,0.298545 0.38162,0 0.60488,-0.301141 0.22326,-0.301142 0.22326,-0.820351 0,-0.516613 -0.22326,-0.817754 -0.22326,-0.303737 -0.60488,-0.303737 z m 0,-0.404983 q 0.62305,0 0.97871,0.404983 0.35565,0.404983 0.35565,1.121491 0,0.713913 -0.35565,1.121492 -0.35566,0.404983 -0.97871,0.404983 -0.62565,0 -0.98131,-0.404983 -0.35306,-0.407579 -0.35306,-1.121492 0,-0.716508 0.35306,-1.121491 0.35566,-0.404983 0.98131,-0.404983 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5427" />
+ <path
+ d="m 178.27414,96.500152 h 0.50623 l 0.90861,2.440282 0.90862,-2.440282 h 0.50623 l -1.09034,2.90757 h -0.64901 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5429" />
+ <path
+ d="m 181.76322,96.500152 h 0.47768 v 2.90757 h -0.47768 z m 0,-1.131875 h 0.47768 v 0.604878 h -0.47768 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5431" />
+ <path
+ d="m 185.15366,96.94148 v -1.573203 h 0.47767 v 4.039445 h -0.47767 v -0.436135 q -0.15057,0.259604 -0.38162,0.386811 -0.22845,0.12461 -0.55036,0.12461 -0.527,0 -0.85929,-0.42056 -0.3297,-0.420559 -0.3297,-1.105915 0,-0.685355 0.3297,-1.105915 0.33229,-0.420559 0.85929,-0.420559 0.32191,0 0.55036,0.127206 0.23105,0.12461 0.38162,0.384215 z m -1.62772,1.015053 q 0,0.526997 0.21547,0.828139 0.21807,0.298545 0.59709,0.298545 0.37902,0 0.59709,-0.298545 0.21807,-0.301142 0.21807,-0.828139 0,-0.526997 -0.21807,-0.825542 -0.21807,-0.301141 -0.59709,-0.301141 -0.37902,0 -0.59709,0.301141 -0.21547,0.298545 -0.21547,0.825542 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5433" />
+ <path
+ d="m 189.10224,97.834519 v 0.233644 h -2.19625 q 0.0311,0.493249 0.29595,0.752853 0.26739,0.257009 0.74247,0.257009 0.27518,0 0.53219,-0.0675 0.2596,-0.0675 0.51401,-0.202492 v 0.451712 q -0.25701,0.109034 -0.52699,0.166147 -0.26999,0.05711 -0.54777,0.05711 -0.69574,0 -1.10332,-0.404983 -0.40498,-0.404983 -0.40498,-1.095531 0,-0.713913 0.38421,-1.131876 0.38681,-0.420559 1.04102,-0.420559 0.5867,0 0.92678,0.379023 0.34268,0.376426 0.34268,1.025437 z m -0.47767,-0.140186 q -0.005,-0.392003 -0.22066,-0.625647 -0.21288,-0.233644 -0.56594,-0.233644 -0.39979,0 -0.64122,0.225856 -0.23884,0.225856 -0.27519,0.636031 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5435" />
+ <path
+ d="m 191.79953,96.94148 v -1.573203 h 0.47768 v 4.039445 h -0.47768 v -0.436135 q -0.15057,0.259604 -0.38161,0.386811 -0.22846,0.12461 -0.55037,0.12461 -0.52699,0 -0.85929,-0.42056 -0.32969,-0.420559 -0.32969,-1.105915 0,-0.685355 0.32969,-1.105915 0.3323,-0.420559 0.85929,-0.420559 0.32191,0 0.55037,0.127206 0.23104,0.12461 0.38161,0.384215 z m -1.62772,1.015053 q 0,0.526997 0.21548,0.828139 0.21806,0.298545 0.59709,0.298545 0.37902,0 0.59709,-0.298545 0.21806,-0.301142 0.21806,-0.828139 0,-0.526997 -0.21806,-0.825542 -0.21807,-0.301141 -0.59709,-0.301141 -0.37903,0 -0.59709,0.301141 -0.21548,0.298545 -0.21548,0.825542 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path5437" />
+ </g>
+ <path
+ id="rect1270"
+ style="fill:#00b200;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 37.217079,109.8297 H 76.53093 v 17.13134 H 37.217079 Z" />
+ <path
+ id="rect1907"
+ style="fill:#9f8a56;fill-opacity:0.46663;stroke:none;stroke-width:1.10816;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 142.70969,157.26704 h 39.2278 v 17.71783 h -39.2278 z" />
+ <path
+ id="rect1909"
+ style="fill:#206020;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="m 89.303658,157.70108 h 39.313852 v 17.13135 H 89.303658 Z" />
+ <g
+ aria-label="+"
+ id="text1913"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.933951">
+ <path
+ d="m 83.42805,162.23707 v 3.38679 h 3.386794 v 1.03367 H 83.42805 v 3.3868 h -1.021511 v -3.3868 h -3.386793 v -1.03367 h 3.386793 v -3.38679 z"
+ style="stroke-width:0.933951"
+ id="path5779" />
+ </g>
+ <g
+ aria-label="→"
+ id="text1917"
+ style="font-size:12.4527px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke-width:0.933951">
+ <path
+ d="m 140.22087,166.58613 v 0.54724 l -2.3896,2.38961 -0.72965,-0.72965 1.41673,-1.41674 h -7.41203 v -1.03367 h 7.41203 l -1.41673,-1.41674 0.72965,-0.72965 z"
+ style="fill:#000000;fill-opacity:1;stroke-width:0.933951"
+ id="path5866" />
+ </g>
+ <path
+ id="rect1919"
+ style="fill:#206020;fill-opacity:0.483526;stroke:none;stroke-width:1.09086;stroke-linecap:round;stroke-miterlimit:10"
+ d="M 37.217079,157.30241 H 76.53093 v 17.13135 H 37.217079 Z" />
+ <g
+ aria-label=">U5"
+ id="text1937"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 50.308698,75.776211 2.691162,1.663816 v 0.716029 l -2.670407,1.663816 -0.432385,-0.633011 2.317582,-1.38709 -2.317582,-1.359417 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6038" />
+ <path
+ d="m 57.30986,75.184709 v 3.199646 q 0,0.48773 -0.197167,0.871688 -0.197167,0.380498 -0.581125,0.59842 -0.380498,0.217922 -0.93741,0.217922 -0.56037,0 -0.940869,-0.211004 -0.380498,-0.214462 -0.574207,-0.594961 -0.193708,-0.380498 -0.193708,-0.882065 v -3.199646 h 0.947787 v 2.933297 q 0,0.612257 0.166036,0.920115 0.166036,0.304399 0.594961,0.304399 0.432385,0 0.59842,-0.304399 0.166036,-0.307858 0.166036,-0.920115 v -2.933297 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6040" />
+ <path
+ d="M 61.166722,75.184709 61.05949,75.85577 h -1.79872 v 1.196841 q 0.190249,-0.0934 0.380499,-0.131445 0.190249,-0.03805 0.366662,-0.03805 0.377039,0 0.677979,0.183331 0.30094,0.183331 0.477352,0.529239 0.176413,0.342448 0.176413,0.82326 0,0.480812 -0.22484,0.854392 -0.221381,0.373581 -0.622634,0.588043 -0.401252,0.211004 -0.940868,0.211004 -0.48773,0 -0.868229,-0.179872 -0.377039,-0.179872 -0.646847,-0.484271 l 0.532698,-0.494648 q 0.377039,0.446221 0.930491,0.446221 0.411631,0 0.653766,-0.249053 0.242135,-0.249054 0.242135,-0.688357 0,-0.48773 -0.204085,-0.688356 -0.204086,-0.200627 -0.518862,-0.200627 -0.311317,0 -0.643388,0.159118 h -0.639929 v -2.507831 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6042" />
+ </g>
+ <g
+ aria-label="S8"
+ id="text1941"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 107.40067,79.03849 q 0,0.435843 -0.22484,0.771374 -0.22138,0.332071 -0.64339,0.518861 -0.41855,0.18679 -1.01005,0.18679 -0.62263,0 -1.06886,-0.183331 -0.44622,-0.18679 -0.74716,-0.477352 l 0.49811,-0.556912 q 0.25943,0.235218 0.58113,0.366663 0.32169,0.127985 0.72294,0.127985 0.38396,0 0.64339,-0.176413 0.26289,-0.176412 0.26289,-0.515402 0,-0.193708 -0.083,-0.328612 -0.083,-0.138363 -0.2871,-0.245595 -0.20063,-0.107231 -0.56037,-0.214463 -0.79213,-0.242135 -1.16917,-0.570747 -0.37704,-0.332072 -0.37704,-0.885524 0,-0.41163 0.2283,-0.709111 0.2283,-0.300939 0.61572,-0.460057 0.38741,-0.162577 0.87168,-0.162577 0.5327,0 0.93741,0.155659 0.40472,0.152199 0.71257,0.435844 l -0.47389,0.536156 q -0.24559,-0.211003 -0.5327,-0.311316 -0.28364,-0.100314 -0.57766,-0.100314 -0.34937,0 -0.57767,0.138363 -0.22484,0.138363 -0.22484,0.41509 0,0.169494 0.0934,0.290562 0.0968,0.117609 0.32515,0.221381 0.23176,0.103772 0.63993,0.228299 0.42546,0.127986 0.7437,0.307858 0.32169,0.179872 0.50157,0.466975 0.17987,0.283645 0.17987,0.729866 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6129" />
+ <path
+ d="m 111.30942,76.772794 q 0,0.33899 -0.19371,0.584584 -0.19025,0.245595 -0.57767,0.463516 0.96162,0.456599 0.96162,1.297154 0,0.37704 -0.20062,0.695275 -0.20063,0.318235 -0.5915,0.511943 -0.38742,0.190249 -0.95125,0.190249 -0.56037,0 -0.94087,-0.18679 -0.3805,-0.190249 -0.57421,-0.501566 -0.1937,-0.311317 -0.1937,-0.684897 0,-0.422007 0.24559,-0.726406 0.24905,-0.304399 0.66414,-0.48773 -0.37358,-0.214463 -0.54653,-0.460057 -0.17295,-0.249054 -0.17295,-0.650307 0,-0.418548 0.21446,-0.705652 0.21792,-0.290562 0.56729,-0.439302 0.35282,-0.148741 0.75753,-0.148741 0.42547,0 0.77138,0.145282 0.34937,0.141822 0.55345,0.422007 0.20755,0.280185 0.20755,0.681438 z m -2.19652,0.04843 q 0,0.311317 0.20755,0.473894 0.211,0.159117 0.61571,0.304399 0.26981,-0.179872 0.38396,-0.356285 0.11415,-0.179872 0.11415,-0.422008 0,-0.294021 -0.1695,-0.473893 -0.16603,-0.183331 -0.48773,-0.183331 -0.31477,0 -0.49118,0.169494 -0.17296,0.169495 -0.17296,0.48773 z m 1.46319,2.296827 q 0,-0.266349 -0.12107,-0.428925 -0.11761,-0.162577 -0.34936,-0.276726 -0.23176,-0.11415 -0.57421,-0.235218 -0.23868,0.134904 -0.40125,0.356285 -0.15912,0.221381 -0.15912,0.567289 0,0.33553 0.20063,0.539616 0.20062,0.204086 0.60188,0.204086 0.40471,0 0.60187,-0.211004 0.20063,-0.214463 0.20063,-0.515403 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6131" />
+ </g>
+ <g
+ aria-label=">U5"
+ id="text1949"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 50.308698,116.61385 2.691162,1.66382 v 0.71603 l -2.670407,1.66381 -0.432385,-0.63301 2.317582,-1.38709 -2.317582,-1.35942 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6218" />
+ <path
+ d="m 57.30986,116.02235 v 3.19964 q 0,0.48773 -0.197167,0.87169 -0.197167,0.3805 -0.581125,0.59842 -0.380498,0.21792 -0.93741,0.21792 -0.56037,0 -0.940869,-0.211 -0.380498,-0.21446 -0.574207,-0.59496 -0.193708,-0.3805 -0.193708,-0.88207 v -3.19964 h 0.947787 v 2.9333 q 0,0.61225 0.166036,0.92011 0.166036,0.3044 0.594961,0.3044 0.432385,0 0.59842,-0.3044 0.166036,-0.30786 0.166036,-0.92011 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6220" />
+ <path
+ d="m 61.166722,116.02235 -0.107232,0.67106 h -1.79872 v 1.19684 q 0.190249,-0.0934 0.380499,-0.13145 0.190249,-0.038 0.366662,-0.038 0.377039,0 0.677979,0.18334 0.30094,0.18333 0.477352,0.52923 0.176413,0.34245 0.176413,0.82327 0,0.48081 -0.22484,0.85439 -0.221381,0.37358 -0.622634,0.58804 -0.401252,0.211 -0.940868,0.211 -0.48773,0 -0.868229,-0.17987 -0.377039,-0.17987 -0.646847,-0.48427 l 0.532698,-0.49465 q 0.377039,0.44622 0.930491,0.44622 0.411631,0 0.653766,-0.24905 0.242135,-0.24905 0.242135,-0.68836 0,-0.48773 -0.204085,-0.68835 -0.204086,-0.20063 -0.518862,-0.20063 -0.311317,0 -0.643388,0.15912 h -0.639929 v -2.50783 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6222" />
+ </g>
+ <g
+ aria-label="<S8"
+ id="text1953"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 103.80675,117.05698 0.40817,0.64685 -2.31412,1.37671 2.31412,1.36634 -0.43238,0.65376 -2.67041,-1.66381 v -0.71257 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6309" />
+ <path
+ d="m 108.59064,119.87613 q 0,0.43584 -0.22484,0.77137 -0.22138,0.33207 -0.64338,0.51886 -0.41855,0.18679 -1.01005,0.18679 -0.62264,0 -1.06886,-0.18333 -0.44622,-0.18679 -0.74716,-0.47735 l 0.49811,-0.55691 q 0.25943,0.23522 0.58112,0.36666 0.3217,0.12799 0.72295,0.12799 0.38396,0 0.64339,-0.17642 0.26289,-0.17641 0.26289,-0.5154 0,-0.19371 -0.083,-0.32861 -0.083,-0.13836 -0.2871,-0.24559 -0.20063,-0.10724 -0.56037,-0.21447 -0.79213,-0.24213 -1.16917,-0.57075 -0.37704,-0.33207 -0.37704,-0.88552 0,-0.41163 0.2283,-0.70911 0.2283,-0.30094 0.61571,-0.46006 0.38742,-0.16257 0.87169,-0.16257 0.5327,0 0.93741,0.15565 0.40471,0.1522 0.71257,0.43585 l -0.47389,0.53616 q -0.2456,-0.21101 -0.5327,-0.31132 -0.28365,-0.10031 -0.57767,-0.10031 -0.34936,0 -0.57766,0.13836 -0.22484,0.13836 -0.22484,0.41509 0,0.16949 0.0934,0.29056 0.0969,0.11761 0.32516,0.22138 0.23175,0.10377 0.63992,0.2283 0.42547,0.12799 0.74371,0.30786 0.32169,0.17987 0.50156,0.46697 0.17987,0.28365 0.17987,0.72987 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6311" />
+ <path
+ d="m 112.49939,117.61043 q 0,0.33899 -0.19371,0.58459 -0.19025,0.24559 -0.57766,0.46351 0.96162,0.4566 0.96162,1.29716 0,0.37704 -0.20063,0.69527 -0.20062,0.31824 -0.5915,0.51195 -0.38741,0.19024 -0.95124,0.19024 -0.56037,0 -0.94087,-0.18679 -0.3805,-0.19025 -0.57421,-0.50156 -0.19371,-0.31132 -0.19371,-0.6849 0,-0.42201 0.2456,-0.72641 0.24905,-0.30439 0.66414,-0.48773 -0.37358,-0.21446 -0.54654,-0.46005 -0.17295,-0.24906 -0.17295,-0.65031 0,-0.41855 0.21446,-0.70565 0.21793,-0.29056 0.56729,-0.4393 0.35283,-0.14874 0.75754,-0.14874 0.42547,0 0.77137,0.14528 0.34937,0.14182 0.55346,0.422 0.20754,0.28019 0.20754,0.68144 z m -2.19651,0.0484 q 0,0.31132 0.20754,0.47389 0.21101,0.15912 0.61572,0.3044 0.26981,-0.17987 0.38396,-0.35628 0.11414,-0.17987 0.11414,-0.42201 0,-0.29402 -0.16949,-0.47389 -0.16604,-0.18333 -0.48773,-0.18333 -0.31478,0 -0.49119,0.16949 -0.17295,0.1695 -0.17295,0.48773 z m 1.46319,2.29683 q 0,-0.26635 -0.12107,-0.42893 -0.11761,-0.16257 -0.34937,-0.27672 -0.23176,-0.11415 -0.5742,-0.23522 -0.23868,0.1349 -0.40126,0.35628 -0.15911,0.22138 -0.15911,0.56729 0,0.33553 0.20062,0.53962 0.20063,0.20408 0.60188,0.20408 0.40471,0 0.60188,-0.211 0.20063,-0.21446 0.20063,-0.5154 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6313" />
+ </g>
+ <g
+ aria-label="Unicode"
+ id="text1967"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 46.871582,163.59882 v 3.19964 q 0,0.48773 -0.197167,0.87169 -0.197168,0.3805 -0.581125,0.59842 -0.380499,0.21792 -0.93741,0.21792 -0.560371,0 -0.940869,-0.211 -0.380498,-0.21446 -0.574207,-0.59496 -0.193708,-0.3805 -0.193708,-0.88207 v -3.19964 h 0.947787 v 2.93329 q 0,0.61226 0.166036,0.92012 0.166035,0.3044 0.594961,0.3044 0.432385,0 0.59842,-0.3044 0.166036,-0.30786 0.166036,-0.92012 v -2.93329 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6400" />
+ <path
+ d="m 47.791687,168.38272 v -3.66316 h 0.795588 l 0.06572,0.45314 q 0.473894,-0.55691 1.16225,-0.55691 0.491189,0 0.75062,0.2871 0.26289,0.28364 0.26289,0.79905 v 2.68078 H 49.91556 v -2.3245 q 0,-0.41509 -0.08648,-0.58804 -0.08302,-0.17296 -0.359744,-0.17296 -0.22484,0 -0.418548,0.14183 -0.193708,0.14182 -0.345908,0.3459 v 2.59777 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6402" />
+ <path
+ d="m 53.457645,162.87241 q 0.249054,0 0.408171,0.15566 0.159118,0.15566 0.159118,0.38742 0,0.23175 -0.159118,0.39087 -0.159117,0.15566 -0.408171,0.15566 -0.252512,0 -0.41163,-0.15566 -0.159117,-0.15912 -0.159117,-0.39087 0,-0.23176 0.159117,-0.38742 0.159118,-0.15566 0.41163,-0.15566 z m 0.591503,1.84715 v 3.01631 h 0.965082 v 0.64685 h -2.950593 v -0.64685 h 1.072314 v -2.36946 h -1.037723 v -0.64685 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6404" />
+ <path
+ d="m 57.93714,167.75317 q 0.242136,0 0.45314,-0.0899 0.211003,-0.0899 0.41163,-0.2283 l 0.415089,0.58459 q -0.242135,0.20408 -0.584584,0.33553 -0.342449,0.13144 -0.733324,0.13144 -0.577666,0 -0.989296,-0.23867 -0.408172,-0.23868 -0.626093,-0.67106 -0.217922,-0.43239 -0.217922,-1.00314 0,-0.56383 0.221381,-1.00659 0.22484,-0.44276 0.63647,-0.69527 0.415089,-0.25597 0.989296,-0.25597 0.394335,0 0.71257,0.11415 0.321694,0.11069 0.588043,0.33207 l -0.404712,0.56037 q -0.204086,-0.13837 -0.422008,-0.21447 -0.217921,-0.0761 -0.44622,-0.0761 -0.404713,0 -0.660684,0.29402 -0.252513,0.29056 -0.252513,0.94778 0,0.65031 0.259431,0.91666 0.259431,0.26289 0.650306,0.26289 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6406" />
+ <path
+ d="m 61.766329,164.61579 q 0.546534,0 0.927033,0.23867 0.380498,0.23868 0.577665,0.67452 0.200627,0.43239 0.200627,1.01351 0,0.89244 -0.446221,1.41822 -0.446221,0.52578 -1.262563,0.52578 -0.816342,0 -1.262563,-0.5154 -0.446221,-0.51886 -0.446221,-1.42168 0,-0.57421 0.200626,-1.01005 0.200627,-0.43584 0.581125,-0.67798 0.383958,-0.24559 0.930492,-0.24559 z m 0,0.68835 q -0.383958,0 -0.574207,0.30094 -0.18679,0.30094 -0.18679,0.94433 0,0.65031 0.18679,0.95125 0.18679,0.29748 0.570748,0.29748 0.383957,0 0.570748,-0.29748 0.18679,-0.30094 0.18679,-0.95817 0,-0.63993 -0.18679,-0.93741 -0.186791,-0.30094 -0.567289,-0.30094 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6408" />
+ <path
+ d="m 66.519091,163.15951 0.913196,0.0969 v 5.12635 h -0.809424 l -0.05534,-0.43238 q -0.169495,0.24213 -0.425466,0.39087 -0.255972,0.14528 -0.594962,0.14528 -0.463516,0 -0.767915,-0.24213 -0.300939,-0.24214 -0.44968,-0.67798 -0.145281,-0.4393 -0.145281,-1.02043 0,-0.55691 0.172954,-0.99275 0.176413,-0.43931 0.501566,-0.68836 0.325153,-0.24905 0.774833,-0.24905 0.536157,0 0.885524,0.37012 z m -0.639929,2.13771 q -0.345908,0 -0.546534,0.30094 -0.197168,0.29748 -0.197168,0.95125 0,0.69182 0.183331,0.972 0.183331,0.28019 0.494648,0.28019 0.228299,0 0.401253,-0.13491 0.172954,-0.13836 0.304399,-0.34245 v -1.66727 q -0.127986,-0.1695 -0.287103,-0.26289 -0.155659,-0.0969 -0.352826,-0.0969 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6410" />
+ <path
+ d="m 69.324393,166.8296 q 0.04151,0.5154 0.304399,0.7437 0.262889,0.2283 0.639929,0.2283 0.26289,0 0.494648,-0.083 0.231758,-0.083 0.456598,-0.23176 l 0.380499,0.52232 q -0.255972,0.21446 -0.612257,0.34591 -0.352826,0.13144 -0.778292,0.13144 -0.594962,0 -1.003133,-0.24559 -0.404712,-0.2456 -0.612256,-0.68144 -0.207545,-0.43584 -0.207545,-1.00313 0,-0.54654 0.200626,-0.98584 0.204086,-0.4393 0.588044,-0.69527 0.387416,-0.25943 0.930491,-0.25943 0.754079,0 1.196841,0.49119 0.442762,0.49118 0.442762,1.35941 0,0.20063 -0.0173,0.36321 z m 0.78521,-1.57043 q -0.332071,0 -0.546534,0.23868 -0.211004,0.23868 -0.249053,0.74716 h 1.542748 q -0.0069,-0.46351 -0.190249,-0.72295 -0.183331,-0.26289 -0.556912,-0.26289 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6412" />
+ </g>
+ <g
+ aria-label="Unicode"
+ id="text1971"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 97.823158,163.99748 v 3.19965 q 0,0.48773 -0.197167,0.87169 -0.197167,0.3805 -0.581125,0.59842 -0.380498,0.21792 -0.93741,0.21792 -0.56037,0 -0.940869,-0.211 -0.380498,-0.21447 -0.574207,-0.59497 -0.193708,-0.38049 -0.193708,-0.88206 v -3.19965 h 0.947787 v 2.9333 q 0,0.61226 0.166036,0.92012 0.166036,0.30439 0.594961,0.30439 0.432385,0 0.598421,-0.30439 0.166035,-0.30786 0.166035,-0.92012 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6499" />
+ <path
+ d="m 98.743263,168.78139 v -3.66317 h 0.795588 l 0.06572,0.45314 q 0.473897,-0.55691 1.162247,-0.55691 0.49119,0 0.75062,0.28711 0.26289,0.28364 0.26289,0.79904 v 2.68079 h -0.91319 v -2.3245 q 0,-0.41509 -0.0865,-0.58805 -0.083,-0.17295 -0.35974,-0.17295 -0.22484,0 -0.41855,0.14182 -0.193711,0.14182 -0.34591,0.34591 v 2.59777 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6501" />
+ <path
+ d="m 104.40922,163.27108 q 0.24906,0 0.40817,0.15566 0.15912,0.15565 0.15912,0.38741 0,0.23176 -0.15912,0.39088 -0.15911,0.15566 -0.40817,0.15566 -0.25251,0 -0.41163,-0.15566 -0.15912,-0.15912 -0.15912,-0.39088 0,-0.23176 0.15912,-0.38741 0.15912,-0.15566 0.41163,-0.15566 z m 0.5915,1.84714 v 3.01632 h 0.96509 v 0.64685 h -2.9506 v -0.64685 h 1.07232 v -2.36947 h -1.03773 v -0.64685 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6503" />
+ <path
+ d="m 108.88872,168.15184 q 0.24213,0 0.45314,-0.0899 0.211,-0.0899 0.41163,-0.2283 l 0.41509,0.58458 q -0.24214,0.20409 -0.58459,0.33553 -0.34245,0.13145 -0.73332,0.13145 -0.57767,0 -0.9893,-0.23868 -0.40817,-0.23867 -0.62609,-0.67106 -0.21792,-0.43238 -0.21792,-1.00313 0,-0.56383 0.22138,-1.00659 0.22484,-0.44276 0.63647,-0.69528 0.41509,-0.25597 0.98929,-0.25597 0.39434,0 0.71257,0.11415 0.3217,0.11069 0.58805,0.33207 l -0.40472,0.56037 q -0.20408,-0.13836 -0.422,-0.21446 -0.21793,-0.0761 -0.44622,-0.0761 -0.40472,0 -0.66069,0.29402 -0.25251,0.29057 -0.25251,0.94779 0,0.65031 0.25943,0.91666 0.25943,0.26289 0.65031,0.26289 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6505" />
+ <path
+ d="m 112.71791,165.01445 q 0.54653,0 0.92703,0.23868 0.3805,0.23868 0.57766,0.67452 0.20063,0.43238 0.20063,1.01351 0,0.89244 -0.44622,1.41822 -0.44622,0.52578 -1.26256,0.52578 -0.81635,0 -1.26257,-0.5154 -0.44622,-0.51886 -0.44622,-1.42168 0,-0.57421 0.20063,-1.01005 0.20063,-0.43585 0.58112,-0.67798 0.38396,-0.2456 0.9305,-0.2456 z m 0,0.68836 q -0.38396,0 -0.57421,0.30094 -0.18679,0.30094 -0.18679,0.94433 0,0.6503 0.18679,0.95124 0.18679,0.29748 0.57075,0.29748 0.38395,0 0.57074,-0.29748 0.18679,-0.30094 0.18679,-0.95816 0,-0.63993 -0.18679,-0.93741 -0.18679,-0.30094 -0.56728,-0.30094 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6507" />
+ <path
+ d="m 117.47067,163.55818 0.91319,0.0969 v 5.12635 h -0.80942 l -0.0553,-0.43239 q -0.16949,0.24214 -0.42546,0.39088 -0.25597,0.14528 -0.59496,0.14528 -0.46352,0 -0.76792,-0.24214 -0.30094,-0.24213 -0.44968,-0.67797 -0.14528,-0.43931 -0.14528,-1.02043 0,-0.55691 0.17295,-0.99276 0.17642,-0.4393 0.50157,-0.68835 0.32515,-0.24906 0.77483,-0.24906 0.53616,0 0.88553,0.37012 z m -0.63993,2.13771 q -0.34591,0 -0.54654,0.30094 -0.19716,0.29748 -0.19716,0.95125 0,0.69181 0.18333,0.972 0.18333,0.28018 0.49465,0.28018 0.22829,0 0.40125,-0.1349 0.17295,-0.13836 0.3044,-0.34245 v -1.66728 q -0.12799,-0.16949 -0.28711,-0.26289 -0.15565,-0.0969 -0.35282,-0.0969 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6509" />
+ <path
+ d="m 120.27597,167.22826 q 0.0415,0.5154 0.3044,0.7437 0.26289,0.2283 0.63993,0.2283 0.26289,0 0.49465,-0.083 0.23175,-0.083 0.45659,-0.23175 l 0.3805,0.52232 q -0.25597,0.21446 -0.61225,0.3459 -0.35283,0.13145 -0.7783,0.13145 -0.59496,0 -1.00313,-0.24559 -0.40471,-0.2456 -0.61226,-0.68144 -0.20754,-0.43585 -0.20754,-1.00314 0,-0.54653 0.20063,-0.98583 0.20408,-0.43931 0.58804,-0.69528 0.38742,-0.25943 0.93049,-0.25943 0.75408,0 1.19684,0.49119 0.44276,0.49119 0.44276,1.35942 0,0.20063 -0.0173,0.3632 z m 0.78521,-1.57042 q -0.33207,0 -0.54653,0.23868 -0.21101,0.23867 -0.24906,0.74716 h 1.54275 q -0.007,-0.46352 -0.19025,-0.72295 -0.18333,-0.26289 -0.55691,-0.26289 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6511" />
+ </g>
+ <g
+ aria-label="Unicode"
+ id="text1989"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;stroke-width:0.505891">
+ <path
+ d="m 152.32117,163.85669 v 3.19965 q 0,0.48773 -0.19717,0.87168 -0.19717,0.3805 -0.58113,0.59842 -0.38049,0.21793 -0.93741,0.21793 -0.56037,0 -0.94086,-0.21101 -0.3805,-0.21446 -0.57421,-0.59496 -0.19371,-0.3805 -0.19371,-0.88206 v -3.19965 h 0.94779 v 2.9333 q 0,0.61225 0.16603,0.92011 0.16604,0.3044 0.59496,0.3044 0.43239,0 0.59843,-0.3044 0.16603,-0.30786 0.16603,-0.92011 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6598" />
+ <path
+ d="m 153.24127,168.64059 v -3.66316 h 0.79559 l 0.0657,0.45314 q 0.4739,-0.55691 1.16225,-0.55691 0.49119,0 0.75062,0.2871 0.26289,0.28365 0.26289,0.79905 v 2.68078 h -0.91319 v -2.3245 q 0,-0.41508 -0.0865,-0.58804 -0.083,-0.17295 -0.35975,-0.17295 -0.22484,0 -0.41854,0.14182 -0.19371,0.14182 -0.34591,0.34591 v 2.59776 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6600" />
+ <path
+ d="m 158.90723,163.13028 q 0.24905,0 0.40817,0.15566 0.15912,0.15566 0.15912,0.38742 0,0.23176 -0.15912,0.39088 -0.15912,0.15565 -0.40817,0.15565 -0.25251,0 -0.41163,-0.15565 -0.15912,-0.15912 -0.15912,-0.39088 0,-0.23176 0.15912,-0.38742 0.15912,-0.15566 0.41163,-0.15566 z m 0.5915,1.84715 v 3.01632 h 0.96509 v 0.64684 h -2.9506 v -0.64684 h 1.07232 v -2.36947 h -1.03773 v -0.64685 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6602" />
+ <path
+ d="m 163.38673,168.01104 q 0.24213,0 0.45313,-0.0899 0.21101,-0.0899 0.41163,-0.2283 l 0.41509,0.58458 q -0.24213,0.20409 -0.58458,0.33553 -0.34245,0.13145 -0.73332,0.13145 -0.57767,0 -0.9893,-0.23868 -0.40817,-0.23868 -0.62609,-0.67106 -0.21793,-0.43239 -0.21793,-1.00313 0,-0.56383 0.22139,-1.00659 0.22484,-0.44277 0.63647,-0.69528 0.41509,-0.25597 0.98929,-0.25597 0.39434,0 0.71257,0.11415 0.3217,0.11069 0.58804,0.33207 l -0.40471,0.56037 q -0.20408,-0.13836 -0.422,-0.21446 -0.21793,-0.0761 -0.44623,-0.0761 -0.40471,0 -0.66068,0.29402 -0.25251,0.29056 -0.25251,0.94779 0,0.6503 0.25943,0.91665 0.25943,0.26289 0.65031,0.26289 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6604" />
+ <path
+ d="m 167.21591,164.87366 q 0.54654,0 0.92704,0.23868 0.3805,0.23867 0.57766,0.67452 0.20063,0.43238 0.20063,1.01351 0,0.89244 -0.44622,1.41822 -0.44622,0.52578 -1.26257,0.52578 -0.81634,0 -1.26256,-0.51541 -0.44622,-0.51886 -0.44622,-1.42168 0,-0.5742 0.20063,-1.01005 0.20062,-0.43584 0.58112,-0.67798 0.38396,-0.24559 0.93049,-0.24559 z m 0,0.68836 q -0.38395,0 -0.5742,0.30094 -0.18679,0.30094 -0.18679,0.94432 0,0.65031 0.18679,0.95125 0.18679,0.29748 0.57074,0.29748 0.38396,0 0.57075,-0.29748 0.18679,-0.30094 0.18679,-0.95816 0,-0.63993 -0.18679,-0.93741 -0.18679,-0.30094 -0.56729,-0.30094 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6606" />
+ <path
+ d="m 171.96868,163.41739 0.91319,0.0968 v 5.12635 h -0.80942 l -0.0554,-0.43238 q -0.16949,0.24214 -0.42546,0.39088 -0.25598,0.14528 -0.59496,0.14528 -0.46352,0 -0.76792,-0.24214 -0.30094,-0.24213 -0.44968,-0.67798 -0.14528,-0.4393 -0.14528,-1.02043 0,-0.55691 0.17295,-0.99275 0.17642,-0.4393 0.50157,-0.68836 0.32515,-0.24905 0.77483,-0.24905 0.53616,0 0.88553,0.37012 z m -0.63993,2.13771 q -0.34591,0 -0.54654,0.30094 -0.19716,0.29748 -0.19716,0.95124 0,0.69182 0.18333,0.972 0.18333,0.28019 0.49464,0.28019 0.2283,0 0.40126,-0.1349 0.17295,-0.13837 0.3044,-0.34245 v -1.66728 q -0.12799,-0.16949 -0.28711,-0.26289 -0.15566,-0.0968 -0.35282,-0.0968 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6608" />
+ <path
+ d="m 174.77398,167.08747 q 0.0415,0.5154 0.3044,0.7437 0.26289,0.2283 0.63993,0.2283 0.26289,0 0.49464,-0.083 0.23176,-0.083 0.4566,-0.23176 l 0.3805,0.52232 q -0.25597,0.21447 -0.61226,0.34591 -0.35282,0.13145 -0.77829,0.13145 -0.59496,0 -1.00313,-0.2456 -0.40471,-0.24559 -0.61226,-0.68144 -0.20754,-0.43584 -0.20754,-1.00313 0,-0.54653 0.20062,-0.98584 0.20409,-0.4393 0.58805,-0.69527 0.38741,-0.25943 0.93049,-0.25943 0.75408,0 1.19684,0.49119 0.44276,0.49119 0.44276,1.35942 0,0.20062 -0.0173,0.3632 z m 0.78521,-1.57042 q -0.33207,0 -0.54654,0.23867 -0.211,0.23868 -0.24905,0.74716 h 1.54275 q -0.007,-0.46351 -0.19025,-0.72294 -0.18333,-0.26289 -0.55691,-0.26289 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6610" />
+ </g>
+ <g
+ aria-label="If not provided"
+ id="text2113"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 164.81105,140.86939 h 0.5244 v 3.8759 h -0.5244 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6697" />
+ <path
+ d="m 167.83025,140.70584 v 0.39719 h -0.4569 q -0.25701,0 -0.35826,0.10385 -0.0986,0.10384 -0.0986,0.37383 v 0.257 h 0.7866 v 0.37124 h -0.7866 v 2.53634 h -0.48027 v -2.53634 h -0.4569 v -0.37124 h 0.4569 v -0.20249 q 0,-0.48546 0.22586,-0.70612 0.22586,-0.22326 0.71651,-0.22326 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6699" />
+ <path
+ d="m 172.33698,142.99036 v 1.75493 h -0.47767 v -1.73936 q 0,-0.41277 -0.16095,-0.61785 -0.16096,-0.20509 -0.48287,-0.20509 -0.38681,0 -0.61007,0.24662 -0.22326,0.24663 -0.22326,0.67238 v 1.6433 h -0.48027 v -2.90758 h 0.48027 v 0.45172 q 0.17134,-0.2622 0.40239,-0.39201 0.23364,-0.1298 0.53738,-0.1298 0.50104,0 0.75805,0.31153 0.257,0.30893 0.257,0.91121 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6701" />
+ <path
+ d="m 174.41642,142.1726 q -0.38422,0 -0.60748,0.30115 -0.22326,0.29854 -0.22326,0.82035 0,0.5218 0.22067,0.82294 0.22326,0.29855 0.61007,0.29855 0.38162,0 0.60487,-0.30114 0.22326,-0.30115 0.22326,-0.82035 0,-0.51662 -0.22326,-0.81776 -0.22325,-0.30374 -0.60487,-0.30374 z m 0,-0.40498 q 0.62305,0 0.97871,0.40498 0.35565,0.40499 0.35565,1.1215 0,0.71391 -0.35565,1.12149 -0.35566,0.40498 -0.97871,0.40498 -0.62565,0 -0.98131,-0.40498 -0.35306,-0.40758 -0.35306,-1.12149 0,-0.71651 0.35306,-1.1215 0.35566,-0.40498 0.98131,-0.40498 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6703" />
+ <path
+ d="m 177.01506,141.01217 v 0.82554 h 0.9839 v 0.37124 h -0.9839 v 1.57839 q 0,0.35566 0.096,0.45691 0.0986,0.10124 0.3972,0.10124 h 0.49065 v 0.3998 h -0.49065 q -0.55296,0 -0.76324,-0.20509 -0.21028,-0.20769 -0.21028,-0.75286 v -1.57839 h -0.35047 v -0.37124 h 0.35047 v -0.82554 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6705" />
+ <path
+ d="m 180.77932,144.30915 v 1.54205 h -0.48026 v -4.01349 h 0.48026 v 0.44133 q 0.15057,-0.2596 0.37903,-0.38421 0.23104,-0.12721 0.55036,-0.12721 0.52959,0 0.85929,0.42056 0.33229,0.42056 0.33229,1.10592 0,0.68535 -0.33229,1.10591 -0.3297,0.42056 -0.85929,0.42056 -0.31932,0 -0.55036,-0.12461 -0.22846,-0.12721 -0.37903,-0.38681 z m 1.62513,-1.01505 q 0,-0.527 -0.21807,-0.82555 -0.21547,-0.30114 -0.59449,-0.30114 -0.37903,0 -0.59709,0.30114 -0.21548,0.29855 -0.21548,0.82555 0,0.52699 0.21548,0.82813 0.21806,0.29855 0.59709,0.29855 0.37902,0 0.59449,-0.29855 0.21807,-0.30114 0.21807,-0.82813 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6707" />
+ <path
+ d="m 185.37692,142.28423 q -0.0805,-0.0467 -0.17653,-0.0675 -0.0935,-0.0234 -0.20769,-0.0234 -0.40498,0 -0.62305,0.2648 -0.21547,0.2622 -0.21547,0.75545 v 1.53167 h -0.48027 v -2.90758 h 0.48027 v 0.45172 q 0.15057,-0.2648 0.392,-0.39201 0.24144,-0.1298 0.58671,-0.1298 0.0493,0 0.10903,0.008 0.0597,0.005 0.1324,0.0182 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6709" />
+ <path
+ d="m 186.88782,142.1726 q -0.38422,0 -0.60748,0.30115 -0.22326,0.29854 -0.22326,0.82035 0,0.5218 0.22067,0.82294 0.22326,0.29855 0.61007,0.29855 0.38162,0 0.60488,-0.30114 0.22326,-0.30115 0.22326,-0.82035 0,-0.51662 -0.22326,-0.81776 -0.22326,-0.30374 -0.60488,-0.30374 z m 0,-0.40498 q 0.62305,0 0.97871,0.40498 0.35565,0.40499 0.35565,1.1215 0,0.71391 -0.35565,1.12149 -0.35566,0.40498 -0.97871,0.40498 -0.62565,0 -0.98131,-0.40498 -0.35306,-0.40758 -0.35306,-1.12149 0,-0.71651 0.35306,-1.1215 0.35566,-0.40498 0.98131,-0.40498 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6711" />
+ <path
+ d="m 188.6713,141.83771 h 0.50623 l 0.90861,2.44029 0.90862,-2.44029 h 0.50623 l -1.09034,2.90758 h -0.64901 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6713" />
+ <path
+ d="m 192.16038,141.83771 h 0.47768 v 2.90758 h -0.47768 z m 0,-1.13187 h 0.47768 v 0.60488 h -0.47768 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6715" />
+ <path
+ d="m 195.55082,142.27904 v -1.5732 h 0.47767 v 4.03945 h -0.47767 v -0.43614 q -0.15057,0.2596 -0.38162,0.38681 -0.22845,0.12461 -0.55036,0.12461 -0.527,0 -0.85929,-0.42056 -0.3297,-0.42056 -0.3297,-1.10591 0,-0.68536 0.3297,-1.10592 0.33229,-0.42056 0.85929,-0.42056 0.32191,0 0.55036,0.12721 0.23105,0.12461 0.38162,0.38421 z m -1.62772,1.01506 q 0,0.52699 0.21547,0.82813 0.21807,0.29855 0.59709,0.29855 0.37902,0 0.59709,-0.29855 0.21807,-0.30114 0.21807,-0.82813 0,-0.527 -0.21807,-0.82555 -0.21807,-0.30114 -0.59709,-0.30114 -0.37902,0 -0.59709,0.30114 -0.21547,0.29855 -0.21547,0.82555 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6717" />
+ <path
+ d="m 199.4994,143.17208 v 0.23365 h -2.19625 q 0.0312,0.49324 0.29595,0.75285 0.26739,0.25701 0.74247,0.25701 0.27518,0 0.53219,-0.0675 0.2596,-0.0675 0.51401,-0.20249 v 0.45171 q -0.257,0.10903 -0.52699,0.16615 -0.26999,0.0571 -0.54777,0.0571 -0.69574,0 -1.10332,-0.40498 -0.40498,-0.40499 -0.40498,-1.09553 0,-0.71392 0.38421,-1.13188 0.38681,-0.42056 1.04102,-0.42056 0.5867,0 0.92679,0.37902 0.34267,0.37643 0.34267,1.02544 z m -0.47767,-0.14018 q -0.005,-0.39201 -0.22066,-0.62565 -0.21288,-0.23365 -0.56594,-0.23365 -0.39979,0 -0.64122,0.22586 -0.23884,0.22586 -0.27518,0.63603 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6719" />
+ <path
+ d="m 202.19669,142.27904 v -1.5732 h 0.47768 v 4.03945 h -0.47768 v -0.43614 q -0.15057,0.2596 -0.38162,0.38681 -0.22845,0.12461 -0.55036,0.12461 -0.52699,0 -0.85929,-0.42056 -0.3297,-0.42056 -0.3297,-1.10591 0,-0.68536 0.3297,-1.10592 0.3323,-0.42056 0.85929,-0.42056 0.32191,0 0.55036,0.12721 0.23105,0.12461 0.38162,0.38421 z m -1.62772,1.01506 q 0,0.52699 0.21547,0.82813 0.21807,0.29855 0.5971,0.29855 0.37902,0 0.59709,-0.29855 0.21806,-0.30114 0.21806,-0.82813 0,-0.527 -0.21806,-0.82555 -0.21807,-0.30114 -0.59709,-0.30114 -0.37903,0 -0.5971,0.30114 -0.21547,0.29855 -0.21547,0.82555 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6721" />
+ </g>
+ <g
+ aria-label="Cast descriptors
+to Loop DTypes"
+ id="text2441"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 42.55534,183.75032 v 0.55295 q -0.264796,-0.24662 -0.565938,-0.36863 -0.298545,-0.12202 -0.636031,-0.12202 -0.664587,0 -1.017649,0.40758 -0.353062,0.40498 -0.353062,1.17341 0,0.76584 0.353062,1.17342 0.353062,0.40498 1.017649,0.40498 0.337486,0 0.636031,-0.12202 0.301142,-0.12201 0.565938,-0.36863 v 0.54776 q -0.275181,0.18692 -0.58411,0.28037 -0.306333,0.0935 -0.649011,0.0935 -0.880059,0 -1.386288,-0.53738 -0.506229,-0.53998 -0.506229,-1.47196 0,-0.93457 0.506229,-1.47195 0.506229,-0.53998 1.386288,-0.53998 0.34787,0 0.654203,0.0935 0.308929,0.0909 0.578918,0.27518 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6808" />
+ <path
+ d="m 44.665925,185.86609 q -0.578918,0 -0.802178,0.1324 -0.22326,0.1324 -0.22326,0.45171 0,0.25442 0.166147,0.40499 0.168743,0.14797 0.456904,0.14797 0.397195,0 0.636031,-0.28037 0.241432,-0.28297 0.241432,-0.75026 v -0.10644 z m 0.952748,-0.1973 v 1.65888 h -0.477672 v -0.44133 q -0.163551,0.2648 -0.407579,0.392 -0.244028,0.12461 -0.597091,0.12461 -0.446519,0 -0.711316,-0.24922 -0.2622,-0.25181 -0.2622,-0.67237 0,-0.49066 0.327101,-0.73988 0.329698,-0.24922 0.981305,-0.24922 h 0.66978 v -0.0467 q 0,-0.32969 -0.218068,-0.50882 -0.215472,-0.18172 -0.607474,-0.18172 -0.249221,0 -0.485461,0.0597 -0.23624,0.0597 -0.454308,0.17912 v -0.44132 q 0.262201,-0.10125 0.508825,-0.15058 0.246624,-0.0519 0.480268,-0.0519 0.630839,0 0.942365,0.32711 0.311525,0.3271 0.311525,0.99168 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6810" />
+ <path
+ d="m 48.45615,184.50577 v 0.45171 q -0.202491,-0.10384 -0.420559,-0.15576 -0.218068,-0.0519 -0.451712,-0.0519 -0.355658,0 -0.534785,0.10904 -0.176531,0.10903 -0.176531,0.3271 0,0.16615 0.127206,0.2622 0.127206,0.0935 0.511421,0.17913 l 0.163551,0.0363 q 0.508825,0.10904 0.7217,0.30893 0.215472,0.1973 0.215472,0.55296 0,0.40498 -0.321909,0.64122 -0.319314,0.23624 -0.88006,0.23624 -0.233644,0 -0.488056,-0.0467 -0.251816,-0.0441 -0.532189,-0.13499 v -0.49325 q 0.264796,0.13759 0.521805,0.20768 0.257008,0.0675 0.508825,0.0675 0.337485,0 0.519209,-0.11422 0.181723,-0.11683 0.181723,-0.32711 0,-0.1947 -0.132399,-0.29854 -0.129802,-0.10384 -0.573726,-0.1999 l -0.166146,-0.0389 q -0.443924,-0.0934 -0.641224,-0.28556 -0.197299,-0.19471 -0.197299,-0.53219 0,-0.41018 0.290757,-0.63344 0.290757,-0.22326 0.825542,-0.22326 0.264797,0 0.498441,0.0389 0.233644,0.0389 0.430943,0.11683 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6812" />
+ <path
+ d="m 49.845034,183.59455 v 0.82555 h 0.983901 v 0.37123 h -0.983901 v 1.5784 q 0,0.35565 0.09605,0.4569 0.09865,0.10125 0.397195,0.10125 h 0.490652 v 0.39979 h -0.490652 q -0.552958,0 -0.763238,-0.20509 -0.210279,-0.20768 -0.210279,-0.75285 v -1.5784 H 49.0143 v -0.37123 h 0.350466 v -0.82555 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6814" />
+ <path
+ d="m 55.060489,184.86142 v -1.5732 h 0.477672 v 4.03945 h -0.477672 v -0.43614 q -0.150571,0.25961 -0.381619,0.38681 -0.228452,0.12461 -0.550362,0.12461 -0.526997,0 -0.85929,-0.42056 -0.329698,-0.42056 -0.329698,-1.10591 0,-0.68536 0.329698,-1.10592 0.332293,-0.42056 0.85929,-0.42056 0.32191,0 0.550362,0.12721 0.231048,0.12461 0.381619,0.38421 z m -1.627721,1.01506 q 0,0.527 0.215472,0.82814 0.218068,0.29854 0.59709,0.29854 0.379023,0 0.597091,-0.29854 0.218068,-0.30114 0.218068,-0.82814 0,-0.527 -0.218068,-0.82554 -0.218068,-0.30115 -0.597091,-0.30115 -0.379022,0 -0.59709,0.30115 -0.215472,0.29854 -0.215472,0.82554 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6816" />
+ <path
+ d="m 59.009072,185.75446 v 0.23365 h -2.196254 q 0.03115,0.49325 0.29595,0.75285 0.267392,0.25701 0.742468,0.25701 0.275181,0 0.53219,-0.0675 0.259604,-0.0675 0.514016,-0.20249 v 0.45171 q -0.257008,0.10904 -0.526997,0.16615 -0.269988,0.0571 -0.547765,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40498 -0.404983,-1.09553 0,-0.71391 0.384214,-1.13188 0.386811,-0.42056 1.041014,-0.42056 0.586707,0 0.926788,0.37903 0.342678,0.37642 0.342678,1.02543 z M 58.5314,185.61428 q -0.0052,-0.39201 -0.220664,-0.62565 -0.212875,-0.23364 -0.565937,-0.23364 -0.399791,0 -0.641224,0.22585 -0.238836,0.22586 -0.27518,0.63603 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6818" />
+ <path
+ d="m 61.646655,184.50577 v 0.45171 q -0.202492,-0.10384 -0.42056,-0.15576 -0.218068,-0.0519 -0.451712,-0.0519 -0.355658,0 -0.534785,0.10904 -0.176531,0.10903 -0.176531,0.3271 0,0.16615 0.127206,0.2622 0.127207,0.0935 0.511421,0.17913 l 0.163551,0.0363 q 0.508825,0.10904 0.7217,0.30893 0.215472,0.1973 0.215472,0.55296 0,0.40498 -0.321909,0.64122 -0.319314,0.23624 -0.88006,0.23624 -0.233644,0 -0.488056,-0.0467 -0.251816,-0.0441 -0.532189,-0.13499 v -0.49325 q 0.264796,0.13759 0.521805,0.20768 0.257008,0.0675 0.508825,0.0675 0.337485,0 0.519209,-0.11422 0.181723,-0.11683 0.181723,-0.32711 0,-0.1947 -0.132399,-0.29854 -0.129802,-0.10384 -0.573725,-0.1999 l -0.166147,-0.0389 q -0.443924,-0.0934 -0.641223,-0.28556 -0.1973,-0.19471 -0.1973,-0.53219 0,-0.41018 0.290757,-0.63344 0.290757,-0.22326 0.825542,-0.22326 0.264797,0 0.498441,0.0389 0.233644,0.0389 0.430944,0.11683 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6820" />
+ <path
+ d="m 64.65547,184.53173 v 0.44652 q -0.202491,-0.11163 -0.407579,-0.16615 -0.202491,-0.0571 -0.410175,-0.0571 -0.464692,0 -0.721701,0.29595 -0.257008,0.29335 -0.257008,0.82554 0,0.53219 0.257008,0.82814 0.257009,0.29335 0.721701,0.29335 0.207684,0 0.410175,-0.0545 0.205088,-0.0571 0.407579,-0.16874 v 0.44133 q -0.199895,0.0935 -0.415367,0.14018 -0.212876,0.0467 -0.454308,0.0467 -0.656799,0 -1.04361,-0.41277 -0.386811,-0.41277 -0.386811,-1.1137 0,-0.71132 0.389407,-1.1189 0.392003,-0.40758 1.072167,-0.40758 0.220663,0 0.430943,0.0467 0.21028,0.0441 0.407579,0.135 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6822" />
+ <path
+ d="m 67.171038,184.86662 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207683,-0.0234 -0.404983,0 -0.623051,0.26479 -0.215472,0.2622 -0.215472,0.75545 v 1.53167 h -0.480268 v -2.90757 h 0.480268 v 0.45171 q 0.150571,-0.2648 0.392003,-0.392 0.241432,-0.12981 0.586706,-0.12981 0.04933,0 0.109034,0.008 0.05971,0.005 0.132398,0.0182 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6824" />
+ <path
+ d="m 67.672074,184.4201 h 0.477673 v 2.90757 h -0.477673 z m 0,-1.13188 h 0.477673 v 0.60488 h -0.477673 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6826" />
+ <path
+ d="m 69.61132,186.89153 v 1.54205 h -0.480268 v -4.01348 h 0.480268 v 0.44132 q 0.150571,-0.2596 0.379023,-0.38421 0.231048,-0.12721 0.550361,-0.12721 0.529594,0 0.859291,0.42056 0.332294,0.42056 0.332294,1.10592 0,0.68535 -0.332294,1.10591 -0.329697,0.42056 -0.859291,0.42056 -0.319313,0 -0.550361,-0.12461 -0.228452,-0.1272 -0.379023,-0.38681 z m 1.625124,-1.01505 q 0,-0.527 -0.218067,-0.82554 -0.215472,-0.30115 -0.594495,-0.30115 -0.379022,0 -0.59709,0.30115 -0.215472,0.29854 -0.215472,0.82554 0,0.527 0.215472,0.82814 0.218068,0.29854 0.59709,0.29854 0.379023,0 0.594495,-0.29854 0.218067,-0.30114 0.218067,-0.82814 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6828" />
+ <path
+ d="m 72.996561,183.59455 v 0.82555 h 0.983901 v 0.37123 h -0.983901 v 1.5784 q 0,0.35565 0.09605,0.4569 0.09865,0.10125 0.397195,0.10125 h 0.490652 v 0.39979 H 73.48981 q -0.552958,0 -0.763237,-0.20509 -0.21028,-0.20768 -0.21028,-0.75285 v -1.5784 h -0.350466 v -0.37123 h 0.350466 v -0.82555 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6830" />
+ <path
+ d="m 75.73539,184.75499 q -0.384215,0 -0.607475,0.30114 -0.223259,0.29854 -0.223259,0.82035 0,0.5218 0.220663,0.82294 0.22326,0.29855 0.610071,0.29855 0.381619,0 0.604878,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81776 -0.223259,-0.30373 -0.604878,-0.30373 z m 0,-0.40499 q 0.623051,0 0.978709,0.40499 0.355658,0.40498 0.355658,1.12149 0,0.71391 -0.355658,1.12149 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 Q 75.109743,184.35 75.73539,184.35 Z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6832" />
+ <path
+ d="m 79.546385,184.86662 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207683,-0.0234 -0.404983,0 -0.623051,0.26479 -0.215472,0.2622 -0.215472,0.75545 v 1.53167 H 77.84338 v -2.90757 h 0.480268 v 0.45171 q 0.150571,-0.2648 0.392003,-0.392 0.241432,-0.12981 0.586706,-0.12981 0.04932,0 0.109034,0.008 0.05971,0.005 0.132398,0.0182 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6834" />
+ <path
+ d="m 81.900996,184.50577 v 0.45171 q -0.202492,-0.10384 -0.42056,-0.15576 -0.218067,-0.0519 -0.451711,-0.0519 -0.355659,0 -0.534786,0.10904 -0.176531,0.10903 -0.176531,0.3271 0,0.16615 0.127206,0.2622 0.127207,0.0935 0.511421,0.17913 l 0.163551,0.0363 q 0.508825,0.10904 0.721701,0.30893 0.215471,0.1973 0.215471,0.55296 0,0.40498 -0.321909,0.64122 -0.319314,0.23624 -0.880059,0.23624 -0.233645,0 -0.488057,-0.0467 -0.251816,-0.0441 -0.532189,-0.13499 v -0.49325 q 0.264796,0.13759 0.521805,0.20768 0.257008,0.0675 0.508825,0.0675 0.337486,0 0.519209,-0.11422 0.181723,-0.11683 0.181723,-0.32711 0,-0.1947 -0.132398,-0.29854 -0.129803,-0.10384 -0.573726,-0.1999 l -0.166147,-0.0389 q -0.443924,-0.0934 -0.641223,-0.28556 -0.1973,-0.19471 -0.1973,-0.53219 0,-0.41018 0.290757,-0.63344 0.290757,-0.22326 0.825543,-0.22326 0.264796,0 0.49844,0.0389 0.233644,0.0389 0.430944,0.11683 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6836" />
+ <path
+ d="m 40.104674,190.24043 v 0.82554 h 0.983901 v 0.37124 h -0.983901 v 1.57839 q 0,0.35566 0.09605,0.45691 0.09865,0.10124 0.397195,0.10124 h 0.490653 v 0.39979 h -0.490653 q -0.552957,0 -0.763237,-0.20509 -0.21028,-0.20768 -0.21028,-0.75285 v -1.57839 h -0.350466 v -0.37124 h 0.350466 v -0.82554 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6838" />
+ <path
+ d="m 42.843501,191.40086 q -0.384215,0 -0.607474,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220664,0.82295 0.223259,0.29854 0.61007,0.29854 0.381619,0 0.604879,-0.30114 0.223259,-0.30114 0.223259,-0.82035 0,-0.51661 -0.223259,-0.81775 -0.22326,-0.30374 -0.604879,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40498 0.355658,1.12149 0,0.71392 -0.355658,1.12149 -0.355658,0.40499 -0.978709,0.40499 -0.625647,0 -0.981305,-0.40499 -0.353062,-0.40757 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6840" />
+ <path
+ d="m 46.680455,190.09765 h 0.524401 v 3.43456 h 1.887325 v 0.44133 h -2.411726 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6842" />
+ <path
+ d="m 50.655,191.40086 q -0.384215,0 -0.607474,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220663,0.82295 0.22326,0.29854 0.610071,0.29854 0.381619,0 0.604878,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.223259,-0.30374 -0.604878,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40498 0.355658,1.12149 0,0.71392 -0.355658,1.12149 -0.355658,0.40499 -0.978709,0.40499 -0.625647,0 -0.981305,-0.40499 -0.353062,-0.40757 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6844" />
+ <path
+ d="m 53.907845,191.40086 q -0.384215,0 -0.607475,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220664,0.82295 0.22326,0.29854 0.610071,0.29854 0.381618,0 0.604878,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.604878,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40498 0.355658,1.12149 0,0.71392 -0.355658,1.12149 -0.355658,0.40499 -0.978709,0.40499 -0.625647,0 -0.981305,-0.40499 -0.353062,-0.40757 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6846" />
+ <path
+ d="m 56.496101,193.53741 v 1.54205 h -0.480268 v -4.01349 h 0.480268 v 0.44133 q 0.150571,-0.2596 0.379023,-0.38422 0.231048,-0.1272 0.550361,-0.1272 0.529593,0 0.859291,0.42056 0.332294,0.42056 0.332294,1.10591 0,0.68536 -0.332294,1.10592 -0.329698,0.42056 -0.859291,0.42056 -0.319313,0 -0.550361,-0.12461 -0.228452,-0.12721 -0.379023,-0.38681 z m 1.625124,-1.01506 q 0,-0.52699 -0.218067,-0.82554 -0.215472,-0.30114 -0.594495,-0.30114 -0.379022,0 -0.59709,0.30114 -0.215472,0.29855 -0.215472,0.82554 0,0.527 0.215472,0.82814 0.218068,0.29855 0.59709,0.29855 0.379023,0 0.594495,-0.29855 0.218067,-0.30114 0.218067,-0.82814 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6848" />
+ <path
+ d="m 61.644059,190.52859 v 3.01401 h 0.633435 q 0.802178,0 1.173412,-0.36345 0.373831,-0.36344 0.373831,-1.14745 0,-0.77881 -0.373831,-1.13966 -0.371234,-0.36345 -1.173412,-0.36345 z m -0.524401,-0.43094 h 1.077358 q 1.126684,0 1.653681,0.46988 0.526997,0.46729 0.526997,1.46417 0,1.00207 -0.529593,1.47196 -0.529593,0.46988 -1.651085,0.46988 h -1.077358 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6850" />
+ <path
+ d="m 64.676238,190.09765 h 3.278805 v 0.44132 h -1.375904 v 3.43457 h -0.526997 v -3.43457 h -1.375904 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6852" />
+ <path
+ d="m 68.822124,194.24353 q -0.202492,0.51921 -0.394599,0.67757 -0.192108,0.15836 -0.514017,0.15836 h -0.381619 v -0.39979 h 0.280373 q 0.1973,0 0.306333,-0.0935 0.109034,-0.0935 0.241433,-0.44133 l 0.08567,-0.21807 -1.176008,-2.86084 h 0.506229 l 0.908615,2.27414 0.908616,-2.27414 h 0.506229 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6854" />
+ <path
+ d="m 71.220869,193.53741 v 1.54205 h -0.480268 v -4.01349 h 0.480268 v 0.44133 q 0.15057,-0.2596 0.379022,-0.38422 0.231048,-0.1272 0.550362,-0.1272 0.529593,0 0.859291,0.42056 0.332294,0.42056 0.332294,1.10591 0,0.68536 -0.332294,1.10592 -0.329698,0.42056 -0.859291,0.42056 -0.319314,0 -0.550362,-0.12461 -0.228452,-0.12721 -0.379022,-0.38681 z m 1.625124,-1.01506 q 0,-0.52699 -0.218068,-0.82554 -0.215472,-0.30114 -0.594494,-0.30114 -0.379023,0 -0.59709,0.30114 -0.215472,0.29855 -0.215472,0.82554 0,0.527 0.215472,0.82814 0.218067,0.29855 0.59709,0.29855 0.379022,0 0.594494,-0.29855 0.218068,-0.30114 0.218068,-0.82814 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6856" />
+ <path
+ d="m 76.620643,192.40034 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267393,0.257 0.742469,0.257 0.27518,0 0.532189,-0.0675 0.259604,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257009,0.10903 -0.526997,0.16614 -0.269989,0.0571 -0.547766,0.0571 -0.69574,0 -1.103319,-0.40499 -0.404983,-0.40498 -0.404983,-1.09553 0,-0.71391 0.384215,-1.13187 0.38681,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477673,-0.14019 q -0.0052,-0.392 -0.220663,-0.62564 -0.212876,-0.23365 -0.565938,-0.23365 -0.399791,0 -0.641223,0.22586 -0.238836,0.22585 -0.275181,0.63603 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6858" />
+ <path
+ d="m 79.258223,191.15164 v 0.45171 q -0.202492,-0.10384 -0.420559,-0.15576 -0.218068,-0.0519 -0.451712,-0.0519 -0.355658,0 -0.534785,0.10903 -0.176531,0.10904 -0.176531,0.32711 0,0.16614 0.127206,0.2622 0.127206,0.0934 0.511421,0.17912 l 0.16355,0.0363 q 0.508825,0.10903 0.721701,0.30893 0.215472,0.1973 0.215472,0.55295 0,0.40499 -0.32191,0.64123 -0.319313,0.23624 -0.880059,0.23624 -0.233644,0 -0.488057,-0.0467 -0.251816,-0.0441 -0.532189,-0.135 v -0.49324 q 0.264797,0.13759 0.521805,0.20768 0.257009,0.0675 0.508825,0.0675 0.337486,0 0.519209,-0.11423 0.181723,-0.11682 0.181723,-0.3271 0,-0.1947 -0.132398,-0.29855 -0.129802,-0.10384 -0.573726,-0.19989 l -0.166147,-0.0389 q -0.443924,-0.0935 -0.641223,-0.28557 -0.197299,-0.1947 -0.197299,-0.53219 0,-0.41017 0.290757,-0.63343 0.290757,-0.22326 0.825542,-0.22326 0.264796,0 0.498441,0.0389 0.233644,0.0389 0.430943,0.11682 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path6860" />
+ </g>
+ <g
+ aria-label="<U13"
+ id="text3113"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:6.7452px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';letter-spacing:0px;word-spacing:0px;opacity:0.5;stroke-width:0.505891">
+ <path
+ d="m 155.87082,116.91618 0.40817,0.64685 -2.31412,1.37671 2.31412,1.36634 -0.43238,0.65376 -2.67041,-1.66381 v -0.71257 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6947" />
+ <path
+ d="m 160.58899,116.32468 v 3.19964 q 0,0.48773 -0.19716,0.87169 -0.19717,0.3805 -0.58113,0.59842 -0.3805,0.21792 -0.93741,0.21792 -0.56037,0 -0.94087,-0.211 -0.3805,-0.21446 -0.5742,-0.59496 -0.19371,-0.3805 -0.19371,-0.88207 v -3.19964 h 0.94778 v 2.9333 q 0,0.61225 0.16604,0.92011 0.16604,0.3044 0.59496,0.3044 0.43239,0 0.59842,-0.3044 0.16604,-0.30786 0.16604,-0.92011 v -2.9333 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6949" />
+ <path
+ d="m 164.68107,120.40639 v 0.70219 h -2.98518 v -0.70219 h 1.15879 v -3.1616 l -1.02043,0.63301 -0.39087,-0.63301 1.50123,-0.92011 h 0.80597 v 4.08171 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6951" />
+ <path
+ d="m 166.97789,116.22091 q 0.49119,0 0.84401,0.16603 0.35283,0.16258 0.53962,0.4393 0.18679,0.27673 0.18679,0.6088 0,0.44968 -0.26981,0.74024 -0.26981,0.28711 -0.69181,0.39434 0.31477,0.038 0.56383,0.17295 0.25251,0.13145 0.40125,0.3805 0.14874,0.24905 0.14874,0.62955 0,0.40472 -0.21792,0.73679 -0.21792,0.33207 -0.61918,0.52924 -0.39779,0.1937 -0.94433,0.1937 -0.49118,0 -0.90627,-0.17295 -0.41163,-0.17641 -0.7022,-0.5154 l 0.53616,-0.48427 q 0.20409,0.23867 0.46698,0.34936 0.26635,0.11069 0.55345,0.11069 0.40471,0 0.64685,-0.20754 0.24559,-0.211 0.24559,-0.5915 0,-0.42547 -0.23868,-0.60188 -0.23521,-0.17987 -0.63301,-0.17987 h -0.42546 l 0.10723,-0.65031 h 0.30094 q 0.32515,0 0.55345,-0.1695 0.23176,-0.17295 0.23176,-0.52923 0,-0.31132 -0.21792,-0.48428 -0.21793,-0.17641 -0.54654,-0.17641 -0.29748,0 -0.52924,0.11069 -0.23175,0.11069 -0.44968,0.31478 l -0.47389,-0.50157 q 0.63647,-0.61225 1.53929,-0.61225 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';stroke-width:0.505891"
+ id="path6953" />
+ </g>
+ <g
+ transform="translate(232.48255,-0.55871913)"
+ id="g4067">
+ <g
+ transform="translate(-7.4083337)"
+ id="g4102">
+ <path
+ id="path3217"
+ style="fill:none;fill-opacity:0.483526;stroke:#800000;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Sstart);marker-end:url(#marker3453)"
+ d="m -33.43701,119.33194 h 18.789774 v 41.58775 93.14908 H -33.43701"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ </g>
+ <g
+ id="g4988"
+ transform="rotate(180,-31.440594,176.71768)">
+ <path
+ id="path4980"
+ style="fill:none;fill-opacity:0.483526;stroke:#000081;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker5002)"
+ d="M -21.573873,211.51421 H -87.252914"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <g
+ aria-label="Registered"
+ transform="scale(-1)"
+ id="text4984"
+ style="font-size:10.5833px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 25.487476,-295.55361 q 0.625283,0 0.893999,-0.23254 0.273884,-0.23254 0.273884,-0.76481 0,-0.5271 -0.273884,-0.75447 -0.268716,-0.22738 -0.893999,-0.22738 H 24.65032 v 1.9792 z m -0.837156,1.37459 v 2.91971 h -1.989536 v -7.71526 h 3.038564 q 1.52445,0 2.232415,0.51159 0.713133,0.5116 0.713133,1.61747 0,0.76481 -0.372069,1.25573 -0.366902,0.49093 -1.11104,0.72347 0.408242,0.093 0.728635,0.42374 0.325561,0.32556 0.656289,0.99219 l 1.080034,2.19107 h -2.118727 l -0.940508,-1.91719 q -0.28422,-0.57877 -0.578775,-0.79064 -0.289387,-0.21188 -0.775144,-0.21188 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7040" />
+ <path
+ d="m 36.504856,-294.16868 v 0.5271 h -4.325304 q 0.06718,0.65112 0.470254,0.97668 0.403075,0.32556 1.126543,0.32556 0.583942,0 1.193722,-0.17053 0.614947,-0.1757 1.260901,-0.5271 v 1.42626 q -0.656289,0.24805 -1.312578,0.37207 -0.656288,0.12919 -1.312577,0.12919 -1.570958,0 -2.444287,-0.79581 -0.868162,-0.80098 -0.868162,-2.24275 0,-1.41593 0.852659,-2.22725 0.857826,-0.81132 2.356438,-0.81132 1.364253,0 2.180738,0.82166 0.821653,0.82165 0.821653,2.19624 z m -1.901687,-0.61495 q 0,-0.5271 -0.310057,-0.84749 -0.30489,-0.32556 -0.800983,-0.32556 -0.537433,0 -0.873328,0.30489 -0.335896,0.29972 -0.418578,0.86816 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7042" />
+ <path
+ d="m 41.843014,-292.24116 q -0.382404,0.50643 -0.842323,0.74414 -0.459919,0.23771 -1.064531,0.23771 -1.059363,0 -1.751825,-0.83199 -0.692462,-0.83715 -0.692462,-2.12906 0,-1.29707 0.692462,-2.12389 0.692462,-0.83199 1.751825,-0.83199 0.604612,0 1.064531,0.23771 0.459919,0.23771 0.842323,0.74931 v -0.85783 h 1.860346 v 5.2038 q 0,1.39526 -0.883664,2.12906 -0.878497,0.73897 -2.552808,0.73897 -0.542601,0 -1.049028,-0.0827 -0.506428,-0.0827 -1.018023,-0.25321 v -1.44177 q 0.485757,0.27905 0.950844,0.41341 0.465086,0.13953 0.93534,0.13953 0.909502,0 1.333248,-0.39791 0.423745,-0.39791 0.423745,-1.2454 z m -1.21956,-3.60183 q -0.573606,0 -0.893999,0.42374 -0.320393,0.42375 -0.320393,1.19889 0,0.79582 0.310058,1.20923 0.310057,0.40824 0.904334,0.40824 0.578775,0 0.899167,-0.42375 0.320393,-0.42374 0.320393,-1.19372 0,-0.77514 -0.320393,-1.19889 -0.320392,-0.42374 -0.899167,-0.42374 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7044" />
+ <path
+ d="m 45.481024,-297.04705 h 1.85001 v 5.78774 h -1.85001 z m 0,-2.25309 h 1.85001 v 1.50895 h -1.85001 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7046" />
+ <path
+ d="m 53.630371,-296.86618 v 1.40559 q -0.594277,-0.24804 -1.147213,-0.37207 -0.552936,-0.12402 -1.043861,-0.12402 -0.527098,0 -0.785479,0.13436 -0.253214,0.12919 -0.253214,0.40307 0,0.22221 0.191202,0.34107 0.19637,0.11885 0.69763,0.1757 l 0.325561,0.0465 q 1.421097,0.18087 1.912021,0.59428 0.490925,0.41341 0.490925,1.29708 0,0.925 -0.682127,1.39009 -0.682126,0.46508 -2.036045,0.46508 -0.573606,0 -1.188554,-0.093 -0.60978,-0.0879 -1.255733,-0.26872 v -1.4056 q 0.552936,0.26872 1.13171,0.40308 0.583942,0.13436 1.183387,0.13436 0.5426,0 0.816485,-0.14986 0.273884,-0.14986 0.273884,-0.44442 0,-0.24805 -0.191202,-0.3669 -0.186035,-0.12402 -0.749306,-0.1912 l -0.325561,-0.0413 q -1.235062,-0.15503 -1.731155,-0.57361 -0.496092,-0.41858 -0.496092,-1.27124 0,-0.91983 0.630451,-1.36425 0.63045,-0.44442 1.932692,-0.44442 0.511595,0 1.074866,0.0775 0.563272,0.0775 1.224728,0.24288 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7048" />
+ <path
+ d="m 57.428577,-298.69036 v 1.64331 h 1.906854 v 1.32291 h -1.906854 v 2.45463 q 0,0.40307 0.160196,0.54776 0.160197,0.13953 0.635619,0.13953 h 0.950843 v 1.32291 h -1.586462 q -1.095536,0 -1.555455,-0.45475 -0.454751,-0.45992 -0.454751,-1.55545 v -2.45463 h -0.919838 v -1.32291 h 0.919838 v -1.64331 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7050" />
+ <path
+ d="m 66.244547,-294.16868 v 0.5271 h -4.325304 q 0.06718,0.65112 0.470254,0.97668 0.403075,0.32556 1.126543,0.32556 0.583942,0 1.193721,-0.17053 0.614948,-0.1757 1.260901,-0.5271 v 1.42626 q -0.656288,0.24805 -1.312577,0.37207 -0.656288,0.12919 -1.312577,0.12919 -1.570959,0 -2.444287,-0.79581 -0.868162,-0.80098 -0.868162,-2.24275 0,-1.41593 0.852659,-2.22725 0.857826,-0.81132 2.356437,-0.81132 1.364254,0 2.180739,0.82166 0.821653,0.82165 0.821653,2.19624 z m -1.901687,-0.61495 q 0,-0.5271 -0.310058,-0.84749 -0.30489,-0.32556 -0.800982,-0.32556 -0.537433,0 -0.873329,0.30489 -0.335895,0.29972 -0.418577,0.86816 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7052" />
+ <path
+ d="m 71.944439,-295.47092 q -0.242879,-0.11369 -0.485757,-0.16537 -0.237711,-0.0568 -0.480589,-0.0568 -0.713133,0 -1.100705,0.45992 -0.382404,0.45475 -0.382404,1.30741 v 2.66649 h -1.850011 v -5.78774 h 1.850011 v 0.95084 q 0.356566,-0.56844 0.816485,-0.82682 0.465086,-0.26355 1.11104,-0.26355 0.09302,0 0.201537,0.0103 0.10852,0.005 0.315225,0.031 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7054" />
+ <path
+ d="m 78.641683,-294.16868 v 0.5271 H 74.31638 q 0.06718,0.65112 0.470254,0.97668 0.403075,0.32556 1.126542,0.32556 0.583942,0 1.193722,-0.17053 0.614948,-0.1757 1.260901,-0.5271 v 1.42626 q -0.656288,0.24805 -1.312577,0.37207 -0.656289,0.12919 -1.312577,0.12919 -1.570959,0 -2.444288,-0.79581 -0.868161,-0.80098 -0.868161,-2.24275 0,-1.41593 0.852658,-2.22725 0.857826,-0.81132 2.356438,-0.81132 1.364254,0 2.180739,0.82166 0.821652,0.82165 0.821652,2.19624 z m -1.901686,-0.61495 q 0,-0.5271 -0.310058,-0.84749 -0.30489,-0.32556 -0.800982,-0.32556 -0.537433,0 -0.873329,0.30489 -0.335896,0.29972 -0.418578,0.86816 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7056" />
+ <path
+ d="m 83.979842,-296.19956 v -3.10058 h 1.860345 v 8.04083 h -1.860345 v -0.83715 q -0.382405,0.51159 -0.842323,0.7493 -0.459919,0.23771 -1.064532,0.23771 -1.069698,0 -1.756993,-0.84749 -0.687294,-0.85266 -0.687294,-2.19107 0,-1.33842 0.687294,-2.18591 0.687295,-0.85266 1.756993,-0.85266 0.599445,0 1.059364,0.24288 0.465086,0.23771 0.847491,0.74414 z m -1.21956,3.74653 q 0.594277,0 0.904335,-0.43408 0.315225,-0.43408 0.315225,-1.2609 0,-0.82682 -0.315225,-1.2609 -0.310058,-0.43408 -0.904335,-0.43408 -0.58911,0 -0.904335,0.43408 -0.310057,0.43408 -0.310057,1.2609 0,0.82682 0.310057,1.2609 0.315225,0.43408 0.904335,0.43408 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7058" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccc"
+ inkscape:connector-curvature="0"
+ d="m -94.24417,121.2914 64.203629,-0.52916 V 83.191271"
+ style="fill:none;fill-opacity:0.483526;stroke:#000081;stroke-width:1.2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker5618)"
+ id="path6082" />
+ <g
+ aria-label="resolve_descriptors"
+ transform="scale(-1)"
+ id="text6086"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.3167px;line-height:1.25;font-family:fira;-inkscape-font-specification:fira;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 29.440542,-123.67085 v -0.49895 h 0.40625 v -1.8922 h -0.40625 v -0.49623 h 0.954279 l 0.133599,0.66254 q 0.158138,-0.36535 0.398071,-0.55348 0.239933,-0.18813 0.60256,-0.18813 0.139052,0 0.245386,0.0218 0.106334,0.0218 0.207215,0.0573 l -0.128146,1.12605 h -0.479867 v -0.56439 q -0.280831,0.0245 -0.485319,0.25629 -0.204488,0.22903 -0.321729,0.60529 v 0.96519 h 0.575295 v 0.49895 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7145" />
+ <path
+ d="m 33.29855,-124.89506 q 0.03272,0.40625 0.239933,0.5862 0.207215,0.17995 0.504405,0.17995 0.207215,0 0.389891,-0.0654 0.182676,-0.0654 0.3599,-0.18268 l 0.299916,0.4117 q -0.201762,0.16905 -0.482593,0.27266 -0.278104,0.1036 -0.613465,0.1036 -0.46896,0 -0.790689,-0.19358 -0.319002,-0.19358 -0.482593,-0.53712 -0.16359,-0.34354 -0.16359,-0.79069 0,-0.43079 0.158137,-0.77706 0.160865,-0.34626 0.463508,-0.54803 0.305369,-0.20449 0.733432,-0.20449 0.594379,0 0.943373,0.38717 0.348994,0.38716 0.348994,1.07152 0,0.15814 -0.01363,0.28628 z m 0.618918,-1.23783 q -0.261745,0 -0.430789,0.18813 -0.166317,0.18813 -0.196309,0.58892 h 1.216025 q -0.0055,-0.36535 -0.149958,-0.56984 -0.144506,-0.20721 -0.438969,-0.20721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7147" />
+ <path
+ d="m 37.055677,-124.12073 q 0.253565,0 0.40625,-0.0873 0.155411,-0.0872 0.155411,-0.25083 0,-0.10361 -0.0518,-0.17723 -0.04908,-0.0763 -0.196308,-0.13905 -0.147232,-0.0654 -0.441696,-0.14451 -0.278104,-0.0709 -0.488045,-0.17449 -0.207215,-0.10634 -0.324455,-0.27265 -0.114514,-0.16632 -0.114514,-0.41989 0,-0.37626 0.316276,-0.61346 0.316275,-0.23994 0.88339,-0.23994 0.370806,0 0.64891,0.0982 0.278104,0.0954 0.47714,0.23993 l -0.294464,0.43897 q -0.174497,-0.11179 -0.378985,-0.17995 -0.201762,-0.0709 -0.436242,-0.0709 -0.253566,0 -0.370806,0.0736 -0.114513,0.0736 -0.114513,0.20449 0,0.0927 0.05726,0.15813 0.05998,0.0627 0.212668,0.1227 0.155412,0.0572 0.441695,0.13905 0.280831,0.0791 0.488046,0.18268 0.209942,0.1036 0.324455,0.27537 0.114514,0.16905 0.114514,0.44715 0,0.31355 -0.182677,0.51804 -0.182676,0.20449 -0.482592,0.30537 -0.299917,0.0981 -0.646184,0.0981 -0.408977,0 -0.714346,-0.11724 -0.30537,-0.11724 -0.518038,-0.30264 l 0.373533,-0.41988 q 0.169043,0.1336 0.384438,0.22084 0.218121,0.0873 0.471687,0.0873 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7149" />
+ <path
+ d="m 40.428365,-126.64003 q 0.430789,0 0.730706,0.18813 0.299916,0.18813 0.455327,0.53167 0.158138,0.34082 0.158138,0.79887 0,0.70344 -0.35172,1.11787 -0.35172,0.41443 -0.995177,0.41443 -0.643457,0 -0.995177,-0.40625 -0.351721,-0.40897 -0.351721,-1.12059 0,-0.45261 0.158138,-0.79615 0.158138,-0.34354 0.458054,-0.53439 0.302643,-0.19359 0.733432,-0.19359 z m 0,0.54258 q -0.302643,0 -0.452601,0.23721 -0.147232,0.2372 -0.147232,0.74434 0,0.51258 0.147232,0.74979 0.147232,0.23448 0.449875,0.23448 0.302643,0 0.449874,-0.23448 0.147232,-0.23721 0.147232,-0.75525 0,-0.5044 -0.147232,-0.73888 -0.147231,-0.23721 -0.447148,-0.23721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7151" />
+ <path
+ d="m 43.87467,-127.71154 v 3.20092 q 0,0.18813 0.111787,0.2672 0.111787,0.0791 0.29719,0.0791 0.11724,0 0.2263,-0.0245 0.109061,-0.0273 0.207215,-0.0654 l 0.177224,0.49078 q -0.136326,0.0709 -0.332635,0.12269 -0.193582,0.0518 -0.449875,0.0518 -0.471686,0 -0.714346,-0.26992 -0.24266,-0.26993 -0.24266,-0.72798 v -2.61473 h -0.864304 v -0.50985 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7153" />
+ <path
+ d="m 48.387042,-126.55823 -0.992451,2.88738 h -0.845219 l -0.997904,-2.88738 h 0.77433 l 0.65709,2.31208 0.670722,-2.31208 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7155" />
+ <path
+ d="m 49.657588,-124.89506 q 0.03272,0.40625 0.239933,0.5862 0.207215,0.17995 0.504405,0.17995 0.207215,0 0.389891,-0.0654 0.182677,-0.0654 0.3599,-0.18268 l 0.299916,0.4117 q -0.201762,0.16905 -0.482592,0.27266 -0.278105,0.1036 -0.613466,0.1036 -0.46896,0 -0.790688,-0.19358 -0.319002,-0.19358 -0.482593,-0.53712 -0.163591,-0.34354 -0.163591,-0.79069 0,-0.43079 0.158138,-0.77706 0.160864,-0.34626 0.463507,-0.54803 0.305369,-0.20449 0.733432,-0.20449 0.59438,0 0.943373,0.38717 0.348994,0.38716 0.348994,1.07152 0,0.15814 -0.01363,0.28628 z m 0.618918,-1.23783 q -0.261745,0 -0.430789,0.18813 -0.166317,0.18813 -0.196309,0.58892 h 1.216025 q -0.0055,-0.36535 -0.149958,-0.56984 -0.144505,-0.20721 -0.438969,-0.20721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7157" />
+ <path
+ d="m 52.149612,-122.66477 v -0.58075 h 2.726513 v 0.58075 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7159" />
+ <path
+ d="m 57.261817,-127.78789 0.719799,0.0764 v 4.04069 h -0.638004 l -0.04362,-0.34082 q -0.133599,0.19086 -0.335361,0.3081 -0.201762,0.11451 -0.46896,0.11451 -0.365353,0 -0.605286,-0.19085 -0.237207,-0.19086 -0.354447,-0.5344 -0.114513,-0.34627 -0.114513,-0.80432 0,-0.43897 0.136325,-0.78251 0.139052,-0.34627 0.395345,-0.54258 0.256292,-0.19631 0.610739,-0.19631 0.422609,0 0.697987,0.29174 z m -0.504405,1.68499 q -0.272651,0 -0.430789,0.2372 -0.155411,0.23448 -0.155411,0.7498 0,0.5453 0.144505,0.76615 0.144505,0.22084 0.389891,0.22084 0.17995,0 0.316276,-0.10633 0.136325,-0.10906 0.239933,-0.26993 v -1.31417 q -0.100881,-0.1336 -0.226301,-0.20722 -0.122693,-0.0763 -0.278104,-0.0763 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7161" />
+ <path
+ d="m 59.473012,-124.89506 q 0.03272,0.40625 0.239933,0.5862 0.207215,0.17995 0.504405,0.17995 0.207215,0 0.389891,-0.0654 0.182677,-0.0654 0.3599,-0.18268 l 0.299916,0.4117 q -0.201762,0.16905 -0.482592,0.27266 -0.278105,0.1036 -0.613466,0.1036 -0.46896,0 -0.790688,-0.19358 -0.319002,-0.19358 -0.482593,-0.53712 -0.163591,-0.34354 -0.163591,-0.79069 0,-0.43079 0.158138,-0.77706 0.160864,-0.34626 0.463507,-0.54803 0.305369,-0.20449 0.733432,-0.20449 0.59438,0 0.943373,0.38717 0.348994,0.38716 0.348994,1.07152 0,0.15814 -0.01363,0.28628 z m 0.618918,-1.23783 q -0.261745,0 -0.430789,0.18813 -0.166317,0.18813 -0.196309,0.58892 h 1.216025 q -0.0055,-0.36535 -0.149958,-0.56984 -0.144505,-0.20721 -0.438969,-0.20721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7163" />
+ <path
+ d="m 63.23014,-124.12073 q 0.253566,0 0.40625,-0.0873 0.155411,-0.0872 0.155411,-0.25083 0,-0.10361 -0.0518,-0.17723 -0.04908,-0.0763 -0.196309,-0.13905 -0.147232,-0.0654 -0.441695,-0.14451 -0.278105,-0.0709 -0.488046,-0.17449 -0.207215,-0.10634 -0.324455,-0.27265 -0.114514,-0.16632 -0.114514,-0.41989 0,-0.37626 0.316276,-0.61346 0.316275,-0.23994 0.88339,-0.23994 0.370806,0 0.64891,0.0982 0.278104,0.0954 0.47714,0.23993 l -0.294464,0.43897 q -0.174496,-0.11179 -0.378985,-0.17995 -0.201762,-0.0709 -0.436242,-0.0709 -0.253566,0 -0.370806,0.0736 -0.114513,0.0736 -0.114513,0.20449 0,0.0927 0.05726,0.15813 0.05998,0.0627 0.212668,0.1227 0.155411,0.0572 0.441695,0.13905 0.28083,0.0791 0.488045,0.18268 0.209942,0.1036 0.324455,0.27537 0.114514,0.16905 0.114514,0.44715 0,0.31355 -0.182676,0.51804 -0.182677,0.20449 -0.482593,0.30537 -0.299917,0.0981 -0.646184,0.0981 -0.408977,0 -0.714346,-0.11724 -0.305369,-0.11724 -0.518037,-0.30264 l 0.373532,-0.41988 q 0.169044,0.1336 0.384438,0.22084 0.218121,0.0873 0.471687,0.0873 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7165" />
+ <path
+ d="m 66.856391,-124.16708 q 0.190856,0 0.357174,-0.0709 0.166317,-0.0709 0.324455,-0.17995 l 0.327181,0.46078 q -0.190856,0.16087 -0.460781,0.26448 -0.269924,0.1036 -0.57802,0.1036 -0.455328,0 -0.779783,-0.18813 -0.321728,-0.18813 -0.493499,-0.52894 -0.17177,-0.34081 -0.17177,-0.79069 0,-0.44442 0.174497,-0.79341 0.177223,-0.349 0.501678,-0.54803 0.327182,-0.20177 0.779783,-0.20177 0.310822,0 0.561661,0.09 0.253566,0.0872 0.463508,0.26175 l -0.319002,0.44169 q -0.160865,-0.10906 -0.332635,-0.16904 -0.17177,-0.06 -0.35172,-0.06 -0.319002,0 -0.520764,0.23176 -0.199036,0.22902 -0.199036,0.74706 0,0.51259 0.204489,0.72253 0.204488,0.20721 0.512584,0.20721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7167" />
+ <path
+ d="m 68.702234,-123.67085 v -0.49895 h 0.40625 v -1.8922 h -0.40625 v -0.49623 h 0.954279 l 0.133599,0.66254 q 0.158138,-0.36535 0.398071,-0.55348 0.239933,-0.18813 0.60256,-0.18813 0.139052,0 0.245386,0.0218 0.106334,0.0218 0.207215,0.0573 l -0.128146,1.12605 h -0.479867 v -0.56439 q -0.28083,0.0245 -0.485319,0.25629 -0.204488,0.22903 -0.321728,0.60529 v 0.96519 h 0.575294 v 0.49895 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7169" />
+ <path
+ d="m 73.14099,-128.01419 q 0.196309,0 0.321728,0.1227 0.12542,0.12269 0.12542,0.30536 0,0.18268 -0.12542,0.3081 -0.125419,0.12269 -0.321728,0.12269 -0.199036,0 -0.324455,-0.12269 -0.12542,-0.12542 -0.12542,-0.3081 0,-0.18267 0.12542,-0.30536 0.125419,-0.1227 0.324455,-0.1227 z m 0.466234,1.45596 v 2.37752 h 0.760697 v 0.50986 h -2.325716 v -0.50986 h 0.845219 v -1.86766 H 72.06947 v -0.50986 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7171" />
+ <path
+ d="m 76.709985,-126.64003 q 0.378985,0 0.610738,0.18813 0.231754,0.18541 0.335362,0.52895 0.106334,0.34081 0.106334,0.80159 0,0.44442 -0.128147,0.79069 -0.128146,0.34627 -0.376258,0.5453 -0.245387,0.19631 -0.605286,0.19631 -0.441695,0 -0.714347,-0.31355 v 1.34417 l -0.719799,0.0764 v -4.07614 h 0.632551 l 0.03817,0.35172 q 0.169044,-0.22357 0.381712,-0.32718 0.215395,-0.10634 0.438969,-0.10634 z m -0.209942,0.53985 q -0.182676,0 -0.321728,0.10906 -0.136326,0.10907 -0.239934,0.26993 v 1.29237 q 0.199036,0.29446 0.507132,0.29446 0.275378,0 0.419883,-0.22903 0.147231,-0.23175 0.147231,-0.74979 0,-0.54803 -0.130872,-0.76615 -0.130873,-0.22085 -0.381712,-0.22085 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7173" />
+ <path
+ d="m 80.982423,-123.83172 q -0.160864,0.10634 -0.389891,0.1745 -0.229027,0.0682 -0.496225,0.0682 -0.528944,0 -0.796142,-0.27265 -0.267198,-0.27538 -0.267198,-0.7307 v -1.45596 h -0.627098 v -0.50986 h 0.627098 v -0.63528 l 0.719799,-0.0872 v 0.72253 h 0.95428 l -0.07362,0.50986 h -0.880664 v 1.45323 q 0,0.22357 0.109061,0.32718 0.10906,0.10361 0.35172,0.10361 0.155411,0 0.283557,-0.0354 0.130873,-0.0382 0.237207,-0.0954 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7175" />
+ <path
+ d="m 82.961865,-126.64003 q 0.430789,0 0.730705,0.18813 0.299917,0.18813 0.455328,0.53167 0.158138,0.34082 0.158138,0.79887 0,0.70344 -0.35172,1.11787 -0.351721,0.41443 -0.995178,0.41443 -0.643457,0 -0.995177,-0.40625 -0.35172,-0.40897 -0.35172,-1.12059 0,-0.45261 0.158138,-0.79615 0.158138,-0.34354 0.458054,-0.53439 0.302643,-0.19359 0.733432,-0.19359 z m 0,0.54258 q -0.302643,0 -0.452601,0.23721 -0.147232,0.2372 -0.147232,0.74434 0,0.51258 0.147232,0.74979 0.147232,0.23448 0.449874,0.23448 0.302643,0 0.449875,-0.23448 0.147232,-0.23721 0.147232,-0.75525 0,-0.5044 -0.147232,-0.73888 -0.147232,-0.23721 -0.447148,-0.23721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7177" />
+ <path
+ d="m 85.061273,-123.67085 v -0.49895 h 0.40625 v -1.8922 h -0.40625 v -0.49623 h 0.95428 l 0.133599,0.66254 q 0.158137,-0.36535 0.398071,-0.55348 0.239933,-0.18813 0.602559,-0.18813 0.139052,0 0.245386,0.0218 0.106334,0.0218 0.207215,0.0573 l -0.128146,1.12605 h -0.479866 v -0.56439 q -0.280831,0.0245 -0.48532,0.25629 -0.204488,0.22903 -0.321728,0.60529 v 0.96519 h 0.575294 v 0.49895 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7179" />
+ <path
+ d="m 89.404601,-124.12073 q 0.253566,0 0.406251,-0.0873 0.155411,-0.0872 0.155411,-0.25083 0,-0.10361 -0.0518,-0.17723 -0.04908,-0.0763 -0.196309,-0.13905 -0.147232,-0.0654 -0.441695,-0.14451 -0.278104,-0.0709 -0.488046,-0.17449 -0.207215,-0.10634 -0.324455,-0.27265 -0.114513,-0.16632 -0.114513,-0.41989 0,-0.37626 0.316275,-0.61346 0.316276,-0.23994 0.88339,-0.23994 0.370806,0 0.64891,0.0982 0.278105,0.0954 0.47714,0.23993 l -0.294463,0.43897 q -0.174497,-0.11179 -0.378985,-0.17995 -0.201762,-0.0709 -0.436243,-0.0709 -0.253565,0 -0.370805,0.0736 -0.114514,0.0736 -0.114514,0.20449 0,0.0927 0.05726,0.15813 0.05998,0.0627 0.212668,0.1227 0.155411,0.0572 0.441695,0.13905 0.280831,0.0791 0.488046,0.18268 0.209941,0.1036 0.324455,0.27537 0.114513,0.16905 0.114513,0.44715 0,0.31355 -0.182676,0.51804 -0.182676,0.20449 -0.482593,0.30537 -0.299916,0.0981 -0.646183,0.0981 -0.408977,0 -0.714347,-0.11724 -0.305369,-0.11724 -0.518037,-0.30264 l 0.373532,-0.41988 q 0.169044,0.1336 0.384439,0.22084 0.218121,0.0873 0.471686,0.0873 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7181" />
+ </g>
+ <path
+ id="path6252"
+ style="fill:none;fill-opacity:0.483526;stroke:#000081;stroke-width:1.2;stroke-linecap:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6260)"
+ d="M -30.040541,83.191271 H -85.328359"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ x="91.053413"
+ y="-80.689705"
+ id="text6256"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ x="91.053413"
+ y="-80.689705"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan6254" /><tspan
+ sodipodi:role="line"
+ x="91.053413"
+ y="-74.043831"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="tspan7420" /></text>
+ <g
+ aria-label="Perform operation with these descriptors
+(setup, inner-loop function, teardown)
+"
+ transform="scale(-1)"
+ id="text7434"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 90.279721,-84.738261 h 1.658872 q 0.739873,0 1.134472,0.329698 0.397195,0.327102 0.397195,0.934576 0,0.610071 -0.397195,0.939768 -0.394599,0.327102 -1.134472,0.327102 h -0.659395 v 1.344751 h -0.999477 z m 0.999477,0.724297 v 1.08255 h 0.552957 q 0.290757,0 0.449116,-0.140186 0.158359,-0.142782 0.158359,-0.402387 0,-0.259604 -0.158359,-0.399791 -0.158359,-0.140186 -0.449116,-0.140186 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7268" />
+ <path
+ d="m 97.037225,-82.323939 v 0.264797 h -2.172889 q 0.03375,0.327101 0.23624,0.490652 0.202491,0.163551 0.565938,0.163551 0.293353,0 0.599686,-0.08567 0.308929,-0.08826 0.633435,-0.264796 v 0.716508 q -0.329698,0.12461 -0.659395,0.186915 -0.329698,0.0649 -0.659396,0.0649 -0.789197,0 -1.227929,-0.399791 -0.436135,-0.402387 -0.436135,-1.126684 0,-0.711316 0.428347,-1.118895 0.430943,-0.407579 1.183796,-0.407579 0.685356,0 1.095531,0.412771 0.412771,0.412771 0.412771,1.103319 z m -0.955344,-0.308929 q 0,-0.264797 -0.155763,-0.425752 -0.153166,-0.163551 -0.402387,-0.163551 -0.269988,0 -0.438731,0.153167 -0.168743,0.150571 -0.21028,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7270" />
+ <path
+ d="m 99.900663,-82.978142 q -0.122014,-0.05711 -0.244028,-0.08307 -0.119418,-0.02856 -0.241432,-0.02856 -0.358254,0 -0.552958,0.231048 -0.192107,0.228452 -0.192107,0.656799 v 1.339559 h -0.929384 v -2.90757 h 0.929384 v 0.477672 q 0.179127,-0.285565 0.410175,-0.415367 0.233644,-0.132398 0.55815,-0.132398 0.04673,0 0.101246,0.0052 0.05452,0.0026 0.158358,0.01558 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7272" />
+ <path
+ d="m 102.27604,-84.901812 v 0.610071 h -0.51401 q -0.1973,0 -0.27518,0.07269 -0.0779,0.07009 -0.0779,0.246624 v 0.202492 h 0.79439 v 0.664587 h -0.79439 v 2.242983 h -0.92939 v -2.242983 h -0.46209 v -0.664587 h 0.46209 v -0.202492 q 0,-0.475076 0.2648,-0.700932 0.26479,-0.228452 0.82035,-0.228452 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7274" />
+ <path
+ d="m 104.05953,-83.175442 q -0.30893,0 -0.47248,0.22326 -0.16096,0.220664 -0.16096,0.638627 0,0.417963 0.16096,0.641223 0.16355,0.220664 0.47248,0.220664 0.30373,0 0.46469,-0.220664 0.16095,-0.22326 0.16095,-0.641223 0,-0.417963 -0.16095,-0.638627 -0.16096,-0.22326 -0.46469,-0.22326 z m 0,-0.664587 q 0.75025,0 1.17081,0.404983 0.42316,0.404983 0.42316,1.121491 0,0.716509 -0.42316,1.121492 -0.42056,0.404983 -1.17081,0.404983 -0.75286,0 -1.17861,-0.404983 -0.42315,-0.404983 -0.42315,-1.121492 0,-0.716508 0.42315,-1.121491 0.42575,-0.404983 1.17861,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7276" />
+ <path
+ d="m 108.48838,-82.978142 q -0.12201,-0.05711 -0.24403,-0.08307 -0.11942,-0.02856 -0.24143,-0.02856 -0.35826,0 -0.55296,0.231048 -0.19211,0.228452 -0.19211,0.656799 v 1.339559 h -0.92938 v -2.90757 h 0.92938 v 0.477672 q 0.17913,-0.285565 0.41018,-0.415367 0.23364,-0.132398 0.55815,-0.132398 0.0467,0 0.10124,0.0052 0.0545,0.0026 0.15836,0.01558 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7278" />
+ <path
+ d="m 111.64517,-83.287072 q 0.17653,-0.269988 0.41796,-0.410175 0.24403,-0.142782 0.53479,-0.142782 0.50104,0 0.76324,0.308929 0.2622,0.308929 0.2622,0.898232 v 1.770502 h -0.93458 v -1.51609 q 0.003,-0.03375 0.003,-0.07009 0.003,-0.03634 0.003,-0.103842 0,-0.308929 -0.0909,-0.44652 -0.0909,-0.140186 -0.29335,-0.140186 -0.2648,0 -0.41018,0.218068 -0.14278,0.218067 -0.14797,0.630839 v 1.427824 h -0.93458 v -1.51609 q 0,-0.482864 -0.0831,-0.620455 -0.0831,-0.140186 -0.29595,-0.140186 -0.26739,0 -0.41277,0.220664 -0.14538,0.218067 -0.14538,0.625647 v 1.43042 h -0.93458 v -2.90757 h 0.93458 v 0.425751 q 0.17134,-0.246624 0.392,-0.371234 0.22326,-0.12461 0.49065,-0.12461 0.30115,0 0.53219,0.145378 0.23105,0.145379 0.35047,0.407579 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7280" />
+ <path
+ d="m 117.72511,-83.175442 q -0.30893,0 -0.47248,0.22326 -0.16096,0.220664 -0.16096,0.638627 0,0.417963 0.16096,0.641223 0.16355,0.220664 0.47248,0.220664 0.30373,0 0.46469,-0.220664 0.16095,-0.22326 0.16095,-0.641223 0,-0.417963 -0.16095,-0.638627 -0.16096,-0.22326 -0.46469,-0.22326 z m 0,-0.664587 q 0.75025,0 1.17081,0.404983 0.42316,0.404983 0.42316,1.121491 0,0.716509 -0.42316,1.121492 -0.42056,0.404983 -1.17081,0.404983 -0.75286,0 -1.17861,-0.404983 -0.42315,-0.404983 -0.42315,-1.121492 0,-0.716508 0.42315,-1.121491 0.42575,-0.404983 1.17861,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7282" />
+ <path
+ d="m 120.92343,-81.282925 v 1.526474 h -0.92938 v -4.013485 h 0.92938 v 0.425751 q 0.19211,-0.254412 0.42576,-0.37383 0.23364,-0.122014 0.53738,-0.122014 0.53738,0 0.88265,0.428347 0.34528,0.425752 0.34528,1.098127 0,0.672376 -0.34528,1.100723 -0.34527,0.425752 -0.88265,0.425752 -0.30374,0 -0.53738,-0.119418 -0.23365,-0.122015 -0.42576,-0.376427 z m 0.61786,-1.882133 q -0.29854,0 -0.4595,0.220664 -0.15836,0.218068 -0.15836,0.630839 0,0.412771 0.15836,0.633435 0.16096,0.218068 0.4595,0.218068 0.29855,0 0.45431,-0.218068 0.15836,-0.218068 0.15836,-0.633435 0,-0.415367 -0.15836,-0.633435 -0.15576,-0.218068 -0.45431,-0.218068 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7284" />
+ <path
+ d="m 126.70223,-82.323939 v 0.264797 h -2.17289 q 0.0337,0.327101 0.23624,0.490652 0.20249,0.163551 0.56594,0.163551 0.29335,0 0.59969,-0.08567 0.30892,-0.08826 0.63343,-0.264796 v 0.716508 q -0.3297,0.12461 -0.6594,0.186915 -0.32969,0.0649 -0.65939,0.0649 -0.7892,0 -1.22793,-0.399791 -0.43614,-0.402387 -0.43614,-1.126684 0,-0.711316 0.42835,-1.118895 0.43095,-0.407579 1.1838,-0.407579 0.68535,0 1.09553,0.412771 0.41277,0.412771 0.41277,1.103319 z m -0.95534,-0.308929 q 0,-0.264797 -0.15577,-0.425752 -0.15316,-0.163551 -0.40238,-0.163551 -0.26999,0 -0.43874,0.153167 -0.16874,0.150571 -0.21027,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7286" />
+ <path
+ d="m 129.56567,-82.978142 q -0.12202,-0.05711 -0.24403,-0.08307 -0.11942,-0.02856 -0.24143,-0.02856 -0.35826,0 -0.55296,0.231048 -0.19211,0.228452 -0.19211,0.656799 v 1.339559 h -0.92938 v -2.90757 h 0.92938 v 0.477672 q 0.17913,-0.285565 0.41018,-0.415367 0.23364,-0.132398 0.55815,-0.132398 0.0467,0 0.10124,0.0052 0.0545,0.0026 0.15836,0.01558 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7288" />
+ <path
+ d="m 131.33098,-82.170772 q -0.29076,0 -0.43873,0.09865 -0.14538,0.09865 -0.14538,0.290757 0,0.176531 0.11682,0.277777 0.11942,0.09865 0.3297,0.09865 0.2622,0 0.44133,-0.186915 0.17912,-0.189512 0.17912,-0.472481 v -0.106437 z m 1.42004,-0.350466 v 1.658872 h -0.93718 v -0.430943 q -0.18691,0.264796 -0.42056,0.386811 -0.23364,0.119418 -0.56853,0.119418 -0.45171,0 -0.73468,-0.262201 -0.28037,-0.264797 -0.28037,-0.685356 0,-0.511421 0.35046,-0.750257 0.35307,-0.238836 1.10592,-0.238836 h 0.54776 v -0.07269 q 0,-0.220664 -0.17393,-0.32191 -0.17394,-0.103842 -0.54257,-0.103842 -0.29855,0 -0.55556,0.05971 -0.25701,0.05971 -0.47767,0.179128 v -0.708721 q 0.29854,-0.07269 0.59969,-0.109034 0.30114,-0.03894 0.60228,-0.03894 0.7866,0 1.13447,0.311525 0.35047,0.308929 0.35047,1.007266 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7290" />
+ <path
+ d="m 134.63055,-84.595478 v 0.825542 h 0.95794 v 0.664587 h -0.95794 v 1.233122 q 0,0.202491 0.0805,0.275181 0.0805,0.07009 0.31931,0.07009 h 0.47768 v 0.664587 h -0.79699 q -0.55036,0 -0.78141,-0.228452 -0.22845,-0.231048 -0.22845,-0.781409 v -1.233122 h -0.4621 v -0.664587 h 0.4621 v -0.825542 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7292" />
+ <path
+ d="m 136.15703,-83.769936 h 0.92938 v 2.90757 h -0.92938 z m 0,-1.131876 h 0.92938 v 0.758046 h -0.92938 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7294" />
+ <path
+ d="m 139.36314,-83.175442 q -0.30893,0 -0.47248,0.22326 -0.16095,0.220664 -0.16095,0.638627 0,0.417963 0.16095,0.641223 0.16355,0.220664 0.47248,0.220664 0.30374,0 0.4647,-0.220664 0.16095,-0.22326 0.16095,-0.641223 0,-0.417963 -0.16095,-0.638627 -0.16096,-0.22326 -0.4647,-0.22326 z m 0,-0.664587 q 0.75026,0 1.17082,0.404983 0.42316,0.404983 0.42316,1.121491 0,0.716509 -0.42316,1.121492 -0.42056,0.404983 -1.17082,0.404983 -0.75285,0 -1.1786,-0.404983 -0.42316,-0.404983 -0.42316,-1.121492 0,-0.716508 0.42316,-1.121491 0.42575,-0.404983 1.1786,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7296" />
+ <path
+ d="m 144.55523,-82.632868 v 1.770502 h -0.93457 v -0.288161 -1.066974 q 0,-0.376427 -0.0182,-0.519209 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14797,-0.140186 -0.0935,-0.05192 -0.21288,-0.05192 -0.29076,0 -0.4569,0.225856 -0.16615,0.22326 -0.16615,0.620455 v 1.43042 h -0.92938 v -2.90757 h 0.92938 v 0.425751 q 0.21028,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.5218,-0.122014 0.50364,0 0.76324,0.308929 0.2622,0.308929 0.2622,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7298" />
+ <path
+ d="m 147.00849,-83.769936 h 0.90343 l 0.48805,2.004147 0.49066,-2.004147 h 0.77621 l 0.48806,1.983378 0.49065,-1.983378 h 0.90343 l -0.76584,2.90757 h -1.01505 l -0.49065,-1.998954 -0.48806,1.998954 h -1.01505 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7300" />
+ <path
+ d="m 152.17982,-83.769936 h 0.92938 v 2.90757 h -0.92938 z m 0,-1.131876 h 0.92938 v 0.758046 h -0.92938 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7302" />
+ <path
+ d="m 155.01729,-84.595478 v 0.825542 h 0.95795 v 0.664587 h -0.95795 v 1.233122 q 0,0.202491 0.0805,0.275181 0.0805,0.07009 0.31932,0.07009 h 0.47767 v 0.664587 h -0.79699 q -0.55036,0 -0.78141,-0.228452 -0.22845,-0.231048 -0.22845,-0.781409 v -1.233122 h -0.4621 v -0.664587 h 0.4621 v -0.825542 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7304" />
+ <path
+ d="m 159.46691,-82.632868 v 1.770502 h -0.93458 v -0.288161 -1.061782 q 0,-0.381619 -0.0182,-0.524401 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14798,-0.140186 -0.0934,-0.05192 -0.21287,-0.05192 -0.29076,0 -0.45691,0.225856 -0.16614,0.22326 -0.16614,0.620455 v 1.43042 h -0.92939 v -4.039446 h 0.92939 v 1.557627 q 0.21028,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.5218,-0.122014 0.50364,0 0.76324,0.308929 0.2622,0.308929 0.2622,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7306" />
+ <path
+ d="m 163.19483,-84.595478 v 0.825542 h 0.95794 v 0.664587 h -0.95794 v 1.233122 q 0,0.202491 0.0805,0.275181 0.0805,0.07009 0.31932,0.07009 h 0.47767 v 0.664587 h -0.79699 q -0.55036,0 -0.78141,-0.228452 -0.22845,-0.231048 -0.22845,-0.781409 v -1.233122 h -0.4621 v -0.664587 h 0.4621 v -0.825542 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7308" />
+ <path
+ d="m 167.64445,-82.632868 v 1.770502 h -0.93457 v -0.288161 -1.061782 q 0,-0.381619 -0.0182,-0.524401 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14797,-0.140186 -0.0935,-0.05192 -0.21288,-0.05192 -0.29075,0 -0.4569,0.225856 -0.16615,0.22326 -0.16615,0.620455 v 1.43042 h -0.92938 v -4.039446 h 0.92938 v 1.557627 q 0.21028,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.52181,-0.122014 0.50363,0 0.76323,0.308929 0.2622,0.308929 0.2622,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7310" />
+ <path
+ d="m 171.40872,-82.323939 v 0.264797 h -2.17289 q 0.0337,0.327101 0.23624,0.490652 0.20249,0.163551 0.56594,0.163551 0.29335,0 0.59968,-0.08567 0.30893,-0.08826 0.63344,-0.264796 v 0.716508 q -0.3297,0.12461 -0.6594,0.186915 -0.32969,0.0649 -0.65939,0.0649 -0.7892,0 -1.22793,-0.399791 -0.43614,-0.402387 -0.43614,-1.126684 0,-0.711316 0.42835,-1.118895 0.43094,-0.407579 1.1838,-0.407579 0.68535,0 1.09553,0.412771 0.41277,0.412771 0.41277,1.103319 z m -0.95534,-0.308929 q 0,-0.264797 -0.15577,-0.425752 -0.15316,-0.163551 -0.40238,-0.163551 -0.26999,0 -0.43874,0.153167 -0.16874,0.150571 -0.21028,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7312" />
+ <path
+ d="m 174.38378,-83.679074 v 0.706124 q -0.29854,-0.12461 -0.57632,-0.186915 -0.27777,-0.06231 -0.5244,-0.06231 -0.26479,0 -0.3946,0.0675 -0.1272,0.0649 -0.1272,0.202491 0,0.11163 0.0961,0.171339 0.0986,0.05971 0.35047,0.08827 l 0.16355,0.02336 q 0.71391,0.09086 0.96053,0.298545 0.24663,0.207684 0.24663,0.651607 0,0.464692 -0.34268,0.698337 -0.34268,0.233644 -1.02284,0.233644 -0.28816,0 -0.59709,-0.04673 -0.30634,-0.04413 -0.63084,-0.134995 v -0.706124 q 0.27778,0.134995 0.56853,0.202492 0.29336,0.0675 0.5945,0.0675 0.27258,0 0.41017,-0.07529 0.13759,-0.07529 0.13759,-0.22326 0,-0.12461 -0.096,-0.184319 -0.0935,-0.06231 -0.37643,-0.09605 l -0.16355,-0.02077 q -0.62045,-0.07788 -0.86967,-0.288161 -0.24922,-0.21028 -0.24922,-0.638628 0,-0.462096 0.31671,-0.685355 0.31672,-0.22326 0.97092,-0.22326 0.25701,0 0.53998,0.03894 0.28297,0.03894 0.61526,0.122015 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7314" />
+ <path
+ d="m 178.1792,-82.323939 v 0.264797 h -2.17288 q 0.0337,0.327101 0.23624,0.490652 0.20249,0.163551 0.56593,0.163551 0.29336,0 0.59969,-0.08567 0.30893,-0.08826 0.63343,-0.264796 v 0.716508 q -0.32969,0.12461 -0.65939,0.186915 -0.3297,0.0649 -0.6594,0.0649 -0.78919,0 -1.22793,-0.399791 -0.43613,-0.402387 -0.43613,-1.126684 0,-0.711316 0.42835,-1.118895 0.43094,-0.407579 1.18379,-0.407579 0.68536,0 1.09553,0.412771 0.41277,0.412771 0.41277,1.103319 z m -0.95534,-0.308929 q 0,-0.264797 -0.15576,-0.425752 -0.15317,-0.163551 -0.40239,-0.163551 -0.26999,0 -0.43873,0.153167 -0.16874,0.150571 -0.21028,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7316" />
+ <path
+ d="m 182.7119,-83.344185 v -1.557627 h 0.93458 v 4.039446 h -0.93458 v -0.420559 q -0.19211,0.257008 -0.42316,0.376427 -0.23104,0.119418 -0.53478,0.119418 -0.53738,0 -0.88266,-0.425752 -0.34527,-0.428347 -0.34527,-1.100723 0,-0.672375 0.34527,-1.098127 0.34528,-0.428347 0.88266,-0.428347 0.30114,0 0.53219,0.122014 0.23364,0.119418 0.42575,0.37383 z m -0.61267,1.882133 q 0.29855,0 0.45431,-0.218068 0.15836,-0.218068 0.15836,-0.633435 0,-0.415367 -0.15836,-0.633435 -0.15576,-0.218068 -0.45431,-0.218068 -0.29595,0 -0.45431,0.218068 -0.15576,0.218068 -0.15576,0.633435 0,0.415367 0.15576,0.633435 0.15836,0.218068 0.45431,0.218068 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7318" />
+ <path
+ d="m 187.44189,-82.323939 v 0.264797 H 185.269 q 0.0337,0.327101 0.23624,0.490652 0.20249,0.163551 0.56594,0.163551 0.29335,0 0.59969,-0.08567 0.30893,-0.08826 0.63343,-0.264796 v 0.716508 q -0.3297,0.12461 -0.65939,0.186915 -0.3297,0.0649 -0.6594,0.0649 -0.7892,0 -1.22793,-0.399791 -0.43613,-0.402387 -0.43613,-1.126684 0,-0.711316 0.42834,-1.118895 0.43095,-0.407579 1.1838,-0.407579 0.68536,0 1.09553,0.412771 0.41277,0.412771 0.41277,1.103319 z m -0.95534,-0.308929 q 0,-0.264797 -0.15576,-0.425752 -0.15317,-0.163551 -0.40239,-0.163551 -0.26999,0 -0.43873,0.153167 -0.16875,0.150571 -0.21028,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7320" />
+ <path
+ d="m 190.41696,-83.679074 v 0.706124 q -0.29854,-0.12461 -0.57632,-0.186915 -0.27777,-0.06231 -0.5244,-0.06231 -0.26479,0 -0.3946,0.0675 -0.1272,0.0649 -0.1272,0.202491 0,0.11163 0.096,0.171339 0.0986,0.05971 0.35047,0.08827 l 0.16355,0.02336 q 0.71391,0.09086 0.96053,0.298545 0.24663,0.207684 0.24663,0.651607 0,0.464692 -0.34268,0.698337 -0.34268,0.233644 -1.02284,0.233644 -0.28816,0 -0.59709,-0.04673 -0.30633,-0.04413 -0.63084,-0.134995 v -0.706124 q 0.27778,0.134995 0.56853,0.202492 0.29336,0.0675 0.5945,0.0675 0.27258,0 0.41017,-0.07529 0.13759,-0.07529 0.13759,-0.22326 0,-0.12461 -0.096,-0.184319 -0.0935,-0.06231 -0.37643,-0.09605 l -0.16355,-0.02077 q -0.62045,-0.07788 -0.86967,-0.288161 -0.24922,-0.21028 -0.24922,-0.638628 0,-0.462096 0.31671,-0.685355 0.31672,-0.22326 0.97092,-0.22326 0.25701,0 0.53998,0.03894 0.28297,0.03894 0.61526,0.122015 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7322" />
+ <path
+ d="m 193.65942,-83.679074 v 0.758045 q -0.18951,-0.129803 -0.38162,-0.192108 -0.18951,-0.06231 -0.3946,-0.06231 -0.3894,0 -0.60747,0.228452 -0.21547,0.225856 -0.21547,0.633435 0,0.407579 0.21547,0.636031 0.21807,0.225856 0.60747,0.225856 0.21807,0 0.41277,-0.0649 0.1973,-0.0649 0.36345,-0.192107 v 0.760641 q -0.21807,0.08048 -0.44392,0.119418 -0.22326,0.04154 -0.44912,0.04154 -0.7866,0 -1.23052,-0.402387 -0.44393,-0.404983 -0.44393,-1.124088 0,-0.719104 0.44393,-1.121491 0.44392,-0.404983 1.23052,-0.404983 0.22845,0 0.44912,0.04154 0.22326,0.03894 0.44392,0.119419 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7324" />
+ <path
+ d="m 196.62151,-82.978142 q -0.12201,-0.05711 -0.24403,-0.08307 -0.11941,-0.02856 -0.24143,-0.02856 -0.35825,0 -0.55296,0.231048 -0.1921,0.228452 -0.1921,0.656799 v 1.339559 h -0.92939 v -2.90757 h 0.92939 v 0.477672 q 0.17912,-0.285565 0.41017,-0.415367 0.23365,-0.132398 0.55815,-0.132398 0.0467,0 0.10125,0.0052 0.0545,0.0026 0.15836,0.01558 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7326" />
+ <path
+ d="m 197.0836,-83.769936 h 0.92939 v 2.90757 h -0.92939 z m 0,-1.131876 h 0.92939 v 0.758046 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7328" />
+ <path
+ d="m 199.83541,-81.282925 v 1.526474 h -0.92938 v -4.013485 h 0.92938 v 0.425751 q 0.19211,-0.254412 0.42576,-0.37383 0.23364,-0.122014 0.53738,-0.122014 0.53738,0 0.88265,0.428347 0.34528,0.425752 0.34528,1.098127 0,0.672376 -0.34528,1.100723 -0.34527,0.425752 -0.88265,0.425752 -0.30374,0 -0.53738,-0.119418 -0.23365,-0.122015 -0.42576,-0.376427 z m 0.61786,-1.882133 q -0.29854,0 -0.4595,0.220664 -0.15836,0.218068 -0.15836,0.630839 0,0.412771 0.15836,0.633435 0.16096,0.218068 0.4595,0.218068 0.29855,0 0.45431,-0.218068 0.15836,-0.218068 0.15836,-0.633435 0,-0.415367 -0.15836,-0.633435 -0.15576,-0.218068 -0.45431,-0.218068 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7330" />
+ <path
+ d="m 203.72689,-84.595478 v 0.825542 h 0.95794 v 0.664587 h -0.95794 v 1.233122 q 0,0.202491 0.0805,0.275181 0.0805,0.07009 0.31932,0.07009 h 0.47767 v 0.664587 h -0.79699 q -0.55036,0 -0.78141,-0.228452 -0.22845,-0.231048 -0.22845,-0.781409 v -1.233122 h -0.46209 v -0.664587 h 0.46209 v -0.825542 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7332" />
+ <path
+ d="m 206.63705,-83.175442 q -0.30893,0 -0.47248,0.22326 -0.16095,0.220664 -0.16095,0.638627 0,0.417963 0.16095,0.641223 0.16355,0.220664 0.47248,0.220664 0.30374,0 0.46469,-0.220664 0.16096,-0.22326 0.16096,-0.641223 0,-0.417963 -0.16096,-0.638627 -0.16095,-0.22326 -0.46469,-0.22326 z m 0,-0.664587 q 0.75026,0 1.17082,0.404983 0.42315,0.404983 0.42315,1.121491 0,0.716509 -0.42315,1.121492 -0.42056,0.404983 -1.17082,0.404983 -0.75285,0 -1.1786,-0.404983 -0.42316,-0.404983 -0.42316,-1.121492 0,-0.716508 0.42316,-1.121491 0.42575,-0.404983 1.1786,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7334" />
+ <path
+ d="m 211.0659,-82.978142 q -0.12201,-0.05711 -0.24403,-0.08307 -0.11941,-0.02856 -0.24143,-0.02856 -0.35825,0 -0.55296,0.231048 -0.1921,0.228452 -0.1921,0.656799 v 1.339559 h -0.92939 v -2.90757 h 0.92939 v 0.477672 q 0.17912,-0.285565 0.41017,-0.415367 0.23365,-0.132398 0.55815,-0.132398 0.0467,0 0.10125,0.0052 0.0545,0.0026 0.15836,0.01558 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7336" />
+ <path
+ d="m 213.79954,-83.679074 v 0.706124 q -0.29854,-0.12461 -0.57632,-0.186915 -0.27778,-0.06231 -0.5244,-0.06231 -0.2648,0 -0.3946,0.0675 -0.12721,0.0649 -0.12721,0.202491 0,0.11163 0.0961,0.171339 0.0987,0.05971 0.35046,0.08827 l 0.16355,0.02336 q 0.71392,0.09086 0.96054,0.298545 0.24662,0.207684 0.24662,0.651607 0,0.464692 -0.34267,0.698337 -0.34268,0.233644 -1.02285,0.233644 -0.28816,0 -0.59709,-0.04673 -0.30633,-0.04413 -0.63083,-0.134995 v -0.706124 q 0.27777,0.134995 0.56853,0.202492 0.29335,0.0675 0.59449,0.0675 0.27259,0 0.41018,-0.07529 0.13759,-0.07529 0.13759,-0.22326 0,-0.12461 -0.0961,-0.184319 -0.0935,-0.06231 -0.37643,-0.09605 l -0.16355,-0.02077 q -0.62046,-0.07788 -0.86968,-0.288161 -0.24922,-0.21028 -0.24922,-0.638628 0,-0.462096 0.31672,-0.685355 0.31672,-0.22326 0.97092,-0.22326 0.25701,0 0.53998,0.03894 0.28297,0.03894 0.61526,0.122015 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7338" />
+ <path
+ d="m 91.795811,-73.515559 h -0.771026 q -0.397194,-0.641223 -0.586706,-1.217545 -0.189511,-0.578918 -0.189511,-1.147452 0,-0.568533 0.189511,-1.150047 0.192108,-0.584111 0.586706,-1.220142 h 0.771026 q -0.332294,0.615263 -0.498441,1.204565 -0.166147,0.586706 -0.166147,1.160432 0,0.573726 0.163551,1.163028 0.166147,0.589303 0.501037,1.207161 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7340" />
+ <path
+ d="m 94.939621,-77.033199 v 0.706124 q -0.298545,-0.12461 -0.576322,-0.186915 -0.277777,-0.06231 -0.524401,-0.06231 -0.264796,0 -0.394599,0.0675 -0.127206,0.0649 -0.127206,0.202491 0,0.11163 0.09605,0.171339 0.09865,0.05971 0.350466,0.08827 l 0.163551,0.02336 q 0.713912,0.09086 0.960536,0.298545 0.246625,0.207684 0.246625,0.651607 0,0.464692 -0.342678,0.698337 -0.342678,0.233644 -1.022842,0.233644 -0.288161,0 -0.59709,-0.04673 -0.306334,-0.04413 -0.630839,-0.134995 v -0.706124 q 0.277776,0.134995 0.568534,0.202492 0.293353,0.0675 0.594494,0.0675 0.272585,0 0.410175,-0.07529 0.13759,-0.07529 0.13759,-0.22326 0,-0.12461 -0.09605,-0.184319 -0.09346,-0.06231 -0.376427,-0.09605 l -0.163551,-0.02077 q -0.620454,-0.07788 -0.869675,-0.28816 -0.24922,-0.21028 -0.24922,-0.638628 0,-0.462096 0.316717,-0.685355 0.316718,-0.22326 0.970921,-0.22326 0.257009,0 0.539978,0.03894 0.282968,0.03894 0.615262,0.122015 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7342" />
+ <path
+ d="m 98.735039,-75.678064 v 0.264797 h -2.17289 q 0.03375,0.327101 0.23624,0.490652 0.202492,0.163551 0.565938,0.163551 0.293353,0 0.599686,-0.08567 0.30893,-0.08826 0.633435,-0.264796 v 0.716508 q -0.329697,0.12461 -0.659395,0.186915 -0.329698,0.0649 -0.659395,0.0649 -0.789198,0 -1.22793,-0.399791 -0.436135,-0.402387 -0.436135,-1.126684 0,-0.711316 0.428347,-1.118895 0.430944,-0.407579 1.183797,-0.407579 0.685356,0 1.095531,0.412771 0.412771,0.412771 0.412771,1.103319 z m -0.955345,-0.308929 q 0,-0.264797 -0.155762,-0.425752 -0.153167,-0.163551 -0.402387,-0.163551 -0.269989,0 -0.438732,0.153167 -0.168743,0.150571 -0.21028,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7344" />
+ <path
+ d="m 100.45362,-77.949603 v 0.825542 h 0.95794 v 0.664587 h -0.95794 v 1.233122 q 0,0.202491 0.0805,0.275181 0.0805,0.07009 0.31931,0.07009 h 0.47767 v 0.664587 h -0.79698 q -0.550364,0 -0.781412,-0.228452 -0.228451,-0.231048 -0.228451,-0.781409 v -1.233122 h -0.462096 v -0.664587 h 0.462096 v -0.825542 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7346" />
+ <path
+ d="m 101.94894,-75.348366 v -1.775695 h 0.93458 v 0.290757 q 0,0.23624 -0.003,0.594494 -0.003,0.355658 -0.003,0.475076 0,0.350467 0.0182,0.506229 0.0182,0.153167 0.0623,0.22326 0.0571,0.09086 0.14798,0.140187 0.0935,0.04932 0.21287,0.04932 0.29076,0 0.45691,-0.223259 0.16614,-0.22326 0.16614,-0.620455 v -1.435613 h 0.92939 v 2.90757 h -0.92939 v -0.420559 q -0.21027,0.254412 -0.44651,0.376426 -0.23365,0.119419 -0.51662,0.119419 -0.50363,0 -0.76843,-0.30893 -0.2622,-0.308929 -0.2622,-0.898231 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7348" />
+ <path
+ d="m 106.69451,-74.63705 v 1.526474 h -0.92938 v -4.013485 h 0.92938 v 0.425751 q 0.19211,-0.254412 0.42575,-0.37383 0.23365,-0.122014 0.53739,-0.122014 0.53738,0 0.88265,0.428347 0.34527,0.425752 0.34527,1.098127 0,0.672376 -0.34527,1.100723 -0.34527,0.425752 -0.88265,0.425752 -0.30374,0 -0.53739,-0.119419 -0.23364,-0.122014 -0.42575,-0.376426 z m 0.61786,-1.882133 q -0.29854,0 -0.4595,0.220664 -0.15836,0.218068 -0.15836,0.630839 0,0.412771 0.15836,0.633435 0.16096,0.218068 0.4595,0.218068 0.29855,0 0.45431,-0.218068 0.15836,-0.218068 0.15836,-0.633435 0,-0.415367 -0.15836,-0.633435 -0.15576,-0.218068 -0.45431,-0.218068 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7350" />
+ <path
+ d="m 109.66698,-75.22116 h 0.93458 v 0.791794 l -0.64122,0.968324 h -0.55296 l 0.2596,-0.968324 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7352" />
+ <path
+ d="m 113.44163,-77.124061 h 0.92939 v 2.90757 h -0.92939 z m 0,-1.131876 h 0.92939 v 0.758045 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7354" />
+ <path
+ d="m 118.1872,-75.986993 v 1.770502 h -0.93457 v -0.288161 -1.066974 q 0,-0.376427 -0.0182,-0.519209 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14797,-0.140186 -0.0935,-0.05192 -0.21288,-0.05192 -0.29076,0 -0.4569,0.225856 -0.16615,0.22326 -0.16615,0.620455 v 1.43042 h -0.92938 v -2.90757 h 0.92938 v 0.425751 q 0.21028,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.52181,-0.122014 0.50363,0 0.76323,0.308929 0.2622,0.308929 0.2622,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7356" />
+ <path
+ d="m 121.97224,-75.986993 v 1.770502 h -0.93458 v -0.288161 -1.066974 q 0,-0.376427 -0.0182,-0.519209 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14798,-0.140186 -0.0935,-0.05192 -0.21287,-0.05192 -0.29076,0 -0.45691,0.225856 -0.16614,0.22326 -0.16614,0.620455 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.425751 q 0.21027,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.5218,-0.122014 0.50363,0 0.76324,0.308929 0.2622,0.308929 0.2622,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7358" />
+ <path
+ d="m 125.7365,-75.678064 v 0.264797 h -2.17289 q 0.0337,0.327101 0.23624,0.490652 0.20249,0.163551 0.56594,0.163551 0.29335,0 0.59969,-0.08567 0.30893,-0.08826 0.63343,-0.264796 v 0.716508 q -0.3297,0.12461 -0.65939,0.186915 -0.3297,0.0649 -0.6594,0.0649 -0.7892,0 -1.22793,-0.399791 -0.43613,-0.402387 -0.43613,-1.126684 0,-0.711316 0.42834,-1.118895 0.43095,-0.407579 1.1838,-0.407579 0.68536,0 1.09553,0.412771 0.41277,0.412771 0.41277,1.103319 z m -0.95534,-0.308929 q 0,-0.264797 -0.15577,-0.425752 -0.15316,-0.163551 -0.40238,-0.163551 -0.26999,0 -0.43873,0.153167 -0.16875,0.150571 -0.21028,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7360" />
+ <path
+ d="m 128.59994,-76.332267 q -0.12201,-0.05711 -0.24403,-0.08307 -0.11942,-0.02856 -0.24143,-0.02856 -0.35825,0 -0.55296,0.231048 -0.1921,0.228452 -0.1921,0.656799 v 1.339559 h -0.92939 v -2.90757 h 0.92939 v 0.477672 q 0.17912,-0.285565 0.41017,-0.415367 0.23364,-0.132398 0.55815,-0.132398 0.0467,0 0.10125,0.0052 0.0545,0.0026 0.15835,0.01558 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7362" />
+ <path
+ d="m 128.90368,-76.124584 h 1.63031 v 0.755449 h -1.63031 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7364" />
+ <path
+ d="m 131.26867,-78.255937 h 0.92939 v 4.039446 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7366" />
+ <path
+ d="m 134.47479,-76.529567 q -0.30893,0 -0.47248,0.22326 -0.16096,0.220664 -0.16096,0.638627 0,0.417963 0.16096,0.641223 0.16355,0.220664 0.47248,0.220664 0.30374,0 0.46469,-0.220664 0.16096,-0.22326 0.16096,-0.641223 0,-0.417963 -0.16096,-0.638627 -0.16095,-0.22326 -0.46469,-0.22326 z m 0,-0.664587 q 0.75026,0 1.17081,0.404983 0.42316,0.404983 0.42316,1.121491 0,0.716509 -0.42316,1.121492 -0.42055,0.404983 -1.17081,0.404983 -0.75285,0 -1.17861,-0.404983 -0.42315,-0.404983 -0.42315,-1.121492 0,-0.716508 0.42315,-1.121491 0.42576,-0.404983 1.17861,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7368" />
+ <path
+ d="m 138.12743,-76.529567 q -0.30893,0 -0.47248,0.22326 -0.16096,0.220664 -0.16096,0.638627 0,0.417963 0.16096,0.641223 0.16355,0.220664 0.47248,0.220664 0.30373,0 0.46469,-0.220664 0.16095,-0.22326 0.16095,-0.641223 0,-0.417963 -0.16095,-0.638627 -0.16096,-0.22326 -0.46469,-0.22326 z m 0,-0.664587 q 0.75025,0 1.17081,0.404983 0.42316,0.404983 0.42316,1.121491 0,0.716509 -0.42316,1.121492 -0.42056,0.404983 -1.17081,0.404983 -0.75286,0 -1.17861,-0.404983 -0.42315,-0.404983 -0.42315,-1.121492 0,-0.716508 0.42315,-1.121491 0.42575,-0.404983 1.17861,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7370" />
+ <path
+ d="m 141.32575,-74.63705 v 1.526474 h -0.92938 v -4.013485 h 0.92938 v 0.425751 q 0.19211,-0.254412 0.42575,-0.37383 0.23365,-0.122014 0.53738,-0.122014 0.53739,0 0.88266,0.428347 0.34527,0.425752 0.34527,1.098127 0,0.672376 -0.34527,1.100723 -0.34527,0.425752 -0.88266,0.425752 -0.30373,0 -0.53738,-0.119419 -0.23364,-0.122014 -0.42575,-0.376426 z m 0.61786,-1.882133 q -0.29854,0 -0.4595,0.220664 -0.15836,0.218068 -0.15836,0.630839 0,0.412771 0.15836,0.633435 0.16096,0.218068 0.4595,0.218068 0.29855,0 0.45431,-0.218068 0.15836,-0.218068 0.15836,-0.633435 0,-0.415367 -0.15836,-0.633435 -0.15576,-0.218068 -0.45431,-0.218068 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7372" />
+ <path
+ d="m 147.96643,-78.255937 v 0.610071 h -0.51401 q -0.1973,0 -0.27518,0.07269 -0.0779,0.07009 -0.0779,0.246624 v 0.202492 h 0.79439 v 0.664587 h -0.79439 v 2.242983 h -0.92938 v -2.242983 h -0.4621 v -0.664587 h 0.4621 v -0.202492 q 0,-0.475076 0.2648,-0.700932 0.26479,-0.228452 0.82035,-0.228452 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7374" />
+ <path
+ d="m 148.33507,-75.348366 v -1.775695 h 0.93458 v 0.290757 q 0,0.23624 -0.003,0.594494 -0.003,0.355658 -0.003,0.475076 0,0.350467 0.0182,0.506229 0.0182,0.153167 0.0623,0.22326 0.0571,0.09086 0.14798,0.140187 0.0935,0.04932 0.21287,0.04932 0.29076,0 0.45691,-0.223259 0.16614,-0.22326 0.16614,-0.620455 v -1.435613 h 0.92939 v 2.90757 h -0.92939 v -0.420559 q -0.21028,0.254412 -0.44652,0.376426 -0.23364,0.119419 -0.51661,0.119419 -0.50363,0 -0.76843,-0.30893 -0.2622,-0.308929 -0.2622,-0.898231 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7376" />
+ <path
+ d="m 155.0744,-75.986993 v 1.770502 h -0.93457 v -0.288161 -1.066974 q 0,-0.376427 -0.0182,-0.519209 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14797,-0.140186 -0.0935,-0.05192 -0.21288,-0.05192 -0.29075,0 -0.4569,0.225856 -0.16615,0.22326 -0.16615,0.620455 v 1.43042 h -0.92938 v -2.90757 h 0.92938 v 0.425751 q 0.21028,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.52181,-0.122014 0.50363,0 0.76323,0.308929 0.2622,0.308929 0.2622,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7378" />
+ <path
+ d="m 158.28571,-77.033199 v 0.758045 q -0.18951,-0.129803 -0.38162,-0.192108 -0.18951,-0.0623 -0.3946,-0.0623 -0.3894,0 -0.60747,0.228452 -0.21547,0.225856 -0.21547,0.633435 0,0.407579 0.21547,0.636031 0.21807,0.225856 0.60747,0.225856 0.21807,0 0.41277,-0.0649 0.1973,-0.0649 0.36345,-0.192107 v 0.760641 q -0.21807,0.08048 -0.44392,0.119418 -0.22326,0.04154 -0.44912,0.04154 -0.7866,0 -1.23053,-0.402387 -0.44392,-0.404983 -0.44392,-1.124088 0,-0.719104 0.44392,-1.121491 0.44393,-0.404983 1.23053,-0.404983 0.22845,0 0.44912,0.04154 0.22326,0.03894 0.44392,0.119419 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7380" />
+ <path
+ d="m 160.10295,-77.949603 v 0.825542 h 0.95794 v 0.664587 h -0.95794 v 1.233122 q 0,0.202491 0.0805,0.275181 0.0805,0.07009 0.31932,0.07009 h 0.47767 v 0.664587 h -0.79699 q -0.55036,0 -0.78141,-0.228452 -0.22845,-0.231048 -0.22845,-0.781409 v -1.233122 h -0.46209 v -0.664587 h 0.46209 v -0.825542 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7382" />
+ <path
+ d="m 161.62942,-77.124061 h 0.92938 v 2.90757 h -0.92938 z m 0,-1.131876 h 0.92938 v 0.758045 h -0.92938 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7384" />
+ <path
+ d="m 164.83554,-76.529567 q -0.30893,0 -0.47248,0.22326 -0.16096,0.220664 -0.16096,0.638627 0,0.417963 0.16096,0.641223 0.16355,0.220664 0.47248,0.220664 0.30373,0 0.46469,-0.220664 0.16095,-0.22326 0.16095,-0.641223 0,-0.417963 -0.16095,-0.638627 -0.16096,-0.22326 -0.46469,-0.22326 z m 0,-0.664587 q 0.75025,0 1.17081,0.404983 0.42316,0.404983 0.42316,1.121491 0,0.716509 -0.42316,1.121492 -0.42056,0.404983 -1.17081,0.404983 -0.75286,0 -1.17861,-0.404983 -0.42315,-0.404983 -0.42315,-1.121492 0,-0.716508 0.42315,-1.121491 0.42575,-0.404983 1.17861,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7386" />
+ <path
+ d="m 170.02763,-75.986993 v 1.770502 h -0.93458 v -0.288161 -1.066974 q 0,-0.376427 -0.0182,-0.519209 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14797,-0.140186 -0.0935,-0.05192 -0.21288,-0.05192 -0.29075,0 -0.4569,0.225856 -0.16615,0.22326 -0.16615,0.620455 v 1.43042 h -0.92938 v -2.90757 h 0.92938 v 0.425751 q 0.21028,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.52181,-0.122014 0.50363,0 0.76323,0.308929 0.26221,0.308929 0.26221,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7388" />
+ <path
+ d="m 170.98557,-75.22116 h 0.93457 v 0.791794 l -0.64122,0.968324 h -0.55296 l 0.25961,-0.968324 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7390" />
+ <path
+ d="m 175.77527,-77.949603 v 0.825542 h 0.95794 v 0.664587 h -0.95794 v 1.233122 q 0,0.202491 0.0805,0.275181 0.0805,0.07009 0.31931,0.07009 h 0.47767 v 0.664587 h -0.79698 q -0.55036,0 -0.78141,-0.228452 -0.22845,-0.231048 -0.22845,-0.781409 v -1.233122 h -0.4621 v -0.664587 h 0.4621 v -0.825542 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7392" />
+ <path
+ d="m 180.20412,-75.678064 v 0.264797 h -2.17289 q 0.0337,0.327101 0.23624,0.490652 0.20249,0.163551 0.56594,0.163551 0.29335,0 0.59969,-0.08567 0.30893,-0.08826 0.63343,-0.264796 v 0.716508 q -0.3297,0.12461 -0.65939,0.186915 -0.3297,0.0649 -0.6594,0.0649 -0.7892,0 -1.22793,-0.399791 -0.43613,-0.402387 -0.43613,-1.126684 0,-0.711316 0.42834,-1.118895 0.43095,-0.407579 1.1838,-0.407579 0.68536,0 1.09553,0.412771 0.41277,0.412771 0.41277,1.103319 z m -0.95534,-0.308929 q 0,-0.264797 -0.15576,-0.425752 -0.15317,-0.163551 -0.40239,-0.163551 -0.26999,0 -0.43873,0.153167 -0.16875,0.150571 -0.21028,0.436136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7394" />
+ <path
+ d="m 182.21086,-75.524897 q -0.29075,0 -0.43873,0.09865 -0.14538,0.09865 -0.14538,0.290757 0,0.176531 0.11682,0.277777 0.11942,0.09865 0.3297,0.09865 0.2622,0 0.44133,-0.186915 0.17913,-0.189512 0.17913,-0.472481 v -0.106437 z m 1.42004,-0.350466 v 1.658872 h -0.93717 v -0.430943 q -0.18692,0.264796 -0.42056,0.38681 -0.23365,0.119419 -0.56854,0.119419 -0.45171,0 -0.73468,-0.262201 -0.28037,-0.264797 -0.28037,-0.685356 0,-0.511421 0.35047,-0.750257 0.35306,-0.238836 1.10591,-0.238836 h 0.54777 v -0.07269 q 0,-0.220664 -0.17394,-0.32191 -0.17393,-0.103842 -0.54257,-0.103842 -0.29855,0 -0.55556,0.05971 -0.257,0.05971 -0.47767,0.179128 v -0.708721 q 0.29855,-0.07269 0.59969,-0.109034 0.30114,-0.03894 0.60228,-0.03894 0.7866,0 1.13447,0.311525 0.35047,0.308929 0.35047,1.007266 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7396" />
+ <path
+ d="m 186.6553,-76.332267 q -0.12202,-0.05711 -0.24403,-0.08307 -0.11942,-0.02856 -0.24144,-0.02856 -0.35825,0 -0.55295,0.231048 -0.19211,0.228452 -0.19211,0.656799 v 1.339559 h -0.92938 v -2.90757 h 0.92938 v 0.477672 q 0.17913,-0.285565 0.41018,-0.415367 0.23364,-0.132398 0.55814,-0.132398 0.0467,0 0.10125,0.0052 0.0545,0.0026 0.15836,0.01558 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7398" />
+ <path
+ d="m 189.09557,-76.69831 v -1.557627 h 0.93458 v 4.039446 h -0.93458 v -0.420559 q -0.1921,0.257008 -0.42315,0.376426 -0.23105,0.119419 -0.53479,0.119419 -0.53738,0 -0.88265,-0.425752 -0.34528,-0.428347 -0.34528,-1.100723 0,-0.672375 0.34528,-1.098127 0.34527,-0.428347 0.88265,-0.428347 0.30114,0 0.53219,0.122014 0.23365,0.119418 0.42575,0.37383 z m -0.61266,1.882133 q 0.29854,0 0.45431,-0.218068 0.15835,-0.218068 0.15835,-0.633435 0,-0.415367 -0.15835,-0.633435 -0.15577,-0.218068 -0.45431,-0.218068 -0.29595,0 -0.45431,0.218068 -0.15576,0.218068 -0.15576,0.633435 0,0.415367 0.15576,0.633435 0.15836,0.218068 0.45431,0.218068 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7400" />
+ <path
+ d="m 192.30688,-76.529567 q -0.30893,0 -0.47248,0.22326 -0.16095,0.220664 -0.16095,0.638627 0,0.417963 0.16095,0.641223 0.16355,0.220664 0.47248,0.220664 0.30374,0 0.46469,-0.220664 0.16096,-0.22326 0.16096,-0.641223 0,-0.417963 -0.16096,-0.638627 -0.16095,-0.22326 -0.46469,-0.22326 z m 0,-0.664587 q 0.75026,0 1.17082,0.404983 0.42315,0.404983 0.42315,1.121491 0,0.716509 -0.42315,1.121492 -0.42056,0.404983 -1.17082,0.404983 -0.75285,0 -1.1786,-0.404983 -0.42316,-0.404983 -0.42316,-1.121492 0,-0.716508 0.42316,-1.121491 0.42575,-0.404983 1.1786,-0.404983 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7402" />
+ <path
+ d="m 194.31622,-77.124061 h 0.90342 l 0.48806,2.004147 0.49065,-2.004147 h 0.77622 l 0.48805,1.983378 0.49066,-1.983378 h 0.90342 l -0.76583,2.90757 h -1.01506 l -0.49065,-1.998954 -0.48805,1.998954 h -1.01506 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7404" />
+ <path
+ d="m 202.41069,-75.986993 v 1.770502 h -0.93458 v -0.288161 -1.066974 q 0,-0.376427 -0.0182,-0.519209 -0.0156,-0.142783 -0.0571,-0.21028 -0.0545,-0.09086 -0.14798,-0.140186 -0.0934,-0.05192 -0.21287,-0.05192 -0.29076,0 -0.45691,0.225856 -0.16614,0.22326 -0.16614,0.620455 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.425751 q 0.21028,-0.254412 0.44652,-0.37383 0.23624,-0.122014 0.5218,-0.122014 0.50363,0 0.76324,0.308929 0.2622,0.308929 0.2622,0.898232 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7406" />
+ <path
+ d="m 203.25181,-73.515559 q 0.33229,-0.617858 0.49844,-1.207161 0.16615,-0.589302 0.16615,-1.163028 0,-0.573726 -0.16615,-1.160432 -0.16615,-0.589302 -0.49844,-1.204565 h 0.77102 q 0.3946,0.636031 0.58411,1.220142 0.19211,0.581514 0.19211,1.150047 0,0.568534 -0.18951,1.147452 -0.18951,0.576322 -0.58671,1.217545 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7408" />
+ </g>
+ <g
+ aria-label="NumPy"
+ transform="scale(-1)"
+ id="text7580"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 256.86208,-298.97457 h 2.22208 l 2.80602,5.29165 v -5.29165 h 1.88618 v 7.71526 h -2.22208 l -2.80602,-5.29165 v 5.29165 h -1.88618 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7495" />
+ <path
+ d="m 265.5747,-293.51239 v -3.53466 h 1.86034 v 0.57877 q 0,0.47026 -0.005,1.18339 -0.005,0.70797 -0.005,0.94568 0,0.69763 0.0362,1.00768 0.0362,0.30489 0.12402,0.44442 0.11369,0.18087 0.29456,0.27905 0.18603,0.0982 0.42374,0.0982 0.57878,0 0.90951,-0.44442 0.33072,-0.44442 0.33072,-1.23506 v -2.8577 h 1.85001 v 5.78774 h -1.85001 v -0.83715 q -0.41857,0.50642 -0.88883,0.7493 -0.46508,0.23771 -1.02836,0.23771 -1.00252,0 -1.52961,-0.61494 -0.52193,-0.61495 -0.52193,-1.788 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7497" />
+ <path
+ d="m 278.5351,-296.08587 q 0.3514,-0.53743 0.83199,-0.81649 0.48576,-0.28422 1.06453,-0.28422 0.99736,0 1.51929,0.61495 0.52193,0.61495 0.52193,1.788 v 3.52432 h -1.86035 v -3.01789 q 0.005,-0.0672 0.005,-0.13953 0.005,-0.0723 0.005,-0.2067 0,-0.61495 -0.18087,-0.88883 -0.18087,-0.27906 -0.58394,-0.27906 -0.5271,0 -0.81649,0.43408 -0.28422,0.43408 -0.29455,1.25574 v 2.84219 h -1.86035 v -3.01789 q 0,-0.96118 -0.16536,-1.23506 -0.16537,-0.27906 -0.58911,-0.27906 -0.53227,0 -0.82165,0.43925 -0.28939,0.43408 -0.28939,1.2454 v 2.84736 h -1.86035 v -5.78774 h 1.86035 v 0.84749 q 0.34106,-0.49092 0.78031,-0.73897 0.44442,-0.24805 0.97668,-0.24805 0.59945,0 1.05936,0.28939 0.45992,0.28939 0.69763,0.81132 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7499" />
+ <path
+ d="m 284.28151,-298.97457 h 3.30211 q 1.47277,0 2.25825,0.65628 0.79065,0.65112 0.79065,1.86035 0,1.21439 -0.79065,1.87068 -0.78548,0.65112 -2.25825,0.65112 h -1.31258 v 2.67683 h -1.98953 z m 1.98953,1.44176 v 2.1549 h 1.10071 q 0.57877,0 0.894,-0.27905 0.31522,-0.28422 0.31522,-0.80098 0,-0.51676 -0.31522,-0.79581 -0.31523,-0.27906 -0.894,-0.27906 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7501" />
+ <path
+ d="m 291.39216,-297.04705 h 1.85001 l 1.55546,3.9274 1.32291,-3.9274 h 1.85001 l -2.43395,6.33551 q -0.3669,0.96635 -0.85783,1.34875 -0.48576,0.38757 -1.28674,0.38757 h -1.0697 v -1.21439 h 0.57878 q 0.47025,0 0.68212,-0.14986 0.21704,-0.14986 0.3359,-0.53743 l 0.0517,-0.1602 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7503" />
+ </g>
+ <g
+ aria-label="Registered or default"
+ transform="scale(-1)"
+ id="text1141"
+ style="font-size:5.3167px;line-height:1.65;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 22.811873,-215.97443 q 0.168743,0.0571 0.327102,0.24403 0.160955,0.18692 0.321909,0.51402 l 0.53219,1.05918 h -0.563342 l -0.495845,-0.99428 q -0.192107,-0.38941 -0.37383,-0.51661 -0.179127,-0.12721 -0.490653,-0.12721 h -0.57113 v 1.6381 h -0.524401 v -3.87589 h 1.183797 q 0.664587,0 0.991689,0.27778 0.327102,0.27777 0.327102,0.83852 0,0.36604 -0.171339,0.60747 -0.168743,0.24143 -0.493249,0.33489 z m -1.313599,-1.62772 v 1.37591 h 0.659396 q 0.379022,0 0.57113,-0.17394 0.194703,-0.17653 0.194703,-0.51661 0,-0.34008 -0.194703,-0.51142 -0.192108,-0.17394 -0.57113,-0.17394 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7590" />
+ <path
+ d="m 26.895452,-215.7304 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267392,0.25701 0.742469,0.25701 0.27518,0 0.532189,-0.0675 0.259604,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257009,0.10903 -0.526997,0.16615 -0.269989,0.0571 -0.547766,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40499 -0.404983,-1.09553 0,-0.71392 0.384215,-1.13188 0.38681,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477673,-0.14019 q -0.0052,-0.392 -0.220663,-0.62564 -0.212876,-0.23365 -0.565938,-0.23365 -0.399791,0 -0.641223,0.22586 -0.238836,0.22586 -0.275181,0.63603 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7592" />
+ <path
+ d="m 29.592742,-215.64473 q 0,-0.51921 -0.215471,-0.80477 -0.212876,-0.28557 -0.599687,-0.28557 -0.384214,0 -0.599686,0.28557 -0.212876,0.28556 -0.212876,0.80477 0,0.51661 0.212876,0.80218 0.215472,0.28556 0.599686,0.28556 0.386811,0 0.599687,-0.28556 0.215471,-0.28557 0.215471,-0.80218 z m 0.477673,1.12668 q 0,0.74247 -0.329698,1.10332 -0.329698,0.36345 -1.009862,0.36345 -0.251816,0 -0.475076,-0.0389 -0.22326,-0.0363 -0.433539,-0.11423 v -0.46469 q 0.210279,0.11423 0.415367,0.16874 0.205087,0.0545 0.417963,0.0545 0.469884,0 0.703528,-0.24662 0.233644,-0.24403 0.233644,-0.73988 v -0.23624 q -0.147974,0.25701 -0.379022,0.38422 -0.231048,0.1272 -0.552958,0.1272 -0.534785,0 -0.861887,-0.40758 -0.327101,-0.40757 -0.327101,-1.07995 0,-0.67497 0.327101,-1.08255 0.327102,-0.40758 0.861887,-0.40758 0.32191,0 0.552958,0.12721 0.231048,0.1272 0.379022,0.38421 v -0.44133 h 0.477673 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7594" />
+ <path
+ d="m 31.054316,-217.06477 h 0.477672 v 2.90757 h -0.477672 z m 0,-1.13187 h 0.477672 v 0.60488 h -0.477672 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7596" />
+ <path
+ d="m 34.385042,-216.9791 v 0.45171 q -0.202492,-0.10384 -0.42056,-0.15576 -0.218067,-0.0519 -0.451711,-0.0519 -0.355659,0 -0.534786,0.10904 -0.176531,0.10903 -0.176531,0.3271 0,0.16614 0.127206,0.2622 0.127207,0.0935 0.511421,0.17912 l 0.163551,0.0363 q 0.508825,0.10903 0.721701,0.30893 0.215471,0.1973 0.215471,0.55296 0,0.40498 -0.321909,0.64122 -0.319314,0.23624 -0.880059,0.23624 -0.233645,0 -0.488057,-0.0467 -0.251816,-0.0441 -0.532189,-0.13499 v -0.49325 q 0.264796,0.13759 0.521805,0.20768 0.257008,0.0675 0.508825,0.0675 0.337486,0 0.519209,-0.11423 0.181723,-0.11682 0.181723,-0.3271 0,-0.1947 -0.132398,-0.29854 -0.129803,-0.10385 -0.573726,-0.1999 l -0.166147,-0.0389 q -0.443924,-0.0935 -0.641223,-0.28557 -0.1973,-0.1947 -0.1973,-0.53218 0,-0.41018 0.290757,-0.63344 0.290757,-0.22326 0.825543,-0.22326 0.264796,0 0.49844,0.0389 0.233644,0.0389 0.430944,0.11682 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7598" />
+ <path
+ d="m 35.773925,-217.89031 v 0.82554 h 0.983901 v 0.37124 h -0.983901 v 1.57839 q 0,0.35566 0.09605,0.45691 0.09865,0.10124 0.397195,0.10124 h 0.490652 v 0.39979 h -0.490652 q -0.552958,0 -0.763237,-0.20508 -0.21028,-0.20769 -0.21028,-0.75286 v -1.57839 h -0.350466 v -0.37124 h 0.350466 v -0.82554 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7600" />
+ <path
+ d="m 39.87308,-215.7304 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267393,0.25701 0.742469,0.25701 0.275181,0 0.53219,-0.0675 0.259604,-0.0675 0.514016,-0.20249 v 0.45171 q -0.257008,0.10903 -0.526997,0.16615 -0.269988,0.0571 -0.547765,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40499 -0.404983,-1.09553 0,-0.71392 0.384214,-1.13188 0.386811,-0.42056 1.041014,-0.42056 0.586707,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477672,-0.14019 q -0.0052,-0.392 -0.220664,-0.62564 -0.212875,-0.23365 -0.565938,-0.23365 -0.39979,0 -0.641223,0.22586 -0.238836,0.22586 -0.27518,0.63603 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7602" />
+ <path
+ d="m 42.34192,-216.61825 q -0.08048,-0.0467 -0.176532,-0.0675 -0.09346,-0.0234 -0.207683,-0.0234 -0.404983,0 -0.623051,0.2648 -0.215472,0.2622 -0.215472,0.75545 v 1.53166 h -0.480268 v -2.90757 h 0.480268 v 0.45172 q 0.150571,-0.2648 0.392003,-0.39201 0.241432,-0.1298 0.586706,-0.1298 0.04933,0 0.109034,0.008 0.05971,0.005 0.132399,0.0182 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7604" />
+ <path
+ d="m 45.213145,-215.7304 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267393,0.25701 0.742469,0.25701 0.275181,0 0.53219,-0.0675 0.259604,-0.0675 0.514016,-0.20249 v 0.45171 q -0.257008,0.10903 -0.526997,0.16615 -0.269988,0.0571 -0.547765,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40499 -0.404983,-1.09553 0,-0.71392 0.384214,-1.13188 0.386811,-0.42056 1.041014,-0.42056 0.586707,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477672,-0.14019 q -0.0052,-0.392 -0.220664,-0.62564 -0.212875,-0.23365 -0.565938,-0.23365 -0.39979,0 -0.641223,0.22586 -0.238836,0.22586 -0.27518,0.63603 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7606" />
+ <path
+ d="m 47.910435,-216.62344 v -1.5732 h 0.477672 v 4.03944 h -0.477672 v -0.43613 q -0.150571,0.2596 -0.381619,0.38681 -0.228452,0.12461 -0.550362,0.12461 -0.526997,0 -0.85929,-0.42056 -0.329698,-0.42056 -0.329698,-1.10592 0,-0.68535 0.329698,-1.10591 0.332293,-0.42056 0.85929,-0.42056 0.32191,0 0.550362,0.12721 0.231048,0.12461 0.381619,0.38421 z m -1.627721,1.01505 q 0,0.527 0.215472,0.82814 0.218068,0.29855 0.59709,0.29855 0.379023,0 0.597091,-0.29855 0.218068,-0.30114 0.218068,-0.82814 0,-0.52699 -0.218068,-0.82554 -0.218068,-0.30114 -0.597091,-0.30114 -0.379022,0 -0.59709,0.30114 -0.215472,0.29855 -0.215472,0.82554 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7608" />
+ <path
+ d="m 52.188717,-216.72988 q -0.384214,0 -0.607474,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.220664,0.82295 0.223259,0.29855 0.61007,0.29855 0.381619,0 0.604879,-0.30114 0.223259,-0.30115 0.223259,-0.82036 0,-0.51661 -0.223259,-0.81775 -0.22326,-0.30374 -0.604879,-0.30374 z m 0,-0.40498 q 0.623051,0 0.978709,0.40498 0.355658,0.40499 0.355658,1.12149 0,0.71392 -0.355658,1.1215 -0.355658,0.40498 -0.978709,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.1215 0,-0.7165 0.353062,-1.12149 0.355658,-0.40498 0.981305,-0.40498 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7610" />
+ <path
+ d="m 55.999713,-216.61825 q -0.08048,-0.0467 -0.176531,-0.0675 -0.09346,-0.0234 -0.207684,-0.0234 -0.404983,0 -0.623051,0.2648 -0.215472,0.2622 -0.215472,0.75545 v 1.53166 h -0.480268 v -2.90757 h 0.480268 v 0.45172 q 0.150571,-0.2648 0.392003,-0.39201 0.241432,-0.1298 0.586706,-0.1298 0.04932,0 0.109034,0.008 0.05971,0.005 0.132399,0.0182 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7612" />
+ <path
+ d="m 60.104057,-216.62344 v -1.5732 h 0.477672 v 4.03944 h -0.477672 v -0.43613 q -0.15057,0.2596 -0.381618,0.38681 -0.228452,0.12461 -0.550362,0.12461 -0.526997,0 -0.859291,-0.42056 -0.329698,-0.42056 -0.329698,-1.10592 0,-0.68535 0.329698,-1.10591 0.332294,-0.42056 0.859291,-0.42056 0.32191,0 0.550362,0.12721 0.231048,0.12461 0.381618,0.38421 z m -1.62772,1.01505 q 0,0.527 0.215472,0.82814 0.218068,0.29855 0.59709,0.29855 0.379023,0 0.59709,-0.29855 0.218068,-0.30114 0.218068,-0.82814 0,-0.52699 -0.218068,-0.82554 -0.218067,-0.30114 -0.59709,-0.30114 -0.379022,0 -0.59709,0.30114 -0.215472,0.29855 -0.215472,0.82554 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7614" />
+ <path
+ d="m 64.052642,-215.7304 v 0.23364 h -2.196254 q 0.03115,0.49325 0.295949,0.75286 0.267393,0.25701 0.742469,0.25701 0.275181,0 0.532189,-0.0675 0.259605,-0.0675 0.514017,-0.20249 v 0.45171 q -0.257008,0.10903 -0.526997,0.16615 -0.269989,0.0571 -0.547766,0.0571 -0.69574,0 -1.103319,-0.40498 -0.404983,-0.40499 -0.404983,-1.09553 0,-0.71392 0.384215,-1.13188 0.386811,-0.42056 1.041014,-0.42056 0.586706,0 0.926788,0.37902 0.342678,0.37643 0.342678,1.02544 z m -0.477672,-0.14019 q -0.0052,-0.392 -0.220664,-0.62564 -0.212876,-0.23365 -0.565938,-0.23365 -0.399791,0 -0.641223,0.22586 -0.238836,0.22586 -0.275181,0.63603 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7616" />
+ <path
+ d="m 66.308607,-218.19664 v 0.39719 h -0.456904 q -0.257008,0 -0.358254,0.10384 -0.09865,0.10385 -0.09865,0.37384 v 0.257 h 0.786601 v 0.37124 H 65.3948 v 2.53633 h -0.480269 v -2.53633 h -0.456904 v -0.37124 h 0.456904 v -0.20249 q 0,-0.48546 0.225856,-0.70612 0.225856,-0.22326 0.716509,-0.22326 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7618" />
+ <path
+ d="m 68.029783,-215.61877 q -0.578918,0 -0.802178,0.1324 -0.22326,0.1324 -0.22326,0.45171 0,0.25441 0.166147,0.40498 0.168743,0.14798 0.456904,0.14798 0.397195,0 0.636031,-0.28037 0.241432,-0.28297 0.241432,-0.75026 v -0.10644 z m 0.952748,-0.1973 v 1.65887 h -0.477672 v -0.44132 q -0.163551,0.26479 -0.407579,0.392 -0.244028,0.12461 -0.59709,0.12461 -0.44652,0 -0.711317,-0.24922 -0.2622,-0.25182 -0.2622,-0.67238 0,-0.49065 0.327101,-0.73987 0.329698,-0.24922 0.981305,-0.24922 h 0.66978 v -0.0467 q 0,-0.3297 -0.218068,-0.50882 -0.215471,-0.18173 -0.607474,-0.18173 -0.249221,0 -0.485461,0.0597 -0.23624,0.0597 -0.454307,0.17913 v -0.44133 q 0.2622,-0.10124 0.508824,-0.15057 0.246625,-0.0519 0.480269,-0.0519 0.630839,0 0.942364,0.3271 0.311525,0.3271 0.311525,0.99169 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7620" />
+ <path
+ d="m 69.917109,-215.30465 v -1.76012 h 0.477672 v 1.74195 q 0,0.41277 0.160955,0.62045 0.160955,0.20509 0.482864,0.20509 0.386811,0 0.610071,-0.24662 0.225856,-0.24663 0.225856,-0.67238 v -1.64849 h 0.477672 v 2.90757 h -0.477672 v -0.44652 q -0.173935,0.2648 -0.404983,0.3946 -0.228452,0.12721 -0.53219,0.12721 -0.501036,0 -0.760641,-0.31153 -0.259604,-0.31152 -0.259604,-0.91121 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7622" />
+ <path
+ d="m 73.336101,-218.19664 h 0.477672 v 4.03944 h -0.477672 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7624" />
+ <path
+ d="m 75.285731,-217.89031 v 0.82554 h 0.983901 v 0.37124 h -0.983901 v 1.57839 q 0,0.35566 0.09605,0.45691 0.09865,0.10124 0.397195,0.10124 h 0.490653 v 0.39979 h -0.490653 q -0.552957,0 -0.763237,-0.20508 -0.21028,-0.20769 -0.21028,-0.75286 v -1.57839 h -0.350466 v -0.37124 h 0.350466 v -0.82554 z"
+ style="fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7626" />
+ </g>
+ <g
+ aria-label="ArrayMethod"
+ transform="rotate(90)"
+ id="text4678"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.45542px;line-height:1.25;font-family:fira;-inkscape-font-specification:fira;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 116.73407,24.293717 h -1.97293 l -0.37291,1.374547 h -1.22712 l 1.87754,-5.996843 h 1.45693 l 1.8732,5.996843 h -1.26181 z m -1.76047,-0.888903 h 1.53932 l -0.76749,-2.84449 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7713" />
+ <path
+ d="m 119.10591,25.668264 v -0.793508 h 0.64608 v -3.009262 h -0.64608 v -0.789173 h 1.51764 l 0.21247,1.053676 q 0.25149,-0.58104 0.63307,-0.880231 0.38158,-0.299192 0.95828,-0.299192 0.22114,0 0.39025,0.03469 0.16911,0.03469 0.32954,0.09106 l -0.20379,1.790815 h -0.76316 V 21.96956 q -0.44662,0.03902 -0.77183,0.407595 -0.3252,0.364233 -0.51166,0.962617 v 1.534984 h 0.91492 v 0.793508 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7715" />
+ <path
+ d="m 124.30923,25.668264 v -0.793508 h 0.64608 v -3.009262 h -0.64608 v -0.789173 h 1.51764 l 0.21247,1.053676 q 0.25149,-0.58104 0.63307,-0.880231 0.38158,-0.299192 0.95828,-0.299192 0.22114,0 0.39025,0.03469 0.16911,0.03469 0.32955,0.09106 l -0.2038,1.790815 h -0.76316 V 21.96956 q -0.44661,0.03902 -0.77182,0.407595 -0.32521,0.364233 -0.51166,0.962617 v 1.534984 h 0.91492 v 0.793508 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7717" />
+ <path
+ d="m 133.13321,24.458489 q 0,0.264503 0.0781,0.385914 0.078,0.121411 0.25149,0.177781 l -0.24716,0.767492 q -0.36423,-0.03902 -0.6244,-0.182117 -0.26016,-0.147428 -0.39892,-0.437948 -0.26017,0.316537 -0.65909,0.472637 -0.39458,0.1561 -0.8282,0.1561 -0.70245,0 -1.11438,-0.398923 -0.41193,-0.398922 -0.41193,-1.03633 0,-0.732804 0.57237,-1.12739 0.5767,-0.398922 1.63038,-0.398922 h 0.64174 v -0.247159 q 0,-0.407594 -0.25583,-0.589711 -0.25149,-0.186453 -0.71979,-0.186453 -0.22114,0 -0.55503,0.06071 -0.33388,0.05637 -0.68076,0.17778 l -0.27318,-0.784836 q 0.43795,-0.164772 0.88023,-0.242822 0.44662,-0.07805 0.81085,-0.07805 0.96696,0 1.43526,0.41193 0.4683,0.407595 0.4683,1.157743 z m -2.05532,0.511661 q 0.26017,0 0.52467,-0.143091 0.2645,-0.147428 0.4206,-0.416267 v -0.893239 h -0.45095 q -0.63741,0 -0.9236,0.203797 -0.28184,0.203797 -0.28184,0.576703 0,0.672097 0.71112,0.672097 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7719" />
+ <path
+ d="m 138.83085,21.076321 -1.55667,4.600616 q -0.28184,0.841205 -0.83687,1.32685 -0.55502,0.489981 -1.55232,0.559359 l -0.1431,-0.828198 q 0.45963,-0.06504 0.73714,-0.195125 0.28185,-0.130083 0.44662,-0.342553 0.16911,-0.212469 0.29052,-0.529006 h -0.39025 l -1.50463,-4.591943 h 1.20978 l 1.04066,3.828788 1.08403,-3.828788 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7721" />
+ <path
+ d="m 143.85205,19.671421 0.33822,5.996843 h -1.05801 l -0.11274,-2.762103 q -0.026,-0.685106 -0.013,-1.20544 0.013,-0.520333 0.0434,-1.001642 l -0.79351,3.928518 h -0.96261 l -0.84988,-3.928518 q 0.0347,0.455292 0.0477,1.005978 0.0173,0.546351 0,1.209776 l -0.0824,2.753431 h -1.04067 l 0.33822,-5.996843 h 1.31818 l 0.77183,3.95887 0.73714,-3.95887 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7723" />
+ <path
+ d="m 146.05479,23.72135 q 0.052,0.646081 0.38157,0.932264 0.32955,0.286183 0.80218,0.286183 0.32955,0 0.62007,-0.104066 0.29052,-0.104067 0.57237,-0.29052 l 0.47697,0.654753 q -0.32087,0.268839 -0.76749,0.433611 -0.44229,0.164773 -0.97563,0.164773 -0.74581,0 -1.25747,-0.307864 -0.50733,-0.307864 -0.76749,-0.854214 -0.26017,-0.546351 -0.26017,-1.257473 0,-0.685106 0.25149,-1.235792 0.25583,-0.550686 0.73714,-0.871559 0.48565,-0.325208 1.16642,-0.325208 0.94527,0 1.50029,0.615728 0.55502,0.615728 0.55502,1.704092 0,0.251495 -0.0217,0.455292 z m 0.98429,-1.968595 q -0.41626,0 -0.6851,0.299191 -0.26451,0.299192 -0.3122,0.936601 h 1.9339 q -0.009,-0.581039 -0.23848,-0.906248 -0.22982,-0.329544 -0.69812,-0.329544 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7725" />
+ <path
+ d="m 154.24569,25.412434 q -0.25583,0.169108 -0.62006,0.277511 -0.36424,0.108403 -0.78918,0.108403 -0.8412,0 -1.26614,-0.433611 -0.42494,-0.437948 -0.42494,-1.162079 v -2.315484 h -0.99731 v -0.810853 h 0.99731 v -1.010314 l 1.14473,-0.138756 v 1.14907 h 1.51764 l -0.11707,0.810853 h -1.40057 v 2.311148 q 0,0.355561 0.17345,0.520334 0.17344,0.164772 0.55936,0.164772 0.24716,0 0.45095,-0.05637 0.20814,-0.06071 0.37724,-0.151764 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7727" />
+ <path
+ d="m 156.63054,19.133743 v 2.458576 q 0.28618,-0.325209 0.64175,-0.485645 0.35989,-0.160436 0.75014,-0.160436 0.63308,0 0.94961,0.359897 0.32087,0.355561 0.32087,1.001642 v 3.360487 h -1.14473 v -3.104656 q 0,-0.416267 -0.13008,-0.589712 -0.12575,-0.173444 -0.43361,-0.173444 -0.27752,0 -0.52034,0.186453 -0.24282,0.182117 -0.43361,0.446619 v 3.23474 h -1.14473 v -6.421782 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7729" />
+ <path
+ d="m 162.59702,20.946238 q 0.68511,0 1.16208,0.299192 0.47697,0.299191 0.72413,0.845542 0.25149,0.542014 0.25149,1.27048 0,1.118718 -0.55935,1.777807 -0.55936,0.659089 -1.58269,0.659089 -1.02332,0 -1.58268,-0.646081 -0.55936,-0.650417 -0.55936,-1.782142 0,-0.719795 0.2515,-1.266145 0.25149,-0.54635 0.72847,-0.849878 0.4813,-0.307864 1.16641,-0.307864 z m 0,0.862886 q -0.48131,0 -0.71979,0.377242 -0.23415,0.377242 -0.23415,1.183759 0,0.815189 0.23415,1.192431 0.23415,0.372905 0.71545,0.372905 0.48131,0 0.71546,-0.372905 0.23415,-0.377242 0.23415,-1.201104 0,-0.80218 -0.23415,-1.175086 -0.23415,-0.377242 -0.71112,-0.377242 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7731" />
+ <path
+ d="m 168.55483,19.120734 1.14473,0.121412 v 6.426118 h -1.01465 l -0.0694,-0.542014 q -0.21247,0.303528 -0.53334,0.489981 -0.32087,0.182117 -0.74581,0.182117 -0.58104,0 -0.96262,-0.303528 -0.37724,-0.303528 -0.56369,-0.849878 -0.18212,-0.550686 -0.18212,-1.279153 0,-0.698115 0.21681,-1.244465 0.22114,-0.550686 0.62873,-0.862886 0.4076,-0.3122 0.97129,-0.3122 0.6721,0 1.11005,0.463964 z m -0.80218,2.679718 q -0.43362,0 -0.68511,0.377242 -0.24716,0.372905 -0.24716,1.192431 0,0.867222 0.22982,1.218447 0.22981,0.351225 0.62006,0.351225 0.28618,0 0.50299,-0.169108 0.2168,-0.173444 0.38158,-0.429275 v -2.090006 q -0.16044,-0.21247 -0.3599,-0.329545 -0.19513,-0.121411 -0.44228,-0.121411 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path7733" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:3.52777px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;stroke-width:0.264583"
+ x="92.373795"
+ y="-75.619186"
+ id="text4844"
+ transform="scale(-1)"><tspan
+ sodipodi:role="line"
+ id="tspan4842"
+ x="92.373795"
+ y="-75.619186"
+ style="stroke-width:0.264583" /></text>
+ <g
+ aria-label="Casting, Result Allocation and Outer Iteration
+done by UFunc Machinery (within ArrayMethod)
+"
+ transform="rotate(-90)"
+ id="text4856"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m -231.92408,-282.92647 q -0.27518,0.14278 -0.57373,0.21547 -0.29854,0.0727 -0.62305,0.0727 -0.96832,0 -1.53426,-0.53997 -0.56594,-0.54258 -0.56594,-1.46937 0,-0.92938 0.56594,-1.46936 0.56594,-0.54257 1.53426,-0.54257 0.32451,0 0.62305,0.0727 0.29855,0.0727 0.57373,0.21547 v 0.80218 q -0.27778,-0.18951 -0.54777,-0.27778 -0.26999,-0.0883 -0.56853,-0.0883 -0.53479,0 -0.84112,0.34267 -0.30633,0.34268 -0.30633,0.94496 0,0.59969 0.30633,0.94237 0.30633,0.34268 0.84112,0.34268 0.29854,0 0.56853,-0.0883 0.26999,-0.0883 0.54777,-0.27778 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7820" />
+ <path
+ d="m -229.83427,-284.022 q -0.29075,0 -0.43873,0.0986 -0.14538,0.0987 -0.14538,0.29076 0,0.17653 0.11683,0.27777 0.11941,0.0987 0.32969,0.0987 0.2622,0 0.44133,-0.18691 0.17913,-0.18951 0.17913,-0.47248 v -0.10644 z m 1.42004,-0.35047 v 1.65888 h -0.93717 v -0.43095 q -0.18692,0.2648 -0.42056,0.38681 -0.23364,0.11942 -0.56853,0.11942 -0.45172,0 -0.73468,-0.2622 -0.28038,-0.26479 -0.28038,-0.68535 0,-0.51142 0.35047,-0.75026 0.35306,-0.23884 1.10591,-0.23884 h 0.54777 v -0.0727 q 0,-0.22066 -0.17394,-0.32191 -0.17393,-0.10384 -0.54257,-0.10384 -0.29854,0 -0.55555,0.0597 -0.25701,0.0597 -0.47768,0.17913 v -0.70872 q 0.29855,-0.0727 0.59969,-0.10904 0.30114,-0.0389 0.60228,-0.0389 0.78661,0 1.13448,0.31153 0.35046,0.30893 0.35046,1.00726 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7822" />
+ <path
+ d="m -225.27821,-285.5303 v 0.70612 q -0.29854,-0.12461 -0.57632,-0.18691 -0.27778,-0.0623 -0.5244,-0.0623 -0.2648,0 -0.3946,0.0675 -0.1272,0.0649 -0.1272,0.20249 0,0.11163 0.0961,0.17134 0.0986,0.0597 0.35047,0.0883 l 0.16355,0.0234 q 0.71391,0.0909 0.96053,0.29855 0.24663,0.20768 0.24663,0.6516 0,0.46469 -0.34268,0.69834 -0.34268,0.23364 -1.02284,0.23364 -0.28816,0 -0.59709,-0.0467 -0.30634,-0.0441 -0.63084,-0.13499 v -0.70612 q 0.27777,0.13499 0.56853,0.20249 0.29336,0.0675 0.5945,0.0675 0.27258,0 0.41017,-0.0753 0.13759,-0.0753 0.13759,-0.22326 0,-0.12461 -0.096,-0.18432 -0.0935,-0.0623 -0.37643,-0.096 l -0.16355,-0.0208 q -0.62045,-0.0779 -0.86967,-0.28816 -0.24922,-0.21028 -0.24922,-0.63863 0,-0.4621 0.31671,-0.68536 0.31672,-0.22326 0.97092,-0.22326 0.25701,0 0.53998,0.0389 0.28297,0.0389 0.61526,0.12202 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7824" />
+ <path
+ d="m -223.37011,-286.44671 v 0.82555 h 0.95794 v 0.66458 h -0.95794 v 1.23313 q 0,0.20249 0.0805,0.27518 0.0805,0.0701 0.31932,0.0701 h 0.47767 v 0.66459 h -0.79699 q -0.55036,0 -0.78141,-0.22845 -0.22845,-0.23105 -0.22845,-0.78141 v -1.23313 h -0.46209 v -0.66458 h 0.46209 v -0.82555 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7826" />
+ <path
+ d="m -221.84364,-285.62116 h 0.92938 v 2.90757 h -0.92938 z m 0,-1.13188 h 0.92938 v 0.75805 h -0.92938 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7828" />
+ <path
+ d="m -217.09807,-284.4841 v 1.77051 h -0.93458 v -0.28816 -1.06698 q 0,-0.37642 -0.0182,-0.51921 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14798,-0.14018 -0.0934,-0.0519 -0.21287,-0.0519 -0.29076,0 -0.4569,0.22585 -0.16615,0.22326 -0.16615,0.62046 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12202 0.5218,-0.12202 0.50364,0 0.76324,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7830" />
+ <path
+ d="m -214.258,-283.20684 q -0.1921,0.25441 -0.42315,0.37383 -0.23105,0.11942 -0.53479,0.11942 -0.53218,0 -0.88005,-0.41797 -0.34787,-0.42056 -0.34787,-1.06957 0,-0.6516 0.34787,-1.06697 0.34787,-0.41796 0.88005,-0.41796 0.30374,0 0.53479,0.11941 0.23105,0.11942 0.42315,0.37643 v -0.43094 h 0.93458 v 2.61421 q 0,0.70094 -0.44392,1.06957 -0.44133,0.37124 -1.28245,0.37124 -0.27258,0 -0.527,-0.0415 -0.25441,-0.0415 -0.51142,-0.1272 v -0.7243 q 0.24403,0.14019 0.47768,0.20768 0.23364,0.0701 0.46988,0.0701 0.4569,0 0.66978,-0.1999 0.21287,-0.19989 0.21287,-0.62565 z m -0.61266,-1.80944 q -0.28816,0 -0.44912,0.21287 -0.16095,0.21288 -0.16095,0.60228 0,0.39979 0.15576,0.60748 0.15576,0.20509 0.45431,0.20509 0.29076,0 0.45171,-0.21288 0.16095,-0.21288 0.16095,-0.59969 0,-0.3894 -0.16095,-0.60228 -0.16095,-0.21287 -0.45171,-0.21287 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7832" />
+ <path
+ d="m -212.33433,-283.71826 h 0.93458 v 0.79179 l -0.64122,0.96833 h -0.55296 l 0.2596,-0.96833 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7834" />
+ <path
+ d="m -207.0981,-284.87091 q 0.31412,0 0.44911,-0.11682 0.13759,-0.11682 0.13759,-0.38421 0,-0.2648 -0.13759,-0.37903 -0.13499,-0.11422 -0.44911,-0.11422 h -0.42056 v 0.99428 z m -0.42056,0.69055 v 1.46677 h -0.99948 v -3.8759 h 1.52647 q 0.76584,0 1.1215,0.25701 0.35825,0.25701 0.35825,0.81256 0,0.38422 -0.18692,0.63084 -0.18431,0.24663 -0.55815,0.36345 0.20509,0.0467 0.36605,0.21287 0.16355,0.16355 0.32969,0.49844 l 0.54258,1.10073 h -1.06438 l -0.47248,-0.96314 q -0.14278,-0.29075 -0.29076,-0.39719 -0.14538,-0.10644 -0.3894,-0.10644 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7836" />
+ <path
+ d="m -201.56334,-284.17517 v 0.2648 h -2.17289 q 0.0337,0.3271 0.23624,0.49065 0.20249,0.16355 0.56594,0.16355 0.29335,0 0.59969,-0.0857 0.30893,-0.0883 0.63343,-0.26479 v 0.71651 q -0.3297,0.12461 -0.65939,0.18691 -0.3297,0.0649 -0.6594,0.0649 -0.7892,0 -1.22793,-0.39979 -0.43613,-0.40239 -0.43613,-1.12668 0,-0.71132 0.42834,-1.1189 0.43095,-0.40758 1.1838,-0.40758 0.68536,0 1.09553,0.41278 0.41277,0.41277 0.41277,1.10331 z m -0.95534,-0.30893 q 0,-0.26479 -0.15576,-0.42575 -0.15317,-0.16355 -0.40239,-0.16355 -0.26999,0 -0.43873,0.15317 -0.16875,0.15057 -0.21028,0.43613 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7838" />
+ <path
+ d="m -198.58827,-285.5303 v 0.70612 q -0.29854,-0.12461 -0.57632,-0.18691 -0.27778,-0.0623 -0.5244,-0.0623 -0.2648,0 -0.3946,0.0675 -0.12721,0.0649 -0.12721,0.20249 0,0.11163 0.0961,0.17134 0.0987,0.0597 0.35046,0.0883 l 0.16355,0.0234 q 0.71392,0.0909 0.96054,0.29855 0.24662,0.20768 0.24662,0.6516 0,0.46469 -0.34267,0.69834 -0.34268,0.23364 -1.02285,0.23364 -0.28816,0 -0.59709,-0.0467 -0.30633,-0.0441 -0.63083,-0.13499 v -0.70612 q 0.27777,0.13499 0.56853,0.20249 0.29335,0.0675 0.59449,0.0675 0.27259,0 0.41018,-0.0753 0.13759,-0.0753 0.13759,-0.22326 0,-0.12461 -0.096,-0.18432 -0.0935,-0.0623 -0.37643,-0.096 l -0.16355,-0.0208 q -0.62046,-0.0779 -0.86968,-0.28816 -0.24922,-0.21028 -0.24922,-0.63863 0,-0.4621 0.31672,-0.68536 0.31672,-0.22326 0.97092,-0.22326 0.25701,0 0.53998,0.0389 0.28297,0.0389 0.61526,0.12202 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7840" />
+ <path
+ d="m -197.72638,-283.84547 v -1.77569 h 0.93457 v 0.29075 q 0,0.23624 -0.003,0.5945 -0.003,0.35566 -0.003,0.47507 0,0.35047 0.0182,0.50623 0.0182,0.15317 0.0623,0.22326 0.0571,0.0909 0.14797,0.14019 0.0935,0.0493 0.21288,0.0493 0.29076,0 0.4569,-0.22326 0.16615,-0.22326 0.16615,-0.62045 v -1.43561 h 0.92938 v 2.90757 h -0.92938 v -0.42056 q -0.21028,0.25441 -0.44652,0.37642 -0.23364,0.11942 -0.51661,0.11942 -0.50364,0 -0.76843,-0.30893 -0.2622,-0.30893 -0.2622,-0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7842" />
+ <path
+ d="m -193.9102,-286.75304 h 0.92939 v 4.03945 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7844" />
+ <path
+ d="m -191.07272,-286.44671 v 0.82555 h 0.95794 v 0.66458 h -0.95794 v 1.23313 q 0,0.20249 0.0805,0.27518 0.0805,0.0701 0.31931,0.0701 h 0.47767 v 0.66459 h -0.79698 q -0.55036,0 -0.78141,-0.22845 -0.22845,-0.23105 -0.22845,-0.78141 v -1.23313 h -0.4621 v -0.66458 h 0.4621 v -0.82555 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7846" />
+ <path
+ d="m -185.30171,-283.41972 h -1.56282 l -0.24662,0.70613 h -1.00467 l 1.43561,-3.8759 h 1.19158 l 1.43562,3.8759 h -1.00467 z m -1.3136,-0.7191 h 1.06178 l -0.52959,-1.54205 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7848" />
+ <path
+ d="m -183.58053,-286.75304 h 0.92938 v 4.03945 h -0.92938 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7850" />
+ <path
+ d="m -181.75811,-286.75304 h 0.92939 v 4.03945 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7852" />
+ <path
+ d="m -178.55199,-285.02667 q -0.30893,0 -0.47248,0.22326 -0.16096,0.22067 -0.16096,0.63863 0,0.41796 0.16096,0.64122 0.16355,0.22067 0.47248,0.22067 0.30373,0 0.46469,-0.22067 0.16095,-0.22326 0.16095,-0.64122 0,-0.41796 -0.16095,-0.63863 -0.16096,-0.22326 -0.46469,-0.22326 z m 0,-0.66459 q 0.75025,0 1.17081,0.40499 0.42316,0.40498 0.42316,1.12149 0,0.71651 -0.42316,1.12149 -0.42056,0.40498 -1.17081,0.40498 -0.75286,0 -1.17861,-0.40498 -0.42315,-0.40498 -0.42315,-1.12149 0,-0.71651 0.42315,-1.12149 0.42575,-0.40499 1.17861,-0.40499 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7854" />
+ <path
+ d="m -173.93363,-285.5303 v 0.75804 q -0.18951,-0.1298 -0.38162,-0.1921 -0.18951,-0.0623 -0.3946,-0.0623 -0.38941,0 -0.60747,0.22845 -0.21548,0.22586 -0.21548,0.63344 0,0.40758 0.21548,0.63603 0.21806,0.22586 0.60747,0.22586 0.21807,0 0.41277,-0.0649 0.1973,-0.0649 0.36345,-0.1921 v 0.76064 q -0.21807,0.0805 -0.44393,0.11942 -0.22326,0.0415 -0.44911,0.0415 -0.7866,0 -1.23053,-0.40238 -0.44392,-0.40499 -0.44392,-1.12409 0,-0.71911 0.44392,-1.12149 0.44393,-0.40499 1.23053,-0.40499 0.22845,0 0.44911,0.0415 0.22326,0.0389 0.44393,0.11942 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7856" />
+ <path
+ d="m -171.82824,-284.022 q -0.29076,0 -0.43873,0.0986 -0.14538,0.0987 -0.14538,0.29076 0,0.17653 0.11682,0.27777 0.11942,0.0987 0.3297,0.0987 0.2622,0 0.44133,-0.18691 0.17913,-0.18951 0.17913,-0.47248 v -0.10644 z m 1.42004,-0.35047 v 1.65888 h -0.93717 v -0.43095 q -0.18692,0.2648 -0.42056,0.38681 -0.23365,0.11942 -0.56854,0.11942 -0.45171,0 -0.73468,-0.2622 -0.28037,-0.26479 -0.28037,-0.68535 0,-0.51142 0.35047,-0.75026 0.35306,-0.23884 1.10591,-0.23884 h 0.54777 v -0.0727 q 0,-0.22066 -0.17394,-0.32191 -0.17393,-0.10384 -0.54257,-0.10384 -0.29855,0 -0.55556,0.0597 -0.257,0.0597 -0.47767,0.17913 v -0.70872 q 0.29855,-0.0727 0.59969,-0.10904 0.30114,-0.0389 0.60228,-0.0389 0.7866,0 1.13447,0.31153 0.35047,0.30893 0.35047,1.00726 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7858" />
+ <path
+ d="m -168.52866,-286.44671 v 0.82555 h 0.95794 v 0.66458 h -0.95794 v 1.23313 q 0,0.20249 0.0805,0.27518 0.0805,0.0701 0.31931,0.0701 h 0.47767 v 0.66459 h -0.79698 q -0.55037,0 -0.78141,-0.22845 -0.22846,-0.23105 -0.22846,-0.78141 v -1.23313 h -0.46209 v -0.66458 h 0.46209 v -0.82555 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7860" />
+ <path
+ d="m -167.00219,-285.62116 h 0.92939 v 2.90757 h -0.92939 z m 0,-1.13188 h 0.92939 v 0.75805 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7862" />
+ <path
+ d="m -163.79608,-285.02667 q -0.30893,0 -0.47248,0.22326 -0.16095,0.22067 -0.16095,0.63863 0,0.41796 0.16095,0.64122 0.16355,0.22067 0.47248,0.22067 0.30374,0 0.46469,-0.22067 0.16096,-0.22326 0.16096,-0.64122 0,-0.41796 -0.16096,-0.63863 -0.16095,-0.22326 -0.46469,-0.22326 z m 0,-0.66459 q 0.75026,0 1.17082,0.40499 0.42315,0.40498 0.42315,1.12149 0,0.71651 -0.42315,1.12149 -0.42056,0.40498 -1.17082,0.40498 -0.75285,0 -1.1786,-0.40498 -0.42316,-0.40498 -0.42316,-1.12149 0,-0.71651 0.42316,-1.12149 0.42575,-0.40499 1.1786,-0.40499 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7864" />
+ <path
+ d="m -158.60398,-284.4841 v 1.77051 h -0.93458 v -0.28816 -1.06698 q 0,-0.37642 -0.0182,-0.51921 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14798,-0.14018 -0.0935,-0.0519 -0.21287,-0.0519 -0.29076,0 -0.45691,0.22585 -0.16614,0.22326 -0.16614,0.62046 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12202 0.5218,-0.12202 0.50363,0 0.76324,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7866" />
+ <path
+ d="m -154.5879,-284.022 q -0.29076,0 -0.43874,0.0986 -0.14537,0.0987 -0.14537,0.29076 0,0.17653 0.11682,0.27777 0.11942,0.0987 0.3297,0.0987 0.2622,0 0.44132,-0.18691 0.17913,-0.18951 0.17913,-0.47248 v -0.10644 z m 1.42003,-0.35047 v 1.65888 h -0.93717 v -0.43095 q -0.18692,0.2648 -0.42056,0.38681 -0.23364,0.11942 -0.56853,0.11942 -0.45172,0 -0.73468,-0.2622 -0.28038,-0.26479 -0.28038,-0.68535 0,-0.51142 0.35047,-0.75026 0.35306,-0.23884 1.10591,-0.23884 h 0.54777 v -0.0727 q 0,-0.22066 -0.17394,-0.32191 -0.17393,-0.10384 -0.54257,-0.10384 -0.29854,0 -0.55555,0.0597 -0.25701,0.0597 -0.47767,0.17913 v -0.70872 q 0.29854,-0.0727 0.59968,-0.10904 0.30114,-0.0389 0.60228,-0.0389 0.78661,0 1.13448,0.31153 0.35046,0.30893 0.35046,1.00726 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7868" />
+ <path
+ d="m -149.38023,-284.4841 v 1.77051 h -0.93458 v -0.28816 -1.06698 q 0,-0.37642 -0.0182,-0.51921 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14797,-0.14018 -0.0935,-0.0519 -0.21288,-0.0519 -0.29075,0 -0.4569,0.22585 -0.16615,0.22326 -0.16615,0.62046 v 1.43042 h -0.92938 v -2.90757 h 0.92938 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12202 0.52181,-0.12202 0.50363,0 0.76323,0.30893 0.26221,0.30893 0.26221,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7870" />
+ <path
+ d="m -146.54017,-285.19541 v -1.55763 h 0.93458 v 4.03945 h -0.93458 v -0.42056 q -0.19211,0.25701 -0.42315,0.37642 -0.23105,0.11942 -0.53479,0.11942 -0.53738,0 -0.88265,-0.42575 -0.34528,-0.42835 -0.34528,-1.10072 0,-0.67238 0.34528,-1.09813 0.34527,-0.42835 0.88265,-0.42835 0.30114,0 0.53219,0.12202 0.23364,0.11942 0.42575,0.37383 z m -0.61266,1.88213 q 0.29854,0 0.4543,-0.21807 0.15836,-0.21806 0.15836,-0.63343 0,-0.41537 -0.15836,-0.63344 -0.15576,-0.21806 -0.4543,-0.21806 -0.29595,0 -0.45431,0.21806 -0.15577,0.21807 -0.15577,0.63344 0,0.41537 0.15577,0.63343 0.15836,0.21807 0.45431,0.21807 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7872" />
+ <path
+ d="m -141.04953,-285.93528 q -0.45691,0 -0.70872,0.33748 -0.25182,0.33749 -0.25182,0.95015 0,0.61007 0.25182,0.94756 0.25181,0.33749 0.70872,0.33749 0.4595,0 0.71132,-0.33749 0.25181,-0.33749 0.25181,-0.94756 0,-0.61266 -0.25181,-0.95015 -0.25182,-0.33748 -0.71132,-0.33748 z m 0,-0.7243 q 0.93458,0 1.46417,0.53478 0.52959,0.53479 0.52959,1.47715 0,0.93977 -0.52959,1.47456 -0.52959,0.53478 -1.46417,0.53478 -0.93198,0 -1.46417,-0.53478 -0.52959,-0.53479 -0.52959,-1.47456 0,-0.94236 0.52959,-1.47715 0.53219,-0.53478 1.46417,-0.53478 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7874" />
+ <path
+ d="m -138.37301,-283.84547 v -1.77569 h 0.93458 v 0.29075 q 0,0.23624 -0.003,0.5945 -0.003,0.35566 -0.003,0.47507 0,0.35047 0.0182,0.50623 0.0182,0.15317 0.0623,0.22326 0.0571,0.0909 0.14798,0.14019 0.0934,0.0493 0.21287,0.0493 0.29076,0 0.45691,-0.22326 0.16614,-0.22326 0.16614,-0.62045 v -1.43561 h 0.92939 v 2.90757 h -0.92939 v -0.42056 q -0.21028,0.25441 -0.44652,0.37642 -0.23364,0.11942 -0.51661,0.11942 -0.50363,0 -0.76843,-0.30893 -0.2622,-0.30893 -0.2622,-0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7876" />
+ <path
+ d="m -133.54177,-286.44671 v 0.82555 h 0.95794 v 0.66458 h -0.95794 v 1.23313 q 0,0.20249 0.0805,0.27518 0.0805,0.0701 0.31931,0.0701 h 0.47767 v 0.66459 h -0.79698 q -0.55036,0 -0.78141,-0.22845 -0.22845,-0.23105 -0.22845,-0.78141 v -1.23313 h -0.4621 v -0.66458 h 0.4621 v -0.82555 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7878" />
+ <path
+ d="m -129.11292,-284.17517 v 0.2648 h -2.17289 q 0.0337,0.3271 0.23624,0.49065 0.2025,0.16355 0.56594,0.16355 0.29335,0 0.59969,-0.0857 0.30893,-0.0883 0.63343,-0.26479 v 0.71651 q -0.3297,0.12461 -0.65939,0.18691 -0.3297,0.0649 -0.6594,0.0649 -0.7892,0 -1.22793,-0.39979 -0.43613,-0.40239 -0.43613,-1.12668 0,-0.71132 0.42834,-1.1189 0.43095,-0.40758 1.1838,-0.40758 0.68536,0 1.09553,0.41278 0.41277,0.41277 0.41277,1.10331 z m -0.95534,-0.30893 q 0,-0.26479 -0.15576,-0.42575 -0.15317,-0.16355 -0.40239,-0.16355 -0.26999,0 -0.43873,0.15317 -0.16875,0.15057 -0.21028,0.43613 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7880" />
+ <path
+ d="m -126.24947,-284.82937 q -0.12202,-0.0571 -0.24403,-0.0831 -0.11942,-0.0286 -0.24143,-0.0286 -0.35826,0 -0.55296,0.23105 -0.19211,0.22845 -0.19211,0.6568 v 1.33956 h -0.92938 v -2.90757 h 0.92938 v 0.47767 q 0.17913,-0.28557 0.41018,-0.41537 0.23364,-0.1324 0.55814,-0.1324 0.0467,0 0.10125,0.005 0.0545,0.003 0.15836,0.0156 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7882" />
+ <path
+ d="m -123.89486,-286.58949 h 0.99947 v 3.8759 h -0.99947 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7884" />
+ <path
+ d="m -120.94316,-286.44671 v 0.82555 h 0.95794 v 0.66458 h -0.95794 v 1.23313 q 0,0.20249 0.0805,0.27518 0.0805,0.0701 0.31931,0.0701 h 0.47767 v 0.66459 h -0.79698 q -0.55036,0 -0.78141,-0.22845 -0.22845,-0.23105 -0.22845,-0.78141 v -1.23313 h -0.4621 v -0.66458 h 0.4621 v -0.82555 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7886" />
+ <path
+ d="m -116.51431,-284.17517 v 0.2648 h -2.17289 q 0.0337,0.3271 0.23624,0.49065 0.20249,0.16355 0.56594,0.16355 0.29335,0 0.59969,-0.0857 0.30893,-0.0883 0.63343,-0.26479 v 0.71651 q -0.3297,0.12461 -0.65939,0.18691 -0.3297,0.0649 -0.6594,0.0649 -0.7892,0 -1.22793,-0.39979 -0.43613,-0.40239 -0.43613,-1.12668 0,-0.71132 0.42834,-1.1189 0.43095,-0.40758 1.1838,-0.40758 0.68536,0 1.09553,0.41278 0.41277,0.41277 0.41277,1.10331 z m -0.95534,-0.30893 q 0,-0.26479 -0.15576,-0.42575 -0.15317,-0.16355 -0.40239,-0.16355 -0.26999,0 -0.43873,0.15317 -0.16875,0.15057 -0.21028,0.43613 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7888" />
+ <path
+ d="m -113.65087,-284.82937 q -0.12202,-0.0571 -0.24403,-0.0831 -0.11942,-0.0286 -0.24143,-0.0286 -0.35826,0 -0.55296,0.23105 -0.19211,0.22845 -0.19211,0.6568 v 1.33956 h -0.92938 v -2.90757 h 0.92938 v 0.47767 q 0.17913,-0.28557 0.41018,-0.41537 0.23364,-0.1324 0.55815,-0.1324 0.0467,0 0.10124,0.005 0.0545,0.003 0.15836,0.0156 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7890" />
+ <path
+ d="m -111.88556,-284.022 q -0.29075,0 -0.43873,0.0986 -0.14538,0.0987 -0.14538,0.29076 0,0.17653 0.11682,0.27777 0.11942,0.0987 0.3297,0.0987 0.2622,0 0.44133,-0.18691 0.17913,-0.18951 0.17913,-0.47248 v -0.10644 z m 1.42004,-0.35047 v 1.65888 h -0.93717 v -0.43095 q -0.18692,0.2648 -0.42056,0.38681 -0.23365,0.11942 -0.56854,0.11942 -0.45171,0 -0.73468,-0.2622 -0.28037,-0.26479 -0.28037,-0.68535 0,-0.51142 0.35047,-0.75026 0.35306,-0.23884 1.10591,-0.23884 h 0.54777 v -0.0727 q 0,-0.22066 -0.17394,-0.32191 -0.17393,-0.10384 -0.54257,-0.10384 -0.29855,0 -0.55556,0.0597 -0.257,0.0597 -0.47767,0.17913 v -0.70872 q 0.29855,-0.0727 0.59969,-0.10904 0.30114,-0.0389 0.60228,-0.0389 0.7866,0 1.13447,0.31153 0.35047,0.30893 0.35047,1.00726 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7892" />
+ <path
+ d="m -108.58599,-286.44671 v 0.82555 h 0.95794 v 0.66458 h -0.95794 v 1.23313 q 0,0.20249 0.0805,0.27518 0.0805,0.0701 0.31931,0.0701 h 0.47767 v 0.66459 h -0.79698 q -0.55036,0 -0.78141,-0.22845 -0.22845,-0.23105 -0.22845,-0.78141 v -1.23313 h -0.4621 v -0.66458 h 0.4621 v -0.82555 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7894" />
+ <path
+ d="m -107.05952,-285.62116 h 0.92939 v 2.90757 h -0.92939 z m 0,-1.13188 h 0.92939 v 0.75805 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7896" />
+ <path
+ d="m -103.8534,-285.02667 q -0.30893,0 -0.47248,0.22326 -0.16095,0.22067 -0.16095,0.63863 0,0.41796 0.16095,0.64122 0.16355,0.22067 0.47248,0.22067 0.30374,0 0.46469,-0.22067 0.16096,-0.22326 0.16096,-0.64122 0,-0.41796 -0.16096,-0.63863 -0.16095,-0.22326 -0.46469,-0.22326 z m 0,-0.66459 q 0.75026,0 1.17082,0.40499 0.42315,0.40498 0.42315,1.12149 0,0.71651 -0.42315,1.12149 -0.42056,0.40498 -1.17082,0.40498 -0.75285,0 -1.1786,-0.40498 -0.42316,-0.40498 -0.42316,-1.12149 0,-0.71651 0.42316,-1.12149 0.42575,-0.40499 1.1786,-0.40499 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7898" />
+ <path
+ d="m -98.661309,-284.4841 v 1.77051 h -0.934576 v -0.28816 -1.06698 q 0,-0.37642 -0.01817,-0.51921 -0.01558,-0.14278 -0.05711,-0.21028 -0.05452,-0.0909 -0.147974,-0.14018 -0.09346,-0.0519 -0.212875,-0.0519 -0.29076,0 -0.4569,0.22585 -0.16615,0.22326 -0.16615,0.62046 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.236238,-0.12202 0.521803,-0.12202 0.503633,0 0.763237,0.30893 0.262201,0.30893 0.262201,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7900" />
+ <path
+ d="m -233.06115,-278.54954 v -1.55762 h 0.93458 v 4.03944 h -0.93458 v -0.42056 q -0.19211,0.25701 -0.42315,0.37643 -0.23105,0.11942 -0.53479,0.11942 -0.53738,0 -0.88265,-0.42575 -0.34528,-0.42835 -0.34528,-1.10073 0,-0.67237 0.34528,-1.09812 0.34527,-0.42835 0.88265,-0.42835 0.30114,0 0.53219,0.12201 0.23364,0.11942 0.42575,0.37383 z m -0.61267,1.88214 q 0.29855,0 0.45431,-0.21807 0.15836,-0.21807 0.15836,-0.63344 0,-0.41536 -0.15836,-0.63343 -0.15576,-0.21807 -0.45431,-0.21807 -0.29594,0 -0.4543,0.21807 -0.15577,0.21807 -0.15577,0.63343 0,0.41537 0.15577,0.63344 0.15836,0.21807 0.4543,0.21807 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7902" />
+ <path
+ d="m -229.84984,-278.38079 q -0.30893,0 -0.47248,0.22326 -0.16096,0.22066 -0.16096,0.63862 0,0.41797 0.16096,0.64123 0.16355,0.22066 0.47248,0.22066 0.30374,0 0.46469,-0.22066 0.16096,-0.22326 0.16096,-0.64123 0,-0.41796 -0.16096,-0.63862 -0.16095,-0.22326 -0.46469,-0.22326 z m 0,-0.66459 q 0.75026,0 1.17081,0.40498 0.42316,0.40498 0.42316,1.12149 0,0.71651 -0.42316,1.12149 -0.42055,0.40499 -1.17081,0.40499 -0.75285,0 -1.17861,-0.40499 -0.42315,-0.40498 -0.42315,-1.12149 0,-0.71651 0.42315,-1.12149 0.42576,-0.40498 1.17861,-0.40498 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7904" />
+ <path
+ d="m -224.65775,-277.83822 v 1.7705 h -0.93458 v -0.28816 -1.06697 q 0,-0.37643 -0.0182,-0.51921 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14798,-0.14019 -0.0935,-0.0519 -0.21287,-0.0519 -0.29076,0 -0.45691,0.22586 -0.16614,0.22326 -0.16614,0.62045 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12201 0.5218,-0.12201 0.50363,0 0.76324,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7906" />
+ <path
+ d="m -220.89349,-277.52929 v 0.2648 h -2.17289 q 0.0337,0.3271 0.23624,0.49065 0.2025,0.16355 0.56594,0.16355 0.29335,0 0.59969,-0.0857 0.30893,-0.0883 0.63343,-0.2648 v 0.71651 q -0.3297,0.12461 -0.65939,0.18692 -0.3297,0.0649 -0.6594,0.0649 -0.7892,0 -1.22793,-0.39979 -0.43613,-0.40239 -0.43613,-1.12669 0,-0.71131 0.42834,-1.11889 0.43095,-0.40758 1.1838,-0.40758 0.68536,0 1.09553,0.41277 0.41277,0.41277 0.41277,1.10332 z m -0.95534,-0.30893 q 0,-0.2648 -0.15576,-0.42575 -0.15317,-0.16355 -0.40239,-0.16355 -0.26999,0 -0.43873,0.15316 -0.16875,0.15057 -0.21028,0.43614 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7908" />
+ <path
+ d="m -216.79174,-276.6674 q 0.29855,0 0.45431,-0.21807 0.15836,-0.21807 0.15836,-0.63344 0,-0.41536 -0.15836,-0.63343 -0.15576,-0.21807 -0.45431,-0.21807 -0.29854,0 -0.4595,0.22066 -0.15835,0.21807 -0.15835,0.63084 0,0.41277 0.15835,0.63344 0.16096,0.21807 0.4595,0.21807 z m -0.61785,-1.88214 q 0.1921,-0.25441 0.42575,-0.37383 0.23364,-0.12201 0.53738,-0.12201 0.53738,0 0.88265,0.42835 0.34528,0.42575 0.34528,1.09812 0,0.67238 -0.34528,1.10073 -0.34527,0.42575 -0.88265,0.42575 -0.30374,0 -0.53738,-0.11942 -0.23365,-0.12201 -0.42575,-0.37643 v 0.42056 h -0.92939 v -4.03944 h 0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7910" />
+ <path
+ d="m -214.9148,-278.97529 h 0.92939 l 0.78141,1.973 0.66459,-1.973 h 0.92938 l -1.22274,3.18275 q -0.18432,0.48546 -0.43094,0.67757 -0.24403,0.1947 -0.64642,0.1947 h -0.53738 v -0.61007 h 0.29076 q 0.23624,0 0.34268,-0.0753 0.10903,-0.0753 0.16874,-0.26999 l 0.026,-0.0805 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7912" />
+ <path
+ d="m -209.17494,-279.94361 h 0.99948 v 2.32346 q 0,0.48027 0.15576,0.68795 0.15836,0.20509 0.51402,0.20509 0.35825,0 0.51401,-0.20509 0.15836,-0.20768 0.15836,-0.68795 v -2.32346 h 0.99948 v 2.32346 q 0,0.82294 -0.41277,1.22533 -0.41277,0.40239 -1.25908,0.40239 -0.84372,0 -1.25649,-0.40239 -0.41277,-0.40239 -0.41277,-1.22533 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7914" />
+ <path
+ d="m -204.85772,-279.94361 h 2.69729 v 0.75545 h -1.69781 v 0.7217 h 1.59657 v 0.75545 h -1.59657 v 1.64329 h -0.99948 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7916" />
+ <path
+ d="m -201.56334,-277.19959 v -1.7757 h 0.93458 v 0.29076 q 0,0.23624 -0.003,0.59449 -0.003,0.35566 -0.003,0.47508 0,0.35047 0.0182,0.50623 0.0182,0.15317 0.0623,0.22326 0.0571,0.0909 0.14797,0.14018 0.0935,0.0493 0.21288,0.0493 0.29075,0 0.4569,-0.22326 0.16615,-0.22326 0.16615,-0.62046 v -1.43561 h 0.92938 v 2.90757 h -0.92938 v -0.42056 q -0.21028,0.25442 -0.44652,0.37643 -0.23365,0.11942 -0.51662,0.11942 -0.50363,0 -0.76842,-0.30893 -0.26221,-0.30893 -0.26221,-0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7918" />
+ <path
+ d="m -194.824,-277.83822 v 1.7705 h -0.93458 v -0.28816 -1.06697 q 0,-0.37643 -0.0182,-0.51921 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14798,-0.14019 -0.0935,-0.0519 -0.21287,-0.0519 -0.29076,0 -0.45691,0.22586 -0.16614,0.22326 -0.16614,0.62045 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12201 0.5218,-0.12201 0.50363,0 0.76324,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7920" />
+ <path
+ d="m -191.6127,-278.88443 v 0.75805 q -0.18951,-0.1298 -0.38162,-0.19211 -0.18951,-0.0623 -0.3946,-0.0623 -0.3894,0 -0.60747,0.22845 -0.21547,0.22585 -0.21547,0.63343 0,0.40758 0.21547,0.63603 0.21807,0.22586 0.60747,0.22586 0.21807,0 0.41278,-0.0649 0.1973,-0.0649 0.36344,-0.19211 v 0.76064 q -0.21807,0.0805 -0.44392,0.11942 -0.22326,0.0415 -0.44912,0.0415 -0.7866,0 -1.23052,-0.40239 -0.44393,-0.40498 -0.44393,-1.12409 0,-0.7191 0.44393,-1.12149 0.44392,-0.40498 1.23052,-0.40498 0.22845,0 0.44912,0.0415 0.22326,0.0389 0.44392,0.11941 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7922" />
+ <path
+ d="m -188.918,-279.94361 h 1.27206 l 0.88265,2.07424 0.88785,-2.07424 h 1.26947 v 3.87589 h -0.94496 v -2.83488 l -0.89304,2.08982 h -0.63344 l -0.89304,-2.08982 v 2.83488 h -0.94755 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7924" />
+ <path
+ d="m -182.36558,-277.37612 q -0.29076,0 -0.43874,0.0987 -0.14537,0.0987 -0.14537,0.29075 0,0.17653 0.11682,0.27778 0.11942,0.0986 0.3297,0.0986 0.2622,0 0.44132,-0.18692 0.17913,-0.18951 0.17913,-0.47248 v -0.10643 z m 1.42003,-0.35047 v 1.65887 h -0.93717 v -0.43094 q -0.18691,0.2648 -0.42056,0.38681 -0.23364,0.11942 -0.56853,0.11942 -0.45171,0 -0.73468,-0.2622 -0.28038,-0.2648 -0.28038,-0.68536 0,-0.51142 0.35047,-0.75026 0.35306,-0.23883 1.10591,-0.23883 h 0.54777 v -0.0727 q 0,-0.22066 -0.17393,-0.32191 -0.17394,-0.10384 -0.54258,-0.10384 -0.29854,0 -0.55555,0.0597 -0.25701,0.0597 -0.47767,0.17912 v -0.70872 q 0.29854,-0.0727 0.59968,-0.10903 0.30114,-0.0389 0.60228,-0.0389 0.78661,0 1.13448,0.31152 0.35046,0.30893 0.35046,1.00727 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7926" />
+ <path
+ d="m -177.73164,-278.88443 v 0.75805 q -0.18951,-0.1298 -0.38162,-0.19211 -0.18951,-0.0623 -0.3946,-0.0623 -0.38941,0 -0.60748,0.22845 -0.21547,0.22585 -0.21547,0.63343 0,0.40758 0.21547,0.63603 0.21807,0.22586 0.60748,0.22586 0.21807,0 0.41277,-0.0649 0.1973,-0.0649 0.36345,-0.19211 v 0.76064 q -0.21807,0.0805 -0.44393,0.11942 -0.22326,0.0415 -0.44911,0.0415 -0.7866,0 -1.23053,-0.40239 -0.44392,-0.40498 -0.44392,-1.12409 0,-0.7191 0.44392,-1.12149 0.44393,-0.40498 1.23053,-0.40498 0.22845,0 0.44911,0.0415 0.22326,0.0389 0.44393,0.11941 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7928" />
+ <path
+ d="m -174.00632,-277.83822 v 1.7705 h -0.93457 v -0.28816 -1.06178 q 0,-0.38162 -0.0182,-0.5244 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14797,-0.14019 -0.0935,-0.0519 -0.21288,-0.0519 -0.29076,0 -0.4569,0.22586 -0.16615,0.22326 -0.16615,0.62045 v 1.43042 h -0.92938 v -4.03944 h 0.92938 v 1.55762 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12201 0.5218,-0.12201 0.50364,0 0.76324,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7930" />
+ <path
+ d="m -173.14443,-278.97529 h 0.92938 v 2.90757 h -0.92938 z m 0,-1.13187 h 0.92938 v 0.75804 h -0.92938 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7932" />
+ <path
+ d="m -168.39886,-277.83822 v 1.7705 h -0.93458 v -0.28816 -1.06697 q 0,-0.37643 -0.0182,-0.51921 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14798,-0.14019 -0.0935,-0.0519 -0.21287,-0.0519 -0.29076,0 -0.45691,0.22586 -0.16614,0.22326 -0.16614,0.62045 v 1.43042 h -0.92939 v -2.90757 h 0.92939 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12201 0.5218,-0.12201 0.50363,0 0.76324,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7934" />
+ <path
+ d="m -164.6346,-277.52929 v 0.2648 h -2.17289 q 0.0337,0.3271 0.23624,0.49065 0.20249,0.16355 0.56594,0.16355 0.29335,0 0.59968,-0.0857 0.30893,-0.0883 0.63344,-0.2648 v 0.71651 q -0.3297,0.12461 -0.6594,0.18692 -0.32969,0.0649 -0.65939,0.0649 -0.7892,0 -1.22793,-0.39979 -0.43614,-0.40239 -0.43614,-1.12669 0,-0.71131 0.42835,-1.11889 0.43095,-0.40758 1.1838,-0.40758 0.68535,0 1.09553,0.41277 0.41277,0.41277 0.41277,1.10332 z m -0.95534,-0.30893 q 0,-0.2648 -0.15577,-0.42575 -0.15316,-0.16355 -0.40238,-0.16355 -0.26999,0 -0.43874,0.15316 -0.16874,0.15057 -0.21028,0.43614 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7936" />
+ <path
+ d="m -161.77116,-278.18349 q -0.12201,-0.0571 -0.24403,-0.0831 -0.11941,-0.0285 -0.24143,-0.0285 -0.35825,0 -0.55296,0.23104 -0.1921,0.22846 -0.1921,0.6568 v 1.33956 h -0.92939 v -2.90757 h 0.92939 v 0.47767 q 0.17912,-0.28556 0.41017,-0.41536 0.23365,-0.1324 0.55815,-0.1324 0.0467,0 0.10125,0.005 0.0545,0.003 0.15836,0.0156 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7938" />
+ <path
+ d="m -161.69068,-278.97529 h 0.92938 l 0.78141,1.973 0.66459,-1.973 h 0.92938 l -1.22274,3.18275 q -0.18431,0.48546 -0.43094,0.67757 -0.24403,0.1947 -0.64641,0.1947 h -0.53739 v -0.61007 h 0.29076 q 0.23624,0 0.34268,-0.0753 0.10903,-0.0753 0.16874,-0.26999 l 0.026,-0.0805 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7940" />
+ <path
+ d="m -154.43473,-275.36679 h -0.77103 q -0.39719,-0.64122 -0.58671,-1.21754 -0.18951,-0.57892 -0.18951,-1.14745 0,-0.56854 0.18951,-1.15005 0.19211,-0.58411 0.58671,-1.22014 h 0.77103 q -0.3323,0.61526 -0.49844,1.20456 -0.16615,0.58671 -0.16615,1.16044 0,0.57372 0.16355,1.16302 0.16615,0.58931 0.50104,1.20716 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7942" />
+ <path
+ d="m -153.82207,-278.97529 h 0.90342 l 0.48806,2.00415 0.49065,-2.00415 h 0.77622 l 0.48805,1.98338 0.49066,-1.98338 h 0.90342 l -0.76583,2.90757 h -1.01506 l -0.49065,-1.99895 -0.48806,1.99895 h -1.01505 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7944" />
+ <path
+ d="m -148.65075,-278.97529 h 0.92939 v 2.90757 h -0.92939 z m 0,-1.13187 h 0.92939 v 0.75804 h -0.92939 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7946" />
+ <path
+ d="m -145.81327,-279.80083 v 0.82554 h 0.95794 v 0.66459 h -0.95794 v 1.23312 q 0,0.20249 0.0805,0.27518 0.0805,0.0701 0.31931,0.0701 h 0.47768 v 0.66459 h -0.79699 q -0.55036,0 -0.78141,-0.22845 -0.22845,-0.23105 -0.22845,-0.78141 v -1.23312 h -0.4621 v -0.66459 h 0.4621 v -0.82554 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7948" />
+ <path
+ d="m -141.36365,-277.83822 v 1.7705 h -0.93457 v -0.28816 -1.06178 q 0,-0.38162 -0.0182,-0.5244 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14797,-0.14019 -0.0935,-0.0519 -0.21288,-0.0519 -0.29076,0 -0.4569,0.22586 -0.16615,0.22326 -0.16615,0.62045 v 1.43042 h -0.92938 v -4.03944 h 0.92938 v 1.55762 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12201 0.5218,-0.12201 0.50364,0 0.76324,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7950" />
+ <path
+ d="m -140.50176,-278.97529 h 0.92938 v 2.90757 h -0.92938 z m 0,-1.13187 h 0.92938 v 0.75804 h -0.92938 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7952" />
+ <path
+ d="m -135.7562,-277.83822 v 1.7705 h -0.93457 v -0.28816 -1.06697 q 0,-0.37643 -0.0182,-0.51921 -0.0156,-0.14278 -0.0571,-0.21028 -0.0545,-0.0909 -0.14797,-0.14019 -0.0935,-0.0519 -0.21288,-0.0519 -0.29075,0 -0.4569,0.22586 -0.16615,0.22326 -0.16615,0.62045 v 1.43042 h -0.92938 v -2.90757 h 0.92938 v 0.42575 q 0.21028,-0.25441 0.44652,-0.37383 0.23624,-0.12201 0.52181,-0.12201 0.50363,0 0.76323,0.30893 0.2622,0.30893 0.2622,0.89823 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path7954" />
+ <path
+ d="m -131.30864,-276.88294 h -1.10696 l -0.19903,0.81522 h -0.9352 l 1.15604,-3.77894 h 1.08515 l 1.15605,3.77894 h -0.95701 z m -0.96518,-0.64891 h 0.81795 l -0.40897,-1.67136 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7956" />
+ <path
+ d="m -129.80906,-276.06772 v -0.57802 h 0.38171 v -1.74497 h -0.38171 v -0.57256 h 1.0388 l 0.15814,0.65163 q 0.15541,-0.37353 0.39534,-0.55621 0.24266,-0.18267 0.59165,-0.18267 0.14723,0 0.26175,0.0245 0.11451,0.0218 0.21539,0.0627 l -0.16086,1.21057 h -0.53985 v -0.5344 q -0.24539,0.0436 -0.43079,0.2672 -0.1854,0.22085 -0.28628,0.5453 v 0.82886 h 0.57256 v 0.57802 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7958" />
+ <path
+ d="m -126.53725,-276.06772 v -0.57802 h 0.38171 v -1.74497 h -0.38171 v -0.57256 h 1.0388 l 0.15814,0.65163 q 0.15541,-0.37353 0.39534,-0.55621 0.24266,-0.18267 0.59166,-0.18267 0.14723,0 0.26174,0.0245 0.11451,0.0218 0.2154,0.0627 l -0.16087,1.21057 h -0.53985 v -0.5344 q -0.24538,0.0436 -0.43079,0.2672 -0.1854,0.22085 -0.28628,0.5453 v 0.82886 h 0.57257 v 0.57802 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7960" />
+ <path
+ d="m -120.85521,-276.90203 q 0,0.16359 0.0436,0.23721 0.0464,0.0736 0.14723,0.11178 l -0.17723,0.56712 q -0.25629,-0.0245 -0.43351,-0.11179 -0.1745,-0.09 -0.27538,-0.26992 -0.16632,0.19903 -0.42534,0.29719 -0.25901,0.0954 -0.52894,0.0954 -0.44715,0 -0.71435,-0.25356 -0.26447,-0.25629 -0.26447,-0.65709 0,-0.47169 0.36808,-0.72798 0.37081,-0.25629 1.04153,-0.25629 h 0.38989 v -0.10906 q 0,-0.44442 -0.57257,-0.44442 -0.13905,0 -0.35717,0.0409 -0.21812,0.0382 -0.43624,0.11179 l -0.19904,-0.57257 q 0.28083,-0.10633 0.58348,-0.16086 0.30537,-0.0545 0.5453,-0.0545 0.64618,0 0.95428,0.26447 0.31082,0.26174 0.31082,0.75797 z m -1.35235,0.31082 q 0.13905,0 0.29174,-0.0818 0.15268,-0.0845 0.23175,-0.23721 v -0.46896 h -0.21267 q -0.3599,0 -0.52894,0.11179 -0.16904,0.10906 -0.16904,0.32173 0,0.16631 0.10088,0.26174 0.1036,0.0927 0.28628,0.0927 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7962" />
+ <path
+ d="m -117.28349,-278.96327 -0.96518,2.89555 q -0.19086,0.5753 -0.57802,0.87521 -0.38444,0.29992 -1.04426,0.33809 l -0.0982,-0.60801 q 0.28628,-0.0355 0.46078,-0.10634 0.17722,-0.0709 0.28356,-0.19358 0.10906,-0.11996 0.18812,-0.30537 h -0.29446 l -0.91883,-2.89555 h 0.91065 l 0.56166,2.3448 0.61074,-2.3448 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7964" />
+ <path
+ d="m -114.16709,-279.84666 0.21267,3.77894 h -0.77978 l -0.0464,-1.61682 q -0.008,-0.29992 -0.005,-0.52076 0.005,-0.22085 0.0191,-0.42261 0.0136,-0.20449 0.0327,-0.45806 l -0.42534,2.3748 h -0.67617 l -0.45806,-2.3748 q 0.0218,0.23721 0.0354,0.44715 0.0136,0.20722 0.0164,0.43624 0.005,0.22903 0,0.53167 l -0.0273,1.60319 h -0.76615 l 0.21267,-3.77894 h 0.91883 l 0.41989,2.44295 0.39807,-2.44295 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7966" />
+ <path
+ d="m -112.73022,-277.26466 q 0.0436,0.35445 0.23175,0.50986 0.18813,0.15269 0.46351,0.15269 0.19903,0 0.38443,-0.0654 0.18541,-0.0654 0.35718,-0.1745 l 0.34626,0.46896 q -0.20448,0.1745 -0.49622,0.28629 -0.28901,0.11178 -0.65982,0.11178 -0.49622,0 -0.83158,-0.19631 -0.33536,-0.19903 -0.50441,-0.5453 -0.16904,-0.34626 -0.16904,-0.79614 0,-0.42806 0.16359,-0.77706 0.16359,-0.35172 0.47714,-0.55893 0.31627,-0.20994 0.7716,-0.20994 0.41443,0 0.71707,0.17722 0.30537,0.17722 0.47169,0.50986 0.16905,0.33263 0.16905,0.79887 0,0.0736 -0.005,0.15814 -0.003,0.0845 -0.0109,0.14995 z m 0.53439,-1.21602 q -0.23175,0 -0.37353,0.16632 -0.14178,0.16631 -0.17177,0.53167 h 1.06334 q -0.003,-0.31628 -0.12269,-0.50714 -0.11997,-0.19085 -0.39535,-0.19085 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7968" />
+ <path
+ d="m -107.59894,-276.23676 q -0.16904,0.10906 -0.40898,0.1854 -0.23993,0.0763 -0.53984,0.0763 -0.56712,0 -0.8425,-0.28901 -0.27538,-0.29173 -0.27538,-0.79069 v -1.31417 h -0.60801 v -0.59438 h 0.60801 v -0.6271 l 0.86158,-0.10361 v 0.73071 h 0.93247 l -0.0845,0.59438 h -0.84795 v 1.31417 q 0,0.2154 0.0982,0.3081 0.0982,0.0927 0.31355,0.0927 0.15268,0 0.2781,-0.0354 0.12815,-0.0382 0.22903,-0.0954 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7970" />
+ <path
+ d="m -106.07209,-280.19838 v 1.52139 q 0.36262,-0.38171 0.85067,-0.38171 0.38716,0 0.59165,0.2263 0.20449,0.2263 0.20449,0.638 v 2.12668 h -0.86158 v -1.88674 q 0,-0.26175 -0.06,-0.36536 -0.0573,-0.1036 -0.21812,-0.1036 -0.13633,0 -0.26175,0.0954 -0.12269,0.0927 -0.24538,0.2563 v 2.00398 h -0.86158 v -4.04614 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7972" />
+ <path
+ d="m -102.40767,-279.0587 q 0.44715,0 0.7607,0.19085 0.31354,0.19086 0.47986,0.53713 0.16632,0.34354 0.16632,0.80704 0,0.72526 -0.37081,1.13696 -0.3708,0.4117 -1.03607,0.4117 -0.66527,0 -1.03608,-0.40625 -0.3708,-0.40625 -0.3708,-1.13695 0,-0.46078 0.16632,-0.80705 0.16904,-0.34627 0.48259,-0.53985 0.31627,-0.19358 0.75797,-0.19358 z m 0,0.63528 q -0.26447,0 -0.39262,0.21812 -0.12542,0.21539 -0.12542,0.68708 0,0.47986 0.12542,0.69526 0.12815,0.21539 0.39262,0.21539 0.26447,0 0.38989,-0.21539 0.12815,-0.2154 0.12815,-0.70072 0,-0.46896 -0.12815,-0.68435 -0.12542,-0.21539 -0.38989,-0.21539 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7974" />
+ <path
+ d="m -98.743249,-280.20384 0.861578,0.09 v 4.04614 h -0.763423 l -0.04363,-0.319 q -0.119966,0.16904 -0.319002,0.29174 -0.199035,0.11996 -0.482592,0.11996 -0.3599,0 -0.597107,-0.19358 -0.23448,-0.19358 -0.35172,-0.53985 -0.11451,-0.34899 -0.11451,-0.81523 0,-0.44714 0.13905,-0.79341 0.13905,-0.34627 0.39807,-0.54258 0.259018,-0.19903 0.616192,-0.19903 0.389891,0 0.657089,0.2672 z m -0.425336,1.77496 q -0.223574,0 -0.359899,0.21267 -0.136326,0.20994 -0.136326,0.69799 0,0.35717 0.05726,0.55621 0.05726,0.19631 0.158137,0.27537 0.100881,0.0791 0.231754,0.0791 0.144505,0 0.261745,-0.09 0.119967,-0.09 0.212668,-0.24539 v -1.24874 q -0.08997,-0.11179 -0.190856,-0.1745 -0.100881,-0.0627 -0.23448,-0.0627 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7976" />
+ <path
+ d="m -95.648667,-277.97628 q 0,-0.44987 -0.106334,-0.8234 -0.106334,-0.37626 -0.335361,-0.73344 -0.226301,-0.3599 -0.59438,-0.75797 l 0.501678,-0.4526 q 0.430789,0.37081 0.747065,0.78251 0.316275,0.41171 0.488046,0.89975 0.17177,0.48805 0.17177,1.08515 0,0.59711 -0.17177,1.08516 -0.171771,0.48804 -0.488046,0.89974 -0.316276,0.41171 -0.747065,0.78251 l -0.501678,-0.4526 q 0.294463,-0.319 0.493499,-0.59438 0.199035,-0.2781 0.319002,-0.5453 0.119966,-0.2672 0.17177,-0.55076 0.0518,-0.28628 0.0518,-0.62437 z"
+ style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold'"
+ id="path7978" />
+ </g>
+ <g
+ aria-label="Promoter"
+ transform="scale(-1)"
+ id="text5366"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.3167px;line-height:1.25;font-family:fira;-inkscape-font-specification:fira;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 23.637677,-208.1394 q 0,0.43896 -0.188129,0.71979 -0.18813,0.27811 -0.523491,0.41171 -0.332634,0.13087 -0.771603,0.13087 h -0.433516 v 1.306 h -0.747064 v -3.77077 h 1.109691 q 0.733432,0 1.142409,0.29719 0.411703,0.29719 0.411703,0.90521 z m -0.77433,0.005 q 0,-0.349 -0.199035,-0.50441 -0.199036,-0.15813 -0.553482,-0.15813 h -0.389892 v 1.36598 h 0.411704 q 0.332634,0 0.53167,-0.15814 0.199035,-0.16086 0.199035,-0.5453 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8065" />
+ <path
+ d="m 24.27022,-205.57103 v -0.49895 h 0.406251 v -1.8922 H 24.27022 v -0.49623 h 0.95428 l 0.133599,0.66255 q 0.158138,-0.36536 0.398071,-0.55349 0.239933,-0.18813 0.602559,-0.18813 0.139052,0 0.245386,0.0218 0.106334,0.0218 0.207215,0.0573 l -0.128146,1.12605 h -0.479866 v -0.56439 q -0.280831,0.0245 -0.485319,0.2563 -0.204489,0.22902 -0.321729,0.60528 v 0.96519 h 0.575294 v 0.49895 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8067" />
+ <path
+ d="m 28.714428,-208.5402 q 0.430789,0 0.730706,0.18813 0.299916,0.18813 0.455327,0.53167 0.158138,0.34081 0.158138,0.79887 0,0.70344 -0.35172,1.11787 -0.35172,0.41443 -0.995177,0.41443 -0.643457,0 -0.995177,-0.40625 -0.35172,-0.40898 -0.35172,-1.1206 0,-0.4526 0.158137,-0.79614 0.158138,-0.34354 0.458054,-0.5344 0.302643,-0.19358 0.733432,-0.19358 z m 0,0.54257 q -0.302643,0 -0.452601,0.23721 -0.147231,0.23721 -0.147231,0.74434 0,0.51258 0.147231,0.74979 0.147232,0.23448 0.449875,0.23448 0.302643,0 0.449875,-0.23448 0.147231,-0.23721 0.147231,-0.75524 0,-0.50441 -0.147231,-0.73889 -0.147232,-0.23721 -0.447149,-0.23721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8069" />
+ <path
+ d="m 32.839635,-208.5402 q 0.272651,0 0.430789,0.18267 0.158137,0.17995 0.158137,0.64619 v 2.14031 h -0.627098 v -2.05034 q 0,-0.19358 -0.02999,-0.27538 -0.02999,-0.0845 -0.141779,-0.0845 -0.08998,0 -0.182676,0.0545 -0.0927,0.0518 -0.18813,0.18813 v 2.16758 h -0.542576 v -2.05034 q 0,-0.19358 -0.02999,-0.27538 -0.02999,-0.0845 -0.141779,-0.0845 -0.08997,0 -0.182676,0.0545 -0.0927,0.0518 -0.18813,0.18813 v 2.16758 h -0.635277 v -2.88738 h 0.537123 l 0.04635,0.29992 q 0.128146,-0.17722 0.269924,-0.2781 0.141779,-0.10361 0.340814,-0.10361 0.163591,0 0.289011,0.0818 0.128146,0.0791 0.182676,0.27265 0.12542,-0.15813 0.278104,-0.25629 0.155412,-0.0982 0.357174,-0.0982 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8071" />
+ <path
+ d="m 35.258044,-208.5402 q 0.430789,0 0.730705,0.18813 0.299917,0.18813 0.455328,0.53167 0.158138,0.34081 0.158138,0.79887 0,0.70344 -0.351721,1.11787 -0.35172,0.41443 -0.995177,0.41443 -0.643457,0 -0.995177,-0.40625 -0.35172,-0.40898 -0.35172,-1.1206 0,-0.4526 0.158138,-0.79614 0.158137,-0.34354 0.458054,-0.5344 0.302643,-0.19358 0.733432,-0.19358 z m 0,0.54257 q -0.302643,0 -0.452601,0.23721 -0.147232,0.23721 -0.147232,0.74434 0,0.51258 0.147232,0.74979 0.147231,0.23448 0.449874,0.23448 0.302643,0 0.449875,-0.23448 0.147232,-0.23721 0.147232,-0.75524 0,-0.50441 -0.147232,-0.73889 -0.147232,-0.23721 -0.447148,-0.23721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8073" />
+ <path
+ d="m 39.822219,-205.73189 q -0.160864,0.10633 -0.389891,0.17449 -0.229027,0.0682 -0.496225,0.0682 -0.528944,0 -0.796142,-0.27266 -0.267198,-0.27537 -0.267198,-0.7307 v -1.45596 h -0.627098 v -0.50986 h 0.627098 v -0.63527 l 0.719799,-0.0872 v 0.72252 h 0.95428 l -0.07362,0.50986 h -0.880664 v 1.45323 q 0,0.22358 0.109061,0.32718 0.10906,0.10361 0.35172,0.10361 0.155411,0 0.283557,-0.0354 0.130873,-0.0382 0.237207,-0.0954 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8075" />
+ <path
+ d="m 41.215459,-206.79523 q 0.03272,0.40625 0.239933,0.5862 0.207215,0.17995 0.504405,0.17995 0.207215,0 0.389891,-0.0654 0.182677,-0.0654 0.3599,-0.18268 l 0.299916,0.41171 q -0.201762,0.16904 -0.482592,0.27265 -0.278105,0.10361 -0.613466,0.10361 -0.46896,0 -0.790689,-0.19359 -0.319002,-0.19358 -0.482592,-0.53712 -0.163591,-0.34354 -0.163591,-0.79069 0,-0.43079 0.158138,-0.77705 0.160864,-0.34627 0.463507,-0.54803 0.305369,-0.20449 0.733432,-0.20449 0.59438,0 0.943373,0.38716 0.348994,0.38717 0.348994,1.07152 0,0.15814 -0.01363,0.28629 z m 0.618918,-1.23784 q -0.261745,0 -0.430789,0.18813 -0.166317,0.18813 -0.196309,0.58893 h 1.216025 q -0.0055,-0.36536 -0.149958,-0.56985 -0.144505,-0.20721 -0.438969,-0.20721 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8077" />
+ <path
+ d="m 43.901065,-205.57103 v -0.49895 h 0.406251 v -1.8922 h -0.406251 v -0.49623 h 0.95428 l 0.133599,0.66255 q 0.158138,-0.36536 0.398071,-0.55349 0.239933,-0.18813 0.602559,-0.18813 0.139052,0 0.245386,0.0218 0.106334,0.0218 0.207215,0.0573 l -0.128146,1.12605 h -0.479866 v -0.56439 q -0.280831,0.0245 -0.485319,0.2563 -0.204489,0.22902 -0.321729,0.60528 v 0.96519 h 0.575294 v 0.49895 z"
+ style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Semi-Bold';fill:#000080;fill-opacity:1;stroke-width:0.398751"
+ id="path8079" />
+ </g>
+ </g>
+ <g
+ aria-label="Inputs"
+ id="text1097"
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#008100;fill-opacity:1;stroke-width:0.505891">
+ <path
+ d="m 72.923006,56.52514 h 0.665298 v 4.917277 h -0.665298 z"
+ style="fill:#008100;fill-opacity:1;stroke-width:0.505891"
+ id="path8166" />
+ <path
+ d="m 77.952264,59.215974 v 2.226443 H 77.34625 v -2.206682 q 0,-0.523675 -0.2042,-0.783866 -0.204201,-0.26019 -0.612601,-0.26019 -0.49074,0 -0.773986,0.312887 -0.283246,0.312888 -0.283246,0.853031 v 2.08482 H 74.86291 v -3.688781 h 0.609307 v 0.573078 q 0.217375,-0.332649 0.510501,-0.497326 0.29642,-0.164678 0.681766,-0.164678 0.635656,0 0.961718,0.395226 0.326062,0.391933 0.326062,1.156038 z"
+ style="fill:#008100;fill-opacity:1;stroke-width:0.505891"
+ id="path8168" />
+ <path
+ d="m 79.747251,60.8891 v 1.956371 h -0.609307 v -5.091835 h 0.609307 v 0.559904 q 0.191026,-0.329355 0.480859,-0.487446 0.293127,-0.161384 0.698234,-0.161384 0.671885,0 1.090167,0.533556 0.421575,0.533556 0.421575,1.403054 0,0.869498 -0.421575,1.403054 -0.418282,0.533556 -1.090167,0.533556 -0.405107,0 -0.698234,-0.15809 -0.289833,-0.161385 -0.480859,-0.49074 z m 2.061766,-1.28778 q 0,-0.668592 -0.276659,-1.04735 -0.273365,-0.382053 -0.754224,-0.382053 -0.480859,0 -0.757518,0.382053 -0.273365,0.378758 -0.273365,1.04735 0,0.668592 0.273365,1.050644 0.276659,0.378759 0.757518,0.378759 0.480859,0 0.754224,-0.378759 0.276659,-0.382052 0.276659,-1.050644 z"
+ style="fill:#008100;fill-opacity:1;stroke-width:0.505891"
+ id="path8170" />
+ <path
+ d="m 83.380042,59.986666 v -2.23303 h 0.606015 v 2.209975 q 0,0.523675 0.2042,0.78716 0.2042,0.26019 0.612601,0.26019 0.49074,0 0.773985,-0.312887 0.28654,-0.312888 0.28654,-0.853031 v -2.091407 h 0.606014 v 3.688781 h -0.606014 v -0.566491 q -0.220668,0.335942 -0.513795,0.50062 -0.289833,0.161384 -0.675179,0.161384 -0.635656,0 -0.965011,-0.395226 -0.329356,-0.395227 -0.329356,-1.156038 z"
+ style="fill:#008100;fill-opacity:1;stroke-width:0.505891"
+ id="path8172" />
+ <path
+ d="m 88.317081,56.706285 v 1.047351 h 1.248257 v 0.470978 h -1.248257 v 2.002481 q 0,0.451217 0.121861,0.579666 0.125156,0.128449 0.503914,0.128449 h 0.622482 v 0.507207 h -0.622482 q -0.701527,0 -0.968305,-0.260191 -0.266778,-0.263484 -0.266778,-0.955131 v -2.002481 h -0.44463 v -0.470978 h 0.44463 v -1.047351 z"
+ style="fill:#008100;fill-opacity:1;stroke-width:0.505891"
+ id="path8174" />
+ <path
+ d="m 92.713977,57.862323 v 0.573079 q -0.256897,-0.131743 -0.533556,-0.197614 -0.276659,-0.06587 -0.573079,-0.06587 -0.451217,0 -0.678472,0.13833 -0.223962,0.138329 -0.223962,0.414987 0,0.210788 0.161385,0.332649 0.161384,0.118568 0.64883,0.227256 l 0.207494,0.04611 q 0.645537,0.138329 0.915608,0.391933 0.273365,0.25031 0.273365,0.701527 0,0.513794 -0.408401,0.813508 -0.405107,0.299713 -1.116515,0.299713 -0.29642,0 -0.619188,-0.05928 -0.319475,-0.05599 -0.675179,-0.171265 v -0.625775 q 0.335943,0.174558 0.662005,0.263484 0.326062,0.08563 0.645537,0.08563 0.428162,0 0.65871,-0.144917 0.230549,-0.14821 0.230549,-0.414988 0,-0.247016 -0.167971,-0.378758 -0.164678,-0.131742 -0.727876,-0.253604 l -0.210787,-0.0494 q -0.563198,-0.118568 -0.813508,-0.362291 -0.25031,-0.247017 -0.25031,-0.675179 0,-0.520382 0.368878,-0.803627 0.368878,-0.283246 1.04735,-0.283246 0.335943,0 0.632363,0.0494 0.29642,0.0494 0.54673,0.14821 z"
+ style="fill:#008100;fill-opacity:1;stroke-width:0.505891"
+ id="path8176" />
+ </g>
+ <g
+ aria-label="Output"
+ id="text1101"
+ style="font-size:6.7452px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#d99b00;fill-opacity:1;stroke-width:0.505891">
+ <path
+ d="m 153.15762,56.976357 q -0.72458,0 -1.15274,0.540143 -0.42487,0.540143 -0.42487,1.472219 0,0.928782 0.42487,1.468925 0.42816,0.540143 1.15274,0.540143 0.72459,0 1.14616,-0.540143 0.42487,-0.540143 0.42487,-1.468925 0,-0.932076 -0.42487,-1.472219 -0.42157,-0.540143 -1.14616,-0.540143 z m 0,-0.540143 q 1.03418,0 1.65337,0.69494 0.61919,0.691646 0.61919,1.857565 0,1.162625 -0.61919,1.857565 -0.61919,0.691646 -1.65337,0.691646 -1.03747,0 -1.65995,-0.691646 -0.61919,-0.691647 -0.61919,-1.857565 0,-1.165919 0.61919,-1.857565 0.62248,-0.69494 1.65995,-0.69494 z"
+ style="fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ id="path8263" />
+ <path
+ d="m 156.38201,59.986666 v -2.23303 h 0.60602 v 2.209975 q 0,0.523675 0.2042,0.78716 0.2042,0.26019 0.6126,0.26019 0.49074,0 0.77399,-0.312887 0.28653,-0.312888 0.28653,-0.853031 v -2.091407 h 0.60602 v 3.688781 h -0.60602 v -0.566491 q -0.22066,0.335942 -0.51379,0.50062 -0.28983,0.161384 -0.67518,0.161384 -0.63565,0 -0.96501,-0.395226 -0.32936,-0.395227 -0.32936,-1.156038 z"
+ style="fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ id="path8265" />
+ <path
+ d="m 161.31905,56.706285 v 1.047351 h 1.24826 v 0.470978 h -1.24826 v 2.002481 q 0,0.451217 0.12186,0.579666 0.12516,0.128449 0.50392,0.128449 h 0.62248 v 0.507207 h -0.62248 q -0.70153,0 -0.96831,-0.260191 -0.26678,-0.263484 -0.26678,-0.955131 v -2.002481 h -0.44463 v -0.470978 h 0.44463 v -1.047351 z"
+ style="fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ id="path8267" />
+ <path
+ d="m 163.9506,60.8891 v 1.956371 h -0.6093 v -5.091835 h 0.6093 v 0.559904 q 0.19103,-0.329355 0.48086,-0.487446 0.29313,-0.161384 0.69824,-0.161384 0.67188,0 1.09016,0.533556 0.42158,0.533556 0.42158,1.403054 0,0.869498 -0.42158,1.403054 -0.41828,0.533556 -1.09016,0.533556 -0.40511,0 -0.69824,-0.15809 -0.28983,-0.161385 -0.48086,-0.49074 z m 2.06177,-1.28778 q 0,-0.668592 -0.27666,-1.04735 -0.27337,-0.382053 -0.75422,-0.382053 -0.48086,0 -0.75752,0.382053 -0.27337,0.378758 -0.27337,1.04735 0,0.668592 0.27337,1.050644 0.27666,0.378759 0.75752,0.378759 0.48085,0 0.75422,-0.378759 0.27666,-0.382052 0.27666,-1.050644 z"
+ style="fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ id="path8269" />
+ <path
+ d="m 167.58339,59.986666 v -2.23303 h 0.60602 v 2.209975 q 0,0.523675 0.2042,0.78716 0.2042,0.26019 0.6126,0.26019 0.49074,0 0.77398,-0.312887 0.28654,-0.312888 0.28654,-0.853031 v -2.091407 h 0.60602 v 3.688781 h -0.60602 v -0.566491 q -0.22066,0.335942 -0.51379,0.50062 -0.28983,0.161384 -0.67518,0.161384 -0.63566,0 -0.96501,-0.395226 -0.32936,-0.395227 -0.32936,-1.156038 z"
+ style="fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ id="path8271" />
+ <path
+ d="m 172.52043,56.706285 v 1.047351 h 1.24826 v 0.470978 h -1.24826 v 2.002481 q 0,0.451217 0.12186,0.579666 0.12516,0.128449 0.50392,0.128449 h 0.62248 v 0.507207 h -0.62248 q -0.70153,0 -0.96831,-0.260191 -0.26678,-0.263484 -0.26678,-0.955131 v -2.002481 h -0.44463 v -0.470978 h 0.44463 v -1.047351 z"
+ style="fill:#d99b00;fill-opacity:1;stroke-width:0.505891"
+ id="path8273" />
+ </g>
+ <g
+ aria-label="… including correct
+output descriptor"
+ id="text1791"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000080;stroke-width:0.398751">
+ <path
+ d="m 95.177533,230.17717 h 0.550362 v 0.65939 h -0.550362 z m 1.767907,0 h 0.552957 v 0.65939 H 96.94544 Z m -3.538409,0 h 0.552957 v 0.65939 h -0.552957 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8360" />
+ <path
+ d="m 100.30213,227.92899 h 0.47767 v 2.90757 h -0.47767 z m 0,-1.13187 h 0.47767 v 0.60488 h -0.47767 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8362" />
+ <path
+ d="m 104.19619,229.08164 v 1.75492 h -0.47767 v -1.73935 q 0,-0.41277 -0.16095,-0.61786 -0.16096,-0.20508 -0.48287,-0.20508 -0.38681,0 -0.61007,0.24662 -0.22326,0.24663 -0.22326,0.67238 v 1.64329 h -0.48027 v -2.90757 h 0.48027 v 0.45171 q 0.17134,-0.2622 0.40239,-0.392 0.23364,-0.1298 0.53738,-0.1298 0.50104,0 0.75805,0.31152 0.257,0.30893 0.257,0.91122 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8364" />
+ <path
+ d="m 107.24135,228.04062 v 0.44652 q -0.20249,-0.11163 -0.40757,-0.16614 -0.2025,-0.0571 -0.41018,-0.0571 -0.46469,0 -0.7217,0.29595 -0.25701,0.29335 -0.25701,0.82554 0,0.53219 0.25701,0.82814 0.25701,0.29336 0.7217,0.29336 0.20768,0 0.41018,-0.0545 0.20508,-0.0571 0.40757,-0.16874 v 0.44132 q -0.19989,0.0935 -0.41536,0.14019 -0.21288,0.0467 -0.45431,0.0467 -0.6568,0 -1.04361,-0.41277 -0.38681,-0.41277 -0.38681,-1.11371 0,-0.71131 0.38941,-1.11889 0.392,-0.40758 1.07216,-0.40758 0.22067,0 0.43095,0.0467 0.21027,0.0441 0.40757,0.13499 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8366" />
+ <path
+ d="m 108.07209,226.79712 h 0.47767 v 4.03944 h -0.47767 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8368" />
+ <path
+ d="m 109.49991,229.68911 v -1.76012 h 0.47768 v 1.74195 q 0,0.41277 0.16095,0.62045 0.16096,0.20509 0.48286,0.20509 0.38682,0 0.61008,-0.24662 0.22585,-0.24663 0.22585,-0.67238 v -1.64849 h 0.47767 v 2.90757 h -0.47767 v -0.44652 q -0.17393,0.2648 -0.40498,0.3946 -0.22845,0.12721 -0.53219,0.12721 -0.50104,0 -0.76064,-0.31153 -0.25961,-0.31152 -0.25961,-0.91121 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8370" />
+ <path
+ d="m 114.83219,228.37032 v -1.5732 h 0.47767 v 4.03944 h -0.47767 v -0.43613 q -0.15057,0.2596 -0.38162,0.38681 -0.22845,0.12461 -0.55036,0.12461 -0.527,0 -0.85929,-0.42056 -0.3297,-0.42056 -0.3297,-1.10592 0,-0.68535 0.3297,-1.10591 0.33229,-0.42056 0.85929,-0.42056 0.32191,0 0.55036,0.12721 0.23105,0.12461 0.38162,0.38421 z m -1.62772,1.01505 q 0,0.527 0.21547,0.82814 0.21807,0.29855 0.59709,0.29855 0.37902,0 0.59709,-0.29855 0.21807,-0.30114 0.21807,-0.82814 0,-0.52699 -0.21807,-0.82554 -0.21807,-0.30114 -0.59709,-0.30114 -0.37902,0 -0.59709,0.30114 -0.21547,0.29855 -0.21547,0.82554 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8372" />
+ <path
+ d="m 116.29376,227.92899 h 0.47767 v 2.90757 h -0.47767 z m 0,-1.13187 h 0.47767 v 0.60488 h -0.47767 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8374" />
+ <path
+ d="m 120.18783,229.08164 v 1.75492 h -0.47767 v -1.73935 q 0,-0.41277 -0.16096,-0.61786 -0.16095,-0.20508 -0.48286,-0.20508 -0.38681,0 -0.61007,0.24662 -0.22326,0.24663 -0.22326,0.67238 v 1.64329 h -0.48027 v -2.90757 h 0.48027 v 0.45171 q 0.17134,-0.2622 0.40239,-0.392 0.23364,-0.1298 0.53738,-0.1298 0.50103,0 0.75804,0.31152 0.25701,0.30893 0.25701,0.91122 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8376" />
+ <path
+ d="m 123.05386,229.34903 q 0,-0.51921 -0.21547,-0.80477 -0.21287,-0.28557 -0.59968,-0.28557 -0.38422,0 -0.59969,0.28557 -0.21288,0.28556 -0.21288,0.80477 0,0.51661 0.21288,0.80218 0.21547,0.28556 0.59969,0.28556 0.38681,0 0.59968,-0.28556 0.21547,-0.28557 0.21547,-0.80218 z m 0.47768,1.12668 q 0,0.74247 -0.3297,1.10332 -0.3297,0.36345 -1.00986,0.36345 -0.25182,0 -0.47508,-0.0389 -0.22326,-0.0363 -0.43354,-0.11423 v -0.46469 q 0.21028,0.11423 0.41537,0.16874 0.20509,0.0545 0.41796,0.0545 0.46989,0 0.70353,-0.24662 0.23364,-0.24403 0.23364,-0.73988 v -0.23624 q -0.14797,0.25701 -0.37902,0.38422 -0.23105,0.1272 -0.55296,0.1272 -0.53478,0 -0.86188,-0.40758 -0.3271,-0.40757 -0.3271,-1.07995 0,-0.67497 0.3271,-1.08255 0.3271,-0.40758 0.86188,-0.40758 0.32191,0 0.55296,0.12721 0.23105,0.1272 0.37902,0.38421 v -0.44133 h 0.47768 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8378" />
+ <path
+ d="m 128.29787,228.04062 v 0.44652 q -0.20249,-0.11163 -0.40758,-0.16614 -0.20249,-0.0571 -0.41017,-0.0571 -0.46469,0 -0.7217,0.29595 -0.25701,0.29335 -0.25701,0.82554 0,0.53219 0.25701,0.82814 0.25701,0.29336 0.7217,0.29336 0.20768,0 0.41017,-0.0545 0.20509,-0.0571 0.40758,-0.16874 v 0.44132 q -0.19989,0.0935 -0.41536,0.14019 -0.21288,0.0467 -0.45431,0.0467 -0.6568,0 -1.04361,-0.41277 -0.38681,-0.41277 -0.38681,-1.11371 0,-0.71131 0.3894,-1.11889 0.39201,-0.40758 1.07217,-0.40758 0.22067,0 0.43094,0.0467 0.21028,0.0441 0.40758,0.13499 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8380" />
+ <path
+ d="m 130.25529,228.26388 q -0.38421,0 -0.60747,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.22066,0.82295 0.22326,0.29855 0.61007,0.29855 0.38162,0 0.60488,-0.30115 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.60488,-0.30374 z m 0,-0.40498 q 0.62305,0 0.97871,0.40498 0.35566,0.40499 0.35566,1.12149 0,0.71392 -0.35566,1.1215 -0.35566,0.40498 -0.97871,0.40498 -0.62565,0 -0.9813,-0.40498 -0.35307,-0.40758 -0.35307,-1.1215 0,-0.7165 0.35307,-1.12149 0.35565,-0.40498 0.9813,-0.40498 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8382" />
+ <path
+ d="m 134.06629,228.37551 q -0.0805,-0.0467 -0.17654,-0.0675 -0.0934,-0.0234 -0.20768,-0.0234 -0.40498,0 -0.62305,0.2648 -0.21547,0.2622 -0.21547,0.75545 v 1.53166 h -0.48027 v -2.90757 h 0.48027 v 0.45171 q 0.15057,-0.26479 0.392,-0.392 0.24143,-0.1298 0.58671,-0.1298 0.0493,0 0.10903,0.008 0.0597,0.005 0.1324,0.0182 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8384" />
+ <path
+ d="m 136.1587,228.37551 q -0.0805,-0.0467 -0.17653,-0.0675 -0.0935,-0.0234 -0.20769,-0.0234 -0.40498,0 -0.62305,0.2648 -0.21547,0.2622 -0.21547,0.75545 v 1.53166 h -0.48027 v -2.90757 h 0.48027 v 0.45171 q 0.15057,-0.26479 0.392,-0.392 0.24143,-0.1298 0.58671,-0.1298 0.0493,0 0.10903,0.008 0.0597,0.005 0.1324,0.0182 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8386" />
+ <path
+ d="m 139.02992,229.26336 v 0.23364 h -2.19625 q 0.0311,0.49325 0.29595,0.75286 0.26739,0.25701 0.74247,0.25701 0.27518,0 0.53219,-0.0675 0.2596,-0.0675 0.51401,-0.20249 v 0.45171 q -0.257,0.10903 -0.52699,0.16615 -0.26999,0.0571 -0.54777,0.0571 -0.69574,0 -1.10332,-0.40498 -0.40498,-0.40499 -0.40498,-1.09554 0,-0.71391 0.38421,-1.13187 0.38682,-0.42056 1.04102,-0.42056 0.5867,0 0.92679,0.37902 0.34267,0.37643 0.34267,1.02544 z m -0.47767,-0.14019 q -0.005,-0.392 -0.22066,-0.62564 -0.21288,-0.23365 -0.56594,-0.23365 -0.39979,0 -0.64122,0.22586 -0.23884,0.22585 -0.27518,0.63603 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8388" />
+ <path
+ d="m 141.90634,228.04062 v 0.44652 q -0.20249,-0.11163 -0.40758,-0.16614 -0.20249,-0.0571 -0.41017,-0.0571 -0.4647,0 -0.7217,0.29595 -0.25701,0.29335 -0.25701,0.82554 0,0.53219 0.25701,0.82814 0.257,0.29336 0.7217,0.29336 0.20768,0 0.41017,-0.0545 0.20509,-0.0571 0.40758,-0.16874 v 0.44132 q -0.19989,0.0935 -0.41537,0.14019 -0.21287,0.0467 -0.4543,0.0467 -0.6568,0 -1.04361,-0.41277 -0.38681,-0.41277 -0.38681,-1.11371 0,-0.71131 0.3894,-1.11889 0.392,-0.40758 1.07217,-0.40758 0.22066,0 0.43094,0.0467 0.21028,0.0441 0.40758,0.13499 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8390" />
+ <path
+ d="m 143.20956,227.10345 v 0.82554 h 0.9839 v 0.37124 h -0.9839 v 1.57839 q 0,0.35566 0.096,0.45691 0.0986,0.10124 0.3972,0.10124 h 0.49065 v 0.39979 h -0.49065 q -0.55296,0 -0.76324,-0.20508 -0.21028,-0.20769 -0.21028,-0.75286 v -1.57839 h -0.35047 v -0.37124 h 0.35047 v -0.82554 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8392" />
+ <path
+ d="m 99.821858,234.90976 q -0.384215,0 -0.607475,0.30114 -0.22326,0.29854 -0.22326,0.82035 0,0.5218 0.220664,0.82295 0.22326,0.29854 0.610071,0.29854 0.381622,0 0.604882,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81776 -0.22326,-0.30373 -0.604882,-0.30373 z m 0,-0.40499 q 0.623052,0 0.978712,0.40499 0.35565,0.40498 0.35565,1.12149 0,0.71391 -0.35565,1.12149 -0.35566,0.40498 -0.978712,0.40498 -0.625647,0 -0.981305,-0.40498 -0.353062,-0.40758 -0.353062,-1.12149 0,-0.71651 0.353062,-1.12149 0.355658,-0.40499 0.981305,-0.40499 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8394" />
+ <path
+ d="m 101.89869,236.33499 v -1.76012 h 0.47768 v 1.74194 q 0,0.41278 0.16095,0.62046 0.16096,0.20509 0.48286,0.20509 0.38682,0 0.61008,-0.24663 0.22585,-0.24662 0.22585,-0.67237 v -1.64849 h 0.47767 v 2.90757 h -0.47767 v -0.44652 q -0.17393,0.26479 -0.40498,0.3946 -0.22845,0.1272 -0.53219,0.1272 -0.50104,0 -0.76064,-0.31152 -0.25961,-0.31153 -0.25961,-0.91121 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8396" />
+ <path
+ d="m 105.79017,233.74933 v 0.82554 h 0.9839 v 0.37123 h -0.9839 v 1.5784 q 0,0.35566 0.096,0.4569 0.0987,0.10125 0.39719,0.10125 h 0.49066 v 0.39979 h -0.49066 q -0.55295,0 -0.76323,-0.20509 -0.21028,-0.20768 -0.21028,-0.75285 v -1.5784 h -0.35047 v -0.37123 h 0.35047 v -0.82554 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8398" />
+ <path
+ d="m 107.8644,237.0463 v 1.54205 h -0.48026 v -4.01348 h 0.48026 v 0.44133 q 0.15057,-0.25961 0.37903,-0.38422 0.23104,-0.12721 0.55036,-0.12721 0.52959,0 0.85929,0.42056 0.33229,0.42056 0.33229,1.10592 0,0.68535 -0.33229,1.10591 -0.3297,0.42056 -0.85929,0.42056 -0.31932,0 -0.55036,-0.12461 -0.22846,-0.1272 -0.37903,-0.38681 z m 1.62513,-1.01505 q 0,-0.527 -0.21807,-0.82554 -0.21547,-0.30114 -0.59449,-0.30114 -0.37903,0 -0.59709,0.30114 -0.21548,0.29854 -0.21548,0.82554 0,0.527 0.21548,0.82814 0.21806,0.29854 0.59709,0.29854 0.37902,0 0.59449,-0.29854 0.21807,-0.30114 0.21807,-0.82814 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8400" />
+ <path
+ d="m 110.72784,236.33499 v -1.76012 h 0.47767 v 1.74194 q 0,0.41278 0.16096,0.62046 0.16095,0.20509 0.48286,0.20509 0.38681,0 0.61007,-0.24663 0.22586,-0.24662 0.22586,-0.67237 v -1.64849 h 0.47767 v 2.90757 h -0.47767 v -0.44652 q -0.17393,0.26479 -0.40498,0.3946 -0.22845,0.1272 -0.53219,0.1272 -0.50104,0 -0.76064,-0.31152 -0.25961,-0.31153 -0.25961,-0.91121 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8402" />
+ <path
+ d="m 114.61931,233.74933 v 0.82554 h 0.9839 v 0.37123 h -0.9839 v 1.5784 q 0,0.35566 0.0961,0.4569 0.0987,0.10125 0.39719,0.10125 h 0.49065 v 0.39979 h -0.49065 q -0.55296,0 -0.76324,-0.20509 -0.21027,-0.20768 -0.21027,-0.75285 v -1.5784 h -0.35047 v -0.37123 h 0.35047 v -0.82554 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8404" />
+ <path
+ d="m 119.83477,235.0162 v -1.57321 h 0.47767 v 4.03945 h -0.47767 v -0.43614 q -0.15057,0.25961 -0.38162,0.38681 -0.22845,0.12461 -0.55036,0.12461 -0.527,0 -0.85929,-0.42056 -0.3297,-0.42056 -0.3297,-1.10591 0,-0.68536 0.3297,-1.10592 0.33229,-0.42056 0.85929,-0.42056 0.32191,0 0.55036,0.12721 0.23105,0.12461 0.38162,0.38422 z m -1.62772,1.01505 q 0,0.527 0.21547,0.82814 0.21807,0.29854 0.59709,0.29854 0.37902,0 0.59709,-0.29854 0.21807,-0.30114 0.21807,-0.82814 0,-0.527 -0.21807,-0.82554 -0.21807,-0.30114 -0.59709,-0.30114 -0.37902,0 -0.59709,0.30114 -0.21547,0.29854 -0.21547,0.82554 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8406" />
+ <path
+ d="m 123.78335,235.90923 v 0.23365 h -2.19625 q 0.0311,0.49325 0.29595,0.75285 0.26739,0.25701 0.74247,0.25701 0.27518,0 0.53219,-0.0675 0.2596,-0.0675 0.51401,-0.20249 v 0.45171 q -0.25701,0.10904 -0.52699,0.16615 -0.26999,0.0571 -0.54777,0.0571 -0.69574,0 -1.10332,-0.40498 -0.40498,-0.40498 -0.40498,-1.09553 0,-0.71391 0.38421,-1.13188 0.38681,-0.42056 1.04102,-0.42056 0.5867,0 0.92678,0.37903 0.34268,0.37642 0.34268,1.02543 z m -0.47767,-0.14018 q -0.005,-0.392 -0.22066,-0.62565 -0.21288,-0.23364 -0.56594,-0.23364 -0.39979,0 -0.64122,0.22585 -0.23884,0.22586 -0.27518,0.63603 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8408" />
+ <path
+ d="m 126.42093,234.66054 v 0.45171 q -0.20249,-0.10384 -0.42056,-0.15576 -0.21806,-0.0519 -0.45171,-0.0519 -0.35566,0 -0.53478,0.10903 -0.17653,0.10903 -0.17653,0.3271 0,0.16615 0.1272,0.2622 0.12721,0.0935 0.51142,0.17913 l 0.16355,0.0363 q 0.50883,0.10904 0.7217,0.30893 0.21548,0.1973 0.21548,0.55296 0,0.40498 -0.32191,0.64122 -0.31932,0.23624 -0.88006,0.23624 -0.23365,0 -0.48806,-0.0467 -0.25182,-0.0441 -0.53219,-0.13499 v -0.49325 q 0.2648,0.13759 0.52181,0.20769 0.257,0.0675 0.50882,0.0675 0.33749,0 0.51921,-0.11422 0.18172,-0.11683 0.18172,-0.32711 0,-0.1947 -0.1324,-0.29854 -0.1298,-0.10384 -0.57372,-0.1999 l -0.16615,-0.0389 q -0.44392,-0.0934 -0.64122,-0.28556 -0.1973,-0.1947 -0.1973,-0.53219 0,-0.41018 0.29076,-0.63344 0.29075,-0.22326 0.82554,-0.22326 0.2648,0 0.49844,0.0389 0.23364,0.0389 0.43094,0.11682 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8410" />
+ <path
+ d="m 129.42975,234.6865 v 0.44652 q -0.20249,-0.11163 -0.40758,-0.16615 -0.20249,-0.0571 -0.41017,-0.0571 -0.4647,0 -0.7217,0.29595 -0.25701,0.29335 -0.25701,0.82554 0,0.53219 0.25701,0.82814 0.257,0.29335 0.7217,0.29335 0.20768,0 0.41017,-0.0545 0.20509,-0.0571 0.40758,-0.16874 v 0.44133 q -0.19989,0.0935 -0.41537,0.14018 -0.21287,0.0467 -0.4543,0.0467 -0.6568,0 -1.04361,-0.41277 -0.38682,-0.41277 -0.38682,-1.1137 0,-0.71132 0.38941,-1.1189 0.392,-0.40758 1.07217,-0.40758 0.22066,0 0.43094,0.0467 0.21028,0.0441 0.40758,0.135 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8412" />
+ <path
+ d="m 131.94532,235.02139 q -0.0805,-0.0467 -0.17653,-0.0675 -0.0935,-0.0234 -0.20769,-0.0234 -0.40498,0 -0.62305,0.26479 -0.21547,0.2622 -0.21547,0.75545 v 1.53167 h -0.48027 v -2.90757 h 0.48027 v 0.45171 q 0.15057,-0.2648 0.392,-0.392 0.24143,-0.12981 0.58671,-0.12981 0.0493,0 0.10903,0.008 0.0597,0.005 0.1324,0.0182 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8414" />
+ <path
+ d="m 132.44635,234.57487 h 0.47768 v 2.90757 h -0.47768 z m 0,-1.13188 h 0.47768 v 0.60488 h -0.47768 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8416" />
+ <path
+ d="m 134.3856,237.0463 v 1.54205 h -0.48027 v -4.01348 h 0.48027 v 0.44133 q 0.15057,-0.25961 0.37902,-0.38422 0.23105,-0.12721 0.55036,-0.12721 0.5296,0 0.85929,0.42056 0.3323,0.42056 0.3323,1.10592 0,0.68535 -0.3323,1.10591 -0.32969,0.42056 -0.85929,0.42056 -0.31931,0 -0.55036,-0.12461 -0.22845,-0.1272 -0.37902,-0.38681 z m 1.62512,-1.01505 q 0,-0.527 -0.21806,-0.82554 -0.21548,-0.30114 -0.5945,-0.30114 -0.37902,0 -0.59709,0.30114 -0.21547,0.29854 -0.21547,0.82554 0,0.527 0.21547,0.82814 0.21807,0.29854 0.59709,0.29854 0.37902,0 0.5945,-0.29854 0.21806,-0.30114 0.21806,-0.82814 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8418" />
+ <path
+ d="m 137.77084,233.74933 v 0.82554 h 0.9839 v 0.37123 h -0.9839 v 1.5784 q 0,0.35566 0.0961,0.4569 0.0987,0.10125 0.39719,0.10125 h 0.49065 v 0.39979 h -0.49065 q -0.55296,0 -0.76324,-0.20509 -0.21028,-0.20768 -0.21028,-0.75285 v -1.5784 h -0.35046 v -0.37123 h 0.35046 v -0.82554 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8420" />
+ <path
+ d="m 140.50967,234.90976 q -0.38421,0 -0.60747,0.30114 -0.22326,0.29854 -0.22326,0.82035 0,0.5218 0.22066,0.82295 0.22326,0.29854 0.61007,0.29854 0.38162,0 0.60488,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81776 -0.22326,-0.30373 -0.60488,-0.30373 z m 0,-0.40499 q 0.62305,0 0.97871,0.40499 0.35566,0.40498 0.35566,1.12149 0,0.71391 -0.35566,1.12149 -0.35566,0.40498 -0.97871,0.40498 -0.62565,0 -0.9813,-0.40498 -0.35307,-0.40758 -0.35307,-1.12149 0,-0.71651 0.35307,-1.12149 0.35565,-0.40499 0.9813,-0.40499 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8422" />
+ <path
+ d="m 144.32066,235.02139 q -0.0805,-0.0467 -0.17653,-0.0675 -0.0935,-0.0234 -0.20768,-0.0234 -0.40499,0 -0.62305,0.26479 -0.21548,0.2622 -0.21548,0.75545 v 1.53167 h -0.48026 v -2.90757 h 0.48026 v 0.45171 q 0.15058,-0.2648 0.39201,-0.392 0.24143,-0.12981 0.5867,-0.12981 0.0493,0 0.10904,0.008 0.0597,0.005 0.1324,0.0182 z"
+ style="text-align:end;text-anchor:end;fill:#000080;stroke-width:0.398751"
+ id="path8424" />
+ </g>
+ <path
+ id="rect5208"
+ style="opacity:0.25;fill:#830000;fill-opacity:0.64;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.2, 2.4;stroke-dashoffset:0;stroke-opacity:0.497957"
+ d="m 103.27132,134.54594 h 42.29433 c 1.14406,0 2.06509,0.92103 2.06509,2.06509 v 15.54342 c 0,1.14406 -0.92103,2.06509 -2.06509,2.06509 h -42.29433 c -1.14406,0 -2.06509,-0.92103 -2.06509,-2.06509 v -15.54342 c 0,-1.14406 0.92103,-2.06509 2.06509,-2.06509 z" />
+ <g
+ aria-label="+ ArrayMethod
+ lookup"
+ id="text5218"
+ style="font-size:5.3167px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#800000;fill-opacity:1;stroke-width:0.398751">
+ <path
+ d="m 106.10878,139.41425 v 1.446 h 1.446 v 0.44133 h -1.446 v 1.44599 h -0.43613 v -1.44599 h -1.446 v -0.44133 h 1.446 v -1.446 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path8596" />
+ <path
+ d="m 112.17203,141.79057 h -1.48595 l -0.29991,0.957 h -0.46624 l 1.22148,-3.7544 h 0.60529 l 1.22147,3.7544 h -0.49622 z m -1.36325,-0.39262 h 1.24056 l -0.61619,-2.00671 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8598" />
+ <path
+ d="m 113.65525,142.74757 v -0.35172 h 0.44715 v -2.16757 h -0.44715 v -0.35172 h 0.79614 l 0.0845,0.6789 q 0.16632,-0.35445 0.40352,-0.54803 0.23721,-0.19358 0.6271,-0.19358 0.11997,0 0.21267,0.0191 0.0954,0.0164 0.19358,0.0436 l -0.0654,0.97063 h -0.37626 v -0.61073 q -0.0109,0 -0.0245,0 -0.65982,0 -0.9461,0.94337 v 1.21602 h 0.58347 v 0.35172 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8600" />
+ <path
+ d="m 116.92706,142.74757 v -0.35172 h 0.44714 v -2.16757 h -0.44714 v -0.35172 h 0.79614 l 0.0845,0.6789 q 0.16632,-0.35445 0.40352,-0.54803 0.23721,-0.19358 0.6271,-0.19358 0.11997,0 0.21267,0.0191 0.0954,0.0164 0.19358,0.0436 l -0.0654,0.97063 h -0.37625 v -0.61073 q -0.0109,0 -0.0245,0 -0.65982,0 -0.9461,0.94337 v 1.21602 h 0.58347 v 0.35172 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8602" />
+ <path
+ d="m 122.22739,142.12048 q 0,0.17449 0.0573,0.25356 0.0572,0.0791 0.17722,0.11452 l -0.11179,0.32172 q -0.1854,-0.0245 -0.32445,-0.11724 -0.13906,-0.0954 -0.20177,-0.28628 -0.15541,0.19904 -0.38989,0.30264 -0.23175,0.10088 -0.50985,0.10088 -0.43079,0 -0.67891,-0.24266 -0.24811,-0.24266 -0.24811,-0.64345 0,-0.44442 0.34627,-0.68163 0.34627,-0.23721 1.00063,-0.23721 h 0.42261 v -0.23993 q 0,-0.31082 -0.18268,-0.43897 -0.17995,-0.13087 -0.50168,-0.13087 -0.14178,0 -0.33263,0.0354 -0.19086,0.0327 -0.41443,0.11179 l -0.11997,-0.34627 q 0.26175,-0.0982 0.4935,-0.13905 0.23448,-0.0409 0.44442,-0.0409 0.5344,0 0.80432,0.25084 0.26993,0.25084 0.26993,0.67618 z m -1.18603,0.34081 q 0.21266,0 0.40352,-0.10633 0.19358,-0.10906 0.32173,-0.29992 v -0.73889 h -0.41443 q -0.47442,0 -0.67072,0.1636 -0.19359,0.16359 -0.19359,0.43896 0,0.54258 0.55349,0.54258 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8604" />
+ <path
+ d="m 125.83183,139.87656 -1.00881,2.8901 q -0.10088,0.29174 -0.25629,0.5344 -0.15269,0.24266 -0.4008,0.40079 -0.24538,0.16087 -0.62437,0.19904 l -0.0709,-0.36535 q 0.29719,-0.0491 0.46896,-0.14996 0.17177,-0.10088 0.26993,-0.25902 0.10088,-0.15541 0.17722,-0.37899 h -0.15269 l -1.00335,-2.87101 h 0.49077 l 0.82341,2.52202 0.8125,-2.52202 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8606" />
+ <path
+ d="m 129.06001,138.99317 0.21267,3.7544 h -0.45533 l -0.11724,-1.96036 q -0.0136,-0.26174 -0.0218,-0.5344 -0.005,-0.27265 -0.008,-0.49349 -0.003,-0.22358 0,-0.33264 l -0.63255,2.64745 h -0.47441 l -0.6789,-2.64745 q 0.005,0.10634 0.008,0.33809 0.003,0.23175 0,0.50713 -0.003,0.27538 -0.0136,0.50986 l -0.10088,1.96581 h -0.44442 l 0.21267,-3.7544 h 0.65981 l 0.60802,2.5711 0.58074,-2.5711 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8608" />
+ <path
+ d="m 130.34692,141.47429 q 0.0191,0.49895 0.26175,0.72798 0.24538,0.2263 0.57802,0.2263 0.22084,0 0.39807,-0.0654 0.17722,-0.0654 0.36808,-0.19359 l 0.21539,0.30265 q -0.19903,0.15813 -0.45805,0.24811 -0.25902,0.09 -0.52895,0.09 -0.41988,0 -0.71434,-0.18813 -0.29174,-0.18813 -0.44715,-0.52349 -0.15269,-0.33808 -0.15269,-0.78251 0,-0.43624 0.15269,-0.77433 0.15541,-0.33808 0.43624,-0.53167 0.28356,-0.19358 0.66527,-0.19358 0.54258,0 0.8534,0.37626 0.31355,0.37626 0.31355,1.03062 0,0.0736 -0.005,0.13906 -0.003,0.0654 -0.005,0.11178 z m 0.77978,-1.28146 q -0.319,0 -0.53439,0.2263 -0.2154,0.2263 -0.24266,0.70072 h 1.49685 q -0.008,-0.46078 -0.20176,-0.69254 -0.19358,-0.23448 -0.51804,-0.23448 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8610" />
+ <path
+ d="m 135.53819,142.60307 q -0.14723,0.0982 -0.35717,0.15268 -0.20994,0.0545 -0.4117,0.0545 -0.46351,0 -0.71435,-0.24266 -0.25084,-0.24266 -0.25084,-0.62437 V 140.231 h -0.65982 v -0.35444 h 0.65982 v -0.65164 l 0.45805,-0.0545 v 0.70617 h 0.99245 l -0.0545,0.35444 h -0.93792 v 1.7068 q 0,0.23993 0.12542,0.36535 0.12815,0.12542 0.42261,0.12542 0.16087,0 0.29719,-0.0382 0.13633,-0.0382 0.25357,-0.0982 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8612" />
+ <path
+ d="m 136.98869,138.67689 v 1.59228 q 0.16904,-0.22357 0.41443,-0.33808 0.24811,-0.11452 0.50168,-0.11452 0.41988,0 0.61346,0.22358 0.19358,0.22357 0.19358,0.62164 v 2.08578 h -0.45805 v -2.07487 q 0,-0.25902 -0.11997,-0.37626 -0.11996,-0.11997 -0.37626,-0.11997 -0.16359,0 -0.31082,0.0736 -0.14723,0.0736 -0.26447,0.18267 -0.11724,0.10906 -0.19358,0.22358 v 2.09123 h -0.45806 v -4.0216 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8614" />
+ <path
+ d="m 140.89577,139.81657 q 0.60802,0 0.91884,0.40625 0.31082,0.40625 0.31082,1.08788 0,0.43897 -0.14178,0.77706 -0.14178,0.33809 -0.41715,0.53167 -0.27538,0.19085 -0.67618,0.19085 -0.60801,0 -0.92156,-0.40897 -0.31355,-0.40898 -0.31355,-1.08516 0,-0.44169 0.14178,-0.77978 0.14178,-0.34081 0.41716,-0.52894 0.2781,-0.19086 0.68162,-0.19086 z m 0,0.37353 q -0.3708,0 -0.56166,0.27538 -0.18813,0.27538 -0.18813,0.85067 0,0.56985 0.18541,0.84522 0.18813,0.27265 0.55893,0.27265 0.37081,0 0.55621,-0.27537 0.18813,-0.27538 0.18813,-0.84795 0,-0.57257 -0.1854,-0.84522 -0.18541,-0.27538 -0.55349,-0.27538 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8616" />
+ <path
+ d="m 144.79195,138.66326 0.45806,0.0572 v 4.02706 h -0.4008 l -0.0436,-0.37898 q -0.16087,0.22903 -0.37081,0.33536 -0.20721,0.10633 -0.44442,0.10633 -0.37353,0 -0.61619,-0.18813 -0.24266,-0.18813 -0.3599,-0.52349 -0.11724,-0.33808 -0.11724,-0.78251 0,-0.43078 0.1336,-0.76887 0.1336,-0.34082 0.38444,-0.5344 0.25356,-0.19631 0.60801,-0.19631 0.47714,0 0.76887,0.33809 z m -0.64891,1.52139 q -0.3599,0 -0.55348,0.28083 -0.19358,0.28083 -0.19358,0.85067 0,1.12333 0.68981,1.12333 0.24266,0 0.41715,-0.13633 0.1745,-0.13905 0.28901,-0.31627 v -1.43415 q -0.11724,-0.1745 -0.28355,-0.26992 -0.16632,-0.0982 -0.36536,-0.0982 z"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Fira Code';-inkscape-font-specification:'Fira Code'"
+ id="path8618" />
+ <path
+ d="m 110.92444,145.40592 h 0.47768 v 4.03945 h -0.47768 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path8620" />
+ <path
+ d="m 113.52828,146.87269 q -0.38422,0 -0.60748,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.22067,0.82295 0.22326,0.29854 0.61007,0.29854 0.38162,0 0.60488,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.60488,-0.30374 z m 0,-0.40498 q 0.62305,0 0.97871,0.40498 0.35565,0.40498 0.35565,1.12149 0,0.71391 -0.35565,1.12149 -0.35566,0.40499 -0.97871,0.40499 -0.62565,0 -0.98131,-0.40499 -0.35306,-0.40758 -0.35306,-1.12149 0,-0.71651 0.35306,-1.12149 0.35566,-0.40498 0.98131,-0.40498 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path8622" />
+ <path
+ d="m 116.78112,146.87269 q -0.38421,0 -0.60747,0.30114 -0.22326,0.29855 -0.22326,0.82035 0,0.52181 0.22066,0.82295 0.22326,0.29854 0.61007,0.29854 0.38162,0 0.60488,-0.30114 0.22326,-0.30114 0.22326,-0.82035 0,-0.51661 -0.22326,-0.81775 -0.22326,-0.30374 -0.60488,-0.30374 z m 0,-0.40498 q 0.62305,0 0.97871,0.40498 0.35566,0.40498 0.35566,1.12149 0,0.71391 -0.35566,1.12149 -0.35566,0.40499 -0.97871,0.40499 -0.62564,0 -0.9813,-0.40499 -0.35306,-0.40758 -0.35306,-1.12149 0,-0.71651 0.35306,-1.12149 0.35566,-0.40498 0.9813,-0.40498 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path8624" />
+ <path
+ d="m 118.88911,145.40592 h 0.48027 v 2.38577 l 1.42523,-1.25389 h 0.61007 l -1.54205,1.36033 1.60695,1.54724 h -0.62305 l -1.47715,-1.42004 v 1.42004 h -0.48027 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path8626" />
+ <path
+ d="m 121.77332,148.29792 v -1.76012 h 0.47767 v 1.74195 q 0,0.41277 0.16095,0.62045 0.16096,0.20509 0.48287,0.20509 0.38681,0 0.61007,-0.24663 0.22585,-0.24662 0.22585,-0.67237 v -1.64849 h 0.47768 v 2.90757 h -0.47768 v -0.44652 q -0.17393,0.2648 -0.40498,0.3946 -0.22845,0.12721 -0.53219,0.12721 -0.50104,0 -0.76064,-0.31153 -0.2596,-0.31153 -0.2596,-0.91121 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path8628" />
+ <path
+ d="m 125.6544,149.00923 v 1.54205 h -0.48026 v -4.01348 h 0.48026 v 0.44133 q 0.15057,-0.25961 0.37903,-0.38422 0.23104,-0.1272 0.55036,-0.1272 0.52959,0 0.85929,0.42056 0.33229,0.42055 0.33229,1.10591 0,0.68536 -0.33229,1.10592 -0.3297,0.42056 -0.85929,0.42056 -0.31932,0 -0.55036,-0.12462 -0.22846,-0.1272 -0.37903,-0.38681 z m 1.62513,-1.01505 q 0,-0.527 -0.21807,-0.82554 -0.21547,-0.30114 -0.59449,-0.30114 -0.37903,0 -0.59709,0.30114 -0.21548,0.29854 -0.21548,0.82554 0,0.527 0.21548,0.82814 0.21806,0.29854 0.59709,0.29854 0.37902,0 0.59449,-0.29854 0.21807,-0.30114 0.21807,-0.82814 z"
+ style="fill:#800000;fill-opacity:1;stroke-width:0.398751"
+ id="path8630" />
+ </g>
+ </g>
+</svg>
source_suffix = '.rst'
# The master toctree document.
-master_doc = 'index'
+master_doc = 'content'
# General information about the project.
project = u'NumPy Enhancement Proposals'
## -- Options for HTML output ----------------------------------------------
#
-## The theme to use for HTML and HTML Help pages. See the documentation for
-## a list of builtin themes.
-##
-#html_theme = 'alabaster'
-#
-## Theme options are theme-specific and customize the look and feel of a theme
-## further. For a list of options available for each theme, see the
-## documentation.
-##
-## html_theme_options = {}
-#
-## Add any paths that contain custom static files (such as style sheets) here,
-## relative to this directory. They are copied after the builtin static files,
-## so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = ['_static']
-#
-## Custom sidebar templates, must be a dictionary that maps document names
-## to template names.
-##
-## This is required for the alabaster theme
-## refs: https://alabaster.readthedocs.io/en/latest/installation.html#sidebars
-#html_sidebars = {
-# '**': [
-# 'relations.html', # needs 'show_related': True theme option to display
-# 'searchbox.html',
-# ]
-#}
-
-## -----------------------------------------------------------------------------
-# HTML output
-# -----------------------------------------------------------------------------
-themedir = os.path.join(os.pardir, 'scipy-sphinx-theme', '_theme')
-if not os.path.isdir(themedir):
- raise RuntimeError("Get the scipy-sphinx-theme first, "
- "via git submodule init && git submodule update")
-
-html_theme = 'scipy'
-html_theme_path = [themedir]
-
-#if 'scipyorg' in tags:
-if True:
- # Build for the scipy.org website
- html_theme_options = {
- "edit_link": True,
- "sidebar": "right",
- "scipy_org_logo": True,
- "rootlinks": [("https://scipy.org/", "Scipy.org"),
- ("https://docs.scipy.org/", "Docs")]
- }
-else:
- # Default build
- html_theme_options = {
- "edit_link": False,
- "sidebar": "left",
- "scipy_org_logo": False,
- "rootlinks": []
- }
- html_sidebars = {'index': 'indexsidebar.html'}
-
-#html_additional_pages = {
-# 'index': 'indexcontent.html',
-#}
+html_theme = 'pydata_sphinx_theme'
+
+html_logo = '../source/_static/numpylogo.svg'
+
+html_theme_options = {
+ "github_url": "https://github.com/numpy/numpy",
+ "twitter_url": "https://twitter.com/numpy_team",
+ "external_links": [
+ {"name": "Wishlist",
+ "url": "https://github.com/numpy/numpy/issues?q=is%3Aopen+is%3Aissue+label%3A%2223+-+Wish+List%22",
+ },
+ ],
+ "show_prev_next": False,
+}
html_title = "%s" % (project)
html_static_path = ['../source/_static']
--- /dev/null
+=====================================
+Roadmap & NumPy Enhancement Proposals
+=====================================
+
+This page provides an overview of development priorities for NumPy.
+Specifically, it contains a roadmap with a higher-level overview, as
+well as NumPy Enhancement Proposals (NEPs)—suggested changes
+to the library—in various stages of discussion or completion (see `NEP
+0 <nep-0000>`__).
+
+Roadmap
+-------
+.. toctree::
+ :maxdepth: 1
+
+ Index <index>
+ The Scope of NumPy <scope>
+ Current roadmap <roadmap>
+ Wishlist (opens new window) |wishlist_link|
+
+.. |wishlist_link| raw:: html
+
+ <a href="https://github.com/numpy/numpy/issues?q=is%3Aopen+is%3Aissue+label%3A%2223+-+Wish+List%22" target=" blank">WishList</a>
+
+
nep-template
+
+{% if has_provisional %}
+
Provisional NEPs (provisionally accepted; interface may change)
---------------------------------------------------------------
{{ tags['Title'] }} <{{ tags['Filename'] }}>
{% endfor %}
+{% endif %}
+
Accepted NEPs (implementation in progress)
------------------------------------------
+.. _NEP00:
+
===========================
NEP 0 — Purpose and Process
===========================
Each NEP must begin with a header preamble. The headers
must appear in the following order. Headers marked with ``*`` are
-optional. All other headers are required. ::
+optional. All other headers are required.
+
+.. code-block:: rst
:Author: <list of authors' real names and optionally, email addresses>
:Status: <Draft | Active | Accepted | Deferred | Rejected |
of all the authors of the NEP. The format of the Author header
value must be
+.. code-block:: rst
+
Random J. User <address@dom.ain>
if the email address is included, and just
+.. code-block:: rst
+
Random J. User
if the address is not given. If there are multiple authors, each should be on
+.. _NEP01:
+
=============================================
NEP 1 — A Simple File Format for NumPy Arrays
=============================================
+.. _NEP02:
+
=================================================================================
NEP 2 — A proposal to build numpy without warning with a big set of warning flags
=================================================================================
:Date: 2008-09-04
:Status: Deferred
+.. highlight:: c
+
Executive summary
=================
=============
Each compiler detects a different set of potential errors. The baseline will
-be gcc -Wall -W -Wextra. Ideally, a complete set would be nice::
+be gcc -Wall -W -Wextra. Ideally, a complete set would be nice:
+
+.. code-block:: bash
-W -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return
-Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast
int foo(int * NPY_UNUSED(dummy))
-expanded to
-
-::
+expanded to::
int foo(int * __NPY_UNUSED_TAGGEDdummy __COMP_NPY_UNUSED)
+.. _NEP03:
+
=====================================================
NEP 3 — Cleaning the math configuration of numpy.core
=====================================================
+.. _NEP04:
+
=========================================================================
NEP 4 — A (third) proposal for implementing some date/time types in NumPy
=========================================================================
+.. _NEP05:
+
=======================================
NEP 5 — Generalized Universal Functions
=======================================
+.. _NEP06:
+
===================================================
NEP 6 — Replacing Trac with a different bug tracker
===================================================
+.. _NEP07:
+
==================================================================
NEP 7 — A proposal for implementing some date/time types in NumPy
==================================================================
+.. _NEP08:
+
=============================================================
NEP 8 — A proposal for adding groupby functionality to NumPy
=============================================================
+.. _NEP09:
+
===================================
NEP 9 — Structured array extensions
===================================
+.. _NEP10:
+
==============================================
NEP 10 — Optimizing Iterator/UFunc Performance
==============================================
‘K’ a layout equivalent to ‘C’ followed by some permutation of the axes, as close to the layout of the input(s) as possible (“Keep Layout”)
=== =====================================================================================
-Or as an enum::
+Or as an enum:
+
+.. code-block:: c
/* For specifying array memory layout or iteration order */
typedef enum {
The iterator can do automatic casting, and I have created a sequence
of progressively more permissive casting rules. Perhaps for 2.0, NumPy
-could adopt this enum as its preferred way of dealing with casting.::
+could adopt this enum as its preferred way of dealing with casting.
+
+.. code-block:: c
/* For specifying allowed casting in operations which support it */
typedef enum {
The following struct describes the iterator memory. All items
are packed together, which means that different values of the flags,
-ndim, and niter will produce slightly different layouts. ::
+ndim, and niter will produce slightly different layouts.
+
+.. code-block:: c
struct {
/* Flags indicate what optimizations have been applied, and
Returns NULL if there is an error, otherwise returns the allocated
iterator.
- To make an iterator similar to the old iterator, this should work.::
+ To make an iterator similar to the old iterator, this should work.
+
+ .. code-block:: c
iter = NpyIter_New(op, NPY_ITER_READWRITE,
NPY_CORDER, NPY_NO_CASTING, NULL, 0, NULL);
If you want to edit an array with aligned ``double`` code,
- but the order doesn't matter, you would use this.::
+ but the order doesn't matter, you would use this.
+
+ .. code-block:: c
dtype = PyArray_DescrFromType(NPY_DOUBLE);
iter = NpyIter_New(op, NPY_ITER_READWRITE |
In ``op_axes[j][i]`` is stored either a valid axis of ``op[j]``, or
-1 which means ``newaxis``. Within each ``op_axes[j]`` array, axes
may not be repeated. The following example is how normal broadcasting
- applies to a 3-D array, a 2-D array, a 1-D array and a scalar.::
+ applies to a 3-D array, a 2-D array, a 1-D array and a scalar.
+
+ .. code-block:: c
npy_intp oa_ndim = 3; /* # iteration axes */
npy_intp op0_axes[] = {0, 1, 2}; /* 3-D operand */
If you want to reset both the ``iterindex`` range and the base
pointers at the same time, you can do the following to avoid
extra buffer copying (be sure to add the return code error checks
- when you copy this code).::
+ when you copy this code).
+
+ .. code-block:: c
/* Set to a trivial empty range */
NpyIter_ResetToIterIndexRange(iter, 0, 0);
is used as the source for ``baseptrs``, it will point into a small buffer
instead of the array and the inner iteration will be invalid.
- The pattern for using nested iterators is as follows.::
+ The pattern for using nested iterators is as follows:
+
+ .. code-block:: c
NpyIter *iter1, *iter1;
NpyIter_IterNext_Fn iternext1, iternext2;
non-NULL, the function may be safely called without holding
the Python GIL.
- The typical looping construct is as follows.::
+ The typical looping construct is as follows:
+
+ .. code-block:: c
NpyIter_IterNext_Fn iternext = NpyIter_GetIterNext(iter, NULL);
char **dataptr = NpyIter_GetDataPtrArray(iter);
} while(iternext(iter));
When ``NPY_ITER_NO_INNER_ITERATION`` is specified, the typical
- inner loop construct is as follows.::
+ inner loop construct is as follows:
+
+ .. code-block:: c
NpyIter_IterNext_Fn iternext = NpyIter_GetIterNext(iter, NULL);
char **dataptr = NpyIter_GetDataPtrArray(iter);
to become zero when ``iternext()`` returns false, enabling the
following loop construct. Note that if you use this construct,
you should not pass ``NPY_ITER_GROWINNER`` as a flag, because it
- will cause larger sizes under some circumstances.::
+ will cause larger sizes under some circumstances:
+
+ .. code-block:: c
/* The constructor should have buffersize passed as this value */
#define FIXED_BUFFER_SIZE 1024
If the input is a reference type, this function will fail.
To fix this, the code must be changed to specially handle writeable
-references, and add ``NPY_ITER_WRITEABLE_REFERENCES`` to the flags.::
+references, and add ``NPY_ITER_WRITEABLE_REFERENCES`` to the flags:
+
+.. code-block:: c
/* NOTE: This code has not been compiled/tested */
PyObject *CopyArray(PyObject *arr, NPY_ORDER order)
+.. _NEP11:
+
==================================
NEP 11 — Deferred UFunc Evaluation
==================================
changing the Python code, consider the C++ technique of
expression templates. These can be used to quite arbitrarily
rearrange expressions using
-vectors or other data structures, example,::
+vectors or other data structures, example:
+
+.. code-block:: cpp
A = B + C + D;
-can be transformed into something equivalent to::
+can be transformed into something equivalent to:
+
+.. code-block:: cpp
for(i = 0; i < A.size; ++i) {
A[i] = B[i] + C[i] + D[i];
+.. _NEP12:
+
============================================
NEP 12 — Missing Data Functionality in NumPy
============================================
C Implementation Details
************************
+.. highlight:: c
+
The first version to implement is the array masks, because it is
the more general approach. The mask itself is an array, but since
it is intended to never be directly accessible from Python, it won't
In addition to feedback from Travis Oliphant and others at Enthought,
this NEP has been revised based on a great deal of feedback from
the NumPy-Discussion mailing list. The people participating in
-the discussion are::
-
- Nathaniel Smith
- Robert Kern
- Charles Harris
- Gael Varoquaux
- Eric Firing
- Keith Goodman
- Pierre GM
- Christopher Barker
- Josef Perktold
- Ben Root
- Laurent Gautier
- Neal Becker
- Bruce Southey
- Matthew Brett
- Wes McKinney
- Lluís
- Olivier Delalleau
- Alan G Isaac
- E. Antero Tammi
- Jason Grout
- Dag Sverre Seljebotn
- Joe Harrington
- Gary Strangman
- Chris Jordan-Squire
- Peter
+the discussion are:
+
+- Nathaniel Smith
+- Robert Kern
+- Charles Harris
+- Gael Varoquaux
+- Eric Firing
+- Keith Goodman
+- Pierre GM
+- Christopher Barker
+- Josef Perktold
+- Ben Root
+- Laurent Gautier
+- Neal Becker
+- Bruce Southey
+- Matthew Brett
+- Wes McKinney
+- Lluís
+- Olivier Delalleau
+- Alan G Isaac
+- E. Antero Tammi
+- Jason Grout
+- Dag Sverre Seljebotn
+- Joe Harrington
+- Gary Strangman
+- Chris Jordan-Squire
+- Peter
I apologize if I missed anyone.
+.. _NEP13:
+
==========================================
NEP 13 — A Mechanism for Overriding Ufuncs
==========================================
[ 4, 1, 4]], dtype=int64)
In [5]: np.multiply(a, bsp) # Returns NotImplemented to user, bad!
- Out[5]: NotImplemted
+ Out[5]: NotImplemented
Returning :obj:`NotImplemented` to user should not happen. Moreover::
+.. _NEP14:
+
=============================================
NEP 14 — Plan for dropping Python 2.7 support
=============================================
+.. _NEP15:
+
=====================================
NEP 15 — Merging multiarray and umath
=====================================
+.. _NEP16:
+
=============================================================
NEP 16 — An abstract base class for identifying "duck arrays"
=============================================================
+.. _NEP17:
+
================================
NEP 17 — Split Out Masked Arrays
================================
+.. _NEP18:
+
====================================================================
NEP 18 — A dispatch mechanism for NumPy's high level array functions
====================================================================
:Author: Marten van Kerkwijk <mhvk@astro.utoronto.ca>
:Author: Hameer Abbasi <hameerabbasi@yahoo.com>
:Author: Eric Wieser <wieser.eric@gmail.com>
-:Status: Provisional
+:Status: Final
:Type: Standards Track
:Created: 2018-05-29
:Updated: 2019-05-25
+.. _NEP19:
+
=======================================
NEP 19 — Random Number Generator Policy
=======================================
+.. _NEP20:
+
===============================================================
NEP 20 — Expansion of Generalized Universal Function Signatures
===============================================================
+.. _NEP21:
+
==================================================
NEP 21 — Simplified and explicit advanced indexing
==================================================
+.. _NEP22:
+
===========================================================
NEP 22 — Duck typing for NumPy arrays – high level overview
===========================================================
--------------------
Traditionally, NumPy’s ``ndarray`` objects have provided two things: a
-high level API for expression operations on homogenously-typed,
+high level API for expression operations on homogeneously-typed,
arbitrary-dimensional, array-structured data, and a concrete
implementation of the API based on strided in-RAM storage. The API is
powerful, fairly general, and used ubiquitously across the scientific
+.. _NEP23:
+
=======================================================
NEP 23 — Backwards compatibility and deprecation policy
=======================================================
+.. _NEP24:
+
=============================================================
NEP 24 — Missing Data Functionality - Alternative 1 to NEP 12
=============================================================
+.. _NEP25:
+
======================================
NEP 25 — NA support via special dtypes
======================================
dtype C-level API extensions
============================
+.. highlight:: c
+
The `PyArray_Descr`_ struct gains the following new fields::
void * NA_value;
own global singleton.) So for now we stick to scalar indexing just returning
``np.NA``, but this can be revisited if anyone objects.
+.. highlight:: python
+
Python API for generic NA support
=================================
+.. _NEP26:
+
====================================================
NEP 26 — Summary of Missing Data NEPs and discussion
====================================================
:Created: 2012-04-22
*Context*: this NEP was written as summary of the large number of discussions
-and proposals (`NEP 12`_, `NEP 24`_, `NEP 25`_), regarding missing data
+and proposals (:ref:`NEP12`, :ref:`NEP24`, :ref:`NEP25`), regarding missing data
functionality.
The debate about how NumPy should handle missing data, a subject with
One option is to copy numpy.ma closely, but with a more optimized
implementation. (Or to simply optimize the existing implementation.)
-One option is that described in `NEP 12`_, for which an implementation
+One option is that described in `NEP12`, for which an implementation
of mask-based missing data exists. This system is roughly:
* There is both bitpattern and mask-based missing data, and both
a bitpattern NA to an array which supports both requires accessing
the data by "peeking under the mask".
-Another option is that described in `NEP 24`_, which is to implement
+Another option is that described in `NEP24`, which is to implement
bitpattern dtypes with NA semantics for the "statistical missing data"
use case, and to also implement a totally independent API for masked
arrays with ignore semantics and all mask manipulation done explicitly
References and Footnotes
------------------------
-`NEP 12`_ describes Mark's NA-semantics/mask implementation/view based mask
+:ref:`NEP12` describes Mark's NA-semantics/mask implementation/view based mask
handling API.
-`NEP 24`_ ("the alterNEP") was Nathaniel's initial attempt at separating MISSING
+:ref:`NEP24` ("the alterNEP") was Nathaniel's initial attempt at separating MISSING
and IGNORED handling into bit-patterns versus masks, though there's a bunch
he would change about the proposal at this point.
-`NEP 25`_ ("miniNEP 2") was a later attempt by Nathaniel to sketch out an
+:ref:`NEP25` ("miniNEP 2") was a later attempt by Nathaniel to sketch out an
implementation strategy for NA dtypes.
A further discussion overview page can be found at:
---------
This document has been placed in the public domain.
-
-.. _NEP 12: http://www.numpy.org/neps/nep-0012-missing-data.html
-
-.. _NEP 24: http://www.numpy.org/neps/nep-0024-missing-data-2.html
-
-.. _NEP 25: http://www.numpy.org/neps/nep-0025-missing-data-3.html
+.. _NEP27:
+
=========================
NEP 27 — Zero Rank Arrays
=========================
+.. _NEP28:
+
===================================
NEP 28 — numpy.org website redesign
===================================
+.. _NEP29:
+
==================================================================================
NEP 29 — Recommend Python and Numpy version support as a community policy standard
==================================================================================
The current Python release cadence is 18 months so a 42 month window
ensures that there will always be at least two minor versions of Python
in the window. The window is extended 6 months beyond the anticipated two-release
-interval for Python to provides resilience against small fluctuations /
+interval for Python to provide resilience against small fluctuations /
delays in its release schedule.
Because Python minor version support is based only on historical
Jul 23, 2020 3.7+ 1.16+
Jan 13, 2021 3.7+ 1.17+
Jul 26, 2021 3.7+ 1.18+
-Dec 26, 2021 3.8+ 1.18+
-Apr 14, 2023 3.9+ 1.18+
+Dec 22, 2021 3.7+ 1.19+
+Dec 26, 2021 3.8+ 1.19+
+Jun 21, 2022 3.8+ 1.20+
+Apr 14, 2023 3.9+ 1.20+
============ ====== =====
On Jul 23, 2020 drop support for Numpy 1.15 (initially released on Jul 23, 2018)
On Jan 13, 2021 drop support for Numpy 1.16 (initially released on Jan 13, 2019)
On Jul 26, 2021 drop support for Numpy 1.17 (initially released on Jul 26, 2019)
+ On Dec 22, 2021 drop support for Numpy 1.18 (initially released on Dec 22, 2019)
On Dec 26, 2021 drop support for Python 3.7 (initially released on Jun 27, 2018)
+ On Jun 21, 2022 drop support for Numpy 1.19 (initially released on Jun 20, 2020)
On Apr 14, 2023 drop support for Python 3.8 (initially released on Oct 14, 2019)
Jan 13, 2019: Numpy 1.16
Jul 26, 2019: Numpy 1.17
Oct 14, 2019: Python 3.8
+ Dec 22, 2019: Numpy 1.18
+ Jun 20, 2020: Numpy 1.19
"""
releases = []
releases = sorted(releases, key=lambda x: x[0])
- minpy = '3.9+'
- minnum = '1.18+'
+
+ py_major,py_minor = sorted([int(x) for x in r[2].split('.')] for r in releases if r[1] == 'Python')[-1]
+ minpy = f"{py_major}.{py_minor+1}+"
+
+ num_major,num_minor = sorted([int(x) for x in r[2].split('.')] for r in releases if r[1] == 'Numpy')[-1]
+ minnum = f"{num_major}.{num_minor+1}+"
toprint_drop_dates = ['']
toprint_support_table = []
minnum = v+'+'
else:
minpy = v+'+'
-
- for e in toprint_drop_dates[::-1]:
+ print("On next release, drop support for Python 3.5 (initially released on Sep 13, 2015)")
+ for e in toprint_drop_dates[-4::-1]:
print(e)
print('============ ====== =====')
print('Date Python NumPy')
print('------------ ------ -----')
- for e in toprint_support_table[::-1]:
+ for e in toprint_support_table[-4::-1]:
print(e)
print('============ ====== =====')
+.. _NEP30:
+
======================================================
NEP 30 — Duck Typing for NumPy Arrays - Implementation
======================================================
+.. _NEP31:
+
============================================================
NEP 31 — Context-local and global overrides of the NumPy API
============================================================
+.. _NEP32:
+
==================================================
NEP 32 — Remove the financial functions from NumPy
==================================================
+.. _NEP34:
+
===========================================================
NEP 34 — Disallow inferring ``dtype=object`` from sequences
===========================================================
+.. _NEP35:
+
===========================================================
NEP 35 — Array Creation Dispatching With __array_function__
===========================================================
:Status: Draft
:Type: Standards Track
:Created: 2019-10-15
-:Updated: 2019-10-15
+:Updated: 2020-11-06
:Resolution:
Abstract
--------
We propose the introduction of a new keyword argument ``like=`` to all array
-creation functions to permit dispatching of such functions by the
-``__array_function__`` protocol, addressing one of the protocol shortcomings,
-as described by NEP-18 [1]_.
+creation functions to address one of the shortcomings of ``__array_function__``,
+as described by NEP 18 [1]_. The ``like=`` keyword argument will create an
+instance of the argument's type, enabling direct creation of non-NumPy arrays.
+The target array type must implement the ``__array_function__`` protocol.
+
+Motivation and Scope
+--------------------
+
+Many libraries implement the NumPy API, such as Dask for graph
+computing, CuPy for GPGPU computing, xarray for N-D labeled arrays, etc. Underneath,
+they have adopted the ``__array_function__`` protocol which allows NumPy to understand
+and treat downstream objects as if they are the native ``numpy.ndarray`` object.
+Hence the community while using various libraries still benefits from a unified
+NumPy API. This not only brings great convenience for standardization but also
+removes the burden of learning a new API and rewriting code for every new
+object. In more technical terms, this mechanism of the protocol is called a
+"dispatcher", which is the terminology we use from here onwards when referring
+to that.
+
+
+.. code:: python
+
+ x = dask.array.arange(5) # Creates dask.array
+ np.diff(x) # Returns dask.array
+
+Note above how we called Dask's implementation of ``diff`` via the NumPy
+namespace by calling ``np.diff``, and the same would apply if we had a CuPy
+array or any other array from a library that adopts ``__array_function__``.
+This allows writing code that is agnostic to the implementation library, thus
+users can write their code once and still be able to use different array
+implementations according to their needs.
+
+Obviously, having a protocol in-place is useful if the arrays are created
+elsewhere and let NumPy handle them. But still these arrays have to be started
+in their native library and brought back. Instead if it was possible to create
+these objects through NumPy API then there would be an almost complete
+experience, all using NumPy syntax. For example, say we have some CuPy array
+``cp_arr``, and want a similar CuPy array with identity matrix. We could still
+write the following:
+
+.. code:: python
+
+ x = cupy.identity(3)
+
+Instead, the better way would be using to only use the NumPy API, this could now
+be achieved with:
+
+.. code:: python
+
+ x = np.identity(3, like=cp_arr)
+
+As if by magic, ``x`` will also be a CuPy array, as NumPy was capable to infer
+that from the type of ``cp_arr``. Note that this last step would not be possible
+without ``like=``, as it would be impossible for the NumPy to know the user
+expects a CuPy array based only on the integer input.
+
+The new ``like=`` keyword proposed is solely intended to identify the downstream
+library where to dispatch and the object is used only as reference, meaning that
+no modifications, copies or processing will be performed on that object.
+
+We expect that this functionality will be mostly useful to library developers,
+allowing them to create new arrays for internal usage based on arrays passed
+by the user, preventing unnecessary creation of NumPy arrays that will
+ultimately lead to an additional conversion into a downstream array type.
+
+Support for Python 2.7 has been dropped since NumPy 1.17, therefore we make use
+of the keyword-only argument standard described in PEP-3102 [2]_ to implement
+``like=``, thus preventing it from being passed by position.
+
+.. _neps.like-kwarg.usage-and-impact:
+
+Usage and Impact
+----------------
+
+NumPy users who don't use other arrays from downstream libraries can continue
+to use array creation routines without a ``like=`` argument. Using
+``like=np.ndarray`` will work as if no array was passed via that argument.
+However, this will incur additional checks that will negatively impact
+performance.
+
+To understand the intended use for ``like=``, and before we move to more complex
+cases, consider the following illustrative example consisting only of NumPy and
+CuPy arrays:
+
+.. code:: python
+
+ import numpy as np
+ import cupy
+
+ def my_pad(arr, padding):
+ padding = np.array(padding, like=arr)
+ return np.concatenate((padding, arr, padding))
+
+ my_pad(np.arange(5), [-1, -1]) # Returns np.ndarray
+ my_pad(cupy.arange(5), [-1, -1]) # Returns cupy.core.core.ndarray
+
+Note in the ``my_pad`` function above how ``arr`` is used as a reference to
+dictate what array type padding should have, before concatenating the arrays to
+produce the result. On the other hand, if ``like=`` wasn't used, the NumPy case
+would still work, but CuPy wouldn't allow this kind of automatic
+conversion, ultimately raising a
+``TypeError: Only cupy arrays can be concatenated`` exception.
+
+Now we should look at how a library like Dask could benefit from ``like=``.
+Before we understand that, it's important to understand a bit about Dask basics
+and how it ensures correctness with ``__array_function__``. Note that Dask can
+perform computations on different sorts of objects, like dataframes, bags and
+arrays, here we will focus strictly on arrays, which are the objects we can use
+``__array_function__`` with.
+
+Dask uses a graph computing model, meaning it breaks down a large problem in
+many smaller problems and merges their results to reach the final result. To
+break the problem down into smaller ones, Dask also breaks arrays into smaller
+arrays that it calls "chunks". A Dask array can thus consist of one or more
+chunks and they may be of different types. However, in the context of
+``__array_function__``, Dask only allows chunks of the same type; for example,
+a Dask array can be formed of several NumPy arrays or several CuPy arrays, but
+not a mix of both.
+
+To avoid mismatched types during computation, Dask keeps an attribute ``_meta`` as
+part of its array throughout computation: this attribute is used to both predict
+the output type at graph creation time, and to create any intermediary arrays
+that are necessary within some function's computation. Going back to our
+previous example, we can use ``_meta`` information to identify what kind of
+array we would use for padding, as seen below:
+
+.. code:: python
+
+ import numpy as np
+ import cupy
+ import dask.array as da
+ from dask.array.utils import meta_from_array
+
+ def my_dask_pad(arr, padding):
+ padding = np.array(padding, like=meta_from_array(arr))
+ return np.concatenate((padding, arr, padding))
+
+ # Returns dask.array<concatenate, shape=(9,), dtype=int64, chunksize=(5,), chunktype=numpy.ndarray>
+ my_dask_pad(da.arange(5), [-1, -1])
+
+ # Returns dask.array<concatenate, shape=(9,), dtype=int64, chunksize=(5,), chunktype=cupy.ndarray>
+ my_dask_pad(da.from_array(cupy.arange(5)), [-1, -1])
+
+Note how ``chunktype`` in the return value above changes from
+``numpy.ndarray`` in the first ``my_dask_pad`` call to ``cupy.ndarray`` in the
+second. We have also renamed the function to ``my_dask_pad`` in this example
+with the intent to make it clear that this is how Dask would implement such
+functionality, should it need to do so, as it requires Dask's internal tools
+that are not of much use elsewhere.
+
+To enable proper identification of the array type we use Dask's utility function
+``meta_from_array``, which was introduced as part of the work to support
+``__array_function__``, allowing Dask to handle ``_meta`` appropriately. Readers
+can think of ``meta_from_array`` as a special function that just returns the
+type of the underlying Dask array, for example:
+
+.. code:: python
+
+ np_arr = da.arange(5)
+ cp_arr = da.from_array(cupy.arange(5))
+
+ meta_from_array(np_arr) # Returns a numpy.ndarray
+ meta_from_array(cp_arr) # Returns a cupy.ndarray
+
+Since the value returned by ``meta_from_array`` is a NumPy-like array, we can
+just pass that directly into the ``like=`` argument.
+
+The ``meta_from_array`` function is primarily targeted at the library's internal
+usage to ensure chunks are created with correct types. Without the ``like=``
+argument, it would be impossible to ensure ``my_pad`` creates a padding array
+with a type matching that of the input array, which would cause a ``TypeError``
+exception to be raised by CuPy, as discussed above would happen to the CuPy case
+alone. Combining Dask's internal handling of meta arrays and the proposed
+``like=`` argument, it now becomes possible to handle cases involving creation
+of non-NumPy arrays, which is likely the heaviest limitation Dask currently
+faces from the ``__array_function__`` protocol.
+
+Backward Compatibility
+----------------------
+
+This proposal does not raise any backward compatibility issues within NumPy,
+given that it only introduces a new keyword argument to existing array creation
+functions with a default ``None`` value, thus not changing current behavior.
Detailed description
--------------------
libraries, preventing those libraries from using such important functionality in
that context.
-Other NEPs have been written to address parts of that limitation, such as the
-introduction of the ``__duckarray__`` protocol in NEP-30 [2]_, and the
-introduction of an overriding mechanism called ``uarray`` by NEP-31 [3]_.
-
The purpose of this NEP is to address that shortcoming in a simple and
straighforward way: introduce a new ``like=`` keyword argument, similar to how
the ``empty_like`` family of functions work. When array creation functions
and call the downstream library's own array creation function implementation.
The ``like=`` argument, as its own name suggests, shall be used solely for the
purpose of identifying where to dispatch. In contrast to the way
-``__array_function__`` has been used so far (the first argument identifies where
-to dispatch), and to avoid breaking NumPy's API with regards to array creation,
-the new ``like=`` keyword shall be used for the purpose of dispatching.
-
-Usage Guidance
-~~~~~~~~~~~~~~
-
-The new ``like=`` keyword is solely intended to identify the downstream library
-where to dispatch and the object is used only as reference, meaning that no
-modifications, copies or processing will be performed on that object.
-
-We expect that this functionality will be mostly useful to library developers,
-allowing them to create new arrays for internal usage based on arrays passed
-by the user, preventing unnecessary creation of NumPy arrays that will
-ultimately lead to an additional conversion into a downstream array type.
+``__array_function__`` has been used so far (the first argument identifies the
+target downstream library), and to avoid breaking NumPy's API with regards to
+array creation, the new ``like=`` keyword shall be used for the purpose of
+dispatching.
+
+Downstream libraries will benefit from the ``like=`` argument without any
+changes to their API, given the argument only needs to be implemented by NumPy.
+It's still allowed that downstream libraries include the ``like=`` argument,
+as it can be useful in some cases, please refer to
+:ref:`neps.like-kwarg.implementation` for details on those cases. It will still
+be required that downstream libraries implement the ``__array_function__``
+protocol, as described by NEP 18 [1]_, and appropriately introduce the argument
+to their calls to NumPy array creation functions, as exemplified in
+:ref:`neps.like-kwarg.usage-and-impact`.
+
+Related work
+------------
+
+Other NEPs have been written to address parts of ``__array_function__``
+protocol's limitation, such as the introduction of the ``__duckarray__``
+protocol in NEP 30 [3]_, and the introduction of an overriding mechanism called
+``uarray`` by NEP 31 [4]_.
+
+.. _neps.like-kwarg.implementation:
Implementation
--------------
array creation functions of NumPy. As examples of functions that would add this
new argument (but not limited to) we can cite those taking array-like objects
such as ``array`` and ``asarray``, functions that create arrays based on
-numerical ranges such as ``range`` and ``linspace``, as well as the ``empty``
-family of functions, even though that may be redundant, since there exists
-already specializations for those with the naming format ``empty_like``. As of
-the writing of this NEP, a complete list of array creation functions can be
-found in [4]_.
+numerical inputs such as ``range`` and ``identity``, as well as the ``empty``
+family of functions, even though that may be redundant, since specializations
+for those already exist with the naming format ``empty_like``. As of the
+writing of this NEP, a complete list of array creation functions can be
+found in [5]_.
This newly proposed keyword shall be removed by the ``__array_function__``
mechanism from the keyword dictionary before dispatching. The purpose for this
is twofold:
-1. The object will have no use in the downstream library's implementation; and
-2. Simplifies adoption of array creation by those libraries already opting-in
+1. Simplifies adoption of array creation by those libraries already opting-in
to implement the ``__array_function__`` protocol, thus removing the
- requirement to explicitly opt-in for all array creation functions.
-
-Downstream libraries thus shall _NOT_ include the ``like=`` keyword to their
-array creation APIs, which is a NumPy-exclusive keyword.
+ requirement to explicitly opt-in for all array creation functions; and
+2. Most downstream libraries will have no use for the keyword argument, and
+ those that do may accomplish so by capturing ``self`` from
+ ``__array_function__``.
+
+Downstream libraries thus do not require to include the ``like=`` keyword to
+their array creation APIs. In some cases (e.g., Dask), having the ``like=``
+keyword can be useful, as it would allow the implementation to identify
+array internals. As an example, Dask could benefit from the reference array
+to identify its chunk type (e.g., NumPy, CuPy, Sparse), and thus create a new
+Dask array backed by the same chunk type, something that's not possible unless
+Dask can read the reference array's attributes.
Function Dispatching
~~~~~~~~~~~~~~~~~~~~
.. code:: python
- def _asarray_decorator(a, dtype=None, order=None, like=None):
+ def _asarray_decorator(a, dtype=None, order=None, *, like=None):
return (like,)
@set_module('numpy')
@array_function_dispatch(_asarray_decorator)
- def asarray(a, dtype=None, order=None, like=None):
+ def asarray(a, dtype=None, order=None, *, like=None):
return array(a, dtype, copy=False, order=order)
Note in the example above that the implementation remains unchanged, the only
module='numpy', docs_from_dispatcher=False, verify=False)
@array_function_nodocs_from_c_func_and_dispatcher(_multiarray_umath.array)
- def array(a, dtype=None, copy=True, order='K', subok=False, ndmin=0, like=None):
+ def array(a, dtype=None, *, copy=True, order='K', subok=False, ndmin=0,
+ like=None):
return (like,)
There are two downsides to the implementation above for C functions:
2. To follow current implementation standards, documentation should be attached
directly to the Python source code.
-Alternatively for C functions, the implementation of ``like=`` could be moved
-into the C implementation itself. This is not the primary suggestion here due
-to its inherent complexity which would be difficult too long to describe in its
-entirety here, and too tedious for the reader. However, we leave that as an
-option open for discussion.
+The first version of this proposal suggested the implementation above as one
+viable solution for NumPy functions implemented in C. However, due to the
+downsides pointed out above we have decided to discard any changes on the Python
+side and resolve those issues with a pure-C implementation. Please refer to
+[implementation]_ for details.
+
+Reading the Reference Array Downstream
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Usage
------
+As stated in the beginning of :ref:`neps.like-kwarg.implementation` section,
+``like=`` is not propagated to the downstream library, nevertheless, it's still
+possible to access it. This requires some changes in the downstream library's
+``__array_function__`` definition, where the ``self`` attribute is in practice
+that passed via ``like=``. This is the case because we use ``like=`` as the
+dispatching array, unlike other compute functions covered by NEP-18 that usually
+dispatch on the first positional argument.
-The purpose of this NEP is to keep things simple. Similarly, we can exemplify
-the usage of ``like=`` in a simple way. Imagine you have an array of ones
-created by a downstream library, such as CuPy. What you need now is a new array
-that can be created using the NumPy API, but that will in fact be created by
-the downstream library, a simple way to achieve that is shown below.
+An example of such use is to create a new Dask array while preserving its
+backend type:
.. code:: python
+ # Returns dask.array<array, shape=(3,), dtype=int64, chunksize=(3,), chunktype=cupy.ndarray>
+ np.asarray([1, 2, 3], like=da.array(cp.array(())))
- x = cupy.ones(2)
- np.array([1, 3, 5], like=x) # Returns cupy.ndarray
+ # Returns a cupy.ndarray
+ type(np.asarray([1, 2, 3], like=da.array(cp.array(()))).compute())
-As a second example, we could also create an array of evenly spaced numbers
-using a Dask identity matrix as reference:
+Note how above the array is backed by ``chunktype=cupy.ndarray``, and the
+resulting array after computing it is also a ``cupy.ndarray``. If Dask did
+not use the ``like=`` argument via the ``self`` attribute from
+``__array_function__``, the example above would be backed by ``numpy.ndarray``
+instead:
.. code:: python
+ # Returns dask.array<array, shape=(3,), dtype=int64, chunksize=(3,), chunktype=numpy.ndarray>
+ np.asarray([1, 2, 3], like=da.array(cp.array(())))
- x = dask.array.eye(3)
- np.linspace(0, 2, like=x) # Returns dask.array
+ # Returns a numpy.ndarray
+ type(np.asarray([1, 2, 3], like=da.array(cp.array(()))).compute())
+Given the library would need to rely on ``self`` attribute from
+``__array_function__`` to dispatch the function with the correct reference
+array, we suggest one of two alternatives:
-Compatibility
--------------
+1. Introduce a list of functions in the downstream library that do support the
+ ``like=`` argument and pass ``like=self`` when calling the function; or
+2. Inspect whether the function's signature and verify whether it includes the
+ ``like=`` argument. Note that this may incur in a higher performance penalty
+ and assumes introspection is possible, which may not be if the function is
+ a C function.
-This proposal does not raise any backward compatibility issues within NumPy,
-given that it only introduces a new keyword argument to existing array creation
-functions.
+To make things clearer, let's take a look at how suggestion 2 could be
+implemented in Dask. The current relevant part of ``__array_function__``
+definition in Dask is seen below:
+
+.. code:: python
+ def __array_function__(self, func, types, args, kwargs):
+ # Code not relevant for this example here
+
+ # Dispatch ``da_func`` (da.asarray, for example) with *args and **kwargs
+ da_func(*args, **kwargs)
+
+And this is how the updated code would look like:
+
+.. code:: python
+ def __array_function__(self, func, types, args, kwargs):
+ # Code not relevant for this example here
+
+ # Inspect ``da_func``'s signature and store keyword-only arguments
+ import inspect
+ kwonlyargs = inspect.getfullargspec(da_func).kwonlyargs
+
+ # If ``like`` is contained in ``da_func``'s signature, add ``like=self``
+ # to the kwargs dictionary.
+ if 'like' in kwonlyargs:
+ kwargs['like'] = self
+
+ # Dispatch ``da_func`` (da.asarray, for example) with args and kwargs.
+ # Here, kwargs contain ``like=self`` if the function's signature does too.
+ da_func(*args, **kwargs)
+
+Alternatives
+------------
+
+Recently a new protocol to replace ``__array_function__`` entirely was proposed
+by NEP 37 [6]_, which would require considerable rework by downstream libraries
+that adopt ``__array_function__`` already, because of that we still believe the
+``like=`` argument is beneficial for NumPy and downstream libraries. However,
+that proposal wouldn't necessarily be considered a direct alternative to the
+present NEP, as it would replace NEP 18 entirely, upon which this builds.
+Discussion on details about this new proposal and why that would require rework
+by downstream libraries is beyond the scope of the present proposal.
+
+Discussion
+----------
+
+.. [implementation] `Implementation's pull request on GitHub <https://github.com/numpy/numpy/pull/16935>`_
+.. [discussion] `Further discussion on implementation and the NEP's content <https://mail.python.org/pipermail/numpy-discussion/2020-August/080919.html>`_
+
+References
+----------
-Downstream libraries will benefit from the ``like=`` argument automatically,
-that is, without any explicit changes in their codebase. The only requirement
-is that they already implement the ``__array_function__`` protocol, as
-described by NEP-18 [2]_.
+.. [1] `NEP 18 - A dispatch mechanism for NumPy's high level array functions <https://numpy.org/neps/nep-0018-array-function-protocol.html>`_.
-References and Footnotes
-------------------------
+.. [2] `PEP 3102 — Keyword-Only Arguments <https://www.python.org/dev/peps/pep-3102/>`_.
-.. [1] `NEP-18 - A dispatch mechanism for NumPy's high level array functions <https://numpy.org/neps/nep-0018-array-function-protocol.html>`_.
+.. [3] `NEP 30 — Duck Typing for NumPy Arrays - Implementation <https://numpy.org/neps/nep-0030-duck-array-protocol.html>`_.
-.. [2] `NEP 30 — Duck Typing for NumPy Arrays - Implementation <https://numpy.org/neps/nep-0030-duck-array-protocol.html>`_.
+.. [4] `NEP 31 — Context-local and global overrides of the NumPy API <https://github.com/numpy/numpy/pull/14389>`_.
-.. [3] `NEP 31 — Context-local and global overrides of the NumPy API <https://github.com/numpy/numpy/pull/14389>`_.
+.. [5] `Array creation routines <https://docs.scipy.org/doc/numpy-1.17.0/reference/routines.array-creation.html>`_.
-.. [4] `Array creation routines <https://docs.scipy.org/doc/numpy-1.17.0/reference/routines.array-creation.html>`_.
+.. [6] `NEP 37 — A dispatch protocol for NumPy-like modules <https://numpy.org/neps/nep-0037-array-module.html>`_.
Copyright
---------
--- /dev/null
+==================
+NEP 36 — Fair play
+==================
+
+:Author: Stéfan van der Walt <stefanv@berkeley.edu>
+:Status: Draft
+:Type: Informational
+:Created: 2019-10-24
+:Resolution: Draft
+
+
+Abstract
+--------
+
+This document sets out Rules of Play for companies and outside
+developers that engage with the NumPy project. It covers:
+
+- Restrictions on use of the NumPy name
+- How and whether to publish a modified distribution
+- How to make us aware of patched versions
+
+Companies and developers will know after reading this NEP what kinds
+of behavior the community would like to see, and which we consider
+troublesome, bothersome, and unacceptable.
+
+Motivation
+----------
+
+We sometimes learn of NumPy versions modified and circulated by outsiders.
+These patched versions can cause problems for the NumPy community.
+
+- In December 2018, a `bug report
+ <https://github.com/numpy/numpy/issues/12515>`__ was filed against
+ `np.erf` -- a function that didn't exist in the NumPy distribution.
+ It came to light that a company had published a NumPy version with
+ an extended API footprint. After several months of discussion, the
+ company agreed to make its patches public, and we added a label to
+ the NumPy issue tracker to identify issues pertaining to that
+ distribution.
+
+- In another case, after a security issue (CVE-2019-6446) was filed
+ against NumPy, distributions put in their own fixes, most often by
+ changing a default keyword value. As a result the NumPy API was
+ inconsistent across distributions.
+
+When issues arise in cases like these, our developers waste time
+identifying the problematic release, locating alterations,
+and determining an appropriate course of action.
+
+During a community call on `October 16th, 2019
+<https://github.com/numpy/archive/blob/master/status_meetings/status-2019-10-16.md>`__
+the community resolved to draft guidelines on the distribution of
+modified NumPy versions.
+
+Scope
+-----
+
+This document aims to define a minimal set of rules that, when
+followed, will be considered good-faith efforts in line with the
+expectations of the NumPy developers.
+
+Our hope is that developers who feel they need to modify NumPy will
+first consider contributing to the project, or use one of several existing
+mechanisms for extending our APIs and for operating on
+externally defined array objects.
+
+When in doubt, please `talk to us first
+<https://numpy.org/community/>`__. We may suggest an alternative; at
+minimum, we'll be prepared.
+
+Fair play rules
+---------------
+
+1. Do not reuse the NumPy name for projects not developed by the NumPy
+ community.
+
+ At time of writing, there are only a handful of ``numpy``-named
+ packages developed by the community, including ``numpy``,
+ ``numpy-financial``, and ``unumpy``. We ask that external packages not
+ include the phrase ``numpy``, i.e., avoid names such as
+ ``mycompany_numpy``.
+
+ To be clear, this rule only applies to modules (package names); it
+ is perfectly acceptable to have a *submodule* of your own library
+ named ``mylibrary.numpy``.
+
+ NumPy is a trademark owned by NumFOCUS.
+
+2. Do not republish modified versions of NumPy.
+
+ Modified versions of NumPy make it very difficult for the
+ developers to address bug reports, since we typically do not know
+ which parts of NumPy have been modified.
+
+ If you have to break this rule (and we implore you not
+ to!), then make it clear in the ``__version__`` tag that
+ you have modified NumPy, e.g.::
+
+ >>> print(np.__version__)
+ '1.17.2+mycompany.15`
+
+ We understand that minor patches are often required to make a
+ library work under a certain distribution. E.g., Debian may patch
+ NumPy so that it searches for optimized BLAS libraries in the
+ correct locations. But we ask that no substantive changes are
+ made.
+
+3. Do not extend NumPy's API footprint.
+
+ If you absolutely have to break rule two, please do not add
+ additional functions to the namespace. NumPy's API is already
+ quite large, and we are working hard to reduce it where feasible.
+ Having additional functions exposed in distributed versions is
+ confusing for users and developers alike.
+
+4. *DO* use official mechanism to engage with the API.
+
+ Protocols such as `__array_ufunc__
+ <https://numpy.org/neps/nep-0013-ufunc-overrides.html>`__ and
+ `__array_function__
+ <https://numpy.org/neps/nep-0018-array-function-protocol.html>`__
+ were designed to help external packages interact more easily with
+ NumPy. E.g., the latter allows objects from foreign libraries to
+ pass through NumPy unharmed. We actively encourage using any of
+ these "officialy sanctioned" mechanisms for overriding or
+ interacting with NumPy.
+
+ If these mechanisms are deemed insufficient, please start a
+ discussion on the mailing list before monkeypatching NumPy.
+
+Questions and answers
+-------------------
+
+**Q:** We would like to distribute an optimized version of NumPy that
+utilizes special instructions for our company's CPU. You recommend
+against that, so what are we to do?
+
+**A:** Please consider including the patches required in the official
+NumPy repository. Not only do we encourage such contributions, but we
+already have optimized loops for some platforms available.
+
+**Q:** We would like to ship a much faster version of FFT than NumPy
+provides, but NumPy has no mechanism for overriding its FFT routines.
+How do we proceed?
+
+**A:** There are two solutions that we approve of: let the users
+install your optimizations using a piece of code, such as::
+
+ from my_company_accel import patch_numpy_fft
+ patch_numpy_fft()
+
+or have your distribution automatically perform the above, but print a
+message to the terminal clearly stating what is happening::
+
+ We are now patching NumPy for optimal performance under MyComp
+ Special Platform. Please direct all bug reports to
+ https://mycomp.com/numpy-bugs
+
+If you require additional mechanisms for overriding code, please
+discuss this with the development team on the mailing list.
+
+**Q:** We would like to distribute NumPy with faster linear algebra
+routines. Are we allowed to do this?
+
+**A:** Yes, this is explicitly supported by linking to a different
+version of BLAS.
+
+Discussion
+----------
+
+References and footnotes
+------------------------
+
+Copyright
+---------
+
+This document has been placed in the public domain.
+.. _NEP37:
+
===================================================
NEP 37 — A dispatch protocol for NumPy-like modules
===================================================
+.. _NEP38:
+
=============================================================
NEP 38 — Using SIMD optimization instructions for performance
=============================================================
.. note::
- This NEP is part of a series of NEPs encompassing first information
- about the previous dtype implementation and issues with it in NEP 40
- (this document).
- :ref:`NEP 41 <NEP41>` then provides an overview and generic design choices
- for the refactor.
- Further NEPs 42 and 43 go into the technical details of the datatype
- and universal function related internal and external API changes.
- In some cases it may be necessary to consult the other NEPs for a full
- picture of the desired changes and why these changes are necessary.
+ This NEP is first in a series:
+
+ - NEP 40 (this document) explains the shortcomings of NumPy's dtype implementation.
+
+ - :ref:`NEP 41 <NEP41>` gives an overview of our proposed replacement.
+
+ - :ref:`NEP 42 <NEP42>` describes the new design's datatype-related APIs.
+
+ - NEP 43 describes the new design's API for universal functions.
In many cases subsections will be split roughly to first describe the
current implementation and then follow with an "Issues and Discussion" section.
+.. _parametric-datatype-discussion:
+
Parametric Datatypes
^^^^^^^^^^^^^^^^^^^^
In fact, some control flow within NumPy currently uses
``issubclass(a.dtype.type, np.inexact)``.
+.. _nep-0040_dtype-hierarchy:
+
.. figure:: _static/nep-0040_dtype-hierarchy.png
**Figure:** Hierarchy of NumPy scalar types reproduced from the reference
in C, which does the actual calculation, and may be called multiple times.
The main step in finding the correct inner-loop function is to call a
-:c:type:`PyUFunc_TypeResolutionFunc` which retrieves the input dtypes from
+:c:type:`PyUFunc_TypeResolutionFunc` which retrieves the input dtypes from
the provided input arrays
and will determine the full type signature (including output dtype) to be executed.
if any of the inputs (or the outputs) has the user datatype, since it uses the
`OO->O` signature.
For example, given that a ufunc loop to implement ``fraction_divide(int, int)
--> Fraction`` has been implemented,
+-> Fraction`` has been implemented,
the call ``fraction_divide(4, 5)`` (with no specific output dtype) will fail
because the loop that
includes the user datatype ``Fraction`` (as output) can only be found if any of
------------
* Julia types are an interesting blueprint for a type hierarchy, and define
- abstract and concrete types [julia-types]_.
+ abstract and concrete types [julia-types]_.
* In Julia promotion can occur based on abstract types. If a promoter is
defined, it will cast the inputs and then Julia can then retry to find
* https://hackmd.io/ok21UoAQQmOtSVk6keaJhw and https://hackmd.io/s/ryTFaOPHE
(2019-04-30) Proposals for subclassing implementation approach.
-
+
* Discussion about the calling convention of ufuncs and need for more
powerful UFuncs: https://github.com/numpy/numpy/issues/12518
.. note::
- This NEP is part of a series of NEPs encompassing first information
- about the previous dtype implementation and issues with it in
- :ref:`NEP 40 <NEP40>`.
- NEP 41 (this document) then provides an overview and generic design
- choices for the refactor.
- Further NEPs 42 and 43 go into the technical details of the datatype
- and universal function related internal and external API changes.
- In some cases it may be necessary to consult the other NEPs for a full
- picture of the desired changes and why these changes are necessary.
+ This NEP is second in a series:
+
+ - :ref:`NEP 40 <NEP40>` explains the shortcomings of NumPy's dtype implementation.
+
+ - NEP 41 (this document) gives an overview of our proposed replacement.
+
+ - :ref:`NEP 42 <NEP42>` describes the new design's datatype-related APIs.
+
+ - NEP 43 describes the new design's API for universal functions.
Abstract
* Phase II: Incrementally define or rework API
- * Create a new and easily extensible API for defining new datatypes
- and related functionality. (NEP 42)
-
- * Incrementally define all necessary functionality through the new API (NEP 42):
-
- * Defining operations such as ``np.common_type``.
- * Allowing to define casting between datatypes.
- * Add functionality necessary to create a numpy array from Python scalars
- (i.e. ``np.array(...)``).
- * …
-
- * Restructure how universal functions work (NEP 43), in order to:
-
- * make it possible to allow a `~numpy.ufunc` such as ``np.add`` to be
- extended by user-defined datatypes such as Units.
-
- * allow efficient lookup for the correct implementation for user-defined
- datatypes.
-
- * enable reuse of existing code. Units should be able to use the
- normal math loops and add additional logic to determine output type.
+ * Incrementally define all necessary functionality through methods and
+ properties on the DType (NEP 42):
+
+ * The properties of the class hierarchy and DType class itself,
+ including methods not covered by the following, most central, points.
+ * The functionality that will support dtype casting using ``arr.astype()``
+ and casting related operations such as ``np.common_type``.
+ * The implementation of item access and storage, and the way shape and
+ dtype are determined when creating an array with ``np.array()``
+ * Create a public C-API to define new DTypes.
+
+ * Restructure how universal functions work (NEP 43), to allow extending
+ a `~numpy.ufunc` such as ``np.add`` for user-defined datatypes
+ such as Units:
+
+ * Refactor how the low-level C functions are organized to make it
+ extensible and flexible enough for complicated DTypes such as Units.
+ * Implement registration and efficient lookup for these low-level C
+ functions as defined by the user.
+ * Define how promotion will be used to implement behaviour when casting
+ is required. For example ``np.float64(3) + np.int32(3)`` promotes the
+ ``int32`` to a ``float64``.
* Phase III: Growth of NumPy and Scientific Python Ecosystem capabilities:
* **C-API**:
- * In old versions of NumPy ``PyArray_DescrCheck`` is a macro which uses
- ``type(dtype) is np.dtype``. When compiling against an old NumPy version,
- the macro may have to be replaced with the corresponding
- ``PyObject_IsInstance`` call. (If this is a problem, we could backport
- fixing the macro)
+ * In old versions of NumPy ``PyArray_DescrCheck`` is a macro which uses
+ ``type(dtype) is np.dtype``. When compiling against an old NumPy version,
+ the macro may have to be replaced with the corresponding
+ ``PyObject_IsInstance`` call. (If this is a problem, we could backport
+ fixing the macro)
- * The UFunc machinery changes will break *limited* parts of the current
- implementation. Replacing e.g. the default ``TypeResolver`` is expected
- to remain supported for a time, although optimized masked inner loop iteration
- (which is not even used *within* NumPy) will no longer be supported.
+ * The UFunc machinery changes will break *limited* parts of the current
+ implementation. Replacing e.g. the default ``TypeResolver`` is expected
+ to remain supported for a time, although optimized masked inner loop iteration
+ (which is not even used *within* NumPy) will no longer be supported.
- * All functions currently defined on the dtypes, such as
- ``PyArray_Descr->f->nonzero``, will be defined and accessed differently.
- This means that in the long run lowlevel access code will
- have to be changed to use the new API. Such changes are expected to be
- necessary in very few project.
+ * All functions currently defined on the dtypes, such as
+ ``PyArray_Descr->f->nonzero``, will be defined and accessed differently.
+ This means that in the long run lowlevel access code will
+ have to be changed to use the new API. Such changes are expected to be
+ necessary in very few project.
* **dtype implementors (C-API)**:
At least in some code paths, a similar mechanism is already used.
* The ``scalarkind`` slot and registration of scalar casting will be
- removed/ignored without replacement.
- It currently allows partial value-based casting.
- The ``PyArray_ScalarKind`` function will continue to work for builtin types,
- but will not be used internally and be deprecated.
+ removed/ignored without replacement.
+ It currently allows partial value-based casting.
+ The ``PyArray_ScalarKind`` function will continue to work for builtin types,
+ but will not be used internally and be deprecated.
- * Currently user dtypes are defined as instances of ``np.dtype``.
- The creation works by the user providing a prototype instance.
- NumPy will need to modify at least the type during registration.
- This has no effect for either ``rational`` or ``quaternion`` and mutation
- of the structure seems unlikely after registration.
+ * Currently user dtypes are defined as instances of ``np.dtype``.
+ The creation works by the user providing a prototype instance.
+ NumPy will need to modify at least the type during registration.
+ This has no effect for either ``rational`` or ``quaternion`` and mutation
+ of the structure seems unlikely after registration.
Since there is a fairly large API surface concerning datatypes, further changes
or the limitation certain function to currently existing datatypes is
This is the typical design pattern used in Python.
Organizing these methods and information in a more Pythonic way provides a
solid foundation for refining and extending the API in the future.
-The current API cannot be extended due to how it is exposed publically.
+The current API cannot be extended due to how it is exposed publicly.
This means for example that the methods currently stored in ``PyArray_ArrFuncs``
on each datatype (see :ref:`NEP 40 <NEP40>`)
will be defined differently in the future and
it seems practical to split out the information and functionality necessary
for numpy into the DType class.
+The dtype instances provide parameters and storage options
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+From a computer science point of view a type defines the *value space*
+(all possible values its instances can take) and their *behaviour*.
+As proposed in this NEP, the DType class defines value space and behaviour.
+The ``dtype`` instance can be seen as part of the value, so that the typical
+Python ``instance`` corresponds to ``dtype + element`` (where *element* is the
+data stored in the array).
+An alternative view would be to define value space and behaviour on the
+``dtype`` instances directly.
+These two options are presented in the following figure and compared to
+similar Python implementation patterns:
+
+.. image:: _static/nep-0041-type-sketch-no-fonts.svg
+
+The difference is in how parameters, such as string length or the datetime
+units (``ms``, ``ns``, ...), and storage options, such as byte-order, are handled.
+When implementing a Python (scalar) ``type`` parameters, for example the datetimes
+unit, will be stored in the instance.
+This is the design NEP 42 tries to mimic, however, the parameters are now part
+of the dtype instance, meaning that part of the data stored in the instance
+is shared by all array elements.
+As mentioned previously, this means that the Python ``instance`` corresponds
+to the ``dtype + element`` stored in a NumPy array.
+
+An more advanced approach in Python is to use a class factory and an abstract
+base class (ABC).
+This allows moving the parameter into the dynamically created ``type`` and
+behaviour implementation may be specific to those parameters.
+An alternative approach might use this model and implemented behaviour
+directly on the ``dtype`` instance.
+
+We believe that the version as proposed here is easier to work with and understand.
+Python class factories are not commonly used and NumPy does not use code
+specialized for dtype parameters or byte-orders.
+Making such specialization easier to implement such specialization does not
+seem to be a priority.
+One result of this choice is that some DTypes may only have a singleton instance
+if they have no parameters or storage variation.
+However, all of the NumPy dtypes require dynamically created instances due
+to allowing metadata to be attached.
+
Scalars should not be instances of the datatypes (2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+.. _NEP42:
+
+==============================================================================
+NEP 42 — New and extensible DTypes
+==============================================================================
+
+:title: New and extensible DTypes
+:Author: Sebastian Berg
+:Author: Ben Nathanson
+:Author: Marten van Kerkwijk
+:Status: Draft
+:Type: Standard
+:Created: 2019-07-17
+
+
+.. note::
+
+ This NEP is third in a series:
+
+ - :ref:`NEP40` explains the shortcomings of NumPy's dtype implementation.
+
+ - :ref:`NEP41` gives an overview of our proposed replacement.
+
+ - NEP 42 (this document) describes the new design's datatype-related APIs.
+
+ - :ref:`NEP43` describes the new design's API for universal functions.
+
+
+******************************************************************************
+Abstract
+******************************************************************************
+
+NumPy's dtype architecture is monolithic -- each dtype is an instance of a
+single class. There's no principled way to expand it for new dtypes, and the
+code is difficult to read and maintain.
+
+As :ref:`NEP 41 <NEP41>` explains, we are proposing a new architecture that is
+modular and open to user additions. dtypes will derive from a new ``DType``
+class serving as the extension point for new types. ``np.dtype("float64")``
+will return an instance of a ``Float64`` class, a subclass of root class
+``np.dtype``.
+
+This NEP is one of two that lay out the design and API of this new
+architecture. This NEP addresses dtype implementation; :ref:`NEP 43 <NEP43>` addresses
+universal functions.
+
+.. note::
+
+ Details of the private and external APIs may change to reflect user
+ comments and implementation constraints. The underlying principles and
+ choices should not change significantly.
+
+
+******************************************************************************
+Motivation and scope
+******************************************************************************
+
+Our goal is to allow user code to create fully featured dtypes for a broad
+variety of uses, from physical units (such as meters) to domain-specific
+representations of geometric objects. :ref:`NEP 41 <NEP41>` describes a number
+of these new dtypes and their benefits.
+
+Any design supporting dtypes must consider:
+
+- How shape and dtype are determined when an array is created
+- How array elements are stored and accessed
+- The rules for casting dtypes to other dtypes
+
+In addition:
+
+- We want dtypes to comprise a class hierarchy open to new types and to
+ subhierarchies, as motivated in :ref:`NEP 41 <NEP41>`.
+
+And to provide this,
+
+- We need to define a user API.
+
+All these are the subjects of this NEP.
+
+- The class hierarchy, its relation to the Python scalar types, and its
+ important attributes are described in `nep42_DType class`_.
+
+- The functionality that will support dtype casting is described in `Casting`_.
+
+- The implementation of item access and storage, and the way shape and dtype
+ are determined when creating an array, are described in :ref:`nep42_array_coercion`.
+
+- The functionality for users to define their own DTypes is described in
+ `Public C-API`_.
+
+The API here and in :ref:`NEP 43 <NEP43>` is entirely on the C side. A Python-side version
+will be proposed in a future NEP. A future Python API is expected to be
+similar, but provide a more convenient API to reuse the functionality of
+existing DTypes. It could also provide shorthands to create structured DTypes
+similar to Python's
+`dataclasses <https://docs.python.org/3.8/library/dataclasses.html>`_.
+
+
+******************************************************************************
+Backward compatibility
+******************************************************************************
+
+The disruption is expected to be no greater than that of a typical NumPy
+release.
+
+- The main issues are noted in :ref:`NEP 41 <NEP41>` and will mostly affect
+ heavy users of the NumPy C-API.
+
+- Eventually we will want to deprecate the API currently used for creating
+ user-defined dtypes.
+
+- Small, rarely noticed inconsistencies are likely to change. Examples:
+
+ - ``np.array(np.nan, dtype=np.int64)`` behaves differently from
+ ``np.array([np.nan], dtype=np.int64)`` with the latter raising an error.
+ This may require identical results (either both error or both succeed).
+ - ``np.array([array_like])`` sometimes behaves differently from
+ ``np.array([np.array(array_like)])``
+ - array operations may or may not preserve dtype metadata
+
+- Documentation that describes the internal structure of dtypes will need
+ to be updated.
+
+The new code must pass NumPy's regular test suite, giving some assurance that
+the changes are compatible with existing code.
+
+******************************************************************************
+Usage and impact
+******************************************************************************
+
+We believe the few structures in this section are sufficient to consolidate
+NumPy's present functionality and also to support complex user-defined DTypes.
+
+The rest of the NEP fills in details and provides support for the claim.
+
+Again, though Python is used for illustration, the implementation is a C API only; a
+future NEP will tackle the Python API.
+
+After implementing this NEP, creating a DType will be possible by implementing
+the following outlined DType base class,
+that is further described in `nep42_DType class`_:
+
+.. code-block:: python
+ :dedent: 0
+
+ class DType(np.dtype):
+ type : type # Python scalar type
+ parametric : bool # (may be indicated by superclass)
+
+ @property
+ def canonical(self) -> bool:
+ raise NotImplementedError
+
+ def ensure_canonical(self : DType) -> DType:
+ raise NotImplementedError
+
+For casting, a large part of the functionality is provided by the "methods" stored
+in ``_castingimpl``
+
+.. code-block:: python
+ :dedent: 0
+
+ @classmethod
+ def common_dtype(cls : DTypeMeta, other : DTypeMeta) -> DTypeMeta:
+ raise NotImplementedError
+
+ def common_instance(self : DType, other : DType) -> DType:
+ raise NotImplementedError
+
+ # A mapping of "methods" each detailing how to cast to another DType
+ # (further specified at the end of the section)
+ _castingimpl = {}
+
+For array-coercion, also part of casting:
+
+.. code-block:: python
+ :dedent: 0
+
+ def __dtype_setitem__(self, item_pointer, value):
+ raise NotImplementedError
+
+ def __dtype_getitem__(self, item_pointer, base_obj) -> object:
+ raise NotImplementedError
+
+ @classmethod
+ def __discover_descr_from_pyobject__(cls, obj : object) -> DType:
+ raise NotImplementedError
+
+ # initially private:
+ @classmethod
+ def _known_scalar_type(cls, obj : object) -> bool:
+ raise NotImplementedError
+
+
+Other elements of the casting implementation is the ``CastingImpl``:
+
+.. code-block:: python
+ :dedent: 0
+
+ casting = Union["safe", "same_kind", "unsafe"]
+
+ class CastingImpl:
+ # Object describing and performing the cast
+ casting : casting
+
+ def resolve_descriptors(self, Tuple[DType] : input) -> (casting, Tuple[DType]):
+ raise NotImplementedError
+
+ # initially private:
+ def _get_loop(...) -> lowlevel_C_loop:
+ raise NotImplementedError
+
+which describes the casting from one DType to another. In
+:ref:`NEP 43 <NEP43>` this ``CastingImpl`` object is used unchanged to
+support universal functions.
+
+
+******************************************************************************
+Definitions
+******************************************************************************
+.. glossary::
+
+ dtype
+ The dtype *instance*; this is the object attached to a numpy array.
+
+ DType
+ Any subclass of the base type ``np.dtype``.
+
+ coercion
+ Conversion of Python types to NumPy arrays and values stored in a NumPy
+ array.
+
+ cast
+ Conversion of an array to a different dtype.
+
+ parametric type
+ A dtype whose representation can change based on a parameter value,
+ like a string dtype with a length parameter. All members of the current
+ ``flexible`` dtype class are parametric. See
+ :ref:`NEP 40 <parametric-datatype-discussion>`.
+
+ promotion
+ Finding a dtype that can perform an operation on a mix of dtypes without
+ loss of information.
+
+ safe cast
+ A cast is safe if no information is lost when changing type.
+
+On the C level we use ``descriptor`` or ``descr`` to mean
+*dtype instance*. In the proposed C-API, these terms will distinguish
+dtype instances from DType classes.
+
+.. note::
+ NumPy has an existing class hierarchy for scalar types, as
+ seen :ref:`in the figure <nep-0040_dtype-hierarchy>` of
+ :ref:`NEP 40 <NEP40>`, and the new DType hierarchy will resemble it. The
+ types are used as an attribute of the single dtype class in the current
+ NumPy; they're not dtype classes. They neither harm nor help this work.
+
+.. _nep42_DType class:
+
+******************************************************************************
+The DType class
+******************************************************************************
+
+This section reviews the structure underlying the proposed DType class,
+including the type hierarchy and the use of abstract DTypes.
+
+Class getter
+==============================================================================
+
+To create a DType instance from a scalar type users now call
+``np.dtype`` (for instance, ``np.dtype(np.int64)``). Sometimes it is
+also necessary to access the underlying DType class; this comes up in
+particular with type hinting because the "type" of a DType instance is
+the DType class. Taking inspiration from type hinting, we propose the
+following getter syntax::
+
+ np.dtype[np.int64]
+
+to get the DType class corresponding to a scalar type. The notation
+works equally well with built-in and user-defined DTypes.
+
+This getter eliminates the need to create an explicit name for every
+DType, crowding the ``np`` namespace; the getter itself signifies the
+type. It also opens the possibility of making ``np.ndarray`` generic
+over DType class using annotations like::
+
+ np.ndarray[np.dtype[np.float64]]
+
+The above is fairly verbose, so it is possible that we will include
+aliases like::
+
+ Float64 = np.dtype[np.float64]
+
+in ``numpy.typing``, thus keeping annotations concise but still
+avoiding crowding the ``np`` namespace as discussed above. For a
+user-defined DType::
+
+ class UserDtype(dtype): ...
+
+one can do ``np.ndarray[UserDtype]``, keeping annotations concise in
+that case without introducing boilerplate in NumPy itself. For a user
+user-defined scalar type::
+
+ class UserScalar(generic): ...
+
+we would need to add a typing overload to ``dtype``::
+
+ @overload
+ __new__(cls, dtype: Type[UserScalar], ...) -> UserDtype
+
+to allow ``np.dtype[UserScalar]``.
+
+The initial implementation probably will return only concrete (not abstract)
+DTypes.
+
+*This item is still under review.*
+
+
+Hierarchy and abstract classes
+==============================================================================
+
+We will use abstract classes as building blocks of our extensible DType class
+hierarchy.
+
+1. Abstract classes are inherited cleanly, in principle allowing checks like
+ ``isinstance(np.dtype("float64"), np.inexact)``.
+
+2. Abstract classes allow a single piece of code to handle a multiplicity of
+ input types. Code written to accept Complex objects can work with numbers
+ of any precision; the precision of the results is determined by the
+ precision of the arguments.
+
+3. There's room for user-created families of DTypes. We can envision an
+ abstract ``Unit`` class for physical units, with a concrete subclass like
+ ``Float64Unit``. Calling ``Unit(np.float64, "m")`` (``m`` for meters) would
+ be equivalent to ``Float64Unit("m")``.
+
+4. The implementation of universal functions in :ref:`NEP 43 <NEP43>` may require
+ a class hierarchy.
+
+**Example:** A NumPy ``Categorical`` class would be a match for pandas
+``Categorical`` objects, which can contain integers or general Python objects.
+NumPy needs a DType that it can assign a Categorical to, but it also needs
+DTypes like ``CategoricalInt64`` and ``CategoricalObject`` such that
+``common_dtype(CategoricalInt64, String)`` raises an error, but
+``common_dtype(CategoricalObject, String)`` returns an ``object`` DType. In
+our scheme, ``Categorical`` is an abstract type with ``CategoricalInt64`` and
+``CategoricalObject`` subclasses.
+
+
+Rules for the class structure, illustrated :ref:`below <nep42_hierarchy_figure>`:
+
+1. Abstract DTypes cannot be instantiated. Instantiating an abstract DType
+ raises an error, or perhaps returns an instance of a concrete subclass.
+ Raising an error will be the default behavior and may be required initially.
+
+2. While abstract DTypes may be superclasses, they may also act like Python's
+ abstract base classes (ABC) allowing registration instead of subclassing.
+ It may be possible to simply use or inherit from Python ABCs.
+
+3. Concrete DTypes may not be subclassed. In the future this might be relaxed
+ to allow specialized implementations such as a GPU float64 subclassing a
+ NumPy float64.
+
+The
+`Julia language <https://docs.julialang.org/en/v1/manual/types/#man-abstract-types-1>`_
+has a similar prohibition against subclassing concrete types.
+For example methods such as the later ``__common_instance__`` or
+``__common_dtype__`` cannot work for a subclass unless they were designed
+very carefully.
+It helps avoid unintended vulnerabilities to implementation changes that
+result from subclassing types that were not written to be subclassed.
+We believe that the DType API should rather be extended to simplify wrapping
+of existing functionality.
+
+The DType class requires C-side storage of methods and additional information,
+to be implemented by a ``DTypeMeta`` class. Each ``DType`` class is an
+instance of ``DTypeMeta`` with a well-defined and extensible interface;
+end users ignore it.
+
+.. _nep42_hierarchy_figure:
+.. figure:: _static/dtype_hierarchy.svg
+ :figclass: align-center
+
+
+Miscellaneous methods and attributes
+==============================================================================
+
+This section collects definitions in the DType class that are not used in
+casting and array coercion, which are described in detail below.
+
+* Existing dtype methods (:class:`numpy.dtype`) and C-side fields are preserved.
+
+* ``DType.type`` replaces ``dtype.type``. Unless a use case arises,
+ ``dtype.type`` will be deprecated.
+ This indicates a Python scalar type which represents the same values as
+ the DType. This is the same type as used in the proposed `Class getter`_
+ and for `DType discovery during array coercion`_.
+ (This can may also be set for abstract DTypes, this is necessary
+ for array coercion.)
+
+* A new ``self.canonical`` property generalizes the notion of byte order to
+ indicate whether data has been stored in a default/canonical way. For
+ existing code, "canonical" will just signify native byte order, but it can
+ take on new meanings in new DTypes -- for instance, to distinguish a
+ complex-conjugated instance of Complex which stores ``real - imag`` instead
+ of ``real + imag``. The ISNBO ("is
+ native byte order") flag might be repurposed as the canonical flag.
+
+* Support is included for parametric DTypes. A DType will be deemed parametric
+ if it inherits from ParametricDType.
+
+* DType methods may resemble or even reuse existing Python slots. Thus Python
+ special slots are off-limits for user-defined DTypes (for instance, defining
+ ``Unit("m") > Unit("cm")``), since we may want to develop a meaning for these
+ operators that is common to all DTypes.
+
+* Sorting functions are moved to the DType class. They may be implemented by
+ defining a method ``dtype_get_sort_function(self, sortkind="stable") ->
+ sortfunction`` that must return ``NotImplemented`` if the given ``sortkind``
+ is not known.
+
+* Functions that cannot be removed are implemented as special methods.
+ Many of these were previously defined part of the :c:type:`PyArray_ArrFuncs`
+ slot of the dtype instance (``PyArray_Descr *``) and include functions
+ such as ``nonzero``, ``fill`` (used for ``np.arange``), and
+ ``fromstr`` (used to parse text files).
+ These old methods will be deprecated and replacements
+ following the new design principles added.
+ The API is not defined here. Since these methods can be deprecated and renamed
+ replacements added, it is acceptable if these new methods have to be modified.
+
+* Use of ``kind`` for non-built-in types is discouraged in favor of
+ ``isinstance`` checks. ``kind`` will return the ``__qualname__`` of the
+ object to ensure uniqueness for all DTypes. On the C side, ``kind`` and
+ ``char`` are set to ``\0`` (NULL character).
+ While ``kind`` will be discouraged, the current ``np.issubdtype``
+ may remain the preferred method for this type of check.
+
+* A method ``ensure_canonical(self) -> dtype`` returns a new dtype (or
+ ``self``) with the ``canonical`` flag set.
+
+* Since NumPy's approach is to provide functionality through unfuncs,
+ functions like sorting that will be implemented in DTypes might eventually be
+ reimplemented as generalized ufuncs.
+
+.. _nep_42_casting:
+
+******************************************************************************
+Casting
+******************************************************************************
+
+We review here the operations related to casting arrays:
+
+- Finding the "common dtype," returned by :func:`numpy.promote_types` and
+ :func:`numpy.result_type`
+
+- The result of calling :func:`numpy.can_cast`
+
+We show how casting arrays with ``astype(new_dtype)`` will be implemented.
+
+`Common DType` operations
+==============================================================================
+
+When input types are mixed, a first step is to find a DType that can hold
+the result without loss of information -- a "common DType."
+
+Array coercion and concatenation both return a common dtype instance. Most
+universal functions use the common DType for dispatching, though they might
+not use it for a result (for instance, the result of a comparison is always
+bool).
+
+We propose the following implementation:
+
+- For two DType classes::
+
+ __common_dtype__(cls, other : DTypeMeta) -> DTypeMeta
+
+ Returns a new DType, often one of the inputs, which can represent values
+ of both input DTypes. This should usually be minimal:
+ the common DType of ``Int16`` and ``Uint16`` is ``Int32`` and not ``Int64``.
+ ``__common_dtype__`` may return NotImplemented to defer to other and,
+ like Python operators, subclasses take precedence (their
+ ``__common_dtype__`` method is tried first).
+
+- For two instances of the same DType::
+
+ __common_instance__(self: SelfT, other : SelfT) -> SelfT
+
+ For nonparametric built-in dtypes, this returns a canonicalized copy of
+ ``self``, preserving metadata. For nonparametric user types, this provides
+ a default implementation.
+
+- For instances of different DTypes, for example ``>float64`` and ``S8``,
+ the operation is done in three steps:
+
+ 1. ``Float64.__common_dtype__(type(>float64), type(S8))``
+ returns ``String`` (or defers to ``String.__common_dtype__``).
+
+ 2. The casting machinery (explained in detail below) provides the
+ information that ``">float64"`` casts to ``"S32"``
+
+ 3. ``String.__common_instance__("S8", "S32")`` returns the final ``"S32"``.
+
+The benefit of this handoff is to reduce duplicated code and keep concerns
+separate. DType implementations don't need to know how to cast, and the
+results of casting can be extended to new types, such as a new string encoding.
+
+This means the implementation will work like this::
+
+ def common_dtype(DType1, DType2):
+ common_dtype = type(dtype1).__common_dtype__(type(dtype2))
+ if common_dtype is NotImplemented:
+ common_dtype = type(dtype2).__common_dtype__(type(dtype1))
+ if common_dtype is NotImplemented:
+ raise TypeError("no common dtype")
+ return common_dtype
+
+ def promote_types(dtype1, dtype2):
+ common = common_dtype(type(dtype1), type(dtype2))
+
+ if type(dtype1) is not common:
+ # Find what dtype1 is cast to when cast to the common DType
+ # by using the CastingImpl as described below:
+ castingimpl = get_castingimpl(type(dtype1), common)
+ safety, (_, dtype1) = castingimpl.resolve_descriptors((dtype1, None))
+ assert safety == "safe" # promotion should normally be a safe cast
+
+ if type(dtype2) is not common:
+ # Same as above branch for dtype1.
+
+ if dtype1 is not dtype2:
+ return common.__common_instance__(dtype1, dtype2)
+
+Some of these steps may be optimized for nonparametric DTypes.
+
+Since the type returned by ``__common_dtype__`` is not necessarily one of the
+two arguments, it's not equivalent to NumPy's "safe" casting.
+Safe casting works for ``np.promote_types(int16, int64)``, which returns
+``int64``, but fails for::
+
+ np.promote_types("int64", "float32") -> np.dtype("float64")
+
+It is the responsibility of the DType author to ensure that the inputs
+can be safely cast to the ``__common_dtype__``.
+
+Exceptions may apply. For example, casting ``int32`` to
+a (long enough) string is at least at this time considered "safe".
+However ``np.promote_types(int32, String)`` will *not* be defined.
+
+**Example:**
+
+``object`` always chooses ``object`` as the common DType. For
+``datetime64`` type promotion is defined with no other datatype, but if
+someone were to implement a new higher precision datetime, then::
+
+ HighPrecisionDatetime.__common_dtype__(np.dtype[np.datetime64])
+
+would return ``HighPrecisionDatetime``, and the casting implementation,
+as described below, may need to decide how to handle the datetime unit.
+
+
+**Alternatives:**
+
+- We're pushing the decision on common DTypes to the DType classes. Suppose
+ instead we could turn to a universal algorithm based on safe casting,
+ imposing a total order on DTypes and returning the first type that both
+ arguments could cast to safely.
+
+ It would be difficult to devise a reasonable total order, and it would have
+ to accept new entries. Beyond that, the approach is flawed because
+ importing a type can change the behavior of a program. For example, a
+ program requiring the common DType of ``int16`` and ``uint16`` would
+ ordinarily get the built-in type ``int32`` as the first match; if the
+ program adds ``import int24``, the first match becomes ``int24`` and the
+ smaller type might make the program overflow for the first time. [1]_
+
+- A more flexible common DType could be implemented in the future where
+ ``__common_dtype__`` relies on information from the casting logic.
+ Since ``__commond_dtype__`` is a method a such a default implementation
+ could be added at a later time.
+
+- The three-step handling of differing dtypes could, of course, be coalesced.
+ It would lose the value of splitting in return for a possibly faster
+ execution. But few cases would benefit. Most cases, such as array coercion,
+ involve a single Python type (and thus dtype).
+
+
+The cast operation
+==============================================================================
+
+Casting is perhaps the most complex and interesting DType operation. It
+is much like a typical universal function on arrays, converting one input to a
+new output, with two distinctions:
+
+- Casting always requires an explicit output datatype.
+- The NumPy iterator API requires access to functions that are lower-level
+ than what universal functions currently need.
+
+Casting can be complex and may not implement all details of each input
+datatype (such as non-native byte order or unaligned access). So a complex
+type conversion might entail 3 steps:
+
+1. The input datatype is normalized and prepared for the cast.
+2. The cast is performed.
+3. The result, which is in a normalized form, is cast to the requested
+ form (non-native byte order).
+
+Further, NumPy provides different casting kinds or safety specifiers:
+
+* ``equivalent``, allowing only byte-order changes
+* ``safe``, requiring a type large enough to preserve value
+* ``same_kind``, requiring a safe cast or one within a kind, like float64 to float32
+* ``unsafe``, allowing any data conversion
+
+and in some cases a cast may be just a view.
+
+We need to support the two current signatures of ``arr.astype``:
+
+- For DTypes: ``arr.astype(np.String)``
+
+ - current spelling ``arr.astype("S")``
+ - ``np.String`` can be an abstract DType
+
+- For dtypes: ``arr.astype(np.dtype("S8"))``
+
+
+We also have two signatures of ``np.can_cast``:
+
+- Instance to class: ``np.can_cast(dtype, DType, "safe")``
+- Instance to instance: ``np.can_cast(dtype, other_dtype, "safe")``
+
+On the Python level ``dtype`` is overloaded to mean class or instance.
+
+A third ``can_cast`` signature, ``np.can_cast(DType, OtherDType, "safe")``,may be used
+internally but need not be exposed to Python.
+
+During DType creation, DTypes will be able to pass a list of ``CastingImpl``
+objects, which can define casting to and from the DType.
+
+One of them should define the cast between instances of that DType. It can be
+omitted if the DType has only a single implementation and is nonparametric.
+
+Each ``CastingImpl`` has a distinct DType signature:
+
+ ``CastingImpl[InputDtype, RequestedDtype]``
+
+and implements the following methods and attributes:
+
+
+* To report safeness,
+
+ ``resolve_descriptors(self, Tuple[DType] : input) -> casting, Tuple[DType]``.
+
+ The ``casting`` output reports safeness (safe, unsafe, or same-kind), and
+ the tuple is used for more multistep casting, as in the example below.
+
+* To get a casting function,
+
+ ``get_loop(...) -> function_to_handle_cast (signature to be decided)``
+
+ returns a low-level implementation of a strided casting function
+ ("transfer function") capable of performing the
+ cast.
+
+ Initially the implementation will be *private*, and users will only be
+ able to provide strided loops with the signature.
+
+* For performance, a ``casting`` attribute taking a value of ``equivalent``, ``safe``,
+ ``unsafe``, or ``same-kind``.
+
+
+**Performing a cast**
+
+.. _nep42_cast_figure:
+
+.. figure:: _static/casting_flow.svg
+ :figclass: align-center
+
+The above figure illustrates a multistep
+cast of an ``int24`` with a value of ``42`` to a string of length 20
+(``"S20"``).
+
+We've picked an example where the implementer has only provided limited
+functionality: a function to cast an ``int24`` to an ``S8`` string (which can
+hold all 24-bit integers). This means multiple conversions are needed.
+
+The full process is:
+
+1. Call
+
+ ``CastingImpl[Int24, String].resolve_descriptors((int24, "S20"))``.
+
+ This provides the information that ``CastingImpl[Int24, String]`` only
+ implements the cast of ``int24`` to ``"S8"``.
+
+2. Since ``"S8"`` does not match ``"S20"``, use
+
+ ``CastingImpl[String, String].get_loop()``
+
+ to find the transfer (casting) function to convert an ``"S8"`` into an ``"S20"``
+
+3. Fetch the transfer function to convert an ``int24`` to an ``"S8"`` using
+
+ ``CastingImpl[Int24, String].get_loop()``
+
+4. Perform the actual cast using the two transfer functions:
+
+ ``int24(42) -> S8("42") -> S20("42")``.
+
+ ``resolve_descriptors`` allows the implementation for
+
+ ``np.array(42, dtype=int24).astype(String)``
+
+ to call
+
+ ``CastingImpl[Int24, String].resolve_descriptors((int24, None))``.
+
+ In this case the result of ``(int24, "S8")`` defines the correct cast:
+
+ ``np.array(42, dtype=int24).astype(String) == np.array("42", dtype="S8")``.
+
+**Casting safety**
+
+To compute ``np.can_cast(int24, "S20", casting="safe")``, only the
+``resolve_descriptors`` function is required and
+is called in the same way as in :ref:`the figure describing a cast <nep42_cast_figure>`.
+
+In this case, the calls to ``resolve_descriptors``, will also provide the
+information that ``int24 -> "S8"`` as well as ``"S8" -> "S20"`` are safe
+casts, and thus also the ``int24 -> "S20"`` is a safe cast.
+
+In some cases, no cast is necessary. For example, on most Linux systems
+``np.dtype("long")`` and ``np.dtype("longlong")`` are different dtypes but are
+both 64-bit integers. In this case, the cast can be performed using
+``long_arr.view("longlong")``. The information that a cast is a view will be
+handled by an additional flag. Thus the ``casting`` can have the 8 values in
+total: the original 4 of ``equivalent``, ``safe``, ``unsafe``, and ``same-kind``,
+plus ``equivalent+view``, ``safe+view``, ``unsafe+view``, and
+``same-kind+view``. NumPy currently defines ``dtype1 == dtype2`` to be True
+only if byte order matches. This functionality can be replaced with the
+combination of "equivalent" casting and the "view" flag.
+
+(For more information on the ``resolve_descriptors`` signature see the
+:ref:`nep42_C-API` section below and :ref:`NEP 43 <NEP43>`.)
+
+
+**Casting between instances of the same DType**
+
+To keep down the number of casting
+steps, CastingImpl must be capable of any conversion between all instances
+of this DType.
+
+In general the DType implementer must include ``CastingImpl[DType, DType]``
+unless there is only a singleton instance.
+
+**General multistep casting**
+
+We could implement certain casts, such as ``int8`` to ``int24``,
+even if the user provides only an ``int16 -> int24`` cast. This proposal does
+not provide that, but future work might find such casts dynamically, or at least
+allow ``resolve_descriptors`` to return arbitrary ``dtypes``.
+
+If ``CastingImpl[Int8, Int24].resolve_descriptors((int8, int24))`` returns
+``(int16, int24)``, the actual casting process could be extended to include
+the ``int8 -> int16`` cast. This adds a step.
+
+
+**Example:**
+
+The implementation for casting integers to datetime would generally
+say that this cast is unsafe (because it is always an unsafe cast).
+Its ``resolve_descriptors`` function may look like::
+
+ def resolve_descriptors(self, given_dtypes):
+ from_dtype, to_dtype = given_dtypes
+ from_dtype = from_dtype.ensure_canonical() # ensure not byte-swapped
+ if to_dtype is None:
+ raise TypeError("Cannot convert to a NumPy datetime without a unit")
+ to_dtype = to_dtype.ensure_canonical() # ensure not byte-swapped
+
+ # This is always an "unsafe" cast, but for int64, we can represent
+ # it by a simple view (if the dtypes are both canonical).
+ # (represented as C-side flags here).
+ safety_and_view = NPY_UNSAFE_CASTING | _NPY_CAST_IS_VIEW
+ return safety_and_view, (from_dtype, to_dtype)
+
+.. note::
+
+ While NumPy currently defines integer-to-datetime casts, with the possible
+ exception of the unit-less ``timedelta64`` it may be better to not define
+ these casts at all. In general we expect that user defined DTypes will be
+ using custom methods such as ``unit.drop_unit(arr)`` or ``arr *
+ unit.seconds``.
+
+
+**Alternatives:**
+
+- Our design objectives are:
+ - Minimize the number of DType methods and avoid code duplication.
+ - Mirror the implementation of universal functions.
+
+- The decision to use only the DType classes in the first step of finding the
+ correct ``CastingImpl`` in addition to defining ``CastingImpl.casting``,
+ allows to retain the current default implementation of
+ ``__common_dtype__`` for existing user defined dtypes, which could be
+ expanded in the future.
+
+- The split into multiple steps may seem to add complexity rather than reduce
+ it, but it consolidates the signatures of ``np.can_cast(dtype, DTypeClass)``
+ and ``np.can_cast(dtype, other_dtype)``.
+
+ Further, the API guarantees separation of concerns for user DTypes. The user
+ ``Int24`` dtype does not have to handle all string lengths if it does not
+ wish to do so. Further, an encoding added to the ``String`` DType would
+ not affect the overall cast. The ``resolve_descriptors`` function
+ can keep returning the default encoding and the ``CastingImpl[String,
+ String]`` can take care of any necessary encoding changes.
+
+- The main alternative is moving most of the information that is here pushed
+ into the ``CastingImpl`` directly into methods on the DTypes. But this
+ obscures the similarity between casting and universal functions. It does
+ reduce indirection, as noted below.
+
+- An earlier proposal defined two methods ``__can_cast_to__(self, other)`` to
+ dynamically return ``CastingImpl``. This
+ removes the requirement to define all possible casts at DType creation
+ (of one of the involved DTypes).
+
+ Such an API could be added later. It resembles Python's ``__getattr__`` in
+ providing additional control over attribute lookup.
+
+
+**Notes:**
+
+The proposed ``CastingImpl`` is designed to be identical to the
+``PyArrayMethod`` proposed in NEP43 as part of restructuring ufuncs to handle
+new DTypes.
+
+The way dispatching works for ``CastingImpl`` is planned to be limited
+initially and fully opaque. In the future, it may or may not be moved into a
+special UFunc, or behave more like a universal function.
+
+
+.. _nep42_array_coercion:
+
+
+Coercion to and from Python objects
+==============================================================================
+
+When storing a single value in an array or taking it out, it is necessary to
+coerce it -- that is, convert it -- to and from the low-level representation
+inside the array.
+
+Coercion is slightly more complex than typical casts. One reason is that a
+Python object could itself be a 0-dimensional array or scalar with an
+associated DType.
+
+Coercing to and from Python scalars requires two to three
+methods that largely correspond to the current definitions:
+
+1. ``__dtype_setitem__(self, item_pointer, value)``
+
+2. ``__dtype_getitem__(self, item_pointer, base_obj) -> object``;
+ ``base_obj`` is for memory management and usually ignored; it points to
+ an object owning the data. Its only role is to support structured datatypes
+ with subarrays within NumPy, which currently return views into the array.
+ The function returns an equivalent Python scalar (i.e. typically a NumPy
+ scalar).
+
+3. ``__dtype_get_pyitem__(self, item_pointer, base_obj) -> object`` (initially
+ hidden for new-style user-defined datatypes, may be exposed on user
+ request). This corresponds to the ``arr.item()`` method also used by
+ ``arr.tolist()`` and returns Python floats, for example, instead of NumPy
+ floats.
+
+(The above is meant for C-API. A Python-side API would have to use byte
+buffers or similar to implement this, which may be useful for prototyping.)
+
+When a certain scalar
+has a known (different) dtype, NumPy may in the future use casting instead of
+``__dtype_setitem__``.
+
+A user datatype is (initially) expected to implement
+``__dtype_setitem__`` for its own ``DType.type`` and all basic Python scalars
+it wishes to support (e.g. ``int`` and ``float``). In the future a
+function ``known_scalar_type`` may be made public to allow a user dtype to signal
+which Python scalars it can store directly.
+
+
+**Implementation:** The pseudocode implementation for setting a single item in
+an array from an arbitrary Python object ``value`` is (some
+functions here are defined later)::
+
+ def PyArray_Pack(dtype, item_pointer, value):
+ DType = type(dtype)
+ if DType.type is type(value) or DType.known_scalartype(type(value)):
+ return dtype.__dtype_setitem__(item_pointer, value)
+
+ # The dtype cannot handle the value, so try casting:
+ arr = np.array(value)
+ if arr.dtype is object or arr.ndim != 0:
+ # not a numpy or user scalar; try using the dtype after all:
+ return dtype.__dtype_setitem__(item_pointer, value)
+
+ arr.astype(dtype)
+ item_pointer.write(arr[()])
+
+where the call to ``np.array()`` represents the dtype discovery and is
+not actually performed.
+
+**Example:** Current ``datetime64`` returns ``np.datetime64`` scalars and can
+be assigned from ``np.datetime64``. However, the datetime
+``__dtype_setitem__`` also allows assignment from date strings ("2016-05-01")
+or Python integers. Additionally the datetime ``__dtype_get_pyitem__``
+function actually returns a Python ``datetime.datetime`` object (most of the
+time).
+
+
+**Alternatives:** This functionality could also be implemented as a cast to and
+from the ``object`` dtype.
+However, coercion is slightly more complex than typical casts.
+One reason is that in general a Python object could itself be a
+zero-dimensional array or scalar with an associated DType.
+Such an object has a DType, and the correct cast to another DType is already
+defined::
+
+ np.array(np.float32(4), dtype=object).astype(np.float64)
+
+is identical to::
+
+ np.array(4, dtype=np.float32).astype(np.float64)
+
+Implementing the first ``object`` to ``np.float64`` cast explicitly,
+would require the user to take to duplicate or fall back to existing
+casting functionality.
+
+It is certainly possible to describe the coercion to and from Python objects
+using the general casting machinery, but the ``object`` dtype is special and
+important enough to be handled by NumPy using the presented methods.
+
+**Further issues and discussion:**
+
+- The ``__dtype_setitem__`` function duplicates some code, such as coercion
+ from a string.
+
+ ``datetime64`` allows assignment from string, but the same conversion also
+ occurs for casting from the string dtype to ``datetime64``.
+
+ We may in the future expose the ``known_scalartype`` function to allow the
+ user to implement such duplication.
+
+ For example, NumPy would normally use
+
+ ``np.array(np.string_("2019")).astype(datetime64)``
+
+ but ``datetime64`` could choose to use its ``__dtype_setitem__`` instead
+ for performance reasons.
+
+- There is an issue about how subclasses of scalars should be handled. We
+ anticipate to stop automatically detecting the dtype for
+ ``np.array(float64_subclass)`` to be float64. The user can still provide
+ ``dtype=np.float64``. However, the above automatic casting using
+ ``np.array(scalar_subclass).astype(requested_dtype)`` will fail. In many
+ cases, this is not an issue, since the Python ``__float__`` protocol can be
+ used instead. But in some cases, this will mean that subclasses of Python
+ scalars will behave differently.
+
+.. note::
+
+ *Example:* ``np.complex256`` should not use ``__float__`` in its
+ ``__dtype_setitem__`` method in the future unless it is a known floating
+ point type. If the scalar is a subclass of a different high precision
+ floating point type (e.g. ``np.float128``) then this currently loses
+ precision without notifying the user.
+ In that case ``np.array(float128_subclass(3), dtype=np.complex256)``
+ may fail unless the ``float128_subclass`` is first converted to the
+ ``np.float128`` base class.
+
+
+DType discovery during array coercion
+==============================================================================
+
+An important step in the use of NumPy arrays is creation of the array from
+collections of generic Python objects.
+
+**Motivation:** Although the distinction is not clear currently, there are two main needs::
+
+ np.array([1, 2, 3, 4.])
+
+needs to guess the correct dtype based on the Python objects inside.
+Such an array may include a mix of datatypes, as long as they can be
+promoted.
+A second use case is when users provide the output DType class, but not the
+specific DType instance::
+
+ np.array([object(), None], dtype=np.dtype[np.string_]) # (or `dtype="S"`)
+
+In this case the user indicates that ``object()`` and ``None`` should be
+interpreted as strings.
+The need to consider the user provided DType also arises for a future
+``Categorical``::
+
+ np.array([1, 2, 1, 1, 2], dtype=Categorical)
+
+which must interpret the numbers as unique categorical values rather than
+integers.
+
+There are three further issues to consider:
+
+1. It may be desirable to create datatypes associated
+ with normal Python scalars (such as ``datetime.datetime``) that do not
+ have a ``dtype`` attribute already.
+
+2. In general, a datatype could represent a sequence, however, NumPy currently
+ assumes that sequences are always collections of elements
+ (the sequence cannot be an element itself).
+ An example would be a ``vector`` DType.
+
+3. An array may itself contain arrays with a specific dtype (even
+ general Python objects). For example:
+ ``np.array([np.array(None, dtype=object)], dtype=np.String)``
+ poses the issue of how to handle the included array.
+
+Some of these difficulties arise because finding the correct shape
+of the output array and finding the correct datatype are closely related.
+
+**Implementation:** There are two distinct cases above:
+
+1. The user has provided no dtype information.
+
+2. The user provided a DType class -- as represented, for example, by ``"S"``
+ representing a string of any length.
+
+In the first case, it is necessary to establish a mapping from the Python type(s)
+of the constituent elements to the DType class.
+Once the DType class is known, the correct dtype instance needs to be found.
+In the case of strings, this requires to find the string length.
+
+These two cases shall be implemented by leveraging two pieces of information:
+
+1. ``DType.type``: The current type attribute to indicate which Python scalar
+ type is associated with the DType class (this is a *class* attribute that always
+ exists for any datatype and is not limited to array coercion).
+
+2. ``__discover_descr_from_pyobject__(cls, obj) -> dtype``: A classmethod that
+ returns the correct descriptor given the input object.
+ Note that only parametric DTypes have to implement this.
+ For nonparametric DTypes using the default instance will always be acceptable.
+
+The Python scalar type which is already associated with a DType through the
+``DType.type`` attribute maps from the DType to the Python scalar type.
+At registration time, a DType may choose to allow automatically discover for
+this Python scalar type.
+This requires a lookup in the opposite direction, which will be implemented
+using global a mapping (dictionary-like) of::
+
+ known_python_types[type] = DType
+
+Correct garbage collection requires additional care.
+If both the Python scalar type (``pytype``) and ``DType`` are created dynamically,
+they will potentially be deleted again.
+To allow this, it must be possible to make the above mapping weak.
+This requires that the ``pytype`` holds a reference of ``DType`` explicitly.
+Thus, in addition to building the global mapping, NumPy will store the ``DType`` as
+``pytype.__associated_array_dtype__`` in the Python type.
+This does *not* define the mapping and should *not* be accessed directly.
+In particular potential inheritance of the attribute does not mean that NumPy will use the
+superclasses ``DType`` automatically. A new ``DType`` must be created for the
+subclass.
+
+.. note::
+
+ Python integers do not have a clear/concrete NumPy type associated right
+ now. This is because during array coercion NumPy currently finds the first
+ type capable of representing their value in the list of `long`, `unsigned
+ long`, `int64`, `unsigned int64`, and `object` (on many machines `long` is
+ 64 bit).
+
+ Instead they will need to be implemented using an ``AbstractPyInt``. This
+ DType class can then provide ``__discover_descr_from_pyobject__`` and
+ return the actual dtype which is e.g. ``np.dtype("int64")``. For
+ dispatching/promotion in ufuncs, it will also be necessary to dynamically
+ create ``AbstractPyInt[value]`` classes (creation can be cached), so that
+ they can provide the current value based promotion functionality provided
+ by ``np.result_type(python_integer, array)`` [2]_ .
+
+To allow for a DType to accept inputs as scalars that are not basic Python
+types or instances of ``DType.type``, we use ``known_scalar_type`` method.
+This can allow discovery of a ``vector`` as a scalar (element) instead of a sequence
+(for the command ``np.array(vector, dtype=VectorDType)``) even when ``vector`` is itself a
+sequence or even an array subclass. This will *not* be public API initially,
+but may be made public at a later time.
+
+**Example:** The current datetime DType requires a
+``__discover_descr_from_pyobject__`` which returns the correct unit for string
+inputs. This allows it to support::
+
+ np.array(["2020-01-02", "2020-01-02 11:24"], dtype="M8")
+
+By inspecting the date strings. Together with the common dtype
+operation, this allows it to automatically find that the datetime64 unit
+should be "minutes".
+
+
+**NumPy internal implementation:** The implementation to find the correct dtype
+will work similar to the following pseudocode::
+
+ def find_dtype(array_like):
+ common_dtype = None
+ for element in array_like:
+ # default to object dtype, if unknown
+ DType = known_python_types.get(type(element), np.dtype[object])
+ dtype = DType.__discover_descr_from_pyobject__(element)
+
+ if common_dtype is None:
+ common_dtype = dtype
+ else:
+ common_dtype = np.promote_types(common_dtype, dtype)
+
+In practice, the input to ``np.array()`` is a mix of sequences and array-like
+objects, so that deciding what is an element requires to check whether it
+is a sequence.
+The full algorithm (without user provided dtypes) thus looks more like::
+
+ def find_dtype_recursive(array_like, dtype=None):
+ """
+ Recursively find the dtype for a nested sequences (arrays are not
+ supported here).
+ """
+ DType = known_python_types.get(type(element), None)
+
+ if DType is None and is_array_like(array_like):
+ # Code for a sequence, an array_like may have a DType we
+ # can use directly:
+ for element in array_like:
+ dtype = find_dtype_recursive(element, dtype=dtype)
+ return dtype
+
+ elif DType is None:
+ DType = np.dtype[object]
+
+ # dtype discovery and promotion as in `find_dtype` above
+
+If the user provides ``DType``, then this DType will be tried first, and the
+``dtype`` may need to be cast before the promotion is performed.
+
+**Limitations:** The motivational point 3. of a nested array
+``np.array([np.array(None, dtype=object)], dtype=np.String)`` is currently
+(sometimes) supported by inspecting all elements of the nested array.
+User DTypes will implicitly handle these correctly if the nested array
+is of ``object`` dtype.
+In some other cases NumPy will retain backward compatibility for existing
+functionality only.
+NumPy uses such functionality to allow code such as::
+
+ >>> np.array([np.array(["2020-05-05"], dtype="S")], dtype=np.datetime64)
+ array([['2020-05-05']], dtype='datetime64[D]')
+
+which discovers the datetime unit ``D`` (days).
+This possibility will not be accessible to user DTypes without an
+intermediate cast to ``object`` or a custom function.
+
+The use of a global type map means that an error or warning has to be given if
+two DTypes wish to map to the same Python type. In most cases user DTypes
+should only be implemented for types defined within the same library to avoid
+the potential for conflicts. It will be the DType implementor's responsibility
+to be careful about this and use avoid registration when in doubt.
+
+**Alternatives:**
+
+- Instead of a global mapping, we could rely on the scalar attribute
+ ``scalar.__associated_array_dtype__``. This only creates a difference in
+ behavior for subclasses, and the exact implementation can be undefined
+ initially. Scalars will be expected to derive from a NumPy scalar. In
+ principle NumPy could, for a time, still choose to rely on the attribute.
+
+- An earlier proposal for the ``dtype`` discovery algorithm used a two-pass
+ approach, first finding the correct ``DType`` class and only then
+ discovering the parametric ``dtype`` instance. It was rejected as
+ needlessly complex. But it would have enabled value-based promotion
+ in universal functions, allowing::
+
+ np.add(np.array([8], dtype="uint8"), [4])
+
+ to return a ``uint8`` result (instead of ``int16``), which currently happens for::
+
+ np.add(np.array([8], dtype="uint8"), 4)
+
+ (note the list ``[4]`` instead of scalar ``4``).
+ This is not a feature NumPy currently has or desires to support.
+
+**Further issues and discussion:** It is possible to create a DType
+such as Categorical, array, or vector which can only be used if ``dtype=DType``
+is provided. Such DTypes cannot roundtrip correctly. For example::
+
+ np.array(np.array(1, dtype=Categorical)[()])
+
+will result in an integer array. To get the original ``Categorical`` array
+``dtype=Categorical`` will need to be passed explicitly.
+This is a general limitation, but round-tripping is always possible if
+``dtype=original_arr.dtype`` is passed.
+
+
+.. _nep42_c-api:
+
+******************************************************************************
+Public C-API
+******************************************************************************
+
+DType creation
+==============================================================================
+
+To create a new DType the user will need to define the methods and attributes
+outlined in the `Usage and impact`_ section and detailed throughout this
+proposal.
+
+In addition, some methods similar to those in :c:type:`PyArray_ArrFuncs` will
+be needed for the slots struct below.
+
+As mentioned in :ref:`NEP 41 <NEP41>`, the interface to define this DType
+class in C is modeled after :PEP:`384`: Slots and some additional information
+will be passed in a slots struct and identified by ``ssize_t`` integers::
+
+ static struct PyArrayMethodDef slots[] = {
+ {NPY_dt_method, method_implementation},
+ ...,
+ {0, NULL}
+ }
+
+ typedef struct{
+ PyTypeObject *typeobj; /* type of python scalar or NULL */
+ int flags /* flags, including parametric and abstract */
+ /* NULL terminated CastingImpl; is copied and references are stolen */
+ CastingImpl *castingimpls[];
+ PyType_Slot *slots;
+ PyTypeObject *baseclass; /* Baseclass or NULL */
+ } PyArrayDTypeMeta_Spec;
+
+ PyObject* PyArray_InitDTypeMetaFromSpec(PyArrayDTypeMeta_Spec *dtype_spec);
+
+All of this is passed by copying.
+
+**TODO:** The DType author should be able to define new methods for the
+DType, up to defining a full object, and, in the future, possibly even
+extending the ``PyArrayDTypeMeta_Type`` struct. We have to decide what to make
+available initially. A solution may be to allow inheriting only from an
+existing class: ``class MyDType(np.dtype, MyBaseclass)``. If ``np.dtype`` is
+first in the method resolution order, this also prevents an undesirable
+override of slots like ``==``.
+
+The ``slots`` will be identified by names which are prefixed with ``NPY_dt_``
+and are:
+
+* ``is_canonical(self) -> {0, 1}``
+* ``ensure_canonical(self) -> dtype``
+* ``default_descr(self) -> dtype`` (return must be native and should normally be a singleton)
+* ``setitem(self, char *item_ptr, PyObject *value) -> {-1, 0}``
+* ``getitem(self, char *item_ptr, PyObject (base_obj) -> object or NULL``
+* ``discover_descr_from_pyobject(cls, PyObject) -> dtype or NULL``
+* ``common_dtype(cls, other) -> DType, NotImplemented, or NULL``
+* ``common_instance(self, other) -> dtype or NULL``
+
+Where possible, a default implementation will be provided if the slot is
+omitted or set to ``NULL``. Nonparametric dtypes do not have to implement:
+
+* ``discover_descr_from_pyobject`` (uses ``default_descr`` instead)
+* ``common_instance`` (uses ``default_descr`` instead)
+* ``ensure_canonical`` (uses ``default_descr`` instead).
+
+Sorting is expected to be implemented using:
+
+* ``get_sort_function(self, NPY_SORTKIND sort_kind) -> {out_sortfunction, NotImplemented, NULL}``.
+
+For convenience, it will be sufficient if the user implements only:
+
+* ``compare(self, char *item_ptr1, char *item_ptr2, int *res) -> {-1, 0, 1}``
+
+
+**Limitations:** The ``PyArrayDTypeMeta_Spec`` struct is clumsy to extend (for
+instance, by adding a version tag to the ``slots`` to indicate a new, longer
+version). We could use a function to provide the struct; it would require
+memory management but would allow ABI-compatible extension (the struct is
+freed again when the DType is created).
+
+
+CastingImpl
+==============================================================================
+
+The external API for ``CastingImpl`` will be limited initially to defining:
+
+* ``casting`` attribute, which can be one of the supported casting kinds.
+ This is the safest cast possible. For example, casting between two NumPy
+ strings is of course "safe" in general, but may be "same kind" in a specific
+ instance if the second string is shorter. If neither type is parametric the
+ ``resolve_descriptors`` must use it.
+
+* ``resolve_descriptors(dtypes_in[2], dtypes_out[2], casting_out) -> int {0,
+ -1}`` The out
+ dtypes must be set correctly to dtypes which the strided loop
+ (transfer function) can handle. Initially the result must have instances
+ of the same DType class as the ``CastingImpl`` is defined for. The
+ ``casting`` will be set to ``NPY_EQUIV_CASTING``, ``NPY_SAFE_CASTING``,
+ ``NPY_UNSAFE_CASTING``, or ``NPY_SAME_KIND_CASTING``.
+ A new, additional flag,
+ ``_NPY_CAST_IS_VIEW``, can be set to indicate that no cast is necessary and a
+ view is sufficient to perform the cast. The cast should return
+ ``-1`` when a custom error is set and ``NPY_NO_CASTING`` to indicate
+ that a generic casting error should be set (this is in most cases
+ preferable).
+
+* ``strided_loop(char **args, npy_intp *dimensions, npy_intp *strides,
+ ...) -> int {0, -1}`` (signature will be fully defined in :ref:`NEP 43 <NEP43>`)
+
+This is identical to the proposed API for ufuncs. The additional ``...``
+part of the signature will include information such as the two ``dtype``\s.
+More optimized loops are in use internally, and
+will be made available to users in the future (see notes).
+
+Although verbose, the API will mimic the one for creating a new DType:
+
+.. code-block:: C
+
+ typedef struct{
+ int flags; /* e.g. whether the cast requires the API */
+ int nin, nout; /* Number of Input and outputs (always 1) */
+ NPY_CASTING casting; /* The default casting level */
+ PyArray_DTypeMeta *dtypes; /* input and output DType class */
+ /* NULL terminated slots defining the methods */
+ PyType_Slot *slots;
+ } PyArrayMethod_Spec;
+
+The focus differs between casting and general ufuncs. For example, for casts
+``nin == nout == 1`` is always correct, while for ufuncs ``casting`` is
+expected to be usually `"safe"`.
+
+**Notes:** We may initially allow users to define only a single loop.
+Internally NumPy optimizes far more, and this should be made public
+incrementally in one of two ways:
+
+* Allow multiple versions, such as:
+
+ * contiguous inner loop
+ * strided inner loop
+ * scalar inner loop
+
+* Or, more likely, expose the ``get_loop`` function which is passed additional
+ information, such as the fixed strides (similar to our internal API).
+
+The example does not yet include setup and error handling. Since these are
+similar to the UFunc machinery, they will be defined in :ref:`NEP 43 <NEP43>` and then
+incorporated identically into casting.
+
+The slots/methods used will be prefixed with ``NPY_meth_``.
+
+
+**Alternatives:**
+
+- Aside from name changes and signature tweaks, there seem to be few
+ alternatives to the above structure. The proposed API using ``*_FromSpec``
+ function is a good way to achieve a stable and extensible API. The slots
+ design is extensible and can be changed without breaking binary
+ compatibility. Convenience functions can still be provided to allow creation
+ with less code.
+
+- One downside is that compilers cannot warn about function-pointer
+ incompatibilities.
+
+
+******************************************************************************
+Implementation
+******************************************************************************
+
+Steps for implementation are outlined in the Implementation section of
+:ref:`NEP 41 <NEP41>`. In brief, we first will rewrite the internals of
+casting and array coercion. After that, the new public API will be added
+incrementally. We plan to expose it in a preliminary state initially to gain
+experience. All functionality currently implemented on the dtypes will be
+replaced systematically as new features are added.
+
+
+******************************************************************************
+Alternatives
+******************************************************************************
+
+The space of possible implementations is large, so there have been many
+discussions, conceptions, and design documents. These are listed in
+:ref:`NEP 40 <NEP40>`. Alternatives were also been discussed in the
+relevant sections above.
+
+
+******************************************************************************
+References
+******************************************************************************
+
+.. [1] To be clear, the program is broken: It should not have stored a value
+ in the common DType that was below the lowest int16 or above the highest
+ uint16. It avoided overflow earlier by an accident of implementation.
+ Nonetheless, we insist that program behavior not be altered just by
+ importing a type.
+
+.. [2] NumPy currently inspects the value to allow the operations::
+
+ np.array([1], dtype=np.uint8) + 1
+ np.array([1.2], dtype=np.float32) + 1.
+
+ to return a ``uint8`` or ``float32`` array respectively. This is
+ further described in the documentation for :func:`numpy.result_type`.
+
+
+******************************************************************************
+Copyright
+******************************************************************************
+
+This document has been placed in the public domain.
--- /dev/null
+.. _NEP43:
+
+==============================================================================
+NEP 43 — Enhancing the Extensibility of UFuncs
+==============================================================================
+
+:title: Enhancing the Extensibility of UFuncs
+:Author: Sebastian Berg
+:Status: Draft
+:Type: Standard
+:Created: 2020-06-20
+
+
+.. note::
+
+ This NEP is fourth in a series:
+
+ - :ref:`NEP 40 <NEP40>` explains the shortcomings of NumPy's dtype implementation.
+
+ - :ref:`NEP 41 <NEP41>` gives an overview of our proposed replacement.
+
+ - :ref:`NEP 42 <NEP42>` describes the new design's datatype-related APIs.
+
+ - NEP 43 (this document) describes the new design's API for universal functions.
+
+
+******************************************************************************
+Abstract
+******************************************************************************
+
+The previous NEP 42 proposes the creation of new DTypes which can
+be defined by users outside of NumPy itself.
+The implementation of NEP 42 will enable users to create arrays with a custom dtype
+and stored values.
+This NEP outlines how NumPy will operate on arrays with custom dtypes in the future.
+The most important functions operating on NumPy arrays are the so called
+"universal functions" (ufunc) which include all math functions, such as
+``np.add``, ``np.multiply``, and even ``np.matmul``.
+These ufuncs must operate efficiently on multiple arrays with
+different datatypes.
+
+This NEP proposes to expand the design of ufuncs.
+It makes a new distinction between the ufunc which can operate
+on many different dtypes such as floats or integers,
+and a new ``ArrayMethod`` which defines the efficient operation for
+specific dtypes.
+
+.. note::
+
+ Details of the private and external APIs may change to reflect user
+ comments and implementation constraints. The underlying principles and
+ choices should not change significantly.
+
+
+******************************************************************************
+Motivation and scope
+******************************************************************************
+
+The goal of this NEP is to extend universal
+functions support the new DType system detailed in NEPs 41 and 42.
+While the main motivation is enabling new user-defined DTypes, this will
+also significantly simplify defining universal functions for NumPy strings or
+structured DTypes.
+Until now, these DTypes are not supported by any of NumPy's functions
+(such as ``np.add`` or ``np.equal``), due to difficulties arising from
+their parametric nature (compare NEP 41 and 42), e.g. the string length.
+
+Functions on arrays must handle a number of distinct steps which are
+described in more detail in section "`Steps involved in a UFunc call`_".
+The most important ones are:
+
+- Organizing all functionality required to define a ufunc call for specific
+ DTypes. This is often called the "inner-loop".
+- Deal with input for which no exact matching implementation is found.
+ For example when ``int32`` and ``float64`` are added, the ``int32``
+ is cast to ``float64``. This requires a distinct "promotion" step.
+
+After organizing and defining these, we need to:
+
+- Define the user API for customizing both of the above points.
+- Allow convenient reuse of existing functionality.
+ For example a DType representing physical units, such as meters,
+ should be able to fall back to NumPy's existing math implementations.
+
+This NEP details how these requirements will be achieved in NumPy:
+
+- All DTyper-specific functionality currently part of the ufunc
+ definition will be defined as part of a new `ArrayMethod`_ object.
+ This ``ArrayMethod`` object will be the new, preferred, way to describe any
+ function operating on arrays.
+
+- Ufuncs will dispatch to the ``ArrayMethod`` and potentially use promotion
+ to find the correct ``ArrayMethod`` to use.
+ This will be described in the `Promotion and dispatching`_ section.
+
+A new C-API will be outlined in each section. A future Python API is
+expected to be very similar and the C-API is presented in terms of Python
+code for readability.
+
+The NEP proposes a large, but necessary, refactor of the NumPy ufunc internals.
+This modernization will not affect end users directly and is not only a necessary
+step for new DTypes, but in itself a maintenance effort which is expected to
+help with future improvements to the ufunc machinery.
+
+While the most important restructure proposed is the new ``ArrayMethod``
+object, the largest long-term consideration is the API choice for
+promotion and dispatching.
+
+
+***********************
+Backwards Compatibility
+***********************
+
+The general backwards compatibility issues have also been listed
+previously in NEP 41.
+
+The vast majority of users should not see any changes beyond those typical
+for NumPy releases.
+There are three main users or use-cases impacted by the proposed changes:
+
+1. The Numba package uses direct access to the NumPy C-loops and modifies
+ the NumPy ufunc struct directly for its own purposes.
+2. Astropy uses its own "type resolver", meaning that a default switch over
+ from the existing type resolution to a new default Promoter requires care.
+3. It is currently possible to register loops for dtype *instances*.
+ This is theoretically useful for structured dtypes and is a resolution
+ step happening *after* the DType resolution step proposed here.
+
+This NEP will try hard to maintain backward compatibility as much as
+possible. However, both of these projects have signaled willingness to adapt
+to breaking changes.
+
+The main reason why NumPy will be able to provide backward compatibility
+is that:
+
+* Existing inner-loops can be wrapped, adding an indirection to the call but
+ maintaining full backwards compatibility.
+ The ``get_loop`` function can, in this case, search the existing
+ inner-loop functions (which are stored on the ufunc directly) in order
+ to maintain full compatibility even with potential direct structure access.
+* Legacy type resolvers can be called as a fallback (potentially caching
+ the result). The resolver may need to be called twice (once for the DType
+ resolution and once for the ``resolve_descriptor`` implementation).
+* The fallback to the legacy type resolver should in most cases handle loops
+ defined for such structured dtype instances. This is because if there is no
+ other ``np.Void`` implementation, the legacy fallback will retain the old
+ behaviour at least initially.
+
+The masked type resolvers specifically will *not* remain supported, but
+has no known users (including NumPy itself, which only uses the default
+version).
+
+While the above changes potentially break some workflows,
+we believe that the long-term improvements vastly outweigh this.
+Further, packages such as astropy and Numba are capable of adapting so that
+end-users may need to update their libraries but not their code.
+
+
+******************************************************************************
+Usage and impact
+******************************************************************************
+
+This NEP restructures how operations on NumPy arrays are defined both
+within NumPy and for external implementers.
+The NEP mainly concerns those who either extend ufuncs for custom DTypes
+or create custom ufuncs. It does not aim to finalize all
+potential use-cases, but rather restructure NumPy to be extensible and allow
+addressing new issues or feature requests as they arise.
+
+
+Overview and end user API
+=========================
+
+To give an overview of how this NEP proposes to structure ufuncs,
+the following describes the potential exposure of the proposed restructure
+to the end user.
+
+Universal functions are much like a Python method defined on the DType of
+the array when considering a ufunc with only a single input::
+
+ res = np.positive(arr)
+
+could be implemented (conceptually) as::
+
+ positive_impl = arr.dtype.positive
+ res = positive_impl(arr)
+
+However, unlike methods, ``positive_impl`` is not stored on the dtype itself.
+It is rather the implementation of ``np.positive`` for a specific DType.
+Current NumPy partially exposes this "choice of implementation" using
+the ``dtype`` (or more exact ``signature``) attribute in universal functions,
+although these are rarely used::
+
+ np.positive(arr, dtype=np.float64)
+
+forces NumPy to use the ``positive_impl`` written specifically for the Float64
+DType.
+
+This NEP makes the distinction more explicit, by creating a new object to
+represent ``positive_impl``::
+
+ positive_impl = np.positive.resolve_impl((type(arr.dtype), None))
+ # The `None` represents the output DType which is automatically chosen.
+
+While the creation of a ``positive_impl`` object and the ``resolve_impl``
+method is part of this NEP, the following code::
+
+ res = positive_impl(arr)
+
+may not be implemented initially and is not central to the redesign.
+
+In general NumPy universal functions can take many inputs.
+This requires looking up the implementation by considering all of them
+and makes ufuncs "multi-methods" with respect to the input DTypes::
+
+ add_impl = np.add.resolve_impl((type(arr1.dtype), type(arr2.dtype), None))
+
+This NEP defines how ``positive_impl`` and ``add_impl`` will be represented
+as a new ``ArrayMethod`` which can be implemented outside of NumPy.
+Further, it defines how ``resolve_impl`` will implement and solve dispatching
+and promotion.
+
+The reasons for this split may be more clear after reviewing the
+`Steps involved in a UFunc call`_ section.
+
+
+Defining a new ufunc implementation
+===================================
+
+The following is a mock-up of how a new implementation, in this case
+to define string equality, will be added to a ufunc.
+
+.. code-block:: python
+
+ class StringEquality(BoundArrayMethod):
+ nin = 1
+ nout = 1
+ DTypes = (String, String, Bool)
+
+ def resolve_descriptors(context, given_descrs):
+ """The strided loop supports all input string dtype instances
+ and always returns a boolean. (String is always native byte order.)
+
+ Defining this function is not necessary, since NumPy can provide
+ it by default.
+ """
+ assert isinstance(given_descrs[0], context.DTypes[0])
+ assert isinstance(given_descrs[1], context.DTypes[1])
+
+ # The operation is always "safe" casting (most ufuncs are)
+ return (given_descrs[0], given_descrs[1], context.DTypes[2]()), "safe"
+
+ def strided_loop(context, dimensions, data, strides, innerloop_data):
+ """The 1-D strided loop, similar to those used in current ufuncs"""
+ # dimensions: Number of loop items and core dimensions
+ # data: Pointers to the array data.
+ # strides: strides to iterate all elements
+ n = dimensions[0] # number of items to loop over
+ num_chars1 = context.descriptors[0].itemsize
+ num_chars2 = context.descriptors[1].itemsize
+
+ # C code using the above information to compare the strings in
+ # both arrays. In particular, this loop requires the `num_chars1`
+ # and `num_chars2`. Information which is currently not easily
+ # available.
+
+ np.equal.register_impl(StringEquality)
+ del StringEquality # may be deleted.
+
+
+This definition will be sufficient to create a new loop, and the
+structure allows for expansion in the future; something that is already
+required to implement casting within NumPy itself.
+We use ``BoundArrayMethod`` and a ``context`` structure here. These
+are described and motivated in details later. Briefly:
+
+* ``context`` is a generalization of the ``self`` that Python passes to its
+ methods.
+* ``BoundArrayMethod`` is equivalent to the Python distinction that
+ ``class.method`` is a method, while ``class().method`` returns a "bound" method.
+
+
+Customizing Dispatching and Promotion
+=====================================
+
+Finding the correct implementation when ``np.positive.resolve_impl()`` is
+called is largely an implementation detail.
+But, in some cases it may be necessary to influence this process when no
+implementation matches the requested DTypes exactly:
+
+.. code-block:: python
+
+ np.multiple.resolve_impl((Timedelta64, Int8, None))
+
+will not have an exact match, because NumPy only has an implementation for
+multiplying ``Timedelta64`` with ``Int64``.
+In simple cases, NumPy will use a default promotion step to attempt to find
+the correct implementation, but to implement the above step, we will allow
+the following:
+
+.. code-block:: python
+
+ def promote_timedelta_integer(ufunc, dtypes):
+ new_dtypes = (Timdelta64, Int64, dtypes[-1])
+ # Resolve again, using Int64:
+ return ufunc.resolve_impl(new_dtypes)
+
+ np.multiple.register_promoter(
+ (Timedelta64, Integer, None), promote_timedelta_integer)
+
+Where ``Integer`` is an abstract DType (compare NEP 42).
+
+
+.. _steps_of_a_ufunc_call:
+
+****************************************************************************
+Steps involved in a UFunc call
+****************************************************************************
+
+Before going into more detailed API choices, it is helpful to review the
+steps involved in a call to a universal function in NumPy.
+
+A UFunc call is split into the following steps:
+
+1. *Handle ``__array_ufunc__`` protocol:*
+
+ * For array-likes such as a Dask arrays, NumPy can defer the operation.
+ This step is performed first, and unaffected by this NEP (compare :ref:`NEP18`).
+
+2. *Promotion and dispatching*
+
+ * Given the DTypes of all inputs, find the correct implementation.
+ E.g. an implementation for ``float64``, ``int64`` or a user-defined DType.
+
+ * When no exact implementation exists, *promotion* has to be performed.
+ For example, adding a ``float32`` and a ``float64`` is implemented by
+ first casting the ``float32`` to ``float64``.
+
+3. *Parametric ``dtype`` resolution:*
+
+ * In general, whenever an output DType is parametric the parameters have
+ to be found (resolved).
+ * For example, if a loop adds two strings, it is necessary to define the
+ correct output (and possibly input) dtypes. ``S5 + S4 -> S9``, while
+ an ``upper`` function has the signature ``S5 -> S5``.
+ * When they are not parametric, a default implementation is provided
+ which fills in the default dtype instances (ensuring for example native
+ byte order).
+
+4. *Preparing the iteration:*
+
+ * This step is largely handled by ``NpyIter`` internally (the iterator).
+ * Allocate all outputs and temporary buffers necessary to perform casts.
+ * Find the best iteration order, which includes information to efficiently
+ implement broadcasting. For example, adding a single value to an array
+ repeats the same value.
+
+5. *Setup and fetch the C-level function:*
+
+ * If necessary, allocate temporary working space.
+ * Find the C-implemented, light weight, inner-loop function.
+ Finding the inner-loop function can allow specialized implementations
+ in the future.
+ For example casting currently optimizes contiguous casts and
+ reductions have optimizations that are currently handled
+ inside the inner-loop function itself.
+ * Signal whether the inner-loop requires the Python API or whether
+ the GIL may be released (to allow threading).
+ * Clear floating point exception flags.
+
+6. *Perform the actual calculation:*
+
+ * Run the DType specific inner-loop function.
+ * The inner-loop may require access to additional data, such as dtypes or
+ additional data set in the previous step.
+ * The inner-loop function may be called an undefined number of times.
+
+7. *Finalize:*
+
+ * Free any temporary working space allocated in 5.
+ * Check for floating point exception flags.
+ * Return the result.
+
+The ``ArrayMethod`` provides a concept to group steps 3 to 6 and partially 7.
+However, implementers of a new ufunc or ``ArrayMethod`` do not need to
+customize the behaviour in steps 4 or 6, aside from the inner-loop function.
+For the ``ArrayMethod`` implementer, the central steps to have control over
+are step 3 and step 5 to provide the custom inner-loop function.
+Further customization is a potential future extension.
+
+Step 2. is promotion and dispatching which will also be restructured
+with new API which allows influencing the process where necessary.
+
+Step 1 is listed for completeness and is unaffected by this NEP.
+
+The following sketch provides an overview of step 2 to 6 with an emphasize
+of how dtypes are handled:
+
+.. figure:: _static/nep43-sketch.svg
+ :figclass: align-center
+
+
+*****************************************************************************
+ArrayMethod
+*****************************************************************************
+
+A central proposal of this NEP is the creation of the ``ArrayMethod`` as an object
+describing each implementation specific to a given set of DTypes.
+We use the ``class`` syntax to describe the information required to create
+a new ``ArrayMethod`` object:
+
+.. code-block:: python
+ :dedent: 0
+
+ class ArrayMethod:
+ name: str # Name, mainly useful for debugging
+
+ # Casting safety information (almost always "safe", necessary to
+ # unify casting and universal functions)
+ casting: Casting = "safe"
+
+ # More general flags:
+ flags: int
+
+ @staticmethod
+ def resolve_descriptors(
+ Context: context, Tuple[DType]: given_descrs)-> Casting, Tuple[DType]:
+ """Returns the safety of the operation (casting safety) and the
+ """
+ # A default implementation can be provided for non-parametric
+ # output dtypes.
+ raise NotImplementedError
+
+ @staticmethod
+ def get_loop(Context : context, strides, ...) -> strided_loop_function, flags:
+ """Returns the low-level C (strided inner-loop) function which
+ performs the actual operation.
+
+ This method may initially private, users will be able to provide
+ a set of optimized inner-loop functions instead:
+
+ * `strided_inner_loop`
+ * `contiguous_inner_loop`
+ * `unaligned_strided_loop`
+ * ...
+ """
+ raise NotImplementedError
+
+ @staticmethod
+ def strided_inner_loop(
+ Context : context, data, dimensions, strides, innerloop_data):
+ """The inner-loop (equivalent to the current ufunc loop)
+ which is returned by the default `get_loop()` implementation."""
+ raise NotImplementedError
+
+With ``Context`` providing mostly static information about the function call:
+
+.. code-block:: python
+ :dedent: 0
+
+ class Context:
+ # The ArrayMethod object itself:
+ ArrayMethod : method
+
+ # Information about the caller, e.g. the ufunc, such as `np.add`:
+ callable : caller = None
+ # The number of input arguments:
+ int : nin = 1
+ # The number of output arguments:
+ int : nout = 1
+ # The DTypes this Method operates on/is defined for:
+ Tuple[DTypeMeta] : dtypes
+ # The actual dtypes instances the inner-loop operates on:
+ Tuple[DType] : descriptors
+
+ # Any additional information required. In the future, this will
+ # generalize or duplicate things currently stored on the ufunc:
+ # - The ufunc signature of generalized ufuncs
+ # - The identity used for reductions
+
+And ``flags`` stored properties, for whether:
+
+* the ``ArrayMethod`` supports unaligned input and output arrays
+* the inner-loop function requires the Python API (GIL)
+* NumPy has to check the floating point error CPU flags.
+
+*Note: More information is expected to be added as necessary.*
+
+
+The call ``Context``
+====================
+
+The "context" object is analogous to Python's ``self`` that is
+passed to all methods.
+To understand why the "context" object is necessary and its
+internal structure, it is helpful to remember
+that a Python method can be written in the following way
+(see also the `documentation of __get__
+<https://docs.python.org/3.8/reference/datamodel.html#object.__get__>`_):
+
+.. code-block:: python
+
+ class BoundMethod:
+ def __init__(self, instance, method):
+ self.instance = instance
+ self.method = method
+
+ def __call__(self, *args, **kwargs):
+ return self.method.function(self.instance, *args, **kwargs)
+
+
+ class Method:
+ def __init__(self, function):
+ self.function = function
+
+ def __get__(self, instance, owner=None):
+ assert instance is not None # unsupported here
+ return BoundMethod(instance, self)
+
+
+With which the following ``method1`` and ``method2`` below, behave identically:
+
+.. code-block:: python
+
+ def function(self):
+ print(self)
+
+ class MyClass:
+ def method1(self):
+ print(self)
+
+ method2 = Method(function)
+
+And both will print the same result:
+
+.. code-block:: python
+
+ >>> myinstance = MyClass()
+ >>> myinstance.method1()
+ <__main__.MyClass object at 0x7eff65436d00>
+ >>> myinstance.method2()
+ <__main__.MyClass object at 0x7eff65436d00>
+
+Here ``self.instance`` would be all information passed on by ``Context``.
+The ``Context`` is a generalization and has to pass additional information:
+
+* Unlike a method which operates on a single class instance, the ``ArrayMethod``
+ operates on many input arrays and thus multiple dtypes.
+* The ``__call__`` of the ``BoundMethod`` above contains only a single call
+ to a function. But an ``ArrayMethod`` has to call ``resolve_descriptors``
+ and later pass on that information to the inner-loop function.
+* A Python function has no state except that defined by its outer scope.
+ Within C, ``Context`` is able to provide additional state if necessary.
+
+Just as Python requires the distinction of a method and a bound method,
+NumPy will have a ``BoundArrayMethod``.
+This stores all of the constant information that is part of the ``Context``,
+such as:
+
+* the ``DTypes``
+* the number of input and ouput arguments
+* the ufunc signature (specific to generalized ufuncs, compare :ref:`NEP20`).
+
+Fortunately, most users and even ufunc implementers will not have to worry
+about these internal details; just like few Python users need to know
+about the ``__get__`` dunder method.
+The ``Context`` object or C-structure provides all necessary data to the
+fast C-functions and NumPy API creates the new ``ArrayMethod`` or
+``BoundArrayMethod`` as required.
+
+
+.. _ArrayMethod_specs:
+
+ArrayMethod Specifications
+==========================
+
+.. highlight:: c
+
+These specifications provide a minimal initial C-API, which shall be expanded
+in the future, for example to allow specialized inner-loops.
+
+Briefly, NumPy currently relies on strided inner-loops and this
+will be the only allowed method of defining a ufunc initially.
+We expect the addition of a ``setup`` function or exposure of ``get_loop``
+in the future.
+
+UFuncs require the same information as casting, giving the following
+definitions (see also :ref:`NEP 42 <NEP42>` ``CastingImpl``):
+
+* A new structure to be passed to the resolve function and inner-loop::
+
+ typedef struct {
+ PyObject *caller; /* The ufunc object */
+ PyArrayMethodObject *method;
+
+ int nin, nout;
+
+ PyArray_DTypeMeta **dtypes;
+ /* Operand descriptors, filled in by resolve_desciptors */
+ PyArray_Descr **descriptors;
+
+ void *reserved; // For Potential in threading (Interpreter state)
+ } PyArrayMethod_Context
+
+ This structure may be appended to include additional information in future
+ versions of NumPy and includes all constant loop metadata.
+
+ We could version this structure, although it may be simpler to version
+ the ``ArrayMethod`` itself.
+
+* Similar to casting, ufuncs may need to find the correct loop dtype
+ or indicate that a loop is only capable of handling certain instances of
+ the involved DTypes (e.g. only native byteorder). This is handled by
+ a ``resolve_descriptors`` function (identical to the ``resolve_descriptors``
+ of ``CastingImpl``)::
+
+ NPY_CASTING
+ resolve_descriptors(
+ PyArrayMethod_Context *context,
+ PyArray_Descr *given_dtypes[nin+nout],
+ PyArray_Descr *loop_dtypes[nin+nout]);
+
+ The function fills ``loop_dtypes`` based on the given ``given_dtypes``.
+ This requires filling in the descriptor of the output(s).
+ Often also the input descriptor(s) have to be found, e.g. to ensure native
+ byteorder when needed by the inner-loop.
+
+ In most cases an ``ArrayMethod`` will have non-parametric output DTypes
+ so that a default implementation can be provided.
+
+* An additional ``void *user_data`` will usually be typed to extend
+ the existing ``NpyAuxData *`` struct::
+
+ struct {
+ NpyAuxData_FreeFunc *free;
+ NpyAuxData_CloneFunc *clone;
+ /* To allow for a bit of expansion without breaking the ABI */
+ void *reserved[2];
+ } NpyAuxData;
+
+ This struct is currently mainly used for the NumPy internal casting
+ machinery and as of now both ``free`` and ``clone`` must be provided,
+ although this could be relaxed.
+
+ Unlike NumPy casts, the vast majority of ufuncs currently do not require
+ this additional scratch-space, but may need simple flagging capability
+ for example for implementing warnings (see Error and Warning Handling below).
+ To simplify this NumPy will pass a single zero initialized ``npy_intp *``
+ when ``user_data`` is not set.
+ *NOTE that it would be possible to pass this as part of ``Context``.*
+
+* The optional ``get_loop`` function will not be public initially, to avoid
+ finalizing the API which requires design choices also with casting:
+
+ .. code-block::
+
+ innerloop *
+ get_loop(
+ PyArrayMethod_Context *context,
+ /* (move_references is currently used internally for casting) */
+ int aligned, int move_references,
+ npy_intp *strides,
+ PyArray_StridedUnaryOp **out_loop,
+ NpyAuxData **innerloop_data,
+ NPY_ARRAYMETHOD_FLAGS *flags);
+
+ The ``NPY_ARRAYMETHOD_FLAGS`` can indicate whether the Python API is required
+ and floating point errors must be checked.
+
+* The inner-loop function::
+
+ int inner_loop(PyArrayMethod_Context *context, ..., void *innerloop_data);
+
+ Will have the identical signature to current inner-loops with the following
+ changes:
+
+ * A return value to indicate an error when returning ``-1`` instead of ``0``.
+ When returning ``-1`` a Python error must be set.
+ * The new first argument ``PyArrayMethod_Context *`` is used to pass in
+ potentially required information about the ufunc or descriptors in a
+ convenient way.
+ * The ``void *innerloop_data`` will be the ``NpyAuxData **innerloop_data`` as set by
+ ``get_loop``. If ``get_loop`` does not set ``innerloop_data`` an ``npy_intp *``
+ is passed instead (see `Error Handling`_ below for the motivation).
+
+ *Note:* Since ``get_loop`` is expected to be private, the exact implementation
+ of ``innerloop_data`` can be modified until final exposure.
+
+Creation of a new ``BoundArrayMethod`` will use a ``PyArrayMethod_FromSpec()``
+function. A shorthand will allow direct registration to a ufunc using
+``PyUFunc_AddImplementationFromSpec()``. The specification is expected
+to contain the following (this may extend in the future)::
+
+ typedef struct {
+ const char *name; /* Generic name, mainly for debugging */
+ int nin, nout;
+ NPY_CASTING casting;
+ NPY_ARRAYMETHOD_FLAGS flags;
+ PyArray_DTypeMeta **dtypes;
+ PyType_Slot *slots;
+ } PyArrayMethod_Spec;
+
+.. highlight:: python
+
+Discussion and alternatives
+===========================
+
+The above split into an ``ArrayMethod`` and ``Context`` and the additional
+requirement of a ``BoundArrayMethod`` is a necessary split mirroring the
+implementation of methods and bound methods in Python.
+
+One reason for this requirement is that it allows storing the ``ArrayMethod``
+object in many cases without holding references to the ``DTypes`` which may
+be important if DTypes are created (and deleted) dynamically.
+(This is a complex topic, which does not have a complete solution in current
+Python, but the approach solves the issue with respect to casting.)
+
+There seem to be no alternatives to this structure. Separating the
+DType-specific steps from the general ufunc dispatching and promotion is
+absolutely necessary to allow future extension and flexibility.
+Furthermore, it allows unifying casting and ufuncs.
+
+Since the structure of ``ArrayMethod`` and ``BoundArrayMethod`` will be
+opaque and can be extended, there are few long-term design implications aside
+from the choice of making them Python objects.
+
+
+``resolve_descriptors``
+-----------------------
+
+The ``resolve_descriptors`` method is possibly the main innovation of this
+NEP and it is central also in the implementation of casting in NEP 42.
+
+By ensuring that every ``ArrayMethod`` provides ``resolve_descriptors`` we
+define a unified, clear API for step 3 in `Steps involved in a UFunc call`_.
+This step is required to allocate output arrays and has to happen before
+casting can be prepared.
+
+While the returned casting-safety (``NPY_CASTING``) will almost always be
+"safe" for universal functions, including it has two big advantages:
+
+* Returning the casting safety is central to NEP 42 for casting and
+ allows the unmodified use of ``ArrayMethod`` there.
+* There may be a future desire to implement fast but unsafe implementations.
+ For example for ``int64 + int64 -> int32`` which is unsafe from a casting
+ perspective. Currently, this would use ``int64 + int64 -> int64`` and then
+ cast to ``int32``. An implementation that skips the cast would
+ have to signal that it effectively includes the "same-kind" cast and is
+ thus not considered "safe".
+
+
+``get_loop`` method
+-------------------
+
+Currently, NumPy ufuncs typically only provide a single strided loop, so that
+the ``get_loop`` method may seem unnecessary.
+For this reason we plan for ``get_loop`` to be a private function initially.
+
+However, ``get_loop`` is required for casting where specialized loops are
+used even beyond strided and contiguous loops.
+Thus, the ``get_loop`` function must be a full replacement for
+the internal ``PyArray_GetDTypeTransferFunction``.
+
+In the future, ``get_loop`` may be made public or a new ``setup`` function
+be exposed to allow more control, for example to allow allocating
+working memory.
+Further, we could expand ``get_loop`` and allow the ``ArrayMethod`` implementer
+to also control the outer iteration and not only the 1-D inner-loop.
+
+
+Extending the inner-loop signature
+----------------------------------
+
+Extending the inner-loop signature is another central and necessary part of
+the NEP.
+
+**Passing in the ``Context``:**
+
+Passing in the ``Context`` potentially allows for the future extension of
+the signature by adding new fields to the context struct.
+Furthermore it provides direct access to the dtype instances which
+the inner-loop operates on.
+This is necessary information for parametric dtypes since for example comparing
+two strings requires knowing the length of both strings.
+The ``Context`` can also hold potentially useful information such as the
+the original ``ufunc``, which can be helpful when reporting errors.
+
+In principle passing in Context is not necessary, as all information could be
+included in ``innerloop_data`` and set up in the ``get_loop`` function.
+In this NEP we propose passing the struct to simplify creation of loops for
+parametric DTypes.
+
+**Passing in user data:**
+
+The current casting implementation uses the existing ``NpyAuxData *`` to pass
+in additional data as defined by ``get_loop``.
+There are certainly alternatives to the use of this structure, but it
+provides a simple solution, which is already used in NumPy and public API.
+
+``NpyAyxData *`` is a light weight, allocated structure and since it already
+exists in NumPy for this purpose, it seems a natural choice.
+To simplify some use-cases (see "Error Handling" below), we will pass a
+``npy_intp *innerloop_data = 0`` instead when ``innerloop_data`` is not provided.
+
+*Note: Since ``get_loop`` is expected to be private initially we can gain
+experience with ``innerloop_data`` before exposing it as public API.*
+
+**Return value:**
+
+The return value to indicate an error is an important, but currently missing
+feature in NumPy. The error handling is further complicated by the way
+CPUs signal floating point errors.
+Both are discussed in the next section.
+
+Error Handling
+""""""""""""""
+
+.. highlight:: c
+
+We expect that future inner-loops will generally set Python errors as soon
+as an error is found. This is complicated when the inner-loop is run without
+locking the GIL. In this case the function will have to lock the GIL,
+set the Python error and return ``-1`` to indicate an error occurred:::
+
+ int
+ inner_loop(PyArrayMethod_Context *context, ..., void *innerloop_data)
+ {
+ NPY_ALLOW_C_API_DEF
+
+ for (npy_intp i = 0; i < N; i++) {
+ /* calculation */
+
+ if (error_occurred) {
+ NPY_ALLOW_C_API;
+ PyErr_SetString(PyExc_ValueError,
+ "Error occurred inside inner_loop.");
+ NPY_DISABLE_C_API
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+Floating point errors are special, since they require checking the hardware
+state which is too expensive if done within the inner-loop function itself.
+Thus, NumPy will handle these if flagged by the ``ArrayMethod``.
+An ``ArrayMethod`` should never cause floating point error flags to be set
+if it flags that these should not be checked. This could interfere when
+calling multiple functions; in particular when casting is necessary.
+
+An alternative solution would be to allow setting the error only at the later
+finalization step when NumPy will also check the floating point error flags.
+
+We decided against this pattern at this time. It seems more complex and
+generally unnecessary.
+While safely grabbing the GIL in the loop may require passing in an additional
+``PyThreadState`` or ``PyInterpreterState`` in the future (for subinterpreter
+support), this is acceptable and can be anticipated.
+Setting the error at a later point would add complexity: for instance
+if an operation is paused (which can currently happen for casting in particular),
+the error check needs to run explicitly ever time this happens.
+
+We expect that setting errors immediately is the easiest and most convenient
+solution and more complex solution may be possible future extensions.
+
+Handling *warnings* is slightly more complex: A warning should be
+given exactly once for each function call (i.e. for the whole array) even
+if naively it would be given many times.
+To simplify such a use case, we will pass in ``npy_intp *innerloop_data = 0``
+by default which can be used to store flags (or other simple persistent data).
+For instance, we could imagine an integer multiplication loop which warns
+when an overflow occurred::
+
+ int
+ integer_multiply(PyArrayMethod_Context *context, ..., npy_intp *innerloop_data)
+ {
+ int overflow;
+ NPY_ALLOW_C_API_DEF
+
+ for (npy_intp i = 0; i < N; i++) {
+ *out = multiply_integers(*in1, *in2, &overflow);
+
+ if (overflow && !*innerloop_data) {
+ NPY_ALLOW_C_API;
+ if (PyErr_Warn(PyExc_UserWarning,
+ "Integer overflow detected.") < 0) {
+ NPY_DISABLE_C_API
+ return -1;
+ }
+ *innerloop_data = 1;
+ NPY_DISABLE_C_API
+ }
+ return 0;
+ }
+
+*TODO:* The idea of passing an ``npy_intp`` scratch space when ``innerloop_data``
+is not set seems convenient, but I am uncertain about it, since I am not
+aware of any similar prior art. This "scratch space" could also be part of
+the ``context`` in principle.
+
+.. highlight:: python
+
+Reusing existing Loops/Implementations
+======================================
+
+For many DTypes the above definition for adding additional C-level loops will be
+sufficient and require no more than a single strided loop implementation
+and if the loop works with parametric DTypes, the
+``resolve_descriptors`` function *must* additionally be provided.
+
+However, in some use-cases it is desirable to call back to an existing implementation.
+In Python, this could be achieved by simply calling into the original ufunc.
+
+For better performance in C, and for large arrays, it is desirable to reuse
+an existing ``ArrayMethod`` as directly as possible, so that its inner-loop function
+can be used directly without additional overhead.
+We will thus allow to create a new, wrapping, ``ArrayMethod`` from an existing
+``ArrayMethod``.
+
+This wrapped ``ArrayMethod`` will have two additional methods:
+
+* ``view_inputs(Tuple[DType]: input_descr) -> Tuple[DType]`` replacing the
+ user input descriptors with descriptors matching the wrapped loop.
+ It must be possible to *view* the inputs as the output.
+ For example for ``Unit[Float64]("m") + Unit[Float32]("km")`` this will
+ return ``float64 + int32``. The original ``resolve_descriptors`` will
+ convert this to ``float64 + float64``.
+
+* ``wrap_outputs(Tuple[DType]: input_descr) -> Tuple[DType]`` replacing the
+ resolved descriptors with with the desired actual loop descriptors.
+ The original ``resolve_descriptors`` function will be called between these
+ two calls, so that the output descriptors may not be set in the first call.
+ In the above example it will use the ``float64`` as returned (which might
+ have changed the byte-order), and further resolve the physical unit making
+ the final signature::
+
+ ``Unit[Float64]("m") + Unit[Float64]("m") -> Unit[Float64]("m")``
+
+ the UFunc machinery will take care of casting the "km" input to "m".
+
+
+The ``view_inputs`` method allows passing the correct inputs into the
+original ``resolve_descriptors`` function, while ``wrap_outputs`` ensures
+the correct descriptors are used for output allocation and input buffering casts.
+
+An important use-case for this is that of an abstract Unit DType
+with subclasses for each numeric dtype (which could be dynamically created)::
+
+ Unit[Float64]("m")
+ # with Unit[Float64] being the concrete DType:
+ isinstance(Unit[Float64], Unit) # is True
+
+Such a ``Unit[Float64]("m")`` instance has a well-defined signature with
+respect to type promotion.
+The author of the ``Unit`` DType can implement most necessary logic by
+wrapping the existing math functions and using the two additional methods
+above.
+Using the *promotion* step, this will allow to create a register a single
+promoter for the abstract ``Unit`` DType with the ``ufunc``.
+The promoter can then add the wrapped concrete ``ArrayMethod`` dynamically
+at promotion time, and NumPy can cache (or store it) after the first call.
+
+**Alternative use-case:**
+
+A different use-case is that of a ``Unit(float64, "m")`` DType, where
+the numerical type is part of the DType parameter.
+This approach is possible, but will require a custom ``ArrayMethod``
+which wraps existing loops.
+It must also always require require two steps of dispatching
+(one to the ``Unit`` DType and a second one for the numerical type).
+
+Furthermore, the efficient implementation will require the ability to
+fetch and reuse the inner-loop function from another ``ArrayMethod``.
+(Which is probably necessary for users like Numba, but it is uncertain
+whether it should be a common pattern and it cannot be accessible from
+Python itself.)
+
+
+.. _promotion_and_dispatching:
+
+*************************
+Promotion and dispatching
+*************************
+
+NumPy ufuncs are multi-methods in the sense that they operate on (or with)
+multiple DTypes at once.
+While the input (and output) dtypes are attached to NumPy arrays,
+the ``ndarray`` type itself does not carry the information of which
+function to apply to the data.
+
+For example, given the input::
+
+ int_arr = np.array([1, 2, 3], dtype=np.int64)
+ float_arr = np.array([1, 2, 3], dtype=np.float64)
+ np.add(int_arr, float_arr)
+
+has to find the correct ``ArrayMethod`` to perform the operation.
+Ideally, there is an exact match defined, e.g. for ``np.add(int_arr, int_arr)``
+the ``ArrayMethod[Int64, Int64, out=Int64]`` matches exactly and can be used.
+However, for ``np.add(int_arr, float_arr)`` there is no direct match,
+requiring a promotion step.
+
+Promotion and dispatching process
+=================================
+
+In general the ``ArrayMethod`` is found by searching for an exact match of
+all input DTypes.
+The output dtypes should *not* affect calculation, but if multiple registered
+``ArrayMethod``\ s match exactly, the output DType will be used to find the
+better match.
+This will allow the current distinction for ``np.equal`` loops which define
+both ``Object, Object -> Bool`` (default) and ``Object, Object -> Object``.
+
+Initially, an ``ArrayMethod`` will be defined for *concrete* DTypes only
+and since these cannot be subclassed an exact match is guaranteed.
+In the future we expect that ``ArrayMethod``\ s can also be defined for
+*abstract* DTypes. In which case the best match is found as detailed below.
+
+**Promotion:**
+
+If a matching ``ArrayMethod`` exists, dispatching is straight forward.
+However, when it does not, require additional definitions to implement
+promotion:
+
+* By default any UFunc has a promotion which uses the common DType of all
+ inputs and dispatches a second time. This is well-defined for most
+ mathematical functions, but can be disabled or customized if necessary.
+ For instances ``int32 + float64`` tries again using ``float64 + float64``
+ which is the common DType.
+
+* Users can *register* new Promoters just as they can register a
+ new ``ArrayMethod``. These will use abstract DTypes to allow matching
+ a large variety of signatures.
+ The return value of a promotion function shall be a new ``ArrayMethod``
+ or ``NotImplemented``. It must be consistent over multiple calls with
+ the same input to allow caching of the result.
+
+The signature of a promotion function would be::
+
+ promoter(np.ufunc: ufunc, Tuple[DTypeMeta]: DTypes): -> Union[ArrayMethod, NotImplemented]
+
+Note that DTypes may include the output's DType, however, normally the
+output DType will *not* affect which ``ArrayMethod`` is chosen.
+
+In most cases, it should not be necessary to add a custom promotion function.
+An example which requires this is multiplication with a unit:
+in NumPy ``timedelta64`` can be multiplied with most integers,
+but NumPy only defines a loop (``ArrayMethod``) for ``timedelta64 * int64``
+so that multiplying with ``int32`` would fail.
+
+To allow this, the following promoter can be registered for
+``(Timedelta64, Integral, None)``::
+
+ def promote(ufunc, DTypes):
+ res = list(DTypes)
+ try:
+ res[1] = np.common_dtype(DTypes[1], Int64)
+ except TypeError:
+ return NotImplemented
+
+ # Could check that res[1] is actually Int64
+ return ufunc.resolve_impl(tuple(res))
+
+In this case, just as a ``Timedelta64 * int64`` and ``int64 * timedelta64``
+``ArrayMethod`` is necessary, a second promoter will have to be registered to
+handle the case where the integer is passed first.
+
+**Dispatching rules for ``ArrayMethod`` and Promoters:**
+
+Promoter and ``ArrayMethod`` are discovered by finding the best match as
+defined by the DType class hierarchy.
+The best match is defined if:
+
+* The signature matches for all input DTypes, so that
+ ``issubclass(input_DType, registered_DType)`` returns true.
+* No other promoter or ``ArrayMethod`` is more precise in any input:
+ ``issubclass(other_DType, this_DType)`` is true (this may include if both
+ are identical).
+* This promoter or ``ArrayMethod`` is more precise in at least one input or
+ output DType.
+
+It will be an error if ``NotImplemented`` is returned or if two
+promoters match the input equally well.
+When an existing promoter is not precise enough for new functionality, a
+new promoter has to be added.
+To ensure that this promoter takes precedence it may be necessary to define
+new abstract DTypes as more precise subclasses of existing ones.
+
+The above rules enable specialization if an output is supplied
+or the full loop is specified. This should not typically be necessary,
+but allows resolving ``np.logic_or``, etc. which have both
+``Object, Object -> Bool`` and ``Object, Object -> Object`` loops (using the
+first by default).
+
+
+Discussion and alternatives
+===========================
+
+Instead of resolving and returning a new implementation, we could also
+return a new set of DTypes to use for dispatching. This works, however,
+it has the disadvantage that it is impossible to dispatch to a loop
+defined on a different ufunc or to dynamically create a new ``ArrayMethod``.
+
+
+**Rejected Alternatives:**
+
+In the above the promoters use a multiple dispatching style type resolution
+while the current UFunc machinery uses the first
+"safe" loop (see also :ref:`NEP 40 <NEP40>`) in an ordered hierarchy.
+
+While the "safe" casting rule is not restrictive enough, we could imagine
+using a new "promote" casting rule, or the common-DType logic to find the
+best matching loop by upcasting the inputs as necessary.
+
+One downside to this approach is that upcasting alone allows upcasting the
+result beyond what is expected by users:
+Currently (which will remain supported as a fallback) any ufunc which defines
+only a float64 loop will also work for float16 and float32 by *upcasting*::
+
+ >>> from scipy.special import erf
+ >>> erf(np.array([4.], dtype=np.float16)) # float16
+ array([1.], dtype=float32)
+
+with a float32 result. It is impossible to change the ``erf`` function to
+return a float16 result without changing the result of following code.
+In general, we argue that automatic upcasting should not occur in cases
+where a less precise loop can be defined, *unless* the ufunc
+author does this intentionally using a promotion.
+
+This consideration means that upcasting has to be limited by some additional
+method.
+
+*Alternative 1:*
+
+Assuming general upcasting is not intended, a rule must be defined to
+limit upcasting the input from ``float16 -> float32`` either using generic
+logic on the DTypes or the UFunc itself (or a combination of both).
+The UFunc cannot do this easily on its own, since it cannot know all possible
+DTypes which register loops.
+Consider the two examples:
+
+First (should be rejected):
+
+* Input: ``float16 * float16``
+* Existing loop: ``float32 * float32``
+
+Second (should be accepted):
+
+* Input: ``timedelta64 * int32``
+* Existing loop: ``timedelta64 * int16``
+
+
+This requires either:
+
+1. The ``timedelta64`` to somehow signal that the ``int64`` upcast is
+ always supported if it is involved in the operation.
+2. The ``float32 * float32`` loop to reject upcasting.
+
+Implementing the first approach requires signaling that upcasts are
+acceptable in the specific context. This would require additional hooks
+and may not be simple for complex DTypes.
+
+For the second approach in most cases a simple ``np.common_dtype`` rule will
+work for initial dispatching, however, even this is only clearly the case
+for homogeneous loops.
+This option will require adding a function to check whether the input
+is a valid upcast to each loop individually, which seems problematic.
+In many cases a default could be provided (homogeneous signature).
+
+*Alternative 2:*
+
+An alternative "promotion" step is to ensure that the *output* DType matches
+with the loop after first finding the correct output DType.
+If the output DTypes are known, finding a safe loop becomes easy.
+In the majority of cases this works, the correct output dtype is just::
+
+ np.common_dtype(*input_DTypes)
+
+or some fixed DType (e.g. Bool for logical functions).
+
+However, it fails for example in the ``timedelta64 * int32`` case above since
+there is a-priori no way to know that the "expected" result type of this
+output is indeed ``timedelta64`` (``np.common_dtype(Datetime64, Int32)`` fails).
+This requires some additional knowledge of the timedelta64 precision being
+int64. Since a ufunc can have an arbitrary number of (relevant) inputs
+it would thus at least require an additional ``__promoted_dtypes__`` method
+on ``Datetime64`` (and all DTypes).
+
+A further limitation is shown by masked DTypes. Logical functions do not
+have a boolean result when masked are involved, which would thus require the
+original ufunc author to anticipate masked DTypes in this scheme.
+Similarly, some functions defined for complex values will return real numbers
+while others return complex numbers. If the original author did not anticipate
+complex numbers, the promotion may be incorrect for a later added complex loop.
+
+
+We believe that promoters, while allowing for an huge theoretical complexity,
+are the best solution:
+
+1. Promotion allows for dynamically adding new loops. E.g. it is possible
+ to define an abstract Unit DType, which dynamically creates classes to
+ wrap other existing DTypes. Using a single promoter, this DType can
+ dynamically wrap existing ``ArrayMethod`` enabling it to find the correct
+ loop in a single lookup instead of two.
+2. The promotion logic will usually err on the safe side: A newly-added
+ loop cannot be misused unless a promoter is added as well.
+3. They put the burden of carefully thinking of whether the logic is correct
+ on the programmer adding new loops to a UFunc. (Compared to Alternative 2)
+4. In case of incorrect existing promotion, writing a promoter to restrict
+ or refine a generic rule is possible. In general a promotion rule should
+ never return an *incorrect* promotion, but if it the existing promotion
+ logic fails or is incorrect for a newly-added loop, the loop can add a
+ new promoter to refine the logic.
+
+The option of having each loop verify that no upcast occured is probably
+the best alternative, but does not include the ability to dynamically
+adding new loops.
+
+The main downsides of general promoters is that they allow a possible
+very large complexity.
+A third-party library *could* add incorrect promotions to NumPy, however,
+this is already possible by adding new incorrect loops.
+In general we believe we can rely on downstream projects to use this
+power and complexity carefully and responsibly.
+
+
+***************
+User Guidelines
+***************
+
+In general adding a promoter to a UFunc must be done very carefully.
+A promoter should never affect loops which can be reasonably defined
+by other datatypes. Defining a hypothetical ``erf(UnitFloat16)`` loop
+must not lead to ``erf(float16)``.
+In general a promoter should fulfill the following requirements:
+
+* Be conservative when defining a new promotion rule. An incorrect result
+ is a much more dangerous error than an unexpected error.
+* One of the (abstract) DTypes added should typically match specifically with a
+ DType (or family of DTypes) defined by your project.
+ Never add promotion rules which go beyond normal common DType rules!
+ It is *not* reasonable to add a loop for ``int16 + uint16 -> int24`` if
+ you write an ``int24`` dtype. The result of this operation was already
+ defined previously as ``int32`` and will be used with this assumption.
+* A promoter (or loop) should never affect existing loop results.
+ This includes adding faster but less precise loops/promoters to replace
+ existing ones.
+* Try to stay within a clear, linear hierarchy for all promotion (and casting)
+ related logic. NumPy itself breaks this logic for integers and floats
+ (they are not strictly linear, since int64 cannot promote to float32).
+* Loops and promoters can be added by any project, which could be:
+
+ * The project defining the ufunc
+ * The project defining the DType
+ * A third-party project
+
+ Try to find out which is the best project to add the loop. If neither
+ the project defining the ufunc nor the project defining the DType add the
+ loop, issues with multiple definitions (which are rejected) may arise
+ and care should be taken that the loop behaviour is always more desirable
+ than an error.
+
+In some cases exceptions to these rules may make sense, however, in general
+we ask you to use extreme caution and when in doubt create a new UFunc
+instead. This clearly notifies the users of differing rules.
+When in doubt, ask on the NumPy mailing list or issue tracker!
+
+
+**************
+Implementation
+**************
+
+Implementation of this NEP will entail a large refactor and restructuring
+of the current ufunc machinery (as well as casting).
+
+The implementation unfortunately will require large maintenance of the
+UFunc machinery, since both the actual UFunc loop calls, as well as the
+the initial dispatching steps have to be modified.
+
+In general, the correct ``ArrayMethod``, also those returned by a promoter,
+will be cached (or stored) inside a hashtable for efficient lookup.
+
+
+**********
+Discussion
+**********
+
+There is a large space of possible implementations with many discussions
+in various places, as well as initial thoughts and design documents.
+These are listed in the discussion of :ref:`NEP 40 <NEP40>` and not repeated here for
+brevity.
+
+A long discussion which touches many of these points and points towards
+similar solutions can be found in
+`the github issue 12518 "What should be the calling convention for ufunc inner loop signatures?" <https://github.com/numpy/numpy/issues/12518>`_
+
+
+**********
+References
+**********
+
+Please see NEP 40 and 41 for more discussion and references.
+
+
+*********
+Copyright
+*********
+
+This document has been placed in the public domain.
+.. _NEP44:
+
===================================================
NEP 44 — Restructuring the NumPy Documentation
===================================================
--- /dev/null
+.. _NEP45:
+
+=================================
+NEP 45 — C Style Guide
+=================================
+
+:Author: Charles Harris <charlesr.harris@gmail.com>
+:Status: Accepted
+:Type: Process
+:Created: 2012-02-26
+:Resolution: https://github.com/numpy/numpy/issues/11911
+
+.. highlight:: c
+
+Abstract
+--------
+
+This document gives coding conventions for the C code comprising
+the C implementation of NumPy.
+
+Motivation and Scope
+--------------------
+
+The NumPy C coding conventions are based on Python
+`PEP 7 -- Style Guide for C Code <https://www.python.org/dev/peps/pep-0007>`_
+by Guido van Rossum with a few added strictures.
+
+Because the NumPy conventions are very close to those in PEP 7, that PEP is
+used as a template with the NumPy additions and variations in the appropriate
+spots.
+
+Usage and Impact
+----------------
+
+There are many C coding conventions and it must be emphasized that the primary
+goal of the NumPy conventions isn't to choose the "best," about which there is
+certain to be disagreement, but to achieve uniformity.
+
+Two good reasons to break a particular rule:
+
+1. When applying the rule would make the code less readable, even
+ for someone who is used to reading code that follows the rules.
+
+2. To be consistent with surrounding code that also breaks it
+ (maybe for historic reasons) -- although this is also an
+ opportunity to clean up someone else's mess.
+
+
+Backward compatibility
+----------------------
+
+No impact.
+
+
+Detailed description
+--------------------
+
+C dialect
+=========
+
+* Use C99 (that is, the standard defined by ISO/IEC 9899:1999).
+
+* Don't use GCC extensions (for instance, don't write multi-line strings
+ without trailing backslashes). Preferably break long strings
+ up onto separate lines like so::
+
+ "blah blah"
+ "blah blah"
+
+ This will work with MSVC, which otherwise chokes on very long
+ strings.
+
+* All function declarations and definitions must use full prototypes (that is,
+ specify the types of all arguments).
+
+* No compiler warnings with major compilers (gcc, VC++, a few others).
+
+.. note::
+ NumPy still produces compiler warnings that need to be addressed.
+
+Code layout
+============
+
+* Use 4-space indents and no tabs at all.
+
+* No line should be longer than 80 characters. If this and the
+ previous rule together don't give you enough room to code, your code is
+ too complicated -- consider using subroutines.
+
+* No line should end in whitespace. If you think you need
+ significant trailing whitespace, think again; somebody's editor might
+ delete it as a matter of routine.
+
+* Function definition style: function name in column 1, outermost
+ curly braces in column 1, blank line after local variable declarations::
+
+ static int
+ extra_ivars(PyTypeObject *type, PyTypeObject *base)
+ {
+ int t_size = PyType_BASICSIZE(type);
+ int b_size = PyType_BASICSIZE(base);
+
+ assert(t_size >= b_size); /* type smaller than base! */
+ ...
+ return 1;
+ }
+
+ If the transition to C++ goes through it is possible that this form will
+ be relaxed so that short class methods meant to be inlined can have the
+ return type on the same line as the function name. However, that is yet to
+ be determined.
+
+* Code structure: one space between keywords like ``if``, ``for`` and
+ the following left parenthesis; no spaces inside the parenthesis; braces
+ around all ``if`` branches, and no statements on the same line as the
+ ``if``. They should be formatted as shown::
+
+ if (mro != NULL) {
+ one_line_statement;
+ }
+ else {
+ ...
+ }
+
+
+ for (i = 0; i < n; i++) {
+ one_line_statement;
+ }
+
+
+ while (isstuff) {
+ dostuff;
+ }
+
+
+ do {
+ stuff;
+ } while (isstuff);
+
+
+ switch (kind) {
+ /* Boolean kind */
+ case 'b':
+ return 0;
+ /* Unsigned int kind */
+ case 'u':
+ ...
+ /* Anything else */
+ default:
+ return 3;
+ }
+
+
+* The return statement should *not* get redundant parentheses::
+
+ return Py_None; /* correct */
+ return(Py_None); /* incorrect */
+
+* Function and macro call style: ``foo(a, b, c)``, no space before
+ the open paren, no spaces inside the parens, no spaces before
+ commas, one space after each comma.
+
+* Always put spaces around the assignment, Boolean, and comparison
+ operators. In expressions using a lot of operators, add spaces
+ around the outermost (lowest priority) operators.
+
+* Breaking long lines: If you can, break after commas in the
+ outermost argument list. Always indent continuation lines
+ appropriately: ::
+
+ PyErr_SetString(PyExc_TypeError,
+ "Oh dear, you messed up.");
+
+ Here appropriately means at least a double indent (8 spaces). It isn't
+ necessary to line everything up with the opening parenthesis of the function
+ call.
+
+* When you break a long expression at a binary operator, the
+ operator goes at the end of the previous line, for example: ::
+
+ if (type > tp_dictoffset != 0 &&
+ base > tp_dictoffset == 0 &&
+ type > tp_dictoffset == b_size &&
+ (size_t)t_size == b_size + sizeof(PyObject *)) {
+ return 0;
+ }
+
+ Note that the terms in the multi-line Boolean expression are indented so
+ as to make the beginning of the code block clearly visible.
+
+* Put blank lines around functions, structure definitions, and
+ major sections inside functions.
+
+* Comments go before the code they describe. Multi-line comments should
+ be like so: ::
+
+ /*
+ * This would be a long
+ * explanatory comment.
+ */
+
+ Trailing comments should be used sparingly. Instead of ::
+
+ if (yes) { // Success!
+
+ do ::
+
+ if (yes) {
+ // Success!
+
+* All functions and global variables should be declared static
+ when they aren't needed outside the current compilation unit.
+
+* Declare external functions and variables in a header file.
+
+
+Naming conventions
+==================
+
+* There has been no consistent prefix for NumPy public functions, but
+ they all begin with a prefix of some sort, followed by an underscore, and
+ are in camel case: ``PyArray_DescrAlignConverter``, ``NpyIter_GetIterNext``.
+ In the future the names should be of the form ``Npy*_PublicFunction``,
+ where the star is something appropriate.
+
+* Public Macros should have a ``NPY_`` prefix and then use upper case,
+ for example, ``NPY_DOUBLE``.
+
+* Private functions should be lower case with underscores, for example:
+ ``array_real_get``. Single leading underscores should not be used, but
+ some current function names violate that rule due to historical accident.
+
+.. note::
+
+ Functions whose names begin with a single underscore should be renamed at
+ some point.
+
+
+Function documentation
+======================
+
+NumPy doesn't have a C function documentation standard at this time, but
+needs one. Most NumPy functions are not documented in the code, and that
+should change. One possibility is Doxygen with a plugin so that the same
+NumPy style used for Python functions can also be used for documenting
+C functions, see the files in ``doc/cdoc/``.
+
+
+Related Work
+------------
+
+Based on Van Rossum and Warsaw, :pep:`7`
+
+
+Discussion
+----------
+
+https://github.com/numpy/numpy/issues/11911
+recommended that this proposal, which originated as ``doc/C_STYLE_GUIDE.rst.txt``,
+be turned into an NEP.
+
+
+Copyright
+---------
+
+This document has been placed in the public domain.
in. It may be used to encourage and inspire developers and to search for
funding.
+
Interoperability
----------------
may include (among other things) interoperability protocols, better duck typing
support and ndarray subclass handling.
-- The ``__array_function__`` protocol is currently experimental and needs to be
- matured. See `NEP 18`_ for details.
-- New protocols for overriding other functionality in NumPy may be needed.
-- Array duck typing, or handling "duck arrays", needs improvements. See
- `NEP 22`_ for details.
+The ``__array_ufunc__`` and ``__array_function__`` protocols are stable, but
+do not cover the whole API. New protocols for overriding other functionality
+in NumPy are needed. Work in this area aims to bring to completion one or more
+of the following proposals:
+
+- :ref:`NEP30`
+- :ref:`NEP31`
+- :ref:`NEP35`
+- :ref:`NEP37`
+
+In addition we aim to provide ways to make it easier for other libraries to
+implement a NumPy-compatible API. This may include defining consistent subsets
+of the API, as discussed in `this section of NEP 37
+<https://numpy.org/neps/nep-0037-array-module.html#requesting-restricted-subsets-of-numpy-s-api>`__.
+
Extensibility
-------------
- One of these should probably be the default for text data. The current
behavior on Python 3 is neither efficient nor user friendly.
-- ``np.dtype(int)`` should not be platform dependent
-- Better coercion for string + number
Performance
-----------
-We want to further improve NumPy's performance, through:
+Improvements to NumPy's performance are important to many users. The primary
+topic at the moment is better use of SIMD instructions, also on platforms other
+than x86 - see :ref:`NEP38`.
+
+Other performance improvement ideas include:
-- Better use of SIMD instructions, also on platforms other than x86.
-- Reducing ufunc overhead.
+- Reducing ufunc and ``__array_function__`` overhead.
- Optimizations in individual functions.
+- A better story around parallel execution.
Furthermore we would like to improve the benchmarking system, in terms of coverage,
easy of use, and publication of the results (now
`here <https://pv.github.io/numpy-bench>`__) as part of the docs or website.
+
Website and documentation
-------------------------
-Our website (https://numpy.org) is in very poor shape and needs to be rewritten
-completely.
-
-The NumPy `documentation <https://www.numpy.org/devdocs/user/index.html>`__ is
-of varying quality - in particular the User Guide needs major improvements.
+The NumPy `documentation <https://www.numpy.org/devdocs>`__ is of varying
+quality. The API documentation is in good shape; tutorials and high-level
+documentation on many topics are missing or outdated. See :ref:`NEP44` for
+planned improvements.
-Random number generation policy & rewrite
------------------------------------------
+Our website (https://numpy.org) was completely redesigned recently. We aim to
+further improve it by adding translations, better Hugo-Sphinx integration via a
+new Sphinx theme, and more (see `this tracking issue <https://github.com/numpy/numpy.org/issues/266>`__).
-A new random number generation framework with higher performance generators is
-close to completion, see `NEP 19`_ and `PR 13163`_.
-Indexing
---------
+User experience
+---------------
-We intend to add new indexing modes for "vectorized indexing" and "outer indexing",
-see `NEP 21`_.
+Type annotations
+````````````````
+We aim to add type annotations for all NumPy functionality, so users can use
+tools like `mypy`_ to type check their code and IDEs can improve their support
+for NumPy. The existing type stubs in the `numpy-stubs`_ repository are being
+improved and will be moved into the NumPy code base.
-Continuous Integration
-----------------------
+Platform support
+````````````````
+We aim to increase our support for different hardware architectures. This
+includes adding CI coverage when CI services are available, providing wheels on
+PyPI for ARM64 (``aarch64``) and POWER8/9 (``ppc64le``), providing better
+build and install documentation, and resolving build issues on other platforms
+like AIX.
-We depend on CI to discover problems as we continue to develop NumPy before the
-code reaches downstream users.
-- CI for more exotic platforms (if available as a service).
-- Multi-package testing
-- Add an official channel for numpy dev builds for CI usage by other projects so
- they may confirm new builds do not break their package.
-
-Other functionality
--------------------
+Maintenance
+-----------
- ``MaskedArray`` needs to be improved, ideas include:
- MaskedArray as a duck-array type, and/or
- dtypes that support missing values
-- A backend system for ``numpy.fft`` (so that e.g. ``fft-mkl`` doesn't need to monkeypatch numpy)
-- Write a strategy on how to deal with overlap between NumPy and SciPy for ``linalg``
- and ``fft`` (and implement it).
-- Deprecate ``np.matrix`` (very slowly)
+- Fortran integration via ``numpy.f2py`` requires a number of improvements, see
+ `this tracking issue <https://github.com/numpy/numpy/issues/14938>`__.
+- A backend system for ``numpy.fft`` (so that e.g. ``fft-mkl`` doesn't need to monkeypatch numpy).
+- Write a strategy on how to deal with overlap between NumPy and SciPy for ``linalg``.
+- Deprecate ``np.matrix`` (very slowly).
+- Add new indexing modes for "vectorized indexing" and "outer indexing" (see :ref:`NEP21`).
+- Make the polynomial API easier to use.
+- Integrate an improved text file loader.
+- Ufunc and gufunc improvements, see `gh-8892 <https://github.com/numpy/numpy/issues/8892>`__
+ and `gh-11492 <https://github.com/numpy/numpy/issues/11492>`__.
-.. _`NEP 19`: https://www.numpy.org/neps/nep-0019-rng-policy.html
-.. _`NEP 22`: http://www.numpy.org/neps/nep-0022-ndarray-duck-typing-overview.html
-.. _`NEP 18`: https://www.numpy.org/neps/nep-0018-array-function-protocol.html
-.. _implementation: https://gist.github.com/shoyer/1f0a308a06cd96df20879a1ddb8f0006
-.. _`reference implementation`: https://github.com/bashtage/randomgen
-.. _`NEP 21`: https://www.numpy.org/neps/nep-0021-advanced-indexing.html
-.. _`PR 13163`: https://github.com/numpy/numpy/pull/13163
+.. _`mypy`: https://mypy.readthedocs.io
+.. _`numpy-stubs`: https://github.com/numpy/numpy-stubs
meta_re = r':([a-zA-Z\-]*): (.*)'
+ has_provisional = False
neps = {}
print('Loading metadata for:')
for source in sources:
f'NEP {nr} is Accepted/Rejected/Withdrawn but '
'has no Resolution tag'
)
+ if tags['Status'] == 'Provisional':
+ has_provisional = True
neps[nr] = tags
f'been set to Superseded'
)
- return {'neps': neps}
+ return {'neps': neps, 'has_provisional': has_provisional}
infile = 'index.rst.tmpl'
backwards compatible. (Not to be used for removal of deprecated features.)
* ``c_api``: Changes in the Numpy C-API exported functions
* ``new_feature``: New user facing features like ``kwargs``.
-* ``improvement``: Performance and edge-case changes
+* ``improvement``: General improvements and edge-case changes which are
+ not new features or compatibility related.
+* ``performance``: Performance changes that should not affect other behaviour.
* ``change``: Other changes
* ``highlight``: Adds a highlight bullet point to use as a possibly highlight
of the release.
+It is possible to add two files with different categories (and text) if both
+are relevant. For example a change may improve performance but have some
+compatibility concerns.
+
Most categories should be formatted as paragraphs with a heading.
So for example: ``123.new_feature.rst`` would have the content::
--- /dev/null
+@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&display=swap');
+
+.navbar-brand img {
+ height: 75px;
+}
+.navbar-brand {
+ height: 75px;
+}
+
+body {
+ font-family: 'Open Sans', sans-serif;
+ color:#4A4A4A; /* numpy.org body color */
+}
+
+pre, code {
+ font-size: 100%;
+ line-height: 155%;
+}
+
+h1 {
+ font-style: "Lato", sans-serif;
+ color: #013243; /* warm black */
+ font-weight: 700;
+ letter-spacing: -.04em;
+ text-align: right;
+ margin-top: 3rem;
+ margin-bottom: 4rem;
+ font-size: 3rem;
+}
+
+
+h2 {
+ color: #4d77cf; /* han blue */
+ letter-spacing: -.03em;
+}
+
+h3 {
+ color: #013243; /* warm black */
+ letter-spacing: -.03em;
+}
--- /dev/null
+<?xml version="1.0" standalone="no"?>\r
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\r
+<!--Generator: Xara Designer (www.xara.com), SVG filter version: 6.4.0.3-->\r
+<svg fill="none" fill-rule="evenodd" stroke="black" stroke-width="0.501" stroke-linejoin="bevel" stroke-miterlimit="10" font-family="Times New Roman" font-size="16" style="font-variant-ligatures:none" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" overflow="visible" width="255.845pt" height="123.322pt" viewBox="0 -123.322 255.845 123.322">\r
+ <defs>\r
+ </defs>\r
+ <g id="Layer 1" transform="scale(1 -1)">\r
+ <path d="M 107.188,79.018 C 107.386,78.994 107.58,78.94 107.762,78.859 C 107.941,78.774 108.106,78.663 108.252,78.529 C 108.44,78.349 108.616,78.158 108.78,77.955 L 123.492,59.358 C 123.432,59.95 123.393,60.531 123.364,61.088 C 123.336,61.644 123.322,62.176 123.322,62.672 L 123.322,79.079 L 129.655,79.079 L 129.655,48.109 L 125.913,48.109 C 125.433,48.095 124.956,48.182 124.513,48.364 C 124.073,48.581 123.693,48.902 123.407,49.3 L 108.801,67.73 C 108.847,67.195 108.879,66.667 108.907,66.149 C 108.936,65.632 108.953,65.146 108.953,64.692 L 108.953,48.091 L 102.616,48.091 L 102.616,79.079 L 106.398,79.079 C 106.662,79.076 106.926,79.056 107.188,79.018 Z" fill="#013243" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 138.934,70.158 L 138.934,56.172 C 138.934,55.08 139.182,54.237 139.679,53.641 C 140.233,53.023 141.04,52.693 141.869,52.748 C 142.571,52.744 143.265,52.896 143.9,53.195 C 144.571,53.52 145.191,53.943 145.739,54.45 L 145.739,70.158 L 152.328,70.158 L 152.328,48.116 L 148.249,48.116 C 147.515,48.055 146.839,48.516 146.629,49.222 L 146.228,50.498 C 145.814,50.096 145.373,49.722 144.91,49.378 C 144.455,49.046 143.966,48.763 143.453,48.531 C 142.913,48.287 142.349,48.099 141.77,47.971 C 141.128,47.831 140.473,47.763 139.817,47.769 C 138.721,47.749 137.634,47.962 136.627,48.396 C 135.723,48.797 134.92,49.395 134.277,50.147 C 133.624,50.928 133.132,51.832 132.831,52.805 C 132.495,53.893 132.33,55.026 132.342,56.165 L 132.342,70.158 Z" fill="#013243" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 156.578,48.109 L 156.578,70.158 L 160.661,70.158 C 161.024,70.171 161.384,70.075 161.692,69.881 C 161.978,69.682 162.185,69.388 162.277,69.052 L 162.631,67.861 C 162.989,68.24 163.371,68.596 163.776,68.924 C 164.175,69.245 164.606,69.522 165.063,69.754 C 166.067,70.263 167.18,70.522 168.306,70.509 C 169.494,70.555 170.661,70.191 171.612,69.477 C 172.508,68.755 173.194,67.805 173.597,66.727 C 173.947,67.379 174.403,67.969 174.948,68.471 C 175.463,68.94 176.043,69.333 176.67,69.637 C 177.291,69.936 177.947,70.157 178.623,70.296 C 179.299,70.437 179.988,70.508 180.679,70.509 C 181.822,70.528 182.96,70.337 184.035,69.945 C 184.97,69.598 185.811,69.037 186.491,68.308 C 187.174,67.546 187.685,66.647 187.99,65.671 C 188.347,64.524 188.519,63.327 188.501,62.126 L 188.501,48.119 L 181.908,48.119 L 181.908,62.116 C 181.908,64.398 180.931,65.538 178.977,65.536 C 178.146,65.563 177.341,65.243 176.755,64.653 C 176.167,64.07 175.873,63.224 175.873,62.116 L 175.873,48.109 L 169.291,48.109 L 169.291,62.116 C 169.291,63.378 169.043,64.264 168.547,64.774 C 168.05,65.284 167.32,65.536 166.356,65.536 C 165.769,65.537 165.19,65.4 164.666,65.135 C 164.115,64.85 163.61,64.484 163.166,64.051 L 163.166,48.102 Z" fill="#013243" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 199.516,58.462 L 199.516,48.109 L 192.332,48.109 L 192.332,79.079 L 203.255,79.079 C 205.159,79.121 207.058,78.861 208.88,78.309 C 210.302,77.874 211.618,77.15 212.747,76.183 C 213.741,75.307 214.51,74.206 214.991,72.972 C 215.476,71.697 215.716,70.342 215.699,68.977 C 215.716,67.526 215.464,66.084 214.955,64.724 C 214.472,63.453 213.692,62.316 212.68,61.407 C 211.553,60.424 210.232,59.69 208.802,59.252 C 207.007,58.695 205.135,58.429 203.255,58.462 Z M 199.516,63.881 L 203.255,63.881 C 205.127,63.881 206.474,64.324 207.296,65.221 C 208.118,66.117 208.529,67.347 208.529,68.96 C 208.538,69.619 208.43,70.274 208.21,70.895 C 208.007,71.462 207.676,71.975 207.243,72.394 C 206.774,72.832 206.215,73.162 205.605,73.362 C 204.847,73.607 204.053,73.726 203.255,73.716 L 199.516,73.716 Z" fill="#013243" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 228.466,42.388 C 228.316,42.012 228.072,41.68 227.757,41.424 C 227.345,41.186 226.87,41.078 226.396,41.116 L 221.452,41.116 L 225.705,50.04 L 216.908,70.158 L 222.731,70.158 C 223.157,70.179 223.577,70.054 223.922,69.803 C 224.192,69.595 224.398,69.315 224.517,68.995 L 228.129,59.493 C 228.463,58.637 228.74,57.759 228.958,56.867 C 229.1,57.32 229.256,57.767 229.426,58.203 C 229.596,58.639 229.759,59.089 229.915,59.543 L 233.19,69.002 C 233.314,69.343 233.55,69.632 233.86,69.821 C 234.174,70.034 234.544,70.148 234.923,70.151 L 240.24,70.151 Z" fill="#013243" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 46.918,89.155 L 33.759,95.797 L 19.312,88.588 L 32.83,81.801 L 46.918,89.155 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 52.954,86.11 L 66.752,79.142 L 52.437,71.955 L 38.898,78.752 L 52.954,86.11 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 71.384,95.698 L 85.561,88.588 L 72.88,82.222 L 59.054,89.197 L 71.384,95.698 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 65.281,98.76 L 52.518,105.161 L 39.894,98.859 L 53.046,92.228 L 65.281,98.76 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 55.304,43.803 L 55.304,26.386 L 70.764,34.102 L 70.75,51.526 L 55.304,43.803 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 70.743,57.607 L 70.725,74.847 L 55.304,67.18 L 55.304,49.934 L 70.743,57.607 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 89.304,60.836 L 89.304,43.352 L 76.116,36.774 L 76.105,54.177 L 89.304,60.836 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 89.304,66.95 L 89.304,84.083 L 76.091,77.516 L 76.102,60.241 L 89.304,66.95 Z" fill="#4dabcf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ <path d="M 49.846,67.18 L 39.433,72.419 L 39.433,49.792 C 39.433,49.792 26.695,76.892 25.518,79.327 C 25.366,79.642 24.742,79.986 24.582,80.071 C 22.286,81.269 15.594,84.657 15.594,84.657 L 15.594,44.667 L 24.852,39.705 L 24.852,60.617 C 24.852,60.617 37.452,36.402 37.583,36.136 C 37.714,35.871 38.972,33.322 40.326,32.426 C 42.123,31.231 49.839,26.592 49.839,26.592 Z" fill="#4d77cf" stroke="none" stroke-width="0.354" fill-rule="nonzero" stroke-linejoin="miter" marker-start="none" marker-end="none"/>\r
+ </g>\r
+</svg>\r
attribute
-.. auto{{ objtype }}:: {{ objname }}
+.. auto{{ objtype }}:: {{ fullname | replace("numpy.", "numpy::") }}
+{# In the fullname (e.g. `numpy.ma.MaskedArray.methodname`), the module name
+is ambiguous. Using a `::` separator (e.g. `numpy::ma.MaskedArray.methodname`)
+specifies `numpy` as the module name. #}
property
{% endif %}
-.. auto{{ objtype }}:: {{ objname }}
+.. auto{{ objtype }}:: {{ fullname | replace("numpy.", "numpy::") }}
+{# In the fullname (e.g. `numpy.ma.MaskedArray.methodname`), the module name
+is ambiguous. Using a `::` separator (e.g. `numpy::ma.MaskedArray.methodname`)
+specifies `numpy` as the module name. #}
member
-.. auto{{ objtype }}:: {{ objname }}
-
+.. auto{{ objtype }}:: {{ fullname | replace("numpy.", "numpy::") }}
+{# In the fullname (e.g. `numpy.ma.MaskedArray.methodname`), the module name
+is ambiguous. Using a `::` separator (e.g. `numpy::ma.MaskedArray.methodname`)
+specifies `numpy` as the module name. #}
method
-.. auto{{ objtype }}:: {{ objname }}
+.. auto{{ objtype }}:: {{ fullname | replace("numpy.", "numpy::") }}
+{# In the fullname (e.g. `numpy.ma.MaskedArray.methodname`), the module name
+is ambiguous. Using a `::` separator (e.g. `numpy::ma.MaskedArray.methodname`)
+specifies `numpy` as the module name. #}
+++ /dev/null
-{#
- basic/defindex.html
- ~~~~~~~~~~~~~~~~~~~
-
- Default template for the "index" page.
-
- :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{%- extends "layout.html" %}
-{% set title = _('Overview') %}
-{% block body %}
- <h1>{{ docstitle|e }}</h1>
- <p>
- {{ _('Welcome! This is') }}
- {% block description %}{{ _('the documentation for') }} {{ project|e }}
- {{ release|e }}{% if last_updated %}, {{ _('last updated') }} {{ last_updated|e }}{% endif %}{% endblock %}.
- </p>
- {% block tables %}
- <p><strong>{{ _('Indices and tables:') }}</strong></p>
- <table class="contentstable"><tr>
- <td style="width: 50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">{{ _('Complete Table of Contents') }}</a><br>
- <span class="linkdescr">{{ _('lists all sections and subsections') }}</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">{{ _('Search Page') }}</a><br>
- <span class="linkdescr">{{ _('search this documentation') }}</span></p>
- </td><td style="width: 50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("modindex") }}">{{ _('Global Module Index') }}</a><br>
- <span class="linkdescr">{{ _('quick access to all modules') }}</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">{{ _('General Index') }}</a><br>
- <span class="linkdescr">{{ _('all functions, classes, terms') }}</span></p>
- </td></tr>
- </table>
- {% endblock %}
-{% endblock %}
-{% extends "defindex.html" %}
-{% block tables %}
+{#
+ Loosely inspired by the deprecated sphinx/themes/basic/defindex.html
+#}
+{%- extends "layout.html" %}
+{% set title = _('Overview') %}
+{% block body %}
+<h1>{{ docstitle|e }}</h1>
+<p>
+ Welcome! This is the documentation for NumPy {{ release|e }}
+ {% if last_updated %}, last updated {{ last_updated|e }}{% endif %}.
+</p>
<p><strong>For users:</strong></p>
<table class="contentstable" align="center"><tr>
<td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("user/setting-up") }}">Setting Up</a><br/>
- <span class="linkdescr">Learn about what NumPy is and how to install it</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("user/quickstart") }}">Quickstart Tutorial</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("user/whatisnumpy") }}">What is NumPy?</a><br/>
+ <span class="linkdescr">Who uses it and why</span></p>
+ <p class="biglink"><a class="biglink" href="https://numpy.org/install/">Installation</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("user/quickstart") }}">Quickstart</a><br/>
<span class="linkdescr">Aimed at domain experts or people migrating to NumPy</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("user/absolute_beginners") }}">Absolute Beginners Tutorial</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("user/absolute_beginners") }}">Absolute beginner's guide</a><br/>
<span class="linkdescr">Start here for an overview of NumPy features and syntax</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("user/tutorials_index") }}">Tutorials</a><br/>
<span class="linkdescr">Learn about concepts and submodules</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("user/howtos_index") }}">How Tos</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("user/howtos_index") }}">How-tos</a><br/>
<span class="linkdescr">How to do common tasks with NumPy</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("reference/index") }}">NumPy API Reference</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("reference/index") }}">NumPy API reference</a><br/>
<span class="linkdescr">Automatically generated reference documentation</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("user/explanations_index") }}">Explanations</a><br/>
<span class="linkdescr">In depth explanation of concepts, best practices and techniques</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("f2py/index") }}">F2Py Guide</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("f2py/index") }}">F2Py guide</a><br/>
<span class="linkdescr">Documentation for the f2py module (Fortran extensions for Python)</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("glossary") }}">Glossary</a><br/>
<span class="linkdescr">List of the most important terms</span></p>
<p><strong>For developers/contributors:</strong></p>
<table class="contentstable" align="center"><tr>
<td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("dev/index") }}">NumPy Contributor Guide</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("dev/index") }}">NumPy contributor guide</a><br/>
<span class="linkdescr">Contributing to NumPy</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("dev/underthehood") }}">Under-the-hood docs</a><br/>
<span class="linkdescr">Specialized, in-depth documentation</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("docs/index") }}">Building and Extending the Documentation</a><br/>
+ <p class="biglink"><a class="biglink" href="{{ pathto("docs/index") }}">Building and extending the documentation</a><br/>
<span class="linkdescr">How to contribute to this documentation (user and API)</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("docs/howto_document") }}">The numpydoc docstring guide</a><br/>
<span class="linkdescr">How to write docstrings in the numpydoc format</span></p>
<table class="contentstable" align="center"><tr>
<td width="50%">
<p class="biglink"><a class="biglink" href="{{ pathto("bugs") }}">Reporting bugs</a></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("release") }}">Release Notes</a></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("release") }}">Release notes</a></p>
</td><td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("about") }}">About NumPy</a></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("doc_conventions") }}">Document conventions</a></p>
<p class="biglink"><a class="biglink" href="{{ pathto("license") }}">License of NumPy</a></p>
</td></tr>
</table>
<p>
Large parts of this manual originate from Travis E. Oliphant's book
<a href="https://archive.org/details/NumPyBook">"Guide to NumPy"</a>
- (which generously entered Public Domain in August 2008). The reference
+ (which generously entered public domain in August 2008). The reference
documentation for many of the functions are written by numerous
contributors and developers of NumPy.
</p>
<p>
The preferred way to update the documentation is by submitting a pull
- request on Github (see the <a href="{{ pathto("docs/index") }}">Documentation Index</a>).
+ request on GitHub (see the <a href="{{ pathto("docs/index") }}">Documentation index</a>).
Please help us to further improve the NumPy documentation!
</p>
{% endblock %}
{% extends "!layout.html" %}
-{%- block header %}
-<div class="container">
- <div class="top-scipy-org-logo-header" style="background-color: #a2bae8;">
- <a href="{{ pathto('index') }}">
- <img border=0 alt="NumPy" src="{{ pathto('_static/numpy_logo.png', 1) }}"></a>
- </div>
- </div>
-</div>
+{%- block extrahead %}
+{{ super() }}
+<link rel="stylesheet" href="{{ pathto('_static/numpy.css', 1) }}" type="text/css" />
-{% endblock %}
-{% block rootrellink %}
- {% if pagename != 'index' %}
- <li class="active"><a href="{{ pathto('index') }}">{{ shorttitle|e }}</a></li>
- {% endif %}
-{% endblock %}
+ <!-- PR #17220: This is added via javascript in versionwarning.js -->
+ <!-- link rel="canonical" href="http://numpy.org/doc/stable/{{ pagename }}{{ file_suffix }}" / -->
-{% block sidebarsearch %}
-{%- if sourcename %}
-<ul class="this-page-menu">
-{%- if 'reference/generated' in sourcename %}
- <li><a href="/numpy/docs/{{ sourcename.replace('reference/generated/', '').replace('.txt', '') |e }}">{{_('Edit page')}}</a></li>
-{%- else %}
- <li><a href="/numpy/docs/numpy-docs/{{ sourcename.replace('.txt', '.rst') |e }}">{{_('Edit page')}}</a></li>
-{%- endif %}
-</ul>
-{%- endif %}
-{{ super() }}
{% endblock %}
+++ /dev/null
-About NumPy
-===========
-
-NumPy is the fundamental package
-needed for scientific computing with Python. This package contains:
-
-- a powerful N-dimensional :ref:`array object <arrays>`
-- sophisticated :ref:`(broadcasting) functions <ufuncs>`
-- basic :ref:`linear algebra functions <routines.linalg>`
-- basic :ref:`Fourier transforms <routines.fft>`
-- sophisticated :ref:`random number capabilities <numpyrandom>`
-- tools for integrating Fortran code
-- tools for integrating C/C++ code
-
-Besides its obvious scientific uses, *NumPy* can also be used as an
-efficient multi-dimensional container of generic data. Arbitrary
-data types can be defined. This allows *NumPy* to seamlessly and
-speedily integrate with a wide variety of databases.
-
-NumPy is a successor for two earlier scientific Python libraries:
-Numeric and Numarray.
-
-NumPy community
----------------
-
-NumPy is a distributed, volunteer, open-source project. *You* can help
-us make it better; if you believe something should be improved either
-in functionality or in documentation, don't hesitate to contact us --- or
-even better, contact us and participate in fixing the problem.
-
-Our main means of communication are:
-
-- `scipy.org website <https://scipy.org/>`__
-
-- `Mailing lists <https://scipy.org/scipylib/mailing-lists.html>`__
-
-- `NumPy Issues <https://github.com/numpy/numpy/issues>`__ (bug reports go here)
-
-- `Old NumPy Trac <http://projects.scipy.org/numpy>`__ (dead link)
-
-More information about the development of NumPy can be found at our `Developer Zone <https://scipy.scipy.org/scipylib/dev-zone.html>`__.
-
-The project management structure can be found at our :doc:`governance page <dev/governance/index>`
-
-
-About this documentation
-========================
-
-Conventions
------------
-
-Names of classes, objects, constants, etc. are given in **boldface** font.
-Often they are also links to a more detailed documentation of the
-referred object.
-
-This manual contains many examples of use, usually prefixed with the
-Python prompt ``>>>`` (which is not a part of the example code). The
-examples assume that you have first entered::
-
->>> import numpy as np
-
-before running the examples.
# Minimum version, enforced by sphinx
needs_sphinx = '2.2.0'
+
+# This is a nasty hack to use platform-agnostic names for types in the
+# documentation.
+
+# must be kept alive to hold the patched names
+_name_cache = {}
+
+def replace_scalar_type_names():
+ """ Rename numpy types to use the canonical names to make sphinx behave """
+ import ctypes
+
+ Py_ssize_t = ctypes.c_int64 if ctypes.sizeof(ctypes.c_void_p) == 8 else ctypes.c_int32
+
+ class PyObject(ctypes.Structure):
+ pass
+
+ class PyTypeObject(ctypes.Structure):
+ pass
+
+ PyObject._fields_ = [
+ ('ob_refcnt', Py_ssize_t),
+ ('ob_type', ctypes.POINTER(PyTypeObject)),
+ ]
+
+
+ PyTypeObject._fields_ = [
+ # varhead
+ ('ob_base', PyObject),
+ ('ob_size', Py_ssize_t),
+ # declaration
+ ('tp_name', ctypes.c_char_p),
+ ]
+
+ # prevent numpy attaching docstrings to the scalar types
+ assert 'numpy.core._add_newdocs_scalars' not in sys.modules
+ sys.modules['numpy.core._add_newdocs_scalars'] = object()
+
+ import numpy
+
+ # change the __name__ of the scalar types
+ for name in [
+ 'byte', 'short', 'intc', 'int_', 'longlong',
+ 'ubyte', 'ushort', 'uintc', 'uint', 'ulonglong',
+ 'half', 'single', 'double', 'longdouble',
+ 'half', 'csingle', 'cdouble', 'clongdouble',
+ ]:
+ typ = getattr(numpy, name)
+ c_typ = PyTypeObject.from_address(id(typ))
+ c_typ.tp_name = _name_cache[typ] = b"numpy." + name.encode('utf8')
+
+ # now generate the docstrings as usual
+ del sys.modules['numpy.core._add_newdocs_scalars']
+ import numpy.core._add_newdocs_scalars
+
+replace_scalar_type_names()
+
# -----------------------------------------------------------------------------
# General configuration
# -----------------------------------------------------------------------------
def setup(app):
# add a config value for `ifconfig` directives
app.add_config_value('python_version_major', str(sys.version_info.major), 'env')
- app.add_lexer('NumPyC', NumPyLexer(stripnl=False))
+ app.add_lexer('NumPyC', NumPyLexer)
# -----------------------------------------------------------------------------
# HTML output
# -----------------------------------------------------------------------------
-themedir = os.path.join(os.pardir, 'scipy-sphinx-theme', '_theme')
-if not os.path.isdir(themedir):
- raise RuntimeError("Get the scipy-sphinx-theme first, "
- "via git submodule init && git submodule update")
-
-html_theme = 'scipy'
-html_theme_path = [themedir]
-
-if 'scipyorg' in tags:
- # Build for the scipy.org website
- html_theme_options = {
- "edit_link": True,
- "sidebar": "right",
- "scipy_org_logo": True,
- "rootlinks": [("https://scipy.org/", "Scipy.org"),
- ("https://docs.scipy.org/", "Docs")]
- }
-else:
- # Default build
- html_theme_options = {
- "edit_link": False,
- "sidebar": "left",
- "scipy_org_logo": False,
- "rootlinks": [("https://numpy.org/", "NumPy.org"),
- ("https://numpy.org/doc", "Docs"),
- ]
- }
- html_sidebars = {'index': ['indexsidebar.html', 'searchbox.html']}
+html_theme = 'pydata_sphinx_theme'
+
+html_logo = '_static/numpylogo.svg'
+
+html_theme_options = {
+ "github_url": "https://github.com/numpy/numpy",
+ "twitter_url": "https://twitter.com/numpy_team",
+}
+
html_additional_pages = {
'index': 'indexcontent.html',
# Intersphinx configuration
# -----------------------------------------------------------------------------
intersphinx_mapping = {
+ 'neps': ('https://numpy.org/neps', None),
'python': ('https://docs.python.org/dev', None),
'scipy': ('https://docs.scipy.org/doc/scipy/reference', None),
'matplotlib': ('https://matplotlib.org', None),
'imageio': ('https://imageio.readthedocs.io/en/stable', None),
- 'skimage': ('https://scikit-image.org/docs/stable', None)
+ 'skimage': ('https://scikit-image.org/docs/stable', None),
+ 'pandas': ('https://pandas.pydata.org/pandas-docs/stable', None),
+ 'scipy-lecture-notes': ('https://scipy-lectures.org', None),
}
else:
print("NOTE: linkcode extension not found -- no links to source generated")
+
+def _get_c_source_file(obj):
+ if issubclass(obj, numpy.generic):
+ return r"core/src/multiarray/scalartypes.c.src"
+ elif obj is numpy.ndarray:
+ return r"core/src/multiarray/arrayobject.c"
+ else:
+ # todo: come up with a better way to generate these
+ return None
+
+
def linkcode_resolve(domain, info):
"""
Determine the URL corresponding to Python object
else:
obj = unwrap(obj)
- try:
- fn = inspect.getsourcefile(obj)
- except Exception:
- fn = None
- if not fn:
- return None
+ fn = None
+ lineno = None
- try:
- source, lineno = inspect.getsourcelines(obj)
- except Exception:
- lineno = None
+ # Make a poor effort at linking C extension types
+ if isinstance(obj, type) and obj.__module__ == 'numpy':
+ fn = _get_c_source_file(obj)
+
+ if fn is None:
+ try:
+ fn = inspect.getsourcefile(obj)
+ except Exception:
+ fn = None
+ if not fn:
+ return None
+
+ try:
+ source, lineno = inspect.getsourcelines(obj)
+ except Exception:
+ lineno = None
+
+ fn = relpath(fn, start=dirname(numpy.__file__))
if lineno:
linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1)
else:
linespec = ""
- fn = relpath(fn, start=dirname(numpy.__file__))
-
if 'dev' in numpy.__version__:
return "https://github.com/numpy/numpy/blob/master/numpy/%s%s" % (
fn, linespec)
numpy.__version__, fn, linespec)
from pygments.lexers import CLexer
-import copy
+from pygments.lexer import inherit, bygroups
+from pygments.token import Comment
class NumPyLexer(CLexer):
name = 'NUMPYLEXER'
- tokens = copy.deepcopy(CLexer.tokens)
- # Extend the regex for valid identifiers with @
- for k, val in tokens.items():
- for i, v in enumerate(val):
- if isinstance(v, tuple):
- if isinstance(v[0], str):
- val[i] = (v[0].replace('a-zA-Z', 'a-zA-Z@'),) + v[1:]
+ tokens = {
+ 'statements': [
+ (r'@[a-zA-Z_]*@', Comment.Preproc, 'macro'),
+ inherit,
+ ],
+ }
###################
.. toctree::
+ :maxdepth: 1
- user/setting-up
- user/quickstart
- user/absolute_beginners
- user/tutorials_index
- user/howtos_index
- reference/index
- user/explanations_index
- f2py/index
- glossary
- dev/index
- dev/underthehood
- docs/index
- docs/howto_document
- benchmarking
- bugs
- release
- about
- license
+ User Guide <user/index>
+ API reference <reference/index>
+ Development <dev/index>
+.. This is not really the index page, that is found in
+ _templates/indexcontent.html The toctree content here will be added to the
+ top of the template header
+++ /dev/null
-NumPy Code of Conduct
-=====================
-
-
-Introduction
-------------
-
-This code of conduct applies to all spaces managed by the NumPy project,
-including all public and private mailing lists, issue trackers, wikis, blogs,
-Twitter, and any other communication channel used by our community. The NumPy
-project does not organise in-person events, however events related to our
-community should have a code of conduct similar in spirit to this one.
-
-This code of conduct should be honored by everyone who participates in
-the NumPy community formally or informally, or claims any affiliation with the
-project, in any project-related activities and especially when representing the
-project, in any role.
-
-This code is not exhaustive or complete. It serves to distill our common
-understanding of a collaborative, shared environment and goals. Please try to
-follow this code in spirit as much as in letter, to create a friendly and
-productive environment that enriches the surrounding community.
-
-
-Specific Guidelines
--------------------
-
-We strive to:
-
-1. Be open. We invite anyone to participate in our community. We prefer to use
- public methods of communication for project-related messages, unless
- discussing something sensitive. This applies to messages for help or
- project-related support, too; not only is a public support request much more
- likely to result in an answer to a question, it also ensures that any
- inadvertent mistakes in answering are more easily detected and corrected.
-
-2. Be empathetic, welcoming, friendly, and patient. We work together to resolve
- conflict, and assume good intentions. We may all experience some frustration
- from time to time, but we do not allow frustration to turn into a personal
- attack. A community where people feel uncomfortable or threatened is not a
- productive one.
-
-3. Be collaborative. Our work will be used by other people, and in turn we will
- depend on the work of others. When we make something for the benefit of the
- project, we are willing to explain to others how it works, so that they can
- build on the work to make it even better. Any decision we make will affect
- users and colleagues, and we take those consequences seriously when making
- decisions.
-
-4. Be inquisitive. Nobody knows everything! Asking questions early avoids many
- problems later, so we encourage questions, although we may direct them to
- the appropriate forum. We will try hard to be responsive and helpful.
-
-5. Be careful in the words that we choose. We are careful and respectful in
- our communication and we take responsibility for our own speech. Be kind to
- others. Do not insult or put down other participants. We will not accept
- harassment or other exclusionary behaviour, such as:
-
- - Violent threats or language directed against another person.
- - Sexist, racist, or otherwise discriminatory jokes and language.
- - Posting sexually explicit or violent material.
- - Posting (or threatening to post) other people's personally identifying information ("doxing").
- - Sharing private content, such as emails sent privately or non-publicly,
- or unlogged forums such as IRC channel history, without the sender's consent.
- - Personal insults, especially those using racist or sexist terms.
- - Unwelcome sexual attention.
- - Excessive profanity. Please avoid swearwords; people differ greatly in their sensitivity to swearing.
- - Repeated harassment of others. In general, if someone asks you to stop, then stop.
- - Advocating for, or encouraging, any of the above behaviour.
-
-
-Diversity Statement
--------------------
-
-The NumPy project welcomes and encourages participation by everyone. We are
-committed to being a community that everyone enjoys being part of. Although
-we may not always be able to accommodate each individual's preferences, we try
-our best to treat everyone kindly.
-
-No matter how you identify yourself or how others perceive you: we welcome you.
-Though no list can hope to be comprehensive, we explicitly honour diversity in:
-age, culture, ethnicity, genotype, gender identity or expression, language,
-national origin, neurotype, phenotype, political beliefs, profession, race,
-religion, sexual orientation, socioeconomic status, subculture and technical
-ability, to the extent that these do not conflict with this code of conduct.
-
-
-Though we welcome people fluent in all languages, NumPy development is
-conducted in English.
-
-Standards for behaviour in the NumPy community are detailed in the Code of
-Conduct above. Participants in our community should uphold these standards
-in all their interactions and help others to do so as well (see next section).
-
-
-Reporting Guidelines
---------------------
-
-We know that it is painfully common for internet communication to start at or
-devolve into obvious and flagrant abuse. We also recognize that sometimes
-people may have a bad day, or be unaware of some of the guidelines in this Code
-of Conduct. Please keep this in mind when deciding on how to respond to a
-breach of this Code.
-
-For clearly intentional breaches, report those to the Code of Conduct committee
-(see below). For possibly unintentional breaches, you may reply to the person
-and point out this code of conduct (either in public or in private, whatever is
-most appropriate). If you would prefer not to do that, please feel free to
-report to the Code of Conduct Committee directly, or ask the Committee for
-advice, in confidence.
-
-You can report issues to the NumPy Code of Conduct committee, at
-numpy-conduct@googlegroups.com. Currently, the committee consists of:
-
-- Stefan van der Walt
-- Melissa Weber Mendonça
-- Anirudh Subramanian
-
-If your report involves any members of the committee, or if they feel they have
-a conflict of interest in handling it, then they will recuse themselves from
-considering your report. Alternatively, if for any reason you feel
-uncomfortable making a report to the committee, then you can also contact:
-
-- Senior `NumFOCUS staff <https://numfocus.org/code-of-conduct#persons-responsible>`__: conduct@numfocus.org
-
-
-Incident reporting resolution & Code of Conduct enforcement
------------------------------------------------------------
-
-*This section summarizes the most important points, more details can be found
-in* :ref:`CoC_reporting_manual`.
-
-We will investigate and respond to all complaints. The NumPy Code of Conduct
-Committee and the NumPy Steering Committee (if involved) will protect the
-identity of the reporter, and treat the content of complaints as confidential
-(unless the reporter agrees otherwise).
-
-In case of severe and obvious breaches, e.g. personal threat or violent, sexist
-or racist language, we will immediately disconnect the originator from NumPy
-communication channels; please see the manual for details.
-
-In cases not involving clear severe and obvious breaches of this code of
-conduct, the process for acting on any received code of conduct violation
-report will be:
-
-1. acknowledge report is received
-2. reasonable discussion/feedback
-3. mediation (if feedback didn't help, and only if both reporter and reportee agree to this)
-4. enforcement via transparent decision (see :ref:`CoC_resolutions`) by the
- Code of Conduct Committee
-
-The committee will respond to any report as soon as possible, and at most
-within 72 hours.
-
-
-Endnotes
---------
-
-We are thankful to the groups behind the following documents, from which we
-drew content and inspiration:
-
-- `The SciPy Code of Conduct <https://docs.scipy.org/doc/scipy/reference/dev/conduct/code_of_conduct.html>`_
-
+++ /dev/null
-:orphan:
-
-.. _CoC_reporting_manual:
-
-NumPy Code of Conduct - How to follow up on a report
-----------------------------------------------------
-
-This is the manual followed by NumPy's Code of Conduct Committee. It's used
-when we respond to an issue to make sure we're consistent and fair.
-
-Enforcing the Code of Conduct impacts our community today and for the future.
-It's an action that we do not take lightly. When reviewing enforcement
-measures, the Code of Conduct Committee will keep the following values and
-guidelines in mind:
-
-* Act in a personal manner rather than impersonal. The Committee can engage
- the parties to understand the situation, while respecting the privacy and any
- necessary confidentiality of reporters. However, sometimes it is necessary
- to communicate with one or more individuals directly: the Committee's goal is
- to improve the health of our community rather than only produce a formal
- decision.
-
-* Emphasize empathy for individuals rather than judging behavior, avoiding
- binary labels of "good" and "bad/evil". Overt, clear-cut aggression and
- harassment exists and we will be address that firmly. But many scenarios
- that can prove challenging to resolve are those where normal disagreements
- devolve into unhelpful or harmful behavior from multiple parties.
- Understanding the full context and finding a path that re-engages all is
- hard, but ultimately the most productive for our community.
-
-* We understand that email is a difficult medium and can be isolating.
- Receiving criticism over email, without personal contact, can be
- particularly painful. This makes it especially important to keep an
- atmosphere of open-minded respect of the views of others. It also means
- that we must be transparent in our actions, and that we will do everything
- in our power to make sure that all our members are treated fairly and with
- sympathy.
-
-* Discrimination can be subtle and it can be unconscious. It can show itself
- as unfairness and hostility in otherwise ordinary interactions. We know
- that this does occur, and we will take care to look out for it. We would
- very much like to hear from you if you feel you have been treated unfairly,
- and we will use these procedures to make sure that your complaint is heard
- and addressed.
-
-* Help increase engagement in good discussion practice: try to identify where
- discussion may have broken down and provide actionable information, pointers
- and resources that can lead to positive change on these points.
-
-* Be mindful of the needs of new members: provide them with explicit support
- and consideration, with the aim of increasing participation from
- underrepresented groups in particular.
-
-* Individuals come from different cultural backgrounds and native languages.
- Try to identify any honest misunderstandings caused by a non-native speaker
- and help them understand the issue and what they can change to avoid causing
- offence. Complex discussion in a foreign language can be very intimidating,
- and we want to grow our diversity also across nationalities and cultures.
-
-*Mediation*: voluntary, informal mediation is a tool at our disposal. In
-contexts such as when two or more parties have all escalated to the point of
-inappropriate behavior (something sadly common in human conflict), it may be
-useful to facilitate a mediation process. This is only an example: the
-Committee can consider mediation in any case, mindful that the process is meant
-to be strictly voluntary and no party can be pressured to participate. If the
-Committee suggests mediation, it should:
-
-* Find a candidate who can serve as a mediator.
-* Obtain the agreement of the reporter(s). The reporter(s) have complete
- freedom to decline the mediation idea, or to propose an alternate mediator.
-* Obtain the agreement of the reported person(s).
-* Settle on the mediator: while parties can propose a different mediator than
- the suggested candidate, only if common agreement is reached on all terms can
- the process move forward.
-* Establish a timeline for mediation to complete, ideally within two weeks.
-
-The mediator will engage with all the parties and seek a resolution that is
-satisfactory to all. Upon completion, the mediator will provide a report
-(vetted by all parties to the process) to the Committee, with recommendations
-on further steps. The Committee will then evaluate these results (whether
-satisfactory resolution was achieved or not) and decide on any additional
-action deemed necessary.
-
-
-How the committee will respond to reports
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When the committee (or a committee member) receives a report, they will first
-determine whether the report is about a clear and severe breach (as defined
-below). If so, immediate action needs to be taken in addition to the regular
-report handling process.
-
-Clear and severe breach actions
-+++++++++++++++++++++++++++++++
-
-We know that it is painfully common for internet communication to start at or
-devolve into obvious and flagrant abuse. We will deal quickly with clear and
-severe breaches like personal threats, violent, sexist or racist language.
-
-When a member of the Code of Conduct committee becomes aware of a clear and
-severe breach, they will do the following:
-
-* Immediately disconnect the originator from all NumPy communication channels.
-* Reply to the reporter that their report has been received and that the
- originator has been disconnected.
-* In every case, the moderator should make a reasonable effort to contact the
- originator, and tell them specifically how their language or actions
- qualify as a "clear and severe breach". The moderator should also say
- that, if the originator believes this is unfair or they want to be
- reconnected to NumPy, they have the right to ask for a review, as below, by
- the Code of Conduct Committee.
- The moderator should copy this explanation to the Code of Conduct Committee.
-* The Code of Conduct Committee will formally review and sign off on all cases
- where this mechanism has been applied to make sure it is not being used to
- control ordinary heated disagreement.
-
-Report handling
-+++++++++++++++
-
-When a report is sent to the committee they will immediately reply to the
-reporter to confirm receipt. This reply must be sent within 72 hours, and the
-group should strive to respond much quicker than that.
-
-If a report doesn't contain enough information, the committee will obtain all
-relevant data before acting. The committee is empowered to act on the Steering
-Council’s behalf in contacting any individuals involved to get a more complete
-account of events.
-
-The committee will then review the incident and determine, to the best of their
-ability:
-
-* What happened.
-* Whether this event constitutes a Code of Conduct violation.
-* Who are the responsible party(ies).
-* Whether this is an ongoing situation, and there is a threat to anyone's
- physical safety.
-
-This information will be collected in writing, and whenever possible the
-group's deliberations will be recorded and retained (i.e. chat transcripts,
-email discussions, recorded conference calls, summaries of voice conversations,
-etc).
-
-It is important to retain an archive of all activities of this committee to
-ensure consistency in behavior and provide institutional memory for the
-project. To assist in this, the default channel of discussion for this
-committee will be a private mailing list accessible to current and future
-members of the committee as well as members of the Steering Council upon
-justified request. If the Committee finds the need to use off-list
-communications (e.g. phone calls for early/rapid response), it should in all
-cases summarize these back to the list so there's a good record of the process.
-
-The Code of Conduct Committee should aim to have a resolution agreed upon within
-two weeks. In the event that a resolution can't be determined in that time, the
-committee will respond to the reporter(s) with an update and projected timeline
-for resolution.
-
-
-.. _CoC_resolutions:
-
-Resolutions
-~~~~~~~~~~~
-
-The committee must agree on a resolution by consensus. If the group cannot reach
-consensus and deadlocks for over a week, the group will turn the matter over to
-the Steering Council for resolution.
-
-
-Possible responses may include:
-
-* Taking no further action
-
- - if we determine no violations have occurred.
- - if the matter has been resolved publicly while the committee was considering responses.
-
-* Coordinating voluntary mediation: if all involved parties agree, the
- Committee may facilitate a mediation process as detailed above.
-* Remind publicly, and point out that some behavior/actions/language have been
- judged inappropriate and why in the current context, or can but hurtful to
- some people, requesting the community to self-adjust.
-* A private reprimand from the committee to the individual(s) involved. In this
- case, the group chair will deliver that reprimand to the individual(s) over
- email, cc'ing the group.
-* A public reprimand. In this case, the committee chair will deliver that
- reprimand in the same venue that the violation occurred, within the limits of
- practicality. E.g., the original mailing list for an email violation, but
- for a chat room discussion where the person/context may be gone, they can be
- reached by other means. The group may choose to publish this message
- elsewhere for documentation purposes.
-* A request for a public or private apology, assuming the reporter agrees to
- this idea: they may at their discretion refuse further contact with the
- violator. The chair will deliver this request. The committee may, if it
- chooses, attach "strings" to this request: for example, the group may ask a
- violator to apologize in order to retain one’s membership on a mailing list.
-* A "mutually agreed upon hiatus" where the committee asks the individual to
- temporarily refrain from community participation. If the individual chooses
- not to take a temporary break voluntarily, the committee may issue a
- "mandatory cooling off period".
-* A permanent or temporary ban from some or all NumPy spaces (mailing lists,
- gitter.im, etc.). The group will maintain records of all such bans so that
- they may be reviewed in the future or otherwise maintained.
-
-Once a resolution is agreed upon, but before it is enacted, the committee will
-contact the original reporter and any other affected parties and explain the
-proposed resolution. The committee will ask if this resolution is acceptable,
-and must note feedback for the record.
-
-Finally, the committee will make a report to the NumPy Steering Council (as
-well as the NumPy core team in the event of an ongoing resolution, such as a
-ban).
-
-The committee will never publicly discuss the issue; all public statements will
-be made by the chair of the Code of Conduct Committee or the NumPy Steering
-Council.
-
-
-Conflicts of Interest
-~~~~~~~~~~~~~~~~~~~~~
-
-In the event of any conflict of interest, a committee member must immediately
-notify the other members, and recuse themselves if necessary.
volunteer project, things do sometimes get dropped and it's totally fine to
ping us if something has sat without a response for about two to four weeks.
-So go ahead and pick something that annoys or confuses you about numpy,
+So go ahead and pick something that annoys or confuses you about NumPy,
experiment with the code, hang around for discussions or go through the
reference documents to try to fix it. Things will fall in place and soon
you'll have a pretty good understanding of the project as a whole. Good Luck!
REL: related to releasing numpy
+.. _workflow_mailing_list:
+
+Get the mailing list's opinion
+=======================================================
+
+If you plan a new feature or API change, it's wisest to first email the
+NumPy `mailing list <https://mail.python.org/mailman/listinfo/numpy-discussion>`_
+asking for comment. If you haven't heard back in a week, it's
+OK to ping the list again.
+
.. _asking-for-merging:
Asking for your changes to be merged with the main repo
has a nice help page that outlines the process for `filing pull requests`_.
If your changes involve modifications to the API or addition/modification of a
-function, you should
+function, add a release note to the ``doc/release/upcoming_changes/``
+directory, following the instructions and format in the
+``doc/release/upcoming_changes/README.rst`` file.
+
+
+.. _workflow_PR_timeline:
+
+Getting your PR reviewed
+========================
+
+We review pull requests as soon as we can, typically within a week. If you get
+no review comments within two weeks, feel free to ask for feedback by
+adding a comment on your PR (this will notify maintainers).
+
+If your PR is large or complicated, asking for input on the numpy-discussion
+mailing list may also be useful.
+
-- send an email to the `NumPy mailing list`_ with a link to your PR along with
- a description of and a motivation for your changes. This may generate
- changes and feedback. It might be prudent to start with this step if your
- change may be controversial.
-- add a release note to the ``doc/release/upcoming_changes/`` directory,
- following the instructions and format in the
- ``doc/release/upcoming_changes/README.rst`` file.
.. _rebasing-on-master:
Do this only for your own feature branches.
-There's an embarrassing typo in a commit you made? Or perhaps the you
+There's an embarrassing typo in a commit you made? Or perhaps you
made several false starts you would like the posterity not to see.
This can be done via *interactive rebasing*.
# delete branch locally
git branch -D my-unwanted-branch
# delete branch on github
- git push origin :my-unwanted-branch
+ git push origin --delete my-unwanted-branch
-(Note the colon ``:`` before ``test-branch``. See also:
-https://github.com/guides/remove-a-remote-branch
+See also:
+https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-locally-and-remotely
Several people sharing a single repository
Pushing changes to the main repo
================================
-*This is only relevant if you have commit rights to the main NumPy repo.*
+*Requires commit rights to the main NumPy repo.*
When you have a set of "ready" changes in a feature branch ready for
NumPy's ``master`` or ``maintenance`` branches, you can push
-====================================
-Getting started with Git development
-====================================
+.. _development-setup:
-This section and the next describe in detail how to set up git for working
-with the NumPy source code. If you have git already set up, skip to
-:ref:`development-workflow`.
+##############################################################################
+Setting up git for NumPy development
+##############################################################################
-Basic Git setup
-###############
+To contribute code or documentation, you first need
-* :ref:`install-git`.
-* Introduce yourself to Git::
+#. git installed on your machine
+#. a GitHub account
+#. a fork of NumPy
- git config --global user.email you@yourdomain.example.com
- git config --global user.name "Your Name Comes Here"
-.. _forking:
+******************************************************************************
+Install git
+******************************************************************************
+
+You may already have git; check by typing ``git --version``. If it's
+installed you'll see some variation of ``git version 2.11.0``.
+If instead you see ``command is not recognized``, ``command not
+found``, etc.,
+`install git <https://git-scm.com/book/en/v2/Getting-Started-Installing-Git>`_.
-Making your own copy (fork) of NumPy
-####################################
+Then set your name and email: ::
-You need to do this only once. The instructions here are very similar
-to the instructions at http://help.github.com/forking/ - please see that
-page for more detail. We're repeating some of it here just to give the
-specifics for the NumPy_ project, and to suggest some default names.
+ git config --global user.email you@yourdomain.example.com
+ git config --global user.name "Your Name"
.. _set-up-and-configure-a-github-account:
-Set up and configure a github_ account
-======================================
+******************************************************************************
+Create a GitHub account
+******************************************************************************
-If you don't have a github_ account, go to the github_ page, and make one.
+If you don't have a GitHub account, visit https://github.com/join to create
+one.
-You then need to configure your account to allow write access - see the
-``Generating SSH keys`` help on `github help`_.
+.. _forking:
-Create your own forked copy of NumPy_
-=========================================
+******************************************************************************
+Create a NumPy fork
+******************************************************************************
-#. Log into your github_ account.
-#. Go to the NumPy_ github home at `NumPy github`_.
-#. Click on the *fork* button:
+``Forking`` has two steps -- visit GitHub to create a fork repo in your
+account, then make a copy of it on your own machine.
- .. image:: forking_button.png
+Create the fork repo
+==============================================================================
- After a short pause, you should find yourself at the home page for
- your own forked copy of NumPy_.
+#. Log into your GitHub account.
+#. Go to the `NumPy GitHub home <https://github.com/numpy/numpy>`_.
+#. At the upper right of the page, click ``Fork``:
-.. include:: git_links.inc
+ .. image:: forking_button.png
+ You'll see
-.. _set-up-fork:
+ .. image:: forking_message.png
-Set up your fork
-################
+ and then you'll be taken to the home page of your forked copy:
-First you follow the instructions for :ref:`forking`.
+ .. image:: forked_page.png
-Overview
-========
-::
+.. _set-up-fork:
- git clone https://github.com/your-user-name/numpy.git
- cd numpy
- git remote add upstream https://github.com/numpy/numpy.git
+Make the local copy
+==============================================================================
-In detail
-=========
+#. In the directory where you want the copy created, run ::
-Clone your fork
----------------
+ git clone https://github.com/your-user-name/numpy.git
-#. Clone your fork to the local computer with ``git clone
- https://github.com/your-user-name/numpy.git``
-#. Investigate. Change directory to your new repo: ``cd numpy``. Then
- ``git branch -a`` to show you all branches. You'll get something
- like::
+ You'll see something like: ::
- * master
- remotes/origin/master
+ $ git clone https://github.com/your-user-name/numpy.git
+ Cloning into 'numpy'...
+ remote: Enumerating objects: 12, done.
+ remote: Counting objects: 100% (12/12), done.
+ remote: Compressing objects: 100% (12/12), done.
+ remote: Total 175837 (delta 0), reused 0 (delta 0), pack-reused 175825
+ Receiving objects: 100% (175837/175837), 78.16 MiB | 9.87 MiB/s, done.
+ Resolving deltas: 100% (139317/139317), done.
- This tells you that you are currently on the ``master`` branch, and
- that you also have a ``remote`` connection to ``origin/master``.
- What remote repository is ``remote/origin``? Try ``git remote -v`` to
- see the URLs for the remote. They will point to your github_ fork.
+ A directory ``numpy`` is created on your machine. (If you already have
+ a numpy directory, GitHub will choose a different name like ``numpy-1``.)
+ ::
- Now you want to connect to the upstream `NumPy github`_ repository, so
- you can merge in changes from trunk.
+ $ ls -l
+ total 0
+ drwxrwxrwx 1 bjn bjn 4096 Jun 20 07:20 numpy
.. _linking-to-upstream:
-Linking your repository to the upstream repo
---------------------------------------------
+#. Give the name ``upstream`` to the main NumPy repo: ::
+
+ cd numpy
+ git remote add upstream https://github.com/numpy/numpy.git
+
+#. Set up your repository so ``git pull`` pulls from ``upstream`` by
+ default: ::
+
+ git config branch.master.remote upstream
+ git config branch.master.merge refs/heads/master
-::
+******************************************************************************
+Look it over
+******************************************************************************
- cd numpy
- git remote add upstream https://github.com/numpy/numpy.git
+#. The branches shown by ``git branch -a`` will include
-``upstream`` here is just the arbitrary name we're using to refer to the
-main NumPy_ repository at `NumPy github`_.
+ - the ``master`` branch you just cloned on your own machine
+ - the ``master`` branch from your fork on GitHub, which git named
+ ``origin`` by default
+ - the ``master`` branch on the the main NumPy repo, which you named
+ ``upstream``.
-Just for your own satisfaction, show yourself that you now have a new
-'remote', with ``git remote -v show``, giving you something like::
+ ::
- upstream https://github.com/numpy/numpy.git (fetch)
- upstream https://github.com/numpy/numpy.git (push)
- origin https://github.com/your-user-name/numpy.git (fetch)
- origin https://github.com/your-user-name/numpy.git (push)
+ master
+ remotes/origin/master
+ remotes/upstream/master
-To keep in sync with changes in NumPy, you want to set up your repository
-so it pulls from ``upstream`` by default. This can be done with::
+ If ``upstream`` isn't there, it will be added after you access the
+ NumPy repo with a command like ``git fetch`` or ``git pull``.
- git config branch.master.remote upstream
- git config branch.master.merge refs/heads/master
-You may also want to have easy access to all pull requests sent to the
-NumPy repository::
+#. The repos shown by ``git remote -v show`` will include your fork on GitHub
+ and the main repo: ::
- git config --add remote.upstream.fetch '+refs/pull/*/head:refs/remotes/upstream/pr/*'
+ upstream https://github.com/numpy/numpy.git (fetch)
+ upstream https://github.com/numpy/numpy.git (push)
+ origin https://github.com/your-user-name/numpy.git (fetch)
+ origin https://github.com/your-user-name/numpy.git (push)
-Your config file should now look something like (from
-``$ cat .git/config``)::
+#. ``git config --list`` will include ::
- [core]
- repositoryformatversion = 0
- filemode = true
- bare = false
- logallrefupdates = true
- ignorecase = true
- precomposeunicode = false
- [remote "origin"]
- url = https://github.com/your-user-name/numpy.git
- fetch = +refs/heads/*:refs/remotes/origin/*
- [remote "upstream"]
- url = https://github.com/numpy/numpy.git
- fetch = +refs/heads/*:refs/remotes/upstream/*
- fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
- [branch "master"]
- remote = upstream
- merge = refs/heads/master
+ user.email=your_email@example.com
+ user.name=Your Name
+ remote.origin.url=git@github.com:your-github-id/numpy.git
+ remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
+ branch.master.remote=upstream
+ branch.master.merge=refs/heads/master
+ remote.upstream.url=https://github.com/numpy/numpy.git
+ remote.upstream.fetch=+refs/heads/*:refs/remotes/upstream/*
.. include:: git_links.inc
+
+
+******************************************************************************
+Optional: set up SSH keys to avoid passwords
+******************************************************************************
+
+Cloning your NumPy fork repo required no password, because it read the remote
+repo without changing it. Later, though, submitting your pull requests will
+write to it, and GitHub will ask for your username and password -- even though
+it's your own repo. You can eliminate this authentication without compromising
+security by `setting up SSH keys \
+<https://help.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh>`_.
+
+**If you set up the keys before cloning**, the instructions above change
+slightly. Instead of ::
+
+ git clone https://github.com/your-user-name/numpy.git
+
+run ::
+
+ git clone git@github.com:numpy/numpy.git
+
+and instead of showing an ``https`` URL, ``git remote -v`` will show ::
+
+ origin git@github.com:your-user-name/numpy.git (fetch)
+ origin git@github.com:your-user-name/numpy.git (push)
+
+
+**If you have cloned already** and want to start using SSH, see
+`Switching remote URLs from HTTPS to SSH \
+<https://help.github.com/en/github/using-git/changing-a-remotes-url#switching-remote-urls-from-https-to-ssh>`_.
and name substitutions. It may be included in many files,
therefore it should only contain link targets and name
substitutions. Try grepping for "^\.\. _" to find plausible
- candidates for this list.
+ candidates for this list.
.. NOTE: reST targets are
__not_case_sensitive__, so only one target definition is needed for
.. _subversion: http://subversion.tigris.org/
.. _git cheat sheet: http://cheat.errtheblog.com/s/git
.. _pro git book: https://git-scm.com/book/
-.. _git svn crash course: https://git-scm.com/course/svn.html
+.. _git svn crash course: https://git.wiki.kernel.org/index.php/GitSvnCrashCourse
.. _learn.github: https://learn.github.com/
-.. _network graph visualizer: https://github.com/blog/39-say-hello-to-the-network-graph-visualizer
+.. _network graph visualizer: https://github.blog/2008-04-10-say-hello-to-the-network-graph-visualizer/
.. _git user manual: https://www.kernel.org/pub/software/scm/git/docs/user-manual.html
.. _git tutorial: https://www.kernel.org/pub/software/scm/git/docs/gittutorial.html
.. _git community book: https://book.git-scm.com/
.. _git config: https://www.kernel.org/pub/software/scm/git/docs/git-config.html
.. _why the -a flag?: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html
.. _git staging area: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html
-.. _tangled working copy problem: https://tomayko.com/writings/the-thing-about-git
-.. _git management: http://kerneltrap.org/Linux/Git_Management
+.. _tangled working copy problem: https://tomayko.com/writings/the-thing-about-git
+.. _git management: https://web.archive.org/web/20090328043540/http://kerneltrap.org/Linux/Git_Management
.. _linux git workflow: https://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html
-.. _ipython git workflow: http://mail.python.org/pipermail/ipython-dev/2010-October/006746.html
+.. _ipython git workflow: https://mail.python.org/pipermail/ipython-dev/2010-October/005632.html
.. _git parable: http://tom.preston-werner.com/2009/05/19/the-git-parable.html
.. _git foundation: http://matthew-brett.github.com/pydagogue/foundation.html
.. _numpy/master: https://github.com/numpy/numpy
.. _git cherry-pick: https://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html
.. _git blame: https://www.kernel.org/pub/software/scm/git/docs/git-blame.html
-.. _this blog post: https://github.com/blog/612-introducing-github-compare-view
-.. _this article on merging conflicts: https://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging#Basic-Merge-Conflicts
-.. _learn git: https://www.atlassian.com/git/tutorials/
+.. _this blog post: https://github.com/blog/612-introducing-github-compare-view
+.. _this article on merging conflicts: https://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging#Basic-Merge-Conflicts
+.. _learn git: https://try.github.io/
.. _filing pull requests: https://help.github.com/articles/using-pull-requests/#initiating-the-pull-request
.. _pull request review: https://help.github.com/articles/using-pull-requests/#reviewing-the-pull-request
================
Substantial portions of this document were adapted from the
-`Jupyter/IPython project's governance document
-<https://github.com/jupyter/governance/blob/master/governance.md>`_.
+`Jupyter/IPython project's governance document <https://github.com/jupyter/governance>`_
License
=======
* Ralf Gommers
+* Allan Haldane
+
* Charles Harris
+* Stephan Hoyer
+
+* Matti Picus
+
* Nathaniel Smith
* Julian Taylor
* Pauli Virtanen
-* Eric Wieser
-
-* Marten van Kerkwijk
-
-* Stephan Hoyer
+* Stéfan van der Walt
-* Allan Haldane
+* Eric Wieser
-* Stefan van der Walt
Emeritus members
----------------
-* Travis Oliphant - Project Founder / Emeritus Leader (served: 2005-2012)
+* Travis Oliphant -- project founder / emeritus leader (2005-2012)
+
+* Alex Griffing (2015-2017)
-* Alex Griffing (served: 2015-2017)
+* Marten van Kerkwijk (2017-2019)
NumFOCUS Subcommittee
Institutional Partners
----------------------
-* UC Berkeley (Stefan van der Walt, Sebastian Berg, Warren Weckesser, Ross Barnowski)
+* UC Berkeley (Stéfan van der Walt, Sebastian Berg, Warren Weckesser, Ross Barnowski)
* Quansight (Ralf Gommers, Hameer Abbasi, Melissa Weber Mendonça, Mars Lee, Matti Picus)
How to contribute to the NumPy documentation
############################################
-The *Documentation* for a software project is the set of reference,
-instructional, educational, informative material generated by the project
-developers and contributors, as well as discussions, presentations, videos and
-other user-generated content. It may include learning-oriented content (such as
-tutorials and how-tos), use-cases or in-depth explanations and reference for
-developers.
-
-If you're reading this page, you probably want to help. This guide is meant to
-help you decide which kind of content you'll write, as well as give you some
-tips and instructions for submitting it to the official NumPy documentation
-(that is, the documentation that ships with NumPy and lives on the
-:ref:`official project pages <numpy_docs_mainpage>`). Keep in mind that if you
-don't want to do this, writing a tutorial on your own blog, creating a YouTube
-video or answering questions on social media or Stack Overflow are also great
-contributions!
-
-NumPy has a Documentation Team. We have open meetings on Zoom every three weeks
-and invite everyone to join. Don't hesitate to reach out if you have questions
-or just need someone to guide you through your first steps - we're always happy
-to help. Meetings are usually announced on the `numpy-discussion mailing list
-<https://mail.python.org/mailman/listinfo/numpy-discussion>`__. Meeting minutes
-are taken `on hackmd.io <https://hackmd.io/oB_boakvRqKR-_2jRV-Qjg>`__ and stored
-in the `NumPy Archive repository <https://github.com/numpy/archive>`__.
-
-You can find larger planned and in-progress documentation improvement ideas `at
+This guide will help you decide what to contribute and how to submit it to the
+official NumPy documentation.
+
+******************************************************************************
+Documentation team meetings
+******************************************************************************
+
+The NumPy community has set a firm goal of improving its documentation. We
+hold regular documentation meetings on Zoom (dates are announced on the
+`numpy-discussion mailing list
+<https://mail.python.org/mailman/listinfo/numpy-discussion>`__), and everyone
+is welcome. Reach out if you have questions or need
+someone to guide you through your first steps -- we're happy to help.
+Minutes are taken `on hackmd.io <https://hackmd.io/oB_boakvRqKR-_2jRV-Qjg>`__
+and stored in the `NumPy Archive repository
+<https://github.com/numpy/archive>`__.
+
+*************************
+What's needed
+*************************
+NumPy docs have the details covered. API reference
+documentation is generated directly from
+`docstrings <https://www.python.org/dev/peps/pep-0257/>`_ in the code
+when the documentation is :ref:`built<howto-build-docs>`.
+
+What we lack are docs with broader scope -- tutorials, how-tos, and explanations.
+Reporting defects is another way to contribute. We discuss both.
+
+*************************
+Contributing fixes
+*************************
+
+We're eager to hear about and fix doc defects. But to attack the biggest
+problems we end up having to defer or overlook some bug reports. Here are the
+best defects to go after.
+
+Top priority goes to **technical inaccuracies** -- a docstring missing a
+parameter, a faulty description of a function/parameter/method, and so on.
+Other "structural" defects like broken links also get priority. All these fixes
+are easy to confirm and put in place. You can submit
+a `pull request (PR) <https://numpy.org/devdocs/dev/index.html#devindex>`__
+with the fix, if you know how to do that; otherwise please `open an issue
+<https://github.com/numpy/numpy/issues>`__.
+
+**Typos and misspellings** fall on a lower rung; we welcome hearing about them but
+may not be able to fix them promptly. These too can be handled as pull
+requests or issues.
+
+Obvious **wording** mistakes (like leaving out a "not") fall into the typo
+category, but other rewordings -- even for grammar -- require a judgment call,
+which raises the bar. Test the waters by first presenting the fix as an issue.
+
+******************************************************************************
+Contributing new pages
+******************************************************************************
+
+Your frustrations using our documents are our best guide to what needs fixing.
+
+If you write a missing doc you join the front line of open source, but it's
+a meaningful contribution just to let us know what's missing. If you want to
+compose a doc, run your thoughts by the `mailing list
+<https://mail.python.org/mailman/listinfo/numpy-discussion>`__ for futher
+ideas and feedback. If you want to alert us to a gap,
+`open an issue <https://github.com/numpy/numpy/issues>`__. See
+`this issue <https://github.com/numpy/numpy/issues/15760>`__ for an example.
+
+If you're looking for subjects, our formal roadmap for documentation is a
+*NumPy Enhancement Proposal (NEP)*,
+`NEP 44 - Restructuring the NumPy Documentation <https://www.numpy.org/neps/nep-0044-restructuring-numpy-docs>`__.
+It identifies areas where our docs need help and lists several
+additions we'd like to see, including Jupyter notebooks.
+
+You can find larger planned and in-progress ideas `at
our GitHub project <https://github.com/orgs/numpy/projects/2>`__.
-Current vision for the documentation: NEP 44
---------------------------------------------
+.. _tutorials_howtos_explanations:
-Recently, the NumPy community approved a *NumPy Enhancement Proposal (NEP)*
-about documentation, `NEP 44 - Restructuring the NumPy Documentation
-<https://www.numpy.org/neps/nep-0044-restructuring-numpy-docs>`__.
-**Where is the documentation?**
+Formula writing
+==============================================================================
+There are formulas for writing useful documents, and four formulas
+cover nearly everything. There are four formulas because there are four
+categories of document -- ``tutorial``, ``how-to guide``, ``explanation``,
+and ``reference``. The insight that docs divide up this way belongs to
+Daniele Procida, who goes on
+`in this short article <https://documentation.divio.com/>`__ to explain
+the differences and reveal the formulas. When you begin a document or
+propose one, have in mind which of these types it will be.
-The main page for the :ref:`NumPy Documentation <numpy_docs_mainpage>` lists
-several categories. The documents mentioned there live in different places.
-- **Tutorials, How-Tos, Explanations:** These documents are stored in the NumPy
- source code tree, which means that in order to add them to the official
- documentation, you have to download the NumPy source code,
- :ref:`build it <howto-build-docs>` and submit your changes via a
- :ref:`GitHub pull request <devindex>`.
+.. _contributing:
-- **API Reference:** These are mainly the result of rendering the NumPy code
- `docstrings <https://www.python.org/dev/peps/pep-0257/>`__ into formatted
- documents. They are automatically generated when the NumPy documentation is
- :ref:`built from source<howto-build-docs>`.
-**Datasets**
+More on contributing
+==============================================================================
-If you are writing a tutorial or how-to, we encourage you to use real images and
-data (provided they are appropriately licensed and available). This makes the
-material more engaging for readers, and choosing the right data can add
-pedagogical value to your content.
+Don't worry if English is not your first language, or if you can only come up
+with a rough draft. Open source is a community effort. Do your best -- we'll
+help fix issues.
-*Note: currently we cannot easily use data in other packages (except, e.g., from
-SciPy or Matplotlib). We plan to create a dedicated datasets package, but that's
-not ready yet - please discuss with us if you have data sources in mind.*
+Images and real-life data make text more engaging and powerful, but be sure
+what you use is appropriately licensed and available. Here again, even a rough
+idea for artwork can be polished by others.
-Creating new content
---------------------
+For now, the only data formats accepted by NumPy are those also used by other
+Python scientific libraries like pandas, SciPy, or Matplotlib. We're
+developing a package to accept more formats; contact us for details.
-The documentation is written in restructuredText, which is the format required
-by Sphinx, the tool most Python projects use to automatically build and link the
-documentation within the project. You can read the
-`Quick reStructuredText Guide
+NumPy documentation is kept in the source code tree. To get your document
+into the docbase you must download the tree, :ref:`build it
+<howto-build-docs>`, and submit a pull request. If GitHub and pull requests
+are new to you, check our :ref:`Contributor Guide <devindex>`.
+
+Our markup language is reStructuredText (rST), which is more elaborate than
+Markdown. Sphinx, the tool many Python projects use to build and link project
+documentation, converts the rST into HTML and other formats. For more on
+rST, see the `Quick reStructuredText Guide
<https://docutils.sourceforge.io/docs/user/rst/quickref.html>`__ or the
`reStructuredText Primer
-<http://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html>`__ for
-more information.
-
-If you have already decided which type of document you want to write, you can
-check out the following specific guides:
-
-- Guide to writing Tutorials (TODO)
-- :ref:`Guide to writing reference (API) documentation: the numpydoc docstring
- guide <howto-document>`
-
-Major additions to the documentation (e.g. new tutorials) should be proposed to
-the `mailing list
-<https://mail.python.org/mailman/listinfo/numpy-discussion>`__.
-
-Other ways to contribute
-------------------------
-
-Correcting technical inaccuracies in the documentation are high priority. For
-example, if a docstring is missing a parameter or the description of a
-fuction/parameter/method etc. is incorrect. Other "structural" defects like
-broken links are also high priority.
-
-Proposals for changes that improve the clarity of the documentation are welcome.
-However, "clarity" is a bit subjective, so such proposals are best made by
-raising issues that describe what could be improved in the current
-documentation. Proposals that include specific suggestions for the improvement
-are encouraged as the proposed changes helps frame the discussion.
-
-Based on the above characterization, "high-priority" changes (i.e. fixing
-technical inaccuracies, broken links, etc.) can be proposed via pull requests
-directly as they are straightforward to review. Other changes should be raised
-as issues first so that the discussion can happen before you make major
-modifications, which in principle saves you from wasting your time on
-undesired changes.
-
-If you see a good tutorial, how-to or explanation that is not included in the
-official documentation, you can suggest it to be added by `opening an issue on
-GitHub <https://github.com/numpy/numpy/issues>`__. Similarly, opening issues to
-suggest a tutorial, how-to or explanation that you can't find anywhere is a
-great way to help the documentation team direct efforts towards what users are
-looking for. `See this issue <https://github.com/numpy/numpy/issues/15760>`__
-for an example of how to do this.
-
-Finally, if you detect a typo or an error in the documentation, or would like to
-suggest a different approach, you can also open an issue or submit a pull
-request with your suggestion. Keep in mind that changes fixing
-grammatical/spelling errors are welcome but not necessarily the highest
-priority. "Grammatical correctness" often gets confused with "style" which can
-result in unfruitful discussions that don't necessarily improve anything.
-Changes that modify wording or rearrange phrasing without changing the technical
-content are discouraged. If you think that a different wording improves clarity,
-you should open an issue as noted above, but again, changes along these lines
-very often tend to be highly subjective and not necessarily do much to improve
-the quality of the documentation.
-
-**Final tips**
-
-- Don't worry if English is not your first language. Do your best - we'll revise
- your content and make sure we fix any issues with the code or text.
-- If you are unsure whether your tutorial is useful to the community, consider
- submitting an issue on GitHub suggesting it, or asking on the mailing
- list or Stack Overflow.
-- If you are unfamiliar with git/GitHub or the process of submitting a pull
- request (PR), check our :ref:`Contributor Guide <devindex>`.
-
-**Other interesting material**
-
-- `writethedocs.org <https://www.writethedocs.org/>`__ has a lot of interesting
- resources for technical writing.
-- Google offers two free `Technical Writing Courses
- <https://developers.google.com/tech-writing>`__
-- `Software Carpentry <https://software-carpentry.org/software>`__ has a lot of
- nice recommendations for creating educational material.
+<http://www.sphinx-doc.org/en/stable/usage/restructuredtext/basics.html>`__
+
+
+************************************************************
+Contributing indirectly
+************************************************************
+
+If you run across outside material that would be a useful addition to the
+NumPy docs, let us know by `opening an issue <https://github.com/numpy/numpy/issues>`__.
+
+You don't have to contribute here to contribute to NumPy. You've contributed
+if you write a tutorial on your blog, create a YouTube video, or answer questions
+on Stack Overflow and other sites.
+
+
+************************************************************
+Documentation reading
+************************************************************
+
+- The leading organization of technical writers,
+ `Write the Docs <https://www.writethedocs.org/>`__,
+ holds conferences, hosts learning resources, and runs a Slack channel.
+
+- "Every engineer is also a writer," says Google's
+ `collection of technical writing resources <https://developers.google.com/tech-writing>`__,
+ which includes free online courses for developers in planning and writing
+ documents.
+
+- `Software Carpentry's <https://software-carpentry.org/lessons>`__ mission is
+ teaching software to researchers. In addition to hosting the curriculum, the
+ website explains how to present ideas effectively.
Contributing to NumPy
#####################
+.. TODO: this is hidden because there's a bug in the pydata theme that won't render TOC items under headers
+
+.. toctree::
+ :hidden:
+
+ Git Basics <gitwash/index>
+ development_environment
+ development_workflow
+ ../benchmarking
+ NumPy C style guide <https://numpy.org/neps/nep-0045-c_style_guide.html>
+ releasing
+ governance/index
+ howto-docs
+
+
Not a coder? Not a problem! NumPy is multi-faceted, and we can use a lot of help.
These are all activities we'd like to get help with (they're all important, so
we list them in alphabetical order):
overall code quality benefits. Therefore, please don't let the review
discourage you from contributing: its only aim is to improve the quality
of project, not to criticize (we are, after all, very grateful for the
- time you're donating!).
+ time you're donating!). See our :ref:`Reviewer Guidelines
+ <reviewer-guidelines>` for more information.
* To update your PR, make your changes on your local repository, commit,
**run tests, and only if they succeed** push to your fork. As soon as
If your change introduces a deprecation, make sure to discuss this first on
GitHub or the mailing list first. If agreement on the deprecation is
- reached, follow `NEP 23 deprecation policy <http://www.numpy.org/neps/
- nep-0023-backwards-compatibility.html>`_ to add the deprecation.
+ reached, follow :ref:`NEP 23 deprecation policy <NEP23>` to add the deprecation.
6. Cross referencing issues
since you started into your branch. Our recommended way to do this is to
:ref:`rebase on master<rebasing-on-master>`.
+.. _guidelines:
+
Guidelines
----------
* All code should be `documented <https://numpydoc.readthedocs.io/
en/latest/format.html#docstring-standard>`_.
* No changes are ever committed without review and approval by a core
- team member.Please ask politely on the PR or on the `mailing list`_ if you
+ team member. Please ask politely on the PR or on the `mailing list`_ if you
get no response to your pull request within a week.
+.. _stylistic-guidelines:
+
Stylistic Guidelines
--------------------
import numpy as np
-* For C code, see the :ref:`numpy-c-style-guide<style_guide>`
+* For C code, see :ref:`NEP 45 <NEP45>`.
Test coverage
$ firefox build/coverage/index.html
+.. _building-docs:
+
Building docs
-------------
git submodule update --init
The documentation includes mathematical formulae with LaTeX formatting.
-A working LaTeX document production system
+A working LaTeX document production system
(e.g. `texlive <https://www.tug.org/texlive/>`__) is required for the
proper rendering of the LaTeX math in the documentation.
.. toctree::
:maxdepth: 2
- conduct/code_of_conduct
Git Basics <gitwash/index>
development_environment
development_workflow
+ reviewer_guidelines
../benchmarking
- style_guide
+ NumPy C style guide <https://numpy.org/neps/nep-0045-c_style_guide.html>
releasing
governance/index
howto-docs
NumPy-specific workflow is in :ref:`numpy-development-workflow
<development-workflow>`.
-.. _`mailing list`: https://mail.python.org/mailman/listinfo/numpy-devel
+.. _`mailing list`: https://mail.python.org/mailman/listinfo/numpy-discussion
--- /dev/null
+.. _reviewer-guidelines:
+
+===================
+Reviewer Guidelines
+===================
+
+Reviewing open pull requests (PRs) helps move the project forward. We encourage
+people outside the project to get involved as well; it's a great way to get
+familiar with the codebase.
+
+Who can be a reviewer?
+======================
+
+Reviews can come from outside the NumPy team -- we welcome contributions from
+domain experts (for instance, `linalg` or `fft`) or maintainers of other
+projects. You do not need to be a NumPy maintainer (a NumPy team member with
+permission to merge a PR) to review.
+
+If we do not know you yet, consider introducing yourself in `the mailing list or
+Slack <https://numpy.org/community/>`_ before you start reviewing pull requests.
+
+Communication Guidelines
+========================
+
+- Every PR, good or bad, is an act of generosity. Opening with a positive
+ comment will help the author feel rewarded, and your subsequent remarks may be
+ heard more clearly. You may feel good also.
+- Begin if possible with the large issues, so the author knows they've been
+ understood. Resist the temptation to immediately go line by line, or to open
+ with small pervasive issues.
+- You are the face of the project, and NumPy some time ago decided `the kind of
+ project it will be <https://numpy.org/code-of-conduct/>`_: open, empathetic,
+ welcoming, friendly and patient. Be `kind
+ <https://youtu.be/tzFWz5fiVKU?t=49m30s>`_ to contributors.
+- Do not let perfect be the enemy of the good, particularly for documentation.
+ If you find yourself making many small suggestions, or being too nitpicky on
+ style or grammar, consider merging the current PR when all important concerns
+ are addressed. Then, either push a commit directly (if you are a maintainer)
+ or open a follow-up PR yourself.
+- If you need help writing replies in reviews, check out some `Standard replies
+ for reviewing
+ <https://scikit-learn.org/stable/developers/tips.html#saved-replies>`_.
+
+Reviewer Checklist
+==================
+
+- Is the intended behavior clear under all conditions? Some things to watch:
+ - What happens with unexpected inputs like empty arrays or nan/inf values?
+ - Are axis or shape arguments tested to be `int` or `tuples`?
+ - Are unusual `dtypes` tested if a function supports those?
+- Should variable names be improved for clarity or consistency?
+- Should comments be added, or rather removed as unhelpful or extraneous?
+- Does the documentation follow the :ref:`NumPy guidelines<howto-document>`? Are
+ the docstrings properly formatted?
+- Does the code follow NumPy's :ref:`Stylistic Guidelines<stylistic-guidelines>`?
+- If you are a maintainer, and it is not obvious from the PR description, add a
+ short explanation of what a branch did to the merge message and, if closing an
+ issue, also add "Closes gh-123" where 123 is the issue number.
+- For code changes, at least one maintainer (i.e. someone with commit rights)
+ should review and approve a pull request. If you are the first to review a
+ PR and approve of the changes use the GitHub `approve review
+ <https://help.github.com/articles/reviewing-changes-in-pull-requests/>`_ tool
+ to mark it as such. If a PR is straightforward, for example it's a clearly
+ correct bug fix, it can be merged straight away. If it's more complex or
+ changes public API, please leave it open for at least a couple of days so
+ other maintainers get a chance to review.
+- If you are a subsequent reviewer on an already approved PR, please use the
+ same review method as for a new PR (focus on the larger issues, resist the
+ temptation to add only a few nitpicks). If you have commit rights and think
+ no more review is needed, merge the PR.
+
+For maintainers
+---------------
+
+- Make sure all automated CI tests pass before merging a PR, and that the
+ :ref:`documentation builds <building-docs>` without any errors.
+- In case of merge conflicts, ask the PR submitter to :ref:`rebase on master
+ <rebasing-on-master>`.
+- For PRs that add new features or are in some way complex, wait at least a day
+ or two before merging it. That way, others get a chance to comment before the
+ code goes in. Consider adding it to the release notes.
+- When merging contributions, a committer is responsible for ensuring that those
+ meet the requirements outlined in the :ref:`Development process guidelines
+ <guidelines>` for NumPy. Also, check that new features and backwards
+ compatibility breaks were discussed on the `numpy-discussion mailing list
+ <https://mail.python.org/mailman/listinfo/numpy-discussion>`_.
+- Squashing commits or cleaning up commit messages of a PR that you consider too
+ messy is OK. Remember to retain the original author's name when doing this.
+ Make sure commit messages follow the :ref:`rules for NumPy
+ <writing-the-commit-message>`.
+- When you want to reject a PR: if it's very obvious, you can just close it and
+ explain why. If it's not, then it's a good idea to first explain why you
+ think the PR is not suitable for inclusion in NumPy and then let a second
+ committer comment or close.
+
+GitHub Workflow
+---------------
+
+When reviewing pull requests, please use workflow tracking features on GitHub as
+appropriate:
+
+- After you have finished reviewing, if you want to ask for the submitter to
+ make changes, change your review status to "Changes requested." This can be
+ done on GitHub, PR page, Files changed tab, Review changes (button on the top
+ right).
+- If you're happy about the current status, mark the pull request as Approved
+ (same way as Changes requested). Alternatively (for maintainers): merge
+ the pull request, if you think it is ready to be merged.
+
+It may be helpful to have a copy of the pull request code checked out on your
+own machine so that you can play with it locally. You can use the `GitHub CLI
+<https://docs.github.com/en/github/getting-started-with-github/github-cli>`_ to
+do this by clicking the ``Open with`` button in the upper right-hand corner of
+the PR page.
+
+Assuming you have your :ref:`development environment<development-environment>`
+set up, you can now build the code and test it.
+
+.. include:: gitwash/git_links.inc
+++ /dev/null
-.. _style_guide:
-
-===================
-NumPy C Style Guide
-===================
-
-.. include:: ../../C_STYLE_GUIDE.rst.txt
- :start-line: 4
--- /dev/null
+.. _documentation_conventions:
+
+##############################################################################
+Documentation conventions
+##############################################################################
+
+- Names that look like :func:`numpy.array` are links to detailed
+ documentation.
+
+- Examples often include the Python prompt ``>>>``. This is not part of the
+ code and will cause an error if typed or pasted into the Python
+ shell. It can be safely typed or pasted into the IPython shell; the ``>>>``
+ is ignored.
+
+- Examples often use ``np`` as an alias for ``numpy``; that is, they assume
+ you've run::
+
+ >>> import numpy as np
+
+- If you're a code contributor writing a docstring, see :ref:`docstring_intro`.
+
+- If you're a writer contributing ordinary (non-docstring) documentation, see
+ :ref:`userdoc_guide`.
.. _howto-document:
-A Guide to NumPy/SciPy Documentation
-====================================
+A Guide to NumPy Documentation
+==============================
+
+.. _userdoc_guide:
+
+User documentation
+******************
+- In general, we follow the
+ `Google developer documentation style guide <https://developers.google.com/style>`_.
+
+- NumPy style governs cases where:
+
+ - Google has no guidance, or
+ - We prefer not to use the Google style
+
+ Our current rules:
+
+ - We pluralize *index* as *indices* rather than
+ `indexes <https://developers.google.com/style/word-list#letter-i>`_,
+ following the precedent of :func:`numpy.indices`.
+
+ - For consistency we also pluralize *matrix* as *matrices*.
+
+- Grammatical issues inadequately addressed by the NumPy or Google rules are
+ decided by the section on "Grammar and Usage" in the most recent edition of
+ the `Chicago Manual of Style
+ <https://en.wikipedia.org/wiki/The_Chicago_Manual_of_Style>`_.
+
+- We welcome being
+ `alerted <https://github.com/numpy/numpy/issues>`_ to cases
+ we should add to the NumPy style rules.
+
+
+
+.. _docstring_intro:
+
+Docstrings
+**********
When using `Sphinx <http://www.sphinx-doc.org/>`__ in combination with the
numpy conventions, you should use the ``numpydoc`` extension so that your
np.fft.fft2(...)
-.. rubric::
- **For convenience the** `formatting standard`_ **is included below with an
- example**
-
-.. include:: ../../sphinxext/doc/format.rst
-
-.. _example:
-
-Example Source
-==============
-
-.. literalinclude:: ../../sphinxext/doc/example.py
-
-
-
-Example Rendered
-================
-
-.. ifconfig:: python_version_major < '3'
-
- The example is rendered only when sphinx is run with python3 and above
-
-.. automodule:: doc.example
- :members:
+Please use the numpydoc `formatting standard`_ as shown in their example_
.. _`formatting standard`: https://numpydoc.readthedocs.io/en/latest/format.html
+.. _example: https://numpydoc.readthedocs.io/en/latest/example.html
>>> import allocarr
>>> print(allocarr.mod.__doc__)
-b - 'f'-array(-1,-1), not allocated
-foo - Function signature:
- foo()
+b : 'f'-array(-1,-1), not allocated
+foo()
+
+Wrapper for ``foo``.
+
+
>>> allocarr.mod.foo()
b is not allocated
>>> import common
>>> print(common.data.__doc__)
-i - 'i'-scalar
-x - 'i'-array(4)
-a - 'f'-array(2,3)
+i : 'i'-scalar
+x : 'i'-array(4)
+a : 'f'-array(2,3)
>>> common.data.i = 5
>>> common.data.x[1] = 2
Using via `numpy.distutils`
=============================
+.. currentmodule:: numpy.distutils.core
+
:mod:`numpy.distutils` is part of NumPy extending standard Python ``distutils``
to deal with Fortran sources and F2PY signature files, e.g. compile Fortran
sources, call F2PY to construct extension modules, etc.
>>> import moddata
>>> print(moddata.mod.__doc__)
-i - 'i'-scalar
-x - 'i'-array(4)
-a - 'f'-array(2,3)
-foo - Function signature:
- foo()
+i : 'i'-scalar
+x : 'i'-array(4)
+a : 'f'-array(2,3)
+b : 'f'-array(-1,-1), not allocated
+foo()
+
+Wrapper for ``foo``.
+
+
>>> moddata.mod.i = 5
>>> moddata.mod.x[:2] = [1,2]
A string can have arbitrary length when using it as a string argument
to F2PY generated wrapper function. If the length is greater than
-expected, the string is truncated. If the length is smaller that
+expected, the string is truncated. If the length is smaller than
expected, additional memory is allocated and filled with ``\0``.
Because Python strings are immutable, an ``intent(inout)`` argument
Glossary
********
-.. toctree::
+.. glossary::
+
+
+ (`n`,)
+ A parenthesized number followed by a comma denotes a tuple with one
+ element. The trailing comma distinguishes a one-element tuple from a
+ parenthesized ``n``.
+
+
+ -1
+ - **In a dimension entry**, instructs NumPy to choose the length
+ that will keep the total number of array elements the same.
+
+ >>> np.arange(12).reshape(4, -1).shape
+ (4, 3)
+
+ - **In an index**, any negative value
+ `denotes <https://docs.python.org/dev/faq/programming.html#what-s-a-negative-index>`_
+ indexing from the right.
+
+ . . .
+ An :py:data:`Ellipsis`.
+
+ - **When indexing an array**, shorthand that the missing axes, if they
+ exist, are full slices.
+
+ >>> a = np.arange(24).reshape(2,3,4)
+
+ >>> a[...].shape
+ (2, 3, 4)
+
+ >>> a[...,0].shape
+ (2, 3)
+
+ >>> a[0,...].shape
+ (3, 4)
+
+ >>> a[0,...,0].shape
+ (3,)
+
+ It can be used at most once; ``a[...,0,...]`` raises an :exc:`IndexError`.
+
+ - **In printouts**, NumPy substitutes ``...`` for the middle elements of
+ large arrays. To see the entire array, use `numpy.printoptions`
+
+
+ :
+ The Python :term:`python:slice`
+ operator. In ndarrays, slicing can be applied to every
+ axis:
+
+ >>> a = np.arange(24).reshape(2,3,4)
+ >>> a
+ array([[[ 0, 1, 2, 3],
+ [ 4, 5, 6, 7],
+ [ 8, 9, 10, 11]],
+ <BLANKLINE>
+ [[12, 13, 14, 15],
+ [16, 17, 18, 19],
+ [20, 21, 22, 23]]])
+ <BLANKLINE>
+ >>> a[1:,-2:,:-1]
+ array([[[16, 17, 18],
+ [20, 21, 22]]])
+
+ Trailing slices can be omitted: ::
+
+ >>> a[1] == a[1,:,:]
+ array([[ True, True, True, True],
+ [ True, True, True, True],
+ [ True, True, True, True]])
+
+ In contrast to Python, where slicing creates a copy, in NumPy slicing
+ creates a :term:`view`.
+
+ For details, see :ref:`combining-advanced-and-basic-indexing`.
+
+
+ <
+ In a dtype declaration, indicates that the data is
+ :term:`little-endian` (the bracket is big on the right). ::
+
+ >>> dt = np.dtype('<f') # little-endian single-precision float
+
+
+ >
+ In a dtype declaration, indicates that the data is
+ :term:`big-endian` (the bracket is big on the left). ::
+
+ >>> dt = np.dtype('>H') # big-endian unsigned short
+
+
+ advanced indexing
+ Rather than using a :doc:`scalar <reference/arrays.scalars>` or slice as
+ an index, an axis can be indexed with an array, providing fine-grained
+ selection. This is known as :ref:`advanced indexing<advanced-indexing>`
+ or "fancy indexing".
+
+
+ along an axis
+ An operation `along axis n` of array ``a`` behaves as if its argument
+ were an array of slices of ``a`` where each slice has a successive
+ index of axis `n`.
+
+ For example, if ``a`` is a 3 x `N` array, an operation along axis 0
+ behaves as if its argument were an array containing slices of each row:
+
+ >>> np.array((a[0,:], a[1,:], a[2,:])) #doctest: +SKIP
+
+ To make it concrete, we can pick the operation to be the array-reversal
+ function :func:`numpy.flip`, which accepts an ``axis`` argument. We
+ construct a 3 x 4 array ``a``:
+
+ >>> a = np.arange(12).reshape(3,4)
+ >>> a
+ array([[ 0, 1, 2, 3],
+ [ 4, 5, 6, 7],
+ [ 8, 9, 10, 11]])
+
+ Reversing along axis 0 (the row axis) yields
+
+ >>> np.flip(a,axis=0)
+ array([[ 8, 9, 10, 11],
+ [ 4, 5, 6, 7],
+ [ 0, 1, 2, 3]])
+
+ Recalling the definition of `along an axis`, ``flip`` along axis 0 is
+ treating its argument as if it were
+
+ >>> np.array((a[0,:], a[1,:], a[2,:]))
+ array([[ 0, 1, 2, 3],
+ [ 4, 5, 6, 7],
+ [ 8, 9, 10, 11]])
+
+ and the result of ``np.flip(a,axis=0)`` is to reverse the slices:
+
+ >>> np.array((a[2,:],a[1,:],a[0,:]))
+ array([[ 8, 9, 10, 11],
+ [ 4, 5, 6, 7],
+ [ 0, 1, 2, 3]])
+
+
+ array
+ Used synonymously in the NumPy docs with :term:`ndarray`.
+
+
+ array_like
+ Any :doc:`scalar <reference/arrays.scalars>` or
+ :term:`python:sequence`
+ that can be interpreted as an ndarray. In addition to ndarrays
+ and scalars this category includes lists (possibly nested and with
+ different element types) and tuples. Any argument accepted by
+ :doc:`numpy.array <reference/generated/numpy.array>`
+ is array_like. ::
+
+ >>> a = np.array([[1, 2.0], [0, 0], (1+1j, 3.)])
+
+ >>> a
+ array([[1.+0.j, 2.+0.j],
+ [0.+0.j, 0.+0.j],
+ [1.+1.j, 3.+0.j]])
+
+
+ array scalar
+ For uniformity in handling operands, NumPy treats
+ a :doc:`scalar <reference/arrays.scalars>` as an array of zero
+ dimension.
+
+
+ axis
+ Another term for an array dimension. Axes are numbered left to right;
+ axis 0 is the first element in the shape tuple.
+
+ In a two-dimensional vector, the elements of axis 0 are rows and the
+ elements of axis 1 are columns.
+
+ In higher dimensions, the picture changes. NumPy prints
+ higher-dimensional vectors as replications of row-by-column building
+ blocks, as in this three-dimensional vector:
+
+ >>> a = np.arange(12).reshape(2,2,3)
+ >>> a
+ array([[[ 0, 1, 2],
+ [ 3, 4, 5]],
+ [[ 6, 7, 8],
+ [ 9, 10, 11]]])
+
+ ``a`` is depicted as a two-element array whose elements are 2x3 vectors.
+ From this point of view, rows and columns are the final two axes,
+ respectively, in any shape.
+
+ This rule helps you anticipate how a vector will be printed, and
+ conversely how to find the index of any of the printed elements. For
+ instance, in the example, the last two values of 8's index must be 0 and
+ 2. Since 8 appears in the second of the two 2x3's, the first index must
+ be 1:
+
+ >>> a[1,0,2]
+ 8
+
+ A convenient way to count dimensions in a printed vector is to
+ count ``[`` symbols after the open-parenthesis. This is
+ useful in distinguishing, say, a (1,2,3) shape from a (2,3) shape:
+
+ >>> a = np.arange(6).reshape(2,3)
+ >>> a.ndim
+ 2
+ >>> a
+ array([[0, 1, 2],
+ [3, 4, 5]])
+
+ >>> a = np.arange(6).reshape(1,2,3)
+ >>> a.ndim
+ 3
+ >>> a
+ array([[[0, 1, 2],
+ [3, 4, 5]]])
+
+
+ .base
+
+ If an array does not own its memory, then its
+ :doc:`base <reference/generated/numpy.ndarray.base>` attribute returns
+ the object whose memory the array is referencing. That object may be
+ referencing the memory from still another object, so the owning object
+ may be ``a.base.base.base...``. Some writers erroneously claim that
+ testing ``base`` determines if arrays are :term:`view`\ s. For the
+ correct way, see :func:`numpy.shares_memory`.
+
+
+ big-endian
+ See `Endianness <https://en.wikipedia.org/wiki/Endianness>`_.
+
+
+ BLAS
+ `Basic Linear Algebra Subprograms <https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms>`_
+
+
+ broadcast
+ *broadcasting* is NumPy's ability to process ndarrays of
+ different sizes as if all were the same size.
+
+ It permits an elegant do-what-I-mean behavior where, for instance,
+ adding a scalar to a vector adds the scalar value to every element.
+
+ >>> a = np.arange(3)
+ >>> a
+ array([0, 1, 2])
+
+ >>> a + [3, 3, 3]
+ array([3, 4, 5])
+
+ >>> a + 3
+ array([3, 4, 5])
+
+ Ordinarly, vector operands must all be the same size, because NumPy
+ works element by element -- for instance, ``c = a * b`` is ::
+
+ c[0,0,0] = a[0,0,0] * b[0,0,0]
+ c[0,0,1] = a[0,0,1] * b[0,0,1]
+ ...
+
+ But in certain useful cases, NumPy can duplicate data along "missing"
+ axes or "too-short" dimensions so shapes will match. The duplication
+ costs no memory or time. For details, see
+ :doc:`Broadcasting. <user/basics.broadcasting>`
+
+
+ C order
+ Same as :term:`row-major`.
+
+
+ column-major
+ See `Row- and column-major order <https://en.wikipedia.org/wiki/Row-_and_column-major_order>`_.
+
+
+ contiguous
+ An array is contiguous if
+ * it occupies an unbroken block of memory, and
+ * array elements with higher indexes occupy higher addresses (that
+ is, no :term:`stride` is negative).
+
+
+ copy
+ See :term:`view`.
+
+
+ dimension
+ See :term:`axis`.
+
+
+ dtype
+ The datatype describing the (identically typed) elements in an ndarray.
+ It can be changed to reinterpret the array contents. For details, see
+ :doc:`Data type objects (dtype). <reference/arrays.dtypes>`
+
+
+ fancy indexing
+ Another term for :term:`advanced indexing`.
+
+
+ field
+ In a :term:`structured data type`, each subtype is called a `field`.
+ The `field` has a name (a string), a type (any valid dtype), and
+ an optional `title`. See :ref:`arrays.dtypes`.
+
+
+ Fortran order
+ Same as :term:`column-major`.
+
+
+ flattened
+ See :term:`ravel`.
+
+
+ homogeneous
+ All elements of a homogeneous array have the same type. ndarrays, in
+ contrast to Python lists, are homogeneous. The type can be complicated,
+ as in a :term:`structured array`, but all elements have that type.
+
+ NumPy `object arrays <#term-object-array>`_, which contain references to
+ Python objects, fill the role of heterogeneous arrays.
+
+
+ itemsize
+ The size of the dtype element in bytes.
+
+
+ little-endian
+ See `Endianness <https://en.wikipedia.org/wiki/Endianness>`_.
+
+
+ mask
+ A boolean array used to select only certain elements for an operation:
+
+ >>> x = np.arange(5)
+ >>> x
+ array([0, 1, 2, 3, 4])
+
+ >>> mask = (x > 2)
+ >>> mask
+ array([False, False, False, True, True])
+
+ >>> x[mask] = -1
+ >>> x
+ array([ 0, 1, 2, -1, -1])
+
+
+ masked array
+ Bad or missing data can be cleanly ignored by putting it in a masked
+ array, which has an internal boolean array indicating invalid
+ entries. Operations with masked arrays ignore these entries. ::
+
+ >>> a = np.ma.masked_array([np.nan, 2, np.nan], [True, False, True])
+ >>> a
+ masked_array(data=[--, 2.0, --],
+ mask=[ True, False, True],
+ fill_value=1e+20)
+
+ >>> a + [1, 2, 3]
+ masked_array(data=[--, 4.0, --],
+ mask=[ True, False, True],
+ fill_value=1e+20)
+
+ For details, see :doc:`Masked arrays. <reference/maskedarray>`
+
+
+ matrix
+ NumPy's two-dimensional
+ :doc:`matrix class <reference/generated/numpy.matrix>`
+ should no longer be used; use regular ndarrays.
+
+
+ ndarray
+ :doc:`NumPy's basic structure <reference/arrays>`.
+
+
+ object array
+ An array whose dtype is ``object``; that is, it contains references to
+ Python objects. Indexing the array dereferences the Python objects, so
+ unlike other ndarrays, an object array has the ability to hold
+ heterogeneous objects.
+
+
+ ravel
+ :doc:`numpy.ravel \
+ <reference/generated/numpy.ravel>`
+ and :doc:`numpy.flatten \
+ <reference/generated/numpy.ndarray.flatten>`
+ both flatten an ndarray. ``ravel`` will return a view if possible;
+ ``flatten`` always returns a copy.
+
+ Flattening collapses a multimdimensional array to a single dimension;
+ details of how this is done (for instance, whether ``a[n+1]`` should be
+ the next row or next column) are parameters.
+
+
+ record array
+ A :term:`structured array` with allowing access in an attribute style
+ (``a.field``) in addition to ``a['field']``. For details, see
+ :doc:`numpy.recarray. <reference/generated/numpy.recarray>`
+
+
+ row-major
+ See `Row- and column-major order <https://en.wikipedia.org/wiki/Row-_and_column-major_order>`_.
+ NumPy creates arrays in row-major order by default.
+
+
+ scalar
+ In NumPy, usually a synonym for :term:`array scalar`.
+
+
+ shape
+ A tuple showing the length of each dimension of an ndarray. The
+ length of the tuple itself is the number of dimensions
+ (:doc:`numpy.ndim <reference/generated/numpy.ndarray.ndim>`).
+ The product of the tuple elements is the number of elements in the
+ array. For details, see
+ :doc:`numpy.ndarray.shape <reference/generated/numpy.ndarray.shape>`.
+
+
+ stride
+ Physical memory is one-dimensional; strides provide a mechanism to map
+ a given index to an address in memory. For an N-dimensional array, its
+ ``strides`` attribute is an N-element tuple; advancing from index
+ ``i`` to index ``i+1`` on axis ``n`` means adding ``a.strides[n]`` bytes
+ to the address.
+
+ Strides are computed automatically from an array's dtype and
+ shape, but can be directly specified using
+ :doc:`as_strided. <reference/generated/numpy.lib.stride_tricks.as_strided>`
+
+ For details, see
+ :doc:`numpy.ndarray.strides <reference/generated/numpy.ndarray.strides>`.
+
+ To see how striding underlies the power of NumPy views, see
+ `The NumPy array: a structure for efficient numerical computation. \
+ <https://arxiv.org/pdf/1102.1523.pdf>`_
+
+
+ structured array
+ Array whose :term:`dtype` is a :term:`structured data type`.
+
+
+ structured data type
+ Users can create arbitrarily complex :term:`dtypes <dtype>`
+ that can include other arrays and dtypes. These composite dtypes are called
+ :doc:`structured data types. <user/basics.rec>`
+
+
+ subarray
+ An array nested in a :term:`structured data type`, as ``b`` is here:
+
+ >>> dt = np.dtype([('a', np.int32), ('b', np.float32, (3,))])
+ >>> np.zeros(3, dtype=dt)
+ array([(0, [0., 0., 0.]), (0, [0., 0., 0.]), (0, [0., 0., 0.])],
+ dtype=[('a', '<i4'), ('b', '<f4', (3,))])
+
+
+ subarray data type
+ An element of a structured datatype that behaves like an ndarray.
+
+
+ title
+ An alias for a field name in a structured datatype.
+
+
+ type
+ In NumPy, usually a synonym for :term:`dtype`. For the more general
+ Python meaning, :term:`see here. <python:type>`
+
+
+ ufunc
+ NumPy's fast element-by-element computation (:term:`vectorization`)
+ gives a choice which function gets applied. The general term for the
+ function is ``ufunc``, short for ``universal function``. NumPy routines
+ have built-in ufuncs, but users can also
+ :doc:`write their own. <reference/ufuncs>`
+
+
+ vectorization
+ NumPy hands off array processing to C, where looping and computation are
+ much faster than in Python. To exploit this, programmers using NumPy
+ eliminate Python loops in favor of array-to-array operations.
+ :term:`vectorization` can refer both to the C offloading and to
+ structuring NumPy code to leverage it.
+
+ view
+ Without touching underlying data, NumPy can make one array appear
+ to change its datatype and shape.
+
+ An array created this way is a `view`, and NumPy often exploits the
+ performance gain of using a view versus making a new array.
+
+ A potential drawback is that writing to a view can alter the original
+ as well. If this is a problem, NumPy instead needs to create a
+ physically distinct array -- a `copy`.
+
+ Some NumPy routines always return views, some always return copies, some
+ may return one or the other, and for some the choice can be specified.
+ Responsiblity for managing views and copies falls to the programmer.
+ :func:`numpy.shares_memory` will check whether ``b`` is a view of
+ ``a``, but an exact answer isn't always feasible, as the documentation
+ page explains.
+
+ >>> x = np.arange(5)
+ >>> x
+ array([0, 1, 2, 3, 4])
+
+ >>> y = x[::2]
+ >>> y
+ array([0, 2, 4])
+
+ >>> x[0] = 3 # changing x changes y as well, since y is a view on x
+ >>> y
+ array([3, 2, 4])
-.. automodule:: numpy.doc.glossary
*************
-NumPy License
+NumPy license
*************
-Copyright (c) 2005, NumPy Developers
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-* Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
-
-* Neither the name of the NumPy Developers nor the names of any
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.. include:: ../../LICENSE.txt
+ :literal:
- ``func`` is an arbitrary callable exposed by NumPy's public API,
which was called in the form ``func(*args, **kwargs)``.
- - ``types`` is a `collection <collections.abc.Collection>`_
+ - ``types`` is a collection :py:class:`collections.abc.Collection`
of unique argument types from the original NumPy function call that
implement ``__array_function__``.
- The tuple ``args`` and dict ``kwargs`` are directly passed on from the
If a class (ndarray subclass or not) having the :func:`__array__`
method is used as the output object of an :ref:`ufunc
- <ufuncs-output-type>`, results will be written to the object
- returned by :func:`__array__`. Similar conversion is done on
- input arrays.
+ <ufuncs-output-type>`, results will *not* be written to the object
+ returned by :func:`__array__`. This practice will return ``TypeError``.
Matrix objects
The `chararray` class exists for backwards compatibility with
Numarray, it is not recommended for new development. Starting from numpy
1.4, if one needs arrays of strings, it is recommended to use arrays of
- `dtype` `object_`, `string_` or `unicode_`, and use the free functions
+ `dtype` `object_`, `bytes_` or `str_`, and use the free functions
in the `numpy.char` module for fast vectorized string operations.
-These are enhanced arrays of either :class:`string_` type or
-:class:`unicode_` type. These arrays inherit from the
+These are enhanced arrays of either :class:`str_` type or
+:class:`bytes_` type. These arrays inherit from the
:class:`ndarray`, but specially-define the operations ``+``, ``*``,
and ``%`` on a (broadcasting) element-by-element basis. These
operations are not available on the standard :class:`ndarray` of
character type. In addition, the :class:`chararray` has all of the
-standard :class:`string <str>` (and :class:`unicode`) methods,
+standard :class:`str` (and :class:`bytes`) methods,
executing them on an element-by-element basis. Perhaps the easiest
way to create a chararray is to use :meth:`self.view(chararray)
<ndarray.view>` where *self* is an ndarray of str or unicode
m minute +/- 1.7e13 years [1.7e13 BC, 1.7e13 AD]
s second +/- 2.9e11 years [2.9e11 BC, 2.9e11 AD]
ms millisecond +/- 2.9e8 years [ 2.9e8 BC, 2.9e8 AD]
- us microsecond +/- 2.9e5 years [290301 BC, 294241 AD]
+us / μs microsecond +/- 2.9e5 years [290301 BC, 294241 AD]
ns nanosecond +/- 292 years [ 1678 AD, 2262 AD]
ps picosecond +/- 106 days [ 1969 AD, 1970 AD]
fs femtosecond +/- 2.6 hours [ 1969 AD, 1970 AD]
What can be converted to a data-type object is described below:
:class:`dtype` object
-
.. index::
triple: dtype; construction; from dtype
Used as-is.
None
-
.. index::
triple: dtype; construction; from None
triple: dtype; construction; from type
Array-scalar types
-
The 24 built-in :ref:`array scalar type objects
<arrays.scalars.built-in>` all convert to an associated data-type object.
This is true for their sub-classes as well.
>>> dt = np.dtype(np.complex128) # 128-bit complex floating-point number
Generic types
-
- .. deprecated NumPy 1.19::
-
- The use of generic types is deprecated. This is because it can be
- unexpected in a context such as ``arr.astype(dtype=np.floating)``.
- ``arr.astype(dtype=np.floating)`` which casts an array of ``float32``
- to an array of ``float64``, even though ``float32`` is a subdtype of
- ``np.floating``.
-
The generic hierarchical type objects convert to corresponding
type objects according to the associations:
:class:`generic`, :class:`flexible` :class:`void`
===================================================== ===============
-Built-in Python types
+ .. deprecated:: 1.19
+
+ This conversion of generic scalar types is deprecated.
+ This is because it can be unexpected in a context such as
+ ``arr.astype(dtype=np.floating)``, which casts an array of ``float32``
+ to an array of ``float64``, even though ``float32`` is a subdtype of
+ ``np.floating``.
+
+Built-in Python types
Several python types are equivalent to a corresponding
array scalar when used to generate a :class:`dtype` object:
.. note::
All other types map to ``object_`` for convenience. Code should expect
- that such types may map to a specific (new) dtype in future the future.
+ that such types may map to a specific (new) dtype in the future.
Types with ``.dtype``
-
Any type object with a ``dtype`` attribute: The attribute will be
accessed and used directly. The attribute must return something
that is convertible into a dtype object.
specify the byte order.
One-character strings
-
Each built-in data-type has a character code
(the updated Numeric typecodes), that uniquely identifies it.
>>> dt = np.dtype('d') # double-precision floating-point number
Array-protocol type strings (see :ref:`arrays.interface`)
-
The first character specifies the kind of data and the remaining
characters specify the number of bytes per item, except for Unicode,
where it is interpreted as the number of characters. The item size
.. admonition:: Note on string types
For backward compatibility with Python 2 the ``S`` and ``a`` typestrings
- remain zero-terminated bytes and ``np.string_`` continues to map to
- ``np.bytes_``.
- To use actual strings in Python 3 use ``U`` or ``np.unicode_``.
+ remain zero-terminated bytes and `numpy.string_` continues to alias
+ `numpy.bytes_`. To use actual strings in Python 3 use ``U`` or `numpy.str_`.
For signed bytes that do not need zero-termination ``b`` or ``i1`` can be
used.
String with comma-separated fields
-
A short-hand notation for specifying the format of a structured data type is
a comma-separated string of basic formats.
>>> dt = np.dtype("a3, 3u8, (3,4)a10")
Type strings
-
Any string in :obj:`numpy.sctypeDict`.keys():
.. admonition:: Example
triple: dtype; construction; from tuple
``(flexible_dtype, itemsize)``
-
The first argument must be an object that is converted to a
zero-sized flexible data-type object, the second argument is
an integer providing the desired itemsize.
>>> dt = np.dtype(('U', 10)) # 10-character unicode string
``(fixed_dtype, shape)``
-
.. index::
pair: dtype; sub-array
triple: dtype; construction; from list
``[(field_name, field_dtype, field_shape), ...]``
-
*obj* should be a list of fields where each field is described by a
tuple of length 2 or 3. (Equivalent to the ``descr`` item in the
- :obj:`__array_interface__` attribute.)
+ :obj:`~object.__array_interface__` attribute.)
The first element, *field_name*, is the field name (if this is
``''`` then a standard field name, ``'f#'``, is assigned). The
triple: dtype; construction; from dict
``{'names': ..., 'formats': ..., 'offsets': ..., 'titles': ..., 'itemsize': ...}``
-
This style has two required and three optional keys. The *names*
and *formats* keys are required. Their respective values are
equal-length lists with the field names and the field formats.
their values must each be lists of the same length as the *names*
and *formats* lists. The *offsets* value is a list of byte offsets
(limited to `ctypes.c_int`) for each field, while the *titles* value is a
- list of titles for each field (None can be used if no title is
- desired for that field). The *titles* can be any :class:`string`
- or :class:`unicode` object and will add another entry to the
+ list of titles for each field (``None`` can be used if no title is
+ desired for that field). The *titles* can be any object, but when a
+ :class:`str` object will add another entry to the
fields dictionary keyed by the title and referencing the same
field tuple which will contain the title as an additional tuple
member.
``{'field1': ..., 'field2': ..., ...}``
-
This usage is discouraged, because it is ambiguous with the
other dict-based construction method. If you have a field
called 'names' and a field called 'formats' there will be
... 'col3': (int, 14)})
``(base_dtype, new_dtype)``
-
In NumPy 1.7 and later, this form allows `base_dtype` to be interpreted as
a structured dtype. Arrays created with this dtype will have underlying
dtype `base_dtype` but will have fields and flags taken from `new_dtype`.
dtype.alignment
dtype.base
+Metadata attached by the user:
+
+.. autosummary::
+ :toctree: generated/
+
+ dtype.metadata
+
Methods
-------
Basic slicing extends Python's basic concept of slicing to N
dimensions. Basic slicing occurs when *obj* is a :class:`slice` object
(constructed by ``start:stop:step`` notation inside of brackets), an
-integer, or a tuple of slice objects and integers. :const:`Ellipsis`
+integer, or a tuple of slice objects and integers. :py:data:`Ellipsis`
and :const:`newaxis` objects can be interspersed with these as
well.
In order to remain backward compatible with a common usage in
Numeric, basic slicing is also initiated if the selection object is
any non-ndarray and non-tuple sequence (such as a :class:`list`) containing
- :class:`slice` objects, the :const:`Ellipsis` object, or the :const:`newaxis`
+ :class:`slice` objects, the :py:data:`Ellipsis` object, or the :const:`newaxis`
object, but not for integer arrays or other embedded sequences.
.. index::
[5],
[6]]])
-- :const:`Ellipsis` expands to the number of ``:`` objects needed for the
+- :py:data:`Ellipsis` expands to the number of ``:`` objects needed for the
selection tuple to index all dimensions. In most cases, this means that
length of the expanded selection tuple is ``x.ndim``. There may only be a
single ellipsis present.
create an axis of length one. :const:`newaxis` is an alias for
'None', and 'None' can be used in place of this with the same result.
+.. _advanced-indexing:
Advanced Indexing
-----------------
most important thing to remember about indexing with multiple advanced
indexes.
+.. _combining-advanced-and-basic-indexing:
+
Combining advanced and basic indexing
"""""""""""""""""""""""""""""""""""""
subspace from the advanced indexing part. Two cases of index combination
need to be distinguished:
-* The advanced indexes are separated by a slice, :const:`Ellipsis` or :const:`newaxis`.
+* The advanced indexes are separated by a slice, :py:data:`Ellipsis` or :const:`newaxis`.
For example ``x[arr1, :, arr2]``.
* The advanced indexes are all next to each other.
For example ``x[..., arr1, arr2, :]`` but *not* ``x[arr1, :, 1]``
boolean index array is practically identical to ``x[obj.nonzero()]`` where,
as described above, :meth:`obj.nonzero() <ndarray.nonzero>` returns a
tuple (of length :attr:`obj.ndim <ndarray.ndim>`) of integer index
-arrays showing the :const:`True` elements of *obj*. However, it is
+arrays showing the :py:data:`True` elements of *obj*. However, it is
faster when ``obj.shape == x.shape``.
If ``obj.ndim == x.ndim``, ``x[obj]`` returns a 1-dimensional array
-filled with the elements of *x* corresponding to the :const:`True`
+filled with the elements of *x* corresponding to the :py:data:`True`
values of *obj*. The search order will be :term:`row-major`,
-C-style. If *obj* has :const:`True` values at entries that are outside
+C-style. If *obj* has :py:data:`True` values at entries that are outside
of the bounds of *x*, then an index error will be raised. If *obj* is
-smaller than *x* it is identical to filling it with :const:`False`.
+smaller than *x* it is identical to filling it with :py:data:`False`.
.. admonition:: Example
array([[ 3, 5],
[ 9, 11]])
- Without the ``np.ix_`` call or only the diagonal elements would be
+ Without the ``np.ix_`` call, only the diagonal elements would be
selected.
Or without ``np.ix_`` (compare the integer array examples):
===========
This approach to the interface consists of the object having an
-:data:`__array_interface__` attribute.
+:data:`~object.__array_interface__` attribute.
-.. data:: __array_interface__
+.. data:: object.__array_interface__
A dictionary of items (3 required and 5 optional). The optional
keys in the dictionary have implied defaults if they are not
The keys are:
**shape** (required)
-
Tuple whose elements are the array size in each dimension. Each
- entry is an integer (a Python int or long). Note that these
- integers could be larger than the platform "int" or "long"
- could hold (a Python int is a C long). It is up to the code
+ entry is an integer (a Python :py:class:`int`). Note that these
+ integers could be larger than the platform ``int`` or ``long``
+ could hold (a Python :py:class:`int` is a C ``long``). It is up to the code
using this attribute to handle this appropriately; either by
raising an error when overflow is possible, or by using
- :c:data:`Py_LONG_LONG` as the C type for the shapes.
+ ``long long`` as the C type for the shapes.
**typestr** (required)
-
- A string providing the basic type of the homogenous array The
+ A string providing the basic type of the homogeneous array The
basic string format consists of 3 parts: a character describing
the byteorder of the data (``<``: little-endian, ``>``:
big-endian, ``|``: not-relevant), a character code giving the
===== ================================================================
**descr** (optional)
-
A list of tuples providing a more detailed description of the
memory layout for each item in the homogeneous array. Each
tuple in the list has two or three elements. Normally, this
**Default**: ``[('', typestr)]``
**data** (optional)
-
A 2-tuple whose first argument is an integer (a long integer
if necessary) that points to the data-area storing the array
contents. This pointer must point to the first element of
means the data area is read-only).
This attribute can also be an object exposing the
- :c:func:`buffer interface <PyObject_AsCharBuffer>` which
+ :ref:`buffer interface <bufferobjects>` which
will be used to share the data. If this key is not present (or
returns None), then memory sharing will be done
through the buffer interface of the object itself. In this
**Default**: None
**strides** (optional)
-
- Either None to indicate a C-style contiguous array or
+ Either ``None`` to indicate a C-style contiguous array or
a Tuple of strides which provides the number of bytes needed
to jump to the next array element in the corresponding
dimension. Each entry must be an integer (a Python
- :const:`int` or :const:`long`). As with shape, the values may
- be larger than can be represented by a C "int" or "long"; the
+ :py:class:`int`). As with shape, the values may
+ be larger than can be represented by a C ``int`` or ``long``; the
calling code should handle this appropriately, either by
- raising an error, or by using :c:type:`Py_LONG_LONG` in C. The
- default is None which implies a C-style contiguous
- memory buffer. In this model, the last dimension of the array
+ raising an error, or by using ``long long`` in C. The
+ default is ``None`` which implies a C-style contiguous
+ memory buffer. In this model, the last dimension of the array
varies the fastest. For example, the default strides tuple
for an object whose array entries are 8 bytes long and whose
- shape is (10,20,30) would be (4800, 240, 8)
+ shape is ``(10, 20, 30)`` would be ``(4800, 240, 8)``
- **Default**: None (C-style contiguous)
+ **Default**: ``None`` (C-style contiguous)
**mask** (optional)
-
None or an object exposing the array interface. All
elements of the mask array should be interpreted only as true
or not true indicating which elements of this array are valid.
**Default**: None (All array values are valid)
**offset** (optional)
-
An integer offset into the array data region. This can only be
- used when data is None or returns a :class:`buffer`
+ used when data is ``None`` or returns a :class:`buffer`
object.
**Default**: 0.
**version** (required)
-
An integer showing the version of the interface (i.e. 3 for
this version). Be careful not to use this to invalidate
objects exposing future versions of the interface.
This approach to the array interface allows for faster access to an
array using only one attribute lookup and a well-defined C-structure.
-.. c:var:: __array_struct__
+.. data:: object.__array_struct__
- A :c:type: `PyCObject` whose :c:data:`voidptr` member contains a
+ A :c:type:`PyCapsule` whose ``pointer`` member contains a
pointer to a filled :c:type:`PyArrayInterface` structure. Memory
- for the structure is dynamically created and the :c:type:`PyCObject`
+ for the structure is dynamically created and the :c:type:`PyCapsule`
is also created with an appropriate destructor so the retriever of
this attribute simply has to apply :c:func:`Py_DECREF()` to the
object returned by this attribute when it is finished. Also,
must also not reallocate their memory if other objects are
referencing them.
-The PyArrayInterface structure is defined in ``numpy/ndarrayobject.h``
+The :c:type:`PyArrayInterface` structure is defined in ``numpy/ndarrayobject.h``
as::
typedef struct {
The flags member may consist of 5 bits showing how the data should be
interpreted and one bit showing how the Interface should be
-interpreted. The data-bits are :const:`CONTIGUOUS` (0x1),
-:const:`FORTRAN` (0x2), :const:`ALIGNED` (0x100), :const:`NOTSWAPPED`
-(0x200), and :const:`WRITEABLE` (0x400). A final flag
-:const:`ARR_HAS_DESCR` (0x800) indicates whether or not this structure
+interpreted. The data-bits are :c:macro:`NPY_ARRAY_C_CONTIGUOUS` (0x1),
+:c:macro:`NPY_ARRAY_F_CONTIGUOUS` (0x2), :c:macro:`NPY_ARRAY_ALIGNED` (0x100),
+:c:macro:`NPY_ARRAY_NOTSWAPPED` (0x200), and :c:macro:`NPY_ARRAY_WRITEABLE` (0x400). A final flag
+:c:macro:`NPY_ARR_HAS_DESCR` (0x800) indicates whether or not this structure
has the arrdescr field. The field should not be accessed unless this
flag is present.
+ .. c:macro:: NPY_ARR_HAS_DESCR
+
.. admonition:: New since June 16, 2006:
- In the past most implementations used the "desc" member of the
- :c:type:`PyCObject` itself (do not confuse this with the "descr" member of
+ In the past most implementations used the ``desc`` member of the ``PyCObject``
+ (now :c:type:`PyCapsule`) itself (do not confuse this with the "descr" member of
the :c:type:`PyArrayInterface` structure above --- they are two separate
things) to hold the pointer to the object exposing the interface.
- This is now an explicit part of the interface. Be sure to own a
- reference to the object when the :c:type:`PyCObject` is created using
- :c:type:`PyCObject_FromVoidPtrAndDesc`.
+ This is now an explicit part of the interface. Be sure to take a
+ reference to the object and call :c:func:`PyCapsule_SetContext` before
+ returning the :c:type:`PyCapsule`, and configure a destructor to decref this
+ reference.
Type description examples
=========================
For clarity it is useful to provide some examples of the type
-description and corresponding :data:`__array_interface__` 'descr'
+description and corresponding :data:`~object.__array_interface__` 'descr'
entries. Thanks to Scott Gilbert for these examples:
In every case, the 'descr' key is optional, but of course provides
1. The PyArrayInterface structure had no descr member at the end
(and therefore no flag ARR_HAS_DESCR)
-2. The desc member of the PyCObject returned from __array_struct__ was
+2. The ``context`` member of the :c:type:`PyCapsule` (formally the ``desc``
+ member of the ``PyCObject``) returned from ``__array_struct__`` was
not specified. Usually, it was the object exposing the array (so
that a reference to it could be kept and destroyed when the
- C-object was destroyed). Now it must be a tuple whose first
- element is a string with "PyArrayInterface Version #" and whose
- second element is the object exposing the array.
+ C-object was destroyed). It is now an explicit requirement that this field
+ be used in some way to hold a reference to the owning object.
+
+ .. note::
+
+ Until August 2020, this said:
+
+ Now it must be a tuple whose first element is a string with
+ "PyArrayInterface Version #" and whose second element is the object
+ exposing the array.
+
+ This design was retracted almost immediately after it was proposed, in
+ <https://mail.python.org/pipermail/numpy-discussion/2006-June/020995.html>.
+ Despite 14 years of documentation to the contrary, at no point was it
+ valid to assume that ``__array_interface__`` capsules held this tuple
+ content.
-3. The tuple returned from __array_interface__['data'] used to be a
+3. The tuple returned from ``__array_interface__['data']`` used to be a
hex-string (now it is an integer or a long integer).
-4. There was no __array_interface__ attribute instead all of the keys
- (except for version) in the __array_interface__ dictionary were
+4. There was no ``__array_interface__`` attribute instead all of the keys
+ (except for version) in the ``__array_interface__`` dictionary were
their own attribute: Thus to obtain the Python-side information you
had to access separately the attributes:
- * __array_data__
- * __array_shape__
- * __array_strides__
- * __array_typestr__
- * __array_descr__
- * __array_offset__
- * __array_mask__
+ * ``__array_data__``
+ * ``__array_shape__``
+ * ``__array_strides__``
+ * ``__array_typestr__``
+ * ``__array_descr__``
+ * ``__array_offset__``
+ * ``__array_mask__``
+.. currentmodule:: numpy
+
.. _arrays.ndarray:
******************************************
The N-dimensional array (:class:`ndarray`)
******************************************
-.. currentmodule:: numpy
-
An :class:`ndarray` is a (usually fixed-size) multidimensional
container of items of the same type and size. The number of dimensions
and items in an array is defined by its :attr:`shape <ndarray.shape>`,
.. seealso:: :ref:`arrays.interface`.
-========================== ===================================
-:obj:`__array_interface__` Python-side of the array interface
-:obj:`__array_struct__` C-side of the array interface
-========================== ===================================
+================================== ===================================
+:obj:`~object.__array_interface__` Python-side of the array interface
+:obj:`~object.__array_struct__` C-side of the array interface
+================================== ===================================
:mod:`ctypes` foreign function interface
----------------------------------------
ndarray.__eq__
ndarray.__ne__
-Truth value of an array (:func:`bool()`):
+Truth value of an array (:class:`bool() <bool>`):
.. autosummary::
:toctree: generated/
ndarray.__setitem__
ndarray.__contains__
-Conversion; the operations :func:`int()`, :func:`float()` and
-:func:`complex()`.
-. They work only on arrays that have one element in them
+Conversion; the operations :class:`int() <int>`,
+:class:`float() <float>` and :class:`complex() <complex>`.
+They work only on arrays that have one element in them
and return the appropriate scalar.
.. autosummary::
should strongly consider directly using the iteration API provided
in C, but for those who are not comfortable with C or C++, Cython
is a good middle ground with reasonable performance tradeoffs. For
-the :class:`nditer` object, this means letting the iterator take care
+the :class:`~numpy.nditer` object, this means letting the iterator take care
of broadcasting, dtype conversion, and buffering, while giving the inner
loop to Cython.
Iterating Over Arrays
*********************
+.. note::
+
+ Arrays support the iterator protocol and can be iterated over like Python
+ lists. See the :ref:`quickstart.indexing-slicing-and-iterating` section in
+ the Quickstart guide for basic usage and examples. The remainder of
+ this document presents the :class:`nditer` object and covers more
+ advanced usage.
+
The iterator object :class:`nditer`, introduced in NumPy 1.6, provides
many flexible ways to visit all the elements of one or more arrays in
a systematic fashion. This page introduces some basic ways to use the
type. The items can be :ref:`indexed <arrays.indexing>` using for
example N integers.
-All ndarrays are :term:`homogenous`: every item takes up the same size
+All ndarrays are :term:`homogeneous`: every item takes up the same size
block of memory, and all blocks are interpreted in exactly the same
way. How each item in the array is to be interpreted is specified by a
separate :ref:`data-type object <arrays.dtypes>`, one of which is associated
Array scalars live in a hierarchy (see the Figure below) of data
types. They can be detected using the hierarchy: For example,
-``isinstance(val, np.generic)`` will return :const:`True` if *val* is
+``isinstance(val, np.generic)`` will return :py:data:`True` if *val* is
an array scalar object. Alternatively, what kind of array scalar is
present can be determined using other members of the data type
hierarchy. Thus, for example ``isinstance(val, np.complexfloating)``
-will return :const:`True` if *val* is a complex valued type, while
-:const:`isinstance(val, np.flexible)` will return true if *val* is one
-of the flexible itemsize array types (:class:`string`,
-:class:`unicode`, :class:`void`).
+will return :py:data:`True` if *val* is a complex valued type, while
+``isinstance(val, np.flexible)`` will return true if *val* is one
+of the flexible itemsize array types (:class:`str_`,
+:class:`bytes_`, :class:`void`).
.. figure:: figures/dtype-hierarchy.png
pointer for the platform. All the number types can be obtained
using bit-width names as well.
+
+.. TODO - use something like this instead of the diagram above, as it generates
+ links to the classes and is a vector graphic. Unfortunately it looks worse
+ and the html <map> element providing the linked regions is misaligned.
+
+ .. inheritance-diagram:: byte short intc int_ longlong ubyte ushort uintc uint ulonglong half single double longdouble csingle cdouble clongdouble bool_ datetime64 timedelta64 object_ bytes_ str_ void
+
.. [#] However, array scalars are immutable, so none of the array
scalar attributes are settable.
Built-in scalar types
=====================
-The built-in scalar types are shown below. Along with their (mostly)
-C-derived names, the integer, float, and complex data-types are also
-available using a bit-width convention so that an array of the right
-size can always be ensured (e.g. :class:`int8`, :class:`float64`,
-:class:`complex128`). Two aliases (:class:`intp` and :class:`uintp`)
-pointing to the integer type that is sufficiently large to hold a C pointer
-are also provided. The C-like names are associated with character codes,
-which are shown in the table. Use of the character codes, however,
+The built-in scalar types are shown below. The C-like names are associated with character codes,
+which are shown in their descriptions. Use of the character codes, however,
is discouraged.
Some of the scalar types are essentially equivalent to fundamental
Python types and therefore inherit from them as well as from the
generic array scalar type:
-==================== ================================
-Array scalar type Related Python type
-==================== ================================
-:class:`int_` :class:`IntType` (Python 2 only)
-:class:`float_` :class:`FloatType`
-:class:`complex_` :class:`ComplexType`
-:class:`bytes_` :class:`BytesType`
-:class:`unicode_` :class:`UnicodeType`
-==================== ================================
+==================== =========================== =============
+Array scalar type Related Python type Inherits?
+==================== =========================== =============
+:class:`int_` :class:`int` Python 2 only
+:class:`float_` :class:`float` yes
+:class:`complex_` :class:`complex` yes
+:class:`bytes_` :class:`bytes` yes
+:class:`str_` :class:`str` yes
+:class:`bool_` :class:`bool` no
+:class:`datetime64` :class:`datetime.datetime` no
+:class:`timedelta64` :class:`datetime.timedelta` no
+==================== =========================== =============
The :class:`bool_` data type is very similar to the Python
-:class:`BooleanType` but does not inherit from it because Python's
-:class:`BooleanType` does not allow itself to be inherited from, and
+:class:`bool` but does not inherit from it because Python's
+:class:`bool` does not allow itself to be inherited from, and
on the C-level the size of the actual bool data is not the same as a
Python Boolean scalar.
-.. warning::
-
- The :class:`bool_` type is not a subclass of the :class:`int_` type
- (the :class:`bool_` is not even a number type). This is different
- than Python's default implementation of :class:`bool` as a
- sub-class of int.
-
.. warning::
The :class:`int_` type does **not** inherit from the
.. tip:: The default data type in NumPy is :class:`float_`.
-In the tables below, ``platform?`` means that the type may not be
-available on all platforms. Compatibility with different C or Python
-types is indicated: two types are compatible if their data is of the
-same size and interpreted in the same way.
-
-Booleans:
-
-=================== ============================= ===============
-Type Remarks Character code
-=================== ============================= ===============
-:class:`bool_` compatible: Python bool ``'?'``
-:class:`bool8` 8 bits
-=================== ============================= ===============
-
-Integers:
-
-=================== ============================= ===============
-:class:`byte` compatible: C char ``'b'``
-:class:`short` compatible: C short ``'h'``
-:class:`intc` compatible: C int ``'i'``
-:class:`int_` compatible: Python int ``'l'``
-:class:`longlong` compatible: C long long ``'q'``
-:class:`intp` large enough to fit a pointer ``'p'``
-:class:`int8` 8 bits
-:class:`int16` 16 bits
-:class:`int32` 32 bits
-:class:`int64` 64 bits
-=================== ============================= ===============
-
-Unsigned integers:
-
-=================== ============================= ===============
-:class:`ubyte` compatible: C unsigned char ``'B'``
-:class:`ushort` compatible: C unsigned short ``'H'``
-:class:`uintc` compatible: C unsigned int ``'I'``
-:class:`uint` compatible: Python int ``'L'``
-:class:`ulonglong` compatible: C long long ``'Q'``
-:class:`uintp` large enough to fit a pointer ``'P'``
-:class:`uint8` 8 bits
-:class:`uint16` 16 bits
-:class:`uint32` 32 bits
-:class:`uint64` 64 bits
-=================== ============================= ===============
-
-Floating-point numbers:
-
-=================== ============================= ===============
-:class:`half` ``'e'``
-:class:`single` compatible: C float ``'f'``
-:class:`double` compatible: C double
-:class:`float_` compatible: Python float ``'d'``
-:class:`longfloat` compatible: C long float ``'g'``
-:class:`float16` 16 bits
-:class:`float32` 32 bits
-:class:`float64` 64 bits
-:class:`float96` 96 bits, platform?
-:class:`float128` 128 bits, platform?
-=================== ============================= ===============
-
-Complex floating-point numbers:
-
-=================== ============================= ===============
-:class:`csingle` ``'F'``
-:class:`complex_` compatible: Python complex ``'D'``
-:class:`clongfloat` ``'G'``
-:class:`complex64` two 32-bit floats
-:class:`complex128` two 64-bit floats
-:class:`complex192` two 96-bit floats,
- platform?
-:class:`complex256` two 128-bit floats,
- platform?
-=================== ============================= ===============
-
-Any Python object:
-
-=================== ============================= ===============
-:class:`object_` any Python object ``'O'``
-=================== ============================= ===============
+.. autoclass:: numpy.generic
+ :exclude-members:
+
+.. autoclass:: numpy.number
+ :exclude-members:
+
+Integer types
+~~~~~~~~~~~~~
+
+.. autoclass:: numpy.integer
+ :exclude-members:
+
+Signed integer types
+++++++++++++++++++++
+
+.. autoclass:: numpy.signedinteger
+ :exclude-members:
+
+.. autoclass:: numpy.byte
+ :exclude-members:
+
+.. autoclass:: numpy.short
+ :exclude-members:
+
+.. autoclass:: numpy.intc
+ :exclude-members:
+
+.. autoclass:: numpy.int_
+ :exclude-members:
+
+.. autoclass:: numpy.longlong
+ :exclude-members:
+
+Unsigned integer types
+++++++++++++++++++++++
+
+.. autoclass:: numpy.unsignedinteger
+ :exclude-members:
+
+.. autoclass:: numpy.ubyte
+ :exclude-members:
+
+.. autoclass:: numpy.ushort
+ :exclude-members:
+
+.. autoclass:: numpy.uintc
+ :exclude-members:
+
+.. autoclass:: numpy.uint
+ :exclude-members:
+
+.. autoclass:: numpy.ulonglong
+ :exclude-members:
+
+Inexact types
+~~~~~~~~~~~~~
+
+.. autoclass:: numpy.inexact
+ :exclude-members:
+
+Floating-point types
+++++++++++++++++++++
+
+.. autoclass:: numpy.floating
+ :exclude-members:
+
+.. autoclass:: numpy.half
+ :exclude-members:
+
+.. autoclass:: numpy.single
+ :exclude-members:
+
+.. autoclass:: numpy.double
+ :exclude-members:
+
+.. autoclass:: numpy.longdouble
+ :exclude-members:
+
+Complex floating-point types
+++++++++++++++++++++++++++++
+
+.. autoclass:: numpy.complexfloating
+ :exclude-members:
+
+.. autoclass:: numpy.csingle
+ :exclude-members:
+
+.. autoclass:: numpy.cdouble
+ :exclude-members:
+
+.. autoclass:: numpy.clongdouble
+ :exclude-members:
+
+Other types
+~~~~~~~~~~~
+
+.. autoclass:: numpy.bool_
+ :exclude-members:
+
+.. autoclass:: numpy.datetime64
+ :exclude-members:
+
+.. autoclass:: numpy.timedelta64
+ :exclude-members:
+
+.. autoclass:: numpy.object_
+ :exclude-members:
.. note::
arrays. (In the character codes ``#`` is an integer denoting how many
elements the data type consists of.)
-=================== ============================== ========
-:class:`bytes_` compatible: Python bytes ``'S#'``
-:class:`unicode_` compatible: Python unicode/str ``'U#'``
-:class:`void` ``'V#'``
-=================== ============================== ========
+.. autoclass:: numpy.flexible
+ :exclude-members:
+
+.. autoclass:: numpy.bytes_
+ :exclude-members:
+
+.. autoclass:: numpy.str_
+ :exclude-members:
+
+.. autoclass:: numpy.void
+ :exclude-members:
.. warning::
convention more consistent with other Python modules such as the
:mod:`struct` module.
+Sized aliases
+~~~~~~~~~~~~~
+
+Along with their (mostly)
+C-derived names, the integer, float, and complex data-types are also
+available using a bit-width convention so that an array of the right
+size can always be ensured. Two aliases (:class:`numpy.intp` and :class:`numpy.uintp`)
+pointing to the integer type that is sufficiently large to hold a C pointer
+are also provided.
+
+.. note that these are documented with ..attribute because that is what
+ autoclass does for aliases under the hood.
+
+.. autoclass:: numpy.bool8
+
+.. attribute:: int8
+ int16
+ int32
+ int64
+
+ Aliases for the signed integer types (one of `numpy.byte`, `numpy.short`,
+ `numpy.intc`, `numpy.int_` and `numpy.longlong`) with the specified number
+ of bits.
+
+ Compatible with the C99 ``int8_t``, ``int16_t``, ``int32_t``, and
+ ``int64_t``, respectively.
+
+.. attribute:: uint8
+ uint16
+ uint32
+ uint64
+
+ Alias for the unsigned integer types (one of `numpy.byte`, `numpy.short`,
+ `numpy.intc`, `numpy.int_` and `numpy.longlong`) with the specified number
+ of bits.
+
+ Compatible with the C99 ``uint8_t``, ``uint16_t``, ``uint32_t``, and
+ ``uint64_t``, respectively.
+
+.. attribute:: intp
+
+ Alias for the signed integer type (one of `numpy.byte`, `numpy.short`,
+ `numpy.intc`, `numpy.int_` and `np.longlong`) that is the same size as a
+ pointer.
+
+ Compatible with the C ``intptr_t``.
+
+ :Character code: ``'p'``
+
+.. attribute:: uintp
+
+ Alias for the unsigned integer type (one of `numpy.byte`, `numpy.short`,
+ `numpy.intc`, `numpy.int_` and `np.longlong`) that is the same size as a
+ pointer.
+
+ Compatible with the C ``uintptr_t``.
+
+ :Character code: ``'P'``
+
+.. autoclass:: numpy.float16
+
+.. autoclass:: numpy.float32
+
+.. autoclass:: numpy.float64
+
+.. attribute:: float96
+ float128
+
+ Alias for `numpy.longdouble`, named after its size in bits.
+ The existence of these aliases depends on the platform.
+
+.. autoclass:: numpy.complex64
+
+.. autoclass:: numpy.complex128
+
+.. attribute:: complex192
+ complex256
+
+ Alias for `numpy.clongdouble`, named after its size in bits.
+ The existance of these aliases depends on the platform.
+
+Other aliases
+~~~~~~~~~~~~~
+
+The first two of these are conveniences which resemble the names of the
+builtin types, in the same style as `bool_`, `int_`, `str_`, `bytes_`, and
+`object_`:
+
+.. autoclass:: numpy.float_
+
+.. autoclass:: numpy.complex_
+
+Some more use alternate naming conventions for extended-precision floats and
+complex numbers:
+
+.. autoclass:: numpy.longfloat
+
+.. autoclass:: numpy.singlecomplex
+
+.. autoclass:: numpy.cfloat
+
+.. autoclass:: numpy.longcomplex
+
+.. autoclass:: numpy.clongfloat
+
+The following aliases originate from Python 2, and it is recommended that they
+not be used in new code.
+
+.. autoclass:: numpy.string_
+
+.. autoclass:: numpy.unicode_
Attributes
==========
The array scalar objects have an :obj:`array priority
-<__array_priority__>` of :c:data:`NPY_SCALAR_PRIORITY`
+<class.__array_priority__>` of :c:data:`NPY_SCALAR_PRIORITY`
(-1,000,000.0). They also do not (yet) have a :attr:`ctypes <ndarray.ctypes>`
attribute. Otherwise, they share the same attributes as arrays:
.. autosummary::
:toctree: generated/
- generic
generic.__array__
generic.__array_wrap__
generic.squeeze
defined in ``ndarraytypes.h``. The input argument, *arr*, can be any
:c:type:`PyObject *<PyObject>` that is directly interpretable as a
:c:type:`PyArrayObject *` (any instance of the :c:data:`PyArray_Type`
-and itssub-types).
+and its sub-types).
.. c:function:: int PyArray_NDIM(PyArrayObject *arr)
.. versionadded:: 1.6
This function steals a reference to *descr* if it is not NULL.
-
This array creation routine allows for the convenient creation of
a new array matching an existing array's shapes and memory layout,
possibly changing the layout and/or data type.
Create a new array with the provided data-type descriptor, *descr*,
of the shape determined by *nd* and *dims*.
-.. c:function:: PyArray_FILLWBYTE(PyObject* obj, int val)
+.. c:function:: void PyArray_FILLWBYTE(PyObject* obj, int val)
Fill the array pointed to by *obj* ---which must be a (subclass
of) ndarray---with the contents of *val* (evaluated as a byte).
have :c:data:`NPY_ARRAY_DEFAULT` as its flags member. The *context*
argument is unused.
- .. c:var:: NPY_ARRAY_C_CONTIGUOUS
+ .. c:macro:: NPY_ARRAY_C_CONTIGUOUS
Make sure the returned array is C-style contiguous
- .. c:var:: NPY_ARRAY_F_CONTIGUOUS
+ .. c:macro:: NPY_ARRAY_F_CONTIGUOUS
Make sure the returned array is Fortran-style contiguous.
- .. c:var:: NPY_ARRAY_ALIGNED
+ .. c:macro:: NPY_ARRAY_ALIGNED
Make sure the returned array is aligned on proper boundaries for its
data type. An aligned array has the data pointer and every strides
factor as a multiple of the alignment factor for the data-type-
descriptor.
- .. c:var:: NPY_ARRAY_WRITEABLE
+ .. c:macro:: NPY_ARRAY_WRITEABLE
Make sure the returned array can be written to.
- .. c:var:: NPY_ARRAY_ENSURECOPY
+ .. c:macro:: NPY_ARRAY_ENSURECOPY
Make sure a copy is made of *op*. If this flag is not
present, data is not copied if it can be avoided.
- .. c:var:: NPY_ARRAY_ENSUREARRAY
+ .. c:macro:: NPY_ARRAY_ENSUREARRAY
Make sure the result is a base-class ndarray. By
default, if *op* is an instance of a subclass of
ndarray, an instance of that same subclass is returned. If
this flag is set, an ndarray object will be returned instead.
- .. c:var:: NPY_ARRAY_FORCECAST
+ .. c:macro:: NPY_ARRAY_FORCECAST
Force a cast to the output type even if it cannot be done
safely. Without this flag, a data cast will occur only if it
can be done safely, otherwise an error is raised.
- .. c:var:: NPY_ARRAY_WRITEBACKIFCOPY
+ .. c:macro:: NPY_ARRAY_WRITEBACKIFCOPY
If *op* is already an array, but does not satisfy the
requirements, then a copy is made (which will satisfy the
will be made writeable again. If *op* is not writeable to begin
with, or if it is not already an array, then an error is raised.
- .. c:var:: NPY_ARRAY_UPDATEIFCOPY
+ .. c:macro:: NPY_ARRAY_UPDATEIFCOPY
Deprecated. Use :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`, which is similar.
This flag "automatically" copies the data back when the returned
array is deallocated, which is not supported in all python
implementations.
- .. c:var:: NPY_ARRAY_BEHAVED
+ .. c:macro:: NPY_ARRAY_BEHAVED
:c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE`
- .. c:var:: NPY_ARRAY_CARRAY
+ .. c:macro:: NPY_ARRAY_CARRAY
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED`
- .. c:var:: NPY_ARRAY_CARRAY_RO
+ .. c:macro:: NPY_ARRAY_CARRAY_RO
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED`
- .. c:var:: NPY_ARRAY_FARRAY
+ .. c:macro:: NPY_ARRAY_FARRAY
:c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED`
- .. c:var:: NPY_ARRAY_FARRAY_RO
+ .. c:macro:: NPY_ARRAY_FARRAY_RO
:c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED`
- .. c:var:: NPY_ARRAY_DEFAULT
+ .. c:macro:: NPY_ARRAY_DEFAULT
:c:data:`NPY_ARRAY_CARRAY`
- .. c:var:: NPY_ARRAY_IN_ARRAY
+ .. c:macro:: NPY_ARRAY_IN_ARRAY
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED`
- .. c:var:: NPY_ARRAY_IN_FARRAY
+ .. c:macro:: NPY_ARRAY_IN_FARRAY
:c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED`
- .. c:var:: NPY_OUT_ARRAY
+ .. c:macro:: NPY_OUT_ARRAY
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \|
:c:data:`NPY_ARRAY_ALIGNED`
- .. c:var:: NPY_ARRAY_OUT_ARRAY
+ .. c:macro:: NPY_ARRAY_OUT_ARRAY
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED` \|
:c:data:`NPY_ARRAY_WRITEABLE`
- .. c:var:: NPY_ARRAY_OUT_FARRAY
+ .. c:macro:: NPY_ARRAY_OUT_FARRAY
:c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \|
:c:data:`NPY_ARRAY_ALIGNED`
- .. c:var:: NPY_ARRAY_INOUT_ARRAY
+ .. c:macro:: NPY_ARRAY_INOUT_ARRAY
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \|
:c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` \|
:c:data:`NPY_ARRAY_UPDATEIFCOPY`
- .. c:var:: NPY_ARRAY_INOUT_FARRAY
+ .. c:macro:: NPY_ARRAY_INOUT_FARRAY
:c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_WRITEABLE` \|
:c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` \|
did not have the _ARRAY_ macro namespace in them. That form
of the constant names is deprecated in 1.7.
-.. c:var:: NPY_ARRAY_NOTSWAPPED
+.. c:macro:: NPY_ARRAY_NOTSWAPPED
Make sure the returned array has a data-type descriptor that is in
machine byte-order, over-riding any specification in the *dtype*
not in machine byte- order), then a new data-type descriptor is
created and used with its byte-order field set to native.
-.. c:var:: NPY_ARRAY_BEHAVED_NS
+.. c:macro:: NPY_ARRAY_BEHAVED_NS
:c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` \| :c:data:`NPY_ARRAY_NOTSWAPPED`
-.. c:var:: NPY_ARRAY_ELEMENTSTRIDES
+.. c:macro:: NPY_ARRAY_ELEMENTSTRIDES
Make sure the returned array has strides that are multiples of the
element size.
.. c:function:: PyObject* PyArray_FromStructInterface(PyObject* op)
Returns an ndarray object from a Python object that exposes the
- :obj:`__array_struct__` attribute and follows the array interface
+ :obj:`~object.__array_struct__` attribute and follows the array interface
protocol. If the object does not contain this attribute then a
borrowed reference to :c:data:`Py_NotImplemented` is returned.
.. c:function:: PyObject* PyArray_FromInterface(PyObject* op)
Returns an ndarray object from a Python object that exposes the
- :obj:`__array_interface__` attribute following the array interface
+ :obj:`~object.__array_interface__` attribute following the array interface
protocol. If the object does not contain this attribute then a
borrowed reference to :c:data:`Py_NotImplemented` is returned.
requirements set to :c:data:`NPY_ARRAY_DEFAULT` and the type_num member of the
type argument set to *typenum*.
-.. c:function:: PyObject *PyArray_FromObject( \
- PyObject *op, int typenum, int min_depth, int max_depth)
+.. c:function:: PyObject* PyArray_ContiguousFromObject( \
+ PyObject* op, int typenum, int min_depth, int max_depth)
+
+ This function returns a well-behaved C-style contiguous array from any nested
+ sequence or array-interface exporting object. The minimum number of dimensions
+ the array can have is given by `min_depth` while the maximum is `max_depth`.
+ This is equivalent to call :c:func:`PyArray_FromAny` with requirements
+ :c:data:`NPY_ARRAY_DEFAULT` and :c:data:`NPY_ARRAY_ENSUREARRAY`.
+
+.. c:function:: PyObject* PyArray_FromObject( \
+ PyObject* op, int typenum, int min_depth, int max_depth)
Return an aligned and in native-byteorder array from any nested
sequence or array-interface exporting object, op, of a type given by
General check of Python Type
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. c:function:: PyArray_Check(PyObject *op)
+.. c:function:: int PyArray_Check(PyObject *op)
Evaluates true if *op* is a Python object whose type is a sub-type
of :c:data:`PyArray_Type`.
-.. c:function:: PyArray_CheckExact(PyObject *op)
+.. c:function:: int PyArray_CheckExact(PyObject *op)
Evaluates true if *op* is a Python object with type
:c:data:`PyArray_Type`.
-.. c:function:: PyArray_HasArrayInterface(PyObject *op, PyObject *out)
+.. c:function:: int PyArray_HasArrayInterface(PyObject *op, PyObject *out)
If ``op`` implements any part of the array interface, then ``out``
will contain a new reference to the newly created ndarray using
conversion occurs. Otherwise, out will contain a borrowed
reference to :c:data:`Py_NotImplemented` and no error condition is set.
-.. c:function:: PyArray_HasArrayInterfaceType(op, dtype, context, out)
+.. c:function:: int PyArray_HasArrayInterfaceType(\
+ PyObject *op, PyArray_Descr *dtype, PyObject *context, PyObject *out)
If ``op`` implements any part of the array interface, then ``out``
will contain a new reference to the newly created ndarray using
that looks for the :obj:`~numpy.class.__array__` attribute. `context` is
unused.
-.. c:function:: PyArray_IsZeroDim(op)
+.. c:function:: int PyArray_IsZeroDim(PyObject *op)
Evaluates true if *op* is an instance of (a subclass of)
:c:data:`PyArray_Type` and has 0 dimensions.
.. c:function:: PyArray_IsScalar(op, cls)
- Evaluates true if *op* is an instance of :c:data:`Py{cls}ArrType_Type`.
+ Evaluates true if *op* is an instance of ``Py{cls}ArrType_Type``.
-.. c:function:: PyArray_CheckScalar(op)
+.. c:function:: int PyArray_CheckScalar(PyObject *op)
Evaluates true if *op* is either an array scalar (an instance of a
sub-type of :c:data:`PyGenericArr_Type` ), or an instance of (a
sub-class of) :c:data:`PyArray_Type` whose dimensionality is 0.
-.. c:function:: PyArray_IsPythonNumber(op)
+.. c:function:: int PyArray_IsPythonNumber(PyObject *op)
Evaluates true if *op* is an instance of a builtin numeric type (int,
float, complex, long, bool)
-.. c:function:: PyArray_IsPythonScalar(op)
+.. c:function:: int PyArray_IsPythonScalar(PyObject *op)
Evaluates true if *op* is a builtin Python scalar object (int,
float, complex, bytes, str, long, bool).
-.. c:function:: PyArray_IsAnyScalar(op)
+.. c:function:: int PyArray_IsAnyScalar(PyObject *op)
Evaluates true if *op* is either a Python scalar object (see
:c:func:`PyArray_IsPythonScalar`) or an array scalar (an instance of a sub-
type of :c:data:`PyGenericArr_Type` ).
-.. c:function:: PyArray_CheckAnyScalar(op)
+.. c:function:: int PyArray_CheckAnyScalar(PyObject *op)
Evaluates true if *op* is a Python scalar object (see
:c:func:`PyArray_IsPythonScalar`), an array scalar (an instance of a
argument must be a :c:type:`PyObject *<PyObject>` that can be directly interpreted as a
:c:type:`PyArrayObject *`.
-.. c:function:: PyTypeNum_ISUNSIGNED(int num)
+.. c:function:: int PyTypeNum_ISUNSIGNED(int num)
-.. c:function:: PyDataType_ISUNSIGNED(PyArray_Descr *descr)
+.. c:function:: int PyDataType_ISUNSIGNED(PyArray_Descr *descr)
-.. c:function:: PyArray_ISUNSIGNED(PyArrayObject *obj)
+.. c:function:: int PyArray_ISUNSIGNED(PyArrayObject *obj)
Type represents an unsigned integer.
-.. c:function:: PyTypeNum_ISSIGNED(int num)
+.. c:function:: int PyTypeNum_ISSIGNED(int num)
-.. c:function:: PyDataType_ISSIGNED(PyArray_Descr *descr)
+.. c:function:: int PyDataType_ISSIGNED(PyArray_Descr *descr)
-.. c:function:: PyArray_ISSIGNED(PyArrayObject *obj)
+.. c:function:: int PyArray_ISSIGNED(PyArrayObject *obj)
Type represents a signed integer.
-.. c:function:: PyTypeNum_ISINTEGER(int num)
+.. c:function:: int PyTypeNum_ISINTEGER(int num)
-.. c:function:: PyDataType_ISINTEGER(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISINTEGER(PyArray_Descr* descr)
-.. c:function:: PyArray_ISINTEGER(PyArrayObject *obj)
+.. c:function:: int PyArray_ISINTEGER(PyArrayObject *obj)
Type represents any integer.
-.. c:function:: PyTypeNum_ISFLOAT(int num)
+.. c:function:: int PyTypeNum_ISFLOAT(int num)
-.. c:function:: PyDataType_ISFLOAT(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISFLOAT(PyArray_Descr* descr)
-.. c:function:: PyArray_ISFLOAT(PyArrayObject *obj)
+.. c:function:: int PyArray_ISFLOAT(PyArrayObject *obj)
Type represents any floating point number.
-.. c:function:: PyTypeNum_ISCOMPLEX(int num)
+.. c:function:: int PyTypeNum_ISCOMPLEX(int num)
-.. c:function:: PyDataType_ISCOMPLEX(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISCOMPLEX(PyArray_Descr* descr)
-.. c:function:: PyArray_ISCOMPLEX(PyArrayObject *obj)
+.. c:function:: int PyArray_ISCOMPLEX(PyArrayObject *obj)
Type represents any complex floating point number.
-.. c:function:: PyTypeNum_ISNUMBER(int num)
+.. c:function:: int PyTypeNum_ISNUMBER(int num)
-.. c:function:: PyDataType_ISNUMBER(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISNUMBER(PyArray_Descr* descr)
-.. c:function:: PyArray_ISNUMBER(PyArrayObject *obj)
+.. c:function:: int PyArray_ISNUMBER(PyArrayObject *obj)
Type represents any integer, floating point, or complex floating point
number.
-.. c:function:: PyTypeNum_ISSTRING(int num)
+.. c:function:: int PyTypeNum_ISSTRING(int num)
-.. c:function:: PyDataType_ISSTRING(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISSTRING(PyArray_Descr* descr)
-.. c:function:: PyArray_ISSTRING(PyArrayObject *obj)
+.. c:function:: int PyArray_ISSTRING(PyArrayObject *obj)
Type represents a string data type.
-.. c:function:: PyTypeNum_ISPYTHON(int num)
+.. c:function:: int PyTypeNum_ISPYTHON(int num)
-.. c:function:: PyDataType_ISPYTHON(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISPYTHON(PyArray_Descr* descr)
-.. c:function:: PyArray_ISPYTHON(PyArrayObject *obj)
+.. c:function:: int PyArray_ISPYTHON(PyArrayObject *obj)
Type represents an enumerated type corresponding to one of the
standard Python scalar (bool, int, float, or complex).
-.. c:function:: PyTypeNum_ISFLEXIBLE(int num)
+.. c:function:: int PyTypeNum_ISFLEXIBLE(int num)
-.. c:function:: PyDataType_ISFLEXIBLE(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISFLEXIBLE(PyArray_Descr* descr)
-.. c:function:: PyArray_ISFLEXIBLE(PyArrayObject *obj)
+.. c:function:: int PyArray_ISFLEXIBLE(PyArrayObject *obj)
Type represents one of the flexible array types ( :c:data:`NPY_STRING`,
:c:data:`NPY_UNICODE`, or :c:data:`NPY_VOID` ).
-.. c:function:: PyDataType_ISUNSIZED(PyArray_Descr* descr):
+.. c:function:: int PyDataType_ISUNSIZED(PyArray_Descr* descr)
Type has no size information attached, and can be resized. Should only be
called on flexible dtypes. Types that are attached to an array will always
For structured datatypes with no fields this function now returns False.
-.. c:function:: PyTypeNum_ISUSERDEF(int num)
+.. c:function:: int PyTypeNum_ISUSERDEF(int num)
-.. c:function:: PyDataType_ISUSERDEF(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISUSERDEF(PyArray_Descr* descr)
-.. c:function:: PyArray_ISUSERDEF(PyArrayObject *obj)
+.. c:function:: int PyArray_ISUSERDEF(PyArrayObject *obj)
Type represents a user-defined type.
-.. c:function:: PyTypeNum_ISEXTENDED(int num)
+.. c:function:: int PyTypeNum_ISEXTENDED(int num)
-.. c:function:: PyDataType_ISEXTENDED(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISEXTENDED(PyArray_Descr* descr)
-.. c:function:: PyArray_ISEXTENDED(PyArrayObject *obj)
+.. c:function:: int PyArray_ISEXTENDED(PyArrayObject *obj)
Type is either flexible or user-defined.
-.. c:function:: PyTypeNum_ISOBJECT(int num)
+.. c:function:: int PyTypeNum_ISOBJECT(int num)
-.. c:function:: PyDataType_ISOBJECT(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISOBJECT(PyArray_Descr* descr)
-.. c:function:: PyArray_ISOBJECT(PyArrayObject *obj)
+.. c:function:: int PyArray_ISOBJECT(PyArrayObject *obj)
Type represents object data type.
-.. c:function:: PyTypeNum_ISBOOL(int num)
+.. c:function:: int PyTypeNum_ISBOOL(int num)
-.. c:function:: PyDataType_ISBOOL(PyArray_Descr* descr)
+.. c:function:: int PyDataType_ISBOOL(PyArray_Descr* descr)
-.. c:function:: PyArray_ISBOOL(PyArrayObject *obj)
+.. c:function:: int PyArray_ISBOOL(PyArrayObject *obj)
Type represents Boolean data type.
-.. c:function:: PyDataType_HASFIELDS(PyArray_Descr* descr)
+.. c:function:: int PyDataType_HASFIELDS(PyArray_Descr* descr)
-.. c:function:: PyArray_HASFIELDS(PyArrayObject *obj)
+.. c:function:: int PyArray_HASFIELDS(PyArrayObject *obj)
Type has fields associated with it.
-.. c:function:: PyArray_ISNOTSWAPPED(m)
+.. c:function:: int PyArray_ISNOTSWAPPED(PyArrayObject *m)
Evaluates true if the data area of the ndarray *m* is in machine
byte-order according to the array's data-type descriptor.
-.. c:function:: PyArray_ISBYTESWAPPED(m)
+.. c:function:: int PyArray_ISBYTESWAPPED(PyArrayObject *m)
Evaluates true if the data area of the ndarray *m* is **not** in
machine byte-order according to the array's data-type descriptor.
-.. c:function:: Bool PyArray_EquivTypes( \
+.. c:function:: npy_bool PyArray_EquivTypes( \
PyArray_Descr* type1, PyArray_Descr* type2)
Return :c:data:`NPY_TRUE` if *type1* and *type2* actually represent
:c:data:`NPY_LONG` and :c:data:`NPY_INT` are equivalent. Otherwise
return :c:data:`NPY_FALSE`.
-.. c:function:: Bool PyArray_EquivArrTypes( \
+.. c:function:: npy_bool PyArray_EquivArrTypes( \
PyArrayObject* a1, PyArrayObject * a2)
Return :c:data:`NPY_TRUE` if *a1* and *a2* are arrays with equivalent
types for this platform.
-.. c:function:: Bool PyArray_EquivTypenums(int typenum1, int typenum2)
+.. c:function:: npy_bool PyArray_EquivTypenums(int typenum1, int typenum2)
Special case of :c:func:`PyArray_EquivTypes` (...) that does not accept
flexible data types but may be easier to call.
-.. c:function:: int PyArray_EquivByteorders({byteorder} b1, {byteorder} b2)
+.. c:function:: int PyArray_EquivByteorders(int b1, int b2)
True if byteorder characters ( :c:data:`NPY_LITTLE`,
:c:data:`NPY_BIG`, :c:data:`NPY_NATIVE`, :c:data:`NPY_IGNORE` ) are
storing the max value of the input types converted to a string or unicode.
.. c:function:: PyArray_Descr* PyArray_ResultType( \
- npy_intp narrs, PyArrayObject**arrs, npy_intp ndtypes, \
- PyArray_Descr**dtypes)
+ npy_intp narrs, PyArrayObject **arrs, npy_intp ndtypes, \
+ PyArray_Descr **dtypes)
.. versionadded:: 1.6
locations in the structure with object data-types. No checking is
performed but *arr* must be of data-type :c:type:`NPY_OBJECT` and be
single-segment and uninitialized (no previous objects in
- position). Use :c:func:`PyArray_DECREF` (*arr*) if you need to
+ position). Use :c:func:`PyArray_XDECREF` (*arr*) if you need to
decrement all the items in the object array prior to calling this
function.
Precondition: ``arr`` is a copy of ``base`` (though possibly with different
strides, ordering, etc.) Set the UPDATEIFCOPY flag and ``arr->base`` so
that when ``arr`` is destructed, it will copy any changes back to ``base``.
- DEPRECATED, use :c:func:`PyArray_SetWritebackIfCopyBase``.
+ DEPRECATED, use :c:func:`PyArray_SetWritebackIfCopyBase`.
Returns 0 for success, -1 for failure.
strides, ordering, etc.) Sets the :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` flag
and ``arr->base``, and set ``base`` to READONLY. Call
:c:func:`PyArray_ResolveWritebackIfCopy` before calling
- `Py_DECREF`` in order copy any changes back to ``base`` and
+ `Py_DECREF` in order copy any changes back to ``base`` and
reset the READONLY flag.
Returns 0 for success, -1 for failure.
did not have the _ARRAY_ macro namespace in them. That form
of the constant names is deprecated in 1.7.
-.. c:var:: NPY_ARRAY_C_CONTIGUOUS
+.. c:macro:: NPY_ARRAY_C_CONTIGUOUS
The data area is in C-style contiguous order (last index varies the
fastest).
-.. c:var:: NPY_ARRAY_F_CONTIGUOUS
+.. c:macro:: NPY_ARRAY_F_CONTIGUOUS
The data area is in Fortran-style contiguous order (first index varies
the fastest).
.. seealso:: :ref:`Internal memory layout of an ndarray <arrays.ndarray>`
-.. c:var:: NPY_ARRAY_OWNDATA
+.. c:macro:: NPY_ARRAY_OWNDATA
The data area is owned by this array.
-.. c:var:: NPY_ARRAY_ALIGNED
+.. c:macro:: NPY_ARRAY_ALIGNED
The data area and all array elements are aligned appropriately.
-.. c:var:: NPY_ARRAY_WRITEABLE
+.. c:macro:: NPY_ARRAY_WRITEABLE
The data area can be written to.
Notice that the above 3 flags are defined so that a new, well-
behaved array has these flags defined as true.
-.. c:var:: NPY_ARRAY_WRITEBACKIFCOPY
+.. c:macro:: NPY_ARRAY_WRITEBACKIFCOPY
The data area represents a (well-behaved) copy whose information
should be transferred back to the original when
would have returned an error because :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`
would not have been possible.
-.. c:var:: NPY_ARRAY_UPDATEIFCOPY
+.. c:macro:: NPY_ARRAY_UPDATEIFCOPY
A deprecated version of :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` which
depends upon ``dealloc`` to trigger the writeback. For backwards
Combinations of array flags
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. c:var:: NPY_ARRAY_BEHAVED
+.. c:macro:: NPY_ARRAY_BEHAVED
:c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE`
-.. c:var:: NPY_ARRAY_CARRAY
+.. c:macro:: NPY_ARRAY_CARRAY
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED`
-.. c:var:: NPY_ARRAY_CARRAY_RO
+.. c:macro:: NPY_ARRAY_CARRAY_RO
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED`
-.. c:var:: NPY_ARRAY_FARRAY
+.. c:macro:: NPY_ARRAY_FARRAY
:c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_BEHAVED`
-.. c:var:: NPY_ARRAY_FARRAY_RO
+.. c:macro:: NPY_ARRAY_FARRAY_RO
:c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED`
-.. c:var:: NPY_ARRAY_DEFAULT
+.. c:macro:: NPY_ARRAY_DEFAULT
:c:data:`NPY_ARRAY_CARRAY`
-.. c:var:: NPY_ARRAY_UPDATE_ALL
+.. c:macro:: NPY_ARRAY_UPDATE_ALL
:c:data:`NPY_ARRAY_C_CONTIGUOUS` \| :c:data:`NPY_ARRAY_F_CONTIGUOUS` \| :c:data:`NPY_ARRAY_ALIGNED`
These constants are used in :c:func:`PyArray_FromAny` (and its macro forms) to
specify desired properties of the new array.
-.. c:var:: NPY_ARRAY_FORCECAST
+.. c:macro:: NPY_ARRAY_FORCECAST
Cast to the desired type, even if it can't be done without losing
information.
-.. c:var:: NPY_ARRAY_ENSURECOPY
+.. c:macro:: NPY_ARRAY_ENSURECOPY
Make sure the resulting array is a copy of the original.
-.. c:var:: NPY_ARRAY_ENSUREARRAY
+.. c:macro:: NPY_ARRAY_ENSUREARRAY
Make sure the resulting object is an actual ndarray, and not a sub-class.
-.. c:var:: NPY_ARRAY_NOTSWAPPED
-
- Only used in :c:func:`PyArray_CheckFromAny` to over-ride the byteorder
- of the data-type object passed in.
-
-.. c:var:: NPY_ARRAY_BEHAVED_NS
-
- :c:data:`NPY_ARRAY_ALIGNED` \| :c:data:`NPY_ARRAY_WRITEABLE` \| :c:data:`NPY_ARRAY_NOTSWAPPED`
-
Flag checking
^^^^^^^^^^^^^
For all of these macros *arr* must be an instance of a (subclass of)
:c:data:`PyArray_Type`.
-.. c:function:: PyArray_CHKFLAGS(PyObject *arr, flags)
+.. c:function:: int PyArray_CHKFLAGS(PyObject *arr, int flags)
The first parameter, arr, must be an ndarray or subclass. The
parameter, *flags*, should be an integer consisting of bitwise
:c:data:`NPY_ARRAY_WRITEABLE`, :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`,
:c:data:`NPY_ARRAY_UPDATEIFCOPY`.
-.. c:function:: PyArray_IS_C_CONTIGUOUS(PyObject *arr)
+.. c:function:: int PyArray_IS_C_CONTIGUOUS(PyObject *arr)
Evaluates true if *arr* is C-style contiguous.
-.. c:function:: PyArray_IS_F_CONTIGUOUS(PyObject *arr)
+.. c:function:: int PyArray_IS_F_CONTIGUOUS(PyObject *arr)
Evaluates true if *arr* is Fortran-style contiguous.
-.. c:function:: PyArray_ISFORTRAN(PyObject *arr)
+.. c:function:: int PyArray_ISFORTRAN(PyObject *arr)
Evaluates true if *arr* is Fortran-style contiguous and *not*
C-style contiguous. :c:func:`PyArray_IS_F_CONTIGUOUS`
is the correct way to test for Fortran-style contiguity.
-.. c:function:: PyArray_ISWRITEABLE(PyObject *arr)
+.. c:function:: int PyArray_ISWRITEABLE(PyObject *arr)
Evaluates true if the data area of *arr* can be written to
-.. c:function:: PyArray_ISALIGNED(PyObject *arr)
+.. c:function:: int PyArray_ISALIGNED(PyObject *arr)
Evaluates true if the data area of *arr* is properly aligned on
the machine.
-.. c:function:: PyArray_ISBEHAVED(PyObject *arr)
+.. c:function:: int PyArray_ISBEHAVED(PyObject *arr)
Evaluates true if the data area of *arr* is aligned and writeable
and in machine byte-order according to its descriptor.
-.. c:function:: PyArray_ISBEHAVED_RO(PyObject *arr)
+.. c:function:: int PyArray_ISBEHAVED_RO(PyObject *arr)
Evaluates true if the data area of *arr* is aligned and in machine
byte-order.
-.. c:function:: PyArray_ISCARRAY(PyObject *arr)
+.. c:function:: int PyArray_ISCARRAY(PyObject *arr)
Evaluates true if the data area of *arr* is C-style contiguous,
and :c:func:`PyArray_ISBEHAVED` (*arr*) is true.
-.. c:function:: PyArray_ISFARRAY(PyObject *arr)
+.. c:function:: int PyArray_ISFARRAY(PyObject *arr)
Evaluates true if the data area of *arr* is Fortran-style
contiguous and :c:func:`PyArray_ISBEHAVED` (*arr*) is true.
-.. c:function:: PyArray_ISCARRAY_RO(PyObject *arr)
+.. c:function:: int PyArray_ISCARRAY_RO(PyObject *arr)
Evaluates true if the data area of *arr* is C-style contiguous,
aligned, and in machine byte-order.
-.. c:function:: PyArray_ISFARRAY_RO(PyObject *arr)
+.. c:function:: int PyArray_ISFARRAY_RO(PyObject *arr)
Evaluates true if the data area of *arr* is Fortran-style
contiguous, aligned, and in machine byte-order **.**
-.. c:function:: PyArray_ISONESEGMENT(PyObject *arr)
+.. c:function:: int PyArray_ISONESEGMENT(PyObject *arr)
Evaluates true if the data area of *arr* consists of a single
(C-style or Fortran-style) contiguous segment.
destination must be an integer multiple of the number of elements
in *val*.
-.. c:function:: PyObject* PyArray_Byteswap(PyArrayObject* self, Bool inplace)
+.. c:function:: PyObject* PyArray_Byteswap(PyArrayObject* self, npy_bool inplace)
Equivalent to :meth:`ndarray.byteswap<numpy.ndarray.byteswap>` (*self*, *inplace*). Return an array
whose data area is byteswapped. If *inplace* is non-zero, then do
created. The *clipmode* argument determines behavior for when
entries in *self* are not between 0 and len(*op*).
- .. c:var:: NPY_RAISE
+ .. c:macro:: NPY_RAISE
raise a ValueError;
- .. c:var:: NPY_WRAP
+ .. c:macro:: NPY_WRAP
wrap values < 0 by adding len(*op*) and values >=len(*op*)
by subtracting len(*op*) until they are in range;
- .. c:var:: NPY_CLIP
+ .. c:macro:: NPY_CLIP
all values are clipped to the region [0, len(*op*) ).
See the :func:`~numpy.einsum` function for more details.
-.. c:function:: PyObject* PyArray_CopyAndTranspose(PyObject \* op)
+.. c:function:: PyObject* PyArray_CopyAndTranspose(PyObject * op)
A specialized copy and transpose function that works only for 2-d
arrays. The returned array is a transposed copy of *op*.
Other functions
^^^^^^^^^^^^^^^
-.. c:function:: Bool PyArray_CheckStrides( \
+.. c:function:: npy_bool PyArray_CheckStrides( \
int elsize, int nd, npy_intp numbytes, npy_intp const* dims, \
npy_intp const* newstrides)
Defining an :c:type:`NpyAuxData` is similar to defining a class in C++,
but the object semantics have to be tracked manually since the API is in C.
Here's an example for a function which doubles up an element using
-an element copier function as a primitive.::
+an element copier function as a primitive.
+
+.. code-block:: c
typedef struct {
NpyAuxData base;
functions should never set the Python exception on error, because
they may be called from a multi-threaded context.
-.. c:function:: NPY_AUXDATA_FREE(auxdata)
+.. c:function:: void NPY_AUXDATA_FREE(NpyAuxData *auxdata)
A macro which calls the auxdata's free function appropriately,
does nothing if auxdata is NULL.
-.. c:function:: NPY_AUXDATA_CLONE(auxdata)
+.. c:function:: NpyAuxData *NPY_AUXDATA_CLONE(NpyAuxData *auxdata)
A macro which calls the auxdata's clone function appropriately,
returning a deep copy of the auxiliary data.
it easy to loop over an N-dimensional non-contiguous array in
C-style contiguous fashion.
-.. c:function:: PyObject* PyArray_IterAllButAxis(PyObject* arr, int \*axis)
+.. c:function:: PyObject* PyArray_IterAllButAxis(PyObject* arr, int* axis)
Return an array iterator that will iterate over all axes but the
one provided in *\*axis*. The returned iterator cannot be used
*destination*, which must have size at least *iterator*
->nd_m1+1.
-.. c:function:: PyArray_ITER_GOTO1D(PyObject* iterator, npy_intp index)
+.. c:function:: void PyArray_ITER_GOTO1D(PyObject* iterator, npy_intp index)
Set the *iterator* index and dataptr to the location in the array
indicated by the integer *index* which points to an element in the
Create a new data-type object with the byteorder set according to
*newendian*. All referenced data-type objects (in subdescr and
fields members of the data-type object) are also changed
- (recursively). If a byteorder of :c:data:`NPY_IGNORE` is encountered it
+ (recursively).
+
+ The value of *newendian* is one of these macros:
+
+ .. c:macro:: NPY_IGNORE
+ NPY_SWAP
+ NPY_NATIVE
+ NPY_LITTLE
+ NPY_BIG
+
+ If a byteorder of :c:data:`NPY_IGNORE` is encountered it
is left alone. If newendian is :c:data:`NPY_SWAP`, then all byte-orders
are swapped. Other valid newendian values are :c:data:`NPY_NATIVE`,
- :c:data:`NPY_LITTLE`, and :c:data:`NPY_BIG` which all cause the returned
- data-typed descriptor (and all it's
+ :c:data:`NPY_LITTLE`, and :c:data:`NPY_BIG` which all cause
+ the returned data-typed descriptor (and all it's
referenced data-type descriptors) to have the corresponding byte-
order.
already a buffer object pointing to another object). If you need
to hold on to the memory be sure to INCREF the base member. The
chunk of memory is pointed to by *buf* ->ptr member and has length
- *buf* ->len. The flags member of *buf* is :c:data:`NPY_BEHAVED_RO` with
- the :c:data:`NPY_ARRAY_WRITEABLE` flag set if *obj* has a writeable buffer
- interface.
+ *buf* ->len. The flags member of *buf* is :c:data:`NPY_ARRAY_ALIGNED`
+ with the :c:data:`NPY_ARRAY_WRITEABLE` flag set if *obj* has
+ a writeable buffer interface.
-.. c:function:: int PyArray_AxisConverter(PyObject \* obj, int* axis)
+.. c:function:: int PyArray_AxisConverter(PyObject* obj, int* axis)
Convert a Python object, *obj*, representing an axis argument to
the proper value for passing to the functions that take an integer
:c:data:`NPY_MAXDIMS` which is interpreted correctly by the C-API
functions that take axis arguments.
-.. c:function:: int PyArray_BoolConverter(PyObject* obj, Bool* value)
+.. c:function:: int PyArray_BoolConverter(PyObject* obj, npy_bool* value)
Convert any Python object, *obj*, to :c:data:`NPY_TRUE` or
:c:data:`NPY_FALSE`, and place the result in *value*.
Internally, these #defines work as follows:
* If neither is defined, the C-API is declared to be
- :c:type:`static void**`, so it is only visible within the
+ ``static void**``, so it is only visible within the
compilation unit that #includes numpy/arrayobject.h.
* If :c:macro:`PY_ARRAY_UNIQUE_SYMBOL` is #defined, but
:c:macro:`NO_IMPORT_ARRAY` is not, the C-API is declared to
- be :c:type:`void**`, so that it will also be visible to other
+ be ``void**``, so that it will also be visible to other
compilation units.
* If :c:macro:`NO_IMPORT_ARRAY` is #defined, regardless of
whether :c:macro:`PY_ARRAY_UNIQUE_SYMBOL` is, the C-API is
- declared to be :c:type:`extern void**`, so it is expected to
+ declared to be ``extern void**``, so it is expected to
be defined in another compilation unit.
* Whenever :c:macro:`PY_ARRAY_UNIQUE_SYMBOL` is #defined, it
also changes the name of the variable holding the C-API, which
- defaults to :c:data:`PyArray_API`, to whatever the macro is
+ defaults to ``PyArray_API``, to whatever the macro is
#defined to.
Checking the API Version
numpy versions. The macros :c:data:`NPY_VERSION` and
:c:data:`NPY_FEATURE_VERSION` corresponds to the numpy version used to build the
extension, whereas the versions returned by the functions
-PyArray_GetNDArrayCVersion and PyArray_GetNDArrayCFeatureVersion corresponds to
-the runtime numpy's version.
+:c:func:`PyArray_GetNDArrayCVersion` and :c:func:`PyArray_GetNDArrayCFeatureVersion`
+corresponds to the runtime numpy's version.
The rules for ABI and API compatibilities can be summarized as follows:
- * Whenever :c:data:`NPY_VERSION` != PyArray_GetNDArrayCVersion, the
+ * Whenever :c:data:`NPY_VERSION` != ``PyArray_GetNDArrayCVersion()``, the
extension has to be recompiled (ABI incompatibility).
- * :c:data:`NPY_VERSION` == PyArray_GetNDArrayCVersion and
- :c:data:`NPY_FEATURE_VERSION` <= PyArray_GetNDArrayCFeatureVersion means
+ * :c:data:`NPY_VERSION` == ``PyArray_GetNDArrayCVersion()`` and
+ :c:data:`NPY_FEATURE_VERSION` <= ``PyArray_GetNDArrayCFeatureVersion()`` means
backward compatible changes.
ABI incompatibility is automatically detected in every numpy's version. API
incompatibility detection was added in numpy 1.4.0. If you want to supported
many different numpy versions with one extension binary, you have to build your
-extension with the lowest NPY_FEATURE_VERSION as possible.
+extension with the lowest :c:data:`NPY_FEATURE_VERSION` as possible.
+
+.. c:macro:: NPY_VERSION
+
+ The current version of the ndarray object (check to see if this
+ variable is defined to guarantee the ``numpy/arrayobject.h`` header is
+ being used).
+
+.. c:macro:: NPY_FEATURE_VERSION
+
+ The current version of the C-API.
.. c:function:: unsigned int PyArray_GetNDArrayCVersion(void)
.. c:function:: char* PyDataMem_NEW(size_t nbytes)
-.. c:function:: PyDataMem_FREE(char* ptr)
+.. c:function:: void PyDataMem_FREE(char* ptr)
.. c:function:: char* PyDataMem_RENEW(void * ptr, size_t newbytes)
.. c:function:: npy_intp* PyDimMem_NEW(int nd)
-.. c:function:: PyDimMem_FREE(char* ptr)
+.. c:function:: void PyDimMem_FREE(char* ptr)
.. c:function:: npy_intp* PyDimMem_RENEW(void* ptr, size_t newnd)
.. c:function:: void* PyArray_malloc(size_t nbytes)
-.. c:function:: PyArray_free(void* ptr)
+.. c:function:: void PyArray_free(void* ptr)
.. c:function:: void* PyArray_realloc(npy_intp* ptr, size_t nbytes)
:c:data:`NPY_USE_PYMEM` is 0, if :c:data:`NPY_USE_PYMEM` is 1, then
the Python memory allocator is used.
+ .. c:macro:: NPY_USE_PYMEM
+
.. c:function:: int PyArray_ResolveWritebackIfCopy(PyArrayObject* obj)
If ``obj.flags`` has :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` or (deprecated)
a group is used in a code block, all of them must be used in the same
code block. Currently, :c:data:`NPY_ALLOW_THREADS` is defined to the
python-defined :c:data:`WITH_THREADS` constant unless the environment
-variable :c:data:`NPY_NOSMP` is set in which case
+variable ``NPY_NOSMP`` is set in which case
:c:data:`NPY_ALLOW_THREADS` is defined to be 0.
+.. c:macro:: NPY_ALLOW_THREADS
+
+.. c:macro:: WITH_THREADS
+
Group 1
"""""""
interpreter. This macro acquires the GIL and restores the
Python state from the saved variable.
- .. c:function:: NPY_BEGIN_THREADS_DESCR(PyArray_Descr *dtype)
+ .. c:function:: void NPY_BEGIN_THREADS_DESCR(PyArray_Descr *dtype)
Useful to release the GIL only if *dtype* does not contain
arbitrary Python objects which may need the Python interpreter
during execution of the loop.
- .. c:function:: NPY_END_THREADS_DESCR(PyArray_Descr *dtype)
+ .. c:function:: void NPY_END_THREADS_DESCR(PyArray_Descr *dtype)
Useful to regain the GIL in situations where it was released
using the BEGIN form of this macro.
- .. c:function:: NPY_BEGIN_THREADS_THRESHOLDED(int loop_size)
+ .. c:function:: void NPY_BEGIN_THREADS_THRESHOLDED(int loop_size)
Useful to release the GIL only if *loop_size* exceeds a
minimum threshold, currently set to 500. Should be matched
Priority
^^^^^^^^
-.. c:var:: NPY_PRIORITY
+.. c:macro:: NPY_PRIORITY
Default priority for arrays.
-.. c:var:: NPY_SUBTYPE_PRIORITY
+.. c:macro:: NPY_SUBTYPE_PRIORITY
Default subtype priority.
-.. c:var:: NPY_SCALAR_PRIORITY
+.. c:macro:: NPY_SCALAR_PRIORITY
Default scalar priority (very small)
Default buffers
^^^^^^^^^^^^^^^
-.. c:var:: NPY_BUFSIZE
+.. c:macro:: NPY_BUFSIZE
Default size of the user-settable internal buffers.
-.. c:var:: NPY_MIN_BUFSIZE
+.. c:macro:: NPY_MIN_BUFSIZE
Smallest size of user-settable internal buffers.
-.. c:var:: NPY_MAX_BUFSIZE
+.. c:macro:: NPY_MAX_BUFSIZE
Largest size allowed for the user-settable buffers.
Other constants
^^^^^^^^^^^^^^^
-.. c:var:: NPY_NUM_FLOATTYPE
+.. c:macro:: NPY_NUM_FLOATTYPE
The number of floating-point types
-.. c:var:: NPY_MAXDIMS
+.. c:macro:: NPY_MAXDIMS
The maximum number of dimensions allowed in arrays.
-.. c:var:: NPY_MAXARGS
+.. c:macro:: NPY_MAXARGS
The maximum number of array arguments that can be used in functions.
-.. c:var:: NPY_VERSION
-
- The current version of the ndarray object (check to see if this
- variable is defined to guarantee the numpy/arrayobject.h header is
- being used).
-
-.. c:var:: NPY_FALSE
+.. c:macro:: NPY_FALSE
Defined as 0 for use with Bool.
-.. c:var:: NPY_TRUE
+.. c:macro:: NPY_TRUE
Defined as 1 for use with Bool.
-.. c:var:: NPY_FAIL
+.. c:macro:: NPY_FAIL
The return value of failed converter functions which are called using
the "O&" syntax in :c:func:`PyArg_ParseTuple`-like functions.
-.. c:var:: NPY_SUCCEED
+.. c:macro:: NPY_SUCCEED
The return value of successful converter functions which are called
using the "O&" syntax in :c:func:`PyArg_ParseTuple`-like functions.
Miscellaneous Macros
^^^^^^^^^^^^^^^^^^^^
-.. c:function:: PyArray_SAMESHAPE(PyArrayObject *a1, PyArrayObject *a2)
+.. c:function:: int PyArray_SAMESHAPE(PyArrayObject *a1, PyArrayObject *a2)
Evaluates as True if arrays *a1* and *a2* have the same shape.
of the ordering which is lexicographic: comparing the real parts
first and then the complex parts if the real parts are equal.
-.. c:function:: PyArray_REFCOUNT(PyObject* op)
+.. c:function:: npy_intp PyArray_REFCOUNT(PyObject* op)
Returns the reference count of any Python object.
-.. c:function:: PyArray_DiscardWritebackIfCopy(PyObject* obj)
+.. c:function:: void PyArray_DiscardWritebackIfCopy(PyObject* obj)
If ``obj.flags`` has :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` or (deprecated)
:c:data:`NPY_ARRAY_UPDATEIFCOPY`, this function clears the flags, `DECREF` s
error when you are finished with ``obj``, just before ``Py_DECREF(obj)``.
It may be called multiple times, or with ``NULL`` input.
-.. c:function:: PyArray_XDECREF_ERR(PyObject* obj)
+.. c:function:: void PyArray_XDECREF_ERR(PyObject* obj)
Deprecated in 1.14, use :c:func:`PyArray_DiscardWritebackIfCopy`
followed by ``Py_XDECREF``
Wraps an index to the valid range if it is out of bounds.
+.. c:type:: NPY_SEARCHSIDE
+
+ A variable type indicating whether the index returned should be that of
+ the first suitable location (if :c:data:`NPY_SEARCHLEFT`) or of the last
+ (if :c:data:`NPY_SEARCHRIGHT`).
+
+ .. c:var:: NPY_SEARCHLEFT
+
+ .. c:var:: NPY_SEARCHRIGHT
+
+.. c:type:: NPY_SELECTKIND
+
+ A variable type indicating the selection algorithm being used.
+
+ .. c:var:: NPY_INTROSELECT
+
.. c:type:: NPY_CASTING
.. versionadded:: 1.6
Data type sizes
---------------
-The :c:data:`NPY_SIZEOF_{CTYPE}` constants are defined so that sizeof
+The ``NPY_SIZEOF_{CTYPE}`` constants are defined so that sizeof
information is available to the pre-processor.
-.. c:var:: NPY_SIZEOF_SHORT
+.. c:macro:: NPY_SIZEOF_SHORT
sizeof(short)
-.. c:var:: NPY_SIZEOF_INT
+.. c:macro:: NPY_SIZEOF_INT
sizeof(int)
-.. c:var:: NPY_SIZEOF_LONG
+.. c:macro:: NPY_SIZEOF_LONG
sizeof(long)
-.. c:var:: NPY_SIZEOF_LONGLONG
+.. c:macro:: NPY_SIZEOF_LONGLONG
sizeof(longlong) where longlong is defined appropriately on the
platform.
-.. c:var:: NPY_SIZEOF_PY_LONG_LONG
+.. c:macro:: NPY_SIZEOF_PY_LONG_LONG
-.. c:var:: NPY_SIZEOF_FLOAT
+.. c:macro:: NPY_SIZEOF_FLOAT
sizeof(float)
-.. c:var:: NPY_SIZEOF_DOUBLE
+.. c:macro:: NPY_SIZEOF_DOUBLE
sizeof(double)
-.. c:var:: NPY_SIZEOF_LONG_DOUBLE
+.. c:macro:: NPY_SIZEOF_LONG_DOUBLE
- sizeof(longdouble) (A macro defines **NPY_SIZEOF_LONGDOUBLE** as well.)
+.. c:macro:: NPY_SIZEOF_LONGDOUBLE
-.. c:var:: NPY_SIZEOF_PY_INTPTR_T
+ sizeof(longdouble)
- Size of a pointer on this platform (sizeof(void \*)) (A macro defines
- NPY_SIZEOF_INTP as well.)
+.. c:macro:: NPY_SIZEOF_PY_INTPTR_T
+
+.. c:macro:: NPY_SIZEOF_INTP
+
+ Size of a pointer on this platform (sizeof(void \*))
Platform information
--------------------
-.. c:var:: NPY_CPU_X86
-.. c:var:: NPY_CPU_AMD64
-.. c:var:: NPY_CPU_IA64
-.. c:var:: NPY_CPU_PPC
-.. c:var:: NPY_CPU_PPC64
-.. c:var:: NPY_CPU_SPARC
-.. c:var:: NPY_CPU_SPARC64
-.. c:var:: NPY_CPU_S390
-.. c:var:: NPY_CPU_PARISC
+.. c:macro:: NPY_CPU_X86
+.. c:macro:: NPY_CPU_AMD64
+.. c:macro:: NPY_CPU_IA64
+.. c:macro:: NPY_CPU_PPC
+.. c:macro:: NPY_CPU_PPC64
+.. c:macro:: NPY_CPU_SPARC
+.. c:macro:: NPY_CPU_SPARC64
+.. c:macro:: NPY_CPU_S390
+.. c:macro:: NPY_CPU_PARISC
.. versionadded:: 1.3.0
Defined in ``numpy/npy_cpu.h``
-.. c:var:: NPY_LITTLE_ENDIAN
+.. c:macro:: NPY_LITTLE_ENDIAN
-.. c:var:: NPY_BIG_ENDIAN
+.. c:macro:: NPY_BIG_ENDIAN
-.. c:var:: NPY_BYTE_ORDER
+.. c:macro:: NPY_BYTE_ORDER
.. versionadded:: 1.3.0
Defined in ``numpy/npy_endian.h``.
-.. c:function:: PyArray_GetEndianness()
+.. c:function:: int PyArray_GetEndianness()
.. versionadded:: 1.3.0
One of :c:data:`NPY_CPU_BIG`, :c:data:`NPY_CPU_LITTLE`,
or :c:data:`NPY_CPU_UNKNOWN_ENDIAN`.
+ .. c:macro:: NPY_CPU_BIG
+
+ .. c:macro:: NPY_CPU_LITTLE
+
+ .. c:macro:: NPY_CPU_UNKNOWN_ENDIAN
+
Compiler directives
-------------------
-.. c:var:: NPY_LIKELY
-.. c:var:: NPY_UNLIKELY
-.. c:var:: NPY_UNUSED
+.. c:macro:: NPY_LIKELY
+.. c:macro:: NPY_UNLIKELY
+.. c:macro:: NPY_UNUSED
Interrupt Handling
------------------
-.. c:var:: NPY_INTERRUPT_H
-.. c:var:: NPY_SIGSETJMP
-.. c:var:: NPY_SIGLONGJMP
-.. c:var:: NPY_SIGJMP_BUF
-.. c:var:: NPY_SIGINT_ON
-.. c:var:: NPY_SIGINT_OFF
+.. c:macro:: NPY_INTERRUPT_H
+.. c:macro:: NPY_SIGSETJMP
+.. c:macro:: NPY_SIGLONGJMP
+.. c:macro:: NPY_SIGJMP_BUF
+.. c:macro:: NPY_SIGINT_ON
+.. c:macro:: NPY_SIGINT_OFF
Floating point classification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. c:var:: NPY_NAN
+.. c:macro:: NPY_NAN
This macro is defined to a NaN (Not a Number), and is guaranteed to have
the signbit unset ('positive' NaN). The corresponding single and extension
precision macro are available with the suffix F and L.
-.. c:var:: NPY_INFINITY
+.. c:macro:: NPY_INFINITY
This macro is defined to a positive inf. The corresponding single and
extension precision macro are available with the suffix F and L.
-.. c:var:: NPY_PZERO
+.. c:macro:: NPY_PZERO
This macro is defined to positive zero. The corresponding single and
extension precision macro are available with the suffix F and L.
-.. c:var:: NPY_NZERO
+.. c:macro:: NPY_NZERO
This macro is defined to negative zero (that is with the sign bit set). The
corresponding single and extension precision macro are available with the
and extended precision are also available by adding the ``f`` and
``l`` suffixes respectively.
-.. c:var:: NPY_E
+.. c:macro:: NPY_E
Base of natural logarithm (:math:`e`)
-.. c:var:: NPY_LOG2E
+.. c:macro:: NPY_LOG2E
Logarithm to base 2 of the Euler constant (:math:`\frac{\ln(e)}{\ln(2)}`)
-.. c:var:: NPY_LOG10E
+.. c:macro:: NPY_LOG10E
Logarithm to base 10 of the Euler constant (:math:`\frac{\ln(e)}{\ln(10)}`)
-.. c:var:: NPY_LOGE2
+.. c:macro:: NPY_LOGE2
Natural logarithm of 2 (:math:`\ln(2)`)
-.. c:var:: NPY_LOGE10
+.. c:macro:: NPY_LOGE10
Natural logarithm of 10 (:math:`\ln(10)`)
-.. c:var:: NPY_PI
+.. c:macro:: NPY_PI
Pi (:math:`\pi`)
-.. c:var:: NPY_PI_2
+.. c:macro:: NPY_PI_2
Pi divided by 2 (:math:`\frac{\pi}{2}`)
-.. c:var:: NPY_PI_4
+.. c:macro:: NPY_PI_4
Pi divided by 4 (:math:`\frac{\pi}{4}`)
-.. c:var:: NPY_1_PI
+.. c:macro:: NPY_1_PI
Reciprocal of pi (:math:`\frac{1}{\pi}`)
-.. c:var:: NPY_2_PI
+.. c:macro:: NPY_2_PI
Two times the reciprocal of pi (:math:`\frac{2}{\pi}`)
-.. c:var:: NPY_EULER
+.. c:macro:: NPY_EULER
The Euler constant
:math:`\lim_{n\rightarrow\infty}({\sum_{k=1}^n{\frac{1}{k}}-\ln n})`
__ https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_half_float_pixel.txt
__ https://www.openexr.com/about.html
-.. c:var:: NPY_HALF_ZERO
+.. c:macro:: NPY_HALF_ZERO
This macro is defined to positive zero.
-.. c:var:: NPY_HALF_PZERO
+.. c:macro:: NPY_HALF_PZERO
This macro is defined to positive zero.
-.. c:var:: NPY_HALF_NZERO
+.. c:macro:: NPY_HALF_NZERO
This macro is defined to negative zero.
-.. c:var:: NPY_HALF_ONE
+.. c:macro:: NPY_HALF_ONE
This macro is defined to 1.0.
-.. c:var:: NPY_HALF_NEGONE
+.. c:macro:: NPY_HALF_NEGONE
This macro is defined to -1.0.
-.. c:var:: NPY_HALF_PINF
+.. c:macro:: NPY_HALF_PINF
This macro is defined to +inf.
-.. c:var:: NPY_HALF_NINF
+.. c:macro:: NPY_HALF_NINF
This macro is defined to -inf.
-.. c:var:: NPY_HALF_NAN
+.. c:macro:: NPY_HALF_NAN
This macro is defined to a NaN value, guaranteed to have its sign bit unset.
To use the NPY_NO_DEPRECATED_API mechanism, you need to #define it to
the target API version of NumPy before #including any NumPy headers.
-If you want to confirm that your code is clean against 1.7, use::
+If you want to confirm that your code is clean against 1.7, use:
+
+.. code-block:: c
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
There is a list of enumerated types defined providing the basic 24
data types plus some useful generic names. Whenever the code requires
a type number, one of these enumerated types is requested. The types
-are all called :c:data:`NPY_{NAME}`:
+are all called ``NPY_{NAME}``:
.. c:var:: NPY_BOOL
Other useful related constants are
-.. c:var:: NPY_NTYPES
+.. c:macro:: NPY_NTYPES
The total number of built-in NumPy types. The enumeration covers
the range from 0 to NPY_NTYPES-1.
-.. c:var:: NPY_NOTYPE
+.. c:macro:: NPY_NOTYPE
A signal value guaranteed not to be a valid type enumeration number.
-.. c:var:: NPY_USERDEF
+.. c:macro:: NPY_USERDEF
The start of type numbers used for Custom Data types.
The various character codes indicating certain types are also part of
an enumerated list. References to type characters (should they be
needed at all) should always use these enumerations. The form of them
-is :c:data:`NPY_{NAME}LTR` where ``{NAME}`` can be
+is ``NPY_{NAME}LTR`` where ``{NAME}`` can be
**BOOL**, **BYTE**, **UBYTE**, **SHORT**, **USHORT**, **INT**,
**UINT**, **LONG**, **ULONG**, **LONGLONG**, **ULONGLONG**,
Max and min values for integers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. c:var:: NPY_MAX_INT{bits}
-
-.. c:var:: NPY_MAX_UINT{bits}
-
-.. c:var:: NPY_MIN_INT{bits}
-
+``NPY_MAX_INT{bits}``, ``NPY_MAX_UINT{bits}``, ``NPY_MIN_INT{bits}``
These are defined for ``{bits}`` = 8, 16, 32, 64, 128, and 256 and provide
the maximum (minimum) value of the corresponding (unsigned) integer
type. Note: the actual integer type may not be available on all
platforms (i.e. 128-bit and 256-bit integers are rare).
-.. c:var:: NPY_MIN_{type}
-
+``NPY_MIN_{type}``
This is defined for ``{type}`` = **BYTE**, **SHORT**, **INT**,
**LONG**, **LONGLONG**, **INTP**
-.. c:var:: NPY_MAX_{type}
-
+``NPY_MAX_{type}``
This is defined for all defined for ``{type}`` = **BYTE**, **UBYTE**,
**SHORT**, **USHORT**, **INT**, **UINT**, **LONG**, **ULONG**,
**LONGLONG**, **ULONGLONG**, **INTP**, **UINTP**
Number of bits in data types
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-All :c:data:`NPY_SIZEOF_{CTYPE}` constants have corresponding
-:c:data:`NPY_BITSOF_{CTYPE}` constants defined. The :c:data:`NPY_BITSOF_{CTYPE}`
+All ``NPY_SIZEOF_{CTYPE}`` constants have corresponding
+``NPY_BITSOF_{CTYPE}`` constants defined. The ``NPY_BITSOF_{CTYPE}``
constants provide the number of bits in the data type. Specifically,
the available ``{CTYPE}s`` are
have constants that are defined to be a specific enumerated type
number. Exactly which enumerated type a bit-width type refers to is
platform dependent. In particular, the constants available are
-:c:data:`PyArray_{NAME}{BITS}` where ``{NAME}`` is **INT**, **UINT**,
+``PyArray_{NAME}{BITS}`` where ``{NAME}`` is **INT**, **UINT**,
**FLOAT**, **COMPLEX** and ``{BITS}`` can be 8, 16, 32, 64, 80, 96, 128,
160, 192, 256, and 512. Obviously not all bit-widths are available on
all platforms for all the kinds of numeric types. Commonly 8-, 16-,
floating point, and complex floating point types of specific bit-
widths. The available type names are
- :c:type:`npy_int{bits}`, :c:type:`npy_uint{bits}`, :c:type:`npy_float{bits}`,
- and :c:type:`npy_complex{bits}`
+ ``npy_int{bits}``, ``npy_uint{bits}``, ``npy_float{bits}``,
+ and ``npy_complex{bits}``
where ``{bits}`` is the number of bits in the type and can be **8**,
**16**, **32**, **64**, 128, and 256 for integer types; 16, **32**
For help in printing, the following strings are defined as the correct
format specifier in printf and related commands.
- :c:data:`NPY_LONGLONG_FMT`, :c:data:`NPY_ULONGLONG_FMT`,
- :c:data:`NPY_INTP_FMT`, :c:data:`NPY_UINTP_FMT`,
- :c:data:`NPY_LONGDOUBLE_FMT`
+.. c:macro:: NPY_LONGLONG_FMT
+
+.. c:macro:: NPY_ULONGLONG_FMT
+
+.. c:macro:: NPY_INTP_FMT
+
+.. c:macro:: NPY_UINTP_FMT
+
+.. c:macro:: NPY_LONGDOUBLE_FMT
Flags that may be passed in ``flags``, applying to the whole
iterator, are:
- .. c:var:: NPY_ITER_C_INDEX
+ .. c:macro:: NPY_ITER_C_INDEX
Causes the iterator to track a raveled flat index matching C
order. This option cannot be used with :c:data:`NPY_ITER_F_INDEX`.
- .. c:var:: NPY_ITER_F_INDEX
+ .. c:macro:: NPY_ITER_F_INDEX
Causes the iterator to track a raveled flat index matching Fortran
order. This option cannot be used with :c:data:`NPY_ITER_C_INDEX`.
- .. c:var:: NPY_ITER_MULTI_INDEX
+ .. c:macro:: NPY_ITER_MULTI_INDEX
Causes the iterator to track a multi-index.
This prevents the iterator from coalescing axes to
However, it is possible to remove axes again and use the iterator
normally if the size is small enough after removal.
- .. c:var:: NPY_ITER_EXTERNAL_LOOP
+ .. c:macro:: NPY_ITER_EXTERNAL_LOOP
Causes the iterator to skip iteration of the innermost
loop, requiring the user of the iterator to handle it.
This flag is incompatible with :c:data:`NPY_ITER_C_INDEX`,
:c:data:`NPY_ITER_F_INDEX`, and :c:data:`NPY_ITER_MULTI_INDEX`.
- .. c:var:: NPY_ITER_DONT_NEGATE_STRIDES
+ .. c:macro:: NPY_ITER_DONT_NEGATE_STRIDES
This only affects the iterator when :c:type:`NPY_KEEPORDER` is
specified for the order parameter. By default with
but don't want an axis reversed. This is the behavior of
``numpy.ravel(a, order='K')``, for instance.
- .. c:var:: NPY_ITER_COMMON_DTYPE
+ .. c:macro:: NPY_ITER_COMMON_DTYPE
Causes the iterator to convert all the operands to a common
data type, calculated based on the ufunc type promotion rules.
If the common data type is known ahead of time, don't use this
flag. Instead, set the requested dtype for all the operands.
- .. c:var:: NPY_ITER_REFS_OK
+ .. c:macro:: NPY_ITER_REFS_OK
Indicates that arrays with reference types (object
arrays or structured arrays containing an object type)
:c:func:`NpyIter_IterationNeedsAPI(iter)` is true, in which case
it may not release the GIL during iteration.
- .. c:var:: NPY_ITER_ZEROSIZE_OK
+ .. c:macro:: NPY_ITER_ZEROSIZE_OK
Indicates that arrays with a size of zero should be permitted.
Since the typical iteration loop does not naturally work with
than zero before entering the iteration loop.
Currently only the operands are checked, not a forced shape.
- .. c:var:: NPY_ITER_REDUCE_OK
+ .. c:macro:: NPY_ITER_REDUCE_OK
Permits writeable operands with a dimension with zero
stride and size greater than one. Note that such operands
after initializing the allocated operand to prepare the
buffers.
- .. c:var:: NPY_ITER_RANGED
+ .. c:macro:: NPY_ITER_RANGED
Enables support for iteration of sub-ranges of the full
``iterindex`` range ``[0, NpyIter_IterSize(iter))``. Use
would require special handling, effectively making it more
like the buffered version.
- .. c:var:: NPY_ITER_BUFFERED
+ .. c:macro:: NPY_ITER_BUFFERED
Causes the iterator to store buffering data, and use buffering
to satisfy data type, alignment, and byte-order requirements.
the inner loops may become smaller depending
on the structure of the reduction.
- .. c:var:: NPY_ITER_GROWINNER
+ .. c:macro:: NPY_ITER_GROWINNER
When buffering is enabled, this allows the size of the inner
loop to grow when buffering isn't necessary. This option
data, rather than anything with small cache-friendly arrays
of temporary values for each inner loop.
- .. c:var:: NPY_ITER_DELAY_BUFALLOC
+ .. c:macro:: NPY_ITER_DELAY_BUFALLOC
When buffering is enabled, this delays allocation of the
buffers until :c:func:`NpyIter_Reset` or another reset function is
Then, call :c:func:`NpyIter_Reset` to allocate and fill the buffers
with their initial values.
- .. c:var:: NPY_ITER_COPY_IF_OVERLAP
+ .. c:macro:: NPY_ITER_COPY_IF_OVERLAP
If any write operand has overlap with any read operand, eliminate all
overlap by making temporary copies (enabling UPDATEIFCOPY for write
Flags that may be passed in ``op_flags[i]``, where ``0 <= i < nop``:
- .. c:var:: NPY_ITER_READWRITE
- .. c:var:: NPY_ITER_READONLY
- .. c:var:: NPY_ITER_WRITEONLY
+ .. c:macro:: NPY_ITER_READWRITE
+ .. c:macro:: NPY_ITER_READONLY
+ .. c:macro:: NPY_ITER_WRITEONLY
Indicate how the user of the iterator will read or write
to ``op[i]``. Exactly one of these flags must be specified
semantics. The data will be written back to the original array
when ``NpyIter_Deallocate`` is called.
- .. c:var:: NPY_ITER_COPY
+ .. c:macro:: NPY_ITER_COPY
Allow a copy of ``op[i]`` to be made if it does not
meet the data type or alignment requirements as specified
by the constructor flags and parameters.
- .. c:var:: NPY_ITER_UPDATEIFCOPY
+ .. c:macro:: NPY_ITER_UPDATEIFCOPY
Triggers :c:data:`NPY_ITER_COPY`, and when an array operand
is flagged for writing and is copied, causes the data
to back to ``op[i]`` on calling ``NpyIter_Deallocate``, instead of
doing the unnecessary copy operation.
- .. c:var:: NPY_ITER_NBO
- .. c:var:: NPY_ITER_ALIGNED
- .. c:var:: NPY_ITER_CONTIG
+ .. c:macro:: NPY_ITER_NBO
+ .. c:macro:: NPY_ITER_ALIGNED
+ .. c:macro:: NPY_ITER_CONTIG
Causes the iterator to provide data for ``op[i]``
that is in native byte order, aligned according to
the NBO flag overrides it and the requested data type is
converted to be in native byte order.
- .. c:var:: NPY_ITER_ALLOCATE
+ .. c:macro:: NPY_ITER_ALLOCATE
This is for output arrays, and requires that the flag
:c:data:`NPY_ITER_WRITEONLY` or :c:data:`NPY_ITER_READWRITE`
getting the i-th object in the returned C array. The caller
must call Py_INCREF on it to claim a reference to the array.
- .. c:var:: NPY_ITER_NO_SUBTYPE
+ .. c:macro:: NPY_ITER_NO_SUBTYPE
For use with :c:data:`NPY_ITER_ALLOCATE`, this flag disables
allocating an array subtype for the output, forcing
TODO: Maybe it would be better to introduce a function
``NpyIter_GetWrappedOutput`` and remove this flag?
- .. c:var:: NPY_ITER_NO_BROADCAST
+ .. c:macro:: NPY_ITER_NO_BROADCAST
Ensures that the input or output matches the iteration
dimensions exactly.
- .. c:var:: NPY_ITER_ARRAYMASK
+ .. c:macro:: NPY_ITER_ARRAYMASK
.. versionadded:: 1.7
modified. This is useful when the mask should be a combination
of input masks.
- .. c:var:: NPY_ITER_WRITEMASKED
+ .. c:macro:: NPY_ITER_WRITEMASKED
.. versionadded:: 1.7
returns true from the corresponding element in the ARRAYMASK
operand.
- .. c:var:: NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE
+ .. c:macro:: NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE
In memory overlap checks, assume that operands with
``NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE`` enabled are accessed only
:c:func:`NpyIter_Deallocate` must be called for each copy.
-.. c:function:: int NpyIter_RemoveAxis(NpyIter* iter, int axis)``
+.. c:function:: int NpyIter_RemoveAxis(NpyIter* iter, int axis)
Removes an axis from iteration. This requires that
:c:data:`NPY_ITER_MULTI_INDEX` was set for iterator creation, and does
NPY_MAX_INTP is placed in the stride.
Once the iterator is prepared for iteration (after a reset if
- :c:data:`NPY_DELAY_BUFALLOC` was used), call this to get the strides
+ :c:data:`NPY_ITER_DELAY_BUFALLOC` was used), call this to get the strides
which may be used to select a fast inner loop function. For example,
if the stride is 0, that means the inner loop can always load its
value into a variable once, then use the variable throughout the loop,
Python. The ndarray object is an example of a new type defined in C.
New types are defined in C by two basic steps:
-1. creating a C-structure (usually named :c:type:`Py{Name}Object`) that is
+1. creating a C-structure (usually named ``Py{Name}Object``) that is
binary- compatible with the :c:type:`PyObject` structure itself but holds
the additional information needed for that particular object;
typeobject.
.. c:type:: PyArrayObject
+ NPY_AO
The :c:type:`PyArrayObject` C-structure contains all of the required
information for an array. All instances of an ndarray (and its
provided macros. If you need a shorter name, then you can make use
of :c:type:`NPY_AO` (deprecated) which is defined to be equivalent to
:c:type:`PyArrayObject`. Direct access to the struct fields are
- deprecated. Use the `PyArray_*(arr)` form instead.
+ deprecated. Use the ``PyArray_*(arr)`` form instead.
+ As of NumPy 1.20, the size of this struct is not considered part of
+ the NumPy ABI (see note at the end of the member list).
.. code-block:: c
PyArray_Descr *descr;
int flags;
PyObject *weakreflist;
+ /* version dependend private members */
} PyArrayObject;
-.. c:macro:: PyArrayObject.PyObject_HEAD
+ .. c:macro:: PyObject_HEAD
- This is needed by all Python objects. It consists of (at least)
- a reference count member ( ``ob_refcnt`` ) and a pointer to the
- typeobject ( ``ob_type`` ). (Other elements may also be present
- if Python was compiled with special options see
- Include/object.h in the Python source tree for more
- information). The ob_type member points to a Python type
- object.
+ This is needed by all Python objects. It consists of (at least)
+ a reference count member ( ``ob_refcnt`` ) and a pointer to the
+ typeobject ( ``ob_type`` ). (Other elements may also be present
+ if Python was compiled with special options see
+ Include/object.h in the Python source tree for more
+ information). The ob_type member points to a Python type
+ object.
-.. c:member:: char *PyArrayObject.data
+ .. c:member:: char *data
- Accessible via :c:data:`PyArray_DATA`, this data member is a
- pointer to the first element of the array. This pointer can
- (and normally should) be recast to the data type of the array.
+ Accessible via :c:data:`PyArray_DATA`, this data member is a
+ pointer to the first element of the array. This pointer can
+ (and normally should) be recast to the data type of the array.
-.. c:member:: int PyArrayObject.nd
+ .. c:member:: int nd
- An integer providing the number of dimensions for this
- array. When nd is 0, the array is sometimes called a rank-0
- array. Such arrays have undefined dimensions and strides and
- cannot be accessed. Macro :c:data:`PyArray_NDIM` defined in
- ``ndarraytypes.h`` points to this data member. :c:data:`NPY_MAXDIMS`
- is the largest number of dimensions for any array.
+ An integer providing the number of dimensions for this
+ array. When nd is 0, the array is sometimes called a rank-0
+ array. Such arrays have undefined dimensions and strides and
+ cannot be accessed. Macro :c:data:`PyArray_NDIM` defined in
+ ``ndarraytypes.h`` points to this data member. :c:data:`NPY_MAXDIMS`
+ is the largest number of dimensions for any array.
-.. c:member:: npy_intp PyArrayObject.dimensions
+ .. c:member:: npy_intp dimensions
- An array of integers providing the shape in each dimension as
- long as nd :math:`\geq` 1. The integer is always large enough
- to hold a pointer on the platform, so the dimension size is
- only limited by memory. :c:data:`PyArray_DIMS` is the macro
- associated with this data member.
+ An array of integers providing the shape in each dimension as
+ long as nd :math:`\geq` 1. The integer is always large enough
+ to hold a pointer on the platform, so the dimension size is
+ only limited by memory. :c:data:`PyArray_DIMS` is the macro
+ associated with this data member.
-.. c:member:: npy_intp *PyArrayObject.strides
+ .. c:member:: npy_intp *strides
- An array of integers providing for each dimension the number of
- bytes that must be skipped to get to the next element in that
- dimension. Associated with macro :c:data:`PyArray_STRIDES`.
+ An array of integers providing for each dimension the number of
+ bytes that must be skipped to get to the next element in that
+ dimension. Associated with macro :c:data:`PyArray_STRIDES`.
-.. c:member:: PyObject *PyArrayObject.base
+ .. c:member:: PyObject *base
- Pointed to by :c:data:`PyArray_BASE`, this member is used to hold a
- pointer to another Python object that is related to this array.
- There are two use cases:
+ Pointed to by :c:data:`PyArray_BASE`, this member is used to hold a
+ pointer to another Python object that is related to this array.
+ There are two use cases:
- - If this array does not own its own memory, then base points to the
- Python object that owns it (perhaps another array object)
- - If this array has the (deprecated) :c:data:`NPY_ARRAY_UPDATEIFCOPY` or
- :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` flag set, then this array is a working
- copy of a "misbehaved" array.
+ - If this array does not own its own memory, then base points to the
+ Python object that owns it (perhaps another array object)
+ - If this array has the (deprecated) :c:data:`NPY_ARRAY_UPDATEIFCOPY` or
+ :c:data:`NPY_ARRAY_WRITEBACKIFCOPY` flag set, then this array is a working
+ copy of a "misbehaved" array.
- When ``PyArray_ResolveWritebackIfCopy`` is called, the array pointed to
- by base will be updated with the contents of this array.
+ When ``PyArray_ResolveWritebackIfCopy`` is called, the array pointed to
+ by base will be updated with the contents of this array.
-.. c:member:: PyArray_Descr *PyArrayObject.descr
+ .. c:member:: PyArray_Descr *descr
- A pointer to a data-type descriptor object (see below). The
- data-type descriptor object is an instance of a new built-in
- type which allows a generic description of memory. There is a
- descriptor structure for each data type supported. This
- descriptor structure contains useful information about the type
- as well as a pointer to a table of function pointers to
- implement specific functionality. As the name suggests, it is
- associated with the macro :c:data:`PyArray_DESCR`.
+ A pointer to a data-type descriptor object (see below). The
+ data-type descriptor object is an instance of a new built-in
+ type which allows a generic description of memory. There is a
+ descriptor structure for each data type supported. This
+ descriptor structure contains useful information about the type
+ as well as a pointer to a table of function pointers to
+ implement specific functionality. As the name suggests, it is
+ associated with the macro :c:data:`PyArray_DESCR`.
-.. c:member:: int PyArrayObject.flags
+ .. c:member:: int flags
- Pointed to by the macro :c:data:`PyArray_FLAGS`, this data member represents
- the flags indicating how the memory pointed to by data is to be
- interpreted. Possible flags are :c:data:`NPY_ARRAY_C_CONTIGUOUS`,
- :c:data:`NPY_ARRAY_F_CONTIGUOUS`, :c:data:`NPY_ARRAY_OWNDATA`,
- :c:data:`NPY_ARRAY_ALIGNED`, :c:data:`NPY_ARRAY_WRITEABLE`,
- :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`, and :c:data:`NPY_ARRAY_UPDATEIFCOPY`.
+ Pointed to by the macro :c:data:`PyArray_FLAGS`, this data member represents
+ the flags indicating how the memory pointed to by data is to be
+ interpreted. Possible flags are :c:data:`NPY_ARRAY_C_CONTIGUOUS`,
+ :c:data:`NPY_ARRAY_F_CONTIGUOUS`, :c:data:`NPY_ARRAY_OWNDATA`,
+ :c:data:`NPY_ARRAY_ALIGNED`, :c:data:`NPY_ARRAY_WRITEABLE`,
+ :c:data:`NPY_ARRAY_WRITEBACKIFCOPY`, and :c:data:`NPY_ARRAY_UPDATEIFCOPY`.
-.. c:member:: PyObject *PyArrayObject.weakreflist
+ .. c:member:: PyObject *weakreflist
- This member allows array objects to have weak references (using the
- weakref module).
+ This member allows array objects to have weak references (using the
+ weakref module).
+
+ .. note::
+
+ Further members are considered private and version dependend. If the size
+ of the struct is important for your code, special care must be taken.
+ A possible use-case when this is relevant is subclassing in C.
+ If your code relies on ``sizeof(PyArrayObject)`` to be constant,
+ you must add the following check at import time:
+
+ .. code-block:: c
+
+ if (sizeof(PyArrayObject) < PyArray_Type.tp_basicsize) {
+ PyErr_SetString(PyExc_ImportError,
+ "Binary incompatibility with NumPy, must recompile/update X.");
+ return NULL;
+ }
+
+ To ensure that your code does not have to be compiled for a specific
+ NumPy version, you may add a constant, leaving room for changes in NumPy.
+ A solution guaranteed to be compatible with any future NumPy version
+ requires the use of a runtime calculate offset and allocation size.
PyArrayDescr_Type and PyArray_Descr
npy_hash_t hash;
} PyArray_Descr;
-.. c:member:: PyTypeObject *PyArray_Descr.typeobj
-
- Pointer to a typeobject that is the corresponding Python type for
- the elements of this array. For the builtin types, this points to
- the corresponding array scalar. For user-defined types, this
- should point to a user-defined typeobject. This typeobject can
- either inherit from array scalars or not. If it does not inherit
- from array scalars, then the :c:data:`NPY_USE_GETITEM` and
- :c:data:`NPY_USE_SETITEM` flags should be set in the ``flags`` member.
+ .. c:member:: PyTypeObject *typeobj
-.. c:member:: char PyArray_Descr.kind
+ Pointer to a typeobject that is the corresponding Python type for
+ the elements of this array. For the builtin types, this points to
+ the corresponding array scalar. For user-defined types, this
+ should point to a user-defined typeobject. This typeobject can
+ either inherit from array scalars or not. If it does not inherit
+ from array scalars, then the :c:data:`NPY_USE_GETITEM` and
+ :c:data:`NPY_USE_SETITEM` flags should be set in the ``flags`` member.
- A character code indicating the kind of array (using the array
- interface typestring notation). A 'b' represents Boolean, a 'i'
- represents signed integer, a 'u' represents unsigned integer, 'f'
- represents floating point, 'c' represents complex floating point, 'S'
- represents 8-bit zero-terminated bytes, 'U' represents 32-bit/character
- unicode string, and 'V' represents arbitrary.
+ .. c:member:: char kind
-.. c:member:: char PyArray_Descr.type
+ A character code indicating the kind of array (using the array
+ interface typestring notation). A 'b' represents Boolean, a 'i'
+ represents signed integer, a 'u' represents unsigned integer, 'f'
+ represents floating point, 'c' represents complex floating point, 'S'
+ represents 8-bit zero-terminated bytes, 'U' represents 32-bit/character
+ unicode string, and 'V' represents arbitrary.
- A traditional character code indicating the data type.
+ .. c:member:: char type
-.. c:member:: char PyArray_Descr.byteorder
+ A traditional character code indicating the data type.
- A character indicating the byte-order: '>' (big-endian), '<' (little-
- endian), '=' (native), '\|' (irrelevant, ignore). All builtin data-
- types have byteorder '='.
+ .. c:member:: char byteorder
-.. c:member:: char PyArray_Descr.flags
+ A character indicating the byte-order: '>' (big-endian), '<' (little-
+ endian), '=' (native), '\|' (irrelevant, ignore). All builtin data-
+ types have byteorder '='.
- A data-type bit-flag that determines if the data-type exhibits object-
- array like behavior. Each bit in this member is a flag which are named
- as:
+ .. c:member:: char flags
- .. c:var:: NPY_ITEM_REFCOUNT
+ A data-type bit-flag that determines if the data-type exhibits object-
+ array like behavior. Each bit in this member is a flag which are named
+ as:
- Indicates that items of this data-type must be reference
- counted (using :c:func:`Py_INCREF` and :c:func:`Py_DECREF` ).
+ .. c:macro:: NPY_ITEM_REFCOUNT
- .. c:var:: NPY_ITEM_HASOBJECT
+ Indicates that items of this data-type must be reference
+ counted (using :c:func:`Py_INCREF` and :c:func:`Py_DECREF` ).
- Same as :c:data:`NPY_ITEM_REFCOUNT`.
+ .. c:macro:: NPY_ITEM_HASOBJECT
- .. c:var:: NPY_LIST_PICKLE
+ Same as :c:data:`NPY_ITEM_REFCOUNT`.
- Indicates arrays of this data-type must be converted to a list
- before pickling.
+ .. c:macro:: NPY_LIST_PICKLE
- .. c:var:: NPY_ITEM_IS_POINTER
+ Indicates arrays of this data-type must be converted to a list
+ before pickling.
- Indicates the item is a pointer to some other data-type
+ .. c:macro:: NPY_ITEM_IS_POINTER
- .. c:var:: NPY_NEEDS_INIT
+ Indicates the item is a pointer to some other data-type
- Indicates memory for this data-type must be initialized (set
- to 0) on creation.
+ .. c:macro:: NPY_NEEDS_INIT
- .. c:var:: NPY_NEEDS_PYAPI
+ Indicates memory for this data-type must be initialized (set
+ to 0) on creation.
- Indicates this data-type requires the Python C-API during
- access (so don't give up the GIL if array access is going to
- be needed).
+ .. c:macro:: NPY_NEEDS_PYAPI
- .. c:var:: NPY_USE_GETITEM
+ Indicates this data-type requires the Python C-API during
+ access (so don't give up the GIL if array access is going to
+ be needed).
- On array access use the ``f->getitem`` function pointer
- instead of the standard conversion to an array scalar. Must
- use if you don't define an array scalar to go along with
- the data-type.
+ .. c:macro:: NPY_USE_GETITEM
- .. c:var:: NPY_USE_SETITEM
+ On array access use the ``f->getitem`` function pointer
+ instead of the standard conversion to an array scalar. Must
+ use if you don't define an array scalar to go along with
+ the data-type.
- When creating a 0-d array from an array scalar use
- ``f->setitem`` instead of the standard copy from an array
- scalar. Must use if you don't define an array scalar to go
- along with the data-type.
+ .. c:macro:: NPY_USE_SETITEM
- .. c:var:: NPY_FROM_FIELDS
+ When creating a 0-d array from an array scalar use
+ ``f->setitem`` instead of the standard copy from an array
+ scalar. Must use if you don't define an array scalar to go
+ along with the data-type.
- The bits that are inherited for the parent data-type if these
- bits are set in any field of the data-type. Currently (
- :c:data:`NPY_NEEDS_INIT` \| :c:data:`NPY_LIST_PICKLE` \|
- :c:data:`NPY_ITEM_REFCOUNT` \| :c:data:`NPY_NEEDS_PYAPI` ).
+ .. c:macro:: NPY_FROM_FIELDS
- .. c:var:: NPY_OBJECT_DTYPE_FLAGS
+ The bits that are inherited for the parent data-type if these
+ bits are set in any field of the data-type. Currently (
+ :c:data:`NPY_NEEDS_INIT` \| :c:data:`NPY_LIST_PICKLE` \|
+ :c:data:`NPY_ITEM_REFCOUNT` \| :c:data:`NPY_NEEDS_PYAPI` ).
- Bits set for the object data-type: ( :c:data:`NPY_LIST_PICKLE`
- \| :c:data:`NPY_USE_GETITEM` \| :c:data:`NPY_ITEM_IS_POINTER` \|
- :c:data:`NPY_REFCOUNT` \| :c:data:`NPY_NEEDS_INIT` \|
- :c:data:`NPY_NEEDS_PYAPI`).
+ .. c:macro:: NPY_OBJECT_DTYPE_FLAGS
- .. c:function:: PyDataType_FLAGCHK(PyArray_Descr *dtype, int flags)
+ Bits set for the object data-type: ( :c:data:`NPY_LIST_PICKLE`
+ \| :c:data:`NPY_USE_GETITEM` \| :c:data:`NPY_ITEM_IS_POINTER` \|
+ :c:data:`NPY_ITEM_REFCOUNT` \| :c:data:`NPY_NEEDS_INIT` \|
+ :c:data:`NPY_NEEDS_PYAPI`).
- Return true if all the given flags are set for the data-type
- object.
+ .. c:function:: int PyDataType_FLAGCHK(PyArray_Descr *dtype, int flags)
- .. c:function:: PyDataType_REFCHK(PyArray_Descr *dtype)
+ Return true if all the given flags are set for the data-type
+ object.
- Equivalent to :c:func:`PyDataType_FLAGCHK` (*dtype*,
- :c:data:`NPY_ITEM_REFCOUNT`).
+ .. c:function:: int PyDataType_REFCHK(PyArray_Descr *dtype)
-.. c:member:: int PyArray_Descr.type_num
+ Equivalent to :c:func:`PyDataType_FLAGCHK` (*dtype*,
+ :c:data:`NPY_ITEM_REFCOUNT`).
- A number that uniquely identifies the data type. For new data-types,
- this number is assigned when the data-type is registered.
+ .. c:member:: int type_num
-.. c:member:: int PyArray_Descr.elsize
+ A number that uniquely identifies the data type. For new data-types,
+ this number is assigned when the data-type is registered.
- For data types that are always the same size (such as long), this
- holds the size of the data type. For flexible data types where
- different arrays can have a different elementsize, this should be
- 0.
+ .. c:member:: int elsize
-.. c:member:: int PyArray_Descr.alignment
+ For data types that are always the same size (such as long), this
+ holds the size of the data type. For flexible data types where
+ different arrays can have a different elementsize, this should be
+ 0.
- A number providing alignment information for this data type.
- Specifically, it shows how far from the start of a 2-element
- structure (whose first element is a ``char`` ), the compiler
- places an item of this type: ``offsetof(struct {char c; type v;},
- v)``
+ .. c:member:: int alignment
-.. c:member:: PyArray_ArrayDescr *PyArray_Descr.subarray
+ A number providing alignment information for this data type.
+ Specifically, it shows how far from the start of a 2-element
+ structure (whose first element is a ``char`` ), the compiler
+ places an item of this type: ``offsetof(struct {char c; type v;},
+ v)``
- If this is non- ``NULL``, then this data-type descriptor is a
- C-style contiguous array of another data-type descriptor. In
- other-words, each element that this descriptor describes is
- actually an array of some other base descriptor. This is most
- useful as the data-type descriptor for a field in another
- data-type descriptor. The fields member should be ``NULL`` if this
- is non- ``NULL`` (the fields member of the base descriptor can be
- non- ``NULL`` however). The :c:type:`PyArray_ArrayDescr` structure is
- defined using
+ .. c:member:: PyArray_ArrayDescr *subarray
- .. code-block:: c
+ If this is non- ``NULL``, then this data-type descriptor is a
+ C-style contiguous array of another data-type descriptor. In
+ other-words, each element that this descriptor describes is
+ actually an array of some other base descriptor. This is most
+ useful as the data-type descriptor for a field in another
+ data-type descriptor. The fields member should be ``NULL`` if this
+ is non- ``NULL`` (the fields member of the base descriptor can be
+ non- ``NULL`` however).
- typedef struct {
- PyArray_Descr *base;
- PyObject *shape;
- } PyArray_ArrayDescr;
+ .. c:type:: PyArray_ArrayDescr
- The elements of this structure are:
+ .. code-block:: c
- .. c:member:: PyArray_Descr *PyArray_ArrayDescr.base
+ typedef struct {
+ PyArray_Descr *base;
+ PyObject *shape;
+ } PyArray_ArrayDescr;
- The data-type-descriptor object of the base-type.
+ .. c:member:: PyArray_Descr *base
- .. c:member:: PyObject *PyArray_ArrayDescr.shape
+ The data-type-descriptor object of the base-type.
- The shape (always C-style contiguous) of the sub-array as a Python
- tuple.
+ .. c:member:: PyObject *shape
+ The shape (always C-style contiguous) of the sub-array as a Python
+ tuple.
-.. c:member:: PyObject *PyArray_Descr.fields
+ .. c:member:: PyObject *fields
- If this is non-NULL, then this data-type-descriptor has fields
- described by a Python dictionary whose keys are names (and also
- titles if given) and whose values are tuples that describe the
- fields. Recall that a data-type-descriptor always describes a
- fixed-length set of bytes. A field is a named sub-region of that
- total, fixed-length collection. A field is described by a tuple
- composed of another data- type-descriptor and a byte
- offset. Optionally, the tuple may contain a title which is
- normally a Python string. These tuples are placed in this
- dictionary keyed by name (and also title if given).
+ If this is non-NULL, then this data-type-descriptor has fields
+ described by a Python dictionary whose keys are names (and also
+ titles if given) and whose values are tuples that describe the
+ fields. Recall that a data-type-descriptor always describes a
+ fixed-length set of bytes. A field is a named sub-region of that
+ total, fixed-length collection. A field is described by a tuple
+ composed of another data- type-descriptor and a byte
+ offset. Optionally, the tuple may contain a title which is
+ normally a Python string. These tuples are placed in this
+ dictionary keyed by name (and also title if given).
-.. c:member:: PyObject *PyArray_Descr.names
+ .. c:member:: PyObject *names
- An ordered tuple of field names. It is NULL if no field is
- defined.
+ An ordered tuple of field names. It is NULL if no field is
+ defined.
-.. c:member:: PyArray_ArrFuncs *PyArray_Descr.f
+ .. c:member:: PyArray_ArrFuncs *f
- A pointer to a structure containing functions that the type needs
- to implement internal features. These functions are not the same
- thing as the universal functions (ufuncs) described later. Their
- signatures can vary arbitrarily.
+ A pointer to a structure containing functions that the type needs
+ to implement internal features. These functions are not the same
+ thing as the universal functions (ufuncs) described later. Their
+ signatures can vary arbitrarily.
-.. c:member:: PyObject *PyArray_Descr.metadata
+ .. c:member:: PyObject *metadata
- Metadata about this dtype.
+ Metadata about this dtype.
-.. c:member:: NpyAuxData *PyArray_Descr.c_metadata
+ .. c:member:: NpyAuxData *c_metadata
- Metadata specific to the C implementation
- of the particular dtype. Added for NumPy 1.7.0.
+ Metadata specific to the C implementation
+ of the particular dtype. Added for NumPy 1.7.0.
-.. c:member:: Npy_hash_t *PyArray_Descr.hash
+ .. c:type:: npy_hash_t
+ .. c:member:: npy_hash_t *hash
- Currently unused. Reserved for future use in caching
- hash values.
+ Currently unused. Reserved for future use in caching
+ hash values.
.. c:type:: PyArray_ArrFuncs
This function should be called without holding the Python GIL, and
has to grab it for error reporting.
- .. c:member:: Bool nonzero(void* data, void* arr)
+ .. c:member:: npy_bool nonzero(void* data, void* arr)
A pointer to a function that returns TRUE if the item of
``arr`` pointed to by ``data`` is nonzero. This function can
Either ``NULL`` or a dictionary containing low-level casting
functions for user- defined data-types. Each function is
- wrapped in a :c:type:`PyCObject *` and keyed by the data-type number.
+ wrapped in a :c:type:`PyCapsule *<PyCapsule>` and keyed by
+ the data-type number.
.. c:member:: NPY_SCALARKIND scalarkind(PyArrayObject* arr)
npy_uint32 *iter_flags;
/* new in API version 0x0000000D */
npy_intp *core_dim_sizes;
- npy_intp *core_dim_flags;
-
+ npy_uint32 *core_dim_flags;
+ PyObject *identity_value;
} PyUFuncObject;
- .. c:macro: PyUFuncObject.PyObject_HEAD
+ .. c:macro: PyObject_HEAD
required for all Python objects.
- .. c:member:: int PyUFuncObject.nin
+ .. c:member:: int nin
The number of input arguments.
- .. c:member:: int PyUFuncObject.nout
+ .. c:member:: int nout
The number of output arguments.
- .. c:member:: int PyUFuncObject.nargs
+ .. c:member:: int nargs
The total number of arguments (*nin* + *nout*). This must be
less than :c:data:`NPY_MAXARGS`.
- .. c:member:: int PyUFuncObject.identity
+ .. c:member:: int identity
Either :c:data:`PyUFunc_One`, :c:data:`PyUFunc_Zero`,
- :c:data:`PyUFunc_None` or :c:data:`PyUFunc_AllOnes` to indicate
+ :c:data:`PyUFunc_MinusOne`, :c:data:`PyUFunc_None`,
+ :c:data:`PyUFunc_ReorderableNone`, or
+ :c:data:`PyUFunc_IdentityValue` to indicate
the identity for this operation. It is only used for a
reduce-like call on an empty array.
- .. c:member:: void PyUFuncObject.functions( \
+ .. c:member:: void functions( \
char** args, npy_intp* dims, npy_intp* steps, void* extradata)
An array of function pointers --- one for each data type
passed in as *extradata*. The size of this function pointer
array is ntypes.
- .. c:member:: void **PyUFuncObject.data
+ .. c:member:: void **data
Extra data to be passed to the 1-d vector loops or ``NULL`` if
no extra-data is needed. This C-array must be the same size (
just 1-d vector loops that make use of this extra data to
receive a pointer to the actual function to call.
- .. c:member:: int PyUFuncObject.ntypes
+ .. c:member:: int ntypes
The number of supported data types for the ufunc. This number
specifies how many different 1-d loops (of the builtin data
types) are available.
- .. c:member:: int PyUFuncObject.reserved1
+ .. c:member:: int reserved1
Unused.
- .. c:member:: char *PyUFuncObject.name
+ .. c:member:: char *name
A string name for the ufunc. This is used dynamically to build
the __doc\__ attribute of ufuncs.
- .. c:member:: char *PyUFuncObject.types
+ .. c:member:: char *types
An array of :math:`nargs \times ntypes` 8-bit type_numbers
which contains the type signature for the function for each of
vector loop. These type numbers do not have to be the same type
and mixed-type ufuncs are supported.
- .. c:member:: char *PyUFuncObject.doc
+ .. c:member:: char *doc
Documentation for the ufunc. Should not contain the function
signature as this is generated dynamically when __doc\__ is
retrieved.
- .. c:member:: void *PyUFuncObject.ptr
+ .. c:member:: void *ptr
Any dynamically allocated memory. Currently, this is used for
dynamic ufuncs created from a python function to store room for
the types, data, and name members.
- .. c:member:: PyObject *PyUFuncObject.obj
+ .. c:member:: PyObject *obj
For ufuncs dynamically created from python functions, this member
holds a reference to the underlying Python function.
- .. c:member:: PyObject *PyUFuncObject.userloops
+ .. c:member:: PyObject *userloops
A dictionary of user-defined 1-d vector loops (stored as CObject
ptrs) for user-defined types. A loop may be registered by the
User defined type numbers are always larger than
:c:data:`NPY_USERDEF`.
- .. c:member:: int PyUFuncObject.core_enabled
+ .. c:member:: int core_enabled
0 for scalar ufuncs; 1 for generalized ufuncs
- .. c:member:: int PyUFuncObject.core_num_dim_ix
+ .. c:member:: int core_num_dim_ix
Number of distinct core dimension names in the signature
- .. c:member:: int *PyUFuncObject.core_num_dims
+ .. c:member:: int *core_num_dims
Number of core dimensions of each argument
- .. c:member:: int *PyUFuncObject.core_dim_ixs
+ .. c:member:: int *core_dim_ixs
Dimension indices in a flattened form; indices of argument ``k`` are
stored in ``core_dim_ixs[core_offsets[k] : core_offsets[k] +
core_numdims[k]]``
- .. c:member:: int *PyUFuncObject.core_offsets
+ .. c:member:: int *core_offsets
Position of 1st core dimension of each argument in ``core_dim_ixs``,
equivalent to cumsum(``core_num_dims``)
- .. c:member:: char *PyUFuncObject.core_signature
+ .. c:member:: char *core_signature
Core signature string
- .. c:member:: PyUFunc_TypeResolutionFunc *PyUFuncObject.type_resolver
+ .. c:member:: PyUFunc_TypeResolutionFunc *type_resolver
A function which resolves the types and fills an array with the dtypes
for the inputs and outputs
- .. c:member:: PyUFunc_LegacyInnerLoopSelectionFunc *PyUFuncObject.legacy_inner_loop_selector
+ .. c:member:: PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector
A function which returns an inner loop. The ``legacy`` in the name arises
because for NumPy 1.6 a better variant had been planned. This variant
has not yet come about.
- .. c:member:: void *PyUFuncObject.reserved2
+ .. c:member:: void *reserved2
For a possible future loop selector with a different signature.
- .. c:member:: PyUFunc_MaskedInnerLoopSelectionFunc *PyUFuncObject.masked_inner_loop_selector
+ .. c:member:: PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector
Function which returns a masked inner loop for the ufunc
- .. c:member:: npy_uint32 PyUFuncObject.op_flags
+ .. c:member:: npy_uint32 op_flags
Override the default operand flags for each ufunc operand.
- .. c:member:: npy_uint32 PyUFuncObject.iter_flags
+ .. c:member:: npy_uint32 iter_flags
Override the default nditer flags for the ufunc.
Added in API version 0x0000000D
- .. c:member:: npy_intp *PyUFuncObject.core_dim_sizes
+ .. c:member:: npy_intp *core_dim_sizes
For each distinct core dimension, the possible
- :ref:`frozen <frozen>` size if :c:data:`UFUNC_CORE_DIM_SIZE_INFERRED` is 0
+ :ref:`frozen <frozen>` size if
+ :c:data:`UFUNC_CORE_DIM_SIZE_INFERRED` is ``0``
- .. c:member:: npy_uint32 *PyUFuncObject.core_dim_flags
+ .. c:member:: npy_uint32 *core_dim_flags
For each distinct core dimension, a set of ``UFUNC_CORE_DIM*`` flags
- - :c:data:`UFUNC_CORE_DIM_CAN_IGNORE` if the dim name ends in ``?``
- - :c:data:`UFUNC_CORE_DIM_SIZE_INFERRED` if the dim size will be
- determined from the operands and not from a :ref:`frozen <frozen>` signature
+ .. c:macro:: UFUNC_CORE_DIM_CAN_IGNORE
+
+ if the dim name ends in ``?``
+
+ .. c:macro:: UFUNC_CORE_DIM_SIZE_INFERRED
+
+ if the dim size will be determined from the operands
+ and not from a :ref:`frozen <frozen>` signature
+
+ .. c:member:: PyObject *identity_value
+
+ Identity for reduction, when :c:member:`PyUFuncObject.identity`
+ is equal to :c:data:`PyUFunc_IdentityValue`.
PyArrayIter_Type and PyArrayIterObject
--------------------------------------
npy_intp factors[NPY_MAXDIMS];
PyArrayObject *ao;
char *dataptr;
- Bool contiguous;
+ npy_bool contiguous;
} PyArrayIterObject;
- .. c:member:: int PyArrayIterObject.nd_m1
+ .. c:member:: int nd_m1
:math:`N-1` where :math:`N` is the number of dimensions in the
underlying array.
- .. c:member:: npy_intp PyArrayIterObject.index
+ .. c:member:: npy_intp index
The current 1-d index into the array.
- .. c:member:: npy_intp PyArrayIterObject.size
+ .. c:member:: npy_intp size
The total size of the underlying array.
- .. c:member:: npy_intp *PyArrayIterObject.coordinates
+ .. c:member:: npy_intp *coordinates
An :math:`N` -dimensional index into the array.
- .. c:member:: npy_intp *PyArrayIterObject.dims_m1
+ .. c:member:: npy_intp *dims_m1
The size of the array minus 1 in each dimension.
- .. c:member:: npy_intp *PyArrayIterObject.strides
+ .. c:member:: npy_intp *strides
The strides of the array. How many bytes needed to jump to the next
element in each dimension.
- .. c:member:: npy_intp *PyArrayIterObject.backstrides
+ .. c:member:: npy_intp *backstrides
How many bytes needed to jump from the end of a dimension back
to its beginning. Note that ``backstrides[k] == strides[k] *
dims_m1[k]``, but it is stored here as an optimization.
- .. c:member:: npy_intp *PyArrayIterObject.factors
+ .. c:member:: npy_intp *factors
This array is used in computing an N-d index from a 1-d index. It
contains needed products of the dimensions.
- .. c:member:: PyArrayObject *PyArrayIterObject.ao
+ .. c:member:: PyArrayObject *ao
A pointer to the underlying ndarray this iterator was created to
represent.
- .. c:member:: char *PyArrayIterObject.dataptr
+ .. c:member:: char *dataptr
This member points to an element in the ndarray indicated by the
index.
- .. c:member:: Bool PyArrayIterObject.contiguous
+ .. c:member:: npy_bool contiguous
This flag is true if the underlying array is
:c:data:`NPY_ARRAY_C_CONTIGUOUS`. It is used to simplify
PyArrayIterObject *iters[NPY_MAXDIMS];
} PyArrayMultiIterObject;
- .. c:macro: PyArrayMultiIterObject.PyObject_HEAD
+ .. c:macro: PyObject_HEAD
Needed at the start of every Python object (holds reference count
and type identification).
- .. c:member:: int PyArrayMultiIterObject.numiter
+ .. c:member:: int numiter
The number of arrays that need to be broadcast to the same shape.
- .. c:member:: npy_intp PyArrayMultiIterObject.size
+ .. c:member:: npy_intp size
The total broadcasted size.
- .. c:member:: npy_intp PyArrayMultiIterObject.index
+ .. c:member:: npy_intp index
The current (1-d) index into the broadcasted result.
- .. c:member:: int PyArrayMultiIterObject.nd
+ .. c:member:: int nd
The number of dimensions in the broadcasted result.
- .. c:member:: npy_intp *PyArrayMultiIterObject.dimensions
+ .. c:member:: npy_intp *dimensions
The shape of the broadcasted result (only ``nd`` slots are used).
- .. c:member:: PyArrayIterObject **PyArrayMultiIterObject.iters
+ .. c:member:: PyArrayIterObject **iters
An array of iterator objects that holds the iterators for the
arrays to be broadcast together. On return, the iterators are
There is a Python type for each of the different built-in data types
that can be present in the array Most of these are simple wrappers
around the corresponding data type in C. The C-names for these types
-are :c:data:`Py{TYPE}ArrType_Type` where ``{TYPE}`` can be
+are ``Py{TYPE}ArrType_Type`` where ``{TYPE}`` can be
**Bool**, **Byte**, **Short**, **Int**, **Long**, **LongLong**,
**UByte**, **UShort**, **UInt**, **ULong**, **ULongLong**,
**Object**.
These type names are part of the C-API and can therefore be created in
-extension C-code. There is also a :c:data:`PyIntpArrType_Type` and a
-:c:data:`PyUIntpArrType_Type` that are simple substitutes for one of the
+extension C-code. There is also a ``PyIntpArrType_Type`` and a
+``PyUIntpArrType_Type`` that are simple substitutes for one of the
integer types that can hold a pointer on the platform. The structure
of these scalar objects is not exposed to C-code. The function
:c:func:`PyArray_ScalarAsCtype` (..) can be used to extract the C-type
The members of this structure are
- .. c:member:: npy_intp *PyArray_Dims.ptr
+ .. c:member:: npy_intp *ptr
A pointer to a list of (:c:type:`npy_intp`) integers which
usually represent array shape or array strides.
- .. c:member:: int PyArray_Dims.len
+ .. c:member:: int len
The length of the list of integers. It is assumed safe to
access *ptr* [0] to *ptr* [len-1].
The members are
- .. c:macro: PyArray_Chunk.PyObject_HEAD
+ .. c:macro: PyObject_HEAD
Necessary for all Python objects. Included here so that the
:c:type:`PyArray_Chunk` structure matches that of the buffer object
(at least to the len member).
- .. c:member:: PyObject *PyArray_Chunk.base
+ .. c:member:: PyObject *base
The Python object this chunk of memory comes from. Needed so that
memory can be accounted for properly.
- .. c:member:: void *PyArray_Chunk.ptr
+ .. c:member:: void *ptr
A pointer to the start of the single-segment chunk of memory.
- .. c:member:: npy_intp PyArray_Chunk.len
+ .. c:member:: npy_intp len
The length of the segment in bytes.
- .. c:member:: int PyArray_Chunk.flags
+ .. c:member:: int flags
Any data flags (*e.g.* :c:data:`NPY_ARRAY_WRITEABLE` ) that should
be used to interpret the memory.
The :c:type:`PyArrayInterface` structure is defined so that NumPy and
other extension modules can use the rapid array interface
- protocol. The :obj:`__array_struct__` method of an object that
+ protocol. The :obj:`~object.__array_struct__` method of an object that
supports the rapid array interface protocol should return a
- :c:type:`PyCObject` that contains a pointer to a :c:type:`PyArrayInterface`
+ :c:type:`PyCapsule` that contains a pointer to a :c:type:`PyArrayInterface`
structure with the relevant details of the array. After the new
array is created, the attribute should be ``DECREF``'d which will
free the :c:type:`PyArrayInterface` structure. Remember to ``INCREF`` the
- object (whose :obj:`__array_struct__` attribute was retrieved) and
+ object (whose :obj:`~object.__array_struct__` attribute was retrieved) and
point the base member of the new :c:type:`PyArrayObject` to this same
object. In this way the memory for the array will be managed
correctly.
PyObject *descr;
} PyArrayInterface;
- .. c:member:: int PyArrayInterface.two
+ .. c:member:: int two
the integer 2 as a sanity check.
- .. c:member:: int PyArrayInterface.nd
+ .. c:member:: int nd
the number of dimensions in the array.
- .. c:member:: char PyArrayInterface.typekind
+ .. c:member:: char typekind
A character indicating what kind of array is present according to the
typestring convention with 't' -> bitfield, 'b' -> Boolean, 'i' ->
complex floating point, 'O' -> object, 'S' -> (byte-)string, 'U' ->
unicode, 'V' -> void.
- .. c:member:: int PyArrayInterface.itemsize
+ .. c:member:: int itemsize
The number of bytes each item in the array requires.
- .. c:member:: int PyArrayInterface.flags
+ .. c:member:: int flags
Any of the bits :c:data:`NPY_ARRAY_C_CONTIGUOUS` (1),
:c:data:`NPY_ARRAY_F_CONTIGUOUS` (2), :c:data:`NPY_ARRAY_ALIGNED` (0x100),
structure is present (it will be ignored by objects consuming
version 2 of the array interface).
- .. c:member:: npy_intp *PyArrayInterface.shape
+ .. c:member:: npy_intp *shape
An array containing the size of the array in each dimension.
- .. c:member:: npy_intp *PyArrayInterface.strides
+ .. c:member:: npy_intp *strides
An array containing the number of bytes to jump to get to the next
element in each dimension.
- .. c:member:: void *PyArrayInterface.data
+ .. c:member:: void *data
A pointer *to* the first element of the array.
- .. c:member:: PyObject *PyArrayInterface.descr
+ .. c:member:: PyObject *descr
A Python object describing the data-type in more detail (same
- as the *descr* key in :obj:`__array_interface__`). This can be
+ as the *descr* key in :obj:`~object.__array_interface__`). This can be
``NULL`` if *typekind* and *itemsize* provide enough
information. This field is also ignored unless
- :c:data:`ARR_HAS_DESCR` flag is on in *flags*.
+ :c:data:`NPY_ARR_HAS_DESCR` flag is on in *flags*.
Internally used structures
Advanced indexing is handled with this Python type. It is simply a
loose wrapper around the C-structure containing the variables
needed for advanced array indexing. The associated C-structure,
- :c:type:`PyArrayMapIterObject`, is useful if you are trying to
+ ``PyArrayMapIterObject``, is useful if you are trying to
understand the advanced-index mapping code. It is defined in the
``arrayobject.h`` header. This type is not exposed to Python and
could be replaced with a C-structure. As a Python type it takes
Constants
---------
-.. c:var:: UFUNC_ERR_{HANDLER}
+``UFUNC_ERR_{HANDLER}``
+ .. c:macro:: UFUNC_ERR_IGNORE
- ``{HANDLER}`` can be **IGNORE**, **WARN**, **RAISE**, or **CALL**
+ .. c:macro:: UFUNC_ERR_WARN
-.. c:var:: UFUNC_{THING}_{ERR}
+ .. c:macro:: UFUNC_ERR_RAISE
- ``{THING}`` can be **MASK**, **SHIFT**, or **FPE**, and ``{ERR}`` can
- be **DIVIDEBYZERO**, **OVERFLOW**, **UNDERFLOW**, and **INVALID**.
+ .. c:macro:: UFUNC_ERR_CALL
-.. c:var:: PyUFunc_{VALUE}
+``UFUNC_{THING}_{ERR}``
+ .. c:macro:: UFUNC_MASK_DIVIDEBYZERO
- .. c:var:: PyUFunc_One
+ .. c:macro:: UFUNC_MASK_OVERFLOW
- .. c:var:: PyUFunc_Zero
+ .. c:macro:: UFUNC_MASK_UNDERFLOW
- .. c:var:: PyUFunc_MinusOne
+ .. c:macro:: UFUNC_MASK_INVALID
- .. c:var:: PyUFunc_ReorderableNone
+ .. c:macro:: UFUNC_SHIFT_DIVIDEBYZERO
- .. c:var:: PyUFunc_None
+ .. c:macro:: UFUNC_SHIFT_OVERFLOW
- .. c:var:: PyUFunc_IdentityValue
+ .. c:macro:: UFUNC_SHIFT_UNDERFLOW
+
+ .. c:macro:: UFUNC_SHIFT_INVALID
+
+ .. c:macro:: UFUNC_FPE_DIVIDEBYZERO
+
+ .. c:macro:: UFUNC_FPE_OVERFLOW
+
+ .. c:macro:: UFUNC_FPE_UNDERFLOW
+
+ .. c:macro:: UFUNC_FPE_INVALID
+
+``PyUFunc_{VALUE}``
+ .. c:macro:: PyUFunc_One
+
+ .. c:macro:: PyUFunc_Zero
+
+ .. c:macro:: PyUFunc_MinusOne
+
+ .. c:macro:: PyUFunc_ReorderableNone
+
+ .. c:macro:: PyUFunc_None
+
+ .. c:macro:: PyUFunc_IdentityValue
Macros
was released (because loop->obj was not true).
+Types
+-----
+
+.. c:type:: PyUFuncGenericFunction
+
+ pointers to functions that actually implement the underlying
+ (element-by-element) function :math:`N` times with the following
+ signature:
+
+ .. c:function:: void loopfunc(\
+ char** args, npy_intp const *dimensions, npy_intp const *steps, void* data)
+
+ *args*
+
+ An array of pointers to the actual data for the input and output
+ arrays. The input arguments are given first followed by the output
+ arguments.
+
+ *dimensions*
+
+ A pointer to the size of the dimension over which this function is
+ looping.
+
+ *steps*
+
+ A pointer to the number of bytes to jump to get to the
+ next element in this dimension for each of the input and
+ output arguments.
+
+ *data*
+
+ Arbitrary data (extra arguments, function names, *etc.* )
+ that can be stored with the ufunc and will be passed in
+ when it is called.
+
+ This is an example of a func specialized for addition of doubles
+ returning doubles.
+
+ .. code-block:: c
+
+ static void
+ double_add(char **args,
+ npy_intp const *dimensions,
+ npy_intp const *steps,
+ void *extra)
+ {
+ npy_intp i;
+ npy_intp is1 = steps[0], is2 = steps[1];
+ npy_intp os = steps[2], n = dimensions[0];
+ char *i1 = args[0], *i2 = args[1], *op = args[2];
+ for (i = 0; i < n; i++) {
+ *((double *)op) = *((double *)i1) +
+ *((double *)i2);
+ i1 += is1;
+ i2 += is2;
+ op += os;
+ }
+ }
+
+
Functions
---------
:param func:
Must to an array of length *ntypes* containing
- :c:type:`PyUFuncGenericFunction` items. These items are pointers to
- functions that actually implement the underlying
- (element-by-element) function :math:`N` times with the following
- signature:
-
- .. c:function:: void loopfunc(
- char** args, npy_intp const *dimensions, npy_intp const *steps, void* data)
-
- *args*
-
- An array of pointers to the actual data for the input and output
- arrays. The input arguments are given first followed by the output
- arguments.
-
- *dimensions*
-
- A pointer to the size of the dimension over which this function is
- looping.
-
- *steps*
-
- A pointer to the number of bytes to jump to get to the
- next element in this dimension for each of the input and
- output arguments.
-
- *data*
-
- Arbitrary data (extra arguments, function names, *etc.* )
- that can be stored with the ufunc and will be passed in
- when it is called.
-
- This is an example of a func specialized for addition of doubles
- returning doubles.
-
- .. code-block:: c
-
- static void
- double_add(char **args,
- npy_intp const *dimensions,
- npy_intp const *steps,
- void *extra)
- {
- npy_intp i;
- npy_intp is1 = steps[0], is2 = steps[1];
- npy_intp os = steps[2], n = dimensions[0];
- char *i1 = args[0], *i2 = args[1], *op = args[2];
- for (i = 0; i < n; i++) {
- *((double *)op) = *((double *)i1) +
- *((double *)i2);
- i1 += is1;
- i2 += is2;
- op += os;
- }
- }
+ :c:type:`PyUFuncGenericFunction` items.
:param data:
Should be ``NULL`` or a pointer to an array of size *ntypes*
.. c:function:: int PyUFunc_checkfperr(int errmask, PyObject* errobj)
A simple interface to the IEEE error-flag checking support. The
- *errmask* argument is a mask of :c:data:`UFUNC_MASK_{ERR}` bitmasks
+ *errmask* argument is a mask of ``UFUNC_MASK_{ERR}`` bitmasks
indicating which errors to check for (and how to check for
them). The *errobj* must be a Python tuple with two elements: a
string containing the name which will be used in any communication
Importing the API
-----------------
-.. c:var:: PY_UFUNC_UNIQUE_SYMBOL
+.. c:macro:: PY_UFUNC_UNIQUE_SYMBOL
-.. c:var:: NO_IMPORT_UFUNC
+.. c:macro:: NO_IMPORT_UFUNC
.. c:function:: void import_ufunc(void)
:toctree: generated/
ccompiler
+ ccompiler_opt
cpuinfo.cpu
core.Extension
exec_command
debug option can be interesting for testing code written
in C which iterates through arrays that may or may not be
contiguous in memory.
-Most users will have no reason to change these, for details
-please see the `memory layout <memory-layout>`_ documentation.
+Most users will have no reason to change these; for details
+see the :ref:`memory layout <memory-layout>` documentation.
+
+Using the new casting implementation
+------------------------------------
+
+Within NumPy 1.20 it is possible to enable the new experimental casting
+implementation for testing purposes. To do this set::
+
+ NPY_USE_NEW_CASTINGIMPL=1
+
+Setting the flag is only useful to aid with NumPy developement to ensure the
+new version is bug free and should be avoided for production code.
+It is a helpful test for projects that either create custom datatypes or
+use for example complicated structured dtypes. The flag is expected to be
+removed in 1.21 with the new version being always in use.
+
constants
ufuncs
routines
+ typing
global_state
distutils
distutils_guide
c-api/index
internals
+ simd/simd-optimizations
swig
The :c:func:`PyArray_Broadcast` function takes the iterators that have already
been defined and uses them to determine the broadcast shape in each
dimension (to create the iterators at the same time that broadcasting
-occurs then use the :c:func:`PyMultiIter_New` function). Then, the iterators are
+occurs then use the :c:func:`PyArray_MultiIterNew` function).
+Then, the iterators are
adjusted so that each iterator thinks it is iterating over an array
with the broadcast size. This is done by adjusting the iterators
number of dimensions, and the shape in each dimension. This works
NumPy. The big difference is that now the array of strides is kept
track of in a :c:type:`PyArrayIterObject`, the iterators involved in a
broadcast result are kept track of in a :c:type:`PyArrayMultiIterObject`,
-and the :c:func:`PyArray_BroadCast` call implements the broad-casting rules.
+and the :c:func:`PyArray_Broadcast` call implements the broad-casting rules.
Array Scalars
return arrays are constructed. If any provided output array doesn't
have the correct type (or is mis-aligned) and is smaller than the
buffer size, then a new output array is constructed with the special
-:c:data:`WRITEBACKIFCOPY` flag set. At the end of the function,
+:c:data:`NPY_ARRAY_WRITEBACKIFCOPY` flag set. At the end of the function,
:c:func:`PyArray_ResolveWritebackIfCopy` is called so that
its contents will be copied back into the output array.
Iterators for the output arguments are then processed.
internals.code-explanations
alignment
-.. automodule:: numpy.doc.internals
+Internal organization of numpy arrays
+=====================================
+
+It helps to understand a bit about how numpy arrays are handled under the covers to help understand numpy better. This section will not go into great detail. Those wishing to understand the full details are referred to Travis Oliphant's book "Guide to NumPy".
+
+NumPy arrays consist of two major components, the raw array data (from now on,
+referred to as the data buffer), and the information about the raw array data.
+The data buffer is typically what people think of as arrays in C or Fortran,
+a contiguous (and fixed) block of memory containing fixed sized data items.
+NumPy also contains a significant set of data that describes how to interpret
+the data in the data buffer. This extra information contains (among other things):
+
+ 1) The basic data element's size in bytes
+ 2) The start of the data within the data buffer (an offset relative to the
+ beginning of the data buffer).
+ 3) The number of dimensions and the size of each dimension
+ 4) The separation between elements for each dimension (the 'stride'). This
+ does not have to be a multiple of the element size
+ 5) The byte order of the data (which may not be the native byte order)
+ 6) Whether the buffer is read-only
+ 7) Information (via the dtype object) about the interpretation of the basic
+ data element. The basic data element may be as simple as a int or a float,
+ or it may be a compound object (e.g., struct-like), a fixed character field,
+ or Python object pointers.
+ 8) Whether the array is to interpreted as C-order or Fortran-order.
+
+This arrangement allow for very flexible use of arrays. One thing that it allows
+is simple changes of the metadata to change the interpretation of the array buffer.
+Changing the byteorder of the array is a simple change involving no rearrangement
+of the data. The shape of the array can be changed very easily without changing
+anything in the data buffer or any data copying at all
+
+Among other things that are made possible is one can create a new array metadata
+object that uses the same data buffer
+to create a new view of that data buffer that has a different interpretation
+of the buffer (e.g., different shape, offset, byte order, strides, etc) but
+shares the same data bytes. Many operations in numpy do just this such as
+slices. Other operations, such as transpose, don't move data elements
+around in the array, but rather change the information about the shape and strides so that the indexing of the array changes, but the data in the doesn't move.
+
+Typically these new versions of the array metadata but the same data buffer are
+new 'views' into the data buffer. There is a different ndarray object, but it
+uses the same data buffer. This is why it is necessary to force copies through
+use of the .copy() method if one really wants to make a new and independent
+copy of the data buffer.
+
+New views into arrays mean the object reference counts for the data buffer
+increase. Simply doing away with the original array object will not remove the
+data buffer if other views of it still exist.
+
+Multidimensional Array Indexing Order Issues
+============================================
+
+What is the right way to index
+multi-dimensional arrays? Before you jump to conclusions about the one and
+true way to index multi-dimensional arrays, it pays to understand why this is
+a confusing issue. This section will try to explain in detail how numpy
+indexing works and why we adopt the convention we do for images, and when it
+may be appropriate to adopt other conventions.
+
+The first thing to understand is
+that there are two conflicting conventions for indexing 2-dimensional arrays.
+Matrix notation uses the first index to indicate which row is being selected and
+the second index to indicate which column is selected. This is opposite the
+geometrically oriented-convention for images where people generally think the
+first index represents x position (i.e., column) and the second represents y
+position (i.e., row). This alone is the source of much confusion;
+matrix-oriented users and image-oriented users expect two different things with
+regard to indexing.
+
+The second issue to understand is how indices correspond
+to the order the array is stored in memory. In Fortran the first index is the
+most rapidly varying index when moving through the elements of a two
+dimensional array as it is stored in memory. If you adopt the matrix
+convention for indexing, then this means the matrix is stored one column at a
+time (since the first index moves to the next row as it changes). Thus Fortran
+is considered a Column-major language. C has just the opposite convention. In
+C, the last index changes most rapidly as one moves through the array as
+stored in memory. Thus C is a Row-major language. The matrix is stored by
+rows. Note that in both cases it presumes that the matrix convention for
+indexing is being used, i.e., for both Fortran and C, the first index is the
+row. Note this convention implies that the indexing convention is invariant
+and that the data order changes to keep that so.
+
+But that's not the only way
+to look at it. Suppose one has large two-dimensional arrays (images or
+matrices) stored in data files. Suppose the data are stored by rows rather than
+by columns. If we are to preserve our index convention (whether matrix or
+image) that means that depending on the language we use, we may be forced to
+reorder the data if it is read into memory to preserve our indexing
+convention. For example if we read row-ordered data into memory without
+reordering, it will match the matrix indexing convention for C, but not for
+Fortran. Conversely, it will match the image indexing convention for Fortran,
+but not for C. For C, if one is using data stored in row order, and one wants
+to preserve the image index convention, the data must be reordered when
+reading into memory.
+
+In the end, which you do for Fortran or C depends on
+which is more important, not reordering data or preserving the indexing
+convention. For large images, reordering data is potentially expensive, and
+often the indexing convention is inverted to avoid that.
+
+The situation with
+numpy makes this issue yet more complicated. The internal machinery of numpy
+arrays is flexible enough to accept any ordering of indices. One can simply
+reorder indices by manipulating the internal stride information for arrays
+without reordering the data at all. NumPy will know how to map the new index
+order to the data without moving the data.
+
+So if this is true, why not choose
+the index order that matches what you most expect? In particular, why not define
+row-ordered images to use the image convention? (This is sometimes referred
+to as the Fortran convention vs the C convention, thus the 'C' and 'FORTRAN'
+order options for array ordering in numpy.) The drawback of doing this is
+potential performance penalties. It's common to access the data sequentially,
+either implicitly in array operations or explicitly by looping over rows of an
+image. When that is done, then the data will be accessed in non-optimal order.
+As the first index is incremented, what is actually happening is that elements
+spaced far apart in memory are being sequentially accessed, with usually poor
+memory access speeds. For example, for a two dimensional image 'im' defined so
+that im[0, 10] represents the value at x=0, y=10. To be consistent with usual
+Python behavior then im[0] would represent a column at x=0. Yet that data
+would be spread over the whole array since the data are stored in row order.
+Despite the flexibility of numpy's indexing, it can't really paper over the fact
+basic operations are rendered inefficient because of data order or that getting
+contiguous subarrays is still awkward (e.g., im[:,0] for the first row, vs
+im[0]), thus one can't use an idiom such as for row in im; for col in im does
+work, but doesn't yield contiguous column data.
+
+As it turns out, numpy is
+smart enough when dealing with ufuncs to determine which index is the most
+rapidly varying one in memory and uses that for the innermost loop. Thus for
+ufuncs there is no large intrinsic advantage to either approach in most cases.
+On the other hand, use of .flat with an FORTRAN ordered array will lead to
+non-optimal memory access as adjacent elements in the flattened array (iterator,
+actually) are not contiguous in memory.
+
+Indeed, the fact is that Python
+indexing on lists and other sequences naturally leads to an outside-to inside
+ordering (the first index gets the largest grouping, the next the next largest,
+and the last gets the smallest element). Since image data are normally stored
+by rows, this corresponds to position within rows being the last item indexed.
+
+If you do want to use Fortran ordering realize that
+there are two approaches to consider: 1) accept that the first index is just not
+the most rapidly changing in memory and have all your I/O routines reorder
+your data when going from memory to disk or visa versa, or use numpy's
+mechanism for mapping the first index to the most rapidly varying data. We
+recommend the former if possible. The disadvantage of the latter is that many
+of numpy's functions will yield arrays without Fortran ordering unless you are
+careful to use the 'order' keyword. Doing this would be highly inconvenient.
+
+Otherwise we recommend simply learning to reverse the usual order of indices
+when accessing elements of an array. Granted, it goes against the grain, but
+it is more in line with Python semantics and the natural order of the data.
+
+
MaskedArray.__eq__
MaskedArray.__ne__
-Truth value of an array (:func:`bool()`):
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Truth value of an array (:class:`bool() <bool>`):
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autosummary::
:toctree: generated/
*invalid* data.
Another possibility is to use the :func:`getmask` and :func:`getmaskarray`
-functions. :func:`getmask(x)` outputs the mask of ``x`` if ``x`` is a masked
-array, and the special value :data:`nomask` otherwise. :func:`getmaskarray(x)`
+functions. ``getmask(x)`` outputs the mask of ``x`` if ``x`` is a masked
+array, and the special value :data:`nomask` otherwise. ``getmaskarray(x)``
outputs the mask of ``x`` if ``x`` is a masked array. If ``x`` has no invalid
entry or is not a masked array, the function outputs a boolean array of
``False`` with as many elements as ``x``.
.. note::
Unmasking an entry by direct assignment will silently fail if the masked
- array has a *hard* mask, as shown by the :attr:`hardmask` attribute. This
- feature was introduced to prevent overwriting the mask. To force the
- unmasking of an entry where the array has a hard mask, the mask must first
- to be softened using the :meth:`soften_mask` method before the allocation.
- It can be re-hardened with :meth:`harden_mask`::
+ array has a *hard* mask, as shown by the :attr:`~MaskedArray.hardmask`
+ attribute. This feature was introduced to prevent overwriting the mask.
+ To force the unmasking of an entry where the array has a hard mask,
+ the mask must first to be softened using the :meth:`soften_mask` method
+ before the allocation. It can be re-hardened with :meth:`harden_mask`::
>>> x = ma.array([1, 2, 3], mask=[0, 0, 1], hard_mask=True)
>>> x
Arithmetic and comparison operations are supported by masked arrays.
As much as possible, invalid entries of a masked array are not processed,
-meaning that the corresponding :attr:`data` entries *should* be the same
-before and after the operation.
+meaning that the corresponding :attr:`~MaskedArray.data` entries
+*should* be the same before and after the operation.
.. warning::
We need to stress that this behavior may not be systematic, that masked
-Cython API for random
----------------------
+C API for random
+----------------
.. currentmodule:: numpy.random
-Typed versions of many of the `Generator` and `BitGenerator` methods as well as
-the classes themselves can be accessed directly from Cython via
-
-.. code-block:: cython
-
- cimport numpy.random
+Access to various distributions below is available via Cython or C-wrapper
+libraries like CFFI. All the functions accept a :c:type:`bitgen_t` as their
+first argument. To access these from Cython or C, you must link with the
+``npyrandom`` library which is part of the NumPy distribution, located in
+``numpy/random/lib``.
-C API for random
-----------------
-
-Access to various distributions is available via Cython or C-wrapper libraries
-like CFFI. All the functions accept a :c:type:`bitgen_t` as their first argument.
.. c:type:: bitgen_t
Generate random uint64 numbers in closed interval [off, off + rng].
-.. c:function:: npy_uint64 random_bounded_uint64(bitgen_t *bitgen_state, npy_uint64 off, npy_uint64 rng, npy_uint64 mask, bint use_masked)
-
+.. c:function:: npy_uint64 random_bounded_uint64(bitgen_t *bitgen_state, npy_uint64 off, npy_uint64 rng, npy_uint64 mask, bool use_masked)
Permutations
============
+The methods for randomly permuting a sequence are
+
.. autosummary::
:toctree: generated/
~numpy.random.Generator.shuffle
~numpy.random.Generator.permutation
+ ~numpy.random.Generator.permuted
+
+The following table summarizes the behaviors of the methods.
+
++--------------+-------------------+------------------+
+| method | copy/in-place | axis handling |
++==============+===================+==================+
+| shuffle | in-place | as if 1d |
++--------------+-------------------+------------------+
+| permutation | copy | as if 1d |
++--------------+-------------------+------------------+
+| permuted | either (use 'out' | axis independent |
+| | for in-place) | |
++--------------+-------------------+------------------+
+
+The following subsections provide more details about the differences.
+
+In-place vs. copy
+~~~~~~~~~~~~~~~~~
+The main difference between `Generator.shuffle` and `Generator.permutation`
+is that `Generator.shuffle` operates in-place, while `Generator.permutation`
+returns a copy.
+
+By default, `Generator.permuted` returns a copy. To operate in-place with
+`Generator.permuted`, pass the same array as the first argument *and* as
+the value of the ``out`` parameter. For example,
+
+ >>> rg = np.random.default_rng()
+ >>> x = np.arange(0, 15).reshape(3, 5)
+ >>> x
+ array([[ 0, 1, 2, 3, 4],
+ [ 5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14]])
+ >>> y = rg.permuted(x, axis=1, out=x)
+ >>> x
+ array([[ 1, 0, 2, 4, 3], # random
+ [ 6, 7, 8, 9, 5],
+ [10, 14, 11, 13, 12]])
+
+Note that when ``out`` is given, the return value is ``out``:
+
+ >>> y is x
+ True
+
+Handling the ``axis`` parameter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+An important distinction for these methods is how they handle the ``axis``
+parameter. Both `Generator.shuffle` and `Generator.permutation` treat the
+input as a one-dimensional sequence, and the ``axis`` parameter determines
+which dimension of the input array to use as the sequence. In the case of a
+two-dimensional array, ``axis=0`` will, in effect, rearrange the rows of the
+array, and ``axis=1`` will rearrange the columns. For example
+
+ >>> rg = np.random.default_rng()
+ >>> x = np.arange(0, 15).reshape(3, 5)
+ >>> x
+ array([[ 0, 1, 2, 3, 4],
+ [ 5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14]])
+ >>> rg.permutation(x, axis=1)
+ array([[ 1, 3, 2, 0, 4], # random
+ [ 6, 8, 7, 5, 9],
+ [11, 13, 12, 10, 14]])
+
+Note that the columns have been rearranged "in bulk": the values within
+each column have not changed.
+
+The method `Generator.permuted` treats the ``axis`` parameter similar to
+how `numpy.sort` treats it. Each slice along the given axis is shuffled
+independently of the others. Compare the following example of the use of
+`Generator.permuted` to the above example of `Generator.permutation`:
+
+ >>> rg.permuted(x, axis=1)
+ array([[ 1, 0, 2, 4, 3], # random
+ [ 5, 7, 6, 9, 8],
+ [10, 14, 12, 13, 11]])
+
+In this example, the values within each row (i.e. the values along
+``axis=1``) have been shuffled independently. This is not a "bulk"
+shuffle of the columns.
+
+Shuffling non-NumPy sequences
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+`Generator.shuffle` works on non-NumPy sequences. That is, if it is given
+a sequence that is not a NumPy array, it shuffles that sequence in-place.
+For example,
+
+ >>> rg = np.random.default_rng()
+ >>> a = ['A', 'B', 'C', 'D', 'E']
+ >>> rg.shuffle(a) # shuffle the list in-place
+ >>> a
+ ['B', 'D', 'A', 'E', 'C'] # random
Distributions
=============
distributions. See `NEP 19 <https://www.numpy.org/neps/
nep-0019-rng-policy.html>`_ for context on the updated random Numpy number
routines. The legacy `RandomState` random number routines are still
-available, but limited to a single BitGenerator.
+available, but limited to a single BitGenerator. See :ref:`new-or-different`
+for a complete list of improvements and differences from the legacy
+``Randomstate``.
For convenience and backward compatibility, a single `RandomState`
instance's methods are imported into the numpy.random namespace, see
.. code-block:: python
- # Do this
+ # Do this (new version)
from numpy.random import default_rng
rng = default_rng()
vals = rng.standard_normal(10)
more_vals = rng.standard_normal(10)
- # instead of this
+ # instead of this (legacy version)
from numpy import random
vals = random.standard_normal(10)
more_vals = random.standard_normal(10)
``seed`` removed Use `SeedSequence.spawn`
=================== ============== ============
-See :ref:`new-or-different` for more information
+See :ref:`new-or-different` for more information.
Something like the following code can be used to support both ``RandomState``
and ``Generator``, with the understanding that the interfaces are slightly
from numpy.random import Generator, PCG64
rg = Generator(PCG64(12345))
rg.standard_normal()
+
+Here we use `default_rng` to create an instance of `Generator` to generate a
+random float:
+
+>>> import numpy as np
+>>> rng = np.random.default_rng(12345)
+>>> print(rng)
+Generator(PCG64)
+>>> rfloat = rng.random()
+>>> rfloat
+0.22733602246716966
+>>> type(rfloat)
+<class 'float'>
+
+Here we use `default_rng` to create an instance of `Generator` to generate 3
+random integers between 0 (inclusive) and 10 (exclusive):
+
+>>> import numpy as np
+>>> rng = np.random.default_rng(12345)
+>>> rints = rng.integers(low=0, high=10, size=3)
+>>> rints
+array([6, 2, 7])
+>>> type(rints[0])
+<class 'numpy.int64'>
Introduction
------------
distributions, e.g., simulated normal random values. This structure allows
alternative bit generators to be used with little code duplication.
-The `Generator` is the user-facing object that is nearly identical to
-`RandomState`. The canonical method to initialize a generator passes a
-`PCG64` bit generator as the sole argument.
+The `Generator` is the user-facing object that is nearly identical to the
+legacy `RandomState`. It accepts a bit generator instance as an argument.
+The default is currently `PCG64` but this may change in future versions.
+As a convenience NumPy provides the `default_rng` function to hide these
+details:
+
+>>> from numpy.random import default_rng
+>>> rg = default_rng(12345)
+>>> print(rg)
+Generator(PCG64)
+>>> print(rg.random())
+0.22733602246716966
+
+One can also instantiate `Generator` directly with a `BitGenerator` instance.
-.. code-block:: python
+To use the default `PCG64` bit generator, one can instantiate it directly and
+pass it to `Generator`:
- from numpy.random import default_rng
- rg = default_rng(12345)
- rg.random()
+>>> from numpy.random import Generator, PCG64
+>>> rg = Generator(PCG64(12345))
+>>> print(rg)
+Generator(PCG64)
-One can also instantiate `Generator` directly with a `BitGenerator` instance.
-To use the older `MT19937` algorithm, one can instantiate it directly
-and pass it to `Generator`.
+Similarly to use the older `MT19937` bit generator (not recommended), one can
+instantiate it directly and pass it to `Generator`:
-.. code-block:: python
-
- from numpy.random import Generator, MT19937
- rg = Generator(MT19937(12345))
- rg.random()
+>>> from numpy.random import Generator, MT19937
+>>> rg = Generator(MT19937(12345))
+>>> print(rg)
+Generator(MT19937)
What's New or Different
~~~~~~~~~~~~~~~~~~~~~~~
This package was developed independently of NumPy and was integrated in version
1.17.0. The original repo is at https://github.com/bashtage/randomgen.
-
streams, use `RandomState`, i.e., `RandomState.gamma` or
`RandomState.standard_t`.
-Quick comparison of legacy `mtrand <legacy>`_ to the new `Generator`
+Quick comparison of legacy :ref:`mtrand <legacy>` to the new `Generator`
================== ==================== =============
Feature Older Equivalent Notes
methods which are 2-10 times faster than NumPy's default implementation in
`~.Generator.standard_normal`, `~.Generator.standard_exponential` or
`~.Generator.standard_gamma`.
-
+
.. ipython:: python
hstack
dstack
column_stack
+ row_stack
Splitting arrays
================
.. module:: numpy.char
The `numpy.char` module provides a set of vectorized string
-operations for arrays of type `numpy.string_` or `numpy.unicode_`.
+operations for arrays of type `numpy.str_` or `numpy.bytes_`.
All of them are based on the string methods in the Python standard library.
String operations
.. autofunction:: as_array
.. autofunction:: as_ctypes
.. autofunction:: as_ctypes_type
-.. autofunction:: ctypes_load_library
.. autofunction:: load_library
.. autofunction:: ndpointer
-Optionally Scipy-accelerated routines (:mod:`numpy.dual`)
+Optionally SciPy-accelerated routines (:mod:`numpy.dual`)
*********************************************************
.. automodule:: numpy.dual
+++ /dev/null
-Financial functions
-*******************
-
-.. currentmodule:: numpy
-
-Simple financial functions
---------------------------
-
-.. autosummary::
- :toctree: generated/
-
- fv
- pv
- npv
- pmt
- ppmt
- ipmt
- irr
- mirr
- nper
- rate
diag
diagonal
select
+ lib.stride_tricks.sliding_window_view
lib.stride_tricks.as_strided
Inserting data into arrays
:toctree: generated/
memmap
+ lib.format.open_memmap
Text formatting options
-----------------------
Binary Format Description
-------------------------
.. autosummary::
- :template: autosummary/minimal_module.rst
:toctree: generated/
- lib.format
+ lib.format
ma.size
ma.is_masked
ma.is_mask
+ ma.isMaskedArray
+ ma.isMA
+ ma.isarray
ma.MaskedArray.all
ma.common_fill_value
ma.default_fill_value
ma.maximum_fill_value
- ma.maximum_fill_value
+ ma.minimum_fill_value
ma.set_fill_value
ma.MaskedArray.get_fill_value
show_config
deprecate
deprecate_with_doc
+ broadcast_shapes
Matlab-like Functions
---------------------
>>> p.window
array([-1., 1.])
-Printing a polynomial yields a shorter form without the domain
-and window::
+Printing a polynomial yields the polynomial expression in a more familiar
+format::
>>> print(p)
- poly([1. 2. 3.])
+ 1.0 + 2.0·x¹ + 3.0·x²
+
+Note that the string representation of polynomials uses Unicode characters
+by default (except on Windows) to express powers and subscripts. An ASCII-based
+representation is also available (default on Windows). The polynomial string
+format can be toggled at the package-level with the
+`~numpy.polynomial.set_default_printstyle` function::
+
+ >>> numpy.polynomial.set_default_printstyle('ascii')
+ >>> print(p)
+ 1.0 + 2.0 x**1 + 3.0 x**2
+
+or controlled for individual polynomial instances with string formatting::
+
+ >>> print(f"{p:unicode}")
+ 1.0 + 2.0·x¹ + 3.0·x²
We will deal with the domain and window when we get to fitting, for the moment
we ignore them and run through the basic algebraic and arithmetic operations.
:no-members:
:no-inherited-members:
:no-special-members:
+
+Configuration
+-------------
+
+.. autosummary::
+ :toctree: generated/
+
+ numpy.polynomial.set_default_printstyle
routines.emath
routines.err
routines.fft
- routines.financial
routines.functional
routines.help
routines.indexing
.. currentmodule:: numpy
+.. autosummary::
+ :toctree: generated/
+
+ lib.arraysetops
+
Making proper sets
------------------
.. autosummary::
--- /dev/null
+.. generated via source/reference/simd/simd-optimizations.py
+
+x86::Intel Compiler - CPU feature names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ =========== ==================================================================================================================
+ Name Implies
+ =========== ==================================================================================================================
+ ``FMA3`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` **AVX2**
+ ``AVX2`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` **FMA3**
+ ``AVX512F`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` **AVX512CD**
+ =========== ==================================================================================================================
+
+.. note::
+ The following features aren't supported by x86::Intel Compiler:
+ **XOP FMA4**
+
+x86::Microsoft Visual C/C++ - CPU feature names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ ============ =================================================================================================================================
+ Name Implies
+ ============ =================================================================================================================================
+ ``FMA3`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` **AVX2**
+ ``AVX2`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` **FMA3**
+ ``AVX512F`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` **AVX512CD** **AVX512_SKX**
+ ``AVX512CD`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F`` **AVX512_SKX**
+ ============ =================================================================================================================================
+
+.. note::
+ The following features aren't supported by x86::Microsoft Visual C/C++:
+ **AVX512_KNL AVX512_KNM**
+
--- /dev/null
+.. generated via source/reference/simd/simd-optimizations.py
+
+x86 - CPU feature names
+~~~~~~~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ ============ =================================================================================================================
+ Name Implies
+ ============ =================================================================================================================
+ ``SSE`` ``SSE2``
+ ``SSE2`` ``SSE``
+ ``SSE3`` ``SSE`` ``SSE2``
+ ``SSSE3`` ``SSE`` ``SSE2`` ``SSE3``
+ ``SSE41`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3``
+ ``POPCNT`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41``
+ ``SSE42`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT``
+ ``AVX`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42``
+ ``XOP`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX``
+ ``FMA4`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX``
+ ``F16C`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX``
+ ``FMA3`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C``
+ ``AVX2`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C``
+ ``AVX512F`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2``
+ ``AVX512CD`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F``
+ ============ =================================================================================================================
+
+x86 - Group names
+~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ ============== ===================================================== ===========================================================================================================================================================================
+ Name Gather Implies
+ ============== ===================================================== ===========================================================================================================================================================================
+ ``AVX512_KNL`` ``AVX512ER`` ``AVX512PF`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F`` ``AVX512CD``
+ ``AVX512_KNM`` ``AVX5124FMAPS`` ``AVX5124VNNIW`` ``AVX512VPOPCNTDQ`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F`` ``AVX512CD`` ``AVX512_KNL``
+ ``AVX512_SKX`` ``AVX512VL`` ``AVX512BW`` ``AVX512DQ`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F`` ``AVX512CD``
+ ``AVX512_CLX`` ``AVX512VNNI`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F`` ``AVX512CD`` ``AVX512_SKX``
+ ``AVX512_CNL`` ``AVX512IFMA`` ``AVX512VBMI`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F`` ``AVX512CD`` ``AVX512_SKX``
+ ``AVX512_ICL`` ``AVX512VBMI2`` ``AVX512BITALG`` ``AVX512VPOPCNTDQ`` ``SSE`` ``SSE2`` ``SSE3`` ``SSSE3`` ``SSE41`` ``POPCNT`` ``SSE42`` ``AVX`` ``F16C`` ``FMA3`` ``AVX2`` ``AVX512F`` ``AVX512CD`` ``AVX512_SKX`` ``AVX512_CLX`` ``AVX512_CNL``
+ ============== ===================================================== ===========================================================================================================================================================================
+
+IBM/POWER big-endian - CPU feature names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ ======== ================
+ Name Implies
+ ======== ================
+ ``VSX``
+ ``VSX2`` ``VSX``
+ ``VSX3`` ``VSX`` ``VSX2``
+ ======== ================
+
+IBM/POWER little-endian - CPU feature names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ ======== ================
+ Name Implies
+ ======== ================
+ ``VSX`` ``VSX2``
+ ``VSX2`` ``VSX``
+ ``VSX3`` ``VSX`` ``VSX2``
+ ======== ================
+
+ARMv7/A32 - CPU feature names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ ============== ===========================================================
+ Name Implies
+ ============== ===========================================================
+ ``NEON``
+ ``NEON_FP16`` ``NEON``
+ ``NEON_VFPV4`` ``NEON`` ``NEON_FP16``
+ ``ASIMD`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4``
+ ``ASIMDHP`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4`` ``ASIMD``
+ ``ASIMDDP`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4`` ``ASIMD``
+ ``ASIMDFHM`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4`` ``ASIMD`` ``ASIMDHP``
+ ============== ===========================================================
+
+ARMv8/A64 - CPU feature names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. table::
+ :align: left
+
+ ============== ===========================================================
+ Name Implies
+ ============== ===========================================================
+ ``NEON`` ``NEON_FP16`` ``NEON_VFPV4`` ``ASIMD``
+ ``NEON_FP16`` ``NEON`` ``NEON_VFPV4`` ``ASIMD``
+ ``NEON_VFPV4`` ``NEON`` ``NEON_FP16`` ``ASIMD``
+ ``ASIMD`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4``
+ ``ASIMDHP`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4`` ``ASIMD``
+ ``ASIMDDP`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4`` ``ASIMD``
+ ``ASIMDFHM`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4`` ``ASIMD`` ``ASIMDHP``
+ ============== ===========================================================
+
--- /dev/null
+"""
+Generate CPU features tables from CCompilerOpt
+"""
+from os import sys, path
+gen_path = path.dirname(path.realpath(__file__))
+#sys.path.append(path.abspath(path.join(gen_path, *([".."]*4), "numpy", "distutils")))
+#from ccompiler_opt import CCompilerOpt
+from numpy.distutils.ccompiler_opt import CCompilerOpt
+
+class FakeCCompilerOpt(CCompilerOpt):
+ fake_info = ("arch", "compiler", "extra_args")
+ # disable caching no need for it
+ conf_nocache = True
+ def __init__(self, *args, **kwargs):
+ no_cc = None
+ CCompilerOpt.__init__(self, no_cc, **kwargs)
+ def dist_compile(self, sources, flags, **kwargs):
+ return sources
+ def dist_info(self):
+ return FakeCCompilerOpt.fake_info
+ @staticmethod
+ def dist_log(*args, stderr=False):
+ # avoid printing
+ pass
+ def feature_test(self, name, force_flags=None):
+ # To speed up
+ return True
+
+ def gen_features_table(self, features, ignore_groups=True,
+ field_names=["Name", "Implies"],
+ fstyle=None, fstyle_implies=None, **kwargs):
+ rows = []
+ if fstyle is None:
+ fstyle = lambda ft: f'``{ft}``'
+ if fstyle_implies is None:
+ fstyle_implies = lambda origin, ft: fstyle(ft)
+ for f in self.feature_sorted(features):
+ is_group = "group" in self.feature_supported.get(f, {})
+ if ignore_groups and is_group:
+ continue
+ implies = self.feature_sorted(self.feature_implies(f))
+ implies = ' '.join([fstyle_implies(f, i) for i in implies])
+ rows.append([fstyle(f), implies])
+ if rows:
+ return self.gen_rst_table(field_names, rows, **kwargs)
+
+ def gen_gfeatures_table(self, features,
+ field_names=["Name", "Gather", "Implies"],
+ fstyle=None, fstyle_implies=None, **kwargs):
+ rows = []
+ if fstyle is None:
+ fstyle = lambda ft: f'``{ft}``'
+ if fstyle_implies is None:
+ fstyle_implies = lambda origin, ft: fstyle(ft)
+ for f in self.feature_sorted(features):
+ gather = self.feature_supported.get(f, {}).get("group", None)
+ if not gather:
+ continue
+ implies = self.feature_sorted(self.feature_implies(f))
+ implies = ' '.join([fstyle_implies(f, i) for i in implies])
+ gather = ' '.join([fstyle_implies(f, i) for i in gather])
+ rows.append([fstyle(f), gather, implies])
+ if rows:
+ return self.gen_rst_table(field_names, rows, **kwargs)
+
+ def gen_rst_table(self, field_names, rows, tab_size=4):
+ assert(not rows or len(field_names) == len(rows[0]))
+ rows.append(field_names)
+ fld_len = len(field_names)
+ cls_len = [max(len(c[i]) for c in rows) for i in range(fld_len)]
+ del rows[-1]
+ cformat = ' '.join('{:<%d}' % i for i in cls_len)
+ border = cformat.format(*['='*i for i in cls_len])
+
+ rows = [cformat.format(*row) for row in rows]
+ # header
+ rows = [border, cformat.format(*field_names), border] + rows
+ # footer
+ rows += [border]
+ # add left margin
+ rows = [(' ' * tab_size) + r for r in rows]
+ return '\n'.join(rows)
+
+def features_table_sections(name, ftable=None, gtable=None, tab_size=4):
+ tab = ' '*tab_size
+ content = ''
+ if ftable:
+ title = f"{name} - CPU feature names"
+ content = (
+ f"{title}\n{'~'*len(title)}"
+ f"\n.. table::\n{tab}:align: left\n\n"
+ f"{ftable}\n\n"
+ )
+ if gtable:
+ title = f"{name} - Group names"
+ content += (
+ f"{title}\n{'~'*len(title)}"
+ f"\n.. table::\n{tab}:align: left\n\n"
+ f"{gtable}\n\n"
+ )
+ return content
+
+def features_table(arch, cc="gcc", pretty_name=None, **kwargs):
+ FakeCCompilerOpt.fake_info = (arch, cc, '')
+ ccopt = FakeCCompilerOpt(cpu_baseline="max")
+ features = ccopt.cpu_baseline_names()
+ ftable = ccopt.gen_features_table(features, **kwargs)
+ gtable = ccopt.gen_gfeatures_table(features, **kwargs)
+
+ if not pretty_name:
+ pretty_name = arch + '/' + cc
+ return features_table_sections(pretty_name, ftable, gtable, **kwargs)
+
+def features_table_diff(arch, cc, cc_vs="gcc", pretty_name=None, **kwargs):
+ FakeCCompilerOpt.fake_info = (arch, cc, '')
+ ccopt = FakeCCompilerOpt(cpu_baseline="max")
+ fnames = ccopt.cpu_baseline_names()
+ features = {f:ccopt.feature_implies(f) for f in fnames}
+
+ FakeCCompilerOpt.fake_info = (arch, cc_vs, '')
+ ccopt_vs = FakeCCompilerOpt(cpu_baseline="max")
+ fnames_vs = ccopt_vs.cpu_baseline_names()
+ features_vs = {f:ccopt_vs.feature_implies(f) for f in fnames_vs}
+
+ common = set(fnames).intersection(fnames_vs)
+ extra_avl = set(fnames).difference(fnames_vs)
+ not_avl = set(fnames_vs).difference(fnames)
+ diff_impl_f = {f:features[f].difference(features_vs[f]) for f in common}
+ diff_impl = {k for k, v in diff_impl_f.items() if v}
+
+ fbold = lambda ft: f'**{ft}**' if ft in extra_avl else f'``{ft}``'
+ fbold_implies = lambda origin, ft: (
+ f'**{ft}**' if ft in diff_impl_f.get(origin, {}) else f'``{ft}``'
+ )
+ diff_all = diff_impl.union(extra_avl)
+ ftable = ccopt.gen_features_table(
+ diff_all, fstyle=fbold, fstyle_implies=fbold_implies, **kwargs
+ )
+ gtable = ccopt.gen_gfeatures_table(
+ diff_all, fstyle=fbold, fstyle_implies=fbold_implies, **kwargs
+ )
+ if not pretty_name:
+ pretty_name = arch + '/' + cc
+ content = features_table_sections(pretty_name, ftable, gtable, **kwargs)
+
+ if not_avl:
+ not_avl = ccopt_vs.feature_sorted(not_avl)
+ not_avl = ' '.join(not_avl)
+ content += (
+ ".. note::\n"
+ f" The following features aren't supported by {pretty_name}:\n"
+ f" **{not_avl}**\n\n"
+ )
+ return content
+
+if __name__ == '__main__':
+ pretty_names = {
+ "PPC64": "IBM/POWER big-endian",
+ "PPC64LE": "IBM/POWER little-endian",
+ "ARMHF": "ARMv7/A32",
+ "AARCH64": "ARMv8/A64",
+ "ICC": "Intel Compiler",
+ # "ICCW": "Intel Compiler msvc-like",
+ "MSVC": "Microsoft Visual C/C++"
+ }
+ with open(path.join(gen_path, 'simd-optimizations-tables.inc'), 'wt') as fd:
+ fd.write(f'.. generated via {__file__}\n\n')
+ for arch in (
+ ("x86", "PPC64", "PPC64LE", "ARMHF", "AARCH64")
+ ):
+ pretty_name = pretty_names.get(arch, arch)
+ table = features_table(arch=arch, pretty_name=pretty_name)
+ assert(table)
+ fd.write(table)
+
+ with open(path.join(gen_path, 'simd-optimizations-tables-diff.inc'), 'wt') as fd:
+ fd.write(f'.. generated via {__file__}\n\n')
+ for arch, cc_names in (
+ ("x86", ("clang", "ICC", "MSVC")),
+ ("PPC64", ("clang",)),
+ ("PPC64LE", ("clang",)),
+ ("ARMHF", ("clang",)),
+ ("AARCH64", ("clang",))
+ ):
+ arch_pname = pretty_names.get(arch, arch)
+ for cc in cc_names:
+ pretty_name = f"{arch_pname}::{pretty_names.get(cc, cc)}"
+ table = features_table_diff(arch=arch, cc=cc, pretty_name=pretty_name)
+ if table:
+ fd.write(table)
--- /dev/null
+******************
+SIMD Optimizations
+******************
+
+NumPy provides a set of macros that define `Universal Intrinsics`_ to
+abstract out typical platform-specific intrinsics so SIMD code needs to be
+written only once. There are three layers:
+
+- Code is *written* using the universal intrinsic macros, with guards that
+ will enable use of the macros only when the compiler recognizes them.
+ In NumPy, these are used to construct multiple ufunc loops. Current policy is
+ to create three loops: One loop is the default and uses no intrinsics. One
+ uses the minimum intrinsics required on the architecture. And the third is
+ written using the maximum set of intrinsics possible.
+- At *compile* time, a distutils command is used to define the minimum and
+ maximum features to support, based on user choice and compiler support. The
+ appropriate macros are overlayed with the platform / architecture intrinsics,
+ and the three loops are compiled.
+- At *runtime import*, the CPU is probed for the set of supported intrinsic
+ features. A mechanism is used to grab the pointer to the most appropriate
+ function, and this will be the one called for the function.
+
+
+Build options for compilation
+=============================
+
+- ``--cpu-baseline``: minimal set of required optimizations. Default
+ value is ``min`` which provides the minimum CPU features that can
+ safely run on a wide range of platforms within the processor family.
+
+- ``--cpu-dispatch``: dispatched set of additional optimizations.
+ The default value is ``max -xop -fma4`` which enables all CPU
+ features, except for AMD legacy features(in case of X86).
+
+The command arguments are available in ``build``, ``build_clib``, and
+``build_ext``.
+if ``build_clib`` or ``build_ext`` are not specified by the user, the arguments of
+``build`` will be used instead, which also holds the default values.
+
+Optimization names can be CPU features or groups of features that gather
+several features or :ref:`special options <special-options>` to perform a series of procedures.
+
+
+The following tables show the current supported optimizations sorted from the lowest to the highest interest.
+
+.. include:: simd-optimizations-tables.inc
+
+----
+
+.. _tables-diff:
+
+While the above tables are based on the GCC Compiler, the following tables showing the differences in the
+other compilers:
+
+.. include:: simd-optimizations-tables-diff.inc
+
+.. _special-options:
+
+Special options
+~~~~~~~~~~~~~~~
+
+- ``NONE``: enable no features
+
+- ``NATIVE``: Enables all CPU features that supported by the current
+ machine, this operation is based on the compiler flags (``-march=native, -xHost, /QxHost``)
+
+- ``MIN``: Enables the minimum CPU features that can safely run on a wide range of platforms:
+
+ .. table::
+ :align: left
+
+ ====================================== =======================================
+ For Arch Returns
+ ====================================== =======================================
+ ``x86`` ``SSE`` ``SSE2``
+ ``x86`` ``64-bit mode`` ``SSE`` ``SSE2`` ``SSE3``
+ ``IBM/POWER`` ``big-endian mode`` ``NONE``
+ ``IBM/POWER`` ``little-endian mode`` ``VSX`` ``VSX2``
+ ``ARMHF`` ``NONE``
+ ``ARM64`` ``AARCH64`` ``NEON`` ``NEON_FP16`` ``NEON_VFPV4``
+ ``ASIMD``
+ ====================================== =======================================
+
+- ``MAX``: Enables all supported CPU features by the Compiler and platform.
+
+- ``Operators-/+``: remove or add features, useful with options ``MAX``, ``MIN`` and ``NATIVE``.
+
+NOTES
+~~~~~~~~~~~~~
+- CPU features and other options are case-insensitive.
+
+- The order of the requsted optimizations doesn't matter.
+
+- Either commas or spaces can be used as a separator, e.g. ``--cpu-dispatch``\ =
+ "avx2 avx512f" or ``--cpu-dispatch``\ = "avx2, avx512f" both work, but the
+ arguments must be enclosed in quotes.
+
+- The operand ``+`` is only added for nominal reasons, For example:
+ ``--cpu-basline= "min avx2"`` is equivalent to ``--cpu-basline="min + avx2"``.
+ ``--cpu-basline="min,avx2"`` is equivalent to ``--cpu-basline`="min,+avx2"``
+
+- If the CPU feature is not supported by the user platform or
+ compiler, it will be skipped rather than raising a fatal error.
+
+- Any specified CPU feature to ``--cpu-dispatch`` will be skipped if
+ it's part of CPU baseline features
+
+- The ``--cpu-baseline`` argument force-enables implied features,
+ e.g. ``--cpu-baseline``\ ="sse42" is equivalent to
+ ``--cpu-baseline``\ ="sse sse2 sse3 ssse3 sse41 popcnt sse42"
+
+- The value of ``--cpu-baseline`` will be treated as "native" if
+ compiler native flag ``-march=native`` or ``-xHost`` or ``QxHost`` is
+ enabled through environment variable ``CFLAGS``
+
+- The validation process for the requsted optimizations when it comes to
+ ``--cpu-baseline`` isn't strict. For example, if the user requested
+ ``AVX2`` but the compiler doesn't support it then we just skip it and return
+ the maximum optimization that the compiler can handle depending on the
+ implied features of ``AVX2``, let us assume ``AVX``.
+
+- The user should always check the final report through the build log
+ to verify the enabled features.
+
+Special cases
+~~~~~~~~~~~~~
+
+**Interrelated CPU features**: Some exceptional conditions force us to link some features together when it come to certain compilers or architectures, resulting in the impossibility of building them separately.
+These conditions can be divided into two parts, as follows:
+
+- **Architectural compatibility**: The need to align certain CPU features that are assured
+ to be supported by successive generations of the same architecture, for example:
+
+ - On ppc64le `VSX(ISA 2.06)` and `VSX2(ISA 2.07)` both imply one another since the
+ first generation that supports little-endian mode is Power-8`(ISA 2.07)`
+ - On AArch64 `NEON` `FP16` `VFPV4` `ASIMD` implies each other since they are part of the
+ hardware baseline.
+
+- **Compilation compatibility**: Not all **C/C++** compilers provide independent support for all CPU
+ features. For example, **Intel**'s compiler doesn't provide separated flags for `AVX2` and `FMA3`,
+ it makes sense since all Intel CPUs that comes with `AVX2` also support `FMA3` and vice versa,
+ but this approach is incompatible with other **x86** CPUs from **AMD** or **VIA**.
+ Therefore, there are differences in the depiction of CPU features between the C/C++ compilers,
+ as shown in the :ref:`tables above <tables-diff>`.
+
+
+Behaviors and Errors
+~~~~~~~~~~~~~~~~~~~~
+
+
+
+Usage and Examples
+~~~~~~~~~~~~~~~~~~
+
+Report and Trace
+~~~~~~~~~~~~~~~~
+
+Understanding CPU Dispatching, How the NumPy dispatcher works?
+==============================================================
+
+NumPy dispatcher is based on multi-source compiling, which means taking
+a certain source and compiling it multiple times with different compiler
+flags and also with different **C** definitions that affect the code
+paths to enable certain instruction-sets for each compiled object
+depending on the required optimizations, then combining the returned
+objects together.
+
+.. figure:: ../figures/opt-infra.png
+
+This mechanism should support all compilers and it doesn't require any
+compiler-specific extension, but at the same time it is adds a few steps to
+normal compilation that are explained as follows:
+
+1- Configuration
+~~~~~~~~~~~~~~~~
+
+Configuring the required optimization by the user before starting to build the
+source files via the two command arguments as explained above:
+
+- ``--cpu-baseline``: minimal set of required optimizations.
+
+- ``--cpu-dispatch``: dispatched set of additional optimizations.
+
+
+2- Discovering the environment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this part, we check the compiler and platform architecture
+and cache some of the intermediary results to speed up rebuilding.
+
+3- Validating the requested optimizations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By testing them against the compiler, and seeing what the compiler can
+support according to the requested optimizations.
+
+4- Generating the main configuration header
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The generated header ``_cpu_dispatch.h`` contains all the definitions and
+headers of instruction-sets for the required optimizations that have been
+validated during the previous step.
+
+It also contains extra C definitions that are used for defining NumPy's
+Python-level module attributes ``__cpu_baseline__`` and ``__cpu_dispaٍtch__``.
+
+**What is in this header?**
+
+The example header was dynamically generated by gcc on an X86 machine.
+The compiler supports ``--cpu-baseline="sse sse2 sse3"`` and
+``--cpu-dispatch="ssse3 sse41"``, and the result is below.
+
+.. code:: c
+
+ // The header should be located at numpy/numpy/core/src/common/_cpu_dispatch.h
+ /**NOTE
+ ** C definitions prefixed with "NPY_HAVE_" represent
+ ** the required optimzations.
+ **
+ ** C definitions prefixed with 'NPY__CPU_TARGET_' are protected and
+ ** shouldn't be used by any NumPy C sources.
+ */
+ /******* baseline features *******/
+ /** SSE **/
+ #define NPY_HAVE_SSE 1
+ #include <xmmintrin.h>
+ /** SSE2 **/
+ #define NPY_HAVE_SSE2 1
+ #include <emmintrin.h>
+ /** SSE3 **/
+ #define NPY_HAVE_SSE3 1
+ #include <pmmintrin.h>
+
+ /******* dispatch-able features *******/
+ #ifdef NPY__CPU_TARGET_SSSE3
+ /** SSSE3 **/
+ #define NPY_HAVE_SSSE3 1
+ #include <tmmintrin.h>
+ #endif
+ #ifdef NPY__CPU_TARGET_SSE41
+ /** SSE41 **/
+ #define NPY_HAVE_SSE41 1
+ #include <smmintrin.h>
+ #endif
+
+**Baseline features** are the minimal set of required optimizations configured
+via ``--cpu-baseline``. They have no preprocessor guards and they're
+always on, which means they can be used in any source.
+
+Does this mean NumPy's infrastructure passes the compiler's flags of
+baseline features to all sources?
+
+Definitely, yes. But the :ref:`dispatch-able sources <dispatchable-sources>` are
+treated differently.
+
+What if the user specifies certain **baseline features** during the
+build but at runtime the machine doesn't support even these
+features? Will the compiled code be called via one of these definitions, or
+maybe the compiler itself auto-generated/vectorized certain piece of code
+based on the provided command line compiler flags?
+
+During the loading of the NumPy module, there's a validation step
+which detects this behavior. It will raise a Python runtime error to inform the
+user. This is to prevent the CPU reaching an illegal instruction error causing
+a segfault.
+
+**Dispatch-able features** are our dispatched set of additional optimizations
+that were configured via ``--cpu-dispatch``. They are not activated by
+default and are always guarded by other C definitions prefixed with
+``NPY__CPU_TARGET_``. C definitions ``NPY__CPU_TARGET_`` are only
+enabled within **dispatch-able sources**.
+
+.. _dispatchable-sources:
+
+5- Dispatch-able sources and configuration statements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Dispatch-able sources are special **C** files that can be compiled multiple
+times with different compiler flags and also with different **C**
+definitions. These affect code paths to enable certain
+instruction-sets for each compiled object according to "**the
+configuration statements**" that must be declared between a **C**
+comment\ ``(/**/)`` and start with a special mark **@targets** at the
+top of each dispatch-able source. At the same time, dispatch-able
+sources will be treated as normal **C** sources if the optimization was
+disabled by the command argument ``--disable-optimization`` .
+
+**What are configuration statements?**
+
+Configuration statements are sort of keywords combined together to
+determine the required optimization for the dispatch-able source.
+
+Example:
+
+.. code:: c
+
+ /*@targets avx2 avx512f vsx2 vsx3 asimd asimdhp */
+ // C code
+
+The keywords mainly represent the additional optimizations configured
+through ``--cpu-dispatch``, but it can also represent other options such as:
+
+- Target groups: pre-configured configuration statements used for
+ managing the required optimizations from outside the dispatch-able source.
+
+- Policies: collections of options used for changing the default
+ behaviors or forcing the compilers to perform certain things.
+
+- "baseline": a unique keyword represents the minimal optimizations
+ that configured through ``--cpu-baseline``
+
+**Numpy's infrastructure handles dispatch-able sources in four steps**:
+
+- **(A) Recognition**: Just like source templates and F2PY, the
+ dispatch-able sources requires a special extension ``*.dispatch.c``
+ to mark C dispatch-able source files, and for C++
+ ``*.dispatch.cpp`` or ``*.dispatch.cxx``
+ **NOTE**: C++ not supported yet.
+
+- **(B) Parsing and validating**: In this step, the
+ dispatch-able sources that had been filtered by the previous step
+ are parsed and validated by the configuration statements for each one
+ of them one by one in order to determine the required optimizations.
+
+- **(C) Wrapping**: This is the approach taken by NumPy's
+ infrastructure, which has proved to be sufficiently flexible in order
+ to compile a single source multiple times with different **C**
+ definitions and flags that affect the code paths. The process is
+ achieved by creating a temporary **C** source for each required
+ optimization that related to the additional optimization, which
+ contains the declarations of the **C** definitions and includes the
+ involved source via the **C** directive **#include**. For more
+ clarification take a look at the following code for AVX512F :
+
+ .. code:: c
+
+ /*
+ * this definition is used by NumPy utilities as suffixes for the
+ * exported symbols
+ */
+ #define NPY__CPU_TARGET_CURRENT AVX512F
+ /*
+ * The following definitions enable
+ * definitions of the dispatch-able features that are defined within the main
+ * configuration header. These are definitions for the implied features.
+ */
+ #define NPY__CPU_TARGET_SSE
+ #define NPY__CPU_TARGET_SSE2
+ #define NPY__CPU_TARGET_SSE3
+ #define NPY__CPU_TARGET_SSSE3
+ #define NPY__CPU_TARGET_SSE41
+ #define NPY__CPU_TARGET_POPCNT
+ #define NPY__CPU_TARGET_SSE42
+ #define NPY__CPU_TARGET_AVX
+ #define NPY__CPU_TARGET_F16C
+ #define NPY__CPU_TARGET_FMA3
+ #define NPY__CPU_TARGET_AVX2
+ #define NPY__CPU_TARGET_AVX512F
+ // our dispatch-able source
+ #include "/the/absuolate/path/of/hello.dispatch.c"
+
+- **(D) Dispatch-able configuration header**: The infrastructure
+ generates a config header for each dispatch-able source, this header
+ mainly contains two abstract **C** macros used for identifying the
+ generated objects, so they can be used for runtime dispatching
+ certain symbols from the generated objects by any **C** source. It is
+ also used for forward declarations.
+
+ The generated header takes the name of the dispatch-able source after
+ excluding the extension and replace it with '**.h**', for example
+ assume we have a dispatch-able source called **hello.dispatch.c** and
+ contains the following:
+
+ .. code:: c
+
+ // hello.dispatch.c
+ /*@targets baseline sse42 avx512f */
+ #include <stdio.h>
+ #include "numpy/utils.h" // NPY_CAT, NPY_TOSTR
+
+ #ifndef NPY__CPU_TARGET_CURRENT
+ // wrapping the dispatch-able source only happens to the addtional optimizations
+ // but if the keyword 'baseline' provided within the configuration statments,
+ // the infrastructure will add extra compiling for the dispatch-able source by
+ // passing it as-is to the compiler without any changes.
+ #define CURRENT_TARGET(X) X
+ #define NPY__CPU_TARGET_CURRENT baseline // for printing only
+ #else
+ // since we reach to this point, that's mean we're dealing with
+ // the addtional optimizations, so it could be SSE42 or AVX512F
+ #define CURRENT_TARGET(X) NPY_CAT(NPY_CAT(X, _), NPY__CPU_TARGET_CURRENT)
+ #endif
+ // Macro 'CURRENT_TARGET' adding the current target as suffux to the exported symbols,
+ // to avoid linking duplications, NumPy already has a macro called
+ // 'NPY_CPU_DISPATCH_CURFX' similar to it, located at
+ // numpy/numpy/core/src/common/npy_cpu_dispatch.h
+ // NOTE: we tend to not adding suffixes to the baseline exported symbols
+ void CURRENT_TARGET(simd_whoami)(const char *extra_info)
+ {
+ printf("I'm " NPY_TOSTR(NPY__CPU_TARGET_CURRENT) ", %s\n", extra_info);
+ }
+
+ Now assume you attached **hello.dispatch.c** to the source tree, then
+ the infrastructure should generate a temporary config header called
+ **hello.dispatch.h** that can be reached by any source in the source
+ tree, and it should contain the following code :
+
+ .. code:: c
+
+ #ifndef NPY__CPU_DISPATCH_EXPAND_
+ // To expand the macro calls in this header
+ #define NPY__CPU_DISPATCH_EXPAND_(X) X
+ #endif
+ // Undefining the following macros, due to the possibility of including config headers
+ // multiple times within the same source and since each config header represents
+ // different required optimizations according to the specified configuration
+ // statements in the dispatch-able source that derived from it.
+ #undef NPY__CPU_DISPATCH_BASELINE_CALL
+ #undef NPY__CPU_DISPATCH_CALL
+ // nothing strange here, just a normal preprocessor callback
+ // enabled only if 'baseline' spesfied withiin the configration statments
+ #define NPY__CPU_DISPATCH_BASELINE_CALL(CB, ...) \
+ NPY__CPU_DISPATCH_EXPAND_(CB(__VA_ARGS__))
+ // 'NPY__CPU_DISPATCH_CALL' is an abstract macro is used for dispatching
+ // the required optimizations that specified within the configuration statements.
+ //
+ // @param CHK, Expected a macro that can be used to detect CPU features
+ // in runtime, which takes a CPU feature name without string quotes and
+ // returns the testing result in a shape of boolean value.
+ // NumPy already has macro called "NPY_CPU_HAVE", which fit this requirment.
+ //
+ // @param CB, a callback macro that expected to be called multiple times depending
+ // on the required optimizations, the callback should receive the following arguments:
+ // 1- The pending calls of @param CHK filled up with the required CPU features,
+ // that need to be tested first in runtime before executing call belong to
+ // the compiled object.
+ // 2- The required optimization name, same as in 'NPY__CPU_TARGET_CURRENT'
+ // 3- Extra arguments in the macro itself
+ //
+ // By default the callback calls are sorted depending on the highest interest
+ // unless the policy "$keep_sort" was in place within the configuration statements
+ // see "Dive into the CPU dispatcher" for more clarification.
+ #define NPY__CPU_DISPATCH_CALL(CHK, CB, ...) \
+ NPY__CPU_DISPATCH_EXPAND_(CB((CHK(AVX512F)), AVX512F, __VA_ARGS__)) \
+ NPY__CPU_DISPATCH_EXPAND_(CB((CHK(SSE)&&CHK(SSE2)&&CHK(SSE3)&&CHK(SSSE3)&&CHK(SSE41)), SSE41, __VA_ARGS__))
+
+ An example of using the config header in light of the above:
+
+ .. code:: c
+
+ // NOTE: The following macros are only defined for demonstration purposes only.
+ // NumPy already has a collections of macros located at
+ // numpy/numpy/core/src/common/npy_cpu_dispatch.h, that covers all dispatching
+ // and declarations scenarios.
+
+ #include "numpy/npy_cpu_features.h" // NPY_CPU_HAVE
+ #include "numpy/utils.h" // NPY_CAT, NPY_EXPAND
+
+ // An example for setting a macro that calls all the exported symbols at once
+ // after checking if they're supported by the running machine.
+ #define DISPATCH_CALL_ALL(FN, ARGS) \
+ NPY__CPU_DISPATCH_CALL(NPY_CPU_HAVE, DISPATCH_CALL_ALL_CB, FN, ARGS) \
+ NPY__CPU_DISPATCH_BASELINE_CALL(DISPATCH_CALL_BASELINE_ALL_CB, FN, ARGS)
+ // The preprocessor callbacks.
+ // The same suffixes as we define it in the dispatch-able source.
+ #define DISPATCH_CALL_ALL_CB(CHECK, TARGET_NAME, FN, ARGS) \
+ if (CHECK) { NPY_CAT(NPY_CAT(FN, _), TARGET_NAME) ARGS; }
+ #define DISPATCH_CALL_BASELINE_ALL_CB(FN, ARGS) \
+ FN NPY_EXPAND(ARGS);
+
+ // An example for setting a macro that calls the exported symbols of highest
+ // interest optimization, after checking if they're supported by the running machine.
+ #define DISPATCH_CALL_HIGH(FN, ARGS) \
+ if (0) {} \
+ NPY__CPU_DISPATCH_CALL(NPY_CPU_HAVE, DISPATCH_CALL_HIGH_CB, FN, ARGS) \
+ NPY__CPU_DISPATCH_BASELINE_CALL(DISPATCH_CALL_BASELINE_HIGH_CB, FN, ARGS)
+ // The preprocessor callbacks
+ // The same suffixes as we define it in the dispatch-able source.
+ #define DISPATCH_CALL_HIGH_CB(CHECK, TARGET_NAME, FN, ARGS) \
+ else if (CHECK) { NPY_CAT(NPY_CAT(FN, _), TARGET_NAME) ARGS; }
+ #define DISPATCH_CALL_BASELINE_HIGH_CB(FN, ARGS) \
+ else { FN NPY_EXPAND(ARGS); }
+
+ // NumPy has a macro called 'NPY_CPU_DISPATCH_DECLARE' can be used
+ // for forward declrations any kind of prototypes based on
+ // 'NPY__CPU_DISPATCH_CALL' and 'NPY__CPU_DISPATCH_BASELINE_CALL'.
+ // However in this example, we just handle it manually.
+ void simd_whoami(const char *extra_info);
+ void simd_whoami_AVX512F(const char *extra_info);
+ void simd_whoami_SSE41(const char *extra_info);
+
+ void trigger_me(void)
+ {
+ // bring the auto-gernreated config header
+ // which contains config macros 'NPY__CPU_DISPATCH_CALL' and
+ // 'NPY__CPU_DISPATCH_BASELINE_CALL'.
+ // it highely recomaned to include the config header before exectuing
+ // the dispatching macros in case if there's another header in the scope.
+ #include "hello.dispatch.h"
+ DISPATCH_CALL_ALL(simd_whoami, ("all"))
+ DISPATCH_CALL_HIGH(simd_whoami, ("the highest interest"))
+ // An example of including multiple config headers in the same source
+ // #include "hello2.dispatch.h"
+ // DISPATCH_CALL_HIGH(another_function, ("the highest interest"))
+ }
+
+
+Dive into the CPU dispatcher
+============================
+
+The baseline
+~~~~~~~~~~~~
+
+Dispatcher
+~~~~~~~~~~
+
+Groups and Policies
+~~~~~~~~~~~~~~~~~~~
+
+Examples
+~~~~~~~~
+
+Report and Trace
+~~~~~~~~~~~~~~~~
+
+
+.. _`Universal Intrinsics`: https://numpy.org/neps/nep-0038-SIMD-optimizations.html
--- /dev/null
+.. _typing:
+.. automodule:: numpy.typing
.. sectionauthor:: adapted from "Guide to NumPy" by Travis E. Oliphant
+.. currentmodule:: numpy
+
.. _ufuncs:
************************************
.. note: XXX: section might need to be made more reference-guideish...
-.. currentmodule:: numpy
-
.. index: ufunc, universal function, arithmetic, operation
A universal function (or :term:`ufunc` for short) is a function that
:class:`ndarray`, if all input arguments are not :class:`ndarrays <ndarray>`.
Indeed, if any input defines an :obj:`~class.__array_ufunc__` method,
control will be passed completely to that function, i.e., the ufunc is
-`overridden <ufuncs.overrides>`_.
+:ref:`overridden <ufuncs.overrides>`.
If none of the inputs overrides the ufunc, then
all output arrays will be passed to the :obj:`~class.__array_prepare__` and
:class:`ufunc`
==============
+.. autosummary::
+ :toctree: generated/
+
+ numpy.ufunc
+
.. _ufuncs.kwargs:
Optional keyword arguments
Note that outputs not explicitly filled are left with their
uninitialized values.
+ .. versionadded:: 1.13
+
+ Operations where ufunc input and output operands have memory overlap are
+ defined to be the same as for equivalent operations where there
+ is no memory overlap. Operations affected make temporary copies
+ as needed to eliminate data dependency. As detecting these cases
+ is computationally expensive, a heuristic is used, which may in rare
+ cases result in needless temporary copies. For operations where the
+ data dependency is simple enough for the heuristic to analyze,
+ temporary copies will not be made even if the arrays overlap, if it
+ can be deduced copies are not necessary. As an example,
+ ``np.add(a, b, out=a)`` will not involve copies.
+
*where*
.. versionadded:: 1.7
.. toctree::
:maxdepth: 3
+ 1.20.0 <release/1.20.0-notes>
1.19.5 <release/1.19.5-notes>
1.19.4 <release/1.19.4-notes>
1.19.3 <release/1.19.3-notes>
C API changes
=============
-The :c:data:`NPY_API_VERSION` was incremented to 0x0000D, due to the addition
-of:
+The :c:data:`NPY_FEATURE_VERSION` was incremented to 0x0000D, due to
+the addition of:
* :c:member:`PyUFuncObject.core_dim_flags`
* :c:member:`PyUFuncObject.core_dim_sizes`
`CVE-2019-6446 <https://nvd.nist.gov/vuln/detail/CVE-2019-6446>`_.
-.. currentmodule:: numpy.random.mtrand
+.. currentmodule:: numpy.random
Potential changes to the random stream in old random module
-----------------------------------------------------------
Due to bugs in the application of ``log`` to random floating point numbers,
the stream may change when sampling from `~RandomState.beta`, `~RandomState.binomial`,
`~RandomState.laplace`, `~RandomState.logistic`, `~RandomState.logseries` or
-`~RandomState.multinomial` if a ``0`` is generated in the underlying `MT19937
-<~numpy.random.mt11937.MT19937>` random stream. There is a ``1`` in
+`~RandomState.multinomial` if a ``0`` is generated in the underlying `MT19937`
+random stream. There is a ``1`` in
:math:`10^{53}` chance of this occurring, so the probability that the stream
changes for any given seed is extremely small. If a ``0`` is encountered in the
underlying generator, then the incorrect value produced (either `numpy.inf` or
----------------------------------------------------------------------------------------
``arr['bad_field']`` on a structured type raises ``KeyError``, for consistency
with ``dict['bad_field']``.
-
--- /dev/null
+.. currentmodule:: numpy
+
+==========================
+NumPy 1.20.0 Release Notes
+==========================
+This NumPy release is the largest so made to date, some 684 PRs contributed by
+184 people have been merged. See the list of highlights below for more details.
+The Python versions supported for this release are 3.7-3.9, support for Python
+3.6 has been dropped. Highlights are
+
+- Annotations for NumPy functions. This work is ongoing and improvements can
+ be expected pending feedback from users.
+
+- Wider use of SIMD to increase execution speed of ufuncs. Much work has been
+ done in introducing universal functions that will ease use of modern
+ features across different hardware platforms. This work is ongoing.
+
+- Preliminary work in changing the dtype and casting implementations in order to
+ provide an easier path to extending dtypes. This work is ongoing but enough
+ has been done to allow experimentation and feedback.
+
+- Extensive documentation improvements comprising some 185 PR merges. This work
+ is ongoing and part of the larger project to improve NumPy's online presence
+ and usefulness to new users.
+
+- Further cleanups related to removing Python 2.7. This improves code
+ readability and removes technical debt.
+
+- Preliminary support for the upcoming Cython 3.0.
+
+
+New functions
+=============
+
+The random.Generator class has a new ``permuted`` function.
+-----------------------------------------------------------
+The new function differs from ``shuffle`` and ``permutation`` in that the
+subarrays indexed by an axis are permuted rather than the axis being treated as
+a separate 1-D array for every combination of the other indexes. For example,
+it is now possible to permute the rows or columns of a 2-D array.
+
+(`gh-15121 <https://github.com/numpy/numpy/pull/15121>`__)
+
+``sliding_window_view`` provides a sliding window view for numpy arrays
+-----------------------------------------------------------------------
+`numpy.lib.stride_tricks.sliding_window_view` constructs views on numpy
+arrays that offer a sliding or moving window access to the array. This allows
+for the simple implementation of certain algorithms, such as running means.
+
+(`gh-17394 <https://github.com/numpy/numpy/pull/17394>`__)
+
+`numpy.broadcast_shapes` is a new user-facing function
+------------------------------------------------------
+`~numpy.broadcast_shapes` gets the resulting shape from
+broadcasting the given shape tuples against each other.
+
+.. code:: python
+
+ >>> np.broadcast_shapes((1, 2), (3, 1))
+ (3, 2)
+
+ >>> np.broadcast_shapes(2, (3, 1))
+ (3, 2)
+
+ >>> np.broadcast_shapes((6, 7), (5, 6, 1), (7,), (5, 1, 7))
+ (5, 6, 7)
+
+(`gh-17535 <https://github.com/numpy/numpy/pull/17535>`__)
+
+
+Deprecations
+============
+
+Using the aliases of builtin types like ``np.int`` is deprecated
+----------------------------------------------------------------
+
+For a long time, ``np.int`` has been an alias of the builtin ``int``. This is
+repeatedly a cause of confusion for newcomers, and existed mainly for historic
+reasons.
+
+These aliases have been deprecated. The table below shows the full list of
+deprecated aliases, along with their exact meaning. Replacing uses of items in
+the first column with the contents of the second column will work identically
+and silence the deprecation warning.
+
+The third column lists alternative NumPy names which may occasionally be
+preferential. See also :ref:`basics.types` for additional details.
+
+================= ============ ==================================================================
+Deprecated name Identical to NumPy scalar type names
+================= ============ ==================================================================
+``numpy.bool`` ``bool`` `numpy.bool_`
+``numpy.int`` ``int`` `numpy.int_` (default), ``numpy.int64``, or ``numpy.int32``
+``numpy.float`` ``float`` `numpy.float64`, `numpy.float_`, `numpy.double` (equivalent)
+``numpy.complex`` ``complex`` `numpy.complex128`, `numpy.complex_`, `numpy.cdouble` (equivalent)
+``numpy.object`` ``object`` `numpy.object_`
+``numpy.str`` ``str`` `numpy.str_`
+``numpy.long`` ``int`` `numpy.int_` (C ``long``), `numpy.longlong` (largest integer type)
+``numpy.unicode`` ``str`` `numpy.unicode_`
+================= ============ ==================================================================
+
+To give a clear guideline for the vast majority of cases, for the types
+``bool``, ``object``, ``str`` (and ``unicode``) using the plain version
+is shorter and clear, and generally a good replacement.
+For ``float`` and ``complex`` you can use ``float64`` and ``complex128``
+if you wish to be more explicit about the precision.
+
+For ``np.int`` a direct replacement with ``np.int_`` or ``int`` is also
+good and will not change behavior, but the precision will continue to depend
+on the computer and operating system.
+If you want to be more explicit and review the current use, you have the
+following alternatives:
+
+* ``np.int64`` or ``np.int32`` to specify the precision exactly.
+ This ensures that results cannot depend on the computer or operating system.
+* ``np.int_`` or ``int`` (the default), but be aware that it depends on
+ the computer and operating system.
+* The C types: ``np.cint`` (int), ``np.int_`` (long), ``np.longlong``.
+* ``np.intp`` which is 32bit on 32bit machines 64bit on 64bit machines.
+ This can be the best type to use for indexing.
+
+When used with ``np.dtype(...)`` or ``dtype=...`` changing it to the
+NumPy name as mentioned above will have no effect on the output.
+If used as a scalar with::
+
+ np.float(123)
+
+changing it can subtly change the result. In this case, the Python version
+``float(123)`` or ``int(12.)`` is normally preferable, although the NumPy
+version may be useful for consistency with NumPy arrays (for example,
+NumPy behaves differently for things like division by zero).
+
+(`gh-14882 <https://github.com/numpy/numpy/pull/14882>`__)
+
+Passing ``shape=None`` to functions with a non-optional shape argument is deprecated
+------------------------------------------------------------------------------------
+Previously, this was an alias for passing ``shape=()``.
+This deprecation is emitted by `PyArray_IntpConverter` in the C API. If your
+API is intended to support passing ``None``, then you should check for ``None``
+prior to invoking the converter, so as to be able to distinguish ``None`` and
+``()``.
+
+(`gh-15886 <https://github.com/numpy/numpy/pull/15886>`__)
+
+Indexing errors will be reported even when index result is empty
+----------------------------------------------------------------
+In the future, NumPy will raise an IndexError when an
+integer array index contains out of bound values even if a non-indexed
+dimension is of length 0. This will now emit a DeprecationWarning.
+This can happen when the array is previously empty, or an empty
+slice is involved::
+
+ arr1 = np.zeros((5, 0))
+ arr1[[20]]
+ arr2 = np.zeros((5, 5))
+ arr2[[20], :0]
+
+Previously the non-empty index ``[20]`` was not checked for correctness.
+It will now be checked causing a deprecation warning which will be turned
+into an error. This also applies to assignments.
+
+(`gh-15900 <https://github.com/numpy/numpy/pull/15900>`__)
+
+Inexact matches for ``mode`` and ``searchside`` are deprecated
+--------------------------------------------------------------
+Inexact and case insensitive matches for ``mode`` and ``searchside`` were valid
+inputs earlier and will give a DeprecationWarning now. For example, below are
+some example usages which are now deprecated and will give a
+DeprecationWarning::
+
+ import numpy as np
+ arr = np.array([[3, 6, 6], [4, 5, 1]])
+ # mode: inexact match
+ np.ravel_multi_index(arr, (7, 6), mode="clap") # should be "clip"
+ # searchside: inexact match
+ np.searchsorted(arr[0], 4, side='random') # should be "right"
+
+(`gh-16056 <https://github.com/numpy/numpy/pull/16056>`__)
+
+Deprecation of `numpy.dual`
+---------------------------
+The module `numpy.dual` is deprecated. Instead of importing functions
+from `numpy.dual`, the functions should be imported directly from NumPy
+or SciPy.
+
+(`gh-16156 <https://github.com/numpy/numpy/pull/16156>`__)
+
+``outer`` and ``ufunc.outer`` deprecated for matrix
+---------------------------------------------------
+``np.matrix`` use with `~numpy.outer` or generic ufunc outer
+calls such as ``numpy.add.outer``. Previously, matrix was
+converted to an array here. This will not be done in the future
+requiring a manual conversion to arrays.
+
+(`gh-16232 <https://github.com/numpy/numpy/pull/16232>`__)
+
+Further Numeric Style types Deprecated
+--------------------------------------
+
+The remaining numeric-style type codes ``Bytes0``, ``Str0``,
+``Uint32``, ``Uint64``, and ``Datetime64``
+have been deprecated. The lower-case variants should be used
+instead. For bytes and string ``"S"`` and ``"U"``
+are further alternatives.
+
+(`gh-16554 <https://github.com/numpy/numpy/pull/16554>`__)
+
+The ``ndincr`` method of ``ndindex`` is deprecated
+--------------------------------------------------
+The documentation has warned against using this function since NumPy 1.8.
+Use ``next(it)`` instead of ``it.ndincr()``.
+
+(`gh-17233 <https://github.com/numpy/numpy/pull/17233>`__)
+
+ArrayLike objects which do not define ``__len__`` and ``__getitem__``
+---------------------------------------------------------------------
+Objects which define one of the protocols ``__array__``,
+``__array_interface__``, or ``__array_struct__`` but are not sequences
+(usually defined by having a ``__len__`` and ``__getitem__``) will behave
+differently during array-coercion in the future.
+
+When nested inside sequences, such as ``np.array([array_like])``, these
+were handled as a single Python object rather than an array.
+In the future they will behave identically to::
+
+ np.array([np.array(array_like)])
+
+This change should only have an effect if ``np.array(array_like)`` is not 0-D.
+The solution to this warning may depend on the object:
+
+* Some array-likes may expect the new behaviour, and users can ignore the
+ warning. The object can choose to expose the sequence protocol to opt-in
+ to the new behaviour.
+* For example, ``shapely`` will allow conversion to an array-like using
+ ``line.coords`` rather than ``np.asarray(line)``. Users may work around
+ the warning, or use the new convention when it becomes available.
+
+Unfortunately, using the new behaviour can only be achieved by
+calling ``np.array(array_like)``.
+
+If you wish to ensure that the old behaviour remains unchanged, please create
+an object array and then fill it explicitly, for example::
+
+ arr = np.empty(3, dtype=object)
+ arr[:] = [array_like1, array_like2, array_like3]
+
+This will ensure NumPy knows to not enter the array-like and use it as
+a object instead.
+
+(`gh-17973 <https://github.com/numpy/numpy/pull/17973>`__)
+
+
+Future Changes
+==============
+
+Arrays cannot be using subarray dtypes
+--------------------------------------
+Array creation and casting using ``np.array(arr, dtype)``
+and ``arr.astype(dtype)`` will use different logic when ``dtype``
+is a subarray dtype such as ``np.dtype("(2)i,")``.
+
+For such a ``dtype`` the following behaviour is true::
+
+ res = np.array(arr, dtype)
+
+ res.dtype is not dtype
+ res.dtype is dtype.base
+ res.shape == arr.shape + dtype.shape
+
+But ``res`` is filled using the logic::
+
+ res = np.empty(arr.shape + dtype.shape, dtype=dtype.base)
+ res[...] = arr
+
+which uses incorrect broadcasting (and often leads to an error).
+In the future, this will instead cast each element individually,
+leading to the same result as::
+
+ res = np.array(arr, dtype=np.dtype(["f", dtype]))["f"]
+
+Which can normally be used to opt-in to the new behaviour.
+
+This change does not affect ``np.array(list, dtype="(2)i,")`` unless the
+``list`` itself includes at least one array. In particular, the behaviour
+is unchanged for a list of tuples.
+
+(`gh-17596 <https://github.com/numpy/numpy/pull/17596>`__)
+
+
+Expired deprecations
+====================
+
+* The deprecation of numeric style type-codes ``np.dtype("Complex64")``
+ (with upper case spelling), is expired. ``"Complex64"`` corresponded to
+ ``"complex128"`` and ``"Complex32"`` corresponded to ``"complex64"``.
+* The deprecation of ``np.sctypeNA`` and ``np.typeNA`` is expired. Both
+ have been removed from the public API. Use ``np.typeDict`` instead.
+
+ (`gh-16554 <https://github.com/numpy/numpy/pull/16554>`__)
+
+* The 14-year deprecation of ``np.ctypeslib.ctypes_load_library`` is expired.
+ Use :func:`~numpy.ctypeslib.load_library` instead, which is identical.
+
+ (`gh-17116 <https://github.com/numpy/numpy/pull/17116>`__)
+
+Financial functions removed
+---------------------------
+In accordance with NEP 32, the financial functions are removed
+from NumPy 1.20. The functions that have been removed are ``fv``,
+``ipmt``, ``irr``, ``mirr``, ``nper``, ``npv``, ``pmt``, ``ppmt``,
+``pv``, and ``rate``. These functions are available in the
+`numpy_financial <https://pypi.org/project/numpy-financial>`_
+library.
+
+(`gh-17067 <https://github.com/numpy/numpy/pull/17067>`__)
+
+
+Compatibility notes
+===================
+
+``isinstance(dtype, np.dtype)`` and not ``type(dtype) is not np.dtype``
+-----------------------------------------------------------------------
+NumPy dtypes are not direct instances of ``np.dtype`` anymore. Code that
+may have used ``type(dtype) is np.dtype`` will always return ``False`` and
+must be updated to use the correct version ``isinstance(dtype, np.dtype)``.
+
+This change also affects the C-side macro ``PyArray_DescrCheck`` if compiled
+against a NumPy older than 1.16.6. If code uses this macro and wishes to
+compile against an older version of NumPy, it must replace the macro
+(see also `C API changes`_ section).
+
+
+Same kind casting in concatenate with ``axis=None``
+---------------------------------------------------
+When `~numpy.concatenate` is called with ``axis=None``,
+the flattened arrays were cast with ``unsafe``. Any other axis
+choice uses "same kind". That different default
+has been deprecated and "same kind" casting will be used
+instead. The new ``casting`` keyword argument
+can be used to retain the old behaviour.
+
+(`gh-16134 <https://github.com/numpy/numpy/pull/16134>`__)
+
+NumPy Scalars are cast when assigned to arrays
+----------------------------------------------
+
+When creating or assigning to arrays, in all relevant cases NumPy
+scalars will now be cast identically to NumPy arrays. In particular
+this changes the behaviour in some cases which previously raised an
+error::
+
+ np.array([np.float64(np.nan)], dtype=np.int64)
+
+will succeed and return an undefined result (usually the smallest possible
+integer). This also affects assignments::
+
+ arr[0] = np.float64(np.nan)
+
+At this time, NumPy retains the behaviour for::
+
+ np.array(np.float64(np.nan), dtype=np.int64)
+
+The above changes do not affect Python scalars::
+
+ np.array([float("NaN")], dtype=np.int64)
+
+remains unaffected (``np.nan`` is a Python ``float``, not a NumPy one).
+Unlike signed integers, unsigned integers do not retain this special case,
+since they always behaved more like casting.
+The following code stops raising an error::
+
+ np.array([np.float64(np.nan)], dtype=np.uint64)
+
+To avoid backward compatibility issues, at this time assignment from
+``datetime64`` scalar to strings of too short length remains supported.
+This means that ``np.asarray(np.datetime64("2020-10-10"), dtype="S5")``
+succeeds now, when it failed before. In the long term this may be
+deprecated or the unsafe cast may be allowed generally to make assignment
+of arrays and scalars behave consistently.
+
+
+Array coercion changes when Strings and other types are mixed
+-------------------------------------------------------------
+
+When strings and other types are mixed, such as::
+
+ np.array(["string", np.float64(3.)], dtype="S")
+
+The results will change, which may lead to string dtypes with longer strings
+in some cases. In particularly, if ``dtype="S"`` is not provided any numerical
+value will lead to a string results long enough to hold all possible numerical
+values. (e.g. "S32" for floats). Note that you should always provide
+``dtype="S"`` when converting non-strings to strings.
+
+If ``dtype="S"`` is provided the results will be largely identical to before,
+but NumPy scalars (not a Python float like ``1.0``), will still enforce
+a uniform string length::
+
+ np.array([np.float64(3.)], dtype="S") # gives "S32"
+ np.array([3.0], dtype="S") # gives "S3"
+
+Previously the first version gave the same result as the second.
+
+
+Array coercion restructure
+--------------------------
+
+Array coercion has been restructured. In general, this should not affect
+users. In extremely rare corner cases where array-likes are nested::
+
+ np.array([array_like1])
+
+Things will now be more consistent with::
+
+ np.array([np.array(array_like1)])
+
+This can subtly change output for some badly defined array-likes.
+One example for this are array-like objects which are not also sequences
+of matching shape.
+In NumPy 1.20, a warning will be given when an array-like is not also a
+sequence (but behaviour remains identical, see deprecations).
+If an array like is also a sequence (defines ``__getitem__`` and ``__len__``)
+NumPy will now only use the result given by ``__array__``,
+``__array_interface__``, or ``__array_struct__``. This will result in
+differences when the (nested) sequence describes a different shape.
+
+(`gh-16200 <https://github.com/numpy/numpy/pull/16200>`__)
+
+Writing to the result of `numpy.broadcast_arrays` will export readonly buffers
+------------------------------------------------------------------------------
+
+In NumPy 1.17 `numpy.broadcast_arrays` started warning when the resulting array
+was written to. This warning was skipped when the array was used through the
+buffer interface (e.g. ``memoryview(arr)``). The same thing will now occur for the
+two protocols ``__array_interface__``, and ``__array_struct__`` returning read-only
+buffers instead of giving a warning.
+
+(`gh-16350 <https://github.com/numpy/numpy/pull/16350>`__)
+
+Numeric-style type names have been removed from type dictionaries
+-----------------------------------------------------------------
+
+To stay in sync with the deprecation for ``np.dtype("Complex64")``
+and other numeric-style (capital case) types. These were removed
+from ``np.sctypeDict`` and ``np.typeDict``. You should use
+the lower case versions instead. Note that ``"Complex64"``
+corresponds to ``"complex128"`` and ``"Complex32"`` corresponds
+to ``"complex64"``. The numpy style (new) versions, denote the full
+size and not the size of the real/imaginary part.
+
+(`gh-16554 <https://github.com/numpy/numpy/pull/16554>`__)
+
+The ``operator.concat`` function now raises TypeError for array arguments
+-------------------------------------------------------------------------
+The previous behavior was to fall back to addition and add the two arrays,
+which was thought to be unexpected behavior for a concatenation function.
+
+(`gh-16570 <https://github.com/numpy/numpy/pull/16570>`__)
+
+``nickname`` attribute removed from ABCPolyBase
+-----------------------------------------------
+
+An abstract property ``nickname`` has been removed from ``ABCPolyBase`` as it
+was no longer used in the derived convenience classes.
+This may affect users who have derived classes from ``ABCPolyBase`` and
+overridden the methods for representation and display, e.g. ``__str__``,
+``__repr__``, ``_repr_latex``, etc.
+
+(`gh-16589 <https://github.com/numpy/numpy/pull/16589>`__)
+
+``float->timedelta`` and ``uint64->timedelta`` promotion will raise a TypeError
+-------------------------------------------------------------------------------
+Float and timedelta promotion consistently raises a TypeError.
+``np.promote_types("float32", "m8")`` aligns with
+``np.promote_types("m8", "float32")`` now and both raise a TypeError.
+Previously, ``np.promote_types("float32", "m8")`` returned ``"m8"`` which
+was considered a bug.
+
+Uint64 and timedelta promotion consistently raises a TypeError.
+``np.promote_types("uint64", "m8")`` aligns with
+``np.promote_types("m8", "uint64")`` now and both raise a TypeError.
+Previously, ``np.promote_types("uint64", "m8")`` returned ``"m8"`` which
+was considered a bug.
+
+(`gh-16592 <https://github.com/numpy/numpy/pull/16592>`__)
+
+``numpy.genfromtxt`` now correctly unpacks structured arrays
+------------------------------------------------------------
+Previously, `numpy.genfromtxt` failed to unpack if it was called with
+``unpack=True`` and a structured datatype was passed to the ``dtype`` argument
+(or ``dtype=None`` was passed and a structured datatype was inferred).
+For example::
+
+ >>> data = StringIO("21 58.0\n35 72.0")
+ >>> np.genfromtxt(data, dtype=None, unpack=True)
+ array([(21, 58.), (35, 72.)], dtype=[('f0', '<i8'), ('f1', '<f8')])
+
+Structured arrays will now correctly unpack into a list of arrays,
+one for each column::
+
+ >>> np.genfromtxt(data, dtype=None, unpack=True)
+ [array([21, 35]), array([58., 72.])]
+
+(`gh-16650 <https://github.com/numpy/numpy/pull/16650>`__)
+
+``mgrid``, ``r_``, etc. consistently return correct outputs for non-default precision input
+-------------------------------------------------------------------------------------------
+Previously, ``np.mgrid[np.float32(0.1):np.float32(0.35):np.float32(0.1),]``
+and ``np.r_[0:10:np.complex64(3j)]`` failed to return meaningful output.
+This bug potentially affects `~numpy.mgrid`, `~numpy.ogrid`, `~numpy.r_`,
+and `~numpy.c_` when an input with dtype other than the default
+``float64`` and ``complex128`` and equivalent Python types were used.
+The methods have been fixed to handle varying precision correctly.
+
+(`gh-16815 <https://github.com/numpy/numpy/pull/16815>`__)
+
+Boolean array indices with mismatching shapes now properly give ``IndexError``
+------------------------------------------------------------------------------
+
+Previously, if a boolean array index matched the size of the indexed array but
+not the shape, it was incorrectly allowed in some cases. In other cases, it
+gave an error, but the error was incorrectly a ``ValueError`` with a message
+about broadcasting instead of the correct ``IndexError``.
+
+For example, the following used to incorrectly give ``ValueError: operands
+could not be broadcast together with shapes (2,2) (1,4)``:
+
+.. code:: python
+
+ np.empty((2, 2))[np.array([[True, False, False, False]])]
+
+And the following used to incorrectly return ``array([], dtype=float64)``:
+
+.. code:: python
+
+ np.empty((2, 2))[np.array([[False, False, False, False]])]
+
+Both now correctly give ``IndexError: boolean index did not match indexed
+array along dimension 0; dimension is 2 but corresponding boolean dimension is
+1``.
+
+(`gh-17010 <https://github.com/numpy/numpy/pull/17010>`__)
+
+Casting errors interrupt Iteration
+----------------------------------
+When iterating while casting values, an error may stop the iteration
+earlier than before. In any case, a failed casting operation always
+returned undefined, partial results. Those may now be even more
+undefined and partial.
+For users of the ``NpyIter`` C-API such cast errors will now
+cause the `iternext()` function to return 0 and thus abort
+iteration.
+Currently, there is no API to detect such an error directly.
+It is necessary to check ``PyErr_Occurred()``, which
+may be problematic in combination with ``NpyIter_Reset``.
+These issues always existed, but new API could be added
+if required by users.
+
+(`gh-17029 <https://github.com/numpy/numpy/pull/17029>`__)
+
+f2py generated code may return unicode instead of byte strings
+--------------------------------------------------------------
+Some byte strings previously returned by f2py generated code may now be unicode
+strings. This results from the ongoing Python2 -> Python3 cleanup.
+
+(`gh-17068 <https://github.com/numpy/numpy/pull/17068>`__)
+
+The first element of the ``__array_interface__["data"]`` tuple must be an integer
+----------------------------------------------------------------------------------
+This has been the documented interface for many years, but there was still
+code that would accept a byte string representation of the pointer address.
+That code has been removed, passing the address as a byte string will now
+raise an error.
+
+(`gh-17241 <https://github.com/numpy/numpy/pull/17241>`__)
+
+poly1d respects the dtype of all-zero argument
+----------------------------------------------
+Previously, constructing an instance of ``poly1d`` with all-zero
+coefficients would cast the coefficients to ``np.float64``.
+This affected the output dtype of methods which construct
+``poly1d`` instances internally, such as ``np.polymul``.
+
+(`gh-17577 <https://github.com/numpy/numpy/pull/17577>`__)
+
+The numpy.i file for swig is Python 3 only.
+-------------------------------------------
+Uses of Python 2.7 C-API functions have been updated to Python 3 only. Users
+who need the old version should take it from an older version of NumPy.
+
+(`gh-17580 <https://github.com/numpy/numpy/pull/17580>`__)
+
+Void dtype discovery in ``np.array``
+------------------------------------
+In calls using ``np.array(..., dtype="V")``, ``arr.astype("V")``,
+and similar a TypeError will now be correctly raised unless all
+elements have the identical void length. An example for this is::
+
+ np.array([b"1", b"12"], dtype="V")
+
+Which previously returned an array with dtype ``"V2"`` which
+cannot represent ``b"1"`` faithfully.
+
+(`gh-17706 <https://github.com/numpy/numpy/pull/17706>`__)
+
+
+C API changes
+=============
+
+The ``PyArray_DescrCheck`` macro is modified
+--------------------------------------------
+The ``PyArray_DescrCheck`` macro has been updated since NumPy 1.16.6 to be::
+
+ #define PyArray_DescrCheck(op) PyObject_TypeCheck(op, &PyArrayDescr_Type)
+
+Starting with NumPy 1.20 code that is compiled against an earlier version
+will be API incompatible with NumPy 1.20.
+The fix is to either compile against 1.16.6 (if the NumPy 1.16 release is
+the oldest release you wish to support), or manually inline the macro by
+replacing it with the new definition::
+
+ PyObject_TypeCheck(op, &PyArrayDescr_Type)
+
+which is compatible with all NumPy versions.
+
+
+Size of ``np.ndarray`` and ``np.void_`` changed
+-----------------------------------------------
+The size of the ``PyArrayObject`` and ``PyVoidScalarObject``
+structures have changed. The following header definition has been
+removed::
+
+ #define NPY_SIZEOF_PYARRAYOBJECT (sizeof(PyArrayObject_fields))
+
+since the size must not be considered a compile time constant: it will
+change for different runtime versions of NumPy.
+
+The most likely relevant use are potential subclasses written in C which
+will have to be recompiled and should be updated. Please see the
+documentation for :c:type:`PyArrayObject` for more details and contact
+the NumPy developers if you are affected by this change.
+
+NumPy will attempt to give a graceful error but a program expecting a
+fixed structure size may have undefined behaviour and likely crash.
+
+(`gh-16938 <https://github.com/numpy/numpy/pull/16938>`__)
+
+
+New Features
+============
+
+``where`` keyword argument for ``numpy.all`` and ``numpy.any`` functions
+------------------------------------------------------------------------
+The keyword argument ``where`` is added and allows to only consider specified
+elements or subaxes from an array in the Boolean evaluation of ``all`` and
+``any``. This new keyword is available to the functions ``all`` and ``any``
+both via ``numpy`` directly or in the methods of ``numpy.ndarray``.
+
+Any broadcastable Boolean array or a scalar can be set as ``where``. It
+defaults to ``True`` to evaluate the functions for all elements in an array if
+``where`` is not set by the user. Examples are given in the documentation of
+the functions.
+
+
+``where`` keyword argument for ``numpy`` functions ``mean``, ``std``, ``var``
+-----------------------------------------------------------------------------
+The keyword argument ``where`` is added and allows to limit the scope in the
+calculation of ``mean``, ``std`` and ``var`` to only a subset of elements. It
+is available both via ``numpy`` directly or in the methods of
+``numpy.ndarray``.
+
+Any broadcastable Boolean array or a scalar can be set as ``where``. It
+defaults to ``True`` to evaluate the functions for all elements in an array if
+``where`` is not set by the user. Examples are given in the documentation of
+the functions.
+
+(`gh-15852 <https://github.com/numpy/numpy/pull/15852>`__)
+
+``norm=backward``, ``forward`` keyword options for ``numpy.fft`` functions
+--------------------------------------------------------------------------
+The keyword argument option ``norm=backward`` is added as an alias for ``None``
+and acts as the default option; using it has the direct transforms unscaled
+and the inverse transforms scaled by ``1/n``.
+
+Using the new keyword argument option ``norm=forward`` has the direct
+transforms scaled by ``1/n`` and the inverse transforms unscaled (i.e. exactly
+opposite to the default option ``norm=backward``).
+
+(`gh-16476 <https://github.com/numpy/numpy/pull/16476>`__)
+
+NumPy is now typed
+------------------
+Type annotations have been added for large parts of NumPy. There is
+also a new `numpy.typing` module that contains useful types for
+end-users. The currently available types are
+
+- ``ArrayLike``: for objects that can be coerced to an array
+- ``DtypeLike``: for objects that can be coerced to a dtype
+
+(`gh-16515 <https://github.com/numpy/numpy/pull/16515>`__)
+
+``numpy.typing`` is accessible at runtime
+-----------------------------------------
+The types in ``numpy.typing`` can now be imported at runtime. Code
+like the following will now work:
+
+.. code:: python
+
+ from numpy.typing import ArrayLike
+ x: ArrayLike = [1, 2, 3, 4]
+
+(`gh-16558 <https://github.com/numpy/numpy/pull/16558>`__)
+
+New ``__f2py_numpy_version__`` attribute for f2py generated modules.
+--------------------------------------------------------------------
+Because f2py is released together with NumPy, ``__f2py_numpy_version__``
+provides a way to track the version f2py used to generate the module.
+
+(`gh-16594 <https://github.com/numpy/numpy/pull/16594>`__)
+
+``mypy`` tests can be run via runtests.py
+-----------------------------------------
+Currently running mypy with the NumPy stubs configured requires
+either:
+
+* Installing NumPy
+* Adding the source directory to MYPYPATH and linking to the ``mypy.ini``
+
+Both options are somewhat inconvenient, so add a ``--mypy`` option to runtests
+that handles setting things up for you. This will also be useful in the future
+for any typing codegen since it will ensure the project is built before type
+checking.
+
+(`gh-17123 <https://github.com/numpy/numpy/pull/17123>`__)
+
+Negation of user defined BLAS/LAPACK detection order
+----------------------------------------------------
+`~numpy.distutils` allows negation of libraries when determining BLAS/LAPACK
+libraries.
+This may be used to remove an item from the library resolution phase, i.e.
+to disallow NetLIB libraries one could do:
+
+.. code:: bash
+
+ NPY_BLAS_ORDER='^blas' NPY_LAPACK_ORDER='^lapack' python setup.py build
+
+That will use any of the accelerated libraries instead.
+
+(`gh-17219 <https://github.com/numpy/numpy/pull/17219>`__)
+
+Allow passing optimizations arguments to asv build
+--------------------------------------------------
+It is now possible to pass ``-j``, ``--cpu-baseline``, ``--cpu-dispatch`` and
+``--disable-optimization`` flags to ASV build when the ``--bench-compare``
+argument is used.
+
+(`gh-17284 <https://github.com/numpy/numpy/pull/17284>`__)
+
+The NVIDIA HPC SDK nvfortran compiler is now supported
+------------------------------------------------------
+Support for the nvfortran compiler, a version of pgfortran, has been added.
+
+(`gh-17344 <https://github.com/numpy/numpy/pull/17344>`__)
+
+``dtype`` option for ``cov`` and ``corrcoef``
+---------------------------------------------
+The ``dtype`` option is now available for `numpy.cov` and `numpy.corrcoef`.
+It specifies which data-type the returned result should have.
+By default the functions still return a `numpy.float64` result.
+
+(`gh-17456 <https://github.com/numpy/numpy/pull/17456>`__)
+
+
+Improvements
+============
+
+Improved string representation for polynomials (``__str__``)
+------------------------------------------------------------
+
+The string representation (``__str__``) of all six polynomial types in
+`numpy.polynomial` has been updated to give the polynomial as a mathematical
+expression instead of an array of coefficients. Two package-wide formats for
+the polynomial expressions are available - one using Unicode characters for
+superscripts and subscripts, and another using only ASCII characters.
+
+(`gh-15666 <https://github.com/numpy/numpy/pull/15666>`__)
+
+Remove the Accelerate library as a candidate LAPACK library
+-----------------------------------------------------------
+Apple no longer supports Accelerate. Remove it.
+
+(`gh-15759 <https://github.com/numpy/numpy/pull/15759>`__)
+
+Object arrays containing multi-line objects have a more readable ``repr``
+-------------------------------------------------------------------------
+If elements of an object array have a ``repr`` containing new lines, then the
+wrapped lines will be aligned by column. Notably, this improves the ``repr`` of
+nested arrays::
+
+ >>> np.array([np.eye(2), np.eye(3)], dtype=object)
+ array([array([[1., 0.],
+ [0., 1.]]),
+ array([[1., 0., 0.],
+ [0., 1., 0.],
+ [0., 0., 1.]])], dtype=object)
+
+(`gh-15997 <https://github.com/numpy/numpy/pull/15997>`__)
+
+Concatenate supports providing an output dtype
+----------------------------------------------
+Support was added to `~numpy.concatenate` to provide
+an output ``dtype`` and ``casting`` using keyword
+arguments. The ``dtype`` argument cannot be provided
+in conjunction with the ``out`` one.
+
+(`gh-16134 <https://github.com/numpy/numpy/pull/16134>`__)
+
+Thread safe f2py callback functions
+-----------------------------------
+
+Callback functions in f2py are now thread safe.
+
+(`gh-16519 <https://github.com/numpy/numpy/pull/16519>`__)
+
+`numpy.core.records.fromfile` now supports file-like objects
+------------------------------------------------------------
+`numpy.rec.fromfile` can now use file-like objects, for instance
+:py:class:`io.BytesIO`
+
+(`gh-16675 <https://github.com/numpy/numpy/pull/16675>`__)
+
+RPATH support on AIX added to distutils
+---------------------------------------
+This allows SciPy to be built on AIX.
+
+(`gh-16710 <https://github.com/numpy/numpy/pull/16710>`__)
+
+Use f90 compiler specified by the command line args
+---------------------------------------------------
+
+The compiler command selection for Fortran Portland Group Compiler is changed
+in `numpy.distutils.fcompiler`. This only affects the linking command. This
+forces the use of the executable provided by the command line option (if
+provided) instead of the pgfortran executable. If no executable is provided to
+the command line option it defaults to the pgf90 executable, wich is an alias
+for pgfortran according to the PGI documentation.
+
+(`gh-16730 <https://github.com/numpy/numpy/pull/16730>`__)
+
+Add NumPy declarations for Cython 3.0 and later
+-----------------------------------------------
+
+The pxd declarations for Cython 3.0 were improved to avoid using deprecated
+NumPy C-API features. Extension modules built with Cython 3.0+ that use NumPy
+can now set the C macro ``NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION`` to avoid
+C compiler warnings about deprecated API usage.
+
+(`gh-16986 <https://github.com/numpy/numpy/pull/16986>`__)
+
+Make the window functions exactly symmetric
+-------------------------------------------
+Make sure the window functions provided by NumPy are symmetric. There were
+previously small deviations from symmetry due to numerical precision that are
+now avoided by better arrangement of the computation.
+
+(`gh-17195 <https://github.com/numpy/numpy/pull/17195>`__)
+
+
+Performance improvements and changes
+====================================
+
+Enable multi-platform SIMD compiler optimizations
+-------------------------------------------------
+
+A series of improvements for NumPy infrastructure to pave the way to
+**NEP-38**, that can be summarized as follow:
+
+- **New Build Arguments**
+
+ - ``--cpu-baseline`` to specify the minimal set of required
+ optimizations, default value is ``min`` which provides the minimum
+ CPU features that can safely run on a wide range of users
+ platforms.
+
+ - ``--cpu-dispatch`` to specify the dispatched set of additional
+ optimizations, default value is ``max -xop -fma4`` which enables
+ all CPU features, except for AMD legacy features.
+
+ - ``--disable-optimization`` to explicitly disable the whole new
+ improvements, It also adds a new **C** compiler #definition
+ called ``NPY_DISABLE_OPTIMIZATION`` which it can be used as
+ guard for any SIMD code.
+
+- **Advanced CPU dispatcher**
+
+ A flexible cross-architecture CPU dispatcher built on the top of
+ Python/Numpy distutils, support all common compilers with a wide range of
+ CPU features.
+
+ The new dispatcher requires a special file extension ``*.dispatch.c`` to
+ mark the dispatch-able **C** sources. These sources have the ability to be
+ compiled multiple times so that each compilation process represents certain
+ CPU features and provides different #definitions and flags that affect the
+ code paths.
+
+- **New auto-generated C header ``core/src/common/_cpu_dispatch.h``**
+
+ This header is generated by the distutils module ``ccompiler_opt``, and
+ contains all the #definitions and headers of instruction sets, that had been
+ configured through command arguments '--cpu-baseline' and '--cpu-dispatch'.
+
+- **New C header ``core/src/common/npy_cpu_dispatch.h``**
+
+ This header contains all utilities that required for the whole CPU
+ dispatching process, it also can be considered as a bridge linking the new
+ infrastructure work with NumPy CPU runtime detection.
+
+- **Add new attributes to NumPy umath module(Python level)**
+
+ - ``__cpu_baseline__`` a list contains the minimal set of required
+ optimizations that supported by the compiler and platform according to the
+ specified values to command argument '--cpu-baseline'.
+
+ - ``__cpu_dispatch__`` a list contains the dispatched set of additional
+ optimizations that supported by the compiler and platform according to the
+ specified values to command argument '--cpu-dispatch'.
+
+- **Print the supported CPU features during the run of PytestTester**
+
+(`gh-13516 <https://github.com/numpy/numpy/pull/13516>`__)
+
+
+Changes
+=======
+
+Changed behavior of ``divmod(1., 0.)`` and related functions
+------------------------------------------------------------
+The changes also assure that different compiler versions have the same behavior
+for nan or inf usages in these operations. This was previously compiler
+dependent, we now force the invalid and divide by zero flags, making the
+results the same across compilers. For example, gcc-5, gcc-8, or gcc-9 now
+result in the same behavior. The changes are tabulated below:
+
+.. list-table:: Summary of New Behavior
+ :widths: auto
+ :header-rows: 1
+
+ * - Operator
+ - Old Warning
+ - New Warning
+ - Old Result
+ - New Result
+ - Works on MacOS
+ * - np.divmod(1.0, 0.0)
+ - Invalid
+ - Invalid and Dividebyzero
+ - nan, nan
+ - inf, nan
+ - Yes
+ * - np.fmod(1.0, 0.0)
+ - Invalid
+ - Invalid
+ - nan
+ - nan
+ - No? Yes
+ * - np.floor_divide(1.0, 0.0)
+ - Invalid
+ - Dividebyzero
+ - nan
+ - inf
+ - Yes
+ * - np.remainder(1.0, 0.0)
+ - Invalid
+ - Invalid
+ - nan
+ - nan
+ - Yes
+
+(`gh-16161 <https://github.com/numpy/numpy/pull/16161>`__)
+
+``np.linspace`` on integers now uses floor
+------------------------------------------
+When using a ``int`` dtype in `numpy.linspace`, previously float values would
+be rounded towards zero. Now `numpy.floor` is used instead, which rounds toward
+``-inf``. This changes the results for negative values. For example, the
+following would previously give::
+
+ >>> np.linspace(-3, 1, 8, dtype=int)
+ array([-3, -2, -1, -1, 0, 0, 0, 1])
+
+and now results in::
+
+ >>> np.linspace(-3, 1, 8, dtype=int)
+ array([-3, -3, -2, -2, -1, -1, 0, 1])
+
+The former result can still be obtained with::
+
+ >>> np.linspace(-3, 1, 8).astype(int)
+ array([-3, -2, -1, -1, 0, 0, 0, 1])
+
+(`gh-16841 <https://github.com/numpy/numpy/pull/16841>`__)
+
This is the first NumPy release which is compatible with Python 3. Support for
Python 3 and Python 2 is done from a single code base. Extensive notes on
changes can be found at
-`<http://projects.scipy.org/numpy/browser/trunk/doc/Py3K.txt>`_.
+`<https://web.archive.org/web/20100814160313/http://projects.scipy.org/numpy/browser/trunk/doc/Py3K.txt>`_.
Note that the Numpy testing framework relies on nose, which does not have a
Python 3 compatible release yet. A working Python 3 branch of nose can be found
-at `<http://bitbucket.org/jpellerin/nose3/>`_ however.
+at `<https://web.archive.org/web/20100817112505/http://bitbucket.org/jpellerin/nose3/>`_ however.
Porting of SciPy to Python 3 is expected to be completed soon.
NumPy gives you an enormous range of fast and efficient ways of creating arrays
and manipulating numerical data inside them. While a Python list can contain
different data types within a single list, all of the elements in a NumPy array
-should be homogenous. The mathematical operations that are meant to be performed
-on arrays would be extremely inefficient if the arrays weren't homogenous.
+should be homogeneous. The mathematical operations that are meant to be performed
+on arrays would be extremely inefficient if the arrays weren't homogeneous.
**Why use NumPy?**
Transposing and reshaping a matrix
----------------------------------
-*This section covers* ``arr.reshape()``, ``arr.transpose()``, ``arr.T()``
+*This section covers* ``arr.reshape()``, ``arr.transpose()``, ``arr.T``
-----
.. image:: images/np_reshape.png
-You can also use ``.transpose`` to reverse or change the axes of an array
+You can also use ``.transpose()`` to reverse or change the axes of an array
according to the values you specify.
If you start with this array::
[1, 4],
[2, 5]])
+You can also use ``arr.T``::
+
+ >>> arr.T
+ array([[0, 3],
+ [1, 4],
+ [2, 5]])
+
To learn more about transposing and reshaping arrays, see `transpose` and
`reshape`.
How to reverse an array
-----------------------
-*This section covers* ``np.flip``
+*This section covers* ``np.flip()``
-----
NumPy's ``np.flip()`` function allows you to flip, or reverse, the contents of
-an array along an axis. When using ``np.flip``, specify the array you would like
+an array along an axis. When using ``np.flip()``, specify the array you would like
to reverse and the axis. If you don't specify the axis, NumPy will reverse the
contents along all of the axes of your input array.
-----------------------------
.. save a csv
-
+
>>> with open('music.csv', 'w') as fid:
... n = fid.write('Artist,Genre,Listeners,Plays\n')
... n = fid.write('Billie Holiday,Jazz,1300000,27000000\n')
... n = fid.write('Jimmie Hendrix,Rock,2700000,70000000\n')
... n = fid.write('Miles Davis,Jazz,1500000,48000000\n')
... n = fid.write('SIA,Pop,2000000,74000000\n')
-
+
It's simple to read in a CSV that contains existing information. The best and
easiest way to do this is to use
-`Pandas <https://pandas.pydata.org/getpandas.html>`_. ::
+`Pandas <https://pandas.pydata.org>`_. ::
>>> import pandas as pd
:ref:`array-broadcasting-in-numpy`
An introduction to the concepts discussed here
-.. automodule:: numpy.doc.broadcasting
+.. note::
+ See `this article
+ <https://numpy.org/devdocs/user/theory.broadcasting.html>`_
+ for illustrations of broadcasting concepts.
+
+
+The term broadcasting describes how numpy treats arrays with different
+shapes during arithmetic operations. Subject to certain constraints,
+the smaller array is "broadcast" across the larger array so that they
+have compatible shapes. Broadcasting provides a means of vectorizing
+array operations so that looping occurs in C instead of Python. It does
+this without making needless copies of data and usually leads to
+efficient algorithm implementations. There are, however, cases where
+broadcasting is a bad idea because it leads to inefficient use of memory
+that slows computation.
+
+NumPy operations are usually done on pairs of arrays on an
+element-by-element basis. In the simplest case, the two arrays must
+have exactly the same shape, as in the following example:
+
+ >>> a = np.array([1.0, 2.0, 3.0])
+ >>> b = np.array([2.0, 2.0, 2.0])
+ >>> a * b
+ array([ 2., 4., 6.])
+
+NumPy's broadcasting rule relaxes this constraint when the arrays'
+shapes meet certain constraints. The simplest broadcasting example occurs
+when an array and a scalar value are combined in an operation:
+
+>>> a = np.array([1.0, 2.0, 3.0])
+>>> b = 2.0
+>>> a * b
+array([ 2., 4., 6.])
+
+The result is equivalent to the previous example where ``b`` was an array.
+We can think of the scalar ``b`` being *stretched* during the arithmetic
+operation into an array with the same shape as ``a``. The new elements in
+``b`` are simply copies of the original scalar. The stretching analogy is
+only conceptual. NumPy is smart enough to use the original scalar value
+without actually making copies so that broadcasting operations are as
+memory and computationally efficient as possible.
+
+The code in the second example is more efficient than that in the first
+because broadcasting moves less memory around during the multiplication
+(``b`` is a scalar rather than an array).
+
+General Broadcasting Rules
+==========================
+When operating on two arrays, NumPy compares their shapes element-wise.
+It starts with the trailing (i.e. rightmost) dimensions and works its
+way left. Two dimensions are compatible when
+
+1) they are equal, or
+2) one of them is 1
+
+If these conditions are not met, a
+``ValueError: operands could not be broadcast together`` exception is
+thrown, indicating that the arrays have incompatible shapes. The size of
+the resulting array is the size that is not 1 along each axis of the inputs.
+
+Arrays do not need to have the same *number* of dimensions. For example,
+if you have a ``256x256x3`` array of RGB values, and you want to scale
+each color in the image by a different value, you can multiply the image
+by a one-dimensional array with 3 values. Lining up the sizes of the
+trailing axes of these arrays according to the broadcast rules, shows that
+they are compatible::
+
+ Image (3d array): 256 x 256 x 3
+ Scale (1d array): 3
+ Result (3d array): 256 x 256 x 3
+
+When either of the dimensions compared is one, the other is
+used. In other words, dimensions with size 1 are stretched or "copied"
+to match the other.
+
+In the following example, both the ``A`` and ``B`` arrays have axes with
+length one that are expanded to a larger size during the broadcast
+operation::
+
+ A (4d array): 8 x 1 x 6 x 1
+ B (3d array): 7 x 1 x 5
+ Result (4d array): 8 x 7 x 6 x 5
+
+Here are some more examples::
+
+ A (2d array): 5 x 4
+ B (1d array): 1
+ Result (2d array): 5 x 4
+
+ A (2d array): 5 x 4
+ B (1d array): 4
+ Result (2d array): 5 x 4
+
+ A (3d array): 15 x 3 x 5
+ B (3d array): 15 x 1 x 5
+ Result (3d array): 15 x 3 x 5
+
+ A (3d array): 15 x 3 x 5
+ B (2d array): 3 x 5
+ Result (3d array): 15 x 3 x 5
+
+ A (3d array): 15 x 3 x 5
+ B (2d array): 3 x 1
+ Result (3d array): 15 x 3 x 5
+
+Here are examples of shapes that do not broadcast::
+
+ A (1d array): 3
+ B (1d array): 4 # trailing dimensions do not match
+
+ A (2d array): 2 x 1
+ B (3d array): 8 x 4 x 3 # second from last dimensions mismatched
+
+An example of broadcasting in practice::
+
+ >>> x = np.arange(4)
+ >>> xx = x.reshape(4,1)
+ >>> y = np.ones(5)
+ >>> z = np.ones((3,4))
+
+ >>> x.shape
+ (4,)
+
+ >>> y.shape
+ (5,)
+
+ >>> x + y
+ ValueError: operands could not be broadcast together with shapes (4,) (5,)
+
+ >>> xx.shape
+ (4, 1)
+
+ >>> y.shape
+ (5,)
+
+ >>> (xx + y).shape
+ (4, 5)
+
+ >>> xx + y
+ array([[ 1., 1., 1., 1., 1.],
+ [ 2., 2., 2., 2., 2.],
+ [ 3., 3., 3., 3., 3.],
+ [ 4., 4., 4., 4., 4.]])
+
+ >>> x.shape
+ (4,)
+
+ >>> z.shape
+ (3, 4)
+
+ >>> (x + z).shape
+ (3, 4)
+
+ >>> x + z
+ array([[ 1., 2., 3., 4.],
+ [ 1., 2., 3., 4.],
+ [ 1., 2., 3., 4.]])
+
+Broadcasting provides a convenient way of taking the outer product (or
+any other outer operation) of two arrays. The following example shows an
+outer addition operation of two 1-d arrays::
+
+ >>> a = np.array([0.0, 10.0, 20.0, 30.0])
+ >>> b = np.array([1.0, 2.0, 3.0])
+ >>> a[:, np.newaxis] + b
+ array([[ 1., 2., 3.],
+ [ 11., 12., 13.],
+ [ 21., 22., 23.],
+ [ 31., 32., 33.]])
+
+Here the ``newaxis`` index operator inserts a new axis into ``a``,
+making it a two-dimensional ``4x1`` array. Combining the ``4x1`` array
+with ``b``, which has shape ``(3,)``, yields a ``4x3`` array.
+
+
Byte-swapping
*************
-.. automodule:: numpy.doc.byteswapping
+Introduction to byte ordering and ndarrays
+==========================================
+
+The ``ndarray`` is an object that provide a python array interface to data
+in memory.
+
+It often happens that the memory that you want to view with an array is
+not of the same byte ordering as the computer on which you are running
+Python.
+
+For example, I might be working on a computer with a little-endian CPU -
+such as an Intel Pentium, but I have loaded some data from a file
+written by a computer that is big-endian. Let's say I have loaded 4
+bytes from a file written by a Sun (big-endian) computer. I know that
+these 4 bytes represent two 16-bit integers. On a big-endian machine, a
+two-byte integer is stored with the Most Significant Byte (MSB) first,
+and then the Least Significant Byte (LSB). Thus the bytes are, in memory order:
+
+#. MSB integer 1
+#. LSB integer 1
+#. MSB integer 2
+#. LSB integer 2
+
+Let's say the two integers were in fact 1 and 770. Because 770 = 256 *
+3 + 2, the 4 bytes in memory would contain respectively: 0, 1, 3, 2.
+The bytes I have loaded from the file would have these contents:
+
+>>> big_end_buffer = bytearray([0,1,3,2])
+>>> big_end_buffer
+bytearray(b'\\x00\\x01\\x03\\x02')
+
+We might want to use an ``ndarray`` to access these integers. In that
+case, we can create an array around this memory, and tell numpy that
+there are two integers, and that they are 16 bit and big-endian:
+
+>>> import numpy as np
+>>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_buffer)
+>>> big_end_arr[0]
+1
+>>> big_end_arr[1]
+770
+
+Note the array ``dtype`` above of ``>i2``. The ``>`` means 'big-endian'
+(``<`` is little-endian) and ``i2`` means 'signed 2-byte integer'. For
+example, if our data represented a single unsigned 4-byte little-endian
+integer, the dtype string would be ``<u4``.
+
+In fact, why don't we try that?
+
+>>> little_end_u4 = np.ndarray(shape=(1,),dtype='<u4', buffer=big_end_buffer)
+>>> little_end_u4[0] == 1 * 256**1 + 3 * 256**2 + 2 * 256**3
+True
+
+Returning to our ``big_end_arr`` - in this case our underlying data is
+big-endian (data endianness) and we've set the dtype to match (the dtype
+is also big-endian). However, sometimes you need to flip these around.
+
+.. warning::
+
+ Scalars currently do not include byte order information, so extracting
+ a scalar from an array will return an integer in native byte order.
+ Hence:
+
+ >>> big_end_arr[0].dtype.byteorder == little_end_u4[0].dtype.byteorder
+ True
+
+Changing byte ordering
+======================
+
+As you can imagine from the introduction, there are two ways you can
+affect the relationship between the byte ordering of the array and the
+underlying memory it is looking at:
+
+* Change the byte-ordering information in the array dtype so that it
+ interprets the underlying data as being in a different byte order.
+ This is the role of ``arr.newbyteorder()``
+* Change the byte-ordering of the underlying data, leaving the dtype
+ interpretation as it was. This is what ``arr.byteswap()`` does.
+
+The common situations in which you need to change byte ordering are:
+
+#. Your data and dtype endianness don't match, and you want to change
+ the dtype so that it matches the data.
+#. Your data and dtype endianness don't match, and you want to swap the
+ data so that they match the dtype
+#. Your data and dtype endianness match, but you want the data swapped
+ and the dtype to reflect this
+
+Data and dtype endianness don't match, change dtype to match data
+-----------------------------------------------------------------
+
+We make something where they don't match:
+
+>>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='<i2', buffer=big_end_buffer)
+>>> wrong_end_dtype_arr[0]
+256
+
+The obvious fix for this situation is to change the dtype so it gives
+the correct endianness:
+
+>>> fixed_end_dtype_arr = wrong_end_dtype_arr.newbyteorder()
+>>> fixed_end_dtype_arr[0]
+1
+
+Note the array has not changed in memory:
+
+>>> fixed_end_dtype_arr.tobytes() == big_end_buffer
+True
+
+Data and type endianness don't match, change data to match dtype
+----------------------------------------------------------------
+
+You might want to do this if you need the data in memory to be a certain
+ordering. For example you might be writing the memory out to a file
+that needs a certain byte ordering.
+
+>>> fixed_end_mem_arr = wrong_end_dtype_arr.byteswap()
+>>> fixed_end_mem_arr[0]
+1
+
+Now the array *has* changed in memory:
+
+>>> fixed_end_mem_arr.tobytes() == big_end_buffer
+False
+
+Data and dtype endianness match, swap data and dtype
+----------------------------------------------------
+
+You may have a correctly specified array dtype, but you need the array
+to have the opposite byte order in memory, and you want the dtype to
+match so the array values make sense. In this case you just do both of
+the previous operations:
+
+>>> swapped_end_arr = big_end_arr.byteswap().newbyteorder()
+>>> swapped_end_arr[0]
+1
+>>> swapped_end_arr.tobytes() == big_end_buffer
+False
+
+An easier way of casting the data to a specific dtype and byte ordering
+can be achieved with the ndarray astype method:
+
+>>> swapped_end_arr = big_end_arr.astype('<i2')
+>>> swapped_end_arr[0]
+1
+>>> swapped_end_arr.tobytes() == big_end_buffer
+False
+
+
.. seealso:: :ref:`Array creation routines <routines.array-creation>`
-.. automodule:: numpy.doc.creation
+Introduction
+============
+
+There are 5 general mechanisms for creating arrays:
+
+1) Conversion from other Python structures (e.g., lists, tuples)
+2) Intrinsic numpy array creation objects (e.g., arange, ones, zeros,
+ etc.)
+3) Reading arrays from disk, either from standard or custom formats
+4) Creating arrays from raw bytes through the use of strings or buffers
+5) Use of special library functions (e.g., random)
+
+This section will not cover means of replicating, joining, or otherwise
+expanding or mutating existing arrays. Nor will it cover creating object
+arrays or structured arrays. Both of those are covered in their own sections.
+
+Converting Python array_like Objects to NumPy Arrays
+====================================================
+
+In general, numerical data arranged in an array-like structure in Python can
+be converted to arrays through the use of the array() function. The most
+obvious examples are lists and tuples. See the documentation for array() for
+details for its use. Some objects may support the array-protocol and allow
+conversion to arrays this way. A simple way to find out if the object can be
+converted to a numpy array using array() is simply to try it interactively and
+see if it works! (The Python Way).
+
+Examples: ::
+
+ >>> x = np.array([2,3,1,0])
+ >>> x = np.array([2, 3, 1, 0])
+ >>> x = np.array([[1,2.0],[0,0],(1+1j,3.)]) # note mix of tuple and lists,
+ and types
+ >>> x = np.array([[ 1.+0.j, 2.+0.j], [ 0.+0.j, 0.+0.j], [ 1.+1.j, 3.+0.j]])
+
+Intrinsic NumPy Array Creation
+==============================
+
+NumPy has built-in functions for creating arrays from scratch:
+
+zeros(shape) will create an array filled with 0 values with the specified
+shape. The default dtype is float64. ::
+
+ >>> np.zeros((2, 3))
+ array([[ 0., 0., 0.], [ 0., 0., 0.]])
+
+ones(shape) will create an array filled with 1 values. It is identical to
+zeros in all other respects.
+
+arange() will create arrays with regularly incrementing values. Check the
+docstring for complete information on the various ways it can be used. A few
+examples will be given here: ::
+
+ >>> np.arange(10)
+ array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+ >>> np.arange(2, 10, dtype=float)
+ array([ 2., 3., 4., 5., 6., 7., 8., 9.])
+ >>> np.arange(2, 3, 0.1)
+ array([ 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9])
+
+Note that there are some subtleties regarding the last usage that the user
+should be aware of that are described in the arange docstring.
+
+linspace() will create arrays with a specified number of elements, and
+spaced equally between the specified beginning and end values. For
+example: ::
+
+ >>> np.linspace(1., 4., 6)
+ array([ 1. , 1.6, 2.2, 2.8, 3.4, 4. ])
+
+The advantage of this creation function is that one can guarantee the
+number of elements and the starting and end point, which arange()
+generally will not do for arbitrary start, stop, and step values.
+
+indices() will create a set of arrays (stacked as a one-higher dimensioned
+array), one per dimension with each representing variation in that dimension.
+An example illustrates much better than a verbal description: ::
+
+ >>> np.indices((3,3))
+ array([[[0, 0, 0], [1, 1, 1], [2, 2, 2]], [[0, 1, 2], [0, 1, 2], [0, 1, 2]]])
+
+This is particularly useful for evaluating functions of multiple dimensions on
+a regular grid.
+
+Reading Arrays From Disk
+========================
+
+This is presumably the most common case of large array creation. The details,
+of course, depend greatly on the format of data on disk and so this section
+can only give general pointers on how to handle various formats.
+
+Standard Binary Formats
+-----------------------
+
+Various fields have standard formats for array data. The following lists the
+ones with known python libraries to read them and return numpy arrays (there
+may be others for which it is possible to read and convert to numpy arrays so
+check the last section as well)
+::
+
+ HDF5: h5py
+ FITS: Astropy
+
+Examples of formats that cannot be read directly but for which it is not hard to
+convert are those formats supported by libraries like PIL (able to read and
+write many image formats such as jpg, png, etc).
+
+Common ASCII Formats
+------------------------
+
+Comma Separated Value files (CSV) are widely used (and an export and import
+option for programs like Excel). There are a number of ways of reading these
+files in Python. There are CSV functions in Python and functions in pylab
+(part of matplotlib).
+
+More generic ascii files can be read using the io package in scipy.
+
+Custom Binary Formats
+---------------------
+
+There are a variety of approaches one can use. If the file has a relatively
+simple format then one can write a simple I/O library and use the numpy
+fromfile() function and .tofile() method to read and write numpy arrays
+directly (mind your byteorder though!) If a good C or C++ library exists that
+read the data, one can wrap that library with a variety of techniques though
+that certainly is much more work and requires significantly more advanced
+knowledge to interface with C or C++.
+
+Use of Special Libraries
+------------------------
+
+There are libraries that can be used to generate arrays for special purposes
+and it isn't possible to enumerate all of them. The most common uses are use
+of the many array generation functions in random that can generate arrays of
+random values, and some utility functions to generate special matrices (e.g.
+diagonal).
+
+
Writing custom array containers
*******************************
-.. automodule:: numpy.doc.dispatch
+Numpy's dispatch mechanism, introduced in numpy version v1.16 is the
+recommended approach for writing custom N-dimensional array containers that are
+compatible with the numpy API and provide custom implementations of numpy
+functionality. Applications include `dask <http://dask.pydata.org>`_ arrays, an
+N-dimensional array distributed across multiple nodes, and `cupy
+<https://docs-cupy.chainer.org/en/stable/>`_ arrays, an N-dimensional array on
+a GPU.
+
+To get a feel for writing custom array containers, we'll begin with a simple
+example that has rather narrow utility but illustrates the concepts involved.
+
+>>> import numpy as np
+>>> class DiagonalArray:
+... def __init__(self, N, value):
+... self._N = N
+... self._i = value
+... def __repr__(self):
+... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
+... def __array__(self):
+... return self._i * np.eye(self._N)
+
+Our custom array can be instantiated like:
+
+>>> arr = DiagonalArray(5, 1)
+>>> arr
+DiagonalArray(N=5, value=1)
+
+We can convert to a numpy array using :func:`numpy.array` or
+:func:`numpy.asarray`, which will call its ``__array__`` method to obtain a
+standard ``numpy.ndarray``.
+
+>>> np.asarray(arr)
+array([[1., 0., 0., 0., 0.],
+ [0., 1., 0., 0., 0.],
+ [0., 0., 1., 0., 0.],
+ [0., 0., 0., 1., 0.],
+ [0., 0., 0., 0., 1.]])
+
+If we operate on ``arr`` with a numpy function, numpy will again use the
+``__array__`` interface to convert it to an array and then apply the function
+in the usual way.
+
+>>> np.multiply(arr, 2)
+array([[2., 0., 0., 0., 0.],
+ [0., 2., 0., 0., 0.],
+ [0., 0., 2., 0., 0.],
+ [0., 0., 0., 2., 0.],
+ [0., 0., 0., 0., 2.]])
+
+
+Notice that the return type is a standard ``numpy.ndarray``.
+
+>>> type(arr)
+numpy.ndarray
+
+How can we pass our custom array type through this function? Numpy allows a
+class to indicate that it would like to handle computations in a custom-defined
+way through the interfaces ``__array_ufunc__`` and ``__array_function__``. Let's
+take one at a time, starting with ``_array_ufunc__``. This method covers
+:ref:`ufuncs`, a class of functions that includes, for example,
+:func:`numpy.multiply` and :func:`numpy.sin`.
+
+The ``__array_ufunc__`` receives:
+
+- ``ufunc``, a function like ``numpy.multiply``
+- ``method``, a string, differentiating between ``numpy.multiply(...)`` and
+ variants like ``numpy.multiply.outer``, ``numpy.multiply.accumulate``, and so
+ on. For the common case, ``numpy.multiply(...)``, ``method == '__call__'``.
+- ``inputs``, which could be a mixture of different types
+- ``kwargs``, keyword arguments passed to the function
+
+For this example we will only handle the method ``__call__``
+
+>>> from numbers import Number
+>>> class DiagonalArray:
+... def __init__(self, N, value):
+... self._N = N
+... self._i = value
+... def __repr__(self):
+... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
+... def __array__(self):
+... return self._i * np.eye(self._N)
+... def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
+... if method == '__call__':
+... N = None
+... scalars = []
+... for input in inputs:
+... if isinstance(input, Number):
+... scalars.append(input)
+... elif isinstance(input, self.__class__):
+... scalars.append(input._i)
+... if N is not None:
+... if N != self._N:
+... raise TypeError("inconsistent sizes")
+... else:
+... N = self._N
+... else:
+... return NotImplemented
+... return self.__class__(N, ufunc(*scalars, **kwargs))
+... else:
+... return NotImplemented
+
+Now our custom array type passes through numpy functions.
+
+>>> arr = DiagonalArray(5, 1)
+>>> np.multiply(arr, 3)
+DiagonalArray(N=5, value=3)
+>>> np.add(arr, 3)
+DiagonalArray(N=5, value=4)
+>>> np.sin(arr)
+DiagonalArray(N=5, value=0.8414709848078965)
+
+At this point ``arr + 3`` does not work.
+
+>>> arr + 3
+TypeError: unsupported operand type(s) for *: 'DiagonalArray' and 'int'
+
+To support it, we need to define the Python interfaces ``__add__``, ``__lt__``,
+and so on to dispatch to the corresponding ufunc. We can achieve this
+conveniently by inheriting from the mixin
+:class:`~numpy.lib.mixins.NDArrayOperatorsMixin`.
+
+>>> import numpy.lib.mixins
+>>> class DiagonalArray(numpy.lib.mixins.NDArrayOperatorsMixin):
+... def __init__(self, N, value):
+... self._N = N
+... self._i = value
+... def __repr__(self):
+... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
+... def __array__(self):
+... return self._i * np.eye(self._N)
+... def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
+... if method == '__call__':
+... N = None
+... scalars = []
+... for input in inputs:
+... if isinstance(input, Number):
+... scalars.append(input)
+... elif isinstance(input, self.__class__):
+... scalars.append(input._i)
+... if N is not None:
+... if N != self._N:
+... raise TypeError("inconsistent sizes")
+... else:
+... N = self._N
+... else:
+... return NotImplemented
+... return self.__class__(N, ufunc(*scalars, **kwargs))
+... else:
+... return NotImplemented
+
+>>> arr = DiagonalArray(5, 1)
+>>> arr + 3
+DiagonalArray(N=5, value=4)
+>>> arr > 0
+DiagonalArray(N=5, value=True)
+
+Now let's tackle ``__array_function__``. We'll create dict that maps numpy
+functions to our custom variants.
+
+>>> HANDLED_FUNCTIONS = {}
+>>> class DiagonalArray(numpy.lib.mixins.NDArrayOperatorsMixin):
+... def __init__(self, N, value):
+... self._N = N
+... self._i = value
+... def __repr__(self):
+... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
+... def __array__(self):
+... return self._i * np.eye(self._N)
+... def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
+... if method == '__call__':
+... N = None
+... scalars = []
+... for input in inputs:
+... # In this case we accept only scalar numbers or DiagonalArrays.
+... if isinstance(input, Number):
+... scalars.append(input)
+... elif isinstance(input, self.__class__):
+... scalars.append(input._i)
+... if N is not None:
+... if N != self._N:
+... raise TypeError("inconsistent sizes")
+... else:
+... N = self._N
+... else:
+... return NotImplemented
+... return self.__class__(N, ufunc(*scalars, **kwargs))
+... else:
+... return NotImplemented
+... def __array_function__(self, func, types, args, kwargs):
+... if func not in HANDLED_FUNCTIONS:
+... return NotImplemented
+... # Note: this allows subclasses that don't override
+... # __array_function__ to handle DiagonalArray objects.
+... if not all(issubclass(t, self.__class__) for t in types):
+... return NotImplemented
+... return HANDLED_FUNCTIONS[func](*args, **kwargs)
+...
+
+A convenient pattern is to define a decorator ``implements`` that can be used
+to add functions to ``HANDLED_FUNCTIONS``.
+
+>>> def implements(np_function):
+... "Register an __array_function__ implementation for DiagonalArray objects."
+... def decorator(func):
+... HANDLED_FUNCTIONS[np_function] = func
+... return func
+... return decorator
+...
+
+Now we write implementations of numpy functions for ``DiagonalArray``.
+For completeness, to support the usage ``arr.sum()`` add a method ``sum`` that
+calls ``numpy.sum(self)``, and the same for ``mean``.
+
+>>> @implements(np.sum)
+... def sum(arr):
+... "Implementation of np.sum for DiagonalArray objects"
+... return arr._i * arr._N
+...
+>>> @implements(np.mean)
+... def mean(arr):
+... "Implementation of np.mean for DiagonalArray objects"
+... return arr._i / arr._N
+...
+>>> arr = DiagonalArray(5, 1)
+>>> np.sum(arr)
+5
+>>> np.mean(arr)
+0.2
+
+If the user tries to use any numpy functions not included in
+``HANDLED_FUNCTIONS``, a ``TypeError`` will be raised by numpy, indicating that
+this operation is not supported. For example, concatenating two
+``DiagonalArrays`` does not produce another diagonal array, so it is not
+supported.
+
+>>> np.concatenate([arr, arr])
+TypeError: no implementation found for 'numpy.concatenate' on types that implement __array_function__: [<class '__main__.DiagonalArray'>]
+
+Additionally, our implementations of ``sum`` and ``mean`` do not accept the
+optional arguments that numpy's implementation does.
+
+>>> np.sum(arr, axis=0)
+TypeError: sum() got an unexpected keyword argument 'axis'
+
+The user always has the option of converting to a normal ``numpy.ndarray`` with
+:func:`numpy.asarray` and using standard numpy from there.
+
+>>> np.concatenate([np.asarray(arr), np.asarray(arr)])
+array([[1., 0., 0., 0., 0.],
+ [0., 1., 0., 0., 0.],
+ [0., 0., 1., 0., 0.],
+ [0., 0., 0., 1., 0.],
+ [0., 0., 0., 0., 1.],
+ [1., 0., 0., 0., 0.],
+ [0., 1., 0., 0., 0.],
+ [0., 0., 1., 0., 0.],
+ [0., 0., 0., 1., 0.],
+ [0., 0., 0., 0., 1.]])
+
+Refer to the `dask source code <https://github.com/dask/dask>`_ and
+`cupy source code <https://github.com/cupy/cupy>`_ for more fully-worked
+examples of custom array containers.
+
+See also :doc:`NEP 18<neps:nep-0018-array-function-protocol>`.
:ref:`Indexing routines <routines.indexing>`
-.. automodule:: numpy.doc.indexing
+Array indexing refers to any use of the square brackets ([]) to index
+array values. There are many options to indexing, which give numpy
+indexing great power, but with power comes some complexity and the
+potential for confusion. This section is just an overview of the
+various options and issues related to indexing. Aside from single
+element indexing, the details on most of these options are to be
+found in related sections.
+
+Assignment vs referencing
+=========================
+
+Most of the following examples show the use of indexing when
+referencing data in an array. The examples work just as well
+when assigning to an array. See the section at the end for
+specific examples and explanations on how assignments work.
+
+Single element indexing
+=======================
+
+Single element indexing for a 1-D array is what one expects. It work
+exactly like that for other standard Python sequences. It is 0-based,
+and accepts negative indices for indexing from the end of the array. ::
+
+ >>> x = np.arange(10)
+ >>> x[2]
+ 2
+ >>> x[-2]
+ 8
+
+Unlike lists and tuples, numpy arrays support multidimensional indexing
+for multidimensional arrays. That means that it is not necessary to
+separate each dimension's index into its own set of square brackets. ::
+
+ >>> x.shape = (2,5) # now x is 2-dimensional
+ >>> x[1,3]
+ 8
+ >>> x[1,-1]
+ 9
+
+Note that if one indexes a multidimensional array with fewer indices
+than dimensions, one gets a subdimensional array. For example: ::
+
+ >>> x[0]
+ array([0, 1, 2, 3, 4])
+
+That is, each index specified selects the array corresponding to the
+rest of the dimensions selected. In the above example, choosing 0
+means that the remaining dimension of length 5 is being left unspecified,
+and that what is returned is an array of that dimensionality and size.
+It must be noted that the returned array is not a copy of the original,
+but points to the same values in memory as does the original array.
+In this case, the 1-D array at the first position (0) is returned.
+So using a single index on the returned array, results in a single
+element being returned. That is: ::
+
+ >>> x[0][2]
+ 2
+
+So note that ``x[0,2] = x[0][2]`` though the second case is more
+inefficient as a new temporary array is created after the first index
+that is subsequently indexed by 2.
+
+Note to those used to IDL or Fortran memory order as it relates to
+indexing. NumPy uses C-order indexing. That means that the last
+index usually represents the most rapidly changing memory location,
+unlike Fortran or IDL, where the first index represents the most
+rapidly changing location in memory. This difference represents a
+great potential for confusion.
+
+Other indexing options
+======================
+
+It is possible to slice and stride arrays to extract arrays of the
+same number of dimensions, but of different sizes than the original.
+The slicing and striding works exactly the same way it does for lists
+and tuples except that they can be applied to multiple dimensions as
+well. A few examples illustrates best: ::
+
+ >>> x = np.arange(10)
+ >>> x[2:5]
+ array([2, 3, 4])
+ >>> x[:-7]
+ array([0, 1, 2])
+ >>> x[1:7:2]
+ array([1, 3, 5])
+ >>> y = np.arange(35).reshape(5,7)
+ >>> y[1:5:2,::3]
+ array([[ 7, 10, 13],
+ [21, 24, 27]])
+
+Note that slices of arrays do not copy the internal array data but
+only produce new views of the original data. This is different from
+list or tuple slicing and an explicit ``copy()`` is recommended if
+the original data is not required anymore.
+
+It is possible to index arrays with other arrays for the purposes of
+selecting lists of values out of arrays into new arrays. There are
+two different ways of accomplishing this. One uses one or more arrays
+of index values. The other involves giving a boolean array of the proper
+shape to indicate the values to be selected. Index arrays are a very
+powerful tool that allow one to avoid looping over individual elements in
+arrays and thus greatly improve performance.
+
+It is possible to use special features to effectively increase the
+number of dimensions in an array through indexing so the resulting
+array acquires the shape needed for use in an expression or with a
+specific function.
+
+Index arrays
+============
+
+NumPy arrays may be indexed with other arrays (or any other sequence-
+like object that can be converted to an array, such as lists, with the
+exception of tuples; see the end of this document for why this is). The
+use of index arrays ranges from simple, straightforward cases to
+complex, hard-to-understand cases. For all cases of index arrays, what
+is returned is a copy of the original data, not a view as one gets for
+slices.
+
+Index arrays must be of integer type. Each value in the array indicates
+which value in the array to use in place of the index. To illustrate: ::
+
+ >>> x = np.arange(10,1,-1)
+ >>> x
+ array([10, 9, 8, 7, 6, 5, 4, 3, 2])
+ >>> x[np.array([3, 3, 1, 8])]
+ array([7, 7, 9, 2])
+
+
+The index array consisting of the values 3, 3, 1 and 8 correspondingly
+create an array of length 4 (same as the index array) where each index
+is replaced by the value the index array has in the array being indexed.
+
+Negative values are permitted and work as they do with single indices
+or slices: ::
+
+ >>> x[np.array([3,3,-3,8])]
+ array([7, 7, 4, 2])
+
+It is an error to have index values out of bounds: ::
+
+ >>> x[np.array([3, 3, 20, 8])]
+ <type 'exceptions.IndexError'>: index 20 out of bounds 0<=index<9
+
+Generally speaking, what is returned when index arrays are used is
+an array with the same shape as the index array, but with the type
+and values of the array being indexed. As an example, we can use a
+multidimensional index array instead: ::
+
+ >>> x[np.array([[1,1],[2,3]])]
+ array([[9, 9],
+ [8, 7]])
+
+Indexing Multi-dimensional arrays
+=================================
+
+Things become more complex when multidimensional arrays are indexed,
+particularly with multidimensional index arrays. These tend to be
+more unusual uses, but they are permitted, and they are useful for some
+problems. We'll start with the simplest multidimensional case (using
+the array y from the previous examples): ::
+
+ >>> y[np.array([0,2,4]), np.array([0,1,2])]
+ array([ 0, 15, 30])
+
+In this case, if the index arrays have a matching shape, and there is
+an index array for each dimension of the array being indexed, the
+resultant array has the same shape as the index arrays, and the values
+correspond to the index set for each position in the index arrays. In
+this example, the first index value is 0 for both index arrays, and
+thus the first value of the resultant array is y[0,0]. The next value
+is y[2,1], and the last is y[4,2].
+
+If the index arrays do not have the same shape, there is an attempt to
+broadcast them to the same shape. If they cannot be broadcast to the
+same shape, an exception is raised: ::
+
+ >>> y[np.array([0,2,4]), np.array([0,1])]
+ <type 'exceptions.ValueError'>: shape mismatch: objects cannot be
+ broadcast to a single shape
+
+The broadcasting mechanism permits index arrays to be combined with
+scalars for other indices. The effect is that the scalar value is used
+for all the corresponding values of the index arrays: ::
+
+ >>> y[np.array([0,2,4]), 1]
+ array([ 1, 15, 29])
+
+Jumping to the next level of complexity, it is possible to only
+partially index an array with index arrays. It takes a bit of thought
+to understand what happens in such cases. For example if we just use
+one index array with y: ::
+
+ >>> y[np.array([0,2,4])]
+ array([[ 0, 1, 2, 3, 4, 5, 6],
+ [14, 15, 16, 17, 18, 19, 20],
+ [28, 29, 30, 31, 32, 33, 34]])
+
+What results is the construction of a new array where each value of
+the index array selects one row from the array being indexed and the
+resultant array has the resulting shape (number of index elements,
+size of row).
+
+An example of where this may be useful is for a color lookup table
+where we want to map the values of an image into RGB triples for
+display. The lookup table could have a shape (nlookup, 3). Indexing
+such an array with an image with shape (ny, nx) with dtype=np.uint8
+(or any integer type so long as values are with the bounds of the
+lookup table) will result in an array of shape (ny, nx, 3) where a
+triple of RGB values is associated with each pixel location.
+
+In general, the shape of the resultant array will be the concatenation
+of the shape of the index array (or the shape that all the index arrays
+were broadcast to) with the shape of any unused dimensions (those not
+indexed) in the array being indexed.
+
+Boolean or "mask" index arrays
+==============================
+
+Boolean arrays used as indices are treated in a different manner
+entirely than index arrays. Boolean arrays must be of the same shape
+as the initial dimensions of the array being indexed. In the
+most straightforward case, the boolean array has the same shape: ::
+
+ >>> b = y>20
+ >>> y[b]
+ array([21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34])
+
+Unlike in the case of integer index arrays, in the boolean case, the
+result is a 1-D array containing all the elements in the indexed array
+corresponding to all the true elements in the boolean array. The
+elements in the indexed array are always iterated and returned in
+:term:`row-major` (C-style) order. The result is also identical to
+``y[np.nonzero(b)]``. As with index arrays, what is returned is a copy
+of the data, not a view as one gets with slices.
+
+The result will be multidimensional if y has more dimensions than b.
+For example: ::
+
+ >>> b[:,5] # use a 1-D boolean whose first dim agrees with the first dim of y
+ array([False, False, False, True, True])
+ >>> y[b[:,5]]
+ array([[21, 22, 23, 24, 25, 26, 27],
+ [28, 29, 30, 31, 32, 33, 34]])
+
+Here the 4th and 5th rows are selected from the indexed array and
+combined to make a 2-D array.
+
+In general, when the boolean array has fewer dimensions than the array
+being indexed, this is equivalent to y[b, ...], which means
+y is indexed by b followed by as many : as are needed to fill
+out the rank of y.
+Thus the shape of the result is one dimension containing the number
+of True elements of the boolean array, followed by the remaining
+dimensions of the array being indexed.
+
+For example, using a 2-D boolean array of shape (2,3)
+with four True elements to select rows from a 3-D array of shape
+(2,3,5) results in a 2-D result of shape (4,5): ::
+
+ >>> x = np.arange(30).reshape(2,3,5)
+ >>> x
+ array([[[ 0, 1, 2, 3, 4],
+ [ 5, 6, 7, 8, 9],
+ [10, 11, 12, 13, 14]],
+ [[15, 16, 17, 18, 19],
+ [20, 21, 22, 23, 24],
+ [25, 26, 27, 28, 29]]])
+ >>> b = np.array([[True, True, False], [False, True, True]])
+ >>> x[b]
+ array([[ 0, 1, 2, 3, 4],
+ [ 5, 6, 7, 8, 9],
+ [20, 21, 22, 23, 24],
+ [25, 26, 27, 28, 29]])
+
+For further details, consult the numpy reference documentation on array indexing.
+
+Combining index arrays with slices
+==================================
+
+Index arrays may be combined with slices. For example: ::
+
+ >>> y[np.array([0, 2, 4]), 1:3]
+ array([[ 1, 2],
+ [15, 16],
+ [29, 30]])
+
+In effect, the slice and index array operation are independent.
+The slice operation extracts columns with index 1 and 2,
+(i.e. the 2nd and 3rd columns),
+followed by the index array operation which extracts rows with
+index 0, 2 and 4 (i.e the first, third and fifth rows).
+
+This is equivalent to::
+
+ >>> y[:, 1:3][np.array([0, 2, 4]), :]
+ array([[ 1, 2],
+ [15, 16],
+ [29, 30]])
+
+Likewise, slicing can be combined with broadcasted boolean indices: ::
+
+ >>> b = y > 20
+ >>> b
+ array([[False, False, False, False, False, False, False],
+ [False, False, False, False, False, False, False],
+ [False, False, False, False, False, False, False],
+ [ True, True, True, True, True, True, True],
+ [ True, True, True, True, True, True, True]])
+ >>> y[b[:,5],1:3]
+ array([[22, 23],
+ [29, 30]])
+
+Structural indexing tools
+=========================
+
+To facilitate easy matching of array shapes with expressions and in
+assignments, the np.newaxis object can be used within array indices
+to add new dimensions with a size of 1. For example: ::
+
+ >>> y.shape
+ (5, 7)
+ >>> y[:,np.newaxis,:].shape
+ (5, 1, 7)
+
+Note that there are no new elements in the array, just that the
+dimensionality is increased. This can be handy to combine two
+arrays in a way that otherwise would require explicitly reshaping
+operations. For example: ::
+
+ >>> x = np.arange(5)
+ >>> x[:,np.newaxis] + x[np.newaxis,:]
+ array([[0, 1, 2, 3, 4],
+ [1, 2, 3, 4, 5],
+ [2, 3, 4, 5, 6],
+ [3, 4, 5, 6, 7],
+ [4, 5, 6, 7, 8]])
+
+The ellipsis syntax maybe used to indicate selecting in full any
+remaining unspecified dimensions. For example: ::
+
+ >>> z = np.arange(81).reshape(3,3,3,3)
+ >>> z[1,...,2]
+ array([[29, 32, 35],
+ [38, 41, 44],
+ [47, 50, 53]])
+
+This is equivalent to: ::
+
+ >>> z[1,:,:,2]
+ array([[29, 32, 35],
+ [38, 41, 44],
+ [47, 50, 53]])
+
+Assigning values to indexed arrays
+==================================
+
+As mentioned, one can select a subset of an array to assign to using
+a single index, slices, and index and mask arrays. The value being
+assigned to the indexed array must be shape consistent (the same shape
+or broadcastable to the shape the index produces). For example, it is
+permitted to assign a constant to a slice: ::
+
+ >>> x = np.arange(10)
+ >>> x[2:7] = 1
+
+or an array of the right size: ::
+
+ >>> x[2:7] = np.arange(5)
+
+Note that assignments may result in changes if assigning
+higher types to lower types (like floats to ints) or even
+exceptions (assigning complex to floats or ints): ::
+
+ >>> x[1] = 1.2
+ >>> x[1]
+ 1
+ >>> x[1] = 1.2j
+ TypeError: can't convert complex to int
+
+
+Unlike some of the references (such as array and mask indices)
+assignments are always made to the original data in the array
+(indeed, nothing else would make sense!). Note though, that some
+actions may not work as one may naively expect. This particular
+example is often surprising to people: ::
+
+ >>> x = np.arange(0, 50, 10)
+ >>> x
+ array([ 0, 10, 20, 30, 40])
+ >>> x[np.array([1, 1, 3, 1])] += 1
+ >>> x
+ array([ 0, 11, 20, 31, 40])
+
+Where people expect that the 1st location will be incremented by 3.
+In fact, it will only be incremented by 1. The reason is because
+a new array is extracted from the original (as a temporary) containing
+the values at 1, 1, 3, 1, then the value 1 is added to the temporary,
+and then the temporary is assigned back to the original array. Thus
+the value of the array at x[1]+1 is assigned to x[1] three times,
+rather than being incremented 3 times.
+
+Dealing with variable numbers of indices within programs
+========================================================
+
+The index syntax is very powerful but limiting when dealing with
+a variable number of indices. For example, if you want to write
+a function that can handle arguments with various numbers of
+dimensions without having to write special case code for each
+number of possible dimensions, how can that be done? If one
+supplies to the index a tuple, the tuple will be interpreted
+as a list of indices. For example (using the previous definition
+for the array z): ::
+
+ >>> indices = (1,1,1,1)
+ >>> z[indices]
+ 40
+
+So one can use code to construct tuples of any number of indices
+and then use these within an index.
+
+Slices can be specified within programs by using the slice() function
+in Python. For example: ::
+
+ >>> indices = (1,1,1,slice(0,2)) # same as [1,1,1,0:2]
+ >>> z[indices]
+ array([39, 40])
+
+Likewise, ellipsis can be specified by code by using the Ellipsis
+object: ::
+
+ >>> indices = (1, Ellipsis, 1) # same as [1,...,1]
+ >>> z[indices]
+ array([[28, 31, 34],
+ [37, 40, 43],
+ [46, 49, 52]])
+
+For this reason it is possible to use the output from the np.nonzero()
+function directly as an index since it always returns a tuple of index
+arrays.
+
+Because the special treatment of tuples, they are not automatically
+converted to an array as a list would be. As an example: ::
+
+ >>> z[[1,1,1,1]] # produces a large array
+ array([[[[27, 28, 29],
+ [30, 31, 32], ...
+ >>> z[(1,1,1,1)] # returns a single value
+ 40
+
+
The only mandatory argument of :func:`~numpy.genfromtxt` is the source of
the data. It can be a string, a list of strings, a generator or an open
-file-like object with a :meth:`read` method, for example, a file or
+file-like object with a ``read`` method, for example, a file or
:class:`io.StringIO` object. If a single string is provided, it is assumed
to be the name of a local or remote file. If a list of strings or a generator
returning strings is provided, each string is treated as one line in a file.
to the current directory and opened.
Recognized file types are text files and archives. Currently, the function
-recognizes :class:`gzip` and :class:`bz2` (`bzip2`) archives. The type of
+recognizes ``gzip`` and ``bz2`` (``bzip2``) archives. The type of
the archive is determined from the extension of the file: if the filename
-ends with ``'.gz'``, a :class:`gzip` archive is expected; if it ends with
-``'bz2'``, a :class:`bzip2` archive is assumed.
+ends with ``'.gz'``, a ``gzip`` archive is expected; if it ends with
+``'bz2'``, a ``bzip2`` archive is assumed.
Usually, defining a dtype is sufficient to define how the sequence of
strings must be converted. However, some additional control may sometimes
be required. For example, we may want to make sure that a date in a format
-``YYYY/MM/DD`` is converted to a :class:`datetime` object, or that a string
-like ``xx%`` is properly converted to a float between 0 and 1. In such
-cases, we should define conversion functions with the ``converters``
+``YYYY/MM/DD`` is converted to a :class:`~datetime.datetime` object, or that
+a string like ``xx%`` is properly converted to a float between 0 and 1. In
+such cases, we should define conversion functions with the ``converters``
arguments.
The value of this argument is typically a dictionary with column indices or
float. However, user-defined converters may rapidly become cumbersome to
manage.
-The :func:`~nummpy.genfromtxt` function provides two other complementary
+The :func:`~numpy.genfromtxt` function provides two other complementary
mechanisms: the ``missing_values`` argument is used to recognize
missing data and a second argument, ``filling_values``, is used to
process these missing data.
Shortcut functions
==================
-In addition to :func:`~numpy.genfromtxt`, the :mod:`numpy.lib.io` module
+In addition to :func:`~numpy.genfromtxt`, the :mod:`numpy.lib.npyio` module
provides several convenience functions derived from
:func:`~numpy.genfromtxt`. These functions work the same way as the
original, but they have different default values.
-:func:`~numpy.recfromtxt`
+:func:`~numpy.npyio.recfromtxt`
Returns a standard :class:`numpy.recarray` (if ``usemask=False``) or a
- :class:`~numpy.ma.MaskedRecords` array (if ``usemaske=True``). The
+ :class:`~numpy.ma.mrecords.MaskedRecords` array (if ``usemaske=True``). The
default dtype is ``dtype=None``, meaning that the types of each column
will be automatically determined.
-:func:`~numpy.recfromcsv`
- Like :func:`~numpy.recfromtxt`, but with a default ``delimiter=","``.
+:func:`~numpy.npyio.recfromcsv`
+ Like :func:`~numpy.npyio.recfromtxt`, but with a default ``delimiter=","``.
Structured arrays
*****************
-.. automodule:: numpy.doc.structured_arrays
+Introduction
+============
+
+Structured arrays are ndarrays whose datatype is a composition of simpler
+datatypes organized as a sequence of named :term:`fields <field>`. For example,
+::
+
+ >>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)],
+ ... dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
+ >>> x
+ array([('Rex', 9, 81.), ('Fido', 3, 27.)],
+ dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
+
+Here ``x`` is a one-dimensional array of length two whose datatype is a
+structure with three fields: 1. A string of length 10 or less named 'name', 2.
+a 32-bit integer named 'age', and 3. a 32-bit float named 'weight'.
+
+If you index ``x`` at position 1 you get a structure::
+
+ >>> x[1]
+ ('Fido', 3, 27.0)
+
+You can access and modify individual fields of a structured array by indexing
+with the field name::
+
+ >>> x['age']
+ array([9, 3], dtype=int32)
+ >>> x['age'] = 5
+ >>> x
+ array([('Rex', 5, 81.), ('Fido', 5, 27.)],
+ dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
+
+Structured datatypes are designed to be able to mimic 'structs' in the C
+language, and share a similar memory layout. They are meant for interfacing with
+C code and for low-level manipulation of structured buffers, for example for
+interpreting binary blobs. For these purposes they support specialized features
+such as subarrays, nested datatypes, and unions, and allow control over the
+memory layout of the structure.
+
+Users looking to manipulate tabular data, such as stored in csv files, may find
+other pydata projects more suitable, such as xarray, pandas, or DataArray.
+These provide a high-level interface for tabular data analysis and are better
+optimized for that use. For instance, the C-struct-like memory layout of
+structured arrays in numpy can lead to poor cache behavior in comparison.
+
+.. _defining-structured-types:
+
+Structured Datatypes
+====================
+
+A structured datatype can be thought of as a sequence of bytes of a certain
+length (the structure's :term:`itemsize`) which is interpreted as a collection
+of fields. Each field has a name, a datatype, and a byte offset within the
+structure. The datatype of a field may be any numpy datatype including other
+structured datatypes, and it may also be a :term:`subarray data type` which
+behaves like an ndarray of a specified shape. The offsets of the fields are
+arbitrary, and fields may even overlap. These offsets are usually determined
+automatically by numpy, but can also be specified.
+
+Structured Datatype Creation
+----------------------------
+
+Structured datatypes may be created using the function :func:`numpy.dtype`.
+There are 4 alternative forms of specification which vary in flexibility and
+conciseness. These are further documented in the
+:ref:`Data Type Objects <arrays.dtypes.constructing>` reference page, and in
+summary they are:
+
+1. A list of tuples, one tuple per field
+
+ Each tuple has the form ``(fieldname, datatype, shape)`` where shape is
+ optional. ``fieldname`` is a string (or tuple if titles are used, see
+ :ref:`Field Titles <titles>` below), ``datatype`` may be any object
+ convertible to a datatype, and ``shape`` is a tuple of integers specifying
+ subarray shape.
+
+ >>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2, 2))])
+ dtype([('x', '<f4'), ('y', '<f4'), ('z', '<f4', (2, 2))])
+
+ If ``fieldname`` is the empty string ``''``, the field will be given a
+ default name of the form ``f#``, where ``#`` is the integer index of the
+ field, counting from 0 from the left::
+
+ >>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')])
+ dtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')])
+
+ The byte offsets of the fields within the structure and the total
+ structure itemsize are determined automatically.
+
+2. A string of comma-separated dtype specifications
+
+ In this shorthand notation any of the :ref:`string dtype specifications
+ <arrays.dtypes.constructing>` may be used in a string and separated by
+ commas. The itemsize and byte offsets of the fields are determined
+ automatically, and the field names are given the default names ``f0``,
+ ``f1``, etc. ::
+
+ >>> np.dtype('i8, f4, S3')
+ dtype([('f0', '<i8'), ('f1', '<f4'), ('f2', 'S3')])
+ >>> np.dtype('3int8, float32, (2, 3)float64')
+ dtype([('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))])
+
+3. A dictionary of field parameter arrays
+
+ This is the most flexible form of specification since it allows control
+ over the byte-offsets of the fields and the itemsize of the structure.
+
+ The dictionary has two required keys, 'names' and 'formats', and four
+ optional keys, 'offsets', 'itemsize', 'aligned' and 'titles'. The values
+ for 'names' and 'formats' should respectively be a list of field names and
+ a list of dtype specifications, of the same length. The optional 'offsets'
+ value should be a list of integer byte-offsets, one for each field within
+ the structure. If 'offsets' is not given the offsets are determined
+ automatically. The optional 'itemsize' value should be an integer
+ describing the total size in bytes of the dtype, which must be large
+ enough to contain all the fields.
+ ::
+
+ >>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']})
+ dtype([('col1', '<i4'), ('col2', '<f4')])
+ >>> np.dtype({'names': ['col1', 'col2'],
+ ... 'formats': ['i4', 'f4'],
+ ... 'offsets': [0, 4],
+ ... 'itemsize': 12})
+ dtype({'names':['col1','col2'], 'formats':['<i4','<f4'], 'offsets':[0,4], 'itemsize':12})
+
+ Offsets may be chosen such that the fields overlap, though this will mean
+ that assigning to one field may clobber any overlapping field's data. As
+ an exception, fields of :class:`numpy.object_` type cannot overlap with
+ other fields, because of the risk of clobbering the internal object
+ pointer and then dereferencing it.
+
+ The optional 'aligned' value can be set to ``True`` to make the automatic
+ offset computation use aligned offsets (see :ref:`offsets-and-alignment`),
+ as if the 'align' keyword argument of :func:`numpy.dtype` had been set to
+ True.
+
+ The optional 'titles' value should be a list of titles of the same length
+ as 'names', see :ref:`Field Titles <titles>` below.
+
+4. A dictionary of field names
+
+ The use of this form of specification is discouraged, but documented here
+ because older numpy code may use it. The keys of the dictionary are the
+ field names and the values are tuples specifying type and offset::
+
+ >>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)})
+ dtype([('col1', 'i1'), ('col2', '<f4')])
+
+ This form is discouraged because Python dictionaries do not preserve order
+ in Python versions before Python 3.6, and the order of the fields in a
+ structured dtype has meaning. :ref:`Field Titles <titles>` may be
+ specified by using a 3-tuple, see below.
+
+Manipulating and Displaying Structured Datatypes
+------------------------------------------------
+
+The list of field names of a structured datatype can be found in the ``names``
+attribute of the dtype object::
+
+ >>> d = np.dtype([('x', 'i8'), ('y', 'f4')])
+ >>> d.names
+ ('x', 'y')
+
+The field names may be modified by assigning to the ``names`` attribute using a
+sequence of strings of the same length.
+
+The dtype object also has a dictionary-like attribute, ``fields``, whose keys
+are the field names (and :ref:`Field Titles <titles>`, see below) and whose
+values are tuples containing the dtype and byte offset of each field. ::
+
+ >>> d.fields
+ mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})
+
+Both the ``names`` and ``fields`` attributes will equal ``None`` for
+unstructured arrays. The recommended way to test if a dtype is structured is
+with `if dt.names is not None` rather than `if dt.names`, to account for dtypes
+with 0 fields.
+
+The string representation of a structured datatype is shown in the "list of
+tuples" form if possible, otherwise numpy falls back to using the more general
+dictionary form.
+
+.. _offsets-and-alignment:
+
+Automatic Byte Offsets and Alignment
+------------------------------------
+
+Numpy uses one of two methods to automatically determine the field byte offsets
+and the overall itemsize of a structured datatype, depending on whether
+``align=True`` was specified as a keyword argument to :func:`numpy.dtype`.
+
+By default (``align=False``), numpy will pack the fields together such that
+each field starts at the byte offset the previous field ended, and the fields
+are contiguous in memory. ::
+
+ >>> def print_offsets(d):
+ ... print("offsets:", [d.fields[name][1] for name in d.names])
+ ... print("itemsize:", d.itemsize)
+ >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2'))
+ offsets: [0, 1, 2, 6, 7, 15]
+ itemsize: 17
+
+If ``align=True`` is set, numpy will pad the structure in the same way many C
+compilers would pad a C-struct. Aligned structures can give a performance
+improvement in some cases, at the cost of increased datatype size. Padding
+bytes are inserted between fields such that each field's byte offset will be a
+multiple of that field's alignment, which is usually equal to the field's size
+in bytes for simple datatypes, see :c:member:`PyArray_Descr.alignment`. The
+structure will also have trailing padding added so that its itemsize is a
+multiple of the largest field's alignment. ::
+
+ >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2', align=True))
+ offsets: [0, 1, 4, 8, 16, 24]
+ itemsize: 32
+
+Note that although almost all modern C compilers pad in this way by default,
+padding in C structs is C-implementation-dependent so this memory layout is not
+guaranteed to exactly match that of a corresponding struct in a C program. Some
+work may be needed, either on the numpy side or the C side, to obtain exact
+correspondence.
+
+If offsets were specified using the optional ``offsets`` key in the
+dictionary-based dtype specification, setting ``align=True`` will check that
+each field's offset is a multiple of its size and that the itemsize is a
+multiple of the largest field size, and raise an exception if not.
+
+If the offsets of the fields and itemsize of a structured array satisfy the
+alignment conditions, the array will have the ``ALIGNED`` :attr:`flag
+<numpy.ndarray.flags>` set.
+
+A convenience function :func:`numpy.lib.recfunctions.repack_fields` converts an
+aligned dtype or array to a packed one and vice versa. It takes either a dtype
+or structured ndarray as an argument, and returns a copy with fields re-packed,
+with or without padding bytes.
+
+.. _titles:
+
+Field Titles
+------------
+
+In addition to field names, fields may also have an associated :term:`title`,
+an alternate name, which is sometimes used as an additional description or
+alias for the field. The title may be used to index an array, just like a
+field name.
+
+To add titles when using the list-of-tuples form of dtype specification, the
+field name may be specified as a tuple of two strings instead of a single
+string, which will be the field's title and field name respectively. For
+example::
+
+ >>> np.dtype([(('my title', 'name'), 'f4')])
+ dtype([(('my title', 'name'), '<f4')])
+
+When using the first form of dictionary-based specification, the titles may be
+supplied as an extra ``'titles'`` key as described above. When using the second
+(discouraged) dictionary-based specification, the title can be supplied by
+providing a 3-element tuple ``(datatype, offset, title)`` instead of the usual
+2-element tuple::
+
+ >>> np.dtype({'name': ('i4', 0, 'my title')})
+ dtype([(('my title', 'name'), '<i4')])
+
+The ``dtype.fields`` dictionary will contain titles as keys, if any
+titles are used. This means effectively that a field with a title will be
+represented twice in the fields dictionary. The tuple values for these fields
+will also have a third element, the field title. Because of this, and because
+the ``names`` attribute preserves the field order while the ``fields``
+attribute may not, it is recommended to iterate through the fields of a dtype
+using the ``names`` attribute of the dtype, which will not list titles, as
+in::
+
+ >>> for name in d.names:
+ ... print(d.fields[name][:2])
+ (dtype('int64'), 0)
+ (dtype('float32'), 8)
+
+Union types
+-----------
+
+Structured datatypes are implemented in numpy to have base type
+:class:`numpy.void` by default, but it is possible to interpret other numpy
+types as structured types using the ``(base_dtype, dtype)`` form of dtype
+specification described in
+:ref:`Data Type Objects <arrays.dtypes.constructing>`. Here, ``base_dtype`` is
+the desired underlying dtype, and fields and flags will be copied from
+``dtype``. This dtype is similar to a 'union' in C.
+
+Indexing and Assignment to Structured arrays
+============================================
+
+Assigning data to a Structured Array
+------------------------------------
+
+There are a number of ways to assign values to a structured array: Using python
+tuples, using scalar values, or using other structured arrays.
+
+Assignment from Python Native Types (Tuples)
+````````````````````````````````````````````
+
+The simplest way to assign values to a structured array is using python tuples.
+Each assigned value should be a tuple of length equal to the number of fields
+in the array, and not a list or array as these will trigger numpy's
+broadcasting rules. The tuple's elements are assigned to the successive fields
+of the array, from left to right::
+
+ >>> x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8, f4, f8')
+ >>> x[1] = (7, 8, 9)
+ >>> x
+ array([(1, 2., 3.), (7, 8., 9.)],
+ dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '<f8')])
+
+Assignment from Scalars
+```````````````````````
+
+A scalar assigned to a structured element will be assigned to all fields. This
+happens when a scalar is assigned to a structured array, or when an
+unstructured array is assigned to a structured array::
+
+ >>> x = np.zeros(2, dtype='i8, f4, ?, S1')
+ >>> x[:] = 3
+ >>> x
+ array([(3, 3., True, b'3'), (3, 3., True, b'3')],
+ dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
+ >>> x[:] = np.arange(2)
+ >>> x
+ array([(0, 0., False, b'0'), (1, 1., True, b'1')],
+ dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
+
+Structured arrays can also be assigned to unstructured arrays, but only if the
+structured datatype has just a single field::
+
+ >>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')])
+ >>> onefield = np.zeros(2, dtype=[('A', 'i4')])
+ >>> nostruct = np.zeros(2, dtype='i4')
+ >>> nostruct[:] = twofield
+ Traceback (most recent call last):
+ ...
+ TypeError: Cannot cast array data from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'
+
+Assignment from other Structured Arrays
+```````````````````````````````````````
+
+Assignment between two structured arrays occurs as if the source elements had
+been converted to tuples and then assigned to the destination elements. That
+is, the first field of the source array is assigned to the first field of the
+destination array, and the second field likewise, and so on, regardless of
+field names. Structured arrays with a different number of fields cannot be
+assigned to each other. Bytes of the destination structure which are not
+included in any of the fields are unaffected. ::
+
+ >>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')])
+ >>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')])
+ >>> b[:] = a
+ >>> b
+ array([(0., b'0.0', b''), (0., b'0.0', b''), (0., b'0.0', b'')],
+ dtype=[('x', '<f4'), ('y', 'S3'), ('z', 'O')])
+
+
+Assignment involving subarrays
+``````````````````````````````
+
+When assigning to fields which are subarrays, the assigned value will first be
+broadcast to the shape of the subarray.
+
+Indexing Structured Arrays
+--------------------------
+
+Accessing Individual Fields
+```````````````````````````
+
+Individual fields of a structured array may be accessed and modified by indexing
+the array with the field name. ::
+
+ >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
+ >>> x['foo']
+ array([1, 3])
+ >>> x['foo'] = 10
+ >>> x
+ array([(10, 2.), (10, 4.)],
+ dtype=[('foo', '<i8'), ('bar', '<f4')])
+
+The resulting array is a view into the original array. It shares the same
+memory locations and writing to the view will modify the original array. ::
+
+ >>> y = x['bar']
+ >>> y[:] = 11
+ >>> x
+ array([(10, 11.), (10, 11.)],
+ dtype=[('foo', '<i8'), ('bar', '<f4')])
+
+This view has the same dtype and itemsize as the indexed field, so it is
+typically a non-structured array, except in the case of nested structures.
+
+ >>> y.dtype, y.shape, y.strides
+ (dtype('float32'), (2,), (12,))
+
+If the accessed field is a subarray, the dimensions of the subarray
+are appended to the shape of the result::
+
+ >>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])
+ >>> x['a'].shape
+ (2, 2)
+ >>> x['b'].shape
+ (2, 2, 3, 3)
+
+Accessing Multiple Fields
+```````````````````````````
+
+One can index and assign to a structured array with a multi-field index, where
+the index is a list of field names.
+
+.. warning::
+ The behavior of multi-field indexes changed from Numpy 1.15 to Numpy 1.16.
+
+The result of indexing with a multi-field index is a view into the original
+array, as follows::
+
+ >>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')])
+ >>> a[['a', 'c']]
+ array([(0, 0.), (0, 0.), (0, 0.)],
+ dtype={'names':['a','c'], 'formats':['<i4','<f4'], 'offsets':[0,8], 'itemsize':12})
+
+Assignment to the view modifies the original array. The view's fields will be
+in the order they were indexed. Note that unlike for single-field indexing, the
+dtype of the view has the same itemsize as the original array, and has fields
+at the same offsets as in the original array, and unindexed fields are merely
+missing.
+
+.. warning::
+ In Numpy 1.15, indexing an array with a multi-field index returned a copy of
+ the result above, but with fields packed together in memory as if
+ passed through :func:`numpy.lib.recfunctions.repack_fields`.
+
+ The new behavior as of Numpy 1.16 leads to extra "padding" bytes at the
+ location of unindexed fields compared to 1.15. You will need to update any
+ code which depends on the data having a "packed" layout. For instance code
+ such as::
+
+ >>> a[['a', 'c']].view('i8') # Fails in Numpy 1.16
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype
+
+ will need to be changed. This code has raised a ``FutureWarning`` since
+ Numpy 1.12, and similar code has raised ``FutureWarning`` since 1.7.
+
+ In 1.16 a number of functions have been introduced in the
+ :mod:`numpy.lib.recfunctions` module to help users account for this
+ change. These are
+ :func:`numpy.lib.recfunctions.repack_fields`.
+ :func:`numpy.lib.recfunctions.structured_to_unstructured`,
+ :func:`numpy.lib.recfunctions.unstructured_to_structured`,
+ :func:`numpy.lib.recfunctions.apply_along_fields`,
+ :func:`numpy.lib.recfunctions.assign_fields_by_name`, and
+ :func:`numpy.lib.recfunctions.require_fields`.
+
+ The function :func:`numpy.lib.recfunctions.repack_fields` can always be
+ used to reproduce the old behavior, as it will return a packed copy of the
+ structured array. The code above, for example, can be replaced with:
+
+ >>> from numpy.lib.recfunctions import repack_fields
+ >>> repack_fields(a[['a', 'c']]).view('i8') # supported in 1.16
+ array([0, 0, 0])
+
+ Furthermore, numpy now provides a new function
+ :func:`numpy.lib.recfunctions.structured_to_unstructured` which is a safer
+ and more efficient alternative for users who wish to convert structured
+ arrays to unstructured arrays, as the view above is often indeded to do.
+ This function allows safe conversion to an unstructured type taking into
+ account padding, often avoids a copy, and also casts the datatypes
+ as needed, unlike the view. Code such as:
+
+ >>> b = np.zeros(3, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
+ >>> b[['x', 'z']].view('f4')
+ array([0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
+
+ can be made safer by replacing with:
+
+ >>> from numpy.lib.recfunctions import structured_to_unstructured
+ >>> structured_to_unstructured(b[['x', 'z']])
+ array([0, 0, 0])
+
+
+Assignment to an array with a multi-field index modifies the original array::
+
+ >>> a[['a', 'c']] = (2, 3)
+ >>> a
+ array([(2, 0, 3.), (2, 0, 3.), (2, 0, 3.)],
+ dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')])
+
+This obeys the structured array assignment rules described above. For example,
+this means that one can swap the values of two fields using appropriate
+multi-field indexes::
+
+ >>> a[['a', 'c']] = a[['c', 'a']]
+
+Indexing with an Integer to get a Structured Scalar
+```````````````````````````````````````````````````
+
+Indexing a single element of a structured array (with an integer index) returns
+a structured scalar::
+
+ >>> x = np.array([(1, 2., 3.)], dtype='i, f, f')
+ >>> scalar = x[0]
+ >>> scalar
+ (1, 2., 3.)
+ >>> type(scalar)
+ <class 'numpy.void'>
+
+Unlike other numpy scalars, structured scalars are mutable and act like views
+into the original array, such that modifying the scalar will modify the
+original array. Structured scalars also support access and assignment by field
+name::
+
+ >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
+ >>> s = x[0]
+ >>> s['bar'] = 100
+ >>> x
+ array([(1, 100.), (3, 4.)],
+ dtype=[('foo', '<i8'), ('bar', '<f4')])
+
+Similarly to tuples, structured scalars can also be indexed with an integer::
+
+ >>> scalar = np.array([(1, 2., 3.)], dtype='i, f, f')[0]
+ >>> scalar[0]
+ 1
+ >>> scalar[1] = 4
+
+Thus, tuples might be thought of as the native Python equivalent to numpy's
+structured types, much like native python integers are the equivalent to
+numpy's integer types. Structured scalars may be converted to a tuple by
+calling `numpy.ndarray.item`::
+
+ >>> scalar.item(), type(scalar.item())
+ ((1, 4.0, 3.0), <class 'tuple'>)
+
+Viewing Structured Arrays Containing Objects
+--------------------------------------------
+
+In order to prevent clobbering object pointers in fields of
+:class:`object` type, numpy currently does not allow views of structured
+arrays containing objects.
+
+Structure Comparison
+--------------------
+
+If the dtypes of two void structured arrays are equal, testing the equality of
+the arrays will result in a boolean array with the dimensions of the original
+arrays, with elements set to ``True`` where all fields of the corresponding
+structures are equal. Structured dtypes are equal if the field names,
+dtypes and titles are the same, ignoring endianness, and the fields are in
+the same order::
+
+ >>> a = np.zeros(2, dtype=[('a', 'i4'), ('b', 'i4')])
+ >>> b = np.ones(2, dtype=[('a', 'i4'), ('b', 'i4')])
+ >>> a == b
+ array([False, False])
+
+Currently, if the dtypes of two void structured arrays are not equivalent the
+comparison fails, returning the scalar value ``False``. This behavior is
+deprecated as of numpy 1.10 and will raise an error or perform elementwise
+comparison in the future.
+
+The ``<`` and ``>`` operators always return ``False`` when comparing void
+structured arrays, and arithmetic and bitwise operations are not supported.
+
+Record Arrays
+=============
+
+As an optional convenience numpy provides an ndarray subclass,
+:class:`numpy.recarray` that allows access to fields of structured arrays by
+attribute instead of only by index.
+Record arrays use a special datatype, :class:`numpy.record`, that allows
+field access by attribute on the structured scalars obtained from the array.
+The :mod:`numpy.rec` module provides functions for creating recarrays from
+various objects.
+Additional helper functions for creating and manipulating structured arrays
+can be found in :mod:`numpy.lib.recfunctions`.
+
+The simplest way to create a record array is with ``numpy.rec.array``::
+
+ >>> recordarr = np.rec.array([(1, 2., 'Hello'), (2, 3., "World")],
+ ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])
+ >>> recordarr.bar
+ array([ 2., 3.], dtype=float32)
+ >>> recordarr[1:2]
+ rec.array([(2, 3., b'World')],
+ dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])
+ >>> recordarr[1:2].foo
+ array([2], dtype=int32)
+ >>> recordarr.foo[1:2]
+ array([2], dtype=int32)
+ >>> recordarr[1].baz
+ b'World'
+
+:func:`numpy.rec.array` can convert a wide variety of arguments into record
+arrays, including structured arrays::
+
+ >>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
+ ... dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')])
+ >>> recordarr = np.rec.array(arr)
+
+The :mod:`numpy.rec` module provides a number of other convenience functions for
+creating record arrays, see :ref:`record array creation routines
+<routines.array-creation.rec>`.
+
+A record array representation of a structured array can be obtained using the
+appropriate `view <numpy-ndarray-view>`_::
+
+ >>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
+ ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'a10')])
+ >>> recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)),
+ ... type=np.recarray)
+
+For convenience, viewing an ndarray as type :class:`numpy.recarray` will
+automatically convert to :class:`numpy.record` datatype, so the dtype can be left
+out of the view::
+
+ >>> recordarr = arr.view(np.recarray)
+ >>> recordarr.dtype
+ dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))
+
+To get back to a plain ndarray both the dtype and type must be reset. The
+following view does so, taking into account the unusual case that the
+recordarr was not a structured type::
+
+ >>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray)
+
+Record array fields accessed by index or by attribute are returned as a record
+array if the field has a structured type but as a plain ndarray otherwise. ::
+
+ >>> recordarr = np.rec.array([('Hello', (1, 2)), ("World", (3, 4))],
+ ... dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])])
+ >>> type(recordarr.foo)
+ <class 'numpy.ndarray'>
+ >>> type(recordarr.bar)
+ <class 'numpy.recarray'>
+
+Note that if a field has the same name as an ndarray attribute, the ndarray
+attribute takes precedence. Such fields will be inaccessible by attribute but
+will still be accessible by index.
+
Recarray Helper Functions
-*************************
+-------------------------
.. automodule:: numpy.lib.recfunctions
:members:
Subclassing ndarray
*******************
-.. automodule:: numpy.doc.subclassing
+Introduction
+------------
+
+Subclassing ndarray is relatively simple, but it has some complications
+compared to other Python objects. On this page we explain the machinery
+that allows you to subclass ndarray, and the implications for
+implementing a subclass.
+
+ndarrays and object creation
+============================
+
+Subclassing ndarray is complicated by the fact that new instances of
+ndarray classes can come about in three different ways. These are:
+
+#. Explicit constructor call - as in ``MySubClass(params)``. This is
+ the usual route to Python instance creation.
+#. View casting - casting an existing ndarray as a given subclass
+#. New from template - creating a new instance from a template
+ instance. Examples include returning slices from a subclassed array,
+ creating return types from ufuncs, and copying arrays. See
+ :ref:`new-from-template` for more details
+
+The last two are characteristics of ndarrays - in order to support
+things like array slicing. The complications of subclassing ndarray are
+due to the mechanisms numpy has to support these latter two routes of
+instance creation.
+
+.. _view-casting:
+
+View casting
+------------
+
+*View casting* is the standard ndarray mechanism by which you take an
+ndarray of any subclass, and return a view of the array as another
+(specified) subclass:
+
+>>> import numpy as np
+>>> # create a completely useless ndarray subclass
+>>> class C(np.ndarray): pass
+>>> # create a standard ndarray
+>>> arr = np.zeros((3,))
+>>> # take a view of it, as our useless subclass
+>>> c_arr = arr.view(C)
+>>> type(c_arr)
+<class 'C'>
+
+.. _new-from-template:
+
+Creating new from template
+--------------------------
+
+New instances of an ndarray subclass can also come about by a very
+similar mechanism to :ref:`view-casting`, when numpy finds it needs to
+create a new instance from a template instance. The most obvious place
+this has to happen is when you are taking slices of subclassed arrays.
+For example:
+
+>>> v = c_arr[1:]
+>>> type(v) # the view is of type 'C'
+<class 'C'>
+>>> v is c_arr # but it's a new instance
+False
+
+The slice is a *view* onto the original ``c_arr`` data. So, when we
+take a view from the ndarray, we return a new ndarray, of the same
+class, that points to the data in the original.
+
+There are other points in the use of ndarrays where we need such views,
+such as copying arrays (``c_arr.copy()``), creating ufunc output arrays
+(see also :ref:`array-wrap`), and reducing methods (like
+``c_arr.mean()``).
+
+Relationship of view casting and new-from-template
+--------------------------------------------------
+
+These paths both use the same machinery. We make the distinction here,
+because they result in different input to your methods. Specifically,
+:ref:`view-casting` means you have created a new instance of your array
+type from any potential subclass of ndarray. :ref:`new-from-template`
+means you have created a new instance of your class from a pre-existing
+instance, allowing you - for example - to copy across attributes that
+are particular to your subclass.
+
+Implications for subclassing
+----------------------------
+
+If we subclass ndarray, we need to deal not only with explicit
+construction of our array type, but also :ref:`view-casting` or
+:ref:`new-from-template`. NumPy has the machinery to do this, and it is
+this machinery that makes subclassing slightly non-standard.
+
+There are two aspects to the machinery that ndarray uses to support
+views and new-from-template in subclasses.
+
+The first is the use of the ``ndarray.__new__`` method for the main work
+of object initialization, rather then the more usual ``__init__``
+method. The second is the use of the ``__array_finalize__`` method to
+allow subclasses to clean up after the creation of views and new
+instances from templates.
+
+A brief Python primer on ``__new__`` and ``__init__``
+=====================================================
+
+``__new__`` is a standard Python method, and, if present, is called
+before ``__init__`` when we create a class instance. See the `python
+__new__ documentation
+<https://docs.python.org/reference/datamodel.html#object.__new__>`_ for more detail.
+
+For example, consider the following Python code:
+
+.. testcode::
+
+ class C:
+ def __new__(cls, *args):
+ print('Cls in __new__:', cls)
+ print('Args in __new__:', args)
+ # The `object` type __new__ method takes a single argument.
+ return object.__new__(cls)
+
+ def __init__(self, *args):
+ print('type(self) in __init__:', type(self))
+ print('Args in __init__:', args)
+
+meaning that we get:
+
+>>> c = C('hello')
+Cls in __new__: <class 'C'>
+Args in __new__: ('hello',)
+type(self) in __init__: <class 'C'>
+Args in __init__: ('hello',)
+
+When we call ``C('hello')``, the ``__new__`` method gets its own class
+as first argument, and the passed argument, which is the string
+``'hello'``. After python calls ``__new__``, it usually (see below)
+calls our ``__init__`` method, with the output of ``__new__`` as the
+first argument (now a class instance), and the passed arguments
+following.
+
+As you can see, the object can be initialized in the ``__new__``
+method or the ``__init__`` method, or both, and in fact ndarray does
+not have an ``__init__`` method, because all the initialization is
+done in the ``__new__`` method.
+
+Why use ``__new__`` rather than just the usual ``__init__``? Because
+in some cases, as for ndarray, we want to be able to return an object
+of some other class. Consider the following:
+
+.. testcode::
+
+ class D(C):
+ def __new__(cls, *args):
+ print('D cls is:', cls)
+ print('D args in __new__:', args)
+ return C.__new__(C, *args)
+
+ def __init__(self, *args):
+ # we never get here
+ print('In D __init__')
+
+meaning that:
+
+>>> obj = D('hello')
+D cls is: <class 'D'>
+D args in __new__: ('hello',)
+Cls in __new__: <class 'C'>
+Args in __new__: ('hello',)
+>>> type(obj)
+<class 'C'>
+
+The definition of ``C`` is the same as before, but for ``D``, the
+``__new__`` method returns an instance of class ``C`` rather than
+``D``. Note that the ``__init__`` method of ``D`` does not get
+called. In general, when the ``__new__`` method returns an object of
+class other than the class in which it is defined, the ``__init__``
+method of that class is not called.
+
+This is how subclasses of the ndarray class are able to return views
+that preserve the class type. When taking a view, the standard
+ndarray machinery creates the new ndarray object with something
+like::
+
+ obj = ndarray.__new__(subtype, shape, ...
+
+where ``subdtype`` is the subclass. Thus the returned view is of the
+same class as the subclass, rather than being of class ``ndarray``.
+
+That solves the problem of returning views of the same type, but now
+we have a new problem. The machinery of ndarray can set the class
+this way, in its standard methods for taking views, but the ndarray
+``__new__`` method knows nothing of what we have done in our own
+``__new__`` method in order to set attributes, and so on. (Aside -
+why not call ``obj = subdtype.__new__(...`` then? Because we may not
+have a ``__new__`` method with the same call signature).
+
+The role of ``__array_finalize__``
+==================================
+
+``__array_finalize__`` is the mechanism that numpy provides to allow
+subclasses to handle the various ways that new instances get created.
+
+Remember that subclass instances can come about in these three ways:
+
+#. explicit constructor call (``obj = MySubClass(params)``). This will
+ call the usual sequence of ``MySubClass.__new__`` then (if it exists)
+ ``MySubClass.__init__``.
+#. :ref:`view-casting`
+#. :ref:`new-from-template`
+
+Our ``MySubClass.__new__`` method only gets called in the case of the
+explicit constructor call, so we can't rely on ``MySubClass.__new__`` or
+``MySubClass.__init__`` to deal with the view casting and
+new-from-template. It turns out that ``MySubClass.__array_finalize__``
+*does* get called for all three methods of object creation, so this is
+where our object creation housekeeping usually goes.
+
+* For the explicit constructor call, our subclass will need to create a
+ new ndarray instance of its own class. In practice this means that
+ we, the authors of the code, will need to make a call to
+ ``ndarray.__new__(MySubClass,...)``, a class-hierarchy prepared call to
+ ``super(MySubClass, cls).__new__(cls, ...)``, or do view casting of an
+ existing array (see below)
+* For view casting and new-from-template, the equivalent of
+ ``ndarray.__new__(MySubClass,...`` is called, at the C level.
+
+The arguments that ``__array_finalize__`` receives differ for the three
+methods of instance creation above.
+
+The following code allows us to look at the call sequences and arguments:
+
+.. testcode::
+
+ import numpy as np
+
+ class C(np.ndarray):
+ def __new__(cls, *args, **kwargs):
+ print('In __new__ with class %s' % cls)
+ return super(C, cls).__new__(cls, *args, **kwargs)
+
+ def __init__(self, *args, **kwargs):
+ # in practice you probably will not need or want an __init__
+ # method for your subclass
+ print('In __init__ with class %s' % self.__class__)
+
+ def __array_finalize__(self, obj):
+ print('In array_finalize:')
+ print(' self type is %s' % type(self))
+ print(' obj type is %s' % type(obj))
+
+
+Now:
+
+>>> # Explicit constructor
+>>> c = C((10,))
+In __new__ with class <class 'C'>
+In array_finalize:
+ self type is <class 'C'>
+ obj type is <type 'NoneType'>
+In __init__ with class <class 'C'>
+>>> # View casting
+>>> a = np.arange(10)
+>>> cast_a = a.view(C)
+In array_finalize:
+ self type is <class 'C'>
+ obj type is <type 'numpy.ndarray'>
+>>> # Slicing (example of new-from-template)
+>>> cv = c[:1]
+In array_finalize:
+ self type is <class 'C'>
+ obj type is <class 'C'>
+
+The signature of ``__array_finalize__`` is::
+
+ def __array_finalize__(self, obj):
+
+One sees that the ``super`` call, which goes to
+``ndarray.__new__``, passes ``__array_finalize__`` the new object, of our
+own class (``self``) as well as the object from which the view has been
+taken (``obj``). As you can see from the output above, the ``self`` is
+always a newly created instance of our subclass, and the type of ``obj``
+differs for the three instance creation methods:
+
+* When called from the explicit constructor, ``obj`` is ``None``
+* When called from view casting, ``obj`` can be an instance of any
+ subclass of ndarray, including our own.
+* When called in new-from-template, ``obj`` is another instance of our
+ own subclass, that we might use to update the new ``self`` instance.
+
+Because ``__array_finalize__`` is the only method that always sees new
+instances being created, it is the sensible place to fill in instance
+defaults for new object attributes, among other tasks.
+
+This may be clearer with an example.
+
+Simple example - adding an extra attribute to ndarray
+-----------------------------------------------------
+
+.. testcode::
+
+ import numpy as np
+
+ class InfoArray(np.ndarray):
+
+ def __new__(subtype, shape, dtype=float, buffer=None, offset=0,
+ strides=None, order=None, info=None):
+ # Create the ndarray instance of our type, given the usual
+ # ndarray input arguments. This will call the standard
+ # ndarray constructor, but return an object of our type.
+ # It also triggers a call to InfoArray.__array_finalize__
+ obj = super(InfoArray, subtype).__new__(subtype, shape, dtype,
+ buffer, offset, strides,
+ order)
+ # set the new 'info' attribute to the value passed
+ obj.info = info
+ # Finally, we must return the newly created object:
+ return obj
+
+ def __array_finalize__(self, obj):
+ # ``self`` is a new object resulting from
+ # ndarray.__new__(InfoArray, ...), therefore it only has
+ # attributes that the ndarray.__new__ constructor gave it -
+ # i.e. those of a standard ndarray.
+ #
+ # We could have got to the ndarray.__new__ call in 3 ways:
+ # From an explicit constructor - e.g. InfoArray():
+ # obj is None
+ # (we're in the middle of the InfoArray.__new__
+ # constructor, and self.info will be set when we return to
+ # InfoArray.__new__)
+ if obj is None: return
+ # From view casting - e.g arr.view(InfoArray):
+ # obj is arr
+ # (type(obj) can be InfoArray)
+ # From new-from-template - e.g infoarr[:3]
+ # type(obj) is InfoArray
+ #
+ # Note that it is here, rather than in the __new__ method,
+ # that we set the default value for 'info', because this
+ # method sees all creation of default objects - with the
+ # InfoArray.__new__ constructor, but also with
+ # arr.view(InfoArray).
+ self.info = getattr(obj, 'info', None)
+ # We do not need to return anything
+
+
+Using the object looks like this:
+
+ >>> obj = InfoArray(shape=(3,)) # explicit constructor
+ >>> type(obj)
+ <class 'InfoArray'>
+ >>> obj.info is None
+ True
+ >>> obj = InfoArray(shape=(3,), info='information')
+ >>> obj.info
+ 'information'
+ >>> v = obj[1:] # new-from-template - here - slicing
+ >>> type(v)
+ <class 'InfoArray'>
+ >>> v.info
+ 'information'
+ >>> arr = np.arange(10)
+ >>> cast_arr = arr.view(InfoArray) # view casting
+ >>> type(cast_arr)
+ <class 'InfoArray'>
+ >>> cast_arr.info is None
+ True
+
+This class isn't very useful, because it has the same constructor as the
+bare ndarray object, including passing in buffers and shapes and so on.
+We would probably prefer the constructor to be able to take an already
+formed ndarray from the usual numpy calls to ``np.array`` and return an
+object.
+
+Slightly more realistic example - attribute added to existing array
+-------------------------------------------------------------------
+
+Here is a class that takes a standard ndarray that already exists, casts
+as our type, and adds an extra attribute.
+
+.. testcode::
+
+ import numpy as np
+
+ class RealisticInfoArray(np.ndarray):
+
+ def __new__(cls, input_array, info=None):
+ # Input array is an already formed ndarray instance
+ # We first cast to be our class type
+ obj = np.asarray(input_array).view(cls)
+ # add the new attribute to the created instance
+ obj.info = info
+ # Finally, we must return the newly created object:
+ return obj
+
+ def __array_finalize__(self, obj):
+ # see InfoArray.__array_finalize__ for comments
+ if obj is None: return
+ self.info = getattr(obj, 'info', None)
+
+
+So:
+
+ >>> arr = np.arange(5)
+ >>> obj = RealisticInfoArray(arr, info='information')
+ >>> type(obj)
+ <class 'RealisticInfoArray'>
+ >>> obj.info
+ 'information'
+ >>> v = obj[1:]
+ >>> type(v)
+ <class 'RealisticInfoArray'>
+ >>> v.info
+ 'information'
+
+.. _array-ufunc:
+
+``__array_ufunc__`` for ufuncs
+------------------------------
+
+ .. versionadded:: 1.13
+
+A subclass can override what happens when executing numpy ufuncs on it by
+overriding the default ``ndarray.__array_ufunc__`` method. This method is
+executed *instead* of the ufunc and should return either the result of the
+operation, or :obj:`NotImplemented` if the operation requested is not
+implemented.
+
+The signature of ``__array_ufunc__`` is::
+
+ def __array_ufunc__(ufunc, method, *inputs, **kwargs):
+
+ - *ufunc* is the ufunc object that was called.
+ - *method* is a string indicating how the Ufunc was called, either
+ ``"__call__"`` to indicate it was called directly, or one of its
+ :ref:`methods<ufuncs.methods>`: ``"reduce"``, ``"accumulate"``,
+ ``"reduceat"``, ``"outer"``, or ``"at"``.
+ - *inputs* is a tuple of the input arguments to the ``ufunc``
+ - *kwargs* contains any optional or keyword arguments passed to the
+ function. This includes any ``out`` arguments, which are always
+ contained in a tuple.
+
+A typical implementation would convert any inputs or outputs that are
+instances of one's own class, pass everything on to a superclass using
+``super()``, and finally return the results after possible
+back-conversion. An example, taken from the test case
+``test_ufunc_override_with_super`` in ``core/tests/test_umath.py``, is the
+following.
+
+.. testcode::
+
+ input numpy as np
+
+ class A(np.ndarray):
+ def __array_ufunc__(self, ufunc, method, *inputs, out=None, **kwargs):
+ args = []
+ in_no = []
+ for i, input_ in enumerate(inputs):
+ if isinstance(input_, A):
+ in_no.append(i)
+ args.append(input_.view(np.ndarray))
+ else:
+ args.append(input_)
+
+ outputs = out
+ out_no = []
+ if outputs:
+ out_args = []
+ for j, output in enumerate(outputs):
+ if isinstance(output, A):
+ out_no.append(j)
+ out_args.append(output.view(np.ndarray))
+ else:
+ out_args.append(output)
+ kwargs['out'] = tuple(out_args)
+ else:
+ outputs = (None,) * ufunc.nout
+
+ info = {}
+ if in_no:
+ info['inputs'] = in_no
+ if out_no:
+ info['outputs'] = out_no
+
+ results = super(A, self).__array_ufunc__(ufunc, method,
+ *args, **kwargs)
+ if results is NotImplemented:
+ return NotImplemented
+
+ if method == 'at':
+ if isinstance(inputs[0], A):
+ inputs[0].info = info
+ return
+
+ if ufunc.nout == 1:
+ results = (results,)
+
+ results = tuple((np.asarray(result).view(A)
+ if output is None else output)
+ for result, output in zip(results, outputs))
+ if results and isinstance(results[0], A):
+ results[0].info = info
+
+ return results[0] if len(results) == 1 else results
+
+So, this class does not actually do anything interesting: it just
+converts any instances of its own to regular ndarray (otherwise, we'd
+get infinite recursion!), and adds an ``info`` dictionary that tells
+which inputs and outputs it converted. Hence, e.g.,
+
+>>> a = np.arange(5.).view(A)
+>>> b = np.sin(a)
+>>> b.info
+{'inputs': [0]}
+>>> b = np.sin(np.arange(5.), out=(a,))
+>>> b.info
+{'outputs': [0]}
+>>> a = np.arange(5.).view(A)
+>>> b = np.ones(1).view(A)
+>>> c = a + b
+>>> c.info
+{'inputs': [0, 1]}
+>>> a += b
+>>> a.info
+{'inputs': [0, 1], 'outputs': [0]}
+
+Note that another approach would be to to use ``getattr(ufunc,
+methods)(*inputs, **kwargs)`` instead of the ``super`` call. For this example,
+the result would be identical, but there is a difference if another operand
+also defines ``__array_ufunc__``. E.g., lets assume that we evalulate
+``np.add(a, b)``, where ``b`` is an instance of another class ``B`` that has
+an override. If you use ``super`` as in the example,
+``ndarray.__array_ufunc__`` will notice that ``b`` has an override, which
+means it cannot evaluate the result itself. Thus, it will return
+`NotImplemented` and so will our class ``A``. Then, control will be passed
+over to ``b``, which either knows how to deal with us and produces a result,
+or does not and returns `NotImplemented`, raising a ``TypeError``.
+
+If instead, we replace our ``super`` call with ``getattr(ufunc, method)``, we
+effectively do ``np.add(a.view(np.ndarray), b)``. Again, ``B.__array_ufunc__``
+will be called, but now it sees an ``ndarray`` as the other argument. Likely,
+it will know how to handle this, and return a new instance of the ``B`` class
+to us. Our example class is not set up to handle this, but it might well be
+the best approach if, e.g., one were to re-implement ``MaskedArray`` using
+``__array_ufunc__``.
+
+As a final note: if the ``super`` route is suited to a given class, an
+advantage of using it is that it helps in constructing class hierarchies.
+E.g., suppose that our other class ``B`` also used the ``super`` in its
+``__array_ufunc__`` implementation, and we created a class ``C`` that depended
+on both, i.e., ``class C(A, B)`` (with, for simplicity, not another
+``__array_ufunc__`` override). Then any ufunc on an instance of ``C`` would
+pass on to ``A.__array_ufunc__``, the ``super`` call in ``A`` would go to
+``B.__array_ufunc__``, and the ``super`` call in ``B`` would go to
+``ndarray.__array_ufunc__``, thus allowing ``A`` and ``B`` to collaborate.
+
+.. _array-wrap:
+
+``__array_wrap__`` for ufuncs and other functions
+-------------------------------------------------
+
+Prior to numpy 1.13, the behaviour of ufuncs could only be tuned using
+``__array_wrap__`` and ``__array_prepare__``. These two allowed one to
+change the output type of a ufunc, but, in contrast to
+``__array_ufunc__``, did not allow one to make any changes to the inputs.
+It is hoped to eventually deprecate these, but ``__array_wrap__`` is also
+used by other numpy functions and methods, such as ``squeeze``, so at the
+present time is still needed for full functionality.
+
+Conceptually, ``__array_wrap__`` "wraps up the action" in the sense of
+allowing a subclass to set the type of the return value and update
+attributes and metadata. Let's show how this works with an example. First
+we return to the simpler example subclass, but with a different name and
+some print statements:
+
+.. testcode::
+
+ import numpy as np
+
+ class MySubClass(np.ndarray):
+
+ def __new__(cls, input_array, info=None):
+ obj = np.asarray(input_array).view(cls)
+ obj.info = info
+ return obj
+
+ def __array_finalize__(self, obj):
+ print('In __array_finalize__:')
+ print(' self is %s' % repr(self))
+ print(' obj is %s' % repr(obj))
+ if obj is None: return
+ self.info = getattr(obj, 'info', None)
+
+ def __array_wrap__(self, out_arr, context=None):
+ print('In __array_wrap__:')
+ print(' self is %s' % repr(self))
+ print(' arr is %s' % repr(out_arr))
+ # then just call the parent
+ return super(MySubClass, self).__array_wrap__(self, out_arr, context)
+
+We run a ufunc on an instance of our new array:
+
+>>> obj = MySubClass(np.arange(5), info='spam')
+In __array_finalize__:
+ self is MySubClass([0, 1, 2, 3, 4])
+ obj is array([0, 1, 2, 3, 4])
+>>> arr2 = np.arange(5)+1
+>>> ret = np.add(arr2, obj)
+In __array_wrap__:
+ self is MySubClass([0, 1, 2, 3, 4])
+ arr is array([1, 3, 5, 7, 9])
+In __array_finalize__:
+ self is MySubClass([1, 3, 5, 7, 9])
+ obj is MySubClass([0, 1, 2, 3, 4])
+>>> ret
+MySubClass([1, 3, 5, 7, 9])
+>>> ret.info
+'spam'
+
+Note that the ufunc (``np.add``) has called the ``__array_wrap__`` method
+with arguments ``self`` as ``obj``, and ``out_arr`` as the (ndarray) result
+of the addition. In turn, the default ``__array_wrap__``
+(``ndarray.__array_wrap__``) has cast the result to class ``MySubClass``,
+and called ``__array_finalize__`` - hence the copying of the ``info``
+attribute. This has all happened at the C level.
+
+But, we could do anything we wanted:
+
+.. testcode::
+
+ class SillySubClass(np.ndarray):
+
+ def __array_wrap__(self, arr, context=None):
+ return 'I lost your data'
+
+>>> arr1 = np.arange(5)
+>>> obj = arr1.view(SillySubClass)
+>>> arr2 = np.arange(5)
+>>> ret = np.multiply(obj, arr2)
+>>> ret
+'I lost your data'
+
+So, by defining a specific ``__array_wrap__`` method for our subclass,
+we can tweak the output from ufuncs. The ``__array_wrap__`` method
+requires ``self``, then an argument - which is the result of the ufunc -
+and an optional parameter *context*. This parameter is returned by
+ufuncs as a 3-element tuple: (name of the ufunc, arguments of the ufunc,
+domain of the ufunc), but is not set by other numpy functions. Though,
+as seen above, it is possible to do otherwise, ``__array_wrap__`` should
+return an instance of its containing class. See the masked array
+subclass for an implementation.
+
+In addition to ``__array_wrap__``, which is called on the way out of the
+ufunc, there is also an ``__array_prepare__`` method which is called on
+the way into the ufunc, after the output arrays are created but before any
+computation has been performed. The default implementation does nothing
+but pass through the array. ``__array_prepare__`` should not attempt to
+access the array data or resize the array, it is intended for setting the
+output array type, updating attributes and metadata, and performing any
+checks based on the input that may be desired before computation begins.
+Like ``__array_wrap__``, ``__array_prepare__`` must return an ndarray or
+subclass thereof or raise an error.
+
+Extra gotchas - custom ``__del__`` methods and ndarray.base
+-----------------------------------------------------------
+
+One of the problems that ndarray solves is keeping track of memory
+ownership of ndarrays and their views. Consider the case where we have
+created an ndarray, ``arr`` and have taken a slice with ``v = arr[1:]``.
+The two objects are looking at the same memory. NumPy keeps track of
+where the data came from for a particular array or view, with the
+``base`` attribute:
+
+>>> # A normal ndarray, that owns its own data
+>>> arr = np.zeros((4,))
+>>> # In this case, base is None
+>>> arr.base is None
+True
+>>> # We take a view
+>>> v1 = arr[1:]
+>>> # base now points to the array that it derived from
+>>> v1.base is arr
+True
+>>> # Take a view of a view
+>>> v2 = v1[1:]
+>>> # base points to the original array that it was derived from
+>>> v2.base is arr
+True
+
+In general, if the array owns its own memory, as for ``arr`` in this
+case, then ``arr.base`` will be None - there are some exceptions to this
+- see the numpy book for more details.
+
+The ``base`` attribute is useful in being able to tell whether we have
+a view or the original array. This in turn can be useful if we need
+to know whether or not to do some specific cleanup when the subclassed
+array is deleted. For example, we may only want to do the cleanup if
+the original array is deleted, but not the views. For an example of
+how this can work, have a look at the ``memmap`` class in
+``numpy.core``.
+
+Subclassing and Downstream Compatibility
+----------------------------------------
+
+When sub-classing ``ndarray`` or creating duck-types that mimic the ``ndarray``
+interface, it is your responsibility to decide how aligned your APIs will be
+with those of numpy. For convenience, many numpy functions that have a corresponding
+``ndarray`` method (e.g., ``sum``, ``mean``, ``take``, ``reshape``) work by checking
+if the first argument to a function has a method of the same name. If it exists, the
+method is called instead of coercing the arguments to a numpy array.
+
+For example, if you want your sub-class or duck-type to be compatible with
+numpy's ``sum`` function, the method signature for this object's ``sum`` method
+should be the following:
+
+.. testcode::
+
+ def sum(self, axis=None, dtype=None, out=None, keepdims=False):
+ ...
+
+This is the exact same method signature for ``np.sum``, so now if a user calls
+``np.sum`` on this object, numpy will call the object's own ``sum`` method and
+pass in these arguments enumerated above in the signature, and no errors will
+be raised because the signatures are completely compatible with each other.
+
+If, however, you decide to deviate from this signature and do something like this:
+
+.. testcode::
+
+ def sum(self, axis=None, dtype=None):
+ ...
+
+This object is no longer compatible with ``np.sum`` because if you call ``np.sum``,
+it will pass in unexpected arguments ``out`` and ``keepdims``, causing a TypeError
+to be raised.
+
+If you wish to maintain compatibility with numpy and its subsequent versions (which
+might add new keyword arguments) but do not want to surface all of numpy's arguments,
+your function's signature should accept ``**kwargs``. For example:
+
+.. testcode::
+
+ def sum(self, axis=None, dtype=None, **unused_kwargs):
+ ...
+
+This object is now compatible with ``np.sum`` again because any extraneous arguments
+(i.e. keywords that are not ``axis`` or ``dtype``) will be hidden away in the
+``**unused_kwargs`` parameter.
+
+
+.. _basics.types:
+
**********
Data types
**********
.. seealso:: :ref:`Data type objects <arrays.dtypes>`
-.. automodule:: numpy.doc.basics
+Array types and conversions between types
+=========================================
+
+NumPy supports a much greater variety of numerical types than Python does.
+This section shows which are available, and how to modify an array's data-type.
+
+The primitive types supported are tied closely to those in C:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Numpy type
+ - C type
+ - Description
+
+ * - `numpy.bool_`
+ - ``bool``
+ - Boolean (True or False) stored as a byte
+
+ * - `numpy.byte`
+ - ``signed char``
+ - Platform-defined
+
+ * - `numpy.ubyte`
+ - ``unsigned char``
+ - Platform-defined
+
+ * - `numpy.short`
+ - ``short``
+ - Platform-defined
+
+ * - `numpy.ushort`
+ - ``unsigned short``
+ - Platform-defined
+
+ * - `numpy.intc`
+ - ``int``
+ - Platform-defined
+
+ * - `numpy.uintc`
+ - ``unsigned int``
+ - Platform-defined
+
+ * - `numpy.int_`
+ - ``long``
+ - Platform-defined
+
+ * - `numpy.uint`
+ - ``unsigned long``
+ - Platform-defined
+
+ * - `numpy.longlong`
+ - ``long long``
+ - Platform-defined
+
+ * - `numpy.ulonglong`
+ - ``unsigned long long``
+ - Platform-defined
+
+ * - `numpy.half` / `numpy.float16`
+ -
+ - Half precision float:
+ sign bit, 5 bits exponent, 10 bits mantissa
+
+ * - `numpy.single`
+ - ``float``
+ - Platform-defined single precision float:
+ typically sign bit, 8 bits exponent, 23 bits mantissa
+
+ * - `numpy.double`
+ - ``double``
+ - Platform-defined double precision float:
+ typically sign bit, 11 bits exponent, 52 bits mantissa.
+
+ * - `numpy.longdouble`
+ - ``long double``
+ - Platform-defined extended-precision float
+
+ * - `numpy.csingle`
+ - ``float complex``
+ - Complex number, represented by two single-precision floats (real and imaginary components)
+
+ * - `numpy.cdouble`
+ - ``double complex``
+ - Complex number, represented by two double-precision floats (real and imaginary components).
+
+ * - `numpy.clongdouble`
+ - ``long double complex``
+ - Complex number, represented by two extended-precision floats (real and imaginary components).
+
+
+Since many of these have platform-dependent definitions, a set of fixed-size
+aliases are provided:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Numpy type
+ - C type
+ - Description
+
+ * - `numpy.int8`
+ - ``int8_t``
+ - Byte (-128 to 127)
+
+ * - `numpy.int16`
+ - ``int16_t``
+ - Integer (-32768 to 32767)
+
+ * - `numpy.int32`
+ - ``int32_t``
+ - Integer (-2147483648 to 2147483647)
+
+ * - `numpy.int64`
+ - ``int64_t``
+ - Integer (-9223372036854775808 to 9223372036854775807)
+
+ * - `numpy.uint8`
+ - ``uint8_t``
+ - Unsigned integer (0 to 255)
+
+ * - `numpy.uint16`
+ - ``uint16_t``
+ - Unsigned integer (0 to 65535)
+
+ * - `numpy.uint32`
+ - ``uint32_t``
+ - Unsigned integer (0 to 4294967295)
+
+ * - `numpy.uint64`
+ - ``uint64_t``
+ - Unsigned integer (0 to 18446744073709551615)
+
+ * - `numpy.intp`
+ - ``intptr_t``
+ - Integer used for indexing, typically the same as ``ssize_t``
+
+ * - `numpy.uintp`
+ - ``uintptr_t``
+ - Integer large enough to hold a pointer
+
+ * - `numpy.float32`
+ - ``float``
+ -
+
+ * - `numpy.float64` / `numpy.float_`
+ - ``double``
+ - Note that this matches the precision of the builtin python `float`.
+
+ * - `numpy.complex64`
+ - ``float complex``
+ - Complex number, represented by two 32-bit floats (real and imaginary components)
+
+ * - `numpy.complex128` / `numpy.complex_`
+ - ``double complex``
+ - Note that this matches the precision of the builtin python `complex`.
+
+
+NumPy numerical types are instances of ``dtype`` (data-type) objects, each
+having unique characteristics. Once you have imported NumPy using
+
+ ::
+
+ >>> import numpy as np
+
+the dtypes are available as ``np.bool_``, ``np.float32``, etc.
+
+Advanced types, not listed in the table above, are explored in
+section :ref:`structured_arrays`.
+
+There are 5 basic numerical types representing booleans (bool), integers (int),
+unsigned integers (uint) floating point (float) and complex. Those with numbers
+in their name indicate the bitsize of the type (i.e. how many bits are needed
+to represent a single value in memory). Some types, such as ``int`` and
+``intp``, have differing bitsizes, dependent on the platforms (e.g. 32-bit
+vs. 64-bit machines). This should be taken into account when interfacing
+with low-level code (such as C or Fortran) where the raw memory is addressed.
+
+Data-types can be used as functions to convert python numbers to array scalars
+(see the array scalar section for an explanation), python sequences of numbers
+to arrays of that type, or as arguments to the dtype keyword that many numpy
+functions or methods accept. Some examples::
+
+ >>> import numpy as np
+ >>> x = np.float32(1.0)
+ >>> x
+ 1.0
+ >>> y = np.int_([1,2,4])
+ >>> y
+ array([1, 2, 4])
+ >>> z = np.arange(3, dtype=np.uint8)
+ >>> z
+ array([0, 1, 2], dtype=uint8)
+
+Array types can also be referred to by character codes, mostly to retain
+backward compatibility with older packages such as Numeric. Some
+documentation may still refer to these, for example::
+
+ >>> np.array([1, 2, 3], dtype='f')
+ array([ 1., 2., 3.], dtype=float32)
+
+We recommend using dtype objects instead.
+
+To convert the type of an array, use the .astype() method (preferred) or
+the type itself as a function. For example: ::
+
+ >>> z.astype(float) #doctest: +NORMALIZE_WHITESPACE
+ array([ 0., 1., 2.])
+ >>> np.int8(z)
+ array([0, 1, 2], dtype=int8)
+
+Note that, above, we use the *Python* float object as a dtype. NumPy knows
+that ``int`` refers to ``np.int_``, ``bool`` means ``np.bool_``,
+that ``float`` is ``np.float_`` and ``complex`` is ``np.complex_``.
+The other data-types do not have Python equivalents.
+
+To determine the type of an array, look at the dtype attribute::
+
+ >>> z.dtype
+ dtype('uint8')
+
+dtype objects also contain information about the type, such as its bit-width
+and its byte-order. The data type can also be used indirectly to query
+properties of the type, such as whether it is an integer::
+
+ >>> d = np.dtype(int)
+ >>> d
+ dtype('int32')
+
+ >>> np.issubdtype(d, np.integer)
+ True
+
+ >>> np.issubdtype(d, np.floating)
+ False
+
+
+Array Scalars
+=============
+
+NumPy generally returns elements of arrays as array scalars (a scalar
+with an associated dtype). Array scalars differ from Python scalars, but
+for the most part they can be used interchangeably (the primary
+exception is for versions of Python older than v2.x, where integer array
+scalars cannot act as indices for lists and tuples). There are some
+exceptions, such as when code requires very specific attributes of a scalar
+or when it checks specifically whether a value is a Python scalar. Generally,
+problems are easily fixed by explicitly converting array scalars
+to Python scalars, using the corresponding Python type function
+(e.g., ``int``, ``float``, ``complex``, ``str``, ``unicode``).
+
+The primary advantage of using array scalars is that
+they preserve the array type (Python may not have a matching scalar type
+available, e.g. ``int16``). Therefore, the use of array scalars ensures
+identical behaviour between arrays and scalars, irrespective of whether the
+value is inside an array or not. NumPy scalars also have many of the same
+methods arrays do.
+
+Overflow Errors
+===============
+
+The fixed size of NumPy numeric types may cause overflow errors when a value
+requires more memory than available in the data type. For example,
+`numpy.power` evaluates ``100 * 10 ** 8`` correctly for 64-bit integers,
+but gives 1874919424 (incorrect) for a 32-bit integer.
+
+ >>> np.power(100, 8, dtype=np.int64)
+ 10000000000000000
+ >>> np.power(100, 8, dtype=np.int32)
+ 1874919424
+
+The behaviour of NumPy and Python integer types differs significantly for
+integer overflows and may confuse users expecting NumPy integers to behave
+similar to Python's ``int``. Unlike NumPy, the size of Python's ``int`` is
+flexible. This means Python integers may expand to accommodate any integer and
+will not overflow.
+
+NumPy provides `numpy.iinfo` and `numpy.finfo` to verify the
+minimum or maximum values of NumPy integer and floating point values
+respectively ::
+
+ >>> np.iinfo(int) # Bounds of the default integer on this system.
+ iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)
+ >>> np.iinfo(np.int32) # Bounds of a 32-bit integer
+ iinfo(min=-2147483648, max=2147483647, dtype=int32)
+ >>> np.iinfo(np.int64) # Bounds of a 64-bit integer
+ iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)
+
+If 64-bit integers are still too small the result may be cast to a
+floating point number. Floating point numbers offer a larger, but inexact,
+range of possible values.
+
+ >>> np.power(100, 100, dtype=np.int64) # Incorrect even with 64-bit int
+ 0
+ >>> np.power(100, 100, dtype=np.float64)
+ 1e+200
+
+Extended Precision
+==================
+
+Python's floating-point numbers are usually 64-bit floating-point numbers,
+nearly equivalent to ``np.float64``. In some unusual situations it may be
+useful to use floating-point numbers with more precision. Whether this
+is possible in numpy depends on the hardware and on the development
+environment: specifically, x86 machines provide hardware floating-point
+with 80-bit precision, and while most C compilers provide this as their
+``long double`` type, MSVC (standard for Windows builds) makes
+``long double`` identical to ``double`` (64 bits). NumPy makes the
+compiler's ``long double`` available as ``np.longdouble`` (and
+``np.clongdouble`` for the complex numbers). You can find out what your
+numpy provides with ``np.finfo(np.longdouble)``.
+
+NumPy does not provide a dtype with more precision than C's
+``long double``\\; in particular, the 128-bit IEEE quad precision
+data type (FORTRAN's ``REAL*16``\\) is not available.
+
+For efficient memory alignment, ``np.longdouble`` is usually stored
+padded with zero bits, either to 96 or 128 bits. Which is more efficient
+depends on hardware and development environment; typically on 32-bit
+systems they are padded to 96 bits, while on 64-bit systems they are
+typically padded to 128 bits. ``np.longdouble`` is padded to the system
+default; ``np.float96`` and ``np.float128`` are provided for users who
+want specific padding. In spite of the names, ``np.float96`` and
+``np.float128`` provide only as much precision as ``np.longdouble``,
+that is, 80 bits on most x86 machines and 64 bits in standard
+Windows builds.
+
+Be warned that even if ``np.longdouble`` offers more precision than
+python ``float``, it is easy to lose that extra precision, since
+python often forces values to pass through ``float``. For example,
+the ``%`` formatting operator requires its arguments to be converted
+to standard python types, and it is therefore impossible to preserve
+extended precision even if many decimal places are requested. It can
+be useful to test your code with the value
+``1 + np.finfo(np.longdouble).eps``.
+
+
A general overview of building NumPy from source is given here, with detailed
instructions for specific platforms given separately.
+..
+ This page is referenced from numpy/numpy/__init__.py. Please keep its
+ location in sync with the link there.
+
Prerequisites
-------------
MSVC and Clang compilers. Compilers from other vendors such as Intel,
Absoft, Sun, NAG, Compaq, Vast, Portland, Lahey, HP, IBM are only supported
in the form of community feedback, and may not work out of the box.
- GCC 4.x (and later) compilers are recommended.
+ GCC 4.x (and later) compilers are recommended. On ARM64 (aarch64) GCC 8.x (and later) are recommended.
3) Linear Algebra libraries
If libgfortran.so is a dependency, gfortran has been used. If both are dependencies,
this means both have been used, which is almost always a very bad idea.
+.. _accelerated-blas-lapack-libraries:
+
Accelerated BLAS/LAPACK libraries
---------------------------------
2. BLIS
3. OpenBLAS
4. ATLAS
-5. Accelerate (MacOS)
-6. BLAS (NetLIB)
+5. BLAS (NetLIB)
If you wish to build against OpenBLAS but you also have BLIS available one
may predefine the order of searching via the environment variable
If neither of these exists the build will fail (names are compared
lower case).
+Alternatively one may use ``!`` or ``^`` to negate all items::
+
+ NPY_BLAS_ORDER='^blas,atlas' python setup.py build
+
+will allow using anything **but** NetLIB BLAS and ATLAS libraries, the order of the above
+list is retained.
+
+One cannot mix negation and positives, nor have multiple negations, such cases will
+raise an error.
+
LAPACK
~~~~~~
2. OpenBLAS
3. libFLAME
4. ATLAS
-5. Accelerate (MacOS)
-6. LAPACK (NetLIB)
+5. LAPACK (NetLIB)
If you wish to build against OpenBLAS but you also have MKL available one
If neither of these exists the build will fail (names are compared
lower case).
+Alternatively one may use ``!`` or ``^`` to negate all items::
+
+ NPY_LAPACK_ORDER='^lapack' python setup.py build
+
+will allow using anything **but** the NetLIB LAPACK library, the order of the above
+list is retained.
+
+One cannot mix negation and positives, nor have multiple negations, such cases will
+raise an error.
+
+
+.. deprecated:: 1.20
+ The native libraries on macOS, provided by Accelerate, are not fit for use
+ in NumPy since they have bugs that cause wrong output under easily reproducible
+ conditions. If the vendor fixes those bugs, the library could be reinstated,
+ but until then users compiling for themselves should use another linear
+ algebra library or use the built-in (but slower) default, see the next
+ section.
+
Disabling ATLAS and other accelerated libraries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The :c:func:`PyArray_IterAllButAxis` ( ``array``, ``&dim`` ) constructs an
iterator object that is modified so that it will not iterate over the
dimension indicated by dim. The only restriction on this iterator
-object, is that the :c:func:`PyArray_Iter_GOTO1D` ( ``it``, ``ind`` ) macro
+object, is that the :c:func:`PyArray_ITER_GOTO1D` ( ``it``, ``ind`` ) macro
cannot be used (thus flat indexing won't work either if you pass this
object back to Python --- so you shouldn't do this). Note that the
returned object from this routine is still usually cast to
writeable). The syntax is
:c:func:`PyArray_FROM_OTF`
-
Return an ndarray from any Python object, *obj*, that can be
converted to an array. The number of dimensions in the returned
array is determined by the object. The desired data-type of the
exception is set.
*obj*
-
The object can be any Python object convertible to an ndarray.
If the object is already (a subclass of) the ndarray that
satisfies the requirements then a new reference is returned.
to the requirements flag.
*typenum*
-
One of the enumerated types or :c:data:`NPY_NOTYPE` if the data-type
should be determined from the object itself. The C-based names
can be used:
requirements flag to override this behavior.
*requirements*
-
The memory model for an ndarray admits arbitrary strides in
each dimension to advance to the next element of the array.
Often, however, you need to interface with code that expects a
:c:data:`NPY_OUT_ARRAY`, and :c:data:`NPY_ARRAY_INOUT_ARRAY`:
:c:data:`NPY_ARRAY_IN_ARRAY`
-
This flag is useful for arrays that must be in C-contiguous
order and aligned. These kinds of arrays are usually input
arrays for some algorithm.
:c:data:`NPY_ARRAY_OUT_ARRAY`
-
This flag is useful to specify an array that is
in C-contiguous order, is aligned, and can be written to
as well. Such an array is usually returned as output
scratch).
:c:data:`NPY_ARRAY_INOUT_ARRAY`
-
This flag is useful to specify an array that will be used for both
input and output. :c:func:`PyArray_ResolveWritebackIfCopy`
must be called before :c:func:`Py_DECREF` at
Other useful flags that can be OR'd as additional requirements are:
:c:data:`NPY_ARRAY_FORCECAST`
-
Cast to the desired type, even if it can't be done without losing
information.
:c:data:`NPY_ARRAY_ENSURECOPY`
-
Make sure the resulting array is a copy of the original.
:c:data:`NPY_ARRAY_ENSUREARRAY`
-
Make sure the resulting object is an actual ndarray and not a sub-
class.
f2py -c -m add add.f
This command leaves a file named add.{ext} in the current directory
-(where {ext} is the appropriate extension for a python extension
+(where {ext} is the appropriate extension for a Python extension
module on your platform --- so, pyd, *etc.* ). This module may then be
imported from Python. It will contain a method for each subroutine in
add (zadd, cadd, dadd, sadd). The docstring of each method contains
>>> import add
>>> print(add.zadd.__doc__)
- zadd - Function signature:
- zadd(a,b,c,n)
- Required arguments:
- a : input rank-1 array('D') with bounds (*)
- b : input rank-1 array('D') with bounds (*)
- c : input rank-1 array('D') with bounds (*)
- n : input int
+ zadd(a,b,c,n)
+ Wrapper for ``zadd``.
+
+ Parameters
+ ----------
+ a : input rank-1 array('D') with bounds (*)
+ b : input rank-1 array('D') with bounds (*)
+ c : input rank-1 array('D') with bounds (*)
+ n : input int
Improving the basic interface
-----------------------------
-The default interface is a very literal translation of the fortran
+The default interface is a very literal translation of the Fortran
code into Python. The Fortran array arguments must now be NumPy arrays
and the integer argument should be an integer. The interface will
attempt to convert all arguments to their required types (and shapes)
should really match the array sizes), it is possible to abuse this
function in ways that can cause Python to crash. For example::
- >>> add.zadd([1,2,3], [1,2], [3,4], 1000)
+ >>> add.zadd([1, 2, 3], [1, 2], [3, 4], 1000)
will cause a program crash on most systems. Under the covers, the
lists are being converted to proper arrays but then the underlying add
that it won't try to create the variable n until the variable a is
created).
-After modifying ``add.pyf``, the new python module file can be generated
+After modifying ``add.pyf``, the new Python module file can be generated
by compiling both ``add.f`` and ``add.pyf``::
f2py -c add.pyf add.f
>>> import add
>>> print(add.zadd.__doc__)
- zadd - Function signature:
- c = zadd(a,b)
- Required arguments:
- a : input rank-1 array('D') with bounds (n)
- b : input rank-1 array('D') with bounds (n)
- Return objects:
- c : rank-1 array('D') with bounds (n)
+ c = zadd(a,b)
+
+ Wrapper for ``zadd``.
+
+ Parameters
+ ----------
+ a : input rank-1 array('D') with bounds (n)
+ b : input rank-1 array('D') with bounds (n)
+
+ Returns
+ -------
+ c : rank-1 array('D') with bounds (n)
Now, the function can be called in a much more robust way::
- >>> add.zadd([1,2,3],[4,5,6])
- array([ 5.+0.j, 7.+0.j, 9.+0.j])
+ >>> add.zadd([1, 2, 3], [4, 5, 6])
+ array([5.+0.j, 7.+0.j, 9.+0.j])
Notice the automatic conversion to the correct format that occurred.
--------------------------------------
The nice interface can also be generated automatically by placing the
-variable directives as special comments in the original fortran code.
+variable directives as special comments in the original Fortran code.
Thus, if I modify the source code to contain:
.. code-block:: none
2. Load the shared library.
-3. Convert the python objects to ctypes-understood arguments.
+3. Convert the Python objects to ctypes-understood arguments.
4. Call the function from the library with the ctypes arguments.
--- /dev/null
+.. _how-to-how-to:\r
+\r
+##############################################################################\r
+How to write a NumPy how-to\r
+##############################################################################\r
+\r
+How-tos get straight to the point -- they\r
+\r
+ - answer a focused question, or\r
+ - narrow a broad question into focused questions that the user can\r
+ choose among.\r
+\r
+******************************************************************************\r
+A stranger has asked for directions...\r
+******************************************************************************\r
+\r
+**"I need to refuel my car."**\r
+\r
+******************************************************************************\r
+Give a brief but explicit answer\r
+******************************************************************************\r
+\r
+ - `"Three kilometers/miles, take a right at Hayseed Road, it's on your left."`\r
+\r
+Add helpful details for newcomers ("Hayseed Road", even though it's the only\r
+turnoff at three km/mi). But not irrelevant ones:\r
+\r
+ - Don't also give directions from Route 7.\r
+ - Don't explain why the town has only one filling station.\r
+\r
+If there's related background (tutorial, explanation, reference, alternative\r
+approach), bring it to the user's attention with a link ("Directions from Route 7,"\r
+"Why so few filling stations?").\r
+\r
+\r
+******************************************************************************\r
+Delegate\r
+******************************************************************************\r
+\r
+ - `"Three km/mi, take a right at Hayseed Road, follow the signs."`\r
+\r
+If the information is already documented and succinct enough for a how-to,\r
+just link to it, possibly after an introduction ("Three km/mi, take a right").\r
+\r
+******************************************************************************\r
+If the question is broad, narrow and redirect it\r
+******************************************************************************\r
+\r
+ **"I want to see the sights."**\r
+\r
+The `See the sights` how-to should link to a set of narrower how-tos:\r
+\r
+- Find historic buildings\r
+- Find scenic lookouts\r
+- Find the town center\r
+\r
+and these might in turn link to still narrower how-tos -- so the town center\r
+page might link to\r
+\r
+ - Find the court house\r
+ - Find city hall\r
+\r
+By organizing how-tos this way, you not only display the options for people\r
+who need to narrow their question, you also have provided answers for users\r
+who start with narrower questions ("I want to see historic buildings," "Which\r
+way to city hall?").\r
+\r
+******************************************************************************\r
+If there are many steps, break them up\r
+******************************************************************************\r
+\r
+If a how-to has many steps:\r
+\r
+ - Consider breaking a step out into an individual how-to and linking to it.\r
+ - Include subheadings. They help readers grasp what's coming and return\r
+ where they left off.\r
+\r
+******************************************************************************\r
+Why write how-tos when there's Stack Overflow, Reddit, Gitter...?\r
+******************************************************************************\r
+\r
+ - We have authoritative answers.\r
+ - How-tos make the site less forbidding to non-experts.\r
+ - How-tos bring people into the site and help them discover other information\r
+ that's here .\r
+ - Creating how-tos helps us see NumPy usability through new eyes.\r
+\r
+******************************************************************************\r
+Aren't how-tos and tutorials the same thing?\r
+******************************************************************************\r
+\r
+People use the terms "how-to" and "tutorial" interchangeably, but we draw a\r
+distinction, following Daniele Procida's `taxonomy of documentation`_.\r
+\r
+ .. _`taxonomy of documentation`: https://documentation.divio.com/\r
+\r
+Documentation needs to meet users where they are. `How-tos` offer get-it-done\r
+information; the user wants steps to copy and doesn't necessarily want to\r
+understand NumPy. `Tutorials` are warm-fuzzy information; the user wants a\r
+feel for some aspect of NumPy (and again, may or may not care about deeper\r
+knowledge).\r
+\r
+We distinguish both tutorials and how-tos from `Explanations`, which are\r
+deep dives intended to give understanding rather than immediate assistance,\r
+and `References`, which give complete, autoritative data on some concrete\r
+part of NumPy (like its API) but aren't obligated to paint a broader picture.\r
+\r
+For more on tutorials, see the `tutorial how-to`_.\r
+\r
+.. _`tutorial how-to`: https://github.com/numpy/numpy-tutorials/blob/master/tutorial_style.ipynb\r
+\r
+\r
+******************************************************************************\r
+Is this page an example of a how-to?\r
+******************************************************************************\r
+\r
+Yes -- until the sections with question-mark headings; they explain rather\r
+than giving directions. In a how-to, those would be links.
\ No newline at end of file
--- /dev/null
+.. _how-to-io:\r
+\r
+##############################################################################\r
+Reading and writing files\r
+##############################################################################\r
+\r
+This page tackles common applications; for the full collection of I/O\r
+routines, see :ref:`routines.io`.\r
+\r
+\r
+******************************************************************************\r
+Reading text and CSV_ files\r
+******************************************************************************\r
+\r
+.. _CSV: https://en.wikipedia.org/wiki/Comma-separated_values\r
+\r
+With no missing values\r
+==============================================================================\r
+\r
+Use :func:`numpy.loadtxt`.\r
+\r
+With missing values\r
+==============================================================================\r
+\r
+Use :func:`numpy.genfromtxt`.\r
+\r
+:func:`numpy.genfromtxt` will either\r
+\r
+ - return a :ref:`masked array<maskedarray.generic>`\r
+ **masking out missing values** (if ``usemask=True``), or\r
+\r
+ - **fill in the missing value** with the value specified in\r
+ ``filling_values`` (default is ``np.nan`` for float, -1 for int).\r
+\r
+With non-whitespace delimiters\r
+------------------------------------------------------------------------------\r
+::\r
+\r
+ >>> print(open("csv.txt").read()) # doctest: +SKIP\r
+ 1, 2, 3\r
+ 4,, 6\r
+ 7, 8, 9\r
+\r
+\r
+Masked-array output\r
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r
+::\r
+\r
+ >>> np.genfromtxt("csv.txt", delimiter=",", usemask=True) # doctest: +SKIP\r
+ masked_array(\r
+ data=[[1.0, 2.0, 3.0],\r
+ [4.0, --, 6.0],\r
+ [7.0, 8.0, 9.0]],\r
+ mask=[[False, False, False],\r
+ [False, True, False],\r
+ [False, False, False]],\r
+ fill_value=1e+20)\r
+\r
+Array output\r
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r
+::\r
+\r
+ >>> np.genfromtxt("csv.txt", delimiter=",") # doctest: +SKIP\r
+ array([[ 1., 2., 3.],\r
+ [ 4., nan, 6.],\r
+ [ 7., 8., 9.]])\r
+\r
+Array output, specified fill-in value\r
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r
+::\r
+\r
+ >>> np.genfromtxt("csv.txt", delimiter=",", dtype=np.int8, filling_values=99) # doctest: +SKIP\r
+ array([[ 1, 2, 3],\r
+ [ 4, 99, 6],\r
+ [ 7, 8, 9]], dtype=int8)\r
+\r
+Whitespace-delimited\r
+-------------------------------------------------------------------------------\r
+\r
+:func:`numpy.genfromtxt` can also parse whitespace-delimited data files\r
+that have missing values if\r
+\r
+* **Each field has a fixed width**: Use the width as the `delimiter` argument.\r
+ ::\r
+\r
+ # File with width=4. The data does not have to be justified (for example,\r
+ # the 2 in row 1), the last column can be less than width (for example, the 6\r
+ # in row 2), and no delimiting character is required (for instance 8888 and 9\r
+ # in row 3)\r
+\r
+ >>> f = open("fixedwidth.txt").read() # doctest: +SKIP\r
+ >>> print(f) # doctest: +SKIP\r
+ 1 2 3\r
+ 44 6\r
+ 7 88889\r
+\r
+ # Showing spaces as ^\r
+ >>> print(f.replace(" ","^")) # doctest: +SKIP\r
+ 1^^^2^^^^^^3\r
+ 44^^^^^^6\r
+ 7^^^88889\r
+\r
+ >>> np.genfromtxt("fixedwidth.txt", delimiter=4) # doctest: +SKIP\r
+ array([[1.000e+00, 2.000e+00, 3.000e+00],\r
+ [4.400e+01, nan, 6.000e+00],\r
+ [7.000e+00, 8.888e+03, 9.000e+00]])\r
+\r
+* **A special value (e.g. "x") indicates a missing field**: Use it as the\r
+ `missing_values` argument.\r
+ ::\r
+\r
+ >>> print(open("nan.txt").read()) # doctest: +SKIP\r
+ 1 2 3\r
+ 44 x 6\r
+ 7 8888 9\r
+\r
+ >>> np.genfromtxt("nan.txt", missing_values="x") # doctest: +SKIP\r
+ array([[1.000e+00, 2.000e+00, 3.000e+00],\r
+ [4.400e+01, nan, 6.000e+00],\r
+ [7.000e+00, 8.888e+03, 9.000e+00]])\r
+\r
+* **You want to skip the rows with missing values**: Set\r
+ `invalid_raise=False`.\r
+ ::\r
+\r
+ >>> print(open("skip.txt").read()) # doctest: +SKIP\r
+ 1 2 3\r
+ 44 6\r
+ 7 888 9\r
+\r
+ >>> np.genfromtxt("skip.txt", invalid_raise=False) # doctest: +SKIP\r
+ __main__:1: ConversionWarning: Some errors were detected !\r
+ Line #2 (got 2 columns instead of 3)\r
+ array([[ 1., 2., 3.],\r
+ [ 7., 888., 9.]])\r
+\r
+\r
+* **The delimiter whitespace character is different from the whitespace that\r
+ indicates missing data**. For instance, if columns are delimited by ``\t``,\r
+ then missing data will be recognized if it consists of one\r
+ or more spaces.\r
+ ::\r
+\r
+ >>> f = open("tabs.txt").read() # doctest: +SKIP\r
+ >>> print(f) # doctest: +SKIP\r
+ 1 2 3\r
+ 44 6\r
+ 7 888 9\r
+\r
+ # Tabs vs. spaces\r
+ >>> print(f.replace("\t","^")) # doctest: +SKIP\r
+ 1^2^3\r
+ 44^ ^6\r
+ 7^888^9\r
+\r
+ >>> np.genfromtxt("tabs.txt", delimiter="\t", missing_values=" +") # doctest: +SKIP\r
+ array([[ 1., 2., 3.],\r
+ [ 44., nan, 6.],\r
+ [ 7., 888., 9.]])\r
+\r
+******************************************************************************\r
+Read a file in .npy or .npz format\r
+******************************************************************************\r
+\r
+Choices:\r
+\r
+ - Use :func:`numpy.load`. It can read files generated by any of\r
+ :func:`numpy.save`, :func:`numpy.savez`, or :func:`numpy.savez_compressed`.\r
+\r
+ - Use memory mapping. See `numpy.lib.format.open_memmap`.\r
+\r
+******************************************************************************\r
+Write to a file to be read back by NumPy\r
+******************************************************************************\r
+\r
+Binary\r
+===============================================================================\r
+\r
+Use\r
+:func:`numpy.save`, or to store multiple arrays :func:`numpy.savez`\r
+or :func:`numpy.savez_compressed`.\r
+\r
+For :ref:`security and portability <how-to-io-pickle-file>`, set\r
+``allow_pickle=False`` unless the dtype contains Python objects, which\r
+requires pickling.\r
+\r
+Masked arrays :any:`can't currently be saved <MaskedArray.tofile>`,\r
+nor can other arbitrary array subclasses.\r
+\r
+Human-readable\r
+==============================================================================\r
+\r
+:func:`numpy.save` and :func:`numpy.savez` create binary files. To **write a\r
+human-readable file**, use :func:`numpy.savetxt`. The array can only be 1- or\r
+2-dimensional, and there's no ` savetxtz` for multiple files.\r
+\r
+Large arrays\r
+==============================================================================\r
+\r
+See :ref:`how-to-io-large-arrays`.\r
+\r
+******************************************************************************\r
+Read an arbitrarily formatted binary file ("binary blob")\r
+******************************************************************************\r
+\r
+Use a :doc:`structured array <basics.rec>`.\r
+\r
+**Example:**\r
+\r
+The ``.wav`` file header is a 44-byte block preceding ``data_size`` bytes of the\r
+actual sound data::\r
+\r
+ chunk_id "RIFF"\r
+ chunk_size 4-byte unsigned little-endian integer\r
+ format "WAVE"\r
+ fmt_id "fmt "\r
+ fmt_size 4-byte unsigned little-endian integer\r
+ audio_fmt 2-byte unsigned little-endian integer\r
+ num_channels 2-byte unsigned little-endian integer\r
+ sample_rate 4-byte unsigned little-endian integer\r
+ byte_rate 4-byte unsigned little-endian integer\r
+ block_align 2-byte unsigned little-endian integer\r
+ bits_per_sample 2-byte unsigned little-endian integer\r
+ data_id "data"\r
+ data_size 4-byte unsigned little-endian integer\r
+\r
+The ``.wav`` file header as a NumPy structured dtype::\r
+\r
+ wav_header_dtype = np.dtype([\r
+ ("chunk_id", (bytes, 4)), # flexible-sized scalar type, item size 4\r
+ ("chunk_size", "<u4"), # little-endian unsigned 32-bit integer\r
+ ("format", "S4"), # 4-byte string, alternate spelling of (bytes, 4)\r
+ ("fmt_id", "S4"),\r
+ ("fmt_size", "<u4"),\r
+ ("audio_fmt", "<u2"), #\r
+ ("num_channels", "<u2"), # .. more of the same ...\r
+ ("sample_rate", "<u4"), #\r
+ ("byte_rate", "<u4"),\r
+ ("block_align", "<u2"),\r
+ ("bits_per_sample", "<u2"),\r
+ ("data_id", "S4"),\r
+ ("data_size", "<u4"),\r
+ #\r
+ # the sound data itself cannot be represented here:\r
+ # it does not have a fixed size\r
+ ])\r
+\r
+ header = np.fromfile(f, dtype=wave_header_dtype, count=1)[0]\r
+\r
+This ``.wav`` example is for illustration; to read a ``.wav`` file in real\r
+life, use Python's built-in module :mod:`wave`.\r
+\r
+(Adapted from Pauli Virtanen, :ref:`advanced_numpy`, licensed\r
+under `CC BY 4.0 <https://creativecommons.org/licenses/by/4.0/>`_.)\r
+\r
+.. _how-to-io-large-arrays:\r
+\r
+******************************************************************************\r
+Write or read large arrays\r
+******************************************************************************\r
+\r
+**Arrays too large to fit in memory** can be treated like ordinary in-memory\r
+arrays using memory mapping.\r
+\r
+- Raw array data written with :func:`numpy.ndarray.tofile` or\r
+ :func:`numpy.ndarray.tobytes` can be read with :func:`numpy.memmap`::\r
+\r
+ array = numpy.memmap("mydata/myarray.arr", mode="r", dtype=np.int16, shape=(1024, 1024))\r
+\r
+- Files output by :func:`numpy.save` (that is, using the numpy format) can be read\r
+ using :func:`numpy.load` with the ``mmap_mode`` keyword argument::\r
+\r
+ large_array[some_slice] = np.load("path/to/small_array", mmap_mode="r")\r
+\r
+Memory mapping lacks features like data chunking and compression; more\r
+full-featured formats and libraries usable with NumPy include:\r
+\r
+* **HDF5**: `h5py <https://www.h5py.org/>`_ or `PyTables <https://www.pytables.org/>`_.\r
+* **Zarr**: `here <https://zarr.readthedocs.io/en/stable/tutorial.html#reading-and-writing-data>`_.\r
+* **NetCDF**: :class:`scipy.io.netcdf_file`.\r
+\r
+For tradeoffs among memmap, Zarr, and HDF5, see\r
+`pythonspeed.com <https://pythonspeed.com/articles/mmap-vs-zarr-hdf5/>`_.\r
+\r
+******************************************************************************\r
+Write files for reading by other (non-NumPy) tools\r
+******************************************************************************\r
+\r
+Formats for **exchanging data** with other tools include HDF5, Zarr, and\r
+NetCDF (see :ref:`how-to-io-large-arrays`).\r
+\r
+******************************************************************************\r
+Write or read a JSON file\r
+******************************************************************************\r
+\r
+NumPy arrays are **not** directly\r
+`JSON serializable <https://github.com/numpy/numpy/issues/12481>`_.\r
+\r
+\r
+.. _how-to-io-pickle-file:\r
+\r
+******************************************************************************\r
+Save/restore using a pickle file\r
+******************************************************************************\r
+\r
+Avoid when possible; :doc:`pickles <python:library/pickle>` are not secure\r
+against erroneous or maliciously constructed data.\r
+\r
+Use :func:`numpy.save` and :func:`numpy.load`. Set ``allow_pickle=False``,\r
+unless the array dtype includes Python objects, in which case pickling is\r
+required.\r
+\r
+******************************************************************************\r
+Convert from a pandas DataFrame to a NumPy array\r
+******************************************************************************\r
+\r
+See :meth:`pandas.DataFrame.to_numpy`.\r
+\r
+******************************************************************************\r
+ Save/restore using `~numpy.ndarray.tofile` and `~numpy.fromfile`\r
+******************************************************************************\r
+\r
+In general, prefer :func:`numpy.save` and :func:`numpy.load`.\r
+\r
+:func:`numpy.ndarray.tofile` and :func:`numpy.fromfile` lose information on\r
+endianness and precision and so are unsuitable for anything but scratch\r
+storage.\r
+\r
.. toctree::
:maxdepth: 1
- ionumpy
+ how-to-how-to
+ how-to-io
.. _user:
################
-NumPy User Guide
+NumPy user guide
################
-This guide is intended as an introductory overview of NumPy and
-explains how to install and make use of the most important features of
-NumPy. For detailed reference documentation of the functions and
-classes contained in the package, see the :ref:`reference`.
+This guide is an overview and explains the important features;
+details are found in :ref:`reference`.
.. toctree::
:maxdepth: 1
- setting-up
+ whatisnumpy
+ Installation <https://numpy.org/install/>
quickstart
absolute_beginners
basics
c-info
tutorials_index
howtos_index
+
+
+.. Links to these files are placed directly in the top-level html
+ (doc/source/_templates/indexcontent.html, which appears for the URLs
+ numpy.org/devdocs and numpy.org/doc/XX) and are not in any toctree, so
+ we include them here to avoid a "WARNING: document isn't included in any
+ toctree" message
+
+.. toctree::
+ :hidden:
+
+ explanations_index
+ ../f2py/index
+ ../glossary
+ ../dev/underthehood
+ ../docs/index
+ ../bugs
+ ../release
+ ../doc_conventions
+ ../license
-****************
-Installing NumPy
-****************
-
-In most use cases the best way to install NumPy on your system is by using a
-pre-built package for your operating system. Please see
-https://scipy.org/install.html for links to available options.
-
-For instructions on building for source package, see
-:doc:`building`. This information is useful mainly for advanced users.
+:orphan:\r
+\r
+****************\r
+Installing NumPy\r
+****************\r
+\r
+See `Installing NumPy <https://numpy.org/install/>`_.
\ No newline at end of file
+++ /dev/null
-================================================
-How to read and write data using NumPy
-================================================
-
-.. currentmodule:: numpy
-
-.. testsetup::
-
- import numpy as np
- np.random.seed(1)
-
-**Objectives**
-
-- Writing NumPy arrays to files
-- Reading NumPy arrays from files
-- Dealing with encoding and dtype issues
-
-**Content**
-
-To be completed.
Miscellaneous
*************
-.. automodule:: numpy.doc.misc
+IEEE 754 Floating Point Special Values
+--------------------------------------
+
+Special values defined in numpy: nan, inf,
+
+NaNs can be used as a poor-man's mask (if you don't care what the
+original value was)
+
+Note: cannot use equality to test NaNs. E.g.: ::
+
+ >>> myarr = np.array([1., 0., np.nan, 3.])
+ >>> np.nonzero(myarr == np.nan)
+ (array([], dtype=int64),)
+ >>> np.nan == np.nan # is always False! Use special numpy functions instead.
+ False
+ >>> myarr[myarr == np.nan] = 0. # doesn't work
+ >>> myarr
+ array([ 1., 0., NaN, 3.])
+ >>> myarr[np.isnan(myarr)] = 0. # use this instead find
+ >>> myarr
+ array([ 1., 0., 0., 3.])
+
+Other related special value functions: ::
+
+ isinf(): True if value is inf
+ isfinite(): True if not nan or inf
+ nan_to_num(): Map nan to 0, inf to max float, -inf to min float
+
+The following corresponds to the usual functions except that nans are excluded
+from the results: ::
+
+ nansum()
+ nanmax()
+ nanmin()
+ nanargmax()
+ nanargmin()
+
+ >>> x = np.arange(10.)
+ >>> x[3] = np.nan
+ >>> x.sum()
+ nan
+ >>> np.nansum(x)
+ 42.0
+
+How numpy handles numerical exceptions
+--------------------------------------
+
+The default is to ``'warn'`` for ``invalid``, ``divide``, and ``overflow``
+and ``'ignore'`` for ``underflow``. But this can be changed, and it can be
+set individually for different kinds of exceptions. The different behaviors
+are:
+
+ - 'ignore' : Take no action when the exception occurs.
+ - 'warn' : Print a `RuntimeWarning` (via the Python `warnings` module).
+ - 'raise' : Raise a `FloatingPointError`.
+ - 'call' : Call a function specified using the `seterrcall` function.
+ - 'print' : Print a warning directly to ``stdout``.
+ - 'log' : Record error in a Log object specified by `seterrcall`.
+
+These behaviors can be set for all kinds of errors or specific ones:
+
+ - all : apply to all numeric exceptions
+ - invalid : when NaNs are generated
+ - divide : divide by zero (for integers as well!)
+ - overflow : floating point overflows
+ - underflow : floating point underflows
+
+Note that integer divide-by-zero is handled by the same machinery.
+These behaviors are set on a per-thread basis.
+
+Examples
+--------
+
+::
+
+ >>> oldsettings = np.seterr(all='warn')
+ >>> np.zeros(5,dtype=np.float32)/0.
+ invalid value encountered in divide
+ >>> j = np.seterr(under='ignore')
+ >>> np.array([1.e-100])**10
+ >>> j = np.seterr(invalid='raise')
+ >>> np.sqrt(np.array([-1.]))
+ FloatingPointError: invalid value encountered in sqrt
+ >>> def errorhandler(errstr, errflag):
+ ... print("saw stupid error!")
+ >>> np.seterrcall(errorhandler)
+ <function err_handler at 0x...>
+ >>> j = np.seterr(all='call')
+ >>> np.zeros(5, dtype=np.int32)/0
+ FloatingPointError: invalid value encountered in divide
+ saw stupid error!
+ >>> j = np.seterr(**oldsettings) # restore previous
+ ... # error-handling settings
+
+Interfacing to C
+----------------
+Only a survey of the choices. Little detail on how each works.
+
+1) Bare metal, wrap your own C-code manually.
+
+ - Plusses:
+
+ - Efficient
+ - No dependencies on other tools
+
+ - Minuses:
+
+ - Lots of learning overhead:
+
+ - need to learn basics of Python C API
+ - need to learn basics of numpy C API
+ - need to learn how to handle reference counting and love it.
+
+ - Reference counting often difficult to get right.
+
+ - getting it wrong leads to memory leaks, and worse, segfaults
+
+ - API will change for Python 3.0!
+
+2) Cython
+
+ - Plusses:
+
+ - avoid learning C API's
+ - no dealing with reference counting
+ - can code in pseudo python and generate C code
+ - can also interface to existing C code
+ - should shield you from changes to Python C api
+ - has become the de-facto standard within the scientific Python community
+ - fast indexing support for arrays
+
+ - Minuses:
+
+ - Can write code in non-standard form which may become obsolete
+ - Not as flexible as manual wrapping
+
+3) ctypes
+
+ - Plusses:
+
+ - part of Python standard library
+ - good for interfacing to existing sharable libraries, particularly
+ Windows DLLs
+ - avoids API/reference counting issues
+ - good numpy support: arrays have all these in their ctypes
+ attribute: ::
+
+ a.ctypes.data a.ctypes.get_strides
+ a.ctypes.data_as a.ctypes.shape
+ a.ctypes.get_as_parameter a.ctypes.shape_as
+ a.ctypes.get_data a.ctypes.strides
+ a.ctypes.get_shape a.ctypes.strides_as
+
+ - Minuses:
+
+ - can't use for writing code to be turned into C extensions, only a wrapper
+ tool.
+
+4) SWIG (automatic wrapper generator)
+
+ - Plusses:
+
+ - around a long time
+ - multiple scripting language support
+ - C++ support
+ - Good for wrapping large (many functions) existing C libraries
+
+ - Minuses:
+
+ - generates lots of code between Python and the C code
+ - can cause performance problems that are nearly impossible to optimize
+ out
+ - interface files can be hard to write
+ - doesn't necessarily avoid reference counting issues or needing to know
+ API's
+
+5) scipy.weave
+
+ - Plusses:
+
+ - can turn many numpy expressions into C code
+ - dynamic compiling and loading of generated C code
+ - can embed pure C code in Python module and have weave extract, generate
+ interfaces and compile, etc.
+
+ - Minuses:
+
+ - Future very uncertain: it's the only part of Scipy not ported to Python 3
+ and is effectively deprecated in favor of Cython.
+
+6) Psyco
+
+ - Plusses:
+
+ - Turns pure python into efficient machine code through jit-like
+ optimizations
+ - very fast when it optimizes well
+
+ - Minuses:
+
+ - Only on intel (windows?)
+ - Doesn't do much for numpy?
+
+Interfacing to Fortran:
+-----------------------
+The clear choice to wrap Fortran code is
+`f2py <https://docs.scipy.org/doc/numpy/f2py/>`_.
+
+Pyfort is an older alternative, but not supported any longer.
+Fwrap is a newer project that looked promising but isn't being developed any
+longer.
+
+Interfacing to C++:
+-------------------
+ 1) Cython
+ 2) CXX
+ 3) Boost.python
+ 4) SWIG
+ 5) SIP (used mainly in PyQT)
+
+
.. _numpy-for-matlab-users:
======================
-NumPy for Matlab users
+NumPy for MATLAB users
======================
Introduction
============
-MATLAB® and NumPy/SciPy have a lot in common. But there are many
-differences. NumPy and SciPy were created to do numerical and scientific
-computing in the most natural way with Python, not to be MATLAB® clones.
-This page is intended to be a place to collect wisdom about the
-differences, mostly for the purpose of helping proficient MATLAB® users
-become proficient NumPy and SciPy users.
+MATLAB® and NumPy have a lot in common, but NumPy was created to work with
+Python, not to be a MATLAB clone. This guide will help MATLAB users get started
+with NumPy.
.. raw:: html
table.docutils td { border: solid 1px #ccc; }
</style>
-Some Key Differences
+Some key differences
====================
.. list-table::
-
- * - In MATLAB®, the basic data type is a multidimensional array of
- double precision floating point numbers. Most expressions take such
- arrays and return such arrays. Operations on the 2-D instances of
- these arrays are designed to act more or less like matrix operations
- in linear algebra.
- - In NumPy the basic type is a multidimensional ``array``. Operations
- on these arrays in all dimensionalities including 2D are element-wise
- operations. One needs to use specific functions for linear algebra
- (though for matrix multiplication, one can use the ``@`` operator
- in python 3.5 and above).
-
- * - MATLAB® uses 1 (one) based indexing. The initial element of a
- sequence is found using a(1).
+ :class: docutils
+
+ * - In MATLAB, the basic type, even for scalars, is a
+ multidimensional array. Array assignments in MATLAB are stored as
+ 2D arrays of double precision floating point numbers, unless you
+ specify the number of dimensions and type. Operations on the 2D
+ instances of these arrays are modeled on matrix operations in
+ linear algebra.
+
+ - In NumPy, the basic type is a multidimensional ``array``. Array
+ assignments in NumPy are usually stored as :ref:`n-dimensional arrays<arrays>` with the
+ minimum type required to hold the objects in sequence, unless you
+ specify the number of dimensions and type. NumPy performs
+ operations element-by-element, so multiplying 2D arrays with
+ ``*`` is not a matrix multiplication -- it's an
+ element-by-element multiplication. (The ``@`` operator, available
+ since Python 3.5, can be used for conventional matrix
+ multiplication.)
+
+ * - MATLAB numbers indices from 1; ``a(1)`` is the first element.
:ref:`See note INDEXING <numpy-for-matlab-users.notes>`
- - Python uses 0 (zero) based indexing. The initial element of a
- sequence is found using a[0].
-
- * - MATLAB®'s scripting language was created for doing linear algebra.
- The syntax for basic matrix operations is nice and clean, but the API
- for adding GUIs and making full-fledged applications is more or less
- an afterthought.
- - NumPy is based on Python, which was designed from the outset to be
- an excellent general-purpose programming language. While Matlab's
- syntax for some array manipulations is more compact than
- NumPy's, NumPy (by virtue of being an add-on to Python) can do many
- things that Matlab just cannot, for instance dealing properly with
- stacks of matrices.
-
- * - In MATLAB®, arrays have pass-by-value semantics, with a lazy
- copy-on-write scheme to prevent actually creating copies until they
- are actually needed. Slice operations copy parts of the array.
- - In NumPy arrays have pass-by-reference semantics. Slice operations
- are views into an array.
-
-
-'array' or 'matrix'? Which should I use?
-========================================
-
-Historically, NumPy has provided a special matrix type, `np.matrix`, which
-is a subclass of ndarray which makes binary operations linear algebra
-operations. You may see it used in some existing code instead of `np.array`.
-So, which one to use?
-
-Short answer
-------------
-
-**Use arrays**.
-
-- They are the standard vector/matrix/tensor type of numpy. Many numpy
- functions return arrays, not matrices.
-- There is a clear distinction between element-wise operations and
- linear algebra operations.
-- You can have standard vectors or row/column vectors if you like.
-
-Until Python 3.5 the only disadvantage of using the array type was that you
-had to use ``dot`` instead of ``*`` to multiply (reduce) two tensors
-(scalar product, matrix vector multiplication etc.). Since Python 3.5 you
-can use the matrix multiplication ``@`` operator.
-
-Given the above, we intend to deprecate ``matrix`` eventually.
-
-Long answer
------------
-
-NumPy contains both an ``array`` class and a ``matrix`` class. The
-``array`` class is intended to be a general-purpose n-dimensional array
-for many kinds of numerical computing, while ``matrix`` is intended to
-facilitate linear algebra computations specifically. In practice there
-are only a handful of key differences between the two.
-
-- Operators ``*`` and ``@``, functions ``dot()``, and ``multiply()``:
-
- - For ``array``, **``*`` means element-wise multiplication**, while
- **``@`` means matrix multiplication**; they have associated functions
- ``multiply()`` and ``dot()``. (Before python 3.5, ``@`` did not exist
- and one had to use ``dot()`` for matrix multiplication).
- - For ``matrix``, **``*`` means matrix multiplication**, and for
- element-wise multiplication one has to use the ``multiply()`` function.
-
-- Handling of vectors (one-dimensional arrays)
-
- - For ``array``, the **vector shapes 1xN, Nx1, and N are all different
- things**. Operations like ``A[:,1]`` return a one-dimensional array of
- shape N, not a two-dimensional array of shape Nx1. Transpose on a
- one-dimensional ``array`` does nothing.
- - For ``matrix``, **one-dimensional arrays are always upconverted to 1xN
- or Nx1 matrices** (row or column vectors). ``A[:,1]`` returns a
- two-dimensional matrix of shape Nx1.
-
-- Handling of higher-dimensional arrays (ndim > 2)
-
- - ``array`` objects **can have number of dimensions > 2**;
- - ``matrix`` objects **always have exactly two dimensions**.
-
-- Convenience attributes
-
- - ``array`` **has a .T attribute**, which returns the transpose of
- the data.
- - ``matrix`` **also has .H, .I, and .A attributes**, which return
- the conjugate transpose, inverse, and ``asarray()`` of the matrix,
- respectively.
-
-- Convenience constructor
-
- - The ``array`` constructor **takes (nested) Python sequences as
- initializers**. As in, ``array([[1,2,3],[4,5,6]])``.
- - The ``matrix`` constructor additionally **takes a convenient
- string initializer**. As in ``matrix("[1 2 3; 4 5 6]")``.
-
-There are pros and cons to using both:
-
-- ``array``
-
- - ``:)`` Element-wise multiplication is easy: ``A*B``.
- - ``:(`` You have to remember that matrix multiplication has its own
- operator, ``@``.
- - ``:)`` You can treat one-dimensional arrays as *either* row or column
- vectors. ``A @ v`` treats ``v`` as a column vector, while
- ``v @ A`` treats ``v`` as a row vector. This can save you having to
- type a lot of transposes.
- - ``:)`` ``array`` is the "default" NumPy type, so it gets the most
- testing, and is the type most likely to be returned by 3rd party
- code that uses NumPy.
- - ``:)`` Is quite at home handling data of any number of dimensions.
- - ``:)`` Closer in semantics to tensor algebra, if you are familiar
- with that.
- - ``:)`` *All* operations (``*``, ``/``, ``+``, ``-`` etc.) are
- element-wise.
- - ``:(`` Sparse matrices from ``scipy.sparse`` do not interact as well
- with arrays.
-
-- ``matrix``
-
- - ``:\\`` Behavior is more like that of MATLAB® matrices.
- - ``<:(`` Maximum of two-dimensional. To hold three-dimensional data you
- need ``array`` or perhaps a Python list of ``matrix``.
- - ``<:(`` Minimum of two-dimensional. You cannot have vectors. They must be
- cast as single-column or single-row matrices.
- - ``<:(`` Since ``array`` is the default in NumPy, some functions may
- return an ``array`` even if you give them a ``matrix`` as an
- argument. This shouldn't happen with NumPy functions (if it does
- it's a bug), but 3rd party code based on NumPy may not honor type
- preservation like NumPy does.
- - ``:)`` ``A*B`` is matrix multiplication, so it looks just like you write
- it in linear algebra (For Python >= 3.5 plain arrays have the same
- convenience with the ``@`` operator).
- - ``<:(`` Element-wise multiplication requires calling a function,
- ``multiply(A,B)``.
- - ``<:(`` The use of operator overloading is a bit illogical: ``*``
- does not work element-wise but ``/`` does.
- - Interaction with ``scipy.sparse`` is a bit cleaner.
+ - NumPy, like Python, numbers indices from 0; ``a[0]`` is the first
+ element.
-The ``array`` is thus much more advisable to use. Indeed, we intend to
-deprecate ``matrix`` eventually.
-
-Table of Rough MATLAB-NumPy Equivalents
+ * - MATLAB's scripting language was created for linear algebra so the
+ syntax for some array manipulations is more compact than
+ NumPy's. On the other hand, the API for adding GUIs and creating
+ full-fledged applications is more or less an afterthought.
+ - NumPy is based on Python, a
+ general-purpose language. The advantage to NumPy
+ is access to Python libraries including: `SciPy
+ <https://www.scipy.org/>`_, `Matplotlib <https://matplotlib.org/>`_,
+ `Pandas <https://pandas.pydata.org/>`_, `OpenCV <https://opencv.org/>`_,
+ and more. In addition, Python is often `embedded as a scripting language
+ <https://en.wikipedia.org/wiki/List_of_Python_software#Embedded_as_a_scripting_language>`_
+ in other software, allowing NumPy to be used there too.
+
+ * - MATLAB array slicing uses pass-by-value semantics, with a lazy
+ copy-on-write scheme to prevent creating copies until they are
+ needed. Slicing operations copy parts of the array.
+ - NumPy array slicing uses pass-by-reference, that does not copy
+ the arguments. Slicing operations are views into an array.
+
+
+Rough equivalents
=======================================
-The table below gives rough equivalents for some common MATLAB®
-expressions. **These are not exact equivalents**, but rather should be
-taken as hints to get you going in the right direction. For more detail
-read the built-in documentation on the NumPy functions.
+The table below gives rough equivalents for some common MATLAB
+expressions. These are similar expressions, not equivalents. For
+details, see the :ref:`documentation<reference>`.
In the table below, it is assumed that you have executed the following
commands in Python:
::
- from numpy import *
- import scipy.linalg
+ import numpy as np
+ from scipy import io, integrate, linalg, signal
+ from scipy.sparse.linalg import eigs
Also assume below that if the Notes talk about "matrix" that the
arguments are two-dimensional entities.
-General Purpose Equivalents
+General purpose equivalents
---------------------------
.. list-table::
:header-rows: 1
- * - **MATLAB**
- - **numpy**
- - **Notes**
+ * - MATLAB
+ - NumPy
+ - Notes
* - ``help func``
- - ``info(func)`` or ``help(func)`` or ``func?`` (in Ipython)
+ - ``info(func)`` or ``help(func)`` or ``func?`` (in IPython)
- get help on the function *func*
* - ``which func``
- - `see note HELP <numpy-for-matlab-users.notes>`__
+ - :ref:`see note HELP <numpy-for-matlab-users.notes>`
- find out where *func* is defined
* - ``type func``
- - ``source(func)`` or ``func??`` (in Ipython)
+ - ``np.source(func)`` or ``func??`` (in IPython)
- print source for *func* (if not a native function)
+ * - ``% comment``
+ - ``# comment``
+ - comment a line of code with the text ``comment``
+
+ * - ::
+
+ for i=1:3
+ fprintf('%i\n',i)
+ end
+
+ - ::
+
+ for i in range(1, 4):
+ print(i)
+
+ - use a for-loop to print the numbers 1, 2, and 3 using :py:class:`range <range>`
+
* - ``a && b``
- ``a and b``
- - short-circuiting logical AND operator (Python native operator);
+ - short-circuiting logical AND operator (:ref:`Python native operator <python:boolean>`);
scalar arguments only
* - ``a || b``
- ``a or b``
- - short-circuiting logical OR operator (Python native operator);
+ - short-circuiting logical OR operator (:ref:`Python native operator <python:boolean>`);
scalar arguments only
+ * - .. code:: matlab
+
+ >> 4 == 4
+ ans = 1
+ >> 4 == 5
+ ans = 0
+
+ - ::
+
+ >>> 4 == 4
+ True
+ >>> 4 == 5
+ False
+
+ - The :ref:`boolean objects <python:bltin-boolean-values>`
+ in Python are ``True`` and ``False``, as opposed to MATLAB
+ logical types of ``1`` and ``0``.
+
+ * - .. code:: matlab
+
+ a=4
+ if a==4
+ fprintf('a = 4\n')
+ elseif a==5
+ fprintf('a = 5\n')
+ end
+
+ - ::
+
+ a = 4
+ if a == 4:
+ print('a = 4')
+ elif a == 5:
+ print('a = 5')
+
+ - create an if-else statement to check if ``a`` is 4 or 5 and print result
+
* - ``1*i``, ``1*j``, ``1i``, ``1j``
- ``1j``
- complex numbers
* - ``eps``
- - ``np.spacing(1)``
- - Distance between 1 and the nearest floating point number.
+ - ``np.finfo(float).eps`` or ``np.spacing(1)``
+ - Upper bound to relative error due to rounding in 64-bit floating point
+ arithmetic.
+
+ * - ``load data.mat``
+ - ``io.loadmat('data.mat')``
+ - Load MATLAB variables saved to the file ``data.mat``. (Note: When saving arrays to
+ ``data.mat`` in MATLAB/Octave, use a recent binary format. :func:`scipy.io.loadmat`
+ will create a dictionary with the saved arrays and further information.)
* - ``ode45``
- - ``scipy.integrate.solve_ivp(f)``
+ - ``integrate.solve_ivp(f)``
- integrate an ODE with Runge-Kutta 4,5
* - ``ode15s``
- - ``scipy.integrate.solve_ivp(f, method='BDF')``
+ - ``integrate.solve_ivp(f, method='BDF')``
- integrate an ODE with BDF method
-Linear Algebra Equivalents
+
+Linear algebra equivalents
--------------------------
.. list-table::
- Notes
* - ``ndims(a)``
- - ``ndim(a)`` or ``a.ndim``
- - get the number of dimensions of an array
+ - ``np.ndim(a)`` or ``a.ndim``
+ - number of dimensions of array ``a``
* - ``numel(a)``
- - ``size(a)`` or ``a.size``
- - get the number of elements of an array
+ - ``np.size(a)`` or ``a.size``
+ - number of elements of array ``a``
* - ``size(a)``
- - ``shape(a)`` or ``a.shape``
- - get the "size" of the matrix
+ - ``np.shape(a)`` or ``a.shape``
+ - "size" of array ``a``
* - ``size(a,n)``
- ``a.shape[n-1]``
- get the number of elements of the n-th dimension of array ``a``. (Note
- that MATLAB® uses 1 based indexing while Python uses 0 based indexing,
+ that MATLAB uses 1 based indexing while Python uses 0 based indexing,
See note :ref:`INDEXING <numpy-for-matlab-users.notes>`)
* - ``[ 1 2 3; 4 5 6 ]``
- - ``array([[1.,2.,3.], [4.,5.,6.]])``
- - 2x3 matrix literal
+ - ``np.array([[1. ,2. ,3.], [4. ,5. ,6.]])``
+ - define a 2x3 2D array
* - ``[ a b; c d ]``
- - ``block([[a,b], [c,d]])``
+ - ``np.block([[a, b], [c, d]])``
- construct a matrix from blocks ``a``, ``b``, ``c``, and ``d``
* - ``a(end)``
- ``a[-1]``
- - access last element in the 1xn matrix ``a``
+ - access last element in MATLAB vector (1xn or nx1) or 1D NumPy array
+ ``a`` (length n)
* - ``a(2,5)``
- - ``a[1,4]``
- - access element in second row, fifth column
+ - ``a[1, 4]``
+ - access element in second row, fifth column in 2D array ``a``
* - ``a(2,:)``
- - ``a[1]`` or ``a[1,:]``
- - entire second row of ``a``
+ - ``a[1]`` or ``a[1, :]``
+ - entire second row of 2D array ``a``
* - ``a(1:5,:)``
- - ``a[0:5]`` or ``a[:5]`` or ``a[0:5,:]``
- - the first five rows of ``a``
+ - ``a[0:5]`` or ``a[:5]`` or ``a[0:5, :]``
+ - first 5 rows of 2D array ``a``
* - ``a(end-4:end,:)``
- ``a[-5:]``
- - the last five rows of ``a``
+ - last 5 rows of 2D array ``a``
* - ``a(1:3,5:9)``
- - ``a[0:3][:,4:9]``
- - rows one to three and columns five to nine of ``a``. This gives
- read-only access.
+ - ``a[0:3, 4:9]``
+ - The first through third rows and fifth through ninth columns of a 2D array, ``a``.
* - ``a([2,4,5],[1,3])``
- - ``a[ix_([1,3,4],[0,2])]``
+ - ``a[np.ix_([1, 3, 4], [0, 2])]``
- rows 2,4 and 5 and columns 1 and 3. This allows the matrix to be
modified, and doesn't require a regular slice.
* - ``a(3:2:21,:)``
- - ``a[ 2:21:2,:]``
+ - ``a[2:21:2,:]``
- every other row of ``a``, starting with the third and going to the
twenty-first
- every other row of ``a``, starting with the first
* - ``a(end:-1:1,:)`` or ``flipud(a)``
- - ``a[ ::-1,:]``
+ - ``a[::-1,:]``
- ``a`` with rows in reverse order
* - ``a([1:end 1],:)``
- - ``a[r_[:len(a),0]]``
+ - ``a[np.r_[:len(a),0]]``
- ``a`` with copy of the first row appended to the end
* - ``a.'``
- ``a**3``
- element-wise exponentiation
- * - ``(a>0.5)``
- - ``(a>0.5)``
- - matrix whose i,jth element is (a_ij > 0.5). The Matlab result is an
- array of 0s and 1s. The NumPy result is an array of the boolean
+ * - ``(a > 0.5)``
+ - ``(a > 0.5)``
+ - matrix whose i,jth element is (a_ij > 0.5). The MATLAB result is an
+ array of logical values 0 and 1. The NumPy result is an array of the boolean
values ``False`` and ``True``.
- * - ``find(a>0.5)``
- - ``nonzero(a>0.5)``
+ * - ``find(a > 0.5)``
+ - ``np.nonzero(a > 0.5)``
- find the indices where (``a`` > 0.5)
- * - ``a(:,find(v>0.5))``
- - ``a[:,nonzero(v>0.5)[0]]``
+ * - ``a(:,find(v > 0.5))``
+ - ``a[:,np.nonzero(v > 0.5)[0]]``
- extract the columms of ``a`` where vector v > 0.5
* - ``a(:,find(v>0.5))``
- - ``a[:,v.T>0.5]``
+ - ``a[:, v.T > 0.5]``
- extract the columms of ``a`` where column vector v > 0.5
* - ``a(a<0.5)=0``
- - ``a[a<0.5]=0``
+ - ``a[a < 0.5]=0``
- ``a`` with elements less than 0.5 zeroed out
* - ``a .* (a>0.5)``
- - ``a * (a>0.5)``
+ - ``a * (a > 0.5)``
- ``a`` with elements less than 0.5 zeroed out
* - ``a(:) = 3``
* - ``y=x``
- ``y = x.copy()``
- - numpy assigns by reference
+ - NumPy assigns by reference
* - ``y=x(2,:)``
- - ``y = x[1,:].copy()``
- - numpy slices are by reference
+ - ``y = x[1, :].copy()``
+ - NumPy slices are by reference
* - ``y=x(:)``
- ``y = x.flatten()``
- turn array into vector (note that this forces a copy). To obtain the
- same data ordering as in Matlab, use ``x.flatten('F')``.
+ same data ordering as in MATLAB, use ``x.flatten('F')``.
* - ``1:10``
- - ``arange(1.,11.)`` or ``r_[1.:11.]`` or ``r_[1:10:10j]``
+ - ``np.arange(1., 11.)`` or ``np.r_[1.:11.]`` or ``np.r_[1:10:10j]``
- create an increasing vector (see note :ref:`RANGES
<numpy-for-matlab-users.notes>`)
* - ``0:9``
- - ``arange(10.)`` or ``r_[:10.]`` or ``r_[:9:10j]``
+ - ``np.arange(10.)`` or ``np.r_[:10.]`` or ``np.r_[:9:10j]``
- create an increasing vector (see note :ref:`RANGES
<numpy-for-matlab-users.notes>`)
* - ``[1:10]'``
- - ``arange(1.,11.)[:, newaxis]``
+ - ``np.arange(1.,11.)[:, np.newaxis]``
- create a column vector
* - ``zeros(3,4)``
- - ``zeros((3,4))``
+ - ``np.zeros((3, 4))``
- 3x4 two-dimensional array full of 64-bit floating point zeros
* - ``zeros(3,4,5)``
- - ``zeros((3,4,5))``
+ - ``np.zeros((3, 4, 5))``
- 3x4x5 three-dimensional array full of 64-bit floating point zeros
* - ``ones(3,4)``
- - ``ones((3,4))``
+ - ``np.ones((3, 4))``
- 3x4 two-dimensional array full of 64-bit floating point ones
* - ``eye(3)``
- - ``eye(3)``
+ - ``np.eye(3)``
- 3x3 identity matrix
* - ``diag(a)``
- - ``diag(a)``
- - vector of diagonal elements of ``a``
+ - ``np.diag(a)``
+ - returns a vector of the diagonal elements of 2D array, ``a``
+
+ * - ``diag(v,0)``
+ - ``np.diag(v, 0)``
+ - returns a square diagonal matrix whose nonzero values are the elements of
+ vector, ``v``
- * - ``diag(a,0)``
- - ``diag(a,0)``
- - square diagonal matrix whose nonzero values are the elements of
- ``a``
+ * - .. code:: matlab
+
+ rng(42,'twister')
+ rand(3,4)
- * - ``rand(3,4)``
- - ``random.rand(3,4)`` or ``random.random_sample((3, 4))``
- - random 3x4 matrix
+ - ::
+
+ from numpy.random import default_rng
+ rng = default_rng(42)
+ rng.random(3, 4)
+
+ or older version: ``random.rand((3, 4))``
+
+ - generate a random 3x4 array with default random number generator and
+ seed = 42
* - ``linspace(1,3,4)``
- - ``linspace(1,3,4)``
+ - ``np.linspace(1,3,4)``
- 4 equally spaced samples between 1 and 3, inclusive
* - ``[x,y]=meshgrid(0:8,0:5)``
- - ``mgrid[0:9.,0:6.]`` or ``meshgrid(r_[0:9.],r_[0:6.]``
+ - ``np.mgrid[0:9.,0:6.]`` or ``np.meshgrid(r_[0:9.],r_[0:6.]``
- two 2D arrays: one of x values, the other of y values
* -
- - ``ogrid[0:9.,0:6.]`` or ``ix_(r_[0:9.],r_[0:6.]``
+ - ``ogrid[0:9.,0:6.]`` or ``np.ix_(np.r_[0:9.],np.r_[0:6.]``
- the best way to eval functions on a grid
* - ``[x,y]=meshgrid([1,2,4],[2,4,5])``
- - ``meshgrid([1,2,4],[2,4,5])``
+ - ``np.meshgrid([1,2,4],[2,4,5])``
-
* -
- the best way to eval functions on a grid
* - ``repmat(a, m, n)``
- - ``tile(a, (m, n))``
+ - ``np.tile(a, (m, n))``
- create m by n copies of ``a``
* - ``[a b]``
- - ``concatenate((a,b),1)`` or ``hstack((a,b))`` or
- ``column_stack((a,b))`` or ``c_[a,b]``
+ - ``np.concatenate((a,b),1)`` or ``np.hstack((a,b))`` or
+ ``np.column_stack((a,b))`` or ``np.c_[a,b]``
- concatenate columns of ``a`` and ``b``
* - ``[a; b]``
- - ``concatenate((a,b))`` or ``vstack((a,b))`` or ``r_[a,b]``
+ - ``np.concatenate((a,b))`` or ``np.vstack((a,b))`` or ``np.r_[a,b]``
- concatenate rows of ``a`` and ``b``
* - ``max(max(a))``
- - ``a.max()``
- - maximum element of ``a`` (with ndims(a)<=2 for matlab)
+ - ``a.max()`` or ``np.nanmax(a)``
+ - maximum element of ``a`` (with ndims(a)<=2 for MATLAB, if there are
+ NaN's, ``nanmax`` will ignore these and return largest value)
* - ``max(a)``
- ``a.max(0)``
- - maximum element of each column of matrix ``a``
+ - maximum element of each column of array ``a``
* - ``max(a,[],2)``
- ``a.max(1)``
- - maximum element of each row of matrix ``a``
+ - maximum element of each row of array ``a``
* - ``max(a,b)``
- - ``maximum(a, b)``
+ - ``np.maximum(a, b)``
- compares ``a`` and ``b`` element-wise, and returns the maximum value
from each pair
* - ``norm(v)``
- - ``sqrt(v @ v)`` or ``np.linalg.norm(v)``
+ - ``np.sqrt(v @ v)`` or ``np.linalg.norm(v)``
- L2 norm of vector ``v``
* - ``a & b``
LOGICOPS <numpy-for-matlab-users.notes>`
* - ``a | b``
- - ``logical_or(a,b)``
+ - ``np.logical_or(a,b)``
- element-by-element OR operator (NumPy ufunc) :ref:`See note LOGICOPS
<numpy-for-matlab-users.notes>`
* - ``inv(a)``
- ``linalg.inv(a)``
- - inverse of square matrix ``a``
+ - inverse of square 2D array ``a``
* - ``pinv(a)``
- ``linalg.pinv(a)``
- - pseudo-inverse of matrix ``a``
+ - pseudo-inverse of 2D array ``a``
* - ``rank(a)``
- ``linalg.matrix_rank(a)``
- - matrix rank of a 2D array / matrix ``a``
+ - matrix rank of a 2D array ``a``
* - ``a\b``
- - ``linalg.solve(a,b)`` if ``a`` is square; ``linalg.lstsq(a,b)``
+ - ``linalg.solve(a, b)`` if ``a`` is square; ``linalg.lstsq(a, b)``
otherwise
- solution of a x = b for x
* - ``b/a``
- - Solve a.T x.T = b.T instead
+ - Solve ``a.T x.T = b.T`` instead
- solution of x a = b for x
* - ``[U,S,V]=svd(a)``
- ``U, S, Vh = linalg.svd(a), V = Vh.T``
- singular value decomposition of ``a``
- * - ``chol(a)``
- - ``linalg.cholesky(a).T``
- - cholesky factorization of a matrix (``chol(a)`` in matlab returns an
- upper triangular matrix, but ``linalg.cholesky(a)`` returns a lower
- triangular matrix)
+ * - ``c=chol(a)`` where ``a==c'*c``
+ - ``c = linalg.cholesky(a)`` where ``a == c@c.T``
+ - Cholesky factorization of a 2D array (``chol(a)`` in MATLAB returns an
+ upper triangular 2D array, but :func:`~scipy.linalg.cholesky` returns a lower
+ triangular 2D array)
* - ``[V,D]=eig(a)``
- ``D,V = linalg.eig(a)``
- - eigenvalues and eigenvectors of ``a``
+ - eigenvalues :math:`\lambda` and eigenvectors :math:`\bar{v}` of ``a``,
+ where :math:`\lambda\bar{v}=\mathbf{a}\bar{v}`
* - ``[V,D]=eig(a,b)``
- - ``D,V = scipy.linalg.eig(a,b)``
- - eigenvalues and eigenvectors of ``a``, ``b``
+ - ``D,V = linalg.eig(a, b)``
+ - eigenvalues :math:`\lambda` and eigenvectors :math:`\bar{v}` of
+ ``a``, ``b``
+ where :math:`\lambda\mathbf{b}\bar{v}=\mathbf{a}\bar{v}`
- * - ``[V,D]=eigs(a,k)``
- -
- - find the ``k`` largest eigenvalues and eigenvectors of ``a``
+ * - ``[V,D]=eigs(a,3)``
+ - ``D,V = eigs(a, k = 3)``
+ - find the ``k=3`` largest eigenvalues and eigenvectors of 2D array, ``a``
* - ``[Q,R,P]=qr(a,0)``
- - ``Q,R = scipy.linalg.qr(a)``
+ - ``Q,R = linalg.qr(a)``
- QR decomposition
- * - ``[L,U,P]=lu(a)``
- - ``L,U = scipy.linalg.lu(a)`` or ``LU,P=scipy.linalg.lu_factor(a)``
- - LU decomposition (note: P(Matlab) == transpose(P(numpy)) )
+ * - ``[L,U,P]=lu(a)`` where ``a==P'*L*U``
+ - ``P,L,U = linalg.lu(a)`` where ``a == P@L@U``
+ - LU decomposition (note: P(MATLAB) == transpose(P(NumPy)))
* - ``conjgrad``
- - ``scipy.sparse.linalg.cg``
+ - ``cg``
- Conjugate gradients solver
* - ``fft(a)``
- - ``fft(a)``
+ - ``np.fft(a)``
- Fourier transform of ``a``
* - ``ifft(a)``
- - ``ifft(a)``
+ - ``np.ifft(a)``
- inverse Fourier transform of ``a``
* - ``sort(a)``
- - ``sort(a)`` or ``a.sort()``
- - sort the matrix
+ - ``np.sort(a)`` or ``a.sort(axis=0)``
+ - sort each column of a 2D array, ``a``
- * - ``[b,I] = sortrows(a,i)``
- - ``I = argsort(a[:,i]), b=a[I,:]``
- - sort the rows of the matrix
+ * - ``sort(a, 2)``
+ - ``np.sort(a, axis = 1)`` or ``a.sort(axis = 1)``
+ - sort the each row of 2D array, ``a``
- * - ``regress(y,X)``
- - ``linalg.lstsq(X,y)``
- - multilinear regression
+ * - ``[b,I]=sortrows(a,1)``
+ - ``I = np.argsort(a[:, 0]); b = a[I,:]``
+ - save the array ``a`` as array ``b`` with rows sorted by the first column
+
+ * - ``x = Z\y``
+ - ``x = linalg.lstsq(Z, y)``
+ - perform a linear regression of the form :math:`\mathbf{Zx}=\mathbf{y}`
* - ``decimate(x, q)``
- - ``scipy.signal.resample(x, len(x)/q)``
+ - ``signal.resample(x, np.ceil(len(x)/q))``
- downsample with low-pass filtering
* - ``unique(a)``
- - ``unique(a)``
- -
+ - ``np.unique(a)``
+ - a vector of unique values in array ``a``
* - ``squeeze(a)``
- ``a.squeeze()``
- -
+ - remove singleton dimensions of array ``a``. Note that MATLAB will always
+ return arrays of 2D or higher while NumPy will return arrays of 0D or
+ higher
.. _numpy-for-matlab-users.notes:
=====
\ **Submatrix**: Assignment to a submatrix can be done with lists of
-indexes using the ``ix_`` command. E.g., for 2d array ``a``, one might
-do: ``ind=[1,3]; a[np.ix_(ind,ind)]+=100``.
+indices using the ``ix_`` command. E.g., for 2D array ``a``, one might
+do: ``ind=[1, 3]; a[np.ix_(ind, ind)] += 100``.
\ **HELP**: There is no direct equivalent of MATLAB's ``which`` command,
-but the commands ``help`` and ``source`` will usually list the filename
+but the commands :func:`help` and :func:`numpy.source` will usually list the filename
where the function is located. Python also has an ``inspect`` module (do
``import inspect``) which provides a ``getfile`` that often works.
-\ **INDEXING**: MATLAB® uses one based indexing, so the initial element
+\ **INDEXING**: MATLAB uses one based indexing, so the initial element
of a sequence has index 1. Python uses zero based indexing, so the
initial element of a sequence has index 0. Confusion and flamewars arise
because each has advantages and disadvantages. One based indexing is
See also `a text by prof.dr. Edsger W.
Dijkstra <https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html>`__.
-\ **RANGES**: In MATLAB®, ``0:5`` can be used as both a range literal
+\ **RANGES**: In MATLAB, ``0:5`` can be used as both a range literal
and a 'slice' index (inside parentheses); however, in Python, constructs
like ``0:5`` can *only* be used as a slice index (inside square
brackets). Thus the somewhat quirky ``r_`` object was created to allow
-numpy to have a similarly terse range construction mechanism. Note that
+NumPy to have a similarly terse range construction mechanism. Note that
``r_`` is not called like a function or a constructor, but rather
*indexed* using square brackets, which allows the use of Python's slice
syntax in the arguments.
-\ **LOGICOPS**: & or \| in NumPy is bitwise AND/OR, while in Matlab &
-and \| are logical AND/OR. The difference should be clear to anyone with
-significant programming experience. The two can appear to work the same,
-but there are important differences. If you would have used Matlab's &
-or \| operators, you should use the NumPy ufuncs
-logical\_and/logical\_or. The notable differences between Matlab's and
-NumPy's & and \| operators are:
+\ **LOGICOPS**: ``&`` or ``|`` in NumPy is bitwise AND/OR, while in MATLAB &
+and ``|`` are logical AND/OR. The two can appear to work the same,
+but there are important differences. If you would have used MATLAB's ``&``
+or ``|`` operators, you should use the NumPy ufuncs
+``logical_and``/``logical_or``. The notable differences between MATLAB's and
+NumPy's ``&`` and ``|`` operators are:
- Non-logical {0,1} inputs: NumPy's output is the bitwise AND of the
- inputs. Matlab treats any non-zero value as 1 and returns the logical
- AND. For example (3 & 4) in NumPy is 0, while in Matlab both 3 and 4
- are considered logical true and (3 & 4) returns 1.
+ inputs. MATLAB treats any non-zero value as 1 and returns the logical
+ AND. For example ``(3 & 4)`` in NumPy is ``0``, while in MATLAB both ``3``
+ and ``4``
+ are considered logical true and ``(3 & 4)`` returns ``1``.
- Precedence: NumPy's & operator is higher precedence than logical
- operators like < and >; Matlab's is the reverse.
+ operators like ``<`` and ``>``; MATLAB's is the reverse.
If you know you have boolean arguments, you can get away with using
-NumPy's bitwise operators, but be careful with parentheses, like this: z
-= (x > 1) & (x < 2). The absence of NumPy operator forms of logical\_and
-and logical\_or is an unfortunate consequence of Python's design.
+NumPy's bitwise operators, but be careful with parentheses, like this: ``z
+= (x > 1) & (x < 2)``. The absence of NumPy operator forms of ``logical_and``
+and ``logical_or`` is an unfortunate consequence of Python's design.
-**RESHAPE and LINEAR INDEXING**: Matlab always allows multi-dimensional
+**RESHAPE and LINEAR INDEXING**: MATLAB always allows multi-dimensional
arrays to be accessed using scalar or linear indices, NumPy does not.
-Linear indices are common in Matlab programs, e.g. find() on a matrix
+Linear indices are common in MATLAB programs, e.g. ``find()`` on a matrix
returns them, whereas NumPy's find behaves differently. When converting
-Matlab code it might be necessary to first reshape a matrix to a linear
+MATLAB code it might be necessary to first reshape a matrix to a linear
sequence, perform some indexing operations and then reshape back. As
reshape (usually) produces views onto the same storage, it should be
possible to do this fairly efficiently. Note that the scan order used by
-reshape in NumPy defaults to the 'C' order, whereas Matlab uses the
+reshape in NumPy defaults to the 'C' order, whereas MATLAB uses the
Fortran order. If you are simply converting to a linear sequence and
-back this doesn't matter. But if you are converting reshapes from Matlab
-code which relies on the scan order, then this Matlab code: z =
-reshape(x,3,4); should become z = x.reshape(3,4,order='F').copy() in
+back this doesn't matter. But if you are converting reshapes from MATLAB
+code which relies on the scan order, then this MATLAB code: ``z =
+reshape(x,3,4);`` should become ``z = x.reshape(3,4,order='F').copy()`` in
NumPy.
-Customizing Your Environment
+'array' or 'matrix'? Which should I use?
+========================================
+
+Historically, NumPy has provided a special matrix type, `np.matrix`, which
+is a subclass of ndarray which makes binary operations linear algebra
+operations. You may see it used in some existing code instead of `np.array`.
+So, which one to use?
+
+Short answer
+------------
+
+**Use arrays**.
+
+- They support multidimensional array algebra that is supported in MATLAB
+- They are the standard vector/matrix/tensor type of NumPy. Many NumPy
+ functions return arrays, not matrices.
+- There is a clear distinction between element-wise operations and
+ linear algebra operations.
+- You can have standard vectors or row/column vectors if you like.
+
+Until Python 3.5 the only disadvantage of using the array type was that you
+had to use ``dot`` instead of ``*`` to multiply (reduce) two tensors
+(scalar product, matrix vector multiplication etc.). Since Python 3.5 you
+can use the matrix multiplication ``@`` operator.
+
+Given the above, we intend to deprecate ``matrix`` eventually.
+
+Long answer
+-----------
+
+NumPy contains both an ``array`` class and a ``matrix`` class. The
+``array`` class is intended to be a general-purpose n-dimensional array
+for many kinds of numerical computing, while ``matrix`` is intended to
+facilitate linear algebra computations specifically. In practice there
+are only a handful of key differences between the two.
+
+- Operators ``*`` and ``@``, functions ``dot()``, and ``multiply()``:
+
+ - For ``array``, **``*`` means element-wise multiplication**, while
+ **``@`` means matrix multiplication**; they have associated functions
+ ``multiply()`` and ``dot()``. (Before Python 3.5, ``@`` did not exist
+ and one had to use ``dot()`` for matrix multiplication).
+ - For ``matrix``, **``*`` means matrix multiplication**, and for
+ element-wise multiplication one has to use the ``multiply()`` function.
+
+- Handling of vectors (one-dimensional arrays)
+
+ - For ``array``, the **vector shapes 1xN, Nx1, and N are all different
+ things**. Operations like ``A[:,1]`` return a one-dimensional array of
+ shape N, not a two-dimensional array of shape Nx1. Transpose on a
+ one-dimensional ``array`` does nothing.
+ - For ``matrix``, **one-dimensional arrays are always upconverted to 1xN
+ or Nx1 matrices** (row or column vectors). ``A[:,1]`` returns a
+ two-dimensional matrix of shape Nx1.
+
+- Handling of higher-dimensional arrays (ndim > 2)
+
+ - ``array`` objects **can have number of dimensions > 2**;
+ - ``matrix`` objects **always have exactly two dimensions**.
+
+- Convenience attributes
+
+ - ``array`` **has a .T attribute**, which returns the transpose of
+ the data.
+ - ``matrix`` **also has .H, .I, and .A attributes**, which return
+ the conjugate transpose, inverse, and ``asarray()`` of the matrix,
+ respectively.
+
+- Convenience constructor
+
+ - The ``array`` constructor **takes (nested) Python sequences as
+ initializers**. As in, ``array([[1,2,3],[4,5,6]])``.
+ - The ``matrix`` constructor additionally **takes a convenient
+ string initializer**. As in ``matrix("[1 2 3; 4 5 6]")``.
+
+There are pros and cons to using both:
+
+- ``array``
+
+ - ``:)`` Element-wise multiplication is easy: ``A*B``.
+ - ``:(`` You have to remember that matrix multiplication has its own
+ operator, ``@``.
+ - ``:)`` You can treat one-dimensional arrays as *either* row or column
+ vectors. ``A @ v`` treats ``v`` as a column vector, while
+ ``v @ A`` treats ``v`` as a row vector. This can save you having to
+ type a lot of transposes.
+ - ``:)`` ``array`` is the "default" NumPy type, so it gets the most
+ testing, and is the type most likely to be returned by 3rd party
+ code that uses NumPy.
+ - ``:)`` Is quite at home handling data of any number of dimensions.
+ - ``:)`` Closer in semantics to tensor algebra, if you are familiar
+ with that.
+ - ``:)`` *All* operations (``*``, ``/``, ``+``, ``-`` etc.) are
+ element-wise.
+ - ``:(`` Sparse matrices from ``scipy.sparse`` do not interact as well
+ with arrays.
+
+- ``matrix``
+
+ - ``:\\`` Behavior is more like that of MATLAB matrices.
+ - ``<:(`` Maximum of two-dimensional. To hold three-dimensional data you
+ need ``array`` or perhaps a Python list of ``matrix``.
+ - ``<:(`` Minimum of two-dimensional. You cannot have vectors. They must be
+ cast as single-column or single-row matrices.
+ - ``<:(`` Since ``array`` is the default in NumPy, some functions may
+ return an ``array`` even if you give them a ``matrix`` as an
+ argument. This shouldn't happen with NumPy functions (if it does
+ it's a bug), but 3rd party code based on NumPy may not honor type
+ preservation like NumPy does.
+ - ``:)`` ``A*B`` is matrix multiplication, so it looks just like you write
+ it in linear algebra (For Python >= 3.5 plain arrays have the same
+ convenience with the ``@`` operator).
+ - ``<:(`` Element-wise multiplication requires calling a function,
+ ``multiply(A,B)``.
+ - ``<:(`` The use of operator overloading is a bit illogical: ``*``
+ does not work element-wise but ``/`` does.
+ - Interaction with ``scipy.sparse`` is a bit cleaner.
+
+The ``array`` is thus much more advisable to use. Indeed, we intend to
+deprecate ``matrix`` eventually.
+
+Customizing your environment
============================
-In MATLAB® the main tool available to you for customizing the
+In MATLAB the main tool available to you for customizing the
environment is to modify the search path with the locations of your
favorite functions. You can put such customizations into a startup
script that MATLAB will run on startup.
interpreter is started, define the ``PYTHONSTARTUP`` environment
variable to contain the name of your startup script.
-Unlike MATLAB®, where anything on your path can be called immediately,
+Unlike MATLAB, where anything on your path can be called immediately,
with Python you need to first do an 'import' statement to make functions
in a particular file accessible.
# Make all numpy available via shorter 'np' prefix
import numpy as np
- # Make all matlib functions accessible at the top level via M.func()
- import numpy.matlib as M
- # Make some matlib functions accessible directly at the top level via, e.g. rand(3,3)
- from numpy.matlib import rand,zeros,ones,empty,eye
+ #
+ # Make the SciPy linear algebra functions available as linalg.func()
+ # e.g. linalg.lu, linalg.eig (for general l*B@u==A@u solution)
+ from scipy import linalg
+ #
# Define a Hermitian function
def hermitian(A, **kwargs):
- return np.transpose(A,**kwargs).conj()
- # Make some shortcuts for transpose,hermitian:
- # np.transpose(A) --> T(A)
+ return np.conj(A,**kwargs).T
+ # Make a shortcut for hermitian:
# hermitian(A) --> H(A)
- T = np.transpose
H = hermitian
+To use the deprecated `matrix` and other `matlib` functions:
+
+::
+
+ # Make all matlib functions accessible at the top level via M.func()
+ import numpy.matlib as M
+ # Make some matlib functions accessible directly at the top level via, e.g. rand(3,3)
+ from numpy.matlib import matrix,rand,zeros,ones,empty,eye
+
Links
=====
-See http://mathesaurus.sf.net/ for another MATLAB®/NumPy
-cross-reference.
+Another somewhat outdated MATLAB/NumPy cross-reference can be found at
+http://mathesaurus.sf.net/
-An extensive list of tools for scientific work with python can be
+An extensive list of tools for scientific work with Python can be
found in the `topical software page <https://scipy.org/topical-software.html>`__.
-MATLAB® and SimuLink® are registered trademarks of The MathWorks.
+See
+`List of Python software: scripting
+<https://en.wikipedia.org/wiki/List_of_Python_software#Embedded_as_a_scripting_language>`_
+for a list of softwares that use Python as a scripting language
+
+MATLAB® and SimuLink® are registered trademarks of The MathWorks, Inc.
===================
-Quickstart tutorial
+NumPy quickstart
===================
.. currentmodule:: numpy
Prerequisites
=============
-Before reading this tutorial you should know a bit of Python. If you
-would like to refresh your memory, take a look at the `Python
+You'll need to know a bit of Python. For a refresher, see the `Python
tutorial <https://docs.python.org/tutorial/>`__.
-If you wish to work the examples in this tutorial, you must also have
-some software installed on your computer. Please see
-https://scipy.org/install.html for instructions.
+To work the examples, you'll need ``matplotlib`` installed
+in addition to NumPy.
**Learner profile**
-This tutorial is intended as a quick overview of
-algebra and arrays in NumPy and want to understand how n-dimensional
+This is a quick overview of
+algebra and arrays in NumPy. It demonstrates how n-dimensional
(:math:`n>=2`) arrays are represented and can be manipulated. In particular, if
you don't know how to apply common functions to n-dimensional arrays (without
using for-loops), or if you want to understand axis and shape properties for
-n-dimensional arrays, this tutorial might be of help.
+n-dimensional arrays, this article might be of help.
**Learning Objectives**
-After this tutorial, you should be able to:
+After reading, you should be able to:
- Understand the difference between one-, two- and n-dimensional arrays in
NumPy;
Less Basic
==========
+.. _broadcasting-rules:
+
Broadcasting rules
------------------
"broadcast" array.
After application of the broadcasting rules, the sizes of all arrays
-must match. More details can be found in :doc:`basics.broadcasting`.
+must match. More details can be found in :ref:`basics.broadcasting`.
Advanced indexing and index tricks
==================================
[14, 13, 15, 17, 12]]])
The advantage of this version of reduce compared to the normal
-ufunc.reduce is that it makes use of the `Broadcasting
-Rules <Tentative_NumPy_Tutorial.html#head-c43f3f81719d84f09ae2b33a22eaf50b26333db8>`__
+ufunc.reduce is that it makes use of the
+:ref:`broadcasting rules <broadcasting-rules>`
in order to avoid creating an argument array the size of the output
times the number of vectors.
+++ /dev/null
-**********
-Setting up
-**********
-
-.. toctree::
- :maxdepth: 1
-
- whatisnumpy
- install
- troubleshooting-importerror
+:orphan:
+
+.. Reason for orphan: This page is referenced by the installation
+ instructions, which have moved from Sphinx to https://numpy.org/install.
+ All install links in Sphinx now point there, leaving no Sphinx references
+ to this page.
+
+
***************************
Troubleshooting ImportError
***************************
Using Eclipse/PyDev with Anaconda/conda Python (or environments)
----------------------------------------------------------------
-Please see the
+Please see the
`Anaconda Documentation <https://docs.anaconda.com/anaconda/user-guide/tasks/integration/eclipse-pydev/>`_
on how to properly configure Eclipse/PyDev to use Anaconda Python with specific
conda environments.
--- /dev/null
+=======================
+Tutorial: Masked Arrays
+=======================
+
+.. currentmodule:: numpy
+
+.. testsetup::
+
+ import numpy as np
+ np.random.seed(1)
+
+Prerequisites
+-------------
+
+Before reading this tutorial, you should know a bit of Python. If you
+would like to refresh your memory, take a look at the
+:doc:`Python tutorial <python:tutorial/index>`.
+
+If you want to be able to run the examples in this tutorial, you should also
+have `matplotlib <https://matplotlib.org/>`_ installed on your computer.
+
+Learner profile
+---------------
+
+This tutorial is for people who have a basic understanding of NumPy and want to
+understand how masked arrays and the :mod:`numpy.ma` module can be used in
+practice.
+
+Learning Objectives
+-------------------
+
+After this tutorial, you should be able to:
+
+- Understand what are masked arrays and how they can be created
+- Understand how to access and modify data for masked arrays
+- Decide when the use of masked arrays is appropriate in some of your
+ applications
+
+What are masked arrays?
+-----------------------
+
+Consider the following problem. You have a dataset with missing or invalid
+entries. If you're doing any kind of processing on this data, and want to
+`skip` or flag these unwanted entries without just deleting them, you may have
+to use conditionals or filter your data somehow. The :mod:`numpy.ma` module
+provides some of the same funcionality of
+:class:`NumPy ndarrays <numpy.ndarray>` with added structure to ensure
+invalid entries are not used in computation.
+
+From the :mod:`Reference Guide <numpy.ma>`:
+
+ A masked array is the combination of a standard :class:`numpy.ndarray` and
+ a **mask**. A mask is either ``nomask``, indicating that no value of the
+ associated array is invalid, or an array of booleans that determines for
+ each element of the associated array whether the value is valid or not.
+ When an element of the mask is ``False``, the corresponding element of the
+ associated array is valid and is said to be unmasked. When an element of
+ the mask is ``True``, the corresponding element of the associated array is
+ said to be masked (invalid).
+
+
+We can think of a :class:`MaskedArray <numpy.ma.MaskedArray>` as a
+combination of:
+
+- Data, as a regular :class:`numpy.ndarray` of any shape or datatype;
+- A boolean mask with the same shape as the data;
+- A ``fill_value``, a value that may be used to replace the invalid entries
+ in order to return a standard :class:`numpy.ndarray`.
+
+When can they be useful?
+------------------------
+
+There are a few situations where masked arrays can be more useful than just
+eliminating the invalid entries of an array:
+
+- When you want to preserve the values you masked for later processing, without
+ copying the array;
+- When you have to handle many arrays, each with their own mask. If the mask is
+ part of the array, you avoid bugs and the code is possibly more compact;
+- When you have different flags for missing or invalid values, and wish to
+ preserve these flags without replacing them in the original dataset, but
+ exclude them from computations;
+- If you can't avoid or eliminate missing values, but don't want to deal with
+ :class:`NaN <numpy.nan>` (Not A Number) values in your operations.
+
+Masked arrays are also a good idea since the :mod:`numpy.ma` module also
+comes with a specific implementation of most :term:`NumPy universal functions
+(ufuncs) <ufunc>`, which means that you can still apply fast vectorized
+functions and operations on masked data. The output is then a masked array.
+We'll see some examples of how this works in practice below.
+
+Using masked arrays to see COVID-19 data
+----------------------------------------
+
+From `Kaggle <https://www.kaggle.com/atilamadai/covid19>`_ it is possible to
+download a dataset with initial data about the COVID-19 outbreak in the
+beginning of 2020. We are going to look at a small subset of this data,
+contained in the file ``who_covid_19_sit_rep_time_series.csv``.
+
+.. ipython:: python
+
+ import numpy as np
+ import os
+ # The os.getcwd() function returns the current folder; you can change
+ # the filepath variable to point to the folder where you saved the .csv file
+ filepath = os.getcwd()
+ @suppress
+ filepath = os.path.join(filepath, "source", "user")
+ filename = os.path.join(filepath, "who_covid_19_sit_rep_time_series.csv")
+
+The data file contains data of different types and is organized as follows:
+
+- The first row is a header line that (mostly) describes the data in each column
+ that follow in the rows below, and beginning in the fourth column, the header
+ is the date of the observation.
+- The second through seventh row contain summary data that is of a different
+ type than that which we are going to examine, so we will need to exclude that
+ from the data with which we will work.
+- The numerical data we wish to work with begins at column 4, row 8, and extends
+ from there to the rightmost column and the lowermost row.
+
+Let's explore the data inside this file for the first 14 days of records. To
+gather data from the ``.csv`` file, we will use the :func:`numpy.genfromtxt`
+function, making sure we select only the columns with actual numbers instead of
+the first three columns which contain location data. We also skip the first 7
+rows of this file, since they contain other data we are not interested in.
+Separately, we will extract the information about dates and location for this
+data.
+
+.. ipython:: python
+
+ # Note we are using skip_header and usecols to read only portions of the
+ # data file into each variable.
+ # Read just the dates for columns 3-7 from the first row
+ dates = np.genfromtxt(filename, dtype=np.unicode_, delimiter=",",
+ max_rows=1, usecols=range(3, 17),
+ encoding="utf-8-sig")
+ # Read the names of the geographic locations from the first two
+ # columns, skipping the first seven rows
+ locations = np.genfromtxt(filename, dtype=np.unicode_, delimiter=",",
+ skip_header=7, usecols=(0, 1),
+ encoding="utf-8-sig")
+ # Read the numeric data from just the first 14 days
+ nbcases = np.genfromtxt(filename, dtype=np.int_, delimiter=",",
+ skip_header=7, usecols=range(3, 17),
+ encoding="utf-8-sig")
+
+Included in the :func:`numpy.genfromtxt` function call, we have selected the
+:class:`numpy.dtype` for each subset of the data (either an integer -
+:class:`numpy.int_` - or a string of characters - :class:`numpy.unicode_`). We
+have also used the ``encoding`` argument to select ``utf-8-sig`` as the encoding
+for the file (read more about encoding in the `official Python documentation
+<https://docs.python.org/3/library/codecs.html#encodings-and-unicode>`__). You
+can read more about the :func:`numpy.genfromtxt` function from
+the :func:`Reference Documentation <numpy.genfromtxt>` or from the
+:doc:`Basic IO tutorial <basics.io.genfromtxt>`.
+
+Exploring the data
+------------------
+
+First of all, we can plot the whole set of data we have and see what it looks
+like. In order to get a readable plot, we select only a few of the dates to
+show in our :func:`x-axis ticks <matplotlib.pyplot.xticks>`. Note also that in
+our plot command, we use ``nbcases.T`` (the transpose of the ``nbcases`` array)
+since this means we will plot each row of the file as a separate line. We choose
+to plot a dashed line (using the ``'--'`` line style). See the
+`matplotlib <https://matplotlib.org/>`_ documentation for more info on this.
+
+.. ipython:: python
+
+ import matplotlib.pyplot as plt
+ selected_dates = [0, 3, 11, 13]
+ plt.plot(dates, nbcases.T, '--');
+ plt.xticks(selected_dates, dates[selected_dates]);
+ @savefig plot_covid_1.png
+ plt.title("COVID-19 cumulative cases from Jan 21 to Feb 3 2020");
+
+.. note::
+
+ If you are executing the commands above in the IPython shell, it might be
+ necessary to use the command ``plt.show()`` to show the image window. Note
+ also that we use a semicolon at the end of a line to suppress its output, but
+ this is optional.
+
+The graph has a strange shape from January 24th to February 1st. It would be
+interesing to know where this data comes from. If we look at the ``locations``
+array we extracted from the ``.csv`` file, we can see that we have two columns,
+where the first would contain regions and the second would contain the name of
+the country. However, only the first few rows contain data for the the first
+column (province names in China). Following that, we only have country names. So
+it would make sense to group all the data from China into a single row. For
+this, we'll select from the ``nbcases`` array only the rows for which the
+second entry of the ``locations`` array corresponds to China. Next, we'll use
+the :func:`numpy.sum` function to sum all the selected rows (``axis=0``):
+
+.. ipython:: python
+
+ china_total = nbcases[locations[:, 1] == 'China'].sum(axis=0)
+ china_total
+
+Something's wrong with this data - we are not supposed to have negative values
+in a cumulative data set. What's going on?
+
+Missing data
+------------
+
+Looking at the data, here's what we find: there is a period with
+**missing data**:
+
+.. ipython:: python
+
+ nbcases
+
+All the ``-1`` values we are seeing come from :func:`numpy.genfromtxt`
+attempting to read missing data from the original ``.csv`` file. Obviously, we
+don't want to compute missing data as ``-1`` - we just want to skip this value
+so it doesn't interfere in our analysis. After importing the :mod:`numpy.ma`
+module, we'll create a new array, this time masking the invalid values:
+
+.. ipython:: python
+
+ from numpy import ma
+ nbcases_ma = ma.masked_values(nbcases, -1)
+
+If we look at the ``nbcases_ma`` masked array, this is what we have:
+
+.. ipython:: python
+
+ nbcases_ma
+
+We can see that this is a different kind of array. As mentioned in the
+introduction, it has three attributes (``data``, ``mask`` and ``fill_value``).
+Keep in mind that the ``mask`` attribute has a ``True`` value for elements
+corresponding to **invalid** data (represented by two dashes in the ``data``
+attribute).
+
+.. note::
+
+ Adding ``-1`` to missing data is not a problem with :func:`numpy.genfromtxt`;
+ in this particular case, substituting the missing value with ``0`` might have
+ been fine, but we'll see later that this is far from a general solution.
+ Also, it is possible to call the :func:`numpy.genfromtxt` function using the
+ ``usemask`` parameter. If ``usemask=True``, :func:`numpy.genfromtxt`
+ automatically returns a masked array.
+
+Let's try and see what the data looks like excluding the first row
+(data from the Hubei province in China) so we can look at the missing data more
+closely:
+
+.. ipython:: python
+
+ plt.plot(dates, nbcases_ma[1:].T, '--');
+ plt.xticks(selected_dates, dates[selected_dates]);
+ @savefig plot_covid_2.png
+ plt.title("COVID-19 cumulative cases from Jan 21 to Feb 3 2020");
+
+Now that our data has been masked, let's try summing up all the cases in China:
+
+.. ipython:: python
+
+ china_masked = nbcases_ma[locations[:, 1] == 'China'].sum(axis=0)
+ china_masked
+
+Note that ``china_masked`` is a masked array, so it has a different data
+structure than a regular NumPy array. Now, we can access its data directly by
+using the ``.data`` attribute:
+
+.. ipython:: python
+
+ china_total = china_masked.data
+ china_total
+
+That is better: no more negative values. However, we can still see that for some
+days, the cumulative number of cases seems to go down (from 835 to 10, for
+example), which does not agree with the definition of "cumulative data". If we
+look more closely at the data, we can see that in the period where there was
+missing data in mainland China, there was valid data for Hong Kong, Taiwan,
+Macau and "Unspecified" regions of China. Maybe we can remove those from the
+total sum of cases in China, to get a better understanding of the data.
+
+First, we'll identify the indices of locations in mainland China:
+
+.. ipython:: python
+
+ china_mask = ((locations[:, 1] == 'China') &
+ (locations[:, 0] != 'Hong Kong') &
+ (locations[:, 0] != 'Taiwan') &
+ (locations[:, 0] != 'Macau') &
+ (locations[:, 0] != 'Unspecified*'))
+
+Now, ``china_mask`` is an array of boolean values (``True`` or ``False``); we
+can check that the indices are what we wanted with the :func:`ma.nonzero` method
+for masked arrays:
+
+.. ipython:: python
+
+ china_mask.nonzero()
+
+Now we can correctly sum entries for mainland China:
+
+.. ipython:: python
+
+ china_total = nbcases_ma[china_mask].sum(axis=0)
+ china_total
+
+We can replace the data with this information and plot a new graph, focusing on
+Mainland China:
+
+.. ipython:: python
+
+ plt.plot(dates, china_total.T, '--');
+ plt.xticks(selected_dates, dates[selected_dates]);
+ @savefig plot_covid_3.png
+ plt.title("COVID-19 cumulative cases from Jan 21 to Feb 3 2020 - Mainland China");
+
+It's clear that masked arrays are the right solution here. We cannot represent
+the missing data without mischaracterizing the evolution of the curve.
+
+Fitting Data
+------------
+
+One possibility we can think of is to interpolate the missing data to estimate
+the number of cases in late January. Observe that we can select the masked
+elements using the ``.mask`` attribute:
+
+.. ipython:: python
+
+ china_total.mask
+ invalid = china_total[china_total.mask]
+ invalid
+
+We can also access the valid entries by using the logical negation for this
+mask:
+
+.. ipython:: python
+
+ valid = china_total[~china_total.mask]
+ valid
+
+Now, if we want to create a very simple approximation for this data, we should
+take into account the valid entries around the invalid ones. So first let's
+select the dates for which the data is valid. Note that we can use the mask
+from the ``china_total`` masked array to index the dates array:
+
+.. ipython:: python
+
+ dates[~china_total.mask]
+
+Finally, we can use the :func:`numpy.polyfit` and :func:`numpy.polyval`
+functions to create a cubic polynomial that fits the data as best as possible:
+
+.. ipython:: python
+
+ t = np.arange(len(china_total))
+ params = np.polyfit(t[~china_total.mask], valid, 3)
+ cubic_fit = np.polyval(params, t)
+ plt.plot(t, china_total);
+ @savefig plot_covid_4.png
+ plt.plot(t, cubic_fit, '--');
+
+This plot is not so readable since the lines seem to be over each other, so
+let's summarize in a more elaborate plot. We'll plot the real data when
+available, and show the cubic fit for unavailable data, using this fit to
+compute an estimate to the observed number of cases on January 28th 2020, 7 days
+after the beginning of the records:
+
+.. ipython:: python
+
+ plt.plot(t, china_total);
+ plt.plot(t[china_total.mask], cubic_fit[china_total.mask], '--', color='orange');
+ plt.plot(7, np.polyval(params, 7), 'r*');
+ plt.xticks([0, 7, 13], dates[[0, 7, 13]]);
+ plt.yticks([0, np.polyval(params, 7), 10000, 17500]);
+ plt.legend(['Mainland China', 'Cubic estimate', '7 days after start']);
+ @savefig plot_covid_5.png
+ plt.title("COVID-19 cumulative cases from Jan 21 to Feb 3 2020 - Mainland China\n"
+ "Cubic estimate for 7 days after start");
+
+More reading
+------------
+
+Topics not covered in this tutorial can be found in the documentation:
+
+- :func:`Hardmasks <numpy.ma.harden_mask>` vs. :func:`softmasks
+ <numpy.ma.soften_mask>`
+- :ref:`The numpy.ma module <maskedarray.generic>`
import numpy as np
np.random.seed(1)
-**Prerequisites**
+Prerequisites
+-------------
Before reading this tutorial, you should know a bit of Python. If you
would like to refresh your memory, take a look at the
have `matplotlib <https://matplotlib.org/>`_ and `SciPy <https://scipy.org>`_
installed on your computer.
-**Learner profile**
+Learner profile
+---------------
This tutorial is for people who have a basic understanding of linear
algebra and arrays in NumPy and want to understand how n-dimensional
using for-loops), or if you want to understand axis and shape properties for
n-dimensional arrays, this tutorial might be of help.
-**Learning Objectives**
+Learning Objectives
+-------------------
After this tutorial, you should be able to:
arrays without using for-loops;
- Understand axis and shape properties for n-dimensional arrays.
-**Content**
+Content
+-------
In this tutorial, we will use a `matrix decomposition
<https://en.wikipedia.org/wiki/Matrix_decomposition>`_ from linear algebra, the
If you are executing the commands above in the IPython shell, it might be
necessary to use the command ``plt.show()`` to show the image window.
-**Shape, axis and array properties**
+Shape, axis and array properties
+--------------------------------
Note that, in linear algebra, the dimension of a vector refers to the number of
entries in an array. In NumPy, it instead defines the number of axes. For
>>> green_array = img_array[:, :, 1]
>>> blue_array = img_array[:, :, 2]
-**Operations on an axis**
+Operations on an axis
+---------------------
It is possible to use methods from linear algebra to approximate an existing set
of data. Here, we will use the `SVD (Singular Value Decomposition)
Now, we want to check if the reconstructed ``U @ Sigma @ Vt`` is
close to the original ``img_gray`` matrix.
-**Approximation**
+Approximation
+-------------
The `linalg` module includes a ``norm`` function, which
computes the norm of a vector or matrix represented in a NumPy array. For
each of your experiments should give you a slightly better (or worse) image
depending on the value you choose.
-**Applying to all colors**
+Applying to all colors
+----------------------
Now we want to do the same kind of operation, but to all three colors. Our
first instinct might be to repeat the same operation we did above to each color
To build the final approximation matrix, we must understand how multiplication
across different axes works.
-**Products with n-dimensional arrays**
+Products with n-dimensional arrays
+----------------------------------
If you have worked before with only one- or two-dimensional arrays in NumPy,
you might use `numpy.dot` and `numpy.matmul` (or the ``@`` operator)
values (compared to the original set of 768 values), we can recover many of the
distinguishing features from this image.
-**Final words**
+Final words
+-----------
Of course, this is not the best method to *approximate* an image.
However, there is, in fact, a result in linear algebra that says that the
C. F. Van Loan, Matrix Computations, Baltimore, MD, Johns Hopkins University
Press, 1985*.
-**Further reading**
+Further reading
+---------------
- :doc:`Python tutorial <python:tutorial/index>`
- :ref:`reference`
.. toctree::
:maxdepth: 1
- basics
- misc
- numpy-for-matlab-users
tutorial-svd
- building
- c-info
+ tutorial-ma
+
different shapes, provided that the smaller array is "expandable" to
the shape of the larger in such a way that the resulting broadcast is
unambiguous. For detailed "rules" of broadcasting see
-`numpy.doc.broadcasting`.
+`basics.broadcasting`.
Who Else Uses NumPy?
--------------------
--- /dev/null
+Province/States,Country/Region,WHO region,1/21/20,1/22/20,1/23/20,1/24/20,1/25/20,1/26/20,1/27/20,1/28/20,1/29/20,1/30/20,1/31/20,2/1/20,2/2/20,2/3/20,2/4/20,2/5/20,2/6/20,2/7/20,2/8/20,2/9/20,2/10/20,2/11/20,2/12/20,2/13/20,2/14/20,2/15/20,2/16/20,2/17/20,2/18/20,2/19/20,2/20/20,2/21/20,2/22/20,2/23/20,2/24/20,2/25/20,2/26/20,2/27/20,2/28/20,2/29/20,3/1/20,3/2/20,3/3/20\r
+Confirmed,Globally,,282,314,581,846,1320,2014,2798,4593,6065,7818,9826,11953,14557,17391,20630,24554,28276,31481,34886,37558,40554,43103,45171,46997,49053,50580,51857,71429,73332,75204,75748,76769,77794,78811,79331,80239,81109,82294,83652,85403,87137,88948,90870\r
+Confirmed,Mainland China,Western Pacific Region,278,309,571,830,1297,1985,2741,4537,5997,7736,9720,11821,14411,17238,20471,24363,28060,31211,34598,37251,40235,42708,44730,46550,48548,50054,51174,70635,72528,74280,74675,75569,76392,77042,77262,77780,78191,78630,78961,79394,79968,80174,80304\r
+Confirmed,Outside of China,,4,5,10,16,23,29,57,56,68,82,106,132,146,153,159,191,216,270,288,307,319,395,441,447,505,526,683,794,804,924,1073,1200,1402,1769,2069,2459,2918,3664,4691,6009,7169,8774,10566\r
+Suspected,Mainland China,Western Pacific Region,,,,,,,5794,6973,9239,12167,15238,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+Severe,Mainland China,Western Pacific Region,,,,,,,461,976,1239,1370,1527,1795,2110,2296,2788,3219,3859,4821,6101,6188,6484,7333,8204,,,,,,,,,,,,,,,,,,,,\r
+Deaths,Mainland China,Western Pacific Region,,,,,,,80,106,132,170,213,259,304,361,425,491,564,637,723,812,909,1017,1114,1260,1381,1524,1666,1772,1870,2006,2121,2239,2348,2445,2595,2666,2718,2747,2791,2838,2873,2915,2946\r
+Hubei ,China,Western Pacific Region,258,270,375,375,,,,,,,,7153,9074,11177,13522,16678,19665,22112,24953,27100,29631,31728,33366,34874,51968,54406,56249,58182,59989,61682,62031,62662,63454,64084,64287,64786,65187,65596,65914,66337,66907,67103,67217\r
+Guangdong,China,Western Pacific Region,14,17,26,32,,,,,,,,520,604,683,797,870,944,1018,1075,1120,1151,1177,1219,1241,1261,1295,1316,1322,1328,1331,1332,1333,1339,1342,1345,1347,1347,1347,1348,1349,1349,1350,1350\r
+Henan,China,Western Pacific Region,,1,1,1,,,,,,,,422,493,566,675,764,851,914,981,1033,1073,1105,1135,1169,1184,1212,1231,1246,1257,1262,1265,1267,1270,1271,1271,1271,1271,1272,1272,1272,1272,1272,1272\r
+Zhejiang,China,Western Pacific Region,,5,5,5,,,,,,,,599,661,724,829,895,954,1006,1048,1075,1104,1117,1131,1145,1155,1162,1167,1171,1172,1173,1175,1203,1205,1205,1205,1205,1205,1205,1205,1205,1205,1206,1213\r
+Hunan,China,Western Pacific Region,,1,1,1,,,,,,,,389,463,521,593,661,711,772,803,838,879,912,946,968,988,1001,1004,1006,1007,1008,1010,1011,1013,1016,1016,1016,1016,1017,1017,1018,1018,1018,1018\r
+Anhui,China,Western Pacific Region,,,,,,,,,,,,297,340,408,480,530,591,665,733,779,830,860,889,910,934,950,962,973,982,986,987,988,989,989,989,989,989,989,990,990,990,990,990\r
+Jiangxi,China,Western Pacific Region,,1,2,2,,,,,,,,286,333,391,476,548,600,661,698,740,771,804,844,872,900,913,925,930,933,934,934,934,934,934,934,934,934,934,935,935,935,935,935\r
+Shandong,China,Western Pacific Region,,1,1,1,,,,,,,,202,225,246,270,298,343,379,407,435,459,486,497,506,519,530,537,541,543,544,546,748,750,754,755,755,756,756,756,756,756,758,758\r
+Jiangsu,China,Western Pacific Region,,,,,,,,,,,,202,231,271,308,341,373,408,439,468,492,515,543,570,593,604,617,626,629,631,631,631,631,631,631,631,631,631,631,631,631,631,631\r
+Chongqing,China,Western Pacific Region,,1,5,5,,,,,,,,238,262,300,337,366,389,411,426,446,468,486,505,518,529,537,544,551,553,555,560,567,572,573,575,576,576,576,576,576,576,576,576\r
+Sichuan,China,Western Pacific Region,,1,2,2,,,,,,,,207,236,254,282,301,321,344,363,386,405,417,436,451,463,470,481,495,508,514,520,525,526,526,527,529,531,534,538,538,538,538,538\r
+Heilongjiang,China,Western Pacific Region,,,,,,,,,,,,80,95,118,155,190,227,277,282,307,331,360,378,395,418,425,445,457,464,470,476,479,479,480,480,480,480,480,480,480,480,480,480\r
+Beijing,China,Western Pacific Region,5,5,10,10,,,,,,,,156,183,212,228,253,274,297,315,326,337,342,352,366,372,375,380,381,387,393,395,396,399,399,399,400,400,410,410,411,413,414,414\r
+Shanghai,China,Western Pacific Region,1,2,9,9,,,,,,,,153,177,193,208,233,254,269,281,292,295,302,306,313,318,326,328,331,333,333,333,334,334,335,335,335,336,337,337,337,337,337,338\r
+Hebei,China,Western Pacific Region,,,,,,,,,,,,96,104,113,126,135,157,171,195,206,218,239,251,265,283,291,300,301,302,306,307,308,309,311,311,311,312,317,318,318,318,318,318\r
+Fujian,China,Western Pacific Region,,,,,,,,,,,,144,159,179,194,205,215,224,239,250,261,267,272,279,281,285,287,290,292,293,293,293,293,293,293,294,294,296,296,296,296,296,296\r
+Guangxi,China,Western Pacific Region,,,,,,,,,,,,100,111,127,139,150,168,172,183,195,210,215,222,222,226,235,237,238,242,244,245,246,249,249,251,252,252,252,252,252,252,252,252\r
+Shaanxi,China,Western Pacific Region,,,,,,,,,,,,101,116,128,142,165,173,184,195,208,213,219,225,229,230,232,236,240,240,242,245,245,245,245,245,245,245,245,245,245,245,245,245\r
+Yunnan,China,Western Pacific Region,,1,1,1,,,,,,,,91,99,109,117,122,128,135,138,140,141,149,154,155,162,168,169,171,172,172,172,174,174,174,174,174,174,174,174,174,174,174,174\r
+Hainan,China,Western Pacific Region,,,,,,,,,,,,57,63,70,79,89,100,111,123,128,136,142,145,157,157,162,162,162,163,163,168,168,168,168,168,168,168,168,168,168,168,168,168\r
+Guizhou,China,Western Pacific Region,,,,,,,,,,,,29,38,46,56,64,69,77,89,96,109,118,131,135,140,143,144,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146\r
+Tianjin,China,Western Pacific Region,,2,2,2,,,,,,,,34,40,49,63,67,70,94,81,88,91,96,106,112,119,120,122,124,125,128,130,131,133,135,135,135,135,135,136,136,136,136,136\r
+Shanxi,China,Western Pacific Region,,,,,,,,,,,,47,56,66,74,81,90,96,104,115,119,122,124,126,126,127,128,129,130,131,131,132,132,132,132,133,133,133,133,133,133,133,133\r
+Liaoning,China,Western Pacific Region,,,,,,,,,,,,60,64,70,74,81,89,94,99,105,107,108,111,116,117,119,120,121,121,121,121,121,121,121,121,121,121,121,121,121,122,122,125\r
+Hong Kong,China,Western Pacific Region,,,1,2,5,5,8,8,8,10,12,13,14,15,15,18,21,24,26,26,36,42,49,50,53,56,56,57,60,62,65,68,68,70,74,81,85,91,93,94,95,98,101\r
+Jilin,China,Western Pacific Region,,,,,,,,,,,,17,21,31,42,54,59,65,69,78,80,81,83,84,86,88,88,89,89,90,91,91,91,91,93,93,93,93,93,93,93,93,93\r
+Gansu,China,Western Pacific Region,,,,,,,,,,,,35,45,51,56,57,62,70,71,81,85,86,86,87,90,90,90,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91\r
+Xinjiang,China,Western Pacific Region,,,,,,,,,,,,18,23,24,29,32,36,39,42,45,49,55,59,63,65,70,71,73,76,76,76,76,76,75,76,76,76,76,76,76,76,76,76\r
+Inner Mongolia,China,Western Pacific Region,,,,,,,,,,,,23,26,33,37,42,46,49,50,54,58,58,60,61,63,68,70,72,73,75,75,75,75,75,75,75,75,75,75,75,75,75,75\r
+Ningxia,China,Western Pacific Region,,,,,,,,,,,,26,28,31,34,34,40,43,45,45,49,53,58,64,67,70,70,70,70,71,71,71,71,71,71,71,71,72,72,73,73,74,74\r
+Taiwan,China,Western Pacific Region,,1,1,1,3,3,4,7,8,8,9,10,10,10,10,11,11,16,16,17,18,18,18,18,18,18,18,20,22,23,24,26,26,23,28,31,32,32,34,39,39,40,42\r
+Qinghai,China,Western Pacific Region,,,,,,,,,,,,8,9,13,15,17,18,18,18,18,18,18,18,18,18,18,18,18,18,12,18,18,18,18,18,18,18,18,18,18,18,18,18\r
+Macau,China,Western Pacific Region,,,1,2,2,2,5,7,7,7,7,7,7,8,8,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10\r
+Xizang,China,Western Pacific Region,,,,,,,,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1\r
+Unspecified*,China,Western Pacific Region,,,131,384,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+,Japan,Western Pacific Region,1,1,1,1,3,3,4,6,7,11,14,17,20,20,20,33,25,25,25,26,26,26,28,29,33,41,53,59,65,73,85,93,105,132,144,157,164,186,210,230,239,254,268\r
+,Republic of Korea,Western Pacific Region,1,1,1,2,2,2,4,4,4,4,11,12,15,15,16,18,23,24,24,27,27,28,28,28,28,28,29,30,31,51,104,204,346,602,763,977,1261,1766,2337,3150,3736,4212,4812\r
+,Thailand,South-East Asia Region,2,2,2,4,4,5,5,14,14,14,14,19,19,19,19,25,25,25,32,32,32,33,33,33,33,34,34,35,35,35,35,35,35,35,35,37,40,40,40,42,42,42,43\r
+,United States of America,Region of the Americas,,,1,1,2,2,5,5,5,5,6,7,8,11,11,11,12,12,12,12,12,13,13,14,15,15,15,15,15,15,15,15,35,35,35,53,53,59,59,62,62,62,64\r
+,Vietnam,Western Pacific Region,,,,2,2,2,2,2,2,2,5,6,7,8,9,10,10,12,13,14,14,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16\r
+,Singapore,Western Pacific Region,,,,1,3,3,4,7,7,10,13,16,18,18,18,24,28,30,33,40,43,45,47,50,58,67,72,75,77,81,84,85,86,89,89,90,91,93,96,98,102,106,108\r
+,Italy,European Region,,,,,,,,,,,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,9,76,124,229,322,400,650,888,1128,1689,2036\r
+,Nepal,South-East Asia Region,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1\r
+,Australia,Western Pacific Region,,,,,3,3,4,5,7,7,9,12,12,12,12,13,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17,21,21,21,22,23,23,23,24,25,27,33\r
+,Malaysia,Western Pacific Region,,,,,,3,4,4,4,7,8,8,8,8,10,10,12,14,15,17,18,18,18,18,19,21,22,22,22,22,22,22,22,22,22,22,22,22,24,24,24,24,29\r
+,Canada,Region of the Americas,,,,,,,1,2,3,3,3,4,4,4,4,5,5,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,9,9,10,10,11,11,14,19,19,27\r
+,Cambodia,Western Pacific Region,,,,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1\r
+,France,European Region,,,,,3,3,3,3,4,5,6,6,6,6,6,6,6,6,6,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,18,38,57,100,100,191\r
+,Sri Lanka,South-East Asia Region,,,,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1\r
+,Iran,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,5,18,28,43,61,95,141,245,388,593,978,1501\r
+,India,South-East Asia Region,,,,,,,,,,1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,5\r
+,Germany,European Region,,,,,,,,1,4,4,5,7,8,10,12,12,12,13,14,14,14,14,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,21,26,57,57,129,157\r
+,Philippines,Western Pacific Region,,,,,,,,,,1,1,1,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3\r
+,Spain,European Region,,,,,,,,,,,,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,12,25,32,45,45,114\r
+,United Kingdom,European Region,,,,,,,,,,,,2,2,2,2,2,2,3,3,3,4,8,8,9,9,9,9,9,9,9,9,9,9,9,9,13,13,13,16,20,23,36,39\r
+,Sweden,European Region,,,,,,,,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,7,12,13,14,15\r
+,Switzerland,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,6,10,18,26,30\r
+,Austria,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,2,4,5,10,10,18\r
+,Norway,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,4,6,15,19,25\r
+,Kuwait,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,8,12,43,43,45,45,56,56\r
+,Bahrain,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,26,33,33,38,40,47,49\r
+,United Arab Emirates,Eastern Mediterranean Region,,,,,,,,,4,4,4,4,5,5,5,5,5,5,7,7,7,8,8,8,8,8,8,9,9,9,9,9,11,13,13,13,13,13,19,19,19,21,21\r
+,Israel,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,2,2,2,3,5,7,7,10\r
+,Iraq,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,5,6,7,8,13,19,26\r
+,Oman,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,4,4,6,6,6,6,6\r
+,Lebanon,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,2,2,2,2,10,13\r
+,Pakistan,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,2,2,4,4,5\r
+,Egypt,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2\r
+,Croatia,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,3,3,5,7,7,9\r
+,Greece,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,3,3,3,7,7\r
+,Finland,European Region,,,,,,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,6,7\r
+,Algeria,African Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,1,5\r
+,Brazil,Region of the Americas,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,2,2,2\r
+,Russian,European Region,,,,,,,,,,,,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3\r
+,Belgium,European Region,,,,,,,,,,,,,,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,8\r
+,Denmark,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,2,3,4,5\r
+,Estonia,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,1\r
+,Georgia,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,2,3,3,3\r
+,North Macedonia,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,1\r
+,Romania,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,3,3,3,3\r
+,Afghanistan,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1,1,1,1\r
+,New Zealand,Western Pacific Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,2\r
+,Belarus,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1\r
+,Lithuania,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1\r
+,Netherlands,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,2,7,13,18\r
+,Nigeria,African Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,1,1\r
+,Mexico,Region of the Americas,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,2,5,5\r
+,San Marino,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1,8\r
+,Azerbaijan,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,3,3\r
+,Ireland,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1\r
+,Monaco,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,1\r
+,Qatar,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,3,7\r
+,Ecuador,Region of the Americas,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1,6\r
+,Czechia,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,3\r
+,Iceland,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,9\r
+,Armenia,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1\r
+,Luxembourg,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1\r
+,Indonesia,South-East Asia Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,2\r
+,Dominican Republic,Region of the Americas,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,1\r
+,Portugal,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2\r
+,Andorra,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1\r
+,Latvia,European Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1\r
+,Jordan,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1\r
+,Morocco,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1\r
+,Saudi Arabia,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1\r
+,Tunisia,Eastern Mediterranean Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1\r
+,Senegal,African Region,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1\r
+Case on an international conveyance,Other,Other,,,,,,,,,,,,,,,,,20,61,64,64,70,135,175,174,218,218,355,454,454,542,621,634,634,634,695,691,691,705,705,705,706,706,706
\ No newline at end of file
sphinx>=2.2.0,<3.0
+numpydoc==1.1.0
ipython
scipy
matplotlib
+pandas
+pydata-sphinx-theme==0.4.1
ctypedef long double npy_float128
ctypedef struct npy_cfloat:
- double real
- double imag
+ float real
+ float imag
ctypedef struct npy_cdouble:
double real
int64_t num
cdef extern from "numpy/arrayscalars.h":
+
+ # abstract types
+ ctypedef class numpy.generic [object PyObject]:
+ pass
+ ctypedef class numpy.number [object PyObject]:
+ pass
+ ctypedef class numpy.integer [object PyObject]:
+ pass
+ ctypedef class numpy.signedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.unsignedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.inexact [object PyObject]:
+ pass
+ ctypedef class numpy.floating [object PyObject]:
+ pass
+ ctypedef class numpy.complexfloating [object PyObject]:
+ pass
+ ctypedef class numpy.flexible [object PyObject]:
+ pass
+ ctypedef class numpy.character [object PyObject]:
+ pass
+
ctypedef struct PyDatetimeScalarObject:
# PyObject_HEAD
npy_datetime obval
cdef extern from "Python.h":
ctypedef int Py_intptr_t
+ bint PyObject_TypeCheck(object obj, PyTypeObject* type)
cdef extern from "numpy/arrayobject.h":
ctypedef Py_intptr_t npy_intp
cdef int type_num
cdef int itemsize "elsize"
cdef int alignment
- cdef dict fields
+ cdef object fields
cdef tuple names
# Use PyDataType_HASSUBARRAY to test whether this field is
# valid (the pointer can be NULL). Most users should access
ctypedef long double npy_float128
ctypedef struct npy_cfloat:
- double real
- double imag
+ float real
+ float imag
ctypedef struct npy_cdouble:
double real
return ()
+cdef extern from "numpy/ndarrayobject.h":
+ PyTypeObject PyTimedeltaArrType_Type
+ PyTypeObject PyDatetimeArrType_Type
+ ctypedef int64_t npy_timedelta
+ ctypedef int64_t npy_datetime
+
+cdef extern from "numpy/ndarraytypes.h":
+ ctypedef struct PyArray_DatetimeMetaData:
+ NPY_DATETIMEUNIT base
+ int64_t num
+
+cdef extern from "numpy/arrayscalars.h":
+
+ # abstract types
+ ctypedef class numpy.generic [object PyObject]:
+ pass
+ ctypedef class numpy.number [object PyObject]:
+ pass
+ ctypedef class numpy.integer [object PyObject]:
+ pass
+ ctypedef class numpy.signedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.unsignedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.inexact [object PyObject]:
+ pass
+ ctypedef class numpy.floating [object PyObject]:
+ pass
+ ctypedef class numpy.complexfloating [object PyObject]:
+ pass
+ ctypedef class numpy.flexible [object PyObject]:
+ pass
+ ctypedef class numpy.character [object PyObject]:
+ pass
+
+ ctypedef struct PyDatetimeScalarObject:
+ # PyObject_HEAD
+ npy_datetime obval
+ PyArray_DatetimeMetaData obmeta
+
+ ctypedef struct PyTimedeltaScalarObject:
+ # PyObject_HEAD
+ npy_timedelta obval
+ PyArray_DatetimeMetaData obmeta
+
+ ctypedef enum NPY_DATETIMEUNIT:
+ NPY_FR_Y
+ NPY_FR_M
+ NPY_FR_W
+ NPY_FR_D
+ NPY_FR_B
+ NPY_FR_h
+ NPY_FR_m
+ NPY_FR_s
+ NPY_FR_ms
+ NPY_FR_us
+ NPY_FR_ns
+ NPY_FR_ps
+ NPY_FR_fs
+ NPY_FR_as
+
+
#
# ufunc API
#
"""
/* NumPy API declarations from "numpy/__init__.pxd" */
"""
+
+
+cdef inline bint is_timedelta64_object(object obj):
+ """
+ Cython equivalent of `isinstance(obj, np.timedelta64)`
+
+ Parameters
+ ----------
+ obj : object
+
+ Returns
+ -------
+ bool
+ """
+ return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type)
+
+
+cdef inline bint is_datetime64_object(object obj):
+ """
+ Cython equivalent of `isinstance(obj, np.datetime64)`
+
+ Parameters
+ ----------
+ obj : object
+
+ Returns
+ -------
+ bool
+ """
+ return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type)
+
+
+cdef inline npy_datetime get_datetime64_value(object obj) nogil:
+ """
+ returns the int64 value underlying scalar numpy datetime64 object
+
+ Note that to interpret this as a datetime, the corresponding unit is
+ also needed. That can be found using `get_datetime64_unit`.
+ """
+ return (<PyDatetimeScalarObject*>obj).obval
+
+
+cdef inline npy_timedelta get_timedelta64_value(object obj) nogil:
+ """
+ returns the int64 value underlying scalar numpy timedelta64 object
+ """
+ return (<PyTimedeltaScalarObject*>obj).obval
+
+
+cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil:
+ """
+ returns the unit part of the dtype for a numpy datetime64 object.
+ """
+ return <NPY_DATETIMEUNIT>(<PyDatetimeScalarObject*>obj).obmeta.base
show_config
Show numpy build configuration
dual
- Overwrite certain functions with high-performance Scipy tools
+ Overwrite certain functions with high-performance SciPy tools.
+ Note: `numpy.dual` is deprecated. Use the functions from NumPy or Scipy
+ directly instead of importing them from `numpy.dual`.
matlib
Make everything matrices.
__version__
else:
try:
from numpy.__config__ import show as show_config
- except ImportError:
+ except ImportError as e:
msg = """Error importing numpy: you should not try to import numpy from
its source directory; please exit the numpy source tree, and relaunch
your python interpreter from there."""
- raise ImportError(msg)
+ raise ImportError(msg) from e
from .version import git_revision as __git_revision__
from .version import version as __version__
__all__ = ['ModuleDeprecationWarning',
'VisibleDeprecationWarning']
+ # mapping of {name: (value, deprecation_msg)}
+ __deprecated_attrs__ = {}
+
# Allow distributors to run custom init code
from . import _distributor_init
from . import matrixlib as _mat
from .matrixlib import *
- # Make these accessible from numpy name-space
- # but not imported in from numpy import *
- # TODO[gh-6103]: Deprecate these
- from builtins import bool, int, float, complex, object, str
- from .compat import long, unicode
+ # Deprecations introduced in NumPy 1.20.0, 2020-06-06
+ import builtins as _builtins
+
+ _msg = (
+ "`np.{n}` is a deprecated alias for the builtin `{n}`. "
+ "To silence this warning, use `{n}` by itself. Doing this will not "
+ "modify any behavior and is safe. {extended_msg}\n"
+ "Deprecated in NumPy 1.20; for more details and guidance: "
+ "https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations")
+
+ _specific_msg = (
+ "If you specifically wanted the numpy scalar type, use `np.{}` here.")
+
+ _int_extended_msg = (
+ "When replacing `np.{}`, you may wish to use e.g. `np.int64` "
+ "or `np.int32` to specify the precision. If you wish to review "
+ "your current use, check the release note link for "
+ "additional information.")
+
+ _type_info = [
+ ("object", ""), # The NumPy scalar only exists by name.
+ ("bool", _specific_msg.format("bool_")),
+ ("float", _specific_msg.format("float64")),
+ ("complex", _specific_msg.format("complex128")),
+ ("str", _specific_msg.format("str_")),
+ ("int", _int_extended_msg.format("int"))]
+
+ __deprecated_attrs__.update({
+ n: (getattr(_builtins, n), _msg.format(n=n, extended_msg=extended_msg))
+ for n, extended_msg in _type_info
+ })
+
+ _msg = (
+ "`np.{n}` is a deprecated alias for `np.compat.{n}`. "
+ "To silence this warning, use `np.compat.{n}` by itself. "
+ "In the likely event your code does not need to work on Python 2 "
+ "you can use the builtin `{n2}` for which `np.compat.{n}` is itself "
+ "an alias. Doing this will not modify any behaviour and is safe. "
+ "{extended_msg}\n"
+ "Deprecated in NumPy 1.20; for more details and guidance: "
+ "https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations")
+
+ __deprecated_attrs__["long"] = (
+ getattr(compat, "long"),
+ _msg.format(n="long", n2="int",
+ extended_msg=_int_extended_msg.format("long")))
+
+ __deprecated_attrs__["unicode"] = (
+ getattr(compat, "long"),
+ _msg.format(n="unciode", n2="str",
+ extended_msg=_specific_msg.format("str_")))
+
+ del _msg, _specific_msg, _int_extended_msg, _type_info, _builtins
from .core import round, abs, max, min
# now that numpy modules are imported, can initialize limits
__all__.extend(lib.__all__)
__all__.extend(['linalg', 'fft', 'random', 'ctypeslib', 'ma'])
- # These are added by `from .core import *` and `core.__all__`, but we
- # overwrite them above with builtins we do _not_ want to export.
+ # These are exported by np.core, but are replaced by the builtins below
+ # remove them to ensure that we don't end up with `np.long == np.int_`,
+ # which would be a breaking change.
+ del long, unicode
__all__.remove('long')
__all__.remove('unicode')
__all__.remove('Arrayterator')
del Arrayterator
+ # These names were removed in NumPy 1.20. For at least one release,
+ # attempts to access these names in the numpy namespace will trigger
+ # a warning, and calling the function will raise an exception.
+ _financial_names = ['fv', 'ipmt', 'irr', 'mirr', 'nper', 'npv', 'pmt',
+ 'ppmt', 'pv', 'rate']
+ __expired_functions__ = {
+ name: (f'In accordance with NEP 32, the function {name} was removed '
+ 'from NumPy version 1.20. A replacement for this function '
+ 'is available in the numpy_financial library: '
+ 'https://pypi.org/project/numpy-financial')
+ for name in _financial_names}
+
# Filter out Cython harmless warnings
warnings.filterwarnings("ignore", message="numpy.dtype size changed")
warnings.filterwarnings("ignore", message="numpy.ufunc size changed")
numarray = 'removed'
if sys.version_info[:2] >= (3, 7):
- # Importing Tester requires importing all of UnitTest which is not a
- # cheap import Since it is mainly used in test suits, we lazy import it
- # here to save on the order of 10 ms of import time for most users
- #
- # The previous way Tester was imported also had a side effect of adding
- # the full `numpy.testing` namespace
- #
# module level getattr is only supported in 3.7 onwards
# https://www.python.org/dev/peps/pep-0562/
def __getattr__(attr):
+ # Warn for expired attributes, and return a dummy function
+ # that always raises an exception.
+ try:
+ msg = __expired_functions__[attr]
+ except KeyError:
+ pass
+ else:
+ warnings.warn(msg, DeprecationWarning, stacklevel=2)
+
+ def _expired(*args, **kwds):
+ raise RuntimeError(msg)
+
+ return _expired
+
+ # Emit warnings for deprecated attributes
+ try:
+ val, msg = __deprecated_attrs__[attr]
+ except KeyError:
+ pass
+ else:
+ warnings.warn(msg, DeprecationWarning, stacklevel=2)
+ return val
+
+ # Importing Tester requires importing all of UnitTest which is not a
+ # cheap import Since it is mainly used in test suits, we lazy import it
+ # here to save on the order of 10 ms of import time for most users
+ #
+ # The previous way Tester was imported also had a side effect of adding
+ # the full `numpy.testing` namespace
if attr == 'testing':
import numpy.testing as testing
return testing
elif attr == 'Tester':
from .testing import Tester
return Tester
- else:
- raise AttributeError("module {!r} has no attribute "
- "{!r}".format(__name__, attr))
+
+ raise AttributeError("module {!r} has no attribute "
+ "{!r}".format(__name__, attr))
def __dir__():
return list(globals().keys() | {'Tester', 'testing'})
# no-one else in the world is using it (though I hope not)
from .testing import Tester
+ # We weren't able to emit a warning about these, so keep them around
+ globals().update({
+ k: v
+ for k, (v, msg) in __deprecated_attrs__.items()
+ })
+
+
# Pytest testing
from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
"by incorrect BLAS library being linked in, or by mixing "
"package managers (pip, conda, apt, ...). Search closed "
"numpy issues for similar problems.")
- raise RuntimeError(msg.format(__file__))
+ raise RuntimeError(msg.format(__file__)) from None
_sanity_check()
del _sanity_check
error_message = "{}: {}".format(w[-1].category.__name__, str(w[-1].message))
msg = (
"Polyfit sanity test emitted a warning, most likely due "
- "to using a buggy Accelerate backend. "
- "If you compiled yourself, "
- "see site.cfg.example for information. "
+ "to using a buggy Accelerate backend. If you compiled "
+ "yourself, more information is available at "
+ "https://numpy.org/doc/stable/user/building.html#accelerated-blas-lapack-libraries "
"Otherwise report this to the vendor "
- "that provided NumPy.\n{}\n".format(
- error_message))
+ "that provided NumPy.\n{}\n".format(error_message))
raise RuntimeError(msg)
del _mac_os_check
- def _win_os_check():
- """
- Quick Sanity check for Windows OS: look for fmod bug issue 16744.
- """
- try:
- a = arange(13 * 13, dtype= float64).reshape(13, 13)
- a = a % 17 # calls fmod
- linalg.eig(a)
- except Exception:
- msg = ("The current Numpy installation ({!r}) fails to "
- "pass a sanity check due to a bug in the windows runtime. "
- "See this issue for more information: "
- "https://tinyurl.com/y3dm3h86")
- raise RuntimeError(msg.format(__file__)) from None
-
- if sys.platform == "win32" and sys.maxsize > 2**32:
- _win_os_check()
-
- del _win_os_check
-
# We usually use madvise hugepages support, but on some old kernels it
# is slow and thus better avoided.
# Specifically kernel version 4.6 had a bug fix which probably fixed this:
--- /dev/null
+import builtins
+import sys
+import datetime as dt
+from abc import abstractmethod
+from types import TracebackType
+from contextlib import ContextDecorator
+
+from numpy.core._internal import _ctypes
+from numpy.typing import (
+ ArrayLike,
+ DTypeLike,
+ _Shape,
+ _ShapeLike,
+ _CharLike,
+ _BoolLike,
+ _IntLike,
+ _FloatLike,
+ _ComplexLike,
+ _NumberLike,
+ _SupportsDType,
+ _VoidDTypeLike,
+ NBitBase,
+ _64Bit,
+ _32Bit,
+ _16Bit,
+ _8Bit,
+)
+from numpy.typing._callable import (
+ _BoolOp,
+ _BoolBitOp,
+ _BoolSub,
+ _BoolTrueDiv,
+ _BoolMod,
+ _BoolDivMod,
+ _TD64Div,
+ _IntTrueDiv,
+ _UnsignedIntOp,
+ _UnsignedIntBitOp,
+ _UnsignedIntMod,
+ _UnsignedIntDivMod,
+ _SignedIntOp,
+ _SignedIntBitOp,
+ _SignedIntMod,
+ _SignedIntDivMod,
+ _FloatOp,
+ _FloatMod,
+ _FloatDivMod,
+ _ComplexOp,
+ _NumberOp,
+)
+
+from typing import (
+ Any,
+ ByteString,
+ Callable,
+ Container,
+ Callable,
+ Dict,
+ Generic,
+ IO,
+ Iterable,
+ List,
+ Mapping,
+ Optional,
+ overload,
+ Sequence,
+ Sized,
+ SupportsComplex,
+ SupportsFloat,
+ SupportsInt,
+ Text,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+)
+
+if sys.version_info >= (3, 8):
+ from typing import Literal, Protocol, SupportsIndex, Final
+else:
+ from typing_extensions import Literal, Protocol, Final
+ class SupportsIndex(Protocol):
+ def __index__(self) -> int: ...
+
+# Ensures that the stubs are picked up
+from numpy import (
+ char,
+ ctypeslib,
+ emath,
+ fft,
+ lib,
+ linalg,
+ ma,
+ matrixlib,
+ polynomial,
+ random,
+ rec,
+ testing,
+ version,
+)
+
+from numpy.core.function_base import (
+ linspace,
+ logspace,
+ geomspace,
+)
+
+from numpy.core.fromnumeric import (
+ take,
+ reshape,
+ choose,
+ repeat,
+ put,
+ swapaxes,
+ transpose,
+ partition,
+ argpartition,
+ sort,
+ argsort,
+ argmax,
+ argmin,
+ searchsorted,
+ resize,
+ squeeze,
+ diagonal,
+ trace,
+ ravel,
+ nonzero,
+ shape,
+ compress,
+ clip,
+ sum,
+ all,
+ any,
+ cumsum,
+ ptp,
+ amax,
+ amin,
+ prod,
+ cumprod,
+ ndim,
+ size,
+ around,
+ mean,
+ std,
+ var,
+)
+
+from numpy.core._asarray import (
+ asarray as asarray,
+ asanyarray as asanyarray,
+ ascontiguousarray as ascontiguousarray,
+ asfortranarray as asfortranarray,
+ require as require,
+)
+
+from numpy.core._type_aliases import (
+ sctypes as sctypes,
+ sctypeDict as sctypeDict,
+)
+
+from numpy.core._ufunc_config import (
+ seterr as seterr,
+ geterr as geterr,
+ setbufsize as setbufsize,
+ getbufsize as getbufsize,
+ seterrcall as seterrcall,
+ geterrcall as geterrcall,
+ _SupportsWrite,
+ _ErrKind,
+ _ErrFunc,
+ _ErrDictOptional,
+)
+
+from numpy.core.numeric import (
+ zeros_like as zeros_like,
+ ones as ones,
+ ones_like as ones_like,
+ empty_like as empty_like,
+ full as full,
+ full_like as full_like,
+ count_nonzero as count_nonzero,
+ isfortran as isfortran,
+ argwhere as argwhere,
+ flatnonzero as flatnonzero,
+ correlate as correlate,
+ convolve as convolve,
+ outer as outer,
+ tensordot as tensordot,
+ roll as roll,
+ rollaxis as rollaxis,
+ moveaxis as moveaxis,
+ cross as cross,
+ indices as indices,
+ fromfunction as fromfunction,
+ isscalar as isscalar,
+ binary_repr as binary_repr,
+ base_repr as base_repr,
+ identity as identity,
+ allclose as allclose,
+ isclose as isclose,
+ array_equal as array_equal,
+ array_equiv as array_equiv,
+)
+
+from numpy.core.numerictypes import (
+ maximum_sctype as maximum_sctype,
+ issctype as issctype,
+ obj2sctype as obj2sctype,
+ issubclass_ as issubclass_,
+ issubsctype as issubsctype,
+ issubdtype as issubdtype,
+ sctype2char as sctype2char,
+ find_common_type as find_common_type,
+)
+
+from numpy.core.shape_base import (
+ atleast_1d as atleast_1d,
+ atleast_2d as atleast_2d,
+ atleast_3d as atleast_3d,
+ block as block,
+ hstack as hstack,
+ stack as stack,
+ vstack as vstack,
+)
+
+# Add an object to `__all__` if their stubs are defined in an external file;
+# their stubs will not be recognized otherwise.
+# NOTE: This is redundant for objects defined within this file.
+__all__ = [
+ "linspace",
+ "logspace",
+ "geomspace",
+ "take",
+ "reshape",
+ "choose",
+ "repeat",
+ "put",
+ "swapaxes",
+ "transpose",
+ "partition",
+ "argpartition",
+ "sort",
+ "argsort",
+ "argmax",
+ "argmin",
+ "searchsorted",
+ "resize",
+ "squeeze",
+ "diagonal",
+ "trace",
+ "ravel",
+ "nonzero",
+ "shape",
+ "compress",
+ "clip",
+ "sum",
+ "all",
+ "any",
+ "cumsum",
+ "ptp",
+ "amax",
+ "amin",
+ "prod",
+ "cumprod",
+ "ndim",
+ "size",
+ "around",
+ "mean",
+ "std",
+ "var",
+]
+
+DataSource: Any
+MachAr: Any
+ScalarType: Any
+angle: Any
+append: Any
+apply_along_axis: Any
+apply_over_axes: Any
+arange: Any
+array2string: Any
+array_repr: Any
+array_split: Any
+array_str: Any
+asarray_chkfinite: Any
+asfarray: Any
+asmatrix: Any
+asscalar: Any
+average: Any
+bartlett: Any
+bincount: Any
+bitwise_not: Any
+blackman: Any
+bmat: Any
+bool8: Any
+broadcast: Any
+broadcast_arrays: Any
+broadcast_to: Any
+busday_count: Any
+busday_offset: Any
+busdaycalendar: Any
+byte: Any
+byte_bounds: Any
+bytes0: Any
+c_: Any
+can_cast: Any
+cast: Any
+cdouble: Any
+cfloat: Any
+chararray: Any
+clongdouble: Any
+clongfloat: Any
+column_stack: Any
+common_type: Any
+compare_chararrays: Any
+complex256: Any
+complex_: Any
+concatenate: Any
+conj: Any
+copy: Any
+copyto: Any
+corrcoef: Any
+cov: Any
+csingle: Any
+cumproduct: Any
+datetime_as_string: Any
+datetime_data: Any
+delete: Any
+deprecate: Any
+deprecate_with_doc: Any
+diag: Any
+diag_indices: Any
+diag_indices_from: Any
+diagflat: Any
+diff: Any
+digitize: Any
+disp: Any
+divide: Any
+dot: Any
+double: Any
+dsplit: Any
+dstack: Any
+ediff1d: Any
+einsum: Any
+einsum_path: Any
+expand_dims: Any
+extract: Any
+eye: Any
+fill_diagonal: Any
+finfo: Any
+fix: Any
+flip: Any
+fliplr: Any
+flipud: Any
+float128: Any
+float_: Any
+format_float_positional: Any
+format_float_scientific: Any
+format_parser: Any
+frombuffer: Any
+fromfile: Any
+fromiter: Any
+frompyfunc: Any
+fromregex: Any
+fromstring: Any
+genfromtxt: Any
+get_include: Any
+get_printoptions: Any
+geterrobj: Any
+gradient: Any
+half: Any
+hamming: Any
+hanning: Any
+histogram: Any
+histogram2d: Any
+histogram_bin_edges: Any
+histogramdd: Any
+hsplit: Any
+i0: Any
+iinfo: Any
+imag: Any
+in1d: Any
+index_exp: Any
+info: Any
+inner: Any
+insert: Any
+int0: Any
+int_: Any
+intc: Any
+interp: Any
+intersect1d: Any
+intp: Any
+is_busday: Any
+iscomplex: Any
+iscomplexobj: Any
+isin: Any
+isneginf: Any
+isposinf: Any
+isreal: Any
+isrealobj: Any
+iterable: Any
+ix_: Any
+kaiser: Any
+kron: Any
+lexsort: Any
+load: Any
+loads: Any
+loadtxt: Any
+longcomplex: Any
+longdouble: Any
+longfloat: Any
+longlong: Any
+lookfor: Any
+mafromtxt: Any
+mask_indices: Any
+mat: Any
+matrix: Any
+max: Any
+may_share_memory: Any
+median: Any
+memmap: Any
+meshgrid: Any
+mgrid: Any
+min: Any
+min_scalar_type: Any
+mintypecode: Any
+mod: Any
+msort: Any
+nan_to_num: Any
+nanargmax: Any
+nanargmin: Any
+nancumprod: Any
+nancumsum: Any
+nanmax: Any
+nanmean: Any
+nanmedian: Any
+nanmin: Any
+nanpercentile: Any
+nanprod: Any
+nanquantile: Any
+nanstd: Any
+nansum: Any
+nanvar: Any
+nbytes: Any
+ndenumerate: Any
+ndfromtxt: Any
+ndindex: Any
+nditer: Any
+nested_iters: Any
+newaxis: Any
+numarray: Any
+object0: Any
+ogrid: Any
+packbits: Any
+pad: Any
+percentile: Any
+piecewise: Any
+place: Any
+poly: Any
+poly1d: Any
+polyadd: Any
+polyder: Any
+polydiv: Any
+polyfit: Any
+polyint: Any
+polymul: Any
+polysub: Any
+polyval: Any
+printoptions: Any
+product: Any
+promote_types: Any
+put_along_axis: Any
+putmask: Any
+quantile: Any
+r_: Any
+ravel_multi_index: Any
+real: Any
+real_if_close: Any
+recarray: Any
+recfromcsv: Any
+recfromtxt: Any
+record: Any
+result_type: Any
+roots: Any
+rot90: Any
+round: Any
+round_: Any
+row_stack: Any
+s_: Any
+save: Any
+savetxt: Any
+savez: Any
+savez_compressed: Any
+select: Any
+set_printoptions: Any
+set_string_function: Any
+setdiff1d: Any
+seterrobj: Any
+setxor1d: Any
+shares_memory: Any
+short: Any
+show_config: Any
+sinc: Any
+single: Any
+singlecomplex: Any
+sort_complex: Any
+source: Any
+split: Any
+string_: Any
+take_along_axis: Any
+tile: Any
+trapz: Any
+tri: Any
+tril: Any
+tril_indices: Any
+tril_indices_from: Any
+trim_zeros: Any
+triu: Any
+triu_indices: Any
+triu_indices_from: Any
+typeDict: Any
+typecodes: Any
+typename: Any
+ubyte: Any
+uint: Any
+uint0: Any
+uintc: Any
+uintp: Any
+ulonglong: Any
+union1d: Any
+unique: Any
+unpackbits: Any
+unravel_index: Any
+unwrap: Any
+ushort: Any
+vander: Any
+vdot: Any
+vectorize: Any
+void0: Any
+vsplit: Any
+where: Any
+who: Any
+
+_NdArraySubClass = TypeVar("_NdArraySubClass", bound=ndarray)
+_DTypeScalar = TypeVar("_DTypeScalar", bound=generic)
+_ByteOrder = Literal["S", "<", ">", "=", "|", "L", "B", "N", "I"]
+
+class dtype(Generic[_DTypeScalar]):
+ names: Optional[Tuple[str, ...]]
+ # Overload for subclass of generic
+ @overload
+ def __new__(
+ cls,
+ dtype: Type[_DTypeScalar],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[_DTypeScalar]: ...
+ # Overloads for string aliases, Python types, and some assorted
+ # other special cases. Order is sometimes important because of the
+ # subtype relationships
+ #
+ # bool < int < float < complex
+ #
+ # so we have to make sure the overloads for the narrowest type is
+ # first.
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[bool],
+ Literal[
+ "?",
+ "=?",
+ "<?",
+ ">?",
+ "bool",
+ "bool_",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[bool_]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint8",
+ "u1",
+ "=u1",
+ "<u1",
+ ">u1",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint8]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint16",
+ "u2",
+ "=u2",
+ "<u2",
+ ">u2",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint16]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint32",
+ "u4",
+ "=u4",
+ "<u4",
+ ">u4",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint32]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint64",
+ "u8",
+ "=u8",
+ "<u8",
+ ">u8",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint64]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int8",
+ "i1",
+ "=i1",
+ "<i1",
+ ">i1",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int8]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int16",
+ "i2",
+ "=i2",
+ "<i2",
+ ">i2",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int16]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int32",
+ "i4",
+ "=i4",
+ "<i4",
+ ">i4",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int32]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int64",
+ "i8",
+ "=i8",
+ "<i8",
+ ">i8",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int64]: ...
+ # "int"/int resolve to int_, which is system dependent and as of
+ # now untyped. Long-term we'll do something fancier here.
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[Type[int], Literal["int"]],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "float16",
+ "f4",
+ "=f4",
+ "<f4",
+ ">f4",
+ "e",
+ "=e",
+ "<e",
+ ">e",
+ "half",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[float16]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "float32",
+ "f4",
+ "=f4",
+ "<f4",
+ ">f4",
+ "f",
+ "=f",
+ "<f",
+ ">f",
+ "single",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[float32]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ None,
+ Type[float],
+ Literal[
+ "float64",
+ "f8",
+ "=f8",
+ "<f8",
+ ">f8",
+ "d",
+ "<d",
+ ">d",
+ "float",
+ "double",
+ "float_",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[float64]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "complex64",
+ "c8",
+ "=c8",
+ "<c8",
+ ">c8",
+ "F",
+ "=F",
+ "<F",
+ ">F",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[complex64]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[complex],
+ Literal[
+ "complex128",
+ "c16",
+ "=c16",
+ "<c16",
+ ">c16",
+ "D",
+ "=D",
+ "<D",
+ ">D",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[complex128]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[bytes],
+ Literal[
+ "S",
+ "=S",
+ "<S",
+ ">S",
+ "bytes",
+ "bytes_",
+ "bytes0",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[bytes_]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[str],
+ Literal[
+ "U",
+ "=U",
+ # <U and >U intentionally not included; they are not
+ # the same dtype and which one dtype("U") translates
+ # to is platform-dependent.
+ "str",
+ "str_",
+ "str0",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[str_]: ...
+ # dtype of a dtype is the same dtype
+ @overload
+ def __new__(
+ cls,
+ dtype: dtype[_DTypeScalar],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[_DTypeScalar]: ...
+ # TODO: handle _SupportsDType better
+ @overload
+ def __new__(
+ cls,
+ dtype: _SupportsDType,
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[Any]: ...
+ # Handle strings that can't be expressed as literals; i.e. s1, s2, ...
+ @overload
+ def __new__(
+ cls,
+ dtype: str,
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[Any]: ...
+ # Catchall overload
+ @overload
+ def __new__(
+ cls,
+ dtype: _VoidDTypeLike,
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[void]: ...
+ def __eq__(self, other: DTypeLike) -> bool: ...
+ def __ne__(self, other: DTypeLike) -> bool: ...
+ def __gt__(self, other: DTypeLike) -> bool: ...
+ def __ge__(self, other: DTypeLike) -> bool: ...
+ def __lt__(self, other: DTypeLike) -> bool: ...
+ def __le__(self, other: DTypeLike) -> bool: ...
+ @property
+ def alignment(self) -> int: ...
+ @property
+ def base(self) -> dtype: ...
+ @property
+ def byteorder(self) -> str: ...
+ @property
+ def char(self) -> str: ...
+ @property
+ def descr(self) -> List[Union[Tuple[str, str], Tuple[str, str, _Shape]]]: ...
+ @property
+ def fields(
+ self,
+ ) -> Optional[Mapping[str, Union[Tuple[dtype, int], Tuple[dtype, int, Any]]]]: ...
+ @property
+ def flags(self) -> int: ...
+ @property
+ def hasobject(self) -> bool: ...
+ @property
+ def isbuiltin(self) -> int: ...
+ @property
+ def isnative(self) -> bool: ...
+ @property
+ def isalignedstruct(self) -> bool: ...
+ @property
+ def itemsize(self) -> int: ...
+ @property
+ def kind(self) -> str: ...
+ @property
+ def metadata(self) -> Optional[Mapping[str, Any]]: ...
+ @property
+ def name(self) -> str: ...
+ @property
+ def num(self) -> int: ...
+ @property
+ def shape(self) -> _Shape: ...
+ @property
+ def ndim(self) -> int: ...
+ @property
+ def subdtype(self) -> Optional[Tuple[dtype, _Shape]]: ...
+ def newbyteorder(self, __new_order: _ByteOrder = ...) -> dtype: ...
+ # Leave str and type for end to avoid having to use `builtins.str`
+ # everywhere. See https://github.com/python/mypy/issues/3775
+ @property
+ def str(self) -> builtins.str: ...
+ @property
+ def type(self) -> Type[generic]: ...
+
+_DType = dtype # to avoid name conflicts with ndarray.dtype
+
+class _flagsobj:
+ aligned: bool
+ updateifcopy: bool
+ writeable: bool
+ writebackifcopy: bool
+ @property
+ def behaved(self) -> bool: ...
+ @property
+ def c_contiguous(self) -> bool: ...
+ @property
+ def carray(self) -> bool: ...
+ @property
+ def contiguous(self) -> bool: ...
+ @property
+ def f_contiguous(self) -> bool: ...
+ @property
+ def farray(self) -> bool: ...
+ @property
+ def fnc(self) -> bool: ...
+ @property
+ def forc(self) -> bool: ...
+ @property
+ def fortran(self) -> bool: ...
+ @property
+ def num(self) -> int: ...
+ @property
+ def owndata(self) -> bool: ...
+ def __getitem__(self, key: str) -> bool: ...
+ def __setitem__(self, key: str, value: bool) -> None: ...
+
+_ArrayLikeInt = Union[
+ int,
+ integer,
+ Sequence[Union[int, integer]],
+ Sequence[Sequence[Any]], # TODO: wait for support for recursive types
+ ndarray
+]
+
+_FlatIterSelf = TypeVar("_FlatIterSelf", bound=flatiter)
+
+class flatiter(Generic[_ArraySelf]):
+ @property
+ def base(self) -> _ArraySelf: ...
+ @property
+ def coords(self) -> _Shape: ...
+ @property
+ def index(self) -> int: ...
+ def copy(self) -> _ArraySelf: ...
+ def __iter__(self: _FlatIterSelf) -> _FlatIterSelf: ...
+ def __next__(self) -> generic: ...
+ def __len__(self) -> int: ...
+ @overload
+ def __getitem__(self, key: Union[int, integer]) -> generic: ...
+ @overload
+ def __getitem__(
+ self, key: Union[_ArrayLikeInt, slice, ellipsis],
+ ) -> _ArraySelf: ...
+ def __array__(self, __dtype: DTypeLike = ...) -> ndarray: ...
+
+_OrderKACF = Optional[Literal["K", "A", "C", "F"]]
+_OrderACF = Optional[Literal["A", "C", "F"]]
+_OrderCF = Optional[Literal["C", "F"]]
+
+_ModeKind = Literal["raise", "wrap", "clip"]
+_PartitionKind = Literal["introselect"]
+_SortKind = Literal["quicksort", "mergesort", "heapsort", "stable"]
+_SortSide = Literal["left", "right"]
+
+_ArrayLikeBool = Union[_BoolLike, Sequence[_BoolLike], ndarray]
+_ArrayLikeIntOrBool = Union[
+ _IntLike,
+ _BoolLike,
+ ndarray,
+ Sequence[_IntLike],
+ Sequence[_BoolLike],
+ Sequence[Sequence[Any]], # TODO: wait for support for recursive types
+]
+
+_ArraySelf = TypeVar("_ArraySelf", bound=_ArrayOrScalarCommon)
+
+class _ArrayOrScalarCommon:
+ @property
+ def T(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def data(self) -> memoryview: ...
+ @property
+ def flags(self) -> _flagsobj: ...
+ @property
+ def itemsize(self) -> int: ...
+ @property
+ def nbytes(self) -> int: ...
+ def __array__(self, __dtype: DTypeLike = ...) -> ndarray: ...
+ def __bool__(self) -> bool: ...
+ def __bytes__(self) -> bytes: ...
+ def __str__(self) -> str: ...
+ def __repr__(self) -> str: ...
+ def __copy__(self: _ArraySelf) -> _ArraySelf: ...
+ def __deepcopy__(self: _ArraySelf, __memo: Optional[dict] = ...) -> _ArraySelf: ...
+ def __lt__(self, other): ...
+ def __le__(self, other): ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ def __gt__(self, other): ...
+ def __ge__(self, other): ...
+ def astype(
+ self: _ArraySelf,
+ dtype: DTypeLike,
+ order: _OrderKACF = ...,
+ casting: _Casting = ...,
+ subok: bool = ...,
+ copy: bool = ...,
+ ) -> _ArraySelf: ...
+ def copy(self: _ArraySelf, order: _OrderKACF = ...) -> _ArraySelf: ...
+ def dump(self, file: str) -> None: ...
+ def dumps(self) -> bytes: ...
+ def flatten(self, order: _OrderKACF = ...) -> ndarray: ...
+ def getfield(
+ self: _ArraySelf, dtype: DTypeLike, offset: int = ...
+ ) -> _ArraySelf: ...
+ def ravel(self, order: _OrderKACF = ...) -> ndarray: ...
+ @overload
+ def reshape(
+ self, __shape: Sequence[int], *, order: _OrderACF = ...
+ ) -> ndarray: ...
+ @overload
+ def reshape(
+ self, *shape: int, order: _OrderACF = ...
+ ) -> ndarray: ...
+ def tobytes(self, order: _OrderKACF = ...) -> bytes: ...
+ # NOTE: `tostring()` is deprecated and therefore excluded
+ # def tostring(self, order=...): ...
+ def tofile(
+ self, fid: Union[IO[bytes], str], sep: str = ..., format: str = ...
+ ) -> None: ...
+ # generics and 0d arrays return builtin scalars
+ def tolist(self) -> Any: ...
+ @overload
+ def view(self, type: Type[_NdArraySubClass]) -> _NdArraySubClass: ...
+ @overload
+ def view(self: _ArraySelf, dtype: DTypeLike = ...) -> _ArraySelf: ...
+ @overload
+ def view(
+ self, dtype: DTypeLike, type: Type[_NdArraySubClass]
+ ) -> _NdArraySubClass: ...
+
+ # TODO: Add proper signatures
+ def __getitem__(self, key) -> Any: ...
+ @property
+ def __array_interface__(self): ...
+ @property
+ def __array_priority__(self): ...
+ @property
+ def __array_struct__(self): ...
+ def __array_wrap__(array, context=...): ...
+ def __setstate__(self, __state): ...
+ # a `bool_` is returned when `keepdims=True` and `self` is a 0d array
+ @overload
+ def all(
+ self, axis: None = ..., out: None = ..., keepdims: Literal[False] = ...
+ ) -> bool_: ...
+ @overload
+ def all(
+ self, axis: Optional[_ShapeLike] = ..., out: None = ..., keepdims: bool = ...
+ ) -> Union[bool_, ndarray]: ...
+ @overload
+ def all(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def any(
+ self, axis: None = ..., out: None = ..., keepdims: Literal[False] = ...
+ ) -> bool_: ...
+ @overload
+ def any(
+ self, axis: Optional[_ShapeLike] = ..., out: None = ..., keepdims: bool = ...
+ ) -> Union[bool_, ndarray]: ...
+ @overload
+ def any(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def argmax(self, axis: None = ..., out: None = ...) -> signedinteger: ...
+ @overload
+ def argmax(
+ self, axis: _ShapeLike = ..., out: None = ...
+ ) -> Union[signedinteger, ndarray]: ...
+ @overload
+ def argmax(
+ self, axis: Optional[_ShapeLike] = ..., out: _NdArraySubClass = ...
+ ) -> _NdArraySubClass: ...
+ @overload
+ def argmin(self, axis: None = ..., out: None = ...) -> signedinteger: ...
+ @overload
+ def argmin(
+ self, axis: _ShapeLike = ..., out: None = ...
+ ) -> Union[signedinteger, ndarray]: ...
+ @overload
+ def argmin(
+ self, axis: Optional[_ShapeLike] = ..., out: _NdArraySubClass = ...
+ ) -> _NdArraySubClass: ...
+ def argsort(
+ self,
+ axis: Optional[int] = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> ndarray: ...
+ @overload
+ def choose(
+ self, choices: ArrayLike, out: None = ..., mode: _ModeKind = ...,
+ ) -> ndarray: ...
+ @overload
+ def choose(
+ self, choices: ArrayLike, out: _NdArraySubClass = ..., mode: _ModeKind = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def clip(
+ self,
+ min: ArrayLike = ...,
+ max: Optional[ArrayLike] = ...,
+ out: None = ...,
+ **kwargs: Any,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def clip(
+ self,
+ min: None = ...,
+ max: ArrayLike = ...,
+ out: None = ...,
+ **kwargs: Any,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def clip(
+ self,
+ min: ArrayLike = ...,
+ max: Optional[ArrayLike] = ...,
+ out: _NdArraySubClass = ...,
+ **kwargs: Any,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def clip(
+ self,
+ min: None = ...,
+ max: ArrayLike = ...,
+ out: _NdArraySubClass = ...,
+ **kwargs: Any,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def compress(
+ self, a: ArrayLike, axis: Optional[int] = ..., out: None = ...,
+ ) -> ndarray: ...
+ @overload
+ def compress(
+ self, a: ArrayLike, axis: Optional[int] = ..., out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ def conj(self: _ArraySelf) -> _ArraySelf: ...
+ def conjugate(self: _ArraySelf) -> _ArraySelf: ...
+ @overload
+ def cumprod(
+ self, axis: Optional[int] = ..., dtype: DTypeLike = ..., out: None = ...,
+ ) -> ndarray: ...
+ @overload
+ def cumprod(
+ self,
+ axis: Optional[int] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def cumsum(
+ self, axis: Optional[int] = ..., dtype: DTypeLike = ..., out: None = ...,
+ ) -> ndarray: ...
+ @overload
+ def cumsum(
+ self,
+ axis: Optional[int] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def max(
+ self,
+ axis: None = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def max(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def max(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def mean(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def mean(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def mean(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def min(
+ self,
+ axis: None = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def min(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def min(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ def newbyteorder(self: _ArraySelf, __new_order: _ByteOrder = ...) -> _ArraySelf: ...
+ @overload
+ def prod(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def prod(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def prod(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def ptp(
+ self, axis: None = ..., out: None = ..., keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def ptp(
+ self, axis: Optional[_ShapeLike] = ..., out: None = ..., keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def ptp(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ def repeat(
+ self, repeats: _ArrayLikeIntOrBool, axis: Optional[int] = ...
+ ) -> ndarray: ...
+ @overload
+ def round(self: _ArraySelf, decimals: int = ..., out: None = ...) -> _ArraySelf: ...
+ @overload
+ def round(
+ self, decimals: int = ..., out: _NdArraySubClass = ...
+ ) -> _NdArraySubClass: ...
+ @overload
+ def std(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def std(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def std(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def sum(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def sum(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def sum(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def take(
+ self,
+ indices: Union[_IntLike, _BoolLike],
+ axis: Optional[int] = ...,
+ out: None = ...,
+ mode: _ModeKind = ...,
+ ) -> generic: ...
+ @overload
+ def take(
+ self,
+ indices: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ out: None = ...,
+ mode: _ModeKind = ...,
+ ) -> ndarray: ...
+ @overload
+ def take(
+ self,
+ indices: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ out: _NdArraySubClass = ...,
+ mode: _ModeKind = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def var(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def var(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def var(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+
+_BufferType = Union[ndarray, bytes, bytearray, memoryview]
+_Casting = Literal["no", "equiv", "safe", "same_kind", "unsafe"]
+
+class ndarray(_ArrayOrScalarCommon, Iterable, Sized, Container):
+ @property
+ def base(self) -> Optional[ndarray]: ...
+ @property
+ def ndim(self) -> int: ...
+ @property
+ def size(self) -> int: ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @real.setter
+ def real(self, value: ArrayLike) -> None: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ @imag.setter
+ def imag(self, value: ArrayLike) -> None: ...
+ def __new__(
+ cls: Type[_ArraySelf],
+ shape: Sequence[int],
+ dtype: DTypeLike = ...,
+ buffer: _BufferType = ...,
+ offset: int = ...,
+ strides: _ShapeLike = ...,
+ order: _OrderKACF = ...,
+ ) -> _ArraySelf: ...
+ @property
+ def dtype(self) -> _DType: ...
+ @property
+ def ctypes(self) -> _ctypes: ...
+ @property
+ def shape(self) -> _Shape: ...
+ @shape.setter
+ def shape(self, value: _ShapeLike): ...
+ @property
+ def strides(self) -> _Shape: ...
+ @strides.setter
+ def strides(self, value: _ShapeLike): ...
+ def byteswap(self: _ArraySelf, inplace: bool = ...) -> _ArraySelf: ...
+ def fill(self, value: Any) -> None: ...
+ @property
+ def flat(self: _ArraySelf) -> flatiter[_ArraySelf]: ...
+ @overload
+ def item(self, *args: int) -> Any: ...
+ @overload
+ def item(self, __args: Tuple[int, ...]) -> Any: ...
+ @overload
+ def itemset(self, __value: Any) -> None: ...
+ @overload
+ def itemset(self, __item: _ShapeLike, __value: Any) -> None: ...
+ @overload
+ def resize(self, __new_shape: Sequence[int], *, refcheck: bool = ...) -> None: ...
+ @overload
+ def resize(self, *new_shape: int, refcheck: bool = ...) -> None: ...
+ def setflags(
+ self, write: bool = ..., align: bool = ..., uic: bool = ...
+ ) -> None: ...
+ def squeeze(
+ self: _ArraySelf, axis: Union[int, Tuple[int, ...]] = ...
+ ) -> _ArraySelf: ...
+ def swapaxes(self: _ArraySelf, axis1: int, axis2: int) -> _ArraySelf: ...
+ @overload
+ def transpose(self: _ArraySelf, __axes: Sequence[int]) -> _ArraySelf: ...
+ @overload
+ def transpose(self: _ArraySelf, *axes: int) -> _ArraySelf: ...
+ def argpartition(
+ self,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> ndarray: ...
+ def diagonal(
+ self: _ArraySelf, offset: int = ..., axis1: int = ..., axis2: int = ...
+ ) -> _ArraySelf: ...
+ @overload
+ def dot(self, b: ArrayLike, out: None = ...) -> Union[number, ndarray]: ...
+ @overload
+ def dot(self, b: ArrayLike, out: _NdArraySubClass = ...) -> _NdArraySubClass: ...
+ # `nonzero()` is deprecated for 0d arrays/generics
+ def nonzero(self) -> Tuple[ndarray, ...]: ...
+ def partition(
+ self,
+ kth: _ArrayLikeIntOrBool,
+ axis: int = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> None: ...
+ # `put` is technically available to `generic`,
+ # but is pointless as `generic`s are immutable
+ def put(
+ self, ind: _ArrayLikeIntOrBool, v: ArrayLike, mode: _ModeKind = ...
+ ) -> None: ...
+ def searchsorted(
+ self, # >= 1D array
+ v: ArrayLike,
+ side: _SortSide = ...,
+ sorter: Optional[_ArrayLikeIntOrBool] = ..., # 1D int array
+ ) -> ndarray: ...
+ def setfield(
+ self, val: ArrayLike, dtype: DTypeLike, offset: int = ...
+ ) -> None: ...
+ def sort(
+ self,
+ axis: int = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> None: ...
+ @overload
+ def trace(
+ self, # >= 2D array
+ offset: int = ...,
+ axis1: int = ...,
+ axis2: int = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def trace(
+ self, # >= 2D array
+ offset: int = ...,
+ axis1: int = ...,
+ axis2: int = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ # Many of these special methods are irrelevant currently, since protocols
+ # aren't supported yet. That said, I'm adding them for completeness.
+ # https://docs.python.org/3/reference/datamodel.html
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __len__(self) -> int: ...
+ def __setitem__(self, key, value): ...
+ def __iter__(self) -> Any: ...
+ def __contains__(self, key) -> bool: ...
+ def __index__(self) -> int: ...
+ def __matmul__(self, other: ArrayLike) -> Any: ...
+ # NOTE: `ndarray` does not implement `__imatmul__`
+ def __rmatmul__(self, other: ArrayLike) -> Any: ...
+ def __neg__(self: _ArraySelf) -> Any: ...
+ def __pos__(self: _ArraySelf) -> Any: ...
+ def __abs__(self: _ArraySelf) -> Any: ...
+ def __mod__(self, other: ArrayLike) -> Any: ...
+ def __rmod__(self, other: ArrayLike) -> Any: ...
+ def __divmod__(self, other: ArrayLike) -> Tuple[Any, Any]: ...
+ def __rdivmod__(self, other: ArrayLike) -> Tuple[Any, Any]: ...
+ def __add__(self, other: ArrayLike) -> Any: ...
+ def __radd__(self, other: ArrayLike) -> Any: ...
+ def __sub__(self, other: ArrayLike) -> Any: ...
+ def __rsub__(self, other: ArrayLike) -> Any: ...
+ def __mul__(self, other: ArrayLike) -> Any: ...
+ def __rmul__(self, other: ArrayLike) -> Any: ...
+ def __floordiv__(self, other: ArrayLike) -> Any: ...
+ def __rfloordiv__(self, other: ArrayLike) -> Any: ...
+ def __pow__(self, other: ArrayLike) -> Any: ...
+ def __rpow__(self, other: ArrayLike) -> Any: ...
+ def __truediv__(self, other: ArrayLike) -> Any: ...
+ def __rtruediv__(self, other: ArrayLike) -> Any: ...
+ def __invert__(self: _ArraySelf) -> Any: ...
+ def __lshift__(self, other: ArrayLike) -> Any: ...
+ def __rlshift__(self, other: ArrayLike) -> Any: ...
+ def __rshift__(self, other: ArrayLike) -> Any: ...
+ def __rrshift__(self, other: ArrayLike) -> Any: ...
+ def __and__(self, other: ArrayLike) -> Any: ...
+ def __rand__(self, other: ArrayLike) -> Any: ...
+ def __xor__(self, other: ArrayLike) -> Any: ...
+ def __rxor__(self, other: ArrayLike) -> Any: ...
+ def __or__(self, other: ArrayLike) -> Any: ...
+ def __ror__(self, other: ArrayLike) -> Any: ...
+ # `np.generic` does not support inplace operations
+ def __iadd__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __isub__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __imul__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __itruediv__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ifloordiv__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ipow__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __imod__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ilshift__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __irshift__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __iand__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ixor__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ior__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+
+# NOTE: while `np.generic` is not technically an instance of `ABCMeta`,
+# the `@abstractmethod` decorator is herein used to (forcefully) deny
+# the creation of `np.generic` instances.
+# The `# type: ignore` comments are necessary to silence mypy errors regarding
+# the missing `ABCMeta` metaclass.
+
+# See https://github.com/numpy/numpy-stubs/pull/80 for more details.
+
+_ScalarType = TypeVar("_ScalarType", bound=generic)
+_NBit_co = TypeVar("_NBit_co", covariant=True, bound=NBitBase)
+_NBit_co2 = TypeVar("_NBit_co2", covariant=True, bound=NBitBase)
+
+class generic(_ArrayOrScalarCommon):
+ @abstractmethod
+ def __init__(self, *args: Any, **kwargs: Any) -> None: ...
+ @property
+ def base(self) -> None: ...
+ @property
+ def dtype(self: _ScalarType) -> _DType[_ScalarType]: ...
+ @property
+ def ndim(self) -> Literal[0]: ...
+ @property
+ def size(self) -> Literal[1]: ...
+ @property
+ def shape(self) -> Tuple[()]: ...
+ @property
+ def strides(self) -> Tuple[()]: ...
+ def byteswap(self: _ScalarType, inplace: Literal[False] = ...) -> _ScalarType: ...
+ @property
+ def flat(self) -> flatiter[ndarray]: ...
+ def item(
+ self: _ScalarType,
+ __args: Union[Literal[0], Tuple[()], Tuple[Literal[0]]] = ...,
+ ) -> Any: ...
+ def squeeze(
+ self: _ScalarType, axis: Union[Literal[0], Tuple[()]] = ...
+ ) -> _ScalarType: ...
+ def transpose(self: _ScalarType, __axes: Tuple[()] = ...) -> _ScalarType: ...
+
+class number(generic, Generic[_NBit_co]): # type: ignore
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __neg__(self: _ArraySelf) -> _ArraySelf: ...
+ def __pos__(self: _ArraySelf) -> _ArraySelf: ...
+ def __abs__(self: _ArraySelf) -> _ArraySelf: ...
+ # Ensure that objects annotated as `number` support arithmetic operations
+ __add__: _NumberOp
+ __radd__: _NumberOp
+ __sub__: _NumberOp
+ __rsub__: _NumberOp
+ __mul__: _NumberOp
+ __rmul__: _NumberOp
+ __floordiv__: _NumberOp
+ __rfloordiv__: _NumberOp
+ __pow__: _NumberOp
+ __rpow__: _NumberOp
+ __truediv__: _NumberOp
+ __rtruediv__: _NumberOp
+
+class bool_(generic):
+ def __init__(self, __value: object = ...) -> None: ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __abs__(self: _ArraySelf) -> _ArraySelf: ...
+ __add__: _BoolOp[bool_]
+ __radd__: _BoolOp[bool_]
+ __sub__: _BoolSub
+ __rsub__: _BoolSub
+ __mul__: _BoolOp[bool_]
+ __rmul__: _BoolOp[bool_]
+ __floordiv__: _BoolOp[int8]
+ __rfloordiv__: _BoolOp[int8]
+ __pow__: _BoolOp[int8]
+ __rpow__: _BoolOp[int8]
+ __truediv__: _BoolTrueDiv
+ __rtruediv__: _BoolTrueDiv
+ def __invert__(self) -> bool_: ...
+ __lshift__: _BoolBitOp[int8]
+ __rlshift__: _BoolBitOp[int8]
+ __rshift__: _BoolBitOp[int8]
+ __rrshift__: _BoolBitOp[int8]
+ __and__: _BoolBitOp[bool_]
+ __rand__: _BoolBitOp[bool_]
+ __xor__: _BoolBitOp[bool_]
+ __rxor__: _BoolBitOp[bool_]
+ __or__: _BoolBitOp[bool_]
+ __ror__: _BoolBitOp[bool_]
+ __mod__: _BoolMod
+ __rmod__: _BoolMod
+ __divmod__: _BoolDivMod
+ __rdivmod__: _BoolDivMod
+
+class object_(generic):
+ def __init__(self, __value: object = ...) -> None: ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+
+class datetime64(generic):
+ @overload
+ def __init__(
+ self,
+ __value: Union[None, datetime64, _CharLike, dt.datetime] = ...,
+ __format: Union[_CharLike, Tuple[_CharLike, _IntLike]] = ...,
+ ) -> None: ...
+ @overload
+ def __init__(
+ self,
+ __value: int,
+ __format: Union[_CharLike, Tuple[_CharLike, _IntLike]]
+ ) -> None: ...
+ def __add__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ def __radd__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ @overload
+ def __sub__(self, other: datetime64) -> timedelta64: ...
+ @overload
+ def __sub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ def __rsub__(self, other: datetime64) -> timedelta64: ...
+
+# Support for `__index__` was added in python 3.8 (bpo-20092)
+if sys.version_info >= (3, 8):
+ _IntValue = Union[SupportsInt, _CharLike, SupportsIndex]
+ _FloatValue = Union[None, _CharLike, SupportsFloat, SupportsIndex]
+ _ComplexValue = Union[None, _CharLike, SupportsFloat, SupportsComplex, SupportsIndex]
+else:
+ _IntValue = Union[SupportsInt, _CharLike]
+ _FloatValue = Union[None, _CharLike, SupportsFloat]
+ _ComplexValue = Union[None, _CharLike, SupportsFloat, SupportsComplex]
+
+class integer(number[_NBit_co]): # type: ignore
+ # NOTE: `__index__` is technically defined in the bottom-most
+ # sub-classes (`int64`, `uint32`, etc)
+ def __index__(self) -> int: ...
+ __truediv__: _IntTrueDiv[_NBit_co]
+ __rtruediv__: _IntTrueDiv[_NBit_co]
+ def __mod__(self, value: Union[_IntLike, integer]) -> integer: ...
+ def __rmod__(self, value: Union[_IntLike, integer]) -> integer: ...
+ def __invert__(self: _IntType) -> _IntType: ...
+ # Ensure that objects annotated as `integer` support bit-wise operations
+ def __lshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rlshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rrshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __and__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rand__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __or__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __ror__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __xor__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rxor__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+
+class signedinteger(integer[_NBit_co]):
+ def __init__(self, __value: _IntValue = ...) -> None: ...
+ __add__: _SignedIntOp[_NBit_co]
+ __radd__: _SignedIntOp[_NBit_co]
+ __sub__: _SignedIntOp[_NBit_co]
+ __rsub__: _SignedIntOp[_NBit_co]
+ __mul__: _SignedIntOp[_NBit_co]
+ __rmul__: _SignedIntOp[_NBit_co]
+ __floordiv__: _SignedIntOp[_NBit_co]
+ __rfloordiv__: _SignedIntOp[_NBit_co]
+ __pow__: _SignedIntOp[_NBit_co]
+ __rpow__: _SignedIntOp[_NBit_co]
+ __lshift__: _SignedIntBitOp[_NBit_co]
+ __rlshift__: _SignedIntBitOp[_NBit_co]
+ __rshift__: _SignedIntBitOp[_NBit_co]
+ __rrshift__: _SignedIntBitOp[_NBit_co]
+ __and__: _SignedIntBitOp[_NBit_co]
+ __rand__: _SignedIntBitOp[_NBit_co]
+ __xor__: _SignedIntBitOp[_NBit_co]
+ __rxor__: _SignedIntBitOp[_NBit_co]
+ __or__: _SignedIntBitOp[_NBit_co]
+ __ror__: _SignedIntBitOp[_NBit_co]
+ __mod__: _SignedIntMod[_NBit_co]
+ __rmod__: _SignedIntMod[_NBit_co]
+ __divmod__: _SignedIntDivMod[_NBit_co]
+ __rdivmod__: _SignedIntDivMod[_NBit_co]
+
+int8 = signedinteger[_8Bit]
+int16 = signedinteger[_16Bit]
+int32 = signedinteger[_32Bit]
+int64 = signedinteger[_64Bit]
+
+class timedelta64(generic):
+ def __init__(
+ self,
+ __value: Union[None, int, _CharLike, dt.timedelta, timedelta64] = ...,
+ __format: Union[_CharLike, Tuple[_CharLike, _IntLike]] = ...,
+ ) -> None: ...
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __neg__(self: _ArraySelf) -> _ArraySelf: ...
+ def __pos__(self: _ArraySelf) -> _ArraySelf: ...
+ def __abs__(self: _ArraySelf) -> _ArraySelf: ...
+ def __add__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __radd__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __sub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __rsub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __mul__(self, other: Union[_FloatLike, _BoolLike]) -> timedelta64: ...
+ def __rmul__(self, other: Union[_FloatLike, _BoolLike]) -> timedelta64: ...
+ __truediv__: _TD64Div[float64]
+ __floordiv__: _TD64Div[int64]
+ def __rtruediv__(self, other: timedelta64) -> float64: ...
+ def __rfloordiv__(self, other: timedelta64) -> int64: ...
+ def __mod__(self, other: timedelta64) -> timedelta64: ...
+ def __rmod__(self, other: timedelta64) -> timedelta64: ...
+ def __divmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ...
+ def __rdivmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ...
+
+class unsignedinteger(integer[_NBit_co]):
+ # NOTE: `uint64 + signedinteger -> float64`
+ def __init__(self, __value: _IntValue = ...) -> None: ...
+ __add__: _UnsignedIntOp[_NBit_co]
+ __radd__: _UnsignedIntOp[_NBit_co]
+ __sub__: _UnsignedIntOp[_NBit_co]
+ __rsub__: _UnsignedIntOp[_NBit_co]
+ __mul__: _UnsignedIntOp[_NBit_co]
+ __rmul__: _UnsignedIntOp[_NBit_co]
+ __floordiv__: _UnsignedIntOp[_NBit_co]
+ __rfloordiv__: _UnsignedIntOp[_NBit_co]
+ __pow__: _UnsignedIntOp[_NBit_co]
+ __rpow__: _UnsignedIntOp[_NBit_co]
+ __lshift__: _UnsignedIntBitOp[_NBit_co]
+ __rlshift__: _UnsignedIntBitOp[_NBit_co]
+ __rshift__: _UnsignedIntBitOp[_NBit_co]
+ __rrshift__: _UnsignedIntBitOp[_NBit_co]
+ __and__: _UnsignedIntBitOp[_NBit_co]
+ __rand__: _UnsignedIntBitOp[_NBit_co]
+ __xor__: _UnsignedIntBitOp[_NBit_co]
+ __rxor__: _UnsignedIntBitOp[_NBit_co]
+ __or__: _UnsignedIntBitOp[_NBit_co]
+ __ror__: _UnsignedIntBitOp[_NBit_co]
+ __mod__: _UnsignedIntMod[_NBit_co]
+ __rmod__: _UnsignedIntMod[_NBit_co]
+ __divmod__: _UnsignedIntDivMod[_NBit_co]
+ __rdivmod__: _UnsignedIntDivMod[_NBit_co]
+
+uint8 = unsignedinteger[_8Bit]
+uint16 = unsignedinteger[_16Bit]
+uint32 = unsignedinteger[_32Bit]
+uint64 = unsignedinteger[_64Bit]
+
+class inexact(number[_NBit_co]): ... # type: ignore
+
+_IntType = TypeVar("_IntType", bound=integer)
+_FloatType = TypeVar('_FloatType', bound=floating)
+
+class floating(inexact[_NBit_co]):
+ def __init__(self, __value: _FloatValue = ...) -> None: ...
+ __add__: _FloatOp[_NBit_co]
+ __radd__: _FloatOp[_NBit_co]
+ __sub__: _FloatOp[_NBit_co]
+ __rsub__: _FloatOp[_NBit_co]
+ __mul__: _FloatOp[_NBit_co]
+ __rmul__: _FloatOp[_NBit_co]
+ __truediv__: _FloatOp[_NBit_co]
+ __rtruediv__: _FloatOp[_NBit_co]
+ __floordiv__: _FloatOp[_NBit_co]
+ __rfloordiv__: _FloatOp[_NBit_co]
+ __pow__: _FloatOp[_NBit_co]
+ __rpow__: _FloatOp[_NBit_co]
+ __mod__: _FloatMod[_NBit_co]
+ __rmod__: _FloatMod[_NBit_co]
+ __divmod__: _FloatDivMod[_NBit_co]
+ __rdivmod__: _FloatDivMod[_NBit_co]
+
+float16 = floating[_16Bit]
+float32 = floating[_32Bit]
+float64 = floating[_64Bit]
+
+# The main reason for `complexfloating` having two typevars is cosmetic.
+# It is used to clarify why `complex128`s precision is `_64Bit`, the latter
+# describing the two 64 bit floats representing its real and imaginary component
+
+class complexfloating(inexact[_NBit_co], Generic[_NBit_co, _NBit_co2]):
+ def __init__(self, __value: _ComplexValue = ...) -> None: ...
+ @property
+ def real(self) -> floating[_NBit_co]: ... # type: ignore[override]
+ @property
+ def imag(self) -> floating[_NBit_co2]: ... # type: ignore[override]
+ def __abs__(self) -> floating[_NBit_co]: ... # type: ignore[override]
+ __add__: _ComplexOp[_NBit_co]
+ __radd__: _ComplexOp[_NBit_co]
+ __sub__: _ComplexOp[_NBit_co]
+ __rsub__: _ComplexOp[_NBit_co]
+ __mul__: _ComplexOp[_NBit_co]
+ __rmul__: _ComplexOp[_NBit_co]
+ __truediv__: _ComplexOp[_NBit_co]
+ __rtruediv__: _ComplexOp[_NBit_co]
+ __floordiv__: _ComplexOp[_NBit_co]
+ __rfloordiv__: _ComplexOp[_NBit_co]
+ __pow__: _ComplexOp[_NBit_co]
+ __rpow__: _ComplexOp[_NBit_co]
+
+complex64 = complexfloating[_32Bit, _32Bit]
+complex128 = complexfloating[_64Bit, _64Bit]
+
+class flexible(generic): ... # type: ignore
+
+class void(flexible):
+ def __init__(self, __value: Union[_IntLike, _BoolLike, bytes]): ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ def setfield(
+ self, val: ArrayLike, dtype: DTypeLike, offset: int = ...
+ ) -> None: ...
+
+class character(flexible): # type: ignore
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+
+# NOTE: Most `np.bytes_` / `np.str_` methods return their
+# builtin `bytes` / `str` counterpart
+
+class bytes_(character, bytes):
+ @overload
+ def __init__(self, __value: object = ...) -> None: ...
+ @overload
+ def __init__(
+ self, __value: str, encoding: str = ..., errors: str = ...
+ ) -> None: ...
+
+class str_(character, str):
+ @overload
+ def __init__(self, __value: object = ...) -> None: ...
+ @overload
+ def __init__(
+ self, __value: bytes, encoding: str = ..., errors: str = ...
+ ) -> None: ...
+
+unicode_ = str0 = str_
+
+# TODO(alan): Platform dependent types
+# longcomplex, longdouble, longfloat
+# bytes, short, intc, intp, longlong
+# half, single, double, longdouble
+# uint_, int_, float_, complex_
+# float128, complex256
+# float96
+
+def array(
+ object: object,
+ dtype: DTypeLike = ...,
+ *,
+ copy: bool = ...,
+ order: _OrderKACF = ...,
+ subok: bool = ...,
+ ndmin: int = ...,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+def zeros(
+ shape: _ShapeLike,
+ dtype: DTypeLike = ...,
+ order: _OrderCF = ...,
+ *,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+def empty(
+ shape: _ShapeLike,
+ dtype: DTypeLike = ...,
+ order: _OrderCF = ...,
+ *,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+
+def broadcast_shapes(*args: _ShapeLike) -> _Shape: ...
+
+#
+# Constants
+#
+
+Inf: Final[float]
+Infinity: Final[float]
+NAN: Final[float]
+NINF: Final[float]
+NZERO: Final[float]
+NaN: Final[float]
+PINF: Final[float]
+PZERO: Final[float]
+e: Final[float]
+euler_gamma: Final[float]
+inf: Final[float]
+infty: Final[float]
+nan: Final[float]
+pi: Final[float]
+ALLOW_THREADS: Final[int]
+BUFSIZE: Final[int]
+CLIP: Final[int]
+ERR_CALL: Final[int]
+ERR_DEFAULT: Final[int]
+ERR_IGNORE: Final[int]
+ERR_LOG: Final[int]
+ERR_PRINT: Final[int]
+ERR_RAISE: Final[int]
+ERR_WARN: Final[int]
+FLOATING_POINT_SUPPORT: Final[int]
+FPE_DIVIDEBYZERO: Final[int]
+FPE_INVALID: Final[int]
+FPE_OVERFLOW: Final[int]
+FPE_UNDERFLOW: Final[int]
+MAXDIMS: Final[int]
+MAY_SHARE_BOUNDS: Final[int]
+MAY_SHARE_EXACT: Final[int]
+RAISE: Final[int]
+SHIFT_DIVIDEBYZERO: Final[int]
+SHIFT_INVALID: Final[int]
+SHIFT_OVERFLOW: Final[int]
+SHIFT_UNDERFLOW: Final[int]
+UFUNC_BUFSIZE_DEFAULT: Final[int]
+WRAP: Final[int]
+tracemalloc_domain: Final[int]
+
+little_endian: Final[bool]
+True_: Final[bool_]
+False_: Final[bool_]
+
+UFUNC_PYVALS_NAME: Final[str]
+
+class ufunc:
+ @property
+ def __name__(self) -> str: ...
+ def __call__(
+ self,
+ *args: ArrayLike,
+ out: Optional[Union[ndarray, Tuple[ndarray, ...]]] = ...,
+ where: Optional[ndarray] = ...,
+ # The list should be a list of tuples of ints, but since we
+ # don't know the signature it would need to be
+ # Tuple[int, ...]. But, since List is invariant something like
+ # e.g. List[Tuple[int, int]] isn't a subtype of
+ # List[Tuple[int, ...]], so we can't type precisely here.
+ axes: List[Any] = ...,
+ axis: int = ...,
+ keepdims: bool = ...,
+ casting: _Casting = ...,
+ order: _OrderKACF = ...,
+ dtype: DTypeLike = ...,
+ subok: bool = ...,
+ signature: Union[str, Tuple[str]] = ...,
+ # In reality this should be a length of list 3 containing an
+ # int, an int, and a callable, but there's no way to express
+ # that.
+ extobj: List[Union[int, Callable]] = ...,
+ ) -> Any: ...
+ @property
+ def nin(self) -> int: ...
+ @property
+ def nout(self) -> int: ...
+ @property
+ def nargs(self) -> int: ...
+ @property
+ def ntypes(self) -> int: ...
+ @property
+ def types(self) -> List[str]: ...
+ # Broad return type because it has to encompass things like
+ #
+ # >>> np.logical_and.identity is True
+ # True
+ # >>> np.add.identity is 0
+ # True
+ # >>> np.sin.identity is None
+ # True
+ #
+ # and any user-defined ufuncs.
+ @property
+ def identity(self) -> Any: ...
+ # This is None for ufuncs and a string for gufuncs.
+ @property
+ def signature(self) -> Optional[str]: ...
+ # The next four methods will always exist, but they will just
+ # raise a ValueError ufuncs with that don't accept two input
+ # arguments and return one output argument. Because of that we
+ # can't type them very precisely.
+ @property
+ def reduce(self) -> Any: ...
+ @property
+ def accumulate(self) -> Any: ...
+ @property
+ def reduceat(self) -> Any: ...
+ @property
+ def outer(self) -> Any: ...
+ # Similarly at won't be defined for ufuncs that return multiple
+ # outputs, so we can't type it very precisely.
+ @property
+ def at(self) -> Any: ...
+
+absolute: ufunc
+add: ufunc
+arccos: ufunc
+arccosh: ufunc
+arcsin: ufunc
+arcsinh: ufunc
+arctan2: ufunc
+arctan: ufunc
+arctanh: ufunc
+bitwise_and: ufunc
+bitwise_or: ufunc
+bitwise_xor: ufunc
+cbrt: ufunc
+ceil: ufunc
+conjugate: ufunc
+copysign: ufunc
+cos: ufunc
+cosh: ufunc
+deg2rad: ufunc
+degrees: ufunc
+divmod: ufunc
+equal: ufunc
+exp2: ufunc
+exp: ufunc
+expm1: ufunc
+fabs: ufunc
+float_power: ufunc
+floor: ufunc
+floor_divide: ufunc
+fmax: ufunc
+fmin: ufunc
+fmod: ufunc
+frexp: ufunc
+gcd: ufunc
+greater: ufunc
+greater_equal: ufunc
+heaviside: ufunc
+hypot: ufunc
+invert: ufunc
+isfinite: ufunc
+isinf: ufunc
+isnan: ufunc
+isnat: ufunc
+lcm: ufunc
+ldexp: ufunc
+left_shift: ufunc
+less: ufunc
+less_equal: ufunc
+log10: ufunc
+log1p: ufunc
+log2: ufunc
+log: ufunc
+logaddexp2: ufunc
+logaddexp: ufunc
+logical_and: ufunc
+logical_not: ufunc
+logical_or: ufunc
+logical_xor: ufunc
+matmul: ufunc
+maximum: ufunc
+minimum: ufunc
+modf: ufunc
+multiply: ufunc
+negative: ufunc
+nextafter: ufunc
+not_equal: ufunc
+positive: ufunc
+power: ufunc
+rad2deg: ufunc
+radians: ufunc
+reciprocal: ufunc
+remainder: ufunc
+right_shift: ufunc
+rint: ufunc
+sign: ufunc
+signbit: ufunc
+sin: ufunc
+sinh: ufunc
+spacing: ufunc
+sqrt: ufunc
+square: ufunc
+subtract: ufunc
+tan: ufunc
+tanh: ufunc
+true_divide: ufunc
+trunc: ufunc
+
+abs = absolute
+
+# Warnings
+class ModuleDeprecationWarning(DeprecationWarning): ...
+class VisibleDeprecationWarning(UserWarning): ...
+class ComplexWarning(RuntimeWarning): ...
+class RankWarning(UserWarning): ...
+
+# Errors
+class TooHardError(RuntimeError): ...
+
+class AxisError(ValueError, IndexError):
+ def __init__(
+ self, axis: int, ndim: Optional[int] = ..., msg_prefix: Optional[str] = ...
+ ) -> None: ...
+
+_CallType = TypeVar("_CallType", bound=Union[_ErrFunc, _SupportsWrite])
+
+class errstate(Generic[_CallType], ContextDecorator):
+ call: _CallType
+ kwargs: _ErrDictOptional
+
+ # Expand `**kwargs` into explicit keyword-only arguments
+ def __init__(
+ self,
+ *,
+ call: _CallType = ...,
+ all: Optional[_ErrKind] = ...,
+ divide: Optional[_ErrKind] = ...,
+ over: Optional[_ErrKind] = ...,
+ under: Optional[_ErrKind] = ...,
+ invalid: Optional[_ErrKind] = ...,
+ ) -> None: ...
+ def __enter__(self) -> None: ...
+ def __exit__(
+ self,
+ __exc_type: Optional[Type[BaseException]],
+ __exc_value: Optional[BaseException],
+ __traceback: Optional[TracebackType],
+ ) -> None: ...
+++ /dev/null
-=======
-WARNING
-=======
-
-This directory (numpy/_build_utils) is *not* part of the public numpy API,
- - it is internal build support for numpy.
- - it is only present in source distributions or during an in place build
- - it is *not* installed with the rest of numpy
+++ /dev/null
-import os
-import sys
-import re
-
-__all__ = ['uses_accelerate_framework', 'get_sgemv_fix']
-
-def uses_accelerate_framework(info):
- """ Returns True if Accelerate framework is used for BLAS/LAPACK """
- # If we're not building on Darwin (macOS), don't use Accelerate
- if sys.platform != "darwin":
- return False
- # If we're building on macOS, but targeting a different platform,
- # don't use Accelerate.
- if os.getenv('_PYTHON_HOST_PLATFORM', None):
- return False
- r_accelerate = re.compile("Accelerate")
- extra_link_args = info.get('extra_link_args', '')
- for arg in extra_link_args:
- if r_accelerate.search(arg):
- return True
- return False
-
-def get_sgemv_fix():
- """ Returns source file needed to correct SGEMV """
- path = os.path.abspath(os.path.dirname(__file__))
- return [os.path.join(path, 'src', 'apple_sgemv_fix.c')]
+++ /dev/null
-/* This is a collection of ugly hacks to circumvent a bug in
- * Apple Accelerate framework's SGEMV subroutine.
- *
- * See: https://github.com/numpy/numpy/issues/4007
- *
- * SGEMV in Accelerate framework will segfault on MacOS X version 10.9
- * (aka Mavericks) if arrays are not aligned to 32 byte boundaries
- * and the CPU supports AVX instructions. This can produce segfaults
- * in np.dot.
- *
- * This patch overshadows the symbols cblas_sgemv, sgemv_ and sgemv
- * exported by Accelerate to produce the correct behavior. The MacOS X
- * version and CPU specs are checked on module import. If Mavericks and
- * AVX are detected the call to SGEMV is emulated with a call to SGEMM
- * if the arrays are not 32 byte aligned. If the exported symbols cannot
- * be overshadowed on module import, a fatal error is produced and the
- * process aborts. All the fixes are in a self-contained C file
- * and do not alter the multiarray C code. The patch is not applied
- * unless NumPy is configured to link with Apple's Accelerate
- * framework.
- *
- */
-
-#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-#include "Python.h"
-#include "numpy/arrayobject.h"
-
-#include <string.h>
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#include <string.h>
-
-/* ----------------------------------------------------------------- */
-/* Original cblas_sgemv */
-
-#define VECLIB_FILE "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/vecLib"
-
-enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102};
-enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113};
-extern void cblas_xerbla(int info, const char *rout, const char *form, ...);
-
-typedef void cblas_sgemv_t(const enum CBLAS_ORDER order,
- const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
- const float alpha, const float *A, const int lda,
- const float *X, const int incX,
- const float beta, float *Y, const int incY);
-
-typedef void cblas_sgemm_t(const enum CBLAS_ORDER order,
- const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB,
- const int M, const int N, const int K,
- const float alpha, const float *A, const int lda,
- const float *B, const int ldb,
- const float beta, float *C, const int incC);
-
-typedef void fortran_sgemv_t( const char* trans, const int* m, const int* n,
- const float* alpha, const float* A, const int* ldA,
- const float* X, const int* incX,
- const float* beta, float* Y, const int* incY );
-
-static void *veclib = NULL;
-static cblas_sgemv_t *accelerate_cblas_sgemv = NULL;
-static cblas_sgemm_t *accelerate_cblas_sgemm = NULL;
-static fortran_sgemv_t *accelerate_sgemv = NULL;
-static int AVX_and_10_9 = 0;
-
-/* Dynamic check for AVX support
- * __builtin_cpu_supports("avx") is available in gcc 4.8,
- * but clang and icc do not currently support it. */
-static inline int
-cpu_supports_avx()
-{
- int enabled, r;
- size_t length = sizeof(enabled);
- r = sysctlbyname("hw.optional.avx1_0", &enabled, &length, NULL, 0);
- if ( r == 0 && enabled != 0) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-/* Check if we are using MacOS X version 10.9 */
-static inline int
-using_mavericks()
-{
- int r;
- char str[32] = {0};
- size_t size = sizeof(str);
- r = sysctlbyname("kern.osproductversion", str, &size, NULL, 0);
- if ( r == 0 && strncmp(str, "10.9", strlen("10.9")) == 0) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-__attribute__((destructor))
-static void unloadlib(void)
-{
- if (veclib) dlclose(veclib);
-}
-
-__attribute__((constructor))
-static void loadlib()
-/* automatically executed on module import */
-{
- char errormsg[1024];
- int AVX, MAVERICKS;
- memset((void*)errormsg, 0, sizeof(errormsg));
- /* check if the CPU supports AVX */
- AVX = cpu_supports_avx();
- /* check if the OS is MacOS X Mavericks */
- MAVERICKS = using_mavericks();
- /* we need the workaround when the CPU supports
- * AVX and the OS version is Mavericks */
- AVX_and_10_9 = AVX && MAVERICKS;
- /* load vecLib */
- veclib = dlopen(VECLIB_FILE, RTLD_LOCAL | RTLD_FIRST);
- if (!veclib) {
- veclib = NULL;
- snprintf(errormsg, sizeof(errormsg),
- "Failed to open vecLib from location '%s'.", VECLIB_FILE);
- Py_FatalError(errormsg); /* calls abort() and dumps core */
- }
- /* resolve Fortran SGEMV from Accelerate */
- accelerate_sgemv = (fortran_sgemv_t*) dlsym(veclib, "sgemv_");
- if (!accelerate_sgemv) {
- unloadlib();
- Py_FatalError("Failed to resolve symbol 'sgemv_'.");
- }
- /* resolve cblas_sgemv from Accelerate */
- accelerate_cblas_sgemv = (cblas_sgemv_t*) dlsym(veclib, "cblas_sgemv");
- if (!accelerate_cblas_sgemv) {
- unloadlib();
- Py_FatalError("Failed to resolve symbol 'cblas_sgemv'.");
- }
- /* resolve cblas_sgemm from Accelerate */
- accelerate_cblas_sgemm = (cblas_sgemm_t*) dlsym(veclib, "cblas_sgemm");
- if (!accelerate_cblas_sgemm) {
- unloadlib();
- Py_FatalError("Failed to resolve symbol 'cblas_sgemm'.");
- }
-}
-
-/* ----------------------------------------------------------------- */
-/* Fortran SGEMV override */
-
-void sgemv_( const char* trans, const int* m, const int* n,
- const float* alpha, const float* A, const int* ldA,
- const float* X, const int* incX,
- const float* beta, float* Y, const int* incY )
-{
- /* It is safe to use the original SGEMV if we are not using AVX on Mavericks
- * or the input arrays A, X and Y are all aligned on 32 byte boundaries. */
- #define BADARRAY(x) (((npy_intp)(void*)x) % 32)
- const int use_sgemm = AVX_and_10_9 && (BADARRAY(A) || BADARRAY(X) || BADARRAY(Y));
- if (!use_sgemm) {
- accelerate_sgemv(trans,m,n,alpha,A,ldA,X,incX,beta,Y,incY);
- return;
- }
-
- /* Arrays are misaligned, the CPU supports AVX, and we are running
- * Mavericks.
- *
- * Emulation of SGEMV with SGEMM:
- *
- * SGEMV allows vectors to be strided. SGEMM requires all arrays to be
- * contiguous along the leading dimension. To emulate striding in SGEMV
- * with the leading dimension arguments in SGEMM we compute
- *
- * Y = alpha * op(A) @ X + beta * Y
- *
- * as
- *
- * Y.T = alpha * X.T @ op(A).T + beta * Y.T
- *
- * Because Fortran uses column major order and X.T and Y.T are row vectors,
- * the leading dimensions of X.T and Y.T in SGEMM become equal to the
- * strides of the column vectors X and Y in SGEMV. */
-
- switch (*trans) {
- case 'T':
- case 't':
- case 'C':
- case 'c':
- accelerate_cblas_sgemm( CblasColMajor, CblasNoTrans, CblasNoTrans,
- 1, *n, *m, *alpha, X, *incX, A, *ldA, *beta, Y, *incY );
- break;
- case 'N':
- case 'n':
- accelerate_cblas_sgemm( CblasColMajor, CblasNoTrans, CblasTrans,
- 1, *m, *n, *alpha, X, *incX, A, *ldA, *beta, Y, *incY );
- break;
- default:
- cblas_xerbla(1, "SGEMV", "Illegal transpose setting: %c\n", *trans);
- }
-}
-
-/* ----------------------------------------------------------------- */
-/* Override for an alias symbol for sgemv_ in Accelerate */
-
-void sgemv (char *trans,
- const int *m, const int *n,
- const float *alpha,
- const float *A, const int *lda,
- const float *B, const int *incB,
- const float *beta,
- float *C, const int *incC)
-{
- sgemv_(trans,m,n,alpha,A,lda,B,incB,beta,C,incC);
-}
-
-/* ----------------------------------------------------------------- */
-/* cblas_sgemv override, based on Netlib CBLAS code */
-
-void cblas_sgemv(const enum CBLAS_ORDER order,
- const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
- const float alpha, const float *A, const int lda,
- const float *X, const int incX, const float beta,
- float *Y, const int incY)
-{
- char TA;
- if (order == CblasColMajor)
- {
- if (TransA == CblasNoTrans) TA = 'N';
- else if (TransA == CblasTrans) TA = 'T';
- else if (TransA == CblasConjTrans) TA = 'C';
- else
- {
- cblas_xerbla(2, "cblas_sgemv","Illegal TransA setting, %d\n", TransA);
- }
- sgemv_(&TA, &M, &N, &alpha, A, &lda, X, &incX, &beta, Y, &incY);
- }
- else if (order == CblasRowMajor)
- {
- if (TransA == CblasNoTrans) TA = 'T';
- else if (TransA == CblasTrans) TA = 'N';
- else if (TransA == CblasConjTrans) TA = 'N';
- else
- {
- cblas_xerbla(2, "cblas_sgemv", "Illegal TransA setting, %d\n", TransA);
- return;
- }
- sgemv_(&TA, &N, &M, &alpha, A, &lda, X, &incX, &beta, Y, &incY);
- }
- else
- cblas_xerbla(1, "cblas_sgemv", "Illegal Order setting, %d\n", order);
-}
``__init__.py`` file::
from numpy._pytesttester import PytestTester
- test = PytestTester(__name__).test
+ test = PytestTester(__name__)
del PytestTester
def _show_numpy_info():
+ from numpy.core._multiarray_umath import (
+ __cpu_features__, __cpu_baseline__, __cpu_dispatch__
+ )
import numpy as np
print("NumPy version %s" % np.__version__)
relaxed_strides = np.ones((10, 1), order="C").flags.f_contiguous
print("NumPy relaxed strides checking option:", relaxed_strides)
+ if len(__cpu_baseline__) == 0 and len(__cpu_dispatch__) == 0:
+ enabled_features = "nothing enabled"
+ else:
+ enabled_features = ' '.join(__cpu_baseline__)
+ for feature in __cpu_dispatch__:
+ if __cpu_features__[feature]:
+ enabled_features += " %s*" % feature
+ else:
+ enabled_features += " %s?" % feature
+ print("NumPy CPU features:", enabled_features)
+
+
class PytestTester:
"""
import pytest
import warnings
- # Imported after pytest to enable assertion rewriting
- import hypothesis
-
module = sys.modules[self.module_name]
module_path = os.path.abspath(module.__path__[0])
pytest_args += ["--pyargs"] + list(tests)
- # This configuration is picked up by numpy.conftest, and ensures that
- # running `np.test()` is deterministic and does not write any files.
- # See https://hypothesis.readthedocs.io/en/latest/settings.html
- hypothesis.settings.register_profile(
- name="np.test() profile",
- deadline=None, print_blob=True, database=None, derandomize=True,
- suppress_health_check=hypothesis.HealthCheck.all(),
- )
-
# run tests.
_show_numpy_info()
--- /dev/null
+from typing import Any
+
+equal: Any
+not_equal: Any
+greater_equal: Any
+less_equal: Any
+greater: Any
+less: Any
+str_len: Any
+add: Any
+multiply: Any
+mod: Any
+capitalize: Any
+center: Any
+count: Any
+decode: Any
+encode: Any
+endswith: Any
+expandtabs: Any
+find: Any
+index: Any
+isalnum: Any
+isalpha: Any
+isdigit: Any
+islower: Any
+isspace: Any
+istitle: Any
+isupper: Any
+join: Any
+ljust: Any
+lower: Any
+lstrip: Any
+partition: Any
+replace: Any
+rfind: Any
+rindex: Any
+rjust: Any
+rpartition: Any
+rsplit: Any
+rstrip: Any
+split: Any
+splitlines: Any
+startswith: Any
+strip: Any
+swapcase: Any
+title: Any
+translate: Any
+upper: Any
+zfill: Any
+isnumeric: Any
+isdecimal: Any
+array: Any
+asarray: Any
import sys
import os
-from pathlib import Path, PurePath
+from pathlib import Path
import io
import abc
def is_pathlib_path(obj):
"""
- Check whether obj is a pathlib.Path object.
+ Check whether obj is a `pathlib.Path` object.
- Prefer using `isinstance(obj, os_PathLike)` instead of this function.
+ Prefer using ``isinstance(obj, os.PathLike)`` instead of this function.
"""
- return Path is not None and isinstance(obj, Path)
+ return isinstance(obj, Path)
# from Python 3.7
class contextlib_nullcontext:
return SourceFileLoader(name, fn).load_module()
-# Backport os.fs_path, os.PathLike, and PurePath.__fspath__
-if sys.version_info[:2] >= (3, 6):
- os_fspath = os.fspath
- os_PathLike = os.PathLike
-else:
- def _PurePath__fspath__(self):
- return str(self)
-
- class os_PathLike(abc_ABC):
- """Abstract base class for implementing the file system path protocol."""
-
- @abc.abstractmethod
- def __fspath__(self):
- """Return the file system path representation of the object."""
- raise NotImplementedError
-
- @classmethod
- def __subclasshook__(cls, subclass):
- if PurePath is not None and issubclass(subclass, PurePath):
- return True
- return hasattr(subclass, '__fspath__')
-
-
- def os_fspath(path):
- """Return the path representation of a path-like object.
- If str or bytes is passed in, it is returned unchanged. Otherwise the
- os.PathLike interface is used to get the path representation. If the
- path representation is not str or bytes, TypeError is raised. If the
- provided path is not str, bytes, or os.PathLike, TypeError is raised.
- """
- if isinstance(path, (str, bytes)):
- return path
-
- # Work from the object's type to match method resolution of other magic
- # methods.
- path_type = type(path)
- try:
- path_repr = path_type.__fspath__(path)
- except AttributeError:
- if hasattr(path_type, '__fspath__'):
- raise
- elif PurePath is not None and issubclass(path_type, PurePath):
- return _PurePath__fspath__(path)
- else:
- raise TypeError("expected str, bytes or os.PathLike object, "
- "not " + path_type.__name__)
- if isinstance(path_repr, (str, bytes)):
- return path_repr
- else:
- raise TypeError("expected {}.__fspath__() to return str or bytes, "
- "not {}".format(path_type.__name__,
- type(path_repr).__name__))
+os_fspath = os.fspath
+os_PathLike = os.PathLike
hypothesis.configuration.set_hypothesis_home_dir(
os.path.join(tempfile.gettempdir(), ".hypothesis")
)
-# See https://hypothesis.readthedocs.io/en/latest/settings.html
+
+# We register two custom profiles for Numpy - for details see
+# https://hypothesis.readthedocs.io/en/latest/settings.html
+# The first is designed for our own CI runs; the latter also
+# forces determinism and is designed for use via np.test()
hypothesis.settings.register_profile(
name="numpy-profile", deadline=None, print_blob=True,
)
-# We try loading the profile defined by np.test(), which disables the
-# database and forces determinism, and fall back to the profile defined
-# above if we're running pytest directly. The odd dance is required
-# because np.test() executes this file *after* its own setup code.
-try:
- hypothesis.settings.load_profile("np.test() profile")
-except hypothesis.errors.InvalidArgument: # profile not found
- hypothesis.settings.load_profile("numpy-profile")
+hypothesis.settings.register_profile(
+ name="np.test() profile",
+ deadline=None, print_blob=True, database=None, derandomize=True,
+ suppress_health_check=hypothesis.HealthCheck.all(),
+)
+# Note that the default profile is chosen based on the presence
+# of pytest.ini, but can be overriden by passing the
+# --hypothesis-profile=NAME argument to pytest.
+_pytest_ini = os.path.join(os.path.dirname(__file__), "..", "pytest.ini")
+hypothesis.settings.load_profile(
+ "numpy-profile" if os.path.isfile(_pytest_ini) else "np.test() profile"
+)
def pytest_configure(config):
@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
doctest_namespace['np'] = numpy
+
+@pytest.fixture(autouse=True)
+def env_setup(monkeypatch):
+ monkeypatch.setenv('PYTHONHASHSEED', '0')
# do this after everything else, to minimize the chance of this misleadingly
# appearing in an import-time traceback
from . import _add_newdocs
+from . import _add_newdocs_scalars
# add these for module-freeze analysis (like PyInstaller)
from . import _dtype_ctypes
from . import _internal
__all__ += shape_base.__all__
__all__ += einsumfunc.__all__
-# Make it possible so that ufuncs can be pickled
-# Here are the loading and unloading functions
-# The name numpy.core._ufunc_reconstruct must be
-# available for unpickling to work.
+# We used to use `np.core._ufunc_reconstruct` to unpickle. This is unnecessary,
+# but old pickles saved before 1.20 will be using it, and there is no reason
+# to break loading them.
def _ufunc_reconstruct(module, name):
# The `fromlist` kwarg is required to ensure that `mod` points to the
# inner-most module rather than the parent package when module name is
return getattr(mod, name)
def _ufunc_reduce(func):
- from pickle import whichmodule
- name = func.__name__
- return _ufunc_reconstruct, (whichmodule(func, name), name)
+ # Report the `__name__`. pickle will try to find the module. Note that
+ # pickle supports for this `__name__` to be a `__qualname__`. It may
+ # make sense to add a `__qualname__` to ufuncs, to allow this more
+ # explicitly (Numba has ufuncs as attributes).
+ # See also: https://github.com/dask/distributed/issues/3450
+ return func.__name__
import copyreg
-copyreg.pickle(ufunc, _ufunc_reduce, _ufunc_reconstruct)
+copyreg.pickle(ufunc, _ufunc_reduce)
# Unclutter namespace (must keep _ufunc_reconstruct for unpickling)
del copyreg
del _ufunc_reduce
"""
-from numpy.core import numerictypes as _numerictypes
-from numpy.core import dtype
from numpy.core.function_base import add_newdoc
+from numpy.core.overrides import array_function_like_doc
###############################################################################
#
--------
broadcast_arrays
broadcast_to
+ broadcast_shapes
Examples
--------
add_newdoc('numpy.core.multiarray', 'array',
"""
- array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0)
+ array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0,
+ like=None)
Create an array.
Specifies the minimum number of dimensions that the resulting
array should have. Ones will be pre-pended to the shape as
needed to meet this requirement.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
matrix([[1, 2],
[3, 4]])
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core.multiarray', 'empty',
"""
- empty(shape, dtype=float, order='C')
+ empty(shape, dtype=float, order='C', *, like=None)
Return a new array of given shape and type, without initializing entries.
Whether to store multi-dimensional data in row-major
(C-style) or column-major (Fortran-style) order in
memory.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
array([[-1073741821, -1067949133],
[ 496041986, 19249760]]) #uninitialized
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core.multiarray', 'scalar',
"""
add_newdoc('numpy.core.multiarray', 'zeros',
"""
- zeros(shape, dtype=float, order='C')
+ zeros(shape, dtype=float, order='C', *, like=None)
Return a new array of given shape and type, filled with zeros.
Whether to store multi-dimensional data in row-major
(C-style) or column-major (Fortran-style) order in
memory.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
array([(0, 0), (0, 0)],
dtype=[('x', '<i4'), ('y', '<i4')])
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core.multiarray', 'set_typeDict',
"""set_typeDict(dict)
add_newdoc('numpy.core.multiarray', 'fromstring',
"""
- fromstring(string, dtype=float, count=-1, sep='')
+ fromstring(string, dtype=float, count=-1, sep='', *, like=None)
A new 1-D array initialized from text data in a string.
text, the binary mode of `fromstring` will first encode it into
bytes using either utf-8 (python 3) or the default encoding
(python 2), neither of which produce sane results.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
>>> np.fromstring('1, 2', dtype=int, sep=',')
array([1, 2])
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core.multiarray', 'compare_chararrays',
"""
add_newdoc('numpy.core.multiarray', 'fromiter',
"""
- fromiter(iterable, dtype, count=-1)
+ fromiter(iterable, dtype, count=-1, *, like=None)
Create a new 1-dimensional array from an iterable object.
count : int, optional
The number of items to read from *iterable*. The default is -1,
which means all data is read.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
>>> np.fromiter(iterable, float)
array([ 0., 1., 4., 9., 16.])
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core.multiarray', 'fromfile',
"""
- fromfile(file, dtype=float, count=-1, sep='', offset=0)
+ fromfile(file, dtype=float, count=-1, sep='', offset=0, *, like=None)
Construct an array from data in a text or binary file.
Only permitted for binary files.
.. versionadded:: 1.17.0
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
See also
--------
array([((10, 0), 98.25)],
dtype=[('time', [('min', '<i8'), ('sec', '<i8')]), ('temp', '<f8')])
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core.multiarray', 'frombuffer',
"""
- frombuffer(buffer, dtype=float, count=-1, offset=0)
+ frombuffer(buffer, dtype=float, count=-1, offset=0, *, like=None)
Interpret a buffer as a 1-dimensional array.
Number of items to read. ``-1`` means all data in the buffer.
offset : int, optional
Start reading the buffer from this offset (in bytes); default: 0.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Notes
-----
>>> np.frombuffer(b'\\x01\\x02\\x03\\x04\\x05', dtype=np.uint8, count=3)
array([1, 2, 3], dtype=uint8)
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core', 'fastCopyAndTranspose',
"""_fastCopyAndTranspose(a)""")
add_newdoc('numpy.core.multiarray', 'arange',
"""
- arange([start,] stop[, step,], dtype=None)
+ arange([start,] stop[, step,], dtype=None, *, like=None)
Return evenly spaced values within a given interval.
Parameters
----------
- start : number, optional
+ start : integer or real, optional
Start of interval. The interval includes this value. The default
start value is 0.
- stop : number
+ stop : integer or real
End of interval. The interval does not include this value, except
in some cases where `step` is not an integer and floating point
round-off affects the length of `out`.
- step : number, optional
+ step : integer or real, optional
Spacing between values. For any output `out`, this is the distance
between two adjacent values, ``out[i+1] - out[i]``. The default
step size is 1. If `step` is specified as a position argument,
dtype : dtype
The type of the output array. If `dtype` is not given, infer the data
type from the other input arguments.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
>>> np.arange(3,7,2)
array([3, 5])
- """)
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
add_newdoc('numpy.core.multiarray', '_get_ndarray_c_version',
"""_get_ndarray_c_version()
Controls the memory layout of the output. 'C' means it should
be C contiguous. 'F' means it should be Fortran contiguous,
'A' means it should be 'F' if the inputs are all 'F', 'C' otherwise.
- 'K' means it should be as close to the layout as the inputs as
+ 'K' means it should be as close to the layout of the inputs as
is possible, including arbitrarily permuted axes.
Default is 'K'.
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
add_newdoc('numpy.core.multiarray', 'ndarray', ('all',
"""
- a.all(axis=None, out=None, keepdims=False)
+ a.all(axis=None, out=None, keepdims=False, *, where=True)
Returns True if all elements evaluate to True.
add_newdoc('numpy.core.multiarray', 'ndarray', ('any',
"""
- a.any(axis=None, out=None, keepdims=False)
+ a.any(axis=None, out=None, keepdims=False, *, where=True)
Returns True if any of the elements of `a` evaluate to True.
"""
a.argmin(axis=None, out=None)
- Return indices of the minimum values along the given axis of `a`.
+ Return indices of the minimum values along the given axis.
Refer to `numpy.argmin` for detailed documentation.
add_newdoc('numpy.core.multiarray', 'ndarray', ('mean',
"""
- a.mean(axis=None, dtype=None, out=None, keepdims=False)
+ a.mean(axis=None, dtype=None, out=None, keepdims=False, *, where=True)
Returns the average of the array elements along given axis.
add_newdoc('numpy.core.multiarray', 'ndarray', ('newbyteorder',
"""
- arr.newbyteorder(new_order='S')
+ arr.newbyteorder(new_order='S', /)
Return the array with the same data viewed with a different byte order.
below. `new_order` codes can be any of:
* 'S' - swap dtype from current to opposite endian
- * {'<', 'L'} - little endian
- * {'>', 'B'} - big endian
- * {'=', 'N'} - native order
+ * {'<', 'little'} - little endian
+ * {'>', 'big'} - big endian
+ * '=' - native order, equivalent to `sys.byteorder`
* {'|', 'I'} - ignore (no change to byte order)
The default value ('S') results in swapping the current
- byte order. The code does a case-insensitive check on the first
- letter of `new_order` for the alternatives above. For example,
- any of 'B' or 'b' or 'biggish' are valid to specify big-endian.
+ byte order.
Returns
"""
a.squeeze(axis=None)
- Remove single-dimensional entries from the shape of `a`.
+ Remove axes of length one from `a`.
Refer to `numpy.squeeze` for full documentation.
add_newdoc('numpy.core.multiarray', 'ndarray', ('std',
"""
- a.std(axis=None, dtype=None, out=None, ddof=0, keepdims=False)
+ a.std(axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True)
Returns the standard deviation of the array elements along given axis.
Construct Python bytes containing the raw data bytes in the array.
Constructs Python bytes showing a copy of the raw contents of
- data memory. The bytes object can be produced in either 'C' or 'Fortran',
- or 'Any' order (the default is 'C'-order). 'Any' order means C-order
- unless the F_CONTIGUOUS flag in the array is set, in which case it
- means 'Fortran' order.
+ data memory. The bytes object is produced in C-order by default.
+ This behavior is controlled by the ``order`` parameter.
.. versionadded:: 1.9.0
Parameters
----------
- order : {'C', 'F', None}, optional
- Order of the data for multidimensional arrays:
- C, Fortran, or the same as for the original array.
+ order : {'C', 'F', 'A'}, optional
+ Controls the memory layout of the bytes object. 'C' means C-order,
+ 'F' means F-order, 'A' (short for *Any*) means 'F' if `a` is
+ Fortran contiguous, 'C' otherwise. Default is 'C'.
Returns
-------
add_newdoc('numpy.core.multiarray', 'ndarray', ('var',
"""
- a.var(axis=None, dtype=None, out=None, ddof=0, keepdims=False)
+ a.var(axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True)
Returns the variance of the array elements, along given axis.
A detailed explanation of ufuncs can be found in the docs for :ref:`ufuncs`.
- Calling ufuncs:
- ===============
+ **Calling ufuncs:** ``op(*x[, out], where=True, **kwargs)``
- op(*x[, out], where=True, **kwargs)
Apply `op` to the arguments `*x` elementwise, broadcasting the arguments.
The broadcasting rules are:
add_newdoc('numpy.core', 'ufunc', ('reduce',
"""
- reduce(a, axis=0, dtype=None, out=None, keepdims=False, initial=<no value>, where=True)
+ reduce(array, axis=0, dtype=None, out=None, keepdims=False, initial=<no value>, where=True)
- Reduces `a`'s dimension by one, by applying ufunc along one axis.
+ Reduces `array`'s dimension by one, by applying ufunc along one axis.
- Let :math:`a.shape = (N_0, ..., N_i, ..., N_{M-1})`. Then
- :math:`ufunc.reduce(a, axis=i)[k_0, ..,k_{i-1}, k_{i+1}, .., k_{M-1}]` =
+ Let :math:`array.shape = (N_0, ..., N_i, ..., N_{M-1})`. Then
+ :math:`ufunc.reduce(array, axis=i)[k_0, ..,k_{i-1}, k_{i+1}, .., k_{M-1}]` =
the result of iterating `j` over :math:`range(N_i)`, cumulatively applying
- ufunc to each :math:`a[k_0, ..,k_{i-1}, j, k_{i+1}, .., k_{M-1}]`.
+ ufunc to each :math:`array[k_0, ..,k_{i-1}, j, k_{i+1}, .., k_{M-1}]`.
For a one-dimensional array, reduce produces results equivalent to:
::
Parameters
----------
- a : array_like
+ array : array_like
The array to act on.
axis : None or int or tuple of ints, optional
Axis or axes along which a reduction is performed.
keepdims : bool, optional
If this is set to True, the axes which are reduced are left
in the result as dimensions with size one. With this option,
- the result will broadcast correctly against the original `arr`.
+ the result will broadcast correctly against the original `array`.
.. versionadded:: 1.7.0
initial : scalar, optional
where : array_like of bool, optional
A boolean array which is broadcasted to match the dimensions
- of `a`, and selects elements to include in the reduction. Note
+ of `array`, and selects elements to include in the reduction. Note
that for ufuncs like ``minimum`` that do not have an identity
defined, one has to pass in also ``initial``.
add_newdoc('numpy.core', 'ufunc', ('reduceat',
"""
- reduceat(a, indices, axis=0, dtype=None, out=None)
+ reduceat(array, indices, axis=0, dtype=None, out=None)
Performs a (local) reduce with specified slices over a single axis.
For i in ``range(len(indices))``, `reduceat` computes
- ``ufunc.reduce(a[indices[i]:indices[i+1]])``, which becomes the i-th
+ ``ufunc.reduce(array[indices[i]:indices[i+1]])``, which becomes the i-th
generalized "row" parallel to `axis` in the final result (i.e., in a
2-D array, for example, if `axis = 0`, it becomes the i-th row, but if
`axis = 1`, it becomes the i-th column). There are three exceptions to this:
* when ``i = len(indices) - 1`` (so for the last index),
- ``indices[i+1] = a.shape[axis]``.
+ ``indices[i+1] = array.shape[axis]``.
* if ``indices[i] >= indices[i + 1]``, the i-th generalized "row" is
- simply ``a[indices[i]]``.
- * if ``indices[i] >= len(a)`` or ``indices[i] < 0``, an error is raised.
+ simply ``array[indices[i]]``.
+ * if ``indices[i] >= len(array)`` or ``indices[i] < 0``, an error is raised.
The shape of the output depends on the size of `indices`, and may be
- larger than `a` (this happens if ``len(indices) > a.shape[axis]``).
+ larger than `array` (this happens if ``len(indices) > array.shape[axis]``).
Parameters
----------
- a : array_like
+ array : array_like
The array to act on.
indices : array_like
Paired indices, comma separated (not colon), specifying slices to
-----
A descriptive example:
- If `a` is 1-D, the function `ufunc.accumulate(a)` is the same as
- ``ufunc.reduceat(a, indices)[::2]`` where `indices` is
+ If `array` is 1-D, the function `ufunc.accumulate(array)` is the same as
+ ``ufunc.reduceat(array, indices)[::2]`` where `indices` is
``range(len(array) - 1)`` with a zero placed
in every other element:
- ``indices = zeros(2 * len(a) - 1)``, ``indices[1::2] = range(1, len(a))``.
+ ``indices = zeros(2 * len(array) - 1)``,
+ ``indices[1::2] = range(1, len(array))``.
- Don't be fooled by this attribute's name: `reduceat(a)` is not
- necessarily smaller than `a`.
+ Don't be fooled by this attribute's name: `reduceat(array)` is not
+ necessarily smaller than `array`.
Examples
--------
add_newdoc('numpy.core', 'ufunc', ('outer',
r"""
- outer(A, B, **kwargs)
+ outer(A, B, /, **kwargs)
Apply the ufunc `op` to all pairs (a, b) with a in `A` and b in `B`.
add_newdoc('numpy.core', 'ufunc', ('at',
"""
- at(a, indices, b=None)
+ at(a, indices, b=None, /)
Performs unbuffered in place operation on operand 'a' for elements
specified by 'indices'. For addition ufunc, this method is equivalent to
add_newdoc('numpy.core.multiarray', 'dtype',
"""
- dtype(obj, align=False, copy=False)
+ dtype(dtype, align=False, copy=False)
Create a data type object.
Parameters
----------
- obj
+ dtype
Object to be converted to a data type object.
align : bool, optional
Add padding to the fields to match what a C compiler would output
"""))
+add_newdoc('numpy.core.multiarray', 'dtype', ('metadata',
+ """
+ Either ``None`` or a readonly dictionary of metadata (mappingproxy).
+
+ The metadata field can be set using any dictionary at data-type
+ creation. NumPy currently has no uniform approach to propagating
+ metadata; although some array operations preserve it, there is no
+ guarantee that others will.
+
+ .. warning::
+
+ Although used in certain projects, this feature was long undocumented
+ and is not well supported. Some aspects of metadata propagation
+ are expected to change in the future.
+
+ Examples
+ --------
+
+ >>> dt = np.dtype(float, metadata={"key": "value"})
+ >>> dt.metadata["key"]
+ 'value'
+ >>> arr = np.array([1, 2, 3], dtype=dt)
+ >>> arr.dtype.metadata
+ mappingproxy({'key': 'value'})
+
+ Adding arrays with identical datatypes currently preserves the metadata:
+
+ >>> (arr + arr).dtype.metadata
+ mappingproxy({'key': 'value'})
+
+ But if the arrays have different dtype metadata, the metadata may be
+ dropped:
+
+ >>> dt2 = np.dtype(float, metadata={"key2": "value2"})
+ >>> arr2 = np.array([3, 2, 1], dtype=dt2)
+ >>> (arr + arr2).dtype.metadata is None
+ True # The metadata field is cleared so None is returned
+ """))
+
add_newdoc('numpy.core.multiarray', 'dtype', ('name',
"""
A bit-width name for this data-type.
add_newdoc('numpy.core.multiarray', 'dtype', ('newbyteorder',
"""
- newbyteorder(new_order='S')
+ newbyteorder(new_order='S', /)
Return a new dtype with a different byte order.
byte order. `new_order` codes can be any of:
* 'S' - swap dtype from current to opposite endian
- * {'<', 'L'} - little endian
- * {'>', 'B'} - big endian
- * {'=', 'N'} - native order
+ * {'<', 'little'} - little endian
+ * {'>', 'big'} - big endian
+ * '=' - native order
* {'|', 'I'} - ignore (no change to byte order)
- The code does a case-insensitive check on the first letter of
- `new_order` for these alternatives. For example, any of '>'
- or 'B' or 'b' or 'brian' are valid to specify big-endian.
-
Returns
-------
new_dtype : dtype
# Attributes
-add_newdoc('numpy.core.numerictypes', 'generic', ('T',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class so as to
- provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
+def refer_to_array_attribute(attr, method=True):
+ docstring = """
+ Scalar {} identical to the corresponding array attribute.
-add_newdoc('numpy.core.numerictypes', 'generic', ('base',
+ Please see `ndarray.{}`.
"""
- Not implemented (virtual attribute)
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class so as to
- a uniform API.
+ return attr, docstring.format("method" if method else "attribute", attr)
- See also the corresponding attribute of the derived class of interest.
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('T', method=False))
+
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('base', method=False))
add_newdoc('numpy.core.numerictypes', 'generic', ('data',
"""Pointer to start of data."""))
# Methods
-add_newdoc('numpy.core.numerictypes', 'generic', ('all',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('any',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('argmax',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('argmin',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('argsort',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('astype',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('byteswap',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class so as to
- provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('choose',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('clip',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('compress',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('conjugate',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('copy',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('cumprod',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('cumsum',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('diagonal',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('dump',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('dumps',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('fill',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('flatten',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('all'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('getfield',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('any'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('argmax'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('argmin'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('argsort'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('item',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('astype'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('byteswap'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('choose'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('clip'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('itemset',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('compress'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('conjugate'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('copy'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('cumprod'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('max',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('cumsum'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('diagonal'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('dump'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('dumps'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('mean',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('fill'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('flatten'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('getfield'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('item'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('min',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('itemset'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('max'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('mean'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('min'))
add_newdoc('numpy.core.numerictypes', 'generic', ('newbyteorder',
"""
- newbyteorder(new_order='S')
+ newbyteorder(new_order='S', /)
Return a new `dtype` with a different byte order.
The `new_order` code can be any from the following:
* 'S' - swap dtype from current to opposite endian
- * {'<', 'L'} - little endian
- * {'>', 'B'} - big endian
- * {'=', 'N'} - native order
+ * {'<', 'little'} - little endian
+ * {'>', 'big'} - big endian
+ * '=' - native order
* {'|', 'I'} - ignore (no change to byte order)
Parameters
new_order : str, optional
Byte order to force; a value from the byte order specifications
above. The default value ('S') results in swapping the current
- byte order. The code does a case-insensitive check on the first
- letter of `new_order` for the alternatives above. For example,
- any of 'B' or 'b' or 'biggish' are valid to specify big-endian.
+ byte order.
Returns
"""))
-add_newdoc('numpy.core.numerictypes', 'generic', ('nonzero',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('prod',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('ptp',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('put',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('ravel',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('repeat',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('reshape',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('resize',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('round',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('searchsorted',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('setfield',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('setflags',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class so as to
- provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('sort',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('squeeze',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('std',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('sum',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('swapaxes',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('take',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
-
-add_newdoc('numpy.core.numerictypes', 'generic', ('tofile',
- """
- Not implemented (virtual attribute)
-
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
-
- See also the corresponding attribute of the derived class of interest.
-
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('nonzero'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('tolist',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('prod'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('ptp'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('put'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('ravel'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('tostring',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('repeat'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('reshape'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('resize'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('round'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('trace',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('searchsorted'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('setfield'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('setflags'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('sort'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('transpose',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('squeeze'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('std'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('sum'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('swapaxes'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('var',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('take'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('tofile'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('tolist'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('tostring'))
-add_newdoc('numpy.core.numerictypes', 'generic', ('view',
- """
- Not implemented (virtual attribute)
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('trace'))
- Class generic exists solely to derive numpy scalars from, and possesses,
- albeit unimplemented, all the attributes of the ndarray class
- so as to provide a uniform API.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('transpose'))
- See also the corresponding attribute of the derived class of interest.
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('var'))
- """))
+add_newdoc('numpy.core.numerictypes', 'generic',
+ refer_to_array_attribute('view'))
##############################################################################
Abstract base class of all character string scalar types.
""")
-
-
-##############################################################################
-#
-# Documentation for concrete scalar classes
-#
-##############################################################################
-
-def numeric_type_aliases(aliases):
- def type_aliases_gen():
- for alias, doc in aliases:
- try:
- alias_type = getattr(_numerictypes, alias)
- except AttributeError:
- # The set of aliases that actually exist varies between platforms
- pass
- else:
- yield (alias_type, alias, doc)
- return list(type_aliases_gen())
-
-
-possible_aliases = numeric_type_aliases([
- ('int8', '8-bit signed integer (-128 to 127)'),
- ('int16', '16-bit signed integer (-32768 to 32767)'),
- ('int32', '32-bit signed integer (-2147483648 to 2147483647)'),
- ('int64', '64-bit signed integer (-9223372036854775808 to 9223372036854775807)'),
- ('intp', 'Signed integer large enough to fit pointer, compatible with C ``intptr_t``'),
- ('uint8', '8-bit unsigned integer (0 to 255)'),
- ('uint16', '16-bit unsigned integer (0 to 65535)'),
- ('uint32', '32-bit unsigned integer (0 to 4294967295)'),
- ('uint64', '64-bit unsigned integer (0 to 18446744073709551615)'),
- ('uintp', 'Unsigned integer large enough to fit pointer, compatible with C ``uintptr_t``'),
- ('float16', '16-bit-precision floating-point number type: sign bit, 5 bits exponent, 10 bits mantissa'),
- ('float32', '32-bit-precision floating-point number type: sign bit, 8 bits exponent, 23 bits mantissa'),
- ('float64', '64-bit precision floating-point number type: sign bit, 11 bits exponent, 52 bits mantissa'),
- ('float96', '96-bit extended-precision floating-point number type'),
- ('float128', '128-bit extended-precision floating-point number type'),
- ('complex64', 'Complex number type composed of 2 32-bit-precision floating-point numbers'),
- ('complex128', 'Complex number type composed of 2 64-bit-precision floating-point numbers'),
- ('complex192', 'Complex number type composed of 2 96-bit extended-precision floating-point numbers'),
- ('complex256', 'Complex number type composed of 2 128-bit extended-precision floating-point numbers'),
- ])
-
-
-def add_newdoc_for_scalar_type(obj, fixed_aliases, doc):
- o = getattr(_numerictypes, obj)
-
- character_code = dtype(o).char
- canonical_name_doc = "" if obj == o.__name__ else "Canonical name: ``np.{}``.\n ".format(obj)
- alias_doc = ''.join("Alias: ``np.{}``.\n ".format(alias) for alias in fixed_aliases)
- alias_doc += ''.join("Alias *on this platform*: ``np.{}``: {}.\n ".format(alias, doc)
- for (alias_type, alias, doc) in possible_aliases if alias_type is o)
-
- docstring = """
- {doc}
- Character code: ``'{character_code}'``.
- {canonical_name_doc}{alias_doc}
- """.format(doc=doc.strip(), character_code=character_code,
- canonical_name_doc=canonical_name_doc, alias_doc=alias_doc)
-
- add_newdoc('numpy.core.numerictypes', obj, docstring)
-
-
-add_newdoc_for_scalar_type('bool_', ['bool8'],
- """
- Boolean type (True or False), stored as a byte.
- """)
-
-add_newdoc_for_scalar_type('byte', [],
- """
- Signed integer type, compatible with C ``char``.
- """)
-
-add_newdoc_for_scalar_type('short', [],
- """
- Signed integer type, compatible with C ``short``.
- """)
-
-add_newdoc_for_scalar_type('intc', [],
- """
- Signed integer type, compatible with C ``int``.
- """)
-
-add_newdoc_for_scalar_type('int_', [],
- """
- Signed integer type, compatible with Python `int` anc C ``long``.
- """)
-
-add_newdoc_for_scalar_type('longlong', [],
- """
- Signed integer type, compatible with C ``long long``.
- """)
-
-add_newdoc_for_scalar_type('ubyte', [],
- """
- Unsigned integer type, compatible with C ``unsigned char``.
- """)
-
-add_newdoc_for_scalar_type('ushort', [],
- """
- Unsigned integer type, compatible with C ``unsigned short``.
- """)
-
-add_newdoc_for_scalar_type('uintc', [],
- """
- Unsigned integer type, compatible with C ``unsigned int``.
- """)
-
-add_newdoc_for_scalar_type('uint', [],
- """
- Unsigned integer type, compatible with C ``unsigned long``.
- """)
-
-add_newdoc_for_scalar_type('ulonglong', [],
- """
- Signed integer type, compatible with C ``unsigned long long``.
- """)
-
-add_newdoc_for_scalar_type('half', [],
- """
- Half-precision floating-point number type.
- """)
-
-add_newdoc_for_scalar_type('single', [],
- """
- Single-precision floating-point number type, compatible with C ``float``.
- """)
-
-add_newdoc_for_scalar_type('double', ['float_'],
- """
- Double-precision floating-point number type, compatible with Python `float`
- and C ``double``.
- """)
-
-add_newdoc_for_scalar_type('longdouble', ['longfloat'],
- """
- Extended-precision floating-point number type, compatible with C
- ``long double`` but not necessarily with IEEE 754 quadruple-precision.
- """)
-
-add_newdoc_for_scalar_type('csingle', ['singlecomplex'],
- """
- Complex number type composed of two single-precision floating-point
- numbers.
- """)
-
-add_newdoc_for_scalar_type('cdouble', ['cfloat', 'complex_'],
- """
- Complex number type composed of two double-precision floating-point
- numbers, compatible with Python `complex`.
- """)
-
-add_newdoc_for_scalar_type('clongdouble', ['clongfloat', 'longcomplex'],
- """
- Complex number type composed of two extended-precision floating-point
- numbers.
- """)
-
-add_newdoc_for_scalar_type('object_', [],
- """
- Any Python object.
- """)
-
-# TODO: work out how to put this on the base class, np.floating
-for float_name in ('half', 'single', 'double', 'longdouble'):
- add_newdoc('numpy.core.numerictypes', float_name, ('as_integer_ratio',
- """
- {ftype}.as_integer_ratio() -> (int, int)
-
- Return a pair of integers, whose ratio is exactly equal to the original
- floating point number, and with a positive denominator.
- Raise OverflowError on infinities and a ValueError on NaNs.
-
- >>> np.{ftype}(10.0).as_integer_ratio()
- (10, 1)
- >>> np.{ftype}(0.0).as_integer_ratio()
- (0, 1)
- >>> np.{ftype}(-.25).as_integer_ratio()
- (-1, 4)
- """.format(ftype=float_name)))
--- /dev/null
+"""
+This file is separate from ``_add_newdocs.py`` so that it can be mocked out by
+our sphinx ``conf.py`` during doc builds, where we want to avoid showing
+platform-dependent information.
+"""
+from numpy.core import dtype
+from numpy.core import numerictypes as _numerictypes
+from numpy.core.function_base import add_newdoc
+
+##############################################################################
+#
+# Documentation for concrete scalar classes
+#
+##############################################################################
+
+def numeric_type_aliases(aliases):
+ def type_aliases_gen():
+ for alias, doc in aliases:
+ try:
+ alias_type = getattr(_numerictypes, alias)
+ except AttributeError:
+ # The set of aliases that actually exist varies between platforms
+ pass
+ else:
+ yield (alias_type, alias, doc)
+ return list(type_aliases_gen())
+
+
+possible_aliases = numeric_type_aliases([
+ ('int8', '8-bit signed integer (``-128`` to ``127``)'),
+ ('int16', '16-bit signed integer (``-32_768`` to ``32_767``)'),
+ ('int32', '32-bit signed integer (``-2_147_483_648`` to ``2_147_483_647``)'),
+ ('int64', '64-bit signed integer (``-9_223_372_036_854_775_808`` to ``9_223_372_036_854_775_807``)'),
+ ('intp', 'Signed integer large enough to fit pointer, compatible with C ``intptr_t``'),
+ ('uint8', '8-bit unsigned integer (``0`` to ``255``)'),
+ ('uint16', '16-bit unsigned integer (``0`` to ``65_535``)'),
+ ('uint32', '32-bit unsigned integer (``0`` to ``4_294_967_295``)'),
+ ('uint64', '64-bit unsigned integer (``0`` to ``18_446_744_073_709_551_615``)'),
+ ('uintp', 'Unsigned integer large enough to fit pointer, compatible with C ``uintptr_t``'),
+ ('float16', '16-bit-precision floating-point number type: sign bit, 5 bits exponent, 10 bits mantissa'),
+ ('float32', '32-bit-precision floating-point number type: sign bit, 8 bits exponent, 23 bits mantissa'),
+ ('float64', '64-bit precision floating-point number type: sign bit, 11 bits exponent, 52 bits mantissa'),
+ ('float96', '96-bit extended-precision floating-point number type'),
+ ('float128', '128-bit extended-precision floating-point number type'),
+ ('complex64', 'Complex number type composed of 2 32-bit-precision floating-point numbers'),
+ ('complex128', 'Complex number type composed of 2 64-bit-precision floating-point numbers'),
+ ('complex192', 'Complex number type composed of 2 96-bit extended-precision floating-point numbers'),
+ ('complex256', 'Complex number type composed of 2 128-bit extended-precision floating-point numbers'),
+ ])
+
+
+def add_newdoc_for_scalar_type(obj, fixed_aliases, doc):
+ # note: `:field: value` is rST syntax which renders as field lists.
+ o = getattr(_numerictypes, obj)
+
+ character_code = dtype(o).char
+ canonical_name_doc = "" if obj == o.__name__ else ":Canonical name: `numpy.{}`\n ".format(obj)
+ alias_doc = ''.join(":Alias: `numpy.{}`\n ".format(alias) for alias in fixed_aliases)
+ alias_doc += ''.join(":Alias on this platform: `numpy.{}`: {}.\n ".format(alias, doc)
+ for (alias_type, alias, doc) in possible_aliases if alias_type is o)
+ docstring = """
+ {doc}
+
+ :Character code: ``'{character_code}'``
+ {canonical_name_doc}{alias_doc}
+ """.format(doc=doc.strip(), character_code=character_code,
+ canonical_name_doc=canonical_name_doc, alias_doc=alias_doc)
+
+ add_newdoc('numpy.core.numerictypes', obj, docstring)
+
+
+add_newdoc_for_scalar_type('bool_', ['bool8'],
+ """
+ Boolean type (True or False), stored as a byte.
+
+ .. warning::
+
+ The :class:`bool_` type is not a subclass of the :class:`int_` type
+ (the :class:`bool_` is not even a number type). This is different
+ than Python's default implementation of :class:`bool` as a
+ sub-class of :class:`int`.
+ """)
+
+add_newdoc_for_scalar_type('byte', [],
+ """
+ Signed integer type, compatible with C ``char``.
+ """)
+
+add_newdoc_for_scalar_type('short', [],
+ """
+ Signed integer type, compatible with C ``short``.
+ """)
+
+add_newdoc_for_scalar_type('intc', [],
+ """
+ Signed integer type, compatible with C ``int``.
+ """)
+
+add_newdoc_for_scalar_type('int_', [],
+ """
+ Signed integer type, compatible with Python `int` and C ``long``.
+ """)
+
+add_newdoc_for_scalar_type('longlong', [],
+ """
+ Signed integer type, compatible with C ``long long``.
+ """)
+
+add_newdoc_for_scalar_type('ubyte', [],
+ """
+ Unsigned integer type, compatible with C ``unsigned char``.
+ """)
+
+add_newdoc_for_scalar_type('ushort', [],
+ """
+ Unsigned integer type, compatible with C ``unsigned short``.
+ """)
+
+add_newdoc_for_scalar_type('uintc', [],
+ """
+ Unsigned integer type, compatible with C ``unsigned int``.
+ """)
+
+add_newdoc_for_scalar_type('uint', [],
+ """
+ Unsigned integer type, compatible with C ``unsigned long``.
+ """)
+
+add_newdoc_for_scalar_type('ulonglong', [],
+ """
+ Signed integer type, compatible with C ``unsigned long long``.
+ """)
+
+add_newdoc_for_scalar_type('half', [],
+ """
+ Half-precision floating-point number type.
+ """)
+
+add_newdoc_for_scalar_type('single', [],
+ """
+ Single-precision floating-point number type, compatible with C ``float``.
+ """)
+
+add_newdoc_for_scalar_type('double', ['float_'],
+ """
+ Double-precision floating-point number type, compatible with Python `float`
+ and C ``double``.
+ """)
+
+add_newdoc_for_scalar_type('longdouble', ['longfloat'],
+ """
+ Extended-precision floating-point number type, compatible with C
+ ``long double`` but not necessarily with IEEE 754 quadruple-precision.
+ """)
+
+add_newdoc_for_scalar_type('csingle', ['singlecomplex'],
+ """
+ Complex number type composed of two single-precision floating-point
+ numbers.
+ """)
+
+add_newdoc_for_scalar_type('cdouble', ['cfloat', 'complex_'],
+ """
+ Complex number type composed of two double-precision floating-point
+ numbers, compatible with Python `complex`.
+ """)
+
+add_newdoc_for_scalar_type('clongdouble', ['clongfloat', 'longcomplex'],
+ """
+ Complex number type composed of two extended-precision floating-point
+ numbers.
+ """)
+
+add_newdoc_for_scalar_type('object_', [],
+ """
+ Any Python object.
+ """)
+
+add_newdoc_for_scalar_type('str_', ['unicode_'],
+ r"""
+ A unicode string.
+
+ When used in arrays, this type strips trailing null codepoints.
+
+ Unlike the builtin `str`, this supports the :ref:`python:bufferobjects`, exposing its
+ contents as UCS4:
+
+ >>> m = memoryview(np.str_("abc"))
+ >>> m.format
+ '3w'
+ >>> m.tobytes()
+ b'a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00'
+ """)
+
+add_newdoc_for_scalar_type('bytes_', ['string_'],
+ r"""
+ A byte string.
+
+ When used in arrays, this type strips trailing null bytes.
+ """)
+
+add_newdoc_for_scalar_type('void', [],
+ r"""
+ Either an opaque sequence of bytes, or a structure.
+
+ >>> np.void(b'abcd')
+ void(b'\x61\x62\x63\x64')
+
+ Structured `void` scalars can only be constructed via extraction from :ref:`structured_arrays`:
+
+ >>> arr = np.array((1, 2), dtype=[('x', np.int8), ('y', np.int8)])
+ >>> arr[()]
+ (1, 2) # looks like a tuple, but is `np.void`
+ """)
+
+add_newdoc_for_scalar_type('datetime64', [],
+ """
+ A datetime stored as a 64-bit integer, counting from ``1970-01-01T00:00:00``.
+
+ >>> np.datetime64(10, 'Y')
+ numpy.datetime64('1980')
+ >>> np.datetime64(10, 'D')
+ numpy.datetime64('1970-01-11')
+
+ See :ref:`arrays.datetime` for more information.
+ """)
+
+add_newdoc_for_scalar_type('timedelta64', [],
+ """
+ A timedelta stored as a 64-bit integer.
+
+ See :ref:`arrays.datetime` for more information.
+ """)
+
+# TODO: work out how to put this on the base class, np.floating
+for float_name in ('half', 'single', 'double', 'longdouble'):
+ add_newdoc('numpy.core.numerictypes', float_name, ('as_integer_ratio',
+ """
+ {ftype}.as_integer_ratio() -> (int, int)
+
+ Return a pair of integers, whose ratio is exactly equal to the original
+ floating point number, and with a positive denominator.
+ Raise `OverflowError` on infinities and a `ValueError` on NaNs.
+
+ >>> np.{ftype}(10.0).as_integer_ratio()
+ (10, 1)
+ >>> np.{ftype}(0.0).as_integer_ratio()
+ (0, 1)
+ >>> np.{ftype}(-.25).as_integer_ratio()
+ (-1, 4)
+ """.format(ftype=float_name)))
`require` fits this category despite its name not matching this pattern.
"""
-from .overrides import set_module
+from .overrides import (
+ array_function_dispatch,
+ set_array_function_like_doc,
+ set_module,
+)
from .multiarray import array
"asarray", "asanyarray", "ascontiguousarray", "asfortranarray", "require",
]
+
+def _asarray_dispatcher(a, dtype=None, order=None, *, like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def asarray(a, dtype=None, order=None):
+def asarray(a, dtype=None, order=None, *, like=None):
"""Convert the input to an array.
Parameters
of lists and ndarrays.
dtype : data-type, optional
By default, the data-type is inferred from the input data.
- order : {'C', 'F'}, optional
- Whether to use row-major (C-style) or
- column-major (Fortran-style) memory representation.
+ order : {'C', 'F', 'A', 'K'}, optional
+ Memory layout. 'A' and 'K' depend on the order of input array a.
+ 'C' row-major (C-style),
+ 'F' column-major (Fortran-style) memory representation.
+ 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
+ 'K' (keep) preserve input order
Defaults to 'C'.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
True
"""
+ if like is not None:
+ return _asarray_with_like(a, dtype=dtype, order=order, like=like)
+
return array(a, dtype, copy=False, order=order)
+_asarray_with_like = array_function_dispatch(
+ _asarray_dispatcher
+)(asarray)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def asanyarray(a, dtype=None, order=None):
+def asanyarray(a, dtype=None, order=None, *, like=None):
"""Convert the input to an ndarray, but pass ndarray subclasses through.
Parameters
tuples of lists, and ndarrays.
dtype : data-type, optional
By default, the data-type is inferred from the input data.
- order : {'C', 'F'}, optional
- Whether to use row-major (C-style) or column-major
- (Fortran-style) memory representation. Defaults to 'C'.
+ order : {'C', 'F', 'A', 'K'}, optional
+ Memory layout. 'A' and 'K' depend on the order of input array a.
+ 'C' row-major (C-style),
+ 'F' column-major (Fortran-style) memory representation.
+ 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
+ 'K' (keep) preserve input order
+ Defaults to 'C'.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
True
"""
+ if like is not None:
+ return _asanyarray_with_like(a, dtype=dtype, order=order, like=like)
+
return array(a, dtype, copy=False, order=order, subok=True)
+_asanyarray_with_like = array_function_dispatch(
+ _asarray_dispatcher
+)(asanyarray)
+
+
+def _asarray_contiguous_fortran_dispatcher(a, dtype=None, *, like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def ascontiguousarray(a, dtype=None):
+def ascontiguousarray(a, dtype=None, *, like=None):
"""
Return a contiguous array (ndim >= 1) in memory (C order).
Input array.
dtype : str or dtype object, optional
Data-type of returned array.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
so it will not preserve 0-d arrays.
"""
+ if like is not None:
+ return _ascontiguousarray_with_like(a, dtype=dtype, like=like)
+
return array(a, dtype, copy=False, order='C', ndmin=1)
+_ascontiguousarray_with_like = array_function_dispatch(
+ _asarray_contiguous_fortran_dispatcher
+)(ascontiguousarray)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def asfortranarray(a, dtype=None):
+def asfortranarray(a, dtype=None, *, like=None):
"""
Return an array (ndim >= 1) laid out in Fortran order in memory.
Input array.
dtype : str or dtype object, optional
By default, the data-type is inferred from the input data.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
so it will not preserve 0-d arrays.
"""
+ if like is not None:
+ return _asfortranarray_with_like(a, dtype=dtype, like=like)
+
return array(a, dtype, copy=False, order='F', ndmin=1)
+_asfortranarray_with_like = array_function_dispatch(
+ _asarray_contiguous_fortran_dispatcher
+)(asfortranarray)
+
+
+def _require_dispatcher(a, dtype=None, requirements=None, *, like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def require(a, dtype=None, requirements=None):
+def require(a, dtype=None, requirements=None, *, like=None):
"""
Return an ndarray of the provided type that satisfies requirements.
* 'WRITEABLE' ('W') - ensure a writable array
* 'OWNDATA' ('O') - ensure an array that owns its own data
* 'ENSUREARRAY', ('E') - ensure a base array, instead of a subclass
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
UPDATEIFCOPY : False
"""
+ if like is not None:
+ return _require_with_like(
+ a,
+ dtype=dtype,
+ requirements=requirements,
+ like=like,
+ )
+
possible_flags = {'C': 'C', 'C_CONTIGUOUS': 'C', 'CONTIGUOUS': 'C',
'F': 'F', 'F_CONTIGUOUS': 'F', 'FORTRAN': 'F',
'A': 'A', 'ALIGNED': 'A',
arr = arr.copy(order)
break
return arr
+
+
+_require_with_like = array_function_dispatch(
+ _require_dispatcher
+)(require)
--- /dev/null
+import sys
+from typing import TypeVar, Union, Iterable, overload
+
+from numpy import ndarray, _OrderKACF
+from numpy.typing import ArrayLike, DTypeLike
+
+if sys.version_info >= (3, 8):
+ from typing import Literal
+else:
+ from typing_extensions import Literal
+
+_ArrayType = TypeVar("_ArrayType", bound=ndarray)
+
+def asarray(
+ a: object,
+ dtype: DTypeLike = ...,
+ order: _OrderKACF = ...,
+ *,
+ like: ArrayLike = ...
+) -> ndarray: ...
+@overload
+def asanyarray(
+ a: _ArrayType,
+ dtype: None = ...,
+ order: _OrderKACF = ...,
+ *,
+ like: ArrayLike = ...
+) -> _ArrayType: ...
+@overload
+def asanyarray(
+ a: object,
+ dtype: DTypeLike = ...,
+ order: _OrderKACF = ...,
+ *,
+ like: ArrayLike = ...
+) -> ndarray: ...
+def ascontiguousarray(
+ a: object, dtype: DTypeLike = ..., *, like: ArrayLike = ...
+) -> ndarray: ...
+def asfortranarray(
+ a: object, dtype: DTypeLike = ..., *, like: ArrayLike = ...
+) -> ndarray: ...
+
+_Requirements = Literal[
+ "C", "C_CONTIGUOUS", "CONTIGUOUS",
+ "F", "F_CONTIGUOUS", "FORTRAN",
+ "A", "ALIGNED",
+ "W", "WRITEABLE",
+ "O", "OWNDATA"
+]
+_E = Literal["E", "ENSUREARRAY"]
+_RequirementsWithE = Union[_Requirements, _E]
+
+@overload
+def require(
+ a: _ArrayType,
+ dtype: None = ...,
+ requirements: Union[None, _Requirements, Iterable[_Requirements]] = ...,
+ *,
+ like: ArrayLike = ...
+) -> _ArrayType: ...
+@overload
+def require(
+ a: object,
+ dtype: DTypeLike = ...,
+ requirements: Union[_E, Iterable[_RequirementsWithE]] = ...,
+ *,
+ like: ArrayLike = ...
+) -> ndarray: ...
+@overload
+def require(
+ a: object,
+ dtype: DTypeLike = ...,
+ requirements: Union[None, _Requirements, Iterable[_Requirements]] = ...,
+ *,
+ like: ArrayLike = ...
+) -> ndarray: ...
def _kind_name(dtype):
try:
return _kind_to_stem[dtype.kind]
- except KeyError:
+ except KeyError as e:
raise RuntimeError(
"internal dtype error, unknown kind {!r}"
.format(dtype.kind)
- )
+ ) from None
def __str__(dtype):
def _byte_order_str(dtype):
""" Normalize byteorder to '<' or '>' """
# hack to obtain the native and swapped byte order characters
- swapped = np.dtype(int).newbyteorder('s')
- native = swapped.newbyteorder('s')
+ swapped = np.dtype(int).newbyteorder('S')
+ native = swapped.newbyteorder('S')
byteorder = dtype.byteorder
if byteorder == '=':
return native.byteorder
- if byteorder == 's':
+ if byteorder == 'S':
# TODO: this path can never be reached
return swapped.byteorder
elif byteorder == '|':
def _datetime_metadata_str(dtype):
- # TODO: this duplicates the C append_metastr_to_string
+ # TODO: this duplicates the C metastr_to_unicode functionality
unit, count = np.datetime_data(dtype)
if unit == 'generic':
return ''
IS_PYPY = platform.python_implementation() == 'PyPy'
-if (sys.byteorder == 'little'):
+if sys.byteorder == 'little':
_nbo = '<'
else:
_nbo = '>'
def _makenames_list(adict, align):
allfields = []
- fnames = list(adict.keys())
- for fname in fnames:
- obj = adict[fname]
+
+ for fname, obj in adict.items():
n = len(obj)
- if not isinstance(obj, tuple) or n not in [2, 3]:
+ if not isinstance(obj, tuple) or n not in (2, 3):
raise ValueError("entry not a 2- or 3- tuple")
- if (n > 2) and (obj[2] == fname):
+ if n > 2 and obj[2] == fname:
continue
num = int(obj[1])
- if (num < 0):
+ if num < 0:
raise ValueError("invalid offset.")
format = dtype(obj[0], align=align)
- if (n > 2):
+ if n > 2:
title = obj[2]
else:
title = None
res = adict[name]
formats.append(res[0])
offsets.append(res[1])
- if (len(res) > 2):
+ if len(res) > 2:
titles.append(res[2])
else:
titles.append(None)
for field in ordered_fields:
if field[1] > offset:
num = field[1] - offset
- result.append(('', '|V%d' % num))
+ result.append(('', f'|V{num}'))
offset += num
elif field[1] < offset:
raise ValueError(
if descriptor.itemsize > offset:
num = descriptor.itemsize - offset
- result.append(('', '|V%d' % num))
+ result.append(('', f'|V{num}'))
return result
try:
(order1, repeats, order2, dtype) = mo.groups()
except (TypeError, AttributeError):
- raise ValueError('format number %d of "%s" is not recognized' %
- (len(result)+1, astr))
+ raise ValueError(
+ f'format number {len(result)+1} of "{astr}" is not recognized'
+ ) from None
startindex = mo.end()
# Separator or ending padding
if startindex < len(astr):
(order1, order2))
order = order1
- if order in ['|', '=', _nbo]:
+ if order in ('|', '=', _nbo):
order = ''
dtype = order + dtype
if (repeats == ''):
val = dummy_ctype(np.intp)
else:
char = dtype('p').char
- if (char == 'i'):
+ if char == 'i':
val = ctypes.c_int
elif char == 'l':
val = ctypes.c_long
nameslist.remove(name)
except ValueError:
if name in seen:
- raise ValueError("duplicate field name: %s" % (name,))
+ raise ValueError(f"duplicate field name: {name}") from None
else:
- raise ValueError("unknown field name: %s" % (name,))
+ raise ValueError(f"unknown field name: {name}") from None
seen.add(name)
return tuple(list(order) + nameslist)
- raise ValueError("unsupported order value: %s" % (order,))
+ raise ValueError(f"unsupported order value: {order}")
def _copy_fields(ary):
"""Return copy of structured array with padding between fields removed.
if not (is_padding and name is None):
if name is not None and name in field_spec['names']:
- raise RuntimeError("Duplicate field name '%s' in PEP3118 format"
- % name)
+ raise RuntimeError(f"Duplicate field name '{name}' in PEP3118 format")
field_spec['names'].append(name)
field_spec['formats'].append(value)
field_spec['offsets'].append(offset)
j = 0
while True:
- name = 'f{}'.format(j)
+ name = f'f{j}'
if name not in names:
break
j = j + 1
if ufunc.nin == 1:
in_args = 'x'
else:
- in_args = ', '.join('x{}'.format(i+1) for i in range(ufunc.nin))
+ in_args = ', '.join(f'x{i+1}' for i in range(ufunc.nin))
# output arguments are both keyword or positional
if ufunc.nout == 0:
--- /dev/null
+from typing import Any
+
+# TODO: add better annotations when ctypes is stubbed out
+
+class _ctypes:
+ @property
+ def data(self) -> int: ...
+ @property
+ def shape(self) -> Any: ...
+ @property
+ def strides(self) -> Any: ...
+ def data_as(self, obj: Any) -> Any: ...
+ def shape_as(self, obj: Any) -> Any: ...
+ def strides_as(self, obj: Any) -> Any: ...
+ def get_data(self) -> int: ...
+ def get_shape(self) -> Any: ...
+ def get_strides(self) -> Any: ...
+ def get_as_parameter(self) -> Any: ...
initial=_NoValue, where=True):
return umr_prod(a, axis, dtype, out, keepdims, initial, where)
-def _any(a, axis=None, dtype=None, out=None, keepdims=False):
- return umr_any(a, axis, dtype, out, keepdims)
-
-def _all(a, axis=None, dtype=None, out=None, keepdims=False):
- return umr_all(a, axis, dtype, out, keepdims)
-
-def _count_reduce_items(arr, axis):
- if axis is None:
- axis = tuple(range(arr.ndim))
- if not isinstance(axis, tuple):
- axis = (axis,)
- items = 1
- for ax in axis:
- items *= arr.shape[mu.normalize_axis_index(ax, arr.ndim)]
+def _any(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
+ # Parsing keyword arguments is currently fairly slow, so avoid it for now
+ if where is True:
+ return umr_any(a, axis, dtype, out, keepdims)
+ return umr_any(a, axis, dtype, out, keepdims, where=where)
+
+def _all(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
+ # Parsing keyword arguments is currently fairly slow, so avoid it for now
+ if where is True:
+ return umr_all(a, axis, dtype, out, keepdims)
+ return umr_all(a, axis, dtype, out, keepdims, where=where)
+
+def _count_reduce_items(arr, axis, keepdims=False, where=True):
+ # fast-path for the default case
+ if where is True:
+ # no boolean mask given, calculate items according to axis
+ if axis is None:
+ axis = tuple(range(arr.ndim))
+ elif not isinstance(axis, tuple):
+ axis = (axis,)
+ items = nt.intp(1)
+ for ax in axis:
+ items *= arr.shape[mu.normalize_axis_index(ax, arr.ndim)]
+ else:
+ # TODO: Optimize case when `where` is broadcast along a non-reduction
+ # axis and full sum is more excessive than needed.
+
+ # guarded to protect circular imports
+ from numpy.lib.stride_tricks import broadcast_to
+ # count True values in (potentially broadcasted) boolean mask
+ items = umr_sum(broadcast_to(where, arr.shape), axis, nt.intp, None,
+ keepdims)
return items
# Numpy 1.17.0, 2019-02-24
return _clip_dep_invoke_with_casting(
um.clip, a, min, max, out=out, casting=casting, **kwargs)
-def _mean(a, axis=None, dtype=None, out=None, keepdims=False):
+def _mean(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
arr = asanyarray(a)
is_float16_result = False
- rcount = _count_reduce_items(arr, axis)
- # Make this warning show up first
- if rcount == 0:
+
+ rcount = _count_reduce_items(arr, axis, keepdims=keepdims, where=where)
+ if rcount == 0 if where is True else umr_any(rcount == 0):
warnings.warn("Mean of empty slice.", RuntimeWarning, stacklevel=2)
# Cast bool, unsigned int, and int to float64 by default
dtype = mu.dtype('f4')
is_float16_result = True
- ret = umr_sum(arr, axis, dtype, out, keepdims)
+ ret = umr_sum(arr, axis, dtype, out, keepdims, where=where)
if isinstance(ret, mu.ndarray):
ret = um.true_divide(
ret, rcount, out=ret, casting='unsafe', subok=False)
return ret
-def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
+def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *,
+ where=True):
arr = asanyarray(a)
- rcount = _count_reduce_items(arr, axis)
+ rcount = _count_reduce_items(arr, axis, keepdims=keepdims, where=where)
# Make this warning show up on top.
- if ddof >= rcount:
+ if ddof >= rcount if where is True else umr_any(ddof >= rcount):
warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning,
stacklevel=2)
# Compute the mean.
# Note that if dtype is not of inexact type then arraymean will
# not be either.
- arrmean = umr_sum(arr, axis, dtype, keepdims=True)
+ arrmean = umr_sum(arr, axis, dtype, keepdims=True, where=where)
+ # The shape of rcount has to match arrmean to not change the shape of out
+ # in broadcasting. Otherwise, it cannot be stored back to arrmean.
+ if rcount.ndim == 0:
+ # fast-path for default case when where is True
+ div = rcount
+ else:
+ # matching rcount to arrmean when where is specified as array
+ div = rcount.reshape(arrmean.shape)
if isinstance(arrmean, mu.ndarray):
- arrmean = um.true_divide(
- arrmean, rcount, out=arrmean, casting='unsafe', subok=False)
+ arrmean = um.true_divide(arrmean, div, out=arrmean, casting='unsafe',
+ subok=False)
else:
arrmean = arrmean.dtype.type(arrmean / rcount)
else:
x = um.multiply(x, um.conjugate(x), out=x).real
- ret = umr_sum(x, axis, dtype, out, keepdims)
+ ret = umr_sum(x, axis, dtype, out, keepdims=keepdims, where=where)
# Compute degrees of freedom and make sure it is not negative.
- rcount = max([rcount - ddof, 0])
+ rcount = um.maximum(rcount - ddof, 0)
# divide by degrees of freedom
if isinstance(ret, mu.ndarray):
return ret
-def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
+def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *,
+ where=True):
ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
- keepdims=keepdims)
+ keepdims=keepdims, where=where)
if isinstance(ret, mu.ndarray):
ret = um.sqrt(ret, out=ret)
.. data:: sctypeDict
Similar to `allTypes`, but maps a broader set of aliases to their types.
-.. data:: sctypeNA
- NumArray-compatible names for the scalar types. Contains not only
- ``name: type`` mappings, but ``char: name`` mappings too.
-
- .. deprecated:: 1.16
-
.. data:: sctypes
A dictionary keyed by a "type group" string, providing a list of types
under that group.
"""
-import warnings
from numpy.compat import unicode
-from numpy._globals import VisibleDeprecationWarning
-from numpy.core._string_helpers import english_lower, english_capitalize
+from numpy.core._string_helpers import english_lower
from numpy.core.multiarray import typeinfo, dtype
from numpy.core._dtype import _kind_name
sctypeDict = {} # Contains all leaf-node scalar types with aliases
-class TypeNADict(dict):
- def __getitem__(self, key):
- # 2018-06-24, 1.16
- warnings.warn('sctypeNA and typeNA will be removed in v1.18 '
- 'of numpy', VisibleDeprecationWarning, stacklevel=2)
- return dict.__getitem__(self, key)
- def get(self, key, default=None):
- # 2018-06-24, 1.16
- warnings.warn('sctypeNA and typeNA will be removed in v1.18 '
- 'of numpy', VisibleDeprecationWarning, stacklevel=2)
- return dict.get(self, key, default)
-
-sctypeNA = TypeNADict() # Contails all leaf-node types -> numarray type equivalences
allTypes = {} # Collect the types we will add to the module
if name in ('longdouble', 'clongdouble') and myname in allTypes:
continue
- base_capitalize = english_capitalize(base)
- if base == 'complex':
- na_name = '%s%d' % (base_capitalize, bit//2)
- elif base == 'bool':
- na_name = base_capitalize
- else:
- na_name = "%s%d" % (base_capitalize, bit)
-
allTypes[myname] = info.type
# add mapping for both the bit name and the numarray name
sctypeDict[myname] = info.type
- sctypeDict[na_name] = info.type
# add forward, reverse, and string mapping to numarray
- sctypeNA[na_name] = info.type
- sctypeNA[info.type] = na_name
- sctypeNA[info.char] = na_name
-
sctypeDict[char] = info.type
- sctypeNA[char] = na_name
+
+ # Add deprecated numeric-style type aliases manually, at some point
+ # we may want to deprecate the lower case "bytes0" version as well.
+ for name in ["Bytes0", "Datetime64", "Str0", "Uint32", "Uint64"]:
+ if english_lower(name) not in allTypes:
+ # Only one of Uint32 or Uint64, aliases of `np.uintp`, was (and is) defined, note that this
+ # is not UInt32/UInt64 (capital i), which is removed.
+ continue
+ allTypes[name] = allTypes[english_lower(name)]
+ sctypeDict[name] = sctypeDict[english_lower(name)]
+
_add_aliases()
def _add_integer_aliases():
u_info = _concrete_typeinfo[u_ctype]
bits = i_info.bits # same for both
- for info, charname, intname, Intname in [
- (i_info,'i%d' % (bits//8,), 'int%d' % bits, 'Int%d' % bits),
- (u_info,'u%d' % (bits//8,), 'uint%d' % bits, 'UInt%d' % bits)]:
+ for info, charname, intname in [
+ (i_info,'i%d' % (bits//8,), 'int%d' % bits),
+ (u_info,'u%d' % (bits//8,), 'uint%d' % bits)]:
if bits not in seen_bits:
# sometimes two different types have the same number of bits
# if so, the one iterated over first takes precedence
allTypes[intname] = info.type
sctypeDict[intname] = info.type
- sctypeDict[Intname] = info.type
sctypeDict[charname] = info.type
- sctypeNA[Intname] = info.type
- sctypeNA[charname] = info.type
- sctypeNA[info.type] = Intname
- sctypeNA[info.char] = Intname
seen_bits.add(bits)
--- /dev/null
+import sys
+from typing import Dict, Union, Type, List
+
+from numpy import generic, signedinteger, unsignedinteger, floating, complexfloating
+
+if sys.version_info >= (3, 8):
+ from typing import TypedDict
+else:
+ from typing_extensions import TypedDict
+
+class _SCTypes(TypedDict):
+ int: List[Type[signedinteger]]
+ uint: List[Type[unsignedinteger]]
+ float: List[Type[floating]]
+ complex: List[Type[complexfloating]]
+ others: List[type]
+
+sctypeDict: Dict[Union[int, str], Type[generic]]
+sctypes: _SCTypes
--- /dev/null
+import sys
+from typing import Optional, Union, Callable, Any
+
+if sys.version_info >= (3, 8):
+ from typing import Literal, Protocol, TypedDict
+else:
+ from typing_extensions import Literal, Protocol, TypedDict
+
+_ErrKind = Literal["ignore", "warn", "raise", "call", "print", "log"]
+_ErrFunc = Callable[[str, int], Any]
+
+class _SupportsWrite(Protocol):
+ def write(self, __msg: str) -> Any: ...
+
+class _ErrDict(TypedDict):
+ divide: _ErrKind
+ over: _ErrKind
+ under: _ErrKind
+ invalid: _ErrKind
+
+class _ErrDictOptional(TypedDict, total=False):
+ all: Optional[_ErrKind]
+ divide: Optional[_ErrKind]
+ over: Optional[_ErrKind]
+ under: Optional[_ErrKind]
+ invalid: Optional[_ErrKind]
+
+def seterr(
+ all: Optional[_ErrKind] = ...,
+ divide: Optional[_ErrKind] = ...,
+ over: Optional[_ErrKind] = ...,
+ under: Optional[_ErrKind] = ...,
+ invalid: Optional[_ErrKind] = ...,
+) -> _ErrDict: ...
+def geterr() -> _ErrDict: ...
+def setbufsize(size: int) -> int: ...
+def getbufsize() -> int: ...
+def seterrcall(
+ func: Union[None, _ErrFunc, _SupportsWrite]
+) -> Union[None, _ErrFunc, _SupportsWrite]: ...
+def geterrcall() -> Union[None, _ErrFunc, _SupportsWrite]: ...
+
+# See `numpy/__init__.pyi` for the `errstate` class
def _extendLine(s, line, word, line_width, next_line_prefix, legacy):
needs_wrap = len(line) + len(word) > line_width
if legacy != '1.13':
- s# don't wrap lines if it won't help
+ # don't wrap lines if it won't help
if len(line) <= len(next_line_prefix):
needs_wrap = False
return s, line
+def _extendLine_pretty(s, line, word, line_width, next_line_prefix, legacy):
+ """
+ Extends line with nicely formatted (possibly multi-line) string ``word``.
+ """
+ words = word.splitlines()
+ if len(words) == 1 or legacy == '1.13':
+ return _extendLine(s, line, word, line_width, next_line_prefix, legacy)
+
+ max_word_length = max(len(word) for word in words)
+ if (len(line) + max_word_length > line_width and
+ len(line) > len(next_line_prefix)):
+ s += line.rstrip() + '\n'
+ line = next_line_prefix + words[0]
+ indent = next_line_prefix
+ else:
+ indent = len(line)*' '
+ line += words[0]
+
+ for word in words[1::]:
+ s += line.rstrip() + '\n'
+ line = indent + word
+
+ suffix_length = max_word_length - len(words[-1])
+ line += suffix_length*' '
+
+ return s, line
+
def _formatArray(a, format_function, line_width, next_line_prefix,
separator, edge_items, summary_insert, legacy):
"""formatArray is designed for two modes of operation:
line = hanging_indent
for i in range(leading_items):
word = recurser(index + (i,), next_hanging_indent, next_width)
- s, line = _extendLine(
+ s, line = _extendLine_pretty(
s, line, word, elem_width, hanging_indent, legacy)
line += separator
for i in range(trailing_items, 1, -1):
word = recurser(index + (-i,), next_hanging_indent, next_width)
- s, line = _extendLine(
+ s, line = _extendLine_pretty(
s, line, word, elem_width, hanging_indent, legacy)
line += separator
# width of the separator is not considered on 1.13
elem_width = curr_width
word = recurser(index + (-1,), next_hanging_indent, next_width)
- s, line = _extendLine(
+ s, line = _extendLine_pretty(
s, line, word, elem_width, hanging_indent, legacy)
s += line
return multiarray.set_string_function(_default_array_str, 0)
else:
return multiarray.set_string_function(f, repr)
-
-set_string_function(_default_array_str, False)
-set_string_function(_default_array_repr, True)
# Version 13 (NumPy 1.18) No change.
# Version 13 (NumPy 1.19) No change.
0x0000000d = 5b0e8bbded00b166125974fc71e80a33
+
+# Version 14 (NumPy 1.20)
+# DType related API additions.
+# A new field was added to the end of PyArrayObject_fields.
+0x0000000e = 17a0f366e55ec05e5c5c149123478452
# The files under src/ that are scanned for API functions
API_FILES = [join('multiarray', 'alloc.c'),
+ join('multiarray', 'abstractdtypes.c'),
join('multiarray', 'arrayfunction_override.c'),
join('multiarray', 'array_assign_array.c'),
join('multiarray', 'array_assign_scalar.c'),
+ join('multiarray', 'array_coercion.c'),
+ join('multiarray', 'array_method.c'),
join('multiarray', 'arrayobject.c'),
join('multiarray', 'arraytypes.c.src'),
join('multiarray', 'buffer.c'),
join('multiarray', 'datetime_busdaycal.c'),
join('multiarray', 'datetime_strings.c'),
join('multiarray', 'descriptor.c'),
+ join('multiarray', 'dtypemeta.c'),
join('multiarray', 'einsum.c.src'),
join('multiarray', 'flagsobject.c'),
join('multiarray', 'getset.c'),
# Those *Api classes instances know how to output strings for the generated code
class TypeApi:
- def __init__(self, name, index, ptr_cast, api_name):
+ def __init__(self, name, index, ptr_cast, api_name, internal_type=None):
self.index = index
self.name = name
self.ptr_cast = ptr_cast
self.api_name = api_name
+ # The type used internally, if None, same as exported (ptr_cast)
+ self.internal_type = internal_type
def define_from_array_api_string(self):
return "#define %s (*(%s *)%s[%d])" % (self.name,
return " (void *) &%s" % self.name
def internal_define(self):
- astr = """\
-extern NPY_NO_EXPORT PyTypeObject %(type)s;
-""" % {'type': self.name}
+ if self.internal_type is None:
+ return f"extern NPY_NO_EXPORT {self.ptr_cast} {self.name};\n"
+
+ # If we are here, we need to define a larger struct internally, which
+ # the type can be cast safely. But we want to normally use the original
+ # type, so name mangle:
+ mangled_name = f"{self.name}Full"
+ astr = (
+ # Create the mangled name:
+ f"extern NPY_NO_EXPORT {self.internal_type} {mangled_name};\n"
+ # And define the name as: (*(type *)(&mangled_name))
+ f"#define {self.name} (*({self.ptr_cast} *)(&{mangled_name}))\n"
+ )
return astr
class GlobalVarApi:
for name, val in types_api.items():
index = val[0]
- multiarray_api_dict[name] = TypeApi(name, index, 'PyTypeObject', api_name)
+ internal_type = None if len(val) == 1 else val[1]
+ multiarray_api_dict[name] = TypeApi(
+ name, index, 'PyTypeObject', api_name, internal_type)
if len(multiarray_api_dict) != len(multiarray_api_index):
keys_dict = set(multiarray_api_dict.keys())
import ufunc_docstrings as docstrings
sys.path.pop(0)
-Zero = "PyInt_FromLong(0)"
-One = "PyInt_FromLong(1)"
+Zero = "PyLong_FromLong(0)"
+One = "PyLong_FromLong(1)"
True_ = "(Py_INCREF(Py_True), Py_True)"
False_ = "(Py_INCREF(Py_False), Py_False)"
None_ = object()
-AllOnes = "PyInt_FromLong(-1)"
+AllOnes = "PyLong_FromLong(-1)"
MinusInfinity = 'PyFloat_FromDouble(-NPY_INFINITY)'
ReorderableNone = "(Py_INCREF(Py_None), Py_None)"
simd: list
Available SIMD ufunc loops, dispatched at runtime in specified order
Currently only supported for simples types (see make_arrays)
+ dispatch: list
+ Available SIMD ufunc loops, dispatched at runtime in specified order
+ Currently only supported for simples types (see make_arrays)
"""
- def __init__(self, type, f=None, in_=None, out=None, astype=None, simd=None):
+ def __init__(self, type, f=None, in_=None, out=None, astype=None, simd=None, dispatch=None):
self.type = type
self.func_data = f
if astype is None:
out = out.replace('P', type)
self.out = out
self.simd = simd
+ self.dispatch = dispatch
def finish_signature(self, nin, nout):
if self.in_ is None:
func_data = [_fdata_map.get(t, '%s') % (f,) for t in types]
return func_data
-def TD(types, f=None, astype=None, in_=None, out=None, simd=None):
+def TD(types, f=None, astype=None, in_=None, out=None, simd=None, dispatch=None):
if f is not None:
if isinstance(f, str):
func_data = build_func_data(types, f)
simdt = [k for k, v in simd if t in v]
else:
simdt = []
- tds.append(TypeDescription(t, f=fd, in_=i, out=o, astype=astype, simd=simdt))
+ # [(dispatch file name without extension '.dispatch.c*', list of types)]
+ if dispatch:
+ dispt = [k for k, v in dispatch if t in v]
+ else:
+ dispt = []
+ tds.append(TypeDescription(
+ t, f=fd, in_=i, out=o, astype=astype, simd=simdt, dispatch=dispt
+ ))
return tds
class Ufunc:
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.square'),
None,
- TD(ints+inexact, simd=[('avx2', ints), ('fma', 'fd'), ('avx512f', 'FDfd')]),
+ TD(ints+inexact, simd=[('avx2', ints), ('avx512f', 'FD')], dispatch=[('loops_unary_fp', 'fd')]),
TD(O, f='Py_square'),
),
'reciprocal':
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.reciprocal'),
None,
- TD(ints+inexact, simd=[('avx2', ints), ('fma', 'fd'), ('avx512f','fd')]),
+ TD(ints+inexact, simd=[('avx2', ints)], dispatch=[('loops_unary_fp', 'fd')]),
TD(O, f='Py_reciprocal'),
),
# This is no longer used as numpy.ones_like, however it is
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.absolute'),
'PyUFunc_AbsoluteTypeResolver',
- TD(bints+flts+timedeltaonly, simd=[('fma', 'fd'), ('avx512f', 'fd')]),
+ TD(bints+flts+timedeltaonly, dispatch=[('loops_unary_fp', 'fd')]),
TD(cmplx, simd=[('avx512f', cmplxvec)], out=('f', 'd', 'g')),
TD(O, f='PyNumber_Absolute'),
),
None,
TD('e', f='log', astype={'e':'f'}),
TD('f', simd=[('fma', 'f'), ('avx512f', 'f')]),
+ TD('d', simd=[('avx512f', 'd')]),
TD('fdg' + cmplx, f='log'),
TD(P, f='log'),
),
docstrings.get('numpy.core.umath.sqrt'),
None,
TD('e', f='sqrt', astype={'e':'f'}),
- TD(inexactvec, simd=[('fma', 'fd'), ('avx512f', 'fd')]),
+ TD(inexactvec, dispatch=[('loops_unary_fp', 'fd')]),
TD('fdg' + cmplx, f='sqrt'),
TD(P, f='sqrt'),
),
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.isnan'),
'PyUFunc_IsFiniteTypeResolver',
- TD(noobj, out='?'),
+ TD(noobj, simd=[('avx512_skx', 'fd')], out='?'),
),
'isnat':
Ufunc(1, 1, None,
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.isinf'),
'PyUFunc_IsFiniteTypeResolver',
- TD(noobj, out='?'),
+ TD(noobj, simd=[('avx512_skx', 'fd')], out='?'),
),
'isfinite':
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.isfinite'),
'PyUFunc_IsFiniteTypeResolver',
- TD(noobj, out='?'),
+ TD(noobj, simd=[('avx512_skx', 'fd')], out='?'),
),
'signbit':
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.signbit'),
None,
- TD(flts, out='?'),
+ TD(flts, simd=[('avx512_skx', 'fd')], out='?'),
),
'copysign':
Ufunc(2, 1, None,
docstrings.get('numpy.core.umath.ldexp'),
None,
[TypeDescription('e', None, 'ei', 'e'),
- TypeDescription('f', None, 'fi', 'f'),
+ TypeDescription('f', None, 'fi', 'f', simd=['avx512_skx']),
TypeDescription('e', FuncNameSuffix('long'), 'el', 'e'),
TypeDescription('f', FuncNameSuffix('long'), 'fl', 'f'),
- TypeDescription('d', None, 'di', 'd'),
+ TypeDescription('d', None, 'di', 'd', simd=['avx512_skx']),
TypeDescription('d', FuncNameSuffix('long'), 'dl', 'd'),
TypeDescription('g', None, 'gi', 'g'),
TypeDescription('g', FuncNameSuffix('long'), 'gl', 'g'),
docstrings.get('numpy.core.umath.frexp'),
None,
[TypeDescription('e', None, 'e', 'ei'),
- TypeDescription('f', None, 'f', 'fi'),
- TypeDescription('d', None, 'd', 'di'),
+ TypeDescription('f', None, 'f', 'fi', simd=['avx512_skx']),
+ TypeDescription('d', None, 'd', 'di', simd=['avx512_skx']),
TypeDescription('g', None, 'g', 'gi'),
],
),
ISA=vt.upper(), isa=vt,
fname=name, type=tname, idx=k
))
+ if t.dispatch is not None:
+ for dname in t.dispatch:
+ code2list.append(textwrap.dedent("""\
+ #ifndef NPY_DISABLE_OPTIMIZATION
+ #include "{dname}.dispatch.h"
+ #endif
+ NPY_CPU_DISPATCH_CALL_XB({name}_functions[{k}] = {tname}_{name});
+ """).format(
+ dname=dname, name=name, tname=tname, k=k
+ ))
else:
funclist.append('NULL')
try:
thedict = arity_lookup[uf.nin, uf.nout]
- except KeyError:
- raise ValueError("Could not handle {}[{}]".format(name, t.type))
+ except KeyError as e:
+ raise ValueError(
+ f"Could not handle {name}[{t.type}] "
+ f"with nin={uf.nin}, nout={uf.nout}"
+ ) from None
astype = ''
if not t.astype is None:
multiarray_types_api = {
'PyBigArray_Type': (1,),
'PyArray_Type': (2,),
- 'PyArrayDescr_Type': (3,),
+ # Internally, PyArrayDescr_Type is a PyArray_DTypeMeta,
+ # the following also defines PyArrayDescr_TypeFull (Full appended)
+ 'PyArrayDescr_Type': (3, "PyArray_DTypeMeta"),
'PyArrayFlags_Type': (4,),
'PyArrayIter_Type': (5,),
'PyArrayMultiIter_Type': (6,),
>>> plt.imshow(np.abs(xx), extent=[-10, 10, -10, 10], cmap='gray')
>>> plt.show()
+ The `abs` function can be used as a shorthand for ``np.absolute`` on
+ ndarrays.
+
+ >>> x = np.array([-1.2, 1.2])
+ >>> abs(x)
+ array([1.2, 1.2])
+
""")
add_newdoc('numpy.core.umath', 'add',
[ 3., 5., 7.],
[ 6., 8., 10.]])
+ The ``+`` operator can be used as a shorthand for ``np.add`` on ndarrays.
+
+ >>> x1 = np.arange(9.0).reshape((3, 3))
+ >>> x2 = np.arange(3.0)
+ >>> x1 + x2
+ array([[ 0., 2., 4.],
+ [ 3., 5., 7.],
+ [ 6., 8., 10.]])
""")
add_newdoc('numpy.core.umath', 'arccos',
>>> np.bitwise_and([True, True], [False, True])
array([False, True])
+ The ``&`` operator can be used as a shorthand for ``np.bitwise_and`` on
+ ndarrays.
+
+ >>> x1 = np.array([2, 5, 255])
+ >>> x2 = np.array([3, 14, 16])
+ >>> x1 & x2
+ array([ 2, 4, 16])
+
""")
add_newdoc('numpy.core.umath', 'bitwise_or',
>>> np.bitwise_or([True, True], [False, True])
array([ True, True])
+ The ``|`` operator can be used as a shorthand for ``np.bitwise_or`` on
+ ndarrays.
+
+ >>> x1 = np.array([2, 5, 255])
+ >>> x2 = np.array([4, 4, 4])
+ >>> x1 | x2
+ array([ 6, 5, 255])
+
""")
add_newdoc('numpy.core.umath', 'bitwise_xor',
>>> np.bitwise_xor([True, True], [False, True])
array([ True, False])
+ The ``^`` operator can be used as a shorthand for ``np.bitwise_xor`` on
+ ndarrays.
+
+ >>> x1 = np.array([True, True])
+ >>> x2 = np.array([False, True])
+ >>> x1 ^ x2
+ array([ True, False])
+
""")
add_newdoc('numpy.core.umath', 'ceil',
>>> np.divide(1, 0)
0
+ The ``/`` operator can be used as a shorthand for ``np.divide`` on
+ ndarrays.
+
+ >>> x1 = np.arange(9.0).reshape((3, 3))
+ >>> x2 = 2 * np.ones(3)
+ >>> x1 / x2
+ array([[0. , 0.5, 1. ],
+ [1.5, 2. , 2.5],
+ [3. , 3.5, 4. ]])
+
""")
add_newdoc('numpy.core.umath', 'equal',
>>> np.equal(1, np.ones(1))
array([ True])
+ The ``==`` operator can be used as a shorthand for ``np.equal`` on
+ ndarrays.
+
+ >>> a = np.array([2, 4, 6])
+ >>> b = np.array([2, 4, 2])
+ >>> a == b
+ array([ True, True, False])
+
""")
add_newdoc('numpy.core.umath', 'exp',
>>> np.floor_divide([1., 2., 3., 4.], 2.5)
array([ 0., 0., 1., 1.])
+ The ``//`` operator can be used as a shorthand for ``np.floor_divide``
+ on ndarrays.
+
+ >>> x1 = np.array([1., 2., 3., 4.])
+ >>> x1 // 2.5
+ array([0., 0., 1., 1.])
+
""")
add_newdoc('numpy.core.umath', 'fmod',
>>> np.greater([4,2],[2,2])
array([ True, False])
- If the inputs are ndarrays, then np.greater is equivalent to '>'.
+ The ``>`` operator can be used as a shorthand for ``np.greater`` on
+ ndarrays.
- >>> a = np.array([4,2])
- >>> b = np.array([2,2])
+ >>> a = np.array([4, 2])
+ >>> b = np.array([2, 2])
>>> a > b
array([ True, False])
>>> np.greater_equal([4, 2, 1], [2, 2, 2])
array([ True, True, False])
+ The ``>=`` operator can be used as a shorthand for ``np.greater_equal``
+ on ndarrays.
+
+ >>> a = np.array([4, 2, 1])
+ >>> b = np.array([2, 2, 2])
+ >>> a >= b
+ array([ True, True, False])
+
""")
add_newdoc('numpy.core.umath', 'hypot',
>>> np.invert(np.array([True, False]))
array([False, True])
+ The ``~`` operator can be used as a shorthand for ``np.invert`` on
+ ndarrays.
+
+ >>> x1 = np.array([True, False])
+ >>> ~x1
+ array([False, True])
+
""")
add_newdoc('numpy.core.umath', 'isfinite',
>>> print(b, type(b))
254 <class 'numpy.uint8'>
+ The ``<<`` operator can be used as a shorthand for ``np.left_shift`` on
+ ndarrays.
+
+ >>> x1 = 5
+ >>> x2 = np.array([1, 2, 3])
+ >>> x1 << x2
+ array([10, 20, 40])
+
""")
add_newdoc('numpy.core.umath', 'less',
>>> np.less([1, 2], [2, 2])
array([ True, False])
+ The ``<`` operator can be used as a shorthand for ``np.less`` on ndarrays.
+
+ >>> a = np.array([1, 2])
+ >>> b = np.array([2, 2])
+ >>> a < b
+ array([ True, False])
+
""")
add_newdoc('numpy.core.umath', 'less_equal',
"""
- Return the truth value of (x1 =< x2) element-wise.
+ Return the truth value of (x1 <= x2) element-wise.
Parameters
----------
>>> np.less_equal([4, 2, 1], [2, 2, 2])
array([False, True, True])
+ The ``<=`` operator can be used as a shorthand for ``np.less_equal`` on
+ ndarrays.
+
+ >>> a = np.array([4, 2, 1])
+ >>> b = np.array([2, 2, 2])
+ >>> a <= b
+ array([False, True, True])
+
""")
add_newdoc('numpy.core.umath', 'log',
>>> np.logical_and(x>1, x<4)
array([False, False, True, True, False])
+
+ The ``&`` operator can be used as a shorthand for ``np.logical_and`` on
+ boolean ndarrays.
+
+ >>> a = np.array([True, False])
+ >>> b = np.array([False, False])
+ >>> a & b
+ array([False, False])
+
""")
add_newdoc('numpy.core.umath', 'logical_not',
>>> np.logical_or(x < 1, x > 3)
array([ True, False, False, False, True])
+ The ``|`` operator can be used as a shorthand for ``np.logical_or`` on
+ boolean ndarrays.
+
+ >>> a = np.array([True, False])
+ >>> b = np.array([False, False])
+ >>> a | b
+ array([ True, False])
+
""")
add_newdoc('numpy.core.umath', 'logical_xor',
Raises
------
ValueError
- If the last dimension of `a` is not the same size as
- the second-to-last dimension of `b`.
+ If the last dimension of `x1` is not the same size as
+ the second-to-last dimension of `x2`.
If a scalar value is passed in.
...
ValueError: matmul: Input operand 1 does not have enough dimensions ...
+ The ``@`` operator can be used as a shorthand for ``np.matmul`` on
+ ndarrays.
+
+ >>> x1 = np.array([2j, 3j])
+ >>> x2 = np.array([2j, 3j])
+ >>> x1 @ x2
+ (-13+0j)
+
.. versionadded:: 1.10.0
""")
[ 0., 4., 10.],
[ 0., 7., 16.]])
+ The ``*`` operator can be used as a shorthand for ``np.multiply`` on
+ ndarrays.
+
+ >>> x1 = np.arange(9.0).reshape((3, 3))
+ >>> x2 = np.arange(3.0)
+ >>> x1 * x2
+ array([[ 0., 1., 4.],
+ [ 0., 4., 10.],
+ [ 0., 7., 16.]])
+
""")
add_newdoc('numpy.core.umath', 'negative',
>>> np.negative([1.,-1.])
array([-1., 1.])
+ The unary ``-`` operator can be used as a shorthand for ``np.negative`` on
+ ndarrays.
+
+ >>> x1 = np.array(([1., -1.]))
+ >>> -x1
+ array([-1., 1.])
+
""")
add_newdoc('numpy.core.umath', 'positive',
Equivalent to `x.copy()`, but only defined for types that support
arithmetic.
+ Examples
+ --------
+
+ >>> x1 = np.array(([1., -1.]))
+ >>> np.positive(x1)
+ array([ 1., -1.])
+
+ The unary ``+`` operator can be used as a shorthand for ``np.positive`` on
+ ndarrays.
+
+ >>> x1 = np.array(([1., -1.]))
+ >>> +x1
+ array([ 1., -1.])
+
""")
add_newdoc('numpy.core.umath', 'not_equal',
array([[False, True],
[False, True]])
+ The ``!=`` operator can be used as a shorthand for ``np.not_equal`` on
+ ndarrays.
+
+ >>> a = np.array([1., 2.])
+ >>> b = np.array([1., 3.])
+ >>> a != b
+ array([False, True])
+
+
""")
add_newdoc('numpy.core.umath', '_ones_like',
Examples
--------
- Cube each element in a list.
+ Cube each element in an array.
- >>> x1 = range(6)
+ >>> x1 = np.arange(6)
>>> x1
[0, 1, 2, 3, 4, 5]
>>> np.power(x1, 3)
array([[ 0, 1, 8, 27, 16, 5],
[ 0, 1, 8, 27, 16, 5]])
+ The ``**`` operator can be used as a shorthand for ``np.power`` on
+ ndarrays.
+
+ >>> x2 = np.array([1, 2, 3, 3, 2, 1])
+ >>> x1 = np.arange(6)
+ >>> x1 ** x2
+ array([ 0, 1, 8, 27, 16, 5])
+
""")
add_newdoc('numpy.core.umath', 'float_power',
>>> np.remainder(np.arange(7), 5)
array([0, 1, 2, 3, 4, 0, 1])
+ The ``%`` operator can be used as a shorthand for ``np.remainder`` on
+ ndarrays.
+
+ >>> x1 = np.arange(7)
+ >>> x1 % 5
+ array([0, 1, 2, 3, 4, 0, 1])
+
""")
add_newdoc('numpy.core.umath', 'divmod',
>>> np.divmod(np.arange(5), 3)
(array([0, 0, 0, 1, 1]), array([0, 1, 2, 0, 1]))
+ The `divmod` function can be used as a shorthand for ``np.divmod`` on
+ ndarrays.
+
+ >>> x = np.arange(5)
+ >>> divmod(x, 3)
+ (array([0, 0, 0, 1, 1]), array([0, 1, 2, 0, 1]))
+
""")
add_newdoc('numpy.core.umath', 'right_shift',
>>> np.right_shift(10, [1,2,3])
array([5, 2, 1])
+ The ``>>`` operator can be used as a shorthand for ``np.right_shift`` on
+ ndarrays.
+
+ >>> x1 = 10
+ >>> x2 = np.array([1,2,3])
+ >>> x1 >> x2
+ array([5, 2, 1])
+
""")
add_newdoc('numpy.core.umath', 'rint',
[ 3., 3., 3.],
[ 6., 6., 6.]])
+ The ``-`` operator can be used as a shorthand for ``np.subtract`` on
+ ndarrays.
+
+ >>> x1 = np.arange(9.0).reshape((3, 3))
+ >>> x2 = np.arange(3.0)
+ >>> x1 - x2
+ array([[0., 0., 0.],
+ [3., 3., 3.],
+ [6., 6., 6.]])
+
""")
add_newdoc('numpy.core.umath', 'tan',
>>> x//4
array([0, 0, 0, 0, 1])
+
+ The ``/`` operator can be used as a shorthand for ``np.true_divide`` on
+ ndarrays.
+
+ >>> x = np.arange(5)
+ >>> x / 4
+ array([0. , 0.25, 0.5 , 0.75, 1. ])
+
""")
add_newdoc('numpy.core.umath', 'frexp',
Returns
-------
- out : ndarray or bool
- Output array of bools, or a single bool if x1 and x2 are scalars.
+ out : ndarray
+ Output array of bools.
See Also
--------
Returns
-------
- out : ndarray or bool
- Output array of bools, or a single bool if x1 and x2 are scalars.
+ out : ndarray
+ Output array of bools.
See Also
--------
Returns
-------
- out : ndarray or bool
- Output array of bools, or a single bool if x1 and x2 are scalars.
+ out : ndarray
+ Output array of bools.
See Also
--------
Returns
-------
- out : ndarray or bool
- Output array of bools, or a single bool if x1 and x2 are scalars.
+ out : ndarray
+ Output array of bools.
See Also
--------
Returns
-------
- out : ndarray or bool
- Output array of bools, or a single bool if x1 and x2 are scalars.
+ out : ndarray
+ Output array of bools.
See Also
--------
Returns
-------
- out : ndarray or bool
- Output array of bools, or a single bool if x1 and x2 are scalars.
+ out : ndarray
+ Output array of bools.
See Also
--------
--------
einsum_path, dot, inner, outer, tensordot, linalg.multi_dot
+ einops:
+ similar verbose interface is provided by
+ `einops <https://github.com/arogozhnikov/einops>`_ package to cover
+ additional operations: transpose, reshape/flatten, repeat/tile,
+ squeeze/unsqueeze and reductions.
+
+ opt_einsum:
+ `opt_einsum <https://optimized-einsum.readthedocs.io/en/stable/>`_
+ optimizes contraction order for einsum-like expressions
+ in backend-agnostic manner.
+
Notes
-----
.. versionadded:: 1.6.0
raise TypeError("Did not understand the following kwargs: %s"
% unknown_kwargs)
-
# Build the contraction list and operand
operands, contraction_list = einsum_path(*operands, optimize=optimize,
einsum_call=True)
+ # Handle order kwarg for output array, c_einsum allows mixed case
+ output_order = kwargs.pop('order', 'K')
+ if output_order.upper() == 'A':
+ if all(arr.flags.f_contiguous for arr in operands):
+ output_order = 'F'
+ else:
+ output_order = 'C'
+
# Start contraction loop
for num, contraction in enumerate(contraction_list):
inds, idx_rm, einsum_str, remaining, blas = contraction
if specified_out:
return out
else:
- return operands[0]
+ return asanyarray(operands[0], order=output_order)
See Also
--------
tile : Tile an array.
+ unique : Find the unique elements of an array.
Examples
--------
"""
try:
put = a.put
- except AttributeError:
+ except AttributeError as e:
raise TypeError("argument 1 must be numpy.ndarray, "
- "not {name}".format(name=type(a).__name__))
+ "not {name}".format(name=type(a).__name__)) from e
return put(ind, v, mode=mode)
>>> np.transpose(x, (1, 0, 2)).shape
(2, 1, 3)
+ >>> x = np.ones((2, 3, 4, 5))
+ >>> np.transpose(x).shape
+ (5, 4, 3, 2)
+
"""
return _wrapfunc(a, 'transpose', axes)
See Also
--------
+ np.reshape : Reshape an array without changing the total size.
+ np.pad : Enlarge and pad an array.
+ np.repeat: Repeat elements of an array.
ndarray.resize : resize an array in-place.
Notes
-----
+ When the total size of the array does not change `~numpy.reshape` should
+ be used. In most other cases either indexing (to reduce the size)
+ or padding (to increase the size) may be a more appropriate solution.
+
Warning: This functionality does **not** consider axes separately,
i.e. it does not apply interpolation/extrapolation.
It fills the return array with the required number of elements, taken
"""
if isinstance(new_shape, (int, nt.integer)):
new_shape = (new_shape,)
+
a = ravel(a)
- Na = len(a)
- total_size = um.multiply.reduce(new_shape)
- if Na == 0 or total_size == 0:
- return mu.zeros(new_shape, a.dtype)
- n_copies = int(total_size / Na)
- extra = total_size % Na
+ new_size = 1
+ for dim_length in new_shape:
+ new_size *= dim_length
+ if dim_length < 0:
+ raise ValueError('all elements of `new_shape` must be non-negative')
- if extra != 0:
- n_copies = n_copies + 1
- extra = Na - extra
+ if a.size == 0 or new_size == 0:
+ # First case must zero fill. The second would have repeats == 0.
+ return np.zeros_like(a, shape=new_shape)
- a = concatenate((a,) * n_copies)
- if extra > 0:
- a = a[:-extra]
+ repeats = -(-new_size // a.size) # ceil division
+ a = concatenate((a,) * repeats)[:new_size]
return reshape(a, new_shape)
@array_function_dispatch(_squeeze_dispatcher)
def squeeze(a, axis=None):
"""
- Remove single-dimensional entries from the shape of an array.
+ Remove axes of length one from `a`.
Parameters
----------
axis : None or int or tuple of ints, optional
.. versionadded:: 1.7.0
- Selects a subset of the single-dimensional entries in the
+ Selects a subset of the entries of length one in the
shape. If an axis is selected with shape entry greater than
one, an error is raised.
See Also
--------
- expand_dims : The inverse operation, adding singleton dimensions
+ expand_dims : The inverse operation, adding entries of length one
reshape : Insert, remove, and combine dimensions, and resize existing ones
Examples
.. note::
When called on a zero-d array or scalar, ``nonzero(a)`` is treated
- as ``nonzero(atleast1d(a))``.
+ as ``nonzero(atleast_1d(a))``.
.. deprecated:: 1.17.0
- Use `atleast1d` explicitly if this behavior is deliberate.
+ Use `atleast_1d` explicitly if this behavior is deliberate.
Parameters
----------
See Also
--------
- alen
+ len
ndarray.shape : Equivalent array method.
Examples
--------
take, choose, diag, diagonal, select
ndarray.compress : Equivalent method in ndarray
- np.extract: Equivalent method when working on 1-D arrays
- ufuncs-output-type
+ extract: Equivalent method when working on 1-D arrays
+ :ref:`ufuncs-output-type`
Examples
--------
----------
a : array_like
Array containing elements to clip.
- a_min : scalar or array_like or None
- Minimum value. If None, clipping is not performed on lower
- interval edge. Not more than one of `a_min` and `a_max` may be
- None.
- a_max : scalar or array_like or None
- Maximum value. If None, clipping is not performed on upper
- interval edge. Not more than one of `a_min` and `a_max` may be
- None. If `a_min` or `a_max` are array_like, then the three
- arrays will be broadcasted to match their shapes.
+ a_min, a_max : array_like or None
+ Minimum and maximum value. If ``None``, clipping is not performed on
+ the corresponding edge. Only one of `a_min` and `a_max` may be
+ ``None``. Both are broadcast against `a`.
out : ndarray, optional
The results will be placed in this array. It may be the input
array for in-place clipping. `out` must be of the right shape
See Also
--------
- ufuncs-output-type
+ :ref:`ufuncs-output-type`
Examples
--------
initial=initial, where=where)
-def _any_dispatcher(a, axis=None, out=None, keepdims=None):
- return (a, out)
+def _any_dispatcher(a, axis=None, out=None, keepdims=None, *,
+ where=np._NoValue):
+ return (a, where, out)
@array_function_dispatch(_any_dispatcher)
-def any(a, axis=None, out=None, keepdims=np._NoValue):
+def any(a, axis=None, out=None, keepdims=np._NoValue, *, where=np._NoValue):
"""
Test whether any array element along a given axis evaluates to True.
the same shape as the expected output and its type is preserved
(e.g., if it is of type float, then it will remain so, returning
1.0 for True and 0.0 for False, regardless of the type of `a`).
- See `ufuncs-output-type` for more details.
+ See :ref:`ufuncs-output-type` for more details.
keepdims : bool, optional
If this is set to True, the axes which are reduced are left
sub-class' method does not implement `keepdims` any
exceptions will be raised.
+ where : array_like of bool, optional
+ Elements to include in checking for any `True` values.
+ See `~numpy.ufunc.reduce` for details.
+
+ .. versionadded:: 1.20.0
+
Returns
-------
any : bool or ndarray
>>> np.any(np.nan)
True
+ >>> np.any([[True, False], [False, False]], where=[[False], [True]])
+ False
+
>>> o=np.array(False)
>>> z=np.any([-1, 4, 5], out=o)
>>> z, o
(191614240, 191614240)
"""
- return _wrapreduction(a, np.logical_or, 'any', axis, None, out, keepdims=keepdims)
+ return _wrapreduction(a, np.logical_or, 'any', axis, None, out,
+ keepdims=keepdims, where=where)
-def _all_dispatcher(a, axis=None, out=None, keepdims=None):
- return (a, out)
+def _all_dispatcher(a, axis=None, out=None, keepdims=None, *,
+ where=None):
+ return (a, where, out)
@array_function_dispatch(_all_dispatcher)
-def all(a, axis=None, out=None, keepdims=np._NoValue):
+def all(a, axis=None, out=None, keepdims=np._NoValue, *, where=np._NoValue):
"""
Test whether all array elements along a given axis evaluate to True.
Alternate output array in which to place the result.
It must have the same shape as the expected output and its
type is preserved (e.g., if ``dtype(out)`` is float, the result
- will consist of 0.0's and 1.0's). See `ufuncs-output-type` for more
+ will consist of 0.0's and 1.0's). See :ref:`ufuncs-output-type` for more
details.
keepdims : bool, optional
sub-class' method does not implement `keepdims` any
exceptions will be raised.
+ where : array_like of bool, optional
+ Elements to include in checking for all `True` values.
+ See `~numpy.ufunc.reduce` for details.
+
+ .. versionadded:: 1.20.0
+
Returns
-------
all : ndarray, bool
>>> np.all([1.0, np.nan])
True
+ >>> np.all([[True, True], [False, True]], where=[[True], [False]])
+ True
+
>>> o=np.array(False)
>>> z=np.all([-1, 4, 5], out=o)
>>> id(z), id(o), z
(28293632, 28293632, array(True)) # may vary
"""
- return _wrapreduction(a, np.logical_and, 'all', axis, None, out, keepdims=keepdims)
+ return _wrapreduction(a, np.logical_and, 'all', axis, None, out,
+ keepdims=keepdims, where=where)
def _cumsum_dispatcher(a, axis=None, dtype=None, out=None):
out : ndarray, optional
Alternative output array in which to place the result. It must
have the same shape and buffer length as the expected output
- but the type will be cast if necessary. See `ufuncs-output-type` for
+ but the type will be cast if necessary. See :ref:`ufuncs-output-type` for
more details.
Returns
out : ndarray, optional
Alternative output array in which to place the result. Must
be of the same shape and buffer length as the expected output.
- See `ufuncs-output-type` for more details.
+ See :ref:`ufuncs-output-type` for more details.
keepdims : bool, optional
If this is set to True, the axes which are reduced are left
out : ndarray, optional
Alternative output array in which to place the result. Must
be of the same shape and buffer length as the expected output.
- See `ufuncs-output-type` for more details.
+ See :ref:`ufuncs-output-type` for more details.
keepdims : bool, optional
If this is set to True, the axes which are reduced are left
"""
Return the length of the first dimension of the input array.
+ .. deprecated:: 1.18
+ `numpy.alen` is deprecated, use `len` instead.
+
Parameters
----------
a : array_like
See Also
--------
ndarray.prod : equivalent method
- ufuncs-output-type
+ :ref:`ufuncs-output-type`
Notes
-----
See Also
--------
- ufuncs-output-type
+ :ref:`ufuncs-output-type`
Notes
-----
out : ndarray, optional
Alternative output array in which to place the result. It must have
the same shape as the expected output, but the type of the output
- values will be cast if necessary. See `ufuncs-output-type` for more
+ values will be cast if necessary. See :ref:`ufuncs-output-type` for more
details.
Returns
return _wrapfunc(a, 'round', decimals=decimals, out=out)
-def _mean_dispatcher(a, axis=None, dtype=None, out=None, keepdims=None):
- return (a, out)
+def _mean_dispatcher(a, axis=None, dtype=None, out=None, keepdims=None, *,
+ where=None):
+ return (a, where, out)
@array_function_dispatch(_mean_dispatcher)
-def mean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue):
+def mean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue, *,
+ where=np._NoValue):
"""
Compute the arithmetic mean along the specified axis.
Alternate output array in which to place the result. The default
is ``None``; if provided, it must have the same shape as the
expected output, but the type will be cast if necessary.
- See `ufuncs-output-type` for more details.
+ See :ref:`ufuncs-output-type` for more details.
keepdims : bool, optional
If this is set to True, the axes which are reduced are left
sub-class' method does not implement `keepdims` any
exceptions will be raised.
+ where : array_like of bool, optional
+ Elements to include in the mean. See `~numpy.ufunc.reduce` for details.
+
+ .. versionadded:: 1.20.0
+
Returns
-------
m : ndarray, see dtype parameter above
>>> np.mean(a, dtype=np.float64)
0.55000000074505806 # may vary
+ Specifying a where argument:
+ >>> a = np.array([[5, 9, 13], [14, 10, 12], [11, 15, 19]])
+ >>> np.mean(a)
+ 12.0
+ >>> np.mean(a, where=[[True], [False], [False]])
+ 9.0
+
"""
kwargs = {}
if keepdims is not np._NoValue:
kwargs['keepdims'] = keepdims
+ if where is not np._NoValue:
+ kwargs['where'] = where
if type(a) is not mu.ndarray:
try:
mean = a.mean
out=out, **kwargs)
-def _std_dispatcher(
- a, axis=None, dtype=None, out=None, ddof=None, keepdims=None):
- return (a, out)
+def _std_dispatcher(a, axis=None, dtype=None, out=None, ddof=None,
+ keepdims=None, *, where=None):
+ return (a, where, out)
@array_function_dispatch(_std_dispatcher)
-def std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue):
+def std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue, *,
+ where=np._NoValue):
"""
Compute the standard deviation along the specified axis.
sub-class' method does not implement `keepdims` any
exceptions will be raised.
+ where : array_like of bool, optional
+ Elements to include in the standard deviation.
+ See `~numpy.ufunc.reduce` for details.
+
+ .. versionadded:: 1.20.0
+
Returns
-------
standard_deviation : ndarray, see dtype parameter above.
See Also
--------
var, mean, nanmean, nanstd, nanvar
- ufuncs-output-type
+ :ref:`ufuncs-output-type`
Notes
-----
The standard deviation is the square root of the average of the squared
- deviations from the mean, i.e., ``std = sqrt(mean(abs(x - x.mean())**2))``.
-
- The average squared deviation is normally calculated as
- ``x.sum() / N``, where ``N = len(x)``. If, however, `ddof` is specified,
- the divisor ``N - ddof`` is used instead. In standard statistical
- practice, ``ddof=1`` provides an unbiased estimator of the variance
- of the infinite population. ``ddof=0`` provides a maximum likelihood
- estimate of the variance for normally distributed variables. The
- standard deviation computed in this function is the square root of
- the estimated variance, so even with ``ddof=1``, it will not be an
- unbiased estimate of the standard deviation per se.
+ deviations from the mean, i.e., ``std = sqrt(mean(x))``, where
+ ``x = abs(a - a.mean())**2``.
+
+ The average squared deviation is typically calculated as ``x.sum() / N``,
+ where ``N = len(x)``. If, however, `ddof` is specified, the divisor
+ ``N - ddof`` is used instead. In standard statistical practice, ``ddof=1``
+ provides an unbiased estimator of the variance of the infinite population.
+ ``ddof=0`` provides a maximum likelihood estimate of the variance for
+ normally distributed variables. The standard deviation computed in this
+ function is the square root of the estimated variance, so even with
+ ``ddof=1``, it will not be an unbiased estimate of the standard deviation
+ per se.
Note that, for complex numbers, `std` takes the absolute
value before squaring, so that the result is always real and nonnegative.
>>> np.std(a, dtype=np.float64)
0.44999999925494177 # may vary
+ Specifying a where argument:
+
+ >>> a = np.array([[14, 8, 11, 10], [7, 9, 10, 11], [10, 15, 5, 10]])
+ >>> np.std(a)
+ 2.614064523559687 # may vary
+ >>> np.std(a, where=[[True], [True], [False]])
+ 2.0
+
"""
kwargs = {}
if keepdims is not np._NoValue:
kwargs['keepdims'] = keepdims
-
+ if where is not np._NoValue:
+ kwargs['where'] = where
if type(a) is not mu.ndarray:
try:
std = a.std
**kwargs)
-def _var_dispatcher(
- a, axis=None, dtype=None, out=None, ddof=None, keepdims=None):
- return (a, out)
+def _var_dispatcher(a, axis=None, dtype=None, out=None, ddof=None,
+ keepdims=None, *, where=None):
+ return (a, where, out)
@array_function_dispatch(_var_dispatcher)
-def var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue):
+def var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue, *,
+ where=np._NoValue):
"""
Compute the variance along the specified axis.
sub-class' method does not implement `keepdims` any
exceptions will be raised.
+ where : array_like of bool, optional
+ Elements to include in the variance. See `~numpy.ufunc.reduce` for
+ details.
+
+ .. versionadded:: 1.20.0
+
Returns
-------
variance : ndarray, see dtype parameter above
See Also
--------
std, mean, nanmean, nanstd, nanvar
- ufuncs-output-type
+ :ref:`ufuncs-output-type`
Notes
-----
The variance is the average of the squared deviations from the mean,
- i.e., ``var = mean(abs(x - x.mean())**2)``.
+ i.e., ``var = mean(x)``, where ``x = abs(a - a.mean())**2``.
- The mean is normally calculated as ``x.sum() / N``, where ``N = len(x)``.
+ The mean is typically calculated as ``x.sum() / N``, where ``N = len(x)``.
If, however, `ddof` is specified, the divisor ``N - ddof`` is used
instead. In standard statistical practice, ``ddof=1`` provides an
unbiased estimator of the variance of a hypothetical infinite population.
>>> ((1-0.55)**2 + (0.1-0.55)**2)/2
0.2025
+ Specifying a where argument:
+
+ >>> a = np.array([[14, 8, 11, 10], [7, 9, 10, 11], [10, 15, 5, 10]])
+ >>> np.var(a)
+ 6.833333333333333 # may vary
+ >>> np.var(a, where=[[True], [True], [False]])
+ 4.0
+
"""
kwargs = {}
if keepdims is not np._NoValue:
kwargs['keepdims'] = keepdims
+ if where is not np._NoValue:
+ kwargs['where'] = where
if type(a) is not mu.ndarray:
try:
--- /dev/null
+import sys
+import datetime as dt
+from typing import Optional, Union, Sequence, Tuple, Any, overload, TypeVar
+
+from numpy import (
+ ndarray,
+ number,
+ integer,
+ bool_,
+ generic,
+ _OrderKACF,
+ _OrderACF,
+ _ArrayLikeBool,
+ _ArrayLikeIntOrBool,
+ _ModeKind,
+ _PartitionKind,
+ _SortKind,
+ _SortSide,
+)
+from numpy.typing import (
+ DTypeLike,
+ ArrayLike,
+ _ShapeLike,
+ _Shape,
+ _IntLike,
+ _BoolLike,
+ _NumberLike,
+)
+
+if sys.version_info >= (3, 8):
+ from typing import Literal
+else:
+ from typing_extensions import Literal
+
+# Various annotations for scalars
+
+# While dt.datetime and dt.timedelta are not technically part of NumPy,
+# they are one of the rare few builtin scalars which serve as valid return types.
+# See https://github.com/numpy/numpy-stubs/pull/67#discussion_r412604113.
+_ScalarNumpy = Union[generic, dt.datetime, dt.timedelta]
+_ScalarBuiltin = Union[str, bytes, dt.date, dt.timedelta, bool, int, float, complex]
+_Scalar = Union[_ScalarBuiltin, _ScalarNumpy]
+
+# Integers and booleans can generally be used interchangeably
+_ScalarIntOrBool = TypeVar("_ScalarIntOrBool", bound=Union[integer, bool_])
+_ScalarGeneric = TypeVar("_ScalarGeneric", bound=generic)
+_ScalarGenericDT = TypeVar(
+ "_ScalarGenericDT", bound=Union[dt.datetime, dt.timedelta, generic]
+)
+
+_Number = TypeVar("_Number", bound=number)
+
+# The signature of take() follows a common theme with its overloads:
+# 1. A generic comes in; the same generic comes out
+# 2. A scalar comes in; a generic comes out
+# 3. An array-like object comes in; some keyword ensures that a generic comes out
+# 4. An array-like object comes in; an ndarray or generic comes out
+@overload
+def take(
+ a: _ScalarGenericDT,
+ indices: int,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _ModeKind = ...,
+) -> _ScalarGenericDT: ...
+@overload
+def take(
+ a: _Scalar,
+ indices: int,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _ModeKind = ...,
+) -> _ScalarNumpy: ...
+@overload
+def take(
+ a: ArrayLike,
+ indices: int,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _ModeKind = ...,
+) -> _ScalarNumpy: ...
+@overload
+def take(
+ a: ArrayLike,
+ indices: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _ModeKind = ...,
+) -> Union[_ScalarNumpy, ndarray]: ...
+def reshape(a: ArrayLike, newshape: _ShapeLike, order: _OrderACF = ...) -> ndarray: ...
+@overload
+def choose(
+ a: _ScalarIntOrBool,
+ choices: ArrayLike,
+ out: Optional[ndarray] = ...,
+ mode: _ModeKind = ...,
+) -> _ScalarIntOrBool: ...
+@overload
+def choose(
+ a: Union[_IntLike, _BoolLike], choices: ArrayLike, out: Optional[ndarray] = ..., mode: _ModeKind = ...
+) -> Union[integer, bool_]: ...
+@overload
+def choose(
+ a: _ArrayLikeIntOrBool,
+ choices: ArrayLike,
+ out: Optional[ndarray] = ...,
+ mode: _ModeKind = ...,
+) -> ndarray: ...
+def repeat(
+ a: ArrayLike, repeats: _ArrayLikeIntOrBool, axis: Optional[int] = ...
+) -> ndarray: ...
+def put(
+ a: ndarray, ind: _ArrayLikeIntOrBool, v: ArrayLike, mode: _ModeKind = ...
+) -> None: ...
+def swapaxes(a: ArrayLike, axis1: int, axis2: int) -> ndarray: ...
+def transpose(
+ a: ArrayLike, axes: Union[None, Sequence[int], ndarray] = ...
+) -> ndarray: ...
+def partition(
+ a: ArrayLike,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+@overload
+def argpartition(
+ a: generic,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> integer: ...
+@overload
+def argpartition(
+ a: _ScalarBuiltin,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+@overload
+def argpartition(
+ a: ArrayLike,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+def sort(
+ a: ArrayLike,
+ axis: Optional[int] = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+def argsort(
+ a: ArrayLike,
+ axis: Optional[int] = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+@overload
+def argmax(a: ArrayLike, axis: None = ..., out: Optional[ndarray] = ...) -> integer: ...
+@overload
+def argmax(
+ a: ArrayLike, axis: int = ..., out: Optional[ndarray] = ...
+) -> Union[integer, ndarray]: ...
+@overload
+def argmin(a: ArrayLike, axis: None = ..., out: Optional[ndarray] = ...) -> integer: ...
+@overload
+def argmin(
+ a: ArrayLike, axis: int = ..., out: Optional[ndarray] = ...
+) -> Union[integer, ndarray]: ...
+@overload
+def searchsorted(
+ a: ArrayLike,
+ v: _Scalar,
+ side: _SortSide = ...,
+ sorter: Optional[_ArrayLikeIntOrBool] = ..., # 1D int array
+) -> integer: ...
+@overload
+def searchsorted(
+ a: ArrayLike,
+ v: ArrayLike,
+ side: _SortSide = ...,
+ sorter: Optional[_ArrayLikeIntOrBool] = ..., # 1D int array
+) -> ndarray: ...
+def resize(a: ArrayLike, new_shape: _ShapeLike) -> ndarray: ...
+@overload
+def squeeze(a: _ScalarGeneric, axis: Optional[_ShapeLike] = ...) -> _ScalarGeneric: ...
+@overload
+def squeeze(a: ArrayLike, axis: Optional[_ShapeLike] = ...) -> ndarray: ...
+def diagonal(
+ a: ArrayLike, offset: int = ..., axis1: int = ..., axis2: int = ... # >= 2D array
+) -> ndarray: ...
+def trace(
+ a: ArrayLike, # >= 2D array
+ offset: int = ...,
+ axis1: int = ...,
+ axis2: int = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+) -> Union[number, ndarray]: ...
+def ravel(a: ArrayLike, order: _OrderKACF = ...) -> ndarray: ...
+def nonzero(a: ArrayLike) -> Tuple[ndarray, ...]: ...
+def shape(a: ArrayLike) -> _Shape: ...
+def compress(
+ condition: ArrayLike, # 1D bool array
+ a: ArrayLike,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+) -> ndarray: ...
+@overload
+def clip(
+ a: _Number,
+ a_min: ArrayLike,
+ a_max: Optional[ArrayLike],
+ out: Optional[ndarray] = ...,
+ **kwargs: Any,
+) -> _Number: ...
+@overload
+def clip(
+ a: _Number,
+ a_min: None,
+ a_max: ArrayLike,
+ out: Optional[ndarray] = ...,
+ **kwargs: Any,
+) -> _Number: ...
+@overload
+def clip(
+ a: ArrayLike,
+ a_min: ArrayLike,
+ a_max: Optional[ArrayLike],
+ out: Optional[ndarray] = ...,
+ **kwargs: Any,
+) -> Union[number, ndarray]: ...
+@overload
+def clip(
+ a: ArrayLike,
+ a_min: None,
+ a_max: ArrayLike,
+ out: Optional[ndarray] = ...,
+ **kwargs: Any,
+) -> Union[number, ndarray]: ...
+@overload
+def sum(
+ a: _Number,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> _Number: ...
+@overload
+def sum(
+ a: ArrayLike,
+ axis: _ShapeLike = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> Union[number, ndarray]: ...
+@overload
+def all(
+ a: ArrayLike,
+ axis: None = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: Literal[False] = ...,
+) -> bool_: ...
+@overload
+def all(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+) -> Union[bool_, ndarray]: ...
+@overload
+def any(
+ a: ArrayLike,
+ axis: None = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: Literal[False] = ...,
+) -> bool_: ...
+@overload
+def any(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+) -> Union[bool_, ndarray]: ...
+def cumsum(
+ a: ArrayLike,
+ axis: Optional[int] = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+) -> ndarray: ...
+@overload
+def ptp(
+ a: _Number,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+) -> _Number: ...
+@overload
+def ptp(
+ a: ArrayLike,
+ axis: None = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: Literal[False] = ...,
+) -> number: ...
+@overload
+def ptp(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+) -> Union[number, ndarray]: ...
+@overload
+def amax(
+ a: _Number,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> _Number: ...
+@overload
+def amax(
+ a: ArrayLike,
+ axis: None = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> number: ...
+@overload
+def amax(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> Union[number, ndarray]: ...
+@overload
+def amin(
+ a: _Number,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> _Number: ...
+@overload
+def amin(
+ a: ArrayLike,
+ axis: None = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> number: ...
+@overload
+def amin(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> Union[number, ndarray]: ...
+
+# TODO: `np.prod()``: For object arrays `initial` does not necessarily
+# have to be a numerical scalar.
+# The only requirement is that it is compatible
+# with the `.__mul__()` method(s) of the passed array's elements.
+
+# Note that the same situation holds for all wrappers around
+# `np.ufunc.reduce`, e.g. `np.sum()` (`.__add__()`).
+@overload
+def prod(
+ a: _Number,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> _Number: ...
+@overload
+def prod(
+ a: ArrayLike,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> number: ...
+@overload
+def prod(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+) -> Union[number, ndarray]: ...
+def cumprod(
+ a: ArrayLike,
+ axis: Optional[int] = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+) -> ndarray: ...
+def ndim(a: ArrayLike) -> int: ...
+def size(a: ArrayLike, axis: Optional[int] = ...) -> int: ...
+@overload
+def around(
+ a: _Number, decimals: int = ..., out: Optional[ndarray] = ...
+) -> _Number: ...
+@overload
+def around(
+ a: _NumberLike, decimals: int = ..., out: Optional[ndarray] = ...
+) -> number: ...
+@overload
+def around(
+ a: ArrayLike, decimals: int = ..., out: Optional[ndarray] = ...
+) -> ndarray: ...
+@overload
+def mean(
+ a: ArrayLike,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+) -> number: ...
+@overload
+def mean(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+ keepdims: bool = ...,
+) -> Union[number, ndarray]: ...
+@overload
+def std(
+ a: ArrayLike,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: Literal[False] = ...,
+) -> number: ...
+@overload
+def std(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+) -> Union[number, ndarray]: ...
+@overload
+def var(
+ a: ArrayLike,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: Literal[False] = ...,
+) -> number: ...
+@overload
+def var(
+ a: ArrayLike,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: Optional[ndarray] = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+) -> Union[number, ndarray]: ...
.. versionchanged:: 1.16.0
Non-scalar `start` and `stop` are now supported.
+ .. versionchanged:: 1.20.0
+ Values are rounded towards ``-inf`` instead of ``0`` when an
+ integer ``dtype`` is specified. The old behavior can
+ still be obtained with ``np.linspace(start, stop, num).astype(int)``
+
Parameters
----------
start : array_like
If True, return (`samples`, `step`), where `step` is the spacing
between samples.
dtype : dtype, optional
- The type of the output array. If `dtype` is not given, infer the data
- type from the other input arguments.
+ The type of the output array. If `dtype` is not given, the data type
+ is inferred from `start` and `stop`. The inferred dtype will never be
+ an integer; `float` is chosen even if the arguments would produce an
+ array of integers.
.. versionadded:: 1.9.0
if axis != 0:
y = _nx.moveaxis(y, 0, axis)
+ if _nx.issubdtype(dtype, _nx.integer):
+ _nx.floor(y, out=y)
+
if retstep:
return y.astype(dtype, copy=False), step
else:
endpoint : boolean, optional
If true, `stop` is the last sample. Otherwise, it is not included.
Default is True.
- base : float, optional
+ base : array_like, optional
The base of the log space. The step size between the elements in
``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform.
Default is 10.0.
dtype : dtype
- The type of the output array. If `dtype` is not given, infer the data
- type from the other input arguments.
+ The type of the output array. If `dtype` is not given, the data type
+ is inferred from `start` and `stop`. The inferred type will never be
+ an integer; `float` is chosen even if the arguments would produce an
+ array of integers.
axis : int, optional
The axis in the result to store the samples. Relevant only if start
or stop are array-like. By default (0), the samples will be along a
If true, `stop` is the last sample. Otherwise, it is not included.
Default is True.
dtype : dtype
- The type of the output array. If `dtype` is not given, infer the data
- type from the other input arguments.
+ The type of the output array. If `dtype` is not given, the data type
+ is inferred from `start` and `stop`. The inferred dtype will never be
+ an integer; `float` is chosen even if the arguments would produce an
+ array of integers.
axis : int, optional
The axis in the result to store the samples. Relevant only if start
or stop are array-like. By default (0), the samples will be along a
log_start = _nx.log10(start)
log_stop = _nx.log10(stop)
- result = out_sign * logspace(log_start, log_stop, num=num,
- endpoint=endpoint, base=10.0, dtype=dtype)
+ result = logspace(log_start, log_stop, num=num,
+ endpoint=endpoint, base=10.0, dtype=dtype)
+
+ # Make sure the endpoints match the start and stop arguments. This is
+ # necessary because np.exp(np.log(x)) is not necessarily equal to x.
+ if num > 0:
+ result[0] = start
+ if num > 1 and endpoint:
+ result[-1] = stop
+
+ result = out_sign * result
+
if axis != 0:
result = _nx.moveaxis(result, 0, axis)
--- /dev/null
+import sys
+from typing import overload, Tuple, Union, Sequence, Any
+
+from numpy import ndarray, inexact
+from numpy.typing import ArrayLike, DTypeLike, _SupportsArray, _NumberLike
+
+if sys.version_info >= (3, 8):
+ from typing import SupportsIndex, Literal
+else:
+ from typing_extensions import Literal, Protocol
+
+ class SupportsIndex(Protocol):
+ def __index__(self) -> int: ...
+
+# TODO: wait for support for recursive types
+_ArrayLikeNested = Sequence[Sequence[Any]]
+_ArrayLikeNumber = Union[
+ _NumberLike, Sequence[_NumberLike], ndarray, _SupportsArray, _ArrayLikeNested
+]
+@overload
+def linspace(
+ start: _ArrayLikeNumber,
+ stop: _ArrayLikeNumber,
+ num: SupportsIndex = ...,
+ endpoint: bool = ...,
+ retstep: Literal[False] = ...,
+ dtype: DTypeLike = ...,
+ axis: SupportsIndex = ...,
+) -> ndarray: ...
+@overload
+def linspace(
+ start: _ArrayLikeNumber,
+ stop: _ArrayLikeNumber,
+ num: SupportsIndex = ...,
+ endpoint: bool = ...,
+ retstep: Literal[True] = ...,
+ dtype: DTypeLike = ...,
+ axis: SupportsIndex = ...,
+) -> Tuple[ndarray, inexact]: ...
+def logspace(
+ start: _ArrayLikeNumber,
+ stop: _ArrayLikeNumber,
+ num: SupportsIndex = ...,
+ endpoint: bool = ...,
+ base: _ArrayLikeNumber = ...,
+ dtype: DTypeLike = ...,
+ axis: SupportsIndex = ...,
+) -> ndarray: ...
+def geomspace(
+ start: _ArrayLikeNumber,
+ stop: _ArrayLikeNumber,
+ num: SupportsIndex = ...,
+ endpoint: bool = ...,
+ dtype: DTypeLike = ...,
+ axis: SupportsIndex = ...,
+) -> ndarray: ...
raise ValueError(repr(ftype))
# Detect known / suspected types
key = ftype('-0.1').newbyteorder('<').tobytes()
- ma_like = _KNOWN_TYPES.get(key)
- # Could be 80 bit == 10 byte extended precision, where last bytes can be
- # random garbage. Try comparing first 10 bytes to pattern.
- if ma_like is None and ftype == ntypes.longdouble:
+ ma_like = None
+ if ftype == ntypes.longdouble:
+ # Could be 80 bit == 10 byte extended precision, where last bytes can
+ # be random garbage.
+ # Comparing first 10 bytes to pattern first to avoid branching on the
+ # random garbage.
ma_like = _KNOWN_TYPES.get(key[:10])
+ if ma_like is None:
+ ma_like = _KNOWN_TYPES.get(key)
if ma_like is not None:
return ma_like
# Fall back to parameter discovery
The approximate decimal resolution of this type, i.e.,
``10**-precision``.
tiny : float
- The smallest positive usable number. Type of `tiny` is an
- appropriate floating point type.
+ The smallest positive floating point number with full precision
+ (see Notes).
Parameters
----------
impacts import times. These objects are cached, so calling ``finfo()``
repeatedly inside your functions is not a problem.
+ Note that ``tiny`` is not actually the smallest positive representable
+ value in a NumPy floating point type. As in the IEEE-754 standard [1]_,
+ NumPy floating point types make use of subnormal numbers to fill the
+ gap between 0 and ``tiny``. However, subnormal numbers may have
+ significantly reduced precision [2]_.
+
+ References
+ ----------
+ .. [1] IEEE Standard for Floating-Point Arithmetic, IEEE Std 754-2008,
+ pp.1-70, 2008, http://www.doi.org/10.1109/IEEESTD.2008.4610935
+ .. [2] Wikipedia, "Denormal Numbers",
+ https://en.wikipedia.org/wiki/Denormal_number
"""
_finfo_cache = {}
def __repr__(self):
return "%s(min=%s, max=%s, dtype=%s)" % (self.__class__.__name__,
self.min, self.max, self.dtype)
-
char obval;
} PyScalarObject;
-#define PyStringScalarObject PyStringObject
-#define PyStringScalarObject PyStringObject
+#define PyStringScalarObject PyBytesObject
typedef struct {
/* note that the PyObject_HEAD macro lives right here */
PyUnicodeObject base;
Py_UCS4 *obval;
+ char *buffer_fmt;
} PyUnicodeScalarObject;
PyArray_Descr *descr;
int flags;
PyObject *base;
+ void *_buffer_info; /* private buffer info, tagged to allow warning */
} PyVoidScalarObject;
/* Macros
/* For specifying allowed casting in operations which support it */
typedef enum {
+ _NPY_ERROR_OCCURRED_IN_CAST = -1,
/* Only allow identical types */
NPY_NO_CASTING=0,
/* Allow identical and byte swapped types */
/* Allow safe casts or casts within the same kind */
NPY_SAME_KIND_CASTING=3,
/* Allow any casts */
- NPY_UNSAFE_CASTING=4
+ NPY_UNSAFE_CASTING=4,
+ /*
+ * Flag to allow signalling that a cast is a view, this flag is not
+ * valid when requesting a cast of specific safety.
+ * _NPY_CAST_IS_VIEW|NPY_EQUIV_CASTING means the same as NPY_NO_CASTING.
+ */
+ // TODO-DTYPES: Needs to be documented.
+ _NPY_CAST_IS_VIEW = 1 << 16,
} NPY_CASTING;
typedef enum {
#define NPY_ERR(str) fprintf(stderr, #str); fflush(stderr);
#define NPY_ERR2(str) fprintf(stderr, str); fflush(stderr);
-#define NPY_STRINGIFY(x) #x
-#define NPY_TOSTRING(x) NPY_STRINGIFY(x)
-
/*
* Macros to define how array, and dimension/strides data is
* allocated.
int flags;
/* For weak references */
PyObject *weakreflist;
+ void *_buffer_info; /* private buffer info, tagged to allow warning */
} PyArrayObject_fields;
/*
} PyArrayObject;
#endif
-#define NPY_SIZEOF_PYARRAYOBJECT (sizeof(PyArrayObject_fields))
+/*
+ * Removed 2020-Nov-25, NumPy 1.20
+ * #define NPY_SIZEOF_PYARRAYOBJECT (sizeof(PyArrayObject_fields))
+ *
+ * The above macro was removed as it gave a false sense of a stable ABI
+ * with respect to the structures size. If you require a runtime constant,
+ * you can use `PyArray_Type.tp_basicsize` instead. Otherwise, please
+ * see the PyArrayObject documentation or ask the NumPy developers for
+ * information on how to correctly replace the macro in a way that is
+ * compatible with multiple NumPy versions.
+ */
+
/* Array Flags Object */
typedef struct PyArrayFlagsObject {
(void *)itemptr, (PyArrayObject *)arr);
}
+/*
+ * SETITEM should only be used if it is known that the value is a scalar
+ * and of a type understood by the arrays dtype.
+ * Use `PyArray_Pack` if the value may be of a different dtype.
+ */
static NPY_INLINE int
PyArray_SETITEM(PyArrayObject *arr, char *itemptr, PyObject *v)
{
- return ((PyArrayObject_fields *)arr)->descr->f->setitem(
- v, itemptr, arr);
+ return ((PyArrayObject_fields *)arr)->descr->f->setitem(v, itemptr, arr);
}
#else
} npy_stride_sort_item;
/************************************************************
- * This is the form of the struct that's returned pointed by the
- * PyCObject attribute of an array __array_struct__. See
+ * This is the form of the struct that's stored in the
+ * PyCapsule returned by an array's __array_struct__ attribute. See
* https://docs.scipy.org/doc/numpy/reference/arrays.interface.html for the full
* documentation.
************************************************************/
typedef void (PyDataMem_EventHookFunc)(void *inp, void *outp, size_t size,
void *user_data);
+
+/*
+ * PyArray_DTypeMeta related definitions.
+ *
+ * As of now, this API is preliminary and will be extended as necessary.
+ */
+#if defined(NPY_INTERNAL_BUILD) && NPY_INTERNAL_BUILD
+ /*
+ * The Structures defined in this block are considered private API and
+ * may change without warning!
+ */
+ /* TODO: Make this definition public in the API, as soon as its settled */
+ NPY_NO_EXPORT extern PyTypeObject PyArrayDTypeMeta_Type;
+
+ typedef struct PyArray_DTypeMeta_tag PyArray_DTypeMeta;
+
+ typedef PyArray_Descr *(discover_descr_from_pyobject_function)(
+ PyArray_DTypeMeta *cls, PyObject *obj);
+
+ /*
+ * Before making this public, we should decide whether it should pass
+ * the type, or allow looking at the object. A possible use-case:
+ * `np.array(np.array([0]), dtype=np.ndarray)`
+ * Could consider arrays that are not `dtype=ndarray` "scalars".
+ */
+ typedef int (is_known_scalar_type_function)(
+ PyArray_DTypeMeta *cls, PyTypeObject *obj);
+
+ typedef PyArray_Descr *(default_descr_function)(PyArray_DTypeMeta *cls);
+ typedef PyArray_DTypeMeta *(common_dtype_function)(
+ PyArray_DTypeMeta *dtype1, PyArray_DTypeMeta *dtyep2);
+ typedef PyArray_Descr *(common_instance_function)(
+ PyArray_Descr *dtype1, PyArray_Descr *dtyep2);
+
+ /*
+ * While NumPy DTypes would not need to be heap types the plan is to
+ * make DTypes available in Python at which point they will be heap types.
+ * Since we also wish to add fields to the DType class, this looks like
+ * a typical instance definition, but with PyHeapTypeObject instead of
+ * only the PyObject_HEAD.
+ * This must only be exposed very extremely careful consideration, since
+ * it is a fairly complex construct which may be better to allow
+ * refactoring of.
+ */
+ struct PyArray_DTypeMeta_tag {
+ PyHeapTypeObject super;
+
+ /*
+ * Most DTypes will have a singleton default instance, for the
+ * parametric legacy DTypes (bytes, string, void, datetime) this
+ * may be a pointer to the *prototype* instance?
+ */
+ PyArray_Descr *singleton;
+ /*
+ * Is this DType created using the old API? This exists mainly to
+ * allow for assertions in paths specific to wrapping legacy types.
+ */
+ npy_bool legacy;
+ /* The values stored by a parametric datatype depend on its instance */
+ npy_bool parametric;
+ /* whether the DType can be instantiated (i.e. np.dtype cannot) */
+ npy_bool abstract;
+
+ /*
+ * The following fields replicate the most important dtype information.
+ * In the legacy implementation most of these are stored in the
+ * PyArray_Descr struct.
+ */
+ /* The type object of the scalar instances (may be NULL?) */
+ PyTypeObject *scalar_type;
+ /* kind for this type */
+ char kind;
+ /* unique-character representing this type */
+ char type;
+ /* flags describing data type */
+ char flags;
+ /* number representing this type */
+ int type_num;
+ /*
+ * Point to the original ArrFuncs.
+ * NOTE: We could make a copy to detect changes to `f`.
+ */
+ PyArray_ArrFuncs *f;
+
+ /* DType methods, these could be moved into its own struct */
+ discover_descr_from_pyobject_function *discover_descr_from_pyobject;
+ is_known_scalar_type_function *is_known_scalar_type;
+ default_descr_function *default_descr;
+ common_dtype_function *common_dtype;
+ common_instance_function *common_instance;
+ /*
+ * Dictionary of ArrayMethods representing most possible casts
+ * (structured and object are exceptions).
+ * This should potentially become a weak mapping in the future.
+ */
+ PyObject *castingimpls;
+ };
+
+#endif /* NPY_INTERNAL_BUILD */
+
+
/*
* Use the keyword NPY_DEPRECATED_INCLUDES to ensure that the header files
* npy_*_*_deprecated_api.h are only included from here and nowhere else.
#define _WARN___LOC__ __FILE__ "(" _WARN___STR1__(__LINE__) ") : Warning Msg: "
#pragma message(_WARN___LOC__"Using deprecated NumPy API, disable it with " \
"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION")
-#elif defined(__GNUC__)
+#else
#warning "Using deprecated NumPy API, disable it with " \
"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION"
#endif
-/* TODO: How to do this warning message for other compilers? */
#endif
/*
* PyInt -> PyLong
*/
+
+/*
+ * This is a renamed copy of the Python non-limited API function _PyLong_AsInt. It is
+ * included here because it is missing from the PyPy API. It completes the PyLong_As*
+ * group of functions and can be useful in replacing PyInt_Check.
+ */
+static NPY_INLINE int
+Npy__PyLong_AsInt(PyObject *obj)
+{
+ int overflow;
+ long result = PyLong_AsLongAndOverflow(obj, &overflow);
+
+ /* INT_MAX and INT_MIN are defined in Python.h */
+ if (overflow || result > INT_MAX || result < INT_MIN) {
+ /* XXX: could be cute and give a different
+ message for overflow == -1 */
+ PyErr_SetString(PyExc_OverflowError,
+ "Python int too large to convert to C int");
+ return -1;
+ }
+ return (int)result;
+}
+
+
#if defined(NPY_PY3K)
/* Return True only if the long fits in a C long */
static NPY_INLINE int PyInt_Check(PyObject *op) {
return (overflow == 0);
}
+
#define PyInt_FromLong PyLong_FromLong
#define PyInt_AsLong PyLong_AsLong
#define PyInt_AS_LONG PyLong_AsLong
#if PY_VERSION_HEX < 0x030900a4
/* Introduced in https://github.com/python/cpython/commit/d2ec81a8c99796b51fb8c49b77a7fe369863226f */
- #define Py_SET_TYPE(obj, typ) (Py_TYPE(obj) = typ)
+ #define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0)
/* Introduced in https://github.com/python/cpython/commit/b10dc3e7a11fcdb97e285882eba6da92594f90f9 */
- #define Py_SET_SIZE(obj, size) (Py_SIZE(obj) = size)
+ #define Py_SET_SIZE(obj, size) ((Py_SIZE(obj) = (size)), (void)0)
+ /* Introduced in https://github.com/python/cpython/commit/c86a11221df7e37da389f9c6ce6e47ea22dc44ff */
+ #define Py_SET_REFCNT(obj, refcnt) ((Py_REFCNT(obj) = (refcnt)), (void)0)
#endif
#ifndef _NPY_COMMON_H_
#define _NPY_COMMON_H_
+/* need Python.h for npy_intp, npy_uintp */
+#include <Python.h>
+
/* numpconfig.h is auto-generated */
#include "numpyconfig.h"
#ifdef HAVE_NPY_CONFIG_H
#include <npy_config.h>
#endif
-/* need Python.h for npy_intp, npy_uintp */
-#include <Python.h>
-
/*
* using static inline modifiers when defining npy_math functions
* allows the compiler to make optimizations when possible
#define NPY_GCC_TARGET_AVX512F
#endif
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX && defined HAVE_LINK_AVX512_SKX
+#define NPY_GCC_TARGET_AVX512_SKX __attribute__((target("avx512f,avx512dq,avx512vl,avx512bw,avx512cd")))
+#elif defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS
+#define NPY_GCC_TARGET_AVX512_SKX __attribute__((target("avx512f,avx512dq,avx512vl,avx512bw,avx512cd")))
+#else
+#define NPY_GCC_TARGET_AVX512_SKX
+#endif
/*
* mark an argument (starting from 1) that must not be NULL and is not checked
* DO NOT USE IF FUNCTION CHECKS FOR NULL!! the compiler will remove the check
#define NPY_INLINE
#endif
+#ifdef _MSC_VER
+ #define NPY_FINLINE static __forceinline
+#elif defined(__GNUC__)
+ #define NPY_FINLINE static NPY_INLINE __attribute__((always_inline))
+#else
+ #define NPY_FINLINE static
+#endif
+
#ifdef HAVE___THREAD
#define NPY_TLS __thread
#else
#define constchar char
/* NPY_INTP_FMT Note:
- * Unlike the other NPY_*_FMT macros which are used with
- * PyOS_snprintf, NPY_INTP_FMT is used with PyErr_Format and
- * PyString_Format. These functions use different formatting
- * codes which are portably specified according to the Python
- * documentation. See ticket #1795.
+ * Unlike the other NPY_*_FMT macros, which are used with PyOS_snprintf,
+ * NPY_INTP_FMT is used with PyErr_Format and PyUnicode_FromFormat. Those
+ * functions use different formatting codes that are portably specified
+ * according to the Python documentation. See issue gh-2388.
*/
#if NPY_SIZEOF_PY_INTPTR_T == NPY_SIZEOF_INT
#define NPY_INTP NPY_INT
#define _NPY_CPUARCH_H_
#include "numpyconfig.h"
-#include <string.h> /* for memcpy */
#if defined( __i386__ ) || defined(i386) || defined(_M_IX86)
/*
information about your platform (OS, CPU and compiler)
#endif
-#define NPY_COPY_PYOBJECT_PTR(dst, src) memcpy(dst, src, sizeof(PyObject *))
-
#if (defined(NPY_CPU_X86) || defined(NPY_CPU_AMD64))
#define NPY_CPU_HAVE_UNALIGNED_ACCESS 1
#else
extern "C" {
#endif
+#include <numpy/npy_common.h>
+
#include <math.h>
#ifdef __SUNPRO_CC
#include <sunmath.h>
#endif
-#ifdef HAVE_NPY_CONFIG_H
-#include <npy_config.h>
-#endif
-#include <numpy/npy_common.h>
/* By adding static inline specifiers to npy_math function definitions when
appropriate, compiler is given the opportunity to optimize */
#define NPY_1_17_API_VERSION 0x00000008
#define NPY_1_18_API_VERSION 0x00000008
#define NPY_1_19_API_VERSION 0x00000008
+#define NPY_1_20_API_VERSION 0x0000000e
#endif
#define __NUMPY_UTILS_HEADER__
#ifndef __COMP_NPY_UNUSED
- #if defined(__GNUC__)
- #define __COMP_NPY_UNUSED __attribute__ ((__unused__))
- # elif defined(__ICC)
- #define __COMP_NPY_UNUSED __attribute__ ((__unused__))
- # elif defined(__clang__)
- #define __COMP_NPY_UNUSED __attribute__ ((unused))
- #else
- #define __COMP_NPY_UNUSED
- #endif
+ #if defined(__GNUC__)
+ #define __COMP_NPY_UNUSED __attribute__ ((__unused__))
+ #elif defined(__ICC)
+ #define __COMP_NPY_UNUSED __attribute__ ((__unused__))
+ #elif defined(__clang__)
+ #define __COMP_NPY_UNUSED __attribute__ ((unused))
+ #else
+ #define __COMP_NPY_UNUSED
+ #endif
+#endif
+
+#if defined(__GNUC__) || defined(__ICC) || defined(__clang__)
+ #define NPY_DECL_ALIGNED(x) __attribute__ ((aligned (x)))
+#elif defined(_MSC_VER)
+ #define NPY_DECL_ALIGNED(x) __declspec(align(x))
+#else
+ #define NPY_DECL_ALIGNED(x)
#endif
/* Use this to tag a variable as not used. It will remove unused variable
* warning on support platforms (see __COM_NPY_UNUSED) and mangle the variable
* to avoid accidental use */
#define NPY_UNUSED(x) (__NPY_UNUSED_TAGGED ## x) __COMP_NPY_UNUSED
+#define NPY_EXPAND(x) x
+
+#define NPY_STRINGIFY(x) #x
+#define NPY_TOSTRING(x) NPY_STRINGIFY(x)
+
+#define NPY_CAT__(a, b) a ## b
+#define NPY_CAT_(a, b) NPY_CAT__(a, b)
+#define NPY_CAT(a, b) NPY_CAT_(a, b)
#endif
Smallest (most negative) power of `ibeta` consistent with there
being no leading zeros in the mantissa.
xmin : float
- Floating point number ``beta**minexp`` (the smallest [in
- magnitude] usable floating value).
+ Floating-point number ``beta**minexp`` (the smallest [in
+ magnitude] positive floating point number with full precision).
maxexp : int
Smallest (positive) power of `ibeta` that causes overflow.
xmax : float
This class may at some point be turned into a factory function
which returns a view into an mmap buffer.
- Delete the memmap instance to close the memmap file.
+ Flush the memmap instance to write the changes to the file. Currently there
+ is no API to close the underlying ``mmap``. It is tricky to ensure the
+ resource is actually closed, since it may be shared between different
+ memmap instances.
Parameters
flush
Flush any changes in memory to file on disk.
When you delete a memmap object, flush is called first to write
- changes to disk before removing the object.
+ changes to disk.
See also
>>> fp.filename == path.abspath(filename)
True
- Deletion flushes memory changes to disk before removing the object:
+ Flushes memory changes to disk in order to read them back
- >>> del fp
+ >>> fp.flush()
Load the memmap and verify data was stored:
.. versionadded:: 1.6.0
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 ``prototype`` is Fortran
- contiguous, 'C' otherwise. 'K' means match the layout of ``prototype``
+ 'F' means F-order, 'A' means 'F' if `prototype` is Fortran
+ contiguous, 'C' otherwise. 'K' means match the layout of `prototype`
as closely as possible.
.. versionadded:: 1.6.0
subok : bool, optional.
If True, then the newly created array will use the sub-class
- type of 'a', otherwise it will be a base-class array. Defaults
+ type of `prototype`, otherwise it will be a base-class array. Defaults
to True.
shape : int or sequence of ints, optional.
Overrides the shape of the result. If order='K' and the number of
@array_function_from_c_func_and_dispatcher(_multiarray_umath.concatenate)
-def concatenate(arrays, axis=None, out=None):
+def concatenate(arrays, axis=None, out=None, *, dtype=None, casting=None):
"""
- concatenate((a1, a2, ...), axis=0, out=None)
+ concatenate((a1, a2, ...), axis=0, out=None, dtype=None, casting="same_kind")
Join a sequence of arrays along an existing axis.
If provided, the destination to place the result. The shape must be
correct, matching that of what concatenate would have returned if no
out argument were specified.
+ dtype : str or dtype
+ If provided, the destination array will have this dtype. Cannot be
+ provided together with `out`.
+
+ .. versionadded:: 1.20.0
+
+ casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
+ Controls what kind of data casting may occur. Defaults to 'same_kind'.
+
+ .. versionadded:: 1.20.0
Returns
-------
for the primary sort order, the second-to-last key for the secondary sort
order, and so on. The keys argument must be a sequence of objects that
can be converted to arrays of the same shape. If a 2D array is provided
- for the keys argument, it's rows are interpreted as the sorting keys and
+ for the keys argument, its rows are interpreted as the sorting keys and
sorting is according to the last row, second last row etc.
Parameters
tensordot : Sum products over arbitrary axes.
einsum : Einstein summation convention.
matmul : '@' operator as method with out parameter.
+ linalg.multi_dot : Chained dot product.
Examples
--------
Parameters
----------
- a : array_like
+ a : ndarray
Target array.
mask : array_like
Boolean mask array. It has to be the same shape as `a`.
from . import overrides
from . import umath
from . import shape_base
-from .overrides import set_module
+from .overrides import set_array_function_like_doc, set_module
from .umath import (multiply, invert, sin, PINF, NAN)
from . import numerictypes
from .numerictypes import longlong, intc, int_, float_, complex_, bool_
.. versionadded:: 1.6.0
subok : bool, optional.
If True, then the newly created array will use the sub-class
- type of 'a', otherwise it will be a base-class array. Defaults
+ type of `a`, otherwise it will be a base-class array. Defaults
to True.
shape : int or sequence of ints, optional.
Overrides the shape of the result. If order='K' and the number of
return res
+def _ones_dispatcher(shape, dtype=None, order=None, *, like=None):
+ return(like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def ones(shape, dtype=None, order='C'):
+def ones(shape, dtype=None, order='C', *, like=None):
"""
Return a new array of given shape and type, filled with ones.
Whether to store multi-dimensional data in row-major
(C-style) or column-major (Fortran-style) order in
memory.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
[1., 1.]])
"""
+ if like is not None:
+ return _ones_with_like(shape, dtype=dtype, order=order, like=like)
+
a = empty(shape, dtype, order)
multiarray.copyto(a, 1, casting='unsafe')
return a
+_ones_with_like = array_function_dispatch(
+ _ones_dispatcher
+)(ones)
+
+
def _ones_like_dispatcher(a, dtype=None, order=None, subok=None, shape=None):
return (a,)
.. versionadded:: 1.6.0
subok : bool, optional.
If True, then the newly created array will use the sub-class
- type of 'a', otherwise it will be a base-class array. Defaults
+ type of `a`, otherwise it will be a base-class array. Defaults
to True.
shape : int or sequence of ints, optional.
Overrides the shape of the result. If order='K' and the number of
return res
+def _full_dispatcher(shape, fill_value, dtype=None, order=None, *, like=None):
+ return(like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def full(shape, fill_value, dtype=None, order='C'):
+def full(shape, fill_value, dtype=None, order='C', *, like=None):
"""
Return a new array of given shape and type, filled with `fill_value`.
order : {'C', 'F'}, optional
Whether to store multidimensional data in C- or Fortran-contiguous
(row- or column-wise) order in memory.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
[1, 2]])
"""
+ if like is not None:
+ return _full_with_like(shape, fill_value, dtype=dtype, order=order, like=like)
+
if dtype is None:
- dtype = array(fill_value).dtype
+ fill_value = asarray(fill_value)
+ dtype = fill_value.dtype
a = empty(shape, dtype, order)
multiarray.copyto(a, fill_value, casting='unsafe')
return a
+_full_with_like = array_function_dispatch(
+ _full_dispatcher
+)(full)
+
+
def _full_like_dispatcher(a, fill_value, dtype=None, order=None, subok=None, shape=None):
return (a,)
as possible.
subok : bool, optional.
If True, then the newly created array will use the sub-class
- type of 'a', otherwise it will be a base-class array. Defaults
+ type of `a`, otherwise it will be a base-class array. Defaults
to True.
shape : int or sequence of ints, optional.
Overrides the shape of the result. If order='K' and the number of
>>> y = np.arange(6, dtype=np.double)
>>> np.full_like(y, 0.1)
- array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
+ array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
"""
res = empty_like(a, dtype=dtype, order=order, subok=subok, shape=shape)
return res
+def _fromfunction_dispatcher(function, shape, *, dtype=None, like=None, **kwargs):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def fromfunction(function, shape, *, dtype=float, **kwargs):
+def fromfunction(function, shape, *, dtype=float, like=None, **kwargs):
"""
Construct an array by executing a function over each coordinate.
dtype : data-type, optional
Data-type of the coordinate arrays passed to `function`.
By default, `dtype` is float.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
[2, 3, 4]])
"""
+ if like is not None:
+ return _fromfunction_with_like(function, shape, dtype=dtype, like=like, **kwargs)
+
args = indices(shape, dtype=dtype)
return function(*args, **kwargs)
+_fromfunction_with_like = array_function_dispatch(
+ _fromfunction_dispatcher
+)(fromfunction)
+
+
def _frombuffer(buf, dtype, shape, order):
return frombuffer(buf, dtype=dtype).reshape(shape, order=order)
return tuple(res)
+def _identity_dispatcher(n, dtype=None, *, like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def identity(n, dtype=None):
+def identity(n, dtype=None, *, like=None):
"""
Return the identity array.
Number of rows (and columns) in `n` x `n` output.
dtype : data-type, optional
Data-type of the output. Defaults to ``float``.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
[0., 0., 1.]])
"""
+ if like is not None:
+ return _identity_with_like(n, dtype=dtype, like=like)
+
from numpy import eye
- return eye(n, dtype=dtype)
+ return eye(n, dtype=dtype, like=like)
+
+
+_identity_with_like = array_function_dispatch(
+ _identity_dispatcher
+)(identity)
def _allclose_dispatcher(a, b, rtol=None, atol=None, equal_nan=None):
``allclose(a, b)`` to evaluate to True. The same is true for
`equal` but not `array_equal`.
+ `allclose` is not defined for non-numeric data types.
+
Examples
--------
>>> np.allclose([1e10,1e-7], [1.00001e10,1e-8])
See Also
--------
allclose
+ math.isclose
Notes
-----
`atol` should be carefully selected for the use case at hand. A zero value
for `atol` will result in `False` if either `a` or `b` is zero.
+ `isclose` is not defined for non-numeric data types.
+
Examples
--------
>>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
--- /dev/null
+import sys
+from typing import (
+ Any,
+ Optional,
+ Union,
+ Sequence,
+ Tuple,
+ Callable,
+ List,
+ overload,
+ TypeVar,
+ Iterable,
+)
+
+from numpy import ndarray, generic, dtype, bool_, signedinteger, _OrderKACF, _OrderCF
+from numpy.typing import ArrayLike, DTypeLike, _ShapeLike
+
+if sys.version_info >= (3, 8):
+ from typing import Literal
+else:
+ from typing_extensions import Literal
+
+_T = TypeVar("_T")
+_ArrayType = TypeVar("_ArrayType", bound=ndarray)
+
+_CorrelateMode = Literal["valid", "same", "full"]
+
+@overload
+def zeros_like(
+ a: _ArrayType,
+ dtype: None = ...,
+ order: _OrderKACF = ...,
+ subok: Literal[True] = ...,
+ shape: None = ...,
+) -> _ArrayType: ...
+@overload
+def zeros_like(
+ a: ArrayLike,
+ dtype: DTypeLike = ...,
+ order: _OrderKACF = ...,
+ subok: bool = ...,
+ shape: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+def ones(
+ shape: _ShapeLike,
+ dtype: DTypeLike = ...,
+ order: _OrderCF = ...,
+ *,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+@overload
+def ones_like(
+ a: _ArrayType,
+ dtype: None = ...,
+ order: _OrderKACF = ...,
+ subok: Literal[True] = ...,
+ shape: None = ...,
+) -> _ArrayType: ...
+@overload
+def ones_like(
+ a: ArrayLike,
+ dtype: DTypeLike = ...,
+ order: _OrderKACF = ...,
+ subok: bool = ...,
+ shape: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+@overload
+def empty_like(
+ a: _ArrayType,
+ dtype: None = ...,
+ order: _OrderKACF = ...,
+ subok: Literal[True] = ...,
+ shape: None = ...,
+) -> _ArrayType: ...
+@overload
+def empty_like(
+ a: ArrayLike,
+ dtype: DTypeLike = ...,
+ order: _OrderKACF = ...,
+ subok: bool = ...,
+ shape: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+def full(
+ shape: _ShapeLike,
+ fill_value: Any,
+ dtype: DTypeLike = ...,
+ order: _OrderCF = ...,
+ *,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+@overload
+def full_like(
+ a: _ArrayType,
+ fill_value: Any,
+ dtype: None = ...,
+ order: _OrderKACF = ...,
+ subok: Literal[True] = ...,
+ shape: None = ...,
+) -> _ArrayType: ...
+@overload
+def full_like(
+ a: ArrayLike,
+ fill_value: Any,
+ dtype: DTypeLike = ...,
+ order: _OrderKACF = ...,
+ subok: bool = ...,
+ shape: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+@overload
+def count_nonzero(
+ a: ArrayLike, axis: None = ..., *, keepdims: Literal[False] = ...
+) -> int: ...
+@overload
+def count_nonzero(
+ a: ArrayLike, axis: _ShapeLike = ..., *, keepdims: bool = ...
+) -> Union[signedinteger[Any], ndarray]: ... # TODO: np.intp
+def isfortran(a: Union[ndarray, generic]) -> bool: ...
+def argwhere(a: ArrayLike) -> ndarray: ...
+def flatnonzero(a: ArrayLike) -> ndarray: ...
+def correlate(a: ArrayLike, v: ArrayLike, mode: _CorrelateMode = ...) -> ndarray: ...
+def convolve(a: ArrayLike, v: ArrayLike, mode: _CorrelateMode = ...) -> ndarray: ...
+@overload
+def outer(a: ArrayLike, b: ArrayLike, out: None = ...) -> ndarray: ...
+@overload
+def outer(a: ArrayLike, b: ArrayLike, out: _ArrayType = ...) -> _ArrayType: ...
+def tensordot(
+ a: ArrayLike,
+ b: ArrayLike,
+ axes: Union[int, Tuple[_ShapeLike, _ShapeLike]] = ...,
+) -> ndarray: ...
+def roll(
+ a: ArrayLike,
+ shift: _ShapeLike,
+ axis: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+def rollaxis(a: ndarray, axis: int, start: int = ...) -> ndarray: ...
+def moveaxis(
+ a: ndarray,
+ source: _ShapeLike,
+ destination: _ShapeLike,
+) -> ndarray: ...
+def cross(
+ a: ArrayLike,
+ b: ArrayLike,
+ axisa: int = ...,
+ axisb: int = ...,
+ axisc: int = ...,
+ axis: Optional[int] = ...,
+) -> ndarray: ...
+@overload
+def indices(
+ dimensions: Sequence[int],
+ dtype: DTypeLike = ...,
+ sparse: Literal[False] = ...,
+) -> ndarray: ...
+@overload
+def indices(
+ dimensions: Sequence[int],
+ dtype: DTypeLike = ...,
+ sparse: Literal[True] = ...,
+) -> Tuple[ndarray, ...]: ...
+def fromfunction(
+ function: Callable[..., _T],
+ shape: Sequence[int],
+ *,
+ dtype: DTypeLike = ...,
+ like: ArrayLike = ...,
+ **kwargs: Any,
+) -> _T: ...
+def isscalar(element: Any) -> bool: ...
+def binary_repr(num: int, width: Optional[int] = ...) -> str: ...
+def base_repr(number: int, base: int = ..., padding: int = ...) -> str: ...
+def identity(n: int, dtype: DTypeLike = ..., *, like: ArrayLike = ...) -> ndarray: ...
+def allclose(
+ a: ArrayLike,
+ b: ArrayLike,
+ rtol: float = ...,
+ atol: float = ...,
+ equal_nan: bool = ...,
+) -> bool: ...
+def isclose(
+ a: ArrayLike,
+ b: ArrayLike,
+ rtol: float = ...,
+ atol: float = ...,
+ equal_nan: bool = ...,
+) -> Union[bool_, ndarray]: ...
+def array_equal(a1: ArrayLike, a2: ArrayLike) -> bool: ...
+def array_equiv(a1: ArrayLike, a2: ArrayLike) -> bool: ...
from numpy.core.overrides import set_module
# we add more at the bottom
-__all__ = ['sctypeDict', 'sctypeNA', 'typeDict', 'typeNA', 'sctypes',
+__all__ = ['sctypeDict', 'typeDict', 'sctypes',
'ScalarType', 'obj2sctype', 'cast', 'nbytes', 'sctype2char',
'maximum_sctype', 'issctype', 'typecodes', 'find_common_type',
'issubdtype', 'datetime_data', 'datetime_as_string',
from ._type_aliases import (
sctypeDict,
- sctypeNA,
allTypes,
bitname,
sctypes,
@set_module('numpy')
def issubdtype(arg1, arg2):
- """
+ r"""
Returns True if first argument is a typecode lower/equal in type hierarchy.
+ This is like the builtin :func:`issubclass`, but for `dtype`\ s.
+
Parameters
----------
arg1, arg2 : dtype_like
- dtype or string representing a typecode.
+ `dtype` or object coercible to one
Returns
-------
See Also
--------
+ :ref:`arrays.scalars` : Overview of the numpy type hierarchy.
issubsctype, issubclass_
- numpy.core.numerictypes : Overview of numpy type hierarchy.
Examples
--------
- >>> np.issubdtype('S1', np.string_)
+ `issubdtype` can be used to check the type of arrays:
+
+ >>> ints = np.array([1, 2, 3], dtype=np.int32)
+ >>> np.issubdtype(ints.dtype, np.integer)
+ True
+ >>> np.issubdtype(ints.dtype, np.floating)
+ False
+
+ >>> floats = np.array([1, 2, 3], dtype=np.float32)
+ >>> np.issubdtype(floats.dtype, np.integer)
+ False
+ >>> np.issubdtype(floats.dtype, np.floating)
True
+
+ Similar types of different sizes are not subdtypes of each other:
+
>>> np.issubdtype(np.float64, np.float32)
False
+ >>> np.issubdtype(np.float32, np.float64)
+ False
+
+ but both are subtypes of `floating`:
+
+ >>> np.issubdtype(np.float64, np.floating)
+ True
+ >>> np.issubdtype(np.float32, np.floating)
+ True
+
+ For convenience, dtype-like objects are allowed too:
+
+ >>> np.issubdtype('S1', np.string_)
+ True
+ >>> np.issubdtype('i4', np.signedinteger)
+ True
"""
if not issubclass_(arg1, generic):
# backwards compatibility --- deprecated name
typeDict = sctypeDict
-typeNA = sctypeNA
# b -> boolean
# u -> unsigned integer
--- /dev/null
+from typing import TypeVar, Optional, Type, Union, Tuple, Sequence, overload, Any
+
+from numpy import generic, ndarray, dtype
+from numpy.typing import DTypeLike
+
+_DefaultType = TypeVar("_DefaultType")
+
+def maximum_sctype(t: DTypeLike) -> dtype: ...
+def issctype(rep: object) -> bool: ...
+@overload
+def obj2sctype(rep: object) -> Optional[generic]: ...
+@overload
+def obj2sctype(rep: object, default: None) -> Optional[generic]: ...
+@overload
+def obj2sctype(
+ rep: object, default: Type[_DefaultType]
+) -> Union[generic, Type[_DefaultType]]: ...
+def issubclass_(arg1: object, arg2: Union[object, Tuple[object, ...]]) -> bool: ...
+def issubsctype(
+ arg1: Union[ndarray, DTypeLike], arg2: Union[ndarray, DTypeLike]
+) -> bool: ...
+def issubdtype(arg1: DTypeLike, arg2: DTypeLike) -> bool: ...
+def sctype2char(sctype: object) -> str: ...
+def find_common_type(
+ array_types: Sequence[DTypeLike], scalar_types: Sequence[DTypeLike]
+) -> dtype: ...
+
+# TODO: Add annotations for the following objects:
+# typeDict, nbytes, cast, ScalarType & typecodes
ARRAY_FUNCTION_ENABLED = bool(
int(os.environ.get('NUMPY_EXPERIMENTAL_ARRAY_FUNCTION', 1)))
+array_function_like_doc = (
+ """like : array_like
+ Reference object to allow the creation of arrays which are not
+ NumPy arrays. If an array-like passed in as ``like`` supports
+ the ``__array_function__`` protocol, the result will be defined
+ by it. In this case, it ensures the creation of an array object
+ compatible with that passed in via this argument.
+
+ .. note::
+ The ``like`` keyword is an experimental feature pending on
+ acceptance of :ref:`NEP 35 <NEP35>`."""
+)
+
+def set_array_function_like_doc(public_api):
+ if public_api.__doc__ is not None:
+ public_api.__doc__ = public_api.__doc__.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ )
+ return public_api
+
add_docstring(
implement_array_function,
All arguments are required, and can only be passed by position.
- Arguments
- ---------
+ Parameters
+ ----------
implementation : function
Function that implements the operation on NumPy array without
overrides when called like ``implementation(*args, **kwargs)``.
from . import numeric as sb
from . import numerictypes as nt
from numpy.compat import (
- isfileobj, os_fspath, contextlib_nullcontext
+ os_fspath, contextlib_nullcontext
)
from numpy.core.overrides import set_module
from .arrayprint import get_printoptions
See Also
--------
- rec.fromrecords : Construct a record array from data.
+ core.records.fromrecords : Construct a record array from data.
record : fundamental data-type for `recarray`.
format_parser : determine a data-type from formats, names, titles.
fielddict = ndarray.__getattribute__(self, 'dtype').fields
try:
res = fielddict[attr][:2]
- except (TypeError, KeyError):
- raise AttributeError("recarray has no attribute %s" % attr)
+ except (TypeError, KeyError) as e:
+ raise AttributeError("recarray has no attribute %s" % attr) from e
obj = self.getfield(*res)
# At this point obj will always be a recarray, since (see
return ret
try:
res = fielddict[attr][:2]
- except (TypeError, KeyError):
- raise AttributeError("record array has no attribute %s" % attr)
+ except (TypeError, KeyError) as e:
+ raise AttributeError(
+ "record array has no attribute %s" % attr
+ ) from e
return self.setfield(val, *res)
def __getitem__(self, indx):
>>> x1[1]=34
>>> r.a
array([1, 2, 3, 4])
-
+
>>> x1 = np.array([1, 2, 3, 4])
>>> x2 = np.array(['a', 'dd', 'xyz', '12'])
>>> x3 = np.array([1.1, 2, 3,4])
return _array
def get_remaining_size(fd):
+ pos = fd.tell()
try:
- fn = fd.fileno()
- except AttributeError:
- return os.path.getsize(fd.name) - fd.tell()
- st = os.fstat(fn)
- size = st.st_size - fd.tell()
- return size
+ fd.seek(0, 2)
+ return fd.tell() - pos
+ finally:
+ fd.seek(pos, 0)
def fromfile(fd, dtype=None, shape=None, offset=0, formats=None,
names=None, titles=None, aligned=False, byteorder=None):
elif isinstance(shape, int):
shape = (shape,)
- if isfileobj(fd):
+ if hasattr(fd, 'readinto'):
+ # GH issue 2504. fd supports io.RawIOBase or io.BufferedIOBase interface.
+ # Example of fd: gzip, BytesIO, BufferedReader
# file already opened
ctx = contextlib_nullcontext(fd)
else:
def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None,
names=None, titles=None, aligned=False, byteorder=None, copy=True):
- """Construct a record array from a wide-variety of objects.
+ """
+ Construct a record array from a wide-variety of objects.
+
+ A general-purpose record array constructor that dispatches to the
+ appropriate `recarray` creation function based on the inputs (see Notes).
+
+ Parameters
+ ----------
+ obj: any
+ Input object. See Notes for details on how various input types are
+ treated.
+ dtype: data-type, optional
+ Valid dtype for array.
+ shape: int or tuple of ints, optional
+ Shape of each array.
+ offset: int, optional
+ Position in the file or buffer to start reading from.
+ strides: tuple of ints, optional
+ Buffer (`buf`) is interpreted according to these strides (strides
+ define how many bytes each array element, row, column, etc.
+ occupy in memory).
+ formats, names, titles, aligned, byteorder :
+ If `dtype` is ``None``, these arguments are passed to
+ `numpy.format_parser` to construct a dtype. See that function for
+ detailed documentation.
+ copy: bool, optional
+ Whether to copy the input object (True), or to use a reference instead.
+ This option only applies when the input is an ndarray or recarray.
+ Defaults to True.
+
+ Returns
+ -------
+ np.recarray
+ Record array created from the specified object.
+
+ Notes
+ -----
+ If `obj` is ``None``, then call the `~numpy.recarray` constructor. If
+ `obj` is a string, then call the `fromstring` constructor. If `obj` is a
+ list or a tuple, then if the first object is an `~numpy.ndarray`, call
+ `fromarrays`, otherwise call `fromrecords`. If `obj` is a
+ `~numpy.recarray`, then make a copy of the data in the recarray
+ (if ``copy=True``) and use the new formats, names, and titles. If `obj`
+ is a file, then call `fromfile`. Finally, if obj is an `ndarray`, then
+ return ``obj.view(recarray)``, making a copy of the data if ``copy=True``.
+
+ Examples
+ --------
+ >>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
+ array([[1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9]])
+
+ >>> np.core.records.array(a)
+ rec.array([[1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9]],
+ dtype=int32)
+
+ >>> b = [(1, 1), (2, 4), (3, 9)]
+ >>> c = np.core.records.array(b, formats = ['i2', 'f2'], names = ('x', 'y'))
+ >>> c
+ rec.array([(1, 1.0), (2, 4.0), (3, 9.0)],
+ dtype=[('x', '<i2'), ('y', '<f2')])
+
+ >>> c.x
+ rec.array([1, 2, 3], dtype=int16)
+
+ >>> c.y
+ rec.array([ 1.0, 4.0, 9.0], dtype=float16)
+
+ >>> r = np.rec.array(['abc','def'], names=['col1','col2'])
+ >>> print(r.col1)
+ abc
+
+ >>> r.col1
+ array('abc', dtype='<U3')
+
+ >>> r.col2
+ array('def', dtype='<U3')
"""
- if ((isinstance(obj, (type(None), str)) or isfileobj(obj)) and
+ if ((isinstance(obj, (type(None), str)) or hasattr(obj, 'readinto')) and
formats is None and dtype is None):
raise ValueError("Must define formats (or dtype) if object is "
"None, string, or an open file")
new = new.copy()
return new
- elif isfileobj(obj):
+ elif hasattr(obj, 'readinto'):
return fromfile(obj, dtype=dtype, shape=shape, offset=offset)
elif isinstance(obj, ndarray):
from numpy.distutils import log
from distutils.dep_util import newer
-from distutils.sysconfig import get_config_var
-from numpy._build_utils.apple_accelerate import (
- uses_accelerate_framework, get_sgemv_fix
- )
+from sysconfig import get_config_var
from numpy.compat import npy_load_module
from setup_common import * # noqa: F403
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 to True to use the new casting implementation as much as implemented.
+# Allows running the full test suit to exercise the new machinery until
+# it is used as default and the old version is eventually deleted.
+NPY_USE_NEW_CASTINGIMPL = os.environ.get('NPY_USE_NEW_CASTINGIMPL', "0") != "0"
+
# 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
def configuration(parent_package='',top_path=None):
from numpy.distutils.misc_util import Configuration, dot_join
- from numpy.distutils.system_info import get_info
+ from numpy.distutils.system_info import (get_info, blas_opt_info,
+ lapack_opt_info)
+
+ # Accelerate is buggy, disallow it. See also numpy/linalg/setup.py
+ for opt_order in (blas_opt_info.blas_order, lapack_opt_info.lapack_order):
+ if 'accelerate' in opt_order:
+ opt_order.remove('accelerate')
config = Configuration('core', parent_package, top_path)
local_dir = config.local_path
if NPY_RELAXED_STRIDES_DEBUG:
moredefs.append(('NPY_RELAXED_STRIDES_DEBUG', 1))
+ # Use the new experimental casting implementation in NumPy 1.20:
+ if NPY_USE_NEW_CASTINGIMPL:
+ moredefs.append(('NPY_USE_NEW_CASTINGIMPL', 1))
+
# Get long double representation
rep = check_long_double_representation(config_cmd)
moredefs.append(('HAVE_LDOUBLE_%s' % rep, 1))
config.add_include_dirs(join('src', 'multiarray'))
config.add_include_dirs(join('src', 'umath'))
config.add_include_dirs(join('src', 'npysort'))
+ config.add_include_dirs(join('src', '_simd'))
config.add_define_macros([("NPY_INTERNAL_BUILD", "1")]) # this macro indicates that Numpy build is in process
config.add_define_macros([("HAVE_NPY_CONFIG_H", "1")])
config.add_npy_pkg_config("mlib.ini.in", "lib/npy-pkg-config",
subst_dict)
- #######################################################################
- # npysort library #
- #######################################################################
-
- # This library is created for the build but it is not installed
- npysort_sources = [join('src', 'common', 'npy_sort.h.src'),
- join('src', 'npysort', 'quicksort.c.src'),
- join('src', 'npysort', 'mergesort.c.src'),
- join('src', 'npysort', 'timsort.c.src'),
- join('src', 'npysort', 'heapsort.c.src'),
- join('src', 'npysort', 'radixsort.c.src'),
- join('src', 'common', 'npy_partition.h.src'),
- join('src', 'npysort', 'selection.c.src'),
- join('src', 'common', 'npy_binsearch.h.src'),
- join('src', 'npysort', 'binsearch.c.src'),
- ]
- config.add_library('npysort',
- sources=npysort_sources,
- include_dirs=[])
-
#######################################################################
# multiarray_tests module #
#######################################################################
join('src', 'common', 'ufunc_override.h'),
join('src', 'common', 'umathmodule.h'),
join('src', 'common', 'numpyos.h'),
+ join('src', 'common', 'npy_cpu_dispatch.h'),
+ join('src', 'common', 'simd', 'simd.h'),
]
common_src = [
common_src.extend([join('src', 'common', 'cblasfuncs.c'),
join('src', 'common', 'python_xerbla.c'),
])
- if uses_accelerate_framework(blas_info):
- common_src.extend(get_sgemv_fix())
else:
extra_info = {}
#######################################################################
multiarray_deps = [
+ join('src', 'multiarray', 'abstractdtypes.h'),
join('src', 'multiarray', 'arrayobject.h'),
join('src', 'multiarray', 'arraytypes.h'),
join('src', 'multiarray', 'arrayfunction_override.h'),
+ join('src', 'multiarray', 'array_coercion.h'),
+ join('src', 'multiarray', 'array_method.h'),
join('src', 'multiarray', 'npy_buffer.h'),
join('src', 'multiarray', 'calculation.h'),
join('src', 'multiarray', 'common.h'),
join('src', 'multiarray', 'conversion_utils.h'),
join('src', 'multiarray', 'ctors.h'),
join('src', 'multiarray', 'descriptor.h'),
+ join('src', 'multiarray', 'dtypemeta.h'),
join('src', 'multiarray', 'dragon4.h'),
+ join('src', 'multiarray', 'einsum_debug.h'),
+ join('src', 'multiarray', 'einsum_sumprod.h'),
join('src', 'multiarray', 'getset.h'),
join('src', 'multiarray', 'hashdescr.h'),
join('src', 'multiarray', 'iterators.h'),
+ join('src', 'multiarray', 'legacy_dtype_implementation.h'),
join('src', 'multiarray', 'mapping.h'),
join('src', 'multiarray', 'methods.h'),
join('src', 'multiarray', 'multiarraymodule.h'),
join('include', 'numpy', 'npy_1_7_deprecated_api.h'),
# add library sources as distuils does not consider libraries
# dependencies
- ] + npysort_sources + npymath_sources
+ ] + npymath_sources
multiarray_src = [
+ join('src', 'multiarray', 'abstractdtypes.c'),
join('src', 'multiarray', 'alloc.c'),
join('src', 'multiarray', 'arrayobject.c'),
join('src', 'multiarray', 'arraytypes.c.src'),
+ join('src', 'multiarray', 'array_coercion.c'),
+ join('src', 'multiarray', 'array_method.c'),
join('src', 'multiarray', 'array_assign_scalar.c'),
join('src', 'multiarray', 'array_assign_array.c'),
join('src', 'multiarray', 'arrayfunction_override.c'),
join('src', 'multiarray', 'datetime_busday.c'),
join('src', 'multiarray', 'datetime_busdaycal.c'),
join('src', 'multiarray', 'descriptor.c'),
+ join('src', 'multiarray', 'dtypemeta.c'),
join('src', 'multiarray', 'dragon4.c'),
join('src', 'multiarray', 'dtype_transfer.c'),
join('src', 'multiarray', 'einsum.c.src'),
+ join('src', 'multiarray', 'einsum_sumprod.c.src'),
join('src', 'multiarray', 'flagsobject.c'),
join('src', 'multiarray', 'getset.c'),
join('src', 'multiarray', 'hashdescr.c'),
join('src', 'multiarray', 'item_selection.c'),
join('src', 'multiarray', 'iterators.c'),
+ join('src', 'multiarray', 'legacy_dtype_implementation.c'),
join('src', 'multiarray', 'lowlevel_strided_loops.c.src'),
join('src', 'multiarray', 'mapping.c'),
join('src', 'multiarray', 'methods.c'),
join('src', 'multiarray', 'typeinfo.c'),
join('src', 'multiarray', 'usertypes.c'),
join('src', 'multiarray', 'vdot.c'),
+ join('src', 'common', 'npy_sort.h.src'),
+ join('src', 'npysort', 'quicksort.c.src'),
+ join('src', 'npysort', 'mergesort.c.src'),
+ join('src', 'npysort', 'timsort.c.src'),
+ join('src', 'npysort', 'heapsort.c.src'),
+ join('src', 'npysort', 'radixsort.c.src'),
+ join('src', 'common', 'npy_partition.h.src'),
+ join('src', 'npysort', 'selection.c.src'),
+ join('src', 'common', 'npy_binsearch.h.src'),
+ join('src', 'npysort', 'binsearch.c.src'),
]
#######################################################################
join('src', 'umath', 'simd.inc.src'),
join('src', 'umath', 'loops.h.src'),
join('src', 'umath', 'loops.c.src'),
+ join('src', 'umath', 'loops_unary_fp.dispatch.c.src'),
join('src', 'umath', 'matmul.h.src'),
join('src', 'umath', 'matmul.c.src'),
join('src', 'umath', 'clip.h.src'),
config.add_extension('_multiarray_umath',
sources=multiarray_src + umath_src +
- npymath_sources + common_src +
+ common_src +
[generate_config_h,
generate_numpyconfig_h,
generate_numpy_api,
],
depends=deps + multiarray_deps + umath_deps +
common_deps,
- libraries=['npymath', 'npysort'],
+ libraries=['npymath'],
extra_info=extra_info)
#######################################################################
# umath_tests module #
#######################################################################
- config.add_extension('_umath_tests',
- sources=[join('src', 'umath', '_umath_tests.c.src')])
+ config.add_extension('_umath_tests', sources=[
+ join('src', 'umath', '_umath_tests.c.src'),
+ join('src', 'umath', '_umath_tests.dispatch.c'),
+ join('src', 'common', 'npy_cpu_features.c.src'),
+ ])
#######################################################################
# custom rational dtype module #
config.add_extension('_operand_flag_tests',
sources=[join('src', 'umath', '_operand_flag_tests.c.src')])
+ #######################################################################
+ # SIMD module #
+ #######################################################################
+
+ config.add_extension('_simd', sources=[
+ join('src', 'common', 'npy_cpu_features.c.src'),
+ join('src', '_simd', '_simd.c'),
+ join('src', '_simd', '_simd_inc.h.src'),
+ join('src', '_simd', '_simd_data.inc.src'),
+ join('src', '_simd', '_simd.dispatch.c.src'),
+ ], depends=[
+ join('src', 'common', 'npy_cpu_dispatch.h'),
+ join('src', 'common', 'simd', 'simd.h'),
+ join('src', '_simd', '_simd.h'),
+ join('src', '_simd', '_simd_inc.h.src'),
+ join('src', '_simd', '_simd_data.inc.src'),
+ join('src', '_simd', '_simd_arg.inc'),
+ join('src', '_simd', '_simd_convert.inc'),
+ join('src', '_simd', '_simd_easyintrin.inc'),
+ join('src', '_simd', '_simd_vector.inc'),
+ ])
+
config.add_subpackage('tests')
config.add_data_dir('tests/data')
+ config.add_data_dir('tests/examples')
+ config.add_data_files('*.pyi')
config.make_svn_version_py()
# 0x0000000c - 1.14.x
# 0x0000000c - 1.15.x
# 0x0000000d - 1.16.x
-C_API_VERSION = 0x0000000d
+# 0x0000000d - 1.19.x
+# 0x0000000e - 1.20.x
+C_API_VERSION = 0x0000000e
class MismatchCAPIWarning(Warning):
pass
"stdio.h", "LINK_AVX2"),
("__asm__ volatile", '"vpaddd %zmm1, %zmm2, %zmm3"',
"stdio.h", "LINK_AVX512F"),
+ ("__asm__ volatile", '"vfpclasspd $0x40, %zmm15, %k6\\n"\
+ "vmovdqu8 %xmm0, %xmm1\\n"\
+ "vpbroadcastmb2q %k0, %xmm0\\n"',
+ "stdio.h", "LINK_AVX512_SKX"),
("__asm__ volatile", '"xgetbv"', "stdio.h", "XGETBV"),
]
'attribute_target_avx2'),
('__attribute__((target ("avx512f")))',
'attribute_target_avx512f'),
+ ('__attribute__((target ("avx512f,avx512dq,avx512bw,avx512vl,avx512cd")))',
+ 'attribute_target_avx512_skx'),
]
# function attributes with intrinsics
# gcc 4.8.4 support attributes but not with intrisics
# tested via "#include<%s> int %s %s(void *){code; return 0;};" % (header, attribute, name, code)
# function name will be converted to HAVE_<upper-case-name> preprocessor macro
+# The _mm512_castps_si512 instruction is specific check for AVX-512F support
+# in gcc-4.9 which is missing a subset of intrinsics. See
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61878
OPTIONAL_FUNCTION_ATTRIBUTES_WITH_INTRINSICS = [('__attribute__((target("avx2,fma")))',
'attribute_target_avx2_with_intrinsics',
'__m256 temp = _mm256_set1_ps(1.0); temp = \
'immintrin.h'),
('__attribute__((target("avx512f")))',
'attribute_target_avx512f_with_intrinsics',
- '__m512 temp = _mm512_set1_ps(1.0)',
+ '__m512i temp = _mm512_castps_si512(_mm512_set1_ps(1.0))',
+ 'immintrin.h'),
+ ('__attribute__((target ("avx512f,avx512dq,avx512bw,avx512vl,avx512cd")))',
+ 'attribute_target_avx512_skx_with_intrinsics',
+ '__mmask8 temp = _mm512_fpclass_pd_mask(_mm512_set1_pd(1.0), 0x01);\
+ __m512i temp = _mm512_castps_si512(_mm512_set1_ps(1.0));\
+ _mm_mask_storeu_epi8(NULL, 0xFF, _mm_broadcastmb_epi64(temp))',
'immintrin.h'),
]
def _concatenate_shapes(shapes, axis):
"""Given array shapes, return the resulting shape and slices prefixes.
- These help in nested concatation.
+ These help in nested concatenation.
+
Returns
-------
shape: tuple of int
--- /dev/null
+import sys
+from typing import TypeVar, overload, List, Sequence
+
+from numpy import ndarray
+from numpy.typing import ArrayLike
+
+if sys.version_info >= (3, 8):
+ from typing import SupportsIndex
+else:
+ from typing_extensions import Protocol
+ class SupportsIndex(Protocol):
+ def __index__(self) -> int: ...
+
+_ArrayType = TypeVar("_ArrayType", bound=ndarray)
+
+@overload
+def atleast_1d(__arys: ArrayLike) -> ndarray: ...
+@overload
+def atleast_1d(*arys: ArrayLike) -> List[ndarray]: ...
+
+@overload
+def atleast_2d(__arys: ArrayLike) -> ndarray: ...
+@overload
+def atleast_2d(*arys: ArrayLike) -> List[ndarray]: ...
+
+@overload
+def atleast_3d(__arys: ArrayLike) -> ndarray: ...
+@overload
+def atleast_3d(*arys: ArrayLike) -> List[ndarray]: ...
+
+def vstack(tup: Sequence[ArrayLike]) -> ndarray: ...
+def hstack(tup: Sequence[ArrayLike]) -> ndarray: ...
+@overload
+def stack(
+ arrays: Sequence[ArrayLike], axis: SupportsIndex = ..., out: None = ...
+) -> ndarray: ...
+@overload
+def stack(
+ arrays: Sequence[ArrayLike], axis: SupportsIndex = ..., out: _ArrayType = ...
+) -> _ArrayType: ...
+def block(arrays: ArrayLike) -> ndarray: ...
--- /dev/null
+#include "_simd.h"
+
+PyMODINIT_FUNC PyInit__simd(void)
+{
+ static struct PyModuleDef defs = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "numpy.core._simd",
+ .m_size = -1
+ };
+ if (npy_cpu_init() < 0) {
+ return NULL;
+ }
+ PyObject *m = PyModule_Create(&defs);
+ if (m == NULL) {
+ return NULL;
+ }
+ PyObject *targets = PyDict_New();
+ if (targets == NULL) {
+ goto err;
+ }
+ if (PyModule_AddObject(m, "targets", targets) < 0) {
+ Py_DECREF(targets);
+ goto err;
+ }
+ // add keys for non-supported optimizations with None value
+ #define ATTACH_MODULE(TESTED_FEATURES, TARGET_NAME, MAKE_MSVC_HAPPY) \
+ { \
+ PyObject *simd_mod; \
+ if (!TESTED_FEATURES) { \
+ Py_INCREF(Py_None); \
+ simd_mod = Py_None; \
+ } else { \
+ simd_mod = NPY_CAT(simd_create_module_, TARGET_NAME)(); \
+ if (simd_mod == NULL) { \
+ goto err; \
+ } \
+ } \
+ const char *target_name = NPY_TOSTRING(TARGET_NAME); \
+ if (PyDict_SetItemString(targets, target_name, simd_mod) < 0) { \
+ Py_DECREF(simd_mod); \
+ goto err; \
+ } \
+ Py_INCREF(simd_mod); \
+ if (PyModule_AddObject(m, target_name, simd_mod) < 0) { \
+ Py_DECREF(simd_mod); \
+ goto err; \
+ } \
+ }
+
+ #define ATTACH_BASELINE_MODULE(MAKE_MSVC_HAPPY) \
+ { \
+ PyObject *simd_mod = simd_create_module(); \
+ if (simd_mod == NULL) { \
+ goto err; \
+ } \
+ if (PyDict_SetItemString(targets, "baseline", simd_mod) < 0) { \
+ Py_DECREF(simd_mod); \
+ goto err; \
+ } \
+ Py_INCREF(simd_mod); \
+ if (PyModule_AddObject(m, "baseline", simd_mod) < 0) { \
+ Py_DECREF(simd_mod); \
+ goto err; \
+ } \
+ }
+
+ NPY__CPU_DISPATCH_CALL(NPY_CPU_HAVE, ATTACH_MODULE, MAKE_MSVC_HAPPY)
+ NPY__CPU_DISPATCH_BASELINE_CALL(ATTACH_BASELINE_MODULE, MAKE_MSVC_HAPPY)
+ return m;
+err:
+ Py_DECREF(m);
+ return NULL;
+}
--- /dev/null
+/*@targets $werror #simd_test*/
+#include "_simd.h"
+#include "_simd_inc.h"
+
+#if NPY_SIMD
+#include "_simd_data.inc"
+#include "_simd_convert.inc"
+#include "_simd_vector.inc"
+#include "_simd_arg.inc"
+#include "_simd_easyintrin.inc"
+
+/*************************************************************************
+ * Defining NPYV intrinsics as module functions
+ *************************************************************************/
+/**begin repeat
+ * #sfx = u8, s8, u16, s16, u32, s32, u64, s64, f32, f64#
+ * #bsfx = b8, b8, b16, b16, b32, b32, b64, b64, b32, b64#
+ * #simd_sup = 1, 1, 1, 1, 1, 1, 1, 1, 1, NPY_SIMD_F64#
+ * #fp_only = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #sat_sup = 1, 1, 1, 1, 0, 0, 0, 0, 0, 0#
+ * #mul_sup = 1, 1, 1, 1, 1, 1, 0, 0, 1, 1#
+ * #div_sup = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #fused_sup = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #sum_sup = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #ncont_sup = 0, 0, 0, 0, 1, 1, 1, 1, 1, 1#
+ * #shl_imm = 0, 0, 15, 15, 31, 31, 63, 63, 0, 0#
+ * #shr_imm = 0, 0, 16, 16, 32, 32, 64, 64, 0, 0#
+ */
+#if @simd_sup@
+/***************************
+ * Memory
+ ***************************/
+/**begin repeat1
+ * # intrin = load, loada, loads, loadl#
+ */
+SIMD_IMPL_INTRIN_1(@intrin@_@sfx@, v@sfx@, q@sfx@)
+/**end repeat1**/
+/**begin repeat1
+ * # intrin = store, storea, stores, storel, storeh#
+ */
+// special definition due to the nature of @intrin@
+static PyObject *
+simd__intrin_@intrin@_@sfx@(PyObject* NPY_UNUSED(self), PyObject *args)
+{
+ simd_arg seq_arg = {.dtype = simd_data_q@sfx@};
+ simd_arg vec_arg = {.dtype = simd_data_v@sfx@};
+ if (!PyArg_ParseTuple(
+ args, "O&O&:@intrin@_@sfx@",
+ simd_arg_converter, &seq_arg,
+ simd_arg_converter, &vec_arg
+ )) {
+ return NULL;
+ }
+ npyv_@intrin@_@sfx@(seq_arg.data.q@sfx@, vec_arg.data.v@sfx@);
+ // write-back
+ if (simd_sequence_fill_iterable(seq_arg.obj, seq_arg.data.q@sfx@, simd_data_q@sfx@)) {
+ simd_arg_free(&seq_arg);
+ return NULL;
+ }
+ simd_arg_free(&seq_arg);
+ Py_RETURN_NONE;
+}
+/**end repeat1**/
+
+/****************************************
+ * Non-contiguous/Partial Memory access
+ ****************************************/
+#if @ncont_sup@
+// Partial Load
+SIMD_IMPL_INTRIN_3(load_till_@sfx@, v@sfx@, q@sfx@, u32, @sfx@)
+SIMD_IMPL_INTRIN_2(load_tillz_@sfx@, v@sfx@, q@sfx@, u32)
+
+// Partial Store
+static PyObject *
+simd__intrin_store_till_@sfx@(PyObject* NPY_UNUSED(self), PyObject *args)
+{
+ simd_arg seq_arg = {.dtype = simd_data_q@sfx@};
+ simd_arg nlane_arg = {.dtype = simd_data_u32};
+ simd_arg vec_arg = {.dtype = simd_data_v@sfx@};
+ if (!PyArg_ParseTuple(
+ args, "O&O&O&:store_till_@sfx@",
+ simd_arg_converter, &seq_arg,
+ simd_arg_converter, &nlane_arg,
+ simd_arg_converter, &vec_arg
+ )) {
+ return NULL;
+ }
+ npyv_store_till_@sfx@(
+ seq_arg.data.q@sfx@, nlane_arg.data.u32, vec_arg.data.v@sfx@
+ );
+ // write-back
+ if (simd_sequence_fill_iterable(seq_arg.obj, seq_arg.data.q@sfx@, simd_data_q@sfx@)) {
+ simd_arg_free(&seq_arg);
+ return NULL;
+ }
+ simd_arg_free(&seq_arg);
+ Py_RETURN_NONE;
+}
+
+// Non-contiguous Load
+/**begin repeat1
+ * #intrin = loadn, loadn_till, loadn_tillz#
+ * #till = 0, 1, 1#
+ * #fill = 0, 1, 0#
+ * #format = , O&O&, O&#
+ */
+static PyObject *
+simd__intrin_@intrin@_@sfx@(PyObject* NPY_UNUSED(self), PyObject *args)
+{
+ simd_arg seq_arg = {.dtype = simd_data_q@sfx@};
+ simd_arg stride_arg = {.dtype = simd_data_s64};
+#if @till@
+ simd_arg nlane_arg = {.dtype = simd_data_u32};
+#endif // till
+#if @fill@
+ simd_arg fill_arg = {.dtype = simd_data_@sfx@};
+#endif
+ if (!PyArg_ParseTuple(
+ args, "@format@O&O&:@intrin@_@sfx@",
+ simd_arg_converter, &seq_arg,
+ simd_arg_converter, &stride_arg
+#if @till@
+ ,simd_arg_converter, &nlane_arg
+#endif
+#if @fill@
+ ,simd_arg_converter, &fill_arg
+#endif
+ )) {
+ return NULL;
+ }
+ npyv_lanetype_@sfx@ *seq_ptr = seq_arg.data.q@sfx@;
+ npy_intp stride = (npy_intp)stride_arg.data.s64;
+ Py_ssize_t cur_seq_len = simd_sequence_len(seq_ptr);
+ Py_ssize_t min_seq_len = stride * npyv_nlanes_@sfx@;
+ if (stride < 0) {
+ seq_ptr += cur_seq_len -1;
+ min_seq_len = -min_seq_len;
+ }
+ if (cur_seq_len < min_seq_len) {
+ PyErr_Format(PyExc_ValueError,
+ "@intrin@_@sfx@(), according to provided stride %d, the "
+ "minimum acceptable size of the required sequence is %d, given(%d)",
+ stride, min_seq_len, cur_seq_len
+ );
+ goto err;
+ }
+ npyv_@sfx@ rvec = npyv_@intrin@_@sfx@(
+ seq_ptr, stride
+ #if @till@
+ , nlane_arg.data.u32
+ #endif
+ #if @fill@
+ , fill_arg.data.@sfx@
+ #endif
+ );
+ simd_arg ret = {
+ .dtype = simd_data_v@sfx@, .data = {.v@sfx@=rvec}
+ };
+ simd_arg_free(&seq_arg);
+ return simd_arg_to_obj(&ret);
+err:
+ simd_arg_free(&seq_arg);
+ return NULL;
+}
+/**end repeat1**/
+
+// Non-contiguous Store
+/**begin repeat1
+ * #intrin = storen, storen_till#
+ * #till = 0, 1#
+ * #format = , O&#
+ */
+static PyObject *
+simd__intrin_@intrin@_@sfx@(PyObject* NPY_UNUSED(self), PyObject *args)
+{
+ simd_arg seq_arg = {.dtype = simd_data_q@sfx@};
+ simd_arg stride_arg = {.dtype = simd_data_s64};
+ simd_arg vec_arg = {.dtype = simd_data_v@sfx@};
+#if @till@
+ simd_arg nlane_arg = {.dtype = simd_data_u32};
+#endif
+ if (!PyArg_ParseTuple(
+ args, "@format@O&O&O&:storen_@sfx@",
+ simd_arg_converter, &seq_arg,
+ simd_arg_converter, &stride_arg
+#if @till@
+ ,simd_arg_converter, &nlane_arg
+#endif
+ ,simd_arg_converter, &vec_arg
+ )) {
+ return NULL;
+ }
+ npyv_lanetype_@sfx@ *seq_ptr = seq_arg.data.q@sfx@;
+ npy_intp stride = (npy_intp)stride_arg.data.s64;
+ Py_ssize_t cur_seq_len = simd_sequence_len(seq_ptr);
+ Py_ssize_t min_seq_len = stride * npyv_nlanes_@sfx@;
+ if (stride < 0) {
+ seq_ptr += cur_seq_len -1;
+ min_seq_len = -min_seq_len;
+ }
+ // overflow guard
+ if (cur_seq_len < min_seq_len) {
+ PyErr_Format(PyExc_ValueError,
+ "@intrin@_@sfx@(), according to provided stride %d, the"
+ "minimum acceptable size of the required sequence is %d, given(%d)",
+ stride, min_seq_len, cur_seq_len
+ );
+ goto err;
+ }
+ npyv_@intrin@_@sfx@(
+ seq_ptr, stride
+ #if @till@
+ ,nlane_arg.data.u32
+ #endif
+ ,vec_arg.data.v@sfx@
+ );
+ // write-back
+ if (simd_sequence_fill_iterable(seq_arg.obj, seq_arg.data.q@sfx@, simd_data_q@sfx@)) {
+ goto err;
+ }
+ simd_arg_free(&seq_arg);
+ Py_RETURN_NONE;
+err:
+ simd_arg_free(&seq_arg);
+ return NULL;
+}
+/**end repeat1**/
+#endif // @ncont_sup@
+
+
+/***************************
+ * Misc
+ ***************************/
+SIMD_IMPL_INTRIN_0(zero_@sfx@, v@sfx@)
+SIMD_IMPL_INTRIN_1(setall_@sfx@, v@sfx@, @sfx@)
+SIMD_IMPL_INTRIN_3(select_@sfx@, v@sfx@, v@bsfx@, v@sfx@, v@sfx@)
+
+/**begin repeat1
+ * #sfx_to = u8, s8, u16, s16, u32, s32, u64, s64, f32, f64#
+ * #simd_sup2 = 1, 1, 1, 1, 1, 1, 1, 1, 1, NPY_SIMD_F64#
+ */
+#if @simd_sup2@
+SIMD_IMPL_INTRIN_1(reinterpret_@sfx_to@_@sfx@, v@sfx_to@, v@sfx@)
+#endif // simd_sup2
+/**end repeat1**/
+
+/**
+ * special definition due to the nature of intrinsics
+ * npyv_setf_@sfx@ and npy_set_@sfx@.
+*/
+/**begin repeat1
+ * #intrin = setf, set#
+ */
+static PyObject *
+simd__intrin_@intrin@_@sfx@(PyObject* NPY_UNUSED(self), PyObject *args)
+{
+ npyv_lanetype_@sfx@ *data = simd_sequence_from_iterable(args, simd_data_q@sfx@, npyv_nlanes_@sfx@);
+ if (data == NULL) {
+ return NULL;
+ }
+ simd_data r = {.v@sfx@ = npyv_@intrin@_@sfx@(
+ data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
+ data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
+ data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23],
+ data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31],
+ data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39],
+ data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47],
+ data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55],
+ data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63],
+ data[64] // for setf
+ )};
+ simd_sequence_free(data);
+ return (PyObject*)PySIMDVector_FromData(r, simd_data_v@sfx@);
+}
+/**end repeat1**/
+
+/***************************
+ * Reorder
+ ***************************/
+/**begin repeat1
+ * # intrin = combinel, combineh#
+ */
+SIMD_IMPL_INTRIN_2(@intrin@_@sfx@, v@sfx@, v@sfx@, v@sfx@)
+/**end repeat1**/
+
+/**begin repeat1
+ * # intrin = combine, zip#
+ */
+SIMD_IMPL_INTRIN_2(@intrin@_@sfx@, v@sfx@x2, v@sfx@, v@sfx@)
+/**end repeat1**/
+
+/***************************
+ * Operators
+ ***************************/
+#if @shl_imm@ > 0
+SIMD_IMPL_INTRIN_2(shl_@sfx@, v@sfx@, v@sfx@, u8)
+SIMD_IMPL_INTRIN_2(shr_@sfx@, v@sfx@, v@sfx@, u8)
+// immediate constant
+SIMD_IMPL_INTRIN_2IMM(shli_@sfx@, v@sfx@, v@sfx@, @shl_imm@)
+SIMD_IMPL_INTRIN_2IMM(shri_@sfx@, v@sfx@, v@sfx@, @shr_imm@)
+#endif // shl_imm
+
+/**begin repeat1
+ * #intrin = and, or, xor#
+ */
+SIMD_IMPL_INTRIN_2(@intrin@_@sfx@, v@sfx@, v@sfx@, v@sfx@)
+/**end repeat1**/
+
+SIMD_IMPL_INTRIN_1(not_@sfx@, v@sfx@, v@sfx@)
+
+/**begin repeat1
+ * #intrin = cmpeq, cmpneq, cmpgt, cmpge, cmplt, cmple#
+ */
+SIMD_IMPL_INTRIN_2(@intrin@_@sfx@, v@bsfx@, v@sfx@, v@sfx@)
+/**end repeat1**/
+
+/***************************
+ * Conversion
+ ***************************/
+SIMD_IMPL_INTRIN_1(cvt_@sfx@_@bsfx@, v@sfx@, v@bsfx@)
+SIMD_IMPL_INTRIN_1(cvt_@bsfx@_@sfx@, v@bsfx@, v@sfx@)
+
+/***************************
+ * Arithmetic
+ ***************************/
+/**begin repeat1
+ * #intrin = add, sub#
+ */
+SIMD_IMPL_INTRIN_2(@intrin@_@sfx@, v@sfx@, v@sfx@, v@sfx@)
+/**end repeat1**/
+
+#if @sat_sup@
+/**begin repeat1
+ * #intrin = adds, subs#
+ */
+SIMD_IMPL_INTRIN_2(@intrin@_@sfx@, v@sfx@, v@sfx@, v@sfx@)
+/**end repeat1**/
+#endif // sat_sup
+
+#if @mul_sup@
+SIMD_IMPL_INTRIN_2(mul_@sfx@, v@sfx@, v@sfx@, v@sfx@)
+#endif // mul_sup
+
+#if @div_sup@
+SIMD_IMPL_INTRIN_2(div_@sfx@, v@sfx@, v@sfx@, v@sfx@)
+#endif // div_sup
+
+#if @fused_sup@
+/**begin repeat1
+ * #intrin = muladd, mulsub, nmuladd, nmulsub#
+ */
+SIMD_IMPL_INTRIN_3(@intrin@_@sfx@, v@sfx@, v@sfx@, v@sfx@, v@sfx@)
+/**end repeat1**/
+#endif // fused_sup
+
+#if @sum_sup@
+SIMD_IMPL_INTRIN_1(sum_@sfx@, @sfx@, v@sfx@)
+#endif // sum_sup
+
+/***************************
+ * Math
+ ***************************/
+#if @fp_only@
+/**begin repeat1
+ * #intrin = sqrt, recip, abs, square#
+ */
+SIMD_IMPL_INTRIN_1(@intrin@_@sfx@, v@sfx@, v@sfx@)
+/**end repeat1**/
+#endif
+
+#endif // simd_sup
+/**end repeat**/
+/***************************
+ * Variant
+ ***************************/
+SIMD_IMPL_INTRIN_0N(cleanup)
+
+/*************************************************************************
+ * Attach module functions
+ *************************************************************************/
+static PyMethodDef simd__intrinsics_methods[] = {
+/**begin repeat
+ * #sfx = u8, s8, u16, s16, u32, s32, u64, s64, f32, f64#
+ * #bsfx = b8, b8, b16, b16, b32, b32, b64, b64, b32, b64#
+ * #simd_sup = 1, 1, 1, 1, 1, 1, 1, 1, 1, NPY_SIMD_F64#
+ * #fp_only = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #sat_sup = 1, 1, 1, 1, 0, 0, 0, 0, 0, 0#
+ * #mul_sup = 1, 1, 1, 1, 1, 1, 0, 0, 1, 1#
+ * #div_sup = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #fused_sup = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #sum_sup = 0, 0, 0, 0, 0, 0, 0, 0, 1, 1#
+ * #ncont_sup = 0, 0, 0, 0, 1, 1, 1, 1, 1, 1#
+ * #shl_imm = 0, 0, 15, 15, 31, 31, 63, 63, 0, 0#
+ * #shr_imm = 0, 0, 16, 16, 32, 32, 64, 64, 0, 0#
+ */
+#if @simd_sup@
+
+/***************************
+ * Memory
+ ***************************/
+/**begin repeat1
+ * # intrin = load, loada, loads, loadl, store, storea, stores, storel, storeh#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+
+/****************************************
+ * Non-contiguous/Partial Memory access
+ ****************************************/
+#if @ncont_sup@
+/**begin repeat1
+ * #intrin = load_till, load_tillz, loadn, loadn_till, loadn_tillz,
+ * store_till, storen, storen_till#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+#endif // ncont_sup
+
+
+/***************************
+ * Misc
+ ***************************/
+/**begin repeat1
+ * #sfx_to = u8, s8, u16, s16, u32, s32, u64, s64, f32, f64#
+ * #simd_sup2 = 1, 1, 1, 1, 1, 1, 1, 1, 1, NPY_SIMD_F64#
+ */
+#if @simd_sup2@
+SIMD_INTRIN_DEF(reinterpret_@sfx_to@_@sfx@)
+#endif // simd_sup2
+/**end repeat1**/
+
+/**begin repeat1
+ * # intrin = set, setf, setall, zero, select#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+
+/***************************
+ * Reorder
+ ***************************/
+/**begin repeat1
+ * # intrin = combinel, combineh, combine, zip#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+
+SIMD_INTRIN_DEF(cvt_@sfx@_@bsfx@)
+SIMD_INTRIN_DEF(cvt_@bsfx@_@sfx@)
+
+/***************************
+ * Operators
+ ***************************/
+#if @shl_imm@ > 0
+/**begin repeat1
+ * # intrin = shl, shr, shli, shri#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+#endif // shl_imm
+
+/**begin repeat1
+ * #intrin = and, or, xor, not, cmpeq, cmpneq, cmpgt, cmpge, cmplt, cmple#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+
+/***************************
+ * Conversion
+ ***************************/
+SIMD_INTRIN_DEF(cvt_@sfx@_@bsfx@)
+SIMD_INTRIN_DEF(cvt_@bsfx@_@sfx@)
+
+/***************************
+ * Arithmetic
+ ***************************/
+/**begin repeat1
+ * #intrin = add, sub#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+
+#if @sat_sup@
+/**begin repeat1
+ * #intrin = adds, subs#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+#endif // sat_sup
+
+#if @mul_sup@
+SIMD_INTRIN_DEF(mul_@sfx@)
+#endif // mul_sup
+
+#if @div_sup@
+SIMD_INTRIN_DEF(div_@sfx@)
+#endif // div_sup
+
+#if @fused_sup@
+/**begin repeat1
+ * #intrin = muladd, mulsub, nmuladd, nmulsub#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+#endif // fused_sup
+
+#if @sum_sup@
+SIMD_INTRIN_DEF(sum_@sfx@)
+#endif // sum_sup
+
+/***************************
+ * Math
+ ***************************/
+#if @fp_only@
+/**begin repeat1
+ * #intrin = sqrt, recip, abs, square#
+ */
+SIMD_INTRIN_DEF(@intrin@_@sfx@)
+/**end repeat1**/
+#endif
+
+#endif // simd_sup
+/**end repeat**/
+
+/***************************
+ * Variant
+ ***************************/
+SIMD_INTRIN_DEF(cleanup)
+/***************************/
+{NULL, NULL, 0, NULL}
+}; // PyMethodDef
+
+#endif // NPY_SIMD
+
+/*************************************************************************
+ * Defining a separate module for each target
+ *************************************************************************/
+NPY_VISIBILITY_HIDDEN PyObject *
+NPY_CPU_DISPATCH_CURFX(simd_create_module)(void)
+{
+ static struct PyModuleDef defs = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_size = -1,
+ #ifdef NPY__CPU_TARGET_CURRENT
+ .m_name = "numpy.core._simd." NPY_TOSTRING(NPY__CPU_TARGET_CURRENT),
+ #else
+ .m_name = "numpy.core._simd.baseline",
+ #endif
+ #if NPY_SIMD
+ .m_methods = simd__intrinsics_methods
+ #else
+ .m_methods = NULL
+ #endif
+ };
+ PyObject *m = PyModule_Create(&defs);
+ if (m == NULL) {
+ return NULL;
+ }
+ if (PyModule_AddIntConstant(m, "simd", NPY_SIMD)) {
+ goto err;
+ }
+ if (PyModule_AddIntConstant(m, "simd_f64", NPY_SIMD_F64)) {
+ goto err;
+ }
+ if (PyModule_AddIntConstant(m, "simd_width", NPY_SIMD_WIDTH)) {
+ goto err;
+ }
+#if NPY_SIMD
+ if (PySIMDVectorType_Init(m)) {
+ goto err;
+ }
+ /**begin repeat
+ * #sfx = u8, s8, u16, s16, u32, s32, u64, s64, f32, f64#
+ */
+ if (PyModule_AddIntConstant(m, "nlanes_@sfx@", npyv_nlanes_@sfx@)) {
+ goto err;
+ }
+ /**end repeat**/
+#endif // NPY_SIMD
+ return m;
+err:
+ Py_DECREF(m);
+ return NULL;
+}
--- /dev/null
+/**
+ * A module to expose the NumPy C SIMD vectorization interface "NPYV" for testing purposes.
+ *
+ * Please keep this module independent from other c-extension modules,
+ * since NPYV intrinsics may be involved in their functionality,
+ * which increases the degree of complexity in tracking and detecting errors.
+ *
+ * TODO: Add an independent sphinx doc.
+ *
+ * Please add any new NPYV intrinsics in '_simd.dispatch.c.src'.
+ */
+#ifndef _SIMD_SIMD_H_
+#define _SIMD_SIMD_H_
+
+#include <Python.h>
+#include "numpy/npy_common.h"
+
+#ifndef NPY_DISABLE_OPTIMIZATION
+// autogenerated, required for CPU dispatch macros
+#include "_simd.dispatch.h"
+#endif
+/**
+ * Create a new module for each required optimization which contains all NPYV intrinsics,
+ *
+ * If required optimization is not supported by NPYV, the module will still provides
+ * access to NPYV constants NPY_SIMD, NPY_SIMD_F64, and NPY_SIMD_WIDTH but without
+ * any intrinsics.
+ */
+NPY_CPU_DISPATCH_DECLARE(NPY_VISIBILITY_HIDDEN PyObject *simd_create_module, (void))
+#endif // _SIMD_SIMD_H_
--- /dev/null
+/**
+ * This file is included by `_simd.dispatch.c.src`. Its contents are affected by the simd configuration, and
+ * therefore must be built multiple times. Making it a standalone `.c` file with `NPY_VISIBILITY_HIDDEN`
+ * symbols would require judicious use of `NPY_CPU_DISPATCH_DECLARE` and `NPY_CPU_DISPATCH_CURFX`, which was
+ * deemed too harmful to readability.
+ */
+/************************************
+ ** Protected Definitions
+ ************************************/
+static int
+simd_arg_from_obj(PyObject *obj, simd_arg *arg)
+{
+ assert(arg->dtype != 0);
+ const simd_data_info *info = simd_data_getinfo(arg->dtype);
+ if (info->is_scalar) {
+ arg->data = simd_scalar_from_number(obj, arg->dtype);
+ }
+ else if (info->is_sequence) {
+ unsigned min_seq_size = simd_data_getinfo(info->to_vector)->nlanes;
+ arg->data.qu8 = simd_sequence_from_iterable(obj, arg->dtype, min_seq_size);
+ }
+ else if (info->is_vectorx) {
+ arg->data = simd_vectorx_from_tuple(obj, arg->dtype);
+ }
+ else if (info->is_vector) {
+ arg->data = PySIMDVector_AsData((PySIMDVectorObject*)obj, arg->dtype);
+ } else {
+ arg->data.u64 = 0;
+ PyErr_Format(PyExc_RuntimeError,
+ "unhandled arg from obj type id:%d, name:%s", arg->dtype, info->pyname
+ );
+ return -1;
+ }
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject *
+simd_arg_to_obj(const simd_arg *arg)
+{
+ assert(arg->dtype != 0);
+ const simd_data_info *info = simd_data_getinfo(arg->dtype);
+ if (info->is_scalar) {
+ return simd_scalar_to_number(arg->data, arg->dtype);
+ }
+ if (info->is_sequence) {
+ return simd_sequence_to_list(arg->data.qu8, arg->dtype);
+ }
+ if (info->is_vectorx) {
+ return simd_vectorx_to_tuple(arg->data, arg->dtype);
+ }
+ if (info->is_vector) {
+ return (PyObject*)PySIMDVector_FromData(arg->data, arg->dtype);
+ }
+ PyErr_Format(PyExc_RuntimeError,
+ "unhandled arg to object type id:%d, name:%s", arg->dtype, info->pyname
+ );
+ return NULL;
+}
+
+static void
+simd_arg_free(simd_arg *arg)
+{
+ const simd_data_info *info = simd_data_getinfo(arg->dtype);
+ if (info->is_sequence) {
+ simd_sequence_free(arg->data.qu8);
+ }
+}
+
+static int
+simd_arg_converter(PyObject *obj, simd_arg *arg)
+{
+ if (obj != NULL) {
+ if (simd_arg_from_obj(obj, arg) < 0) {
+ return 0;
+ }
+ arg->obj = obj;
+ return Py_CLEANUP_SUPPORTED;
+ } else {
+ simd_arg_free(arg);
+ }
+ return 1;
+}
--- /dev/null
+/**
+ * This file is included by `_simd.dispatch.c.src`. Its contents are affected by the simd configuration, and
+ * therefore must be built multiple times. Making it a standalone `.c` file with `NPY_VISIBILITY_HIDDEN`
+ * symbols would require judicious use of `NPY_CPU_DISPATCH_DECLARE` and `NPY_CPU_DISPATCH_CURFX`, which was
+ * deemed too harmful to readability.
+ */
+/************************************
+ ** Protected Definitions
+ ************************************/
+static simd_data
+simd_scalar_from_number(PyObject *obj, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ assert(info->is_scalar && info->lane_size > 0);
+ simd_data data;
+ if (info->is_float) {
+ data.f64 = PyFloat_AsDouble(obj);
+ if (dtype == simd_data_f32){
+ data.f32 = (float)data.f64;
+ }
+ } else {
+ data.u64 = PyLong_AsUnsignedLongLongMask(obj);
+ }
+ return data;
+}
+
+static PyObject *
+simd_scalar_to_number(simd_data data, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ assert(info->is_scalar && info->lane_size > 0);
+ if (info->is_float) {
+ if (dtype == simd_data_f32) {
+ return PyFloat_FromDouble(data.f32);
+ }
+ return PyFloat_FromDouble(data.f64);
+ }
+ int leftb = (sizeof(npyv_lanetype_u64) - info->lane_size) * 8;
+ data.u64 <<= leftb;
+ if (info->is_signed) {
+ return PyLong_FromLongLong(data.s64 >> leftb);
+ }
+ return PyLong_FromUnsignedLongLong(data.u64 >> leftb);
+}
+
+typedef struct {
+ Py_ssize_t len;
+ void *ptr;
+} simd__alloc_data;
+
+static void *
+simd_sequence_new(Py_ssize_t len, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ assert(len > 0 && info->is_sequence && info->lane_size > 0);
+ size_t size = sizeof(simd__alloc_data) + len * info->lane_size + NPY_SIMD_WIDTH;
+ void *ptr = malloc(size);
+ if (ptr == NULL) {
+ return PyErr_NoMemory();
+ }
+ // align the pointer
+ simd__alloc_data *a_ptr = (simd__alloc_data *)(
+ ((uintptr_t)ptr + sizeof(simd__alloc_data) + NPY_SIMD_WIDTH) & ~(uintptr_t)(NPY_SIMD_WIDTH-1)
+ );
+ a_ptr[-1].len = len;
+ a_ptr[-1].ptr = ptr;
+ return a_ptr;
+}
+
+static Py_ssize_t
+simd_sequence_len(void const *ptr)
+{
+ return ((simd__alloc_data const*)ptr)[-1].len;
+}
+
+static void
+simd_sequence_free(void *ptr)
+{
+ free(((simd__alloc_data *)ptr)[-1].ptr);
+}
+
+static void *
+simd_sequence_from_iterable(PyObject *obj, simd_data_type dtype, Py_ssize_t min_size)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ assert(info->is_sequence && info->lane_size > 0);
+ PyObject *seq_obj = PySequence_Fast(obj, "expected a sequence");
+ if (seq_obj == NULL) {
+ return NULL;
+ }
+ Py_ssize_t seq_size = PySequence_Fast_GET_SIZE(seq_obj);
+ if (seq_size < min_size) {
+ PyErr_Format(PyExc_ValueError,
+ "minimum acceptable size of the required sequence is %d, given(%d)",
+ min_size, seq_size
+ );
+ return NULL;
+ }
+ npyv_lanetype_u8 *dst = simd_sequence_new(seq_size, dtype);
+ if (dst == NULL) {
+ return NULL;
+ }
+ PyObject **seq_items = PySequence_Fast_ITEMS(seq_obj);
+ for (Py_ssize_t i = 0; i < seq_size; ++i) {
+ simd_data data = simd_scalar_from_number(seq_items[i], info->to_scalar);
+ npyv_lanetype_u8 *sdst = dst + i * info->lane_size;
+ memcpy(sdst, &data.u64, info->lane_size);
+ }
+ Py_DECREF(seq_obj);
+
+ if (PyErr_Occurred()) {
+ simd_sequence_free(dst);
+ return NULL;
+ }
+ return dst;
+}
+
+static int
+simd_sequence_fill_iterable(PyObject *obj, const void *ptr, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ if (!PySequence_Check(obj)) {
+ PyErr_Format(PyExc_TypeError,
+ "a sequence object is required to fill %s", info->pyname
+ );
+ return -1;
+ }
+ const npyv_lanetype_u8 *src = ptr;
+ Py_ssize_t seq_len = simd_sequence_len(ptr);
+ for (Py_ssize_t i = 0; i < seq_len; ++i) {
+ const npyv_lanetype_u8 *ssrc = src + i * info->lane_size;
+ simd_data data;
+ memcpy(&data.u64, ssrc, info->lane_size);
+ PyObject *item = simd_scalar_to_number(data, info->to_scalar);
+ if (item == NULL) {
+ return -1;
+ }
+ int res = PySequence_SetItem(obj, i, item);
+ Py_DECREF(item);
+ if (res < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static PyObject *
+simd_sequence_to_list(const void *ptr, simd_data_type dtype)
+{
+ PyObject *list = PyList_New(simd_sequence_len(ptr));
+ if (list == NULL) {
+ return NULL;
+ }
+ if (simd_sequence_fill_iterable(list, ptr, dtype) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ return list;
+}
+
+static simd_data
+simd_vectorx_from_tuple(PyObject *obj, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ // NPYV currently only supports x2 and x3
+ assert(info->is_vectorx > 1 && info->is_vectorx < 4);
+
+ simd_data data = {.u64 = 0};
+ if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != info->is_vectorx) {
+ PyErr_Format(PyExc_TypeError,
+ "a tuple of %d vector type %s is required",
+ info->is_vectorx, simd_data_getinfo(info->to_vector)->pyname
+ );
+ return data;
+ }
+ for (int i = 0; i < info->is_vectorx; ++i) {
+ PyObject *item = PyTuple_GET_ITEM(obj, i);
+ // get the max multi-vec and let the compiler do the rest
+ data.vu64x3.val[i] = PySIMDVector_AsData((PySIMDVectorObject*)item, info->to_vector).vu64;
+ if (PyErr_Occurred()) {
+ return data;
+ }
+ }
+ return data;
+}
+
+static PyObject *
+simd_vectorx_to_tuple(simd_data data, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ // NPYV currently only supports x2 and x3
+ assert(info->is_vectorx > 1 && info->is_vectorx < 4);
+
+ PyObject *tuple = PyTuple_New(info->is_vectorx);
+ if (tuple == NULL) {
+ return NULL;
+ }
+ for (int i = 0; i < info->is_vectorx; ++i) {
+ // get the max multi-vector and let the compiler handle the rest
+ simd_data vdata = {.vu64 = data.vu64x3.val[i]};
+ PyObject *item = (PyObject*)PySIMDVector_FromData(vdata, info->to_vector);
+ if (item == NULL) {
+ // TODO: improve log add item number
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple, i, item);
+ }
+ return tuple;
+}
--- /dev/null
+/**
+ * This file is included by `_simd.dispatch.c.src`. Its contents are affected by the simd configuration, and
+ * therefore must be built multiple times. Making it a standalone `.c` file with `NPY_VISIBILITY_HIDDEN`
+ * symbols would require judicious use of `NPY_CPU_DISPATCH_DECLARE` and `NPY_CPU_DISPATCH_CURFX`, which was
+ * deemed too harmful to readability.
+ */
+/************************************
+ ** Private Definitions
+ ************************************/
+static simd_data_info simd__data_registry[simd_data_end] =
+{
+ [simd_data_none] = {.pyname="none"},
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ * #sig = 0*4, 1*4, 0*2#
+ * #fp = 0*4, 0*4, 1*2#
+ * #name = int*8, float, float#
+ */
+ [simd_data_@sfx@] = {
+ .pyname="@name@", .is_unsigned=!@sig@&&!@fp@, .is_signed=@sig@, .is_float=@fp@,
+ .is_scalar=1, .to_scalar = simd_data_@sfx@, .to_vector = simd_data_v@sfx@,
+ .lane_size = sizeof(npyv_lanetype_@sfx@)
+ },
+ /**end repeat**/
+ // sequences
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ * #sig = 0*4, 1*4, 0*2#
+ * #fp = 0*4, 0*4, 1*2#
+ * #name = int*8, float, float#
+ */
+ [simd_data_q@sfx@] = {
+ .pyname="[@name@]", .is_unsigned=!@sig@&&!@fp@, .is_signed=@sig@, .is_float=@fp@,
+ .is_sequence=1, .to_scalar = simd_data_@sfx@, .to_vector = simd_data_v@sfx@,
+ .nlanes=npyv_nlanes_@sfx@, .lane_size = sizeof(npyv_lanetype_@sfx@)
+ },
+ /**end repeat**/
+ // vectors
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ * #sig = 0*4, 1*4, 0*2#
+ * #fp = 0*4, 0*4, 1*2#
+ */
+ [simd_data_v@sfx@] = {
+ .pyname="npyv_@sfx@", .is_unsigned=!@sig@&&!@fp@, .is_signed=@sig@, .is_float=@fp@,
+ .is_vector=1, .to_scalar = simd_data_@sfx@, .to_vector = simd_data_v@sfx@,
+ .nlanes=npyv_nlanes_@sfx@, .lane_size = sizeof(npyv_lanetype_@sfx@)
+ },
+ /**end repeat**/
+ // boolean vectors, treated as unsigned and converted internally
+ // to add compatibility among all SIMD extensions
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64#
+ * #bsfx = b8, b16, b32, b64#
+ */
+ [simd_data_v@bsfx@] = {
+ .pyname="npyv_@bsfx@", .is_bool=1, .is_vector=1,
+ .to_scalar = simd_data_@sfx@, .to_vector = simd_data_v@sfx@,
+ .nlanes=npyv_nlanes_@sfx@, .lane_size = sizeof(npyv_lanetype_@sfx@)
+ },
+ /**end repeat**/
+ // multi-vectors x2
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ * #sig = 0*4, 1*4, 0*2#
+ * #fp = 0*4, 0*4, 1*2#
+ */
+ [simd_data_v@sfx@x2] = {
+ .pyname="npyv_@sfx@x2", .is_unsigned=!@sig@&&!@fp@, .is_signed=@sig@, .is_float=@fp@,
+ .is_vectorx=2, .to_scalar = simd_data_@sfx@, .to_vector = simd_data_v@sfx@,
+ .nlanes=2, .lane_size = sizeof(npyv_lanetype_@sfx@)
+ },
+ /**end repeat**/
+ // multi-vectors x3
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ * #sig = 0*4, 1*4, 0*2#
+ * #fp = 0*4, 0*4, 1*2#
+ */
+ [simd_data_v@sfx@x3] = {
+ .pyname="npyv_@sfx@x3", .is_unsigned=!@sig@&&!@fp@, .is_signed=@sig@, .is_float=@fp@,
+ .is_vectorx=3, .to_scalar = simd_data_@sfx@, .to_vector = simd_data_v@sfx@,
+ .nlanes=3, .lane_size = sizeof(npyv_lanetype_@sfx@)
+ },
+ /**end repeat**/
+};
+
+/************************************
+ ** Protected Definitions
+ ************************************/
+static const simd_data_info *
+simd_data_getinfo(simd_data_type dtype)
+{ return &simd__data_registry[dtype]; }
--- /dev/null
+/**
+ * This file is included by `_simd.dispatch.c.src`. Its contents are affected by the simd configuration, and
+ * therefore must be built multiple times. Making it a standalone `.c` file with `NPY_VISIBILITY_HIDDEN`
+ * symbols would require judicious use of `NPY_CPU_DISPATCH_DECLARE` and `NPY_CPU_DISPATCH_CURFX`, which was
+ * deemed too harmful to readability.
+ */
+#define SIMD_INTRIN_DEF(NAME) \
+ { NPY_TOSTRING(NAME), simd__intrin_##NAME, METH_VARARGS, NULL } , // comma
+
+#define SIMD_IMPL_INTRIN_0(NAME, RET) \
+ static PyObject *simd__intrin_##NAME \
+ (PyObject* NPY_UNUSED(self), PyObject *args) \
+ { \
+ if (!PyArg_ParseTuple( \
+ args, ":" NPY_TOSTRING(NAME)) \
+ ) return NULL; \
+ simd_arg a = { \
+ .dtype = simd_data_##RET, \
+ .data = {.RET = npyv_##NAME()}, \
+ }; \
+ return simd_arg_to_obj(&a); \
+ }
+
+#define SIMD_IMPL_INTRIN_0N(NAME) \
+ static PyObject *simd__intrin_##NAME \
+ (PyObject* NPY_UNUSED(self), PyObject *args) \
+ { \
+ if (!PyArg_ParseTuple( \
+ args, ":" NPY_TOSTRING(NAME)) \
+ ) return NULL; \
+ npyv_##NAME(); \
+ Py_RETURN_NONE; \
+ }
+
+#define SIMD_IMPL_INTRIN_1(NAME, RET, IN0) \
+ static PyObject *simd__intrin_##NAME \
+ (PyObject* NPY_UNUSED(self), PyObject *args) \
+ { \
+ simd_arg arg = {.dtype = simd_data_##IN0}; \
+ if (!PyArg_ParseTuple( \
+ args, "O&:"NPY_TOSTRING(NAME), \
+ simd_arg_converter, &arg \
+ )) return NULL; \
+ simd_data data = {.RET = npyv_##NAME( \
+ arg.data.IN0 \
+ )}; \
+ simd_arg_free(&arg); \
+ simd_arg ret = { \
+ .data = data, .dtype = simd_data_##RET \
+ }; \
+ return simd_arg_to_obj(&ret); \
+ }
+
+#define SIMD_IMPL_INTRIN_2(NAME, RET, IN0, IN1) \
+ static PyObject *simd__intrin_##NAME \
+ (PyObject* NPY_UNUSED(self), PyObject *args) \
+ { \
+ simd_arg arg1 = {.dtype = simd_data_##IN0}; \
+ simd_arg arg2 = {.dtype = simd_data_##IN1}; \
+ if (!PyArg_ParseTuple( \
+ args, "O&O&:"NPY_TOSTRING(NAME), \
+ simd_arg_converter, &arg1, \
+ simd_arg_converter, &arg2 \
+ )) return NULL; \
+ simd_data data = {.RET = npyv_##NAME( \
+ arg1.data.IN0, arg2.data.IN1 \
+ )}; \
+ simd_arg_free(&arg1); \
+ simd_arg_free(&arg2); \
+ simd_arg ret = { \
+ .data = data, .dtype = simd_data_##RET \
+ }; \
+ return simd_arg_to_obj(&ret); \
+ }
+
+#define SIMD__REPEAT_2IMM(C, NAME, IN0) \
+ C == arg2.data.u8 ? NPY_CAT(npyv_, NAME)(arg1.data.IN0, C) :
+
+#define SIMD_IMPL_INTRIN_2IMM(NAME, RET, IN0, CONST_RNG) \
+ static PyObject *simd__intrin_##NAME \
+ (PyObject* NPY_UNUSED(self), PyObject *args) \
+ { \
+ simd_arg arg1 = {.dtype = simd_data_##IN0}; \
+ simd_arg arg2 = {.dtype = simd_data_u8}; \
+ if (!PyArg_ParseTuple( \
+ args, "O&O&:"NPY_TOSTRING(NAME), \
+ simd_arg_converter, &arg1, \
+ simd_arg_converter, &arg2 \
+ )) return NULL; \
+ simd_data data = {.u64 = 0}; \
+ data.RET = NPY_CAT(SIMD__IMPL_COUNT_, CONST_RNG)( \
+ SIMD__REPEAT_2IMM, NAME, IN0 \
+ ) data.RET; \
+ simd_arg_free(&arg1); \
+ simd_arg ret = { \
+ .data = data, .dtype = simd_data_##RET \
+ }; \
+ return simd_arg_to_obj(&ret); \
+ }
+
+#define SIMD_IMPL_INTRIN_3(NAME, RET, IN0, IN1, IN2) \
+ static PyObject *simd__intrin_##NAME \
+ (PyObject* NPY_UNUSED(self), PyObject *args) \
+ { \
+ simd_arg arg1 = {.dtype = simd_data_##IN0}; \
+ simd_arg arg2 = {.dtype = simd_data_##IN1}; \
+ simd_arg arg3 = {.dtype = simd_data_##IN2}; \
+ if (!PyArg_ParseTuple( \
+ args, "O&O&O&:"NPY_TOSTRING(NAME), \
+ simd_arg_converter, &arg1, \
+ simd_arg_converter, &arg2, \
+ simd_arg_converter, &arg3 \
+ )) return NULL; \
+ simd_data data = {.RET = npyv_##NAME( \
+ arg1.data.IN0, arg2.data.IN1, \
+ arg3.data.IN2 \
+ )}; \
+ simd_arg_free(&arg1); \
+ simd_arg_free(&arg2); \
+ simd_arg_free(&arg3); \
+ simd_arg ret = { \
+ .data = data, .dtype = simd_data_##RET \
+ }; \
+ return simd_arg_to_obj(&ret); \
+ }
+/**
+ * Helper macros for repeating and expand a certain macro.
+ * Mainly used for converting a scalar to an immediate constant.
+ */
+#define SIMD__IMPL_COUNT_7(FN, ...) \
+ NPY_EXPAND(FN(0, __VA_ARGS__)) \
+ SIMD__IMPL_COUNT_7_(FN, __VA_ARGS__)
+
+#define SIMD__IMPL_COUNT_8(FN, ...) \
+ SIMD__IMPL_COUNT_7_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(8, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_15(FN, ...) \
+ NPY_EXPAND(FN(0, __VA_ARGS__)) \
+ SIMD__IMPL_COUNT_15_(FN, __VA_ARGS__)
+
+#define SIMD__IMPL_COUNT_16(FN, ...) \
+ SIMD__IMPL_COUNT_15_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(16, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_31(FN, ...) \
+ NPY_EXPAND(FN(0, __VA_ARGS__)) \
+ SIMD__IMPL_COUNT_31_(FN, __VA_ARGS__)
+
+#define SIMD__IMPL_COUNT_32(FN, ...) \
+ SIMD__IMPL_COUNT_31_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(32, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_47(FN, ...) \
+ NPY_EXPAND(FN(0, __VA_ARGS__)) \
+ SIMD__IMPL_COUNT_47_(FN, __VA_ARGS__)
+
+#define SIMD__IMPL_COUNT_48(FN, ...) \
+ SIMD__IMPL_COUNT_47_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(48, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_63(FN, ...) \
+ NPY_EXPAND(FN(0, __VA_ARGS__)) \
+ SIMD__IMPL_COUNT_63_(FN, __VA_ARGS__)
+
+#define SIMD__IMPL_COUNT_64(FN, ...) \
+ SIMD__IMPL_COUNT_63_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(64, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_7_(FN, ...) \
+ NPY_EXPAND(FN(1, __VA_ARGS__)) \
+ NPY_EXPAND(FN(2, __VA_ARGS__)) NPY_EXPAND(FN(3, __VA_ARGS__)) \
+ NPY_EXPAND(FN(4, __VA_ARGS__)) NPY_EXPAND(FN(5, __VA_ARGS__)) \
+ NPY_EXPAND(FN(6, __VA_ARGS__)) NPY_EXPAND(FN(7, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_15_(FN, ...) \
+ SIMD__IMPL_COUNT_7_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(8, __VA_ARGS__)) NPY_EXPAND(FN(9, __VA_ARGS__)) \
+ NPY_EXPAND(FN(10, __VA_ARGS__)) NPY_EXPAND(FN(11, __VA_ARGS__)) \
+ NPY_EXPAND(FN(12, __VA_ARGS__)) NPY_EXPAND(FN(13, __VA_ARGS__)) \
+ NPY_EXPAND(FN(14, __VA_ARGS__)) NPY_EXPAND(FN(15, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_31_(FN, ...) \
+ SIMD__IMPL_COUNT_15_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(16, __VA_ARGS__)) NPY_EXPAND(FN(17, __VA_ARGS__)) \
+ NPY_EXPAND(FN(18, __VA_ARGS__)) NPY_EXPAND(FN(19, __VA_ARGS__)) \
+ NPY_EXPAND(FN(20, __VA_ARGS__)) NPY_EXPAND(FN(21, __VA_ARGS__)) \
+ NPY_EXPAND(FN(22, __VA_ARGS__)) NPY_EXPAND(FN(23, __VA_ARGS__)) \
+ NPY_EXPAND(FN(24, __VA_ARGS__)) NPY_EXPAND(FN(25, __VA_ARGS__)) \
+ NPY_EXPAND(FN(26, __VA_ARGS__)) NPY_EXPAND(FN(27, __VA_ARGS__)) \
+ NPY_EXPAND(FN(28, __VA_ARGS__)) NPY_EXPAND(FN(29, __VA_ARGS__)) \
+ NPY_EXPAND(FN(30, __VA_ARGS__)) NPY_EXPAND(FN(31, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_47_(FN, ...) \
+ SIMD__IMPL_COUNT_31_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(32, __VA_ARGS__)) NPY_EXPAND(FN(33, __VA_ARGS__)) \
+ NPY_EXPAND(FN(34, __VA_ARGS__)) NPY_EXPAND(FN(35, __VA_ARGS__)) \
+ NPY_EXPAND(FN(36, __VA_ARGS__)) NPY_EXPAND(FN(37, __VA_ARGS__)) \
+ NPY_EXPAND(FN(38, __VA_ARGS__)) NPY_EXPAND(FN(39, __VA_ARGS__)) \
+ NPY_EXPAND(FN(40, __VA_ARGS__)) NPY_EXPAND(FN(41, __VA_ARGS__)) \
+ NPY_EXPAND(FN(42, __VA_ARGS__)) NPY_EXPAND(FN(43, __VA_ARGS__)) \
+ NPY_EXPAND(FN(44, __VA_ARGS__)) NPY_EXPAND(FN(45, __VA_ARGS__)) \
+ NPY_EXPAND(FN(46, __VA_ARGS__)) NPY_EXPAND(FN(47, __VA_ARGS__))
+
+#define SIMD__IMPL_COUNT_63_(FN, ...) \
+ SIMD__IMPL_COUNT_47_(FN, __VA_ARGS__) \
+ NPY_EXPAND(FN(48, __VA_ARGS__)) NPY_EXPAND(FN(49, __VA_ARGS__)) \
+ NPY_EXPAND(FN(50, __VA_ARGS__)) NPY_EXPAND(FN(51, __VA_ARGS__)) \
+ NPY_EXPAND(FN(52, __VA_ARGS__)) NPY_EXPAND(FN(53, __VA_ARGS__)) \
+ NPY_EXPAND(FN(54, __VA_ARGS__)) NPY_EXPAND(FN(55, __VA_ARGS__)) \
+ NPY_EXPAND(FN(56, __VA_ARGS__)) NPY_EXPAND(FN(57, __VA_ARGS__)) \
+ NPY_EXPAND(FN(58, __VA_ARGS__)) NPY_EXPAND(FN(59, __VA_ARGS__)) \
+ NPY_EXPAND(FN(60, __VA_ARGS__)) NPY_EXPAND(FN(61, __VA_ARGS__)) \
+ NPY_EXPAND(FN(62, __VA_ARGS__)) NPY_EXPAND(FN(63, __VA_ARGS__))
--- /dev/null
+#ifndef _SIMD_SIMD_INC_H_
+#define _SIMD_SIMD_INC_H_
+
+#include <Python.h>
+#include "simd/simd.h"
+
+#if NPY_SIMD
+/************************************
+ ** Types
+ ************************************/
+/**
+ * Gather all data types supported by the module.
+*/
+typedef union
+{
+ // scalars
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ */
+ npyv_lanetype_@sfx@ @sfx@;
+ /**end repeat**/
+ // sequence
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ */
+ npyv_lanetype_@sfx@ *q@sfx@;
+ /**end repeat**/
+ // vectors
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, b8, b16, b32, b64#
+ */
+ npyv_@sfx@ v@sfx@;
+ /**end repeat**/
+ // multi-vectors x2
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32#
+ */
+ npyv_@sfx@x2 v@sfx@x2;
+ /**end repeat**/
+ // multi-vectors x3
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32#
+ */
+ npyv_@sfx@x3 v@sfx@x3;
+ /**end repeat**/
+#if NPY_SIMD_F64
+ npyv_f64 vf64;
+ npyv_f64x2 vf64x2;
+ npyv_f64x3 vf64x3;
+#endif
+} simd_data;
+
+/**
+ * Data types IDs and suffixes. Must be same data types as the ones
+ * in union 'simd_data' to fit the macros in '_simd_inc_easyintrin.h'.
+*/
+typedef enum
+{
+ simd_data_none = 0,
+ // scalars
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ */
+ simd_data_@sfx@,
+ /**end repeat**/
+ // sequences
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ */
+ simd_data_q@sfx@,
+ /**end repeat**/
+ // vectors
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64, b8, b16, b32, b64#
+ */
+ simd_data_v@sfx@,
+ /**end repeat**/
+ // multi-vectors x2
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ */
+ simd_data_v@sfx@x2,
+ /**end repeat**/
+ // multi-vectors x3
+ /**begin repeat
+ * #sfx = u8, u16, u32, u64, s8, s16, s32, s64, f32, f64#
+ */
+ simd_data_v@sfx@x3,
+ /**end repeat**/
+ simd_data_end,
+} simd_data_type;
+/************************************
+ ** Declarations (inc_data)
+ ************************************/
+/**
+ * simd_data_type information
+ */
+typedef struct
+{
+ // type name compatible with python style
+ const char *pyname;
+ // returns '1' if the type represent a unsigned integer
+ int is_unsigned:1;
+ // returns '1' if the type represent a signed integer
+ int is_signed:1;
+ // returns '1' if the type represent a single or double precision
+ int is_float:1;
+ // returns '1' if the type represent a boolean
+ int is_bool:1;
+ // returns '1' if the type represent a sequence
+ int is_sequence:1;
+ // returns '1' if the type represent a scalar
+ int is_scalar:1;
+ // returns '1' if the type represent a vector
+ int is_vector:1;
+ // returns the len of multi-vector if the type reprsent x2 or x3 vector
+ // otherwise returns 0, e.g. returns 2 if data type is simd_data_vu8x2
+ int is_vectorx;
+ // returns the equivalent scalar data type e.g. simd_data_vu8 -> simd_data_u8
+ simd_data_type to_scalar;
+ // returns the equivalent scalar data type e.g. simd_data_s8 -> simd_data_vs8
+ // NOTE: returns the will equivalent "unsigned" vector type in case of "boolean" vector
+ // e.g. simd_data_vb8 -> simd_data_vu8
+ simd_data_type to_vector;
+ // number of vector lanes
+ int nlanes;
+ // sizeof lane type
+ int lane_size;
+} simd_data_info;
+
+/**
+ * Returns data info of certain dtype.
+ *
+ * Example:
+ ** const simd_data_info *info = simd_data_getinfo(simd_data_vu8);
+ ** if (info->is_vector && info->is_unsigned) {
+ ** ...
+ ** }
+ */
+static const simd_data_info *
+simd_data_getinfo(simd_data_type dtype);
+
+/************************************
+ ** Declarations (inc_vector)
+ ************************************/
+typedef struct
+{
+ PyObject_HEAD
+ // vector type id
+ simd_data_type dtype;
+ // vector data, aligned for safe casting
+ npyv_lanetype_u8 NPY_DECL_ALIGNED(NPY_SIMD_WIDTH) data[NPY_SIMD_WIDTH];
+} PySIMDVectorObject;
+/**
+ * Create a Python obj(PySIMDVectorObject) from a NPYV vector based on the contents
+ * of `data`(simd_data) and according to the vector data type `dtype`
+ * on range(simd_data_[vu8:vf64]).
+ * Return NULL and a Python exception on failure, otherwise new reference.
+ *
+ * Example:
+ ** simd_data data = {.vu8 = npyv_setall_u8(0xff)};
+ ** PySIMDVectorObject *obj = PySIMDVector_FromData(data, simd_data_vu8);
+ ** if (obj != NULL) {
+ ** printf("I have a valid vector obj and first element is \n", obj->data[0]);
+ ** Py_DECREF(obj);
+ ** }
+ */
+static PySIMDVectorObject *
+PySIMDVector_FromData(simd_data data, simd_data_type dtype);
+/**
+ * Return a NPYV vector(simd_data) representation of `obj`(PySIMDVectorObject) and
+ * according to the vector data type `dtype` on range (simd_data_[vu8:vf64]).
+ * Raise a Python exception on failure.
+ *
+ * Example:
+ ** simd_data data = PySIMDVector_AsData(vec_obj, simd_data_vf32);
+ ** if (!PyErr_Occurred()) {
+ ** npyv_f32 add_1 = npyv_add_f32(data.vf32, npyv_setall_f32(1));
+ ** ...
+ ** }
+ */
+static simd_data
+PySIMDVector_AsData(PySIMDVectorObject *obj, simd_data_type dtype);
+/**
+ * initialize and register PySIMDVectorType to certain PyModule,
+ * PySIMDVectorType can be reached through attribute 'vector_type'.
+ * return -1 on error, 0 on success.
+ */
+static int
+PySIMDVectorType_Init(PyObject *module);
+
+/************************************
+ ** Declarations (inc_convert)
+ ************************************/
+/**
+ * Return a C scalar(simd_data) representation of `obj` and
+ * according to the scalar data type `dtype` on range (simd_data_[u8:f64]).
+ * Raise a Python exception on failure.
+ *
+ * Example:
+ ** simd_data data = simd_scalar_from_number(obj, simd_data_f32);
+ ** if (!PyErr_Occurred()) {
+ ** printf("I have a valid float %d\n", data.f32);
+ ** }
+ */
+static simd_data
+simd_scalar_from_number(PyObject *obj, simd_data_type dtype);
+/**
+ * Create a Python scalar from a C scalar based on the contents
+ * of `data`(simd_data) and according to the scalar data type `dtype`
+ * on range(simd_data_[u8:f64]).
+ * Return NULL and a Python exception on failure, otherwise new reference.
+ *
+ * Example:
+ ** simd_data data = {.u32 = 0x7fffffff};
+ ** PyObject *obj = simd_scalar_to_number(data, simd_data_s32);
+ ** if (obj != NULL) {
+ ** printf("I have a valid Python integer %d\n", PyLong_AsLong(obj));
+ ** Py_DECREF(obj);
+ ** }
+ */
+static PyObject *
+simd_scalar_to_number(simd_data data, simd_data_type dtype);
+/**
+ * Allocate a C array in memory according to number of elements `len`
+ * and sequence data type `dtype` on range(simd_data_[qu8:qf64]).
+ *
+ * Return aligned pointer based on `NPY_SIMD_WIDTH` or NULL
+ * with a Python exception on failure.
+ *
+ * Example:
+ ** npyv_lanetype_f64 *aligned_ptr = simd_sequence_new(npyv_nlanes_f64, simd_data_f64);
+ ** if (aligned_ptr != NULL) {
+ ** // aligned store
+ ** npyv_storea_f64(aligned_ptr, npyv_setall_f64(1.0));
+ ** printf("The first element of my array %f\n", aligned_ptr[0]);
+ ** simd_sequence_free(aligned_ptr);
+ ** }
+ */
+static void *
+simd_sequence_new(Py_ssize_t len, simd_data_type dtype);
+/**
+ * Return the number of elements of the allocated C array `ptr`
+ * by `simd_sequence_new()` or `simd_sequence_from_iterable()`.
+ */
+static Py_ssize_t
+simd_sequence_len(const void *ptr);
+/**
+ * Free the allocated C array by `simd_sequence_new()` or
+ * `simd_sequence_from_iterable()`.
+ */
+static void
+simd_sequence_free(void *ptr);
+/**
+ * Return a C array representation of a PyObject sequence `obj` and
+ * according to the sequence data type `dtype` on range (simd_data_[qu8:qf64]).
+ *
+ * Note: parameter `min_size` takes the number of minimum acceptable elements.
+ *
+ * Return aligned pointer based on `NPY_SIMD_WIDTH` or NULL
+ * with a Python exception on failure.
+ *
+ * Example:
+ ** npyv_lanetype_u32 *ptr = simd_sequence_from_iterable(seq_obj, simd_data_qu32, npyv_nlanes_u32);
+ ** if (ptr != NULL) {
+ ** npyv_u32 a = npyv_load_u32(ptr);
+ ** ...
+ ** simd_sequence_free(ptr);
+ ** }
+ **
+ */
+static void *
+simd_sequence_from_iterable(PyObject *obj, simd_data_type dtype, Py_ssize_t min_size);
+/**
+ * Fill a Python sequence object `obj` with a C array `ptr` allocated by
+ * `simd_sequence_new()` or `simd_sequence_from_iterable()` according to
+ * to the sequence data type `dtype` on range (simd_data_[qu8:qf64]).
+ *
+ * Return 0 on success or -1 with a Python exception on failure.
+ */
+static int
+simd_sequence_fill_iterable(PyObject *obj, const void *ptr, simd_data_type dtype);
+/**
+ * Create a Python list from a C array `ptr` allocated by
+ * `simd_sequence_new()` or `simd_sequence_from_iterable()` according to
+ * to the sequence data type `dtype` on range (simd_data_[qu8:qf64]).
+ *
+ * Return NULL and a Python exception on failure, otherwise new reference.
+ */
+static PyObject *
+simd_sequence_to_list(const void *ptr, simd_data_type dtype);
+/**
+ * Return a SIMD multi-vector(simd_data) representation of Python tuple of
+ * (simd_vector*,) `obj` according to the scalar data type `dtype`
+ * on range (simd_data_[vu8x2:vf64x2])-(simd_data_[vu8x3:vf64x3]).
+ *
+ * Raise a Python exception on failure.
+ *
+ * Example:
+ ** simd_data data = simd_vectorx_from_tuple(tuple_obj, simd_data_vf32x2);
+ ** if (!PyErr_Occurred()) {
+ ** npyv_f32 sum = npyv_add_f32(data.vf32x2.val[0], data.vf32x2.val[1]);
+ ** ...
+ ** }
+ **
+ */
+static simd_data
+simd_vectorx_from_tuple(PyObject *obj, simd_data_type dtype);
+/**
+ * Create a Python tuple of 'simd_vector' from a SIMD multi-vector
+ * based on the contents of `data`(simd_data) and according to
+ * the multi-vector data type `dtype` on range
+ * (simd_data_[vu8x2:vf64x2])-(simd_data_[vu8x3:vf64x3]).
+ *
+ * Return NULL and a Python exception on failure, otherwise new reference.
+ */
+static PyObject *
+simd_vectorx_to_tuple(simd_data data, simd_data_type dtype);
+
+/************************************
+ ** Declarations (inc_arg)
+ ************************************/
+typedef struct
+{
+ simd_data_type dtype;
+ simd_data data;
+ // set by simd_arg_converter()
+ PyObject *obj;
+} simd_arg;
+/**
+ * The following functions gather all conversions between all data types
+ * and they can used instead of all above functions.
+ */
+/**
+ * Convert a Python object `obj` into simd_data `arg->data` according to the
+ * required data type `arg->dtype`.
+ *
+ * Return -1 and raise Python exception on failure, otherwise return 0.
+ *
+ * Notes:
+ * - requires `simd_arg_free()` or `simd_sequence_free()`
+ * to free allocated C array, in case of sequence data types.
+ * - the number of minimum acceptable elements for sequence data
+ * types is the number of lanes of the equivalent vector data type.
+ *
+ * Example #1:
+ ** simd_arg arg = {.dtype = simd_data_qu8};
+ ** if (simd_arg_from_obj(seq_obj, &arg) < 0) {
+ ** // fails to convert a python sequence object to C array of uint8
+ ** return;
+ ** }
+ ** npyv_u8 v_u8 = npyv_load_u8(arg->data.qu8);
+ ** ...
+ ** simd_arg_free(&arg);
+ *
+ * Example #2:
+ ** simd_arg arg = {.dtype = simd_data_vf32};
+ ** if (simd_arg_from_obj(vector_obj, &arg) < 0) {
+ ** // fails to convert a python simd_vector to NPYV vector
+ ** return;
+ ** }
+ ** npyv_f32 add_one = npyv_add_f32(arg->data.vu8, npyv_setall_f32(1));
+ ** ...
+ */
+static int
+simd_arg_from_obj(PyObject *obj, simd_arg *arg);
+/**
+ * Convert a simd_data `arg->data` to into a Python object according to the
+ * required data type `arg->dtype`.
+ *
+ * Return NULL and raise Python exception on failure, otherwise return
+ * new reference.
+ *
+ * Example:
+ ** simd_arg arg = {.dtype = simd_data_u32, .data = {.u32 = 0xffffffff}};
+ ** PyObject *obj = simd_arg_to_obj(&arg);
+ ** if (obj == NULL) {
+ ** // fails convert C uint32 to Python integer.
+ ** return;
+ ** }
+ **
+ */
+static PyObject *
+simd_arg_to_obj(const simd_arg *arg);
+/**
+ * Converter function used similar to simd_arg_from_obj() but
+ * used with PyArg_Parse*().
+ *
+ * Notes:
+ * - requires `simd_arg_free()` or `simd_sequence_free()`
+ * to free allocated C array, in case of sequence data types.
+ * - the number of minimum acceptable elements for sequence data
+ * types is the number of lanes of the equivalent vector data type.
+ * - use 'arg->obj' to retrieve the parameter obj.
+ *
+ * Example:
+ ** simd_arg seq_f32 = {.dtype = simd_data_qf32};
+ ** simd_arg vec_f32 = {.dtype = simd_data_vf32};
+ ** if (!PyArg_ParseTuple(
+ ** args, "O&O&:add_sum_f32",
+ ** simd_arg_converter, &seq_f32,
+ ** simd_arg_converter, &vec_f32
+ ** )) {
+ ** // fail
+ ** return;
+ ** }
+ ** npyv_f32 load_a = npyv_load_f32(seq_f32.data.qf32);
+ ** npyv_f32 sum = npyv_add_f32(load_a, vec_f32.data.vf32);
+ ** ...
+ ** simd_arg_free(&seq_f32);
+ */
+static int
+simd_arg_converter(PyObject *obj, simd_arg *arg);
+/**
+ * Free the allocated C array, if the arg hold sequence data type.
+ */
+static void
+simd_arg_free(simd_arg *arg);
+
+#endif // NPY_SIMD
+#endif // _SIMD_SIMD_INC_H_
--- /dev/null
+/**
+ * This file is included by `_simd.dispatch.c.src`. Its contents are affected by the simd configuration, and
+ * therefore must be built multiple times. Making it a standalone `.c` file with `NPY_VISIBILITY_HIDDEN`
+ * symbols would require judicious use of `NPY_CPU_DISPATCH_DECLARE` and `NPY_CPU_DISPATCH_CURFX`, which was
+ * deemed too harmful to readability.
+ */
+/************************************
+ ** Private Definitions
+ ************************************/
+static Py_ssize_t
+simd__vector_length(PySIMDVectorObject *self)
+{
+ return simd_data_getinfo(self->dtype)->nlanes;
+}
+static PyObject *
+simd__vector_item(PySIMDVectorObject *self, Py_ssize_t i)
+{
+ const simd_data_info *info = simd_data_getinfo(self->dtype);
+ int nlanes = info->nlanes;
+ if (i >= nlanes) {
+ PyErr_SetString(PyExc_IndexError, "vector index out of range");
+ return NULL;
+ }
+ npyv_lanetype_u8 *src = self->data + i * info->lane_size;
+ simd_data data;
+ memcpy(&data.u64, src, info->lane_size);
+ return simd_scalar_to_number(data, info->to_scalar);
+}
+
+static PySequenceMethods simd__vector_as_sequence = {
+ .sq_length = (lenfunc) simd__vector_length,
+ .sq_item = (ssizeargfunc) simd__vector_item
+};
+
+static PyObject *
+simd__vector_name(PySIMDVectorObject *self)
+{
+ return PyUnicode_FromString(simd_data_getinfo(self->dtype)->pyname);
+}
+static PyGetSetDef simd__vector_getset[] = {
+ { "__name__", (getter)simd__vector_name, NULL, NULL, NULL },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+static PyObject *
+simd__vector_repr(PySIMDVectorObject *self)
+{
+ PyObject *obj = PySequence_List((PyObject*)self);
+ if (obj != NULL) {
+ const char *type_name = simd_data_getinfo(self->dtype)->pyname;
+ PyObject *repr = PyUnicode_FromFormat("<%s of %R>", type_name, obj);
+ Py_DECREF(obj);
+ return repr;
+ }
+ return obj;
+}
+static PyObject *
+simd__vector_compare(PyObject *self, PyObject *other, int cmp_op)
+{
+ PyObject *obj;
+ if (PyTuple_Check(other)) {
+ obj = PySequence_Tuple(self);
+ } else if (PyList_Check(other)) {
+ obj = PySequence_List(self);
+ } else {
+ obj = PySequence_Fast(self, "invalid argument, expected a vector");
+ }
+ if (obj != NULL) {
+ PyObject *rich = PyObject_RichCompare(obj, other, cmp_op);
+ Py_DECREF(obj);
+ return rich;
+ }
+ return obj;
+}
+static PyTypeObject PySIMDVectorType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(VECTOR)),
+ .tp_basicsize = sizeof(PySIMDVectorObject),
+ .tp_repr = (reprfunc)simd__vector_repr,
+ .tp_as_sequence = &simd__vector_as_sequence,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_richcompare = simd__vector_compare,
+ .tp_getset = simd__vector_getset
+};
+
+/************************************
+ ** Protected Definitions
+ ************************************/
+static PySIMDVectorObject *
+PySIMDVector_FromData(simd_data data, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ assert(info->is_vector && info->nlanes > 0);
+
+ PySIMDVectorObject *vec = PyObject_New(PySIMDVectorObject, &PySIMDVectorType);
+ if (vec == NULL) {
+ return (PySIMDVectorObject*)PyErr_NoMemory();
+ }
+ vec->dtype = dtype;
+ if (info->is_bool) {
+ // boolean vectors are internally treated as unsigned
+ // vectors to add compatibility among all SIMD extensions
+ switch(dtype) {
+ case simd_data_vb8:
+ data.vu8 = npyv_cvt_u8_b8(data.vb8);
+ break;
+ case simd_data_vb16:
+ data.vu16 = npyv_cvt_u16_b16(data.vb16);
+ break;
+ case simd_data_vb32:
+ data.vu32 = npyv_cvt_u32_b32(data.vb32);
+ break;
+ default:
+ data.vu64 = npyv_cvt_u64_b64(data.vb64);
+ }
+ }
+ npyv_store_u8(vec->data, data.vu8);
+ return vec;
+}
+
+static simd_data
+PySIMDVector_AsData(PySIMDVectorObject *vec, simd_data_type dtype)
+{
+ const simd_data_info *info = simd_data_getinfo(dtype);
+ assert(info->is_vector && info->nlanes > 0);
+
+ simd_data data = {.u64 = 0};
+ if (!PyObject_IsInstance(
+ (PyObject *)vec, (PyObject *)&PySIMDVectorType
+ )) {
+ PyErr_Format(PyExc_TypeError,
+ "a vector type %s is required", info->pyname
+ );
+ return data;
+ }
+ if (vec->dtype != dtype) {
+ PyErr_Format(PyExc_TypeError,
+ "a vector type %s is required, got(%s)",
+ info->pyname, simd_data_getinfo(vec->dtype)->pyname
+ );
+ return data;
+ }
+
+ data.vu8 = npyv_load_u8(vec->data);
+ if (info->is_bool) {
+ // boolean vectors are internally treated as unsigned
+ // vectors to add compatibility among all SIMD extensions
+ switch(dtype) {
+ case simd_data_vb8:
+ data.vb8 = npyv_cvt_b8_u8(data.vu8);
+ break;
+ case simd_data_vb16:
+ data.vb16 = npyv_cvt_b16_u16(data.vu16);
+ break;
+ case simd_data_vb32:
+ data.vb32 = npyv_cvt_b32_u32(data.vu32);
+ break;
+ default:
+ data.vb64 = npyv_cvt_b64_u64(data.vu64);
+ }
+ }
+ return data;
+}
+
+static int
+PySIMDVectorType_Init(PyObject *module)
+{
+ Py_INCREF(&PySIMDVectorType);
+ if (PyType_Ready(&PySIMDVectorType)) {
+ return -1;
+ }
+ if (PyModule_AddObject(
+ module, "vector_type",(PyObject *)&PySIMDVectorType
+ )) {
+ return -1;
+ }
+ return 0;
+}
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE
#include <numpy/ndarraytypes.h>
-
#include "npy_config.h"
#include "npy_pycompat.h"
return 0;
broadcast_error: {
- PyObject *errmsg;
-
- errmsg = PyUString_FromFormat("could not broadcast %s from shape ",
- strides_name);
- PyUString_ConcatAndDel(&errmsg,
- build_shape_string(strides_ndim, strides_shape));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" into shape "));
- PyUString_ConcatAndDel(&errmsg,
- build_shape_string(ndim, shape));
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
+ PyObject *shape1 = convert_shape_to_string(strides_ndim,
+ strides_shape, "");
+ if (shape1 == NULL) {
+ return -1;
+ }
+ PyObject *shape2 = convert_shape_to_string(ndim, shape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
+ return -1;
+ }
+ PyErr_Format(PyExc_ValueError,
+ "could not broadcast %s from shape %S into shape %S",
+ strides_name, shape1, shape2);
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
return -1;
}
}
* Use NPY_AUXDATA_CLONE and NPY_AUXDATA_FREE to deal with this data.
*
*/
-typedef void (PyArray_StridedUnaryOp)(char *dst, npy_intp dst_stride,
- char *src, npy_intp src_stride,
- npy_intp N, npy_intp src_itemsize,
- NpyAuxData *transferdata);
+typedef int (PyArray_StridedUnaryOp)(
+ char *dst, npy_intp dst_stride, char *src, npy_intp src_stride,
+ npy_intp N, npy_intp src_itemsize, NpyAuxData *transferdata);
/*
* This is for pointers to functions which behave exactly as
* In particular, the 'i'-th element is operated on if and only if
* mask[i*mask_stride] is true.
*/
-typedef void (PyArray_MaskedStridedUnaryOp)(char *dst, npy_intp dst_stride,
- char *src, npy_intp src_stride,
- npy_bool *mask, npy_intp mask_stride,
- npy_intp N, npy_intp src_itemsize,
- NpyAuxData *transferdata);
-
-/*
- * This function pointer is for binary operations that input two
- * arbitrarily strided one-dimensional array segments and output
- * an arbitrarily strided array segment of the same size.
- * It may be a fully general function, or a specialized function
- * when the strides or item size have particular known values.
- *
- * Examples of binary operations are the basic arithmetic operations,
- * logical operators AND, OR, and many others.
- *
- * The 'transferdata' parameter is slightly special, following a
- * generic auxiliary data pattern defined in ndarraytypes.h
- * Use NPY_AUXDATA_CLONE and NPY_AUXDATA_FREE to deal with this data.
- *
- */
-typedef void (PyArray_StridedBinaryOp)(char *dst, npy_intp dst_stride,
- char *src0, npy_intp src0_stride,
- char *src1, npy_intp src1_stride,
- npy_intp N, NpyAuxData *transferdata);
+typedef int (PyArray_MaskedStridedUnaryOp)(
+ char *dst, npy_intp dst_stride, char *src, npy_intp src_stride,
+ npy_bool *mask, npy_intp mask_stride,
+ npy_intp N, npy_intp src_itemsize, NpyAuxData *transferdata);
/*
* Gives back a function pointer to a specialized function for copying
* The return value is the number of elements it couldn't copy. A return value
* of 0 means all elements were copied, a larger value means the end of
* the n-dimensional array was reached before 'count' elements were copied.
+ * A negative return value indicates an error occurred.
*
* ndim:
* The number of dimensions of the n-dimensional array.
* cfloat, cdouble, clongdouble, datetime, timedelta#
*/
-NPY_VISIBILITY_HIDDEN void
+NPY_NO_EXPORT void
binsearch_@side@_@suff@(const char *arr, const char *key, char *ret,
npy_intp arr_len, npy_intp key_len,
npy_intp arr_str, npy_intp key_str, npy_intp ret_str,
PyArrayObject *unused);
-NPY_VISIBILITY_HIDDEN int
+NPY_NO_EXPORT int
argbinsearch_@side@_@suff@(const char *arr, const char *key,
const char *sort, char *ret,
npy_intp arr_len, npy_intp key_len,
PyArrayObject *unused);
/**end repeat1**/
-NPY_VISIBILITY_HIDDEN void
+NPY_NO_EXPORT void
npy_binsearch_@side@(const char *arr, const char *key, char *ret,
npy_intp arr_len, npy_intp key_len,
npy_intp arr_str, npy_intp key_str,
npy_intp ret_str, PyArrayObject *cmp);
-NPY_VISIBILITY_HIDDEN int
+NPY_NO_EXPORT int
npy_argbinsearch_@side@(const char *arr, const char *key,
const char *sort, char *ret,
npy_intp arr_len, npy_intp key_len,
#include "config.h"
#include "npy_cpu_features.h"
+#include "npy_cpu_dispatch.h"
#include "numpy/numpyconfig.h"
#include "numpy/npy_cpu.h"
#include "numpy/npy_os.h"
-/* blacklist */
+/* blocklist */
/* Disable broken Sun Workshop Pro math functions */
#ifdef __SUNPRO_C
#endif
+/* Disable broken functions on z/OS */
+#if defined (__MVS__)
+
+#undef HAVE_POWF
+#undef HAVE_EXPF
+#undef HAVE___THREAD
+
+#endif
+
/* Disable broken MS math functions */
#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__MINGW32_VERSION)
--- /dev/null
+#ifndef NPY_CPU_DISPATCH_H_
+#define NPY_CPU_DISPATCH_H_
+/**
+ * This file is part of the NumPy CPU dispatcher. Please have a look at doc/reference/simd-optimizations.html
+ * To get a better understanding of the mechanism behind it.
+ */
+#include "npy_cpu_features.h" // NPY_CPU_HAVE
+#include "numpy/utils.h" // NPY_EXPAND, NPY_CAT
+/**
+ * Including the main configuration header 'npy_cpu_dispatch_config.h'.
+ *
+ * This header is generated by the distutils module 'ccompiler_opt',
+ * and contains all the #definitions and headers for platform-specific instruction-sets
+ * that had been configured through command arguments '--cpu-baseline' and '--cpu-dispatch'.
+ *
+ * It also contains extra C #definitions and macros that are used for implementing
+ * NumPy module's attributes `__cpu_baseline__` and `__cpu_dispaٍtch__`.
+ */
+/**
+ * Note: Always guard the generated headers within 'NPY_DISABLE_OPTIMIZATION',
+ * due the nature of command argument '--disable-optimization',
+ * which is explicitly disabling the module ccompiler_opt.
+ */
+#ifndef NPY_DISABLE_OPTIMIZATION
+ #if defined(__powerpc64__) && !defined(__cplusplus) && defined(bool)
+ /**
+ * "altivec.h" header contains the definitions(bool, vector, pixel),
+ * usually in c++ we undefine them after including the header.
+ * It's better anyway to take them off and use built-in types(__vector, __pixel, __bool) instead,
+ * since c99 supports bool variables which may lead to ambiguous errors.
+ */
+ // backup 'bool' before including '_cpu_dispatch.h', since it may not defined as a compiler token.
+ #define NPY__DISPATCH_DEFBOOL
+ typedef bool npy__dispatch_bkbool;
+ #endif
+ #include "npy_cpu_dispatch_config.h"
+ #ifdef NPY_HAVE_VSX
+ #undef bool
+ #undef vector
+ #undef pixel
+ #ifdef NPY__DISPATCH_DEFBOOL
+ #define bool npy__dispatch_bkbool
+ #endif
+ #endif
+#endif // !NPY_DISABLE_OPTIMIZATION
+/**
+ * Macro NPY_CPU_DISPATCH_CURFX(NAME)
+ *
+ * Returns @NAME suffixed with "_" + "the current target" during compiling
+ * the wrapped sources that generated from the dispatch-able sources according
+ * to the provided configuration statements.
+ *
+ * It also returns @NAME as-is without any suffix when it comes to the baseline or
+ * in case if the optimization is disabled.
+ *
+ * The idea behind this Macro is to allow exporting certain symbols and to
+ * avoid linking duplications due to the nature of the dispatch-able sources.
+ *
+ * Example:
+ * @targets baseline avx avx512_skx vsx3 asimdhp // configration statments
+ *
+ * void NPY_CPU_DISPATCH_CURFX(dispatch_me)(const int *src, int *dst)
+ * {
+ * // the kernel
+ * }
+ *
+ * By assuming the required optimizations are enabled via '--cpu-dspatch' and
+ * the compiler supported them too, then the generated symbols will be named as follows:
+ *
+ * - x86:
+ * dispatch_me(const int*, int*) // baseline
+ * dispatch_me_AVX(const int*, int*)
+ * dispatch_me_AVX512_SKX(const int*, int*)
+ *
+ * - ppc64:
+ * dispatch_me(const int*, int*)
+ * dispatch_me_VSX3(const int*, int*)
+ *
+ * - ARM:
+ * dispatch_me(const int*, int*)
+ * dispatch_me_ASIMHP(const int*, int*)
+ *
+ * - unsupported arch or when optimization is disabled:
+ * dispatch_me(const int*, int*)
+ *
+ * For forward declarations, see 'NPY_CPU_DISPATCH_DECLARE'.
+ */
+#ifdef NPY__CPU_TARGET_CURRENT
+ // 'NPY__CPU_TARGET_CURRENT': only defined by the dispatch-able sources
+ #define NPY_CPU_DISPATCH_CURFX(NAME) NPY_CAT(NPY_CAT(NAME, _), NPY__CPU_TARGET_CURRENT)
+#else
+ #define NPY_CPU_DISPATCH_CURFX(NAME) NPY_EXPAND(NAME)
+#endif
+/**
+ * Defining the default behavior for the configurable macros of dispatch-able sources,
+ * 'NPY__CPU_DISPATCH_CALL(...)' and 'NPY__CPU_DISPATCH_BASELINE_CALL(...)'
+ *
+ * These macros are defined inside the generated config files that been derived from
+ * the configuration statements of the dispatch-able sources.
+ *
+ * The generated config file takes the same name of the dispatch-able source with replacing
+ * the extension to '.h' instead of '.c', and it should be treated as a header template.
+ *
+ * For more clarification, please have a look at doc/reference/simd-optimizations.html.
+ */
+#ifndef NPY_DISABLE_OPTIMIZATION
+ #define NPY__CPU_DISPATCH_BASELINE_CALL(CB, ...) \
+ &&"Expected config header of the dispatch-able source";
+ #define NPY__CPU_DISPATCH_CALL(CHK, CB, ...) \
+ &&"Expected config header of the dispatch-able source";
+#else
+ /**
+ * We assume by default that all configuration statements contains 'baseline' option however,
+ * if the dispatch-able source doesn't require it, then the dispatch-able source and following macros
+ * need to be guard it with '#ifndef NPY_DISABLE_OPTIMIZATION'
+ */
+ #define NPY__CPU_DISPATCH_BASELINE_CALL(CB, ...) \
+ NPY_EXPAND(CB(__VA_ARGS__))
+ #define NPY__CPU_DISPATCH_CALL(CHK, CB, ...)
+#endif // !NPY_DISABLE_OPTIMIZATION
+/**
+ * Macro NPY_CPU_DISPATCH_DECLARE(LEFT, ...) is used to provide forward
+ * declarations for the exported variables and functions that defined inside
+ * the dispatch-able sources.
+ *
+ * The first argument should ends with the exported function or variable name,
+ * while the Macro pasting the extra arguments.
+ *
+ * Examples:
+ * #ifndef NPY_DISABLE_OPTIMIZATION
+ * #include "dispatchable_source_name.dispatch.h"
+ * #endif
+ *
+ * NPY_CPU_DISPATCH_DECLARE(void dispatch_me, (const int*, int*))
+ * NPY_CPU_DISPATCH_DECLARE(extern cb_type callback_tab, [TAB_SIZE])
+ *
+ * By assuming the provided config header derived from a dispatch-able source,
+ * that configured with "@targets baseline sse41 vsx3 asimdhp",
+ * they supported by the compiler and enabled via '--cpu-dspatch',
+ * then the prototype declrations at the above example will equivalent to the follows:
+ *
+ * - x86:
+ * void dispatch_me(const int*, int*); // baseline
+ * void dispatch_me_SSE41(const int*, int*);
+ *
+ * extern cb_type callback_tab[TAB_SIZE];
+ * extern cb_type callback_tab_SSE41[TAB_SIZE];
+ *
+ * - ppc64:
+ * void dispatch_me(const int*, int*);
+ * void dispatch_me_VSX3(const int*, int*);
+ *
+ * extern cb_type callback_tab[TAB_SIZE];
+ * extern cb_type callback_tab_VSX3[TAB_SIZE];
+ *
+ * - ARM:
+ * void dispatch_me(const int*, int*);
+ * void dispatch_me_ASIMDHP(const int*, int*);
+ *
+ * extern cb_type callback_tab[TAB_SIZE];
+ * extern cb_type callback_tab_ASIMDHP[TAB_SIZE];
+ *
+ * - unsupported arch or when optimization is disabled:
+ * void dispatch_me(const int*, int*);
+ * extern cb_type callback_tab[TAB_SIZE];
+ *
+ * For runtime dispatching, see 'NPY_CPU_DISPATCH_CALL'
+ */
+#define NPY_CPU_DISPATCH_DECLARE(...) \
+ NPY__CPU_DISPATCH_CALL(NPY_CPU_DISPATCH_DECLARE_CHK_, NPY_CPU_DISPATCH_DECLARE_CB_, __VA_ARGS__) \
+ NPY__CPU_DISPATCH_BASELINE_CALL(NPY_CPU_DISPATCH_DECLARE_BASE_CB_, __VA_ARGS__)
+// Preprocessor callbacks
+#define NPY_CPU_DISPATCH_DECLARE_CB_(DUMMY, TARGET_NAME, LEFT, ...) \
+ NPY_CAT(NPY_CAT(LEFT, _), TARGET_NAME) __VA_ARGS__;
+#define NPY_CPU_DISPATCH_DECLARE_BASE_CB_(LEFT, ...) \
+ LEFT __VA_ARGS__;
+// Dummy CPU runtime checking
+#define NPY_CPU_DISPATCH_DECLARE_CHK_(FEATURE)
+/**
+ * Macro NPY_CPU_DISPATCH_DECLARE_XB(LEFT, ...)
+ *
+ * Same as `NPY_CPU_DISPATCH_DECLARE` but exclude the baseline declaration even
+ * if it was provided within the configration statments.
+ */
+#define NPY_CPU_DISPATCH_DECLARE_XB(...) \
+ NPY__CPU_DISPATCH_CALL(NPY_CPU_DISPATCH_DECLARE_CHK_, NPY_CPU_DISPATCH_DECLARE_CB_, __VA_ARGS__)
+/**
+ * Macro NPY_CPU_DISPATCH_CALL(LEFT, ...) is used for runtime dispatching
+ * of the exported functions and variables within the dispatch-able sources
+ * according to the highested interesed CPU features that supported by the
+ * running machine depending on the required optimizations.
+ *
+ * The first argument should ends with the exported function or variable name,
+ * while the Macro pasting the extra arguments.
+ *
+ * Example:
+ * Assume we have a dispatch-able source exporting the following function:
+ *
+ * @targets baseline avx2 avx512_skx // configration statments
+ *
+ * void NPY_CPU_DISPATCH_CURFX(dispatch_me)(const int *src, int *dst)
+ * {
+ * // the kernel
+ * }
+ *
+ * In order to call or to assign the pointer of it from outside the dispatch-able source,
+ * you have to use this Macro as follows:
+ *
+ * // bring the generated config header of the dispatch-able source
+ * #ifndef NPY_DISABLE_OPTIMIZATION
+ * #include "dispatchable_source_name.dispatch.h"
+ * #endif
+ * // forward declaration
+ * NPY_CPU_DISPATCH_DECLARE(dispatch_me, (const int *src, int *dst))
+ *
+ * typedef void(*func_type)(const int*, int*);
+ * func_type the_callee(const int *src, int *dst, func_type *cb)
+ * {
+ * // direct call
+ * NPY_CPU_DISPATCH_CALL(dispatch_me, (src, dst));
+ * // assign the pointer
+ * *cb = NPY_CPU_DISPATCH_CALL(dispatch_me);
+ * // or
+ * NPY_CPU_DISPATCH_CALL(*cb = dispatch_me);
+ * // return the pointer
+ * return NPY_CPU_DISPATCH_CALL(dispatch_me);
+ * }
+ */
+#define NPY_CPU_DISPATCH_CALL(...) \
+ NPY__CPU_DISPATCH_CALL(NPY_CPU_HAVE, NPY_CPU_DISPATCH_CALL_CB_, __VA_ARGS__) \
+ NPY__CPU_DISPATCH_BASELINE_CALL(NPY_CPU_DISPATCH_CALL_BASE_CB_, __VA_ARGS__)
+// Preprocessor callbacks
+#define NPY_CPU_DISPATCH_CALL_CB_(TESTED_FEATURES, TARGET_NAME, LEFT, ...) \
+ (TESTED_FEATURES) ? (NPY_CAT(NPY_CAT(LEFT, _), TARGET_NAME) __VA_ARGS__) :
+#define NPY_CPU_DISPATCH_CALL_BASE_CB_(LEFT, ...) \
+ (LEFT __VA_ARGS__)
+/**
+ * Macro NPY_CPU_DISPATCH_CALL_XB(LEFT, ...)
+ *
+ * Same as `NPY_CPU_DISPATCH_DECLARE` but exclude the baseline declaration even
+ * if it was provided within the configration statements.
+ * Returns void.
+ */
+#define NPY_CPU_DISPATCH_CALL_XB_CB_(TESTED_FEATURES, TARGET_NAME, LEFT, ...) \
+ (TESTED_FEATURES) ? (void) (NPY_CAT(NPY_CAT(LEFT, _), TARGET_NAME) __VA_ARGS__) :
+#define NPY_CPU_DISPATCH_CALL_XB(...) \
+ NPY__CPU_DISPATCH_CALL(NPY_CPU_HAVE, NPY_CPU_DISPATCH_CALL_XB_CB_, __VA_ARGS__) \
+ ((void) 0 /* discarded expression value */)
+/**
+ * Macro NPY_CPU_DISPATCH_CALL_ALL(LEFT, ...)
+ *
+ * Same as `NPY_CPU_DISPATCH_CALL` but dispatching all the required optimizations for
+ * the exported functions and variables instead of highest interested one.
+ * Returns void.
+ */
+#define NPY_CPU_DISPATCH_CALL_ALL(...) \
+ (NPY__CPU_DISPATCH_CALL(NPY_CPU_HAVE, NPY_CPU_DISPATCH_CALL_ALL_CB_, __VA_ARGS__) \
+ NPY__CPU_DISPATCH_BASELINE_CALL(NPY_CPU_DISPATCH_CALL_ALL_BASE_CB_, __VA_ARGS__))
+// Preprocessor callbacks
+#define NPY_CPU_DISPATCH_CALL_ALL_CB_(TESTED_FEATURES, TARGET_NAME, LEFT, ...) \
+ ((TESTED_FEATURES) ? (NPY_CAT(NPY_CAT(LEFT, _), TARGET_NAME) __VA_ARGS__) : (void) 0),
+#define NPY_CPU_DISPATCH_CALL_ALL_BASE_CB_(LEFT, ...) \
+ ( LEFT __VA_ARGS__ )
+
+#endif // NPY_CPU_DISPATCH_H_
#include "npy_cpu_features.h"
+#include "npy_cpu_dispatch.h" // To guarantee the CPU baseline definitions are in scope.
#include "numpy/npy_common.h" // for NPY_INLINE
-#include "numpy/npy_cpu.h" // To guarantee of having CPU definitions in scope.
+#include "numpy/npy_cpu.h" // To guarantee the CPU definitions are in scope.
/******************** Private Definitions *********************/
// Almost detect all CPU features in runtime
static void
npy__cpu_init_features(void);
+/*
+ * Disable CPU dispatched features at runtime if environment variable
+ * 'NPY_DISABLE_CPU_FEATURES' is defined.
+ * Multiple features can be present, and separated by space, comma, or tab.
+ * Raises an error if parsing fails or if the feature was not enabled
+*/
+static int
+npy__cpu_try_disable_env(void);
+
+/* Ensure the build's CPU baseline features are supported at runtime */
+static int
+npy__cpu_validate_baseline(void);
/******************** Public Definitions *********************/
npy_cpu_init(void)
{
npy__cpu_init_features();
+ if (npy__cpu_validate_baseline() < 0) {
+ return -1;
+ }
+ if (npy__cpu_try_disable_env() < 0) {
+ return -1;
+ }
return 0;
}
return dict;
}
+#define NPY__CPU_PYLIST_APPEND_CB(FEATURE, LIST) \
+ item = PyUnicode_FromString(NPY_TOSTRING(FEATURE)); \
+ if (item == NULL) { \
+ Py_DECREF(LIST); \
+ return NULL; \
+ } \
+ PyList_SET_ITEM(LIST, index++, item);
+
+NPY_VISIBILITY_HIDDEN PyObject *
+npy_cpu_baseline_list(void)
+{
+#if !defined(NPY_DISABLE_OPTIMIZATION) && NPY_WITH_CPU_BASELINE_N > 0
+ PyObject *list = PyList_New(NPY_WITH_CPU_BASELINE_N), *item;
+ int index = 0;
+ if (list != NULL) {
+ NPY_WITH_CPU_BASELINE_CALL(NPY__CPU_PYLIST_APPEND_CB, list)
+ }
+ return list;
+#else
+ return PyList_New(0);
+#endif
+}
+
+NPY_VISIBILITY_HIDDEN PyObject *
+npy_cpu_dispatch_list(void)
+{
+#if !defined(NPY_DISABLE_OPTIMIZATION) && NPY_WITH_CPU_DISPATCH_N > 0
+ PyObject *list = PyList_New(NPY_WITH_CPU_DISPATCH_N), *item;
+ int index = 0;
+ if (list != NULL) {
+ NPY_WITH_CPU_DISPATCH_CALL(NPY__CPU_PYLIST_APPEND_CB, list)
+ }
+ return list;
+#else
+ return PyList_New(0);
+#endif
+}
+
+/******************** Private Definitions *********************/
+#define NPY__CPU_FEATURE_ID_CB(FEATURE, WITH_FEATURE) \
+ if (strcmp(NPY_TOSTRING(FEATURE), WITH_FEATURE) == 0) \
+ return NPY_CAT(NPY_CPU_FEATURE_, FEATURE);
+/**
+ * Returns CPU feature's ID, if the 'feature' was part of baseline
+ * features that had been configured via --cpu-baseline
+ * otherwise it returns 0
+*/
+static NPY_INLINE int
+npy__cpu_baseline_fid(const char *feature)
+{
+#if !defined(NPY_DISABLE_OPTIMIZATION) && NPY_WITH_CPU_BASELINE_N > 0
+ NPY_WITH_CPU_BASELINE_CALL(NPY__CPU_FEATURE_ID_CB, feature)
+#endif
+ return 0;
+}
+/**
+ * Returns CPU feature's ID, if the 'feature' was part of dispatched
+ * features that had been configured via --cpu-dispatch
+ * otherwise it returns 0
+*/
+static NPY_INLINE int
+npy__cpu_dispatch_fid(const char *feature)
+{
+#if !defined(NPY_DISABLE_OPTIMIZATION) && NPY_WITH_CPU_DISPATCH_N > 0
+ NPY_WITH_CPU_DISPATCH_CALL(NPY__CPU_FEATURE_ID_CB, feature)
+#endif
+ return 0;
+}
+
+static int
+npy__cpu_validate_baseline(void)
+{
+#if !defined(NPY_DISABLE_OPTIMIZATION) && NPY_WITH_CPU_BASELINE_N > 0
+ char baseline_failure[sizeof(NPY_WITH_CPU_BASELINE) + 1];
+ char *fptr = &baseline_failure[0];
+
+ #define NPY__CPU_VALIDATE_CB(FEATURE, DUMMY) \
+ if (!npy__cpu_have[NPY_CAT(NPY_CPU_FEATURE_, FEATURE)]) { \
+ const int size = sizeof(NPY_TOSTRING(FEATURE)); \
+ memcpy(fptr, NPY_TOSTRING(FEATURE), size); \
+ fptr[size] = ' '; fptr += size + 1; \
+ }
+ NPY_WITH_CPU_BASELINE_CALL(NPY__CPU_VALIDATE_CB, DUMMY) // extra arg for msvc
+ *fptr = '\0';
+
+ if (baseline_failure[0] != '\0') {
+ *(fptr-1) = '\0'; // trim the last space
+ PyErr_Format(PyExc_RuntimeError,
+ "NumPy was built with baseline optimizations: \n"
+ "(" NPY_WITH_CPU_BASELINE ") but your machine doesn't support:\n(%s).",
+ baseline_failure
+ );
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+static int
+npy__cpu_try_disable_env(void)
+{
+ char *disenv = getenv("NPY_DISABLE_CPU_FEATURES");
+ if (disenv == NULL || disenv[0] == 0) {
+ return 0;
+ }
+ #define NPY__CPU_ENV_ERR_HEAD \
+ "During parsing environment variable 'NPY_DISABLE_CPU_FEATURES':\n"
+
+#if !defined(NPY_DISABLE_OPTIMIZATION) && NPY_WITH_CPU_DISPATCH_N > 0
+ #define NPY__MAX_VAR_LEN 1024 // More than enough for this era
+ size_t var_len = strlen(disenv) + 1;
+ if (var_len > NPY__MAX_VAR_LEN) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Length of environment variable 'NPY_DISABLE_CPU_FEATURES' is %d, only %d accepted",
+ var_len, NPY__MAX_VAR_LEN - 1
+ );
+ return -1;
+ }
+ char disable_features[NPY__MAX_VAR_LEN];
+ memcpy(disable_features, disenv, var_len);
+
+ char nexist[NPY__MAX_VAR_LEN];
+ char *nexist_cur = &nexist[0];
+
+ char notsupp[sizeof(NPY_WITH_CPU_DISPATCH) + 1];
+ char *notsupp_cur = ¬supp[0];
+
+ //comma and space including (htab, vtab, CR, LF, FF)
+ const char *delim = ", \t\v\r\n\f";
+ char *feature = strtok(disable_features, delim);
+ while (feature) {
+ if (npy__cpu_baseline_fid(feature) > 0) {
+ PyErr_Format(PyExc_RuntimeError,
+ NPY__CPU_ENV_ERR_HEAD
+ "You cannot disable CPU feature '%s', since it is part of "
+ "the baseline optimizations:\n"
+ "(" NPY_WITH_CPU_BASELINE ").",
+ feature
+ );
+ return -1;
+ }
+ // check if the feature is part of dispatched features
+ int feature_id = npy__cpu_dispatch_fid(feature);
+ if (feature_id == 0) {
+ int flen = strlen(feature);
+ memcpy(nexist_cur, feature, flen);
+ nexist_cur[flen] = ' '; nexist_cur += flen + 1;
+ goto next;
+ }
+ // check if the feature supported by the running machine
+ if (!npy__cpu_have[feature_id]) {
+ int flen = strlen(feature);
+ memcpy(notsupp_cur, feature, flen);
+ notsupp_cur[flen] = ' '; notsupp_cur += flen + 1;
+ goto next;
+ }
+ // Finaly we can disable it
+ npy__cpu_have[feature_id] = 0;
+ next:
+ feature = strtok(NULL, delim);
+ }
+
+ *nexist_cur = '\0';
+ if (nexist[0] != '\0') {
+ *(nexist_cur-1) = '\0'; // trim the last space
+ if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1,
+ NPY__CPU_ENV_ERR_HEAD
+ "You cannot disable CPU features (%s), since "
+ "they are not part of the dispatched optimizations\n"
+ "(" NPY_WITH_CPU_DISPATCH ").",
+ nexist
+ ) < 0) {
+ return -1;
+ }
+ }
+
+ *notsupp_cur = '\0';
+ if (notsupp[0] != '\0') {
+ *(notsupp_cur-1) = '\0'; // trim the last space
+ if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1,
+ NPY__CPU_ENV_ERR_HEAD
+ "You cannot disable CPU features (%s), since "
+ "they are not supported by your machine.",
+ notsupp
+ ) < 0) {
+ return -1;
+ }
+ }
+#else
+ if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1,
+ NPY__CPU_ENV_ERR_HEAD
+ "You cannot use environment variable 'NPY_DISABLE_CPU_FEATURES', since "
+ #ifdef NPY_DISABLE_OPTIMIZATION
+ "the NumPy library was compiled with optimization disabled."
+ #else
+ "the NumPy library was compiled without any dispatched optimizations."
+ #endif
+ ) < 0) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
/****************************************************************
* This section is reserved to defining @npy__cpu_init_features
* for each CPU architecture, please try to keep it clean. Ty
* so we play it safe
*/
#include <stdio.h>
-#include <fcntl.h>
-
-#define NPY__HWCAP 16
-#define NPY__HWCAP2 26
-
-// arch/arm/include/uapi/asm/hwcap.h
-#define NPY__HWCAP_HALF (1 << 1)
-#define NPY__HWCAP_NEON (1 << 12)
-#define NPY__HWCAP_VFPv3 (1 << 13)
-#define NPY__HWCAP_VFPv4 (1 << 16)
-#define NPY__HWCAP2_AES (1 << 0)
-#define NPY__HWCAP2_PMULL (1 << 1)
-#define NPY__HWCAP2_SHA1 (1 << 2)
-#define NPY__HWCAP2_SHA2 (1 << 3)
-#define NPY__HWCAP2_CRC32 (1 << 4)
-// arch/arm64/include/uapi/asm/hwcap.h
-#define NPY__HWCAP_FP (1 << 0)
-#define NPY__HWCAP_ASIMD (1 << 1)
-#define NPY__HWCAP_FPHP (1 << 9)
-#define NPY__HWCAP_ASIMDHP (1 << 10)
-#define NPY__HWCAP_ASIMDDP (1 << 20)
-#define NPY__HWCAP_ASIMDFHM (1 << 23)
+#include "npy_cpuinfo_parser.h"
__attribute__((weak)) unsigned long getauxval(unsigned long); // linker should handle it
static int
}
if (hwcap == 0 && hwcap2 == 0) {
/*
- * FIXME: failback to compiler definitions,
- * BTW we can parse /proc/cpuinfo for badly patched kernels
+ * try parsing with /proc/cpuinfo, if sandboxed
+ * failback to compiler definitions
*/
- return 0;
+ if(!get_feature_from_proc_cpuinfo(&hwcap, &hwcap2)) {
+ return 0;
+ }
}
#ifdef __arm__
// Detect Arm8 (aarch32 state)
return;
#endif
// We have nothing else todo
-#if defined(NPY_HAVE_NEON_ARM8) || defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH >= 8)
+#if defined(NPY_HAVE_ASIMD) || defined(__aarch64__) || (defined(__ARM_ARCH) && __ARM_ARCH >= 8)
#if defined(NPY_HAVE_FPHP) || defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
npy__cpu_have[NPY_CPU_FEATURE_FPHP] = 1;
#endif
static void
npy__cpu_init_features(void)
{
+ /*
+ * just in case if the compiler doesn't respect ANSI
+ * but for knowing paltforms it still nessecery, because @npy__cpu_init_features
+ * may called multiple of times and we need to clear the disabled features by
+ * ENV Var or maybe in the future we can support other methods like
+ * global variables, go back to @npy__cpu_try_disable_env for more understanding
+ */
+ memset(npy__cpu_have, 0, sizeof(npy__cpu_have[0]) * NPY_CPU_FEATURE_MAX);
}
#endif
#ifndef _NPY_CPU_FEATURES_H_
#define _NPY_CPU_FEATURES_H_
-#include "numpy/numpyconfig.h" // for NPY_VISIBILITY_HIDDEN
#include <Python.h> // for PyObject
+#include "numpy/numpyconfig.h" // for NPY_VISIBILITY_HIDDEN
#ifdef __cplusplus
extern "C" {
/*
* Initialize CPU features
+ *
+ * This function
+ * - detects runtime CPU features
+ * - check that baseline CPU features are present
+ * - uses 'NPY_DISABLE_CPU_FEATURES' to disable dispatchable features
+ *
+ * It will set a RuntimeError when
+ * - CPU baseline features from the build are not supported at runtime
+ * - 'NPY_DISABLE_CPU_FEATURES' tries to disable a baseline feature
+ * and will warn if 'NPY_DISABLE_CPU_FEATURES' tries to disable a feature that
+ * is not disabled (the machine or build does not support it, or the project was
+ * not built with any feature optimization support)
* return 0 on success otherwise return -1
-*/
+ */
NPY_VISIBILITY_HIDDEN int
npy_cpu_init(void);
*/
NPY_VISIBILITY_HIDDEN PyObject *
npy_cpu_features_dict(void);
+/*
+ * Return a new a Python list contains the minimal set of required optimizations
+ * that supported by the compiler and platform according to the specified
+ * values to command argument '--cpu-baseline'.
+ *
+ * This function is mainly used to implement umath's attrbute '__cpu_baseline__',
+ * and the items are sorted from the lowest to highest interest.
+ *
+ * For example, according to the default build configuration and by assuming the compiler
+ * support all the involved optimizations then the returned list should equivalent to:
+ *
+ * On x86: ['SSE', 'SSE2']
+ * On x64: ['SSE', 'SSE2', 'SSE3']
+ * On armhf: []
+ * On aarch64: ['NEON', 'NEON_FP16', 'NEON_VPFV4', 'ASIMD']
+ * On ppc64: []
+ * On ppc64le: ['VSX', 'VSX2']
+ * On any other arch or if the optimization is disabled: []
+ */
+NPY_VISIBILITY_HIDDEN PyObject *
+npy_cpu_baseline_list(void);
+/*
+ * Return a new a Python list contains the dispatched set of additional optimizations
+ * that supported by the compiler and platform according to the specified
+ * values to command argument '--cpu-dispatch'.
+ *
+ * This function is mainly used to implement umath's attrbute '__cpu_dispatch__',
+ * and the items are sorted from the lowest to highest interest.
+ *
+ * For example, according to the default build configuration and by assuming the compiler
+ * support all the involved optimizations then the returned list should equivalent to:
+ *
+ * On x86: ['SSE3', 'SSSE3', 'SSE41', 'POPCNT', 'SSE42', 'AVX', 'F16C', 'FMA3', 'AVX2', 'AVX512F', ...]
+ * On x64: ['SSSE3', 'SSE41', 'POPCNT', 'SSE42', 'AVX', 'F16C', 'FMA3', 'AVX2', 'AVX512F', ...]
+ * On armhf: ['NEON', 'NEON_FP16', 'NEON_VPFV4', 'ASIMD', 'ASIMDHP', 'ASIMDDP', 'ASIMDFHM']
+ * On aarch64: ['ASIMDHP', 'ASIMDDP', 'ASIMDFHM']
+ * On ppc64: ['VSX', 'VSX2', 'VSX3']
+ * On ppc64le: ['VSX3']
+ * On any other arch or if the optimization is disabled: []
+ */
+NPY_VISIBILITY_HIDDEN PyObject *
+npy_cpu_dispatch_list(void);
#ifdef __cplusplus
}
--- /dev/null
+/*\r
+ * Copyright (C) 2010 The Android Open Source Project\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * * Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ * notice, this list of conditions and the following disclaimer in\r
+ * the documentation and/or other materials provided with the\r
+ * distribution.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS\r
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\r
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\r
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+ * SUCH DAMAGE.\r
+ */\r
+#ifndef __NPY_CPUINFO_PARSER_H__\r
+#define __NPY_CPUINFO_PARSER_H__\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <fcntl.h>\r
+#include <string.h>\r
+#include <stddef.h>\r
+\r
+#define NPY__HWCAP 16\r
+#define NPY__HWCAP2 26\r
+\r
+// arch/arm/include/uapi/asm/hwcap.h\r
+#define NPY__HWCAP_HALF (1 << 1)\r
+#define NPY__HWCAP_NEON (1 << 12)\r
+#define NPY__HWCAP_VFPv3 (1 << 13)\r
+#define NPY__HWCAP_VFPv4 (1 << 16)\r
+#define NPY__HWCAP2_AES (1 << 0)\r
+#define NPY__HWCAP2_PMULL (1 << 1)\r
+#define NPY__HWCAP2_SHA1 (1 << 2)\r
+#define NPY__HWCAP2_SHA2 (1 << 3)\r
+#define NPY__HWCAP2_CRC32 (1 << 4)\r
+// arch/arm64/include/uapi/asm/hwcap.h\r
+#define NPY__HWCAP_FP (1 << 0)\r
+#define NPY__HWCAP_ASIMD (1 << 1)\r
+#define NPY__HWCAP_FPHP (1 << 9)\r
+#define NPY__HWCAP_ASIMDHP (1 << 10)\r
+#define NPY__HWCAP_ASIMDDP (1 << 20)\r
+#define NPY__HWCAP_ASIMDFHM (1 << 23)\r
+/* \r
+ * Get the size of a file by reading it until the end. This is needed\r
+ * because files under /proc do not always return a valid size when\r
+ * using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed.\r
+ */\r
+static int\r
+get_file_size(const char* pathname)\r
+{\r
+ int fd, result = 0;\r
+ char buffer[256];\r
+\r
+ fd = open(pathname, O_RDONLY);\r
+ if (fd < 0) {\r
+ return -1;\r
+ }\r
+\r
+ for (;;) {\r
+ int ret = read(fd, buffer, sizeof buffer);\r
+ if (ret < 0) {\r
+ if (errno == EINTR) {\r
+ continue;\r
+ }\r
+ break;\r
+ }\r
+ if (ret == 0) {\r
+ break;\r
+ }\r
+ result += ret;\r
+ }\r
+ close(fd);\r
+ return result;\r
+}\r
+\r
+/* \r
+ * Read the content of /proc/cpuinfo into a user-provided buffer.\r
+ * Return the length of the data, or -1 on error. Does *not*\r
+ * zero-terminate the content. Will not read more\r
+ * than 'buffsize' bytes.\r
+ */\r
+static int\r
+read_file(const char* pathname, char* buffer, size_t buffsize)\r
+{\r
+ int fd, count;\r
+\r
+ fd = open(pathname, O_RDONLY);\r
+ if (fd < 0) {\r
+ return -1;\r
+ }\r
+ count = 0;\r
+ while (count < (int)buffsize) {\r
+ int ret = read(fd, buffer + count, buffsize - count);\r
+ if (ret < 0) {\r
+ if (errno == EINTR) {\r
+ continue;\r
+ }\r
+ if (count == 0) {\r
+ count = -1;\r
+ }\r
+ break;\r
+ }\r
+ if (ret == 0) {\r
+ break;\r
+ }\r
+ count += ret;\r
+ }\r
+ close(fd);\r
+ return count;\r
+}\r
+\r
+/* \r
+ * Extract the content of a the first occurence of a given field in\r
+ * the content of /proc/cpuinfo and return it as a heap-allocated\r
+ * string that must be freed by the caller.\r
+ *\r
+ * Return NULL if not found\r
+ */\r
+static char*\r
+extract_cpuinfo_field(const char* buffer, int buflen, const char* field)\r
+{\r
+ int fieldlen = strlen(field);\r
+ const char* bufend = buffer + buflen;\r
+ char* result = NULL;\r
+ int len;\r
+ const char *p, *q;\r
+\r
+ /* Look for first field occurence, and ensures it starts the line. */\r
+ p = buffer;\r
+ for (;;) {\r
+ p = memmem(p, bufend-p, field, fieldlen);\r
+ if (p == NULL) {\r
+ goto EXIT;\r
+ }\r
+\r
+ if (p == buffer || p[-1] == '\n') {\r
+ break;\r
+ }\r
+\r
+ p += fieldlen;\r
+ }\r
+\r
+ /* Skip to the first column followed by a space */\r
+ p += fieldlen;\r
+ p = memchr(p, ':', bufend-p);\r
+ if (p == NULL || p[1] != ' ') {\r
+ goto EXIT;\r
+ }\r
+\r
+ /* Find the end of the line */\r
+ p += 2;\r
+ q = memchr(p, '\n', bufend-p);\r
+ if (q == NULL) {\r
+ q = bufend;\r
+ }\r
+\r
+ /* Copy the line into a heap-allocated buffer */\r
+ len = q - p;\r
+ result = malloc(len + 1);\r
+ if (result == NULL) {\r
+ goto EXIT;\r
+ }\r
+\r
+ memcpy(result, p, len);\r
+ result[len] = '\0';\r
+\r
+EXIT:\r
+ return result;\r
+}\r
+\r
+/* \r
+ * Checks that a space-separated list of items contains one given 'item'.\r
+ * Returns 1 if found, 0 otherwise.\r
+ */\r
+static int\r
+has_list_item(const char* list, const char* item)\r
+{\r
+ const char* p = list;\r
+ int itemlen = strlen(item);\r
+\r
+ if (list == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ while (*p) {\r
+ const char* q;\r
+\r
+ /* skip spaces */\r
+ while (*p == ' ' || *p == '\t') {\r
+ p++;\r
+ }\r
+\r
+ /* find end of current list item */\r
+ q = p;\r
+ while (*q && *q != ' ' && *q != '\t') {\r
+ q++;\r
+ }\r
+\r
+ if (itemlen == q-p && !memcmp(p, item, itemlen)) {\r
+ return 1;\r
+ }\r
+\r
+ /* skip to next item */\r
+ p = q;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static void setHwcap(char* cpuFeatures, unsigned long* hwcap) {\r
+ *hwcap |= has_list_item(cpuFeatures, "neon") ? NPY__HWCAP_NEON : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "half") ? NPY__HWCAP_HALF : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "vfpv3") ? NPY__HWCAP_VFPv3 : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "vfpv4") ? NPY__HWCAP_VFPv4 : 0;\r
+\r
+ *hwcap |= has_list_item(cpuFeatures, "asimd") ? NPY__HWCAP_ASIMD : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "fp") ? NPY__HWCAP_FP : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "fphp") ? NPY__HWCAP_FPHP : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "asimdhp") ? NPY__HWCAP_ASIMDHP : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "asimddp") ? NPY__HWCAP_ASIMDDP : 0;\r
+ *hwcap |= has_list_item(cpuFeatures, "asimdfhm") ? NPY__HWCAP_ASIMDFHM : 0;\r
+}\r
+\r
+static int\r
+get_feature_from_proc_cpuinfo(unsigned long *hwcap, unsigned long *hwcap2) {\r
+ char* cpuinfo = NULL;\r
+ int cpuinfo_len;\r
+ cpuinfo_len = get_file_size("/proc/cpuinfo");\r
+ if (cpuinfo_len < 0) {\r
+ return 0;\r
+ }\r
+ cpuinfo = malloc(cpuinfo_len);\r
+ if (cpuinfo == NULL) {\r
+ return 0;\r
+ }\r
+ cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, cpuinfo_len);\r
+ char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features");\r
+ if(cpuFeatures == NULL) {\r
+ return 0;\r
+ }\r
+ setHwcap(cpuFeatures, hwcap);\r
+ *hwcap2 |= *hwcap;\r
+ *hwcap2 |= has_list_item(cpuFeatures, "aes") ? NPY__HWCAP2_AES : 0;\r
+ *hwcap2 |= has_list_item(cpuFeatures, "pmull") ? NPY__HWCAP2_PMULL : 0;\r
+ *hwcap2 |= has_list_item(cpuFeatures, "sha1") ? NPY__HWCAP2_SHA1 : 0;\r
+ *hwcap2 |= has_list_item(cpuFeatures, "sha2") ? NPY__HWCAP2_SHA2 : 0;\r
+ *hwcap2 |= has_list_item(cpuFeatures, "crc32") ? NPY__HWCAP2_CRC32 : 0;\r
+ return 1;\r
+}\r
+#endif\r
NPY_INLINE static void
npy_cache_import(const char *module, const char *attr, PyObject **cache)
{
- if (*cache == NULL) {
+ if (NPY_UNLIKELY(*cache == NULL)) {
PyObject *mod = PyImport_ImportModule(module);
if (mod != NULL) {
* npy_cdouble, npy_clongdouble#
*/
-NPY_VISIBILITY_HIDDEN int introselect_@suff@(@type@ *v, npy_intp num,
+NPY_NO_EXPORT int introselect_@suff@(@type@ *v, npy_intp num,
npy_intp kth,
npy_intp * pivots,
npy_intp * npiv,
void *NOT_USED);
-NPY_VISIBILITY_HIDDEN int aintroselect_@suff@(@type@ *v, npy_intp* tosort, npy_intp num,
+NPY_NO_EXPORT int aintroselect_@suff@(@type@ *v, npy_intp* tosort, npy_intp num,
npy_intp kth,
npy_intp * pivots,
npy_intp * npiv,
* cfloat, cdouble, clongdouble, datetime, timedelta#
*/
-int quicksort_@suff@(void *vec, npy_intp cnt, void *null);
-int heapsort_@suff@(void *vec, npy_intp cnt, void *null);
-int mergesort_@suff@(void *vec, npy_intp cnt, void *null);
-int timsort_@suff@(void *vec, npy_intp cnt, void *null);
-int aquicksort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int aheapsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int amergesort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
-int atimsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+NPY_NO_EXPORT int quicksort_@suff@(void *vec, npy_intp cnt, void *null);
+NPY_NO_EXPORT int heapsort_@suff@(void *vec, npy_intp cnt, void *null);
+NPY_NO_EXPORT int mergesort_@suff@(void *vec, npy_intp cnt, void *null);
+NPY_NO_EXPORT int timsort_@suff@(void *vec, npy_intp cnt, void *null);
+NPY_NO_EXPORT int aquicksort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+NPY_NO_EXPORT int aheapsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+NPY_NO_EXPORT int amergesort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+NPY_NO_EXPORT int atimsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
/**end repeat**/
* longlong, ulonglong#
*/
-int radixsort_@suff@(void *vec, npy_intp cnt, void *null);
-int aradixsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
+NPY_NO_EXPORT int radixsort_@suff@(void *vec, npy_intp cnt, void *null);
+NPY_NO_EXPORT int aradixsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *null);
/**end repeat**/
* #suff = string, unicode#
*/
-int quicksort_@suff@(void *vec, npy_intp cnt, void *arr);
-int heapsort_@suff@(void *vec, npy_intp cnt, void *arr);
-int mergesort_@suff@(void *vec, npy_intp cnt, void *arr);
-int timsort_@suff@(void *vec, npy_intp cnt, void *arr);
-int aquicksort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
-int aheapsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
-int amergesort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
-int atimsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int quicksort_@suff@(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int heapsort_@suff@(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int mergesort_@suff@(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int timsort_@suff@(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int aquicksort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int aheapsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int amergesort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int atimsort_@suff@(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
/**end repeat**/
*/
-int npy_quicksort(void *vec, npy_intp cnt, void *arr);
-int npy_heapsort(void *vec, npy_intp cnt, void *arr);
-int npy_mergesort(void *vec, npy_intp cnt, void *arr);
-int npy_timsort(void *vec, npy_intp cnt, void *arr);
-int npy_aquicksort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
-int npy_aheapsort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
-int npy_amergesort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
-int npy_atimsort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_quicksort(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_heapsort(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_mergesort(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_timsort(void *vec, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_aquicksort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_aheapsort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_amergesort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
+NPY_NO_EXPORT int npy_atimsort(void *vec, npy_intp *ind, npy_intp cnt, void *arr);
#endif
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX2_ARITHMETIC_H
+#define _NPY_SIMD_AVX2_ARITHMETIC_H
+
+/***************************
+ * Addition
+ ***************************/
+// non-saturated
+#define npyv_add_u8 _mm256_add_epi8
+#define npyv_add_s8 _mm256_add_epi8
+#define npyv_add_u16 _mm256_add_epi16
+#define npyv_add_s16 _mm256_add_epi16
+#define npyv_add_u32 _mm256_add_epi32
+#define npyv_add_s32 _mm256_add_epi32
+#define npyv_add_u64 _mm256_add_epi64
+#define npyv_add_s64 _mm256_add_epi64
+#define npyv_add_f32 _mm256_add_ps
+#define npyv_add_f64 _mm256_add_pd
+
+// saturated
+#define npyv_adds_u8 _mm256_adds_epu8
+#define npyv_adds_s8 _mm256_adds_epi8
+#define npyv_adds_u16 _mm256_adds_epu16
+#define npyv_adds_s16 _mm256_adds_epi16
+// TODO: rest, after implment Packs intrins
+
+/***************************
+ * Subtraction
+ ***************************/
+// non-saturated
+#define npyv_sub_u8 _mm256_sub_epi8
+#define npyv_sub_s8 _mm256_sub_epi8
+#define npyv_sub_u16 _mm256_sub_epi16
+#define npyv_sub_s16 _mm256_sub_epi16
+#define npyv_sub_u32 _mm256_sub_epi32
+#define npyv_sub_s32 _mm256_sub_epi32
+#define npyv_sub_u64 _mm256_sub_epi64
+#define npyv_sub_s64 _mm256_sub_epi64
+#define npyv_sub_f32 _mm256_sub_ps
+#define npyv_sub_f64 _mm256_sub_pd
+
+// saturated
+#define npyv_subs_u8 _mm256_subs_epu8
+#define npyv_subs_s8 _mm256_subs_epi8
+#define npyv_subs_u16 _mm256_subs_epu16
+#define npyv_subs_s16 _mm256_subs_epi16
+// TODO: rest, after implment Packs intrins
+
+/***************************
+ * Multiplication
+ ***************************/
+// non-saturated
+#define npyv_mul_u8 npyv256_mul_u8
+#define npyv_mul_s8 npyv_mul_u8
+#define npyv_mul_u16 _mm256_mullo_epi16
+#define npyv_mul_s16 _mm256_mullo_epi16
+#define npyv_mul_u32 _mm256_mullo_epi32
+#define npyv_mul_s32 _mm256_mullo_epi32
+#define npyv_mul_f32 _mm256_mul_ps
+#define npyv_mul_f64 _mm256_mul_pd
+
+// saturated
+// TODO: after implment Packs intrins
+
+/***************************
+ * Division
+ ***************************/
+// TODO: emulate integer division
+#define npyv_div_f32 _mm256_div_ps
+#define npyv_div_f64 _mm256_div_pd
+
+/***************************
+ * FUSED
+ ***************************/
+#ifdef NPY_HAVE_FMA3
+ // multiply and add, a*b + c
+ #define npyv_muladd_f32 _mm256_fmadd_ps
+ #define npyv_muladd_f64 _mm256_fmadd_pd
+ // multiply and subtract, a*b - c
+ #define npyv_mulsub_f32 _mm256_fmsub_ps
+ #define npyv_mulsub_f64 _mm256_fmsub_pd
+ // negate multiply and add, -(a*b) + c
+ #define npyv_nmuladd_f32 _mm256_fnmadd_ps
+ #define npyv_nmuladd_f64 _mm256_fnmadd_pd
+ // negate multiply and subtract, -(a*b) - c
+ #define npyv_nmulsub_f32 _mm256_fnmsub_ps
+ #define npyv_nmulsub_f64 _mm256_fnmsub_pd
+#else
+ // multiply and add, a*b + c
+ NPY_FINLINE npyv_f32 npyv_muladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return npyv_add_f32(npyv_mul_f32(a, b), c); }
+ NPY_FINLINE npyv_f64 npyv_muladd_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return npyv_add_f64(npyv_mul_f64(a, b), c); }
+ // multiply and subtract, a*b - c
+ NPY_FINLINE npyv_f32 npyv_mulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return npyv_sub_f32(npyv_mul_f32(a, b), c); }
+ NPY_FINLINE npyv_f64 npyv_mulsub_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return npyv_sub_f64(npyv_mul_f64(a, b), c); }
+ // negate multiply and add, -(a*b) + c
+ NPY_FINLINE npyv_f32 npyv_nmuladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return npyv_sub_f32(c, npyv_mul_f32(a, b)); }
+ NPY_FINLINE npyv_f64 npyv_nmuladd_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return npyv_sub_f64(c, npyv_mul_f64(a, b)); }
+ // negate multiply and subtract, -(a*b) - c
+ NPY_FINLINE npyv_f32 npyv_nmulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ {
+ npyv_f32 neg_a = npyv_xor_f32(a, npyv_setall_f32(-0.0f));
+ return npyv_sub_f32(npyv_mul_f32(neg_a, b), c);
+ }
+ NPY_FINLINE npyv_f64 npyv_nmulsub_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ {
+ npyv_f64 neg_a = npyv_xor_f64(a, npyv_setall_f64(-0.0));
+ return npyv_sub_f64(npyv_mul_f64(neg_a, b), c);
+ }
+#endif // !NPY_HAVE_FMA3
+
+// Horizontal add: Calculates the sum of all vector elements.
+NPY_FINLINE float npyv_sum_f32(__m256 a)
+{
+ __m256 sum_halves = _mm256_hadd_ps(a, a);
+ sum_halves = _mm256_hadd_ps(sum_halves, sum_halves);
+ __m128 lo = _mm256_castps256_ps128(sum_halves);
+ __m128 hi = _mm256_extractf128_ps(sum_halves, 1);
+ __m128 sum = _mm_add_ps(lo, hi);
+ return _mm_cvtss_f32(sum);
+}
+
+NPY_FINLINE double npyv_sum_f64(__m256d a)
+{
+ __m256d sum_halves = _mm256_hadd_pd(a, a);
+ __m128d lo = _mm256_castpd256_pd128(sum_halves);
+ __m128d hi = _mm256_extractf128_pd(sum_halves, 1);
+ __m128d sum = _mm_add_pd(lo, hi);
+ return _mm_cvtsd_f64(sum);
+}
+
+#endif // _NPY_SIMD_AVX2_ARITHMETIC_H
+
+
--- /dev/null
+#ifndef _NPY_SIMD_H_
+ #error "Not a standalone header"
+#endif
+
+#define NPY_SIMD 256
+#define NPY_SIMD_WIDTH 32
+#define NPY_SIMD_F64 1
+// Enough limit to allow us to use _mm256_i32gather_*
+#define NPY_SIMD_MAXLOAD_STRIDE32 (0x7fffffff / 8)
+
+typedef __m256i npyv_u8;
+typedef __m256i npyv_s8;
+typedef __m256i npyv_u16;
+typedef __m256i npyv_s16;
+typedef __m256i npyv_u32;
+typedef __m256i npyv_s32;
+typedef __m256i npyv_u64;
+typedef __m256i npyv_s64;
+typedef __m256 npyv_f32;
+typedef __m256d npyv_f64;
+
+typedef __m256i npyv_b8;
+typedef __m256i npyv_b16;
+typedef __m256i npyv_b32;
+typedef __m256i npyv_b64;
+
+typedef struct { __m256i val[2]; } npyv_m256ix2;
+typedef npyv_m256ix2 npyv_u8x2;
+typedef npyv_m256ix2 npyv_s8x2;
+typedef npyv_m256ix2 npyv_u16x2;
+typedef npyv_m256ix2 npyv_s16x2;
+typedef npyv_m256ix2 npyv_u32x2;
+typedef npyv_m256ix2 npyv_s32x2;
+typedef npyv_m256ix2 npyv_u64x2;
+typedef npyv_m256ix2 npyv_s64x2;
+
+typedef struct { __m256i val[3]; } npyv_m256ix3;
+typedef npyv_m256ix3 npyv_u8x3;
+typedef npyv_m256ix3 npyv_s8x3;
+typedef npyv_m256ix3 npyv_u16x3;
+typedef npyv_m256ix3 npyv_s16x3;
+typedef npyv_m256ix3 npyv_u32x3;
+typedef npyv_m256ix3 npyv_s32x3;
+typedef npyv_m256ix3 npyv_u64x3;
+typedef npyv_m256ix3 npyv_s64x3;
+
+typedef struct { __m256 val[2]; } npyv_f32x2;
+typedef struct { __m256d val[2]; } npyv_f64x2;
+typedef struct { __m256 val[3]; } npyv_f32x3;
+typedef struct { __m256d val[3]; } npyv_f64x3;
+
+#define npyv_nlanes_u8 32
+#define npyv_nlanes_s8 32
+#define npyv_nlanes_u16 16
+#define npyv_nlanes_s16 16
+#define npyv_nlanes_u32 8
+#define npyv_nlanes_s32 8
+#define npyv_nlanes_u64 4
+#define npyv_nlanes_s64 4
+#define npyv_nlanes_f32 8
+#define npyv_nlanes_f64 4
+
+#include "utils.h"
+#include "memory.h"
+#include "misc.h"
+#include "reorder.h"
+#include "operators.h"
+#include "conversion.h"
+#include "arithmetic.h"
+#include "math.h"
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX2_CVT_H
+#define _NPY_SIMD_AVX2_CVT_H
+
+// convert mask types to integer types
+#define npyv_cvt_u8_b8(A) A
+#define npyv_cvt_s8_b8(A) A
+#define npyv_cvt_u16_b16(A) A
+#define npyv_cvt_s16_b16(A) A
+#define npyv_cvt_u32_b32(A) A
+#define npyv_cvt_s32_b32(A) A
+#define npyv_cvt_u64_b64(A) A
+#define npyv_cvt_s64_b64(A) A
+#define npyv_cvt_f32_b32(A) _mm256_castsi256_ps(A)
+#define npyv_cvt_f64_b64(A) _mm256_castsi256_pd(A)
+
+// convert integer types to mask types
+#define npyv_cvt_b8_u8(BL) BL
+#define npyv_cvt_b8_s8(BL) BL
+#define npyv_cvt_b16_u16(BL) BL
+#define npyv_cvt_b16_s16(BL) BL
+#define npyv_cvt_b32_u32(BL) BL
+#define npyv_cvt_b32_s32(BL) BL
+#define npyv_cvt_b64_u64(BL) BL
+#define npyv_cvt_b64_s64(BL) BL
+#define npyv_cvt_b32_f32(BL) _mm256_castps_si256(BL)
+#define npyv_cvt_b64_f64(BL) _mm256_castpd_si256(BL)
+
+#endif // _NPY_SIMD_AVX2_CVT_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX2_MATH_H
+#define _NPY_SIMD_AVX2_MATH_H
+/***************************
+ * Elementary
+ ***************************/
+// Square root
+#define npyv_sqrt_f32 _mm256_sqrt_ps
+#define npyv_sqrt_f64 _mm256_sqrt_pd
+
+// Reciprocal
+NPY_FINLINE npyv_f32 npyv_recip_f32(npyv_f32 a)
+{ return _mm256_div_ps(_mm256_set1_ps(1.0f), a); }
+NPY_FINLINE npyv_f64 npyv_recip_f64(npyv_f64 a)
+{ return _mm256_div_pd(_mm256_set1_pd(1.0), a); }
+
+// Absolute
+NPY_FINLINE npyv_f32 npyv_abs_f32(npyv_f32 a)
+{
+ return _mm256_and_ps(
+ a, _mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff))
+ );
+}
+NPY_FINLINE npyv_f64 npyv_abs_f64(npyv_f64 a)
+{
+ return _mm256_and_pd(
+ a, _mm256_castsi256_pd(npyv_setall_s64(0x7fffffffffffffffLL))
+ );
+}
+
+// Square
+NPY_FINLINE npyv_f32 npyv_square_f32(npyv_f32 a)
+{ return _mm256_mul_ps(a, a); }
+NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
+{ return _mm256_mul_pd(a, a); }
+
+#endif
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#include "misc.h"
+
+#ifndef _NPY_SIMD_AVX2_MEMORY_H
+#define _NPY_SIMD_AVX2_MEMORY_H
+
+/***************************
+ * load/store
+ ***************************/
+#define NPYV_IMPL_AVX2_MEM_INT(CTYPE, SFX) \
+ NPY_FINLINE npyv_##SFX npyv_load_##SFX(const CTYPE *ptr) \
+ { return _mm256_loadu_si256((const __m256i*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loada_##SFX(const CTYPE *ptr) \
+ { return _mm256_load_si256((const __m256i*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loads_##SFX(const CTYPE *ptr) \
+ { return _mm256_stream_load_si256((const __m256i*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loadl_##SFX(const CTYPE *ptr) \
+ { return _mm256_castsi128_si256(_mm_loadu_si128((const __m128i*)ptr)); } \
+ NPY_FINLINE void npyv_store_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm256_storeu_si256((__m256i*)ptr, vec); } \
+ NPY_FINLINE void npyv_storea_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm256_store_si256((__m256i*)ptr, vec); } \
+ NPY_FINLINE void npyv_stores_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm256_stream_si256((__m256i*)ptr, vec); } \
+ NPY_FINLINE void npyv_storel_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm_storeu_si128((__m128i*)(ptr), _mm256_castsi256_si128(vec)); } \
+ NPY_FINLINE void npyv_storeh_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm_storeu_si128((__m128i*)(ptr), _mm256_extracti128_si256(vec, 1)); }
+
+NPYV_IMPL_AVX2_MEM_INT(npy_uint8, u8)
+NPYV_IMPL_AVX2_MEM_INT(npy_int8, s8)
+NPYV_IMPL_AVX2_MEM_INT(npy_uint16, u16)
+NPYV_IMPL_AVX2_MEM_INT(npy_int16, s16)
+NPYV_IMPL_AVX2_MEM_INT(npy_uint32, u32)
+NPYV_IMPL_AVX2_MEM_INT(npy_int32, s32)
+NPYV_IMPL_AVX2_MEM_INT(npy_uint64, u64)
+NPYV_IMPL_AVX2_MEM_INT(npy_int64, s64)
+
+// unaligned load
+#define npyv_load_f32 _mm256_loadu_ps
+#define npyv_load_f64 _mm256_loadu_pd
+// aligned load
+#define npyv_loada_f32 _mm256_load_ps
+#define npyv_loada_f64 _mm256_load_pd
+// stream load
+#define npyv_loads_f32(PTR) \
+ _mm256_castsi256_ps(_mm256_stream_load_si256((const __m256i*)(PTR)))
+#define npyv_loads_f64(PTR) \
+ _mm256_castsi256_pd(_mm256_stream_load_si256((const __m256i*)(PTR)))
+// load lower part
+#define npyv_loadl_f32(PTR) _mm256_castps128_ps256(_mm_loadu_ps(PTR))
+#define npyv_loadl_f64(PTR) _mm256_castpd128_pd256(_mm_loadu_pd(PTR))
+// unaligned store
+#define npyv_store_f32 _mm256_storeu_ps
+#define npyv_store_f64 _mm256_storeu_pd
+// aligned store
+#define npyv_storea_f32 _mm256_store_ps
+#define npyv_storea_f64 _mm256_store_pd
+// stream store
+#define npyv_stores_f32 _mm256_stream_ps
+#define npyv_stores_f64 _mm256_stream_pd
+// store lower part
+#define npyv_storel_f32(PTR, VEC) _mm_storeu_ps(PTR, _mm256_castps256_ps128(VEC))
+#define npyv_storel_f64(PTR, VEC) _mm_storeu_pd(PTR, _mm256_castpd256_pd128(VEC))
+// store higher part
+#define npyv_storeh_f32(PTR, VEC) _mm_storeu_ps(PTR, _mm256_extractf128_ps(VEC, 1))
+#define npyv_storeh_f64(PTR, VEC) _mm_storeu_pd(PTR, _mm256_extractf128_pd(VEC, 1))
+/***************************
+ * Non-contiguous Load
+ ***************************/
+//// 32
+NPY_FINLINE npyv_u32 npyv_loadn_u32(const npy_uint32 *ptr, npy_intp stride)
+{
+ assert(llabs(stride) <= NPY_SIMD_MAXLOAD_STRIDE32);
+ const __m256i steps = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
+ const __m256i idx = _mm256_mullo_epi32(_mm256_set1_epi32((int)stride), steps);
+ return _mm256_i32gather_epi32((const int*)ptr, idx, 4);
+}
+NPY_FINLINE npyv_s32 npyv_loadn_s32(const npy_int32 *ptr, npy_intp stride)
+{ return npyv_loadn_u32((const npy_uint32*)ptr, stride); }
+NPY_FINLINE npyv_f32 npyv_loadn_f32(const float *ptr, npy_intp stride)
+{ return _mm256_castsi256_ps(npyv_loadn_u32((const npy_uint32*)ptr, stride)); }
+//// 64
+#if 0 // slower
+NPY_FINLINE npyv_u64 npyv_loadn_u64(const npy_uint64 *ptr, npy_intp stride)
+{
+ const __m256i idx = _mm256_setr_epi64x(0, 1*stride, 2*stride, 3*stride);
+ return _mm256_i64gather_epi64((const void*)ptr, idx, 8);
+}
+NPY_FINLINE npyv_s64 npyv_loadn_s64(const npy_int64 *ptr, npy_intp stride)
+{ return npyv_loadn_u64((const npy_uint64*)ptr, stride); }
+NPY_FINLINE npyv_f64 npyv_loadn_f64(const double *ptr, npy_intp stride)
+{ return _mm256_castsi256_pd(npyv_loadn_u64((const npy_uint64*)ptr, stride)); }
+#endif
+NPY_FINLINE npyv_f64 npyv_loadn_f64(const double *ptr, npy_intp stride)
+{
+ __m128d a0 = _mm_castsi128_pd(_mm_loadl_epi64((const __m128i*)ptr));
+ __m128d a2 = _mm_castsi128_pd(_mm_loadl_epi64((const __m128i*)(ptr + stride*2)));
+ __m128d a01 = _mm_loadh_pd(a0, ptr + stride);
+ __m128d a23 = _mm_loadh_pd(a2, ptr + stride*3);
+ return _mm256_insertf128_pd(_mm256_castpd128_pd256(a01), a23, 1);
+}
+NPY_FINLINE npyv_u64 npyv_loadn_u64(const npy_uint64 *ptr, npy_intp stride)
+{ return _mm256_castpd_si256(npyv_loadn_f64((const double*)ptr, stride)); }
+NPY_FINLINE npyv_s64 npyv_loadn_s64(const npy_int64 *ptr, npy_intp stride)
+{ return _mm256_castpd_si256(npyv_loadn_f64((const double*)ptr, stride)); }
+/***************************
+ * Non-contiguous Store
+ ***************************/
+//// 32
+NPY_FINLINE void npyv_storen_s32(npy_int32 *ptr, npy_intp stride, npyv_s32 a)
+{
+ __m128i a0 = _mm256_castsi256_si128(a);
+ __m128i a1 = _mm256_extracti128_si256(a, 1);
+ ptr[stride * 0] = _mm_cvtsi128_si32(a0);
+ ptr[stride * 1] = _mm_extract_epi32(a0, 1);
+ ptr[stride * 2] = _mm_extract_epi32(a0, 2);
+ ptr[stride * 3] = _mm_extract_epi32(a0, 3);
+ ptr[stride * 4] = _mm_cvtsi128_si32(a1);
+ ptr[stride * 5] = _mm_extract_epi32(a1, 1);
+ ptr[stride * 6] = _mm_extract_epi32(a1, 2);
+ ptr[stride * 7] = _mm_extract_epi32(a1, 3);
+}
+NPY_FINLINE void npyv_storen_u32(npy_uint32 *ptr, npy_intp stride, npyv_u32 a)
+{ npyv_storen_s32((npy_int32*)ptr, stride, a); }
+NPY_FINLINE void npyv_storen_f32(float *ptr, npy_intp stride, npyv_f32 a)
+{ npyv_storen_s32((npy_int32*)ptr, stride, _mm256_castps_si256(a)); }
+//// 64
+NPY_FINLINE void npyv_storen_f64(double *ptr, npy_intp stride, npyv_f64 a)
+{
+ __m128d a0 = _mm256_castpd256_pd128(a);
+ __m128d a1 = _mm256_extractf128_pd(a, 1);
+ _mm_storel_pd(ptr + stride * 0, a0);
+ _mm_storeh_pd(ptr + stride * 1, a0);
+ _mm_storel_pd(ptr + stride * 2, a1);
+ _mm_storeh_pd(ptr + stride * 3, a1);
+}
+NPY_FINLINE void npyv_storen_u64(npy_uint64 *ptr, npy_intp stride, npyv_u64 a)
+{ npyv_storen_f64((double*)ptr, stride, _mm256_castsi256_pd(a)); }
+NPY_FINLINE void npyv_storen_s64(npy_int64 *ptr, npy_intp stride, npyv_s64 a)
+{ npyv_storen_f64((double*)ptr, stride, _mm256_castsi256_pd(a)); }
+
+/*********************************
+ * Partial Load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32 npyv_load_till_s32(const npy_int32 *ptr, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ const __m256i vfill = _mm256_set1_epi32(fill);
+ const __m256i steps = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
+ __m256i vnlane = _mm256_set1_epi32(nlane > 8 ? 8 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi32(vnlane, steps);
+ __m256i payload = _mm256_maskload_epi32((const int*)ptr, mask);
+ return _mm256_blendv_epi8(vfill, payload, mask);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32 npyv_load_tillz_s32(const npy_int32 *ptr, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ const __m256i steps = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
+ __m256i vnlane = _mm256_set1_epi32(nlane > 8 ? 8 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi32(vnlane, steps);
+ return _mm256_maskload_epi32((const int*)ptr, mask);
+}
+//// 64
+NPY_FINLINE npyv_s64 npyv_load_till_s64(const npy_int64 *ptr, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ const __m256i vfill = _mm256_set1_epi64x(fill);
+ const __m256i steps = _mm256_setr_epi64x(0, 1, 2, 3);
+ __m256i vnlane = _mm256_set1_epi64x(nlane > 4 ? 4 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi64(vnlane, steps);
+ __m256i payload = _mm256_maskload_epi64((const void*)ptr, mask);
+ return _mm256_blendv_epi8(vfill, payload, mask);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_load_tillz_s64(const npy_int64 *ptr, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ const __m256i steps = _mm256_setr_epi64x(0, 1, 2, 3);
+ __m256i vnlane = _mm256_set1_epi64x(nlane > 4 ? 4 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi64(vnlane, steps);
+ return _mm256_maskload_epi64((const void*)ptr, mask);
+}
+/*********************************
+ * Non-contiguous partial load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32
+npyv_loadn_till_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ assert(llabs(stride) <= NPY_SIMD_MAXLOAD_STRIDE32);
+ const __m256i vfill = _mm256_set1_epi32(fill);
+ const __m256i steps = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
+ const __m256i idx = _mm256_mullo_epi32(_mm256_set1_epi32((int)stride), steps);
+ __m256i vnlane = _mm256_set1_epi32(nlane > 8 ? 8 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi32(vnlane, steps);
+ return _mm256_mask_i32gather_epi32(vfill, (const int*)ptr, idx, mask, 4);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32
+npyv_loadn_tillz_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s32(ptr, stride, nlane, 0); }
+//// 64
+NPY_FINLINE npyv_s64
+npyv_loadn_till_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ const __m256i vfill = _mm256_set1_epi64x(fill);
+ const __m256i idx = _mm256_setr_epi64x(0, 1*stride, 2*stride, 3*stride);
+ const __m256i steps = _mm256_setr_epi64x(0, 1, 2, 3);
+ __m256i vnlane = _mm256_set1_epi64x(nlane > 4 ? 4 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi64(vnlane, steps);
+ return _mm256_mask_i64gather_epi64(vfill, (const void*)ptr, idx, mask, 8);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64
+npyv_loadn_tillz_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s64(ptr, stride, nlane, 0); }
+/*********************************
+ * Partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_store_till_s32(npy_int32 *ptr, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ const __m256i steps = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
+ __m256i vnlane = _mm256_set1_epi32(nlane > 8 ? 8 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi32(vnlane, steps);
+ _mm256_maskstore_epi32((int*)ptr, mask, a);
+}
+//// 64
+NPY_FINLINE void npyv_store_till_s64(npy_int64 *ptr, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ const __m256i steps = _mm256_setr_epi64x(0, 1, 2, 3);
+ __m256i vnlane = _mm256_set1_epi64x(nlane > 8 ? 8 : (int)nlane);
+ __m256i mask = _mm256_cmpgt_epi64(vnlane, steps);
+ _mm256_maskstore_epi64((void*)ptr, mask, a);
+}
+/*********************************
+ * Non-contiguous partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_storen_till_s32(npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ __m128i a0 = _mm256_castsi256_si128(a);
+ __m128i a1 = _mm256_extracti128_si256(a, 1);
+ switch(nlane) {
+ default:
+ ptr[stride*7] = _mm_extract_epi32(a1, 3);
+ case 7:
+ ptr[stride*6] = _mm_extract_epi32(a1, 2);
+ case 6:
+ ptr[stride*5] = _mm_extract_epi32(a1, 1);
+ case 5:
+ ptr[stride*4] = _mm_extract_epi32(a1, 0);
+ case 4:
+ ptr[stride*3] = _mm_extract_epi32(a0, 3);
+ case 3:
+ ptr[stride*2] = _mm_extract_epi32(a0, 2);
+ case 2:
+ ptr[stride*1] = _mm_extract_epi32(a0, 1);
+ case 1:
+ ptr[stride*0] = _mm_extract_epi32(a0, 0);
+ }
+}
+//// 64
+NPY_FINLINE void npyv_storen_till_s64(npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ __m128d a0 = _mm256_castpd256_pd128(_mm256_castsi256_pd(a));
+ __m128d a1 = _mm256_extractf128_pd(_mm256_castsi256_pd(a), 1);
+ double *dptr = (double*)ptr;
+ switch(nlane) {
+ default:
+ _mm_storeh_pd(dptr + stride * 3, a1);
+ case 3:
+ _mm_storel_pd(dptr + stride * 2, a1);
+ case 2:
+ _mm_storeh_pd(dptr + stride * 1, a0);
+ case 1:
+ _mm_storel_pd(dptr + stride * 0, a0);
+ }
+}
+
+/*****************************************************************************
+ * Implement partial load/store for u32/f32/u64/f64... via reinterpret cast
+ *****************************************************************************/
+#define NPYV_IMPL_AVX2_REST_PARTIAL_TYPES(F_SFX, T_SFX) \
+ NPY_FINLINE npyv_##F_SFX npyv_load_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, \
+ npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_load_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane \
+ )); \
+ } \
+ NPY_FINLINE void npyv_store_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_store_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ } \
+ NPY_FINLINE void npyv_storen_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_storen_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, stride, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ }
+
+NPYV_IMPL_AVX2_REST_PARTIAL_TYPES(u32, s32)
+NPYV_IMPL_AVX2_REST_PARTIAL_TYPES(f32, s32)
+NPYV_IMPL_AVX2_REST_PARTIAL_TYPES(u64, s64)
+NPYV_IMPL_AVX2_REST_PARTIAL_TYPES(f64, s64)
+
+#endif // _NPY_SIMD_AVX2_MEMORY_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX2_MISC_H
+#define _NPY_SIMD_AVX2_MISC_H
+
+// vector with zero lanes
+#define npyv_zero_u8 _mm256_setzero_si256
+#define npyv_zero_s8 _mm256_setzero_si256
+#define npyv_zero_u16 _mm256_setzero_si256
+#define npyv_zero_s16 _mm256_setzero_si256
+#define npyv_zero_u32 _mm256_setzero_si256
+#define npyv_zero_s32 _mm256_setzero_si256
+#define npyv_zero_u64 _mm256_setzero_si256
+#define npyv_zero_s64 _mm256_setzero_si256
+#define npyv_zero_f32 _mm256_setzero_ps
+#define npyv_zero_f64 _mm256_setzero_pd
+
+// vector with a specific value set to all lanes
+#define npyv_setall_u8(VAL) _mm256_set1_epi8((char)VAL)
+#define npyv_setall_s8(VAL) _mm256_set1_epi8((char)VAL)
+#define npyv_setall_u16(VAL) _mm256_set1_epi16((short)VAL)
+#define npyv_setall_s16(VAL) _mm256_set1_epi16((short)VAL)
+#define npyv_setall_u32(VAL) _mm256_set1_epi32((int)VAL)
+#define npyv_setall_s32(VAL) _mm256_set1_epi32(VAL)
+#define npyv_setall_u64(VAL) _mm256_set1_epi64x(VAL)
+#define npyv_setall_s64(VAL) _mm256_set1_epi64x(VAL)
+#define npyv_setall_f32(VAL) _mm256_set1_ps(VAL)
+#define npyv_setall_f64(VAL) _mm256_set1_pd(VAL)
+
+/*
+ * vector with specific values set to each lane and
+ * set a specific value to all remained lanes
+ *
+ * Args that generated by NPYV__SET_FILL_* not going to expand if
+ * _mm256_setr_* are defined as macros.
+*/
+NPY_FINLINE __m256i npyv__setr_epi8(
+ char i0, char i1, char i2, char i3, char i4, char i5, char i6, char i7,
+ char i8, char i9, char i10, char i11, char i12, char i13, char i14, char i15,
+ char i16, char i17, char i18, char i19, char i20, char i21, char i22, char i23,
+ char i24, char i25, char i26, char i27, char i28, char i29, char i30, char i31)
+{
+ return _mm256_setr_epi8(
+ i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15,
+ i16, i17, i18, i19, i20, i21, i22, i23, i24, i25, i26, i27, i28, i29, i30, i31
+ );
+}
+NPY_FINLINE __m256i npyv__setr_epi16(
+ short i0, short i1, short i2, short i3, short i4, short i5, short i6, short i7,
+ short i8, short i9, short i10, short i11, short i12, short i13, short i14, short i15)
+{
+ return _mm256_setr_epi16(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);
+}
+NPY_FINLINE __m256i npyv__setr_epi32(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7)
+{
+ return _mm256_setr_epi32(i0, i1, i2, i3, i4, i5, i6, i7);
+}
+NPY_FINLINE __m256i npyv__setr_epi64(npy_int64 i0, npy_int64 i1, npy_int64 i2, npy_int64 i3)
+{
+ return _mm256_setr_epi64x(i0, i1, i2, i3);
+}
+
+NPY_FINLINE __m256 npyv__setr_ps(float i0, float i1, float i2, float i3, float i4, float i5,
+ float i6, float i7)
+{
+ return _mm256_setr_ps(i0, i1, i2, i3, i4, i5, i6, i7);
+}
+NPY_FINLINE __m256d npyv__setr_pd(double i0, double i1, double i2, double i3)
+{
+ return _mm256_setr_pd(i0, i1, i2, i3);
+}
+#define npyv_setf_u8(FILL, ...) npyv__setr_epi8(NPYV__SET_FILL_32(char, FILL, __VA_ARGS__))
+#define npyv_setf_s8(FILL, ...) npyv__setr_epi8(NPYV__SET_FILL_32(char, FILL, __VA_ARGS__))
+#define npyv_setf_u16(FILL, ...) npyv__setr_epi16(NPYV__SET_FILL_16(short, FILL, __VA_ARGS__))
+#define npyv_setf_s16(FILL, ...) npyv__setr_epi16(NPYV__SET_FILL_16(short, FILL, __VA_ARGS__))
+#define npyv_setf_u32(FILL, ...) npyv__setr_epi32(NPYV__SET_FILL_8(int, FILL, __VA_ARGS__))
+#define npyv_setf_s32(FILL, ...) npyv__setr_epi32(NPYV__SET_FILL_8(int, FILL, __VA_ARGS__))
+#define npyv_setf_u64(FILL, ...) npyv__setr_epi64(NPYV__SET_FILL_4(npy_uint64, FILL, __VA_ARGS__))
+#define npyv_setf_s64(FILL, ...) npyv__setr_epi64(NPYV__SET_FILL_4(npy_int64, FILL, __VA_ARGS__))
+#define npyv_setf_f32(FILL, ...) npyv__setr_ps(NPYV__SET_FILL_8(float, FILL, __VA_ARGS__))
+#define npyv_setf_f64(FILL, ...) npyv__setr_pd(NPYV__SET_FILL_4(double, FILL, __VA_ARGS__))
+
+// vector with specific values set to each lane and
+// set zero to all remained lanes
+#define npyv_set_u8(...) npyv_setf_u8(0, __VA_ARGS__)
+#define npyv_set_s8(...) npyv_setf_s8(0, __VA_ARGS__)
+#define npyv_set_u16(...) npyv_setf_u16(0, __VA_ARGS__)
+#define npyv_set_s16(...) npyv_setf_s16(0, __VA_ARGS__)
+#define npyv_set_u32(...) npyv_setf_u32(0, __VA_ARGS__)
+#define npyv_set_s32(...) npyv_setf_s32(0, __VA_ARGS__)
+#define npyv_set_u64(...) npyv_setf_u64(0, __VA_ARGS__)
+#define npyv_set_s64(...) npyv_setf_s64(0, __VA_ARGS__)
+#define npyv_set_f32(...) npyv_setf_f32(0, __VA_ARGS__)
+#define npyv_set_f64(...) npyv_setf_f64(0, __VA_ARGS__)
+
+// Per lane select
+#define npyv_select_u8(MASK, A, B) _mm256_blendv_epi8(B, A, MASK)
+#define npyv_select_s8 npyv_select_u8
+#define npyv_select_u16 npyv_select_u8
+#define npyv_select_s16 npyv_select_u8
+#define npyv_select_u32 npyv_select_u8
+#define npyv_select_s32 npyv_select_u8
+#define npyv_select_u64 npyv_select_u8
+#define npyv_select_s64 npyv_select_u8
+#define npyv_select_f32(MASK, A, B) _mm256_blendv_ps(B, A, _mm256_castsi256_ps(MASK))
+#define npyv_select_f64(MASK, A, B) _mm256_blendv_pd(B, A, _mm256_castsi256_pd(MASK))
+
+// Reinterpret
+#define npyv_reinterpret_u8_u8(X) X
+#define npyv_reinterpret_u8_s8(X) X
+#define npyv_reinterpret_u8_u16(X) X
+#define npyv_reinterpret_u8_s16(X) X
+#define npyv_reinterpret_u8_u32(X) X
+#define npyv_reinterpret_u8_s32(X) X
+#define npyv_reinterpret_u8_u64(X) X
+#define npyv_reinterpret_u8_s64(X) X
+#define npyv_reinterpret_u8_f32 _mm256_castps_si256
+#define npyv_reinterpret_u8_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_s8_s8(X) X
+#define npyv_reinterpret_s8_u8(X) X
+#define npyv_reinterpret_s8_u16(X) X
+#define npyv_reinterpret_s8_s16(X) X
+#define npyv_reinterpret_s8_u32(X) X
+#define npyv_reinterpret_s8_s32(X) X
+#define npyv_reinterpret_s8_u64(X) X
+#define npyv_reinterpret_s8_s64(X) X
+#define npyv_reinterpret_s8_f32 _mm256_castps_si256
+#define npyv_reinterpret_s8_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_u16_u16(X) X
+#define npyv_reinterpret_u16_u8(X) X
+#define npyv_reinterpret_u16_s8(X) X
+#define npyv_reinterpret_u16_s16(X) X
+#define npyv_reinterpret_u16_u32(X) X
+#define npyv_reinterpret_u16_s32(X) X
+#define npyv_reinterpret_u16_u64(X) X
+#define npyv_reinterpret_u16_s64(X) X
+#define npyv_reinterpret_u16_f32 _mm256_castps_si256
+#define npyv_reinterpret_u16_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_s16_s16(X) X
+#define npyv_reinterpret_s16_u8(X) X
+#define npyv_reinterpret_s16_s8(X) X
+#define npyv_reinterpret_s16_u16(X) X
+#define npyv_reinterpret_s16_u32(X) X
+#define npyv_reinterpret_s16_s32(X) X
+#define npyv_reinterpret_s16_u64(X) X
+#define npyv_reinterpret_s16_s64(X) X
+#define npyv_reinterpret_s16_f32 _mm256_castps_si256
+#define npyv_reinterpret_s16_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_u32_u32(X) X
+#define npyv_reinterpret_u32_u8(X) X
+#define npyv_reinterpret_u32_s8(X) X
+#define npyv_reinterpret_u32_u16(X) X
+#define npyv_reinterpret_u32_s16(X) X
+#define npyv_reinterpret_u32_s32(X) X
+#define npyv_reinterpret_u32_u64(X) X
+#define npyv_reinterpret_u32_s64(X) X
+#define npyv_reinterpret_u32_f32 _mm256_castps_si256
+#define npyv_reinterpret_u32_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_s32_s32(X) X
+#define npyv_reinterpret_s32_u8(X) X
+#define npyv_reinterpret_s32_s8(X) X
+#define npyv_reinterpret_s32_u16(X) X
+#define npyv_reinterpret_s32_s16(X) X
+#define npyv_reinterpret_s32_u32(X) X
+#define npyv_reinterpret_s32_u64(X) X
+#define npyv_reinterpret_s32_s64(X) X
+#define npyv_reinterpret_s32_f32 _mm256_castps_si256
+#define npyv_reinterpret_s32_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_u64_u64(X) X
+#define npyv_reinterpret_u64_u8(X) X
+#define npyv_reinterpret_u64_s8(X) X
+#define npyv_reinterpret_u64_u16(X) X
+#define npyv_reinterpret_u64_s16(X) X
+#define npyv_reinterpret_u64_u32(X) X
+#define npyv_reinterpret_u64_s32(X) X
+#define npyv_reinterpret_u64_s64(X) X
+#define npyv_reinterpret_u64_f32 _mm256_castps_si256
+#define npyv_reinterpret_u64_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_s64_s64(X) X
+#define npyv_reinterpret_s64_u8(X) X
+#define npyv_reinterpret_s64_s8(X) X
+#define npyv_reinterpret_s64_u16(X) X
+#define npyv_reinterpret_s64_s16(X) X
+#define npyv_reinterpret_s64_u32(X) X
+#define npyv_reinterpret_s64_s32(X) X
+#define npyv_reinterpret_s64_u64(X) X
+#define npyv_reinterpret_s64_f32 _mm256_castps_si256
+#define npyv_reinterpret_s64_f64 _mm256_castpd_si256
+
+#define npyv_reinterpret_f32_f32(X) X
+#define npyv_reinterpret_f32_u8 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_s8 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_u16 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_s16 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_u32 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_s32 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_u64 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_s64 _mm256_castsi256_ps
+#define npyv_reinterpret_f32_f64 _mm256_castpd_ps
+
+#define npyv_reinterpret_f64_f64(X) X
+#define npyv_reinterpret_f64_u8 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_s8 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_u16 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_s16 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_u32 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_s32 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_u64 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_s64 _mm256_castsi256_pd
+#define npyv_reinterpret_f64_f32 _mm256_castps_pd
+
+#define npyv_cleanup _mm256_zeroall
+
+#endif // _NPY_SIMD_SSE_MISC_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX2_OPERATORS_H
+#define _NPY_SIMD_AVX2_OPERATORS_H
+
+/***************************
+ * Shifting
+ ***************************/
+
+// left
+#define npyv_shl_u16(A, C) _mm256_sll_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s16(A, C) _mm256_sll_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_u32(A, C) _mm256_sll_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s32(A, C) _mm256_sll_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_u64(A, C) _mm256_sll_epi64(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s64(A, C) _mm256_sll_epi64(A, _mm_cvtsi32_si128(C))
+
+// left by an immediate constant
+#define npyv_shli_u16 _mm256_slli_epi16
+#define npyv_shli_s16 _mm256_slli_epi16
+#define npyv_shli_u32 _mm256_slli_epi32
+#define npyv_shli_s32 _mm256_slli_epi32
+#define npyv_shli_u64 _mm256_slli_epi64
+#define npyv_shli_s64 _mm256_slli_epi64
+
+// right
+#define npyv_shr_u16(A, C) _mm256_srl_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_s16(A, C) _mm256_sra_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_u32(A, C) _mm256_srl_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_s32(A, C) _mm256_sra_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_u64(A, C) _mm256_srl_epi64(A, _mm_cvtsi32_si128(C))
+NPY_FINLINE __m256i npyv_shr_s64(__m256i a, int c)
+{
+ const __m256i sbit = _mm256_set1_epi64x(0x8000000000000000);
+ const __m128i c64 = _mm_cvtsi32_si128(c);
+ __m256i r = _mm256_srl_epi64(_mm256_add_epi64(a, sbit), c64);
+ return _mm256_sub_epi64(r, _mm256_srl_epi64(sbit, c64));
+}
+
+// right by an immediate constant
+#define npyv_shri_u16 _mm256_srli_epi16
+#define npyv_shri_s16 _mm256_srai_epi16
+#define npyv_shri_u32 _mm256_srli_epi32
+#define npyv_shri_s32 _mm256_srai_epi32
+#define npyv_shri_u64 _mm256_srli_epi64
+#define npyv_shri_s64 npyv_shr_s64
+
+/***************************
+ * Logical
+ ***************************/
+// AND
+#define npyv_and_u8 _mm256_and_si256
+#define npyv_and_s8 _mm256_and_si256
+#define npyv_and_u16 _mm256_and_si256
+#define npyv_and_s16 _mm256_and_si256
+#define npyv_and_u32 _mm256_and_si256
+#define npyv_and_s32 _mm256_and_si256
+#define npyv_and_u64 _mm256_and_si256
+#define npyv_and_s64 _mm256_and_si256
+#define npyv_and_f32 _mm256_and_ps
+#define npyv_and_f64 _mm256_and_pd
+
+// OR
+#define npyv_or_u8 _mm256_or_si256
+#define npyv_or_s8 _mm256_or_si256
+#define npyv_or_u16 _mm256_or_si256
+#define npyv_or_s16 _mm256_or_si256
+#define npyv_or_u32 _mm256_or_si256
+#define npyv_or_s32 _mm256_or_si256
+#define npyv_or_u64 _mm256_or_si256
+#define npyv_or_s64 _mm256_or_si256
+#define npyv_or_f32 _mm256_or_ps
+#define npyv_or_f64 _mm256_or_pd
+
+// XOR
+#define npyv_xor_u8 _mm256_xor_si256
+#define npyv_xor_s8 _mm256_xor_si256
+#define npyv_xor_u16 _mm256_xor_si256
+#define npyv_xor_s16 _mm256_xor_si256
+#define npyv_xor_u32 _mm256_xor_si256
+#define npyv_xor_s32 _mm256_xor_si256
+#define npyv_xor_u64 _mm256_xor_si256
+#define npyv_xor_s64 _mm256_xor_si256
+#define npyv_xor_f32 _mm256_xor_ps
+#define npyv_xor_f64 _mm256_xor_pd
+
+// NOT
+#define npyv_not_u8(A) _mm256_xor_si256(A, _mm256_set1_epi32(-1))
+#define npyv_not_s8 npyv_not_u8
+#define npyv_not_u16 npyv_not_u8
+#define npyv_not_s16 npyv_not_u8
+#define npyv_not_u32 npyv_not_u8
+#define npyv_not_s32 npyv_not_u8
+#define npyv_not_u64 npyv_not_u8
+#define npyv_not_s64 npyv_not_u8
+#define npyv_not_f32(A) _mm256_xor_ps(A, _mm256_castsi256_ps(_mm256_set1_epi32(-1)))
+#define npyv_not_f64(A) _mm256_xor_pd(A, _mm256_castsi256_pd(_mm256_set1_epi32(-1)))
+
+/***************************
+ * Comparison
+ ***************************/
+
+// int Equal
+#define npyv_cmpeq_u8 _mm256_cmpeq_epi8
+#define npyv_cmpeq_s8 _mm256_cmpeq_epi8
+#define npyv_cmpeq_u16 _mm256_cmpeq_epi16
+#define npyv_cmpeq_s16 _mm256_cmpeq_epi16
+#define npyv_cmpeq_u32 _mm256_cmpeq_epi32
+#define npyv_cmpeq_s32 _mm256_cmpeq_epi32
+#define npyv_cmpeq_u64 _mm256_cmpeq_epi64
+#define npyv_cmpeq_s64 _mm256_cmpeq_epi64
+
+// int Not Equal
+#define npyv_cmpneq_u8(A, B) npyv_not_u8(_mm256_cmpeq_epi8(A, B))
+#define npyv_cmpneq_s8 npyv_cmpneq_u8
+#define npyv_cmpneq_u16(A, B) npyv_not_u16(_mm256_cmpeq_epi16(A, B))
+#define npyv_cmpneq_s16 npyv_cmpneq_u16
+#define npyv_cmpneq_u32(A, B) npyv_not_u32(_mm256_cmpeq_epi32(A, B))
+#define npyv_cmpneq_s32 npyv_cmpneq_u32
+#define npyv_cmpneq_u64(A, B) npyv_not_u64(_mm256_cmpeq_epi64(A, B))
+#define npyv_cmpneq_s64 npyv_cmpneq_u64
+
+// signed greater than
+#define npyv_cmpgt_s8 _mm256_cmpgt_epi8
+#define npyv_cmpgt_s16 _mm256_cmpgt_epi16
+#define npyv_cmpgt_s32 _mm256_cmpgt_epi32
+#define npyv_cmpgt_s64 _mm256_cmpgt_epi64
+
+// signed greater than or equal
+#define npyv_cmpge_s8(A, B) npyv_not_s8(_mm256_cmpgt_epi8(B, A))
+#define npyv_cmpge_s16(A, B) npyv_not_s16(_mm256_cmpgt_epi16(B, A))
+#define npyv_cmpge_s32(A, B) npyv_not_s32(_mm256_cmpgt_epi32(B, A))
+#define npyv_cmpge_s64(A, B) npyv_not_s64(_mm256_cmpgt_epi64(B, A))
+
+// unsigned greater than
+#define NPYV_IMPL_AVX2_UNSIGNED_GT(LEN, SIGN) \
+ NPY_FINLINE __m256i npyv_cmpgt_u##LEN(__m256i a, __m256i b) \
+ { \
+ const __m256i sbit = _mm256_set1_epi32(SIGN); \
+ return _mm256_cmpgt_epi##LEN( \
+ _mm256_xor_si256(a, sbit), _mm256_xor_si256(b, sbit) \
+ ); \
+ }
+
+NPYV_IMPL_AVX2_UNSIGNED_GT(8, 0x80808080)
+NPYV_IMPL_AVX2_UNSIGNED_GT(16, 0x80008000)
+NPYV_IMPL_AVX2_UNSIGNED_GT(32, 0x80000000)
+
+NPY_FINLINE __m256i npyv_cmpgt_u64(__m256i a, __m256i b)
+{
+ const __m256i sbit = _mm256_set1_epi64x(0x8000000000000000);
+ return _mm256_cmpgt_epi64(_mm256_xor_si256(a, sbit), _mm256_xor_si256(b, sbit));
+}
+
+// unsigned greater than or equal
+NPY_FINLINE __m256i npyv_cmpge_u8(__m256i a, __m256i b)
+{ return _mm256_cmpeq_epi8(a, _mm256_max_epu8(a, b)); }
+NPY_FINLINE __m256i npyv_cmpge_u16(__m256i a, __m256i b)
+{ return _mm256_cmpeq_epi16(a, _mm256_max_epu16(a, b)); }
+NPY_FINLINE __m256i npyv_cmpge_u32(__m256i a, __m256i b)
+{ return _mm256_cmpeq_epi32(a, _mm256_max_epu32(a, b)); }
+#define npyv_cmpge_u64(A, B) npyv_not_u64(npyv_cmpgt_u64(B, A))
+
+// less than
+#define npyv_cmplt_u8(A, B) npyv_cmpgt_u8(B, A)
+#define npyv_cmplt_s8(A, B) npyv_cmpgt_s8(B, A)
+#define npyv_cmplt_u16(A, B) npyv_cmpgt_u16(B, A)
+#define npyv_cmplt_s16(A, B) npyv_cmpgt_s16(B, A)
+#define npyv_cmplt_u32(A, B) npyv_cmpgt_u32(B, A)
+#define npyv_cmplt_s32(A, B) npyv_cmpgt_s32(B, A)
+#define npyv_cmplt_u64(A, B) npyv_cmpgt_u64(B, A)
+#define npyv_cmplt_s64(A, B) npyv_cmpgt_s64(B, A)
+
+// less than or equal
+#define npyv_cmple_u8(A, B) npyv_cmpge_u8(B, A)
+#define npyv_cmple_s8(A, B) npyv_cmpge_s8(B, A)
+#define npyv_cmple_u16(A, B) npyv_cmpge_u16(B, A)
+#define npyv_cmple_s16(A, B) npyv_cmpge_s16(B, A)
+#define npyv_cmple_u32(A, B) npyv_cmpge_u32(B, A)
+#define npyv_cmple_s32(A, B) npyv_cmpge_s32(B, A)
+#define npyv_cmple_u64(A, B) npyv_cmpge_u64(B, A)
+#define npyv_cmple_s64(A, B) npyv_cmpge_s64(B, A)
+
+// precision comparison
+#define npyv_cmpeq_f32(A, B) _mm256_castps_si256(_mm256_cmp_ps(A, B, _CMP_EQ_OQ))
+#define npyv_cmpeq_f64(A, B) _mm256_castpd_si256(_mm256_cmp_pd(A, B, _CMP_EQ_OQ))
+#define npyv_cmpneq_f32(A, B) _mm256_castps_si256(_mm256_cmp_ps(A, B, _CMP_NEQ_OQ))
+#define npyv_cmpneq_f64(A, B) _mm256_castpd_si256(_mm256_cmp_pd(A, B, _CMP_NEQ_OQ))
+#define npyv_cmplt_f32(A, B) _mm256_castps_si256(_mm256_cmp_ps(A, B, _CMP_LT_OQ))
+#define npyv_cmplt_f64(A, B) _mm256_castpd_si256(_mm256_cmp_pd(A, B, _CMP_LT_OQ))
+#define npyv_cmple_f32(A, B) _mm256_castps_si256(_mm256_cmp_ps(A, B, _CMP_LE_OQ))
+#define npyv_cmple_f64(A, B) _mm256_castpd_si256(_mm256_cmp_pd(A, B, _CMP_LE_OQ))
+#define npyv_cmpgt_f32(A, B) _mm256_castps_si256(_mm256_cmp_ps(A, B, _CMP_GT_OQ))
+#define npyv_cmpgt_f64(A, B) _mm256_castpd_si256(_mm256_cmp_pd(A, B, _CMP_GT_OQ))
+#define npyv_cmpge_f32(A, B) _mm256_castps_si256(_mm256_cmp_ps(A, B, _CMP_GE_OQ))
+#define npyv_cmpge_f64(A, B) _mm256_castpd_si256(_mm256_cmp_pd(A, B, _CMP_GE_OQ))
+
+#endif // _NPY_SIMD_AVX2_OPERATORS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX2_REORDER_H
+#define _NPY_SIMD_AVX2_REORDER_H
+
+// combine lower part of two vectors
+#define npyv_combinel_u8(A, B) _mm256_permute2x128_si256(A, B, 0x20)
+#define npyv_combinel_s8 npyv_combinel_u8
+#define npyv_combinel_u16 npyv_combinel_u8
+#define npyv_combinel_s16 npyv_combinel_u8
+#define npyv_combinel_u32 npyv_combinel_u8
+#define npyv_combinel_s32 npyv_combinel_u8
+#define npyv_combinel_u64 npyv_combinel_u8
+#define npyv_combinel_s64 npyv_combinel_u8
+#define npyv_combinel_f32(A, B) _mm256_permute2f128_ps(A, B, 0x20)
+#define npyv_combinel_f64(A, B) _mm256_permute2f128_pd(A, B, 0x20)
+
+// combine higher part of two vectors
+#define npyv_combineh_u8(A, B) _mm256_permute2x128_si256(A, B, 0x31)
+#define npyv_combineh_s8 npyv_combineh_u8
+#define npyv_combineh_u16 npyv_combineh_u8
+#define npyv_combineh_s16 npyv_combineh_u8
+#define npyv_combineh_u32 npyv_combineh_u8
+#define npyv_combineh_s32 npyv_combineh_u8
+#define npyv_combineh_u64 npyv_combineh_u8
+#define npyv_combineh_s64 npyv_combineh_u8
+#define npyv_combineh_f32(A, B) _mm256_permute2f128_ps(A, B, 0x31)
+#define npyv_combineh_f64(A, B) _mm256_permute2f128_pd(A, B, 0x31)
+
+// combine two vectors from lower and higher parts of two other vectors
+NPY_FINLINE npyv_m256ix2 npyv__combine(__m256i a, __m256i b)
+{
+ npyv_m256ix2 r;
+ __m256i a1b0 = _mm256_permute2x128_si256(a, b, 0x21);
+ r.val[0] = _mm256_blend_epi32(a, a1b0, 0xF0);
+ r.val[1] = _mm256_blend_epi32(b, a1b0, 0xF);
+ return r;
+}
+NPY_FINLINE npyv_f32x2 npyv_combine_f32(__m256 a, __m256 b)
+{
+ npyv_f32x2 r;
+ __m256 a1b0 = _mm256_permute2f128_ps(a, b, 0x21);
+ r.val[0] = _mm256_blend_ps(a, a1b0, 0xF0);
+ r.val[1] = _mm256_blend_ps(b, a1b0, 0xF);
+ return r;
+}
+NPY_FINLINE npyv_f64x2 npyv_combine_f64(__m256d a, __m256d b)
+{
+ npyv_f64x2 r;
+ __m256d a1b0 = _mm256_permute2f128_pd(a, b, 0x21);
+ r.val[0] = _mm256_blend_pd(a, a1b0, 0xC);
+ r.val[1] = _mm256_blend_pd(b, a1b0, 0x3);
+ return r;
+}
+#define npyv_combine_u8 npyv__combine
+#define npyv_combine_s8 npyv__combine
+#define npyv_combine_u16 npyv__combine
+#define npyv_combine_s16 npyv__combine
+#define npyv_combine_u32 npyv__combine
+#define npyv_combine_s32 npyv__combine
+#define npyv_combine_u64 npyv__combine
+#define npyv_combine_s64 npyv__combine
+
+// interleave two vectors
+#define NPYV_IMPL_AVX2_ZIP_U(T_VEC, LEN) \
+ NPY_FINLINE T_VEC##x2 npyv_zip_u##LEN(T_VEC a, T_VEC b) \
+ { \
+ __m256i ab0 = _mm256_unpacklo_epi##LEN(a, b); \
+ __m256i ab1 = _mm256_unpackhi_epi##LEN(a, b); \
+ return npyv__combine(ab0, ab1); \
+ }
+
+NPYV_IMPL_AVX2_ZIP_U(npyv_u8, 8)
+NPYV_IMPL_AVX2_ZIP_U(npyv_u16, 16)
+NPYV_IMPL_AVX2_ZIP_U(npyv_u32, 32)
+NPYV_IMPL_AVX2_ZIP_U(npyv_u64, 64)
+#define npyv_zip_s8 npyv_zip_u8
+#define npyv_zip_s16 npyv_zip_u16
+#define npyv_zip_s32 npyv_zip_u32
+#define npyv_zip_s64 npyv_zip_u64
+
+NPY_FINLINE npyv_f32x2 npyv_zip_f32(__m256 a, __m256 b)
+{
+ __m256 ab0 = _mm256_unpacklo_ps(a, b);
+ __m256 ab1 = _mm256_unpackhi_ps(a, b);
+ return npyv_combine_f32(ab0, ab1);
+}
+NPY_FINLINE npyv_f64x2 npyv_zip_f64(__m256d a, __m256d b)
+{
+ __m256d ab0 = _mm256_unpacklo_pd(a, b);
+ __m256d ab1 = _mm256_unpackhi_pd(a, b);
+ return npyv_combine_f64(ab0, ab1);
+}
+
+#endif // _NPY_SIMD_AVX2_REORDER_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX2_UTILS_H
+#define _NPY_SIMD_AVX2_UTILS_H
+
+#define npyv256_shuffle_odd(A) _mm256_permute4x64_epi64(A, _MM_SHUFFLE(3, 1, 2, 0))
+#define npyv256_shuffle_odd_ps(A) _mm256_castsi256_ps(npyv256_shuffle_odd(_mm256_castps_si256(A)))
+#define npyv256_shuffle_odd_pd(A) _mm256_permute4x64_pd(A, _MM_SHUFFLE(3, 1, 2, 0))
+
+NPY_FINLINE __m256i npyv256_mul_u8(__m256i a, __m256i b)
+{
+ const __m256i mask = _mm256_set1_epi32(0xFF00FF00);
+ __m256i even = _mm256_mullo_epi16(a, b);
+ __m256i odd = _mm256_mullo_epi16(_mm256_srai_epi16(a, 8), _mm256_srai_epi16(b, 8));
+ odd = _mm256_slli_epi16(odd, 8);
+ return _mm256_blendv_epi8(even, odd, mask);
+}
+
+#endif // _NPY_SIMD_AVX2_UTILS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_ARITHMETIC_H
+#define _NPY_SIMD_AVX512_ARITHMETIC_H
+
+#include "../avx2/utils.h"
+
+/***************************
+ * Addition
+ ***************************/
+// non-saturated
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_add_u8 _mm512_add_epi8
+ #define npyv_add_u16 _mm512_add_epi16
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_add_u8, _mm256_add_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_add_u16, _mm256_add_epi16)
+#endif
+#define npyv_add_s8 npyv_add_u8
+#define npyv_add_s16 npyv_add_u16
+#define npyv_add_u32 _mm512_add_epi32
+#define npyv_add_s32 _mm512_add_epi32
+#define npyv_add_u64 _mm512_add_epi64
+#define npyv_add_s64 _mm512_add_epi64
+#define npyv_add_f32 _mm512_add_ps
+#define npyv_add_f64 _mm512_add_pd
+
+// saturated
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_adds_u8 _mm512_adds_epu8
+ #define npyv_adds_s8 _mm512_adds_epi8
+ #define npyv_adds_u16 _mm512_adds_epu16
+ #define npyv_adds_s16 _mm512_adds_epi16
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_adds_u8, _mm256_adds_epu8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_adds_s8, _mm256_adds_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_adds_u16, _mm256_adds_epu16)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_adds_s16, _mm256_adds_epi16)
+#endif
+// TODO: rest, after implment Packs intrins
+
+/***************************
+ * Subtraction
+ ***************************/
+// non-saturated
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_sub_u8 _mm512_sub_epi8
+ #define npyv_sub_u16 _mm512_sub_epi16
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_sub_u8, _mm256_sub_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_sub_u16, _mm256_sub_epi16)
+#endif
+#define npyv_sub_s8 npyv_sub_u8
+#define npyv_sub_s16 npyv_sub_u16
+#define npyv_sub_u32 _mm512_sub_epi32
+#define npyv_sub_s32 _mm512_sub_epi32
+#define npyv_sub_u64 _mm512_sub_epi64
+#define npyv_sub_s64 _mm512_sub_epi64
+#define npyv_sub_f32 _mm512_sub_ps
+#define npyv_sub_f64 _mm512_sub_pd
+
+// saturated
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_subs_u8 _mm512_subs_epu8
+ #define npyv_subs_s8 _mm512_subs_epi8
+ #define npyv_subs_u16 _mm512_subs_epu16
+ #define npyv_subs_s16 _mm512_subs_epi16
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_subs_u8, _mm256_subs_epu8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_subs_s8, _mm256_subs_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_subs_u16, _mm256_subs_epu16)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_subs_s16, _mm256_subs_epi16)
+#endif
+// TODO: rest, after implment Packs intrins
+
+/***************************
+ * Multiplication
+ ***************************/
+// non-saturated
+#ifdef NPY_HAVE_AVX512BW
+NPY_FINLINE __m512i npyv_mul_u8(__m512i a, __m512i b)
+{
+ __m512i even = _mm512_mullo_epi16(a, b);
+ __m512i odd = _mm512_mullo_epi16(_mm512_srai_epi16(a, 8), _mm512_srai_epi16(b, 8));
+ odd = _mm512_slli_epi16(odd, 8);
+ return _mm512_mask_blend_epi8(0xAAAAAAAAAAAAAAAA, even, odd);
+}
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_mul_u8, npyv256_mul_u8)
+#endif
+
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_mul_u16 _mm512_mullo_epi16
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_mul_u16, _mm256_mullo_epi16)
+#endif
+#define npyv_mul_s8 npyv_mul_u8
+#define npyv_mul_s16 npyv_mul_u16
+#define npyv_mul_u32 _mm512_mullo_epi32
+#define npyv_mul_s32 _mm512_mullo_epi32
+#define npyv_mul_f32 _mm512_mul_ps
+#define npyv_mul_f64 _mm512_mul_pd
+
+// saturated
+// TODO: after implment Packs intrins
+
+/***************************
+ * Division
+ ***************************/
+// TODO: emulate integer division
+#define npyv_div_f32 _mm512_div_ps
+#define npyv_div_f64 _mm512_div_pd
+
+/***************************
+ * FUSED
+ ***************************/
+// multiply and add, a*b + c
+#define npyv_muladd_f32 _mm512_fmadd_ps
+#define npyv_muladd_f64 _mm512_fmadd_pd
+// multiply and subtract, a*b - c
+#define npyv_mulsub_f32 _mm512_fmsub_ps
+#define npyv_mulsub_f64 _mm512_fmsub_pd
+// negate multiply and add, -(a*b) + c
+#define npyv_nmuladd_f32 _mm512_fnmadd_ps
+#define npyv_nmuladd_f64 _mm512_fnmadd_pd
+// negate multiply and subtract, -(a*b) - c
+#define npyv_nmulsub_f32 _mm512_fnmsub_ps
+#define npyv_nmulsub_f64 _mm512_fnmsub_pd
+
+/***************************
+ * Reduce Sum
+ * there are three ways to implement reduce sum for AVX512:
+ * 1- split(256) /add /split(128) /add /hadd /hadd /extract
+ * 2- shuff(cross) /add /shuff(cross) /add /shuff /add /shuff /add /extract
+ * 3- _mm512_reduce_add_ps/pd
+ * The first one is been widely used by many projects
+ *
+ * the second one is used by Intel Compiler, maybe because the
+ * latency of hadd increased by (2-3) starting from Skylake-X which makes two
+ * extra shuffles(non-cross) cheaper. check https://godbolt.org/z/s3G9Er for more info.
+ *
+ * The third one is almost the same as the second one but only works for
+ * intel compiler/GCC 7.1/Clang 4, we still need to support older GCC.
+ ***************************/
+#ifdef NPY_HAVE_AVX512F_REDUCE
+ #define npyv_sum_f32 _mm512_reduce_add_ps
+ #define npyv_sum_f64 _mm512_reduce_add_pd
+#else
+ NPY_FINLINE float npyv_sum_f32(npyv_f32 a)
+ {
+ __m512 h64 = _mm512_shuffle_f32x4(a, a, _MM_SHUFFLE(3, 2, 3, 2));
+ __m512 sum32 = _mm512_add_ps(a, h64);
+ __m512 h32 = _mm512_shuffle_f32x4(sum32, sum32, _MM_SHUFFLE(1, 0, 3, 2));
+ __m512 sum16 = _mm512_add_ps(sum32, h32);
+ __m512 h16 = _mm512_permute_ps(sum16, _MM_SHUFFLE(1, 0, 3, 2));
+ __m512 sum8 = _mm512_add_ps(sum16, h16);
+ __m512 h4 = _mm512_permute_ps(sum8, _MM_SHUFFLE(2, 3, 0, 1));
+ __m512 sum4 = _mm512_add_ps(sum8, h4);
+ return _mm_cvtss_f32(_mm512_castps512_ps128(sum4));
+ }
+ NPY_FINLINE double npyv_sum_f64(npyv_f64 a)
+ {
+ __m512d h64 = _mm512_shuffle_f64x2(a, a, _MM_SHUFFLE(3, 2, 3, 2));
+ __m512d sum32 = _mm512_add_pd(a, h64);
+ __m512d h32 = _mm512_permutex_pd(sum32, _MM_SHUFFLE(1, 0, 3, 2));
+ __m512d sum16 = _mm512_add_pd(sum32, h32);
+ __m512d h16 = _mm512_permute_pd(sum16, _MM_SHUFFLE(2, 3, 0, 1));
+ __m512d sum8 = _mm512_add_pd(sum16, h16);
+ return _mm_cvtsd_f64(_mm512_castpd512_pd128(sum8));
+ }
+#endif
+
+#endif // _NPY_SIMD_AVX512_ARITHMETIC_H
--- /dev/null
+#ifndef _NPY_SIMD_H_
+ #error "Not a standalone header"
+#endif
+#define NPY_SIMD 512
+#define NPY_SIMD_WIDTH 64
+#define NPY_SIMD_F64 1
+// Enough limit to allow us to use _mm512_i32gather_* and _mm512_i32scatter_*
+#define NPY_SIMD_MAXLOAD_STRIDE32 (0x7fffffff / 16)
+#define NPY_SIMD_MAXSTORE_STRIDE32 (0x7fffffff / 16)
+
+typedef __m512i npyv_u8;
+typedef __m512i npyv_s8;
+typedef __m512i npyv_u16;
+typedef __m512i npyv_s16;
+typedef __m512i npyv_u32;
+typedef __m512i npyv_s32;
+typedef __m512i npyv_u64;
+typedef __m512i npyv_s64;
+typedef __m512 npyv_f32;
+typedef __m512d npyv_f64;
+
+#ifdef NPY_HAVE_AVX512BW
+typedef __mmask64 npyv_b8;
+typedef __mmask32 npyv_b16;
+#else
+typedef __m512i npyv_b8;
+typedef __m512i npyv_b16;
+#endif
+typedef __mmask16 npyv_b32;
+typedef __mmask8 npyv_b64;
+
+typedef struct { __m512i val[2]; } npyv_m512ix2;
+typedef npyv_m512ix2 npyv_u8x2;
+typedef npyv_m512ix2 npyv_s8x2;
+typedef npyv_m512ix2 npyv_u16x2;
+typedef npyv_m512ix2 npyv_s16x2;
+typedef npyv_m512ix2 npyv_u32x2;
+typedef npyv_m512ix2 npyv_s32x2;
+typedef npyv_m512ix2 npyv_u64x2;
+typedef npyv_m512ix2 npyv_s64x2;
+
+typedef struct { __m512i val[3]; } npyv_m512ix3;
+typedef npyv_m512ix3 npyv_u8x3;
+typedef npyv_m512ix3 npyv_s8x3;
+typedef npyv_m512ix3 npyv_u16x3;
+typedef npyv_m512ix3 npyv_s16x3;
+typedef npyv_m512ix3 npyv_u32x3;
+typedef npyv_m512ix3 npyv_s32x3;
+typedef npyv_m512ix3 npyv_u64x3;
+typedef npyv_m512ix3 npyv_s64x3;
+
+typedef struct { __m512 val[2]; } npyv_f32x2;
+typedef struct { __m512d val[2]; } npyv_f64x2;
+typedef struct { __m512 val[3]; } npyv_f32x3;
+typedef struct { __m512d val[3]; } npyv_f64x3;
+
+#define npyv_nlanes_u8 64
+#define npyv_nlanes_s8 64
+#define npyv_nlanes_u16 32
+#define npyv_nlanes_s16 32
+#define npyv_nlanes_u32 16
+#define npyv_nlanes_s32 16
+#define npyv_nlanes_u64 8
+#define npyv_nlanes_s64 8
+#define npyv_nlanes_f32 16
+#define npyv_nlanes_f64 8
+
+#include "utils.h"
+#include "memory.h"
+#include "misc.h"
+#include "reorder.h"
+#include "operators.h"
+#include "conversion.h"
+#include "arithmetic.h"
+#include "math.h"
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_CVT_H
+#define _NPY_SIMD_AVX512_CVT_H
+
+// convert mask to integer vectors
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_cvt_u8_b8 _mm512_movm_epi8
+ #define npyv_cvt_u16_b16 _mm512_movm_epi16
+#else
+ #define npyv_cvt_u8_b8(BL) BL
+ #define npyv_cvt_u16_b16(BL) BL
+#endif
+#define npyv_cvt_s8_b8 npyv_cvt_u8_b8
+#define npyv_cvt_s16_b16 npyv_cvt_u16_b16
+
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_cvt_u32_b32 _mm512_movm_epi32
+ #define npyv_cvt_u64_b64 _mm512_movm_epi64
+#else
+ #define npyv_cvt_u32_b32(BL) _mm512_maskz_set1_epi32(BL, (int)-1)
+ #define npyv_cvt_u64_b64(BL) _mm512_maskz_set1_epi64(BL, (npy_int64)-1)
+#endif
+#define npyv_cvt_s32_b32 npyv_cvt_u32_b32
+#define npyv_cvt_s64_b64 npyv_cvt_u64_b64
+#define npyv_cvt_f32_b32(BL) _mm512_castsi512_ps(npyv_cvt_u32_b32(BL))
+#define npyv_cvt_f64_b64(BL) _mm512_castsi512_pd(npyv_cvt_u64_b64(BL))
+
+// convert integer vectors to mask
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_cvt_b8_u8 _mm512_movepi8_mask
+ #define npyv_cvt_b16_u16 _mm512_movepi16_mask
+#else
+ #define npyv_cvt_b8_u8(A) A
+ #define npyv_cvt_b16_u16(A) A
+#endif
+#define npyv_cvt_b8_s8 npyv_cvt_b8_u8
+#define npyv_cvt_b16_s16 npyv_cvt_b16_u16
+
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_cvt_b32_u32 _mm512_movepi32_mask
+ #define npyv_cvt_b64_u64 _mm512_movepi64_mask
+#else
+ #define npyv_cvt_b32_u32(A) _mm512_cmpneq_epu32_mask(A, _mm512_setzero_si512())
+ #define npyv_cvt_b64_u64(A) _mm512_cmpneq_epu64_mask(A, _mm512_setzero_si512())
+#endif
+#define npyv_cvt_b32_s32 npyv_cvt_b32_u32
+#define npyv_cvt_b64_s64 npyv_cvt_b64_u64
+#define npyv_cvt_b32_f32(A) npyv_cvt_b32_u32(_mm512_castps_si512(A))
+#define npyv_cvt_b64_f64(A) npyv_cvt_b64_u64(_mm512_castpd_si512(A))
+
+// expand
+NPY_FINLINE npyv_u16x2 npyv_expand_u16_u8(npyv_u8 data)
+{
+ npyv_u16x2 r;
+ __m256i lo = npyv512_lower_si256(data);
+ __m256i hi = npyv512_higher_si256(data);
+#ifdef NPY_HAVE_AVX512BW
+ r.val[0] = _mm512_cvtepu8_epi16(lo);
+ r.val[1] = _mm512_cvtepu8_epi16(hi);
+#else
+ __m256i loelo = _mm256_cvtepu8_epi16(_mm256_castsi256_si128(lo));
+ __m256i loehi = _mm256_cvtepu8_epi16(_mm256_extracti128_si256(lo, 1));
+ __m256i hielo = _mm256_cvtepu8_epi16(_mm256_castsi256_si128(hi));
+ __m256i hiehi = _mm256_cvtepu8_epi16(_mm256_extracti128_si256(hi, 1));
+ r.val[0] = npyv512_combine_si256(loelo, loehi);
+ r.val[1] = npyv512_combine_si256(hielo, hiehi);
+#endif
+ return r;
+}
+
+NPY_FINLINE npyv_u32x2 npyv_expand_u32_u16(npyv_u16 data)
+{
+ npyv_u32x2 r;
+ __m256i lo = npyv512_lower_si256(data);
+ __m256i hi = npyv512_higher_si256(data);
+#ifdef NPY_HAVE_AVX512BW
+ r.val[0] = _mm512_cvtepu16_epi32(lo);
+ r.val[1] = _mm512_cvtepu16_epi32(hi);
+#else
+ __m256i loelo = _mm256_cvtepu16_epi32(_mm256_castsi256_si128(lo));
+ __m256i loehi = _mm256_cvtepu16_epi32(_mm256_extracti128_si256(lo, 1));
+ __m256i hielo = _mm256_cvtepu16_epi32(_mm256_castsi256_si128(hi));
+ __m256i hiehi = _mm256_cvtepu16_epi32(_mm256_extracti128_si256(hi, 1));
+ r.val[0] = npyv512_combine_si256(loelo, loehi);
+ r.val[1] = npyv512_combine_si256(hielo, hiehi);
+#endif
+ return r;
+}
+
+// convert boolean vectors to integer bitfield
+NPY_FINLINE npy_uint64 npyv_tobits_b8(npyv_b8 a)
+{
+#ifdef NPY_HAVE_AVX512BW_MASK
+ return (npy_uint64)_cvtmask64_u64(a);
+#elif defined(NPY_HAVE_AVX512BW)
+ return (npy_uint64)a;
+#else
+ int mask_lo = _mm256_movemask_epi8(npyv512_lower_si256(a));
+ int mask_hi = _mm256_movemask_epi8(npyv512_higher_si256(a));
+ return (unsigned)mask_lo | ((npy_uint64)(unsigned)mask_hi << 32);
+#endif
+}
+NPY_FINLINE npy_uint64 npyv_tobits_b16(npyv_b16 a)
+{
+#ifdef NPY_HAVE_AVX512BW_MASK
+ return (npy_uint32)_cvtmask32_u32(a);
+#elif defined(NPY_HAVE_AVX512BW)
+ return (npy_uint32)a;
+#else
+ __m256i pack = _mm256_packs_epi16(
+ npyv512_lower_si256(a), npyv512_higher_si256(a)
+ );
+ return (npy_uint32)_mm256_movemask_epi8(_mm256_permute4x64_epi64(pack, _MM_SHUFFLE(3, 1, 2, 0)));
+#endif
+}
+NPY_FINLINE npy_uint64 npyv_tobits_b32(npyv_b32 a)
+{ return (npy_uint16)a; }
+NPY_FINLINE npy_uint64 npyv_tobits_b64(npyv_b64 a)
+{
+#ifdef NPY_HAVE_AVX512DQ_MASK
+ return _cvtmask8_u32(a);
+#else
+ return (npy_uint8)a;
+#endif
+}
+
+// round to nearest integer (assuming even)
+#define npyv_round_s32_f32 _mm512_cvtps_epi32
+NPY_FINLINE npyv_s32 npyv_round_s32_f64(npyv_f64 a, npyv_f64 b)
+{
+ __m256i lo = _mm512_cvtpd_epi32(a), hi = _mm512_cvtpd_epi32(b);
+ return npyv512_combine_si256(lo, hi);
+}
+
+#endif // _NPY_SIMD_AVX512_CVT_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_MATH_H
+#define _NPY_SIMD_AVX512_MATH_H
+
+/***************************
+ * Elementary
+ ***************************/
+// Square root
+#define npyv_sqrt_f32 _mm512_sqrt_ps
+#define npyv_sqrt_f64 _mm512_sqrt_pd
+
+// Reciprocal
+NPY_FINLINE npyv_f32 npyv_recip_f32(npyv_f32 a)
+{ return _mm512_div_ps(_mm512_set1_ps(1.0f), a); }
+NPY_FINLINE npyv_f64 npyv_recip_f64(npyv_f64 a)
+{ return _mm512_div_pd(_mm512_set1_pd(1.0), a); }
+
+// Absolute
+NPY_FINLINE npyv_f32 npyv_abs_f32(npyv_f32 a)
+{
+#if 0 // def NPY_HAVE_AVX512DQ
+ return _mm512_range_ps(a, a, 8);
+#else
+ return npyv_and_f32(
+ a, _mm512_castsi512_ps(_mm512_set1_epi32(0x7fffffff))
+ );
+#endif
+}
+NPY_FINLINE npyv_f64 npyv_abs_f64(npyv_f64 a)
+{
+#if 0 // def NPY_HAVE_AVX512DQ
+ return _mm512_range_pd(a, a, 8);
+#else
+ return npyv_and_f64(
+ a, _mm512_castsi512_pd(_mm512_set1_epi64(0x7fffffffffffffffLL))
+ );
+#endif
+}
+
+// Square
+NPY_FINLINE npyv_f32 npyv_square_f32(npyv_f32 a)
+{ return _mm512_mul_ps(a, a); }
+NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
+{ return _mm512_mul_pd(a, a); }
+
+#endif
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_MEMORY_H
+#define _NPY_SIMD_AVX512_MEMORY_H
+
+#include "misc.h"
+
+/***************************
+ * load/store
+ ***************************/
+#if defined(__GNUC__)
+ // GCC expect pointer argument type to be `void*` instead of `const void *`,
+ // which cause a massive warning.
+ #define npyv__loads(PTR) _mm512_stream_load_si512((__m512i*)(PTR))
+#else
+ #define npyv__loads(PTR) _mm512_stream_load_si512((const __m512i*)(PTR))
+#endif
+#if defined(_MSC_VER) && defined(_M_IX86)
+ // workaround msvc(32bit) overflow bug, reported at
+ // https://developercommunity.visualstudio.com/content/problem/911872/u.html
+ NPY_FINLINE __m512i npyv__loadl(const __m256i *ptr)
+ {
+ __m256i a = _mm256_loadu_si256(ptr);
+ return _mm512_inserti64x4(_mm512_castsi256_si512(a), a, 0);
+ }
+#else
+ #define npyv__loadl(PTR) \
+ _mm512_castsi256_si512(_mm256_loadu_si256(PTR))
+#endif
+#define NPYV_IMPL_AVX512_MEM_INT(CTYPE, SFX) \
+ NPY_FINLINE npyv_##SFX npyv_load_##SFX(const CTYPE *ptr) \
+ { return _mm512_loadu_si512((const __m512i*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loada_##SFX(const CTYPE *ptr) \
+ { return _mm512_load_si512((const __m512i*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loads_##SFX(const CTYPE *ptr) \
+ { return npyv__loads(ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loadl_##SFX(const CTYPE *ptr) \
+ { return npyv__loadl((const __m256i *)ptr); } \
+ NPY_FINLINE void npyv_store_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm512_storeu_si512((__m512i*)ptr, vec); } \
+ NPY_FINLINE void npyv_storea_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm512_store_si512((__m512i*)ptr, vec); } \
+ NPY_FINLINE void npyv_stores_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm512_stream_si512((__m512i*)ptr, vec); } \
+ NPY_FINLINE void npyv_storel_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm256_storeu_si256((__m256i*)ptr, npyv512_lower_si256(vec)); } \
+ NPY_FINLINE void npyv_storeh_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm256_storeu_si256((__m256i*)(ptr), npyv512_higher_si256(vec)); }
+
+NPYV_IMPL_AVX512_MEM_INT(npy_uint8, u8)
+NPYV_IMPL_AVX512_MEM_INT(npy_int8, s8)
+NPYV_IMPL_AVX512_MEM_INT(npy_uint16, u16)
+NPYV_IMPL_AVX512_MEM_INT(npy_int16, s16)
+NPYV_IMPL_AVX512_MEM_INT(npy_uint32, u32)
+NPYV_IMPL_AVX512_MEM_INT(npy_int32, s32)
+NPYV_IMPL_AVX512_MEM_INT(npy_uint64, u64)
+NPYV_IMPL_AVX512_MEM_INT(npy_int64, s64)
+
+// unaligned load
+#define npyv_load_f32(PTR) _mm512_loadu_ps((const __m512*)(PTR))
+#define npyv_load_f64(PTR) _mm512_loadu_pd((const __m512d*)(PTR))
+// aligned load
+#define npyv_loada_f32(PTR) _mm512_load_ps((const __m512*)(PTR))
+#define npyv_loada_f64(PTR) _mm512_load_pd((const __m512d*)(PTR))
+// load lower part
+#if defined(_MSC_VER) && defined(_M_IX86)
+ #define npyv_loadl_f32(PTR) _mm512_castsi512_ps(npyv__loadl((const __m256i *)(PTR)))
+ #define npyv_loadl_f64(PTR) _mm512_castsi512_pd(npyv__loadl((const __m256i *)(PTR)))
+#else
+ #define npyv_loadl_f32(PTR) _mm512_castps256_ps512(_mm256_loadu_ps(PTR))
+ #define npyv_loadl_f64(PTR) _mm512_castpd256_pd512(_mm256_loadu_pd(PTR))
+#endif
+// stream load
+#define npyv_loads_f32(PTR) _mm512_castsi512_ps(npyv__loads(PTR))
+#define npyv_loads_f64(PTR) _mm512_castsi512_pd(npyv__loads(PTR))
+// unaligned store
+#define npyv_store_f32 _mm512_storeu_ps
+#define npyv_store_f64 _mm512_storeu_pd
+// aligned store
+#define npyv_storea_f32 _mm512_store_ps
+#define npyv_storea_f64 _mm512_store_pd
+// stream store
+#define npyv_stores_f32 _mm512_stream_ps
+#define npyv_stores_f64 _mm512_stream_pd
+// store lower part
+#define npyv_storel_f32(PTR, VEC) _mm256_storeu_ps(PTR, npyv512_lower_ps256(VEC))
+#define npyv_storel_f64(PTR, VEC) _mm256_storeu_pd(PTR, npyv512_lower_pd256(VEC))
+// store higher part
+#define npyv_storeh_f32(PTR, VEC) _mm256_storeu_ps(PTR, npyv512_higher_ps256(VEC))
+#define npyv_storeh_f64(PTR, VEC) _mm256_storeu_pd(PTR, npyv512_higher_pd256(VEC))
+/***************************
+ * Non-contiguous Load
+ ***************************/
+//// 32
+NPY_FINLINE npyv_u32 npyv_loadn_u32(const npy_uint32 *ptr, npy_intp stride)
+{
+ assert(llabs(stride) <= NPY_SIMD_MAXLOAD_STRIDE32);
+ const __m512i steps = npyv_set_s32(
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ );
+ const __m512i idx = _mm512_mullo_epi32(steps, _mm512_set1_epi32((int)stride));
+ return _mm512_i32gather_epi32(idx, (const __m512i*)ptr, 4);
+}
+NPY_FINLINE npyv_s32 npyv_loadn_s32(const npy_int32 *ptr, npy_intp stride)
+{ return npyv_loadn_u32((const npy_uint32*)ptr, stride); }
+NPY_FINLINE npyv_f32 npyv_loadn_f32(const float *ptr, npy_intp stride)
+{ return _mm512_castsi512_ps(npyv_loadn_u32((const npy_uint32*)ptr, stride)); }
+//// 64
+NPY_FINLINE npyv_u64 npyv_loadn_u64(const npy_uint64 *ptr, npy_intp stride)
+{
+ const __m512i idx = _mm512_setr_epi64(
+ 0*stride, 1*stride, 2*stride, 3*stride,
+ 4*stride, 5*stride, 6*stride, 7*stride
+ );
+ return _mm512_i64gather_epi64(idx, (const __m512i*)ptr, 8);
+}
+NPY_FINLINE npyv_s64 npyv_loadn_s64(const npy_int64 *ptr, npy_intp stride)
+{ return npyv_loadn_u64((const npy_uint64*)ptr, stride); }
+NPY_FINLINE npyv_f64 npyv_loadn_f64(const double *ptr, npy_intp stride)
+{ return _mm512_castsi512_pd(npyv_loadn_u64((const npy_uint64*)ptr, stride)); }
+/***************************
+ * Non-contiguous Store
+ ***************************/
+//// 32
+NPY_FINLINE void npyv_storen_u32(npy_uint32 *ptr, npy_intp stride, npyv_u32 a)
+{
+ assert(llabs(stride) <= NPY_SIMD_MAXSTORE_STRIDE32);
+ const __m512i steps = _mm512_setr_epi32(
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ );
+ const __m512i idx = _mm512_mullo_epi32(steps, _mm512_set1_epi32((int)stride));
+ _mm512_i32scatter_epi32((__m512i*)ptr, idx, a, 4);
+}
+NPY_FINLINE void npyv_storen_s32(npy_int32 *ptr, npy_intp stride, npyv_s32 a)
+{ npyv_storen_u32((npy_uint32*)ptr, stride, a); }
+NPY_FINLINE void npyv_storen_f32(float *ptr, npy_intp stride, npyv_f32 a)
+{ npyv_storen_u32((npy_uint32*)ptr, stride, _mm512_castps_si512(a)); }
+//// 64
+NPY_FINLINE void npyv_storen_u64(npy_uint64 *ptr, npy_intp stride, npyv_u64 a)
+{
+ const __m512i idx = _mm512_setr_epi64(
+ 0*stride, 1*stride, 2*stride, 3*stride,
+ 4*stride, 5*stride, 6*stride, 7*stride
+ );
+ _mm512_i64scatter_epi64((__m512i*)ptr, idx, a, 8);
+}
+NPY_FINLINE void npyv_storen_s64(npy_int64 *ptr, npy_intp stride, npyv_s64 a)
+{ npyv_storen_u64((npy_uint64*)ptr, stride, a); }
+NPY_FINLINE void npyv_storen_f64(double *ptr, npy_intp stride, npyv_f64 a)
+{ npyv_storen_u64((npy_uint64*)ptr, stride, _mm512_castpd_si512(a)); }
+
+/*********************************
+ * Partial Load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32 npyv_load_till_s32(const npy_int32 *ptr, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ const __m512i vfill = _mm512_set1_epi32(fill);
+ const __mmask16 mask = nlane > 31 ? -1 : (1 << nlane) - 1;
+ return _mm512_mask_loadu_epi32(vfill, mask, (const __m512i*)ptr);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32 npyv_load_tillz_s32(const npy_int32 *ptr, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ const __mmask16 mask = nlane > 31 ? -1 : (1 << nlane) - 1;
+ return _mm512_maskz_loadu_epi32(mask, (const __m512i*)ptr);
+}
+//// 64
+NPY_FINLINE npyv_s64 npyv_load_till_s64(const npy_int64 *ptr, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ const __m512i vfill = _mm512_set1_epi64(fill);
+ const __mmask8 mask = nlane > 31 ? -1 : (1 << nlane) - 1;
+ return _mm512_mask_loadu_epi64(vfill, mask, (const __m512i*)ptr);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_load_tillz_s64(const npy_int64 *ptr, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ const __mmask8 mask = nlane > 15 ? -1 : (1 << nlane) - 1;
+ return _mm512_maskz_loadu_epi64(mask, (const __m512i*)ptr);
+}
+/*********************************
+ * Non-contiguous partial load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32
+npyv_loadn_till_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ assert(llabs(stride) <= NPY_SIMD_MAXLOAD_STRIDE32);
+ const __m512i steps = npyv_set_s32(
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ );
+ const __m512i idx = _mm512_mullo_epi32(steps, _mm512_set1_epi32((int)stride));
+ const __m512i vfill = _mm512_set1_epi32(fill);
+ const __mmask16 mask = nlane > 31 ? -1 : (1 << nlane) - 1;
+ return _mm512_mask_i32gather_epi32(vfill, mask, idx, (const __m512i*)ptr, 4);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32
+npyv_loadn_tillz_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s32(ptr, stride, nlane, 0); }
+//// 64
+NPY_FINLINE npyv_s64
+npyv_loadn_till_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ const __m512i idx = _mm512_setr_epi64(
+ 0*stride, 1*stride, 2*stride, 3*stride,
+ 4*stride, 5*stride, 6*stride, 7*stride
+ );
+ const __m512i vfill = _mm512_set1_epi64(fill);
+ const __mmask8 mask = nlane > 31 ? -1 : (1 << nlane) - 1;
+ return _mm512_mask_i64gather_epi64(vfill, mask, idx, (const __m512i*)ptr, 8);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64
+npyv_loadn_tillz_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s64(ptr, stride, nlane, 0); }
+/*********************************
+ * Partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_store_till_s32(npy_int32 *ptr, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ const __mmask16 mask = nlane > 31 ? -1 : (1 << nlane) - 1;
+ _mm512_mask_storeu_epi32((__m512i*)ptr, mask, a);
+}
+//// 64
+NPY_FINLINE void npyv_store_till_s64(npy_int64 *ptr, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ const __mmask8 mask = nlane > 15 ? -1 : (1 << nlane) - 1;
+ _mm512_mask_storeu_epi64((__m512i*)ptr, mask, a);
+}
+/*********************************
+ * Non-contiguous partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_storen_till_s32(npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ assert(llabs(stride) <= NPY_SIMD_MAXSTORE_STRIDE32);
+ const __m512i steps = _mm512_setr_epi32(
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ );
+ const __m512i idx = _mm512_mullo_epi32(steps, _mm512_set1_epi32((int)stride));
+ const __mmask16 mask = nlane > 31 ? -1 : (1 << nlane) - 1;
+ _mm512_mask_i32scatter_epi32((__m512i*)ptr, mask, idx, a, 4);
+}
+//// 64
+NPY_FINLINE void npyv_storen_till_s64(npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ const __m512i idx = _mm512_setr_epi64(
+ 0*stride, 1*stride, 2*stride, 3*stride,
+ 4*stride, 5*stride, 6*stride, 7*stride
+ );
+ const __mmask8 mask = nlane > 15 ? -1 : (1 << nlane) - 1;
+ _mm512_mask_i64scatter_epi64((__m512i*)ptr, mask, idx, a, 8);
+}
+
+/*****************************************************************************
+ * Implement partial load/store for u32/f32/u64/f64... via reinterpret cast
+ *****************************************************************************/
+#define NPYV_IMPL_AVX512_REST_PARTIAL_TYPES(F_SFX, T_SFX) \
+ NPY_FINLINE npyv_##F_SFX npyv_load_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, \
+ npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_load_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane \
+ )); \
+ } \
+ NPY_FINLINE void npyv_store_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_store_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ } \
+ NPY_FINLINE void npyv_storen_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_storen_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, stride, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ }
+
+NPYV_IMPL_AVX512_REST_PARTIAL_TYPES(u32, s32)
+NPYV_IMPL_AVX512_REST_PARTIAL_TYPES(f32, s32)
+NPYV_IMPL_AVX512_REST_PARTIAL_TYPES(u64, s64)
+NPYV_IMPL_AVX512_REST_PARTIAL_TYPES(f64, s64)
+
+#endif // _NPY_SIMD_AVX512_MEMORY_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_MISC_H
+#define _NPY_SIMD_AVX512_MISC_H
+
+// set all lanes to zero
+#define npyv_zero_u8 _mm512_setzero_si512
+#define npyv_zero_s8 _mm512_setzero_si512
+#define npyv_zero_u16 _mm512_setzero_si512
+#define npyv_zero_s16 _mm512_setzero_si512
+#define npyv_zero_u32 _mm512_setzero_si512
+#define npyv_zero_s32 _mm512_setzero_si512
+#define npyv_zero_u64 _mm512_setzero_si512
+#define npyv_zero_s64 _mm512_setzero_si512
+#define npyv_zero_f32 _mm512_setzero_ps
+#define npyv_zero_f64 _mm512_setzero_pd
+
+// set all lanes to same value
+#define npyv_setall_u8(VAL) _mm512_set1_epi8((char)VAL)
+#define npyv_setall_s8(VAL) _mm512_set1_epi8((char)VAL)
+#define npyv_setall_u16(VAL) _mm512_set1_epi16((short)VAL)
+#define npyv_setall_s16(VAL) _mm512_set1_epi16((short)VAL)
+#define npyv_setall_u32(VAL) _mm512_set1_epi32((int)VAL)
+#define npyv_setall_s32(VAL) _mm512_set1_epi32(VAL)
+#define npyv_setall_u64(VAL) _mm512_set1_epi64(VAL)
+#define npyv_setall_s64(VAL) _mm512_set1_epi64(VAL)
+#define npyv_setall_f32(VAL) _mm512_set1_ps(VAL)
+#define npyv_setall_f64(VAL) _mm512_set1_pd(VAL)
+
+/**
+ * vector with specific values set to each lane and
+ * set a specific value to all remained lanes
+ *
+ * _mm512_set_epi8 and _mm512_set_epi16 are missing in many compilers
+ */
+NPY_FINLINE __m512i npyv__setr_epi8(
+ char i0, char i1, char i2, char i3, char i4, char i5, char i6, char i7,
+ char i8, char i9, char i10, char i11, char i12, char i13, char i14, char i15,
+ char i16, char i17, char i18, char i19, char i20, char i21, char i22, char i23,
+ char i24, char i25, char i26, char i27, char i28, char i29, char i30, char i31,
+ char i32, char i33, char i34, char i35, char i36, char i37, char i38, char i39,
+ char i40, char i41, char i42, char i43, char i44, char i45, char i46, char i47,
+ char i48, char i49, char i50, char i51, char i52, char i53, char i54, char i55,
+ char i56, char i57, char i58, char i59, char i60, char i61, char i62, char i63)
+{
+ const char NPY_DECL_ALIGNED(64) data[64] = {
+ i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15,
+ i16, i17, i18, i19, i20, i21, i22, i23, i24, i25, i26, i27, i28, i29, i30, i31,
+ i32, i33, i34, i35, i36, i37, i38, i39, i40, i41, i42, i43, i44, i45, i46, i47,
+ i48, i49, i50, i51, i52, i53, i54, i55, i56, i57, i58, i59, i60, i61, i62, i63
+ };
+ return _mm512_load_si512((const void*)data);
+}
+NPY_FINLINE __m512i npyv__setr_epi16(
+ short i0, short i1, short i2, short i3, short i4, short i5, short i6, short i7,
+ short i8, short i9, short i10, short i11, short i12, short i13, short i14, short i15,
+ short i16, short i17, short i18, short i19, short i20, short i21, short i22, short i23,
+ short i24, short i25, short i26, short i27, short i28, short i29, short i30, short i31)
+{
+ const short NPY_DECL_ALIGNED(64) data[32] = {
+ i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15,
+ i16, i17, i18, i19, i20, i21, i22, i23, i24, i25, i26, i27, i28, i29, i30, i31
+ };
+ return _mm512_load_si512((const void*)data);
+}
+// args that generated by NPYV__SET_FILL_* not going to expand if
+// _mm512_setr_* are defined as macros.
+NPY_FINLINE __m512i npyv__setr_epi32(
+ int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7,
+ int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15)
+{
+ return _mm512_setr_epi32(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);
+}
+NPY_FINLINE __m512i npyv__setr_epi64(npy_int64 i0, npy_int64 i1, npy_int64 i2, npy_int64 i3,
+ npy_int64 i4, npy_int64 i5, npy_int64 i6, npy_int64 i7)
+{
+ return _mm512_setr_epi64(i0, i1, i2, i3, i4, i5, i6, i7);
+}
+
+NPY_FINLINE __m512 npyv__setr_ps(
+ float i0, float i1, float i2, float i3, float i4, float i5, float i6, float i7,
+ float i8, float i9, float i10, float i11, float i12, float i13, float i14, float i15)
+{
+ return _mm512_setr_ps(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);
+}
+NPY_FINLINE __m512d npyv__setr_pd(double i0, double i1, double i2, double i3,
+ double i4, double i5, double i6, double i7)
+{
+ return _mm512_setr_pd(i0, i1, i2, i3, i4, i5, i6, i7);
+}
+#define npyv_setf_u8(FILL, ...) npyv__setr_epi8(NPYV__SET_FILL_64(char, FILL, __VA_ARGS__))
+#define npyv_setf_s8(FILL, ...) npyv__setr_epi8(NPYV__SET_FILL_64(char, FILL, __VA_ARGS__))
+#define npyv_setf_u16(FILL, ...) npyv__setr_epi16(NPYV__SET_FILL_32(short, FILL, __VA_ARGS__))
+#define npyv_setf_s16(FILL, ...) npyv__setr_epi16(NPYV__SET_FILL_32(short, FILL, __VA_ARGS__))
+#define npyv_setf_u32(FILL, ...) npyv__setr_epi32(NPYV__SET_FILL_16(int, FILL, __VA_ARGS__))
+#define npyv_setf_s32(FILL, ...) npyv__setr_epi32(NPYV__SET_FILL_16(int, FILL, __VA_ARGS__))
+#define npyv_setf_u64(FILL, ...) npyv__setr_epi64(NPYV__SET_FILL_8(npy_int64, FILL, __VA_ARGS__))
+#define npyv_setf_s64(FILL, ...) npyv__setr_epi64(NPYV__SET_FILL_8(npy_int64, FILL, __VA_ARGS__))
+#define npyv_setf_f32(FILL, ...) npyv__setr_ps(NPYV__SET_FILL_16(float, FILL, __VA_ARGS__))
+#define npyv_setf_f64(FILL, ...) npyv__setr_pd(NPYV__SET_FILL_8(double, FILL, __VA_ARGS__))
+
+// vector with specific values set to each lane and
+// set zero to all remained lanes
+#define npyv_set_u8(...) npyv_setf_u8(0, __VA_ARGS__)
+#define npyv_set_s8(...) npyv_setf_s8(0, __VA_ARGS__)
+#define npyv_set_u16(...) npyv_setf_u16(0, __VA_ARGS__)
+#define npyv_set_s16(...) npyv_setf_s16(0, __VA_ARGS__)
+#define npyv_set_u32(...) npyv_setf_u32(0, __VA_ARGS__)
+#define npyv_set_s32(...) npyv_setf_s32(0, __VA_ARGS__)
+#define npyv_set_u64(...) npyv_setf_u64(0, __VA_ARGS__)
+#define npyv_set_s64(...) npyv_setf_s64(0, __VA_ARGS__)
+#define npyv_set_f32(...) npyv_setf_f32(0, __VA_ARGS__)
+#define npyv_set_f64(...) npyv_setf_f64(0, __VA_ARGS__)
+
+// per lane select
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_select_u8(MASK, A, B) _mm512_mask_blend_epi8(MASK, B, A)
+ #define npyv_select_u16(MASK, A, B) _mm512_mask_blend_epi16(MASK, B, A)
+#else
+ NPY_FINLINE __m512i npyv_select_u8(__m512i mask, __m512i a, __m512i b)
+ { return _mm512_xor_si512(b, _mm512_and_si512(_mm512_xor_si512(b, a), mask)); }
+ #define npyv_select_u16 npyv_select_u8
+#endif
+#define npyv_select_s8 npyv_select_u8
+#define npyv_select_s16 npyv_select_u16
+#define npyv_select_u32(MASK, A, B) _mm512_mask_blend_epi32(MASK, B, A)
+#define npyv_select_s32 npyv_select_u32
+#define npyv_select_u64(MASK, A, B) _mm512_mask_blend_epi64(MASK, B, A)
+#define npyv_select_s64 npyv_select_u64
+#define npyv_select_f32(MASK, A, B) _mm512_mask_blend_ps(MASK, B, A)
+#define npyv_select_f64(MASK, A, B) _mm512_mask_blend_pd(MASK, B, A)
+
+// reinterpret
+#define npyv_reinterpret_u8_u8(X) X
+#define npyv_reinterpret_u8_s8(X) X
+#define npyv_reinterpret_u8_u16(X) X
+#define npyv_reinterpret_u8_s16(X) X
+#define npyv_reinterpret_u8_u32(X) X
+#define npyv_reinterpret_u8_s32(X) X
+#define npyv_reinterpret_u8_u64(X) X
+#define npyv_reinterpret_u8_s64(X) X
+#define npyv_reinterpret_u8_f32 _mm512_castps_si512
+#define npyv_reinterpret_u8_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_s8_s8(X) X
+#define npyv_reinterpret_s8_u8(X) X
+#define npyv_reinterpret_s8_u16(X) X
+#define npyv_reinterpret_s8_s16(X) X
+#define npyv_reinterpret_s8_u32(X) X
+#define npyv_reinterpret_s8_s32(X) X
+#define npyv_reinterpret_s8_u64(X) X
+#define npyv_reinterpret_s8_s64(X) X
+#define npyv_reinterpret_s8_f32 _mm512_castps_si512
+#define npyv_reinterpret_s8_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_u16_u16(X) X
+#define npyv_reinterpret_u16_u8(X) X
+#define npyv_reinterpret_u16_s8(X) X
+#define npyv_reinterpret_u16_s16(X) X
+#define npyv_reinterpret_u16_u32(X) X
+#define npyv_reinterpret_u16_s32(X) X
+#define npyv_reinterpret_u16_u64(X) X
+#define npyv_reinterpret_u16_s64(X) X
+#define npyv_reinterpret_u16_f32 _mm512_castps_si512
+#define npyv_reinterpret_u16_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_s16_s16(X) X
+#define npyv_reinterpret_s16_u8(X) X
+#define npyv_reinterpret_s16_s8(X) X
+#define npyv_reinterpret_s16_u16(X) X
+#define npyv_reinterpret_s16_u32(X) X
+#define npyv_reinterpret_s16_s32(X) X
+#define npyv_reinterpret_s16_u64(X) X
+#define npyv_reinterpret_s16_s64(X) X
+#define npyv_reinterpret_s16_f32 _mm512_castps_si512
+#define npyv_reinterpret_s16_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_u32_u32(X) X
+#define npyv_reinterpret_u32_u8(X) X
+#define npyv_reinterpret_u32_s8(X) X
+#define npyv_reinterpret_u32_u16(X) X
+#define npyv_reinterpret_u32_s16(X) X
+#define npyv_reinterpret_u32_s32(X) X
+#define npyv_reinterpret_u32_u64(X) X
+#define npyv_reinterpret_u32_s64(X) X
+#define npyv_reinterpret_u32_f32 _mm512_castps_si512
+#define npyv_reinterpret_u32_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_s32_s32(X) X
+#define npyv_reinterpret_s32_u8(X) X
+#define npyv_reinterpret_s32_s8(X) X
+#define npyv_reinterpret_s32_u16(X) X
+#define npyv_reinterpret_s32_s16(X) X
+#define npyv_reinterpret_s32_u32(X) X
+#define npyv_reinterpret_s32_u64(X) X
+#define npyv_reinterpret_s32_s64(X) X
+#define npyv_reinterpret_s32_f32 _mm512_castps_si512
+#define npyv_reinterpret_s32_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_u64_u64(X) X
+#define npyv_reinterpret_u64_u8(X) X
+#define npyv_reinterpret_u64_s8(X) X
+#define npyv_reinterpret_u64_u16(X) X
+#define npyv_reinterpret_u64_s16(X) X
+#define npyv_reinterpret_u64_u32(X) X
+#define npyv_reinterpret_u64_s32(X) X
+#define npyv_reinterpret_u64_s64(X) X
+#define npyv_reinterpret_u64_f32 _mm512_castps_si512
+#define npyv_reinterpret_u64_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_s64_s64(X) X
+#define npyv_reinterpret_s64_u8(X) X
+#define npyv_reinterpret_s64_s8(X) X
+#define npyv_reinterpret_s64_u16(X) X
+#define npyv_reinterpret_s64_s16(X) X
+#define npyv_reinterpret_s64_u32(X) X
+#define npyv_reinterpret_s64_s32(X) X
+#define npyv_reinterpret_s64_u64(X) X
+#define npyv_reinterpret_s64_f32 _mm512_castps_si512
+#define npyv_reinterpret_s64_f64 _mm512_castpd_si512
+
+#define npyv_reinterpret_f32_f32(X) X
+#define npyv_reinterpret_f32_u8 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_s8 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_u16 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_s16 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_u32 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_s32 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_u64 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_s64 _mm512_castsi512_ps
+#define npyv_reinterpret_f32_f64 _mm512_castpd_ps
+
+#define npyv_reinterpret_f64_f64(X) X
+#define npyv_reinterpret_f64_u8 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_s8 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_u16 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_s16 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_u32 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_s32 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_u64 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_s64 _mm512_castsi512_pd
+#define npyv_reinterpret_f64_f32 _mm512_castps_pd
+
+#ifdef NPY_HAVE_AVX512_KNL
+ #define npyv_cleanup() ((void)0)
+#else
+ #define npyv_cleanup _mm256_zeroall
+#endif
+
+#endif // _NPY_SIMD_AVX512_MISC_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_OPERATORS_H
+#define _NPY_SIMD_AVX512_OPERATORS_H
+
+/***************************
+ * Shifting
+ ***************************/
+
+// left
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_shl_u16(A, C) _mm512_sll_epi16(A, _mm_cvtsi32_si128(C))
+#else
+ #define NPYV_IMPL_AVX512_SHIFT(FN, INTRIN) \
+ NPY_FINLINE __m512i npyv_##FN(__m512i a, int c) \
+ { \
+ __m256i l = npyv512_lower_si256(a); \
+ __m256i h = npyv512_higher_si256(a); \
+ __m128i cv = _mm_cvtsi32_si128(c); \
+ l = _mm256_##INTRIN(l, cv); \
+ h = _mm256_##INTRIN(h, cv); \
+ return npyv512_combine_si256(l, h); \
+ }
+
+ NPYV_IMPL_AVX512_SHIFT(shl_u16, sll_epi16)
+#endif
+#define npyv_shl_s16 npyv_shl_u16
+#define npyv_shl_u32(A, C) _mm512_sll_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s32(A, C) _mm512_sll_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_u64(A, C) _mm512_sll_epi64(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s64(A, C) _mm512_sll_epi64(A, _mm_cvtsi32_si128(C))
+
+// left by an immediate constant
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_shli_u16 _mm512_slli_epi16
+#else
+ #define npyv_shli_u16 npyv_shl_u16
+#endif
+#define npyv_shli_s16 npyv_shl_u16
+#define npyv_shli_u32 _mm512_slli_epi32
+#define npyv_shli_s32 _mm512_slli_epi32
+#define npyv_shli_u64 _mm512_slli_epi64
+#define npyv_shli_s64 _mm512_slli_epi64
+
+// right
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_shr_u16(A, C) _mm512_srl_epi16(A, _mm_cvtsi32_si128(C))
+ #define npyv_shr_s16(A, C) _mm512_sra_epi16(A, _mm_cvtsi32_si128(C))
+#else
+ NPYV_IMPL_AVX512_SHIFT(shr_u16, srl_epi16)
+ NPYV_IMPL_AVX512_SHIFT(shr_s16, sra_epi16)
+#endif
+#define npyv_shr_u32(A, C) _mm512_srl_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_s32(A, C) _mm512_sra_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_u64(A, C) _mm512_srl_epi64(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_s64(A, C) _mm512_sra_epi64(A, _mm_cvtsi32_si128(C))
+
+// right by an immediate constant
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_shri_u16 _mm512_srli_epi16
+ #define npyv_shri_s16 _mm512_srai_epi16
+#else
+ #define npyv_shri_u16 npyv_shr_u16
+ #define npyv_shri_s16 npyv_shr_s16
+#endif
+#define npyv_shri_u32 _mm512_srli_epi32
+#define npyv_shri_s32 _mm512_srai_epi32
+#define npyv_shri_u64 _mm512_srli_epi64
+#define npyv_shri_s64 _mm512_srai_epi64
+
+/***************************
+ * Logical
+ ***************************/
+
+// AND
+#define npyv_and_u8 _mm512_and_si512
+#define npyv_and_s8 _mm512_and_si512
+#define npyv_and_u16 _mm512_and_si512
+#define npyv_and_s16 _mm512_and_si512
+#define npyv_and_u32 _mm512_and_si512
+#define npyv_and_s32 _mm512_and_si512
+#define npyv_and_u64 _mm512_and_si512
+#define npyv_and_s64 _mm512_and_si512
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_and_f32 _mm512_and_ps
+ #define npyv_and_f64 _mm512_and_pd
+#else
+ NPYV_IMPL_AVX512_FROM_SI512_PS_2ARG(npyv_and_f32, _mm512_and_si512)
+ NPYV_IMPL_AVX512_FROM_SI512_PD_2ARG(npyv_and_f64, _mm512_and_si512)
+#endif
+// OR
+#define npyv_or_u8 _mm512_or_si512
+#define npyv_or_s8 _mm512_or_si512
+#define npyv_or_u16 _mm512_or_si512
+#define npyv_or_s16 _mm512_or_si512
+#define npyv_or_u32 _mm512_or_si512
+#define npyv_or_s32 _mm512_or_si512
+#define npyv_or_u64 _mm512_or_si512
+#define npyv_or_s64 _mm512_or_si512
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_or_f32 _mm512_or_ps
+ #define npyv_or_f64 _mm512_or_pd
+#else
+ NPYV_IMPL_AVX512_FROM_SI512_PS_2ARG(npyv_or_f32, _mm512_or_si512)
+ NPYV_IMPL_AVX512_FROM_SI512_PD_2ARG(npyv_or_f64, _mm512_or_si512)
+#endif
+
+// XOR
+#define npyv_xor_u8 _mm512_xor_si512
+#define npyv_xor_s8 _mm512_xor_si512
+#define npyv_xor_u16 _mm512_xor_si512
+#define npyv_xor_s16 _mm512_xor_si512
+#define npyv_xor_u32 _mm512_xor_si512
+#define npyv_xor_s32 _mm512_xor_si512
+#define npyv_xor_u64 _mm512_xor_si512
+#define npyv_xor_s64 _mm512_xor_si512
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_xor_f32 _mm512_xor_ps
+ #define npyv_xor_f64 _mm512_xor_pd
+#else
+ NPYV_IMPL_AVX512_FROM_SI512_PS_2ARG(npyv_xor_f32, _mm512_xor_si512)
+ NPYV_IMPL_AVX512_FROM_SI512_PD_2ARG(npyv_xor_f64, _mm512_xor_si512)
+#endif
+// NOT
+#define npyv_not_u8(A) _mm512_xor_si512(A, _mm512_set1_epi32(-1))
+#define npyv_not_s8 npyv_not_u8
+#define npyv_not_u16 npyv_not_u8
+#define npyv_not_s16 npyv_not_u8
+#define npyv_not_u32 npyv_not_u8
+#define npyv_not_s32 npyv_not_u8
+#define npyv_not_u64 npyv_not_u8
+#define npyv_not_s64 npyv_not_u8
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_not_f32(A) _mm512_xor_ps(A, _mm512_castsi512_ps(_mm512_set1_epi32(-1)))
+ #define npyv_not_f64(A) _mm512_xor_pd(A, _mm512_castsi512_pd(_mm512_set1_epi32(-1)))
+#else
+ #define npyv_not_f32(A) _mm512_castsi512_ps(npyv_not_u32(_mm512_castps_si512(A)))
+ #define npyv_not_f64(A) _mm512_castsi512_pd(npyv_not_u64(_mm512_castpd_si512(A)))
+#endif
+
+/***************************
+ * Logical (boolean)
+ ***************************/
+#ifdef NPY_HAVE_AVX512BW_MASK
+ #define npyv_and_b8 _kand_mask64
+ #define npyv_and_b16 _kand_mask32
+ #define npyv_or_b8 _kor_mask64
+ #define npyv_or_b16 _kor_mask32
+ #define npyv_xor_b8 _kxor_mask64
+ #define npyv_xor_b16 _kxor_mask32
+ #define npyv_not_b8 _knot_mask64
+ #define npyv_not_b16 _knot_mask32
+#elif defined(NPY_HAVE_AVX512BW)
+ NPY_FINLINE npyv_b8 npyv_and_b8(npyv_b8 a, npyv_b8 b)
+ { return a & b; }
+ NPY_FINLINE npyv_b16 npyv_and_b16(npyv_b16 a, npyv_b16 b)
+ { return a & b; }
+ NPY_FINLINE npyv_b8 npyv_or_b8(npyv_b8 a, npyv_b8 b)
+ { return a | b; }
+ NPY_FINLINE npyv_b16 npyv_or_b16(npyv_b16 a, npyv_b16 b)
+ { return a | b; }
+ NPY_FINLINE npyv_b8 npyv_xor_b8(npyv_b8 a, npyv_b8 b)
+ { return a ^ b; }
+ NPY_FINLINE npyv_b16 npyv_xor_b16(npyv_b16 a, npyv_b16 b)
+ { return a ^ b; }
+ NPY_FINLINE npyv_b8 npyv_not_b8(npyv_b8 a)
+ { return ~a; }
+ NPY_FINLINE npyv_b16 npyv_not_b16(npyv_b16 a)
+ { return ~a; }
+#else
+ #define npyv_and_b8 _mm512_and_si512
+ #define npyv_and_b16 _mm512_and_si512
+ #define npyv_or_b8 _mm512_or_si512
+ #define npyv_or_b16 _mm512_or_si512
+ #define npyv_xor_b8 _mm512_xor_si512
+ #define npyv_xor_b16 _mm512_xor_si512
+ #define npyv_not_b8 npyv_not_u8
+ #define npyv_not_b16 npyv_not_u8
+#endif
+
+#define npyv_and_b32 _mm512_kand
+#define npyv_or_b32 _mm512_kor
+#define npyv_xor_b32 _mm512_kxor
+#define npyv_not_b32 _mm512_knot
+
+#ifdef NPY_HAVE_AVX512DQ_MASK
+ #define npyv_and_b64 _kand_mask8
+ #define npyv_or_b64 _kor_mask8
+ #define npyv_xor_b64 _kxor_mask8
+ #define npyv_not_b64 _knot_mask8
+#else
+ NPY_FINLINE npyv_b64 npyv_and_b64(npyv_b64 a, npyv_b64 b)
+ { return (npyv_b64)_mm512_kand((npyv_b32)a, (npyv_b32)b); }
+ NPY_FINLINE npyv_b64 npyv_or_b64(npyv_b64 a, npyv_b64 b)
+ { return (npyv_b64)_mm512_kor((npyv_b32)a, (npyv_b32)b); }
+ NPY_FINLINE npyv_b64 npyv_xor_b64(npyv_b64 a, npyv_b64 b)
+ { return (npyv_b64)_mm512_kxor((npyv_b32)a, (npyv_b32)b); }
+ NPY_FINLINE npyv_b64 npyv_not_b64(npyv_b64 a)
+ { return (npyv_b64)_mm512_knot((npyv_b32)a); }
+#endif
+
+/***************************
+ * Comparison
+ ***************************/
+
+// int Equal
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_cmpeq_u8 _mm512_cmpeq_epu8_mask
+ #define npyv_cmpeq_s8 _mm512_cmpeq_epi8_mask
+ #define npyv_cmpeq_u16 _mm512_cmpeq_epu16_mask
+ #define npyv_cmpeq_s16 _mm512_cmpeq_epi16_mask
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_cmpeq_u8, _mm256_cmpeq_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_cmpeq_u16, _mm256_cmpeq_epi16)
+ #define npyv_cmpeq_s8 npyv_cmpeq_u8
+ #define npyv_cmpeq_s16 npyv_cmpeq_u16
+#endif
+#define npyv_cmpeq_u32 _mm512_cmpeq_epu32_mask
+#define npyv_cmpeq_s32 _mm512_cmpeq_epi32_mask
+#define npyv_cmpeq_u64 _mm512_cmpeq_epu64_mask
+#define npyv_cmpeq_s64 _mm512_cmpeq_epi64_mask
+
+// int not equal
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_cmpneq_u8 _mm512_cmpneq_epu8_mask
+ #define npyv_cmpneq_s8 _mm512_cmpneq_epi8_mask
+ #define npyv_cmpneq_u16 _mm512_cmpneq_epu16_mask
+ #define npyv_cmpneq_s16 _mm512_cmpneq_epi16_mask
+#else
+ #define npyv_cmpneq_u8(A, B) npyv_not_u8(npyv_cmpeq_u8(A, B))
+ #define npyv_cmpneq_u16(A, B) npyv_not_u16(npyv_cmpeq_u16(A, B))
+ #define npyv_cmpneq_s8 npyv_cmpneq_u8
+ #define npyv_cmpneq_s16 npyv_cmpneq_u16
+#endif
+#define npyv_cmpneq_u32 _mm512_cmpneq_epu32_mask
+#define npyv_cmpneq_s32 _mm512_cmpneq_epi32_mask
+#define npyv_cmpneq_u64 _mm512_cmpneq_epu64_mask
+#define npyv_cmpneq_s64 _mm512_cmpneq_epi64_mask
+
+// greater than
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_cmpgt_u8 _mm512_cmpgt_epu8_mask
+ #define npyv_cmpgt_s8 _mm512_cmpgt_epi8_mask
+ #define npyv_cmpgt_u16 _mm512_cmpgt_epu16_mask
+ #define npyv_cmpgt_s16 _mm512_cmpgt_epi16_mask
+#else
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_cmpgt_s8, _mm256_cmpgt_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv_cmpgt_s16, _mm256_cmpgt_epi16)
+ NPY_FINLINE __m512i npyv_cmpgt_u8(__m512i a, __m512i b)
+ {
+ const __m512i sbit = _mm512_set1_epi32(0x80808080);
+ return npyv_cmpgt_s8(_mm512_xor_si512(a, sbit), _mm512_xor_si512(b, sbit));
+ }
+ NPY_FINLINE __m512i npyv_cmpgt_u16(__m512i a, __m512i b)
+ {
+ const __m512i sbit = _mm512_set1_epi32(0x80008000);
+ return npyv_cmpgt_s16(_mm512_xor_si512(a, sbit), _mm512_xor_si512(b, sbit));
+ }
+#endif
+#define npyv_cmpgt_u32 _mm512_cmpgt_epu32_mask
+#define npyv_cmpgt_s32 _mm512_cmpgt_epi32_mask
+#define npyv_cmpgt_u64 _mm512_cmpgt_epu64_mask
+#define npyv_cmpgt_s64 _mm512_cmpgt_epi64_mask
+
+// greater than or equal
+#ifdef NPY_HAVE_AVX512BW
+ #define npyv_cmpge_u8 _mm512_cmpge_epu8_mask
+ #define npyv_cmpge_s8 _mm512_cmpge_epi8_mask
+ #define npyv_cmpge_u16 _mm512_cmpge_epu16_mask
+ #define npyv_cmpge_s16 _mm512_cmpge_epi16_mask
+#else
+ #define npyv_cmpge_u8(A, B) npyv_not_u8(npyv_cmpgt_u8(B, A))
+ #define npyv_cmpge_s8(A, B) npyv_not_s8(npyv_cmpgt_s8(B, A))
+ #define npyv_cmpge_u16(A, B) npyv_not_u16(npyv_cmpgt_u16(B, A))
+ #define npyv_cmpge_s16(A, B) npyv_not_s16(npyv_cmpgt_s16(B, A))
+#endif
+#define npyv_cmpge_u32 _mm512_cmpge_epu32_mask
+#define npyv_cmpge_s32 _mm512_cmpge_epi32_mask
+#define npyv_cmpge_u64 _mm512_cmpge_epu64_mask
+#define npyv_cmpge_s64 _mm512_cmpge_epi64_mask
+
+// less than
+#define npyv_cmplt_u8(A, B) npyv_cmpgt_u8(B, A)
+#define npyv_cmplt_s8(A, B) npyv_cmpgt_s8(B, A)
+#define npyv_cmplt_u16(A, B) npyv_cmpgt_u16(B, A)
+#define npyv_cmplt_s16(A, B) npyv_cmpgt_s16(B, A)
+#define npyv_cmplt_u32(A, B) npyv_cmpgt_u32(B, A)
+#define npyv_cmplt_s32(A, B) npyv_cmpgt_s32(B, A)
+#define npyv_cmplt_u64(A, B) npyv_cmpgt_u64(B, A)
+#define npyv_cmplt_s64(A, B) npyv_cmpgt_s64(B, A)
+
+// less than or equal
+#define npyv_cmple_u8(A, B) npyv_cmpge_u8(B, A)
+#define npyv_cmple_s8(A, B) npyv_cmpge_s8(B, A)
+#define npyv_cmple_u16(A, B) npyv_cmpge_u16(B, A)
+#define npyv_cmple_s16(A, B) npyv_cmpge_s16(B, A)
+#define npyv_cmple_u32(A, B) npyv_cmpge_u32(B, A)
+#define npyv_cmple_s32(A, B) npyv_cmpge_s32(B, A)
+#define npyv_cmple_u64(A, B) npyv_cmpge_u64(B, A)
+#define npyv_cmple_s64(A, B) npyv_cmpge_s64(B, A)
+
+// precision comparison
+#define npyv_cmpeq_f32(A, B) _mm512_cmp_ps_mask(A, B, _CMP_EQ_OQ)
+#define npyv_cmpeq_f64(A, B) _mm512_cmp_pd_mask(A, B, _CMP_EQ_OQ)
+#define npyv_cmpneq_f32(A, B) _mm512_cmp_ps_mask(A, B, _CMP_NEQ_OQ)
+#define npyv_cmpneq_f64(A, B) _mm512_cmp_pd_mask(A, B, _CMP_NEQ_OQ)
+#define npyv_cmplt_f32(A, B) _mm512_cmp_ps_mask(A, B, _CMP_LT_OQ)
+#define npyv_cmplt_f64(A, B) _mm512_cmp_pd_mask(A, B, _CMP_LT_OQ)
+#define npyv_cmple_f32(A, B) _mm512_cmp_ps_mask(A, B, _CMP_LE_OQ)
+#define npyv_cmple_f64(A, B) _mm512_cmp_pd_mask(A, B, _CMP_LE_OQ)
+#define npyv_cmpgt_f32(A, B) _mm512_cmp_ps_mask(A, B, _CMP_GT_OQ)
+#define npyv_cmpgt_f64(A, B) _mm512_cmp_pd_mask(A, B, _CMP_GT_OQ)
+#define npyv_cmpge_f32(A, B) _mm512_cmp_ps_mask(A, B, _CMP_GE_OQ)
+#define npyv_cmpge_f64(A, B) _mm512_cmp_pd_mask(A, B, _CMP_GE_OQ)
+
+// check special cases
+NPY_FINLINE npyv_b32 npyv_notnan_f32(npyv_f32 a)
+{ return _mm512_cmp_ps_mask(a, a, _CMP_ORD_Q); }
+NPY_FINLINE npyv_b64 npyv_notnan_f64(npyv_f64 a)
+{ return _mm512_cmp_pd_mask(a, a, _CMP_ORD_Q); }
+
+#endif // _NPY_SIMD_AVX512_OPERATORS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_REORDER_H
+#define _NPY_SIMD_AVX512_REORDER_H
+
+// combine lower part of two vectors
+#define npyv_combinel_u8(A, B) _mm512_inserti64x4(A, _mm512_castsi512_si256(B), 1)
+#define npyv_combinel_s8 npyv_combinel_u8
+#define npyv_combinel_u16 npyv_combinel_u8
+#define npyv_combinel_s16 npyv_combinel_u8
+#define npyv_combinel_u32 npyv_combinel_u8
+#define npyv_combinel_s32 npyv_combinel_u8
+#define npyv_combinel_u64 npyv_combinel_u8
+#define npyv_combinel_s64 npyv_combinel_u8
+#define npyv_combinel_f64(A, B) _mm512_insertf64x4(A, _mm512_castpd512_pd256(B), 1)
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_combinel_f32(A, B) \
+ _mm512_insertf32x8(A, _mm512_castps512_ps256(B), 1)
+#else
+ #define npyv_combinel_f32(A, B) \
+ _mm512_castsi512_ps(npyv_combinel_u8(_mm512_castps_si512(A), _mm512_castps_si512(B)))
+#endif
+
+// combine higher part of two vectors
+#define npyv_combineh_u8(A, B) _mm512_inserti64x4(B, _mm512_extracti64x4_epi64(A, 1), 0)
+#define npyv_combineh_s8 npyv_combineh_u8
+#define npyv_combineh_u16 npyv_combineh_u8
+#define npyv_combineh_s16 npyv_combineh_u8
+#define npyv_combineh_u32 npyv_combineh_u8
+#define npyv_combineh_s32 npyv_combineh_u8
+#define npyv_combineh_u64 npyv_combineh_u8
+#define npyv_combineh_s64 npyv_combineh_u8
+#define npyv_combineh_f64(A, B) _mm512_insertf64x4(B, _mm512_extractf64x4_pd(A, 1), 0)
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv_combineh_f32(A, B) \
+ _mm512_insertf32x8(B, _mm512_extractf32x8_ps(A, 1), 0)
+#else
+ #define npyv_combineh_f32(A, B) \
+ _mm512_castsi512_ps(npyv_combineh_u8(_mm512_castps_si512(A), _mm512_castps_si512(B)))
+#endif
+
+// combine two vectors from lower and higher parts of two other vectors
+NPY_FINLINE npyv_m512ix2 npyv__combine(__m512i a, __m512i b)
+{
+ npyv_m512ix2 r;
+ r.val[0] = npyv_combinel_u8(a, b);
+ r.val[1] = npyv_combineh_u8(a, b);
+ return r;
+}
+NPY_FINLINE npyv_f32x2 npyv_combine_f32(__m512 a, __m512 b)
+{
+ npyv_f32x2 r;
+ r.val[0] = npyv_combinel_f32(a, b);
+ r.val[1] = npyv_combineh_f32(a, b);
+ return r;
+}
+NPY_FINLINE npyv_f64x2 npyv_combine_f64(__m512d a, __m512d b)
+{
+ npyv_f64x2 r;
+ r.val[0] = npyv_combinel_f64(a, b);
+ r.val[1] = npyv_combineh_f64(a, b);
+ return r;
+}
+#define npyv_combine_u8 npyv__combine
+#define npyv_combine_s8 npyv__combine
+#define npyv_combine_u16 npyv__combine
+#define npyv_combine_s16 npyv__combine
+#define npyv_combine_u32 npyv__combine
+#define npyv_combine_s32 npyv__combine
+#define npyv_combine_u64 npyv__combine
+#define npyv_combine_s64 npyv__combine
+
+// interleave two vectors
+#ifndef NPY_HAVE_AVX512BW
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv__unpacklo_epi8, _mm256_unpacklo_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv__unpackhi_epi8, _mm256_unpackhi_epi8)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv__unpacklo_epi16, _mm256_unpacklo_epi16)
+ NPYV_IMPL_AVX512_FROM_AVX2_2ARG(npyv__unpackhi_epi16, _mm256_unpackhi_epi16)
+#endif
+
+NPY_FINLINE npyv_u64x2 npyv_zip_u64(__m512i a, __m512i b)
+{
+ npyv_u64x2 r;
+ r.val[0] = _mm512_permutex2var_epi64(a, npyv_set_u64(0, 8, 1, 9, 2, 10, 3, 11), b);
+ r.val[1] = _mm512_permutex2var_epi64(a, npyv_set_u64(4, 12, 5, 13, 6, 14, 7, 15), b);
+ return r;
+}
+#define npyv_zip_s64 npyv_zip_u64
+
+NPY_FINLINE npyv_u8x2 npyv_zip_u8(__m512i a, __m512i b)
+{
+ npyv_u8x2 r;
+#ifdef NPY_HAVE_AVX512VBMI
+ r.val[0] = _mm512_permutex2var_epi8(a,
+ npyv_set_u8(0, 64, 1, 65, 2, 66, 3, 67, 4, 68, 5, 69, 6, 70, 7, 71,
+ 8, 72, 9, 73, 10, 74, 11, 75, 12, 76, 13, 77, 14, 78, 15, 79,
+ 16, 80, 17, 81, 18, 82, 19, 83, 20, 84, 21, 85, 22, 86, 23, 87,
+ 24, 88, 25, 89, 26, 90, 27, 91, 28, 92, 29, 93, 30, 94, 31, 95), b);
+ r.val[1] = _mm512_permutex2var_epi8(a,
+ npyv_set_u8(32, 96, 33, 97, 34, 98, 35, 99, 36, 100, 37, 101, 38, 102, 39, 103,
+ 40, 104, 41, 105, 42, 106, 43, 107, 44, 108, 45, 109, 46, 110, 47, 111,
+ 48, 112, 49, 113, 50, 114, 51, 115, 52, 116, 53, 117, 54, 118, 55, 119,
+ 56, 120, 57, 121, 58, 122, 59, 123, 60, 124, 61, 125, 62, 126, 63, 127), b);
+#else
+ #ifdef NPY_HAVE_AVX512BW
+ __m512i ab0 = _mm512_unpacklo_epi8(a, b);
+ __m512i ab1 = _mm512_unpackhi_epi8(a, b);
+ #else
+ __m512i ab0 = npyv__unpacklo_epi8(a, b);
+ __m512i ab1 = npyv__unpackhi_epi8(a, b);
+ #endif
+ r.val[0] = _mm512_permutex2var_epi64(ab0, npyv_set_u64(0, 1, 8, 9, 2, 3, 10, 11), ab1);
+ r.val[1] = _mm512_permutex2var_epi64(ab0, npyv_set_u64(4, 5, 12, 13, 6, 7, 14, 15), ab1);
+#endif
+ return r;
+}
+#define npyv_zip_s8 npyv_zip_u8
+
+NPY_FINLINE npyv_u16x2 npyv_zip_u16(__m512i a, __m512i b)
+{
+ npyv_u16x2 r;
+#ifdef NPY_HAVE_AVX512BW
+ r.val[0] = _mm512_permutex2var_epi16(a,
+ npyv_set_u16(0, 32, 1, 33, 2, 34, 3, 35, 4, 36, 5, 37, 6, 38, 7, 39,
+ 8, 40, 9, 41, 10, 42, 11, 43, 12, 44, 13, 45, 14, 46, 15, 47), b);
+ r.val[1] = _mm512_permutex2var_epi16(a,
+ npyv_set_u16(16, 48, 17, 49, 18, 50, 19, 51, 20, 52, 21, 53, 22, 54, 23, 55,
+ 24, 56, 25, 57, 26, 58, 27, 59, 28, 60, 29, 61, 30, 62, 31, 63), b);
+#else
+ __m512i ab0 = npyv__unpacklo_epi16(a, b);
+ __m512i ab1 = npyv__unpackhi_epi16(a, b);
+ r.val[0] = _mm512_permutex2var_epi64(ab0, npyv_set_u64(0, 1, 8, 9, 2, 3, 10, 11), ab1);
+ r.val[1] = _mm512_permutex2var_epi64(ab0, npyv_set_u64(4, 5, 12, 13, 6, 7, 14, 15), ab1);
+#endif
+ return r;
+}
+#define npyv_zip_s16 npyv_zip_u16
+
+NPY_FINLINE npyv_u32x2 npyv_zip_u32(__m512i a, __m512i b)
+{
+ npyv_u32x2 r;
+ r.val[0] = _mm512_permutex2var_epi32(a,
+ npyv_set_u32(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23), b);
+ r.val[1] = _mm512_permutex2var_epi32(a,
+ npyv_set_u32(8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31), b);
+ return r;
+}
+#define npyv_zip_s32 npyv_zip_u32
+
+NPY_FINLINE npyv_f32x2 npyv_zip_f32(__m512 a, __m512 b)
+{
+ npyv_f32x2 r;
+ r.val[0] = _mm512_permutex2var_ps(a,
+ npyv_set_u32(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23), b);
+ r.val[1] = _mm512_permutex2var_ps(a,
+ npyv_set_u32(8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31), b);
+ return r;
+}
+
+NPY_FINLINE npyv_f64x2 npyv_zip_f64(__m512d a, __m512d b)
+{
+ npyv_f64x2 r;
+ r.val[0] = _mm512_permutex2var_pd(a, npyv_set_u64(0, 8, 1, 9, 2, 10, 3, 11), b);
+ r.val[1] = _mm512_permutex2var_pd(a, npyv_set_u64(4, 12, 5, 13, 6, 14, 7, 15), b);
+ return r;
+}
+
+#endif // _NPY_SIMD_AVX512_REORDER_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_AVX512_UTILS_H
+#define _NPY_SIMD_AVX512_UTILS_H
+
+#define npyv512_lower_si256 _mm512_castsi512_si256
+#define npyv512_lower_ps256 _mm512_castps512_ps256
+#define npyv512_lower_pd256 _mm512_castpd512_pd256
+
+#define npyv512_higher_si256(A) _mm512_extracti64x4_epi64(A, 1)
+#define npyv512_higher_pd256(A) _mm512_extractf64x4_pd(A, 1)
+
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv512_higher_ps256(A) _mm512_extractf32x8_ps(A, 1)
+#else
+ #define npyv512_higher_ps256(A) \
+ _mm256_castsi256_ps(_mm512_extracti64x4_epi64(_mm512_castps_si512(A), 1))
+#endif
+
+#define npyv512_combine_si256(A, B) _mm512_inserti64x4(_mm512_castsi256_si512(A), B, 1)
+#define npyv512_combine_pd256(A, B) _mm512_insertf64x4(_mm512_castpd256_pd512(A), B, 1)
+
+#ifdef NPY_HAVE_AVX512DQ
+ #define npyv512_combine_ps256(A, B) _mm512_insertf32x8(_mm512_castps256_ps512(A), B, 1)
+#else
+ #define npyv512_combine_ps256(A, B) \
+ _mm512_castsi512_ps(npyv512_combine_si256(_mm512_castps_si512(A), _mm512_castps_si512(B)))
+#endif
+
+#define NPYV_IMPL_AVX512_FROM_AVX2_1ARG(FN_NAME, INTRIN) \
+ NPY_FINLINE __m512i FN_NAME(__m512i a) \
+ { \
+ __m256i l_a = npyv512_lower_si256(a); \
+ __m256i h_a = npyv512_higher_si256(a); \
+ l_a = INTRIN(l_a); \
+ h_a = INTRIN(h_a); \
+ return npyv512_combine_si256(l_a, h_a); \
+ }
+
+#define NPYV_IMPL_AVX512_FROM_AVX2_2ARG(FN_NAME, INTRIN) \
+ NPY_FINLINE __m512i FN_NAME(__m512i a, __m512i b) \
+ { \
+ __m256i l_a = npyv512_lower_si256(a); \
+ __m256i h_a = npyv512_higher_si256(a); \
+ __m256i l_b = npyv512_lower_si256(b); \
+ __m256i h_b = npyv512_higher_si256(b); \
+ l_a = INTRIN(l_a, l_b); \
+ h_a = INTRIN(h_a, h_b); \
+ return npyv512_combine_si256(l_a, h_a); \
+ }
+
+#define NPYV_IMPL_AVX512_FROM_SI512_PS_2ARG(FN_NAME, INTRIN) \
+ NPY_FINLINE __m512 FN_NAME(__m512 a, __m512 b) \
+ { \
+ return _mm512_castsi512_ps(INTRIN( \
+ _mm512_castps_si512(a), _mm512_castps_si512(b) \
+ )); \
+ }
+
+#define NPYV_IMPL_AVX512_FROM_SI512_PD_2ARG(FN_NAME, INTRIN) \
+ NPY_FINLINE __m512d FN_NAME(__m512d a, __m512d b) \
+ { \
+ return _mm512_castsi512_pd(INTRIN( \
+ _mm512_castpd_si512(a), _mm512_castpd_si512(b) \
+ )); \
+ }
+
+#endif // _NPY_SIMD_AVX512_UTILS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_NEON_ARITHMETIC_H
+#define _NPY_SIMD_NEON_ARITHMETIC_H
+
+/***************************
+ * Addition
+ ***************************/
+// non-saturated
+#define npyv_add_u8 vaddq_u8
+#define npyv_add_s8 vaddq_s8
+#define npyv_add_u16 vaddq_u16
+#define npyv_add_s16 vaddq_s16
+#define npyv_add_u32 vaddq_u32
+#define npyv_add_s32 vaddq_s32
+#define npyv_add_u64 vaddq_u64
+#define npyv_add_s64 vaddq_s64
+#define npyv_add_f32 vaddq_f32
+#define npyv_add_f64 vaddq_f64
+
+// saturated
+#define npyv_adds_u8 vqaddq_u8
+#define npyv_adds_s8 vqaddq_s8
+#define npyv_adds_u16 vqaddq_u16
+#define npyv_adds_s16 vqaddq_s16
+
+/***************************
+ * Subtraction
+ ***************************/
+// non-saturated
+#define npyv_sub_u8 vsubq_u8
+#define npyv_sub_s8 vsubq_s8
+#define npyv_sub_u16 vsubq_u16
+#define npyv_sub_s16 vsubq_s16
+#define npyv_sub_u32 vsubq_u32
+#define npyv_sub_s32 vsubq_s32
+#define npyv_sub_u64 vsubq_u64
+#define npyv_sub_s64 vsubq_s64
+#define npyv_sub_f32 vsubq_f32
+#define npyv_sub_f64 vsubq_f64
+
+// saturated
+#define npyv_subs_u8 vqsubq_u8
+#define npyv_subs_s8 vqsubq_s8
+#define npyv_subs_u16 vqsubq_u16
+#define npyv_subs_s16 vqsubq_s16
+
+/***************************
+ * Multiplication
+ ***************************/
+// non-saturated
+#define npyv_mul_u8 vmulq_u8
+#define npyv_mul_s8 vmulq_s8
+#define npyv_mul_u16 vmulq_u16
+#define npyv_mul_s16 vmulq_s16
+#define npyv_mul_u32 vmulq_u32
+#define npyv_mul_s32 vmulq_s32
+#define npyv_mul_f32 vmulq_f32
+#define npyv_mul_f64 vmulq_f64
+
+/***************************
+ * Division
+ ***************************/
+#if NPY_SIMD_F64
+ #define npyv_div_f32 vdivq_f32
+#else
+ NPY_FINLINE npyv_f32 npyv_div_f32(npyv_f32 a, npyv_f32 b)
+ {
+ // Based on ARM doc, see https://developer.arm.com/documentation/dui0204/j/CIHDIACI
+ // estimate to 1/b
+ npyv_f32 recipe = vrecpeq_f32(b);
+ /**
+ * Newton-Raphson iteration:
+ * x[n+1] = x[n] * (2-d * x[n])
+ * converges to (1/d) if x0 is the result of VRECPE applied to d.
+ *
+ * NOTE: at least 3 iterations is needed to improve precision
+ */
+ recipe = vmulq_f32(vrecpsq_f32(b, recipe), recipe);
+ recipe = vmulq_f32(vrecpsq_f32(b, recipe), recipe);
+ recipe = vmulq_f32(vrecpsq_f32(b, recipe), recipe);
+ // a/b = a*recip(b)
+ return vmulq_f32(a, recipe);
+ }
+#endif
+#define npyv_div_f64 vdivq_f64
+
+/***************************
+ * FUSED F32
+ ***************************/
+#ifdef NPY_HAVE_NEON_VFPV4 // FMA
+ // multiply and add, a*b + c
+ NPY_FINLINE npyv_f32 npyv_muladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vfmaq_f32(c, a, b); }
+ // multiply and subtract, a*b - c
+ NPY_FINLINE npyv_f32 npyv_mulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vfmaq_f32(vnegq_f32(c), a, b); }
+ // negate multiply and add, -(a*b) + c
+ NPY_FINLINE npyv_f32 npyv_nmuladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vfmsq_f32(c, a, b); }
+ // negate multiply and subtract, -(a*b) - c
+ NPY_FINLINE npyv_f32 npyv_nmulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vfmsq_f32(vnegq_f32(c), a, b); }
+#else
+ // multiply and add, a*b + c
+ NPY_FINLINE npyv_f32 npyv_muladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vmlaq_f32(c, a, b); }
+ // multiply and subtract, a*b - c
+ NPY_FINLINE npyv_f32 npyv_mulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vmlaq_f32(vnegq_f32(c), a, b); }
+ // negate multiply and add, -(a*b) + c
+ NPY_FINLINE npyv_f32 npyv_nmuladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vmlsq_f32(c, a, b); }
+ // negate multiply and subtract, -(a*b) - c
+ NPY_FINLINE npyv_f32 npyv_nmulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return vmlsq_f32(vnegq_f32(c), a, b); }
+#endif
+/***************************
+ * FUSED F64
+ ***************************/
+#if NPY_SIMD_F64
+ NPY_FINLINE npyv_f64 npyv_muladd_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return vfmaq_f64(c, a, b); }
+ NPY_FINLINE npyv_f64 npyv_mulsub_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return vfmaq_f64(vnegq_f64(c), a, b); }
+ NPY_FINLINE npyv_f64 npyv_nmuladd_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return vfmsq_f64(c, a, b); }
+ NPY_FINLINE npyv_f64 npyv_nmulsub_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return vfmsq_f64(vnegq_f64(c), a, b); }
+#endif // NPY_SIMD_F64
+
+// Horizontal add: Calculates the sum of all vector elements.
+#if NPY_SIMD_F64
+ #define npyv_sum_f32 vaddvq_f32
+ #define npyv_sum_f64 vaddvq_f64
+#else
+ NPY_FINLINE float npyv_sum_f32(npyv_f32 a)
+ {
+ float32x2_t r = vadd_f32(vget_high_f32(a), vget_low_f32(a));
+ return vget_lane_f32(vpadd_f32(r, r), 0);
+ }
+#endif
+
+#endif // _NPY_SIMD_NEON_ARITHMETIC_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_NEON_CVT_H
+#define _NPY_SIMD_NEON_CVT_H
+
+// convert boolean vectors to integer vectors
+#define npyv_cvt_u8_b8(A) A
+#define npyv_cvt_s8_b8(A) vreinterpretq_s8_u8(A)
+#define npyv_cvt_u16_b16(A) A
+#define npyv_cvt_s16_b16(A) vreinterpretq_s16_u16(A)
+#define npyv_cvt_u32_b32(A) A
+#define npyv_cvt_s32_b32(A) vreinterpretq_s32_u32(A)
+#define npyv_cvt_u64_b64(A) A
+#define npyv_cvt_s64_b64(A) vreinterpretq_s64_u64(A)
+#define npyv_cvt_f32_b32(A) vreinterpretq_f32_u32(A)
+#define npyv_cvt_f64_b64(A) vreinterpretq_f64_u64(A)
+
+// convert integer vectors to boolean vectors
+#define npyv_cvt_b8_u8(BL) BL
+#define npyv_cvt_b8_s8(BL) vreinterpretq_u8_s8(BL)
+#define npyv_cvt_b16_u16(BL) BL
+#define npyv_cvt_b16_s16(BL) vreinterpretq_u16_s16(BL)
+#define npyv_cvt_b32_u32(BL) BL
+#define npyv_cvt_b32_s32(BL) vreinterpretq_u32_s32(BL)
+#define npyv_cvt_b64_u64(BL) BL
+#define npyv_cvt_b64_s64(BL) vreinterpretq_u64_s64(BL)
+#define npyv_cvt_b32_f32(BL) vreinterpretq_u32_f32(BL)
+#define npyv_cvt_b64_f64(BL) vreinterpretq_u64_f64(BL)
+
+#endif // _NPY_SIMD_NEON_CVT_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_NEON_MATH_H
+#define _NPY_SIMD_NEON_MATH_H
+
+/***************************
+ * Elementary
+ ***************************/
+// Absolute
+#define npyv_abs_f32 vabsq_f32
+#define npyv_abs_f64 vabsq_f64
+
+// Square
+NPY_FINLINE npyv_f32 npyv_square_f32(npyv_f32 a)
+{ return vmulq_f32(a, a); }
+#if NPY_SIMD_F64
+ NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
+ { return vmulq_f64(a, a); }
+#endif
+
+// Square root
+#if NPY_SIMD_F64
+ #define npyv_sqrt_f32 vsqrtq_f32
+ #define npyv_sqrt_f64 vsqrtq_f64
+#else
+ // Based on ARM doc, see https://developer.arm.com/documentation/dui0204/j/CIHDIACI
+ NPY_FINLINE npyv_f32 npyv_sqrt_f32(npyv_f32 a)
+ {
+ const npyv_f32 zero = vdupq_n_f32(0.0f);
+ const npyv_u32 pinf = vdupq_n_u32(0x7f800000);
+ npyv_u32 is_zero = vceqq_f32(a, zero), is_inf = vceqq_u32(vreinterpretq_u32_f32(a), pinf);
+ // guard agianst floating-point division-by-zero error
+ npyv_f32 guard_byz = vbslq_f32(is_zero, vreinterpretq_f32_u32(pinf), a);
+ // estimate to (1/√a)
+ npyv_f32 rsqrte = vrsqrteq_f32(guard_byz);
+ /**
+ * Newton-Raphson iteration:
+ * x[n+1] = x[n] * (3-d * (x[n]*x[n]) )/2)
+ * converges to (1/√d)if x0 is the result of VRSQRTE applied to d.
+ *
+ * NOTE: at least 3 iterations is needed to improve precision
+ */
+ rsqrte = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a, rsqrte), rsqrte), rsqrte);
+ rsqrte = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a, rsqrte), rsqrte), rsqrte);
+ rsqrte = vmulq_f32(vrsqrtsq_f32(vmulq_f32(a, rsqrte), rsqrte), rsqrte);
+ // a * (1/√a)
+ npyv_f32 sqrt = vmulq_f32(a, rsqrte);
+ // return zero if the a is zero
+ // - return zero if a is zero.
+ // - return positive infinity if a is positive infinity
+ return vbslq_f32(vorrq_u32(is_zero, is_inf), a, sqrt);
+ }
+#endif // NPY_SIMD_F64
+
+// Reciprocal
+NPY_FINLINE npyv_f32 npyv_recip_f32(npyv_f32 a)
+{
+#if NPY_SIMD_F64
+ const npyv_f32 one = vdupq_n_f32(1.0f);
+ return npyv_div_f32(one, a);
+#else
+ npyv_f32 recipe = vrecpeq_f32(a);
+ /**
+ * Newton-Raphson iteration:
+ * x[n+1] = x[n] * (2-d * x[n])
+ * converges to (1/d) if x0 is the result of VRECPE applied to d.
+ *
+ * NOTE: at least 3 iterations is needed to improve precision
+ */
+ recipe = vmulq_f32(vrecpsq_f32(a, recipe), recipe);
+ recipe = vmulq_f32(vrecpsq_f32(a, recipe), recipe);
+ recipe = vmulq_f32(vrecpsq_f32(a, recipe), recipe);
+ return recipe;
+#endif
+}
+#if NPY_SIMD_F64
+ NPY_FINLINE npyv_f64 npyv_recip_f64(npyv_f64 a)
+ {
+ const npyv_f64 one = vdupq_n_f64(1.0);
+ return npyv_div_f64(one, a);
+ }
+#endif // NPY_SIMD_F64
+
+#endif // _NPY_SIMD_SSE_MATH_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_NEON_MEMORY_H
+#define _NPY_SIMD_NEON_MEMORY_H
+
+#include "misc.h"
+
+/***************************
+ * load/store
+ ***************************/
+// GCC requires literal type definitions for pointers types otherwise it causes ambiguous errors
+#define NPYV_IMPL_NEON_MEM(SFX, CTYPE) \
+ NPY_FINLINE npyv_##SFX npyv_load_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { return vld1q_##SFX((const CTYPE*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loada_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { return vld1q_##SFX((const CTYPE*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loads_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { return vld1q_##SFX((const CTYPE*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loadl_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { \
+ return vcombine_##SFX( \
+ vld1_##SFX((const CTYPE*)ptr), vdup_n_##SFX(0) \
+ ); \
+ } \
+ NPY_FINLINE void npyv_store_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { vst1q_##SFX((CTYPE*)ptr, vec); } \
+ NPY_FINLINE void npyv_storea_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { vst1q_##SFX((CTYPE*)ptr, vec); } \
+ NPY_FINLINE void npyv_stores_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { vst1q_##SFX((CTYPE*)ptr, vec); } \
+ NPY_FINLINE void npyv_storel_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { vst1_##SFX((CTYPE*)ptr, vget_low_##SFX(vec)); } \
+ NPY_FINLINE void npyv_storeh_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { vst1_##SFX((CTYPE*)ptr, vget_high_##SFX(vec)); }
+
+NPYV_IMPL_NEON_MEM(u8, uint8_t)
+NPYV_IMPL_NEON_MEM(s8, int8_t)
+NPYV_IMPL_NEON_MEM(u16, uint16_t)
+NPYV_IMPL_NEON_MEM(s16, int16_t)
+NPYV_IMPL_NEON_MEM(u32, uint32_t)
+NPYV_IMPL_NEON_MEM(s32, int32_t)
+NPYV_IMPL_NEON_MEM(u64, uint64_t)
+NPYV_IMPL_NEON_MEM(s64, int64_t)
+NPYV_IMPL_NEON_MEM(f32, float)
+#if NPY_SIMD_F64
+NPYV_IMPL_NEON_MEM(f64, double)
+#endif
+/***************************
+ * Non-contiguous Load
+ ***************************/
+NPY_FINLINE npyv_s32 npyv_loadn_s32(const npy_int32 *ptr, npy_intp stride)
+{
+ switch (stride) {
+ case 2:
+ return vld2q_s32((const int32_t*)ptr).val[0];
+ case 3:
+ return vld3q_s32((const int32_t*)ptr).val[0];
+ case 4:
+ return vld4q_s32((const int32_t*)ptr).val[0];
+ default:;
+ int32x2_t ax = vcreate_s32(*ptr);
+ int32x4_t a = vcombine_s32(ax, ax);
+ a = vld1q_lane_s32((const int32_t*)ptr + stride, a, 1);
+ a = vld1q_lane_s32((const int32_t*)ptr + stride*2, a, 2);
+ a = vld1q_lane_s32((const int32_t*)ptr + stride*3, a, 3);
+ return a;
+ }
+}
+
+NPY_FINLINE npyv_u32 npyv_loadn_u32(const npy_uint32 *ptr, npy_intp stride)
+{
+ return npyv_reinterpret_u32_s32(
+ npyv_loadn_s32((const npy_int32*)ptr, stride)
+ );
+}
+NPY_FINLINE npyv_f32 npyv_loadn_f32(const float *ptr, npy_intp stride)
+{
+ return npyv_reinterpret_f32_s32(
+ npyv_loadn_s32((const npy_int32*)ptr, stride)
+ );
+}
+//// 64
+NPY_FINLINE npyv_s64 npyv_loadn_s64(const npy_int64 *ptr, npy_intp stride)
+{
+ return vcombine_s64(
+ vld1_s64((const int64_t*)ptr), vld1_s64((const int64_t*)ptr + stride)
+ );
+}
+NPY_FINLINE npyv_u64 npyv_loadn_u64(const npy_uint64 *ptr, npy_intp stride)
+{
+ return npyv_reinterpret_u64_s64(
+ npyv_loadn_s64((const npy_int64*)ptr, stride)
+ );
+}
+#if NPY_SIMD_F64
+NPY_FINLINE npyv_f64 npyv_loadn_f64(const double *ptr, npy_intp stride)
+{
+ return npyv_reinterpret_f64_s64(
+ npyv_loadn_s64((const npy_int64*)ptr, stride)
+ );
+}
+#endif
+/***************************
+ * Non-contiguous Store
+ ***************************/
+//// 32
+NPY_FINLINE void npyv_storen_s32(npy_int32 *ptr, npy_intp stride, npyv_s32 a)
+{
+ vst1q_lane_s32((int32_t*)ptr, a, 0);
+ vst1q_lane_s32((int32_t*)ptr + stride, a, 1);
+ vst1q_lane_s32((int32_t*)ptr + stride*2, a, 2);
+ vst1q_lane_s32((int32_t*)ptr + stride*3, a, 3);
+}
+NPY_FINLINE void npyv_storen_u32(npy_uint32 *ptr, npy_intp stride, npyv_u32 a)
+{ npyv_storen_s32((npy_int32*)ptr, stride, npyv_reinterpret_s32_u32(a)); }
+NPY_FINLINE void npyv_storen_f32(float *ptr, npy_intp stride, npyv_f32 a)
+{ npyv_storen_s32((npy_int32*)ptr, stride, npyv_reinterpret_s32_f32(a)); }
+//// 64
+NPY_FINLINE void npyv_storen_s64(npy_int64 *ptr, npy_intp stride, npyv_s64 a)
+{
+ vst1q_lane_s64((int64_t*)ptr, a, 0);
+ vst1q_lane_s64((int64_t*)ptr + stride, a, 1);
+}
+NPY_FINLINE void npyv_storen_u64(npy_uint64 *ptr, npy_intp stride, npyv_u64 a)
+{ npyv_storen_s64((npy_int64*)ptr, stride, npyv_reinterpret_s64_u64(a)); }
+
+#if NPY_SIMD_F64
+NPY_FINLINE void npyv_storen_f64(double *ptr, npy_intp stride, npyv_f64 a)
+{ npyv_storen_s64((npy_int64*)ptr, stride, npyv_reinterpret_s64_f64(a)); }
+#endif
+
+/*********************************
+ * Partial Load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32 npyv_load_till_s32(const npy_int32 *ptr, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ case 1:
+ return vld1q_lane_s32((const int32_t*)ptr, vdupq_n_s32(fill), 0);
+ case 2:
+ return vcombine_s32(vld1_s32((const int32_t*)ptr), vdup_n_s32(fill));
+ case 3:
+ return vcombine_s32(
+ vld1_s32((const int32_t*)ptr),
+ vld1_lane_s32((const int32_t*)ptr + 2, vdup_n_s32(fill), 0)
+ );
+ default:
+ return npyv_load_s32(ptr);
+ }
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32 npyv_load_tillz_s32(const npy_int32 *ptr, npy_uintp nlane)
+{ return npyv_load_till_s32(ptr, nlane, 0); }
+//// 64
+NPY_FINLINE npyv_s64 npyv_load_till_s64(const npy_int64 *ptr, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ return vcombine_s64(vld1_s64((const int64_t*)ptr), vdup_n_s64(fill));
+ }
+ return npyv_load_s64(ptr);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_load_tillz_s64(const npy_int64 *ptr, npy_uintp nlane)
+{ return npyv_load_till_s64(ptr, nlane, 0); }
+
+/*********************************
+ * Non-contiguous partial load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32
+npyv_loadn_till_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ int32x4_t vfill = vdupq_n_s32(fill);
+ switch(nlane) {
+ case 3:
+ vfill = vld1q_lane_s32((const int32_t*)ptr + stride*2, vfill, 2);
+ case 2:
+ vfill = vld1q_lane_s32((const int32_t*)ptr + stride, vfill, 1);
+ case 1:
+ vfill = vld1q_lane_s32((const int32_t*)ptr, vfill, 0);
+ return vfill;
+ default:
+ return npyv_loadn_s32(ptr, stride);
+ }
+}
+NPY_FINLINE npyv_s32
+npyv_loadn_tillz_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s32(ptr, stride, nlane, 0); }
+
+NPY_FINLINE npyv_s64
+npyv_loadn_till_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ return vcombine_s64(vld1_s64((const int64_t*)ptr), vdup_n_s64(fill));
+ }
+ return npyv_loadn_s64(ptr, stride);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_loadn_tillz_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s64(ptr, stride, nlane, 0); }
+
+/*********************************
+ * Partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_store_till_s32(npy_int32 *ptr, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ case 1:
+ vst1q_lane_s32((int32_t*)ptr, a, 0);
+ break;
+ case 2:
+ vst1_s32((int32_t*)ptr, vget_low_s32(a));
+ break;
+ case 3:
+ vst1_s32((int32_t*)ptr, vget_low_s32(a));
+ vst1q_lane_s32((int32_t*)ptr + 2, a, 2);
+ break;
+ default:
+ npyv_store_s32(ptr, a);
+ }
+}
+//// 64
+NPY_FINLINE void npyv_store_till_s64(npy_int64 *ptr, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ vst1q_lane_s64((int64_t*)ptr, a, 0);
+ return;
+ }
+ npyv_store_s64(ptr, a);
+}
+/*********************************
+ * Non-contiguous partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_storen_till_s32(npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ default:
+ vst1q_lane_s32((int32_t*)ptr + stride*3, a, 3);
+ case 3:
+ vst1q_lane_s32((int32_t*)ptr + stride*2, a, 2);
+ case 2:
+ vst1q_lane_s32((int32_t*)ptr + stride, a, 1);
+ case 1:
+ vst1q_lane_s32((int32_t*)ptr, a, 0);
+ break;
+ }
+}
+//// 64
+NPY_FINLINE void npyv_storen_till_s64(npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ vst1q_lane_s64((int64_t*)ptr, a, 0);
+ return;
+ }
+ npyv_storen_s64(ptr, stride, a);
+}
+
+/*****************************************************************
+ * Implement partial load/store for u32/f32/u64/f64... via casting
+ *****************************************************************/
+#define NPYV_IMPL_NEON_REST_PARTIAL_TYPES(F_SFX, T_SFX) \
+ NPY_FINLINE npyv_##F_SFX npyv_load_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, \
+ npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_load_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane \
+ )); \
+ } \
+ NPY_FINLINE void npyv_store_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_store_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ } \
+ NPY_FINLINE void npyv_storen_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_storen_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, stride, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ }
+
+NPYV_IMPL_NEON_REST_PARTIAL_TYPES(u32, s32)
+NPYV_IMPL_NEON_REST_PARTIAL_TYPES(f32, s32)
+NPYV_IMPL_NEON_REST_PARTIAL_TYPES(u64, s64)
+#if NPY_SIMD_F64
+NPYV_IMPL_NEON_REST_PARTIAL_TYPES(f64, s64)
+#endif
+
+#endif // _NPY_SIMD_NEON_MEMORY_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_NEON_MISC_H
+#define _NPY_SIMD_NEON_MISC_H
+
+// vector with zero lanes
+#define npyv_zero_u8() vreinterpretq_u8_s32(npyv_zero_s32())
+#define npyv_zero_s8() vreinterpretq_s8_s32(npyv_zero_s32())
+#define npyv_zero_u16() vreinterpretq_u16_s32(npyv_zero_s32())
+#define npyv_zero_s16() vreinterpretq_s16_s32(npyv_zero_s32())
+#define npyv_zero_u32() vdupq_n_u32((unsigned)0)
+#define npyv_zero_s32() vdupq_n_s32((int)0)
+#define npyv_zero_u64() vreinterpretq_u64_s32(npyv_zero_s32())
+#define npyv_zero_s64() vreinterpretq_s64_s32(npyv_zero_s32())
+#define npyv_zero_f32() vdupq_n_f32(0.0f)
+#define npyv_zero_f64() vdupq_n_f64(0.0)
+
+// vector with a specific value set to all lanes
+#define npyv_setall_u8 vdupq_n_u8
+#define npyv_setall_s8 vdupq_n_s8
+#define npyv_setall_u16 vdupq_n_u16
+#define npyv_setall_s16 vdupq_n_s16
+#define npyv_setall_u32 vdupq_n_u32
+#define npyv_setall_s32 vdupq_n_s32
+#define npyv_setall_u64 vdupq_n_u64
+#define npyv_setall_s64 vdupq_n_s64
+#define npyv_setall_f32 vdupq_n_f32
+#define npyv_setall_f64 vdupq_n_f64
+
+// vector with specific values set to each lane and
+// set a specific value to all remained lanes
+NPY_FINLINE uint8x16_t npyv__set_u8(npy_uint8 i0, npy_uint8 i1, npy_uint8 i2, npy_uint8 i3,
+ npy_uint8 i4, npy_uint8 i5, npy_uint8 i6, npy_uint8 i7, npy_uint8 i8, npy_uint8 i9,
+ npy_uint8 i10, npy_uint8 i11, npy_uint8 i12, npy_uint8 i13, npy_uint8 i14, npy_uint8 i15)
+{
+ const uint8_t NPY_DECL_ALIGNED(16) data[16] = {
+ i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15
+ };
+ return vld1q_u8(data);
+}
+#define npyv_setf_u8(FILL, ...) npyv__set_u8(NPYV__SET_FILL_16(npy_uint8, FILL, __VA_ARGS__))
+
+NPY_FINLINE int8x16_t npyv__set_s8(npy_int8 i0, npy_int8 i1, npy_int8 i2, npy_int8 i3,
+ npy_int8 i4, npy_int8 i5, npy_int8 i6, npy_int8 i7, npy_int8 i8, npy_int8 i9,
+ npy_int8 i10, npy_int8 i11, npy_int8 i12, npy_int8 i13, npy_int8 i14, npy_int8 i15)
+{
+ const int8_t NPY_DECL_ALIGNED(16) data[16] = {
+ i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15
+ };
+ return vld1q_s8(data);
+}
+#define npyv_setf_s8(FILL, ...) npyv__set_s8(NPYV__SET_FILL_16(npy_int8, FILL, __VA_ARGS__))
+
+NPY_FINLINE uint16x8_t npyv__set_u16(npy_uint16 i0, npy_uint16 i1, npy_uint16 i2, npy_uint16 i3,
+ npy_uint16 i4, npy_uint16 i5, npy_uint16 i6, npy_uint16 i7)
+{
+ const uint16_t NPY_DECL_ALIGNED(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7};
+ return vld1q_u16(data);
+}
+#define npyv_setf_u16(FILL, ...) npyv__set_u16(NPYV__SET_FILL_8(npy_uint16, FILL, __VA_ARGS__))
+
+NPY_FINLINE int16x8_t npyv__set_s16(npy_int16 i0, npy_int16 i1, npy_int16 i2, npy_int16 i3,
+ npy_int16 i4, npy_int16 i5, npy_int16 i6, npy_int16 i7)
+{
+ const int16_t NPY_DECL_ALIGNED(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7};
+ return vld1q_s16(data);
+}
+#define npyv_setf_s16(FILL, ...) npyv__set_s16(NPYV__SET_FILL_8(npy_int16, FILL, __VA_ARGS__))
+
+NPY_FINLINE uint32x4_t npyv__set_u32(npy_uint32 i0, npy_uint32 i1, npy_uint32 i2, npy_uint32 i3)
+{
+ const uint32_t NPY_DECL_ALIGNED(16) data[4] = {i0, i1, i2, i3};
+ return vld1q_u32(data);
+}
+#define npyv_setf_u32(FILL, ...) npyv__set_u32(NPYV__SET_FILL_4(npy_uint32, FILL, __VA_ARGS__))
+
+NPY_FINLINE int32x4_t npyv__set_s32(npy_int32 i0, npy_int32 i1, npy_int32 i2, npy_int32 i3)
+{
+ const int32_t NPY_DECL_ALIGNED(16) data[4] = {i0, i1, i2, i3};
+ return vld1q_s32(data);
+}
+#define npyv_setf_s32(FILL, ...) npyv__set_s32(NPYV__SET_FILL_4(npy_int32, FILL, __VA_ARGS__))
+
+NPY_FINLINE uint64x2_t npyv__set_u64(npy_uint64 i0, npy_uint64 i1)
+{
+ const uint64_t NPY_DECL_ALIGNED(16) data[2] = {i0, i1};
+ return vld1q_u64(data);
+}
+#define npyv_setf_u64(FILL, ...) npyv__set_u64(NPYV__SET_FILL_2(npy_int64, FILL, __VA_ARGS__))
+
+NPY_FINLINE int64x2_t npyv__set_s64(npy_int64 i0, npy_int64 i1)
+{
+ const int64_t NPY_DECL_ALIGNED(16) data[2] = {i0, i1};
+ return vld1q_s64(data);
+}
+#define npyv_setf_s64(FILL, ...) npyv__set_s64(NPYV__SET_FILL_2(npy_int64, FILL, __VA_ARGS__))
+
+NPY_FINLINE float32x4_t npyv__set_f32(float i0, float i1, float i2, float i3)
+{
+ const float NPY_DECL_ALIGNED(16) data[4] = {i0, i1, i2, i3};
+ return vld1q_f32(data);
+}
+#define npyv_setf_f32(FILL, ...) npyv__set_f32(NPYV__SET_FILL_4(float, FILL, __VA_ARGS__))
+
+#ifdef __aarch64__
+NPY_FINLINE float64x2_t npyv__set_f64(double i0, double i1)
+{
+ const double NPY_DECL_ALIGNED(16) data[2] = {i0, i1};
+ return vld1q_f64(data);
+}
+#define npyv_setf_f64(FILL, ...) npyv__set_f64(NPYV__SET_FILL_2(double, FILL, __VA_ARGS__))
+#endif
+
+// vector with specific values set to each lane and
+// set zero to all remained lanes
+#define npyv_set_u8(...) npyv_setf_u8(0, __VA_ARGS__)
+#define npyv_set_s8(...) npyv_setf_s8(0, __VA_ARGS__)
+#define npyv_set_u16(...) npyv_setf_u16(0, __VA_ARGS__)
+#define npyv_set_s16(...) npyv_setf_s16(0, __VA_ARGS__)
+#define npyv_set_u32(...) npyv_setf_u32(0, __VA_ARGS__)
+#define npyv_set_s32(...) npyv_setf_s32(0, __VA_ARGS__)
+#define npyv_set_u64(...) npyv_setf_u64(0, __VA_ARGS__)
+#define npyv_set_s64(...) npyv_setf_s64(0, __VA_ARGS__)
+#define npyv_set_f32(...) npyv_setf_f32(0, __VA_ARGS__)
+#define npyv_set_f64(...) npyv_setf_f64(0, __VA_ARGS__)
+
+// Per lane select
+#define npyv_select_u8 vbslq_u8
+#define npyv_select_s8 vbslq_s8
+#define npyv_select_u16 vbslq_u16
+#define npyv_select_s16 vbslq_s16
+#define npyv_select_u32 vbslq_u32
+#define npyv_select_s32 vbslq_s32
+#define npyv_select_u64 vbslq_u64
+#define npyv_select_s64 vbslq_s64
+#define npyv_select_f32 vbslq_f32
+#define npyv_select_f64 vbslq_f64
+
+// Reinterpret
+#define npyv_reinterpret_u8_u8(X) X
+#define npyv_reinterpret_u8_s8 vreinterpretq_u8_s8
+#define npyv_reinterpret_u8_u16 vreinterpretq_u8_u16
+#define npyv_reinterpret_u8_s16 vreinterpretq_u8_s16
+#define npyv_reinterpret_u8_u32 vreinterpretq_u8_u32
+#define npyv_reinterpret_u8_s32 vreinterpretq_u8_s32
+#define npyv_reinterpret_u8_u64 vreinterpretq_u8_u64
+#define npyv_reinterpret_u8_s64 vreinterpretq_u8_s64
+#define npyv_reinterpret_u8_f32 vreinterpretq_u8_f32
+#define npyv_reinterpret_u8_f64 vreinterpretq_u8_f64
+
+#define npyv_reinterpret_s8_s8(X) X
+#define npyv_reinterpret_s8_u8 vreinterpretq_s8_u8
+#define npyv_reinterpret_s8_u16 vreinterpretq_s8_u16
+#define npyv_reinterpret_s8_s16 vreinterpretq_s8_s16
+#define npyv_reinterpret_s8_u32 vreinterpretq_s8_u32
+#define npyv_reinterpret_s8_s32 vreinterpretq_s8_s32
+#define npyv_reinterpret_s8_u64 vreinterpretq_s8_u64
+#define npyv_reinterpret_s8_s64 vreinterpretq_s8_s64
+#define npyv_reinterpret_s8_f32 vreinterpretq_s8_f32
+#define npyv_reinterpret_s8_f64 vreinterpretq_s8_f64
+
+#define npyv_reinterpret_u16_u16(X) X
+#define npyv_reinterpret_u16_u8 vreinterpretq_u16_u8
+#define npyv_reinterpret_u16_s8 vreinterpretq_u16_s8
+#define npyv_reinterpret_u16_s16 vreinterpretq_u16_s16
+#define npyv_reinterpret_u16_u32 vreinterpretq_u16_u32
+#define npyv_reinterpret_u16_s32 vreinterpretq_u16_s32
+#define npyv_reinterpret_u16_u64 vreinterpretq_u16_u64
+#define npyv_reinterpret_u16_s64 vreinterpretq_u16_s64
+#define npyv_reinterpret_u16_f32 vreinterpretq_u16_f32
+#define npyv_reinterpret_u16_f64 vreinterpretq_u16_f64
+
+#define npyv_reinterpret_s16_s16(X) X
+#define npyv_reinterpret_s16_u8 vreinterpretq_s16_u8
+#define npyv_reinterpret_s16_s8 vreinterpretq_s16_s8
+#define npyv_reinterpret_s16_u16 vreinterpretq_s16_u16
+#define npyv_reinterpret_s16_u32 vreinterpretq_s16_u32
+#define npyv_reinterpret_s16_s32 vreinterpretq_s16_s32
+#define npyv_reinterpret_s16_u64 vreinterpretq_s16_u64
+#define npyv_reinterpret_s16_s64 vreinterpretq_s16_s64
+#define npyv_reinterpret_s16_f32 vreinterpretq_s16_f32
+#define npyv_reinterpret_s16_f64 vreinterpretq_s16_f64
+
+#define npyv_reinterpret_u32_u32(X) X
+#define npyv_reinterpret_u32_u8 vreinterpretq_u32_u8
+#define npyv_reinterpret_u32_s8 vreinterpretq_u32_s8
+#define npyv_reinterpret_u32_u16 vreinterpretq_u32_u16
+#define npyv_reinterpret_u32_s16 vreinterpretq_u32_s16
+#define npyv_reinterpret_u32_s32 vreinterpretq_u32_s32
+#define npyv_reinterpret_u32_u64 vreinterpretq_u32_u64
+#define npyv_reinterpret_u32_s64 vreinterpretq_u32_s64
+#define npyv_reinterpret_u32_f32 vreinterpretq_u32_f32
+#define npyv_reinterpret_u32_f64 vreinterpretq_u32_f64
+
+#define npyv_reinterpret_s32_s32(X) X
+#define npyv_reinterpret_s32_u8 vreinterpretq_s32_u8
+#define npyv_reinterpret_s32_s8 vreinterpretq_s32_s8
+#define npyv_reinterpret_s32_u16 vreinterpretq_s32_u16
+#define npyv_reinterpret_s32_s16 vreinterpretq_s32_s16
+#define npyv_reinterpret_s32_u32 vreinterpretq_s32_u32
+#define npyv_reinterpret_s32_u64 vreinterpretq_s32_u64
+#define npyv_reinterpret_s32_s64 vreinterpretq_s32_s64
+#define npyv_reinterpret_s32_f32 vreinterpretq_s32_f32
+#define npyv_reinterpret_s32_f64 vreinterpretq_s32_f64
+
+#define npyv_reinterpret_u64_u64(X) X
+#define npyv_reinterpret_u64_u8 vreinterpretq_u64_u8
+#define npyv_reinterpret_u64_s8 vreinterpretq_u64_s8
+#define npyv_reinterpret_u64_u16 vreinterpretq_u64_u16
+#define npyv_reinterpret_u64_s16 vreinterpretq_u64_s16
+#define npyv_reinterpret_u64_u32 vreinterpretq_u64_u32
+#define npyv_reinterpret_u64_s32 vreinterpretq_u64_s32
+#define npyv_reinterpret_u64_s64 vreinterpretq_u64_s64
+#define npyv_reinterpret_u64_f32 vreinterpretq_u64_f32
+#define npyv_reinterpret_u64_f64 vreinterpretq_u64_f64
+
+#define npyv_reinterpret_s64_s64(X) X
+#define npyv_reinterpret_s64_u8 vreinterpretq_s64_u8
+#define npyv_reinterpret_s64_s8 vreinterpretq_s64_s8
+#define npyv_reinterpret_s64_u16 vreinterpretq_s64_u16
+#define npyv_reinterpret_s64_s16 vreinterpretq_s64_s16
+#define npyv_reinterpret_s64_u32 vreinterpretq_s64_u32
+#define npyv_reinterpret_s64_s32 vreinterpretq_s64_s32
+#define npyv_reinterpret_s64_u64 vreinterpretq_s64_u64
+#define npyv_reinterpret_s64_f32 vreinterpretq_s64_f32
+#define npyv_reinterpret_s64_f64 vreinterpretq_s64_f64
+
+#define npyv_reinterpret_f32_f32(X) X
+#define npyv_reinterpret_f32_u8 vreinterpretq_f32_u8
+#define npyv_reinterpret_f32_s8 vreinterpretq_f32_s8
+#define npyv_reinterpret_f32_u16 vreinterpretq_f32_u16
+#define npyv_reinterpret_f32_s16 vreinterpretq_f32_s16
+#define npyv_reinterpret_f32_u32 vreinterpretq_f32_u32
+#define npyv_reinterpret_f32_s32 vreinterpretq_f32_s32
+#define npyv_reinterpret_f32_u64 vreinterpretq_f32_u64
+#define npyv_reinterpret_f32_s64 vreinterpretq_f32_s64
+#define npyv_reinterpret_f32_f64 vreinterpretq_f32_f64
+
+#define npyv_reinterpret_f64_f64(X) X
+#define npyv_reinterpret_f64_u8 vreinterpretq_f64_u8
+#define npyv_reinterpret_f64_s8 vreinterpretq_f64_s8
+#define npyv_reinterpret_f64_u16 vreinterpretq_f64_u16
+#define npyv_reinterpret_f64_s16 vreinterpretq_f64_s16
+#define npyv_reinterpret_f64_u32 vreinterpretq_f64_u32
+#define npyv_reinterpret_f64_s32 vreinterpretq_f64_s32
+#define npyv_reinterpret_f64_u64 vreinterpretq_f64_u64
+#define npyv_reinterpret_f64_s64 vreinterpretq_f64_s64
+#define npyv_reinterpret_f64_f32 vreinterpretq_f64_f32
+
+// Only required by AVX2/AVX512
+#define npyv_cleanup() ((void)0)
+
+#endif // _NPY_SIMD_NEON_MISC_H
--- /dev/null
+#ifndef _NPY_SIMD_H_
+ #error "Not a standalone header"
+#endif
+
+#define NPY_SIMD 128
+#define NPY_SIMD_WIDTH 16
+
+#ifdef __aarch64__
+ #define NPY_SIMD_F64 1
+#else
+ #define NPY_SIMD_F64 0
+#endif
+
+typedef uint8x16_t npyv_u8;
+typedef int8x16_t npyv_s8;
+typedef uint16x8_t npyv_u16;
+typedef int16x8_t npyv_s16;
+typedef uint32x4_t npyv_u32;
+typedef int32x4_t npyv_s32;
+typedef uint64x2_t npyv_u64;
+typedef int64x2_t npyv_s64;
+typedef float32x4_t npyv_f32;
+#if NPY_SIMD_F64
+typedef float64x2_t npyv_f64;
+#endif
+
+typedef uint8x16_t npyv_b8;
+typedef uint16x8_t npyv_b16;
+typedef uint32x4_t npyv_b32;
+typedef uint64x2_t npyv_b64;
+
+typedef uint8x16x2_t npyv_u8x2;
+typedef int8x16x2_t npyv_s8x2;
+typedef uint16x8x2_t npyv_u16x2;
+typedef int16x8x2_t npyv_s16x2;
+typedef uint32x4x2_t npyv_u32x2;
+typedef int32x4x2_t npyv_s32x2;
+typedef uint64x2x2_t npyv_u64x2;
+typedef int64x2x2_t npyv_s64x2;
+typedef float32x4x2_t npyv_f32x2;
+#if NPY_SIMD_F64
+typedef float64x2x2_t npyv_f64x2;
+#endif
+
+typedef uint8x16x3_t npyv_u8x3;
+typedef int8x16x3_t npyv_s8x3;
+typedef uint16x8x3_t npyv_u16x3;
+typedef int16x8x3_t npyv_s16x3;
+typedef uint32x4x3_t npyv_u32x3;
+typedef int32x4x3_t npyv_s32x3;
+typedef uint64x2x3_t npyv_u64x3;
+typedef int64x2x3_t npyv_s64x3;
+typedef float32x4x3_t npyv_f32x3;
+#if NPY_SIMD_F64
+typedef float64x2x3_t npyv_f64x3;
+#endif
+
+#define npyv_nlanes_u8 16
+#define npyv_nlanes_s8 16
+#define npyv_nlanes_u16 8
+#define npyv_nlanes_s16 8
+#define npyv_nlanes_u32 4
+#define npyv_nlanes_s32 4
+#define npyv_nlanes_u64 2
+#define npyv_nlanes_s64 2
+#define npyv_nlanes_f32 4
+#define npyv_nlanes_f64 2
+
+#include "memory.h"
+#include "misc.h"
+#include "reorder.h"
+#include "operators.h"
+#include "conversion.h"
+#include "arithmetic.h"
+#include "math.h"
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_NEON_OPERATORS_H
+#define _NPY_SIMD_NEON_OPERATORS_H
+
+/***************************
+ * Shifting
+ ***************************/
+
+// left
+#define npyv_shl_u16(A, C) vshlq_u16(A, npyv_setall_s16(C))
+#define npyv_shl_s16(A, C) vshlq_s16(A, npyv_setall_s16(C))
+#define npyv_shl_u32(A, C) vshlq_u32(A, npyv_setall_s32(C))
+#define npyv_shl_s32(A, C) vshlq_s32(A, npyv_setall_s32(C))
+#define npyv_shl_u64(A, C) vshlq_u64(A, npyv_setall_s64(C))
+#define npyv_shl_s64(A, C) vshlq_s64(A, npyv_setall_s64(C))
+
+// left by an immediate constant
+#define npyv_shli_u16 vshlq_n_u16
+#define npyv_shli_s16 vshlq_n_s16
+#define npyv_shli_u32 vshlq_n_u32
+#define npyv_shli_s32 vshlq_n_s32
+#define npyv_shli_u64 vshlq_n_u64
+#define npyv_shli_s64 vshlq_n_s64
+
+// right
+#define npyv_shr_u16(A, C) vshlq_u16(A, npyv_setall_s16(-(C)))
+#define npyv_shr_s16(A, C) vshlq_s16(A, npyv_setall_s16(-(C)))
+#define npyv_shr_u32(A, C) vshlq_u32(A, npyv_setall_s32(-(C)))
+#define npyv_shr_s32(A, C) vshlq_s32(A, npyv_setall_s32(-(C)))
+#define npyv_shr_u64(A, C) vshlq_u64(A, npyv_setall_s64(-(C)))
+#define npyv_shr_s64(A, C) vshlq_s64(A, npyv_setall_s64(-(C)))
+
+// right by an immediate constant
+#define npyv_shri_u16 vshrq_n_u16
+#define npyv_shri_s16 vshrq_n_s16
+#define npyv_shri_u32 vshrq_n_u32
+#define npyv_shri_s32 vshrq_n_s32
+#define npyv_shri_u64 vshrq_n_u64
+#define npyv_shri_s64 vshrq_n_s64
+
+/***************************
+ * Logical
+ ***************************/
+
+// AND
+#define npyv_and_u8 vandq_u8
+#define npyv_and_s8 vandq_s8
+#define npyv_and_u16 vandq_u16
+#define npyv_and_s16 vandq_s16
+#define npyv_and_u32 vandq_u32
+#define npyv_and_s32 vandq_s32
+#define npyv_and_u64 vandq_u64
+#define npyv_and_s64 vandq_s64
+#define npyv_and_f32(A, B) \
+ vreinterpretq_f32_u8(vandq_u8(vreinterpretq_u8_f32(A), vreinterpretq_u8_f32(B)))
+#define npyv_and_f64(A, B) \
+ vreinterpretq_f64_u8(vandq_u8(vreinterpretq_u8_f64(A), vreinterpretq_u8_f64(B)))
+
+// OR
+#define npyv_or_u8 vorrq_u8
+#define npyv_or_s8 vorrq_s8
+#define npyv_or_u16 vorrq_u16
+#define npyv_or_s16 vorrq_s16
+#define npyv_or_u32 vorrq_u32
+#define npyv_or_s32 vorrq_s32
+#define npyv_or_u64 vorrq_u64
+#define npyv_or_s64 vorrq_s64
+#define npyv_or_f32(A, B) \
+ vreinterpretq_f32_u8(vorrq_u8(vreinterpretq_u8_f32(A), vreinterpretq_u8_f32(B)))
+#define npyv_or_f64(A, B) \
+ vreinterpretq_f64_u8(vorrq_u8(vreinterpretq_u8_f64(A), vreinterpretq_u8_f64(B)))
+
+// XOR
+#define npyv_xor_u8 veorq_u8
+#define npyv_xor_s8 veorq_s8
+#define npyv_xor_u16 veorq_u16
+#define npyv_xor_s16 veorq_s16
+#define npyv_xor_u32 veorq_u32
+#define npyv_xor_s32 veorq_s32
+#define npyv_xor_u64 veorq_u64
+#define npyv_xor_s64 veorq_s64
+#define npyv_xor_f32(A, B) \
+ vreinterpretq_f32_u8(veorq_u8(vreinterpretq_u8_f32(A), vreinterpretq_u8_f32(B)))
+#define npyv_xor_f64(A, B) \
+ vreinterpretq_f64_u8(veorq_u8(vreinterpretq_u8_f64(A), vreinterpretq_u8_f64(B)))
+
+// NOT
+#define npyv_not_u8 vmvnq_u8
+#define npyv_not_s8 vmvnq_s8
+#define npyv_not_u16 vmvnq_u16
+#define npyv_not_s16 vmvnq_s16
+#define npyv_not_u32 vmvnq_u32
+#define npyv_not_s32 vmvnq_s32
+#define npyv_not_u64(A) vreinterpretq_u64_u8(vmvnq_u8(vreinterpretq_u8_u64(A)))
+#define npyv_not_s64(A) vreinterpretq_s64_u8(vmvnq_u8(vreinterpretq_u8_s64(A)))
+#define npyv_not_f32(A) vreinterpretq_f32_u8(vmvnq_u8(vreinterpretq_u8_f32(A)))
+#define npyv_not_f64(A) vreinterpretq_f64_u8(vmvnq_u8(vreinterpretq_u8_f64(A)))
+
+/***************************
+ * Comparison
+ ***************************/
+
+// equal
+#define npyv_cmpeq_u8 vceqq_u8
+#define npyv_cmpeq_s8 vceqq_s8
+#define npyv_cmpeq_u16 vceqq_u16
+#define npyv_cmpeq_s16 vceqq_s16
+#define npyv_cmpeq_u32 vceqq_u32
+#define npyv_cmpeq_s32 vceqq_s32
+#define npyv_cmpeq_f32 vceqq_f32
+#define npyv_cmpeq_f64 vceqq_f64
+
+#ifdef __aarch64__
+ #define npyv_cmpeq_u64 vceqq_u64
+ #define npyv_cmpeq_s64 vceqq_s64
+#else
+ NPY_FINLINE uint64x2_t npyv_cmpeq_u64(uint64x2_t a, uint64x2_t b)
+ {
+ uint64x2_t cmpeq = vreinterpretq_u64_u32(vceqq_u32(
+ vreinterpretq_u32_u64(a), vreinterpretq_u32_u64(b)
+ ));
+ uint64x2_t cmpeq_h = vshlq_n_u64(cmpeq, 32);
+ uint64x2_t test = vandq_u64(cmpeq, cmpeq_h);
+ return vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_u64(test), 32));
+ }
+ #define npyv_cmpeq_s64(A, B) \
+ npyv_cmpeq_u64(vreinterpretq_u64_s64(A), vreinterpretq_u64_s64(B))
+#endif
+
+// not Equal
+#define npyv_cmpneq_u8(A, B) vmvnq_u8(vceqq_u8(A, B))
+#define npyv_cmpneq_s8(A, B) vmvnq_u8(vceqq_s8(A, B))
+#define npyv_cmpneq_u16(A, B) vmvnq_u16(vceqq_u16(A, B))
+#define npyv_cmpneq_s16(A, B) vmvnq_u16(vceqq_s16(A, B))
+#define npyv_cmpneq_u32(A, B) vmvnq_u32(vceqq_u32(A, B))
+#define npyv_cmpneq_s32(A, B) vmvnq_u32(vceqq_s32(A, B))
+#define npyv_cmpneq_u64(A, B) npyv_not_u64(npyv_cmpeq_u64(A, B))
+#define npyv_cmpneq_s64(A, B) npyv_not_u64(npyv_cmpeq_s64(A, B))
+#define npyv_cmpneq_f32(A, B) vmvnq_u32(vceqq_f32(A, B))
+#define npyv_cmpneq_f64(A, B) npyv_not_u64(vceqq_f64(A, B))
+
+// greater than
+#define npyv_cmpgt_u8 vcgtq_u8
+#define npyv_cmpgt_s8 vcgtq_s8
+#define npyv_cmpgt_u16 vcgtq_u16
+#define npyv_cmpgt_s16 vcgtq_s16
+#define npyv_cmpgt_u32 vcgtq_u32
+#define npyv_cmpgt_s32 vcgtq_s32
+#define npyv_cmpgt_f32 vcgtq_f32
+#define npyv_cmpgt_f64 vcgtq_f64
+
+#ifdef __aarch64__
+ #define npyv_cmpgt_u64 vcgtq_u64
+ #define npyv_cmpgt_s64 vcgtq_s64
+#else
+ NPY_FINLINE uint64x2_t npyv_cmpgt_s64(int64x2_t a, int64x2_t b)
+ {
+ int64x2_t sub = vsubq_s64(b, a);
+ uint64x2_t nsame_sbit = vreinterpretq_u64_s64(veorq_s64(a, b));
+ int64x2_t test = vbslq_s64(nsame_sbit, b, sub);
+ int64x2_t extend_sbit = vshrq_n_s64(test, 63);
+ return vreinterpretq_u64_s64(extend_sbit);
+ }
+ NPY_FINLINE uint64x2_t npyv_cmpgt_u64(uint64x2_t a, uint64x2_t b)
+ {
+ const uint64x2_t sbit = npyv_setall_u64(0x8000000000000000);
+ a = npyv_xor_u64(a, sbit);
+ b = npyv_xor_u64(b, sbit);
+ return npyv_cmpgt_s64(vreinterpretq_s64_u64(a), vreinterpretq_s64_u64(b));
+ }
+#endif
+
+// greater than or equal
+#define npyv_cmpge_u8 vcgeq_u8
+#define npyv_cmpge_s8 vcgeq_s8
+#define npyv_cmpge_u16 vcgeq_u16
+#define npyv_cmpge_s16 vcgeq_s16
+#define npyv_cmpge_u32 vcgeq_u32
+#define npyv_cmpge_s32 vcgeq_s32
+#define npyv_cmpge_f32 vcgeq_f32
+#define npyv_cmpge_f64 vcgeq_f64
+
+#ifdef __aarch64__
+ #define npyv_cmpge_u64 vcgeq_u64
+ #define npyv_cmpge_s64 vcgeq_s64
+#else
+ #define npyv_cmpge_u64(A, B) npyv_not_u64(npyv_cmpgt_u64(B, A))
+ #define npyv_cmpge_s64(A, B) npyv_not_u64(npyv_cmpgt_s64(B, A))
+#endif
+
+// less than
+#define npyv_cmplt_u8(A, B) npyv_cmpgt_u8(B, A)
+#define npyv_cmplt_s8(A, B) npyv_cmpgt_s8(B, A)
+#define npyv_cmplt_u16(A, B) npyv_cmpgt_u16(B, A)
+#define npyv_cmplt_s16(A, B) npyv_cmpgt_s16(B, A)
+#define npyv_cmplt_u32(A, B) npyv_cmpgt_u32(B, A)
+#define npyv_cmplt_s32(A, B) npyv_cmpgt_s32(B, A)
+#define npyv_cmplt_u64(A, B) npyv_cmpgt_u64(B, A)
+#define npyv_cmplt_s64(A, B) npyv_cmpgt_s64(B, A)
+#define npyv_cmplt_f32(A, B) npyv_cmpgt_f32(B, A)
+#define npyv_cmplt_f64(A, B) npyv_cmpgt_f64(B, A)
+
+// less than or equal
+#define npyv_cmple_u8(A, B) npyv_cmpge_u8(B, A)
+#define npyv_cmple_s8(A, B) npyv_cmpge_s8(B, A)
+#define npyv_cmple_u16(A, B) npyv_cmpge_u16(B, A)
+#define npyv_cmple_s16(A, B) npyv_cmpge_s16(B, A)
+#define npyv_cmple_u32(A, B) npyv_cmpge_u32(B, A)
+#define npyv_cmple_s32(A, B) npyv_cmpge_s32(B, A)
+#define npyv_cmple_u64(A, B) npyv_cmpge_u64(B, A)
+#define npyv_cmple_s64(A, B) npyv_cmpge_s64(B, A)
+#define npyv_cmple_f32(A, B) npyv_cmpge_f32(B, A)
+#define npyv_cmple_f64(A, B) npyv_cmpge_f64(B, A)
+
+#endif // _NPY_SIMD_NEON_OPERATORS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_NEON_REORDER_H
+#define _NPY_SIMD_NEON_REORDER_H
+
+// combine lower part of two vectors
+#ifdef __aarch64__
+ #define npyv_combinel_u8(A, B) vreinterpretq_u8_u64(vzip1q_u64(vreinterpretq_u64_u8(A), vreinterpretq_u64_u8(B)))
+ #define npyv_combinel_s8(A, B) vreinterpretq_s8_u64(vzip1q_u64(vreinterpretq_u64_s8(A), vreinterpretq_u64_s8(B)))
+ #define npyv_combinel_u16(A, B) vreinterpretq_u16_u64(vzip1q_u64(vreinterpretq_u64_u16(A), vreinterpretq_u64_u16(B)))
+ #define npyv_combinel_s16(A, B) vreinterpretq_s16_u64(vzip1q_u64(vreinterpretq_u64_s16(A), vreinterpretq_u64_s16(B)))
+ #define npyv_combinel_u32(A, B) vreinterpretq_u32_u64(vzip1q_u64(vreinterpretq_u64_u32(A), vreinterpretq_u64_u32(B)))
+ #define npyv_combinel_s32(A, B) vreinterpretq_s32_u64(vzip1q_u64(vreinterpretq_u64_s32(A), vreinterpretq_u64_s32(B)))
+ #define npyv_combinel_u64 vzip1q_u64
+ #define npyv_combinel_s64 vzip1q_s64
+ #define npyv_combinel_f32(A, B) vreinterpretq_f32_u64(vzip1q_u64(vreinterpretq_u64_f32(A), vreinterpretq_u64_f32(B)))
+ #define npyv_combinel_f64 vzip1q_f64
+#else
+ #define npyv_combinel_u8(A, B) vcombine_u8(vget_low_u8(A), vget_low_u8(B))
+ #define npyv_combinel_s8(A, B) vcombine_s8(vget_low_s8(A), vget_low_s8(B))
+ #define npyv_combinel_u16(A, B) vcombine_u16(vget_low_u16(A), vget_low_u16(B))
+ #define npyv_combinel_s16(A, B) vcombine_s16(vget_low_s16(A), vget_low_s16(B))
+ #define npyv_combinel_u32(A, B) vcombine_u32(vget_low_u32(A), vget_low_u32(B))
+ #define npyv_combinel_s32(A, B) vcombine_s32(vget_low_s32(A), vget_low_s32(B))
+ #define npyv_combinel_u64(A, B) vcombine_u64(vget_low_u64(A), vget_low_u64(B))
+ #define npyv_combinel_s64(A, B) vcombine_s64(vget_low_s64(A), vget_low_s64(B))
+ #define npyv_combinel_f32(A, B) vcombine_f32(vget_low_f32(A), vget_low_f32(B))
+#endif
+
+// combine higher part of two vectors
+#ifdef __aarch64__
+ #define npyv_combineh_u8(A, B) vreinterpretq_u8_u64(vzip2q_u64(vreinterpretq_u64_u8(A), vreinterpretq_u64_u8(B)))
+ #define npyv_combineh_s8(A, B) vreinterpretq_s8_u64(vzip2q_u64(vreinterpretq_u64_s8(A), vreinterpretq_u64_s8(B)))
+ #define npyv_combineh_u16(A, B) vreinterpretq_u16_u64(vzip2q_u64(vreinterpretq_u64_u16(A), vreinterpretq_u64_u16(B)))
+ #define npyv_combineh_s16(A, B) vreinterpretq_s16_u64(vzip2q_u64(vreinterpretq_u64_s16(A), vreinterpretq_u64_s16(B)))
+ #define npyv_combineh_u32(A, B) vreinterpretq_u32_u64(vzip2q_u64(vreinterpretq_u64_u32(A), vreinterpretq_u64_u32(B)))
+ #define npyv_combineh_s32(A, B) vreinterpretq_s32_u64(vzip2q_u64(vreinterpretq_u64_s32(A), vreinterpretq_u64_s32(B)))
+ #define npyv_combineh_u64 vzip2q_u64
+ #define npyv_combineh_s64 vzip2q_s64
+ #define npyv_combineh_f32(A, B) vreinterpretq_f32_u64(vzip2q_u64(vreinterpretq_u64_f32(A), vreinterpretq_u64_f32(B)))
+ #define npyv_combineh_f64 vzip2q_f64
+#else
+ #define npyv_combineh_u8(A, B) vcombine_u8(vget_high_u8(A), vget_high_u8(B))
+ #define npyv_combineh_s8(A, B) vcombine_s8(vget_high_s8(A), vget_high_s8(B))
+ #define npyv_combineh_u16(A, B) vcombine_u16(vget_high_u16(A), vget_high_u16(B))
+ #define npyv_combineh_s16(A, B) vcombine_s16(vget_high_s16(A), vget_high_s16(B))
+ #define npyv_combineh_u32(A, B) vcombine_u32(vget_high_u32(A), vget_high_u32(B))
+ #define npyv_combineh_s32(A, B) vcombine_s32(vget_high_s32(A), vget_high_s32(B))
+ #define npyv_combineh_u64(A, B) vcombine_u64(vget_high_u64(A), vget_high_u64(B))
+ #define npyv_combineh_s64(A, B) vcombine_s64(vget_high_s64(A), vget_high_s64(B))
+ #define npyv_combineh_f32(A, B) vcombine_f32(vget_high_f32(A), vget_high_f32(B))
+#endif
+
+// combine two vectors from lower and higher parts of two other vectors
+#define NPYV_IMPL_NEON_COMBINE(T_VEC, SFX) \
+ NPY_FINLINE T_VEC##x2 npyv_combine_##SFX(T_VEC a, T_VEC b) \
+ { \
+ T_VEC##x2 r; \
+ r.val[0] = NPY_CAT(npyv_combinel_, SFX)(a, b); \
+ r.val[1] = NPY_CAT(npyv_combineh_, SFX)(a, b); \
+ return r; \
+ }
+
+NPYV_IMPL_NEON_COMBINE(npyv_u8, u8)
+NPYV_IMPL_NEON_COMBINE(npyv_s8, s8)
+NPYV_IMPL_NEON_COMBINE(npyv_u16, u16)
+NPYV_IMPL_NEON_COMBINE(npyv_s16, s16)
+NPYV_IMPL_NEON_COMBINE(npyv_u32, u32)
+NPYV_IMPL_NEON_COMBINE(npyv_s32, s32)
+NPYV_IMPL_NEON_COMBINE(npyv_u64, u64)
+NPYV_IMPL_NEON_COMBINE(npyv_s64, s64)
+NPYV_IMPL_NEON_COMBINE(npyv_f32, f32)
+#ifdef __aarch64__
+NPYV_IMPL_NEON_COMBINE(npyv_f64, f64)
+#endif
+
+// interleave two vectors
+#define NPYV_IMPL_NEON_ZIP(T_VEC, SFX) \
+ NPY_FINLINE T_VEC##x2 npyv_zip_##SFX(T_VEC a, T_VEC b) \
+ { \
+ T_VEC##x2 r; \
+ r.val[0] = vzip1q_##SFX(a, b); \
+ r.val[1] = vzip2q_##SFX(a, b); \
+ return r; \
+ }
+
+#ifdef __aarch64__
+ NPYV_IMPL_NEON_ZIP(npyv_u8, u8)
+ NPYV_IMPL_NEON_ZIP(npyv_s8, s8)
+ NPYV_IMPL_NEON_ZIP(npyv_u16, u16)
+ NPYV_IMPL_NEON_ZIP(npyv_s16, s16)
+ NPYV_IMPL_NEON_ZIP(npyv_u32, u32)
+ NPYV_IMPL_NEON_ZIP(npyv_s32, s32)
+ NPYV_IMPL_NEON_ZIP(npyv_f32, f32)
+ NPYV_IMPL_NEON_ZIP(npyv_f64, f64)
+#else
+ #define npyv_zip_u8 vzipq_u8
+ #define npyv_zip_s8 vzipq_s8
+ #define npyv_zip_u16 vzipq_u16
+ #define npyv_zip_s16 vzipq_s16
+ #define npyv_zip_u32 vzipq_u32
+ #define npyv_zip_s32 vzipq_s32
+ #define npyv_zip_f32 vzipq_f32
+#endif
+#define npyv_zip_u64 npyv_combine_u64
+#define npyv_zip_s64 npyv_combine_s64
+
+#endif // _NPY_SIMD_NEON_REORDER_H
--- /dev/null
+#ifndef _NPY_SIMD_H_
+#define _NPY_SIMD_H_
+/**
+ * the NumPy C SIMD vectorization interface "NPYV" are types and functions intended
+ * to simplify vectorization of code on different platforms, currently supports
+ * the following SIMD extensions SSE, AVX2, AVX512, VSX and NEON.
+ *
+ * TODO: Add an independent sphinx doc.
+*/
+#include "numpy/npy_common.h"
+#include "npy_cpu_dispatch.h"
+#include "simd_utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// lane type by intrin suffix
+typedef npy_uint8 npyv_lanetype_u8;
+typedef npy_int8 npyv_lanetype_s8;
+typedef npy_uint16 npyv_lanetype_u16;
+typedef npy_int16 npyv_lanetype_s16;
+typedef npy_uint32 npyv_lanetype_u32;
+typedef npy_int32 npyv_lanetype_s32;
+typedef npy_uint64 npyv_lanetype_u64;
+typedef npy_int64 npyv_lanetype_s64;
+typedef float npyv_lanetype_f32;
+typedef double npyv_lanetype_f64;
+
+#if defined(NPY_HAVE_AVX512F) && !defined(NPY_SIMD_FORCE_256) && !defined(NPY_SIMD_FORCE_128)
+ #include "avx512/avx512.h"
+#elif defined(NPY_HAVE_AVX2) && !defined(NPY_SIMD_FORCE_128)
+ #include "avx2/avx2.h"
+#elif defined(NPY_HAVE_SSE2)
+ #include "sse/sse.h"
+#endif
+
+// TODO: Add support for VSX(2.06) and BE Mode
+#if defined(NPY_HAVE_VSX2) && defined(__LITTLE_ENDIAN__)
+ #include "vsx/vsx.h"
+#endif
+
+#ifdef NPY_HAVE_NEON
+ #include "neon/neon.h"
+#endif
+
+#ifndef NPY_SIMD
+ #define NPY_SIMD 0
+ #define NPY_SIMD_WIDTH 0
+ #define NPY_SIMD_F64 0
+#endif
+/**
+ * Some SIMD extensions currently(AVX2, AVX512F) require (de facto)
+ * a maximum number of strides sizes when dealing with non-contiguous memory access.
+ *
+ * Therefore the following functions must be used to check the maximum
+ * acceptable limit of strides before using any of non-contiguous load/store intrinsics.
+ *
+ * For instance:
+ * npy_intp ld_stride = step[0] / sizeof(float);
+ * npy_intp st_stride = step[1] / sizeof(float);
+ *
+ * if (npyv_loadable_stride_f32(ld_stride) && npyv_storable_stride_f32(st_stride)) {
+ * for (;;)
+ * npyv_f32 a = npyv_loadn_f32(ld_pointer, ld_stride);
+ * // ...
+ * npyv_storen_f32(st_pointer, st_stride, a);
+ * }
+ * else {
+ * for (;;)
+ * // C scalars
+ * }
+ */
+#ifndef NPY_SIMD_MAXLOAD_STRIDE32
+ #define NPY_SIMD_MAXLOAD_STRIDE32 0
+#endif
+#ifndef NPY_SIMD_MAXSTORE_STRIDE32
+ #define NPY_SIMD_MAXSTORE_STRIDE32 0
+#endif
+#ifndef NPY_SIMD_MAXLOAD_STRIDE64
+ #define NPY_SIMD_MAXLOAD_STRIDE64 0
+#endif
+#ifndef NPY_SIMD_MAXSTORE_STRIDE64
+ #define NPY_SIMD_MAXSTORE_STRIDE64 0
+#endif
+#define NPYV_IMPL_MAXSTRIDE(SFX, MAXLOAD, MAXSTORE) \
+ NPY_FINLINE int npyv_loadable_stride_##SFX(npy_intp stride) \
+ { return MAXLOAD > 0 ? llabs(stride) <= MAXLOAD : 1; } \
+ NPY_FINLINE int npyv_storable_stride_##SFX(npy_intp stride) \
+ { return MAXSTORE > 0 ? llabs(stride) <= MAXSTORE : 1; }
+#if NPY_SIMD
+ NPYV_IMPL_MAXSTRIDE(u32, NPY_SIMD_MAXLOAD_STRIDE32, NPY_SIMD_MAXSTORE_STRIDE32)
+ NPYV_IMPL_MAXSTRIDE(s32, NPY_SIMD_MAXLOAD_STRIDE32, NPY_SIMD_MAXSTORE_STRIDE32)
+ NPYV_IMPL_MAXSTRIDE(f32, NPY_SIMD_MAXLOAD_STRIDE32, NPY_SIMD_MAXSTORE_STRIDE32)
+ NPYV_IMPL_MAXSTRIDE(u64, NPY_SIMD_MAXLOAD_STRIDE64, NPY_SIMD_MAXSTORE_STRIDE64)
+ NPYV_IMPL_MAXSTRIDE(s64, NPY_SIMD_MAXLOAD_STRIDE64, NPY_SIMD_MAXSTORE_STRIDE64)
+#endif
+#if NPY_SIMD_F64
+ NPYV_IMPL_MAXSTRIDE(f64, NPY_SIMD_MAXLOAD_STRIDE64, NPY_SIMD_MAXSTORE_STRIDE64)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif // _NPY_SIMD_H_
--- /dev/null
+#ifndef _NPY_SIMD_UTILS_H
+#define _NPY_SIMD_UTILS_H
+
+#define NPYV__SET_2(CAST, I0, I1, ...) (CAST)(I0), (CAST)(I1)
+
+#define NPYV__SET_4(CAST, I0, I1, I2, I3, ...) \
+ (CAST)(I0), (CAST)(I1), (CAST)(I2), (CAST)(I3)
+
+#define NPYV__SET_8(CAST, I0, I1, I2, I3, I4, I5, I6, I7, ...) \
+ (CAST)(I0), (CAST)(I1), (CAST)(I2), (CAST)(I3), (CAST)(I4), (CAST)(I5), (CAST)(I6), (CAST)(I7)
+
+#define NPYV__SET_16(CAST, I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, ...) \
+ NPYV__SET_8(CAST, I0, I1, I2, I3, I4, I5, I6, I7), \
+ NPYV__SET_8(CAST, I8, I9, I10, I11, I12, I13, I14, I15)
+
+#define NPYV__SET_32(CAST, I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, \
+I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31, ...) \
+ \
+ NPYV__SET_16(CAST, I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15), \
+ NPYV__SET_16(CAST, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31)
+
+#define NPYV__SET_64(CAST, I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, \
+I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31, \
+I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47, \
+I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63, ...) \
+ \
+ NPYV__SET_32(CAST, I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, \
+I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31), \
+ NPYV__SET_32(CAST, I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47, \
+I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63)
+
+#define NPYV__SET_FILL_2(CAST, F, ...) NPY_EXPAND(NPYV__SET_2(CAST, __VA_ARGS__, F, F))
+
+#define NPYV__SET_FILL_4(CAST, F, ...) NPY_EXPAND(NPYV__SET_4(CAST, __VA_ARGS__, F, F, F, F))
+
+#define NPYV__SET_FILL_8(CAST, F, ...) NPY_EXPAND(NPYV__SET_8(CAST, __VA_ARGS__, F, F, F, F, F, F, F, F))
+
+#define NPYV__SET_FILL_16(CAST, F, ...) NPY_EXPAND(NPYV__SET_16(CAST, __VA_ARGS__, \
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F))
+
+#define NPYV__SET_FILL_32(CAST, F, ...) NPY_EXPAND(NPYV__SET_32(CAST, __VA_ARGS__, \
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F))
+
+#define NPYV__SET_FILL_64(CAST, F, ...) NPY_EXPAND(NPYV__SET_64(CAST, __VA_ARGS__, \
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, \
+ F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F))
+
+#endif // _NPY_SIMD_UTILS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_SSE_ARITHMETIC_H
+#define _NPY_SIMD_SSE_ARITHMETIC_H
+
+/***************************
+ * Addition
+ ***************************/
+// non-saturated
+#define npyv_add_u8 _mm_add_epi8
+#define npyv_add_s8 _mm_add_epi8
+#define npyv_add_u16 _mm_add_epi16
+#define npyv_add_s16 _mm_add_epi16
+#define npyv_add_u32 _mm_add_epi32
+#define npyv_add_s32 _mm_add_epi32
+#define npyv_add_u64 _mm_add_epi64
+#define npyv_add_s64 _mm_add_epi64
+#define npyv_add_f32 _mm_add_ps
+#define npyv_add_f64 _mm_add_pd
+
+// saturated
+#define npyv_adds_u8 _mm_adds_epu8
+#define npyv_adds_s8 _mm_adds_epi8
+#define npyv_adds_u16 _mm_adds_epu16
+#define npyv_adds_s16 _mm_adds_epi16
+// TODO: rest, after implment Packs intrins
+
+/***************************
+ * Subtraction
+ ***************************/
+// non-saturated
+#define npyv_sub_u8 _mm_sub_epi8
+#define npyv_sub_s8 _mm_sub_epi8
+#define npyv_sub_u16 _mm_sub_epi16
+#define npyv_sub_s16 _mm_sub_epi16
+#define npyv_sub_u32 _mm_sub_epi32
+#define npyv_sub_s32 _mm_sub_epi32
+#define npyv_sub_u64 _mm_sub_epi64
+#define npyv_sub_s64 _mm_sub_epi64
+#define npyv_sub_f32 _mm_sub_ps
+#define npyv_sub_f64 _mm_sub_pd
+
+// saturated
+#define npyv_subs_u8 _mm_subs_epu8
+#define npyv_subs_s8 _mm_subs_epi8
+#define npyv_subs_u16 _mm_subs_epu16
+#define npyv_subs_s16 _mm_subs_epi16
+// TODO: rest, after implment Packs intrins
+
+/***************************
+ * Multiplication
+ ***************************/
+// non-saturated
+NPY_FINLINE __m128i npyv_mul_u8(__m128i a, __m128i b)
+{
+ const __m128i mask = _mm_set1_epi32(0xFF00FF00);
+ __m128i even = _mm_mullo_epi16(a, b);
+ __m128i odd = _mm_mullo_epi16(_mm_srai_epi16(a, 8), _mm_srai_epi16(b, 8));
+ odd = _mm_slli_epi16(odd, 8);
+ return npyv_select_u8(mask, odd, even);
+}
+#define npyv_mul_s8 npyv_mul_u8
+#define npyv_mul_u16 _mm_mullo_epi16
+#define npyv_mul_s16 _mm_mullo_epi16
+
+#ifdef NPY_HAVE_SSE41
+ #define npyv_mul_u32 _mm_mullo_epi32
+#else
+ NPY_FINLINE __m128i npyv_mul_u32(__m128i a, __m128i b)
+ {
+ __m128i even = _mm_mul_epu32(a, b);
+ __m128i odd = _mm_mul_epu32(_mm_srli_epi64(a, 32), _mm_srli_epi64(b, 32));
+ __m128i low = _mm_unpacklo_epi32(even, odd);
+ __m128i high = _mm_unpackhi_epi32(even, odd);
+ return _mm_unpacklo_epi64(low, high);
+ }
+#endif // NPY_HAVE_SSE41
+#define npyv_mul_s32 npyv_mul_u32
+// TODO: emulate 64-bit*/
+#define npyv_mul_f32 _mm_mul_ps
+#define npyv_mul_f64 _mm_mul_pd
+
+// saturated
+// TODO: after implment Packs intrins
+
+/***************************
+ * Division
+ ***************************/
+// TODO: emulate integer division
+#define npyv_div_f32 _mm_div_ps
+#define npyv_div_f64 _mm_div_pd
+/***************************
+ * FUSED
+ ***************************/
+#ifdef NPY_HAVE_FMA3
+ // multiply and add, a*b + c
+ #define npyv_muladd_f32 _mm_fmadd_ps
+ #define npyv_muladd_f64 _mm_fmadd_pd
+ // multiply and subtract, a*b - c
+ #define npyv_mulsub_f32 _mm_fmsub_ps
+ #define npyv_mulsub_f64 _mm_fmsub_pd
+ // negate multiply and add, -(a*b) + c
+ #define npyv_nmuladd_f32 _mm_fnmadd_ps
+ #define npyv_nmuladd_f64 _mm_fnmadd_pd
+ // negate multiply and subtract, -(a*b) - c
+ #define npyv_nmulsub_f32 _mm_fnmsub_ps
+ #define npyv_nmulsub_f64 _mm_fnmsub_pd
+#elif defined(NPY_HAVE_FMA4)
+ // multiply and add, a*b + c
+ #define npyv_muladd_f32 _mm_macc_ps
+ #define npyv_muladd_f64 _mm_macc_pd
+ // multiply and subtract, a*b - c
+ #define npyv_mulsub_f32 _mm_msub_ps
+ #define npyv_mulsub_f64 _mm_msub_pd
+ // negate multiply and add, -(a*b) + c
+ #define npyv_nmuladd_f32 _mm_nmacc_ps
+ #define npyv_nmuladd_f64 _mm_nmacc_pd
+#else
+ // multiply and add, a*b + c
+ NPY_FINLINE npyv_f32 npyv_muladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return npyv_add_f32(npyv_mul_f32(a, b), c); }
+ NPY_FINLINE npyv_f64 npyv_muladd_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return npyv_add_f64(npyv_mul_f64(a, b), c); }
+ // multiply and subtract, a*b - c
+ NPY_FINLINE npyv_f32 npyv_mulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return npyv_sub_f32(npyv_mul_f32(a, b), c); }
+ NPY_FINLINE npyv_f64 npyv_mulsub_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return npyv_sub_f64(npyv_mul_f64(a, b), c); }
+ // negate multiply and add, -(a*b) + c
+ NPY_FINLINE npyv_f32 npyv_nmuladd_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ { return npyv_sub_f32(c, npyv_mul_f32(a, b)); }
+ NPY_FINLINE npyv_f64 npyv_nmuladd_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ { return npyv_sub_f64(c, npyv_mul_f64(a, b)); }
+#endif // NPY_HAVE_FMA3
+#ifndef NPY_HAVE_FMA3 // for FMA4 and NON-FMA3
+ // negate multiply and subtract, -(a*b) - c
+ NPY_FINLINE npyv_f32 npyv_nmulsub_f32(npyv_f32 a, npyv_f32 b, npyv_f32 c)
+ {
+ npyv_f32 neg_a = npyv_xor_f32(a, npyv_setall_f32(-0.0f));
+ return npyv_sub_f32(npyv_mul_f32(neg_a, b), c);
+ }
+ NPY_FINLINE npyv_f64 npyv_nmulsub_f64(npyv_f64 a, npyv_f64 b, npyv_f64 c)
+ {
+ npyv_f64 neg_a = npyv_xor_f64(a, npyv_setall_f64(-0.0));
+ return npyv_sub_f64(npyv_mul_f64(neg_a, b), c);
+ }
+#endif // !NPY_HAVE_FMA3
+
+// Horizontal add: Calculates the sum of all vector elements.
+NPY_FINLINE float npyv_sum_f32(__m128 a)
+{
+#ifdef NPY_HAVE_SSE3
+ __m128 sum_halves = _mm_hadd_ps(a, a);
+ return _mm_cvtss_f32(_mm_hadd_ps(sum_halves, sum_halves));
+#else
+ __m128 t1 = _mm_movehl_ps(a, a);
+ __m128 t2 = _mm_add_ps(a, t1);
+ __m128 t3 = _mm_shuffle_ps(t2, t2, 1);
+ __m128 t4 = _mm_add_ss(t2, t3);
+ return _mm_cvtss_f32(t4);
+#endif
+}
+
+NPY_FINLINE double npyv_sum_f64(__m128d a)
+{
+#ifdef NPY_HAVE_SSE3
+ return _mm_cvtsd_f64(_mm_hadd_pd(a, a));
+#else
+ return _mm_cvtsd_f64(_mm_add_pd(a, _mm_unpackhi_pd(a, a)));
+#endif
+}
+
+#endif // _NPY_SIMD_SSE_ARITHMETIC_H
+
+
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_SSE_CVT_H
+#define _NPY_SIMD_SSE_CVT_H
+
+// convert mask types to integer types
+#define npyv_cvt_u8_b8(BL) BL
+#define npyv_cvt_s8_b8(BL) BL
+#define npyv_cvt_u16_b16(BL) BL
+#define npyv_cvt_s16_b16(BL) BL
+#define npyv_cvt_u32_b32(BL) BL
+#define npyv_cvt_s32_b32(BL) BL
+#define npyv_cvt_u64_b64(BL) BL
+#define npyv_cvt_s64_b64(BL) BL
+#define npyv_cvt_f32_b32(BL) _mm_castsi128_ps(BL)
+#define npyv_cvt_f64_b64(BL) _mm_castsi128_pd(BL)
+
+// convert integer types to mask types
+#define npyv_cvt_b8_u8(A) A
+#define npyv_cvt_b8_s8(A) A
+#define npyv_cvt_b16_u16(A) A
+#define npyv_cvt_b16_s16(A) A
+#define npyv_cvt_b32_u32(A) A
+#define npyv_cvt_b32_s32(A) A
+#define npyv_cvt_b64_u64(A) A
+#define npyv_cvt_b64_s64(A) A
+#define npyv_cvt_b32_f32(A) _mm_castps_si128(A)
+#define npyv_cvt_b64_f64(A) _mm_castpd_si128(A)
+
+#endif // _NPY_SIMD_SSE_CVT_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_SSE_MATH_H
+#define _NPY_SIMD_SSE_MATH_H
+/***************************
+ * Elementary
+ ***************************/
+// Square root
+#define npyv_sqrt_f32 _mm_sqrt_ps
+#define npyv_sqrt_f64 _mm_sqrt_pd
+
+// Reciprocal
+NPY_FINLINE npyv_f32 npyv_recip_f32(npyv_f32 a)
+{ return _mm_div_ps(_mm_set1_ps(1.0f), a); }
+NPY_FINLINE npyv_f64 npyv_recip_f64(npyv_f64 a)
+{ return _mm_div_pd(_mm_set1_pd(1.0), a); }
+
+// Absolute
+NPY_FINLINE npyv_f32 npyv_abs_f32(npyv_f32 a)
+{
+ return _mm_and_ps(
+ a, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))
+ );
+}
+NPY_FINLINE npyv_f64 npyv_abs_f64(npyv_f64 a)
+{
+ return _mm_and_pd(
+ a, _mm_castsi128_pd(npyv_setall_s64(0x7fffffffffffffffLL))
+ );
+}
+
+// Square
+NPY_FINLINE npyv_f32 npyv_square_f32(npyv_f32 a)
+{ return _mm_mul_ps(a, a); }
+NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
+{ return _mm_mul_pd(a, a); }
+
+#endif
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_SSE_MEMORY_H
+#define _NPY_SIMD_SSE_MEMORY_H
+
+#include "misc.h"
+
+/***************************
+ * load/store
+ ***************************/
+// stream load
+#ifdef NPY_HAVE_SSE41
+ #define npyv__loads(PTR) _mm_stream_load_si128((__m128i *)(PTR))
+#else
+ #define npyv__loads(PTR) _mm_load_si128((const __m128i *)(PTR))
+#endif
+#define NPYV_IMPL_SSE_MEM_INT(CTYPE, SFX) \
+ NPY_FINLINE npyv_##SFX npyv_load_##SFX(const CTYPE *ptr) \
+ { return _mm_loadu_si128((const __m128i*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loada_##SFX(const CTYPE *ptr) \
+ { return _mm_load_si128((const __m128i*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loads_##SFX(const CTYPE *ptr) \
+ { return npyv__loads(ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loadl_##SFX(const CTYPE *ptr) \
+ { return _mm_loadl_epi64((const __m128i*)ptr); } \
+ NPY_FINLINE void npyv_store_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm_storeu_si128((__m128i*)ptr, vec); } \
+ NPY_FINLINE void npyv_storea_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm_store_si128((__m128i*)ptr, vec); } \
+ NPY_FINLINE void npyv_stores_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm_stream_si128((__m128i*)ptr, vec); } \
+ NPY_FINLINE void npyv_storel_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm_storel_epi64((__m128i *)ptr, vec); } \
+ NPY_FINLINE void npyv_storeh_##SFX(CTYPE *ptr, npyv_##SFX vec) \
+ { _mm_storel_epi64((__m128i *)ptr, _mm_unpackhi_epi64(vec, vec)); }
+
+NPYV_IMPL_SSE_MEM_INT(npy_uint8, u8)
+NPYV_IMPL_SSE_MEM_INT(npy_int8, s8)
+NPYV_IMPL_SSE_MEM_INT(npy_uint16, u16)
+NPYV_IMPL_SSE_MEM_INT(npy_int16, s16)
+NPYV_IMPL_SSE_MEM_INT(npy_uint32, u32)
+NPYV_IMPL_SSE_MEM_INT(npy_int32, s32)
+NPYV_IMPL_SSE_MEM_INT(npy_uint64, u64)
+NPYV_IMPL_SSE_MEM_INT(npy_int64, s64)
+
+// unaligned load
+#define npyv_load_f32 _mm_loadu_ps
+#define npyv_load_f64 _mm_loadu_pd
+// aligned load
+#define npyv_loada_f32 _mm_load_ps
+#define npyv_loada_f64 _mm_load_pd
+// load lower part
+#define npyv_loadl_f32(PTR) _mm_castsi128_ps(npyv_loadl_u32((const npy_uint32*)(PTR)))
+#define npyv_loadl_f64(PTR) _mm_castsi128_pd(npyv_loadl_u32((const npy_uint32*)(PTR)))
+// stream load
+#define npyv_loads_f32(PTR) _mm_castsi128_ps(npyv__loads(PTR))
+#define npyv_loads_f64(PTR) _mm_castsi128_pd(npyv__loads(PTR))
+// unaligned store
+#define npyv_store_f32 _mm_storeu_ps
+#define npyv_store_f64 _mm_storeu_pd
+// aligned store
+#define npyv_storea_f32 _mm_store_ps
+#define npyv_storea_f64 _mm_store_pd
+// stream store
+#define npyv_stores_f32 _mm_stream_ps
+#define npyv_stores_f64 _mm_stream_pd
+// store lower part
+#define npyv_storel_f32(PTR, VEC) _mm_storel_epi64((__m128i*)(PTR), _mm_castps_si128(VEC));
+#define npyv_storel_f64(PTR, VEC) _mm_storel_epi64((__m128i*)(PTR), _mm_castpd_si128(VEC));
+// store higher part
+#define npyv_storeh_f32(PTR, VEC) npyv_storeh_u32((npy_uint32*)(PTR), _mm_castps_si128(VEC))
+#define npyv_storeh_f64(PTR, VEC) npyv_storeh_u32((npy_uint32*)(PTR), _mm_castpd_si128(VEC))
+/***************************
+ * Non-contiguous Load
+ ***************************/
+//// 32
+NPY_FINLINE npyv_s32 npyv_loadn_s32(const npy_int32 *ptr, npy_intp stride)
+{
+ __m128i a = _mm_cvtsi32_si128(*ptr);
+#ifdef NPY_HAVE_SSE41
+ a = _mm_insert_epi32(a, ptr[stride], 1);
+ a = _mm_insert_epi32(a, ptr[stride*2], 2);
+ a = _mm_insert_epi32(a, ptr[stride*3], 3);
+#else
+ __m128i a1 = _mm_cvtsi32_si128(ptr[stride]);
+ __m128i a2 = _mm_cvtsi32_si128(ptr[stride*2]);
+ __m128i a3 = _mm_cvtsi32_si128(ptr[stride*3]);
+ a = _mm_unpacklo_epi32(a, a1);
+ a = _mm_unpacklo_epi64(a, _mm_unpacklo_epi32(a2, a3));
+#endif
+ return a;
+}
+NPY_FINLINE npyv_u32 npyv_loadn_u32(const npy_uint32 *ptr, npy_intp stride)
+{ return npyv_loadn_s32((const npy_int32*)ptr, stride); }
+NPY_FINLINE npyv_f32 npyv_loadn_f32(const float *ptr, npy_intp stride)
+{ return _mm_castsi128_ps(npyv_loadn_s32((const npy_int32*)ptr, stride)); }
+//// 64
+NPY_FINLINE npyv_f64 npyv_loadn_f64(const double *ptr, npy_intp stride)
+{ return _mm_loadh_pd(npyv_loadl_f64(ptr), ptr + stride); }
+NPY_FINLINE npyv_u64 npyv_loadn_u64(const npy_uint64 *ptr, npy_intp stride)
+{ return _mm_castpd_si128(npyv_loadn_f64((const double*)ptr, stride)); }
+NPY_FINLINE npyv_s64 npyv_loadn_s64(const npy_int64 *ptr, npy_intp stride)
+{ return _mm_castpd_si128(npyv_loadn_f64((const double*)ptr, stride)); }
+/***************************
+ * Non-contiguous Store
+ ***************************/
+//// 32
+NPY_FINLINE void npyv_storen_s32(npy_int32 *ptr, npy_intp stride, npyv_s32 a)
+{
+ ptr[stride * 0] = _mm_cvtsi128_si32(a);
+#ifdef NPY_HAVE_SSE41
+ ptr[stride * 1] = _mm_extract_epi32(a, 1);
+ ptr[stride * 2] = _mm_extract_epi32(a, 2);
+ ptr[stride * 3] = _mm_extract_epi32(a, 3);
+#else
+ ptr[stride * 1] = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 0, 1)));
+ ptr[stride * 2] = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 0, 2)));
+ ptr[stride * 3] = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 0, 3)));
+#endif
+}
+NPY_FINLINE void npyv_storen_u32(npy_uint32 *ptr, npy_intp stride, npyv_u32 a)
+{ npyv_storen_s32((npy_int32*)ptr, stride, a); }
+NPY_FINLINE void npyv_storen_f32(float *ptr, npy_intp stride, npyv_f32 a)
+{ npyv_storen_s32((npy_int32*)ptr, stride, _mm_castps_si128(a)); }
+//// 64
+NPY_FINLINE void npyv_storen_f64(double *ptr, npy_intp stride, npyv_f64 a)
+{
+ _mm_storel_pd(ptr, a);
+ _mm_storeh_pd(ptr + stride, a);
+}
+NPY_FINLINE void npyv_storen_u64(npy_uint64 *ptr, npy_intp stride, npyv_u64 a)
+{ npyv_storen_f64((double*)ptr, stride, _mm_castsi128_pd(a)); }
+NPY_FINLINE void npyv_storen_s64(npy_int64 *ptr, npy_intp stride, npyv_s64 a)
+{ npyv_storen_f64((double*)ptr, stride, _mm_castsi128_pd(a)); }
+
+/*********************************
+ * Partial Load
+ *********************************/
+#if defined(__clang__) && __clang_major__ > 7
+ /**
+ * Clang >=8 perform aggressive optimization that tends to
+ * zero the bits of upper half part of vectors even
+ * when we try to fill it up with certain scalars,
+ * which my lead to zero division errors.
+ */
+ #define NPYV__CLANG_ZEROUPPER
+#endif
+//// 32
+NPY_FINLINE npyv_s32 npyv_load_till_s32(const npy_int32 *ptr, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+#ifdef NPYV__CLANG_ZEROUPPER
+ if (nlane > 3) {
+ return npyv_load_s32(ptr);
+ }
+ npy_int32 NPY_DECL_ALIGNED(16) data[4] = {fill, fill, fill, fill};
+ for (npy_uint64 i = 0; i < nlane; ++i) {
+ data[i] = ptr[i];
+ }
+ return npyv_loada_s32(data);
+#else
+ #ifndef NPY_HAVE_SSE41
+ const short *wptr = (const short*)ptr;
+ #endif
+ const __m128i vfill = npyv_setall_s32(fill);
+ __m128i a;
+ switch(nlane) {
+ case 2:
+ return _mm_castpd_si128(
+ _mm_loadl_pd(_mm_castsi128_pd(vfill), (double*)ptr)
+ );
+ #ifdef NPY_HAVE_SSE41
+ case 1:
+ return _mm_insert_epi32(vfill, ptr[0], 0);
+ case 3:
+ a = _mm_loadl_epi64((const __m128i*)ptr);
+ a = _mm_insert_epi32(a, ptr[2], 2);
+ a = _mm_insert_epi32(a, fill, 3);
+ return a;
+ #else
+ case 1:
+ a = _mm_insert_epi16(vfill, wptr[0], 0);
+ return _mm_insert_epi16(a, wptr[1], 1);
+ case 3:
+ a = _mm_loadl_epi64((const __m128i*)ptr);
+ a = _mm_unpacklo_epi64(a, vfill);
+ a = _mm_insert_epi16(a, wptr[4], 4);
+ a = _mm_insert_epi16(a, wptr[5], 5);
+ return a;
+ #endif // NPY_HAVE_SSE41
+ default:
+ return npyv_load_s32(ptr);
+ }
+#endif
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32 npyv_load_tillz_s32(const npy_int32 *ptr, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ case 1:
+ return _mm_cvtsi32_si128(*ptr);
+ case 2:
+ return _mm_loadl_epi64((const __m128i*)ptr);
+ case 3:;
+ npyv_s32 a = _mm_loadl_epi64((const __m128i*)ptr);
+ #ifdef NPY_HAVE_SSE41
+ return _mm_insert_epi32(a, ptr[2], 2);
+ #else
+ return _mm_unpacklo_epi64(a, _mm_cvtsi32_si128(ptr[2]));
+ #endif
+ default:
+ return npyv_load_s32(ptr);
+ }
+}
+//// 64
+NPY_FINLINE npyv_s64 npyv_load_till_s64(const npy_int64 *ptr, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+#ifdef NPYV__CLANG_ZEROUPPER
+ if (nlane <= 2) {
+ npy_int64 NPY_DECL_ALIGNED(16) data[2] = {fill, fill};
+ for (npy_uint64 i = 0; i < nlane; ++i) {
+ data[i] = ptr[i];
+ }
+ return npyv_loada_s64(data);
+ }
+#else
+ if (nlane == 1) {
+ const __m128i vfill = npyv_setall_s64(fill);
+ return _mm_castpd_si128(
+ _mm_loadl_pd(_mm_castsi128_pd(vfill), (double*)ptr)
+ );
+ }
+#endif
+ return npyv_load_s64(ptr);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_load_tillz_s64(const npy_int64 *ptr, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ return _mm_loadl_epi64((const __m128i*)ptr);
+ }
+ return npyv_load_s64(ptr);
+}
+/*********************************
+ * Non-contiguous partial load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32
+npyv_loadn_till_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+#ifdef NPYV__CLANG_ZEROUPPER
+ if (nlane > 3) {
+ return npyv_loadn_s32(ptr, stride);
+ }
+ npy_int32 NPY_DECL_ALIGNED(16) data[4] = {fill, fill, fill, fill};
+ for (npy_uint64 i = 0; i < nlane; ++i) {
+ data[i] = ptr[stride*i];
+ }
+ return npyv_loada_s32(data);
+#else
+ __m128i vfill = npyv_setall_s32(fill);
+ #ifndef NPY_HAVE_SSE41
+ const short *wptr = (const short*)ptr;
+ #endif
+ switch(nlane) {
+ #ifdef NPY_HAVE_SSE41
+ case 3:
+ vfill = _mm_insert_epi32(vfill, ptr[stride*2], 2);
+ case 2:
+ vfill = _mm_insert_epi32(vfill, ptr[stride], 1);
+ case 1:
+ vfill = _mm_insert_epi32(vfill, ptr[0], 0);
+ break;
+ #else
+ case 3:
+ vfill = _mm_unpacklo_epi32(_mm_cvtsi32_si128(ptr[stride*2]), vfill);
+ case 2:
+ vfill = _mm_unpacklo_epi64(_mm_unpacklo_epi32(
+ _mm_cvtsi32_si128(*ptr), _mm_cvtsi32_si128(ptr[stride])
+ ), vfill);
+ break;
+ case 1:
+ vfill = _mm_insert_epi16(vfill, wptr[0], 0);
+ vfill = _mm_insert_epi16(vfill, wptr[1], 1);
+ break;
+ #endif // NPY_HAVE_SSE41
+ default:
+ return npyv_loadn_s32(ptr, stride);
+ } // switch
+ return vfill;
+#endif
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32
+npyv_loadn_tillz_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ case 1:
+ return _mm_cvtsi32_si128(ptr[0]);
+ case 2:;
+ npyv_s32 a = _mm_cvtsi32_si128(ptr[0]);
+#ifdef NPY_HAVE_SSE41
+ return _mm_insert_epi32(a, ptr[stride], 1);
+#else
+ return _mm_unpacklo_epi32(a, _mm_cvtsi32_si128(ptr[stride]));
+#endif // NPY_HAVE_SSE41
+ case 3:;
+ a = _mm_cvtsi32_si128(ptr[0]);
+#ifdef NPY_HAVE_SSE41
+ a = _mm_insert_epi32(a, ptr[stride], 1);
+ a = _mm_insert_epi32(a, ptr[stride*2], 2);
+ return a;
+#else
+ a = _mm_unpacklo_epi32(a, _mm_cvtsi32_si128(ptr[stride]));
+ a = _mm_unpacklo_epi64(a, _mm_cvtsi32_si128(ptr[stride*2]));
+ return a;
+#endif // NPY_HAVE_SSE41
+ default:
+ return npyv_loadn_s32(ptr, stride);
+ }
+}
+//// 64
+NPY_FINLINE npyv_s64
+npyv_loadn_till_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+#ifdef NPYV__CLANG_ZEROUPPER
+ if (nlane <= 2) {
+ npy_int64 NPY_DECL_ALIGNED(16) data[2] = {fill, fill};
+ for (npy_uint64 i = 0; i < nlane; ++i) {
+ data[i] = ptr[i*stride];
+ }
+ return npyv_loada_s64(data);
+ }
+#else
+ if (nlane == 1) {
+ const __m128i vfill = npyv_setall_s64(fill);
+ return _mm_castpd_si128(
+ _mm_loadl_pd(_mm_castsi128_pd(vfill), (double*)ptr)
+ );
+ }
+#endif
+ return npyv_loadn_s64(ptr, stride);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_loadn_tillz_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ return _mm_loadl_epi64((const __m128i*)ptr);
+ }
+ return npyv_loadn_s64(ptr, stride);
+}
+/*********************************
+ * Partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_store_till_s32(npy_int32 *ptr, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ case 1:
+ *ptr = _mm_cvtsi128_si32(a);
+ break;
+ case 2:
+ _mm_storel_epi64((__m128i *)ptr, a);
+ break;
+ case 3:
+ _mm_storel_epi64((__m128i *)ptr, a);
+ #ifdef NPY_HAVE_SSE41
+ ptr[2] = _mm_extract_epi32(a, 2);
+ #else
+ ptr[2] = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 0, 2)));
+ #endif
+ break;
+ default:
+ npyv_store_s32(ptr, a);
+ }
+}
+//// 64
+NPY_FINLINE void npyv_store_till_s64(npy_int64 *ptr, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ _mm_storel_epi64((__m128i *)ptr, a);
+ return;
+ }
+ npyv_store_s64(ptr, a);
+}
+/*********************************
+ * Non-contiguous partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_storen_till_s32(npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+#ifdef NPY_HAVE_SSE41
+ default:
+ ptr[stride*3] = _mm_extract_epi32(a, 3);
+ case 3:
+ ptr[stride*2] = _mm_extract_epi32(a, 2);
+ case 2:
+ ptr[stride*1] = _mm_extract_epi32(a, 1);
+#else
+ default:
+ ptr[stride*3] = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 0, 3)));
+ case 3:
+ ptr[stride*2] = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 0, 2)));
+ case 2:
+ ptr[stride*1] = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, _MM_SHUFFLE(0, 0, 0, 1)));
+#endif
+ case 1:
+ ptr[stride*0] = _mm_cvtsi128_si32(a);
+ break;
+ }
+}
+//// 64
+NPY_FINLINE void npyv_storen_till_s64(npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ _mm_storel_epi64((__m128i *)ptr, a);
+ return;
+ }
+ npyv_storen_s64(ptr, stride, a);
+}
+/*****************************************************************
+ * Implement partial load/store for u32/f32/u64/f64... via casting
+ *****************************************************************/
+#define NPYV_IMPL_SSE_REST_PARTIAL_TYPES(F_SFX, T_SFX) \
+ NPY_FINLINE npyv_##F_SFX npyv_load_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, \
+ npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_load_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane \
+ )); \
+ } \
+ NPY_FINLINE void npyv_store_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_store_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ } \
+ NPY_FINLINE void npyv_storen_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_storen_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, stride, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ }
+
+NPYV_IMPL_SSE_REST_PARTIAL_TYPES(u32, s32)
+NPYV_IMPL_SSE_REST_PARTIAL_TYPES(f32, s32)
+NPYV_IMPL_SSE_REST_PARTIAL_TYPES(u64, s64)
+NPYV_IMPL_SSE_REST_PARTIAL_TYPES(f64, s64)
+
+#endif // _NPY_SIMD_SSE_MEMORY_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_SSE_MISC_H
+#define _NPY_SIMD_SSE_MISC_H
+
+// vector with zero lanes
+#define npyv_zero_u8 _mm_setzero_si128
+#define npyv_zero_s8 _mm_setzero_si128
+#define npyv_zero_u16 _mm_setzero_si128
+#define npyv_zero_s16 _mm_setzero_si128
+#define npyv_zero_u32 _mm_setzero_si128
+#define npyv_zero_s32 _mm_setzero_si128
+#define npyv_zero_u64 _mm_setzero_si128
+#define npyv_zero_s64 _mm_setzero_si128
+#define npyv_zero_f32 _mm_setzero_ps
+#define npyv_zero_f64 _mm_setzero_pd
+
+// vector with a specific value set to all lanes
+#define npyv_setall_u8(VAL) _mm_set1_epi8((char)VAL)
+#define npyv_setall_s8(VAL) _mm_set1_epi8((char)VAL)
+#define npyv_setall_u16(VAL) _mm_set1_epi16((short)VAL)
+#define npyv_setall_s16(VAL) _mm_set1_epi16((short)VAL)
+#define npyv_setall_u32(VAL) _mm_set1_epi32((int)VAL)
+#define npyv_setall_s32(VAL) _mm_set1_epi32(VAL)
+#if !defined(__x86_64__) && !defined(_M_X64)
+ #define npyv_setall_u64(VAL) _mm_set_epi32((int)(VAL >> 32), (int)VAL, (int)(VAL >> 32), (int)VAL)
+ #define npyv_setall_s64 npyv_setall_u64
+#else
+ #define npyv_setall_u64(VAL) _mm_set1_epi64x(VAL)
+ #define npyv_setall_s64(VAL) _mm_set1_epi64x(VAL)
+#endif
+#define npyv_setall_f32(VAL) _mm_set1_ps(VAL)
+#define npyv_setall_f64(VAL) _mm_set1_pd(VAL)
+
+/**
+ * vector with specific values set to each lane and
+ * set a specific value to all remained lanes
+ *
+ * Args that generated by NPYV__SET_FILL_* not going to expand if
+ * _mm_setr_* are defined as macros.
+ */
+NPY_FINLINE __m128i npyv__setr_epi8(
+ char i0, char i1, char i2, char i3, char i4, char i5, char i6, char i7,
+ char i8, char i9, char i10, char i11, char i12, char i13, char i14, char i15)
+{
+ return _mm_setr_epi8(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15);
+}
+NPY_FINLINE __m128i npyv__setr_epi16(short i0, short i1, short i2, short i3, short i4, short i5,
+ short i6, short i7)
+{
+ return _mm_setr_epi16(i0, i1, i2, i3, i4, i5, i6, i7);
+}
+NPY_FINLINE __m128i npyv__setr_epi32(int i0, int i1, int i2, int i3)
+{
+ return _mm_setr_epi32(i0, i1, i2, i3);
+}
+NPY_FINLINE __m128i npyv__setr_epi64(npy_int64 i0, npy_int64 i1)
+{
+ return _mm_set_epi64x(i1, i0);
+}
+NPY_FINLINE __m128 npyv__setr_ps(float i0, float i1, float i2, float i3)
+{
+ return _mm_setr_ps(i0, i1, i2, i3);
+}
+NPY_FINLINE __m128d npyv__setr_pd(double i0, double i1)
+{
+ return _mm_setr_pd(i0, i1);
+}
+#define npyv_setf_u8(FILL, ...) npyv__setr_epi8(NPYV__SET_FILL_16(char, FILL, __VA_ARGS__))
+#define npyv_setf_s8(FILL, ...) npyv__setr_epi8(NPYV__SET_FILL_16(char, FILL, __VA_ARGS__))
+#define npyv_setf_u16(FILL, ...) npyv__setr_epi16(NPYV__SET_FILL_8(short, FILL, __VA_ARGS__))
+#define npyv_setf_s16(FILL, ...) npyv__setr_epi16(NPYV__SET_FILL_8(short, FILL, __VA_ARGS__))
+#define npyv_setf_u32(FILL, ...) npyv__setr_epi32(NPYV__SET_FILL_4(int, FILL, __VA_ARGS__))
+#define npyv_setf_s32(FILL, ...) npyv__setr_epi32(NPYV__SET_FILL_4(int, FILL, __VA_ARGS__))
+#define npyv_setf_u64(FILL, ...) npyv__setr_epi64(NPYV__SET_FILL_2(npy_int64, FILL, __VA_ARGS__))
+#define npyv_setf_s64(FILL, ...) npyv__setr_epi64(NPYV__SET_FILL_2(npy_int64, FILL, __VA_ARGS__))
+#define npyv_setf_f32(FILL, ...) npyv__setr_ps(NPYV__SET_FILL_4(float, FILL, __VA_ARGS__))
+#define npyv_setf_f64(FILL, ...) npyv__setr_pd(NPYV__SET_FILL_2(double, FILL, __VA_ARGS__))
+
+// vector with specific values set to each lane and
+// set zero to all remained lanes
+#define npyv_set_u8(...) npyv_setf_u8(0, __VA_ARGS__)
+#define npyv_set_s8(...) npyv_setf_s8(0, __VA_ARGS__)
+#define npyv_set_u16(...) npyv_setf_u16(0, __VA_ARGS__)
+#define npyv_set_s16(...) npyv_setf_s16(0, __VA_ARGS__)
+#define npyv_set_u32(...) npyv_setf_u32(0, __VA_ARGS__)
+#define npyv_set_s32(...) npyv_setf_s32(0, __VA_ARGS__)
+#define npyv_set_u64(...) npyv_setf_u64(0, __VA_ARGS__)
+#define npyv_set_s64(...) npyv_setf_s64(0, __VA_ARGS__)
+#define npyv_set_f32(...) npyv_setf_f32(0, __VA_ARGS__)
+#define npyv_set_f64(...) npyv_setf_f64(0, __VA_ARGS__)
+
+// Per lane select
+#ifdef NPY_HAVE_SSE41
+ #define npyv_select_u8(MASK, A, B) _mm_blendv_epi8(B, A, MASK)
+ #define npyv_select_f32(MASK, A, B) _mm_blendv_ps(B, A, _mm_castsi128_ps(MASK))
+ #define npyv_select_f64(MASK, A, B) _mm_blendv_pd(B, A, _mm_castsi128_pd(MASK))
+#else
+ NPY_FINLINE __m128i npyv_select_u8(__m128i mask, __m128i a, __m128i b)
+ { return _mm_xor_si128(b, _mm_and_si128(_mm_xor_si128(b, a), mask)); }
+ NPY_FINLINE __m128 npyv_select_f32(__m128i mask, __m128 a, __m128 b)
+ { return _mm_xor_ps(b, _mm_and_ps(_mm_xor_ps(b, a), _mm_castsi128_ps(mask))); }
+ NPY_FINLINE __m128d npyv_select_f64(__m128i mask, __m128d a, __m128d b)
+ { return _mm_xor_pd(b, _mm_and_pd(_mm_xor_pd(b, a), _mm_castsi128_pd(mask))); }
+#endif
+#define npyv_select_s8 npyv_select_u8
+#define npyv_select_u16 npyv_select_u8
+#define npyv_select_s16 npyv_select_u8
+#define npyv_select_u32 npyv_select_u8
+#define npyv_select_s32 npyv_select_u8
+#define npyv_select_u64 npyv_select_u8
+#define npyv_select_s64 npyv_select_u8
+
+// Reinterpret
+#define npyv_reinterpret_u8_u8(X) X
+#define npyv_reinterpret_u8_s8(X) X
+#define npyv_reinterpret_u8_u16(X) X
+#define npyv_reinterpret_u8_s16(X) X
+#define npyv_reinterpret_u8_u32(X) X
+#define npyv_reinterpret_u8_s32(X) X
+#define npyv_reinterpret_u8_u64(X) X
+#define npyv_reinterpret_u8_s64(X) X
+#define npyv_reinterpret_u8_f32 _mm_castps_si128
+#define npyv_reinterpret_u8_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_s8_s8(X) X
+#define npyv_reinterpret_s8_u8(X) X
+#define npyv_reinterpret_s8_u16(X) X
+#define npyv_reinterpret_s8_s16(X) X
+#define npyv_reinterpret_s8_u32(X) X
+#define npyv_reinterpret_s8_s32(X) X
+#define npyv_reinterpret_s8_u64(X) X
+#define npyv_reinterpret_s8_s64(X) X
+#define npyv_reinterpret_s8_f32 _mm_castps_si128
+#define npyv_reinterpret_s8_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_u16_u16(X) X
+#define npyv_reinterpret_u16_u8(X) X
+#define npyv_reinterpret_u16_s8(X) X
+#define npyv_reinterpret_u16_s16(X) X
+#define npyv_reinterpret_u16_u32(X) X
+#define npyv_reinterpret_u16_s32(X) X
+#define npyv_reinterpret_u16_u64(X) X
+#define npyv_reinterpret_u16_s64(X) X
+#define npyv_reinterpret_u16_f32 _mm_castps_si128
+#define npyv_reinterpret_u16_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_s16_s16(X) X
+#define npyv_reinterpret_s16_u8(X) X
+#define npyv_reinterpret_s16_s8(X) X
+#define npyv_reinterpret_s16_u16(X) X
+#define npyv_reinterpret_s16_u32(X) X
+#define npyv_reinterpret_s16_s32(X) X
+#define npyv_reinterpret_s16_u64(X) X
+#define npyv_reinterpret_s16_s64(X) X
+#define npyv_reinterpret_s16_f32 _mm_castps_si128
+#define npyv_reinterpret_s16_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_u32_u32(X) X
+#define npyv_reinterpret_u32_u8(X) X
+#define npyv_reinterpret_u32_s8(X) X
+#define npyv_reinterpret_u32_u16(X) X
+#define npyv_reinterpret_u32_s16(X) X
+#define npyv_reinterpret_u32_s32(X) X
+#define npyv_reinterpret_u32_u64(X) X
+#define npyv_reinterpret_u32_s64(X) X
+#define npyv_reinterpret_u32_f32 _mm_castps_si128
+#define npyv_reinterpret_u32_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_s32_s32(X) X
+#define npyv_reinterpret_s32_u8(X) X
+#define npyv_reinterpret_s32_s8(X) X
+#define npyv_reinterpret_s32_u16(X) X
+#define npyv_reinterpret_s32_s16(X) X
+#define npyv_reinterpret_s32_u32(X) X
+#define npyv_reinterpret_s32_u64(X) X
+#define npyv_reinterpret_s32_s64(X) X
+#define npyv_reinterpret_s32_f32 _mm_castps_si128
+#define npyv_reinterpret_s32_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_u64_u64(X) X
+#define npyv_reinterpret_u64_u8(X) X
+#define npyv_reinterpret_u64_s8(X) X
+#define npyv_reinterpret_u64_u16(X) X
+#define npyv_reinterpret_u64_s16(X) X
+#define npyv_reinterpret_u64_u32(X) X
+#define npyv_reinterpret_u64_s32(X) X
+#define npyv_reinterpret_u64_s64(X) X
+#define npyv_reinterpret_u64_f32 _mm_castps_si128
+#define npyv_reinterpret_u64_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_s64_s64(X) X
+#define npyv_reinterpret_s64_u8(X) X
+#define npyv_reinterpret_s64_s8(X) X
+#define npyv_reinterpret_s64_u16(X) X
+#define npyv_reinterpret_s64_s16(X) X
+#define npyv_reinterpret_s64_u32(X) X
+#define npyv_reinterpret_s64_s32(X) X
+#define npyv_reinterpret_s64_u64(X) X
+#define npyv_reinterpret_s64_f32 _mm_castps_si128
+#define npyv_reinterpret_s64_f64 _mm_castpd_si128
+
+#define npyv_reinterpret_f32_f32(X) X
+#define npyv_reinterpret_f32_u8 _mm_castsi128_ps
+#define npyv_reinterpret_f32_s8 _mm_castsi128_ps
+#define npyv_reinterpret_f32_u16 _mm_castsi128_ps
+#define npyv_reinterpret_f32_s16 _mm_castsi128_ps
+#define npyv_reinterpret_f32_u32 _mm_castsi128_ps
+#define npyv_reinterpret_f32_s32 _mm_castsi128_ps
+#define npyv_reinterpret_f32_u64 _mm_castsi128_ps
+#define npyv_reinterpret_f32_s64 _mm_castsi128_ps
+#define npyv_reinterpret_f32_f64 _mm_castpd_ps
+
+#define npyv_reinterpret_f64_f64(X) X
+#define npyv_reinterpret_f64_u8 _mm_castsi128_pd
+#define npyv_reinterpret_f64_s8 _mm_castsi128_pd
+#define npyv_reinterpret_f64_u16 _mm_castsi128_pd
+#define npyv_reinterpret_f64_s16 _mm_castsi128_pd
+#define npyv_reinterpret_f64_u32 _mm_castsi128_pd
+#define npyv_reinterpret_f64_s32 _mm_castsi128_pd
+#define npyv_reinterpret_f64_u64 _mm_castsi128_pd
+#define npyv_reinterpret_f64_s64 _mm_castsi128_pd
+#define npyv_reinterpret_f64_f32 _mm_castps_pd
+
+// Only required by AVX2/AVX512
+#define npyv_cleanup() ((void)0)
+
+#endif // _NPY_SIMD_SSE_MISC_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_SSE_OPERATORS_H
+#define _NPY_SIMD_SSE_OPERATORS_H
+
+/***************************
+ * Shifting
+ ***************************/
+
+// left
+#define npyv_shl_u16(A, C) _mm_sll_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s16(A, C) _mm_sll_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_u32(A, C) _mm_sll_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s32(A, C) _mm_sll_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_u64(A, C) _mm_sll_epi64(A, _mm_cvtsi32_si128(C))
+#define npyv_shl_s64(A, C) _mm_sll_epi64(A, _mm_cvtsi32_si128(C))
+
+// left by an immediate constant
+#define npyv_shli_u16 _mm_slli_epi16
+#define npyv_shli_s16 _mm_slli_epi16
+#define npyv_shli_u32 _mm_slli_epi32
+#define npyv_shli_s32 _mm_slli_epi32
+#define npyv_shli_u64 _mm_slli_epi64
+#define npyv_shli_s64 _mm_slli_epi64
+
+// right
+#define npyv_shr_u16(A, C) _mm_srl_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_s16(A, C) _mm_sra_epi16(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_u32(A, C) _mm_srl_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_s32(A, C) _mm_sra_epi32(A, _mm_cvtsi32_si128(C))
+#define npyv_shr_u64(A, C) _mm_srl_epi64(A, _mm_cvtsi32_si128(C))
+NPY_FINLINE __m128i npyv_shr_s64(__m128i a, int c)
+{
+ const __m128i sbit = npyv_setall_s64(0x8000000000000000);
+ const __m128i cv = _mm_cvtsi32_si128(c);
+ __m128i r = _mm_srl_epi64(_mm_add_epi64(a, sbit), cv);
+ return _mm_sub_epi64(r, _mm_srl_epi64(sbit, cv));
+}
+
+// Right by an immediate constant
+#define npyv_shri_u16 _mm_srli_epi16
+#define npyv_shri_s16 _mm_srai_epi16
+#define npyv_shri_u32 _mm_srli_epi32
+#define npyv_shri_s32 _mm_srai_epi32
+#define npyv_shri_u64 _mm_srli_epi64
+#define npyv_shri_s64 npyv_shr_s64
+
+/***************************
+ * Logical
+ ***************************/
+
+// AND
+#define npyv_and_u8 _mm_and_si128
+#define npyv_and_s8 _mm_and_si128
+#define npyv_and_u16 _mm_and_si128
+#define npyv_and_s16 _mm_and_si128
+#define npyv_and_u32 _mm_and_si128
+#define npyv_and_s32 _mm_and_si128
+#define npyv_and_u64 _mm_and_si128
+#define npyv_and_s64 _mm_and_si128
+#define npyv_and_f32 _mm_and_ps
+#define npyv_and_f64 _mm_and_pd
+
+// OR
+#define npyv_or_u8 _mm_or_si128
+#define npyv_or_s8 _mm_or_si128
+#define npyv_or_u16 _mm_or_si128
+#define npyv_or_s16 _mm_or_si128
+#define npyv_or_u32 _mm_or_si128
+#define npyv_or_s32 _mm_or_si128
+#define npyv_or_u64 _mm_or_si128
+#define npyv_or_s64 _mm_or_si128
+#define npyv_or_f32 _mm_or_ps
+#define npyv_or_f64 _mm_or_pd
+
+// XOR
+#define npyv_xor_u8 _mm_xor_si128
+#define npyv_xor_s8 _mm_xor_si128
+#define npyv_xor_u16 _mm_xor_si128
+#define npyv_xor_s16 _mm_xor_si128
+#define npyv_xor_u32 _mm_xor_si128
+#define npyv_xor_s32 _mm_xor_si128
+#define npyv_xor_u64 _mm_xor_si128
+#define npyv_xor_s64 _mm_xor_si128
+#define npyv_xor_f32 _mm_xor_ps
+#define npyv_xor_f64 _mm_xor_pd
+
+// NOT
+#define npyv_not_u8(A) _mm_xor_si128(A, _mm_set1_epi32(-1))
+#define npyv_not_s8 npyv_not_u8
+#define npyv_not_u16 npyv_not_u8
+#define npyv_not_s16 npyv_not_u8
+#define npyv_not_u32 npyv_not_u8
+#define npyv_not_s32 npyv_not_u8
+#define npyv_not_u64 npyv_not_u8
+#define npyv_not_s64 npyv_not_u8
+#define npyv_not_f32(A) _mm_xor_ps(A, _mm_castsi128_ps(_mm_set1_epi32(-1)))
+#define npyv_not_f64(A) _mm_xor_pd(A, _mm_castsi128_pd(_mm_set1_epi32(-1)))
+
+/***************************
+ * Comparison
+ ***************************/
+
+// Int Equal
+#define npyv_cmpeq_u8 _mm_cmpeq_epi8
+#define npyv_cmpeq_s8 _mm_cmpeq_epi8
+#define npyv_cmpeq_u16 _mm_cmpeq_epi16
+#define npyv_cmpeq_s16 _mm_cmpeq_epi16
+#define npyv_cmpeq_u32 _mm_cmpeq_epi32
+#define npyv_cmpeq_s32 _mm_cmpeq_epi32
+#define npyv_cmpeq_s64 npyv_cmpeq_u64
+
+#ifdef NPY_HAVE_SSE41
+ #define npyv_cmpeq_u64 _mm_cmpeq_epi64
+#else
+ NPY_FINLINE __m128i npyv_cmpeq_u64(__m128i a, __m128i b)
+ {
+ __m128i cmpeq = _mm_cmpeq_epi32(a, b);
+ __m128i cmpeq_h = _mm_srli_epi64(cmpeq, 32);
+ __m128i test = _mm_and_si128(cmpeq, cmpeq_h);
+ return _mm_shuffle_epi32(test, _MM_SHUFFLE(2, 2, 0, 0));
+ }
+#endif
+
+// Int Not Equal
+#ifdef NPY_HAVE_XOP
+ #define npyv_cmpneq_u8 _mm_comneq_epi8
+ #define npyv_cmpneq_u16 _mm_comneq_epi16
+ #define npyv_cmpneq_u32 _mm_comneq_epi32
+ #define npyv_cmpneq_u64 _mm_comneq_epi64
+#else
+ #define npyv_cmpneq_u8(A, B) npyv_not_u8(npyv_cmpeq_u8(A, B))
+ #define npyv_cmpneq_u16(A, B) npyv_not_u16(npyv_cmpeq_u16(A, B))
+ #define npyv_cmpneq_u32(A, B) npyv_not_u32(npyv_cmpeq_u32(A, B))
+ #define npyv_cmpneq_u64(A, B) npyv_not_u64(npyv_cmpeq_u64(A, B))
+#endif
+#define npyv_cmpneq_s8 npyv_cmpneq_u8
+#define npyv_cmpneq_s16 npyv_cmpneq_u16
+#define npyv_cmpneq_s32 npyv_cmpneq_u32
+#define npyv_cmpneq_s64 npyv_cmpneq_u64
+
+// signed greater than
+#define npyv_cmpgt_s8 _mm_cmpgt_epi8
+#define npyv_cmpgt_s16 _mm_cmpgt_epi16
+#define npyv_cmpgt_s32 _mm_cmpgt_epi32
+
+#ifdef NPY_HAVE_SSE42
+ #define npyv_cmpgt_s64 _mm_cmpgt_epi64
+#else
+ NPY_FINLINE __m128i npyv_cmpgt_s64(__m128i a, __m128i b)
+ {
+ __m128i sub = _mm_sub_epi64(b, a);
+ __m128i nsame_sbit = _mm_xor_si128(a, b);
+ // nsame_sbit ? b : sub
+ __m128i test = _mm_xor_si128(sub, _mm_and_si128(_mm_xor_si128(sub, b), nsame_sbit));
+ __m128i extend_sbit = _mm_shuffle_epi32(_mm_srai_epi32(test, 31), _MM_SHUFFLE(3, 3, 1, 1));
+ return extend_sbit;
+ }
+#endif
+
+// signed greater than or equal
+#ifdef NPY_HAVE_XOP
+ #define npyv_cmpge_s8 _mm_comge_epi8
+ #define npyv_cmpge_s16 _mm_comge_epi16
+ #define npyv_cmpge_s32 _mm_comge_epi32
+ #define npyv_cmpge_s64 _mm_comge_epi64
+#else
+ #define npyv_cmpge_s8(A, B) npyv_not_s8(_mm_cmpgt_epi8(B, A))
+ #define npyv_cmpge_s16(A, B) npyv_not_s16(_mm_cmpgt_epi16(B, A))
+ #define npyv_cmpge_s32(A, B) npyv_not_s32(_mm_cmpgt_epi32(B, A))
+ #define npyv_cmpge_s64(A, B) npyv_not_s64(npyv_cmpgt_s64(B, A))
+#endif
+
+// unsigned greater than
+#ifdef NPY_HAVE_XOP
+ #define npyv_cmpgt_u8 _mm_comgt_epu8
+ #define npyv_cmpgt_u16 _mm_comgt_epu16
+ #define npyv_cmpgt_u32 _mm_comgt_epu32
+ #define npyv_cmpgt_u64 _mm_comgt_epu64
+#else
+ #define NPYV_IMPL_SSE_UNSIGNED_GT(LEN, SIGN) \
+ NPY_FINLINE __m128i npyv_cmpgt_u##LEN(__m128i a, __m128i b) \
+ { \
+ const __m128i sbit = _mm_set1_epi32(SIGN); \
+ return _mm_cmpgt_epi##LEN( \
+ _mm_xor_si128(a, sbit), _mm_xor_si128(b, sbit) \
+ ); \
+ }
+
+ NPYV_IMPL_SSE_UNSIGNED_GT(8, 0x80808080)
+ NPYV_IMPL_SSE_UNSIGNED_GT(16, 0x80008000)
+ NPYV_IMPL_SSE_UNSIGNED_GT(32, 0x80000000)
+
+ NPY_FINLINE __m128i npyv_cmpgt_u64(__m128i a, __m128i b)
+ {
+ const __m128i sbit = npyv_setall_s64(0x8000000000000000);
+ return npyv_cmpgt_s64(_mm_xor_si128(a, sbit), _mm_xor_si128(b, sbit));
+ }
+#endif
+
+// unsigned greater than or equal
+#ifdef NPY_HAVE_XOP
+ #define npyv_cmpge_u8 _mm_comge_epu8
+ #define npyv_cmpge_u16 _mm_comge_epu16
+ #define npyv_cmpge_u32 _mm_comge_epu32
+ #define npyv_cmpge_u64 _mm_comge_epu64
+#else
+ NPY_FINLINE __m128i npyv_cmpge_u8(__m128i a, __m128i b)
+ { return _mm_cmpeq_epi8(a, _mm_max_epu8(a, b)); }
+ #ifdef NPY_HAVE_SSE41
+ NPY_FINLINE __m128i npyv_cmpge_u16(__m128i a, __m128i b)
+ { return _mm_cmpeq_epi16(a, _mm_max_epu16(a, b)); }
+ NPY_FINLINE __m128i npyv_cmpge_u32(__m128i a, __m128i b)
+ { return _mm_cmpeq_epi32(a, _mm_max_epu32(a, b)); }
+ #else
+ #define npyv_cmpge_u16(A, B) _mm_cmpeq_epi16(_mm_subs_epu16(B, A), _mm_setzero_si128())
+ #define npyv_cmpge_u32(A, B) npyv_not_u32(npyv_cmpgt_u32(B, A))
+ #endif
+ #define npyv_cmpge_u64(A, B) npyv_not_u64(npyv_cmpgt_u64(B, A))
+#endif
+
+// less than
+#define npyv_cmplt_u8(A, B) npyv_cmpgt_u8(B, A)
+#define npyv_cmplt_s8(A, B) npyv_cmpgt_s8(B, A)
+#define npyv_cmplt_u16(A, B) npyv_cmpgt_u16(B, A)
+#define npyv_cmplt_s16(A, B) npyv_cmpgt_s16(B, A)
+#define npyv_cmplt_u32(A, B) npyv_cmpgt_u32(B, A)
+#define npyv_cmplt_s32(A, B) npyv_cmpgt_s32(B, A)
+#define npyv_cmplt_u64(A, B) npyv_cmpgt_u64(B, A)
+#define npyv_cmplt_s64(A, B) npyv_cmpgt_s64(B, A)
+
+// less than or equal
+#define npyv_cmple_u8(A, B) npyv_cmpge_u8(B, A)
+#define npyv_cmple_s8(A, B) npyv_cmpge_s8(B, A)
+#define npyv_cmple_u16(A, B) npyv_cmpge_u16(B, A)
+#define npyv_cmple_s16(A, B) npyv_cmpge_s16(B, A)
+#define npyv_cmple_u32(A, B) npyv_cmpge_u32(B, A)
+#define npyv_cmple_s32(A, B) npyv_cmpge_s32(B, A)
+#define npyv_cmple_u64(A, B) npyv_cmpge_u64(B, A)
+#define npyv_cmple_s64(A, B) npyv_cmpge_s64(B, A)
+
+// precision comparison
+#define npyv_cmpeq_f32(a, b) _mm_castps_si128(_mm_cmpeq_ps(a, b))
+#define npyv_cmpeq_f64(a, b) _mm_castpd_si128(_mm_cmpeq_pd(a, b))
+#define npyv_cmpneq_f32(a, b) _mm_castps_si128(_mm_cmpneq_ps(a, b))
+#define npyv_cmpneq_f64(a, b) _mm_castpd_si128(_mm_cmpneq_pd(a, b))
+#define npyv_cmplt_f32(a, b) _mm_castps_si128(_mm_cmplt_ps(a, b))
+#define npyv_cmplt_f64(a, b) _mm_castpd_si128(_mm_cmplt_pd(a, b))
+#define npyv_cmple_f32(a, b) _mm_castps_si128(_mm_cmple_ps(a, b))
+#define npyv_cmple_f64(a, b) _mm_castpd_si128(_mm_cmple_pd(a, b))
+#define npyv_cmpgt_f32(a, b) _mm_castps_si128(_mm_cmpgt_ps(a, b))
+#define npyv_cmpgt_f64(a, b) _mm_castpd_si128(_mm_cmpgt_pd(a, b))
+#define npyv_cmpge_f32(a, b) _mm_castps_si128(_mm_cmpge_ps(a, b))
+#define npyv_cmpge_f64(a, b) _mm_castpd_si128(_mm_cmpge_pd(a, b))
+
+#endif // _NPY_SIMD_SSE_OPERATORS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_SSE_REORDER_H
+#define _NPY_SIMD_SSE_REORDER_H
+
+// combine lower part of two vectors
+#define npyv_combinel_u8 _mm_unpacklo_epi64
+#define npyv_combinel_s8 _mm_unpacklo_epi64
+#define npyv_combinel_u16 _mm_unpacklo_epi64
+#define npyv_combinel_s16 _mm_unpacklo_epi64
+#define npyv_combinel_u32 _mm_unpacklo_epi64
+#define npyv_combinel_s32 _mm_unpacklo_epi64
+#define npyv_combinel_u64 _mm_unpacklo_epi64
+#define npyv_combinel_s64 _mm_unpacklo_epi64
+#define npyv_combinel_f32(A, B) _mm_castsi128_ps(_mm_unpacklo_epi64(_mm_castps_si128(A), _mm_castps_si128(B)))
+#define npyv_combinel_f64 _mm_unpacklo_pd
+
+// combine higher part of two vectors
+#define npyv_combineh_u8 _mm_unpackhi_epi64
+#define npyv_combineh_s8 _mm_unpackhi_epi64
+#define npyv_combineh_u16 _mm_unpackhi_epi64
+#define npyv_combineh_s16 _mm_unpackhi_epi64
+#define npyv_combineh_u32 _mm_unpackhi_epi64
+#define npyv_combineh_s32 _mm_unpackhi_epi64
+#define npyv_combineh_u64 _mm_unpackhi_epi64
+#define npyv_combineh_s64 _mm_unpackhi_epi64
+#define npyv_combineh_f32(A, B) _mm_castsi128_ps(_mm_unpackhi_epi64(_mm_castps_si128(A), _mm_castps_si128(B)))
+#define npyv_combineh_f64 _mm_unpackhi_pd
+
+// combine two vectors from lower and higher parts of two other vectors
+NPY_FINLINE npyv_m128ix2 npyv__combine(__m128i a, __m128i b)
+{
+ npyv_m128ix2 r;
+ r.val[0] = npyv_combinel_u8(a, b);
+ r.val[1] = npyv_combineh_u8(a, b);
+ return r;
+}
+NPY_FINLINE npyv_f32x2 npyv_combine_f32(__m128 a, __m128 b)
+{
+ npyv_f32x2 r;
+ r.val[0] = npyv_combinel_f32(a, b);
+ r.val[1] = npyv_combineh_f32(a, b);
+ return r;
+}
+NPY_FINLINE npyv_f64x2 npyv_combine_f64(__m128d a, __m128d b)
+{
+ npyv_f64x2 r;
+ r.val[0] = npyv_combinel_f64(a, b);
+ r.val[1] = npyv_combineh_f64(a, b);
+ return r;
+}
+#define npyv_combine_u8 npyv__combine
+#define npyv_combine_s8 npyv__combine
+#define npyv_combine_u16 npyv__combine
+#define npyv_combine_s16 npyv__combine
+#define npyv_combine_u32 npyv__combine
+#define npyv_combine_s32 npyv__combine
+#define npyv_combine_u64 npyv__combine
+#define npyv_combine_s64 npyv__combine
+
+// interleave two vectors
+#define NPYV_IMPL_SSE_ZIP(T_VEC, SFX, INTR_SFX) \
+ NPY_FINLINE T_VEC##x2 npyv_zip_##SFX(T_VEC a, T_VEC b) \
+ { \
+ T_VEC##x2 r; \
+ r.val[0] = _mm_unpacklo_##INTR_SFX(a, b); \
+ r.val[1] = _mm_unpackhi_##INTR_SFX(a, b); \
+ return r; \
+ }
+
+NPYV_IMPL_SSE_ZIP(npyv_u8, u8, epi8)
+NPYV_IMPL_SSE_ZIP(npyv_s8, s8, epi8)
+NPYV_IMPL_SSE_ZIP(npyv_u16, u16, epi16)
+NPYV_IMPL_SSE_ZIP(npyv_s16, s16, epi16)
+NPYV_IMPL_SSE_ZIP(npyv_u32, u32, epi32)
+NPYV_IMPL_SSE_ZIP(npyv_s32, s32, epi32)
+NPYV_IMPL_SSE_ZIP(npyv_u64, u64, epi64)
+NPYV_IMPL_SSE_ZIP(npyv_s64, s64, epi64)
+NPYV_IMPL_SSE_ZIP(npyv_f32, f32, ps)
+NPYV_IMPL_SSE_ZIP(npyv_f64, f64, pd)
+
+#endif // _NPY_SIMD_SSE_REORDER_H
--- /dev/null
+#ifndef _NPY_SIMD_H_
+ #error "Not a standalone header"
+#endif
+
+#define NPY_SIMD 128
+#define NPY_SIMD_WIDTH 16
+#define NPY_SIMD_F64 1
+
+typedef __m128i npyv_u8;
+typedef __m128i npyv_s8;
+typedef __m128i npyv_u16;
+typedef __m128i npyv_s16;
+typedef __m128i npyv_u32;
+typedef __m128i npyv_s32;
+typedef __m128i npyv_u64;
+typedef __m128i npyv_s64;
+typedef __m128 npyv_f32;
+typedef __m128d npyv_f64;
+
+typedef __m128i npyv_b8;
+typedef __m128i npyv_b16;
+typedef __m128i npyv_b32;
+typedef __m128i npyv_b64;
+
+typedef struct { __m128i val[2]; } npyv_m128ix2;
+typedef npyv_m128ix2 npyv_u8x2;
+typedef npyv_m128ix2 npyv_s8x2;
+typedef npyv_m128ix2 npyv_u16x2;
+typedef npyv_m128ix2 npyv_s16x2;
+typedef npyv_m128ix2 npyv_u32x2;
+typedef npyv_m128ix2 npyv_s32x2;
+typedef npyv_m128ix2 npyv_u64x2;
+typedef npyv_m128ix2 npyv_s64x2;
+
+typedef struct { __m128i val[3]; } npyv_m128ix3;
+typedef npyv_m128ix3 npyv_u8x3;
+typedef npyv_m128ix3 npyv_s8x3;
+typedef npyv_m128ix3 npyv_u16x3;
+typedef npyv_m128ix3 npyv_s16x3;
+typedef npyv_m128ix3 npyv_u32x3;
+typedef npyv_m128ix3 npyv_s32x3;
+typedef npyv_m128ix3 npyv_u64x3;
+typedef npyv_m128ix3 npyv_s64x3;
+
+typedef struct { __m128 val[2]; } npyv_f32x2;
+typedef struct { __m128d val[2]; } npyv_f64x2;
+typedef struct { __m128 val[3]; } npyv_f32x3;
+typedef struct { __m128d val[3]; } npyv_f64x3;
+
+#define npyv_nlanes_u8 16
+#define npyv_nlanes_s8 16
+#define npyv_nlanes_u16 8
+#define npyv_nlanes_s16 8
+#define npyv_nlanes_u32 4
+#define npyv_nlanes_s32 4
+#define npyv_nlanes_u64 2
+#define npyv_nlanes_s64 2
+#define npyv_nlanes_f32 4
+#define npyv_nlanes_f64 2
+
+#include "memory.h"
+#include "misc.h"
+#include "reorder.h"
+#include "operators.h"
+#include "conversion.h"
+#include "arithmetic.h"
+#include "math.h"
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_VSX_ARITHMETIC_H
+#define _NPY_SIMD_VSX_ARITHMETIC_H
+
+/***************************
+ * Addition
+ ***************************/
+// non-saturated
+#define npyv_add_u8 vec_add
+#define npyv_add_s8 vec_add
+#define npyv_add_u16 vec_add
+#define npyv_add_s16 vec_add
+#define npyv_add_u32 vec_add
+#define npyv_add_s32 vec_add
+#define npyv_add_u64 vec_add
+#define npyv_add_s64 vec_add
+#define npyv_add_f32 vec_add
+#define npyv_add_f64 vec_add
+
+// saturated
+#define npyv_adds_u8 vec_adds
+#define npyv_adds_s8 vec_adds
+#define npyv_adds_u16 vec_adds
+#define npyv_adds_s16 vec_adds
+
+/***************************
+ * Subtraction
+ ***************************/
+// non-saturated
+#define npyv_sub_u8 vec_sub
+#define npyv_sub_s8 vec_sub
+#define npyv_sub_u16 vec_sub
+#define npyv_sub_s16 vec_sub
+#define npyv_sub_u32 vec_sub
+#define npyv_sub_s32 vec_sub
+#define npyv_sub_u64 vec_sub
+#define npyv_sub_s64 vec_sub
+#define npyv_sub_f32 vec_sub
+#define npyv_sub_f64 vec_sub
+
+// saturated
+#define npyv_subs_u8 vec_subs
+#define npyv_subs_s8 vec_subs
+#define npyv_subs_u16 vec_subs
+#define npyv_subs_s16 vec_subs
+
+/***************************
+ * Multiplication
+ ***************************/
+// non-saturated
+// up to GCC 6 vec_mul only supports precisions and llong
+#if defined(__GNUC__) && __GNUC__ < 7
+ #define NPYV_IMPL_VSX_MUL(T_VEC, SFX, ...) \
+ NPY_FINLINE T_VEC npyv_mul_##SFX(T_VEC a, T_VEC b) \
+ { \
+ const npyv_u8 ev_od = {__VA_ARGS__}; \
+ return vec_perm( \
+ (T_VEC)vec_mule(a, b), \
+ (T_VEC)vec_mulo(a, b), ev_od \
+ ); \
+ }
+
+ NPYV_IMPL_VSX_MUL(npyv_u8, u8, 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30)
+ NPYV_IMPL_VSX_MUL(npyv_s8, s8, 0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30)
+ NPYV_IMPL_VSX_MUL(npyv_u16, u16, 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29)
+ NPYV_IMPL_VSX_MUL(npyv_s16, s16, 0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29)
+
+ // vmuluwm can be used for unsigned or signed 32-bit integers
+ #define NPYV_IMPL_VSX_MUL_32(T_VEC, SFX) \
+ NPY_FINLINE T_VEC npyv_mul_##SFX(T_VEC a, T_VEC b) \
+ { \
+ T_VEC ret; \
+ __asm__ __volatile__( \
+ "vmuluwm %0,%1,%2" : \
+ "=v" (ret) : "v" (a), "v" (b) \
+ ); \
+ return ret; \
+ }
+
+ NPYV_IMPL_VSX_MUL_32(npyv_u32, u32)
+ NPYV_IMPL_VSX_MUL_32(npyv_s32, s32)
+
+#else
+ #define npyv_mul_u8 vec_mul
+ #define npyv_mul_s8 vec_mul
+ #define npyv_mul_u16 vec_mul
+ #define npyv_mul_s16 vec_mul
+ #define npyv_mul_u32 vec_mul
+ #define npyv_mul_s32 vec_mul
+#endif
+#define npyv_mul_f32 vec_mul
+#define npyv_mul_f64 vec_mul
+
+/***************************
+ * Division
+ ***************************/
+#define npyv_div_f32 vec_div
+#define npyv_div_f64 vec_div
+
+/***************************
+ * FUSED
+ ***************************/
+// multiply and add, a*b + c
+#define npyv_muladd_f32 vec_madd
+#define npyv_muladd_f64 vec_madd
+// multiply and subtract, a*b - c
+#define npyv_mulsub_f32 vec_msub
+#define npyv_mulsub_f64 vec_msub
+// negate multiply and add, -(a*b) + c
+#define npyv_nmuladd_f32 vec_nmsub // equivalent to -(a*b - c)
+#define npyv_nmuladd_f64 vec_nmsub
+// negate multiply and subtract, -(a*b) - c
+#define npyv_nmulsub_f32 vec_nmadd // equivalent to -(a*b + c)
+#define npyv_nmulsub_f64 vec_nmadd
+
+// Horizontal add: Calculates the sum of all vector elements.
+NPY_FINLINE float npyv_sum_f32(npyv_f32 a)
+{
+ npyv_f32 sum = vec_add(a, npyv_combineh_f32(a, a));
+ return vec_extract(sum, 0) + vec_extract(sum, 1);
+}
+
+NPY_FINLINE double npyv_sum_f64(npyv_f64 a)
+{
+ return vec_extract(a, 0) + vec_extract(a, 1);
+}
+
+#endif // _NPY_SIMD_VSX_ARITHMETIC_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_VSX_CVT_H
+#define _NPY_SIMD_VSX_CVT_H
+
+// convert boolean vectors to integer vectors
+#define npyv_cvt_u8_b8(BL) ((npyv_u8) BL)
+#define npyv_cvt_s8_b8(BL) ((npyv_s8) BL)
+#define npyv_cvt_u16_b16(BL) ((npyv_u16) BL)
+#define npyv_cvt_s16_b16(BL) ((npyv_s16) BL)
+#define npyv_cvt_u32_b32(BL) ((npyv_u32) BL)
+#define npyv_cvt_s32_b32(BL) ((npyv_s32) BL)
+#define npyv_cvt_u64_b64(BL) ((npyv_u64) BL)
+#define npyv_cvt_s64_b64(BL) ((npyv_s64) BL)
+#define npyv_cvt_f32_b32(BL) ((npyv_f32) BL)
+#define npyv_cvt_f64_b64(BL) ((npyv_f64) BL)
+
+// convert integer vectors to boolean vectors
+#define npyv_cvt_b8_u8(A) ((npyv_b8) A)
+#define npyv_cvt_b8_s8(A) ((npyv_b8) A)
+#define npyv_cvt_b16_u16(A) ((npyv_b16) A)
+#define npyv_cvt_b16_s16(A) ((npyv_b16) A)
+#define npyv_cvt_b32_u32(A) ((npyv_b32) A)
+#define npyv_cvt_b32_s32(A) ((npyv_b32) A)
+#define npyv_cvt_b64_u64(A) ((npyv_b64) A)
+#define npyv_cvt_b64_s64(A) ((npyv_b64) A)
+#define npyv_cvt_b32_f32(A) ((npyv_b32) A)
+#define npyv_cvt_b64_f64(A) ((npyv_b64) A)
+
+#endif // _NPY_SIMD_VSX_CVT_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_VSX_MATH_H
+#define _NPY_SIMD_VSX_MATH_H
+/***************************
+ * Elementary
+ ***************************/
+// Square root
+#define npyv_sqrt_f32 vec_sqrt
+#define npyv_sqrt_f64 vec_sqrt
+
+// Reciprocal
+NPY_FINLINE npyv_f32 npyv_recip_f32(npyv_f32 a)
+{
+ const npyv_f32 one = npyv_setall_f32(1.0f);
+ return vec_div(one, a);
+}
+NPY_FINLINE npyv_f64 npyv_recip_f64(npyv_f64 a)
+{
+ const npyv_f64 one = npyv_setall_f64(1.0);
+ return vec_div(one, a);
+}
+
+// Absolute
+#define npyv_abs_f32 vec_abs
+#define npyv_abs_f64 vec_abs
+
+// Square
+NPY_FINLINE npyv_f32 npyv_square_f32(npyv_f32 a)
+{ return vec_mul(a, a); }
+NPY_FINLINE npyv_f64 npyv_square_f64(npyv_f64 a)
+{ return vec_mul(a, a); }
+
+#endif // _NPY_SIMD_VSX_MATH_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_VSX_MEMORY_H
+#define _NPY_SIMD_VSX_MEMORY_H
+
+#include "misc.h"
+
+/****************************
+ * Private utilities
+ ****************************/
+// TODO: test load by cast
+#define VSX__CAST_lOAD 0
+#if VSX__CAST_lOAD
+ #define npyv__load(T_VEC, PTR) (*((T_VEC*)(PTR)))
+#else
+ /**
+ * CLANG fails to load unaligned addresses via vec_xl, vec_xst
+ * so we failback to vec_vsx_ld, vec_vsx_st
+ */
+ #if (defined(__GNUC__) && !defined(vec_xl)) || (defined(__clang__) && !defined(__IBMC__))
+ #define npyv__load(T_VEC, PTR) vec_vsx_ld(0, PTR)
+ #else
+ #define npyv__load(T_VEC, PTR) vec_xl(0, PTR)
+ #endif
+#endif
+// unaligned store
+#if (defined(__GNUC__) && !defined(vec_xl)) || (defined(__clang__) && !defined(__IBMC__))
+ #define npyv__store(PTR, VEC) vec_vsx_st(VEC, 0, PTR)
+#else
+ #define npyv__store(PTR, VEC) vec_xst(VEC, 0, PTR)
+#endif
+
+// avoid aliasing rules
+#ifdef __cplusplus
+ template<typename T_PTR>
+ NPY_FINLINE npy_uint64 *npyv__ptr2u64(const T_PTR *ptr)
+ { npy_uint64 *ptr64 = (npy_uint64*)ptr; return ptr64; }
+#else
+ NPY_FINLINE npy_uint64 *npyv__ptr2u64(const void *ptr)
+ { npy_uint64 *ptr64 = (npy_uint64*)ptr; return ptr64; }
+#endif // __cplusplus
+
+// load lower part
+NPY_FINLINE npyv_u64 npyv__loadl(const void *ptr)
+{
+ #if defined(__clang__) && !defined(__IBMC__)
+ // vec_promote doesn't support doubleword on clang
+ return npyv_setall_u64(*npyv__ptr2u64(ptr));
+ #else
+ return vec_promote(*npyv__ptr2u64(ptr), 0);
+ #endif
+}
+// store lower part
+#define npyv__storel(PTR, VEC) \
+ *npyv__ptr2u64(PTR) = vec_extract(((npyv_u64)VEC), 0)
+
+#define npyv__storeh(PTR, VEC) \
+ *npyv__ptr2u64(PTR) = vec_extract(((npyv_u64)VEC), 1)
+
+/****************************
+ * load/store
+ ****************************/
+#define NPYV_IMPL_VSX_MEM(SFX, DW_CAST) \
+ NPY_FINLINE npyv_##SFX npyv_load_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { return (npyv_##SFX)npyv__load(npyv_##SFX, (const npyv_lanetype_##DW_CAST*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loada_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { return (npyv_##SFX)vec_ld(0, (const npyv_lanetype_u32*)ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loads_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { return npyv_loada_##SFX(ptr); } \
+ NPY_FINLINE npyv_##SFX npyv_loadl_##SFX(const npyv_lanetype_##SFX *ptr) \
+ { return (npyv_##SFX)npyv__loadl(ptr); } \
+ NPY_FINLINE void npyv_store_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { npyv__store((npyv_lanetype_##DW_CAST*)ptr, (npyv_##DW_CAST)vec); } \
+ NPY_FINLINE void npyv_storea_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { vec_st((npyv_u32)vec, 0, (npyv_lanetype_u32*)ptr); } \
+ NPY_FINLINE void npyv_stores_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { npyv_storea_##SFX(ptr, vec); } \
+ NPY_FINLINE void npyv_storel_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { npyv__storel(ptr, vec); } \
+ NPY_FINLINE void npyv_storeh_##SFX(npyv_lanetype_##SFX *ptr, npyv_##SFX vec) \
+ { npyv__storeh(ptr, vec); }
+
+NPYV_IMPL_VSX_MEM(u8, u8)
+NPYV_IMPL_VSX_MEM(s8, s8)
+NPYV_IMPL_VSX_MEM(u16, u16)
+NPYV_IMPL_VSX_MEM(s16, s16)
+NPYV_IMPL_VSX_MEM(u32, u32)
+NPYV_IMPL_VSX_MEM(s32, s32)
+NPYV_IMPL_VSX_MEM(u64, f64)
+NPYV_IMPL_VSX_MEM(s64, f64)
+NPYV_IMPL_VSX_MEM(f32, f32)
+NPYV_IMPL_VSX_MEM(f64, f64)
+
+/***************************
+ * Non-contiguous Load
+ ***************************/
+//// 32
+NPY_FINLINE npyv_u32 npyv_loadn_u32(const npy_uint32 *ptr, npy_intp stride)
+{
+ return npyv_set_u32(
+ ptr[stride * 0], ptr[stride * 1],
+ ptr[stride * 2], ptr[stride * 3]
+ );
+}
+NPY_FINLINE npyv_s32 npyv_loadn_s32(const npy_int32 *ptr, npy_intp stride)
+{ return (npyv_s32)npyv_loadn_u32((const npy_uint32*)ptr, stride); }
+NPY_FINLINE npyv_f32 npyv_loadn_f32(const float *ptr, npy_intp stride)
+{ return (npyv_f32)npyv_loadn_u32((const npy_uint32*)ptr, stride); }
+//// 64
+NPY_FINLINE npyv_u64 npyv_loadn_u64(const npy_uint64 *ptr, npy_intp stride)
+{ return npyv_set_u64(ptr[0], ptr[stride]); }
+NPY_FINLINE npyv_s64 npyv_loadn_s64(const npy_int64 *ptr, npy_intp stride)
+{ return npyv_set_s64(ptr[0], ptr[stride]); }
+NPY_FINLINE npyv_f64 npyv_loadn_f64(const double *ptr, npy_intp stride)
+{ return npyv_set_f64(ptr[0], ptr[stride]); }
+/***************************
+ * Non-contiguous Store
+ ***************************/
+//// 32
+NPY_FINLINE void npyv_storen_u32(npy_uint32 *ptr, npy_intp stride, npyv_u32 a)
+{
+ ptr[stride * 0] = vec_extract(a, 0);
+ ptr[stride * 1] = vec_extract(a, 1);
+ ptr[stride * 2] = vec_extract(a, 2);
+ ptr[stride * 3] = vec_extract(a, 3);
+}
+NPY_FINLINE void npyv_storen_s32(npy_int32 *ptr, npy_intp stride, npyv_s32 a)
+{ npyv_storen_u32((npy_uint32*)ptr, stride, (npyv_u32)a); }
+NPY_FINLINE void npyv_storen_f32(float *ptr, npy_intp stride, npyv_f32 a)
+{ npyv_storen_u32((npy_uint32*)ptr, stride, (npyv_u32)a); }
+//// 64
+NPY_FINLINE void npyv_storen_u64(npy_uint64 *ptr, npy_intp stride, npyv_u64 a)
+{
+ ptr[stride * 0] = vec_extract(a, 0);
+ ptr[stride * 1] = vec_extract(a, 1);
+}
+NPY_FINLINE void npyv_storen_s64(npy_int64 *ptr, npy_intp stride, npyv_s64 a)
+{ npyv_storen_u64((npy_uint64*)ptr, stride, (npyv_u64)a); }
+NPY_FINLINE void npyv_storen_f64(double *ptr, npy_intp stride, npyv_f64 a)
+{ npyv_storen_u64((npy_uint64*)ptr, stride, (npyv_u64)a); }
+
+/*********************************
+ * Partial Load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32 npyv_load_till_s32(const npy_int32 *ptr, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ npyv_s32 vfill = npyv_setall_s32(fill);
+ switch(nlane) {
+ case 1:
+ return vec_insert(ptr[0], vfill, 0);
+ case 2:
+ return (npyv_s32)vec_insert(
+ *npyv__ptr2u64(ptr), (npyv_u64)vfill, 0
+ );
+ case 3:
+ vfill = vec_insert(ptr[2], vfill, 2);
+ return (npyv_s32)vec_insert(
+ *npyv__ptr2u64(ptr), (npyv_u64)vfill, 0
+ );
+ default:
+ return npyv_load_s32(ptr);
+ }
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32 npyv_load_tillz_s32(const npy_int32 *ptr, npy_uintp nlane)
+{ return npyv_load_till_s32(ptr, nlane, 0); }
+//// 64
+NPY_FINLINE npyv_s64 npyv_load_till_s64(const npy_int64 *ptr, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ return npyv_set_s64(ptr[0], fill);
+ }
+ return npyv_load_s64(ptr);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_load_tillz_s64(const npy_int64 *ptr, npy_uintp nlane)
+{ return npyv_load_till_s64(ptr, nlane, 0); }
+/*********************************
+ * Non-contiguous partial load
+ *********************************/
+//// 32
+NPY_FINLINE npyv_s32
+npyv_loadn_till_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npy_int32 fill)
+{
+ assert(nlane > 0);
+ npyv_s32 vfill = npyv_setall_s32(fill);
+ switch(nlane) {
+ case 3:
+ vfill = vec_insert(ptr[stride*2], vfill, 2);
+ case 2:
+ vfill = vec_insert(ptr[stride], vfill, 1);
+ case 1:
+ vfill = vec_insert(*ptr, vfill, 0);
+ break;
+ default:
+ return npyv_loadn_s32(ptr, stride);
+ } // switch
+ return vfill;
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s32
+npyv_loadn_tillz_s32(const npy_int32 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s32(ptr, stride, nlane, 0); }
+//// 64
+NPY_FINLINE npyv_s64
+npyv_loadn_till_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npy_int64 fill)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ return npyv_set_s64(*ptr, fill);
+ }
+ return npyv_loadn_s64(ptr, stride);
+}
+// fill zero to rest lanes
+NPY_FINLINE npyv_s64 npyv_loadn_tillz_s64(const npy_int64 *ptr, npy_intp stride, npy_uintp nlane)
+{ return npyv_loadn_till_s64(ptr, stride, nlane, 0); }
+/*********************************
+ * Partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_store_till_s32(npy_int32 *ptr, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ case 1:
+ *ptr = vec_extract(a, 0);
+ break;
+ case 2:
+ npyv_storel_s32(ptr, a);
+ break;
+ case 3:
+ npyv_storel_s32(ptr, a);
+ ptr[2] = vec_extract(a, 2);
+ break;
+ default:
+ npyv_store_s32(ptr, a);
+ }
+}
+//// 64
+NPY_FINLINE void npyv_store_till_s64(npy_int64 *ptr, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ npyv_storel_s64(ptr, a);
+ return;
+ }
+ npyv_store_s64(ptr, a);
+}
+/*********************************
+ * Non-contiguous partial store
+ *********************************/
+//// 32
+NPY_FINLINE void npyv_storen_till_s32(npy_int32 *ptr, npy_intp stride, npy_uintp nlane, npyv_s32 a)
+{
+ assert(nlane > 0);
+ switch(nlane) {
+ default:
+ ptr[stride*3] = vec_extract(a, 3);
+ case 3:
+ ptr[stride*2] = vec_extract(a, 2);
+ case 2:
+ ptr[stride*1] = vec_extract(a, 1);
+ case 1:
+ ptr[stride*0] = vec_extract(a, 0);
+ break;
+ }
+}
+//// 64
+NPY_FINLINE void npyv_storen_till_s64(npy_int64 *ptr, npy_intp stride, npy_uintp nlane, npyv_s64 a)
+{
+ assert(nlane > 0);
+ if (nlane == 1) {
+ npyv_storel_s64(ptr, a);
+ return;
+ }
+ npyv_storen_s64(ptr, stride, a);
+}
+/*****************************************************************
+ * Implement partial load/store for u32/f32/u64/f64... via casting
+ *****************************************************************/
+#define NPYV_IMPL_VSX_REST_PARTIAL_TYPES(F_SFX, T_SFX) \
+ NPY_FINLINE npyv_##F_SFX npyv_load_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_till_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, \
+ npyv_lanetype_##F_SFX fill) \
+ { \
+ union { \
+ npyv_lanetype_##F_SFX from_##F_SFX; \
+ npyv_lanetype_##T_SFX to_##T_SFX; \
+ } pun = {.from_##F_SFX = fill}; \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_till_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane, pun.to_##T_SFX \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_load_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_load_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, nlane \
+ )); \
+ } \
+ NPY_FINLINE npyv_##F_SFX npyv_loadn_tillz_##F_SFX \
+ (const npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane) \
+ { \
+ return npyv_reinterpret_##F_SFX##_##T_SFX(npyv_loadn_tillz_##T_SFX( \
+ (const npyv_lanetype_##T_SFX *)ptr, stride, nlane \
+ )); \
+ } \
+ NPY_FINLINE void npyv_store_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_store_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ } \
+ NPY_FINLINE void npyv_storen_till_##F_SFX \
+ (npyv_lanetype_##F_SFX *ptr, npy_intp stride, npy_uintp nlane, npyv_##F_SFX a) \
+ { \
+ npyv_storen_till_##T_SFX( \
+ (npyv_lanetype_##T_SFX *)ptr, stride, nlane, \
+ npyv_reinterpret_##T_SFX##_##F_SFX(a) \
+ ); \
+ }
+
+NPYV_IMPL_VSX_REST_PARTIAL_TYPES(u32, s32)
+NPYV_IMPL_VSX_REST_PARTIAL_TYPES(f32, s32)
+NPYV_IMPL_VSX_REST_PARTIAL_TYPES(u64, s64)
+NPYV_IMPL_VSX_REST_PARTIAL_TYPES(f64, s64)
+
+#endif // _NPY_SIMD_VSX_MEMORY_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_VSX_MISC_H
+#define _NPY_SIMD_VSX_MISC_H
+
+// vector with zero lanes
+#define npyv_zero_u8() ((npyv_u8) npyv_setall_s32(0))
+#define npyv_zero_s8() ((npyv_s8) npyv_setall_s32(0))
+#define npyv_zero_u16() ((npyv_u16) npyv_setall_s32(0))
+#define npyv_zero_s16() ((npyv_s16) npyv_setall_s32(0))
+#define npyv_zero_u32() npyv_setall_u32(0)
+#define npyv_zero_s32() npyv_setall_s32(0)
+#define npyv_zero_u64() ((npyv_u64) npyv_setall_s32(0))
+#define npyv_zero_s64() ((npyv_s64) npyv_setall_s32(0))
+#define npyv_zero_f32() npyv_setall_f32(0.0f)
+#define npyv_zero_f64() npyv_setall_f64(0.0)
+
+// vector with a specific value set to all lanes
+// the safest way to generate vsplti* and vsplt* instructions
+#define NPYV_IMPL_VSX_SPLTB(T_VEC, V) ((T_VEC){V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V})
+#define NPYV_IMPL_VSX_SPLTH(T_VEC, V) ((T_VEC){V, V, V, V, V, V, V, V})
+#define NPYV_IMPL_VSX_SPLTW(T_VEC, V) ((T_VEC){V, V, V, V})
+#define NPYV_IMPL_VSX_SPLTD(T_VEC, V) ((T_VEC){V, V})
+
+#define npyv_setall_u8(VAL) NPYV_IMPL_VSX_SPLTB(npyv_u8, (unsigned char)VAL)
+#define npyv_setall_s8(VAL) NPYV_IMPL_VSX_SPLTB(npyv_s8, (signed char)VAL)
+#define npyv_setall_u16(VAL) NPYV_IMPL_VSX_SPLTH(npyv_u16, (unsigned short)VAL)
+#define npyv_setall_s16(VAL) NPYV_IMPL_VSX_SPLTH(npyv_s16, (short)VAL)
+#define npyv_setall_u32(VAL) NPYV_IMPL_VSX_SPLTW(npyv_u32, (unsigned int)VAL)
+#define npyv_setall_s32(VAL) NPYV_IMPL_VSX_SPLTW(npyv_s32, (int)VAL)
+#define npyv_setall_f32(VAL) NPYV_IMPL_VSX_SPLTW(npyv_f32, VAL)
+#define npyv_setall_u64(VAL) NPYV_IMPL_VSX_SPLTD(npyv_u64, (npy_uint64)VAL)
+#define npyv_setall_s64(VAL) NPYV_IMPL_VSX_SPLTD(npyv_s64, (npy_int64)VAL)
+#define npyv_setall_f64(VAL) NPYV_IMPL_VSX_SPLTD(npyv_f64, VAL)
+
+// vector with specific values set to each lane and
+// set a specific value to all remained lanes
+#define npyv_setf_u8(FILL, ...) ((npyv_u8){NPYV__SET_FILL_16(char, FILL, __VA_ARGS__)})
+#define npyv_setf_s8(FILL, ...) ((npyv_s8){NPYV__SET_FILL_16(char, FILL, __VA_ARGS__)})
+#define npyv_setf_u16(FILL, ...) ((npyv_u16){NPYV__SET_FILL_8(short, FILL, __VA_ARGS__)})
+#define npyv_setf_s16(FILL, ...) ((npyv_s16){NPYV__SET_FILL_8(short, FILL, __VA_ARGS__)})
+#define npyv_setf_u32(FILL, ...) ((npyv_u32){NPYV__SET_FILL_4(int, FILL, __VA_ARGS__)})
+#define npyv_setf_s32(FILL, ...) ((npyv_s32){NPYV__SET_FILL_4(int, FILL, __VA_ARGS__)})
+#define npyv_setf_u64(FILL, ...) ((npyv_u64){NPYV__SET_FILL_2(npy_int64, FILL, __VA_ARGS__)})
+#define npyv_setf_s64(FILL, ...) ((npyv_s64){NPYV__SET_FILL_2(npy_int64, FILL, __VA_ARGS__)})
+#define npyv_setf_f32(FILL, ...) ((npyv_f32){NPYV__SET_FILL_4(float, FILL, __VA_ARGS__)})
+#define npyv_setf_f64(FILL, ...) ((npyv_f64){NPYV__SET_FILL_2(double, FILL, __VA_ARGS__)})
+
+// vector with specific values set to each lane and
+// set zero to all remained lanes
+#define npyv_set_u8(...) npyv_setf_u8(0, __VA_ARGS__)
+#define npyv_set_s8(...) npyv_setf_s8(0, __VA_ARGS__)
+#define npyv_set_u16(...) npyv_setf_u16(0, __VA_ARGS__)
+#define npyv_set_s16(...) npyv_setf_s16(0, __VA_ARGS__)
+#define npyv_set_u32(...) npyv_setf_u32(0, __VA_ARGS__)
+#define npyv_set_s32(...) npyv_setf_s32(0, __VA_ARGS__)
+#define npyv_set_u64(...) npyv_setf_u64(0, __VA_ARGS__)
+#define npyv_set_s64(...) npyv_setf_s64(0, __VA_ARGS__)
+#define npyv_set_f32(...) npyv_setf_f32(0, __VA_ARGS__)
+#define npyv_set_f64(...) npyv_setf_f64(0, __VA_ARGS__)
+
+// Per lane select
+#define npyv_select_u8(MASK, A, B) vec_sel(B, A, MASK)
+#define npyv_select_s8 npyv_select_u8
+#define npyv_select_u16 npyv_select_u8
+#define npyv_select_s16 npyv_select_u8
+#define npyv_select_u32 npyv_select_u8
+#define npyv_select_s32 npyv_select_u8
+#define npyv_select_u64 npyv_select_u8
+#define npyv_select_s64 npyv_select_u8
+#define npyv_select_f32 npyv_select_u8
+#define npyv_select_f64 npyv_select_u8
+
+// Reinterpret
+#define npyv_reinterpret_u8_u8(X) X
+#define npyv_reinterpret_u8_s8(X) ((npyv_u8)X)
+#define npyv_reinterpret_u8_u16 npyv_reinterpret_u8_s8
+#define npyv_reinterpret_u8_s16 npyv_reinterpret_u8_s8
+#define npyv_reinterpret_u8_u32 npyv_reinterpret_u8_s8
+#define npyv_reinterpret_u8_s32 npyv_reinterpret_u8_s8
+#define npyv_reinterpret_u8_u64 npyv_reinterpret_u8_s8
+#define npyv_reinterpret_u8_s64 npyv_reinterpret_u8_s8
+#define npyv_reinterpret_u8_f32 npyv_reinterpret_u8_s8
+#define npyv_reinterpret_u8_f64 npyv_reinterpret_u8_s8
+
+#define npyv_reinterpret_s8_s8(X) X
+#define npyv_reinterpret_s8_u8(X) ((npyv_s8)X)
+#define npyv_reinterpret_s8_u16 npyv_reinterpret_s8_u8
+#define npyv_reinterpret_s8_s16 npyv_reinterpret_s8_u8
+#define npyv_reinterpret_s8_u32 npyv_reinterpret_s8_u8
+#define npyv_reinterpret_s8_s32 npyv_reinterpret_s8_u8
+#define npyv_reinterpret_s8_u64 npyv_reinterpret_s8_u8
+#define npyv_reinterpret_s8_s64 npyv_reinterpret_s8_u8
+#define npyv_reinterpret_s8_f32 npyv_reinterpret_s8_u8
+#define npyv_reinterpret_s8_f64 npyv_reinterpret_s8_u8
+
+#define npyv_reinterpret_u16_u16(X) X
+#define npyv_reinterpret_u16_u8(X) ((npyv_u16)X)
+#define npyv_reinterpret_u16_s8 npyv_reinterpret_u16_u8
+#define npyv_reinterpret_u16_s16 npyv_reinterpret_u16_u8
+#define npyv_reinterpret_u16_u32 npyv_reinterpret_u16_u8
+#define npyv_reinterpret_u16_s32 npyv_reinterpret_u16_u8
+#define npyv_reinterpret_u16_u64 npyv_reinterpret_u16_u8
+#define npyv_reinterpret_u16_s64 npyv_reinterpret_u16_u8
+#define npyv_reinterpret_u16_f32 npyv_reinterpret_u16_u8
+#define npyv_reinterpret_u16_f64 npyv_reinterpret_u16_u8
+
+#define npyv_reinterpret_s16_s16(X) X
+#define npyv_reinterpret_s16_u8(X) ((npyv_s16)X)
+#define npyv_reinterpret_s16_s8 npyv_reinterpret_s16_u8
+#define npyv_reinterpret_s16_u16 npyv_reinterpret_s16_u8
+#define npyv_reinterpret_s16_u32 npyv_reinterpret_s16_u8
+#define npyv_reinterpret_s16_s32 npyv_reinterpret_s16_u8
+#define npyv_reinterpret_s16_u64 npyv_reinterpret_s16_u8
+#define npyv_reinterpret_s16_s64 npyv_reinterpret_s16_u8
+#define npyv_reinterpret_s16_f32 npyv_reinterpret_s16_u8
+#define npyv_reinterpret_s16_f64 npyv_reinterpret_s16_u8
+
+#define npyv_reinterpret_u32_u32(X) X
+#define npyv_reinterpret_u32_u8(X) ((npyv_u32)X)
+#define npyv_reinterpret_u32_s8 npyv_reinterpret_u32_u8
+#define npyv_reinterpret_u32_u16 npyv_reinterpret_u32_u8
+#define npyv_reinterpret_u32_s16 npyv_reinterpret_u32_u8
+#define npyv_reinterpret_u32_s32 npyv_reinterpret_u32_u8
+#define npyv_reinterpret_u32_u64 npyv_reinterpret_u32_u8
+#define npyv_reinterpret_u32_s64 npyv_reinterpret_u32_u8
+#define npyv_reinterpret_u32_f32 npyv_reinterpret_u32_u8
+#define npyv_reinterpret_u32_f64 npyv_reinterpret_u32_u8
+
+#define npyv_reinterpret_s32_s32(X) X
+#define npyv_reinterpret_s32_u8(X) ((npyv_s32)X)
+#define npyv_reinterpret_s32_s8 npyv_reinterpret_s32_u8
+#define npyv_reinterpret_s32_u16 npyv_reinterpret_s32_u8
+#define npyv_reinterpret_s32_s16 npyv_reinterpret_s32_u8
+#define npyv_reinterpret_s32_u32 npyv_reinterpret_s32_u8
+#define npyv_reinterpret_s32_u64 npyv_reinterpret_s32_u8
+#define npyv_reinterpret_s32_s64 npyv_reinterpret_s32_u8
+#define npyv_reinterpret_s32_f32 npyv_reinterpret_s32_u8
+#define npyv_reinterpret_s32_f64 npyv_reinterpret_s32_u8
+
+#define npyv_reinterpret_u64_u64(X) X
+#define npyv_reinterpret_u64_u8(X) ((npyv_u64)X)
+#define npyv_reinterpret_u64_s8 npyv_reinterpret_u64_u8
+#define npyv_reinterpret_u64_u16 npyv_reinterpret_u64_u8
+#define npyv_reinterpret_u64_s16 npyv_reinterpret_u64_u8
+#define npyv_reinterpret_u64_u32 npyv_reinterpret_u64_u8
+#define npyv_reinterpret_u64_s32 npyv_reinterpret_u64_u8
+#define npyv_reinterpret_u64_s64 npyv_reinterpret_u64_u8
+#define npyv_reinterpret_u64_f32 npyv_reinterpret_u64_u8
+#define npyv_reinterpret_u64_f64 npyv_reinterpret_u64_u8
+
+#define npyv_reinterpret_s64_s64(X) X
+#define npyv_reinterpret_s64_u8(X) ((npyv_s64)X)
+#define npyv_reinterpret_s64_s8 npyv_reinterpret_s64_u8
+#define npyv_reinterpret_s64_u16 npyv_reinterpret_s64_u8
+#define npyv_reinterpret_s64_s16 npyv_reinterpret_s64_u8
+#define npyv_reinterpret_s64_u32 npyv_reinterpret_s64_u8
+#define npyv_reinterpret_s64_s32 npyv_reinterpret_s64_u8
+#define npyv_reinterpret_s64_u64 npyv_reinterpret_s64_u8
+#define npyv_reinterpret_s64_f32 npyv_reinterpret_s64_u8
+#define npyv_reinterpret_s64_f64 npyv_reinterpret_s64_u8
+
+#define npyv_reinterpret_f32_f32(X) X
+#define npyv_reinterpret_f32_u8(X) ((npyv_f32)X)
+#define npyv_reinterpret_f32_s8 npyv_reinterpret_f32_u8
+#define npyv_reinterpret_f32_u16 npyv_reinterpret_f32_u8
+#define npyv_reinterpret_f32_s16 npyv_reinterpret_f32_u8
+#define npyv_reinterpret_f32_u32 npyv_reinterpret_f32_u8
+#define npyv_reinterpret_f32_s32 npyv_reinterpret_f32_u8
+#define npyv_reinterpret_f32_u64 npyv_reinterpret_f32_u8
+#define npyv_reinterpret_f32_s64 npyv_reinterpret_f32_u8
+#define npyv_reinterpret_f32_f64 npyv_reinterpret_f32_u8
+
+#define npyv_reinterpret_f64_f64(X) X
+#define npyv_reinterpret_f64_u8(X) ((npyv_f64)X)
+#define npyv_reinterpret_f64_s8 npyv_reinterpret_f64_u8
+#define npyv_reinterpret_f64_u16 npyv_reinterpret_f64_u8
+#define npyv_reinterpret_f64_s16 npyv_reinterpret_f64_u8
+#define npyv_reinterpret_f64_u32 npyv_reinterpret_f64_u8
+#define npyv_reinterpret_f64_s32 npyv_reinterpret_f64_u8
+#define npyv_reinterpret_f64_u64 npyv_reinterpret_f64_u8
+#define npyv_reinterpret_f64_s64 npyv_reinterpret_f64_u8
+#define npyv_reinterpret_f64_f32 npyv_reinterpret_f64_u8
+
+// Only required by AVX2/AVX512
+#define npyv_cleanup() ((void)0)
+
+#endif // _NPY_SIMD_VSX_MISC_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_VSX_OPERATORS_H
+#define _NPY_SIMD_VSX_OPERATORS_H
+
+/***************************
+ * Shifting
+ ***************************/
+
+// Left
+#define npyv_shl_u16(A, C) vec_sl(A, npyv_setall_u16(C))
+#define npyv_shl_s16(A, C) vec_sl(A, npyv_setall_u16(C))
+#define npyv_shl_u32(A, C) vec_sl(A, npyv_setall_u32(C))
+#define npyv_shl_s32(A, C) vec_sl(A, npyv_setall_u32(C))
+#define npyv_shl_u64(A, C) vec_sl(A, npyv_setall_u64(C))
+#define npyv_shl_s64(A, C) vec_sl(A, npyv_setall_u64(C))
+
+// Left by an immediate constant
+#define npyv_shli_u16 npyv_shl_u16
+#define npyv_shli_s16 npyv_shl_s16
+#define npyv_shli_u32 npyv_shl_u32
+#define npyv_shli_s32 npyv_shl_s32
+#define npyv_shli_u64 npyv_shl_u64
+#define npyv_shli_s64 npyv_shl_s64
+
+// Right
+#define npyv_shr_u16(A, C) vec_sr(A, npyv_setall_u16(C))
+#define npyv_shr_s16(A, C) vec_sra(A, npyv_setall_u16(C))
+#define npyv_shr_u32(A, C) vec_sr(A, npyv_setall_u32(C))
+#define npyv_shr_s32(A, C) vec_sra(A, npyv_setall_u32(C))
+#define npyv_shr_u64(A, C) vec_sr(A, npyv_setall_u64(C))
+#define npyv_shr_s64(A, C) vec_sra(A, npyv_setall_u64(C))
+
+// Right by an immediate constant
+#define npyv_shri_u16 npyv_shr_u16
+#define npyv_shri_s16 npyv_shr_s16
+#define npyv_shri_u32 npyv_shr_u32
+#define npyv_shri_s32 npyv_shr_s32
+#define npyv_shri_u64 npyv_shr_u64
+#define npyv_shri_s64 npyv_shr_s64
+
+/***************************
+ * Logical
+ ***************************/
+
+// AND
+#define npyv_and_u8 vec_and
+#define npyv_and_s8 vec_and
+#define npyv_and_u16 vec_and
+#define npyv_and_s16 vec_and
+#define npyv_and_u32 vec_and
+#define npyv_and_s32 vec_and
+#define npyv_and_u64 vec_and
+#define npyv_and_s64 vec_and
+#define npyv_and_f32 vec_and
+#define npyv_and_f64 vec_and
+
+// OR
+#define npyv_or_u8 vec_or
+#define npyv_or_s8 vec_or
+#define npyv_or_u16 vec_or
+#define npyv_or_s16 vec_or
+#define npyv_or_u32 vec_or
+#define npyv_or_s32 vec_or
+#define npyv_or_u64 vec_or
+#define npyv_or_s64 vec_or
+#define npyv_or_f32 vec_or
+#define npyv_or_f64 vec_or
+
+// XOR
+#define npyv_xor_u8 vec_xor
+#define npyv_xor_s8 vec_xor
+#define npyv_xor_u16 vec_xor
+#define npyv_xor_s16 vec_xor
+#define npyv_xor_u32 vec_xor
+#define npyv_xor_s32 vec_xor
+#define npyv_xor_u64 vec_xor
+#define npyv_xor_s64 vec_xor
+#define npyv_xor_f32 vec_xor
+#define npyv_xor_f64 vec_xor
+
+// NOT
+// note: we implement npyv_not_b*(boolen types) for internal use*/
+#define NPYV_IMPL_VSX_NOT_INT(VEC_LEN) \
+ NPY_FINLINE npyv_u##VEC_LEN npyv_not_u##VEC_LEN(npyv_u##VEC_LEN a) \
+ { return vec_nor(a, a); } \
+ NPY_FINLINE npyv_s##VEC_LEN npyv_not_s##VEC_LEN(npyv_s##VEC_LEN a) \
+ { return vec_nor(a, a); } \
+ NPY_FINLINE npyv_b##VEC_LEN npyv_not_b##VEC_LEN(npyv_b##VEC_LEN a) \
+ { return vec_nor(a, a); }
+
+NPYV_IMPL_VSX_NOT_INT(8)
+NPYV_IMPL_VSX_NOT_INT(16)
+NPYV_IMPL_VSX_NOT_INT(32)
+
+// up to gcc5 vec_nor doesn't support bool long long
+#if defined(__GNUC__) && __GNUC__ > 5
+ NPYV_IMPL_VSX_NOT_INT(64)
+#else
+ NPY_FINLINE npyv_u64 npyv_not_u64(npyv_u64 a)
+ { return vec_nor(a, a); }
+ NPY_FINLINE npyv_s64 npyv_not_s64(npyv_s64 a)
+ { return vec_nor(a, a); }
+ NPY_FINLINE npyv_b64 npyv_not_b64(npyv_b64 a)
+ { return (npyv_b64)vec_nor((npyv_u64)a, (npyv_u64)a); }
+#endif
+
+NPY_FINLINE npyv_f32 npyv_not_f32(npyv_f32 a)
+{ return vec_nor(a, a); }
+NPY_FINLINE npyv_f64 npyv_not_f64(npyv_f64 a)
+{ return vec_nor(a, a); }
+
+/***************************
+ * Comparison
+ ***************************/
+
+// Int Equal
+#define npyv_cmpeq_u8 vec_cmpeq
+#define npyv_cmpeq_s8 vec_cmpeq
+#define npyv_cmpeq_u16 vec_cmpeq
+#define npyv_cmpeq_s16 vec_cmpeq
+#define npyv_cmpeq_u32 vec_cmpeq
+#define npyv_cmpeq_s32 vec_cmpeq
+#define npyv_cmpeq_u64 vec_cmpeq
+#define npyv_cmpeq_s64 vec_cmpeq
+#define npyv_cmpeq_f32 vec_cmpeq
+#define npyv_cmpeq_f64 vec_cmpeq
+
+// Int Not Equal
+#ifdef NPY_HAVE_VSX3
+ #define npyv_cmpneq_u8 vec_cmpne
+ #define npyv_cmpneq_s8 vec_cmpne
+ #define npyv_cmpneq_u16 vec_cmpne
+ #define npyv_cmpneq_s16 vec_cmpne
+ #define npyv_cmpneq_u32 vec_cmpne
+ #define npyv_cmpneq_s32 vec_cmpne
+ #define npyv_cmpneq_u64 vec_cmpne
+ #define npyv_cmpneq_s64 vec_cmpne
+ #define npyv_cmpneq_f32 vec_cmpne
+ #define npyv_cmpneq_f64 vec_cmpne
+#else
+ #define npyv_cmpneq_u8(A, B) npyv_not_b8(vec_cmpeq(A, B))
+ #define npyv_cmpneq_s8(A, B) npyv_not_b8(vec_cmpeq(A, B))
+ #define npyv_cmpneq_u16(A, B) npyv_not_b16(vec_cmpeq(A, B))
+ #define npyv_cmpneq_s16(A, B) npyv_not_b16(vec_cmpeq(A, B))
+ #define npyv_cmpneq_u32(A, B) npyv_not_b32(vec_cmpeq(A, B))
+ #define npyv_cmpneq_s32(A, B) npyv_not_b32(vec_cmpeq(A, B))
+ #define npyv_cmpneq_u64(A, B) npyv_not_b64(vec_cmpeq(A, B))
+ #define npyv_cmpneq_s64(A, B) npyv_not_b64(vec_cmpeq(A, B))
+ #define npyv_cmpneq_f32(A, B) npyv_not_b32(vec_cmpeq(A, B))
+ #define npyv_cmpneq_f64(A, B) npyv_not_b64(vec_cmpeq(A, B))
+#endif
+
+// Greater than
+#define npyv_cmpgt_u8 vec_cmpgt
+#define npyv_cmpgt_s8 vec_cmpgt
+#define npyv_cmpgt_u16 vec_cmpgt
+#define npyv_cmpgt_s16 vec_cmpgt
+#define npyv_cmpgt_u32 vec_cmpgt
+#define npyv_cmpgt_s32 vec_cmpgt
+#define npyv_cmpgt_u64 vec_cmpgt
+#define npyv_cmpgt_s64 vec_cmpgt
+#define npyv_cmpgt_f32 vec_cmpgt
+#define npyv_cmpgt_f64 vec_cmpgt
+
+// Greater than or equal
+// up to gcc5 vec_cmpge only supports single and double precision
+#if defined(__GNUC__) && __GNUC__ > 5
+ #define npyv_cmpge_u8 vec_cmpge
+ #define npyv_cmpge_s8 vec_cmpge
+ #define npyv_cmpge_u16 vec_cmpge
+ #define npyv_cmpge_s16 vec_cmpge
+ #define npyv_cmpge_u32 vec_cmpge
+ #define npyv_cmpge_s32 vec_cmpge
+ #define npyv_cmpge_u64 vec_cmpge
+ #define npyv_cmpge_s64 vec_cmpge
+#else
+ #define npyv_cmpge_u8(A, B) npyv_not_b8(vec_cmpgt(B, A))
+ #define npyv_cmpge_s8(A, B) npyv_not_b8(vec_cmpgt(B, A))
+ #define npyv_cmpge_u16(A, B) npyv_not_b16(vec_cmpgt(B, A))
+ #define npyv_cmpge_s16(A, B) npyv_not_b16(vec_cmpgt(B, A))
+ #define npyv_cmpge_u32(A, B) npyv_not_b32(vec_cmpgt(B, A))
+ #define npyv_cmpge_s32(A, B) npyv_not_b32(vec_cmpgt(B, A))
+ #define npyv_cmpge_u64(A, B) npyv_not_b64(vec_cmpgt(B, A))
+ #define npyv_cmpge_s64(A, B) npyv_not_b64(vec_cmpgt(B, A))
+#endif
+#define npyv_cmpge_f32 vec_cmpge
+#define npyv_cmpge_f64 vec_cmpge
+
+// Less than
+#define npyv_cmplt_u8(A, B) npyv_cmpgt_u8(B, A)
+#define npyv_cmplt_s8(A, B) npyv_cmpgt_s8(B, A)
+#define npyv_cmplt_u16(A, B) npyv_cmpgt_u16(B, A)
+#define npyv_cmplt_s16(A, B) npyv_cmpgt_s16(B, A)
+#define npyv_cmplt_u32(A, B) npyv_cmpgt_u32(B, A)
+#define npyv_cmplt_s32(A, B) npyv_cmpgt_s32(B, A)
+#define npyv_cmplt_u64(A, B) npyv_cmpgt_u64(B, A)
+#define npyv_cmplt_s64(A, B) npyv_cmpgt_s64(B, A)
+#define npyv_cmplt_f32(A, B) npyv_cmpgt_f32(B, A)
+#define npyv_cmplt_f64(A, B) npyv_cmpgt_f64(B, A)
+
+// Less than or equal
+#define npyv_cmple_u8(A, B) npyv_cmpge_u8(B, A)
+#define npyv_cmple_s8(A, B) npyv_cmpge_s8(B, A)
+#define npyv_cmple_u16(A, B) npyv_cmpge_u16(B, A)
+#define npyv_cmple_s16(A, B) npyv_cmpge_s16(B, A)
+#define npyv_cmple_u32(A, B) npyv_cmpge_u32(B, A)
+#define npyv_cmple_s32(A, B) npyv_cmpge_s32(B, A)
+#define npyv_cmple_u64(A, B) npyv_cmpge_u64(B, A)
+#define npyv_cmple_s64(A, B) npyv_cmpge_s64(B, A)
+#define npyv_cmple_f32(A, B) npyv_cmpge_f32(B, A)
+#define npyv_cmple_f64(A, B) npyv_cmpge_f64(B, A)
+
+#endif // _NPY_SIMD_VSX_OPERATORS_H
--- /dev/null
+#ifndef NPY_SIMD
+ #error "Not a standalone header"
+#endif
+
+#ifndef _NPY_SIMD_VSX_REORDER_H
+#define _NPY_SIMD_VSX_REORDER_H
+
+// combine lower part of two vectors
+#define npyv__combinel(A, B) vec_mergeh((npyv_u64)(A), (npyv_u64)(B))
+#define npyv_combinel_u8(A, B) ((npyv_u8) npyv__combinel(A, B))
+#define npyv_combinel_s8(A, B) ((npyv_s8) npyv__combinel(A, B))
+#define npyv_combinel_u16(A, B) ((npyv_u16)npyv__combinel(A, B))
+#define npyv_combinel_s16(A, B) ((npyv_s16)npyv__combinel(A, B))
+#define npyv_combinel_u32(A, B) ((npyv_u32)npyv__combinel(A, B))
+#define npyv_combinel_s32(A, B) ((npyv_s32)npyv__combinel(A, B))
+#define npyv_combinel_u64 vec_mergeh
+#define npyv_combinel_s64 vec_mergeh
+#define npyv_combinel_f32(A, B) ((npyv_f32)npyv__combinel(A, B))
+#define npyv_combinel_f64 vec_mergeh
+
+// combine higher part of two vectors
+#define npyv__combineh(A, B) vec_mergel((npyv_u64)(A), (npyv_u64)(B))
+#define npyv_combineh_u8(A, B) ((npyv_u8) npyv__combineh(A, B))
+#define npyv_combineh_s8(A, B) ((npyv_s8) npyv__combineh(A, B))
+#define npyv_combineh_u16(A, B) ((npyv_u16)npyv__combineh(A, B))
+#define npyv_combineh_s16(A, B) ((npyv_s16)npyv__combineh(A, B))
+#define npyv_combineh_u32(A, B) ((npyv_u32)npyv__combineh(A, B))
+#define npyv_combineh_s32(A, B) ((npyv_s32)npyv__combineh(A, B))
+#define npyv_combineh_u64 vec_mergel
+#define npyv_combineh_s64 vec_mergel
+#define npyv_combineh_f32(A, B) ((npyv_f32)npyv__combineh(A, B))
+#define npyv_combineh_f64 vec_mergel
+
+/*
+ * combine: combine two vectors from lower and higher parts of two other vectors
+ * zip: interleave two vectors
+*/
+#define NPYV_IMPL_VSX_COMBINE_ZIP(T_VEC, SFX) \
+ NPY_FINLINE T_VEC##x2 npyv_combine_##SFX(T_VEC a, T_VEC b) \
+ { \
+ T_VEC##x2 r; \
+ r.val[0] = NPY_CAT(npyv_combinel_, SFX)(a, b); \
+ r.val[1] = NPY_CAT(npyv_combineh_, SFX)(a, b); \
+ return r; \
+ } \
+ NPY_FINLINE T_VEC##x2 npyv_zip_##SFX(T_VEC a, T_VEC b) \
+ { \
+ T_VEC##x2 r; \
+ r.val[0] = vec_mergeh(a, b); \
+ r.val[1] = vec_mergel(a, b); \
+ return r; \
+ }
+
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_u8, u8)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_s8, s8)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_u16, u16)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_s16, s16)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_u32, u32)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_s32, s32)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_u64, u64)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_s64, s64)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_f32, f32)
+NPYV_IMPL_VSX_COMBINE_ZIP(npyv_f64, f64)
+
+#endif // _NPY_SIMD_VSX_REORDER_H
--- /dev/null
+#ifndef _NPY_SIMD_H_
+ #error "Not a standalone header"
+#endif
+
+#define NPY_SIMD 128
+#define NPY_SIMD_WIDTH 16
+#define NPY_SIMD_F64 1
+
+typedef __vector unsigned char npyv_u8;
+typedef __vector signed char npyv_s8;
+typedef __vector unsigned short npyv_u16;
+typedef __vector signed short npyv_s16;
+typedef __vector unsigned int npyv_u32;
+typedef __vector signed int npyv_s32;
+typedef __vector unsigned long long npyv_u64;
+typedef __vector signed long long npyv_s64;
+typedef __vector float npyv_f32;
+typedef __vector double npyv_f64;
+
+typedef struct { npyv_u8 val[2]; } npyv_u8x2;
+typedef struct { npyv_s8 val[2]; } npyv_s8x2;
+typedef struct { npyv_u16 val[2]; } npyv_u16x2;
+typedef struct { npyv_s16 val[2]; } npyv_s16x2;
+typedef struct { npyv_u32 val[2]; } npyv_u32x2;
+typedef struct { npyv_s32 val[2]; } npyv_s32x2;
+typedef struct { npyv_u64 val[2]; } npyv_u64x2;
+typedef struct { npyv_s64 val[2]; } npyv_s64x2;
+typedef struct { npyv_f32 val[2]; } npyv_f32x2;
+typedef struct { npyv_f64 val[2]; } npyv_f64x2;
+
+typedef struct { npyv_u8 val[3]; } npyv_u8x3;
+typedef struct { npyv_s8 val[3]; } npyv_s8x3;
+typedef struct { npyv_u16 val[3]; } npyv_u16x3;
+typedef struct { npyv_s16 val[3]; } npyv_s16x3;
+typedef struct { npyv_u32 val[3]; } npyv_u32x3;
+typedef struct { npyv_s32 val[3]; } npyv_s32x3;
+typedef struct { npyv_u64 val[3]; } npyv_u64x3;
+typedef struct { npyv_s64 val[3]; } npyv_s64x3;
+typedef struct { npyv_f32 val[3]; } npyv_f32x3;
+typedef struct { npyv_f64 val[3]; } npyv_f64x3;
+
+#define npyv_nlanes_u8 16
+#define npyv_nlanes_s8 16
+#define npyv_nlanes_u16 8
+#define npyv_nlanes_s16 8
+#define npyv_nlanes_u32 4
+#define npyv_nlanes_s32 4
+#define npyv_nlanes_u64 2
+#define npyv_nlanes_s64 2
+#define npyv_nlanes_f32 4
+#define npyv_nlanes_f64 2
+
+// using __bool with typdef cause ambiguous errors
+#define npyv_b8 __vector __bool char
+#define npyv_b16 __vector __bool short
+#define npyv_b32 __vector __bool int
+#define npyv_b64 __vector __bool long long
+
+#include "memory.h"
+#include "misc.h"
+#include "reorder.h"
+#include "operators.h"
+#include "conversion.h"
+#include "arithmetic.h"
+#include "math.h"
NPY_NO_EXPORT PyArray_DatetimeMetaData *
get_datetime_metadata_from_dtype(PyArray_Descr *dtype);
+NPY_NO_EXPORT int
+find_string_array_datetime64_type(PyArrayObject *arr,
+ PyArray_DatetimeMetaData *meta);
+
/*
* Both type1 and type2 must be either NPY_DATETIME or NPY_TIMEDELTA.
* Applies the type promotion rules between the two types, returning
PyArray_DatetimeMetaData *out_meta);
/*
- * 'ret' is a PyUString containing the datetime string, and this
- * function appends the metadata string to it.
+ * Returns datetime metadata as a new reference a Unicode object.
+ * Returns NULL on error.
*
* If 'skip_brackets' is true, skips the '[]'.
*
- * This function steals the reference 'ret'
*/
NPY_NO_EXPORT PyObject *
-append_metastr_to_string(PyArray_DatetimeMetaData *meta,
- int skip_brackets,
- PyObject *ret);
+metastr_to_unicode(PyArray_DatetimeMetaData *meta, int skip_brackets);
+
/*
* Tests for and converts a Python datetime.datetime or datetime.date
NPY_NO_EXPORT PyArray_Descr *
find_object_datetime_type(PyObject *obj, int type_num);
+NPY_NO_EXPORT int
+PyArray_InitializeDatetimeCasts(void);
+
#endif
#include "common.h"
#include "mem_overlap.h"
#include "npy_extint128.h"
-#include "common.h"
-
+#include "array_method.h"
#if defined(MS_WIN32) || defined(__CYGWIN__)
#define EXPORT(x) __declspec(dllexport) x
#include "npy_pycompat.h"
+
/** Function to test calling via ctypes */
EXPORT(void*) forward_pointer(void *x)
{
/* Compute boundaries for the neighborhood iterator */
for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) {
PyObject* bound;
+
bound = PySequence_GetItem(b, i);
if (bound == NULL) {
goto clean_itx;
}
- if (!PyInt_Check(bound)) {
+ /* PyLong_AsSsize checks for PyLong */
+ bounds[i] = PyLong_AsSsize_t(bound);
+ if (error_converting(bounds[i])) {
+ PyErr_Clear();
PyErr_SetString(PyExc_ValueError,
- "bound not long");
+ "bound is invalid");
Py_DECREF(bound);
goto clean_itx;
}
- bounds[i] = PyInt_AsLong(bound);
Py_DECREF(bound);
}
/* Compute boundaries for the neighborhood iterator */
for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) {
PyObject* bound;
+
bound = PySequence_GetItem(b1, i);
if (bound == NULL) {
goto clean_itx;
}
- if (!PyInt_Check(bound)) {
+ /* PyLong_AsSsize checks for PyLong */
+ bounds[i] = PyLong_AsSsize_t(bound);
+ if (error_converting(bounds[i])) {
+ PyErr_Clear();
PyErr_SetString(PyExc_ValueError,
- "bound not long");
+ "bound is invalid");
Py_DECREF(bound);
goto clean_itx;
}
- bounds[i] = PyInt_AsLong(bound);
Py_DECREF(bound);
}
for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) {
PyObject* bound;
+
bound = PySequence_GetItem(b2, i);
if (bound == NULL) {
goto clean_itx;
}
- if (!PyInt_Check(bound)) {
+ /* PyLong_AsSsize checks for PyLong */
+ bounds[i] = PyLong_AsSsize_t(bound);
+ if (error_converting(bounds[i])) {
+ PyErr_Clear();
PyErr_SetString(PyExc_ValueError,
- "bound not long");
+ "bound is invalid");
Py_DECREF(bound);
goto clean_itx;
}
- bounds[i] = PyInt_AsLong(bound);
Py_DECREF(bound);
}
}
+/*
+ * Create a custom field dtype from an existing void one (and test some errors).
+ * The dtypes created by this function may be not be usable (or even crash
+ * while using).
+ */
+static PyObject *
+create_custom_field_dtype(PyObject *NPY_UNUSED(mod), PyObject *args)
+{
+ PyArray_Descr *dtype;
+ PyTypeObject *scalar_type;
+ PyTypeObject *original_type = NULL;
+ int error_path;
+
+ if (!PyArg_ParseTuple(args, "O!O!i",
+ &PyArrayDescr_Type, &dtype,
+ &PyType_Type, &scalar_type,
+ &error_path)) {
+ return NULL;
+ }
+ /* check that the result should be more or less valid */
+ if (dtype->type_num != NPY_VOID || dtype->fields == NULL ||
+ !PyDict_CheckExact(dtype->fields) ||
+ PyTuple_Size(dtype->names) != 1 ||
+ !PyDataType_REFCHK(dtype) ||
+ dtype->elsize != sizeof(PyObject *)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Bad dtype passed to test function, must be an object "
+ "containing void with a single field.");
+ return NULL;
+ }
+
+ /* Copy and then appropriate this dtype */
+ original_type = Py_TYPE(dtype);
+ dtype = PyArray_DescrNew(dtype);
+ if (dtype == NULL) {
+ return NULL;
+ }
+
+ Py_INCREF(scalar_type);
+ Py_SETREF(dtype->typeobj, scalar_type);
+ if (error_path == 1) {
+ /* Test that we reject this, if fields was not already set */
+ Py_SETREF(dtype->fields, NULL);
+ }
+ else if (error_path == 2) {
+ /*
+ * Test that we reject this if the type is not set to something that
+ * we are pretty sure can be safely replaced.
+ */
+ Py_SET_TYPE(dtype, scalar_type);
+ }
+ else if (error_path != 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "invalid error argument to test function.");
+ }
+ if (PyArray_RegisterDataType(dtype) < 0) {
+ /* Fix original type in the error_path == 2 case and delete it */
+ Py_SET_TYPE(dtype, original_type);
+ Py_DECREF(dtype);
+ return NULL;
+ }
+ Py_INCREF(dtype); /* hold on to the original (leaks a reference) */
+ return (PyObject *)dtype;
+}
+
+
+PyObject *
+corrupt_or_fix_bufferinfo(PyObject *dummy, PyObject *obj)
+{
+ void **buffer_info_ptr;
+ if (PyArray_Check(obj)) {
+ buffer_info_ptr = &((PyArrayObject_fields *)obj)->_buffer_info;
+ }
+ else if (PyArray_IsScalar(obj, Void)) {
+ buffer_info_ptr = &((PyVoidScalarObject *)obj)->_buffer_info;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be an array or void scalar");
+ return NULL;
+ }
+ if (*buffer_info_ptr == NULL) {
+ /* set to an invalid value (as a subclass might accidentally) */
+ *buffer_info_ptr = obj;
+ assert(((uintptr_t)obj & 7) == 0);
+ }
+ else if (*buffer_info_ptr == obj) {
+ /* Reset to a NULL (good value) */
+ *buffer_info_ptr = NULL;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "buffer was already exported, this test doesn't support that");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+
/* check no elison for avoided increfs */
static PyObject *
incref_elide(PyObject *dummy, PyObject *args)
}
+static PyObject *
+get_all_cast_information(PyObject *NPY_UNUSED(mod), PyObject *NPY_UNUSED(args))
+{
+ PyObject *result = PyList_New(0);
+ if (result == NULL) {
+ return NULL;
+ }
+ PyObject *classes = PyObject_CallMethod(
+ (PyObject *)&PyArrayDescr_Type, "__subclasses__", "");
+ if (classes == NULL) {
+ return NULL;
+ }
+ Py_SETREF(classes, PySequence_Fast(classes, NULL));
+ if (classes == NULL) {
+ goto fail;
+ }
+
+ Py_ssize_t nclass = PySequence_Length(classes);
+ for (Py_ssize_t i = 0; i < nclass; i++) {
+ PyArray_DTypeMeta *from_dtype = (
+ (PyArray_DTypeMeta *)PySequence_Fast_GET_ITEM(classes, i));
+ if (from_dtype->abstract) {
+ /*
+ * TODO: In principle probably needs to recursively check this,
+ * also we may allow casts to abstract dtypes at some point.
+ */
+ continue;
+ }
+
+ PyObject *to_dtype, *cast_obj;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(from_dtype->castingimpls, &pos, &to_dtype, &cast_obj)) {
+ if (cast_obj == Py_None) {
+ continue;
+ }
+ PyArrayMethodObject *cast = (PyArrayMethodObject *)cast_obj;
+
+ /* Pass some information about this cast out! */
+ PyObject *cast_info = Py_BuildValue("{sOsOsisisisisisssi}",
+ "from", from_dtype,
+ "to", to_dtype,
+ "legacy", (cast->name != NULL &&
+ strncmp(cast->name, "legacy_", 7) == 0),
+ "casting", cast->casting & ~_NPY_CAST_IS_VIEW,
+ "requires_pyapi", cast->flags & NPY_METH_REQUIRES_PYAPI,
+ "supports_unaligned",
+ cast->flags & NPY_METH_SUPPORTS_UNALIGNED,
+ "no_floatingpoint_errors",
+ cast->flags & NPY_METH_NO_FLOATINGPOINT_ERRORS,
+ "name", cast->name,
+ "cast_is_view",
+ cast->casting & _NPY_CAST_IS_VIEW);
+ if (cast_info == NULL) {
+ goto fail;
+ }
+ int res = PyList_Append(result, cast_info);
+ Py_DECREF(cast_info);
+ if (res < 0) {
+ goto fail;
+ }
+ }
+ }
+ Py_DECREF(classes);
+ return result;
+
+ fail:
+ Py_XDECREF(classes);
+ Py_XDECREF(result);
+ return NULL;
+}
+
+
/*
* Test C-api level item getting.
*/
}
for (j = 0; j < nterms; ++j) {
- terms[j].a = (npy_int64)PyInt_AsSsize_t(PyTuple_GET_ITEM(A, j));
+ terms[j].a = (npy_int64)PyLong_AsSsize_t(PyTuple_GET_ITEM(A, j));
if (error_converting(terms[j].a)) {
goto fail;
}
- terms[j].ub = (npy_int64)PyInt_AsSsize_t(PyTuple_GET_ITEM(U, j));
+ terms[j].ub = (npy_int64)PyLong_AsSsize_t(PyTuple_GET_ITEM(U, j));
if (error_converting(terms[j].ub)) {
goto fail;
}
/**begin repeat
* #N = 1,2,3#
*/
- alignment = PyInt_FromLong(_ALIGN(struct TestStruct@N@));
- size = PyInt_FromLong(sizeof(struct TestStruct@N@));
+ alignment = PyLong_FromLong(_ALIGN(struct TestStruct@N@));
+ size = PyLong_FromLong(sizeof(struct TestStruct@N@));
val = PyTuple_Pack(2, alignment, size);
Py_DECREF(alignment);
Py_DECREF(size);
PyOS_snprintf(str, sizeof(str), "%.*g", precision, val);
}
- return PyUString_FromString(str);
+ return PyUnicode_FromString(str);
}
return ret;
}
+
+static PyObject *
+uses_new_casts(PyObject* NPY_UNUSED(self), PyObject* NPY_UNUSED(args))
+{
+#if NPY_USE_NEW_CASTINGIMPL
+ Py_RETURN_TRUE;
+#else
+ Py_RETURN_FALSE;
+#endif
+}
+
+
static PyObject *
run_byteorder_converter(PyObject* NPY_UNUSED(self), PyObject *args)
{
case NPY_SWAP: return PyUnicode_FromString("NPY_SWAP");
case NPY_IGNORE: return PyUnicode_FromString("NPY_IGNORE");
}
- return PyInt_FromLong(byteorder);
+ return PyLong_FromLong(byteorder);
}
static PyObject *
case NPY_HEAPSORT: return PyUnicode_FromString("NPY_HEAPSORT");
case NPY_STABLESORT: return PyUnicode_FromString("NPY_STABLESORT");
}
- return PyInt_FromLong(kind);
+ return PyLong_FromLong(kind);
}
static PyObject *
switch (kind) {
case NPY_INTROSELECT: return PyUnicode_FromString("NPY_INTROSELECT");
}
- return PyInt_FromLong(kind);
+ return PyLong_FromLong(kind);
}
static PyObject *
case NPY_SEARCHLEFT: return PyUnicode_FromString("NPY_SEARCHLEFT");
case NPY_SEARCHRIGHT: return PyUnicode_FromString("NPY_SEARCHRIGHT");
}
- return PyInt_FromLong(side);
+ return PyLong_FromLong(side);
}
static PyObject *
case NPY_FORTRANORDER: return PyUnicode_FromString("NPY_FORTRANORDER");
case NPY_KEEPORDER: return PyUnicode_FromString("NPY_KEEPORDER");
}
- return PyInt_FromLong(order);
+ return PyLong_FromLong(order);
}
static PyObject *
case NPY_WRAP: return PyUnicode_FromString("NPY_WRAP");
case NPY_RAISE: return PyUnicode_FromString("NPY_RAISE");
}
- return PyInt_FromLong(mode);
+ return PyLong_FromLong(mode);
}
static PyObject *
case NPY_SAFE_CASTING: return PyUnicode_FromString("NPY_SAFE_CASTING");
case NPY_SAME_KIND_CASTING: return PyUnicode_FromString("NPY_SAME_KIND_CASTING");
case NPY_UNSAFE_CASTING: return PyUnicode_FromString("NPY_UNSAFE_CASTING");
+ default: return PyLong_FromLong(casting);
}
- return PyInt_FromLong(casting);
}
+static PyObject *
+run_intp_converter(PyObject* NPY_UNUSED(self), PyObject *args)
+{
+ PyArray_Dims dims = {NULL, -1};
+ if (!PyArg_ParseTuple(args, "O&", PyArray_IntpConverter, &dims)) {
+ return NULL;
+ }
+ if (dims.len == -1) {
+ Py_RETURN_NONE;
+ }
+
+ PyObject *tup = PyArray_IntTupleFromIntp(dims.len, dims.ptr);
+ PyDimMem_FREE(dims.ptr);
+ return tup;
+}
static PyMethodDef Multiarray_TestsMethods[] = {
{"IsPythonScalar",
{"fromstring_null_term_c_api",
fromstring_null_term_c_api,
METH_O, NULL},
+ {"create_custom_field_dtype",
+ create_custom_field_dtype,
+ METH_VARARGS, NULL},
+ {"corrupt_or_fix_bufferinfo",
+ corrupt_or_fix_bufferinfo,
+ METH_O, NULL},
{"incref_elide",
incref_elide,
METH_VARARGS, NULL},
{"get_c_wrapping_array",
get_c_wrapping_array,
METH_O, NULL},
+ {"get_all_cast_information",
+ get_all_cast_information,
+ METH_NOARGS,
+ "Return a list with info on all available casts. Some of the info"
+ "may differ for an actual cast if it uses value-based casting "
+ "(flexible types)."},
{"array_indexing",
array_indexing,
METH_VARARGS, NULL},
{"getset_numericops",
getset_numericops,
METH_NOARGS, NULL},
+ {"uses_new_casts",
+ uses_new_casts,
+ METH_NOARGS, NULL},
/**begin repeat
* #name = cabs, carg#
*/
{"run_casting_converter",
run_casting_converter,
METH_VARARGS, NULL},
+ {"run_intp_converter",
+ run_intp_converter,
+ METH_VARARGS, NULL},
{NULL, NULL, 0, NULL} /* Sentinel */
};
--- /dev/null
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include "structmember.h"
+
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _MULTIARRAYMODULE
+#include "numpy/ndarraytypes.h"
+#include "numpy/arrayobject.h"
+
+#include "abstractdtypes.h"
+#include "array_coercion.h"
+#include "common.h"
+
+
+static PyArray_Descr *
+discover_descriptor_from_pyint(
+ PyArray_DTypeMeta *NPY_UNUSED(cls), PyObject *obj)
+{
+ assert(PyLong_Check(obj));
+ /*
+ * We check whether long is good enough. If not, check longlong and
+ * unsigned long before falling back to `object`.
+ */
+ long long value = PyLong_AsLongLong(obj);
+ if (error_converting(value)) {
+ PyErr_Clear();
+ }
+ else {
+ if (NPY_MIN_LONG <= value && value <= NPY_MAX_LONG) {
+ return PyArray_DescrFromType(NPY_LONG);
+ }
+ return PyArray_DescrFromType(NPY_LONGLONG);
+ }
+
+ unsigned long long uvalue = PyLong_AsUnsignedLongLong(obj);
+ if (uvalue == (unsigned long long)-1 && PyErr_Occurred()){
+ PyErr_Clear();
+ }
+ else {
+ return PyArray_DescrFromType(NPY_ULONGLONG);
+ }
+
+ return PyArray_DescrFromType(NPY_OBJECT);
+}
+
+
+static PyArray_Descr*
+discover_descriptor_from_pyfloat(
+ PyArray_DTypeMeta* NPY_UNUSED(cls), PyObject *obj)
+{
+ assert(PyFloat_CheckExact(obj));
+ return PyArray_DescrFromType(NPY_DOUBLE);
+}
+
+
+static PyArray_Descr*
+discover_descriptor_from_pycomplex(
+ PyArray_DTypeMeta* NPY_UNUSED(cls), PyObject *obj)
+{
+ assert(PyComplex_CheckExact(obj));
+ return PyArray_DescrFromType(NPY_COMPLEX128);
+}
+
+
+NPY_NO_EXPORT int
+initialize_and_map_pytypes_to_dtypes()
+{
+ PyArrayAbstractObjDTypeMeta_Type.tp_base = &PyArrayDTypeMeta_Type;
+ if (PyType_Ready(&PyArrayAbstractObjDTypeMeta_Type) < 0) {
+ return -1;
+ }
+ ((PyTypeObject *)&PyArray_PyIntAbstractDType)->tp_base = &PyArrayDTypeMeta_Type;
+ PyArray_PyIntAbstractDType.scalar_type = &PyLong_Type;
+ if (PyType_Ready((PyTypeObject *)&PyArray_PyIntAbstractDType) < 0) {
+ return -1;
+ }
+ ((PyTypeObject *)&PyArray_PyFloatAbstractDType)->tp_base = &PyArrayDTypeMeta_Type;
+ PyArray_PyFloatAbstractDType.scalar_type = &PyFloat_Type;
+ if (PyType_Ready((PyTypeObject *)&PyArray_PyFloatAbstractDType) < 0) {
+ return -1;
+ }
+ ((PyTypeObject *)&PyArray_PyComplexAbstractDType)->tp_base = &PyArrayDTypeMeta_Type;
+ PyArray_PyComplexAbstractDType.scalar_type = &PyComplex_Type;
+ if (PyType_Ready((PyTypeObject *)&PyArray_PyComplexAbstractDType) < 0) {
+ return -1;
+ }
+
+ /* Register the new DTypes for discovery */
+ if (_PyArray_MapPyTypeToDType(
+ &PyArray_PyIntAbstractDType, &PyLong_Type, NPY_FALSE) < 0) {
+ return -1;
+ }
+ if (_PyArray_MapPyTypeToDType(
+ &PyArray_PyFloatAbstractDType, &PyFloat_Type, NPY_FALSE) < 0) {
+ return -1;
+ }
+ if (_PyArray_MapPyTypeToDType(
+ &PyArray_PyComplexAbstractDType, &PyComplex_Type, NPY_FALSE) < 0) {
+ return -1;
+ }
+
+ /*
+ * Map str, bytes, and bool, for which we do not need abstract versions
+ * to the NumPy DTypes. This is done here using the `is_known_scalar_type`
+ * function.
+ * TODO: The `is_known_scalar_type` function is considered preliminary,
+ * the same could be achieved e.g. with additional abstract DTypes.
+ */
+ PyArray_DTypeMeta *dtype;
+ dtype = NPY_DTYPE(PyArray_DescrFromType(NPY_UNICODE));
+ if (_PyArray_MapPyTypeToDType(dtype, &PyUnicode_Type, NPY_FALSE) < 0) {
+ return -1;
+ }
+
+ dtype = NPY_DTYPE(PyArray_DescrFromType(NPY_STRING));
+ if (_PyArray_MapPyTypeToDType(dtype, &PyBytes_Type, NPY_FALSE) < 0) {
+ return -1;
+ }
+ dtype = NPY_DTYPE(PyArray_DescrFromType(NPY_BOOL));
+ if (_PyArray_MapPyTypeToDType(dtype, &PyBool_Type, NPY_FALSE) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/* Note: This is currently largely not used, but will be required eventually. */
+NPY_NO_EXPORT PyTypeObject PyArrayAbstractObjDTypeMeta_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "numpy._AbstractObjDTypeMeta",
+ .tp_basicsize = sizeof(PyArray_DTypeMeta),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "Helper MetaClass for value based casting AbstractDTypes.",
+};
+
+NPY_NO_EXPORT PyArray_DTypeMeta PyArray_PyIntAbstractDType = {{{
+ PyVarObject_HEAD_INIT(&PyArrayAbstractObjDTypeMeta_Type, 0)
+ .tp_basicsize = sizeof(PyArray_DTypeMeta),
+ .tp_name = "numpy._PyIntBaseAbstractDType",
+ },},
+ .abstract = 1,
+ .discover_descr_from_pyobject = discover_descriptor_from_pyint,
+ .kind = 'i',
+};
+
+NPY_NO_EXPORT PyArray_DTypeMeta PyArray_PyFloatAbstractDType = {{{
+ PyVarObject_HEAD_INIT(&PyArrayAbstractObjDTypeMeta_Type, 0)
+ .tp_basicsize = sizeof(PyArray_DTypeMeta),
+ .tp_name = "numpy._PyFloatBaseAbstractDType",
+ },},
+ .abstract = 1,
+ .discover_descr_from_pyobject = discover_descriptor_from_pyfloat,
+ .kind = 'f',
+};
+
+NPY_NO_EXPORT PyArray_DTypeMeta PyArray_PyComplexAbstractDType = {{{
+ PyVarObject_HEAD_INIT(&PyArrayAbstractObjDTypeMeta_Type, 0)
+ .tp_basicsize = sizeof(PyArray_DTypeMeta),
+ .tp_name = "numpy._PyComplexBaseAbstractDType",
+ },},
+ .abstract = 1,
+ .discover_descr_from_pyobject = discover_descriptor_from_pycomplex,
+ .kind = 'c',
+};
+
--- /dev/null
+#ifndef _NPY_ABSTRACTDTYPES_H
+#define _NPY_ABSTRACTDTYPES_H
+
+#include "dtypemeta.h"
+
+/*
+ * These are mainly needed for value based promotion in ufuncs. It
+ * may be necessary to make them (partially) public, to allow user-defined
+ * dtypes to perform value based casting.
+ */
+NPY_NO_EXPORT extern PyTypeObject PyArrayAbstractObjDTypeMeta_Type;
+NPY_NO_EXPORT extern PyArray_DTypeMeta PyArray_PyIntAbstractDType;
+NPY_NO_EXPORT extern PyArray_DTypeMeta PyArray_PyFloatAbstractDType;
+NPY_NO_EXPORT extern PyArray_DTypeMeta PyArray_PyComplexAbstractDType;
+
+NPY_NO_EXPORT int
+initialize_and_map_pytypes_to_dtypes(void);
+
+#endif /*_NPY_ABSTRACTDTYPES_H */
#include <Python.h>
#include "structmember.h"
-#if PY_VERSION_HEX >= 0x03060000
#include <pymem.h>
/* public api in 3.7 */
#if PY_VERSION_HEX < 0x03070000
#define PyTraceMalloc_Track _PyTraceMalloc_Track
#define PyTraceMalloc_Untrack _PyTraceMalloc_Untrack
#endif
-#else
-#define PyTraceMalloc_Track(...)
-#define PyTraceMalloc_Untrack(...)
-#endif
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE
NPY_RAW_ITER_START(idim, ndim, coord, shape_it) {
/* Process the innermost dimension */
- stransfer(dst_data, dst_strides_it[0], src_data, src_strides_it[0],
- shape_it[0], src_itemsize, transferdata);
+ if (stransfer(
+ dst_data, dst_strides_it[0], src_data, src_strides_it[0],
+ shape_it[0], src_itemsize, transferdata) < 0) {
+ goto fail;
+ }
} NPY_RAW_ITER_TWO_NEXT(idim, ndim, coord, shape_it,
dst_data, dst_strides_it,
src_data, src_strides_it);
NPY_END_THREADS;
-
NPY_AUXDATA_FREE(transferdata);
-
- return (needs_api && PyErr_Occurred()) ? -1 : 0;
+ return 0;
+fail:
+ NPY_END_THREADS;
+ NPY_AUXDATA_FREE(transferdata);
+ return -1;
}
/*
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);
+ if (stransfer(
+ dst_data, dst_strides_it[0], src_data, 0,
+ shape_it[0], src_itemsize, transferdata) < 0) {
+ goto fail;
+ }
} NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord,
shape_it, dst_data, dst_strides_it);
NPY_END_THREADS;
-
NPY_AUXDATA_FREE(transferdata);
-
- return (needs_api && PyErr_Occurred()) ? -1 : 0;
+ return 0;
+fail:
+ NPY_END_THREADS;
+ NPY_AUXDATA_FREE(transferdata);
+ return -1;
}
/*
--- /dev/null
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _UMATHMODULE
+#define _MULTIARRAYMODULE
+
+#include "Python.h"
+
+#include "numpy/npy_3kcompat.h"
+
+#include "lowlevel_strided_loops.h"
+#include "numpy/arrayobject.h"
+
+#include "descriptor.h"
+#include "convert_datatype.h"
+#include "dtypemeta.h"
+
+#include "array_coercion.h"
+#include "ctors.h"
+#include "common.h"
+#include "_datetime.h"
+#include "npy_import.h"
+
+
+/*
+ * This file defines helpers for some of the ctors.c functions which
+ * create an array from Python sequences and types.
+ * When creating an array with ``np.array(...)`` we have to do two main things:
+ *
+ * 1. Find the exact shape of the resulting array
+ * 2. Find the correct dtype of the resulting array.
+ *
+ * In most cases these two things are can be done in a single processing step.
+ * There are in principle three different calls that should be distinguished:
+ *
+ * 1. The user calls ``np.array(..., dtype=np.dtype("<f8"))``
+ * 2. The user calls ``np.array(..., dtype="S")``
+ * 3. The user calls ``np.array(...)``
+ *
+ * In the first case, in principle only the shape needs to be found. In the
+ * second case, the DType class (e.g. string) is already known but the DType
+ * instance (e.g. length of the string) has to be found.
+ * In the last case the DType class needs to be found as well. Note that
+ * it is not necessary to find the DType class of the entire array, but
+ * the DType class needs to be found for each element before the actual
+ * dtype instance can be found.
+ *
+ * Further, there are a few other things to keep in mind when coercing arrays:
+ *
+ * * For UFunc promotion, Python scalars need to be handled specially to
+ * allow value based casting. This requires python complex/float to
+ * have their own DTypes.
+ * * It is necessary to decide whether or not a sequence is an element.
+ * For example tuples are considered elements for structured dtypes, but
+ * otherwise are considered sequences.
+ * This means that if a dtype is given (either as a class or instance),
+ * it can effect the dimension discovery part.
+ * For the "special" NumPy types structured void and "c" (single character)
+ * this is special cased. For future user-types, this is currently
+ * handled by providing calling an `is_known_scalar` method. This method
+ * currently ensures that Python numerical types are handled quickly.
+ *
+ * In the initial version of this implementation, it is assumed that dtype
+ * discovery can be implemented sufficiently fast. That is, it is not
+ * necessary to create fast paths that only find the correct shape e.g. when
+ * ``dtype=np.dtype("f8")`` is given.
+ *
+ * The code here avoid multiple conversion of array-like objects (including
+ * sequences). These objects are cached after conversion, which will require
+ * additional memory, but can drastically speed up coercion from from array
+ * like objects.
+ */
+
+
+/*
+ * For finding a DType quickly from a type, it is easiest to have a
+ * a mapping of pytype -> DType.
+ * TODO: This mapping means that it is currently impossible to delete a
+ * pair of pytype <-> DType. To resolve this, it is necessary to
+ * weakly reference the pytype. As long as the pytype is alive, we
+ * want to be able to use `np.array([pytype()])`.
+ * It should be possible to retrofit this without too much trouble
+ * (all type objects support weak references).
+ */
+PyObject *_global_pytype_to_type_dict = NULL;
+
+
+/* Enum to track or signal some things during dtype and shape discovery */
+enum _dtype_discovery_flags {
+ FOUND_RAGGED_ARRAY = 1 << 0,
+ GAVE_SUBCLASS_WARNING = 1 << 1,
+ PROMOTION_FAILED = 1 << 2,
+ DISCOVER_STRINGS_AS_SEQUENCES = 1 << 3,
+ DISCOVER_TUPLES_AS_ELEMENTS = 1 << 4,
+ MAX_DIMS_WAS_REACHED = 1 << 5,
+ DESCRIPTOR_WAS_SET = 1 << 6,
+};
+
+
+/**
+ * Adds known sequence types to the global type dictionary, note that when
+ * a DType is passed in, this lookup may be ignored.
+ *
+ * @return -1 on error 0 on success
+ */
+static int
+_prime_global_pytype_to_type_dict(void)
+{
+ int res;
+
+ /* Add the basic Python sequence types */
+ res = PyDict_SetItem(_global_pytype_to_type_dict,
+ (PyObject *)&PyList_Type, Py_None);
+ if (res < 0) {
+ return -1;
+ }
+ res = PyDict_SetItem(_global_pytype_to_type_dict,
+ (PyObject *)&PyTuple_Type, Py_None);
+ if (res < 0) {
+ return -1;
+ }
+ /* NumPy Arrays are not handled as scalars */
+ res = PyDict_SetItem(_global_pytype_to_type_dict,
+ (PyObject *)&PyArray_Type, Py_None);
+ if (res < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * Add a new mapping from a python type to the DType class. For a user
+ * defined legacy dtype, this function does nothing unless the pytype
+ * subclass from `np.generic`.
+ *
+ * This assumes that the DType class is guaranteed to hold on the
+ * python type (this assumption is guaranteed).
+ * This functionality supercedes ``_typenum_fromtypeobj``.
+ *
+ * @param DType DType to map the python type to
+ * @param pytype Python type to map from
+ * @param userdef Whether or not it is user defined. We ensure that user
+ * defined scalars subclass from our scalars (for now).
+ */
+NPY_NO_EXPORT int
+_PyArray_MapPyTypeToDType(
+ PyArray_DTypeMeta *DType, PyTypeObject *pytype, npy_bool userdef)
+{
+ PyObject *Dtype_obj = (PyObject *)DType;
+
+ if (userdef && !PyObject_IsSubclass(
+ (PyObject *)pytype, (PyObject *)&PyGenericArrType_Type)) {
+ /*
+ * We expect that user dtypes (for now) will subclass some numpy
+ * scalar class to allow automatic discovery.
+ */
+ if (DType->legacy) {
+ /*
+ * For legacy user dtypes, discovery relied on subclassing, but
+ * arbitrary type objects are supported, so do nothing.
+ */
+ return 0;
+ }
+ /*
+ * We currently enforce that user DTypes subclass from `np.generic`
+ * (this should become a `np.generic` base class and may be lifted
+ * entirely).
+ */
+ PyErr_Format(PyExc_RuntimeError,
+ "currently it is only possible to register a DType "
+ "for scalars deriving from `np.generic`, got '%S'.",
+ (PyObject *)pytype);
+ return -1;
+ }
+
+ /* Create the global dictionary if it does not exist */
+ if (NPY_UNLIKELY(_global_pytype_to_type_dict == NULL)) {
+ _global_pytype_to_type_dict = PyDict_New();
+ if (_global_pytype_to_type_dict == NULL) {
+ return -1;
+ }
+ if (_prime_global_pytype_to_type_dict() < 0) {
+ return -1;
+ }
+ }
+
+ int res = PyDict_Contains(_global_pytype_to_type_dict, (PyObject *)pytype);
+ if (res < 0) {
+ return -1;
+ }
+ else if (res) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Can only map one python type to DType.");
+ return -1;
+ }
+
+ return PyDict_SetItem(_global_pytype_to_type_dict,
+ (PyObject *)pytype, Dtype_obj);
+}
+
+
+/**
+ * Lookup the DType for a registered known python scalar type.
+ *
+ * @param pytype Python Type to look up
+ * @return DType, None if it a known non-scalar, or NULL if an unknown object.
+ */
+static NPY_INLINE PyArray_DTypeMeta *
+discover_dtype_from_pytype(PyTypeObject *pytype)
+{
+ PyObject *DType;
+
+ if (pytype == &PyArray_Type) {
+ Py_INCREF(Py_None);
+ return (PyArray_DTypeMeta *)Py_None;
+ }
+
+ DType = PyDict_GetItem(_global_pytype_to_type_dict, (PyObject *)pytype);
+ if (DType == NULL) {
+ /* the python type is not known */
+ return NULL;
+ }
+
+ Py_INCREF(DType);
+ if (DType == Py_None) {
+ return (PyArray_DTypeMeta *)Py_None;
+ }
+ assert(PyObject_TypeCheck(DType, (PyTypeObject *)&PyArrayDTypeMeta_Type));
+ return (PyArray_DTypeMeta *)DType;
+}
+
+
+/**
+ * Find the correct DType class for the given python type. If flags is NULL
+ * this is not used to discover a dtype, but only for conversion to an
+ * existing dtype. In that case the Python (not NumPy) scalar subclass
+ * checks are skipped.
+ *
+ * @param obj The python object, mainly type(pyobj) is used, the object
+ * is passed to reuse existing code at this time only.
+ * @param flags Flags used to know if warnings were already given. If
+ * flags is NULL, this is not
+ * @param fixed_DType if not NULL, will be checked first for whether or not
+ * it can/wants to handle the (possible) scalar value.
+ * @return New reference to either a DType class, Py_None, or NULL on error.
+ */
+static NPY_INLINE PyArray_DTypeMeta *
+discover_dtype_from_pyobject(
+ PyObject *obj, enum _dtype_discovery_flags *flags,
+ PyArray_DTypeMeta *fixed_DType)
+{
+ if (fixed_DType != NULL) {
+ /*
+ * Let the given DType handle the discovery. This is when the
+ * scalar-type matches exactly, or the DType signals that it can
+ * handle the scalar-type. (Even if it cannot handle here it may be
+ * asked to attempt to do so later, if no other matching DType exists.)
+ */
+ if ((Py_TYPE(obj) == fixed_DType->scalar_type) ||
+ (fixed_DType->is_known_scalar_type != NULL &&
+ fixed_DType->is_known_scalar_type(fixed_DType, Py_TYPE(obj)))) {
+ Py_INCREF(fixed_DType);
+ return fixed_DType;
+ }
+ }
+
+ PyArray_DTypeMeta *DType = discover_dtype_from_pytype(Py_TYPE(obj));
+ if (DType != NULL) {
+ return DType;
+ }
+ /*
+ * At this point we have not found a clear mapping, but mainly for
+ * backward compatibility we have to make some further attempts at
+ * interpreting the input as a known scalar type.
+ */
+ PyArray_Descr *legacy_descr;
+ if (PyArray_IsScalar(obj, Generic)) {
+ legacy_descr = PyArray_DescrFromScalar(obj);
+ if (legacy_descr == NULL) {
+ return NULL;
+ }
+ }
+ else if (flags == NULL) {
+ Py_INCREF(Py_None);
+ return (PyArray_DTypeMeta *)Py_None;
+ }
+ else if (PyBytes_Check(obj)) {
+ legacy_descr = PyArray_DescrFromType(NPY_BYTE);
+ }
+ else if (PyUnicode_Check(obj)) {
+ legacy_descr = PyArray_DescrFromType(NPY_UNICODE);
+ }
+ else {
+ legacy_descr = _array_find_python_scalar_type(obj);
+ }
+
+ if (legacy_descr != NULL) {
+ DType = NPY_DTYPE(legacy_descr);
+ Py_INCREF(DType);
+ Py_DECREF(legacy_descr);
+ /* TODO: Enable warning about subclass handling */
+ if ((0) && !((*flags) & GAVE_SUBCLASS_WARNING)) {
+ if (DEPRECATE_FUTUREWARNING(
+ "in the future NumPy will not automatically find the "
+ "dtype for subclasses of scalars known to NumPy (i.e. "
+ "python types). Use the appropriate `dtype=...` to create "
+ "this array. This will use the `object` dtype or raise "
+ "an error in the future.") < 0) {
+ return NULL;
+ }
+ *flags |= GAVE_SUBCLASS_WARNING;
+ }
+ return DType;
+ }
+ Py_INCREF(Py_None);
+ return (PyArray_DTypeMeta *)Py_None;
+}
+
+
+/**
+ * Discover the correct descriptor from a known DType class and scalar.
+ * If the fixed DType can discover a dtype instance/descr all is fine,
+ * if it cannot and DType is used instead, a cast will have to be tried.
+ *
+ * @param fixed_DType A user provided fixed DType, can be NULL
+ * @param DType A discovered DType (by discover_dtype_from_pyobject);
+ * this can be identical to `fixed_DType`, if it obj is a
+ * known scalar. Can be `NULL` indicating no known type.
+ * @param obj The Python scalar object. At the time of calling this function
+ * it must be known that `obj` should represent a scalar.
+ */
+static NPY_INLINE PyArray_Descr *
+find_scalar_descriptor(
+ PyArray_DTypeMeta *fixed_DType, PyArray_DTypeMeta *DType,
+ PyObject *obj)
+{
+ PyArray_Descr *descr;
+
+ if (DType == NULL && fixed_DType == NULL) {
+ /* No known DType and no fixed one means we go to object. */
+ return PyArray_DescrFromType(NPY_OBJECT);
+ }
+ else if (DType == NULL) {
+ /*
+ * If no DType is known/found, give the fixed give one a second
+ * chance. This allows for example string, to call `str(obj)` to
+ * figure out the length for arbitrary objects.
+ */
+ descr = fixed_DType->discover_descr_from_pyobject(fixed_DType, obj);
+ }
+ else {
+ descr = DType->discover_descr_from_pyobject(DType, obj);
+ }
+ if (descr == NULL) {
+ return NULL;
+ }
+ if (fixed_DType == NULL) {
+ return descr;
+ }
+
+ Py_SETREF(descr, PyArray_CastDescrToDType(descr, fixed_DType));
+ return descr;
+}
+
+
+/**
+ * Assign a single element in an array from a python value.
+ *
+ * The dtypes SETITEM should only be trusted to generally do the right
+ * thing if something is known to be a scalar *and* is of a python type known
+ * to the DType (which should include all basic Python math types), but in
+ * general a cast may be necessary.
+ * This function handles the cast, which is for example hit when assigning
+ * a float128 to complex128.
+ *
+ * At this time, this function does not support arrays (historically we
+ * mainly supported arrays through `__float__()`, etc.). Such support should
+ * possibly be added (although when called from `PyArray_AssignFromCache`
+ * the input cannot be an array).
+ * Note that this is also problematic for some array-likes, such as
+ * `astropy.units.Quantity` and `np.ma.masked`. These are used to us calling
+ * `__float__`/`__int__` for 0-D instances in many cases.
+ * Eventually, we may want to define this as wrong: They must use DTypes
+ * instead of (only) subclasses. Until then, here as well as in
+ * `PyArray_AssignFromCache` (which already does this), we need to special
+ * case 0-D array-likes to behave like arbitrary (unknown!) Python objects.
+ *
+ * @param descr
+ * @param item
+ * @param value
+ * @return 0 on success -1 on failure.
+ */
+/*
+ * TODO: This function should possibly be public API.
+ */
+NPY_NO_EXPORT int
+PyArray_Pack(PyArray_Descr *descr, char *item, PyObject *value)
+{
+ PyArrayObject_fields arr_fields = {
+ .flags = NPY_ARRAY_WRITEABLE, /* assume array is not behaved. */
+ };
+ Py_SET_TYPE(&arr_fields, &PyArray_Type);
+ Py_SET_REFCNT(&arr_fields, 1);
+
+ if (NPY_UNLIKELY(descr->type_num == NPY_OBJECT)) {
+ /*
+ * We always have store objects directly, casting will lose some
+ * type information. Any other dtype discards the type information.
+ * TODO: For a Categorical[object] this path may be necessary?
+ */
+ arr_fields.descr = descr;
+ return descr->f->setitem(value, item, &arr_fields);
+ }
+
+ /* discover_dtype_from_pyobject includes a check for is_known_scalar_type */
+ PyArray_DTypeMeta *DType = discover_dtype_from_pyobject(
+ value, NULL, NPY_DTYPE(descr));
+ if (DType == NULL) {
+ return -1;
+ }
+ if (DType == NPY_DTYPE(descr) || DType == (PyArray_DTypeMeta *)Py_None) {
+ /* We can set the element directly (or at least will try to) */
+ Py_XDECREF(DType);
+ arr_fields.descr = descr;
+ return descr->f->setitem(value, item, &arr_fields);
+ }
+ PyArray_Descr *tmp_descr;
+ tmp_descr = DType->discover_descr_from_pyobject(DType, value);
+ Py_DECREF(DType);
+ if (tmp_descr == NULL) {
+ return -1;
+ }
+
+ char *data = PyObject_Malloc(tmp_descr->elsize);
+ if (data == NULL) {
+ PyErr_NoMemory();
+ Py_DECREF(tmp_descr);
+ return -1;
+ }
+ if (PyDataType_FLAGCHK(tmp_descr, NPY_NEEDS_INIT)) {
+ memset(data, 0, tmp_descr->elsize);
+ }
+ arr_fields.descr = tmp_descr;
+ if (tmp_descr->f->setitem(value, data, &arr_fields) < 0) {
+ PyObject_Free(data);
+ Py_DECREF(tmp_descr);
+ return -1;
+ }
+ if (PyDataType_REFCHK(tmp_descr)) {
+ /* We could probably use move-references above */
+ PyArray_Item_INCREF(data, tmp_descr);
+ }
+
+ int res = 0;
+ int needs_api = 0;
+ PyArray_StridedUnaryOp *stransfer;
+ NpyAuxData *transferdata;
+ if (PyArray_GetDTypeTransferFunction(
+ 0, 0, 0, tmp_descr, descr, 0, &stransfer, &transferdata,
+ &needs_api) == NPY_FAIL) {
+ res = -1;
+ goto finish;
+ }
+ if (stransfer(item, 0, data, 0, 1, tmp_descr->elsize, transferdata) < 0) {
+ res = -1;
+ }
+ NPY_AUXDATA_FREE(transferdata);
+
+ finish:
+ if (PyDataType_REFCHK(tmp_descr)) {
+ /* We could probably use move-references above */
+ PyArray_Item_XDECREF(data, tmp_descr);
+ }
+ PyObject_Free(data);
+ Py_DECREF(tmp_descr);
+ return res;
+}
+
+
+static int
+update_shape(int curr_ndim, int *max_ndim,
+ npy_intp out_shape[NPY_MAXDIMS], int new_ndim,
+ const npy_intp new_shape[NPY_MAXDIMS], npy_bool sequence,
+ enum _dtype_discovery_flags *flags)
+{
+ int success = 0; /* unsuccessful if array is ragged */
+ const npy_bool max_dims_reached = *flags & MAX_DIMS_WAS_REACHED;
+
+ if (curr_ndim + new_ndim > *max_ndim) {
+ success = -1;
+ /* Only update/check as many dims as possible, max_ndim is unchanged */
+ new_ndim = *max_ndim - curr_ndim;
+ }
+ else if (!sequence && (*max_ndim != curr_ndim + new_ndim)) {
+ /*
+ * Sequences do not update max_ndim, otherwise shrink and check.
+ * This is depth first, so if it is already set, `out_shape` is filled.
+ */
+ *max_ndim = curr_ndim + new_ndim;
+ /* If a shape was already set, this is also ragged */
+ if (max_dims_reached) {
+ success = -1;
+ }
+ }
+ for (int i = 0; i < new_ndim; i++) {
+ npy_intp curr_dim = out_shape[curr_ndim + i];
+ npy_intp new_dim = new_shape[i];
+
+ if (!max_dims_reached) {
+ out_shape[curr_ndim + i] = new_dim;
+ }
+ else if (new_dim != curr_dim) {
+ /* The array is ragged, and this dimension is unusable already */
+ success = -1;
+ if (!sequence) {
+ /* Remove dimensions that we cannot use: */
+ *max_ndim -= new_ndim - i;
+ }
+ else {
+ assert(i == 0);
+ /* max_ndim is usually not updated for sequences, so set now: */
+ *max_ndim = curr_ndim;
+ }
+ break;
+ }
+ }
+ if (!sequence) {
+ *flags |= MAX_DIMS_WAS_REACHED;
+ }
+ return success;
+}
+
+
+#define COERCION_CACHE_CACHE_SIZE 5
+static int _coercion_cache_num = 0;
+static coercion_cache_obj *_coercion_cache_cache[COERCION_CACHE_CACHE_SIZE];
+
+/*
+ * Steals a reference to the object.
+ */
+static NPY_INLINE int
+npy_new_coercion_cache(
+ PyObject *converted_obj, PyObject *arr_or_sequence, npy_bool sequence,
+ coercion_cache_obj ***next_ptr, int ndim)
+{
+ coercion_cache_obj *cache;
+ if (_coercion_cache_num > 0) {
+ _coercion_cache_num--;
+ cache = _coercion_cache_cache[_coercion_cache_num];
+ }
+ else {
+ cache = PyMem_Malloc(sizeof(coercion_cache_obj));
+ }
+ if (cache == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ cache->converted_obj = converted_obj;
+ cache->arr_or_sequence = arr_or_sequence;
+ cache->sequence = sequence;
+ cache->depth = ndim;
+ cache->next = NULL;
+ **next_ptr = cache;
+ *next_ptr = &(cache->next);
+ return 0;
+}
+
+/**
+ * Unlink coercion cache item.
+ *
+ * @param current
+ * @return next coercion cache object (or NULL)
+ */
+NPY_NO_EXPORT NPY_INLINE coercion_cache_obj *
+npy_unlink_coercion_cache(coercion_cache_obj *current)
+{
+ coercion_cache_obj *next = current->next;
+ Py_DECREF(current->arr_or_sequence);
+ if (_coercion_cache_num < COERCION_CACHE_CACHE_SIZE) {
+ _coercion_cache_cache[_coercion_cache_num] = current;
+ _coercion_cache_num++;
+ }
+ else {
+ PyMem_Free(current);
+ }
+ return next;
+}
+
+NPY_NO_EXPORT NPY_INLINE void
+npy_free_coercion_cache(coercion_cache_obj *next) {
+ /* We only need to check from the last used cache pos */
+ while (next != NULL) {
+ next = npy_unlink_coercion_cache(next);
+ }
+}
+
+#undef COERCION_CACHE_CACHE_SIZE
+
+/**
+ * Do the promotion step and possible casting. This function should
+ * never be called if a descriptor was requested. In that case the output
+ * dtype is not of importance, so we must not risk promotion errors.
+ *
+ * @param out_descr The current descriptor.
+ * @param descr The newly found descriptor to promote with
+ * @param fixed_DType The user provided (fixed) DType or NULL
+ * @param flags dtype discover flags to signal failed promotion.
+ * @return -1 on error, 0 on success.
+ */
+static NPY_INLINE int
+handle_promotion(PyArray_Descr **out_descr, PyArray_Descr *descr,
+ PyArray_DTypeMeta *fixed_DType, enum _dtype_discovery_flags *flags)
+{
+ assert(!(*flags & DESCRIPTOR_WAS_SET));
+
+ if (*out_descr == NULL) {
+ Py_INCREF(descr);
+ *out_descr = descr;
+ return 0;
+ }
+ PyArray_Descr *new_descr = PyArray_PromoteTypes(descr, *out_descr);
+ if (NPY_UNLIKELY(new_descr == NULL)) {
+ if (fixed_DType != NULL) {
+ /* If a DType is fixed, promotion must not fail. */
+ return -1;
+ }
+ PyErr_Clear();
+ *flags |= PROMOTION_FAILED;
+ /* Continue with object, since we may need the dimensionality */
+ new_descr = PyArray_DescrFromType(NPY_OBJECT);
+ }
+ Py_SETREF(*out_descr, new_descr);
+ return 0;
+}
+
+
+/**
+ * Handle a leave node (known scalar) during dtype and shape discovery.
+ *
+ * @param obj The python object or nested sequence to convert
+ * @param curr_dims The current number of dimensions (depth in the recursion)
+ * @param max_dims The maximum number of dimensions.
+ * @param out_shape The discovered output shape, will be filled
+ * @param fixed_DType The user provided (fixed) DType or NULL
+ * @param flags used signal that this is a ragged array, used internally and
+ * can be expanded if necessary.
+ * @param DType the DType class that should be used, or NULL, if not provided.
+ *
+ * @return 0 on success -1 on error
+ */
+static NPY_INLINE int
+handle_scalar(
+ PyObject *obj, int curr_dims, int *max_dims,
+ PyArray_Descr **out_descr, npy_intp *out_shape,
+ PyArray_DTypeMeta *fixed_DType,
+ enum _dtype_discovery_flags *flags, PyArray_DTypeMeta *DType)
+{
+ PyArray_Descr *descr;
+
+ if (update_shape(curr_dims, max_dims, out_shape,
+ 0, NULL, NPY_FALSE, flags) < 0) {
+ *flags |= FOUND_RAGGED_ARRAY;
+ return *max_dims;
+ }
+ if (*flags & DESCRIPTOR_WAS_SET) {
+ /* no need to do any promotion */
+ return *max_dims;
+ }
+ /* This is a scalar, so find the descriptor */
+ descr = find_scalar_descriptor(fixed_DType, DType, obj);
+ if (descr == NULL) {
+ return -1;
+ }
+ if (handle_promotion(out_descr, descr, fixed_DType, flags) < 0) {
+ Py_DECREF(descr);
+ return -1;
+ }
+ Py_DECREF(descr);
+ return *max_dims;
+}
+
+
+/**
+ * Return the correct descriptor given an array object and a DType class.
+ *
+ * This is identical to casting the arrays descriptor/dtype to the new
+ * DType class
+ *
+ * @param arr The array object.
+ * @param DType The DType class to cast to (or NULL for convenience)
+ * @param out_descr The output descriptor will set. The result can be NULL
+ * when the array is of object dtype and has no elements.
+ *
+ * @return -1 on failure, 0 on success.
+ */
+static int
+find_descriptor_from_array(
+ PyArrayObject *arr, PyArray_DTypeMeta *DType, PyArray_Descr **out_descr)
+{
+ enum _dtype_discovery_flags flags = 0;
+ *out_descr = NULL;
+
+ if (DType == NULL) {
+ *out_descr = PyArray_DESCR(arr);
+ Py_INCREF(*out_descr);
+ return 0;
+ }
+
+ if (NPY_UNLIKELY(DType->parametric && PyArray_ISOBJECT(arr))) {
+ /*
+ * We have one special case, if (and only if) the input array is of
+ * object DType and the dtype is not fixed already but parametric.
+ * Then, we allow inspection of all elements, treating them as
+ * elements. We do this recursively, so nested 0-D arrays can work,
+ * but nested higher dimensional arrays will lead to an error.
+ */
+ assert(DType->type_num != NPY_OBJECT); /* not parametric */
+
+ PyArrayIterObject *iter;
+ iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arr);
+ if (iter == NULL) {
+ return -1;
+ }
+ while (iter->index < iter->size) {
+ PyArray_DTypeMeta *item_DType;
+ /*
+ * Note: If the array contains typed objects we may need to use
+ * the dtype to use casting for finding the correct instance.
+ */
+ PyObject *elem = PyArray_GETITEM(arr, iter->dataptr);
+ if (elem == NULL) {
+ Py_DECREF(iter);
+ return -1;
+ }
+ item_DType = discover_dtype_from_pyobject(elem, &flags, DType);
+ if (item_DType == NULL) {
+ Py_DECREF(iter);
+ Py_DECREF(elem);
+ return -1;
+ }
+ if (item_DType == (PyArray_DTypeMeta *)Py_None) {
+ Py_SETREF(item_DType, NULL);
+ }
+ int flat_max_dims = 0;
+ if (handle_scalar(elem, 0, &flat_max_dims, out_descr,
+ NULL, DType, &flags, item_DType) < 0) {
+ Py_DECREF(iter);
+ Py_DECREF(elem);
+ Py_XDECREF(item_DType);
+ return -1;
+ }
+ Py_XDECREF(item_DType);
+ Py_DECREF(elem);
+ PyArray_ITER_NEXT(iter);
+ }
+ Py_DECREF(iter);
+ }
+ else if (NPY_UNLIKELY(DType->type_num == NPY_DATETIME) &&
+ PyArray_ISSTRING(arr)) {
+ /*
+ * TODO: This branch should be deprecated IMO, the workaround is
+ * to cast to the object to a string array. Although a specific
+ * function (if there is even any need) would be better.
+ * This is value based casting!
+ * Unless of course we actually want to support this kind of thing
+ * in general (not just for object dtype)...
+ */
+ PyArray_DatetimeMetaData meta;
+ meta.base = NPY_FR_GENERIC;
+ meta.num = 1;
+
+ if (find_string_array_datetime64_type(arr, &meta) < 0) {
+ return -1;
+ }
+ else {
+ *out_descr = create_datetime_dtype(NPY_DATETIME, &meta);
+ if (*out_descr == NULL) {
+ return -1;
+ }
+ }
+ }
+ else {
+ /*
+ * If this is not an object array figure out the dtype cast,
+ * or simply use the returned DType.
+ */
+ *out_descr = PyArray_CastDescrToDType(PyArray_DESCR(arr), DType);
+ if (*out_descr == NULL) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Given a dtype or DType object, find the correct descriptor to cast the
+ * array to.
+ *
+ * This function is identical to normal casting using only the dtype, however,
+ * it supports inspecting the elements when the array has object dtype
+ * (and the given datatype describes a parametric DType class).
+ *
+ * @param arr
+ * @param dtype A dtype instance or class.
+ * @return A concrete dtype instance or NULL
+ */
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_AdaptDescriptorToArray(PyArrayObject *arr, PyObject *dtype)
+{
+ /* If the requested dtype is flexible, adapt it */
+ PyArray_Descr *new_dtype;
+ PyArray_DTypeMeta *new_DType;
+ int res;
+
+ res = PyArray_ExtractDTypeAndDescriptor((PyObject *)dtype,
+ &new_dtype, &new_DType);
+ if (res < 0) {
+ return NULL;
+ }
+ if (new_dtype == NULL) {
+ res = find_descriptor_from_array(arr, new_DType, &new_dtype);
+ if (res < 0) {
+ Py_DECREF(new_DType);
+ return NULL;
+ }
+ if (new_dtype == NULL) {
+ /* This is an object array but contained no elements, use default */
+ new_dtype = new_DType->default_descr(new_DType);
+ }
+ }
+ Py_DECREF(new_DType);
+ return new_dtype;
+}
+
+
+/**
+ * Recursion helper for `PyArray_DiscoverDTypeAndShape`. See its
+ * documentation for additional details.
+ *
+ * @param obj The current (possibly nested) object
+ * @param curr_dims The current depth, i.e. initially 0 and increasing.
+ * @param max_dims Maximum number of dimensions, modified during discovery.
+ * @param out_descr dtype instance (or NULL) to promoted and update.
+ * @param out_shape The current shape (updated)
+ * @param coercion_cache_tail_ptr The tail of the linked list of coercion
+ * cache objects, which hold on to converted sequences and arrays.
+ * This is a pointer to the `->next` slot of the previous cache so
+ * that we can append a new cache object (and update this pointer).
+ * (Initially it is a pointer to the user-provided head pointer).
+ * @param fixed_DType User provided fixed DType class
+ * @param flags Discovery flags (reporting and behaviour flags, see def.)
+ * @return The updated number of maximum dimensions (i.e. scalars will set
+ * this to the current dimensions).
+ */
+NPY_NO_EXPORT int
+PyArray_DiscoverDTypeAndShape_Recursive(
+ PyObject *obj, int curr_dims, int max_dims, PyArray_Descr**out_descr,
+ npy_intp out_shape[NPY_MAXDIMS],
+ coercion_cache_obj ***coercion_cache_tail_ptr,
+ PyArray_DTypeMeta *fixed_DType, enum _dtype_discovery_flags *flags)
+{
+ PyArrayObject *arr = NULL;
+ PyObject *seq;
+
+ /*
+ * The first step is to find the DType class if it was not provided,
+ * alternatively we have to find out that this is not a scalar at all
+ * (which could fail and lead us to `object` dtype).
+ */
+ PyArray_DTypeMeta *DType = NULL;
+
+ if (NPY_UNLIKELY(*flags & DISCOVER_STRINGS_AS_SEQUENCES)) {
+ /*
+ * We currently support that bytes/strings are considered sequences,
+ * if the dtype is np.dtype('c'), this should be deprecated probably,
+ * but requires hacks right now.
+ */
+ if (PyBytes_Check(obj) && PyBytes_Size(obj) != 1) {
+ goto force_sequence_due_to_char_dtype;
+ }
+ else if (PyUnicode_Check(obj) && PyUnicode_GetLength(obj) != 1) {
+ goto force_sequence_due_to_char_dtype;
+ }
+ }
+
+ /* If this is a known scalar, find the corresponding DType class */
+ DType = discover_dtype_from_pyobject(obj, flags, fixed_DType);
+ if (DType == NULL) {
+ return -1;
+ }
+ else if (DType == (PyArray_DTypeMeta *)Py_None) {
+ Py_DECREF(Py_None);
+ }
+ else {
+ max_dims = handle_scalar(
+ obj, curr_dims, &max_dims, out_descr, out_shape, fixed_DType,
+ flags, DType);
+ Py_DECREF(DType);
+ return max_dims;
+ }
+
+ /*
+ * At this point we expect to find either a sequence, or an array-like.
+ * Although it is still possible that this fails and we have to use
+ * `object`.
+ */
+ if (PyArray_Check(obj)) {
+ arr = (PyArrayObject *)obj;
+ Py_INCREF(arr);
+ }
+ else {
+ PyArray_Descr *requested_descr = NULL;
+ if (*flags & DESCRIPTOR_WAS_SET) {
+ /* __array__ may be passed the requested descriptor if provided */
+ requested_descr = *out_descr;
+ }
+ arr = (PyArrayObject *)_array_from_array_like(obj,
+ requested_descr, 0, NULL);
+ if (arr == NULL) {
+ return -1;
+ }
+ else if (arr == (PyArrayObject *)Py_NotImplemented) {
+ Py_DECREF(arr);
+ arr = NULL;
+ }
+ else if (curr_dims > 0 && curr_dims != max_dims) {
+ /*
+ * Deprecated 2020-12-09, NumPy 1.20
+ *
+ * See https://github.com/numpy/numpy/issues/17965
+ * Shapely had objects which are not sequences but did export
+ * the array-interface (and so are arguably array-like).
+ * Previously numpy would not use array-like information during
+ * shape discovery, so that it ended up acting as if this was
+ * an (unknown) scalar but with the specified dtype.
+ * Thus we ignore "scalars" here, as the value stored in the
+ * array should be acceptable.
+ */
+ if (PyArray_NDIM(arr) > 0 && NPY_UNLIKELY(!PySequence_Check(obj))) {
+ if (PyErr_WarnFormat(PyExc_FutureWarning, 1,
+ "The input object of type '%s' is an array-like "
+ "implementing one of the corresponding protocols "
+ "(`__array__`, `__array_interface__` or "
+ "`__array_struct__`); but not a sequence (or 0-D). "
+ "In the future, this object will be coerced as if it "
+ "was first converted using `np.array(obj)`. "
+ "To retain the old behaviour, you have to either "
+ "modify the type '%s', or assign to an empty array "
+ "created with `np.empty(correct_shape, dtype=object)`.",
+ Py_TYPE(obj)->tp_name, Py_TYPE(obj)->tp_name) < 0) {
+ Py_DECREF(arr);
+ return -1;
+ }
+ /*
+ * Strangely enough, even though we threw away the result here,
+ * we did use it during descriptor discovery, so promote it:
+ */
+ if (update_shape(curr_dims, &max_dims, out_shape,
+ 0, NULL, NPY_FALSE, flags) < 0) {
+ *flags |= FOUND_RAGGED_ARRAY;
+ Py_DECREF(arr);
+ return max_dims;
+ }
+ if (!(*flags & DESCRIPTOR_WAS_SET) && handle_promotion(
+ out_descr, PyArray_DESCR(arr), fixed_DType, flags) < 0) {
+ Py_DECREF(arr);
+ return -1;
+ }
+ Py_DECREF(arr);
+ return max_dims;
+ }
+ }
+ }
+ if (arr != NULL) {
+ /*
+ * This is an array object which will be added to the cache, keeps
+ * the reference to the array alive (takes ownership).
+ */
+ if (npy_new_coercion_cache(obj, (PyObject *)arr,
+ 0, coercion_cache_tail_ptr, curr_dims) < 0) {
+ return -1;
+ }
+
+ if (curr_dims == 0) {
+ /*
+ * Special case for reverse broadcasting, ignore max_dims if this
+ * is a single array-like object; needed for PyArray_CopyObject.
+ */
+ memcpy(out_shape, PyArray_SHAPE(arr),
+ PyArray_NDIM(arr) * sizeof(npy_intp));
+ max_dims = PyArray_NDIM(arr);
+ }
+ else if (update_shape(curr_dims, &max_dims, out_shape,
+ PyArray_NDIM(arr), PyArray_SHAPE(arr), NPY_FALSE, flags) < 0) {
+ *flags |= FOUND_RAGGED_ARRAY;
+ return max_dims;
+ }
+
+ if (*flags & DESCRIPTOR_WAS_SET) {
+ return max_dims;
+ }
+ /*
+ * For arrays we may not just need to cast the dtype to the user
+ * provided fixed_DType. If this is an object array, the elements
+ * may need to be inspected individually.
+ * Note, this finds the descriptor of the array first and only then
+ * promotes here (different associativity).
+ */
+ PyArray_Descr *cast_descr;
+ if (find_descriptor_from_array(arr, fixed_DType, &cast_descr) < 0) {
+ return -1;
+ }
+ if (cast_descr == NULL) {
+ /* object array with no elements, no need to promote/adjust. */
+ return max_dims;
+ }
+ if (handle_promotion(out_descr, cast_descr, fixed_DType, flags) < 0) {
+ Py_DECREF(cast_descr);
+ return -1;
+ }
+ Py_DECREF(cast_descr);
+ return max_dims;
+ }
+
+ /*
+ * The last step is to assume the input should be handled as a sequence
+ * and to handle it recursively. That is, unless we have hit the
+ * dimension limit.
+ */
+ npy_bool is_sequence = PySequence_Check(obj);
+ if (is_sequence) {
+ is_sequence = PySequence_Size(obj) >= 0;
+ if (NPY_UNLIKELY(!is_sequence)) {
+ /* NOTE: This should likely just raise all errors */
+ if (PyErr_ExceptionMatches(PyExc_RecursionError) ||
+ PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ /*
+ * Consider these unrecoverable errors, continuing execution
+ * might crash the interpreter.
+ */
+ return -1;
+ }
+ PyErr_Clear();
+ }
+ }
+ if (NPY_UNLIKELY(*flags & DISCOVER_TUPLES_AS_ELEMENTS) &&
+ PyTuple_Check(obj)) {
+ is_sequence = NPY_FALSE;
+ }
+ if (curr_dims == max_dims || !is_sequence) {
+ /* Clear any PySequence_Size error which would corrupts further calls */
+ max_dims = handle_scalar(
+ obj, curr_dims, &max_dims, out_descr, out_shape, fixed_DType,
+ flags, NULL);
+ if (is_sequence) {
+ /* Flag as ragged or too deep array */
+ *flags |= FOUND_RAGGED_ARRAY;
+ }
+ return max_dims;
+ }
+ /* If we stop supporting bytes/str subclasses, more may be required here: */
+ assert(!PyBytes_Check(obj) && !PyUnicode_Check(obj));
+
+ force_sequence_due_to_char_dtype:
+
+ /* Ensure we have a sequence (required for PyPy) */
+ seq = PySequence_Fast(obj, "Could not convert object to sequence");
+ if (seq == NULL) {
+ /*
+ * Specifically do not fail on things that look like a dictionary,
+ * instead treat them as scalar.
+ */
+ if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ max_dims = handle_scalar(
+ obj, curr_dims, &max_dims, out_descr, out_shape, fixed_DType,
+ flags, NULL);
+ return max_dims;
+ }
+ return -1;
+ }
+ /* The cache takes ownership of the sequence here. */
+ if (npy_new_coercion_cache(obj, seq, 1, coercion_cache_tail_ptr, curr_dims) < 0) {
+ return -1;
+ }
+
+ npy_intp size = PySequence_Fast_GET_SIZE(seq);
+ PyObject **objects = PySequence_Fast_ITEMS(seq);
+
+ if (update_shape(curr_dims, &max_dims,
+ out_shape, 1, &size, NPY_TRUE, flags) < 0) {
+ /* But do update, if there this is a ragged case */
+ *flags |= FOUND_RAGGED_ARRAY;
+ return max_dims;
+ }
+ if (size == 0) {
+ /* If the sequence is empty, this must be the last dimension */
+ *flags |= MAX_DIMS_WAS_REACHED;
+ return curr_dims + 1;
+ }
+
+ /* Recursive call for each sequence item */
+ for (Py_ssize_t i = 0; i < size; i++) {
+ max_dims = PyArray_DiscoverDTypeAndShape_Recursive(
+ objects[i], curr_dims + 1, max_dims,
+ out_descr, out_shape, coercion_cache_tail_ptr, fixed_DType,
+ flags);
+
+ if (max_dims < 0) {
+ return -1;
+ }
+ }
+ return max_dims;
+}
+
+
+/**
+ * Finds the DType and shape of an arbitrary nested sequence. This is the
+ * general purpose function to find the parameters of the array (but not
+ * the array itself) as returned by `np.array()`
+ *
+ * Note: Before considering to make part of this public, we should consider
+ * whether things such as `out_descr != NULL` should be supported in
+ * a public API.
+ *
+ * @param obj Scalar or nested sequences.
+ * @param max_dims Maximum number of dimensions (after this scalars are forced)
+ * @param out_shape Will be filled with the output shape (more than the actual
+ * shape may be written).
+ * @param coercion_cache NULL initialized reference to a cache pointer.
+ * May be set to the first coercion_cache, and has to be freed using
+ * npy_free_coercion_cache.
+ * This should be stored in a thread-safe manner (i.e. function static)
+ * and is designed to be consumed by `PyArray_AssignFromCache`.
+ * If not consumed, must be freed using `npy_free_coercion_cache`.
+ * @param fixed_DType A user provided fixed DType class.
+ * @param requested_descr A user provided fixed descriptor. This is always
+ * returned as the discovered descriptor, but currently only used
+ * for the ``__array__`` protocol.
+ * @param out_descr Set to the discovered output descriptor. This may be
+ * non NULL but only when fixed_DType/requested_descr are not given.
+ * If non NULL, it is the first dtype being promoted and used if there
+ * are no elements.
+ * The result may be unchanged (remain NULL) when converting a
+ * sequence with no elements. In this case it is callers responsibility
+ * to choose a default.
+ * @return dimensions of the discovered object or -1 on error.
+ * WARNING: If (and only if) the output is a single array, the ndim
+ * returned _can_ exceed the maximum allowed number of dimensions.
+ * It might be nice to deprecate this? But it allows things such as
+ * `arr1d[...] = np.array([[1,2,3,4]])`
+ */
+NPY_NO_EXPORT int
+PyArray_DiscoverDTypeAndShape(
+ PyObject *obj, int max_dims,
+ npy_intp out_shape[NPY_MAXDIMS],
+ coercion_cache_obj **coercion_cache,
+ PyArray_DTypeMeta *fixed_DType, PyArray_Descr *requested_descr,
+ PyArray_Descr **out_descr)
+{
+ coercion_cache_obj **coercion_cache_head = coercion_cache;
+ *coercion_cache = NULL;
+ enum _dtype_discovery_flags flags = 0;
+
+ /*
+ * Support a passed in descriptor (but only if nothing was specified).
+ */
+ assert(*out_descr == NULL || fixed_DType == NULL);
+ /* Validate input of requested descriptor and DType */
+ if (fixed_DType != NULL) {
+ assert(PyObject_TypeCheck(
+ (PyObject *)fixed_DType, (PyTypeObject *)&PyArrayDTypeMeta_Type));
+ }
+
+ if (requested_descr != NULL) {
+ assert(fixed_DType == NPY_DTYPE(requested_descr));
+ /* The output descriptor must be the input. */
+ Py_INCREF(requested_descr);
+ *out_descr = requested_descr;
+ flags |= DESCRIPTOR_WAS_SET;
+ }
+
+ /*
+ * Call the recursive function, the setup for this may need expanding
+ * to handle caching better.
+ */
+
+ /* Legacy discovery flags */
+ if (requested_descr != NULL) {
+ if (requested_descr->type_num == NPY_STRING &&
+ requested_descr->type == 'c') {
+ /* Character dtype variation of string (should be deprecated...) */
+ flags |= DISCOVER_STRINGS_AS_SEQUENCES;
+ }
+ else if (requested_descr->type_num == NPY_VOID &&
+ (requested_descr->names || requested_descr->subarray)) {
+ /* Void is a chimera, in that it may or may not be structured... */
+ flags |= DISCOVER_TUPLES_AS_ELEMENTS;
+ }
+ }
+
+ int ndim = PyArray_DiscoverDTypeAndShape_Recursive(
+ obj, 0, max_dims, out_descr, out_shape, &coercion_cache,
+ fixed_DType, &flags);
+ if (ndim < 0) {
+ goto fail;
+ }
+
+ if (NPY_UNLIKELY(flags & FOUND_RAGGED_ARRAY)) {
+ /*
+ * If max-dims was reached and the dimensions reduced, this is ragged.
+ * Otherwise, we merely reached the maximum dimensions, which is
+ * slightly different. This happens for example for `[1, [2, 3]]`
+ * where the maximum dimensions is 1, but then a sequence found.
+ *
+ * In this case we need to inform the user and clean out the cache
+ * since it may be too deep.
+ */
+
+ /* Handle reaching the maximum depth differently: */
+ int too_deep = ndim == max_dims;
+
+ if (fixed_DType == NULL) {
+ /* This is discovered as object, but deprecated */
+ static PyObject *visibleDeprecationWarning = NULL;
+ npy_cache_import(
+ "numpy", "VisibleDeprecationWarning",
+ &visibleDeprecationWarning);
+ if (visibleDeprecationWarning == NULL) {
+ goto fail;
+ }
+ if (!too_deep) {
+ /* NumPy 1.19, 2019-11-01 */
+ if (PyErr_WarnEx(visibleDeprecationWarning,
+ "Creating an ndarray from ragged nested sequences (which "
+ "is a list-or-tuple of lists-or-tuples-or ndarrays with "
+ "different lengths or shapes) is deprecated. If you "
+ "meant to do this, you must specify 'dtype=object' "
+ "when creating the ndarray.", 1) < 0) {
+ goto fail;
+ }
+ }
+ else {
+ /* NumPy 1.20, 2020-05-08 */
+ /* Note, max_dims should normally always be NPY_MAXDIMS here */
+ if (PyErr_WarnFormat(visibleDeprecationWarning, 1,
+ "Creating an ndarray from nested sequences exceeding "
+ "the maximum number of dimensions of %d is deprecated. "
+ "If you mean to do this, you must specify "
+ "'dtype=object' when creating the ndarray.",
+ max_dims) < 0) {
+ goto fail;
+ }
+ }
+ /* Ensure that ragged arrays always return object dtype */
+ Py_XSETREF(*out_descr, PyArray_DescrFromType(NPY_OBJECT));
+ }
+ else if (fixed_DType->type_num != NPY_OBJECT) {
+ /* Only object DType supports ragged cases unify error */
+
+ /*
+ * We used to let certain ragged arrays pass if they also
+ * support e.g. conversion using `float(arr)`, which currently
+ * works for arrays with only one element.
+ * Thus we catch at least most of such cases here and give a
+ * DeprecationWarning instead of an error.
+ * Note that some of these will actually error later on when
+ * attempting to do the actual assign.
+ */
+ int deprecate_single_element_ragged = 0;
+ coercion_cache_obj *current = *coercion_cache_head;
+ while (current != NULL) {
+ if (current->sequence) {
+ if (current->depth == ndim) {
+ /*
+ * Assume that only array-likes will allow the deprecated
+ * behaviour
+ */
+ deprecate_single_element_ragged = 0;
+ break;
+ }
+ /* check next converted sequence/array-like */
+ current = current->next;
+ continue;
+ }
+ PyArrayObject *arr = (PyArrayObject *)(current->arr_or_sequence);
+ assert(PyArray_NDIM(arr) + current->depth >= ndim);
+ if (PyArray_NDIM(arr) != ndim - current->depth) {
+ /* This array is not compatible with the final shape */
+ if (PyArray_SIZE(arr) != 1) {
+ deprecate_single_element_ragged = 0;
+ break;
+ }
+ deprecate_single_element_ragged = 1;
+ }
+ current = current->next;
+ }
+
+ if (deprecate_single_element_ragged) {
+ /* Deprecated 2020-07-24, NumPy 1.20 */
+ if (DEPRECATE(
+ "setting an array element with a sequence. "
+ "This was supported in some cases where the elements "
+ "are arrays with a single element. For example "
+ "`np.array([1, np.array([2])], dtype=int)`. "
+ "In the future this will raise the same ValueError as "
+ "`np.array([1, [2]], dtype=int)`.") < 0) {
+ goto fail;
+ }
+ }
+ else if (!too_deep) {
+ PyObject *shape = PyArray_IntTupleFromIntp(ndim, out_shape);
+ PyErr_Format(PyExc_ValueError,
+ "setting an array element with a sequence. The "
+ "requested array has an inhomogeneous shape after "
+ "%d dimensions. The detected shape was "
+ "%R + inhomogeneous part.",
+ ndim, shape);
+ Py_DECREF(shape);
+ goto fail;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "setting an array element with a sequence. The "
+ "requested array would exceed the maximum number of "
+ "dimension of %d.",
+ max_dims);
+ goto fail;
+ }
+ }
+
+ /*
+ * If the array is ragged, the cache may be too deep, so clean it.
+ * The cache is left at the same depth as the array though.
+ */
+ coercion_cache_obj **next_ptr = coercion_cache_head;
+ coercion_cache_obj *current = *coercion_cache_head; /* item to check */
+ while (current != NULL) {
+ if (current->depth > ndim) {
+ /* delete "next" cache item and advanced it (unlike later) */
+ current = npy_unlink_coercion_cache(current);
+ continue;
+ }
+ /* advance both prev and next, and set prev->next to new item */
+ *next_ptr = current;
+ next_ptr = &(current->next);
+ current = current->next;
+ }
+ *next_ptr = NULL;
+ }
+ /* We could check here for max-ndims being reached as well */
+
+ if (requested_descr != NULL) {
+ /* descriptor was provided, we did not accidentally change it */
+ assert(*out_descr == requested_descr);
+ }
+ else if (NPY_UNLIKELY(*out_descr == NULL)) {
+ /*
+ * When the object contained no elements (sequence of length zero),
+ * the no descriptor may have been found. When a DType was requested
+ * we use it to define the output dtype.
+ * Otherwise, out_descr will remain NULL and the caller has to set
+ * the correct default.
+ */
+ if (fixed_DType != NULL) {
+ *out_descr = fixed_DType->default_descr(fixed_DType);
+ if (*out_descr == NULL) {
+ goto fail;
+ }
+ }
+ }
+ return ndim;
+
+ fail:
+ npy_free_coercion_cache(*coercion_cache_head);
+ *coercion_cache_head = NULL;
+ Py_XSETREF(*out_descr, NULL);
+ return -1;
+}
+
+
+
+/**
+ * Check the descriptor is a legacy "flexible" DType instance, this is
+ * an instance which is (normally) not attached to an array, such as a string
+ * of length 0 or a datetime with no unit.
+ * These should be largely deprecated, and represent only the DType class
+ * for most `dtype` parameters.
+ *
+ * TODO: This function should eventually recieve a deprecation warning and
+ * be removed.
+ *
+ * @param descr
+ * @return 1 if this is not a concrete dtype instance 0 otherwise
+ */
+static int
+descr_is_legacy_parametric_instance(PyArray_Descr *descr)
+{
+ if (PyDataType_ISUNSIZED(descr)) {
+ return 1;
+ }
+ /* Flexible descr with generic time unit (which can be adapted) */
+ if (PyDataType_ISDATETIME(descr)) {
+ PyArray_DatetimeMetaData *meta;
+ meta = get_datetime_metadata_from_dtype(descr);
+ if (meta->base == NPY_FR_GENERIC) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Given either a DType instance or class, (or legacy flexible instance),
+ * ands sets output dtype instance and DType class. Both results may be
+ * NULL, but if `out_descr` is set `out_DType` will always be the
+ * corresponding class.
+ *
+ * @param dtype
+ * @param out_descr
+ * @param out_DType
+ * @return 0 on success -1 on failure
+ */
+NPY_NO_EXPORT int
+PyArray_ExtractDTypeAndDescriptor(PyObject *dtype,
+ PyArray_Descr **out_descr, PyArray_DTypeMeta **out_DType)
+{
+ *out_DType = NULL;
+ *out_descr = NULL;
+
+ if (dtype != NULL) {
+ if (PyObject_TypeCheck(dtype, (PyTypeObject *)&PyArrayDTypeMeta_Type)) {
+ assert(dtype != (PyObject * )&PyArrayDescr_Type); /* not np.dtype */
+ *out_DType = (PyArray_DTypeMeta *)dtype;
+ Py_INCREF(*out_DType);
+ }
+ else if (PyObject_TypeCheck((PyObject *)Py_TYPE(dtype),
+ (PyTypeObject *)&PyArrayDTypeMeta_Type)) {
+ *out_DType = NPY_DTYPE(dtype);
+ Py_INCREF(*out_DType);
+ if (!descr_is_legacy_parametric_instance((PyArray_Descr *)dtype)) {
+ *out_descr = (PyArray_Descr *)dtype;
+ Py_INCREF(*out_descr);
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "dtype parameter must be a DType instance or class.");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Python API function to expose the dtype+shape discovery functionality
+ * directly.
+ */
+NPY_NO_EXPORT PyObject *
+_discover_array_parameters(PyObject *NPY_UNUSED(self),
+ PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"obj", "dtype", NULL};
+
+ PyObject *obj;
+ PyObject *dtype = NULL;
+ PyArray_Descr *fixed_descriptor = NULL;
+ PyArray_DTypeMeta *fixed_DType = NULL;
+ npy_intp shape[NPY_MAXDIMS];
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, "O|O:_discover_array_parameters", kwlist,
+ &obj, &dtype)) {
+ return NULL;
+ }
+
+ if (PyArray_ExtractDTypeAndDescriptor(dtype,
+ &fixed_descriptor, &fixed_DType) < 0) {
+ return NULL;
+ }
+
+ coercion_cache_obj *coercion_cache = NULL;
+ PyObject *out_dtype = NULL;
+ int ndim = PyArray_DiscoverDTypeAndShape(
+ obj, NPY_MAXDIMS, shape,
+ &coercion_cache,
+ fixed_DType, fixed_descriptor, (PyArray_Descr **)&out_dtype);
+ Py_XDECREF(fixed_DType);
+ Py_XDECREF(fixed_descriptor);
+ if (ndim < 0) {
+ return NULL;
+ }
+ npy_free_coercion_cache(coercion_cache);
+ if (out_dtype == NULL) {
+ /* Empty sequence, report this as None. */
+ out_dtype = Py_None;
+ Py_INCREF(Py_None);
+ }
+
+ PyObject *shape_tuple = PyArray_IntTupleFromIntp(ndim, shape);
+ if (shape_tuple == NULL) {
+ return NULL;
+ }
+
+ PyObject *res = PyTuple_Pack(2, (PyObject *)out_dtype, shape_tuple);
+ Py_DECREF(out_dtype);
+ Py_DECREF(shape_tuple);
+ return res;
+}
--- /dev/null
+#ifndef _NPY_ARRAY_COERCION_H
+#define _NPY_ARRAY_COERCION_H
+
+
+/*
+ * We do not want to coerce arrays many times unless absolutely necessary.
+ * The same goes for sequences, so everything we have seen, we will have
+ * to store somehow. This is a linked list of these objects.
+ */
+typedef struct coercion_cache_obj {
+ PyObject *converted_obj;
+ PyObject *arr_or_sequence;
+ struct coercion_cache_obj *next;
+ npy_bool sequence;
+ int depth; /* the dimension at which this object was found. */
+} coercion_cache_obj;
+
+
+NPY_NO_EXPORT int
+_PyArray_MapPyTypeToDType(
+ PyArray_DTypeMeta *DType, PyTypeObject *pytype, npy_bool userdef);
+
+NPY_NO_EXPORT int
+PyArray_Pack(PyArray_Descr *descr, char *item, PyObject *value);
+
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_AdaptDescriptorToArray(PyArrayObject *arr, PyObject *dtype);
+
+NPY_NO_EXPORT int
+PyArray_DiscoverDTypeAndShape(
+ PyObject *obj, int max_dims,
+ npy_intp out_shape[NPY_MAXDIMS],
+ coercion_cache_obj **coercion_cache,
+ PyArray_DTypeMeta *fixed_DType, PyArray_Descr *requested_descr,
+ PyArray_Descr **out_descr);
+
+NPY_NO_EXPORT int
+PyArray_ExtractDTypeAndDescriptor(PyObject *dtype,
+ PyArray_Descr **out_descr, PyArray_DTypeMeta **out_DType);
+
+NPY_NO_EXPORT PyObject *
+_discover_array_parameters(PyObject *NPY_UNUSED(self),
+ PyObject *args, PyObject *kwargs);
+
+
+/* Would make sense to inline the freeing functions everywhere */
+/* Frees the coercion cache object recursively. */
+NPY_NO_EXPORT void
+npy_free_coercion_cache(coercion_cache_obj *first);
+
+/* unlink a single item and return the next */
+NPY_NO_EXPORT coercion_cache_obj *
+npy_unlink_coercion_cache(coercion_cache_obj *current);
+
+NPY_NO_EXPORT int
+PyArray_AssignFromCache(PyArrayObject *self, coercion_cache_obj *cache);
+
+#endif /* _NPY_ARRAY_COERCION_H */
--- /dev/null
+/*
+ * This file implements an abstraction layer for "Array methods", which
+ * work with a specific DType class input and provide low-level C function
+ * pointers to do fast operations on the given input functions.
+ * It thus adds an abstraction layer around individual ufunc loops.
+ *
+ * Unlike methods, a ArrayMethod can have multiple inputs and outputs.
+ * This has some serious implication for garbage collection, and as far
+ * as I (@seberg) understands, it is not possible to always guarantee correct
+ * cyclic garbage collection of dynamically created DTypes with methods.
+ * The keyword (or rather the solution) for this seems to be an "ephemeron"
+ * which I believe should allow correct garbage collection but seems
+ * not implemented in Python at this time.
+ * The vast majority of use-cases will not require correct garbage collection.
+ * Some use cases may require the user to be careful.
+ *
+ * Generally there are two main ways to solve this issue:
+ *
+ * 1. A method with a single input (or inputs of all the same DTypes) can
+ * be "owned" by that DType (it becomes unusable when the DType is deleted).
+ * This holds especially for all casts, which must have a defined output
+ * DType and must hold on to it strongly.
+ * 2. A method which can infer the output DType(s) from the input types does
+ * not need to keep the output type alive. (It can use NULL for the type,
+ * or an abstract base class which is known to be persistent.)
+ * It is then sufficient for a ufunc (or other owner) to only hold a
+ * weak reference to the input DTypes.
+ */
+
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _MULTIARRAYMODULE
+#include <npy_pycompat.h>
+#include "arrayobject.h"
+#include "array_method.h"
+#include "dtypemeta.h"
+#include "convert_datatype.h"
+
+
+/*
+ * The default descriptor resolution function. The logic is as follows:
+ *
+ * 1. The output is ensured to be canonical (currently native byte order),
+ * if it is of the correct DType.
+ * 2. If any DType is was not defined, it is replaced by the common DType
+ * of all inputs. (If that common DType is parametric, this is an error.)
+ *
+ * We could allow setting the output descriptors specifically to simplify
+ * this step.
+ */
+static NPY_CASTING
+default_resolve_descriptors(
+ PyArrayMethodObject *method,
+ PyArray_DTypeMeta **dtypes,
+ PyArray_Descr **input_descrs,
+ PyArray_Descr **output_descrs)
+{
+ int nin = method->nin;
+ int nout = method->nout;
+ int all_defined = 1;
+
+ for (int i = 0; i < nin + nout; i++) {
+ PyArray_DTypeMeta *dtype = dtypes[i];
+ if (dtype == NULL) {
+ output_descrs[i] = NULL;
+ all_defined = 0;
+ continue;
+ }
+ if (NPY_DTYPE(input_descrs[i]) == dtype) {
+ output_descrs[i] = ensure_dtype_nbo(input_descrs[i]);
+ }
+ else {
+ output_descrs[i] = dtype->default_descr(dtype);
+ }
+ if (NPY_UNLIKELY(output_descrs[i] == NULL)) {
+ goto fail;
+ }
+ }
+ if (all_defined) {
+ return method->casting;
+ }
+
+ if (NPY_UNLIKELY(nin == 0 || dtypes[0] == NULL)) {
+ /* Registration should reject this, so this would be indicates a bug */
+ PyErr_SetString(PyExc_RuntimeError,
+ "Invalid use of default resolver without inputs or with "
+ "input or output DType incorrectly missing.");
+ goto fail;
+ }
+ /* We find the common dtype of all inputs, and use it for the unknowns */
+ PyArray_DTypeMeta *common_dtype = dtypes[0];
+ assert(common_dtype != NULL);
+ for (int i = 1; i < nin; i++) {
+ Py_SETREF(common_dtype, PyArray_CommonDType(common_dtype, dtypes[i]));
+ if (common_dtype == NULL) {
+ goto fail;
+ }
+ }
+ for (int i = nin; i < nin + nout; i++) {
+ if (output_descrs[i] != NULL) {
+ continue;
+ }
+ if (NPY_DTYPE(input_descrs[i]) == common_dtype) {
+ output_descrs[i] = ensure_dtype_nbo(input_descrs[i]);
+ }
+ else {
+ output_descrs[i] = common_dtype->default_descr(common_dtype);
+ }
+ if (NPY_UNLIKELY(output_descrs[i] == NULL)) {
+ goto fail;
+ }
+ }
+
+ return method->casting;
+
+ fail:
+ for (int i = 0; i < nin + nout; i++) {
+ Py_XDECREF(output_descrs[i]);
+ }
+ return -1;
+}
+
+
+/**
+ * The default method to fetch the correct loop for a cast or ufunc
+ * (at the time of writing only casts).
+ * The default version can return loops explicitly registered during method
+ * creation. It does specialize contiguous loops, although has to check
+ * all descriptors itemsizes for this.
+ *
+ * @param context
+ * @param aligned
+ * @param move_references UNUSED.
+ * @param strides
+ * @param descriptors
+ * @param out_loop
+ * @param out_transferdata
+ * @param flags
+ * @return 0 on success -1 on failure.
+ */
+static int
+default_get_strided_loop(
+ PyArrayMethod_Context *NPY_UNUSED(context),
+ int NPY_UNUSED(aligned), int NPY_UNUSED(move_references),
+ npy_intp *NPY_UNUSED(strides),
+ PyArray_StridedUnaryOp **NPY_UNUSED(out_loop),
+ NpyAuxData **NPY_UNUSED(out_transferdata),
+ NPY_ARRAYMETHOD_FLAGS *NPY_UNUSED(flags))
+{
+ PyErr_SetString(PyExc_NotImplementedError,
+ "default loop getter is not implemented");
+ return -1;
+}
+
+
+/**
+ * Validate that the input is usable to create a new ArrayMethod.
+ *
+ * @param spec
+ * @return 0 on success -1 on error.
+ */
+static int
+validate_spec(PyArrayMethod_Spec *spec)
+{
+ int nargs = spec->nin + spec->nout;
+ /* Check the passed spec for invalid fields/values */
+ if (spec->nin < 0 || spec->nout < 0 || nargs > NPY_MAXARGS) {
+ PyErr_Format(PyExc_ValueError,
+ "ArrayMethod inputs and outputs must be greater zero and"
+ "not exceed %d. (method: %s)", NPY_MAXARGS, spec->name);
+ return -1;
+ }
+ switch (spec->casting & ~_NPY_CAST_IS_VIEW) {
+ case NPY_NO_CASTING:
+ case NPY_EQUIV_CASTING:
+ case NPY_SAFE_CASTING:
+ case NPY_SAME_KIND_CASTING:
+ case NPY_UNSAFE_CASTING:
+ break;
+ default:
+ PyErr_Format(PyExc_TypeError,
+ "ArrayMethod has invalid casting `%d`. (method: %s)",
+ spec->casting, spec->name);
+ return -1;
+ }
+
+ for (int i = 0; i < nargs; i++) {
+ if (spec->dtypes[i] == NULL && i < spec->nin) {
+ PyErr_Format(PyExc_TypeError,
+ "ArrayMethod must have well defined input DTypes. "
+ "(method: %s)", spec->name);
+ return -1;
+ }
+ if (!PyObject_TypeCheck(spec->dtypes[i], &PyArrayDTypeMeta_Type)) {
+ PyErr_Format(PyExc_TypeError,
+ "ArrayMethod provided object %R is not a DType."
+ "(method: %s)", spec->dtypes[i], spec->name);
+ return -1;
+ }
+ if (spec->dtypes[i]->abstract && i < spec->nin) {
+ PyErr_Format(PyExc_TypeError,
+ "abstract DType %S are currently not allowed for inputs."
+ "(method: %s defined at %s)", spec->dtypes[i], spec->name);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Initialize a new BoundArrayMethodObject from slots. Slots which are
+ * not provided may be filled with defaults.
+ *
+ * @param res The new PyBoundArrayMethodObject to be filled.
+ * @param spec The specification list passed by the user.
+ * @param private Private flag to limit certain slots to use in NumPy.
+ * @return -1 on error 0 on success
+ */
+static int
+fill_arraymethod_from_slots(
+ PyBoundArrayMethodObject *res, PyArrayMethod_Spec *spec,
+ int private)
+{
+ PyArrayMethodObject *meth = res->method;
+
+ /* Set the defaults */
+ meth->get_strided_loop = &default_get_strided_loop;
+ meth->resolve_descriptors = &default_resolve_descriptors;
+
+ /* Fill in the slots passed by the user */
+ /*
+ * TODO: This is reasonable for now, but it would be nice to find a
+ * shorter solution, and add some additional error checking (e.g.
+ * the same slot used twice). Python uses an array of slot offsets.
+ */
+ for (PyType_Slot *slot = &spec->slots[0]; slot->slot != 0; slot++) {
+ switch (slot->slot) {
+ case NPY_METH_resolve_descriptors:
+ meth->resolve_descriptors = slot->pfunc;
+ continue;
+ case NPY_METH_get_loop:
+ if (private) {
+ /* Only allow override for private functions initially */
+ meth->get_strided_loop = slot->pfunc;
+ continue;
+ }
+ break;
+ case NPY_METH_strided_loop:
+ meth->strided_loop = slot->pfunc;
+ continue;
+ case NPY_METH_contiguous_loop:
+ meth->contiguous_loop = slot->pfunc;
+ continue;
+ case NPY_METH_unaligned_strided_loop:
+ meth->unaligned_strided_loop = slot->pfunc;
+ continue;
+ case NPY_METH_unaligned_contiguous_loop:
+ meth->unaligned_contiguous_loop = slot->pfunc;
+ continue;
+ default:
+ break;
+ }
+ PyErr_Format(PyExc_RuntimeError,
+ "invalid slot number %d to ArrayMethod: %s",
+ slot->slot, spec->name);
+ return -1;
+ }
+
+ /* Check whether the slots are valid: */
+ if (meth->resolve_descriptors == &default_resolve_descriptors) {
+ for (int i = 0; i < meth->nin + meth->nout; i++) {
+ if (res->dtypes[i] == NULL) {
+ if (i < meth->nin) {
+ PyErr_Format(PyExc_TypeError,
+ "All input DTypes must be specified when using "
+ "the default `resolve_descriptors` function. "
+ "(method: %s)", spec->name);
+ return -1;
+ }
+ else if (meth->nin == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "Must specify output DTypes or use custom "
+ "`resolve_descriptors` when there are no inputs. "
+ "(method: %s defined at %s)", spec->name);
+ return -1;
+ }
+ }
+ if (i >= meth->nin && res->dtypes[i]->parametric) {
+ PyErr_Format(PyExc_TypeError,
+ "must provide a `resolve_descriptors` function if any "
+ "output DType is parametric. (method: %s)",
+ spec->name);
+ return -1;
+ }
+ }
+ }
+ if (meth->get_strided_loop != &default_get_strided_loop) {
+ /* Do not check the actual loop fields. */
+ return 0;
+ }
+
+ /* Check whether the provided loops make sense. */
+ if (meth->strided_loop == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "Must provide a strided inner loop function. (method: %s)",
+ spec->name);
+ return -1;
+ }
+ if (meth->contiguous_loop == NULL) {
+ meth->contiguous_loop = meth->strided_loop;
+ }
+ if (meth->unaligned_contiguous_loop != NULL &&
+ meth->unaligned_strided_loop == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "Must provide unaligned strided inner loop when providing "
+ "a contiguous version. (method: %s)", spec->name);
+ return -1;
+ }
+ if ((meth->unaligned_strided_loop == NULL) !=
+ !(meth->flags & NPY_METH_SUPPORTS_UNALIGNED)) {
+ PyErr_Format(PyExc_TypeError,
+ "Must provide unaligned strided inner loop when providing "
+ "a contiguous version. (method: %s)", spec->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Create a new ArrayMethod (internal version).
+ *
+ * @param name A name for the individual method, may be NULL.
+ * @param spec A filled context object to pass generic information about
+ * the method (such as usually needing the API, and the DTypes).
+ * Unused fields must be NULL.
+ * @param slots Slots with the correct pair of IDs and (function) pointers.
+ * @param private Some slots are currently considered private, if not true,
+ * these will be rejected.
+ *
+ * @returns A new (bound) ArrayMethod object.
+ */
+NPY_NO_EXPORT PyBoundArrayMethodObject *
+PyArrayMethod_FromSpec_int(PyArrayMethod_Spec *spec, int private)
+{
+ int nargs = spec->nin + spec->nout;
+
+ if (spec->name == NULL) {
+ spec->name = "<unknown>";
+ }
+
+ if (validate_spec(spec) < 0) {
+ return NULL;
+ }
+
+ PyBoundArrayMethodObject *res;
+ res = PyObject_New(PyBoundArrayMethodObject, &PyBoundArrayMethod_Type);
+ if (res == NULL) {
+ return NULL;
+ }
+ res->method = NULL;
+
+ res->dtypes = PyMem_Malloc(sizeof(PyArray_DTypeMeta *) * nargs);
+ if (res->dtypes == NULL) {
+ Py_DECREF(res);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ for (int i = 0; i < nargs ; i++) {
+ Py_XINCREF(spec->dtypes[i]);
+ res->dtypes[i] = spec->dtypes[i];
+ }
+
+ res->method = PyObject_New(PyArrayMethodObject, &PyArrayMethod_Type);
+ if (res->method == NULL) {
+ Py_DECREF(res);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ memset((char *)(res->method) + sizeof(PyObject), 0,
+ sizeof(PyArrayMethodObject) - sizeof(PyObject));
+
+ res->method->nin = spec->nin;
+ res->method->nout = spec->nout;
+ res->method->flags = spec->flags;
+ res->method->casting = spec->casting;
+ if (fill_arraymethod_from_slots(res, spec, private) < 0) {
+ Py_DECREF(res);
+ return NULL;
+ }
+
+ ssize_t length = strlen(spec->name);
+ res->method->name = PyMem_Malloc(length + 1);
+ if (res->method->name == NULL) {
+ Py_DECREF(res);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ strcpy(res->method->name, spec->name);
+
+ return res;
+}
+
+
+static void
+arraymethod_dealloc(PyObject *self)
+{
+ PyArrayMethodObject *meth;
+ meth = ((PyArrayMethodObject *)self);
+
+ PyMem_Free(meth->name);
+
+ Py_TYPE(self)->tp_free(self);
+}
+
+
+NPY_NO_EXPORT PyTypeObject PyArrayMethod_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "numpy._ArrayMethod",
+ .tp_basicsize = sizeof(PyArrayMethodObject),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_dealloc = arraymethod_dealloc,
+};
+
+
+
+static PyObject *
+boundarraymethod_repr(PyBoundArrayMethodObject *self)
+{
+ int nargs = self->method->nin + self->method->nout;
+ PyObject *dtypes = PyTuple_New(nargs);
+ if (dtypes == NULL) {
+ return NULL;
+ }
+ for (int i = 0; i < nargs; i++) {
+ Py_INCREF(self->dtypes[i]);
+ PyTuple_SET_ITEM(dtypes, i, (PyObject *)self->dtypes[i]);
+ }
+ return PyUnicode_FromFormat(
+ "<np._BoundArrayMethod `%s` for dtypes %S>",
+ self->method->name, dtypes);
+}
+
+
+static void
+boundarraymethod_dealloc(PyObject *self)
+{
+ PyBoundArrayMethodObject *meth;
+ meth = ((PyBoundArrayMethodObject *)self);
+ int nargs = meth->method->nin + meth->method->nout;
+
+ for (int i = 0; i < nargs; i++) {
+ Py_XDECREF(meth->dtypes[i]);
+ }
+ PyMem_Free(meth->dtypes);
+
+ Py_XDECREF(meth->method);
+
+ Py_TYPE(self)->tp_free(self);
+}
+
+
+/*
+ * Calls resolve_descriptors() and returns the casting level and the resolved
+ * descriptors as a tuple. If the operation is impossible returns (-1, None).
+ * May raise an error, but usually should not.
+ * The function validates the casting attribute compared to the returned
+ * casting level.
+ */
+static PyObject *
+boundarraymethod__resolve_descripors(
+ PyBoundArrayMethodObject *self, PyObject *descr_tuple)
+{
+ int nin = self->method->nin;
+ int nout = self->method->nout;
+
+ PyArray_Descr *given_descrs[NPY_MAXARGS];
+ PyArray_Descr *loop_descrs[NPY_MAXARGS];
+
+ if (!PyTuple_CheckExact(descr_tuple) ||
+ PyTuple_Size(descr_tuple) != nin + nout) {
+ PyErr_Format(PyExc_ValueError,
+ "_resolve_descriptors() takes exactly one tuple with as many "
+ "elements as the method takes arguments (%d+%d).", nin, nout);
+ return NULL;
+ }
+
+ for (int i = 0; i < nin + nout; i++) {
+ PyObject *tmp = PyTuple_GetItem(descr_tuple, i);
+ if (tmp == NULL) {
+ return NULL;
+ }
+ else if (tmp == Py_None) {
+ if (i < nin) {
+ PyErr_SetString(PyExc_ValueError,
+ "only output dtypes may be omitted (set to None).");
+ return NULL;
+ }
+ given_descrs[i] = NULL;
+ }
+ else if (PyArray_DescrCheck(tmp)) {
+ if (Py_TYPE(tmp) != (PyTypeObject *)self->dtypes[i]) {
+ PyErr_Format(PyExc_ValueError,
+ "input dtype %S was not an exact instance of the bound "
+ "DType class %S.", tmp, self->dtypes[i]);
+ return NULL;
+ }
+ given_descrs[i] = (PyArray_Descr *)tmp;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "dtype tuple can only contain dtype instances or None.");
+ return NULL;
+ }
+ }
+
+ NPY_CASTING casting = self->method->resolve_descriptors(
+ self->method, self->dtypes, given_descrs, loop_descrs);
+
+ if (casting < 0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ else if (casting < 0) {
+ return Py_BuildValue("iO", casting, Py_None);
+ }
+
+ PyObject *result_tuple = PyTuple_New(nin + nout);
+ if (result_tuple == NULL) {
+ return NULL;
+ }
+ for (int i = 0; i < nin + nout; i++) {
+ /* transfer ownership to the tuple. */
+ PyTuple_SET_ITEM(result_tuple, i, (PyObject *)loop_descrs[i]);
+ }
+
+ /*
+ * The casting flags should be the most generic casting level (except the
+ * cast-is-view flag. If no input is parametric, it must match exactly.
+ */
+ int parametric = 0;
+ for (int i = 0; i < nin + nout; i++) {
+ if (self->dtypes[i]->parametric) {
+ parametric = 1;
+ break;
+ }
+ }
+ if (!parametric) {
+ /*
+ * Non-parametric can only mismatch if it switches from no to equiv
+ * (e.g. due to byteorder changes).
+ */
+ if (self->method->casting != (casting & ~_NPY_CAST_IS_VIEW) &&
+ !(self->method->casting == NPY_NO_CASTING &&
+ casting == NPY_EQUIV_CASTING)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "resolve_descriptors cast level did not match stored one "
+ "(expected %d, got %d) for method %s",
+ self->method->casting, (casting & ~_NPY_CAST_IS_VIEW),
+ self->method->name);
+ Py_DECREF(result_tuple);
+ return NULL;
+ }
+ }
+ else {
+ NPY_CASTING cast = casting & ~_NPY_CAST_IS_VIEW;
+ if (cast != PyArray_MinCastSafety(cast, self->method->casting)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "resolve_descriptors cast level did not match stored one "
+ "(expected %d, got %d) for method %s",
+ self->method->casting, (casting & ~_NPY_CAST_IS_VIEW),
+ self->method->name);
+ Py_DECREF(result_tuple);
+ return NULL;
+ }
+ }
+
+ return Py_BuildValue("iN", casting, result_tuple);
+}
+
+
+PyMethodDef boundarraymethod_methods[] = {
+ {"_resolve_descriptors", (PyCFunction)boundarraymethod__resolve_descripors,
+ METH_O, "Resolve the given dtypes."},
+ {NULL, 0, 0, NULL},
+};
+
+
+static PyObject *
+boundarraymethod__supports_unaligned(PyBoundArrayMethodObject *self)
+{
+ return PyBool_FromLong(self->method->flags & NPY_METH_SUPPORTS_UNALIGNED);
+}
+
+
+PyGetSetDef boundarraymethods_getters[] = {
+ {"_supports_unaligned",
+ (getter)boundarraymethod__supports_unaligned, NULL,
+ "whether the method supports unaligned inputs/outputs.", NULL},
+ {NULL, NULL, NULL, NULL, NULL},
+};
+
+
+NPY_NO_EXPORT PyTypeObject PyBoundArrayMethod_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "numpy._BoundArrayMethod",
+ .tp_basicsize = sizeof(PyBoundArrayMethodObject),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_repr = (reprfunc)boundarraymethod_repr,
+ .tp_dealloc = boundarraymethod_dealloc,
+ .tp_methods = boundarraymethod_methods,
+ .tp_getset = boundarraymethods_getters,
+};
--- /dev/null
+#ifndef _NPY_ARRAY_METHOD_H
+#define _NPY_ARRAY_METHOD_H
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _MULTIARRAYMODULE
+
+#include <Python.h>
+#include <numpy/ndarraytypes.h>
+#include <lowlevel_strided_loops.h>
+
+
+typedef enum {
+ /* Flag for whether the GIL is required */
+ NPY_METH_REQUIRES_PYAPI = 1 << 1,
+ /*
+ * Some functions cannot set floating point error flags, this flag
+ * gives us the option (not requirement) to skip floating point error
+ * setup/check. No function should set error flags and ignore them
+ * since it would interfere with chaining operations (e.g. casting).
+ */
+ NPY_METH_NO_FLOATINGPOINT_ERRORS = 1 << 2,
+ /* Whether the method supports unaligned access (not runtime) */
+ NPY_METH_SUPPORTS_UNALIGNED = 1 << 3,
+
+ /* All flags which can change at runtime */
+ NPY_METH_RUNTIME_FLAGS = (
+ NPY_METH_REQUIRES_PYAPI |
+ NPY_METH_NO_FLOATINGPOINT_ERRORS),
+} NPY_ARRAYMETHOD_FLAGS;
+
+
+struct PyArrayMethodObject_tag;
+
+/*
+ * This struct is specific to an individual (possibly repeated) call of
+ * the ArrayMethods strided operator, and as such is passed into the various
+ * methods of the ArrayMethod object (the resolve_descriptors function,
+ * the get_loop function and the individual lowlevel strided operator calls).
+ * It thus has to be persistent for one end-user call, and then be discarded.
+ *
+ * TODO: Before making this public, we should review which information should
+ * be stored on the Context/BoundArrayMethod vs. the ArrayMethod.
+ */
+typedef struct {
+ PyObject *caller; /* E.g. the original ufunc, may be NULL */
+ struct PyArrayMethodObject_tag *method;
+
+ /* Operand descriptors, filled in by resolve_descriptors */
+ PyArray_Descr **descriptors;
+} PyArrayMethod_Context;
+
+
+typedef NPY_CASTING (resolve_descriptors_function)(
+ struct PyArrayMethodObject_tag *method,
+ PyArray_DTypeMeta **dtypes,
+ PyArray_Descr **given_descrs,
+ PyArray_Descr **loop_descrs);
+
+
+typedef int (get_loop_function)(
+ PyArrayMethod_Context *context,
+ int aligned, int move_references,
+ npy_intp *strides,
+ PyArray_StridedUnaryOp **out_loop,
+ NpyAuxData **out_transferdata,
+ NPY_ARRAYMETHOD_FLAGS *flags);
+
+
+/*
+ * This struct will be public and necessary for creating a new ArrayMethod
+ * object (casting and ufuncs).
+ * We could version the struct, although since we allow passing arbitrary
+ * data using the slots, and have flags, that may be enough?
+ * (See also PyBoundArrayMethodObject.)
+ */
+typedef struct {
+ const char *name;
+ int nin, nout;
+ NPY_CASTING casting;
+ NPY_ARRAYMETHOD_FLAGS flags;
+ PyArray_DTypeMeta **dtypes;
+ PyType_Slot *slots;
+} PyArrayMethod_Spec;
+
+
+/*
+ * Structure of the ArrayMethod. This structure should probably not be made
+ * public. If necessary, we can make certain operations on it public
+ * (e.g. to allow users indirect access to `get_strided_loop`).
+ *
+ * NOTE: In some cases, it may not be clear whether information should be
+ * stored here or on the bound version. E.g. `nin` and `nout` (and in the
+ * future the gufunc `signature`) is already stored on the ufunc so that
+ * storing these here duplicates the information.
+ */
+typedef struct PyArrayMethodObject_tag {
+ PyObject_HEAD
+ char *name;
+ int nin, nout;
+ /* Casting is normally "safe" for functions, but is important for casts */
+ NPY_CASTING casting;
+ /* default flags. The get_strided_loop function can override these */
+ NPY_ARRAYMETHOD_FLAGS flags;
+ resolve_descriptors_function *resolve_descriptors;
+ get_loop_function *get_strided_loop;
+ /* Typical loop functions (contiguous ones are used in current casts) */
+ PyArray_StridedUnaryOp *strided_loop;
+ PyArray_StridedUnaryOp *contiguous_loop;
+ PyArray_StridedUnaryOp *unaligned_strided_loop;
+ PyArray_StridedUnaryOp *unaligned_contiguous_loop;
+} PyArrayMethodObject;
+
+
+/*
+ * We will sometimes have to create a ArrayMethod and allow passing it around,
+ * similar to `instance.method` returning a bound method, e.g. a function like
+ * `ufunc.resolve()` can return a bound object.
+ * The current main purpose of the BoundArrayMethod is that it holds on to the
+ * `dtypes` (the classes), so that the `ArrayMethod` (e.g. for casts) will
+ * not create references cycles. In principle, it could hold any information
+ * which is also stored on the ufunc (and thus does not need to be repeated
+ * on the `ArrayMethod` itself.
+ */
+typedef struct {
+ PyObject_HEAD
+ PyArray_DTypeMeta **dtypes;
+ PyArrayMethodObject *method;
+} PyBoundArrayMethodObject;
+
+
+extern NPY_NO_EXPORT PyTypeObject PyArrayMethod_Type;
+extern NPY_NO_EXPORT PyTypeObject PyBoundArrayMethod_Type;
+
+/*
+ * SLOTS IDs For the ArrayMethod creation, one public, the IDs are fixed.
+ * TODO: Before making it public, consider adding a large constant to private
+ * slots.
+ */
+#define NPY_METH_resolve_descriptors 1
+#define NPY_METH_get_loop 2
+#define NPY_METH_strided_loop 3
+#define NPY_METH_contiguous_loop 4
+#define NPY_METH_unaligned_strided_loop 5
+#define NPY_METH_unaligned_contiguous_loop 6
+
+
+NPY_NO_EXPORT PyBoundArrayMethodObject *
+PyArrayMethod_FromSpec_int(PyArrayMethod_Spec *spec, int private);
+
+#endif /*_NPY_ARRAY_METHOD_H*/
get_array_function(PyObject *obj)
{
static PyObject *ndarray_array_function = NULL;
- PyObject *array_function;
if (ndarray_array_function == NULL) {
ndarray_array_function = get_ndarray_array_function();
return ndarray_array_function;
}
- array_function = PyArray_LookupSpecial(obj, "__array_function__");
+ PyObject *array_function = PyArray_LookupSpecial(obj, "__array_function__");
if (array_function == NULL && PyErr_Occurred()) {
PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */
}
static void
pyobject_array_insert(PyObject **array, int length, int index, PyObject *item)
{
- int j;
-
- for (j = length; j > index; j--) {
+ for (int j = length; j > index; j--) {
array[j] = array[j - 1];
}
array[index] = item;
PyObject **methods)
{
int num_implementing_args = 0;
- Py_ssize_t i;
- int j;
PyObject **items = PySequence_Fast_ITEMS(relevant_args);
Py_ssize_t length = PySequence_Fast_GET_SIZE(relevant_args);
- for (i = 0; i < length; i++) {
+ for (Py_ssize_t i = 0; i < length; i++) {
int new_class = 1;
PyObject *argument = items[i];
/* Have we seen this type before? */
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
if (Py_TYPE(argument) == Py_TYPE(implementing_args[j])) {
new_class = 0;
break;
/* "subclasses before superclasses, otherwise left to right" */
arg_index = num_implementing_args;
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
PyObject *other_type;
other_type = (PyObject *)Py_TYPE(implementing_args[j]);
if (PyObject_IsInstance(argument, other_type)) {
return num_implementing_args;
fail:
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
Py_DECREF(implementing_args[j]);
Py_DECREF(methods[j]);
}
array_function_method_impl(PyObject *func, PyObject *types, PyObject *args,
PyObject *kwargs)
{
- Py_ssize_t j;
- PyObject *implementation, *result;
-
PyObject **items = PySequence_Fast_ITEMS(types);
Py_ssize_t length = PySequence_Fast_GET_SIZE(types);
- for (j = 0; j < length; j++) {
+ for (Py_ssize_t j = 0; j < length; j++) {
int is_subclass = PyObject_IsSubclass(
items[j], (PyObject *)&PyArray_Type);
if (is_subclass == -1) {
}
}
- implementation = PyObject_GetAttr(func, npy_ma_str_implementation);
+ PyObject *implementation = PyObject_GetAttr(func, npy_ma_str_implementation);
if (implementation == NULL) {
return NULL;
}
- result = PyObject_Call(implementation, args, kwargs);
+ PyObject *result = PyObject_Call(implementation, args, kwargs);
Py_DECREF(implementation);
return result;
}
}
-/*
- * Implements the __array_function__ protocol for a function, as described in
- * in NEP-18. See numpy.core.overrides for a full docstring.
+/**
+ * Internal handler for the array-function dispatching. The helper returns
+ * either the result, or NotImplemented (as a borrowed reference).
+ *
+ * @param public_api The public API symbol used for dispatching
+ * @param relevant_args Arguments which may implement __array_function__
+ * @param args Original arguments
+ * @param kwargs Original keyword arguments
+ *
+ * @returns The result of the dispatched version, or a borrowed reference
+ * to NotImplemented to indicate the default implementation should
+ * be used.
*/
NPY_NO_EXPORT PyObject *
-array_implement_array_function(
- PyObject *NPY_UNUSED(dummy), PyObject *positional_args)
+array_implement_array_function_internal(
+ PyObject *public_api, PyObject *relevant_args,
+ PyObject *args, PyObject *kwargs)
{
- PyObject *implementation, *public_api, *relevant_args, *args, *kwargs;
-
- PyObject *types = NULL;
PyObject *implementing_args[NPY_MAXARGS];
PyObject *array_function_methods[NPY_MAXARGS];
+ PyObject *types = NULL;
- int j, any_overrides;
- int num_implementing_args = 0;
PyObject *result = NULL;
static PyObject *errmsg_formatter = NULL;
- if (!PyArg_UnpackTuple(
- positional_args, "implement_array_function", 5, 5,
- &implementation, &public_api, &relevant_args, &args, &kwargs)) {
- return NULL;
- }
-
relevant_args = PySequence_Fast(
relevant_args,
"dispatcher for __array_function__ did not return an iterable");
}
/* Collect __array_function__ implementations */
- num_implementing_args = get_implementing_args_and_methods(
+ int num_implementing_args = get_implementing_args_and_methods(
relevant_args, implementing_args, array_function_methods);
if (num_implementing_args == -1) {
goto cleanup;
* arguments implement __array_function__ at all (e.g., if they are all
* built-in types).
*/
- any_overrides = 0;
- for (j = 0; j < num_implementing_args; j++) {
+ int any_overrides = 0;
+ for (int j = 0; j < num_implementing_args; j++) {
if (!is_default_array_function(array_function_methods[j])) {
any_overrides = 1;
break;
}
}
if (!any_overrides) {
- result = PyObject_Call(implementation, args, kwargs);
+ /*
+ * When the default implementation should be called, return
+ * `Py_NotImplemented` to indicate this.
+ */
+ result = Py_NotImplemented;
goto cleanup;
}
if (types == NULL) {
goto cleanup;
}
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
PyObject *arg_type = (PyObject *)Py_TYPE(implementing_args[j]);
Py_INCREF(arg_type);
PyTuple_SET_ITEM(types, j, arg_type);
}
/* Call __array_function__ methods */
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
PyObject *argument = implementing_args[j];
PyObject *method = array_function_methods[j];
}
cleanup:
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
Py_DECREF(implementing_args[j]);
Py_DECREF(array_function_methods[j]);
}
}
+/*
+ * Implements the __array_function__ protocol for a Python function, as described in
+ * in NEP-18. See numpy.core.overrides for a full docstring.
+ */
+NPY_NO_EXPORT PyObject *
+array_implement_array_function(
+ PyObject *NPY_UNUSED(dummy), PyObject *positional_args)
+{
+ PyObject *implementation, *public_api, *relevant_args, *args, *kwargs;
+
+ if (!PyArg_UnpackTuple(
+ positional_args, "implement_array_function", 5, 5,
+ &implementation, &public_api, &relevant_args, &args, &kwargs)) {
+ return NULL;
+ }
+
+ /* Remove `like=` kwarg, which is NumPy-exclusive and thus not present
+ * in downstream libraries. If `like=` is specified but doesn't
+ * implement `__array_function__`, raise a `TypeError`.
+ */
+ if (kwargs != NULL && PyDict_Contains(kwargs, npy_ma_str_like)) {
+ PyObject *like_arg = PyDict_GetItem(kwargs, npy_ma_str_like);
+ if (like_arg && !get_array_function(like_arg)) {
+ return PyErr_Format(PyExc_TypeError,
+ "The `like` argument must be an array-like that implements "
+ "the `__array_function__` protocol.");
+ }
+ PyDict_DelItem(kwargs, npy_ma_str_like);
+ }
+
+ PyObject *res = array_implement_array_function_internal(
+ public_api, relevant_args, args, kwargs);
+
+ if (res == Py_NotImplemented) {
+ return PyObject_Call(implementation, args, kwargs);
+ }
+ return res;
+}
+
+
+/*
+ * Implements the __array_function__ protocol for C array creation functions
+ * only. Added as an extension to NEP-18 in an effort to bring NEP-35 to
+ * life with minimal dispatch overhead.
+ */
+NPY_NO_EXPORT PyObject *
+array_implement_c_array_function_creation(
+ const char *function_name, PyObject *args, PyObject *kwargs)
+{
+ if (kwargs == NULL) {
+ return Py_NotImplemented;
+ }
+
+ /* Remove `like=` kwarg, which is NumPy-exclusive and thus not present
+ * in downstream libraries. If that key isn't present, return NULL and
+ * let originating call to continue. If the key is present but doesn't
+ * implement `__array_function__`, raise a `TypeError`.
+ */
+ if (!PyDict_Contains(kwargs, npy_ma_str_like)) {
+ return Py_NotImplemented;
+ }
+
+ PyObject *like_arg = PyDict_GetItem(kwargs, npy_ma_str_like);
+ if (like_arg == NULL) {
+ return NULL;
+ }
+ else if (!get_array_function(like_arg)) {
+ return PyErr_Format(PyExc_TypeError,
+ "The `like` argument must be an array-like that implements "
+ "the `__array_function__` protocol.");
+ }
+ PyObject *relevant_args = PyTuple_Pack(1, like_arg);
+ PyDict_DelItem(kwargs, npy_ma_str_like);
+
+ PyObject *numpy_module = PyImport_Import(npy_ma_str_numpy);
+ if (numpy_module == NULL) {
+ Py_DECREF(relevant_args);
+ return NULL;
+ }
+
+ PyObject *public_api = PyObject_GetAttrString(numpy_module, function_name);
+ Py_DECREF(numpy_module);
+ if (public_api == NULL) {
+ Py_DECREF(relevant_args);
+ return NULL;
+ }
+ if (!PyCallable_Check(public_api)) {
+ Py_DECREF(relevant_args);
+ Py_DECREF(public_api);
+ return PyErr_Format(PyExc_RuntimeError,
+ "numpy.%s is not callable.",
+ function_name);
+ }
+
+ PyObject* result = array_implement_array_function_internal(
+ public_api, relevant_args, args, kwargs);
+
+ Py_DECREF(relevant_args);
+ Py_DECREF(public_api);
+ return result;
+}
+
+
/*
* Python wrapper for get_implementing_args_and_methods, for testing purposes.
*/
PyObject *NPY_UNUSED(dummy), PyObject *positional_args)
{
PyObject *relevant_args;
- int j;
- int num_implementing_args = 0;
PyObject *implementing_args[NPY_MAXARGS];
PyObject *array_function_methods[NPY_MAXARGS];
PyObject *result = NULL;
return NULL;
}
- num_implementing_args = get_implementing_args_and_methods(
+ int num_implementing_args = get_implementing_args_and_methods(
relevant_args, implementing_args, array_function_methods);
if (num_implementing_args == -1) {
goto cleanup;
if (result == NULL) {
goto cleanup;
}
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
PyObject *argument = implementing_args[j];
Py_INCREF(argument);
PyList_SET_ITEM(result, j, argument);
}
cleanup:
- for (j = 0; j < num_implementing_args; j++) {
+ for (int j = 0; j < num_implementing_args; j++) {
Py_DECREF(implementing_args[j]);
Py_DECREF(array_function_methods[j]);
}
array__get_implementing_args(
PyObject *NPY_UNUSED(dummy), PyObject *positional_args);
+NPY_NO_EXPORT PyObject *
+array_implement_c_array_function_creation(
+ const char *function_name, PyObject *args, PyObject *kwargs);
+
NPY_NO_EXPORT PyObject *
array_function_method_impl(PyObject *func, PyObject *types, PyObject *args,
PyObject *kwargs);
#include "arrayobject.h"
#include "conversion_utils.h"
#include "ctors.h"
+#include "dtypemeta.h"
#include "methods.h"
#include "descriptor.h"
#include "iterators.h"
#include "strfuncs.h"
#include "binop_override.h"
+#include "array_coercion.h"
/*NUMPY_API
Compute the size of an array (in number of items)
}
+/**
+ * Assign an arbitrary object a NumPy array. This is largely basically
+ * identical to PyArray_FromAny, but assigns directly to the output array.
+ *
+ * @param dest Array to be written to
+ * @param src_object Object to be assigned, array-coercion rules apply.
+ * @return 0 on success -1 on failures.
+ */
/*NUMPY_API*/
NPY_NO_EXPORT int
PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object)
{
int ret = 0;
- PyArrayObject *src;
+ PyArrayObject *view;
PyArray_Descr *dtype = NULL;
- int ndim = 0;
+ int ndim;
npy_intp dims[NPY_MAXDIMS];
+ coercion_cache_obj *cache = NULL;
- Py_INCREF(src_object);
/*
- * Special code to mimic Numeric behavior for
- * character arrays.
+ * We have to set the maximum number of dimensions here to support
+ * sequences within object arrays.
*/
- if (PyArray_DESCR(dest)->type == NPY_CHARLTR &&
- PyArray_NDIM(dest) > 0 &&
- PyString_Check(src_object)) {
- npy_intp n_new, n_old;
- char *new_string;
- PyObject *tmp;
+ ndim = PyArray_DiscoverDTypeAndShape(src_object,
+ PyArray_NDIM(dest), dims, &cache,
+ NPY_DTYPE(PyArray_DESCR(dest)), PyArray_DESCR(dest), &dtype);
+ if (ndim < 0) {
+ return -1;
+ }
- n_new = PyArray_DIMS(dest)[PyArray_NDIM(dest)-1];
- n_old = PyString_Size(src_object);
- if (n_new > n_old) {
- new_string = malloc(n_new);
- if (new_string == NULL) {
- Py_DECREF(src_object);
- PyErr_NoMemory();
- return -1;
- }
- memcpy(new_string, PyString_AS_STRING(src_object), n_old);
- memset(new_string + n_old, ' ', n_new - n_old);
- tmp = PyString_FromStringAndSize(new_string, n_new);
- free(new_string);
- Py_DECREF(src_object);
- src_object = tmp;
- }
+ if (cache != NULL && !(cache->sequence)) {
+ /* The input is an array or array object, so assign directly */
+ assert(cache->converted_obj == src_object);
+ view = (PyArrayObject *)cache->arr_or_sequence;
+ Py_DECREF(dtype);
+ ret = PyArray_AssignArray(dest, view, NULL, NPY_UNSAFE_CASTING);
+ npy_free_coercion_cache(cache);
+ return ret;
}
/*
- * Get either an array object we can copy from, or its parameters
- * if there isn't a convenient array available.
+ * We may need to broadcast, due to shape mismatches, in this case
+ * create a temporary array first, and assign that after filling
+ * it from the sequences/scalar.
*/
- if (PyArray_GetArrayParamsFromObject_int(src_object,
- PyArray_DESCR(dest), 0, &dtype, &ndim, dims, &src) < 0) {
- Py_DECREF(src_object);
- return -1;
+ if (ndim != PyArray_NDIM(dest) ||
+ !PyArray_CompareLists(PyArray_DIMS(dest), dims, ndim)) {
+ /*
+ * Broadcasting may be necessary, so assign to a view first.
+ * This branch could lead to a shape mismatch error later.
+ */
+ assert (ndim <= PyArray_NDIM(dest)); /* would error during discovery */
+ view = (PyArrayObject *) PyArray_NewFromDescr(
+ &PyArray_Type, dtype, ndim, dims, NULL, NULL,
+ PyArray_FLAGS(dest) & NPY_ARRAY_F_CONTIGUOUS, NULL);
+ if (view == NULL) {
+ npy_free_coercion_cache(cache);
+ return -1;
+ }
+ }
+ else {
+ Py_DECREF(dtype);
+ view = dest;
}
- /* If it's not an array, either assign from a sequence or as a scalar */
- if (src == NULL) {
- /* If the input is scalar */
- if (ndim == 0) {
- /* If there's one dest element and src is a Python scalar */
- if (PyArray_IsScalar(src_object, Generic)) {
- char *value;
- int retcode;
-
- value = scalar_value(src_object, dtype);
- if (value == NULL) {
- Py_DECREF(dtype);
- Py_DECREF(src_object);
- return -1;
- }
-
- /* TODO: switch to SAME_KIND casting */
- retcode = PyArray_AssignRawScalar(dest, dtype, value,
- NULL, NPY_UNSAFE_CASTING);
- Py_DECREF(dtype);
- Py_DECREF(src_object);
- return retcode;
- }
- /* Otherwise use the dtype's setitem function */
- else {
- if (PyArray_SIZE(dest) == 1) {
- Py_DECREF(dtype);
- Py_DECREF(src_object);
- ret = PyArray_SETITEM(dest, PyArray_DATA(dest), src_object);
- return ret;
- }
- else {
- src = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
- dtype, 0, NULL, NULL,
- NULL, 0, NULL);
- if (src == NULL) {
- Py_DECREF(src_object);
- return -1;
- }
- if (PyArray_SETITEM(src, PyArray_DATA(src), src_object) < 0) {
- Py_DECREF(src_object);
- Py_DECREF(src);
- return -1;
- }
- }
- }
+ /* Assign the values to `view` (whichever array that is) */
+ if (cache == NULL) {
+ /* single (non-array) item, assign immediately */
+ if (PyArray_Pack(
+ PyArray_DESCR(view), PyArray_DATA(view), src_object) < 0) {
+ goto fail;
}
- else {
- /*
- * If there are more than enough dims, use AssignFromSequence
- * because it can handle this style of broadcasting.
- */
- if (ndim >= PyArray_NDIM(dest)) {
- int res;
- Py_DECREF(dtype);
- res = PyArray_AssignFromSequence(dest, src_object);
- Py_DECREF(src_object);
- return res;
- }
- /* Otherwise convert to an array and do an array-based copy */
- src = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
- dtype, ndim, dims, NULL, NULL,
- PyArray_ISFORTRAN(dest), NULL);
- if (src == NULL) {
- Py_DECREF(src_object);
- return -1;
- }
- if (PyArray_AssignFromSequence(src, src_object) < 0) {
- Py_DECREF(src);
- Py_DECREF(src_object);
- return -1;
- }
+ }
+ else {
+ if (PyArray_AssignFromCache(view, cache) < 0) {
+ goto fail;
}
}
-
- /* If it's an array, do a move (handling possible overlapping data) */
- ret = PyArray_MoveInto(dest, src);
- Py_DECREF(src);
- Py_DECREF(src_object);
+ if (view == dest) {
+ return 0;
+ }
+ ret = PyArray_AssignArray(dest, view, NULL, NPY_UNSAFE_CASTING);
+ Py_DECREF(view);
return ret;
+
+ fail:
+ if (view != dest) {
+ Py_DECREF(view);
+ }
+ return -1;
}
if (PyErr_WarnEx(warning, msg, 1) < 0) {
PyObject * s;
- s = PyUString_FromString("array_dealloc");
+ s = PyUnicode_FromString("array_dealloc");
if (s) {
PyErr_WriteUnraisable(s);
Py_DECREF(s);
{
PyArrayObject_fields *fa = (PyArrayObject_fields *)self;
- _dealloc_cached_buffer_info((PyObject*)self);
+ if (_buffer_info_free(fa->_buffer_info, (PyObject *)self) < 0) {
+ PyErr_WriteUnraisable(NULL);
+ }
if (fa->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *)self);
NPY_NO_EXPORT PyTypeObject PyArray_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "numpy.ndarray",
- .tp_basicsize = NPY_SIZEOF_PYARRAYOBJECT,
+ .tp_basicsize = sizeof(PyArrayObject_fields),
/* methods */
.tp_dealloc = (destructor)array_dealloc,
.tp_repr = (reprfunc)array_repr,
#include "npy_sort.h"
#include "common.h"
#include "ctors.h"
+#include "dtypemeta.h"
#include "lowlevel_strided_loops.h"
#include "usertypes.h"
#include "_datetime.h"
#include "arrayobject.h"
#include "alloc.h"
#include "typeinfo.h"
+#if defined(__ARM_NEON__) || defined (__ARM_NEON)
+#include <arm_neon.h>
+#endif
#ifdef NPY_HAVE_SSE2_INTRINSICS
#include <emmintrin.h>
#endif
PySequence_NoString_Check(PyObject *op) {
return
PySequence_Check(op) &&
- !PyString_Check(op) &&
+ !PyBytes_Check(op) &&
!PyUnicode_Check(op) &&
!PyArray_IsZeroDim(op);
}
*
* #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, LONG, UINT, ULONG,
* LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE#
- * #func1 = PyBool_FromLong, PyInt_FromLong*6, PyLong_FromUnsignedLong*2,
+ * #func1 = PyBool_FromLong, PyLong_FromLong*6, PyLong_FromUnsignedLong*2,
* PyLong_FromLongLong, PyLong_FromUnsignedLongLong,
* MyPyFloat_FromHalf, PyFloat_FromDouble*2#
* #func2 = PyObject_IsTrue, MyPyLong_AsLong*6, MyPyLong_AsUnsignedLong*2,
OBJECT_getitem(void *ip, void *NPY_UNUSED(ap))
{
PyObject *obj;
- NPY_COPY_PYOBJECT_PTR(&obj, ip);
+ memcpy(&obj, ip, sizeof(obj));
if (obj == NULL) {
Py_RETURN_NONE;
}
{
PyObject *obj;
- NPY_COPY_PYOBJECT_PTR(&obj, ov);
+ memcpy(&obj, ov, sizeof(obj));
Py_INCREF(op);
Py_XDECREF(obj);
- NPY_COPY_PYOBJECT_PTR(ov, &op);
+ memcpy(ov, &op, sizeof(op));
return PyErr_Occurred() ? -1 : 0;
}
npy_intp names_size = PyTuple_GET_SIZE(descr->names);
if (names_size != PyTuple_Size(op)) {
- errmsg = PyUString_FromFormat(
+ errmsg = PyUnicode_FromFormat(
"could not assign tuple of length %zd to structure "
"with %" NPY_INTP_FMT " fields.",
PyTuple_Size(op), names_size);
memset(ip + view.len, 0, itemsize - view.len);
}
PyBuffer_Release(&view);
- _dealloc_cached_buffer_info(op);
}
return 0;
}
dstp = (unsigned char*)dst;
srcp = (unsigned char*)src;
for (i = 0; i < n; i++) {
- NPY_COPY_PYOBJECT_PTR(&tmp, srcp);
+ memcpy(&tmp, srcp, sizeof(tmp));
Py_XINCREF(tmp);
- NPY_COPY_PYOBJECT_PTR(&tmp, dstp);
+ memcpy(&tmp, dstp, sizeof(tmp));
Py_XDECREF(tmp);
- NPY_COPY_PYOBJECT_PTR(dstp, srcp);
+ memcpy(dstp, srcp, sizeof(tmp));
dstp += dstride;
srcp += sstride;
}
}
else {
PyObject *tmp;
- NPY_COPY_PYOBJECT_PTR(&tmp, src);
+ memcpy(&tmp, src, sizeof(tmp));
Py_XINCREF(tmp);
- NPY_COPY_PYOBJECT_PTR(&tmp, dst);
+ memcpy(&tmp, dst, sizeof(tmp));
Py_XDECREF(tmp);
- NPY_COPY_PYOBJECT_PTR(dst, src);
+ memcpy(dst, src, sizeof(tmp));
}
}
}
}
else {
PyObject *obj;
- NPY_COPY_PYOBJECT_PTR(&obj, ip);
+ memcpy(&obj, ip, sizeof(obj));
if (obj == NULL) {
return NPY_FALSE;
}
** ARGFUNC **
*****************************************************************************
*/
-
+#if defined(__ARM_NEON__) || defined (__ARM_NEON)
+ int32_t _mm_movemask_epi8_neon(uint8x16_t input)
+ {
+ int8x8_t m0 = vcreate_s8(0x0706050403020100ULL);
+ uint8x16_t v0 = vshlq_u8(vshrq_n_u8(input, 7), vcombine_s8(m0, m0));
+ uint64x2_t v1 = vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(v0)));
+ return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 8);
+ }
+#endif
#define _LESS_THAN_OR_EQUAL(a,b) ((a) <= (b))
static int
break;
}
}
+#else
+ #if defined(__ARM_NEON__) || defined (__ARM_NEON)
+ uint8x16_t zero = vdupq_n_u8(0);
+ for(; i < n - (n % 32); i+=32) {
+ uint8x16_t d1 = vld1q_u8((uint8_t *)&ip[i]);
+ uint8x16_t d2 = vld1q_u8((uint8_t *)&ip[i + 16]);
+ d1 = vceqq_u8(d1, zero);
+ d2 = vceqq_u8(d2, zero);
+ if(_mm_movemask_epi8_neon(vminq_u8(d1, d2)) != 0xFFFF) {
+ break;
+ }
+ }
+ #endif
#endif
for (; i < n; i++) {
if (ip[i]) {
PyArray_Descr *dtype;
PyObject *cobj, *key;
+ /*
+ * Override the base class for all types, eventually all of this logic
+ * should be defined on the class and inherited to the scalar.
+ * (NPY_HALF is the largest builtin one.)
+ */
+ for (i = 0; i <= NPY_HALF; i++) {
+ if (dtypemeta_wrap_legacy_descriptor(_builtin_descrs[i]) < 0) {
+ return -1;
+ }
+ }
+
/*
* Add cast functions for the new types
*/
return -1;
}
}
- key = PyInt_FromLong(NPY_@name2@);
+ key = PyLong_FromLong(NPY_@name2@);
if (key == NULL) {
return -1;
}
char *p;
size_t to_alloc = (s->allocated == 0) ? INIT_SIZE : (2 * s->allocated);
- p = realloc(s->s, to_alloc);
+ p = PyObject_Realloc(s->s, to_alloc);
if (p == NULL) {
PyErr_SetString(PyExc_MemoryError, "memory allocation failed");
return -1;
* AND, the descr element size is a multiple of the alignment,
* AND, the array data is positioned to alignment granularity.
*/
-static int
+static NPY_INLINE int
_is_natively_aligned_at(PyArray_Descr *descr,
PyArrayObject *arr, Py_ssize_t offset)
{
int k;
+ if (NPY_LIKELY(descr == PyArray_DESCR(arr))) {
+ /*
+ * If the descriptor is the arrays descriptor we can assume the
+ * array's alignment is correct.
+ */
+ assert(offset == 0);
+ if (PyArray_ISALIGNED(arr)) {
+ assert(descr->elsize % descr->alignment == 0);
+ return 1;
+ }
+ return 0;
+ }
+
if ((Py_ssize_t)(PyArray_DATA(arr)) % descr->alignment != 0) {
return 0;
}
child = (PyArray_Descr*)PyTuple_GetItem(item, 0);
offset_obj = PyTuple_GetItem(item, 1);
- new_offset = PyInt_AsLong(offset_obj);
+ new_offset = PyLong_AsLong(offset_obj);
if (error_converting(new_offset)) {
return -1;
}
descr->type_num == NPY_ULONGLONG);
}
- *offset += descr->elsize;
-
if (PyArray_IsScalar(obj, Generic)) {
/* scalars are always natively aligned */
is_natively_aligned = 1;
(PyArrayObject*)obj, *offset);
}
+ *offset += descr->elsize;
+
if (descr->byteorder == '=' && is_natively_aligned) {
/* Prefer native types, to cater for Cython */
is_standard_size = 0;
/*
- * Global information about all active buffers
+ * Information about all active buffers is stored as a linked list on
+ * the ndarray. The initial pointer is currently tagged to have a chance of
+ * detecting incompatible subclasses.
*
* Note: because for backward compatibility we cannot define bf_releasebuffer,
* we must manually keep track of the additional data required by the buffers.
*/
/* Additional per-array data required for providing the buffer interface */
-typedef struct {
+typedef struct _buffer_info_t_tag {
char *format;
int ndim;
Py_ssize_t *strides;
Py_ssize_t *shape;
+ struct _buffer_info_t_tag *next;
} _buffer_info_t;
-/*
- * { id(array): [list of pointers to _buffer_info_t, the last one is latest] }
- *
- * Because shape, strides, and format can be different for different buffers,
- * we may need to keep track of multiple buffer infos for each array.
- *
- * However, when none of them has changed, the same buffer info may be reused.
- *
- * Thread-safety is provided by GIL.
- */
-static PyObject *_buffer_info_cache = NULL;
/* Fill in the info structure */
static _buffer_info_t*
-_buffer_info_new(PyObject *obj, npy_bool f_contiguous)
+_buffer_info_new(PyObject *obj, int flags)
{
+ /*
+ * Note that the buffer info is cached as PyLongObjects making them appear
+ * like unreachable lost memory to valgrind.
+ */
_buffer_info_t *info;
_tmp_string_t fmt = {NULL, 0, 0};
int k;
PyArray_Descr *descr = NULL;
int err = 0;
- /*
- * Note that the buffer info is cached as pyints making them appear like
- * unreachable lost memory to valgrind.
- */
- info = malloc(sizeof(_buffer_info_t));
- if (info == NULL) {
- PyErr_NoMemory();
- goto fail;
- }
-
- if (PyArray_IsScalar(obj, Datetime) || PyArray_IsScalar(obj, Timedelta)) {
- /*
- * Special case datetime64 scalars to remain backward compatible.
- * This will change in a future version.
- * Note arrays of datetime64 and structured arrays with datetime64
- * fields will not hit this code path and are currently unsupported
- * in _buffer_format_string.
- */
- if (_append_char(&fmt, 'B') < 0) {
- goto fail;
- }
- if (_append_char(&fmt, '\0') < 0) {
- goto fail;
- }
- info->ndim = 1;
- info->shape = malloc(sizeof(Py_ssize_t) * 2);
- if (info->shape == NULL) {
+ if (PyArray_IsScalar(obj, Void)) {
+ info = PyObject_Malloc(sizeof(_buffer_info_t));
+ if (info == NULL) {
PyErr_NoMemory();
goto fail;
}
- info->strides = info->shape + info->ndim;
- info->shape[0] = 8;
- info->strides[0] = 1;
- info->format = fmt.s;
- return info;
- }
- else if (PyArray_IsScalar(obj, Generic)) {
+ info->ndim = 0;
+ info->shape = NULL;
+ info->strides = NULL;
+
descr = PyArray_DescrFromScalar(obj);
if (descr == NULL) {
goto fail;
}
- info->ndim = 0;
- info->shape = NULL;
- info->strides = NULL;
}
else {
+ assert(PyArray_Check(obj));
PyArrayObject * arr = (PyArrayObject *)obj;
- descr = PyArray_DESCR(arr);
+
+ info = PyObject_Malloc(sizeof(_buffer_info_t) +
+ sizeof(Py_ssize_t) * PyArray_NDIM(arr) * 2);
+ if (info == NULL) {
+ PyErr_NoMemory();
+ goto fail;
+ }
/* Fill in shape and strides */
info->ndim = PyArray_NDIM(arr);
info->strides = NULL;
}
else {
- info->shape = malloc(sizeof(Py_ssize_t) * PyArray_NDIM(arr) * 2 + 1);
- if (info->shape == NULL) {
- PyErr_NoMemory();
- goto fail;
- }
+ info->shape = (npy_intp *)((char *)info + sizeof(_buffer_info_t));
+ assert((size_t)info->shape % sizeof(npy_intp) == 0);
info->strides = info->shape + PyArray_NDIM(arr);
#if NPY_RELAXED_STRIDES_CHECKING
* (This is unnecessary, but has no effect in the case where
* NPY_RELAXED_STRIDES CHECKING is disabled.)
*/
+ int f_contiguous = (flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS;
if (PyArray_IS_C_CONTIGUOUS(arr) && !(
f_contiguous && PyArray_IS_F_CONTIGUOUS(arr))) {
Py_ssize_t sd = PyArray_ITEMSIZE(arr);
}
}
}
+ descr = PyArray_DESCR(arr);
Py_INCREF(descr);
}
/* Fill in format */
- err = _buffer_format_string(descr, &fmt, obj, NULL, NULL);
- Py_DECREF(descr);
- if (err != 0) {
- free(info->shape);
- goto fail;
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+ err = _buffer_format_string(descr, &fmt, obj, NULL, NULL);
+ Py_DECREF(descr);
+ if (err != 0) {
+ goto fail;
+ }
+ if (_append_char(&fmt, '\0') < 0) {
+ goto fail;
+ }
+ info->format = fmt.s;
}
- if (_append_char(&fmt, '\0') < 0) {
- free(info->shape);
- goto fail;
+ else {
+ Py_DECREF(descr);
+ info->format = NULL;
}
- info->format = fmt.s;
-
+ info->next = NULL;
return info;
fail:
- free(fmt.s);
- free(info);
+ PyObject_Free(fmt.s);
+ PyObject_Free(info);
return NULL;
}
Py_ssize_t c;
int k;
- c = strcmp(a->format, b->format);
- if (c != 0) return c;
-
+ if (a->format != NULL && b->format != NULL) {
+ c = strcmp(a->format, b->format);
+ if (c != 0) return c;
+ }
c = a->ndim - b->ndim;
if (c != 0) return c;
return 0;
}
-static void
-_buffer_info_free(_buffer_info_t *info)
+
+/*
+ * Tag the buffer info pointer by adding 2 (unless it is NULL to simplify
+ * object initialization).
+ * The linked list of buffer-infos was appended to the array struct in
+ * NumPy 1.20. Tagging the pointer gives us a chance to raise/print
+ * a useful error message instead of crashing hard if a C-subclass uses
+ * the same field.
+ */
+static NPY_INLINE void *
+buffer_info_tag(void *buffer_info)
{
- if (info->format) {
- free(info->format);
+ if (buffer_info == NULL) {
+ return buffer_info;
}
- if (info->shape) {
- free(info->shape);
+ else {
+ return (void *)((uintptr_t)buffer_info + 3);
}
- free(info);
}
-/* Get buffer info from the global dictionary */
-static _buffer_info_t*
-_buffer_get_info(PyObject *obj, npy_bool f_contiguous)
-{
- PyObject *key = NULL, *item_list = NULL, *item = NULL;
- _buffer_info_t *info = NULL, *old_info = NULL;
- if (_buffer_info_cache == NULL) {
- _buffer_info_cache = PyDict_New();
- if (_buffer_info_cache == NULL) {
- return NULL;
- }
+static NPY_INLINE int
+_buffer_info_untag(
+ void *tagged_buffer_info, _buffer_info_t **buffer_info, PyObject *obj)
+{
+ if (tagged_buffer_info == NULL) {
+ *buffer_info = NULL;
+ return 0;
}
-
- /* Compute information */
- info = _buffer_info_new(obj, f_contiguous);
- if (info == NULL) {
- return NULL;
+ if (NPY_UNLIKELY(((uintptr_t)tagged_buffer_info & 0x7) != 3)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Object of type %S appears to be C subclassed NumPy array, "
+ "void scalar, or allocated in a non-standard way."
+ "NumPy reserves the right to change the size of these "
+ "structures. Projects are required to take this into account "
+ "by either recompiling against a specific NumPy version or "
+ "padding the struct and enforcing a maximum NumPy version.",
+ Py_TYPE(obj));
+ return -1;
}
+ *buffer_info = (void *)((uintptr_t)tagged_buffer_info - 3);
+ return 0;
+}
- /* Check if it is identical with an old one; reuse old one, if yes */
- key = PyLong_FromVoidPtr((void*)obj);
- if (key == NULL) {
- goto fail;
- }
- item_list = PyDict_GetItem(_buffer_info_cache, key);
-
- if (item_list != NULL) {
- Py_ssize_t item_list_length = PyList_GET_SIZE(item_list);
- Py_INCREF(item_list);
- if (item_list_length > 0) {
- item = PyList_GetItem(item_list, item_list_length - 1);
- old_info = (_buffer_info_t*)PyLong_AsVoidPtr(item);
- if (_buffer_info_cmp(info, old_info) == 0) {
- _buffer_info_free(info);
- info = old_info;
- }
- else {
- if (item_list_length > 1 && info->ndim > 1) {
- /*
- * Some arrays are C- and F-contiguous and if they have more
- * than one dimension, the buffer-info may differ between
- * the two due to RELAXED_STRIDES_CHECKING.
- * If we export both buffers, the first stored one may be
- * the one for the other contiguity, so check both.
- * This is generally very unlikely in all other cases, since
- * in all other cases the first one will match unless array
- * metadata was modified in-place (which is discouraged).
- */
- item = PyList_GetItem(item_list, item_list_length - 2);
- old_info = (_buffer_info_t*)PyLong_AsVoidPtr(item);
- if (_buffer_info_cmp(info, old_info) == 0) {
- _buffer_info_free(info);
- info = old_info;
- }
- }
- }
- }
- }
- else {
- item_list = PyList_New(0);
- if (item_list == NULL) {
- goto fail;
- }
- if (PyDict_SetItem(_buffer_info_cache, key, item_list) != 0) {
- goto fail;
- }
- }
- if (info != old_info) {
- /* Needs insertion */
- item = PyLong_FromVoidPtr((void*)info);
- if (item == NULL) {
- goto fail;
+/*
+ * NOTE: for backward compatibility (esp. with PyArg_ParseTuple("s#", ...))
+ * we do *not* define bf_releasebuffer at all.
+ *
+ * Instead, any extra data allocated with the buffer is released only in
+ * array_dealloc.
+ *
+ * Ensuring that the buffer stays in place is taken care by refcounting;
+ * ndarrays do not reallocate if there are references to them, and a buffer
+ * view holds one reference.
+ *
+ * This is stored in the array's _buffer_info slot (currently as a void *).
+ */
+static void
+_buffer_info_free_untagged(void *_buffer_info)
+{
+ _buffer_info_t *next = _buffer_info;
+ while (next != NULL) {
+ _buffer_info_t *curr = next;
+ next = curr->next;
+ if (curr->format) {
+ PyObject_Free(curr->format);
}
- PyList_Append(item_list, item);
- Py_DECREF(item);
+ /* Shape is allocated as part of info */
+ PyObject_Free(curr);
}
+}
- Py_DECREF(item_list);
- Py_DECREF(key);
- return info;
-fail:
- if (info != NULL && info != old_info) {
- _buffer_info_free(info);
+/*
+ * Checks whether the pointer is tagged, and then frees the cache list.
+ * (The tag check is only for transition due to changed structure size in 1.20)
+ */
+NPY_NO_EXPORT int
+_buffer_info_free(void *buffer_info, PyObject *obj)
+{
+ _buffer_info_t *untagged_buffer_info;
+ if (_buffer_info_untag(buffer_info, &untagged_buffer_info, obj) < 0) {
+ return -1;
}
- Py_XDECREF(item_list);
- Py_XDECREF(key);
- return NULL;
+ _buffer_info_free_untagged(untagged_buffer_info);
+ return 0;
}
-/* Clear buffer info from the global dictionary */
-static void
-_buffer_clear_info(PyObject *arr)
+
+/*
+ * Get the buffer info returning either the old one (passed in) or a new
+ * buffer info which adds holds on to (and thus replaces) the old one.
+ */
+static _buffer_info_t*
+_buffer_get_info(void **buffer_info_cache_ptr, PyObject *obj, int flags)
{
- PyObject *key, *item_list, *item;
- _buffer_info_t *info;
- int k;
+ _buffer_info_t *info = NULL;
+ _buffer_info_t *stored_info; /* First currently stored buffer info */
+
+ if (_buffer_info_untag(*buffer_info_cache_ptr, &stored_info, obj) < 0) {
+ return NULL;
+ }
+ _buffer_info_t *old_info = stored_info;
- if (_buffer_info_cache == NULL) {
- return;
+ /* Compute information (it would be nice to skip this in simple cases) */
+ info = _buffer_info_new(obj, flags);
+ if (info == NULL) {
+ return NULL;
}
- key = PyLong_FromVoidPtr((void*)arr);
- item_list = PyDict_GetItem(_buffer_info_cache, key);
- if (item_list != NULL) {
- for (k = 0; k < PyList_GET_SIZE(item_list); ++k) {
- item = PyList_GET_ITEM(item_list, k);
- info = (_buffer_info_t*)PyLong_AsVoidPtr(item);
- _buffer_info_free(info);
+ if (old_info != NULL && _buffer_info_cmp(info, old_info) != 0) {
+ _buffer_info_t *next_info = old_info->next;
+ old_info = NULL; /* Can't use this one, but possibly next */
+
+ if (info->ndim > 1 && next_info != NULL) {
+ /*
+ * Some arrays are C- and F-contiguous and if they have more
+ * than one dimension, the buffer-info may differ between
+ * the two due to RELAXED_STRIDES_CHECKING.
+ * If we export both buffers, the first stored one may be
+ * the one for the other contiguity, so check both.
+ * This is generally very unlikely in all other cases, since
+ * in all other cases the first one will match unless array
+ * metadata was modified in-place (which is discouraged).
+ */
+ if (_buffer_info_cmp(info, next_info) == 0) {
+ old_info = next_info;
+ }
+ }
+ }
+ if (old_info != NULL) {
+ /*
+ * The two info->format are considered equal if one of them
+ * has no format set (meaning the format is arbitrary and can
+ * be modified). If the new info has a format, but we reuse
+ * the old one, this transfers the ownership to the old one.
+ */
+ if (old_info->format == NULL) {
+ old_info->format = info->format;
+ info->format = NULL;
}
- PyDict_DelItem(_buffer_info_cache, key);
+ _buffer_info_free_untagged(info);
+ info = old_info;
+ }
+ else {
+ /* Insert new info as first item in the linked buffer-info list. */
+ info->next = stored_info;
+ *buffer_info_cache_ptr = buffer_info_tag(info);
}
- Py_DECREF(key);
+ return info;
}
+
/*
* Retrieving buffers for ndarray
*/
goto fail;
}
- /* Fill in information */
- info = _buffer_get_info(obj, (flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS);
+ /* Fill in information (and add it to _buffer_info if necessary) */
+ info = _buffer_get_info(
+ &((PyArrayObject_fields *)self)->_buffer_info, obj, flags);
if (info == NULL) {
goto fail;
}
}
/*
- * Retrieving buffers for scalars
+ * Retrieving buffers for void scalar (which can contain any complex types),
+ * defined in buffer.c since it requires the complex format building logic.
*/
-int
-gentype_getbuffer(PyObject *self, Py_buffer *view, int flags)
+NPY_NO_EXPORT int
+void_getbuffer(PyObject *self, Py_buffer *view, int flags)
{
- _buffer_info_t *info = NULL;
- PyArray_Descr *descr = NULL;
- int elsize;
+ PyVoidScalarObject *scalar = (PyVoidScalarObject *)self;
if (flags & PyBUF_WRITABLE) {
PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly");
- goto fail;
- }
-
- /* Fill in information */
- info = _buffer_get_info(self, 0);
- if (info == NULL) {
- goto fail;
- }
-
- view->ndim = info->ndim;
- view->shape = info->shape;
- view->strides = info->strides;
-
- if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
- view->format = info->format;
- } else {
- view->format = NULL;
- }
-
- descr = PyArray_DescrFromScalar(self);
- view->buf = (void *)scalar_value(self, descr);
- elsize = descr->elsize;
- view->len = elsize;
- if (PyArray_IsScalar(self, Datetime) || PyArray_IsScalar(self, Timedelta)) {
- elsize = 1; /* descr->elsize,char is 8,'M', but we return 1,'B' */
+ return -1;
}
- view->itemsize = elsize;
-
- Py_DECREF(descr);
+ view->ndim = 0;
+ view->shape = NULL;
+ view->strides = NULL;
+ view->suboffsets = NULL;
+ view->len = scalar->descr->elsize;
+ view->itemsize = scalar->descr->elsize;
view->readonly = 1;
view->suboffsets = NULL;
- view->obj = self;
Py_INCREF(self);
- return 0;
-
-fail:
- view->obj = NULL;
- return -1;
-}
-
-/*
- * NOTE: for backward compatibility (esp. with PyArg_ParseTuple("s#", ...))
- * we do *not* define bf_releasebuffer at all.
- *
- * Instead, any extra data allocated with the buffer is released only in
- * array_dealloc.
- *
- * Ensuring that the buffer stays in place is taken care by refcounting;
- * ndarrays do not reallocate if there are references to them, and a buffer
- * view holds one reference.
- */
-
-NPY_NO_EXPORT void
-_dealloc_cached_buffer_info(PyObject *self)
-{
- int reset_error_state = 0;
- PyObject *ptype, *pvalue, *ptraceback;
-
- /* This function may be called when processing an exception --
- * we need to stash the error state to avoid confusing PyDict
- */
+ view->obj = self;
+ view->buf = scalar->obval;
- if (PyErr_Occurred()) {
- reset_error_state = 1;
- PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+ if (((flags & PyBUF_FORMAT) != PyBUF_FORMAT)) {
+ /* It is unnecessary to find the correct format */
+ view->format = NULL;
+ return 0;
}
- _buffer_clear_info(self);
-
- if (reset_error_state) {
- PyErr_Restore(ptype, pvalue, ptraceback);
+ /*
+ * If a format is being exported, we need to use _buffer_get_info
+ * to find the correct format. This format must also be stored, since
+ * at least in theory it can change (in practice it should never change).
+ */
+ _buffer_info_t *info = _buffer_get_info(&scalar->_buffer_info, self, flags);
+ if (info == NULL) {
+ return -1;
}
+ view->format = info->format;
+ return 0;
}
}
*p = '\0';
- str = PyUString_FromStringAndSize(buf, strlen(buf));
+ str = PyUnicode_FromStringAndSize(buf, strlen(buf));
if (str == NULL) {
free(buf);
return NULL;
else {
val = PyArray_DIM(arrnew,i);
}
- PyTuple_SET_ITEM(newshape, i, PyInt_FromLong((long)val));
+ PyTuple_SET_ITEM(newshape, i, PyLong_FromLong((long)val));
}
arr2 = (PyArrayObject *)PyArray_Reshape(arr1, newshape);
Py_DECREF(arr1);
if (min != NULL) {
if (PyArray_ISUNSIGNED(self)) {
int cmp;
- zero = PyInt_FromLong(0);
+ zero = PyLong_FromLong(0);
cmp = PyObject_RichCompareBool(min, zero, Py_LT);
if (cmp == -1) {
Py_DECREF(zero);
#include "npy_pycompat.h"
#include "common.h"
+#include "abstractdtypes.h"
#include "usertypes.h"
-#include "common.h"
#include "npy_buffer.h"
#include "get_attr_string.h"
#include "mem_overlap.h"
+#include "array_coercion.h"
/*
* The casting to use for implicit assignment operations resulting from
else if (PyComplex_Check(op)) {
return PyArray_DescrFromType(NPY_CDOUBLE);
}
- else if (PyInt_Check(op)) {
- /* bools are a subclass of int */
- if (PyBool_Check(op)) {
- return PyArray_DescrFromType(NPY_BOOL);
- }
- else {
- return PyArray_DescrFromType(NPY_LONG);
- }
- }
else if (PyLong_Check(op)) {
- /* check to see if integer can fit into a longlong or ulonglong
- and return that --- otherwise return object */
- if ((PyLong_AsLongLong(op) == -1) && PyErr_Occurred()) {
- PyErr_Clear();
- }
- else {
- return PyArray_DescrFromType(NPY_LONGLONG);
- }
-
- if ((PyLong_AsUnsignedLongLong(op) == (unsigned long long) -1)
- && PyErr_Occurred()){
- PyErr_Clear();
- }
- else {
- return PyArray_DescrFromType(NPY_ULONGLONG);
- }
-
- return PyArray_DescrFromType(NPY_OBJECT);
+ return PyArray_PyIntAbstractDType.discover_descr_from_pyobject(
+ &PyArray_PyIntAbstractDType, op);
}
return NULL;
}
-/*
- * These constants are used to signal that the recursive dtype determination in
- * PyArray_DTypeFromObject encountered a string type, and that the recursive
- * search must be restarted so that string representation lengths can be
- * computed for all scalar types.
- */
-#define RETRY_WITH_STRING 1
-#define RETRY_WITH_UNICODE 2
-
-/*
- * Recursively examines the object to determine an appropriate dtype
- * to use for converting to an ndarray.
- *
- * 'obj' is the object to be converted to an ndarray.
- *
- * 'maxdims' is the maximum recursion depth.
- *
- * 'out_dtype' should be either NULL or a minimal starting dtype when
- * the function is called. It is updated with the results of type
- * promotion. This dtype does not get updated when processing NA objects.
- * This is reset to NULL on failure.
- *
- * Returns 0 on success, -1 on failure.
- */
- NPY_NO_EXPORT int
-PyArray_DTypeFromObject(PyObject *obj, int maxdims, PyArray_Descr **out_dtype)
-{
- int res;
-
- res = PyArray_DTypeFromObjectHelper(obj, maxdims, out_dtype, 0);
- if (res == RETRY_WITH_STRING) {
- res = PyArray_DTypeFromObjectHelper(obj, maxdims,
- out_dtype, NPY_STRING);
- if (res == RETRY_WITH_UNICODE) {
- res = PyArray_DTypeFromObjectHelper(obj, maxdims,
- out_dtype, NPY_UNICODE);
- }
- }
- else if (res == RETRY_WITH_UNICODE) {
- res = PyArray_DTypeFromObjectHelper(obj, maxdims,
- out_dtype, NPY_UNICODE);
- }
- return res;
-}
/*
* Get a suitable string dtype by calling `__str__`.
* For `np.bytes_`, this assumes an ASCII encoding.
*/
-static PyArray_Descr *
+NPY_NO_EXPORT PyArray_Descr *
PyArray_DTypeFromObjectStringDiscovery(
PyObject *obj, PyArray_Descr *last_dtype, int string_type)
{
return NULL;
}
if (last_dtype != NULL &&
- last_dtype->type_num == string_type &&
- last_dtype->elsize >= itemsize) {
+ last_dtype->type_num == string_type &&
+ last_dtype->elsize >= itemsize) {
Py_INCREF(last_dtype);
return last_dtype;
}
return dtype;
}
+
+/*
+ * This function is now identical to the new PyArray_DiscoverDTypeAndShape
+ * but only returns the the dtype. It should in most cases be slowly phased
+ * out. (Which may need some refactoring to PyArray_FromAny to make it simpler)
+ */
NPY_NO_EXPORT int
-PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
- PyArray_Descr **out_dtype, int string_type)
+PyArray_DTypeFromObject(PyObject *obj, int maxdims, PyArray_Descr **out_dtype)
{
- int i, size;
- PyArray_Descr *dtype = NULL;
- PyObject *ip;
- Py_buffer buffer_view;
- /* types for sequence handling */
- PyObject ** objects;
- PyObject * seq;
- PyTypeObject * common_type;
-
- /* Check if it's an ndarray */
- if (PyArray_Check(obj)) {
- dtype = PyArray_DESCR((PyArrayObject *)obj);
- Py_INCREF(dtype);
- goto promote_types;
- }
-
- /* See if it's a python None */
- if (obj == Py_None) {
- dtype = PyArray_DescrFromType(NPY_OBJECT);
- if (dtype == NULL) {
- goto fail;
- }
- goto promote_types;
- }
- /* Check if it's a NumPy scalar */
- else if (PyArray_IsScalar(obj, Generic)) {
- if (!string_type) {
- dtype = PyArray_DescrFromScalar(obj);
- if (dtype == NULL) {
- goto fail;
- }
- }
- else {
- dtype = PyArray_DTypeFromObjectStringDiscovery(
- obj, *out_dtype, string_type);
- if (dtype == NULL) {
- goto fail;
- }
-
- /* nothing to do, dtype is already correct */
- if (dtype == *out_dtype){
- Py_DECREF(dtype);
- return 0;
- }
- }
- goto promote_types;
- }
-
- /* Check if it's a Python scalar */
- dtype = _array_find_python_scalar_type(obj);
- if (dtype != NULL) {
- if (string_type) {
- /* dtype is not used in this (string discovery) branch */
- Py_DECREF(dtype);
- dtype = PyArray_DTypeFromObjectStringDiscovery(
- obj, *out_dtype, string_type);
- if (dtype == NULL) {
- goto fail;
- }
-
- /* nothing to do, dtype is already correct */
- if (dtype == *out_dtype){
- Py_DECREF(dtype);
- return 0;
- }
- }
- goto promote_types;
- }
-
- /* Check if it's an ASCII string */
- if (PyBytes_Check(obj)) {
- int itemsize = PyString_GET_SIZE(obj);
-
- /* If it's already a big enough string, don't bother type promoting */
- if (*out_dtype != NULL &&
- (*out_dtype)->type_num == NPY_STRING &&
- (*out_dtype)->elsize >= itemsize) {
- return 0;
- }
- dtype = PyArray_DescrNewFromType(NPY_STRING);
- if (dtype == NULL) {
- goto fail;
- }
- dtype->elsize = itemsize;
- goto promote_types;
- }
-
- /* Check if it's a Unicode string */
- if (PyUnicode_Check(obj)) {
- int itemsize = PyUnicode_GetLength(obj);
- if (itemsize < 0) {
- goto fail;
- }
- itemsize *= 4;
-
- /*
- * If it's already a big enough unicode object,
- * don't bother type promoting
- */
- if (*out_dtype != NULL &&
- (*out_dtype)->type_num == NPY_UNICODE &&
- (*out_dtype)->elsize >= itemsize) {
- return 0;
- }
- dtype = PyArray_DescrNewFromType(NPY_UNICODE);
- if (dtype == NULL) {
- goto fail;
- }
- dtype->elsize = itemsize;
- goto promote_types;
- }
-
- /* PEP 3118 buffer interface */
- if (PyObject_CheckBuffer(obj) == 1) {
- memset(&buffer_view, 0, sizeof(Py_buffer));
- if (PyObject_GetBuffer(obj, &buffer_view,
- PyBUF_FORMAT|PyBUF_STRIDES) == 0 ||
- PyObject_GetBuffer(obj, &buffer_view,
- PyBUF_FORMAT|PyBUF_SIMPLE) == 0) {
-
- PyErr_Clear();
- dtype = _descriptor_from_pep3118_format(buffer_view.format);
- PyBuffer_Release(&buffer_view);
- _dealloc_cached_buffer_info(obj);
- if (dtype) {
- goto promote_types;
- }
- }
- else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 ||
- PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) {
-
- PyErr_Clear();
- dtype = PyArray_DescrNewFromType(NPY_VOID);
- dtype->elsize = buffer_view.itemsize;
- PyBuffer_Release(&buffer_view);
- _dealloc_cached_buffer_info(obj);
- goto promote_types;
- }
- else {
- PyErr_Clear();
- }
- }
-
- /* The array interface */
- ip = PyArray_LookupSpecial_OnInstance(obj, "__array_interface__");
- if (ip != NULL) {
- if (PyDict_Check(ip)) {
- PyObject *typestr;
- PyObject *tmp = NULL;
- typestr = _PyDict_GetItemStringWithError(ip, "typestr");
- if (typestr == NULL && PyErr_Occurred()) {
- goto fail;
- }
- /* Allow unicode type strings */
- if (typestr && PyUnicode_Check(typestr)) {
- tmp = PyUnicode_AsASCIIString(typestr);
- typestr = tmp;
- }
- if (typestr && PyBytes_Check(typestr)) {
- dtype =_array_typedescr_fromstr(PyBytes_AS_STRING(typestr));
- if (tmp == typestr) {
- Py_DECREF(tmp);
- }
- Py_DECREF(ip);
- if (dtype == NULL) {
- goto fail;
- }
- goto promote_types;
- }
- }
- Py_DECREF(ip);
- }
- else if (PyErr_Occurred()) {
- PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */
- }
-
-
- /* The array struct interface */
- ip = PyArray_LookupSpecial_OnInstance(obj, "__array_struct__");
- if (ip != NULL) {
- PyArrayInterface *inter;
- char buf[40];
-
- if (NpyCapsule_Check(ip)) {
- inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(ip);
- if (inter->two == 2) {
- PyOS_snprintf(buf, sizeof(buf),
- "|%c%d", inter->typekind, inter->itemsize);
- dtype = _array_typedescr_fromstr(buf);
- Py_DECREF(ip);
- if (dtype == NULL) {
- goto fail;
- }
- goto promote_types;
- }
- }
- Py_DECREF(ip);
- }
- else if (PyErr_Occurred()) {
- PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */
- }
-
- /* The __array__ attribute */
- ip = PyArray_LookupSpecial_OnInstance(obj, "__array__");
- if (ip != NULL) {
- Py_DECREF(ip);
- ip = PyObject_CallMethod(obj, "__array__", NULL);
- if(ip && PyArray_Check(ip)) {
- dtype = PyArray_DESCR((PyArrayObject *)ip);
- Py_INCREF(dtype);
- Py_DECREF(ip);
- goto promote_types;
- }
- Py_XDECREF(ip);
- if (PyErr_Occurred()) {
- goto fail;
- }
- }
- else if (PyErr_Occurred()) {
- PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */
- }
-
- /*
- * If we reached the maximum recursion depth without hitting one
- * of the above cases, and obj isn't a sequence-like object, the output
- * dtype should be either OBJECT or a user-defined type.
- *
- * Note that some libraries define sequence-like classes but want them to
- * be treated as objects, and they expect numpy to treat it as an object if
- * __len__ is not defined.
- */
- if (maxdims == 0 || !PySequence_Check(obj) || PySequence_Size(obj) < 0) {
- /* clear any PySequence_Size error which corrupts further calls */
- PyErr_Clear();
+ coercion_cache_obj *cache = NULL;
+ npy_intp shape[NPY_MAXDIMS];
+ int ndim;
- if (*out_dtype == NULL || (*out_dtype)->type_num != NPY_OBJECT) {
- Py_XDECREF(*out_dtype);
- *out_dtype = PyArray_DescrFromType(NPY_OBJECT);
- if (*out_dtype == NULL) {
- return -1;
- }
- }
- return 0;
- }
-
- /*
- * The C-API recommends calling PySequence_Fast before any of the other
- * PySequence_Fast* functions. This is required for PyPy
- */
- seq = PySequence_Fast(obj, "Could not convert object to sequence");
- if (seq == NULL) {
- goto fail;
- }
-
- /* Recursive case, first check the sequence contains only one type */
- size = PySequence_Fast_GET_SIZE(seq);
- /* objects is borrowed, do not release seq */
- objects = PySequence_Fast_ITEMS(seq);
- common_type = size > 0 ? Py_TYPE(objects[0]) : NULL;
- for (i = 1; i < size; ++i) {
- if (Py_TYPE(objects[i]) != common_type) {
- common_type = NULL;
- break;
- }
- }
-
- /* all types are the same and scalar, one recursive call is enough */
- if (common_type != NULL && !string_type &&
- (common_type == &PyFloat_Type ||
-/* TODO: we could add longs if we add a range check */
- common_type == &PyBool_Type ||
- common_type == &PyComplex_Type)) {
- size = 1;
- }
-
- /* Recursive call for each sequence item */
- for (i = 0; i < size; ++i) {
- int res = PyArray_DTypeFromObjectHelper(objects[i], maxdims - 1,
- out_dtype, string_type);
- if (res < 0) {
- Py_DECREF(seq);
- goto fail;
- }
- else if (res > 0) {
- Py_DECREF(seq);
- return res;
- }
+ ndim = PyArray_DiscoverDTypeAndShape(
+ obj, maxdims, shape, &cache, NULL, NULL, out_dtype);
+ if (ndim < 0) {
+ return -1;
}
-
- Py_DECREF(seq);
-
+ npy_free_coercion_cache(cache);
return 0;
-
-
-promote_types:
- /* Set 'out_dtype' if it's NULL */
- if (*out_dtype == NULL) {
- if (!string_type && dtype->type_num == NPY_STRING) {
- Py_DECREF(dtype);
- return RETRY_WITH_STRING;
- }
- if (!string_type && dtype->type_num == NPY_UNICODE) {
- Py_DECREF(dtype);
- return RETRY_WITH_UNICODE;
- }
- *out_dtype = dtype;
- return 0;
- }
- /* Do type promotion with 'out_dtype' */
- else {
- PyArray_Descr *res_dtype = PyArray_PromoteTypes(dtype, *out_dtype);
- Py_DECREF(dtype);
- if (res_dtype == NULL) {
- goto fail;
- }
- if (!string_type &&
- res_dtype->type_num == NPY_UNICODE &&
- (*out_dtype)->type_num != NPY_UNICODE) {
- Py_DECREF(res_dtype);
- return RETRY_WITH_UNICODE;
- }
- if (!string_type &&
- res_dtype->type_num == NPY_STRING &&
- (*out_dtype)->type_num != NPY_STRING) {
- Py_DECREF(res_dtype);
- return RETRY_WITH_STRING;
- }
- Py_DECREF(*out_dtype);
- *out_dtype = res_dtype;
- return 0;
- }
-
-fail:
- Py_XDECREF(*out_dtype);
- *out_dtype = NULL;
- return -1;
}
-#undef RETRY_WITH_STRING
-#undef RETRY_WITH_UNICODE
-
-/* new reference */
-NPY_NO_EXPORT PyArray_Descr *
-_array_typedescr_fromstr(char const *c_str)
-{
- PyArray_Descr *descr = NULL;
- PyObject *stringobj = PyString_FromString(c_str);
-
- if (stringobj == NULL) {
- return NULL;
- }
- if (PyArray_DescrConverter(stringobj, &descr) != NPY_SUCCEED) {
- Py_DECREF(stringobj);
- return NULL;
- }
- Py_DECREF(stringobj);
- return descr;
-}
-
-
NPY_NO_EXPORT char *
index2ptr(PyArrayObject *mp, npy_intp i)
{
_zerofill(PyArrayObject *ret)
{
if (PyDataType_REFCHK(PyArray_DESCR(ret))) {
- PyObject *zero = PyInt_FromLong(0);
+ PyObject *zero = PyLong_FromLong(0);
PyArray_FillObjectArray(ret, zero);
Py_DECREF(zero);
if (PyErr_Occurred()) {
return NPY_FALSE;
}
PyBuffer_Release(&view);
- /*
- * The first call to PyObject_GetBuffer stores a reference to a struct
- * _buffer_info_t (from buffer.c, with format, ndim, strides and shape) in
- * a static dictionary, with id(base) as the key. Usually we release it
- * after the call to PyBuffer_Release, via a call to
- * _dealloc_cached_buffer_info, but in this case leave it in the cache to
- * speed up future calls to _IsWriteable.
- */
return NPY_TRUE;
}
convert_shape_to_string(npy_intp n, npy_intp const *vals, char *ending)
{
npy_intp i;
- PyObject *ret, *tmp;
/*
* Negative dimension indicates "newaxis", which can
for (i = 0; i < n && vals[i] < 0; i++);
if (i == n) {
- return PyUString_FromFormat("()%s", ending);
- }
- else {
- ret = PyUString_FromFormat("(%" NPY_INTP_FMT, vals[i++]);
- if (ret == NULL) {
- return NULL;
- }
+ return PyUnicode_FromFormat("()%s", ending);
}
+ PyObject *ret = PyUnicode_FromFormat("%" NPY_INTP_FMT, vals[i++]);
+ if (ret == NULL) {
+ return NULL;
+ }
for (; i < n; ++i) {
+ PyObject *tmp;
+
if (vals[i] < 0) {
- tmp = PyUString_FromString(",newaxis");
+ tmp = PyUnicode_FromString(",newaxis");
}
else {
- tmp = PyUString_FromFormat(",%" NPY_INTP_FMT, vals[i]);
+ tmp = PyUnicode_FromFormat(",%" NPY_INTP_FMT, vals[i]);
}
if (tmp == NULL) {
Py_DECREF(ret);
return NULL;
}
- PyUString_ConcatAndDel(&ret, tmp);
+ Py_SETREF(ret, PyUnicode_Concat(ret, tmp));
+ Py_DECREF(tmp);
if (ret == NULL) {
return NULL;
}
}
if (i == 1) {
- tmp = PyUString_FromFormat(",)%s", ending);
+ Py_SETREF(ret, PyUnicode_FromFormat("(%S,)%s", ret, ending));
}
else {
- tmp = PyUString_FromFormat(")%s", ending);
+ Py_SETREF(ret, PyUnicode_FromFormat("(%S)%s", ret, ending));
}
- PyUString_ConcatAndDel(&ret, tmp);
return ret;
}
*shape1 = NULL, *shape2 = NULL,
*shape1_i = NULL, *shape2_j = NULL;
- format = PyUString_FromString("shapes %s and %s not aligned:"
+ format = PyUnicode_FromString("shapes %s and %s not aligned:"
" %d (dim %d) != %d (dim %d)");
shape1 = convert_shape_to_string(PyArray_NDIM(a), PyArray_DIMS(a), "");
goto end;
}
- errmsg = PyUString_Format(format, fmt_args);
+ errmsg = PyUnicode_Format(format, fmt_args);
if (errmsg != NULL) {
PyErr_SetObject(PyExc_ValueError, errmsg);
}
*descr = (PyArray_Descr *)PyTuple_GET_ITEM(value, 0);
off = PyTuple_GET_ITEM(value, 1);
- if (PyInt_Check(off)) {
- *offset = PyInt_AsSsize_t(off);
- }
- else if (PyLong_Check(off)) {
+ if (PyLong_Check(off)) {
*offset = PyLong_AsSsize_t(off);
}
else {
#define _NPY_PRIVATE_COMMON_H_
#include "structmember.h"
#include <numpy/npy_common.h>
-#include <numpy/npy_cpu.h>
#include <numpy/ndarraytypes.h>
#include <limits.h>
+#include "npy_import.h"
#define error_converting(x) (((x) == -1) && PyErr_Occurred())
#define NPY_BEGIN_THREADS_NDITER(iter)
#endif
+
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_DTypeFromObjectStringDiscovery(
+ PyObject *obj, PyArray_Descr *last_dtype, int string_type);
+
/*
* Recursively examines the object to determine an appropriate dtype
* to use for converting to an ndarray.
static PyObject *AxisError_cls = NULL;
PyObject *exc;
+ npy_cache_import("numpy.core._exceptions", "AxisError", &AxisError_cls);
if (AxisError_cls == NULL) {
- PyObject *mod = PyImport_ImportModule("numpy.core._exceptions");
-
- if (mod != NULL) {
- AxisError_cls = PyObject_GetAttrString(mod, "AxisError");
- Py_DECREF(mod);
- }
+ return -1;
}
/* Invoke the AxisError constructor */
new_array_for_sum(PyArrayObject *ap1, PyArrayObject *ap2, PyArrayObject* out,
int nd, npy_intp dimensions[], int typenum, PyArrayObject **result);
+
+/*
+ * Used to indicate a broadcast axis, see also `npyiter_get_op_axis` in
+ * `nditer_constr.c`. This may be the preferred API for reduction axes
+ * probably. So we should consider making this public either as a macro or
+ * function (so that the way we flag the axis can be changed).
+ */
+#define NPY_ITER_REDUCTION_AXIS(axis) (axis + (1 << (NPY_BITSOF_INT - 2)))
+
#endif
NPY_END_THREADS
Py_DECREF(arr_x);
- return PyInt_FromLong(monotonic);
+ return PyLong_FromLong(monotonic);
}
/*
{
PyObject *obj;
PyObject *str;
- #if (PY_VERSION_HEX >= 0x030700A2)
+ #if PY_VERSION_HEX >= 0x030700A2 && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM > 0x07030300)
const char *docstr;
#else
char *docstr;
#endif
static char *msg = "already has a different docstring";
- PyObject *tp_dict = PyArrayDescr_Type.tp_dict;
- PyObject *myobj;
- static PyTypeObject *PyMemberDescr_TypePtr = NULL;
- static PyTypeObject *PyGetSetDescr_TypePtr = NULL;
- static PyTypeObject *PyMethodDescr_TypePtr = NULL;
/* Don't add docstrings */
if (Py_OptimizeFlag > 1) {
Py_RETURN_NONE;
}
- if (PyGetSetDescr_TypePtr == NULL) {
- /* Get "subdescr" */
- myobj = _PyDict_GetItemStringWithError(tp_dict, "fields");
- if (myobj == NULL && PyErr_Occurred()) {
- return NULL;
- }
- if (myobj != NULL) {
- PyGetSetDescr_TypePtr = Py_TYPE(myobj);
- }
- }
- if (PyMemberDescr_TypePtr == NULL) {
- myobj = _PyDict_GetItemStringWithError(tp_dict, "alignment");
- if (myobj == NULL && PyErr_Occurred()) {
- return NULL;
- }
- if (myobj != NULL) {
- PyMemberDescr_TypePtr = Py_TYPE(myobj);
- }
- }
- if (PyMethodDescr_TypePtr == NULL) {
- myobj = _PyDict_GetItemStringWithError(tp_dict, "newbyteorder");
- if (myobj == NULL && PyErr_Occurred()) {
- return NULL;
- }
- if (myobj != NULL) {
- PyMethodDescr_TypePtr = Py_TYPE(myobj);
- }
- }
-
if (!PyArg_ParseTuple(args, "OO!:add_docstring", &obj, &PyUnicode_Type, &str)) {
return NULL;
}
return NULL;
}
-#define _TESTDOC1(typebase) (Py_TYPE(obj) == &Py##typebase##_Type)
-#define _TESTDOC2(typebase) (Py_TYPE(obj) == Py##typebase##_TypePtr)
-#define _ADDDOC(typebase, doc, name) do { \
- Py##typebase##Object *new = (Py##typebase##Object *)obj; \
+#define _ADDDOC(doc, name) \
if (!(doc)) { \
doc = docstr; \
+ Py_INCREF(str); /* hold on to string (leaks reference) */ \
} \
else if (strcmp(doc, docstr) != 0) { \
PyErr_Format(PyExc_RuntimeError, "%s method %s", name, msg); \
return NULL; \
- } \
- } while (0)
+ }
- if (_TESTDOC1(CFunction)) {
- _ADDDOC(CFunction, new->m_ml->ml_doc, new->m_ml->ml_name);
+ if (Py_TYPE(obj) == &PyCFunction_Type) {
+ PyCFunctionObject *new = (PyCFunctionObject *)obj;
+ _ADDDOC(new->m_ml->ml_doc, new->m_ml->ml_name);
}
- else if (_TESTDOC1(Type)) {
- _ADDDOC(Type, new->tp_doc, new->tp_name);
+ else if (Py_TYPE(obj) == &PyType_Type) {
+ PyTypeObject *new = (PyTypeObject *)obj;
+ _ADDDOC(new->tp_doc, new->tp_name);
}
- else if (_TESTDOC2(MemberDescr)) {
- _ADDDOC(MemberDescr, new->d_member->doc, new->d_member->name);
+ else if (Py_TYPE(obj) == &PyMemberDescr_Type) {
+ PyMemberDescrObject *new = (PyMemberDescrObject *)obj;
+ _ADDDOC(new->d_member->doc, new->d_member->name);
}
- else if (_TESTDOC2(GetSetDescr)) {
- _ADDDOC(GetSetDescr, new->d_getset->doc, new->d_getset->name);
+ else if (Py_TYPE(obj) == &PyGetSetDescr_Type) {
+ PyGetSetDescrObject *new = (PyGetSetDescrObject *)obj;
+ _ADDDOC(new->d_getset->doc, new->d_getset->name);
}
- else if (_TESTDOC2(MethodDescr)) {
- _ADDDOC(MethodDescr, new->d_method->ml_doc, new->d_method->ml_name);
+ else if (Py_TYPE(obj) == &PyMethodDescr_Type) {
+ PyMethodDescrObject *new = (PyMethodDescrObject *)obj;
+ _ADDDOC(new->d_method->ml_doc, new->d_method->ml_name);
}
else {
PyObject *doc_attr;
doc_attr = PyObject_GetAttrString(obj, "__doc__");
if (doc_attr != NULL && doc_attr != Py_None &&
(PyUnicode_Compare(doc_attr, str) != 0)) {
+ Py_DECREF(doc_attr);
if (PyErr_Occurred()) {
/* error during PyUnicode_Compare */
return NULL;
Py_RETURN_NONE;
}
-#undef _TESTDOC1
-#undef _TESTDOC2
#undef _ADDDOC
- Py_INCREF(str);
Py_RETURN_NONE;
}
#include <emmintrin.h>
#endif
+#ifdef NPY_HAVE_NEON
+ typedef npy_uint64 uint64_unaligned __attribute__((aligned(16)));
+ static NPY_INLINE int32_t
+ sign_mask(uint8x16_t input)
+ {
+ int8x8_t m0 = vcreate_s8(0x0706050403020100ULL);
+ uint8x16_t v0 = vshlq_u8(vshrq_n_u8(input, 7), vcombine_s8(m0, m0));
+ uint64x2_t v1 = vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(v0)));
+ return (int)vgetq_lane_u64(v1, 0) + ((int)vgetq_lane_u64(v1, 1) << 8);
+ }
+#endif
/*
* This function packs boolean values in the input array into the bits of a
* byte array. Truth values are determined as usual: 0 is false, everything
a = npy_bswap8(a);
b = npy_bswap8(b);
}
+
/* note x86 can load unaligned */
__m128i v = _mm_set_epi64(_m_from_int64(b), _m_from_int64(a));
/* false -> 0x00 and true -> 0xFF (there is no cmpneq) */
inptr += 16;
}
}
+#elif defined NPY_HAVE_NEON
+ if (in_stride == 1 && element_size == 1 && n_out > 2) {
+ /* don't handle non-full 8-byte remainder */
+ npy_intp vn_out = n_out - (remain ? 1 : 0);
+ vn_out -= (vn_out & 1);
+ for (index = 0; index < vn_out; index += 2) {
+ unsigned int r;
+ npy_uint64 a = *((uint64_unaligned*)inptr);
+ npy_uint64 b = *((uint64_unaligned*)(inptr + 8));
+ if (order == 'b') {
+ a = npy_bswap8(a);
+ b = npy_bswap8(b);
+ }
+ uint64x2_t v = vcombine_u64(vcreate_u64(a), vcreate_u64(b));
+ uint64x2_t zero = vdupq_n_u64(0);
+ /* false -> 0x00 and true -> 0xFF */
+ v = vreinterpretq_u64_u8(vmvnq_u8(vceqq_u8(vreinterpretq_u8_u64(v), vreinterpretq_u8_u64(zero))));
+ /* extract msb of 16 bytes and pack it into 16 bit */
+ uint8x16_t input = vreinterpretq_u8_u64(v);
+ r = sign_mask(input);
+ /* store result */
+ memcpy(outptr, &r, 1);
+ outptr += out_stride;
+ memcpy(outptr, (char*)&r + 1, 1);
+ outptr += out_stride;
+ inptr += 16;
+ }
+ }
#endif
if (remain == 0) { /* assumes n_in > 0 */
#define _MULTIARRAYMODULE
#include "numpy/arrayobject.h"
#include "numpy/arrayscalars.h"
-#include "numpy/arrayobject.h"
#include "npy_config.h"
#include "npy_pycompat.h"
seq->ptr = NULL;
seq->len = 0;
+
+ /*
+ * When the deprecation below expires, remove the `if` statement, and
+ * update the comment for PyArray_OptionalIntpConverter.
+ */
if (obj == Py_None) {
+ /* Numpy 1.20, 2020-05-31 */
+ if (DEPRECATE(
+ "Passing None into shape arguments as an alias for () is "
+ "deprecated.") < 0){
+ return NPY_FAIL;
+ }
return NPY_SUCCEED;
}
+
len = PySequence_Size(obj);
if (len == -1) {
/* Check to see if it is an integer number */
* sticks around after the release.
*/
PyBuffer_Release(&view);
- _dealloc_cached_buffer_info(obj);
/* Point to the base of the buffer object if present */
if (PyMemoryView_Check(obj)) {
int ret = str_func(str, length, out);
Py_DECREF(str_object);
if (ret < 0) {
+ /* str_func returns -1 without an exception if the value is wrong */
+ if (!PyErr_Occurred()) {
PyErr_Format(PyExc_ValueError,
"%s %s (got %R)", name, message, object);
+ }
return NPY_FAIL;
}
return NPY_SUCCEED;
if (length < 1) {
return -1;
}
- else if (str[0] == NPY_BIG || str[0] == NPY_LITTLE
- || str[0] == NPY_NATIVE || str[0] == NPY_IGNORE) {
+ else if (str[0] == NPY_BIG || str[0] == NPY_LITTLE ||
+ str[0] == NPY_NATIVE || str[0] == NPY_IGNORE) {
*endian = str[0];
return 0;
}
static int searchside_parser(char const *str, Py_ssize_t length, void *data)
{
NPY_SEARCHSIDE *side = (NPY_SEARCHSIDE *)data;
+ int is_exact = 0;
if (length < 1) {
return -1;
}
else if (str[0] == 'l' || str[0] == 'L') {
*side = NPY_SEARCHLEFT;
- return 0;
+ is_exact = (length == 4 && strcmp(str, "left") == 0);
}
else if (str[0] == 'r' || str[0] == 'R') {
*side = NPY_SEARCHRIGHT;
- return 0;
+ is_exact = (length == 5 && strcmp(str, "right") == 0);
}
else {
return -1;
}
+
+ /* Filters out the case sensitive/non-exact
+ * match inputs and other inputs and outputs DeprecationWarning
+ */
+ if (!is_exact) {
+ /* NumPy 1.20, 2020-05-19 */
+ if (DEPRECATE("inexact matches and case insensitive matches "
+ "for search side are deprecated, please use "
+ "one of 'left' or 'right' instead.") < 0) {
+ return -1;
+ }
+ }
+
+ return 0;
}
/*NUMPY_API
static int clipmode_parser(char const *str, Py_ssize_t length, void *data)
{
NPY_CLIPMODE *val = (NPY_CLIPMODE *)data;
+ int is_exact = 0;
+
if (length < 1) {
return -1;
}
if (str[0] == 'C' || str[0] == 'c') {
*val = NPY_CLIP;
- return 0;
+ is_exact = (length == 4 && strcmp(str, "clip") == 0);
}
else if (str[0] == 'W' || str[0] == 'w') {
*val = NPY_WRAP;
- return 0;
+ is_exact = (length == 4 && strcmp(str, "wrap") == 0);
}
else if (str[0] == 'R' || str[0] == 'r') {
*val = NPY_RAISE;
- return 0;
+ is_exact = (length == 5 && strcmp(str, "raise") == 0);
}
else {
return -1;
}
+
+ /* Filters out the case sensitive/non-exact
+ * match inputs and other inputs and outputs DeprecationWarning
+ */
+ if (!is_exact) {
+ /* Numpy 1.20, 2020-05-19 */
+ if (DEPRECATE("inexact matches and case insensitive matches "
+ "for clip mode are deprecated, please use "
+ "one of 'clip', 'raise', or 'wrap' instead.") < 0) {
+ return -1;
+ }
+ }
+
+ return 0;
}
/*NUMPY_API
}
for (i = 0; i < len; i++) {
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
- PyObject *o = PyInt_FromLong((long) vals[i]);
+ PyObject *o = PyLong_FromLong((long) vals[i]);
#else
PyObject *o = PyLong_FromLongLong((npy_longlong) vals[i]);
#endif
#define _MULTIARRAYMODULE
#include "numpy/arrayobject.h"
#include "numpy/arrayscalars.h"
-
-#include "npy_config.h"
-
#include "npy_pycompat.h"
#include "common.h"
return -1;
}
PyTuple_SET_ITEM(tupobj,0,obj);
- obj = PyUString_FromString((const char *)format);
+ obj = PyUnicode_FromString((const char *)format);
if (obj == NULL) {
Py_DECREF(tupobj);
Py_DECREF(it);
return -1;
}
- strobj = PyUString_Format(obj, tupobj);
+ strobj = PyUnicode_Format(obj, tupobj);
Py_DECREF(obj);
Py_DECREF(tupobj);
if (strobj == NULL) {
}
}
/* Python integer */
- else if (PyLong_Check(obj) || PyInt_Check(obj)) {
+ else if (PyLong_Check(obj)) {
/* Try long long before unsigned long long */
npy_longlong ll_v = PyLong_AsLongLong(obj);
if (error_converting(ll_v)) {
#include "npy_pycompat.h"
#include "numpy/npy_math.h"
+#include "array_coercion.h"
#include "common.h"
#include "ctors.h"
+#include "dtypemeta.h"
#include "scalartypes.h"
#include "mapping.h"
+#include "legacy_dtype_implementation.h"
#include "convert_datatype.h"
#include "_datetime.h"
#include "datetime_strings.h"
+#include "array_method.h"
+#include "usertypes.h"
/*
*/
NPY_NO_EXPORT npy_intp REQUIRED_STR_LEN[] = {0, 3, 5, 10, 10, 20, 20, 20, 20};
+
+static PyObject *
+PyArray_GetGenericToVoidCastingImpl(void);
+
+static PyObject *
+PyArray_GetVoidToGenericCastingImpl(void);
+
+static PyObject *
+PyArray_GetGenericToObjectCastingImpl(void);
+
+static PyObject *
+PyArray_GetObjectToGenericCastingImpl(void);
+
+
+/**
+ * Fetch the casting implementation from one DType to another.
+ *
+ * @params from
+ * @params to
+ *
+ * @returns A castingimpl (PyArrayDTypeMethod *), None or NULL with an
+ * error set.
+ */
+static PyObject *
+PyArray_GetCastingImpl(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to)
+{
+ PyObject *res = PyDict_GetItem(from->castingimpls, (PyObject *)to);
+ if (res != NULL || PyErr_Occurred()) {
+ Py_XINCREF(res);
+ return res;
+ }
+ /*
+ * The following code looks up CastingImpl based on the fact that anything
+ * can be cast to and from objects or structured (void) dtypes.
+ *
+ * The last part adds casts dynamically based on legacy definition
+ */
+ if (from->type_num == NPY_OBJECT) {
+ res = PyArray_GetObjectToGenericCastingImpl();
+ }
+ else if (to->type_num == NPY_OBJECT) {
+ res = PyArray_GetGenericToObjectCastingImpl();
+ }
+ else if (from->type_num == NPY_VOID) {
+ res = PyArray_GetVoidToGenericCastingImpl();
+ }
+ else if (to->type_num == NPY_VOID) {
+ res = PyArray_GetGenericToVoidCastingImpl();
+ }
+ else if (from->type_num < NPY_NTYPES && to->type_num < NPY_NTYPES) {
+ /* All builtin dtypes have their casts explicitly defined. */
+ PyErr_Format(PyExc_RuntimeError,
+ "builtin cast from %S to %s not found, this should not "
+ "be possible.", from, to);
+ return NULL;
+ }
+ else {
+ if (from->parametric || to->parametric) {
+ Py_RETURN_NONE;
+ }
+ /* Reject non-legacy dtypes (they need to use the new API) */
+ if (!from->legacy || !to->legacy) {
+ Py_RETURN_NONE;
+ }
+ if (from != to) {
+ /* A cast function must have been registered */
+ PyArray_VectorUnaryFunc *castfunc = PyArray_GetCastFunc(
+ from->singleton, to->type_num);
+ if (castfunc == NULL) {
+ PyErr_Clear();
+ /* Remember that this cast is not possible */
+ if (PyDict_SetItem(from->castingimpls, (PyObject *) to, Py_None) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+ }
+ }
+
+ /* PyArray_AddLegacyWrapping_CastingImpl find the correct casting level: */
+ /*
+ * TODO: Possibly move this to the cast registration time. But if we do
+ * that, we have to also update the cast when the casting safety
+ * is registered.
+ */
+ if (PyArray_AddLegacyWrapping_CastingImpl(from, to, -1) < 0) {
+ return NULL;
+ }
+ return PyArray_GetCastingImpl(from, to);
+ }
+
+ if (res == NULL) {
+ return NULL;
+ }
+ if (PyDict_SetItem(from->castingimpls, (PyObject *)to, res) < 0) {
+ Py_DECREF(res);
+ return NULL;
+ }
+ return res;
+}
+
+
+/**
+ * Fetch the (bound) casting implementation from one DType to another.
+ *
+ * @params from
+ * @params to
+ *
+ * @returns A bound casting implementation or None (or NULL for error).
+ */
+static PyObject *
+PyArray_GetBoundCastingImpl(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to)
+{
+ PyObject *method = PyArray_GetCastingImpl(from, to);
+ if (method == NULL || method == Py_None) {
+ return method;
+ }
+
+ /* TODO: Create better way to wrap method into bound method */
+ PyBoundArrayMethodObject *res;
+ res = PyObject_New(PyBoundArrayMethodObject, &PyBoundArrayMethod_Type);
+ if (res == NULL) {
+ return NULL;
+ }
+ res->method = (PyArrayMethodObject *)method;
+ res->dtypes = PyMem_Malloc(2 * sizeof(PyArray_DTypeMeta *));
+ if (res->dtypes == NULL) {
+ Py_DECREF(res);
+ return NULL;
+ }
+ Py_INCREF(from);
+ res->dtypes[0] = from;
+ Py_INCREF(to);
+ res->dtypes[1] = to;
+
+ return (PyObject *)res;
+}
+
+
+NPY_NO_EXPORT PyObject *
+_get_castingimpl(PyObject *NPY_UNUSED(module), PyObject *args)
+{
+ PyArray_DTypeMeta *from, *to;
+ if (!PyArg_ParseTuple(args, "O!O!:_get_castingimpl",
+ &PyArrayDTypeMeta_Type, &from, &PyArrayDTypeMeta_Type, &to)) {
+ return NULL;
+ }
+ return PyArray_GetBoundCastingImpl(from, to);
+}
+
+
+/**
+ * Find the minimal cast safety level given two cast-levels as input.
+ * Supports the NPY_CAST_IS_VIEW check, and should be preferred to allow
+ * extending cast-levels if necessary.
+ * It is not valid for one of the arguments to be -1 to indicate an error.
+ *
+ * @param casting1
+ * @param casting2
+ * @return The minimal casting error (can be -1).
+ */
+NPY_NO_EXPORT NPY_CASTING
+PyArray_MinCastSafety(NPY_CASTING casting1, NPY_CASTING casting2)
+{
+ if (casting1 < 0 || casting2 < 0) {
+ return -1;
+ }
+ NPY_CASTING view = casting1 & casting2 & _NPY_CAST_IS_VIEW;
+ casting1 = casting1 & ~_NPY_CAST_IS_VIEW;
+ casting2 = casting2 & ~_NPY_CAST_IS_VIEW;
+ /* larger casting values are less safe */
+ if (casting1 > casting2) {
+ return casting1 | view;
+ }
+ return casting2 | view;
+}
+
+
/*NUMPY_API
* For backward compatibility
*
{
PyObject *out;
- /* If the requested dtype is flexible, adapt it */
- dtype = PyArray_AdaptFlexibleDType((PyObject *)arr, PyArray_DESCR(arr), dtype);
+ Py_SETREF(dtype, PyArray_AdaptDescriptorToArray(arr, (PyObject *)dtype));
if (dtype == NULL) {
return NULL;
}
+
out = PyArray_NewFromDescr(Py_TYPE(arr), dtype,
PyArray_NDIM(arr),
PyArray_DIMS(arr),
PyObject *key;
PyObject *cobj;
- key = PyInt_FromLong(type_num);
+ key = PyLong_FromLong(type_num);
cobj = PyDict_GetItem(obj, key);
Py_DECREF(key);
- if (cobj && NpyCapsule_Check(cobj)) {
- castfunc = NpyCapsule_AsVoidPtr(cobj);
+ if (cobj && PyCapsule_CheckExact(cobj)) {
+ castfunc = PyCapsule_GetPointer(cobj, NULL);
+ if (castfunc == NULL) {
+ return NULL;
+ }
}
}
}
return NULL;
}
-/*
- * This function returns a dtype based on flex_dtype and the values in
- * data_dtype and data_obj. It also calls Py_DECREF on the flex_dtype. If the
- * flex_dtype is not flexible, it returns it as-is.
- *
- * Usually, if data_obj is not an array, dtype should be the result
- * given by the PyArray_GetArrayParamsFromObject function.
- *
- * The data_obj may be NULL if just a dtype is known for the source.
- *
- * If *flex_dtype is NULL, returns immediately, without setting an
- * exception, leaving any previous error handling intact.
- *
- * The current flexible dtypes include NPY_STRING, NPY_UNICODE, NPY_VOID,
- * and NPY_DATETIME with generic units.
- */
-NPY_NO_EXPORT PyArray_Descr *
-PyArray_AdaptFlexibleDType(PyObject *data_obj, PyArray_Descr *data_dtype,
- PyArray_Descr *flex_dtype)
-{
- PyArray_DatetimeMetaData *meta;
- PyArray_Descr *retval = NULL;
- int flex_type_num;
-
- if (flex_dtype == NULL) {
- return retval;
- }
-
- flex_type_num = flex_dtype->type_num;
-
- /* Flexible types with expandable size */
- if (PyDataType_ISUNSIZED(flex_dtype)) {
- /* First replace the flex_dtype */
- retval = PyArray_DescrNew(flex_dtype);
- Py_DECREF(flex_dtype);
- if (retval == NULL) {
- return retval;
- }
-
- if (data_dtype->type_num == flex_type_num ||
- flex_type_num == NPY_VOID) {
- (retval)->elsize = data_dtype->elsize;
- }
- else if (flex_type_num == NPY_STRING || flex_type_num == NPY_UNICODE) {
- npy_intp size = 8;
-
- /*
- * Get a string-size estimate of the input. These
- * are generallly the size needed, rounded up to
- * a multiple of eight.
- */
- switch (data_dtype->type_num) {
- case NPY_BOOL:
- case NPY_UBYTE:
- case NPY_BYTE:
- case NPY_USHORT:
- case NPY_SHORT:
- case NPY_UINT:
- case NPY_INT:
- case NPY_ULONG:
- case NPY_LONG:
- case NPY_ULONGLONG:
- case NPY_LONGLONG:
- if (data_dtype->kind == 'b') {
- /* 5 chars needed for cast to 'True' or 'False' */
- size = 5;
- }
- else if (data_dtype->elsize > 8 ||
- data_dtype->elsize < 0) {
- /*
- * Element size should never be greater than 8 or
- * less than 0 for integer type, but just in case...
- */
- break;
- }
- else if (data_dtype->kind == 'u') {
- size = REQUIRED_STR_LEN[data_dtype->elsize];
- }
- else if (data_dtype->kind == 'i') {
- /* Add character for sign symbol */
- size = REQUIRED_STR_LEN[data_dtype->elsize] + 1;
- }
- break;
- case NPY_HALF:
- case NPY_FLOAT:
- case NPY_DOUBLE:
- size = 32;
- break;
- case NPY_LONGDOUBLE:
- size = 48;
- break;
- case NPY_CFLOAT:
- case NPY_CDOUBLE:
- size = 2 * 32;
- break;
- case NPY_CLONGDOUBLE:
- size = 2 * 48;
- break;
- case NPY_OBJECT:
- size = 64;
- if ((flex_type_num == NPY_STRING ||
- flex_type_num == NPY_UNICODE) &&
- data_obj != NULL) {
- PyObject *list;
-
- if (PyArray_CheckScalar(data_obj)) {
- list = PyArray_ToList((PyArrayObject *)data_obj);
- if (list != NULL) {
- PyObject *s = PyObject_Str(list);
- if (s == NULL) {
- Py_DECREF(list);
- Py_DECREF(retval);
- return NULL;
- }
- else {
- size = PyObject_Length(s);
- Py_DECREF(s);
- }
- Py_DECREF(list);
- }
- }
- else if (PyArray_Check(data_obj)) {
- /*
- * Convert data array to list of objects since
- * GetArrayParamsFromObject won't iterate over
- * array.
- */
- PyArray_Descr *dtype = NULL;
- PyArrayObject *arr = NULL;
- int result;
- int ndim = 0;
- npy_intp dims[NPY_MAXDIMS];
- list = PyArray_ToList((PyArrayObject *)data_obj);
- result = PyArray_GetArrayParamsFromObject_int(
- list,
- retval,
- 0, &dtype,
- &ndim, dims, &arr);
- Py_DECREF(list);
- Py_XDECREF(arr);
- if (result < 0) {
- Py_XDECREF(dtype);
- Py_DECREF(retval);
- return NULL;
- }
- if (result == 0 && dtype != NULL) {
- if (flex_type_num == NPY_UNICODE) {
- size = dtype->elsize / 4;
- }
- else {
- size = dtype->elsize;
- }
- }
- Py_XDECREF(dtype);
- }
- else if (PyArray_IsPythonScalar(data_obj)) {
- PyObject *s = PyObject_Str(data_obj);
- if (s == NULL) {
- Py_DECREF(retval);
- return NULL;
- }
- else {
- size = PyObject_Length(s);
- Py_DECREF(s);
- }
- }
- }
- break;
- case NPY_STRING:
- case NPY_VOID:
- size = data_dtype->elsize;
- break;
- case NPY_UNICODE:
- size = data_dtype->elsize / 4;
- break;
- case NPY_DATETIME:
- meta = get_datetime_metadata_from_dtype(data_dtype);
- if (meta == NULL) {
- Py_DECREF(retval);
- return NULL;
- }
- size = get_datetime_iso_8601_strlen(0, meta->base);
- break;
- case NPY_TIMEDELTA:
- size = 21;
- break;
- }
-
- if (flex_type_num == NPY_STRING) {
- retval->elsize = size;
- }
- else if (flex_type_num == NPY_UNICODE) {
- retval->elsize = size * 4;
- }
- }
- else {
- /*
- * We should never get here, but just in case someone adds
- * a new flex dtype...
- */
- PyErr_SetString(PyExc_TypeError,
- "don't know how to adapt flex dtype");
- Py_DECREF(retval);
- return NULL;
- }
- }
- /* Flexible type with generic time unit that adapts */
- else if (flex_type_num == NPY_DATETIME ||
- flex_type_num == NPY_TIMEDELTA) {
- meta = get_datetime_metadata_from_dtype(flex_dtype);
- retval = flex_dtype;
- if (meta == NULL) {
- return NULL;
- }
-
- if (meta->base == NPY_FR_GENERIC) {
- if (data_dtype->type_num == NPY_DATETIME ||
- data_dtype->type_num == NPY_TIMEDELTA) {
- meta = get_datetime_metadata_from_dtype(data_dtype);
- if (meta == NULL) {
- return NULL;
- }
-
- retval = create_datetime_dtype(flex_type_num, meta);
- Py_DECREF(flex_dtype);
- }
- else if (data_obj != NULL) {
- /* Detect the unit from the input's data */
- retval = find_object_datetime_type(data_obj,
- flex_type_num);
- Py_DECREF(flex_dtype);
- }
- }
- }
- else {
- retval = flex_dtype;
- }
- return retval;
-}
/*
* Must be broadcastable.
return PyArray_CopyAnyInto(out, mp);
}
+
+/**
+ * Given two dtype instances, find the correct casting safety.
+ *
+ * Note that in many cases, it may be preferable to fetch the casting
+ * implementations fully to have them available for doing the actual cast
+ * later.
+ *
+ * @param from
+ * @param to The descriptor to cast to (may be NULL)
+ * @param to_dtype If `to` is NULL, must pass the to_dtype (otherwise this
+ * is ignored).
+ * @return NPY_CASTING or -1 on error or if the cast is not possible.
+ */
+NPY_NO_EXPORT NPY_CASTING
+PyArray_GetCastSafety(
+ PyArray_Descr *from, PyArray_Descr *to, PyArray_DTypeMeta *to_dtype)
+{
+ NPY_CASTING casting;
+ if (to != NULL) {
+ to_dtype = NPY_DTYPE(to);
+ }
+ PyObject *meth = PyArray_GetCastingImpl(NPY_DTYPE(from), to_dtype);
+ if (meth == NULL) {
+ return -1;
+ }
+ if (meth == Py_None) {
+ Py_DECREF(Py_None);
+ return -1;
+ }
+
+ PyArrayMethodObject *castingimpl = (PyArrayMethodObject *)meth;
+
+ PyArray_DTypeMeta *dtypes[2] = {NPY_DTYPE(from), to_dtype};
+ PyArray_Descr *descrs[2] = {from, to};
+ PyArray_Descr *out_descrs[2];
+
+ casting = castingimpl->resolve_descriptors(
+ castingimpl, dtypes, descrs, out_descrs);
+ Py_DECREF(meth);
+ if (casting < 0) {
+ return -1;
+ }
+ /* The returned descriptors may not match, requiring a second check */
+ if (out_descrs[0] != descrs[0]) {
+ NPY_CASTING from_casting = PyArray_GetCastSafety(
+ descrs[0], out_descrs[0], NULL);
+ casting = PyArray_MinCastSafety(casting, from_casting);
+ if (casting < 0) {
+ goto finish;
+ }
+ }
+ if (descrs[1] != NULL && out_descrs[1] != descrs[1]) {
+ NPY_CASTING from_casting = PyArray_GetCastSafety(
+ descrs[1], out_descrs[1], NULL);
+ casting = PyArray_MinCastSafety(casting, from_casting);
+ if (casting < 0) {
+ goto finish;
+ }
+ }
+
+ finish:
+ Py_DECREF(out_descrs[0]);
+ Py_DECREF(out_descrs[1]);
+ /* NPY_NO_CASTING has to be used for (NPY_EQUIV_CASTING|_NPY_CAST_IS_VIEW) */
+ assert(casting != (NPY_EQUIV_CASTING|_NPY_CAST_IS_VIEW));
+ return casting;
+}
+
+
/*NUMPY_API
*Check the type coercion rules.
*/
NPY_NO_EXPORT int
PyArray_CanCastSafely(int fromtype, int totype)
{
- PyArray_Descr *from;
-
- /* Fast table lookup for small type numbers */
- if ((unsigned int)fromtype < NPY_NTYPES &&
- (unsigned int)totype < NPY_NTYPES) {
- return _npy_can_cast_safely_table[fromtype][totype];
+#if NPY_USE_NEW_CASTINGIMPL
+ PyArray_DTypeMeta *from = PyArray_DTypeFromTypeNum(fromtype);
+ if (from == NULL) {
+ PyErr_WriteUnraisable(NULL);
+ return 0;
}
-
- /* Identity */
- if (fromtype == totype) {
- return 1;
+ PyArray_DTypeMeta *to = PyArray_DTypeFromTypeNum(totype);
+ if (to == NULL) {
+ PyErr_WriteUnraisable(NULL);
+ return 0;
}
- /* Special-cases for some types */
- switch (fromtype) {
- case NPY_DATETIME:
- case NPY_TIMEDELTA:
- case NPY_OBJECT:
- case NPY_VOID:
- return 0;
- case NPY_BOOL:
- return 1;
+ PyObject *castingimpl = PyArray_GetCastingImpl(from, to);
+ Py_DECREF(from);
+ Py_DECREF(to);
+
+ if (castingimpl == NULL) {
+ PyErr_WriteUnraisable(NULL);
+ return 0;
}
- switch (totype) {
- case NPY_BOOL:
- case NPY_DATETIME:
- case NPY_TIMEDELTA:
- return 0;
- case NPY_OBJECT:
- case NPY_VOID:
- return 1;
+ else if (castingimpl == Py_None) {
+ Py_DECREF(Py_None);
+ return 0;
}
+ NPY_CASTING safety = ((PyArrayMethodObject *)castingimpl)->casting;
+ int res = PyArray_MinCastSafety(safety, NPY_SAFE_CASTING) == NPY_SAFE_CASTING;
+ Py_DECREF(castingimpl);
+ return res;
+#else
+ return PyArray_LegacyCanCastSafely(fromtype, totype);
+#endif
+}
- from = PyArray_DescrFromType(fromtype);
- /*
- * cancastto is a NPY_NOTYPE terminated C-int-array of types that
- * the data-type can be cast to safely.
- */
- if (from->f->cancastto) {
- int *curtype = from->f->cancastto;
- while (*curtype != NPY_NOTYPE) {
- if (*curtype++ == totype) {
- return 1;
- }
- }
- }
- return 0;
-}
/*NUMPY_API
* leaves reference count alone --- cannot be NULL
NPY_NO_EXPORT npy_bool
PyArray_CanCastTo(PyArray_Descr *from, PyArray_Descr *to)
{
- int from_type_num = from->type_num;
- int to_type_num = to->type_num;
- npy_bool ret;
-
- ret = (npy_bool) PyArray_CanCastSafely(from_type_num, to_type_num);
- if (ret) {
- /* Check String and Unicode more closely */
- if (from_type_num == NPY_STRING) {
- if (to_type_num == NPY_STRING) {
- ret = (from->elsize <= to->elsize);
- }
- else if (to_type_num == NPY_UNICODE) {
- ret = (from->elsize << 2 <= to->elsize);
- }
- }
- else if (from_type_num == NPY_UNICODE) {
- if (to_type_num == NPY_UNICODE) {
- ret = (from->elsize <= to->elsize);
- }
- }
- /*
- * For datetime/timedelta, only treat casts moving towards
- * more precision as safe.
- */
- else if (from_type_num == NPY_DATETIME && to_type_num == NPY_DATETIME) {
- PyArray_DatetimeMetaData *meta1, *meta2;
- meta1 = get_datetime_metadata_from_dtype(from);
- if (meta1 == NULL) {
- PyErr_Clear();
- return 0;
- }
- meta2 = get_datetime_metadata_from_dtype(to);
- if (meta2 == NULL) {
- PyErr_Clear();
- return 0;
- }
-
- return can_cast_datetime64_metadata(meta1, meta2,
- NPY_SAFE_CASTING);
- }
- else if (from_type_num == NPY_TIMEDELTA &&
- to_type_num == NPY_TIMEDELTA) {
- PyArray_DatetimeMetaData *meta1, *meta2;
- meta1 = get_datetime_metadata_from_dtype(from);
- if (meta1 == NULL) {
- PyErr_Clear();
- return 0;
- }
- meta2 = get_datetime_metadata_from_dtype(to);
- if (meta2 == NULL) {
- PyErr_Clear();
- return 0;
- }
-
- return can_cast_timedelta64_metadata(meta1, meta2,
- NPY_SAFE_CASTING);
- }
- /*
- * If to_type_num is STRING or unicode
- * see if the length is long enough to hold the
- * stringified value of the object.
- */
- else if (to_type_num == NPY_STRING || to_type_num == NPY_UNICODE) {
- /*
- * Boolean value cast to string type is 5 characters max
- * for string 'False'.
- */
- int char_size = 1;
- if (to_type_num == NPY_UNICODE) {
- char_size = 4;
- }
-
- ret = 0;
- if (PyDataType_ISUNSIZED(to)) {
- ret = 1;
- }
- /*
- * Need at least 5 characters to convert from boolean
- * to 'True' or 'False'.
- */
- else if (from->kind == 'b' && to->elsize >= 5 * char_size) {
- ret = 1;
- }
- else if (from->kind == 'u') {
- /* Guard against unexpected integer size */
- if (from->elsize > 8 || from->elsize < 0) {
- ret = 0;
- }
- else if (to->elsize >=
- REQUIRED_STR_LEN[from->elsize] * char_size) {
- ret = 1;
- }
- }
- else if (from->kind == 'i') {
- /* Guard against unexpected integer size */
- if (from->elsize > 8 || from->elsize < 0) {
- ret = 0;
- }
- /* Extra character needed for sign */
- else if (to->elsize >=
- (REQUIRED_STR_LEN[from->elsize] + 1) * char_size) {
- ret = 1;
- }
- }
- }
- }
- return ret;
+#if NPY_USE_NEW_CASTINGIMPL
+ return PyArray_CanCastTypeTo(from, to, NPY_SAFE_CASTING);
+#else
+ return PyArray_LegacyCanCastTo(from, to);
+#endif
}
+
/* Provides an ordering for the dtype 'kind' character codes */
-static int
+NPY_NO_EXPORT int
dtype_kind_to_ordering(char kind)
{
switch (kind) {
}
}
-/*
- * Compare two field dictionaries for castability.
- *
- * Return 1 if 'field1' can be cast to 'field2' according to the rule
- * 'casting', 0 if not.
- *
- * Castabiliy of field dictionaries is defined recursively: 'field1' and
- * 'field2' must have the same field names (possibly in different
- * orders), and the corresponding field types must be castable according
- * to the given casting rule.
- */
-static int
-can_cast_fields(PyObject *field1, PyObject *field2, NPY_CASTING casting)
-{
- Py_ssize_t ppos;
- PyObject *key;
- PyObject *tuple1, *tuple2;
-
- if (field1 == field2) {
- return 1;
- }
- if (field1 == NULL || field2 == NULL) {
- return 0;
- }
- if (PyDict_Size(field1) != PyDict_Size(field2)) {
- return 0;
- }
-
- /* Iterate over all the fields and compare for castability */
- ppos = 0;
- while (PyDict_Next(field1, &ppos, &key, &tuple1)) {
- if ((tuple2 = PyDict_GetItem(field2, key)) == NULL) {
- return 0;
- }
- /* Compare the dtype of the field for castability */
- if (!PyArray_CanCastTypeTo(
- (PyArray_Descr *)PyTuple_GET_ITEM(tuple1, 0),
- (PyArray_Descr *)PyTuple_GET_ITEM(tuple2, 0),
- casting)) {
- return 0;
- }
- }
-
- return 1;
-}
/*NUMPY_API
* Returns true if data of type 'from' may be cast to data of type
*/
NPY_NO_EXPORT npy_bool
PyArray_CanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to,
- NPY_CASTING casting)
+ NPY_CASTING casting)
{
+#if NPY_USE_NEW_CASTINGIMPL
/*
- * Fast paths for equality and for basic types.
+ * NOTE: This code supports U and S, this is identical to the code
+ * in `ctors.c` which does not allow these dtypes to be attached
+ * to an array. Unlike the code for `np.array(..., dtype=)`
+ * which uses `PyArray_ExtractDTypeAndDescriptor` it rejects "m8"
+ * as a flexible dtype instance representing a DType.
*/
- if (from == to ||
- ((NPY_LIKELY(PyDataType_ISNUMBER(from)) ||
- PyDataType_ISOBJECT(from)) &&
- NPY_LIKELY(from->type_num == to->type_num) &&
- NPY_LIKELY(from->byteorder == to->byteorder))) {
- return 1;
- }
/*
- * Cases with subarrays and fields need special treatment.
+ * TODO: We should grow support for `np.can_cast("d", "S")` being
+ * different from `np.can_cast("d", "S0")` here, at least for
+ * the python side API.
*/
- if (PyDataType_HASFIELDS(from)) {
- /*
- * If from is a structured data type, then it can be cast to a simple
- * non-object one only for unsafe casting *and* if it has a single
- * field; recurse just in case the single field is itself structured.
- */
- if (!PyDataType_HASFIELDS(to) && !PyDataType_ISOBJECT(to)) {
- if (casting == NPY_UNSAFE_CASTING &&
- PyDict_Size(from->fields) == 1) {
- Py_ssize_t ppos = 0;
- PyObject *tuple;
- PyArray_Descr *field;
- PyDict_Next(from->fields, &ppos, NULL, &tuple);
- field = (PyArray_Descr *)PyTuple_GET_ITEM(tuple, 0);
- /*
- * For a subarray, we need to get the underlying type;
- * since we already are casting unsafely, we can ignore
- * the shape.
- */
- if (PyDataType_HASSUBARRAY(field)) {
- field = field->subarray->base;
- }
- return PyArray_CanCastTypeTo(field, to, casting);
- }
- else {
- return 0;
- }
- }
- /*
- * Casting from one structured data type to another depends on the fields;
- * we pass that case on to the EquivTypenums case below.
- *
- * TODO: move that part up here? Need to check whether equivalent type
- * numbers is an addition constraint that is needed.
- *
- * TODO/FIXME: For now, always allow structured to structured for unsafe
- * casting; this is not correct, but needed since the treatment in can_cast
- * below got out of sync with astype; see gh-13667.
- */
- if (casting == NPY_UNSAFE_CASTING) {
- return 1;
- }
+ NPY_CASTING safety;
+ if (PyDataType_ISUNSIZED(to) && to->subarray == NULL) {
+ safety = PyArray_GetCastSafety(from, NULL, NPY_DTYPE(to));
}
- else if (PyDataType_HASFIELDS(to)) {
- /*
- * If "from" is a simple data type and "to" has fields, then only
- * unsafe casting works (and that works always, even to multiple fields).
- */
- return casting == NPY_UNSAFE_CASTING;
+ else {
+ safety = PyArray_GetCastSafety(from, to, NPY_DTYPE(to));
}
- /*
- * Everything else we consider castable for unsafe for now.
- * FIXME: ensure what we do here is consistent with "astype",
- * i.e., deal more correctly with subarrays and user-defined dtype.
- */
- else if (casting == NPY_UNSAFE_CASTING) {
- return 1;
- }
- /*
- * Equivalent simple types can be cast with any value of 'casting', but
- * we need to be careful about structured to structured.
- */
- if (PyArray_EquivTypenums(from->type_num, to->type_num)) {
- /* For complicated case, use EquivTypes (for now) */
- if (PyTypeNum_ISUSERDEF(from->type_num) ||
- from->subarray != NULL) {
- int ret;
-
- /* Only NPY_NO_CASTING prevents byte order conversion */
- if ((casting != NPY_NO_CASTING) &&
- (!PyArray_ISNBO(from->byteorder) ||
- !PyArray_ISNBO(to->byteorder))) {
- PyArray_Descr *nbo_from, *nbo_to;
-
- nbo_from = PyArray_DescrNewByteorder(from, NPY_NATIVE);
- nbo_to = PyArray_DescrNewByteorder(to, NPY_NATIVE);
- if (nbo_from == NULL || nbo_to == NULL) {
- Py_XDECREF(nbo_from);
- Py_XDECREF(nbo_to);
- PyErr_Clear();
- return 0;
- }
- ret = PyArray_EquivTypes(nbo_from, nbo_to);
- Py_DECREF(nbo_from);
- Py_DECREF(nbo_to);
- }
- else {
- ret = PyArray_EquivTypes(from, to);
- }
- return ret;
- }
-
- if (PyDataType_HASFIELDS(from)) {
- switch (casting) {
- case NPY_EQUIV_CASTING:
- case NPY_SAFE_CASTING:
- case NPY_SAME_KIND_CASTING:
- /*
- * `from' and `to' must have the same fields, and
- * corresponding fields must be (recursively) castable.
- */
- return can_cast_fields(from->fields, to->fields, casting);
-
- case NPY_NO_CASTING:
- default:
- return PyArray_EquivTypes(from, to);
- }
- }
-
- switch (from->type_num) {
- case NPY_DATETIME: {
- PyArray_DatetimeMetaData *meta1, *meta2;
- meta1 = get_datetime_metadata_from_dtype(from);
- if (meta1 == NULL) {
- PyErr_Clear();
- return 0;
- }
- meta2 = get_datetime_metadata_from_dtype(to);
- if (meta2 == NULL) {
- PyErr_Clear();
- return 0;
- }
-
- if (casting == NPY_NO_CASTING) {
- return PyArray_ISNBO(from->byteorder) ==
- PyArray_ISNBO(to->byteorder) &&
- can_cast_datetime64_metadata(meta1, meta2, casting);
- }
- else {
- return can_cast_datetime64_metadata(meta1, meta2, casting);
- }
- }
- case NPY_TIMEDELTA: {
- PyArray_DatetimeMetaData *meta1, *meta2;
- meta1 = get_datetime_metadata_from_dtype(from);
- if (meta1 == NULL) {
- PyErr_Clear();
- return 0;
- }
- meta2 = get_datetime_metadata_from_dtype(to);
- if (meta2 == NULL) {
- PyErr_Clear();
- return 0;
- }
-
- if (casting == NPY_NO_CASTING) {
- return PyArray_ISNBO(from->byteorder) ==
- PyArray_ISNBO(to->byteorder) &&
- can_cast_timedelta64_metadata(meta1, meta2, casting);
- }
- else {
- return can_cast_timedelta64_metadata(meta1, meta2, casting);
- }
- }
- default:
- switch (casting) {
- case NPY_NO_CASTING:
- return PyArray_EquivTypes(from, to);
- case NPY_EQUIV_CASTING:
- return (from->elsize == to->elsize);
- case NPY_SAFE_CASTING:
- return (from->elsize <= to->elsize);
- default:
- return 1;
- }
- break;
- }
- }
- /* If safe or same-kind casts are allowed */
- else if (casting == NPY_SAFE_CASTING || casting == NPY_SAME_KIND_CASTING) {
- if (PyArray_CanCastTo(from, to)) {
- return 1;
- }
- else if(casting == NPY_SAME_KIND_CASTING) {
- /*
- * Also allow casting from lower to higher kinds, according
- * to the ordering provided by dtype_kind_to_ordering.
- * Some kinds, like datetime, don't fit in the hierarchy,
- * and are special cased as -1.
- */
- int from_order, to_order;
-
- from_order = dtype_kind_to_ordering(from->kind);
- to_order = dtype_kind_to_ordering(to->kind);
-
- if (to->kind == 'm') {
- /* both types being timedelta is already handled before. */
- int integer_order = dtype_kind_to_ordering('i');
- return (from_order != -1) && (from_order <= integer_order);
- }
-
- return (from_order != -1) && (from_order <= to_order);
- }
- else {
- return 0;
- }
- }
- /* NPY_NO_CASTING or NPY_EQUIV_CASTING was specified */
- else {
- return 0;
+
+ if (safety < 0) {
+ PyErr_Clear();
+ return 0;
}
+ /* If casting is the smaller (or equal) safety we match */
+ return PyArray_MinCastSafety(safety, casting) == casting;
+#else
+ return PyArray_LegacyCanCastTypeTo(from, to, casting);
+#endif
}
+
/* CanCastArrayTo needs this function */
static int min_scalar_type_num(char *valueptr, int type_num,
int *is_small_unsigned);
* Returns a new reference to type if it is already NBO, otherwise
* returns a copy converted to NBO.
*/
-static PyArray_Descr *
+NPY_NO_EXPORT PyArray_Descr *
ensure_dtype_nbo(PyArray_Descr *type)
{
if (PyArray_ISNBO(type->byteorder)) {
}
}
-/*NUMPY_API
- * Produces the smallest size and lowest kind type to which both
- * input types can be cast.
+
+/**
+ * This function should possibly become public API eventually. At this
+ * time it is implemented by falling back to `PyArray_AdaptFlexibleDType`.
+ * We will use `CastingImpl[from, to].resolve_descriptors(...)` to implement
+ * this logic.
+ * Before that, the API needs to be reviewed though.
+ *
+ * WARNING: This function currently does not guarantee that `descr` can
+ * actually be cast to the given DType.
+ *
+ * @param descr The dtype instance to adapt "cast"
+ * @param given_DType The DType class for which we wish to find an instance able
+ * to represent `descr`.
+ * @returns Instance of `given_DType`. If `given_DType` is parametric the
+ * descr may be adapted to hold it.
*/
NPY_NO_EXPORT PyArray_Descr *
-PyArray_PromoteTypes(PyArray_Descr *type1, PyArray_Descr *type2)
+PyArray_CastDescrToDType(PyArray_Descr *descr, PyArray_DTypeMeta *given_DType)
{
- int type_num1, type_num2, ret_type_num;
+ if (NPY_DTYPE(descr) == given_DType) {
+ Py_INCREF(descr);
+ return descr;
+ }
+ if (!given_DType->parametric) {
+ /*
+ * Don't actually do anything, the default is always the result
+ * of any cast.
+ */
+ return given_DType->default_descr(given_DType);
+ }
+ if (PyObject_TypeCheck((PyObject *)descr, (PyTypeObject *)given_DType)) {
+ Py_INCREF(descr);
+ return descr;
+ }
+
+#if NPY_USE_NEW_CASTINGIMPL
+ PyObject *tmp = PyArray_GetCastingImpl(NPY_DTYPE(descr), given_DType);
+ if (tmp == NULL || tmp == Py_None) {
+ Py_XDECREF(tmp);
+ goto error;
+ }
+ PyArray_DTypeMeta *dtypes[2] = {NPY_DTYPE(descr), given_DType};
+ PyArray_Descr *given_descrs[2] = {descr, NULL};
+ PyArray_Descr *loop_descrs[2];
+
+ PyArrayMethodObject *meth = (PyArrayMethodObject *)tmp;
+ NPY_CASTING casting = meth->resolve_descriptors(
+ meth, dtypes, given_descrs, loop_descrs);
+ Py_DECREF(tmp);
+ if (casting < 0) {
+ goto error;
+ }
+ Py_DECREF(loop_descrs[0]);
+ return loop_descrs[1];
+
+ error:; /* (; due to compiler limitations) */
+ PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
+ PyErr_Fetch(&err_type, &err_value, &err_traceback);
+ PyErr_Format(PyExc_ValueError,
+ "cannot cast dtype %S to %S.", descr, given_DType);
+ npy_PyErr_ChainExceptions(err_type, err_value, err_traceback);
+ return NULL;
- /*
- * Fast path for identical dtypes.
- *
- * Non-native-byte-order types are converted to native ones below, so we
- * can't quit early.
- */
- if (type1 == type2 && PyArray_ISNBO(type1->byteorder)) {
- Py_INCREF(type1);
- return type1;
+#else /* NPY_USE_NEW_CASTS */
+ if (!given_DType->legacy) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "Must use casting to find the correct DType for a parametric "
+ "user DType. This is not yet implemented (this error should be "
+ "unreachable).");
+ return NULL;
}
- type_num1 = type1->type_num;
- type_num2 = type2->type_num;
+ PyArray_Descr *flex_dtype = PyArray_DescrNew(given_DType->singleton);
+ return PyArray_AdaptFlexibleDType(descr, flex_dtype);
+#endif /* NPY_USE_NEW_CASTS */
+}
+
- /* If they're built-in types, use the promotion table */
- if (type_num1 < NPY_NTYPES && type_num2 < NPY_NTYPES) {
- ret_type_num = _npy_type_promotion_table[type_num1][type_num2];
- /*
- * The table doesn't handle string/unicode/void/datetime/timedelta,
- * so check the result
- */
- if (ret_type_num >= 0) {
- return PyArray_DescrFromType(ret_type_num);
+/*
+ * Helper to find the target descriptor for multiple arrays given an input
+ * one that may be a DType class (e.g. "U" or "S").
+ * Works with arrays, since that is what `concatenate` works with. However,
+ * unlike `np.array(...)` or `arr.astype()` we will never inspect the array's
+ * content, which means that object arrays can only be cast to strings if a
+ * fixed width is provided (same for string -> generic datetime).
+ *
+ * As this function uses `PyArray_ExtractDTypeAndDescriptor`, it should
+ * eventually be refactored to move the step to an earlier point.
+ */
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_FindConcatenationDescriptor(
+ npy_intp n, PyArrayObject **arrays, PyObject *requested_dtype)
+{
+ if (requested_dtype == NULL) {
+ return PyArray_ResultType(n, arrays, 0, NULL);
+ }
+
+ PyArray_DTypeMeta *common_dtype;
+ PyArray_Descr *result = NULL;
+ if (PyArray_ExtractDTypeAndDescriptor(
+ requested_dtype, &result, &common_dtype) < 0) {
+ return NULL;
+ }
+ if (result != NULL) {
+ if (result->subarray != NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "The dtype `%R` is not a valid dtype for concatenation "
+ "since it is a subarray dtype (the subarray dimensions "
+ "would be added as array dimensions).", result);
+ Py_DECREF(result);
+ return NULL;
+ }
+ goto finish;
+ }
+ assert(n > 0); /* concatenate requires at least one array input. */
+ PyArray_Descr *descr = PyArray_DESCR(arrays[0]);
+ result = PyArray_CastDescrToDType(descr, common_dtype);
+ if (result == NULL || n == 1) {
+ goto finish;
+ }
+ /*
+ * This could short-cut a bit, calling `common_instance` directly and/or
+ * returning the `default_descr()` directly. Avoiding that (for now) as
+ * it would duplicate code from `PyArray_PromoteTypes`.
+ */
+ for (npy_intp i = 1; i < n; i++) {
+ descr = PyArray_DESCR(arrays[i]);
+ PyArray_Descr *curr = PyArray_CastDescrToDType(descr, common_dtype);
+ if (curr == NULL) {
+ Py_SETREF(result, NULL);
+ goto finish;
+ }
+ Py_SETREF(result, PyArray_PromoteTypes(result, curr));
+ Py_DECREF(curr);
+ if (result == NULL) {
+ goto finish;
}
}
- /* If one or both are user defined, calculate it */
- else {
- int skind1 = NPY_NOSCALAR, skind2 = NPY_NOSCALAR, skind;
-
- if (PyArray_CanCastTo(type2, type1)) {
- /* Promoted types are always native byte order */
- return ensure_dtype_nbo(type1);
- }
- else if (PyArray_CanCastTo(type1, type2)) {
- /* Promoted types are always native byte order */
- return ensure_dtype_nbo(type2);
- }
-
- /* Convert the 'kind' char into a scalar kind */
- switch (type1->kind) {
- case 'b':
- skind1 = NPY_BOOL_SCALAR;
- break;
- case 'u':
- skind1 = NPY_INTPOS_SCALAR;
- break;
- case 'i':
- skind1 = NPY_INTNEG_SCALAR;
- break;
- case 'f':
- skind1 = NPY_FLOAT_SCALAR;
- break;
- case 'c':
- skind1 = NPY_COMPLEX_SCALAR;
- break;
- }
- switch (type2->kind) {
- case 'b':
- skind2 = NPY_BOOL_SCALAR;
- break;
- case 'u':
- skind2 = NPY_INTPOS_SCALAR;
- break;
- case 'i':
- skind2 = NPY_INTNEG_SCALAR;
- break;
- case 'f':
- skind2 = NPY_FLOAT_SCALAR;
- break;
- case 'c':
- skind2 = NPY_COMPLEX_SCALAR;
- break;
- }
-
- /* If both are scalars, there may be a promotion possible */
- if (skind1 != NPY_NOSCALAR && skind2 != NPY_NOSCALAR) {
-
- /* Start with the larger scalar kind */
- skind = (skind1 > skind2) ? skind1 : skind2;
- ret_type_num = _npy_smallest_type_of_kind_table[skind];
-
- for (;;) {
-
- /* If there is no larger type of this kind, try a larger kind */
- if (ret_type_num < 0) {
- ++skind;
- /* Use -1 to signal no promoted type found */
- if (skind < NPY_NSCALARKINDS) {
- ret_type_num = _npy_smallest_type_of_kind_table[skind];
- }
- else {
- break;
- }
- }
- /* If we found a type to which we can promote both, done! */
- if (PyArray_CanCastSafely(type_num1, ret_type_num) &&
- PyArray_CanCastSafely(type_num2, ret_type_num)) {
- return PyArray_DescrFromType(ret_type_num);
- }
+ finish:
+ Py_DECREF(common_dtype);
+ return result;
+}
- /* Try the next larger type of this kind */
- ret_type_num = _npy_next_larger_type_table[ret_type_num];
- }
- }
+/**
+ * This function defines the common DType operator.
+ *
+ * Note that the common DType will not be "object" (unless one of the dtypes
+ * is object), even though object can technically represent all values
+ * correctly.
+ *
+ * TODO: Before exposure, we should review the return value (e.g. no error
+ * when no common DType is found).
+ *
+ * @param dtype1 DType class to find the common type for.
+ * @param dtype2 Second DType class.
+ * @return The common DType or NULL with an error set
+ */
+NPY_NO_EXPORT PyArray_DTypeMeta *
+PyArray_CommonDType(PyArray_DTypeMeta *dtype1, PyArray_DTypeMeta *dtype2)
+{
+ if (dtype1 == dtype2) {
+ Py_INCREF(dtype1);
+ return dtype1;
+ }
- PyErr_SetString(PyExc_TypeError,
- "invalid type promotion with custom data type");
+ PyArray_DTypeMeta *common_dtype;
+
+ common_dtype = dtype1->common_dtype(dtype1, dtype2);
+ if (common_dtype == (PyArray_DTypeMeta *)Py_NotImplemented) {
+ Py_DECREF(common_dtype);
+ common_dtype = dtype2->common_dtype(dtype2, dtype1);
+ }
+ if (common_dtype == NULL) {
+ return NULL;
+ }
+ if (common_dtype == (PyArray_DTypeMeta *)Py_NotImplemented) {
+ Py_DECREF(Py_NotImplemented);
+ PyErr_Format(PyExc_TypeError,
+ "The DTypes %S and %S do not have a common DType. "
+ "For example they cannot be stored in a single array unless "
+ "the dtype is `object`.", dtype1, dtype2);
return NULL;
}
+ return common_dtype;
+}
- switch (type_num1) {
- /* BOOL can convert to anything except datetime/void */
- case NPY_BOOL:
- if (type_num2 == NPY_STRING || type_num2 == NPY_UNICODE) {
- int char_size = 1;
- if (type_num2 == NPY_UNICODE) {
- char_size = 4;
- }
- if (type2->elsize < 5 * char_size) {
- PyArray_Descr *ret = NULL;
- PyArray_Descr *temp = PyArray_DescrNew(type2);
- ret = ensure_dtype_nbo(temp);
- ret->elsize = 5 * char_size;
- Py_DECREF(temp);
- return ret;
- }
- return ensure_dtype_nbo(type2);
- }
- else if (type_num2 != NPY_DATETIME && type_num2 != NPY_VOID) {
- return ensure_dtype_nbo(type2);
- }
- break;
- /* For strings and unicodes, take the larger size */
- case NPY_STRING:
- if (type_num2 == NPY_STRING) {
- if (type1->elsize > type2->elsize) {
- return ensure_dtype_nbo(type1);
- }
- else {
- return ensure_dtype_nbo(type2);
- }
- }
- else if (type_num2 == NPY_UNICODE) {
- if (type2->elsize >= type1->elsize * 4) {
- return ensure_dtype_nbo(type2);
- }
- else {
- PyArray_Descr *d = PyArray_DescrNewFromType(NPY_UNICODE);
- if (d == NULL) {
- return NULL;
- }
- d->elsize = type1->elsize * 4;
- return d;
- }
- }
- /* Allow NUMBER -> STRING */
- else if (PyTypeNum_ISNUMBER(type_num2)) {
- PyArray_Descr *ret = NULL;
- PyArray_Descr *temp = PyArray_DescrNew(type1);
- PyDataType_MAKEUNSIZED(temp);
- temp = PyArray_AdaptFlexibleDType(NULL, type2, temp);
- if (temp == NULL) {
- return NULL;
- }
- if (temp->elsize > type1->elsize) {
- ret = ensure_dtype_nbo(temp);
- }
- else {
- ret = ensure_dtype_nbo(type1);
- }
- Py_DECREF(temp);
- return ret;
- }
- break;
- case NPY_UNICODE:
- if (type_num2 == NPY_UNICODE) {
- if (type1->elsize > type2->elsize) {
- return ensure_dtype_nbo(type1);
- }
- else {
- return ensure_dtype_nbo(type2);
- }
- }
- else if (type_num2 == NPY_STRING) {
- if (type1->elsize >= type2->elsize * 4) {
- return ensure_dtype_nbo(type1);
- }
- else {
- PyArray_Descr *d = PyArray_DescrNewFromType(NPY_UNICODE);
- if (d == NULL) {
- return NULL;
- }
- d->elsize = type2->elsize * 4;
- return d;
- }
- }
- /* Allow NUMBER -> UNICODE */
- else if (PyTypeNum_ISNUMBER(type_num2)) {
- PyArray_Descr *ret = NULL;
- PyArray_Descr *temp = PyArray_DescrNew(type1);
- PyDataType_MAKEUNSIZED(temp);
- temp = PyArray_AdaptFlexibleDType(NULL, type2, temp);
- if (temp == NULL) {
- return NULL;
- }
- if (temp->elsize > type1->elsize) {
- ret = ensure_dtype_nbo(temp);
- }
- else {
- ret = ensure_dtype_nbo(type1);
- }
- Py_DECREF(temp);
- return ret;
- }
- break;
- case NPY_DATETIME:
- case NPY_TIMEDELTA:
- if (type_num2 == NPY_DATETIME || type_num2 == NPY_TIMEDELTA) {
- return datetime_type_promotion(type1, type2);
- }
- break;
+/*NUMPY_API
+ * Produces the smallest size and lowest kind type to which both
+ * input types can be cast.
+ */
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_PromoteTypes(PyArray_Descr *type1, PyArray_Descr *type2)
+{
+ PyArray_DTypeMeta *common_dtype;
+ PyArray_Descr *res;
+
+ /* Fast path for identical inputs (NOTE: This path preserves metadata!) */
+ if (type1 == type2 && PyArray_ISNBO(type1->byteorder)) {
+ Py_INCREF(type1);
+ return type1;
}
- switch (type_num2) {
- /* BOOL can convert to almost anything */
- case NPY_BOOL:
- if (type_num2 == NPY_STRING || type_num2 == NPY_UNICODE) {
- int char_size = 1;
- if (type_num2 == NPY_UNICODE) {
- char_size = 4;
- }
- if (type2->elsize < 5 * char_size) {
- PyArray_Descr *ret = NULL;
- PyArray_Descr *temp = PyArray_DescrNew(type2);
- ret = ensure_dtype_nbo(temp);
- ret->elsize = 5 * char_size;
- Py_DECREF(temp);
- return ret;
- }
- return ensure_dtype_nbo(type2);
- }
- else if (type_num1 != NPY_DATETIME && type_num1 != NPY_TIMEDELTA &&
- type_num1 != NPY_VOID) {
- return ensure_dtype_nbo(type1);
- }
- break;
- case NPY_STRING:
- /* Allow NUMBER -> STRING */
- if (PyTypeNum_ISNUMBER(type_num1)) {
- PyArray_Descr *ret = NULL;
- PyArray_Descr *temp = PyArray_DescrNew(type2);
- PyDataType_MAKEUNSIZED(temp);
- temp = PyArray_AdaptFlexibleDType(NULL, type1, temp);
- if (temp == NULL) {
- return NULL;
- }
- if (temp->elsize > type2->elsize) {
- ret = ensure_dtype_nbo(temp);
- }
- else {
- ret = ensure_dtype_nbo(type2);
- }
- Py_DECREF(temp);
- return ret;
- }
- break;
- case NPY_UNICODE:
- /* Allow NUMBER -> UNICODE */
- if (PyTypeNum_ISNUMBER(type_num1)) {
- PyArray_Descr *ret = NULL;
- PyArray_Descr *temp = PyArray_DescrNew(type2);
- PyDataType_MAKEUNSIZED(temp);
- temp = PyArray_AdaptFlexibleDType(NULL, type1, temp);
- if (temp == NULL) {
- return NULL;
- }
- if (temp->elsize > type2->elsize) {
- ret = ensure_dtype_nbo(temp);
- }
- else {
- ret = ensure_dtype_nbo(type2);
- }
- Py_DECREF(temp);
- return ret;
- }
- break;
- case NPY_TIMEDELTA:
- if (PyTypeNum_ISINTEGER(type_num1) ||
- PyTypeNum_ISFLOAT(type_num1)) {
- return ensure_dtype_nbo(type2);
- }
- break;
+ common_dtype = PyArray_CommonDType(NPY_DTYPE(type1), NPY_DTYPE(type2));
+ if (common_dtype == NULL) {
+ return NULL;
}
- /* For types equivalent up to endianness, can return either */
- if (PyArray_CanCastTypeTo(type1, type2, NPY_EQUIV_CASTING)) {
- return ensure_dtype_nbo(type1);
+ if (!common_dtype->parametric) {
+ res = common_dtype->default_descr(common_dtype);
+ Py_DECREF(common_dtype);
+ return res;
}
- /* TODO: Also combine fields, subarrays, strings, etc */
+ /* Cast the input types to the common DType if necessary */
+ type1 = PyArray_CastDescrToDType(type1, common_dtype);
+ if (type1 == NULL) {
+ Py_DECREF(common_dtype);
+ return NULL;
+ }
+ type2 = PyArray_CastDescrToDType(type2, common_dtype);
+ if (type2 == NULL) {
+ Py_DECREF(type1);
+ Py_DECREF(common_dtype);
+ return NULL;
+ }
/*
- printf("invalid type promotion: ");
- PyObject_Print(type1, stdout, 0);
- printf(" ");
- PyObject_Print(type2, stdout, 0);
- printf("\n");
- */
- PyErr_SetString(PyExc_TypeError, "invalid type promotion");
- return NULL;
+ * And find the common instance of the two inputs
+ * NOTE: Common instance preserves metadata (normally and of one input)
+ */
+ res = common_dtype->common_instance(type1, type2);
+ Py_DECREF(type1);
+ Py_DECREF(type2);
+ Py_DECREF(common_dtype);
+ return res;
}
/*
}
if (zero_obj == NULL) {
- zero_obj = PyInt_FromLong((long) 0);
+ zero_obj = PyLong_FromLong((long) 0);
if (zero_obj == NULL) {
return NULL;
}
}
if (one_obj == NULL) {
- one_obj = PyInt_FromLong((long) 1);
+ one_obj = PyLong_FromLong((long) 1);
if (one_obj == NULL) {
return NULL;
}
return NPY_NOTYPE;
}
}
-
if (PyArray_DTypeFromObject(op, NPY_MAXDIMS, &dtype) < 0) {
return NPY_NOTYPE;
}
if (dtype == NULL) {
ret = NPY_DEFAULT_TYPE;
}
+ else if (!NPY_DTYPE(dtype)->legacy) {
+ /*
+ * TODO: If we keep all type number style API working, by defining
+ * type numbers always. We may be able to allow this again.
+ */
+ PyErr_Format(PyExc_TypeError,
+ "This function currently only supports native NumPy dtypes "
+ "and old-style user dtypes, but the dtype was %S.\n"
+ "(The function may need to be updated to support arbitrary"
+ "user dtypes.)",
+ dtype);
+ ret = NPY_NOTYPE;
+ }
else {
ret = dtype->type_num;
}
PyDataMem_FREE(mps);
return NULL;
}
+
+
+/**
+ * Private function to add a casting implementation by unwrapping a bound
+ * array method.
+ *
+ * @param meth
+ * @return 0 on success -1 on failure.
+ */
+NPY_NO_EXPORT int
+PyArray_AddCastingImplmentation(PyBoundArrayMethodObject *meth)
+{
+ if (meth->method->nin != 1 || meth->method->nout != 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "A cast must have one input and one output.");
+ return -1;
+ }
+ if (meth->dtypes[0] == meth->dtypes[1]) {
+ if (!(meth->method->flags & NPY_METH_SUPPORTS_UNALIGNED)) {
+ PyErr_Format(PyExc_TypeError,
+ "A cast where input and output DType (class) are identical "
+ "must currently support unaligned data. (method: %s)",
+ meth->method->name);
+ return -1;
+ }
+ if ((meth->method->casting & ~_NPY_CAST_IS_VIEW) != NPY_NO_CASTING) {
+ PyErr_Format(PyExc_TypeError,
+ "A cast where input and output DType (class) are identical "
+ "must signal `no-casting`. (method: %s)",
+ meth->method->name);
+ return -1;
+ }
+ }
+ if (PyDict_Contains(meth->dtypes[0]->castingimpls,
+ (PyObject *)meth->dtypes[1])) {
+ PyErr_Format(PyExc_RuntimeError,
+ "A cast was already added for %S -> %S. (method: %s)",
+ meth->dtypes[0], meth->dtypes[1], meth->method->name);
+ return -1;
+ }
+ if (PyDict_SetItem(meth->dtypes[0]->castingimpls,
+ (PyObject *)meth->dtypes[1], (PyObject *)meth->method) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Add a new casting implementation using a PyArrayMethod_Spec.
+ *
+ * @param spec
+ * @param private If private, allow slots not publically exposed.
+ * @return 0 on success -1 on failure
+ */
+NPY_NO_EXPORT int
+PyArray_AddCastingImplementation_FromSpec(PyArrayMethod_Spec *spec, int private)
+{
+ /* Create a bound method, unbind and store it */
+ PyBoundArrayMethodObject *meth = PyArrayMethod_FromSpec_int(spec, private);
+ if (meth == NULL) {
+ return -1;
+ }
+ int res = PyArray_AddCastingImplmentation(meth);
+ Py_DECREF(meth);
+ if (res < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+
+NPY_NO_EXPORT NPY_CASTING
+legacy_same_dtype_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+
+ if (given_descrs[1] == NULL) {
+ loop_descrs[1] = ensure_dtype_nbo(loop_descrs[0]);
+ if (loop_descrs[1] == NULL) {
+ Py_DECREF(loop_descrs[0]);
+ return -1;
+ }
+ }
+ else {
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+
+ /* this function only makes sense for non-flexible legacy dtypes: */
+ assert(loop_descrs[0]->elsize == loop_descrs[1]->elsize);
+
+ /*
+ * Legacy dtypes (except datetime) only have byte-order and elsize as
+ * storage parameters.
+ */
+ if (PyDataType_ISNOTSWAPPED(loop_descrs[0]) ==
+ PyDataType_ISNOTSWAPPED(loop_descrs[1])) {
+ return NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
+ }
+ return NPY_EQUIV_CASTING;
+}
+
+
+/*
+ * Simple dtype resolver for casting between two different (non-parametric)
+ * (legacy) dtypes.
+ */
+NPY_NO_EXPORT NPY_CASTING
+simple_cast_resolve_descriptors(
+ PyArrayMethodObject *self,
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ assert(dtypes[0]->legacy && dtypes[1]->legacy);
+
+ loop_descrs[0] = ensure_dtype_nbo(given_descrs[0]);
+ if (loop_descrs[0] == NULL) {
+ return -1;
+ }
+ if (given_descrs[1] != NULL) {
+ loop_descrs[1] = ensure_dtype_nbo(given_descrs[1]);
+ if (loop_descrs[1] == NULL) {
+ Py_DECREF(loop_descrs[0]);
+ return -1;
+ }
+ }
+ else {
+ loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]);
+ }
+
+ if (self->casting != NPY_NO_CASTING) {
+ return self->casting;
+ }
+ if (PyDataType_ISNOTSWAPPED(loop_descrs[0]) ==
+ PyDataType_ISNOTSWAPPED(loop_descrs[1])) {
+ return NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
+ }
+ return NPY_EQUIV_CASTING;
+}
+
+
+static int
+add_numeric_cast(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to)
+{
+ PyType_Slot slots[6];
+ PyArray_DTypeMeta *dtypes[2] = {from, to};
+ PyArrayMethod_Spec spec = {
+ .name = "numeric_cast",
+ .nin = 1,
+ .nout = 1,
+ .flags = NPY_METH_SUPPORTS_UNALIGNED,
+ .slots = slots,
+ .dtypes = dtypes,
+ };
+
+ npy_intp from_itemsize = dtypes[0]->singleton->elsize;
+ npy_intp to_itemsize = dtypes[1]->singleton->elsize;
+
+ slots[0].slot = NPY_METH_resolve_descriptors;
+ slots[0].pfunc = &simple_cast_resolve_descriptors;
+ /* Fetch the optimized loops (2<<10 is a non-contiguous stride) */
+ slots[1].slot = NPY_METH_strided_loop;
+ slots[1].pfunc = PyArray_GetStridedNumericCastFn(
+ 1, 2<<10, 2<<10, from->type_num, to->type_num);
+ slots[2].slot = NPY_METH_contiguous_loop;
+ slots[2].pfunc = PyArray_GetStridedNumericCastFn(
+ 1, from_itemsize, to_itemsize, from->type_num, to->type_num);
+ slots[3].slot = NPY_METH_unaligned_strided_loop;
+ slots[3].pfunc = PyArray_GetStridedNumericCastFn(
+ 0, 2<<10, 2<<10, from->type_num, to->type_num);
+ slots[4].slot = NPY_METH_unaligned_contiguous_loop;
+ slots[4].pfunc = PyArray_GetStridedNumericCastFn(
+ 0, from_itemsize, to_itemsize, from->type_num, to->type_num);
+ slots[5].slot = 0;
+ slots[5].pfunc = NULL;
+
+ assert(slots[1].pfunc && slots[2].pfunc && slots[3].pfunc && slots[4].pfunc);
+
+ /* Find the correct casting level, and special case no-cast */
+ if (dtypes[0]->kind == dtypes[1]->kind && from_itemsize == to_itemsize) {
+ spec.casting = NPY_NO_CASTING;
+
+ /* When there is no casting (equivalent C-types) use byteswap loops */
+ slots[0].slot = NPY_METH_resolve_descriptors;
+ slots[0].pfunc = &legacy_same_dtype_resolve_descriptors;
+ slots[1].slot = NPY_METH_get_loop;
+ slots[1].pfunc = NULL;
+ slots[2].slot = 0;
+ slots[2].pfunc = NULL;
+
+ spec.name = "numeric_copy_or_byteswap";
+ spec.flags |= NPY_METH_NO_FLOATINGPOINT_ERRORS;
+ }
+ else if (_npy_can_cast_safely_table[from->type_num][to->type_num]) {
+ spec.casting = NPY_SAFE_CASTING;
+ }
+ else if (dtype_kind_to_ordering(dtypes[0]->kind) <=
+ dtype_kind_to_ordering(dtypes[1]->kind)) {
+ spec.casting = NPY_SAME_KIND_CASTING;
+ }
+ else {
+ spec.casting = NPY_UNSAFE_CASTING;
+ }
+
+ /* Create a bound method, unbind and store it */
+ return PyArray_AddCastingImplementation_FromSpec(&spec, 1);
+}
+
+
+/*
+ * This registers the castingimpl for all casts between numeric types.
+ * Eventually, this function should likely be defined as part of a .c.src
+ * file to remove `PyArray_GetStridedNumericCastFn` entirely.
+ */
+static int
+PyArray_InitializeNumericCasts(void)
+{
+ for (int from = 0; from < NPY_NTYPES; from++) {
+ if (!PyTypeNum_ISNUMBER(from) && from != NPY_BOOL) {
+ continue;
+ }
+ PyArray_DTypeMeta *from_dt = PyArray_DTypeFromTypeNum(from);
+
+ for (int to = 0; to < NPY_NTYPES; to++) {
+ if (!PyTypeNum_ISNUMBER(to) && to != NPY_BOOL) {
+ continue;
+ }
+ PyArray_DTypeMeta *to_dt = PyArray_DTypeFromTypeNum(to);
+ int res = add_numeric_cast(from_dt, to_dt);
+ Py_DECREF(to_dt);
+ if (res < 0) {
+ Py_DECREF(from_dt);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int
+cast_to_string_resolve_descriptors(
+ PyArrayMethodObject *self,
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ /*
+ * NOTE: The following code used to be part of PyArray_AdaptFlexibleDType
+ *
+ * Get a string-size estimate of the input. These
+ * are generallly the size needed, rounded up to
+ * a multiple of eight.
+ */
+ npy_intp size = -1;
+ switch (dtypes[0]->type_num) {
+ case NPY_BOOL:
+ case NPY_UBYTE:
+ case NPY_BYTE:
+ case NPY_USHORT:
+ case NPY_SHORT:
+ case NPY_UINT:
+ case NPY_INT:
+ case NPY_ULONG:
+ case NPY_LONG:
+ case NPY_ULONGLONG:
+ case NPY_LONGLONG:
+ assert(dtypes[0]->singleton->elsize <= 8);
+ assert(dtypes[0]->singleton->elsize > 0);
+ if (dtypes[0]->kind == 'b') {
+ /* 5 chars needed for cast to 'True' or 'False' */
+ size = 5;
+ }
+ else if (dtypes[0]->kind == 'u') {
+ size = REQUIRED_STR_LEN[dtypes[0]->singleton->elsize];
+ }
+ else if (dtypes[0]->kind == 'i') {
+ /* Add character for sign symbol */
+ size = REQUIRED_STR_LEN[dtypes[0]->singleton->elsize] + 1;
+ }
+ break;
+ case NPY_HALF:
+ case NPY_FLOAT:
+ case NPY_DOUBLE:
+ size = 32;
+ break;
+ case NPY_LONGDOUBLE:
+ size = 48;
+ break;
+ case NPY_CFLOAT:
+ case NPY_CDOUBLE:
+ size = 2 * 32;
+ break;
+ case NPY_CLONGDOUBLE:
+ size = 2 * 48;
+ break;
+ case NPY_STRING:
+ case NPY_VOID:
+ size = given_descrs[0]->elsize;
+ break;
+ case NPY_UNICODE:
+ size = given_descrs[0]->elsize / 4;
+ break;
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "Impossible cast to string path requested.");
+ return -1;
+ }
+ if (dtypes[1]->type_num == NPY_UNICODE) {
+ size *= 4;
+ }
+
+ if (given_descrs[1] == NULL) {
+ loop_descrs[1] = PyArray_DescrNewFromType(dtypes[1]->type_num);
+ if (loop_descrs[1] == NULL) {
+ return -1;
+ }
+ loop_descrs[1]->elsize = size;
+ }
+ else {
+ /* The legacy loop can handle mismatching itemsizes */
+ loop_descrs[1] = ensure_dtype_nbo(given_descrs[1]);
+ if (loop_descrs[1] == NULL) {
+ return -1;
+ }
+ }
+
+ /* Set the input one as well (late for easier error management) */
+ loop_descrs[0] = ensure_dtype_nbo(given_descrs[0]);
+ if (loop_descrs[0] == NULL) {
+ return -1;
+ }
+
+ if (self->casting == NPY_UNSAFE_CASTING) {
+ assert(dtypes[0]->type_num == NPY_UNICODE &&
+ dtypes[1]->type_num == NPY_STRING);
+ return NPY_UNSAFE_CASTING;
+ }
+ assert(self->casting == NPY_SAFE_CASTING);
+
+ if (loop_descrs[1]->elsize >= size) {
+ return NPY_SAFE_CASTING;
+ }
+ return NPY_SAME_KIND_CASTING;
+}
+
+
+static int
+add_other_to_and_from_string_cast(
+ PyArray_DTypeMeta *string, PyArray_DTypeMeta *other)
+{
+ if (string == other) {
+ return 0;
+ }
+
+ /* Casting from string, is always a simple legacy-style cast */
+ if (other->type_num != NPY_STRING && other->type_num != NPY_UNICODE) {
+ if (PyArray_AddLegacyWrapping_CastingImpl(
+ string, other, NPY_UNSAFE_CASTING) < 0) {
+ return -1;
+ }
+ }
+ /*
+ * Casting to strings, is almost the same, but requires a custom resolver
+ * to define the correct string length. Right now we use a generic function
+ * for this.
+ */
+ PyArray_DTypeMeta *dtypes[2] = {other, string};
+ PyType_Slot slots[] = {
+ {NPY_METH_get_loop, NULL},
+ {NPY_METH_resolve_descriptors, &cast_to_string_resolve_descriptors},
+ {0, NULL}};
+ PyArrayMethod_Spec spec = {
+ .name = "legacy_cast_to_string",
+ .nin = 1,
+ .nout = 1,
+ .flags = NPY_METH_REQUIRES_PYAPI,
+ .dtypes = dtypes,
+ .slots = slots,
+ };
+ /* Almost everything can be safely cast to string (except unicode) */
+ if (other->type_num != NPY_UNICODE) {
+ spec.casting = NPY_SAFE_CASTING;
+ }
+ else {
+ spec.casting = NPY_UNSAFE_CASTING;
+ }
+
+ return PyArray_AddCastingImplementation_FromSpec(&spec, 1);
+}
+
+
+NPY_NO_EXPORT NPY_CASTING
+string_to_string_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+
+ if (given_descrs[1] == NULL) {
+ loop_descrs[1] = ensure_dtype_nbo(loop_descrs[0]);
+ if (loop_descrs[1] == NULL) {
+ return -1;
+ }
+ }
+ else {
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+
+ if (loop_descrs[0]->elsize == loop_descrs[1]->elsize) {
+ if (PyDataType_ISNOTSWAPPED(loop_descrs[0]) ==
+ PyDataType_ISNOTSWAPPED(loop_descrs[1])) {
+ return NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
+ }
+ else {
+ return NPY_EQUIV_CASTING;
+ }
+ }
+ else if (loop_descrs[0]->elsize <= loop_descrs[1]->elsize) {
+ return NPY_SAFE_CASTING;
+ }
+ return NPY_SAME_KIND_CASTING;
+}
+
+
+/*
+ * Add string casts. Right now all string casts are just legacy-wrapped ones
+ * (except string<->string and unicode<->unicode), but they do require
+ * custom type resolution for the string length.
+ *
+ * A bit like `object`, it could make sense to define a simpler protocol for
+ * string casts, however, we also need to remember that the itemsize of the
+ * output has to be found.
+ */
+static int
+PyArray_InitializeStringCasts(void)
+{
+ int result = -1;
+ PyArray_DTypeMeta *string = PyArray_DTypeFromTypeNum(NPY_STRING);
+ PyArray_DTypeMeta *unicode = PyArray_DTypeFromTypeNum(NPY_UNICODE);
+ PyArray_DTypeMeta *other_dt = NULL;
+
+ /* Add most casts as legacy ones */
+ for (int other = 0; other < NPY_NTYPES; other++) {
+ if (PyTypeNum_ISDATETIME(other) || other == NPY_VOID ||
+ other == NPY_OBJECT) {
+ continue;
+ }
+ other_dt = PyArray_DTypeFromTypeNum(other);
+
+ /* The functions skip string == other_dt or unicode == other_dt */
+ if (add_other_to_and_from_string_cast(string, other_dt) < 0) {
+ goto finish;
+ }
+ if (add_other_to_and_from_string_cast(unicode, other_dt) < 0) {
+ goto finish;
+ }
+
+ Py_SETREF(other_dt, NULL);
+ }
+
+ /* string<->string and unicode<->unicode have their own specialized casts */
+ PyArray_DTypeMeta *dtypes[2];
+ PyType_Slot slots[] = {
+ {NPY_METH_get_loop, NULL},
+ {NPY_METH_resolve_descriptors, &string_to_string_resolve_descriptors},
+ {0, NULL}};
+ PyArrayMethod_Spec spec = {
+ .name = "string_to_string_cast",
+ .casting = NPY_NO_CASTING,
+ .nin = 1,
+ .nout = 1,
+ .flags = (NPY_METH_REQUIRES_PYAPI |
+ NPY_METH_NO_FLOATINGPOINT_ERRORS |
+ NPY_METH_SUPPORTS_UNALIGNED),
+ .dtypes = dtypes,
+ .slots = slots,
+ };
+
+ dtypes[0] = string;
+ dtypes[1] = string;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto finish;
+ }
+
+ dtypes[0] = unicode;
+ dtypes[1] = unicode;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto finish;
+ }
+
+ result = 0;
+ finish:
+ Py_DECREF(string);
+ Py_DECREF(unicode);
+ Py_XDECREF(other_dt);
+ return result;
+}
+
+
+/*
+ * Small helper function to handle the case of `arr.astype(dtype="V")`.
+ * When the output descriptor is not passed, we always use `V<itemsize>`
+ * of the other dtype.
+ */
+static NPY_CASTING
+cast_to_void_dtype_class(
+ PyArray_Descr **given_descrs, PyArray_Descr **loop_descrs)
+{
+ /* `dtype="V"` means unstructured currently (compare final path) */
+ loop_descrs[1] = PyArray_DescrNewFromType(NPY_VOID);
+ if (loop_descrs[1] == NULL) {
+ return -1;
+ }
+ loop_descrs[1]->elsize = given_descrs[0]->elsize;
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+ return NPY_SAFE_CASTING | _NPY_CAST_IS_VIEW;
+}
+
+
+static NPY_CASTING
+nonstructured_to_structured_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ NPY_CASTING casting;
+
+ if (given_descrs[1] == NULL) {
+ return cast_to_void_dtype_class(given_descrs, loop_descrs);
+ }
+
+ if (given_descrs[1]->subarray != NULL) {
+ /*
+ * We currently consider this at most a safe cast. It would be
+ * possible to allow a view if the field has exactly one element.
+ */
+ casting = NPY_SAFE_CASTING;
+ /* Subarray dtype */
+ NPY_CASTING base_casting = PyArray_GetCastSafety(
+ given_descrs[0], given_descrs[1]->subarray->base, NULL);
+ if (base_casting < 0) {
+ return -1;
+ }
+ casting = PyArray_MinCastSafety(casting, base_casting);
+ }
+ else if (given_descrs[1]->names != NULL) {
+ /* Structured dtype */
+ if (PyTuple_Size(given_descrs[1]->names) == 0) {
+ /* TODO: This retained behaviour, but likely should be changed. */
+ casting = NPY_UNSAFE_CASTING;
+ }
+ else {
+ /* Considered at most unsafe casting (but this could be changed) */
+ casting = NPY_UNSAFE_CASTING;
+ if (PyTuple_Size(given_descrs[1]->names) == 1) {
+ /* A view may be acceptable */
+ casting |= _NPY_CAST_IS_VIEW;
+ }
+
+ Py_ssize_t pos = 0;
+ PyObject *key, *tuple;
+ while (PyDict_Next(given_descrs[1]->fields, &pos, &key, &tuple)) {
+ PyArray_Descr *field_descr = (PyArray_Descr *)PyTuple_GET_ITEM(tuple, 0);
+ NPY_CASTING field_casting = PyArray_GetCastSafety(
+ given_descrs[0], field_descr, NULL);
+ casting = PyArray_MinCastSafety(casting, field_casting);
+ if (casting < 0) {
+ return -1;
+ }
+ }
+ }
+ }
+ else {
+ /* Plain void type. This behaves much like a "view" */
+ if (given_descrs[0]->elsize == given_descrs[1]->elsize &&
+ !PyDataType_REFCHK(given_descrs[0])) {
+ /*
+ * A simple view, at the moment considered "safe" (the refcheck is
+ * probably not necessary, but more future proof
+ */
+ casting = NPY_SAFE_CASTING | _NPY_CAST_IS_VIEW;
+ }
+ else if (given_descrs[0]->elsize <= given_descrs[1]->elsize) {
+ casting = NPY_SAFE_CASTING;
+ }
+ else {
+ casting = NPY_UNSAFE_CASTING;
+ }
+ }
+
+ /* Void dtypes always do the full cast. */
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+
+ return casting;
+}
+
+
+int give_bad_field_error(PyObject *key)
+{
+ if (!PyErr_Occurred()) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Invalid or missing field %R, this should be impossible "
+ "and indicates a NumPy bug.", key);
+ }
+ return -1;
+}
+
+
+static PyObject *
+PyArray_GetGenericToVoidCastingImpl(void)
+{
+ static PyArrayMethodObject *method = NULL;
+
+ if (method != NULL) {
+ Py_INCREF(method);
+ return (PyObject *)method;
+ }
+
+ method = PyObject_New(PyArrayMethodObject, &PyArrayMethod_Type);
+ if (method == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ method->name = "any_to_void_cast";
+ method->flags = NPY_METH_SUPPORTS_UNALIGNED | NPY_METH_REQUIRES_PYAPI;
+ method->casting = NPY_SAFE_CASTING;
+ method->resolve_descriptors = &nonstructured_to_structured_resolve_descriptors;
+ method->get_strided_loop = NULL;
+
+ return (PyObject *)method;
+}
+
+
+static NPY_CASTING
+structured_to_nonstructured_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ PyArray_Descr *base_descr;
+
+ if (given_descrs[0]->subarray != NULL) {
+ base_descr = given_descrs[0]->subarray->base;
+ }
+ else if (given_descrs[0]->names != NULL) {
+ if (PyTuple_Size(given_descrs[0]->names) != 1) {
+ /* Only allow casting a single field */
+ return -1;
+ }
+ PyObject *key = PyTuple_GetItem(given_descrs[0]->names, 0);
+ PyObject *base_tup = PyDict_GetItem(given_descrs[0]->fields, key);
+ base_descr = (PyArray_Descr *)PyTuple_GET_ITEM(base_tup, 0);
+ }
+ else {
+ /*
+ * unstructured voids are considered unsafe casts and defined, albeit,
+ * at this time they go back to legacy behaviour using getitem/setitem.
+ */
+ base_descr = NULL;
+ }
+
+ /*
+ * The cast is always considered unsafe, so the PyArray_GetCastSafety
+ * result currently does not matter.
+ */
+ if (base_descr != NULL && PyArray_GetCastSafety(
+ base_descr, given_descrs[1], dtypes[1]) < 0) {
+ return -1;
+ }
+
+ /* Void dtypes always do the full cast. */
+ if (given_descrs[1] == NULL) {
+ loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]);
+ /*
+ * Special case strings here, it should be useless (and only actually
+ * work for empty arrays). Possibly this should simply raise for
+ * all parametric DTypes.
+ */
+ if (dtypes[1]->type_num == NPY_STRING) {
+ loop_descrs[1]->elsize = given_descrs[0]->elsize;
+ }
+ else if (dtypes[1]->type_num == NPY_UNICODE) {
+ loop_descrs[1]->elsize = given_descrs[0]->elsize * 4;
+ }
+ }
+ else {
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+
+ return NPY_UNSAFE_CASTING;
+}
+
+
+static PyObject *
+PyArray_GetVoidToGenericCastingImpl(void)
+{
+ static PyArrayMethodObject *method = NULL;
+
+ if (method != NULL) {
+ Py_INCREF(method);
+ return (PyObject *)method;
+ }
+
+ method = PyObject_New(PyArrayMethodObject, &PyArrayMethod_Type);
+ if (method == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ method->name = "void_to_any_cast";
+ method->flags = NPY_METH_SUPPORTS_UNALIGNED | NPY_METH_REQUIRES_PYAPI;
+ method->casting = NPY_UNSAFE_CASTING;
+ method->resolve_descriptors = &structured_to_nonstructured_resolve_descriptors;
+ method->get_strided_loop = NULL;
+
+ return (PyObject *)method;
+}
+
+
+/*
+ * Find the correct field casting safety. See the TODO note below, including
+ * in 1.20 (and later) this was based on field names rather than field order
+ * which it should be using.
+ *
+ * NOTE: In theory it would be possible to cache the all the field casting
+ * implementations on the dtype, to avoid duplicate work.
+ */
+static NPY_CASTING
+can_cast_fields_safety(PyArray_Descr *from, PyArray_Descr *to)
+{
+ NPY_CASTING casting = NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
+
+ Py_ssize_t field_count = PyTuple_Size(from->names);
+ if (field_count != PyTuple_Size(to->names)) {
+ /* TODO: This should be rejected! */
+ return NPY_UNSAFE_CASTING;
+ }
+ for (Py_ssize_t i = 0; i < field_count; i++) {
+ PyObject *from_key = PyTuple_GET_ITEM(from->names, i);
+ PyObject *from_tup = PyDict_GetItemWithError(from->fields, from_key);
+ if (from_tup == NULL) {
+ return give_bad_field_error(from_key);
+ }
+ PyArray_Descr *from_base = (PyArray_Descr*)PyTuple_GET_ITEM(from_tup, 0);
+
+ /*
+ * TODO: This should use to_key (order), compare gh-15509 by
+ * by Allan Haldane. And raise an error on failure.
+ * (Fixing that may also requires fixing/changing promotion.)
+ */
+ PyObject *to_tup = PyDict_GetItem(to->fields, from_key);
+ if (to_tup == NULL) {
+ return NPY_UNSAFE_CASTING;
+ }
+ PyArray_Descr *to_base = (PyArray_Descr*)PyTuple_GET_ITEM(to_tup, 0);
+
+ NPY_CASTING field_casting = PyArray_GetCastSafety(from_base, to_base, NULL);
+ if (field_casting < 0) {
+ return -1;
+ }
+ casting = PyArray_MinCastSafety(casting, field_casting);
+ }
+ if (!(casting & _NPY_CAST_IS_VIEW)) {
+ assert((casting & ~_NPY_CAST_IS_VIEW) != NPY_NO_CASTING);
+ return casting;
+ }
+
+ /*
+ * If the itemsize (includes padding at the end), fields, or names
+ * do not match, this cannot be a view and also not a "no" cast
+ * (identical dtypes).
+ * It may be possible that this can be relaxed in some cases.
+ */
+ if (from->elsize != to->elsize) {
+ /*
+ * The itemsize may mismatch even if all fields and formats match
+ * (due to additional padding).
+ */
+ return PyArray_MinCastSafety(casting, NPY_EQUIV_CASTING);
+ }
+
+ int cmp = PyObject_RichCompareBool(from->fields, to->fields, Py_EQ);
+ if (cmp != 1) {
+ if (cmp == -1) {
+ PyErr_Clear();
+ }
+ return PyArray_MinCastSafety(casting, NPY_EQUIV_CASTING);
+ }
+ cmp = PyObject_RichCompareBool(from->names, to->names, Py_EQ);
+ if (cmp != 1) {
+ if (cmp == -1) {
+ PyErr_Clear();
+ }
+ return PyArray_MinCastSafety(casting, NPY_EQUIV_CASTING);
+ }
+ return casting;
+}
+
+
+static NPY_CASTING
+void_to_void_resolve_descriptors(
+ PyArrayMethodObject *self,
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ NPY_CASTING casting;
+
+ if (given_descrs[1] == NULL) {
+ /* This is weird, since it doesn't return the original descr, but... */
+ return cast_to_void_dtype_class(given_descrs, loop_descrs);
+ }
+
+ if (given_descrs[0]->names != NULL && given_descrs[1]->names != NULL) {
+ /* From structured to structured, need to check fields */
+ casting = can_cast_fields_safety(given_descrs[0], given_descrs[1]);
+ }
+ else if (given_descrs[0]->names != NULL) {
+ return structured_to_nonstructured_resolve_descriptors(
+ self, dtypes, given_descrs, loop_descrs);
+ }
+ else if (given_descrs[1]->names != NULL) {
+ return nonstructured_to_structured_resolve_descriptors(
+ self, dtypes, given_descrs, loop_descrs);
+ }
+ else if (given_descrs[0]->subarray == NULL &&
+ given_descrs[1]->subarray == NULL) {
+ /* Both are plain void dtypes */
+ if (given_descrs[0]->elsize == given_descrs[1]->elsize) {
+ casting = NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
+ }
+ else if (given_descrs[0]->elsize < given_descrs[1]->elsize) {
+ casting = NPY_SAFE_CASTING;
+ }
+ else {
+ casting = NPY_SAME_KIND_CASTING;
+ }
+ }
+ else {
+ /*
+ * At this point, one of the dtypes must be a subarray dtype, the
+ * other is definitely not a structured one.
+ */
+ PyArray_ArrayDescr *from_sub = given_descrs[0]->subarray;
+ PyArray_ArrayDescr *to_sub = given_descrs[1]->subarray;
+ assert(from_sub || to_sub);
+
+ /* If the shapes do not match, this is at most an unsafe cast */
+ casting = NPY_UNSAFE_CASTING;
+ if (from_sub && to_sub) {
+ int res = PyObject_RichCompareBool(from_sub->shape, to_sub->shape, Py_EQ);
+ if (res < 0) {
+ return -1;
+ }
+ else if (res) {
+ /* Both are subarrays and the shape matches */
+ casting = NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
+ }
+ }
+ NPY_CASTING field_casting = PyArray_GetCastSafety(
+ given_descrs[0]->subarray->base, given_descrs[1]->subarray->base, NULL);
+ if (field_casting < 0) {
+ return -1;
+ }
+ casting = PyArray_MinCastSafety(casting, field_casting);
+ }
+
+ /* Void dtypes always do the full cast. */
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+
+ return casting;
+}
+
+
+/*
+ * This initializes the void to void cast. Voids include structured dtypes,
+ * which means that they can cast from and to any other dtype and, in that
+ * sense, are special (similar to Object).
+ */
+static int
+PyArray_InitializeVoidToVoidCast(void)
+{
+ PyArray_DTypeMeta *Void = PyArray_DTypeFromTypeNum(NPY_VOID);
+ PyArray_DTypeMeta *dtypes[2] = {Void, Void};
+ PyType_Slot slots[] = {
+ {NPY_METH_get_loop, NULL},
+ {NPY_METH_resolve_descriptors, &void_to_void_resolve_descriptors},
+ {0, NULL}};
+ PyArrayMethod_Spec spec = {
+ .name = "void_to_void_cast",
+ .casting = NPY_NO_CASTING,
+ .nin = 1,
+ .nout = 1,
+ .flags = NPY_METH_REQUIRES_PYAPI | NPY_METH_SUPPORTS_UNALIGNED,
+ .dtypes = dtypes,
+ .slots = slots,
+ };
+
+ int res = PyArray_AddCastingImplementation_FromSpec(&spec, 1);
+ Py_DECREF(Void);
+ return res;
+}
+
+
+/*
+ * Implement object to any casting implementation. Casting from object may
+ * require inspecting of all array elements (for parametric dtypes), and
+ * the resolver will thus reject all parametric dtypes if the out dtype
+ * is not provided.
+ */
+static NPY_CASTING
+object_to_any_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ if (given_descrs[1] == NULL) {
+ /*
+ * This should not really be called, since object -> parametric casts
+ * require inspecting the object array. Allow legacy ones, the path
+ * here is that e.g. "M8" input is considered to be the DType class,
+ * and by allowing it here, we go back to the "M8" instance.
+ */
+ if (dtypes[1]->parametric) {
+ PyErr_Format(PyExc_TypeError,
+ "casting from object to the parametric DType %S requires "
+ "the specified output dtype instance. "
+ "This may be a NumPy issue, since the correct instance "
+ "should be discovered automatically, however.", dtypes[1]);
+ return -1;
+ }
+ loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]);
+ if (loop_descrs[1] == NULL) {
+ return -1;
+ }
+ }
+ else {
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+ return NPY_UNSAFE_CASTING;
+}
+
+
+/*
+ * Casting to object is special since it is generic to all input dtypes.
+ */
+static PyObject *
+PyArray_GetObjectToGenericCastingImpl(void)
+{
+ static PyArrayMethodObject *method = NULL;
+
+ if (method != NULL) {
+ Py_INCREF(method);
+ return (PyObject *)method;
+ }
+
+ method = PyObject_New(PyArrayMethodObject, &PyArrayMethod_Type);
+ if (method == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ method->nin = 1;
+ method->nout = 1;
+ method->name = "object_to_any_cast";
+ method->flags = NPY_METH_SUPPORTS_UNALIGNED | NPY_METH_REQUIRES_PYAPI;
+ method->casting = NPY_UNSAFE_CASTING;
+ method->resolve_descriptors = &object_to_any_resolve_descriptors;
+ method->get_strided_loop = NULL;
+
+ return (PyObject *)method;
+}
+
+
+
+/* Any object object is simple (could even use the default) */
+static NPY_CASTING
+any_to_object_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ if (given_descrs[1] == NULL) {
+ loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]);
+ if (loop_descrs[1] == NULL) {
+ return -1;
+ }
+ }
+ else {
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+ return NPY_SAFE_CASTING;
+}
+
+
+/*
+ * Casting to object is special since it is generic to all input dtypes.
+ */
+static PyObject *
+PyArray_GetGenericToObjectCastingImpl(void)
+{
+ static PyArrayMethodObject *method = NULL;
+
+ if (method != NULL) {
+ Py_INCREF(method);
+ return (PyObject *)method;
+ }
+
+ method = PyObject_New(PyArrayMethodObject, &PyArrayMethod_Type);
+ if (method == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ method->nin = 1;
+ method->nout = 1;
+ method->name = "any_to_object_cast";
+ method->flags = NPY_METH_SUPPORTS_UNALIGNED | NPY_METH_REQUIRES_PYAPI;
+ method->casting = NPY_SAFE_CASTING;
+ method->resolve_descriptors = &any_to_object_resolve_descriptors;
+ method->get_strided_loop = NULL;
+
+ return (PyObject *)method;
+}
+
+
+static int
+PyArray_InitializeObjectToObjectCast(void)
+{
+ /*
+ * The object dtype does not support byte order changes, so its cast
+ * is always a direct view.
+ */
+ PyArray_DTypeMeta *Object = PyArray_DTypeFromTypeNum(NPY_OBJECT);
+ PyArray_DTypeMeta *dtypes[2] = {Object, Object};
+ PyType_Slot slots[] = {
+ {NPY_METH_get_loop, NULL},
+ {0, NULL}};
+ PyArrayMethod_Spec spec = {
+ .name = "object_to_object_cast",
+ .casting = NPY_NO_CASTING | _NPY_CAST_IS_VIEW,
+ .nin = 1,
+ .nout = 1,
+ .flags = NPY_METH_REQUIRES_PYAPI | NPY_METH_SUPPORTS_UNALIGNED,
+ .dtypes = dtypes,
+ .slots = slots,
+ };
+
+ int res = PyArray_AddCastingImplementation_FromSpec(&spec, 1);
+ Py_DECREF(Object);
+ return res;
+}
+
+
+NPY_NO_EXPORT int
+PyArray_InitializeCasts()
+{
+ if (PyArray_InitializeNumericCasts() < 0) {
+ return -1;
+ }
+ if (PyArray_InitializeStringCasts() < 0) {
+ return -1;
+ }
+ if (PyArray_InitializeVoidToVoidCast() < 0) {
+ return -1;
+ }
+ if (PyArray_InitializeObjectToObjectCast() < 0) {
+ return -1;
+ }
+ /* Datetime casts are defined in datetime.c */
+ if (PyArray_InitializeDatetimeCasts() < 0) {
+ return -1;
+ }
+ return 0;
+}
#ifndef _NPY_ARRAY_CONVERT_DATATYPE_H_
#define _NPY_ARRAY_CONVERT_DATATYPE_H_
+#include "array_method.h"
+
+extern NPY_NO_EXPORT npy_intp REQUIRED_STR_LEN[];
+
+NPY_NO_EXPORT PyObject *
+_get_castingimpl(PyObject *NPY_UNUSED(module), PyObject *args);
+
NPY_NO_EXPORT PyArray_VectorUnaryFunc *
PyArray_GetCastFunc(PyArray_Descr *descr, int type_num);
NPY_NO_EXPORT PyArrayObject **
PyArray_ConvertToCommonType(PyObject *op, int *retn);
+NPY_NO_EXPORT PyArray_DTypeMeta *
+PyArray_CommonDType(PyArray_DTypeMeta *dtype1, PyArray_DTypeMeta *dtype2);
+
NPY_NO_EXPORT int
PyArray_ValidType(int type);
+NPY_NO_EXPORT int
+dtype_kind_to_ordering(char kind);
+
/* 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);
+NPY_NO_EXPORT PyArray_Descr *
+ensure_dtype_nbo(PyArray_Descr *type);
+
NPY_NO_EXPORT int
should_use_min_scalar(npy_intp narrs, PyArrayObject **arr,
npy_intp ndtypes, PyArray_Descr **dtypes);
PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
NPY_CASTING casting, npy_bool scalar);
-/*
- * 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
- * and data_obj. If the flex_dtype is not flexible, it returns it as-is.
- *
- * Usually, if data_obj is not an array, dtype should be the result
- * given by the PyArray_GetArrayParamsFromObject function.
- *
- * The data_obj may be NULL if just a dtype is known for the source.
- *
- * If *flex_dtype is NULL, returns immediately, without setting an
- * exception, leaving any previous error handling intact.
- *
- * The current flexible dtypes include NPY_STRING, NPY_UNICODE, NPY_VOID,
- * and NPY_DATETIME with generic units.
- */
NPY_NO_EXPORT PyArray_Descr *
-PyArray_AdaptFlexibleDType(PyObject *data_obj, PyArray_Descr *data_dtype,
- PyArray_Descr *flex_dtype);
+PyArray_CastDescrToDType(PyArray_Descr *descr, PyArray_DTypeMeta *given_DType);
+
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_FindConcatenationDescriptor(
+ npy_intp n, PyArrayObject **arrays, PyObject *requested_dtype);
+
+NPY_NO_EXPORT int
+PyArray_AddCastingImplmentation(PyBoundArrayMethodObject *meth);
+
+NPY_NO_EXPORT int
+PyArray_AddCastingImplementation_FromSpec(PyArrayMethod_Spec *spec, int private);
+
+NPY_NO_EXPORT NPY_CASTING
+PyArray_MinCastSafety(NPY_CASTING casting1, NPY_CASTING casting2);
+
+NPY_NO_EXPORT NPY_CASTING
+PyArray_GetCastSafety(
+ PyArray_Descr *from, PyArray_Descr *to, PyArray_DTypeMeta *to_dtype);
+
+NPY_NO_EXPORT NPY_CASTING
+legacy_same_dtype_resolve_descriptors(
+ PyArrayMethodObject *self,
+ PyArray_DTypeMeta **dtypes,
+ PyArray_Descr **given_descrs,
+ PyArray_Descr **loop_descrs);
+
+NPY_NO_EXPORT NPY_CASTING
+simple_cast_resolve_descriptors(
+ PyArrayMethodObject *self,
+ PyArray_DTypeMeta **dtypes,
+ PyArray_Descr **input_descrs,
+ PyArray_Descr **loop_descrs);
+
+NPY_NO_EXPORT int
+PyArray_InitializeCasts(void);
#endif
#include <assert.h>
#include "get_attr_string.h"
+#include "array_coercion.h"
/*
* Reading from a file or a string.
typedef int (*next_element)(void **, void *, PyArray_Descr *, void *);
typedef int (*skip_separator)(void **, const char *, void *);
-static PyObject *
-_array_from_array_like(PyObject *op,
- PyArray_Descr *requested_dtype, npy_bool writeable, PyObject *context);
static npy_bool
string_is_fully_read(char const* start, char const* end) {
}
if (tuple) {
for (i = 0; i < numnew; i++) {
- mydim[i] = (npy_intp) PyInt_AsLong(
+ mydim[i] = (npy_intp) PyLong_AsLong(
PyTuple_GET_ITEM(old->subarray->shape, i));
}
}
else {
- mydim[0] = (npy_intp) PyInt_AsLong(old->subarray->shape);
+ mydim[0] = (npy_intp) PyLong_AsLong(old->subarray->shape);
}
if (newstrides) {
}
}
+
/*
- * adapted from Numarray,
- * a: destination array
- * s: source object, array or sequence
- * dim: current recursion dimension, must be 0 on first call
- * dst: must be NULL on first call
- * it is a view on the destination array viewing the place where to put the
- * data of the current recursion
+ * Recursive helper to assign using a coercion cache. This function
+ * must consume the cache depth first, just as the cache was originally
+ * produced.
*/
-static int
-setArrayFromSequence(PyArrayObject *a, PyObject *s,
- int dim, PyArrayObject * dst)
+NPY_NO_EXPORT int
+PyArray_AssignFromCache_Recursive(
+ PyArrayObject *self, const int ndim, coercion_cache_obj **cache)
{
- Py_ssize_t i, slen;
- int res = -1;
-
- /* first recursion, view equal destination */
- if (dst == NULL)
- dst = a;
+ /* Consume first cache element by extracting information and freeing it */
+ PyObject *original_obj = (*cache)->converted_obj;
+ PyObject *obj = (*cache)->arr_or_sequence;
+ Py_INCREF(obj);
+ npy_bool sequence = (*cache)->sequence;
+ int depth = (*cache)->depth;
+ *cache = npy_unlink_coercion_cache(*cache);
/*
- * This code is to ensure that the sequence access below will
- * return a lower-dimensional sequence.
+ * The maximum depth is special (specifically for objects), but usually
+ * unrolled in the sequence branch below.
*/
-
- /* INCREF on entry DECREF on exit */
- Py_INCREF(s);
-
- PyObject *seq = NULL;
-
- if (PyArray_Check(s)) {
- if (!(PyArray_CheckExact(s))) {
+ if (NPY_UNLIKELY(depth == ndim)) {
+ /*
+ * We have reached the maximum depth. We should simply assign to the
+ * element in principle. There is one exception. If this is a 0-D
+ * array being stored into a 0-D array (but we do not reach here then).
+ */
+ if (PyArray_ISOBJECT(self)) {
+ assert(ndim != 0); /* guaranteed by PyArray_AssignFromCache */
+ assert(PyArray_NDIM(self) == 0);
+ Py_DECREF(obj);
+ return PyArray_Pack(PyArray_DESCR(self), PyArray_BYTES(self),
+ original_obj);
+ }
+ if (sequence) {
/*
- * make sure a base-class array is used so that the dimensionality
- * reduction assumption is correct.
+ * Sanity check which may be removed, the error is raised already
+ * in `PyArray_DiscoverDTypeAndShape`.
*/
- /* This will DECREF(s) if replaced */
- s = PyArray_EnsureArray(s);
- if (s == NULL) {
- goto fail;
- }
- }
-
- /* dst points to correct array subsection */
- if (PyArray_CopyInto(dst, (PyArrayObject *)s) < 0) {
+ assert(0);
+ PyErr_SetString(PyExc_RuntimeError,
+ "setting an array element with a sequence");
goto fail;
}
-
- Py_DECREF(s);
- return 0;
- }
-
- if (dim > PyArray_NDIM(a)) {
- PyErr_Format(PyExc_ValueError,
- "setArrayFromSequence: sequence/array dimensions mismatch.");
- goto fail;
+ else if (original_obj != obj || !PyArray_CheckExact(obj)) {
+ /*
+ * If the leave node is an array-like, but not a numpy array,
+ * we pretend it is an arbitrary scalar. This means that in
+ * most cases (where the dtype is int or float), we will end
+ * up using float(array-like), or int(array-like). That does
+ * not support general casting, but helps Quantity and masked
+ * arrays, because it allows them to raise an error when
+ * `__float__()` or `__int__()` is called.
+ */
+ Py_DECREF(obj);
+ return PyArray_SETITEM(self, PyArray_BYTES(self), original_obj);
+ }
}
- /* Try __array__ before using s as a sequence */
- PyObject *tmp = _array_from_array_like(s, NULL, 0, NULL);
- if (tmp == NULL) {
- goto fail;
- }
- else if (tmp == Py_NotImplemented) {
- Py_DECREF(tmp);
+ /* The element is either a sequence, or an array */
+ if (!sequence) {
+ /* Straight forward array assignment */
+ assert(PyArray_Check(obj));
+ if (PyArray_CopyInto(self, (PyArrayObject *)obj) < 0) {
+ goto fail;
+ }
}
else {
- int r = PyArray_CopyInto(dst, (PyArrayObject *)tmp);
- Py_DECREF(tmp);
- if (r < 0) {
+ assert(depth != ndim);
+ npy_intp length = PySequence_Length(obj);
+ if (length != PyArray_DIMS(self)[0]) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Inconsistent object during array creation? "
+ "Content of sequences changed (length inconsistent).");
goto fail;
}
- Py_DECREF(s);
- return 0;
- }
-
- seq = PySequence_Fast(s, "Could not convert object to sequence");
- if (seq == NULL) {
- goto fail;
- }
- slen = PySequence_Fast_GET_SIZE(seq);
- /*
- * Either the dimensions match, or the sequence has length 1 and can
- * be broadcast to the destination.
- */
- if (slen != PyArray_DIMS(a)[dim] && slen != 1) {
- PyErr_Format(PyExc_ValueError,
- "cannot copy sequence with size %zd to array axis "
- "with dimension %" NPY_INTP_FMT, slen, PyArray_DIMS(a)[dim]);
- goto fail;
- }
+ for (npy_intp i = 0; i < length; i++) {
+ PyObject *value = PySequence_Fast_GET_ITEM(obj, i);
- /* Broadcast the one element from the sequence to all the outputs */
- if (slen == 1) {
- PyObject *o = PySequence_Fast_GET_ITEM(seq, 0);
- npy_intp alen = PyArray_DIM(a, dim);
-
- for (i = 0; i < alen; i++) {
- if ((PyArray_NDIM(a) - dim) > 1) {
- PyArrayObject * tmp =
- (PyArrayObject *)array_item_asarray(dst, i);
- if (tmp == NULL) {
+ if (*cache == NULL || (*cache)->converted_obj != value ||
+ (*cache)->depth != depth + 1) {
+ if (ndim != depth + 1) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Inconsistent object during array creation? "
+ "Content of sequences changed (now too shallow).");
goto fail;
}
-
- res = setArrayFromSequence(a, o, dim+1, tmp);
- Py_DECREF(tmp);
- }
- else {
- char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
- res = PyArray_SETITEM(dst, b, o);
- }
- if (res < 0) {
- goto fail;
- }
- }
- }
- /* Copy element by element */
- else {
- for (i = 0; i < slen; i++) {
- PyObject * o = PySequence_Fast_GET_ITEM(seq, i);
- if ((PyArray_NDIM(a) - dim) > 1) {
- PyArrayObject * tmp =
- (PyArrayObject *)array_item_asarray(dst, i);
- if (tmp == NULL) {
+ /* Straight forward assignment of elements */
+ char *item;
+ item = (PyArray_BYTES(self) + i * PyArray_STRIDES(self)[0]);
+ if (PyArray_Pack(PyArray_DESCR(self), item, value) < 0) {
goto fail;
}
-
- res = setArrayFromSequence(a, o, dim+1, tmp);
- Py_DECREF(tmp);
- }
- else {
- char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
- res = PyArray_SETITEM(dst, b, o);
- }
- if (res < 0) {
- goto fail;
- }
- }
- }
-
- Py_DECREF(seq);
- Py_DECREF(s);
- return 0;
-
- fail:
- Py_XDECREF(seq);
- Py_DECREF(s);
- return res;
-}
-
-NPY_NO_EXPORT int
-PyArray_AssignFromSequence(PyArrayObject *self, PyObject *v)
-{
- if (!PySequence_Check(v)) {
- PyErr_SetString(PyExc_ValueError,
- "assignment from non-sequence");
- return -1;
- }
- if (PyArray_NDIM(self) == 0) {
- PyErr_SetString(PyExc_ValueError,
- "assignment to 0-d array");
- return -1;
- }
- return setArrayFromSequence(self, v, 0, NULL);
-}
-
-/*
- * The rest of this code is to build the right kind of array
- * from a python object.
- */
-
-static int
-discover_itemsize(PyObject *s, int nd, int *itemsize, int string_type)
-{
- int r;
- npy_intp n, i;
-
- if (PyArray_Check(s)) {
- *itemsize = PyArray_MAX(*itemsize, PyArray_ITEMSIZE((PyArrayObject *)s));
- return 0;
- }
-
- if ((nd == 0) || PyString_Check(s) ||
- PyMemoryView_Check(s) || PyUnicode_Check(s)) {
- /* If an object has no length, leave it be */
- if (string_type && s != NULL &&
- !PyString_Check(s) && !PyUnicode_Check(s)) {
- PyObject *s_string = NULL;
- if (string_type == NPY_STRING) {
- s_string = PyObject_Str(s);
}
else {
- s_string = PyObject_Str(s);
- }
- if (s_string) {
- n = PyObject_Length(s_string);
- Py_DECREF(s_string);
- }
- else {
- n = -1;
+ PyArrayObject *view;
+ view = (PyArrayObject *)array_item_asarray(self, i);
+ if (view < 0) {
+ goto fail;
+ }
+ if (PyArray_AssignFromCache_Recursive(view, ndim, cache) < 0) {
+ Py_DECREF(view);
+ goto fail;
+ }
+ Py_DECREF(view);
}
}
- else {
- n = PyObject_Length(s);
- }
- if (n == -1) {
- PyErr_Clear();
- }
- else {
- *itemsize = PyArray_MAX(*itemsize, n);
- }
- return 0;
}
-
- n = PySequence_Length(s);
- for (i = 0; i < n; i++) {
- PyObject *e = PySequence_GetItem(s,i);
-
- if (e == NULL) {
- return -1;
- }
-
- r = discover_itemsize(e, nd - 1, itemsize, string_type);
- Py_DECREF(e);
- if (r == -1) {
- return -1;
- }
- }
-
+ Py_DECREF(obj);
return 0;
-}
-
-typedef enum {
- DISCOVERED_OK = 0,
- DISCOVERED_RAGGED = 1,
- DISCOVERED_OBJECT = 2
-} discovered_t;
-
-
-static void
-_discover_dimensions_array(PyArrayObject *arr, int *maxndim, npy_intp *d) {
- if (PyArray_NDIM(arr) < *maxndim) {
- *maxndim = PyArray_NDIM(arr);
- }
- for (int i = 0; i < *maxndim; i++) {
- d[i] = PyArray_DIM(arr, i);
- }
+ fail:
+ Py_DECREF(obj);
+ return -1;
}
-/*
- * Take an arbitrary object and discover how many dimensions it
- * has, filling in the dimensions as we go.
+/**
+ * Fills an item based on a coercion cache object. It consumes the cache
+ * object while doing so.
+ *
+ * @param self Array to fill.
+ * @param cache coercion_cache_object, will be consumed. The cache must not
+ * contain a single array (must start with a sequence). The array case
+ * should be handled by `PyArray_FromArray()` before.
+ * @return 0 on success -1 on failure.
*/
-static int
-discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it,
- int stop_at_string, int stop_at_tuple,
- discovered_t *out_is_object)
-{
- PyObject *e;
- npy_intp n, i;
- PyObject * seq;
-
- if (*maxndim == 0) {
- return 0;
- }
-
- /* obj is an Array */
- if (PyArray_Check(obj)) {
- _discover_dimensions_array((PyArrayObject *)obj, maxndim, d);
- return 0;
- }
-
- /* obj is a Scalar */
- if (PyArray_IsScalar(obj, Generic)) {
- *maxndim = 0;
- return 0;
- }
-
- /* obj is not a Sequence */
- if (!PySequence_Check(obj) ||
- PySequence_Length(obj) < 0) {
- *maxndim = 0;
- if (PyErr_Occurred()) {
- if (PyErr_ExceptionMatches(PyExc_RecursionError) ||
- PyErr_ExceptionMatches(PyExc_MemoryError)) {
- return -1;
- }
- PyErr_Clear();
- }
- return 0;
- }
-
- /* obj is a String */
- if (PyString_Check(obj) ||
- PyUnicode_Check(obj)) {
- if (stop_at_string) {
- *maxndim = 0;
- }
- else {
- d[0] = PySequence_Length(obj);
- *maxndim = 1;
- }
- return 0;
- }
-
- /* obj is a Tuple, but tuples aren't expanded */
- if (stop_at_tuple && PyTuple_Check(obj)) {
- *maxndim = 0;
- return 0;
- }
-
+NPY_NO_EXPORT int
+PyArray_AssignFromCache(PyArrayObject *self, coercion_cache_obj *cache) {
+ int ndim = PyArray_NDIM(self);
/*
- * In the future, the result of `_array_from_array_like` should possibly
- * be cached. This may require passing the correct dtype/writable
- * information already in the dimension discovery step (if they are
- * distinct steps).
+ * Do not support ndim == 0 now with an array in the cache.
+ * The ndim == 0 is special because np.array(np.array(0), dtype=object)
+ * should unpack the inner array.
+ * Since the single-array case is special, it is handled previously
+ * in either case.
*/
- e = _array_from_array_like(obj, NULL, NPY_FALSE, NULL);
- if (e == Py_NotImplemented) {
- Py_DECREF(e);
- }
- else if (e != NULL) {
- _discover_dimensions_array((PyArrayObject *)e, maxndim, d);
- Py_DECREF(e);
- return 0;
- }
- else if (PyErr_Occurred()) {
- /*
- * Clear all but clearly fatal errors (previously cleared all).
- * 1.20+ does not clear any errors here.
- */
- if (PyErr_ExceptionMatches(PyExc_RecursionError) ||
- PyErr_ExceptionMatches(PyExc_MemoryError)) {
- return -1;
- }
- PyErr_Clear();
- }
-
- seq = PySequence_Fast(obj, "Could not convert object to sequence");
- if (seq == NULL) {
- /*
- * PySequence_Check detects whether an old type object is a
- * sequence by the presence of the __getitem__ attribute, and
- * for new type objects that aren't dictionaries by the
- * presence of the __len__ attribute as well. In either case it
- * is possible to have an object that tests as a sequence but
- * doesn't behave as a sequence and consequently, the
- * PySequence_GetItem call can fail. When that happens and the
- * object looks like a dictionary, we truncate the dimensions
- * and set the object creation flag, otherwise we pass the
- * error back up the call chain.
- */
- if (PyErr_ExceptionMatches(PyExc_KeyError)) {
- PyErr_Clear();
- *maxndim = 0;
- *out_is_object = DISCOVERED_OBJECT;
- return 0;
- }
- else {
- return -1;
- }
- }
- n = PySequence_Fast_GET_SIZE(seq);
+ assert(cache->sequence);
+ assert(ndim != 0); /* guaranteed if cache contains a sequence */
- d[0] = n;
-
- /* 1-dimensional sequence */
- if (n == 0 || *maxndim == 1) {
- *maxndim = 1;
- Py_DECREF(seq);
- return 0;
+ if (PyArray_AssignFromCache_Recursive(self, ndim, &cache) < 0) {
+ /* free the remaining cache. */
+ npy_free_coercion_cache(cache);
+ return -1;
}
- else {
- int all_elems_maxndim = *maxndim - 1;
- npy_intp *all_elems_d = d + 1;
- int all_dimensions_match = 1;
-
- /* Get the dimensions of the first item as a baseline */
- PyObject *first = PySequence_Fast_GET_ITEM(seq, 0);
- if (discover_dimensions(
- first, &all_elems_maxndim, all_elems_d, check_it,
- stop_at_string, stop_at_tuple, out_is_object) < 0) {
- Py_DECREF(seq);
- return -1;
- }
- /* Compare the dimensions of all the remaining items */
- for (i = 1; i < n; ++i) {
- int j;
- int elem_maxndim = *maxndim - 1;
- npy_intp elem_d[NPY_MAXDIMS];
-
- PyObject *elem = PySequence_Fast_GET_ITEM(seq, i);
- if (discover_dimensions(
- elem, &elem_maxndim, elem_d, check_it,
- stop_at_string, stop_at_tuple, out_is_object) < 0) {
- Py_DECREF(seq);
- return -1;
- }
-
- /* Find the number of left-dimensions which match, j */
- for (j = 0; j < elem_maxndim && j < all_elems_maxndim; ++j) {
- if (elem_d[j] != all_elems_d[j]) {
- break;
- }
- }
- if (j != elem_maxndim || j != all_elems_maxndim) {
- all_dimensions_match = 0;
- }
- all_elems_maxndim = j;
- }
- *maxndim = all_elems_maxndim + 1;
- if (!all_dimensions_match) {
- /* typically results in an array containing variable-length lists */
- *out_is_object = DISCOVERED_RAGGED;
- }
+ /*
+ * Sanity check, this is the initial call, and when it returns, the
+ * cache has to be fully consumed, otherwise something is wrong.
+ * NOTE: May be nicer to put into a recursion helper.
+ */
+ if (cache != NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Inconsistent object during array creation? "
+ "Content of sequences changed (cache not consumed).");
+ npy_free_coercion_cache(cache);
+ return -1;
}
-
- Py_DECREF(seq);
-
return 0;
}
+
static void
raise_memory_error(int nd, npy_intp const *dims, PyArray_Descr *descr)
{
Py_DECREF(descr);
return NULL;
}
+ fa->_buffer_info = NULL;
fa->nd = nd;
fa->dimensions = NULL;
fa->data = NULL;
+
if (data == NULL) {
fa->flags = NPY_ARRAY_DEFAULT;
if (flags) {
func = PyObject_GetAttr((PyObject *)fa, npy_ma_str_array_finalize);
if (func && func != Py_None) {
- if (NpyCapsule_Check(func)) {
+ if (PyCapsule_CheckExact(func)) {
/* A C-function is stored here */
PyArray_FinalizeFunc *cfunc;
- cfunc = NpyCapsule_AsVoidPtr(func);
+ cfunc = PyCapsule_GetPointer(func, NULL);
Py_DECREF(func);
+ if (cfunc == NULL) {
+ goto fail;
+ }
if (cfunc((PyArrayObject *)fa, obj) < 0) {
goto fail;
}
* or NULL with an error set. (A new reference to Py_NotImplemented
* is returned.)
*/
-static PyObject *
+NPY_NO_EXPORT PyObject *
_array_from_array_like(PyObject *op,
PyArray_Descr *requested_dtype, npy_bool writeable, PyObject *context) {
PyObject* tmp;
}
+/*NUMPY_API*/
+NPY_NO_EXPORT int
+PyArray_GetArrayParamsFromObject(PyObject *NPY_UNUSED(op),
+ PyArray_Descr *NPY_UNUSED(requested_dtype),
+ npy_bool NPY_UNUSED(writeable),
+ PyArray_Descr **NPY_UNUSED(out_dtype),
+ int *NPY_UNUSED(out_ndim), npy_intp *NPY_UNUSED(out_dims),
+ PyArrayObject **NPY_UNUSED(out_arr), PyObject *NPY_UNUSED(context))
+{
+ /* Deprecated in NumPy 1.19, removed in NumPy 1.20. */
+ PyErr_SetString(PyExc_RuntimeError,
+ "PyArray_GetArrayParamsFromObject() C-API function is removed "
+ "`PyArray_FromAny()` should be used at this time. New C-API "
+ "may be exposed in the future (please do request this if it "
+ "would help you).");
+ return -1;
+}
+
+
/*
- * Retrieves the array parameters for viewing/converting an arbitrary
- * PyObject* to a NumPy array. This allows the "innate type and shape"
- * of Python list-of-lists to be discovered without
- * actually converting to an array.
- *
- * In some cases, such as structured arrays and the __array__ interface,
- * a data type needs to be used to make sense of the object. When
- * this is needed, provide a Descr for 'requested_dtype', otherwise
- * provide NULL. This reference is not stolen. Also, if the requested
- * dtype doesn't modify the interpretation of the input, out_dtype will
- * still get the "innate" dtype of the object, not the dtype passed
- * in 'requested_dtype'.
- *
- * If writing to the value in 'op' is desired, set the boolean
- * 'writeable' to 1. This raises an error when 'op' is a scalar, list
- * of lists, or other non-writeable 'op'.
- *
- * Result: When success (0 return value) is returned, either out_arr
- * is filled with a non-NULL PyArrayObject and
- * the rest of the parameters are untouched, or out_arr is
- * filled with NULL, and the rest of the parameters are
- * filled.
- *
- * Typical usage:
+ * This function is a legacy implementation to retain subarray dtype
+ * behaviour in array coercion. The behaviour here makes sense if tuples
+ * of matching dimensionality are being coerced. Due to the difficulty
+ * that the result is ill-defined for lists of array-likes, this is deprecated.
*
- * PyArrayObject *arr = NULL;
- * PyArray_Descr *dtype = NULL;
- * int ndim = 0;
- * npy_intp dims[NPY_MAXDIMS];
- *
- * if (PyArray_GetArrayParamsFromObject(op, NULL, 1, &dtype,
- * &ndim, dims, &arr, NULL) < 0) {
- * return NULL;
- * }
- * if (arr == NULL) {
- * ... validate/change dtype, validate flags, ndim, etc ...
- * // Could make custom strides here too
- * arr = PyArray_NewFromDescr(&PyArray_Type, dtype, ndim,
- * dims, NULL,
- * is_f_order ? NPY_ARRAY_F_CONTIGUOUS : 0,
- * NULL);
- * if (arr == NULL) {
- * return NULL;
- * }
- * if (PyArray_CopyObject(arr, op) < 0) {
- * Py_DECREF(arr);
- * return NULL;
- * }
- * }
- * else {
- * ... in this case the other parameters weren't filled, just
- * validate and possibly copy arr itself ...
- * }
- * ... use arr ...
+ * WARNING: Do not use this function, it exists purely to support a deprecated
+ * code path.
*/
-NPY_NO_EXPORT int
-PyArray_GetArrayParamsFromObject_int(PyObject *op,
- PyArray_Descr *requested_dtype,
- npy_bool writeable,
- PyArray_Descr **out_dtype,
- int *out_ndim, npy_intp *out_dims,
- PyArrayObject **out_arr)
+static int
+setArrayFromSequence(PyArrayObject *a, PyObject *s,
+ int dim, PyArrayObject * dst)
{
- PyObject *tmp;
+ Py_ssize_t i, slen;
+ int res = -1;
- /* If op is an array */
- if (PyArray_Check(op)) {
- if (writeable
- && PyArray_FailUnlessWriteable((PyArrayObject *)op, "array") < 0) {
- return -1;
- }
- Py_INCREF(op);
- *out_arr = (PyArrayObject *)op;
- return 0;
- }
+ /* first recursion, view equal destination */
+ if (dst == NULL)
+ dst = a;
- /* If op is a NumPy scalar */
- if (PyArray_IsScalar(op, Generic)) {
- if (writeable) {
- PyErr_SetString(PyExc_RuntimeError,
- "cannot write to scalar");
- return -1;
+ /*
+ * This code is to ensure that the sequence access below will
+ * return a lower-dimensional sequence.
+ */
+
+ /* INCREF on entry DECREF on exit */
+ Py_INCREF(s);
+
+ PyObject *seq = NULL;
+
+ if (PyArray_Check(s)) {
+ if (!(PyArray_CheckExact(s))) {
+ /*
+ * make sure a base-class array is used so that the dimensionality
+ * reduction assumption is correct.
+ */
+ /* This will DECREF(s) if replaced */
+ s = PyArray_EnsureArray(s);
+ if (s == NULL) {
+ goto fail;
+ }
}
- *out_dtype = PyArray_DescrFromScalar(op);
- if (*out_dtype == NULL) {
- return -1;
+
+ /* dst points to correct array subsection */
+ if (PyArray_CopyInto(dst, (PyArrayObject *)s) < 0) {
+ goto fail;
}
- *out_ndim = 0;
- *out_arr = NULL;
+
+ Py_DECREF(s);
return 0;
}
- /* If op is a Python scalar */
- *out_dtype = _array_find_python_scalar_type(op);
- if (*out_dtype != NULL) {
- if (writeable) {
- PyErr_SetString(PyExc_RuntimeError,
- "cannot write to scalar");
- Py_DECREF(*out_dtype);
- return -1;
- }
- *out_ndim = 0;
- *out_arr = NULL;
- return 0;
+ if (dim > PyArray_NDIM(a)) {
+ PyErr_Format(PyExc_ValueError,
+ "setArrayFromSequence: sequence/array dimensions mismatch.");
+ goto fail;
}
- /* If op is an array-like */
- tmp = _array_from_array_like(op, requested_dtype, writeable, NULL);
+ /* Try __array__ before using s as a sequence */
+ PyObject *tmp = _array_from_array_like(s, NULL, 0, NULL);
if (tmp == NULL) {
- return -1;
+ goto fail;
}
- else if (tmp != Py_NotImplemented) {
- *out_arr = (PyArrayObject*) tmp;
- return 0;
+ else if (tmp == Py_NotImplemented) {
+ Py_DECREF(tmp);
}
else {
- Py_DECREF(Py_NotImplemented);
+ int r = PyArray_CopyInto(dst, (PyArrayObject *)tmp);
+ Py_DECREF(tmp);
+ if (r < 0) {
+ goto fail;
+ }
+ Py_DECREF(s);
+ return 0;
}
- /* Try to treat op as a list of lists */
- if (!writeable && PySequence_Check(op)) {
- int check_it, stop_at_string, stop_at_tuple;
- int type_num, type;
+ seq = PySequence_Fast(s, "Could not convert object to sequence");
+ if (seq == NULL) {
+ goto fail;
+ }
+ slen = PySequence_Fast_GET_SIZE(seq);
- /*
- * Determine the type, using the requested data type if
- * it will affect how the array is retrieved
- */
- if (requested_dtype != NULL && (
- requested_dtype->type_num == NPY_STRING ||
- requested_dtype->type_num == NPY_UNICODE ||
- (requested_dtype->type_num == NPY_VOID &&
- (requested_dtype->names || requested_dtype->subarray)) ||
- requested_dtype->type == NPY_CHARLTR ||
- requested_dtype->type_num == NPY_OBJECT)) {
- Py_INCREF(requested_dtype);
- *out_dtype = requested_dtype;
- }
- else {
- *out_dtype = NULL;
- if (PyArray_DTypeFromObject(op, NPY_MAXDIMS, out_dtype) < 0) {
- if (PyErr_ExceptionMatches(PyExc_MemoryError) ||
- PyErr_ExceptionMatches(PyExc_RecursionError)) {
- return -1;
- }
- /* Return NPY_OBJECT for most exceptions */
- else {
- PyErr_Clear();
- *out_dtype = PyArray_DescrFromType(NPY_OBJECT);
- if (*out_dtype == NULL) {
- return -1;
- }
- }
- }
- if (*out_dtype == NULL) {
- *out_dtype = PyArray_DescrFromType(NPY_DEFAULT_TYPE);
- if (*out_dtype == NULL) {
- return -1;
- }
- }
- }
+ /*
+ * Either the dimensions match, or the sequence has length 1 and can
+ * be broadcast to the destination.
+ */
+ if (slen != PyArray_DIMS(a)[dim] && slen != 1) {
+ PyErr_Format(PyExc_ValueError,
+ "cannot copy sequence with size %zd to array axis "
+ "with dimension %" NPY_INTP_FMT, slen, PyArray_DIMS(a)[dim]);
+ goto fail;
+ }
- type_num = (*out_dtype)->type_num;
- type = (*out_dtype)->type;
+ /* Broadcast the one element from the sequence to all the outputs */
+ if (slen == 1) {
+ PyObject *o = PySequence_Fast_GET_ITEM(seq, 0);
+ npy_intp alen = PyArray_DIM(a, dim);
- check_it = (type != NPY_CHARLTR);
- stop_at_string = (type_num != NPY_STRING) ||
- (type == NPY_STRINGLTR);
- stop_at_tuple = (type_num == NPY_VOID &&
- ((*out_dtype)->names || (*out_dtype)->subarray));
+ for (i = 0; i < alen; i++) {
+ if ((PyArray_NDIM(a) - dim) > 1) {
+ PyArrayObject * tmp =
+ (PyArrayObject *)array_item_asarray(dst, i);
+ if (tmp == NULL) {
+ goto fail;
+ }
- *out_ndim = NPY_MAXDIMS;
- discovered_t is_object = DISCOVERED_OK;
- if (discover_dimensions(
- op, out_ndim, out_dims, check_it,
- stop_at_string, stop_at_tuple, &is_object) < 0) {
- Py_DECREF(*out_dtype);
- if (PyErr_Occurred()) {
- return -1;
- }
- *out_dtype = PyArray_DescrFromType(NPY_OBJECT);
- if (*out_dtype == NULL) {
- return -1;
- }
- *out_ndim = 0;
- *out_arr = NULL;
- return 0;
- }
- /* If object arrays are forced */
- if (is_object != DISCOVERED_OK) {
- static PyObject *visibleDeprecationWarning = NULL;
- npy_cache_import(
- "numpy", "VisibleDeprecationWarning",
- &visibleDeprecationWarning);
- if (visibleDeprecationWarning == NULL) {
- return -1;
+ res = setArrayFromSequence(a, o, dim+1, tmp);
+ Py_DECREF(tmp);
}
- if (is_object == DISCOVERED_RAGGED && requested_dtype == NULL) {
- /* NumPy 1.19, 2019-11-01 */
- if (PyErr_WarnEx(visibleDeprecationWarning, "Creating an "
- "ndarray from ragged nested sequences (which is a "
- "list-or-tuple of lists-or-tuples-or ndarrays with "
- "different lengths or shapes) is deprecated. If you "
- "meant to do this, you must specify 'dtype=object' "
- "when creating the ndarray", 1) < 0)
- {
- return -1;
- }
+ else {
+ char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
+ res = PyArray_SETITEM(dst, b, o);
}
- /* either DISCOVERED_OBJECT or there is a requested_dtype */
- Py_DECREF(*out_dtype);
- *out_dtype = PyArray_DescrFromType(NPY_OBJECT);
- if (*out_dtype == NULL) {
- return -1;
+ if (res < 0) {
+ goto fail;
}
}
-
- if ((*out_dtype)->type == NPY_CHARLTR && (*out_ndim) > 0 &&
- out_dims[(*out_ndim) - 1] == 1) {
- (*out_ndim) -= 1;
- }
-
- /* If the type is flexible, determine its size */
- if (PyDataType_ISUNSIZED(*out_dtype) &&
- PyTypeNum_ISEXTENDED((*out_dtype)->type_num)) {
- int itemsize = 0;
- int string_type = 0;
- if ((*out_dtype)->type_num == NPY_STRING ||
- (*out_dtype)->type_num == NPY_UNICODE) {
- string_type = (*out_dtype)->type_num;
- }
- if (discover_itemsize(op, *out_ndim, &itemsize, string_type) < 0) {
- Py_DECREF(*out_dtype);
- if (PyErr_Occurred() &&
- PyErr_GivenExceptionMatches(PyErr_Occurred(),
- PyExc_MemoryError)) {
- return -1;
+ }
+ /* Copy element by element */
+ else {
+ for (i = 0; i < slen; i++) {
+ PyObject * o = PySequence_Fast_GET_ITEM(seq, i);
+ if ((PyArray_NDIM(a) - dim) > 1) {
+ PyArrayObject * tmp =
+ (PyArrayObject *)array_item_asarray(dst, i);
+ if (tmp == NULL) {
+ goto fail;
}
- /* Say it's an OBJECT scalar if there's an error */
- PyErr_Clear();
- *out_dtype = PyArray_DescrFromType(NPY_OBJECT);
- *out_ndim = 0;
- *out_arr = NULL;
- return 0;
+
+ res = setArrayFromSequence(a, o, dim+1, tmp);
+ Py_DECREF(tmp);
}
- if ((*out_dtype)->type_num == NPY_UNICODE) {
- itemsize *= 4;
+ else {
+ char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
+ res = PyArray_SETITEM(dst, b, o);
}
-
- if (itemsize != (*out_dtype)->elsize) {
- PyArray_DESCR_REPLACE(*out_dtype);
- (*out_dtype)->elsize = itemsize;
+ if (res < 0) {
+ goto fail;
}
}
-
- *out_arr = NULL;
- return 0;
}
- /* Anything can be viewed as an object, unless it needs to be writeable */
- if (!writeable) {
- *out_dtype = PyArray_DescrFromType(NPY_OBJECT);
- if (*out_dtype == NULL) {
- return -1;
- }
- *out_ndim = 0;
- *out_arr = NULL;
- return 0;
- }
+ Py_DECREF(seq);
+ Py_DECREF(s);
+ return 0;
- PyErr_SetString(PyExc_RuntimeError,
- "object cannot be viewed as a writeable numpy array");
- return -1;
+ fail:
+ Py_XDECREF(seq);
+ Py_DECREF(s);
+ return res;
}
-/*NUMPY_API*/
-NPY_NO_EXPORT int
-PyArray_GetArrayParamsFromObject(PyObject *op,
- PyArray_Descr *requested_dtype,
- npy_bool writeable,
- PyArray_Descr **out_dtype,
- int *out_ndim, npy_intp *out_dims,
- PyArrayObject **out_arr, PyObject *context)
-{
- /* NumPy 1.19, 2020-01-24 */
- if (DEPRECATE(
- "PyArray_GetArrayParamsFromObject() C-API function is deprecated "
- "and expected to be removed rapidly. If you are using it (i.e. see "
- "this warning/error), please notify the NumPy developers. "
- "As of now it is expected that any use case is served similarly "
- "well by `PyArray_FromAny()` and this function is unused outside "
- "of NumPy itself.") < 0) {
- return -1;
- }
-
- if (context != NULL) {
- PyErr_SetString(PyExc_RuntimeError, "'context' must be NULL");
- return -1;
- }
-
- return PyArray_GetArrayParamsFromObject_int(op,
- requested_dtype, writeable, out_dtype, out_ndim, out_dims,
- out_arr);
-}
-
/*NUMPY_API
* Does not check for NPY_ARRAY_ENSURECOPY and NPY_ARRAY_NOTSWAPPED in flags
*/
PyArrayObject *arr = NULL, *ret;
PyArray_Descr *dtype = NULL;
+ coercion_cache_obj *cache = NULL;
int ndim = 0;
npy_intp dims[NPY_MAXDIMS];
return NULL;
}
- /* Get either the array or its parameters if it isn't an array */
- if (PyArray_GetArrayParamsFromObject_int(op,
- newtype, 0, &dtype, &ndim, dims, &arr) < 0) {
+ PyArray_Descr *fixed_descriptor;
+ PyArray_DTypeMeta *fixed_DType;
+ if (PyArray_ExtractDTypeAndDescriptor((PyObject *)newtype,
+ &fixed_descriptor, &fixed_DType) < 0) {
Py_XDECREF(newtype);
return NULL;
}
+ Py_XDECREF(newtype);
- /* If the requested dtype is flexible, adapt it */
- if (newtype != NULL) {
- newtype = PyArray_AdaptFlexibleDType((arr == NULL) ? op : (PyObject *)arr,
- (dtype == NULL) ? PyArray_DESCR(arr) : dtype,
- newtype);
- if (newtype == NULL) {
- return NULL;
- }
+ ndim = PyArray_DiscoverDTypeAndShape(op,
+ NPY_MAXDIMS, dims, &cache, fixed_DType, fixed_descriptor, &dtype);
+
+ Py_XDECREF(fixed_descriptor);
+ Py_XDECREF(fixed_DType);
+ if (ndim < 0) {
+ return NULL;
}
- /* If we got dimensions and dtype instead of an array */
- if (arr == NULL) {
- if ((flags & NPY_ARRAY_WRITEBACKIFCOPY) ||
- (flags & NPY_ARRAY_UPDATEIFCOPY)) {
- Py_DECREF(dtype);
- Py_XDECREF(newtype);
- PyErr_SetString(PyExc_TypeError,
- "WRITEBACKIFCOPY used for non-array input.");
- return NULL;
- }
- else if (min_depth != 0 && ndim < min_depth) {
- Py_DECREF(dtype);
- Py_XDECREF(newtype);
- PyErr_SetString(PyExc_ValueError,
- "object of too small depth for desired array");
- ret = NULL;
- }
- else if (max_depth != 0 && ndim > max_depth) {
- Py_DECREF(dtype);
- Py_XDECREF(newtype);
- PyErr_SetString(PyExc_ValueError,
- "object too deep for desired array");
- ret = NULL;
- }
- else if (ndim == 0 && PyArray_IsScalar(op, Generic)) {
- ret = (PyArrayObject *)PyArray_FromScalar(op, newtype);
- Py_DECREF(dtype);
- }
- else {
- if (newtype == NULL) {
- newtype = dtype;
- }
- else {
- /*
- * TODO: would be nice to do this too, but it's
- * a behavior change. It's also a bit tricky
- * for downcasting to small integer and float
- * types, and might be better to modify
- * PyArray_AssignFromSequence and descr->f->setitem
- * to have a 'casting' parameter and
- * to check each value with scalar rules like
- * in PyArray_MinScalarType.
- */
- /*
- if (!(flags&NPY_ARRAY_FORCECAST) && ndim > 0 &&
- !PyArray_CanCastTo(dtype, newtype)) {
- Py_DECREF(dtype);
- Py_XDECREF(newtype);
- PyErr_SetString(PyExc_TypeError,
- "object cannot be safely cast to array "
- "of required type");
- return NULL;
+ if (NPY_UNLIKELY(fixed_descriptor != NULL && PyDataType_HASSUBARRAY(dtype))) {
+ /*
+ * When a subarray dtype was passed in, its dimensions are appended
+ * to the array dimension (causing a dimension mismatch).
+ * There is a problem with that, because if we coerce from non-arrays
+ * we do this correctly by element (as defined by tuples), but for
+ * arrays we first append the dimensions and then assign to the base
+ * dtype and then assign which causes the problem.
+ *
+ * Thus, we check if there is an array included, in that case we
+ * give a FutureWarning.
+ * When the warning is removed, PyArray_Pack will have to ensure
+ * that that it does not append the dimensions when creating the
+ * subarrays to assign `arr[0] = obj[0]`.
+ */
+ int includes_array = 0;
+ if (cache != NULL) {
+ /* This is not ideal, but it is a pretty special case */
+ coercion_cache_obj *next = cache;
+ while (next != NULL) {
+ if (!next->sequence) {
+ includes_array = 1;
+ break;
}
- */
- Py_DECREF(dtype);
+ next = next->next;
}
+ }
+ if (includes_array) {
+ npy_free_coercion_cache(cache);
- /* Create an array and copy the data */
- ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, newtype,
- ndim, dims,
- NULL, NULL,
- flags&NPY_ARRAY_F_CONTIGUOUS, NULL);
+ ret = (PyArrayObject *) PyArray_NewFromDescr(
+ &PyArray_Type, dtype, ndim, dims, NULL, NULL,
+ flags & NPY_ARRAY_F_CONTIGUOUS, NULL);
if (ret == NULL) {
return NULL;
}
-
- if (ndim > 0) {
- if (PyArray_AssignFromSequence(ret, op) < 0) {
- Py_DECREF(ret);
- ret = NULL;
- }
+ assert(PyArray_NDIM(ret) != ndim);
+
+ /* NumPy 1.20, 2020-10-01 */
+ if (DEPRECATE_FUTUREWARNING(
+ "creating an array with a subarray dtype will behave "
+ "differently when the `np.array()` (or `asarray`, etc.) "
+ "call includes an array or array object.\n"
+ "If you are converting a single array or a list of arrays,"
+ "you can opt-in to the future behaviour using:\n"
+ " np.array(arr, dtype=np.dtype(['f', dtype]))['f']\n"
+ " np.array([arr1, arr2], dtype=np.dtype(['f', dtype]))['f']\n"
+ "\n"
+ "By including a new field and indexing it after the "
+ "conversion.\n"
+ "This may lead to a different result or to current failures "
+ "succeeding. (FutureWarning since NumPy 1.20)") < 0) {
+ Py_DECREF(ret);
+ return NULL;
}
- else {
- if (PyArray_SETITEM(ret, PyArray_DATA(ret), op) < 0) {
- Py_DECREF(ret);
- ret = NULL;
- }
+
+ if (setArrayFromSequence(ret, op, 0, NULL) < 0) {
+ Py_DECREF(ret);
+ return NULL;
}
+ return (PyObject *)ret;
}
}
- else {
- if (min_depth != 0 && PyArray_NDIM(arr) < min_depth) {
- PyErr_SetString(PyExc_ValueError,
- "object of too small depth for desired array");
- Py_DECREF(arr);
- Py_XDECREF(newtype);
- ret = NULL;
- }
- else if (max_depth != 0 && PyArray_NDIM(arr) > max_depth) {
- PyErr_SetString(PyExc_ValueError,
- "object too deep for desired array");
- Py_DECREF(arr);
- Py_XDECREF(newtype);
- ret = NULL;
- }
- else {
- ret = (PyArrayObject *)PyArray_FromArray(arr, newtype, flags);
- Py_DECREF(arr);
+
+ if (dtype == NULL) {
+ dtype = PyArray_DescrFromType(NPY_DEFAULT_TYPE);
+ }
+
+ if (min_depth != 0 && ndim < min_depth) {
+ PyErr_SetString(PyExc_ValueError,
+ "object of too small depth for desired array");
+ Py_DECREF(dtype);
+ npy_free_coercion_cache(cache);
+ return NULL;
+ }
+ if (max_depth != 0 && ndim > max_depth) {
+ PyErr_SetString(PyExc_ValueError,
+ "object too deep for desired array");
+ Py_DECREF(dtype);
+ npy_free_coercion_cache(cache);
+ return NULL;
+ }
+
+ /* Got the correct parameters, but the cache may already hold the result */
+ if (cache != NULL && !(cache->sequence)) {
+ /*
+ * There is only a single array-like and it was converted, it
+ * may still have the incorrect type, but that is handled below.
+ */
+ assert(cache->converted_obj == op);
+ arr = (PyArrayObject *)(cache->arr_or_sequence);
+ /* we may need to cast or assert flags (e.g. copy) */
+ PyObject *res = PyArray_FromArray(arr, dtype, flags);
+ npy_unlink_coercion_cache(cache);
+ return res;
+ }
+ else if (cache == NULL && PyArray_IsScalar(op, Void) &&
+ !(((PyVoidScalarObject *)op)->flags & NPY_ARRAY_OWNDATA) &&
+ newtype == NULL) {
+ /*
+ * Special case, we return a *view* into void scalars, mainly to
+ * allow things similar to the "reversed" assignment:
+ * arr[indx]["field"] = val # instead of arr["field"][indx] = val
+ *
+ * It is unclear that this is necessary in this particular code path.
+ * Note that this path is only activated when the user did _not_
+ * provide a dtype (newtype is NULL).
+ */
+ assert(ndim == 0);
+
+ return PyArray_NewFromDescrAndBase(
+ &PyArray_Type, dtype,
+ 0, NULL, NULL,
+ ((PyVoidScalarObject *)op)->obval,
+ ((PyVoidScalarObject *)op)->flags,
+ NULL, op);
+ }
+ else if (cache == 0 && newtype != NULL &&
+ PyDataType_ISSIGNED(newtype) && PyArray_IsScalar(op, Generic)) {
+ assert(ndim == 0);
+ /*
+ * This is an (possible) inconsistency where:
+ *
+ * np.array(np.float64(np.nan), dtype=np.int64)
+ *
+ * behaves differently from:
+ *
+ * np.array([np.float64(np.nan)], dtype=np.int64)
+ * arr1d_int64[0] = np.float64(np.nan)
+ * np.array(np.array(np.nan), dtype=np.int64)
+ *
+ * by not raising an error instead of using typical casting.
+ * The error is desirable, but to always error seems like a
+ * larger change to be considered at some other time and it is
+ * undesirable that 0-D arrays behave differently from scalars.
+ * This retains the behaviour, largely due to issues in pandas
+ * which relied on a try/except (although hopefully that will
+ * have a better solution at some point):
+ * https://github.com/pandas-dev/pandas/issues/35481
+ */
+ return PyArray_FromScalar(op, dtype);
+ }
+
+ /* There was no array (or array-like) passed in directly. */
+ if ((flags & NPY_ARRAY_WRITEBACKIFCOPY) ||
+ (flags & NPY_ARRAY_UPDATEIFCOPY)) {
+ PyErr_SetString(PyExc_TypeError,
+ "WRITEBACKIFCOPY used for non-array input.");
+ Py_DECREF(dtype);
+ npy_free_coercion_cache(cache);
+ return NULL;
+ }
+
+ /* Create a new array and copy the data */
+ Py_INCREF(dtype); /* hold on in case of a subarray that is replaced */
+ ret = (PyArrayObject *)PyArray_NewFromDescr(
+ &PyArray_Type, dtype, ndim, dims, NULL, NULL,
+ flags&NPY_ARRAY_F_CONTIGUOUS, NULL);
+ if (ret == NULL) {
+ npy_free_coercion_cache(cache);
+ Py_DECREF(dtype);
+ return NULL;
+ }
+ if (ndim == PyArray_NDIM(ret)) {
+ /*
+ * Appending of dimensions did not occur, so use the actual dtype
+ * below. This is relevant for S0 or U0 which can be replaced with
+ * S1 or U1, although that should likely change.
+ */
+ Py_SETREF(dtype, PyArray_DESCR(ret));
+ Py_INCREF(dtype);
+ }
+
+ if (cache == NULL) {
+ /* This is a single item. Set it directly. */
+ assert(ndim == 0);
+
+ if (PyArray_Pack(dtype, PyArray_BYTES(ret), op) < 0) {
+ Py_DECREF(dtype);
+ Py_DECREF(ret);
+ return NULL;
}
+ Py_DECREF(dtype);
+ return (PyObject *)ret;
}
+ assert(ndim != 0);
+ assert(op == cache->converted_obj);
+
+ /* Decrease the number of dimensions to the detected ones */
+ int out_ndim = PyArray_NDIM(ret);
+ PyArray_Descr *out_descr = PyArray_DESCR(ret);
+ ((PyArrayObject_fields *)ret)->nd = ndim;
+ ((PyArrayObject_fields *)ret)->descr = dtype;
+ int success = PyArray_AssignFromCache(ret, cache);
+
+ ((PyArrayObject_fields *)ret)->nd = out_ndim;
+ ((PyArrayObject_fields *)ret)->descr = out_descr;
+ Py_DECREF(dtype);
+ if (success < 0) {
+ Py_DECREF(ret);
+ return NULL;
+ }
return (PyObject *)ret;
}
return obj;
}
+
/*NUMPY_API
* steals reference to newtype --- acc. NULL
*/
PyArray_FromStructInterface(PyObject *input)
{
PyArray_Descr *thetype = NULL;
- char buf[40];
PyArrayInterface *inter;
PyObject *attr;
- PyArrayObject *ret;
char endian = NPY_NATBYTE;
attr = PyArray_LookupSpecial_OnInstance(input, "__array_struct__");
return Py_NotImplemented;
}
}
- if (!NpyCapsule_Check(attr)) {
+ if (!PyCapsule_CheckExact(attr)) {
+ if (PyType_Check(input) && PyObject_HasAttrString(attr, "__get__")) {
+ /*
+ * If the input is a class `attr` should be a property-like object.
+ * This cannot be interpreted as an array, but is a valid.
+ * (Needed due to the lookup being on the instance rather than type)
+ */
+ Py_DECREF(attr);
+ return Py_NotImplemented;
+ }
+ goto fail;
+ }
+ inter = PyCapsule_GetPointer(attr, NULL);
+ if (inter == NULL) {
goto fail;
}
- inter = NpyCapsule_AsVoidPtr(attr);
if (inter->two != 2) {
goto fail;
}
}
if (thetype == NULL) {
- PyOS_snprintf(buf, sizeof(buf),
- "%c%c%d", endian, inter->typekind, inter->itemsize);
- if (!(thetype=_array_typedescr_fromstr(buf))) {
+ PyObject *type_str = PyUnicode_FromFormat(
+ "%c%c%d", endian, inter->typekind, inter->itemsize);
+ if (type_str == NULL) {
+ Py_DECREF(attr);
+ return NULL;
+ }
+ int ok = PyArray_DescrConverter(type_str, &thetype);
+ Py_DECREF(type_str);
+ if (ok != NPY_SUCCEED) {
Py_DECREF(attr);
return NULL;
}
}
- ret = (PyArrayObject *)PyArray_NewFromDescrAndBase(
+ PyObject *ret = PyArray_NewFromDescrAndBase(
&PyArray_Type, thetype,
inter->nd, inter->shape, inter->strides, inter->data,
inter->flags, NULL, input);
Py_DECREF(attr);
- return (PyObject *)ret;
+ return ret;
fail:
PyErr_SetString(PyExc_ValueError, "invalid __array_struct__");
*/
NPY_NO_EXPORT int
_is_default_descr(PyObject *descr, PyObject *typestr) {
- PyObject *tuple, *name, *typestr2;
- PyObject *tmp = NULL;
- int ret = 0;
-
if (!PyList_Check(descr) || PyList_GET_SIZE(descr) != 1) {
return 0;
}
- tuple = PyList_GET_ITEM(descr, 0);
+ PyObject *tuple = PyList_GET_ITEM(descr, 0);
if (!(PyTuple_Check(tuple) && PyTuple_GET_SIZE(tuple) == 2)) {
return 0;
}
- name = PyTuple_GET_ITEM(tuple, 0);
+ PyObject *name = PyTuple_GET_ITEM(tuple, 0);
if (!(PyUnicode_Check(name) && PyUnicode_GetLength(name) == 0)) {
return 0;
}
- typestr2 = PyTuple_GET_ITEM(tuple, 1);
- /* Allow unicode type strings */
- if (PyUnicode_Check(typestr2)) {
- tmp = PyUnicode_AsASCIIString(typestr2);
- if (tmp == NULL) {
- return 0;
- }
- typestr2 = tmp;
- }
- if (PyBytes_Check(typestr2) &&
- PyObject_RichCompareBool(typestr, typestr2, Py_EQ)) {
- ret = 1;
- }
- Py_XDECREF(tmp);
-
- return ret;
+ PyObject *typestr2 = PyTuple_GET_ITEM(tuple, 1);
+ return PyObject_RichCompareBool(typestr, typestr2, Py_EQ);
}
-#define PyIntOrLong_Check(obj) (PyInt_Check(obj) || PyLong_Check(obj))
-
/*NUMPY_API*/
NPY_NO_EXPORT PyObject *
PyArray_FromInterface(PyObject *origin)
PyArray_Descr *dtype = NULL;
char *data = NULL;
Py_buffer view;
- int res, i, n;
+ int i, n;
npy_intp dims[NPY_MAXDIMS], strides[NPY_MAXDIMS];
int dataflags = NPY_ARRAY_BEHAVED;
- iface = PyArray_LookupSpecial_OnInstance(origin,
- "__array_interface__");
+ iface = PyArray_LookupSpecial_OnInstance(origin, "__array_interface__");
+
if (iface == NULL) {
if (PyErr_Occurred()) {
- /*
- * Clear all but clearly fatal errors (previously cleared all).
- * 1.20+ does not clear any errors here.
- */
if (PyErr_ExceptionMatches(PyExc_RecursionError) ||
PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ /* RecursionError and MemoryError are considered fatal */
return NULL;
}
+ /*
+ * This probably be deprecated, but at least shapely raised
+ * a NotImplementedError expecting it to be cleared (gh-17965)
+ */
+ PyErr_Clear();
}
return Py_NotImplemented;
}
if (!PyDict_Check(iface)) {
+ if (PyType_Check(origin) && PyObject_HasAttrString(iface, "__get__")) {
+ /*
+ * If the input is a class `iface` should be a property-like object.
+ * This cannot be interpreted as an array, but is a valid.
+ * (Needed due to the lookup being on the instance rather than type)
+ */
+ Py_DECREF(iface);
+ return Py_NotImplemented;
+ }
+
Py_DECREF(iface);
PyErr_SetString(PyExc_ValueError,
"Invalid __array_interface__ value, must be a dict");
return NULL;
}
- /* Allow unicode type strings */
- if (PyUnicode_Check(attr)) {
- PyObject *tmp = PyUnicode_AsASCIIString(attr);
- if (tmp == NULL) {
- goto fail;
- }
- attr = tmp;
- }
- else {
- Py_INCREF(attr);
- }
-
- if (!PyBytes_Check(attr)) {
+ /* allow bytes for backwards compatibility */
+ if (!PyBytes_Check(attr) && !PyUnicode_Check(attr)) {
PyErr_SetString(PyExc_TypeError,
"__array_interface__ typestr must be a string");
goto fail;
}
+
/* Get dtype from type string */
- dtype = _array_typedescr_fromstr(PyString_AS_STRING(attr));
- if (dtype == NULL) {
+ if (PyArray_DescrConverter(attr, &dtype) != NPY_SUCCEED) {
goto fail;
}
goto fail;
}
PyArray_Descr *new_dtype = NULL;
+ if (descr != NULL) {
+ int is_default = _is_default_descr(descr, attr);
+ if (is_default < 0) {
+ goto fail;
+ }
+ if (!is_default) {
+ if (PyArray_DescrConverter2(descr, &new_dtype) != NPY_SUCCEED) {
+ goto fail;
+ }
+ if (new_dtype != NULL) {
+ Py_DECREF(dtype);
+ dtype = new_dtype;
+ }
+ }
- if (descr != NULL && !_is_default_descr(descr, attr) &&
- PyArray_DescrConverter2(descr, &new_dtype) == NPY_SUCCEED &&
- new_dtype != NULL) {
- Py_DECREF(dtype);
- dtype = new_dtype;
}
- }
- Py_DECREF(attr); /* Pairs with the unicode handling above */
+ }
/* Get shape tuple from interface specification */
attr = _PyDict_GetItemStringWithError(iface, "shape");
goto fail;
}
dataptr = PyTuple_GET_ITEM(attr, 0);
- if (PyString_Check(dataptr)) {
- res = sscanf(PyString_AsString(dataptr),
- "%p", (void **)&data);
- if (res < 1) {
- PyErr_SetString(PyExc_TypeError,
- "__array_interface__ data string cannot be converted");
+ if (PyLong_Check(dataptr)) {
+ data = PyLong_AsVoidPtr(dataptr);
+ if (data == NULL && PyErr_Occurred()) {
goto fail;
}
}
- else if (PyIntOrLong_Check(dataptr)) {
- data = PyLong_AsVoidPtr(dataptr);
- }
else {
PyErr_SetString(PyExc_TypeError,
"first element of __array_interface__ data tuple "
- "must be integer or string.");
+ "must be an integer.");
goto fail;
}
if (PyObject_IsTrue(PyTuple_GET_ITEM(attr,1))) {
* sticks around after the release.
*/
PyBuffer_Release(&view);
- _dealloc_cached_buffer_info(base);
/* Get offset number from interface specification */
attr = _PyDict_GetItemStringWithError(iface, "offset");
array_meth = PyArray_LookupSpecial_OnInstance(op, "__array__");
if (array_meth == NULL) {
if (PyErr_Occurred()) {
- /*
- * Clear all but clearly fatal errors (previously cleared all).
- * 1.20+ does not clear any errors here.
- */
if (PyErr_ExceptionMatches(PyExc_RecursionError) ||
- PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ /* RecursionError and MemoryError are considered fatal */
return NULL;
}
+ /* This probably be deprecated. */
PyErr_Clear();
}
return Py_NotImplemented;
}
+ if (PyType_Check(op) && PyObject_HasAttrString(array_meth, "__get__")) {
+ /*
+ * If the input is a class `array_meth` may be a property-like object.
+ * This cannot be interpreted as an array (called), but is a valid.
+ * Trying `array_meth.__call__()` on this should not be useful.
+ * (Needed due to the lookup being on the instance rather than type)
+ */
+ Py_DECREF(array_meth);
+ return Py_NotImplemented;
+ }
if (typecode == NULL) {
new = PyObject_CallFunction(array_meth, NULL);
}
return PyArray_EnsureArray(op);
}
-/* TODO: Put the order parameter in PyArray_CopyAnyInto and remove this */
+/*
+ * Private implementation of PyArray_CopyAnyInto with an additional order
+ * parameter.
+ */
NPY_NO_EXPORT int
PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src, NPY_ORDER order)
{
src_count = *src_countptr;
dst_data = dst_dataptr[0];
src_data = src_dataptr[0];
+ int res = 0;
for(;;) {
/* Transfer the biggest amount that fits both */
count = (src_count < dst_count) ? src_count : dst_count;
- stransfer(dst_data, dst_stride,
- src_data, src_stride,
- count, src_itemsize, transferdata);
+ if (stransfer(
+ dst_data, dst_stride, src_data, src_stride,
+ count, src_itemsize, transferdata) < 0) {
+ res = -1;
+ break;
+ }
/* If we exhausted the dst block, refresh it */
if (dst_count == count) {
- if (!dst_iternext(dst_iter)) {
+ res = dst_iternext(dst_iter);
+ if (!res) {
break;
}
dst_count = *dst_countptr;
/* If we exhausted the src block, refresh it */
if (src_count == count) {
- if (!src_iternext(src_iter)) {
+ res = src_iternext(src_iter);
+ if (!res) {
break;
}
src_count = *src_countptr;
NPY_AUXDATA_FREE(transferdata);
NpyIter_Deallocate(dst_iter);
NpyIter_Deallocate(src_iter);
-
- return PyErr_Occurred() ? -1 : 0;
+ if (res > 0) {
+ /* The iteration stopped successfully, do not report an error */
+ return 0;
+ }
+ return res;
}
/*NUMPY_API
return -1;
}
- zero = PyInt_FromLong(0);
+ zero = PyLong_FromLong(0);
if (!zero) {
Py_DECREF(*next);
*next = NULL;
Py_INCREF(dtype);
}
if (!step || step == Py_None) {
- step = PyInt_FromLong(1);
+ step = PyLong_FromLong(1);
}
else {
Py_XINCREF(step);
}
if (!stop || stop == Py_None) {
stop = start;
- start = PyInt_FromLong(0);
+ start = PyLong_FromLong(0);
}
else {
Py_INCREF(start);
npy_intp i;
char *dptr, *clean_sep, *tmp;
int err = 0;
- int stop_reading_flag; /* -1 indicates end reached; -2 a parsing error */
+ int stop_reading_flag = 0; /* -1 means end reached; -2 a parsing error */
npy_intp thisbuf = 0;
npy_intp size;
npy_intp bytes, totalbytes;
* sticks around after the release.
*/
PyBuffer_Release(&view);
- _dealloc_cached_buffer_info(buf);
if ((offset < 0) || (offset > ts)) {
PyErr_Format(PyExc_ValueError,
PyTypeObject *, int nd, npy_intp const *,
int, npy_intp const*, void *, int, int, PyObject *);
-NPY_NO_EXPORT int
-PyArray_GetArrayParamsFromObject_int(PyObject *op,
- PyArray_Descr *requested_dtype,
- npy_bool writeable,
- PyArray_Descr **out_dtype,
- int *out_ndim, npy_intp *out_dims,
- PyArrayObject **out_arr);
+NPY_NO_EXPORT PyObject *
+_array_from_array_like(PyObject *op,
+ PyArray_Descr *requested_dtype, npy_bool writeable, PyObject *context);
NPY_NO_EXPORT PyObject *
PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
NPY_NO_EXPORT void
byte_swap_vector(void *p, npy_intp n, int size);
-NPY_NO_EXPORT int
-PyArray_AssignFromSequence(PyArrayObject *self, PyObject *v);
-
/*
* Calls arr_of_subclass.__array_wrap__(towrap), in order to make 'towrap'
* have the same ndarray subclass as 'arr_of_subclass'.
#include "_datetime.h"
#include "datetime_strings.h"
#include "convert_datatype.h"
+#include "array_method.h"
+#include "dtypemeta.h"
+#include "usertypes.h"
/*
* Computes the python `ret, d = divmod(d, unit)`.
return 0;
}
else {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("Cannot cast %s "
- "from metadata ", object_type);
- errmsg = append_metastr_to_string(src_meta, 0, errmsg);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- errmsg = append_metastr_to_string(dst_meta, 0, errmsg);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" according to the rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ PyObject *src = metastr_to_unicode(src_meta, 0);
+ if (src == NULL) {
+ return -1;
+ }
+ PyObject *dst = metastr_to_unicode(dst_meta, 0);
+ if (dst == NULL) {
+ Py_DECREF(src);
+ return -1;
+ }
+ PyErr_Format(PyExc_TypeError,
+ "Cannot cast %s from metadata %S to %S according to the rule %s",
+ object_type, src, dst, npy_casting_to_string(casting));
+ Py_DECREF(src);
+ Py_DECREF(dst);
return -1;
}
}
return 0;
}
else {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("Cannot cast %s "
- "from metadata ", object_type);
- errmsg = append_metastr_to_string(src_meta, 0, errmsg);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- errmsg = append_metastr_to_string(dst_meta, 0, errmsg);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" according to the rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ PyObject *src = metastr_to_unicode(src_meta, 0);
+ if (src == NULL) {
+ return -1;
+ }
+ PyObject *dst = metastr_to_unicode(dst_meta, 0);
+ if (dst == NULL) {
+ Py_DECREF(src);
+ return -1;
+ }
+ PyErr_Format(PyExc_TypeError,
+ "Cannot cast %s from metadata %S to %S according to the rule %s",
+ object_type, src, dst, npy_casting_to_string(casting));
+ Py_DECREF(src);
+ Py_DECREF(dst);
return -1;
}
}
return 0;
incompatible_units: {
- PyObject *errmsg;
- errmsg = PyUString_FromString("Cannot get "
- "a common metadata divisor for "
- "NumPy datetime metadata ");
- errmsg = append_metastr_to_string(meta1, 0, errmsg);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" and "));
- errmsg = append_metastr_to_string(meta2, 0, errmsg);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" because they have "
- "incompatible nonlinear base time units"));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ PyObject *umeta1 = metastr_to_unicode(meta1, 0);
+ if (umeta1 == NULL) {
+ return -1;
+ }
+ PyObject *umeta2 = metastr_to_unicode(meta2, 0);
+ if (umeta2 == NULL) {
+ Py_DECREF(umeta1);
+ return -1;
+ }
+ PyErr_Format(PyExc_TypeError,
+ "Cannot get a common metadata divisor for Numpy datatime "
+ "metadata %S and %S because they have incompatible nonlinear "
+ "base time units.", umeta1, umeta2);
+ Py_DECREF(umeta1);
+ Py_DECREF(umeta2);
return -1;
}
units_overflow: {
- PyObject *errmsg;
- errmsg = PyUString_FromString("Integer overflow "
- "getting a common metadata divisor for "
- "NumPy datetime metadata ");
- errmsg = append_metastr_to_string(meta1, 0, errmsg);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" and "));
- errmsg = append_metastr_to_string(meta2, 0, errmsg);
- PyErr_SetObject(PyExc_OverflowError, errmsg);
- Py_DECREF(errmsg);
+ PyObject *umeta1 = metastr_to_unicode(meta1, 0);
+ if (umeta1 == NULL) {
+ return -1;
+ }
+ PyObject *umeta2 = metastr_to_unicode(meta2, 0);
+ if (umeta2 == NULL) {
+ Py_DECREF(umeta1);
+ return -1;
+ }
+ PyErr_Format(PyExc_OverflowError,
+ "Integer overflow getting a common metadata divisor for "
+ "NumPy datetime metadata %S and %S.", umeta1, umeta2);
+ Py_DECREF(umeta1);
+ Py_DECREF(umeta2);
return -1;
}
}
return NPY_FR_as;
}
}
+ else if (len == 3 && !strncmp(str, "\xce\xbcs", 3)) {
+ /* greek small letter mu, utf8-encoded */
+ return NPY_FR_us;
+ }
else if (len == 7 && !strncmp(str, "generic", 7)) {
return NPY_FR_GENERIC;
}
}
PyTuple_SET_ITEM(dt_tuple, 0,
- PyUString_FromString(_datetime_strings[meta->base]));
+ PyUnicode_FromString(_datetime_strings[meta->base]));
PyTuple_SET_ITEM(dt_tuple, 1,
- PyInt_FromLong(meta->num));
+ PyLong_FromLong(meta->num));
return dt_tuple;
}
PyArray_DatetimeMetaData *out_meta,
npy_bool from_pickle)
{
- char *basestr = NULL;
- Py_ssize_t len = 0, tuple_size;
int den = 1;
- PyObject *unit_str = NULL;
if (!PyTuple_Check(tuple)) {
- PyObject *errmsg;
- errmsg = PyUString_FromString("Require tuple for tuple to NumPy "
- "datetime metadata conversion, not ");
- PyUString_ConcatAndDel(&errmsg, PyObject_Repr(tuple));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ PyErr_Format(PyExc_TypeError,
+ "Require tuple for tuple to NumPy "
+ "datetime metadata conversion, not %R", tuple);
return -1;
}
- tuple_size = PyTuple_GET_SIZE(tuple);
+ Py_ssize_t tuple_size = PyTuple_GET_SIZE(tuple);
if (tuple_size < 2 || tuple_size > 4) {
PyErr_SetString(PyExc_TypeError,
"Require tuple of size 2 to 4 for "
return -1;
}
- unit_str = PyTuple_GET_ITEM(tuple, 0);
- Py_INCREF(unit_str);
- if (PyUnicode_Check(unit_str)) {
- /* Allow unicode format strings: convert to bytes */
- PyObject *tmp = PyUnicode_AsASCIIString(unit_str);
- Py_DECREF(unit_str);
+ PyObject *unit_str = PyTuple_GET_ITEM(tuple, 0);
+ if (PyBytes_Check(unit_str)) {
+ /* Allow bytes format strings: convert to unicode */
+ PyObject *tmp = PyUnicode_FromEncodedObject(unit_str, NULL, NULL);
if (tmp == NULL) {
return -1;
}
unit_str = tmp;
}
- if (PyBytes_AsStringAndSize(unit_str, &basestr, &len) < 0) {
+ else {
+ Py_INCREF(unit_str);
+ }
+
+ Py_ssize_t len;
+ char const *basestr = PyUnicode_AsUTF8AndSize(unit_str, &len);
+ if (basestr == NULL) {
Py_DECREF(unit_str);
return -1;
}
Py_DECREF(unit_str);
/* Convert the values to longs */
- out_meta->num = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1));
+ out_meta->num = PyLong_AsLong(PyTuple_GET_ITEM(tuple, 1));
if (error_converting(out_meta->num)) {
return -1;
}
if (from_pickle) {
/* if (event == 1) */
PyObject *one = PyLong_FromLong(1);
- int equal_one;
if (one == NULL) {
return -1;
}
- equal_one = PyObject_RichCompareBool(event, one, Py_EQ);
+ int equal_one = PyObject_RichCompareBool(event, one, Py_EQ);
Py_DECREF(one);
if (equal_one == -1) {
return -1;
return -1;
}
}
- den = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 2));
+ den = PyLong_AsLong(PyTuple_GET_ITEM(tuple, 2));
if (error_converting(den)) {
return -1;
}
convert_pyobject_to_datetime_metadata(PyObject *obj,
PyArray_DatetimeMetaData *out_meta)
{
- PyObject *ascii = NULL;
- char *str = NULL;
- Py_ssize_t len = 0;
-
if (PyTuple_Check(obj)) {
return convert_datetime_metadata_tuple_to_datetime_metadata(
obj, out_meta, NPY_FALSE);
}
- /* Get an ASCII string */
- if (PyUnicode_Check(obj)) {
- /* Allow unicode format strings: convert to bytes */
- ascii = PyUnicode_AsASCIIString(obj);
- if (ascii == NULL) {
+ /* Get a UTF8 string */
+ PyObject *utf8 = NULL;
+ if (PyBytes_Check(obj)) {
+ /* Allow bytes format strings: convert to unicode */
+ utf8 = PyUnicode_FromEncodedObject(obj, NULL, NULL);
+ if (utf8 == NULL) {
return -1;
}
}
- else if (PyBytes_Check(obj)) {
- ascii = obj;
- Py_INCREF(ascii);
+ else if (PyUnicode_Check(obj)) {
+ utf8 = obj;
+ Py_INCREF(utf8);
}
else {
PyErr_SetString(PyExc_TypeError,
return -1;
}
- if (PyBytes_AsStringAndSize(ascii, &str, &len) < 0) {
- Py_DECREF(ascii);
+ Py_ssize_t len = 0;
+ char const *str = PyUnicode_AsUTF8AndSize(utf8, &len);
+ if (str == NULL) {
+ Py_DECREF(utf8);
return -1;
}
if (len > 0 && str[0] == '[') {
int r = parse_datetime_metadata_from_metastr(str, len, out_meta);
- Py_DECREF(ascii);
+ Py_DECREF(utf8);
return r;
}
else {
if (parse_datetime_extended_unit_from_string(str, len,
NULL, out_meta) < 0) {
- Py_DECREF(ascii);
+ Py_DECREF(utf8);
return -1;
}
- Py_DECREF(ascii);
+ Py_DECREF(utf8);
return 0;
}
}
/*
- * 'ret' is a PyUString containing the datetime string, and this
- * function appends the metadata string to it.
+ * Return the datetime metadata as a Unicode object.
+ *
+ * Returns new reference, NULL on error.
*
* If 'skip_brackets' is true, skips the '[]'.
*
- * This function steals the reference 'ret'
*/
NPY_NO_EXPORT PyObject *
-append_metastr_to_string(PyArray_DatetimeMetaData *meta,
- int skip_brackets,
- PyObject *ret)
+metastr_to_unicode(PyArray_DatetimeMetaData *meta, int skip_brackets)
{
- PyObject *res;
int num;
char const *basestr;
- if (ret == NULL) {
- return NULL;
- }
-
if (meta->base == NPY_FR_GENERIC) {
/* Without brackets, give a string "generic" */
if (skip_brackets) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString("generic"));
- return ret;
+ return PyUnicode_FromString("generic");
}
- /* But with brackets, append nothing */
+ /* But with brackets, return nothing */
else {
- return ret;
+ return PyUnicode_FromString("");
}
}
if (num == 1) {
if (skip_brackets) {
- res = PyUString_FromFormat("%s", basestr);
+ return PyUnicode_FromFormat("%s", basestr);
}
else {
- res = PyUString_FromFormat("[%s]", basestr);
+ return PyUnicode_FromFormat("[%s]", basestr);
}
}
else {
if (skip_brackets) {
- res = PyUString_FromFormat("%d%s", num, basestr);
+ return PyUnicode_FromFormat("%d%s", num, basestr);
}
else {
- res = PyUString_FromFormat("[%d%s]", num, basestr);
+ return PyUnicode_FromFormat("[%d%s]", num, basestr);
}
}
-
- PyUString_ConcatAndDel(&ret, res);
- return ret;
}
+
/*
* Adjusts a datetimestruct based on a seconds offset. Assumes
* the current values are valid.
if (tmp == NULL) {
return -1;
}
- out->year = PyInt_AsLong(tmp);
+ out->year = PyLong_AsLong(tmp);
if (error_converting(out->year)) {
Py_DECREF(tmp);
return -1;
if (tmp == NULL) {
return -1;
}
- out->month = PyInt_AsLong(tmp);
+ out->month = PyLong_AsLong(tmp);
if (error_converting(out->month)) {
Py_DECREF(tmp);
return -1;
if (tmp == NULL) {
return -1;
}
- out->day = PyInt_AsLong(tmp);
+ out->day = PyLong_AsLong(tmp);
if (error_converting(out->day)) {
Py_DECREF(tmp);
return -1;
if (tmp == NULL) {
return -1;
}
- out->hour = PyInt_AsLong(tmp);
+ out->hour = PyLong_AsLong(tmp);
if (error_converting(out->hour)) {
Py_DECREF(tmp);
return -1;
if (tmp == NULL) {
return -1;
}
- out->min = PyInt_AsLong(tmp);
+ out->min = PyLong_AsLong(tmp);
if (error_converting(out->min)) {
Py_DECREF(tmp);
return -1;
if (tmp == NULL) {
return -1;
}
- out->sec = PyInt_AsLong(tmp);
+ out->sec = PyLong_AsLong(tmp);
if (error_converting(out->sec)) {
Py_DECREF(tmp);
return -1;
if (tmp == NULL) {
return -1;
}
- out->us = PyInt_AsLong(tmp);
+ out->us = PyLong_AsLong(tmp);
if (error_converting(out->us)) {
Py_DECREF(tmp);
return -1;
NPY_CASTING casting, npy_datetime *out)
{
if (PyBytes_Check(obj) || PyUnicode_Check(obj)) {
- PyObject *bytes = NULL;
- char *str = NULL;
- Py_ssize_t len = 0;
- npy_datetimestruct dts;
- NPY_DATETIMEUNIT bestunit = NPY_FR_ERROR;
+ PyObject *utf8 = NULL;
- /* Convert to an ASCII string for the date parser */
- if (PyUnicode_Check(obj)) {
- bytes = PyUnicode_AsASCIIString(obj);
- if (bytes == NULL) {
+ /* Convert to an UTF8 string for the date parser */
+ if (PyBytes_Check(obj)) {
+ utf8 = PyUnicode_FromEncodedObject(obj, NULL, NULL);
+ if (utf8 == NULL) {
return -1;
}
}
else {
- bytes = obj;
- Py_INCREF(bytes);
+ utf8 = obj;
+ Py_INCREF(utf8);
}
- if (PyBytes_AsStringAndSize(bytes, &str, &len) < 0) {
- Py_DECREF(bytes);
+
+ Py_ssize_t len = 0;
+ char const *str = PyUnicode_AsUTF8AndSize(utf8, &len);
+ if (str == NULL) {
+ Py_DECREF(utf8);
return -1;
}
/* Parse the ISO date */
+ npy_datetimestruct dts;
+ NPY_DATETIMEUNIT bestunit = NPY_FR_ERROR;
if (parse_iso_8601_datetime(str, len, meta->base, casting,
&dts, &bestunit, NULL) < 0) {
- Py_DECREF(bytes);
+ Py_DECREF(utf8);
return -1;
}
}
if (convert_datetimestruct_to_datetime(meta, &dts, out) < 0) {
- Py_DECREF(bytes);
+ Py_DECREF(utf8);
return -1;
}
- Py_DECREF(bytes);
+ Py_DECREF(utf8);
return 0;
}
/* Do no conversion on raw integers */
- else if (PyInt_Check(obj) || PyLong_Check(obj)) {
+ else if (PyLong_Check(obj)) {
/* Don't allow conversion from an integer without specifying a unit */
if (meta->base == NPY_FR_ERROR || meta->base == NPY_FR_GENERIC) {
PyErr_SetString(PyExc_ValueError, "Converting an integer to a "
NPY_CASTING casting, npy_timedelta *out)
{
if (PyBytes_Check(obj) || PyUnicode_Check(obj)) {
- PyObject *bytes = NULL;
- char *str = NULL;
- Py_ssize_t len = 0;
+ PyObject *utf8 = NULL;
int succeeded = 0;
- /* Convert to an ASCII string for the date parser */
- if (PyUnicode_Check(obj)) {
- bytes = PyUnicode_AsASCIIString(obj);
- if (bytes == NULL) {
+ /* Convert to an UTF8 string for the date parser */
+ if (PyBytes_Check(obj)) {
+ utf8 = PyUnicode_FromEncodedObject(obj, NULL, NULL);
+ if (utf8 == NULL) {
return -1;
}
}
else {
- bytes = obj;
- Py_INCREF(bytes);
+ utf8 = obj;
+ Py_INCREF(utf8);
}
- if (PyBytes_AsStringAndSize(bytes, &str, &len) < 0) {
- Py_DECREF(bytes);
+
+ Py_ssize_t len = 0;
+ char const *str = PyUnicode_AsUTF8AndSize(utf8, &len);
+ if (str == NULL) {
+ Py_DECREF(utf8);
return -1;
}
succeeded = 1;
}
}
- Py_DECREF(bytes);
+ Py_DECREF(utf8);
if (succeeded) {
/* Use generic units if none was specified */
}
}
/* Do no conversion on raw integers */
- else if (PyInt_Check(obj) || PyLong_Check(obj)) {
+ else if (PyLong_Check(obj)) {
/* Use the default unit if none was specified */
if (meta->base == NPY_FR_ERROR) {
meta->base = NPY_DATETIME_DEFAULTUNIT;
if (tmp == NULL) {
return -1;
}
- seconds = PyInt_AsLong(tmp);
+ seconds = PyLong_AsLong(tmp);
if (error_converting(seconds)) {
Py_DECREF(tmp);
return -1;
if (tmp == NULL) {
return -1;
}
- useconds = PyInt_AsLong(tmp);
+ useconds = PyLong_AsLong(tmp);
if (error_converting(useconds)) {
Py_DECREF(tmp);
return -1;
type_nums[2] = NPY_TIMEDELTA;
}
else {
- if (PyInt_Check(objs[1]) ||
- PyLong_Check(objs[1]) ||
+ if (PyLong_Check(objs[1]) ||
PyArray_IsScalar(objs[1], Integer) ||
is_any_numpy_timedelta(objs[1])) {
type_nums[1] = NPY_TIMEDELTA;
*
* Returns 0 on success, -1 on failure.
*/
-static int
+NPY_NO_EXPORT int
find_string_array_datetime64_type(PyArrayObject *arr,
PyArray_DatetimeMetaData *meta)
{
* Returns 0 on success, -1 on failure.
*/
static int
-recursive_find_object_datetime64_type(PyObject *obj,
- PyArray_DatetimeMetaData *meta)
+find_object_datetime64_meta(PyObject *obj, PyArray_DatetimeMetaData *meta)
{
- /* Array -> use its metadata */
- if (PyArray_Check(obj)) {
- PyArrayObject *arr = (PyArrayObject *)obj;
- PyArray_Descr *arr_dtype = PyArray_DESCR(arr);
-
- if (arr_dtype->type_num == NPY_STRING ||
- arr_dtype->type_num == NPY_UNICODE) {
- return find_string_array_datetime64_type(arr, meta);
- }
- /* If the array has metadata, use it */
- else if (arr_dtype->type_num == NPY_DATETIME ||
- arr_dtype->type_num == NPY_TIMEDELTA) {
- PyArray_DatetimeMetaData *tmp_meta;
-
- /* Get the metadata from the type */
- tmp_meta = get_datetime_metadata_from_dtype(arr_dtype);
- if (tmp_meta == NULL) {
- return -1;
- }
-
- /* Combine it with 'meta' */
- if (compute_datetime_metadata_greatest_common_divisor(meta,
- tmp_meta, meta, 0, 0) < 0) {
- return -1;
- }
-
- return 0;
- }
- /* If it's not an object array, stop looking */
- else if (arr_dtype->type_num != NPY_OBJECT) {
- return 0;
- }
- }
- /* Datetime scalar -> use its metadata */
- else if (PyArray_IsScalar(obj, Datetime)) {
+ if (PyArray_IsScalar(obj, Datetime)) {
PyDatetimeScalarObject *dts = (PyDatetimeScalarObject *)obj;
/* Combine it with 'meta' */
return 0;
}
-
- /* Now check if what we have left is a sequence for recursion */
- if (PySequence_Check(obj)) {
- Py_ssize_t i, len = PySequence_Size(obj);
- if (len < 0 && PyErr_Occurred()) {
- return -1;
- }
-
- for (i = 0; i < len; ++i) {
- int ret;
- PyObject *f = PySequence_GetItem(obj, i);
- if (f == NULL) {
- return -1;
- }
- if (Npy_EnterRecursiveCall(" in recursive_find_object_datetime64_type") != 0) {
- Py_DECREF(f);
- return -1;
- }
- ret = recursive_find_object_datetime64_type(f, meta);
- Py_LeaveRecursiveCall();
- Py_DECREF(f);
- if (ret < 0) {
- return ret;
- }
- }
-
- return 0;
- }
/* Otherwise ignore it */
else {
return 0;
* Returns 0 on success, -1 on failure.
*/
static int
-recursive_find_object_timedelta64_type(PyObject *obj,
- PyArray_DatetimeMetaData *meta)
+find_object_timedelta64_meta(PyObject *obj, PyArray_DatetimeMetaData *meta)
{
- /* Array -> use its metadata */
- if (PyArray_Check(obj)) {
- PyArrayObject *arr = (PyArrayObject *)obj;
- PyArray_Descr *arr_dtype = PyArray_DESCR(arr);
-
- /* If the array has metadata, use it */
- if (arr_dtype->type_num == NPY_DATETIME ||
- arr_dtype->type_num == NPY_TIMEDELTA) {
- PyArray_DatetimeMetaData *tmp_meta;
-
- /* Get the metadata from the type */
- tmp_meta = get_datetime_metadata_from_dtype(arr_dtype);
- if (tmp_meta == NULL) {
- return -1;
- }
-
- /* Combine it with 'meta' */
- if (compute_datetime_metadata_greatest_common_divisor(meta,
- tmp_meta, meta, 0, 0) < 0) {
- return -1;
- }
-
- return 0;
- }
- /* If it's not an object array, stop looking */
- else if (arr_dtype->type_num != NPY_OBJECT) {
- return 0;
- }
- else {
- if (PyArray_NDIM(arr) == 0) {
- /*
- * special handling of 0 dimensional NumPy object
- * arrays, which may be indexed to retrieve their
- * single object using [()], but not by using
- * __getitem__(integer) approaches
- */
- PyObject *item, *args;
-
- args = PyTuple_New(0);
- if (args == NULL) {
- return 0;
- }
- item = PyObject_GetItem(obj, args);
- Py_DECREF(args);
- if (item == NULL) {
- return 0;
- }
- /*
- * NOTE: may need other type checks here in the future
- * for expanded 0 D datetime array conversions?
- */
- if (PyDelta_Check(item)) {
- Py_DECREF(item);
- return delta_checker(meta);
- }
- Py_DECREF(item);
- }
- }
- }
/* Datetime scalar -> use its metadata */
- else if (PyArray_IsScalar(obj, Timedelta)) {
+ if (PyArray_IsScalar(obj, Timedelta)) {
PyTimedeltaScalarObject *dts = (PyTimedeltaScalarObject *)obj;
/* Combine it with 'meta' */
else if (PyDelta_Check(obj)) {
return delta_checker(meta);
}
-
- /* Now check if what we have left is a sequence for recursion */
- if (PySequence_Check(obj)) {
- Py_ssize_t i, len = PySequence_Size(obj);
- if (len < 0 && PyErr_Occurred()) {
- return -1;
- }
-
- for (i = 0; i < len; ++i) {
- int ret;
- PyObject *f = PySequence_GetItem(obj, i);
- if (f == NULL) {
- return -1;
- }
- if (Npy_EnterRecursiveCall(" in recursive_find_object_timedelta64_type") != 0) {
- Py_DECREF(f);
- return -1;
- }
- ret = recursive_find_object_timedelta64_type(f, meta);
- Py_LeaveRecursiveCall();
- Py_DECREF(f);
- if (ret < 0) {
- return ret;
- }
- }
-
- return 0;
- }
/* Otherwise ignore it */
else {
return 0;
meta.num = 1;
if (type_num == NPY_DATETIME) {
- if (recursive_find_object_datetime64_type(obj, &meta) < 0) {
+ if (find_object_datetime64_meta(obj, &meta) < 0) {
return NULL;
}
else {
}
}
else if (type_num == NPY_TIMEDELTA) {
- if (recursive_find_object_timedelta64_type(obj, &meta) < 0) {
+ if (find_object_timedelta64_meta(obj, &meta) < 0) {
return NULL;
}
else {
return NULL;
}
}
+
+
+
+
+/*
+ * Describes casting within datetimes or timedelta
+ */
+static NPY_CASTING
+time_to_time_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ /* This is a within-dtype cast, which currently must handle byteswapping */
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+ if (given_descrs[1] == NULL) {
+ loop_descrs[1] = ensure_dtype_nbo(given_descrs[0]);
+ }
+ else {
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+
+ int is_timedelta = given_descrs[0]->type_num == NPY_TIMEDELTA;
+
+ if (given_descrs[0] == given_descrs[1]) {
+ return NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
+ }
+
+ NPY_CASTING byteorder_may_allow_view = 0;
+ if (PyDataType_ISNOTSWAPPED(loop_descrs[0]) ==
+ PyDataType_ISNOTSWAPPED(loop_descrs[1])) {
+ byteorder_may_allow_view = _NPY_CAST_IS_VIEW;
+ }
+ PyArray_DatetimeMetaData *meta1, *meta2;
+ meta1 = get_datetime_metadata_from_dtype(loop_descrs[0]);
+ assert(meta1 != NULL);
+ meta2 = get_datetime_metadata_from_dtype(loop_descrs[1]);
+ assert(meta2 != NULL);
+
+ if (meta1->base == meta2->base && meta1->num == meta2->num) {
+ if (byteorder_may_allow_view) {
+ return NPY_NO_CASTING | byteorder_may_allow_view;
+ }
+ return NPY_EQUIV_CASTING;
+ }
+ else if (meta1->base == NPY_FR_GENERIC) {
+ return NPY_SAFE_CASTING | byteorder_may_allow_view;
+ }
+ else if (meta2->base == NPY_FR_GENERIC) {
+ /* TODO: This is actually an invalid cast (casting will error) */
+ return NPY_UNSAFE_CASTING;
+ }
+ else if (is_timedelta && (
+ /* jump between time units and date units is unsafe for timedelta */
+ (meta1->base <= NPY_FR_M && meta2->base > NPY_FR_M) ||
+ (meta1->base > NPY_FR_M && meta2->base <= NPY_FR_M))) {
+ return NPY_UNSAFE_CASTING;
+ }
+ else if (meta1->base <= meta2->base) {
+ /* Casting to a more precise unit is currently considered safe */
+ if (datetime_metadata_divides(meta1, meta2, is_timedelta)) {
+ /* If it divides, we consider it to be a safe cast */
+ return NPY_SAFE_CASTING;
+ }
+ else {
+ return NPY_SAME_KIND_CASTING;
+ }
+ }
+ return NPY_SAME_KIND_CASTING;
+}
+
+
+/* Handles datetime<->timedelta type resolution (both directions) */
+static NPY_CASTING
+datetime_to_timedelta_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ loop_descrs[0] = ensure_dtype_nbo(given_descrs[0]);
+ if (loop_descrs[0] == NULL) {
+ return -1;
+ }
+ if (given_descrs[1] == NULL) {
+ PyArray_DatetimeMetaData *meta = get_datetime_metadata_from_dtype(given_descrs[0]);
+ assert(meta != NULL);
+ loop_descrs[1] = create_datetime_dtype(dtypes[1]->type_num, meta);
+ }
+ else {
+ loop_descrs[1] = ensure_dtype_nbo(given_descrs[1]);
+ }
+ if (loop_descrs[1] == NULL) {
+ Py_DECREF(loop_descrs[0]);
+ return -1;
+ }
+ /*
+ * Mostly NPY_UNSAFE_CASTING is not true, the cast will fail.
+ * TODO: Once ufuncs use dtype specific promotion rules,
+ * this is likely unnecessary
+ */
+ return NPY_UNSAFE_CASTING;
+}
+
+
+/* In the current setup both strings and unicode casts support all outputs */
+static NPY_CASTING
+time_to_string_resolve_descriptors(
+ PyArrayMethodObject *self,
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr **given_descrs,
+ PyArray_Descr **loop_descrs)
+{
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+ if (given_descrs[1] != NULL) {
+ /*
+ * At the time of writing, NumPy does not check the length here,
+ * but will error if filling fails.
+ */
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+ else {
+ /* Find the correct string length, possibly based on the unit */
+ int size;
+ if (given_descrs[0]->type_num == NPY_DATETIME) {
+ PyArray_DatetimeMetaData *meta = get_datetime_metadata_from_dtype(given_descrs[0]);
+ assert(meta != NULL);
+ size = get_datetime_iso_8601_strlen(0, meta->base);
+ }
+ else {
+ size = 21;
+ }
+ if (dtypes[1]->type_num == NPY_UNICODE) {
+ size *= 4;
+ }
+ loop_descrs[1] = PyArray_DescrNewFromType(dtypes[1]->type_num);
+ if (loop_descrs[1] == NULL) {
+ Py_DECREF(loop_descrs[0]);
+ return -1;
+ }
+ loop_descrs[1]->elsize = size;
+ }
+ assert(self->casting == NPY_UNSAFE_CASTING);
+ return NPY_UNSAFE_CASTING;
+}
+
+
+static NPY_CASTING
+string_to_datetime_cast_resolve_descriptors(
+ PyArrayMethodObject *NPY_UNUSED(self),
+ PyArray_DTypeMeta *dtypes[2],
+ PyArray_Descr *given_descrs[2],
+ PyArray_Descr *loop_descrs[2])
+{
+ /* We currently support byte-swapping, so any (unicode) string is OK */
+ Py_INCREF(given_descrs[0]);
+ loop_descrs[0] = given_descrs[0];
+
+ if (given_descrs[1] == NULL) {
+ /* NOTE: This doesn't actually work, and will error during the cast */
+ loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]);
+ if (loop_descrs[1] == NULL) {
+ Py_DECREF(loop_descrs[0]);
+ return -1;
+ }
+ }
+ else {
+ Py_INCREF(given_descrs[1]);
+ loop_descrs[1] = given_descrs[1];
+ }
+
+ return NPY_UNSAFE_CASTING;
+}
+
+
+/*
+ * This registers the castingimpl for all datetime related casts.
+ */
+NPY_NO_EXPORT int
+PyArray_InitializeDatetimeCasts()
+{
+ int result = -1;
+
+ PyType_Slot slots[3];
+ PyArray_DTypeMeta *dtypes[2];
+ PyArrayMethod_Spec spec = {
+ .name = "datetime_casts",
+ .nin = 1,
+ .nout = 1,
+ .casting = NPY_NO_CASTING,
+ .flags = NPY_METH_SUPPORTS_UNALIGNED,
+ .slots = slots,
+ .dtypes = dtypes,
+ };
+ slots[0].slot = NPY_METH_resolve_descriptors;
+ slots[0].pfunc = &time_to_time_resolve_descriptors;
+ slots[1].slot = NPY_METH_get_loop;
+ slots[1].pfunc = NULL;
+ slots[2].slot = 0;
+ slots[2].pfunc = NULL;
+
+ PyArray_DTypeMeta *datetime = PyArray_DTypeFromTypeNum(NPY_DATETIME);
+ PyArray_DTypeMeta *timedelta = PyArray_DTypeFromTypeNum(NPY_TIMEDELTA);
+ PyArray_DTypeMeta *string = PyArray_DTypeFromTypeNum(NPY_STRING);
+ PyArray_DTypeMeta *unicode = PyArray_DTypeFromTypeNum(NPY_UNICODE);
+ PyArray_DTypeMeta *tmp = NULL;
+
+ dtypes[0] = datetime;
+ dtypes[1] = datetime;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto fail;
+ }
+ dtypes[0] = timedelta;
+ dtypes[1] = timedelta;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto fail;
+ }
+
+ /*
+ * Casting between timedelta and datetime uses legacy casting loops, but
+ * custom dtype resolution (to handle copying of the time unit).
+ */
+ slots[0].slot = NPY_METH_resolve_descriptors;
+ slots[0].pfunc = &datetime_to_timedelta_resolve_descriptors;
+ slots[1].slot = NPY_METH_get_loop;
+ slots[1].pfunc = NULL;
+ slots[2].slot = 0;
+ slots[2].pfunc = NULL;
+
+ spec.name = "timedelta_and_datetime_cast";
+ dtypes[0] = timedelta;
+ dtypes[1] = datetime;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto fail;
+ }
+ spec.name = "datetime_to_timedelta_cast";
+ dtypes[0] = datetime;
+ dtypes[1] = timedelta;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto fail;
+ }
+
+ /*
+ * Cast from numeric types to times. These use the cast functions
+ * as stored on the datatype, which should be replaced at some point.
+ * Some of these casts can fail (casting to unitless datetime), but these
+ * are rather special.
+ */
+ for (int num = 0; num < NPY_NTYPES; num++) {
+ if (!PyTypeNum_ISNUMBER(num) && num != NPY_BOOL) {
+ continue;
+ }
+
+ Py_XSETREF(tmp, PyArray_DTypeFromTypeNum(num));
+
+ if (PyArray_AddLegacyWrapping_CastingImpl(
+ tmp, datetime, NPY_UNSAFE_CASTING) < 0) {
+ goto fail;
+ }
+ if (PyArray_AddLegacyWrapping_CastingImpl(
+ datetime, tmp, NPY_UNSAFE_CASTING) < 0) {
+ goto fail;
+ }
+
+ NPY_CASTING to_timedelta_casting = NPY_UNSAFE_CASTING;
+ if (PyTypeNum_ISINTEGER(num) || num == NPY_BOOL) {
+ /* timedelta casts like int64 right now... */
+ if (PyTypeNum_ISUNSIGNED(num) && tmp->singleton->elsize == 8) {
+ to_timedelta_casting = NPY_SAME_KIND_CASTING;
+ }
+ else {
+ to_timedelta_casting = NPY_SAFE_CASTING;
+ }
+ }
+ if (PyArray_AddLegacyWrapping_CastingImpl(
+ tmp, timedelta, to_timedelta_casting) < 0) {
+ goto fail;
+ }
+ if (PyArray_AddLegacyWrapping_CastingImpl(
+ timedelta, tmp, NPY_UNSAFE_CASTING) < 0) {
+ goto fail;
+ }
+ }
+
+ /*
+ * Cast times to string and unicode
+ */
+ spec.casting = NPY_UNSAFE_CASTING;
+ /*
+ * Casts can error and need API (unicodes needs it for string->unicode).
+ * Unicode handling is currently implemented via a legacy cast.
+ */
+ spec.flags = NPY_METH_SUPPORTS_UNALIGNED | NPY_METH_REQUIRES_PYAPI;
+
+ slots[0].slot = NPY_METH_resolve_descriptors;
+ slots[0].pfunc = &time_to_string_resolve_descriptors;
+ slots[1].slot = NPY_METH_get_loop;
+ slots[1].pfunc = NULL;
+ slots[2].slot = 0;
+ slots[2].pfunc = NULL;
+
+ for (int num = NPY_DATETIME; num <= NPY_TIMEDELTA; num++) {
+ for (int str = NPY_STRING; str <= NPY_UNICODE; str++) {
+ dtypes[0] = PyArray_DTypeFromTypeNum(num);
+ dtypes[1] = PyArray_DTypeFromTypeNum(str);
+
+ int res = PyArray_AddCastingImplementation_FromSpec(&spec, 1);
+ Py_SETREF(dtypes[0], NULL);
+ Py_SETREF(dtypes[1], NULL);
+ if (res < 0) {
+ return -1;
+ }
+ }
+ }
+
+ /*
+ * Cast strings to timedelta are currently only legacy casts
+ */
+ if (PyArray_AddLegacyWrapping_CastingImpl(
+ string, timedelta, NPY_UNSAFE_CASTING) < 0) {
+ goto fail;
+ }
+ if (PyArray_AddLegacyWrapping_CastingImpl(
+ unicode, timedelta, NPY_UNSAFE_CASTING) < 0) {
+ goto fail;
+ }
+
+ /*
+ * Cast strings to datetime
+ */
+ dtypes[1] = datetime;
+ spec.casting = NPY_UNSAFE_CASTING;
+
+ /* The default type resolution should work fine. */
+ slots[0].slot = NPY_METH_resolve_descriptors;
+ slots[0].pfunc = &string_to_datetime_cast_resolve_descriptors;
+ slots[1].slot = NPY_METH_get_loop;
+ slots[1].pfunc = NULL;
+ slots[2].slot = 0;
+ slots[2].pfunc = NULL;
+
+ dtypes[0] = string;
+ spec.flags = NPY_METH_SUPPORTS_UNALIGNED;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto fail;
+ }
+
+ dtypes[0] = unicode;
+ /*
+ * Unicode handling is currently implemented via a legacy cast, which
+ * requires the Python API.
+ */
+ spec.flags = NPY_METH_SUPPORTS_UNALIGNED | NPY_METH_REQUIRES_PYAPI;
+ if (PyArray_AddCastingImplementation_FromSpec(&spec, 1) < 0) {
+ goto fail;
+ }
+
+ result = 0;
+ fail:
+ Py_DECREF(datetime);
+ Py_DECREF(timedelta);
+ Py_DECREF(string);
+ Py_DECREF(unicode);
+ Py_XDECREF(tmp);
+ return result;
+}
+
PyArray_BusDayRollConverter(PyObject *roll_in, NPY_BUSDAY_ROLL *roll)
{
PyObject *obj = roll_in;
- char *str;
- Py_ssize_t len;
- /* Make obj into an ASCII string */
- Py_INCREF(obj);
- if (PyUnicode_Check(obj)) {
- /* accept unicode input */
- PyObject *obj_str;
- obj_str = PyUnicode_AsASCIIString(obj);
+ /* Make obj into an UTF8 string */
+ if (PyBytes_Check(obj)) {
+ /* accept bytes input */
+ PyObject *obj_str = PyUnicode_FromEncodedObject(obj, NULL, NULL);
if (obj_str == NULL) {
- Py_DECREF(obj);
return 0;
}
- Py_DECREF(obj);
obj = obj_str;
}
+ else {
+ Py_INCREF(obj);
+ }
- if (PyBytes_AsStringAndSize(obj, &str, &len) < 0) {
+ Py_ssize_t len;
+ char const *str = PyUnicode_AsUTF8AndSize(obj, &len);
+ if (str == NULL) {
Py_DECREF(obj);
return 0;
}
{
PyObject *obj = weekmask_in;
- /* Make obj into an ASCII string if it is UNICODE */
- Py_INCREF(obj);
- if (PyUnicode_Check(obj)) {
- /* accept unicode input */
- PyObject *obj_str;
- obj_str = PyUnicode_AsASCIIString(obj);
+ /* Make obj into an UTF8 string */
+ if (PyBytes_Check(obj)) {
+ /* accept bytes input */
+ PyObject *obj_str = PyUnicode_FromEncodedObject(obj, NULL, NULL);
if (obj_str == NULL) {
- Py_DECREF(obj);
return 0;
}
- Py_DECREF(obj);
obj = obj_str;
}
+ else {
+ Py_INCREF(obj);
+ }
- if (PyBytes_Check(obj)) {
- char *str;
- Py_ssize_t len;
- int i;
- if (PyBytes_AsStringAndSize(obj, &str, &len) < 0) {
+ if (PyUnicode_Check(obj)) {
+ Py_ssize_t len;
+ char const *str = PyUnicode_AsUTF8AndSize(obj, &len);
+ if (str == NULL) {
Py_DECREF(obj);
return 0;
}
/* Length 7 is a string like "1111100" */
if (len == 7) {
- for (i = 0; i < 7; ++i) {
+ for (int i = 0; i < 7; ++i) {
switch(str[i]) {
case '0':
weekmask[i] = 0;
general_weekmask_string:
/* a string like "SatSun" or "Mon Tue Wed" */
memset(weekmask, 0, 7);
- for (i = 0; i < len; i += 3) {
+ for (Py_ssize_t i = 0; i < len; i += 3) {
while (isspace(str[i]))
++i;
return 0;
}
- val = PyInt_AsLong(f);
+ val = PyLong_AsLong(f);
if (error_converting(val)) {
Py_DECREF(f);
Py_DECREF(obj);
/* Parse the input unit if provided */
if (unit_in != NULL && unit_in != Py_None) {
PyObject *strobj;
- char *str = NULL;
- Py_ssize_t len = 0;
- if (PyUnicode_Check(unit_in)) {
- strobj = PyUnicode_AsASCIIString(unit_in);
- if (strobj == NULL) {
- goto fail;
+ if (PyBytes_Check(unit_in)) {
+ /* accept bytes input */
+ PyObject *obj_str = PyUnicode_FromEncodedObject(unit_in, NULL, NULL);
+ if (obj_str == NULL) {
+ return 0;
}
+ strobj = obj_str;
}
else {
+ Py_INCREF(unit_in);
strobj = unit_in;
- Py_INCREF(strobj);
}
- if (PyBytes_AsStringAndSize(strobj, &str, &len) < 0) {
+ Py_ssize_t len;
+ char const *str = PyUnicode_AsUTF8AndSize(strobj, &len);
+ if (str == NULL) {
Py_DECREF(strobj);
goto fail;
}
/* Get the input time zone */
if (timezone_obj != NULL) {
- /* Convert to ASCII if it's unicode */
- if (PyUnicode_Check(timezone_obj)) {
- /* accept unicode input */
- PyObject *obj_str;
- obj_str = PyUnicode_AsASCIIString(timezone_obj);
+ PyObject *strobj;
+ if (PyBytes_Check(timezone_obj)) {
+ /* accept bytes input */
+ PyObject *obj_str = PyUnicode_FromEncodedObject(timezone_obj, NULL, NULL);
if (obj_str == NULL) {
goto fail;
}
- Py_DECREF(timezone_obj);
- timezone_obj = obj_str;
+ strobj = obj_str;
}
+ else {
+ Py_INCREF(timezone_obj);
+ strobj = timezone_obj;
+ }
+
+ Py_SETREF(timezone_obj, strobj);
/* Check for the supported string inputs */
- if (PyBytes_Check(timezone_obj)) {
- char *str;
+ if (PyUnicode_Check(timezone_obj)) {
Py_ssize_t len;
-
- if (PyBytes_AsStringAndSize(timezone_obj, &str, &len) < 0) {
+ char const *str = PyUnicode_AsUTF8AndSize(timezone_obj, &len);
+ if (str == NULL) {
goto fail;
}
}
for (int i=0; i < shape.len; i++) {
PyTuple_SET_ITEM(newdescr->subarray->shape, i,
- PyInt_FromLong((long)shape.ptr[i]));
+ PyLong_FromLong((long)shape.ptr[i]));
if (PyTuple_GET_ITEM(newdescr->subarray->shape, i) == NULL) {
Py_DECREF(newdescr);
}
PyObject *name = PyTuple_GET_ITEM(item, 0);
PyObject *title;
- if (PyBaseString_Check(name)) {
+ if (PyUnicode_Check(name)) {
title = NULL;
}
else if (PyTuple_Check(name)) {
}
title = PyTuple_GET_ITEM(name, 0);
name = PyTuple_GET_ITEM(name, 1);
- if (!PyBaseString_Check(name)) {
+ if (!PyUnicode_Check(name)) {
PyErr_SetString(PyExc_TypeError, "Field name must be a str");
goto fail;
}
if (PyUnicode_GetLength(name) == 0) {
Py_DECREF(name);
if (title == NULL) {
- name = PyUString_FromFormat("f%d", i);
+ name = PyUnicode_FromFormat("f%d", i);
if (name == NULL) {
goto fail;
}
}
if ((PyDict_GetItemWithError(fields, name) != NULL)
|| (title
- && PyBaseString_Check(title)
+ && PyUnicode_Check(title)
&& (PyDict_GetItemWithError(fields, title) != NULL))) {
PyErr_Format(PyExc_ValueError,
"field %R occurs more than once", name);
goto fail;
}
PyTuple_SET_ITEM(tup, 0, (PyObject *)conv);
- PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long) totalsize));
+ PyTuple_SET_ITEM(tup, 1, PyLong_FromLong((long) totalsize));
/*
* Title can be "meta-data". Only insert it
if (PyDict_SetItem(fields, name, tup) < 0) {
goto fail;
}
- if (PyBaseString_Check(title)) {
+ if (PyUnicode_Check(title)) {
PyObject *existing = PyDict_GetItemWithError(fields, title);
if (existing == NULL && PyErr_Occurred()) {
goto fail;
}
maxalign = PyArray_MAX(maxalign, _align);
}
- PyObject *size_obj = PyInt_FromLong((long) totalsize);
+ PyObject *size_obj = PyLong_FromLong((long) totalsize);
if (!size_obj) {
Py_DECREF(conv);
goto fail;
}
PyTuple_SET_ITEM(tup, 0, (PyObject *)conv);
PyTuple_SET_ITEM(tup, 1, size_obj);
- PyObject *key = PyUString_FromFormat("f%d", i);
+ PyObject *key = PyUnicode_FromFormat("f%d", i);
if (!key) {
Py_DECREF(tup);
goto fail;
new->metadata = conv->metadata;
Py_XINCREF(new->metadata);
}
- new->flags = conv->flags;
+ /*
+ * Certain flags must be inherited from the fields. This is needed
+ * only for void dtypes (or subclasses of it such as a record dtype).
+ * For other dtypes, the field part will only be used for direct field
+ * access and thus flag inheritance should not be necessary.
+ * (We only allow object fields if the dtype is object as well.)
+ * This ensures copying over of the NPY_FROM_FIELDS "inherited" flags.
+ */
+ if (new->type_num == NPY_VOID) {
+ new->flags = conv->flags;
+ }
Py_DECREF(conv);
return new;
/* Build item to insert (descr, offset, [title])*/
int len = 2;
PyObject *title = NULL;
- PyObject *ind = PyInt_FromLong(i);
+ PyObject *ind = PyLong_FromLong(i);
if (titles) {
title=PyObject_GetItem(titles, ind);
if (title && title != Py_None) {
goto fail;
}
- PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(offset));
+ PyTuple_SET_ITEM(tup, 1, PyLong_FromLong(offset));
/* Flag whether the fields are specified out of order */
if (offset < totalsize) {
has_out_of_order_fields = 1;
if (align && _align > 1) {
totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align);
}
- PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(totalsize));
+ PyTuple_SET_ITEM(tup, 1, PyLong_FromLong(totalsize));
totalsize += newdescr->elsize;
}
if (len == 3) {
Py_DECREF(tup);
goto fail;
}
- if (!PyBaseString_Check(name)) {
+ if (!PyUnicode_Check(name)) {
PyErr_SetString(PyExc_ValueError,
"field names must be strings");
Py_DECREF(tup);
goto fail;
}
if (len == 3) {
- if (PyBaseString_Check(title)) {
+ if (PyUnicode_Check(title)) {
if (PyDict_GetItemWithError(fields, title) != NULL) {
PyErr_SetString(PyExc_ValueError,
"title already used as a name or title.");
}
else if (PyTuple_Check(obj)) {
/* or a tuple */
- return _convert_from_tuple(obj, align);
+ if (Py_EnterRecursiveCall(
+ " while trying to convert the given data type from"
+ " a tuple object" ) != 0) {
+ return NULL;
+ }
+ PyArray_Descr *ret = _convert_from_tuple(obj, align);
+ Py_LeaveRecursiveCall();
+ return ret;
}
else if (PyList_Check(obj)) {
/* or a list */
- return _convert_from_array_descr(obj, align);
+ if (Py_EnterRecursiveCall(
+ " while trying to convert the given data type from"
+ " a list object" ) != 0) {
+ return NULL;
+ }
+ PyArray_Descr *ret = _convert_from_array_descr(obj, align);
+ Py_LeaveRecursiveCall();
+ return ret;
}
else if (PyDict_Check(obj) || PyDictProxy_Check(obj)) {
/* or a dictionary */
- return _convert_from_dict(obj, align);
+ if (Py_EnterRecursiveCall(
+ " while trying to convert the given data type from"
+ " a dict object" ) != 0) {
+ return NULL;
+ }
+ PyArray_Descr *ret = _convert_from_dict(obj, align);
+ Py_LeaveRecursiveCall();
+ return ret;
}
else if (PyArray_Check(obj)) {
PyErr_SetString(PyExc_TypeError, "Cannot construct a dtype from an array");
}
/* Check for a deprecated Numeric-style typecode */
- char *dep_tps[] = {"Bool", "Complex", "Float", "Int",
- "Object0", "String0", "Timedelta64",
- "Unicode0", "UInt", "Void0"};
+ /* `Uint` has deliberately weird uppercasing */
+ char *dep_tps[] = {"Bytes", "Datetime64", "Str", "Uint"};
int ndep_tps = sizeof(dep_tps) / sizeof(dep_tps[0]);
for (int i = 0; i < ndep_tps; ++i) {
char *dep_tp = dep_tps[i];
if (strncmp(type, dep_tp, strlen(dep_tp)) == 0) {
+ /* Deprecated 2020-06-09, NumPy 1.20 */
if (DEPRECATE("Numeric-style type codes are "
"deprecated and will result in "
"an error in the future.") < 0) {
NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrNew(PyArray_Descr *base)
{
- PyArray_Descr *newdescr = PyObject_New(PyArray_Descr, &PyArrayDescr_Type);
+ PyArray_Descr *newdescr = PyObject_New(PyArray_Descr, Py_TYPE(base));
if (newdescr == NULL) {
return NULL;
arraydescr_dealloc(PyArray_Descr *self)
{
if (self->fields == Py_None) {
- fprintf(stderr, "*** Reference count error detected: \n" \
- "an attempt was made to deallocate %d (%c) ***\n",
+ fprintf(stderr, "*** Reference count error detected: "
+ "an attempt was made to deallocate the dtype %d (%c) ***\n",
self->type_num, self->type);
+ assert(0);
Py_INCREF(self);
Py_INCREF(self);
return;
}
- _dealloc_cached_buffer_info((PyObject*)self);
Py_XDECREF(self->typeobj);
Py_XDECREF(self->names);
Py_XDECREF(self->fields);
size >>= 2;
}
if (self->type_num == NPY_OBJECT) {
- ret = PyUString_FromFormat("%c%c", endian, basic_);
+ ret = PyUnicode_FromFormat("%c%c", endian, basic_);
}
else {
- ret = PyUString_FromFormat("%c%c%d", endian, basic_, size);
+ ret = PyUnicode_FromFormat("%c%c%d", endian, basic_, size);
+ }
+ if (ret == NULL) {
+ return NULL;
}
+
if (PyDataType_ISDATETIME(self)) {
PyArray_DatetimeMetaData *meta;
-
meta = get_datetime_metadata_from_dtype(self);
if (meta == NULL) {
Py_DECREF(ret);
return NULL;
}
+ PyObject *umeta = metastr_to_unicode(meta, 0);
+ if (umeta == NULL) {
+ Py_DECREF(ret);
+ return NULL;
+ }
- ret = append_metastr_to_string(meta, 0, ret);
+ Py_SETREF(ret, PyUnicode_Concat(ret, umeta));
+ Py_DECREF(umeta);
}
-
return ret;
}
Py_ssize_t ndim;
if (!PyDataType_HASSUBARRAY(self)) {
- return PyInt_FromLong(0);
+ return PyLong_FromLong(0);
}
/*
* for tuple argument
*/
ndim = PyTuple_Size(self->subarray->shape);
- return PyInt_FromLong(ndim);
+ return PyLong_FromLong(ndim);
}
if (dobj == NULL) {
return NULL;
}
- PyTuple_SET_ITEM(dobj, 0, PyUString_FromString(""));
+ PyTuple_SET_ITEM(dobj, 0, PyUnicode_FromString(""));
PyTuple_SET_ITEM(dobj, 1, arraydescr_protocol_typestr_get(self));
res = PyList_New(1);
if (res == NULL) {
if (PyTypeNum_ISUSERDEF(self->type_num)) {
val = 2;
}
- return PyInt_FromLong(val);
+ return PyLong_FromLong(val);
}
static int
PyObject *item;
int valid = 1;
item = PySequence_GetItem(val, i);
- valid = PyUString_Check(item);
+ valid = PyUnicode_Check(item);
Py_DECREF(item);
if (!valid) {
PyErr_Format(PyExc_ValueError,
};
static PyObject *
-arraydescr_new(PyTypeObject *NPY_UNUSED(subtype),
+arraydescr_new(PyTypeObject *subtype,
PyObject *args, PyObject *kwds)
{
+ if (subtype != &PyArrayDescr_Type) {
+ /* The DTypeMeta class should prevent this from happening. */
+ PyErr_Format(PyExc_SystemError,
+ "'%S' must not inherit np.dtype.__new__().", subtype);
+ return NULL;
+ }
+
PyObject *odescr, *metadata=NULL;
PyArray_Descr *descr, *conv;
npy_bool align = NPY_FALSE;
return (PyObject *)conv;
}
+
/*
* Return a tuple of
* (cleaned metadata dictionary, tuple with (str, num))
PyTuple_SET_ITEM(dt_tuple, 0,
PyBytes_FromString(_datetime_strings[meta->base]));
PyTuple_SET_ITEM(dt_tuple, 1,
- PyInt_FromLong(meta->num));
+ PyLong_FromLong(meta->num));
PyTuple_SET_ITEM(dt_tuple, 2,
- PyInt_FromLong(1));
+ PyLong_FromLong(1));
PyTuple_SET_ITEM(dt_tuple, 3,
- PyInt_FromLong(1));
+ PyLong_FromLong(1));
PyTuple_SET_ITEM(ret, 1, dt_tuple);
if (self->type_num == NPY_UNICODE) {
elsize >>= 2;
}
- obj = PyUString_FromFormat("%c%d",self->kind, elsize);
+ obj = PyUnicode_FromFormat("%c%d",self->kind, elsize);
}
PyTuple_SET_ITEM(ret, 1, Py_BuildValue("(NOO)", obj, Py_False, Py_True));
if (PyDataType_ISDATETIME(self)) {
PyObject *newobj;
state = PyTuple_New(9);
- PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version));
+ PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version));
/*
* newobj is a tuple of the Python metadata dictionary
* and tuple of date_time info (str, num)
}
else if (self->metadata) {
state = PyTuple_New(9);
- PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version));
+ PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version));
Py_INCREF(self->metadata);
PyTuple_SET_ITEM(state, 8, self->metadata);
}
else { /* Use version 3 pickle format */
state = PyTuple_New(8);
- PyTuple_SET_ITEM(state, 0, PyInt_FromLong(3));
+ PyTuple_SET_ITEM(state, 0, PyLong_FromLong(3));
}
- PyTuple_SET_ITEM(state, 1, PyUString_FromFormat("%c", endian));
+ PyTuple_SET_ITEM(state, 1, PyUnicode_FromFormat("%c", endian));
PyTuple_SET_ITEM(state, 2, arraydescr_subdescr_get(self));
if (PyDataType_HASFIELDS(self)) {
Py_INCREF(self->names);
elsize = -1;
alignment = -1;
}
- PyTuple_SET_ITEM(state, 5, PyInt_FromLong(elsize));
- PyTuple_SET_ITEM(state, 6, PyInt_FromLong(alignment));
- PyTuple_SET_ITEM(state, 7, PyInt_FromLong(self->flags));
+ PyTuple_SET_ITEM(state, 5, PyLong_FromLong(elsize));
+ PyTuple_SET_ITEM(state, 6, PyLong_FromLong(alignment));
+ PyTuple_SET_ITEM(state, 7, PyLong_FromLong(self->flags));
PyTuple_SET_ITEM(ret, 2, state);
return ret;
default:
/* raise an error */
if (PyTuple_GET_SIZE(PyTuple_GET_ITEM(args,0)) > 5) {
- version = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));
+ version = PyLong_AsLong(PyTuple_GET_ITEM(args, 0));
}
else {
version = -1;
if (version == 1 || version == 0) {
if (fields != Py_None) {
PyObject *key, *list;
- key = PyInt_FromLong(-1);
+ key = PyLong_FromLong(-1);
list = PyDict_GetItemWithError(fields, key);
if (!list) {
if (!PyErr_Occurred()) {
for (i = 0; i < PyTuple_GET_SIZE(names); ++i) {
name = PyTuple_GET_ITEM(names, i);
- if (!PyUString_Check(name)) {
+ if (!PyUnicode_Check(name)) {
names_ok = 0;
break;
}
}
if (PyDataType_ISDATETIME(self) && (metadata != NULL)) {
- PyObject *old_metadata, *errmsg;
+ PyObject *old_metadata;
PyArray_DatetimeMetaData temp_dt_data;
if ((! PyTuple_Check(metadata)) || (PyTuple_Size(metadata) != 2)) {
- errmsg = PyUString_FromString("Invalid datetime dtype (metadata, c_metadata): ");
- PyUString_ConcatAndDel(&errmsg, PyObject_Repr(metadata));
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
+ PyErr_Format(PyExc_ValueError,
+ "Invalid datetime dtype (metadata, c_metadata): %R",
+ metadata);
return NULL;
}
if (NPY_TITLE_KEY(key, value)) {
continue;
}
- if (!PyUString_Check(key) || !PyTuple_Check(value) ||
+ if (!PyUnicode_Check(key) || !PyTuple_Check(value) ||
((len=PyTuple_GET_SIZE(value)) < 2)) {
continue;
}
seqlen = PyList_GET_SIZE(obj);
for (i = 0; i < seqlen; i++) {
PyObject *item = PyList_GET_ITEM(obj, i);
- if (!PyBaseString_Check(item)) {
+ if (!PyUnicode_Check(item)) {
return NPY_FALSE;
}
}
/* disallow duplicate field indices */
if (PyDict_Contains(fields, name)) {
PyObject *msg = NULL;
- PyObject *fmt = PyUString_FromString(
+ PyObject *fmt = PyUnicode_FromString(
"duplicate field of name {!r}");
if (fmt != NULL) {
msg = PyObject_CallMethod(fmt, "format", "O", name);
return NULL;
}
- if (PyBaseString_Check(op)) {
+ if (PyUnicode_Check(op)) {
return _subscript_by_name(self, op);
}
else if (_is_list_of_strings(op)) {
/****************** End of Mapping Protocol ******************************/
-NPY_NO_EXPORT PyTypeObject PyArrayDescr_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "numpy.dtype",
- .tp_basicsize = sizeof(PyArray_Descr),
- /* methods */
- .tp_dealloc = (destructor)arraydescr_dealloc,
- .tp_repr = (reprfunc)arraydescr_repr,
- .tp_as_number = &descr_as_number,
- .tp_as_sequence = &descr_as_sequence,
- .tp_as_mapping = &descr_as_mapping,
- .tp_str = (reprfunc)arraydescr_str,
- .tp_flags = Py_TPFLAGS_DEFAULT,
- .tp_richcompare = (richcmpfunc)arraydescr_richcompare,
- .tp_methods = arraydescr_methods,
- .tp_members = arraydescr_members,
- .tp_getset = arraydescr_getsets,
- .tp_new = arraydescr_new,
+
+/*
+ * NOTE: Since this is a MetaClass, the name has Full appended here, the
+ * correct name of the type is PyArrayDescr_Type.
+ */
+NPY_NO_EXPORT PyArray_DTypeMeta PyArrayDescr_TypeFull = {
+ {{
+ /* NULL represents `type`, this is set to DTypeMeta at import time */
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "numpy.dtype",
+ .tp_basicsize = sizeof(PyArray_Descr),
+ .tp_dealloc = (destructor)arraydescr_dealloc,
+ .tp_repr = (reprfunc)arraydescr_repr,
+ .tp_as_number = &descr_as_number,
+ .tp_as_sequence = &descr_as_sequence,
+ .tp_as_mapping = &descr_as_mapping,
+ .tp_str = (reprfunc)arraydescr_str,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_richcompare = (richcmpfunc)arraydescr_richcompare,
+ .tp_methods = arraydescr_methods,
+ .tp_members = arraydescr_members,
+ .tp_getset = arraydescr_getsets,
+ .tp_new = arraydescr_new,
+ },},
+ .type_num = -1,
+ .kind = '\0',
+ .abstract = 1,
+ .parametric = 0,
+ .singleton = 0,
+ .scalar_type = NULL,
};
free_dragon4_bigint_scratch(scratch);\
return NULL;\
}\
- ret = PyUString_FromString(scratch->repr);\
+ ret = PyUnicode_FromString(scratch->repr);\
free_dragon4_bigint_scratch(scratch);\
return ret;\
}\
free_dragon4_bigint_scratch(scratch);\
return NULL;\
}\
- ret = PyUString_FromString(scratch->repr);\
+ ret = PyUnicode_FromString(scratch->repr);\
free_dragon4_bigint_scratch(scratch);\
return ret;\
}\
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE
#include <numpy/arrayobject.h>
-#include <numpy/npy_cpu.h>
#include "npy_pycompat.h"
/*************************** COPY REFERENCES *******************************/
/* Moves references from src to dst */
-static void
+static int
_strided_to_strided_move_references(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
{
PyObject *src_ref = NULL, *dst_ref = NULL;
while (N > 0) {
- NPY_COPY_PYOBJECT_PTR(&src_ref, src);
- NPY_COPY_PYOBJECT_PTR(&dst_ref, dst);
+ memcpy(&src_ref, src, sizeof(src_ref));
+ memcpy(&dst_ref, dst, sizeof(dst_ref));
/* Release the reference in dst */
NPY_DT_DBG_REFTRACE("dec dst ref", dst_ref);
Py_XDECREF(dst_ref);
/* Move the reference */
NPY_DT_DBG_REFTRACE("move src ref", src_ref);
- NPY_COPY_PYOBJECT_PTR(dst, &src_ref);
+ memcpy(dst, &src_ref, sizeof(src_ref));
/* Set the source reference to NULL */
src_ref = NULL;
- NPY_COPY_PYOBJECT_PTR(src, &src_ref);
+ memcpy(src, &src_ref, sizeof(src_ref));
src += src_stride;
dst += dst_stride;
--N;
}
+ return 0;
}
/* Copies references from src to dst */
-static void
+static int
_strided_to_strided_copy_references(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
{
PyObject *src_ref = NULL, *dst_ref = NULL;
while (N > 0) {
- NPY_COPY_PYOBJECT_PTR(&src_ref, src);
- NPY_COPY_PYOBJECT_PTR(&dst_ref, dst);
+ memcpy(&src_ref, src, sizeof(src_ref));
+ memcpy(&dst_ref, dst, sizeof(dst_ref));
/* Copy the reference */
NPY_DT_DBG_REFTRACE("copy src ref", src_ref);
- NPY_COPY_PYOBJECT_PTR(dst, &src_ref);
+ memcpy(dst, &src_ref, sizeof(src_ref));
/* Claim the reference */
Py_XINCREF(src_ref);
/* Release the reference in dst */
dst += dst_stride;
--N;
}
+ return 0;
}
* Does a strided to strided zero-padded copy for the case where
* dst_itemsize > src_itemsize
*/
-static void
+static int
_strided_to_strided_zero_pad_copy(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
dst += dst_stride;
--N;
}
+ return 0;
}
/*
* Does a strided to strided zero-padded copy for the case where
* dst_itemsize < src_itemsize
*/
-static void
+static int
_strided_to_strided_truncate_copy(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
dst += dst_stride;
--N;
}
+ return 0;
}
/*
* Does a strided to strided zero-padded or truncated copy for the case where
* unicode swapping is needed.
*/
-static void
+static int
_strided_to_strided_unicode_copyswap(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
dst += dst_stride;
--N;
}
+ return 0;
}
return (NpyAuxData *)newdata;
}
-static void
+static int
_strided_to_strided_contig_align_wrap(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
*todata = d->todata,
*fromdata = d->fromdata;
char *bufferin = d->bufferin, *bufferout = d->bufferout;
- npy_bool init_dest = d->init_dest, out_needs_api = d->out_needs_api;
+ npy_bool init_dest = d->init_dest;
for(;;) {
- /*
- * The caller does not know if a previous call resulted in a Python
- * exception. Much of the Python API is unsafe while an exception is in
- * flight, so just skip all the work. Someone higher in the call stack
- * will check for errors and propagate them.
- */
- if (out_needs_api && PyErr_Occurred()) {
- return;
- }
if (N > NPY_LOWLEVEL_BUFFER_BLOCKSIZE) {
- tobuffer(bufferin, inner_src_itemsize, src, src_stride,
- NPY_LOWLEVEL_BUFFER_BLOCKSIZE,
- src_itemsize, todata);
+ if (tobuffer(
+ bufferin, inner_src_itemsize, src, src_stride,
+ NPY_LOWLEVEL_BUFFER_BLOCKSIZE, src_itemsize, todata) < 0) {
+ return -1;
+ }
if (init_dest) {
memset(bufferout, 0,
- dst_itemsize*NPY_LOWLEVEL_BUFFER_BLOCKSIZE);
+ dst_itemsize*NPY_LOWLEVEL_BUFFER_BLOCKSIZE);
+ }
+ if (wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize,
+ NPY_LOWLEVEL_BUFFER_BLOCKSIZE,
+ inner_src_itemsize, wrappeddata) < 0) {
+ return -1;
+ }
+ if (frombuffer(dst, dst_stride, bufferout, dst_itemsize,
+ NPY_LOWLEVEL_BUFFER_BLOCKSIZE,
+ dst_itemsize, fromdata) < 0) {
+ return -1;
}
- wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize,
- NPY_LOWLEVEL_BUFFER_BLOCKSIZE,
- inner_src_itemsize, wrappeddata);
- frombuffer(dst, dst_stride, bufferout, dst_itemsize,
- NPY_LOWLEVEL_BUFFER_BLOCKSIZE,
- dst_itemsize, fromdata);
N -= NPY_LOWLEVEL_BUFFER_BLOCKSIZE;
src += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*src_stride;
dst += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*dst_stride;
}
else {
- tobuffer(bufferin, inner_src_itemsize, src, src_stride, N,
- src_itemsize, todata);
+ if (tobuffer(bufferin, inner_src_itemsize, src, src_stride,
+ N, src_itemsize, todata) < 0) {
+ return -1;
+ }
if (init_dest) {
memset(bufferout, 0, dst_itemsize*N);
}
- wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize, N,
- inner_src_itemsize, wrappeddata);
- frombuffer(dst, dst_stride, bufferout, dst_itemsize, N,
- dst_itemsize, fromdata);
- return;
+ if (wrapped(bufferout, dst_itemsize, bufferin, inner_src_itemsize,
+ N, inner_src_itemsize, wrappeddata) < 0) {
+ return -1;
+ }
+ if (frombuffer(dst, dst_stride, bufferout, dst_itemsize,
+ N, dst_itemsize, fromdata) < 0) {
+ return -1;
+ }
+ return 0;
}
}
}
return (NpyAuxData *)newdata;
}
-static void
+static int
_strided_to_strided_wrap_copy_swap(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp NPY_UNUSED(src_itemsize),
{
_wrap_copy_swap_data *d = (_wrap_copy_swap_data *)data;
+ /* We assume that d->copyswapn should not be able to error. */
d->copyswapn(dst, dst_stride, src, src_stride, N, d->swap, d->arr);
+ return 0;
}
/* This only gets used for custom data types and for Unicode when swapping */
NpyAuxData base;
PyArray_VectorUnaryFunc *castfunc;
PyArrayObject *aip, *aop;
+ npy_bool needs_api;
} _strided_cast_data;
/* strided cast data free function */
return (NpyAuxData *)newdata;
}
-static void
+static int
_aligned_strided_to_strided_cast(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
_strided_cast_data *d = (_strided_cast_data *)data;
PyArray_VectorUnaryFunc *castfunc = d->castfunc;
PyArrayObject *aip = d->aip, *aop = d->aop;
+ npy_bool needs_api = d->needs_api;
while (N > 0) {
castfunc(src, dst, 1, aip, aop);
+ /*
+ * Since error handling in ufuncs is not ideal (at the time of
+ * writing this, an error could be in process before calling this
+ * function. For most of NumPy history these checks were completely
+ * missing, so this is hopefully OK for the time being (until ufuncs
+ * are fixed).
+ */
+ if (needs_api && PyErr_Occurred()) {
+ return -1;
+ }
dst += dst_stride;
src += src_stride;
--N;
}
+ return 0;
}
/* This one requires src be of type NPY_OBJECT */
-static void
+static int
_aligned_strided_to_strided_cast_decref_src(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
_strided_cast_data *d = (_strided_cast_data *)data;
PyArray_VectorUnaryFunc *castfunc = d->castfunc;
PyArrayObject *aip = d->aip, *aop = d->aop;
+ npy_bool needs_api = d->needs_api;
PyObject *src_ref;
while (N > 0) {
castfunc(src, dst, 1, aip, aop);
-
- /* After casting, decrement the source ref */
- NPY_COPY_PYOBJECT_PTR(&src_ref, src);
- NPY_DT_DBG_REFTRACE("dec src ref (cast object -> not object)", src_ref);
+ /*
+ * See comment in `_aligned_strided_to_strided_cast`, an error could
+ * in principle be set before `castfunc` is called.
+ */
+ if (needs_api && PyErr_Occurred()) {
+ return -1;
+ }
+ /* After casting, decrement the source ref and set it to NULL */
+ memcpy(&src_ref, src, sizeof(src_ref));
Py_XDECREF(src_ref);
+ memset(src, 0, sizeof(PyObject *));
+ NPY_DT_DBG_REFTRACE("dec src ref (cast object -> not object)", src_ref);
dst += dst_stride;
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_aligned_contig_to_contig_cast(char *dst, npy_intp NPY_UNUSED(dst_stride),
char *src, npy_intp NPY_UNUSED(src_stride),
npy_intp N, npy_intp NPY_UNUSED(itemsize),
NpyAuxData *data)
{
_strided_cast_data *d = (_strided_cast_data *)data;
+ npy_bool needs_api = d->needs_api;
d->castfunc(src, dst, N, d->aip, d->aop);
+ /*
+ * See comment in `_aligned_strided_to_strided_cast`, an error could
+ * in principle be set before `castfunc` is called.
+ */
+ if (needs_api && PyErr_Occurred()) {
+ return -1;
+ }
+ return 0;
}
static int
if (PyTypeNum_ISCOMPLEX(src_type_num) &&
!PyTypeNum_ISCOMPLEX(dst_type_num) &&
!PyTypeNum_ISBOOL(dst_type_num)) {
- PyObject *cls = NULL, *obj = NULL;
+ static PyObject *cls = NULL;
int ret;
- obj = PyImport_ImportModule("numpy.core");
- if (obj) {
- cls = PyObject_GetAttrString(obj, "ComplexWarning");
- Py_DECREF(obj);
+ npy_cache_import("numpy.core", "ComplexWarning", &cls);
+ if (cls == NULL) {
+ return NPY_FAIL;
}
ret = PyErr_WarnEx(cls,
"Casting complex values to real discards "
"the imaginary part", 1);
- Py_XDECREF(cls);
if (ret < 0) {
return NPY_FAIL;
}
return (NpyAuxData *)newdata;
}
-static void
+static int
_strided_to_strided_datetime_general_cast(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
if (convert_datetime_to_datetimestruct(&d->src_meta,
dt, &dts) < 0) {
- dt = NPY_DATETIME_NAT;
+ return -1;
}
else {
if (convert_datetimestruct_to_datetime(&d->dst_meta,
&dts, &dt) < 0) {
- dt = NPY_DATETIME_NAT;
+ return -1;
}
}
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_strided_to_strided_datetime_cast(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_aligned_strided_to_strided_datetime_cast(char *dst,
npy_intp dst_stride,
char *src, npy_intp src_stride,
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_strided_to_strided_datetime_to_string(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp NPY_UNUSED(src_itemsize),
if (convert_datetime_to_datetimestruct(&d->src_meta,
dt, &dts) < 0) {
- /* For an error, produce a 'NaT' string */
- dts.year = NPY_DATETIME_NAT;
+ return -1;
}
/* Initialize the destination to all zeros */
memset(dst, 0, dst_itemsize);
- /*
- * This may also raise an error, but the caller needs
- * to use PyErr_Occurred().
- */
- make_iso_8601_datetime(&dts, dst, dst_itemsize,
+ if (make_iso_8601_datetime(&dts, dst, dst_itemsize,
0, 0, d->src_meta.base, -1,
- NPY_UNSAFE_CASTING);
+ NPY_UNSAFE_CASTING) < 0) {
+ return -1;
+ }
dst += dst_stride;
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_strided_to_strided_string_to_datetime(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
if (parse_iso_8601_datetime(tmp_buffer, src_itemsize,
d->dst_meta.base, NPY_SAME_KIND_CASTING,
&dts, NULL, NULL) < 0) {
- dt = NPY_DATETIME_NAT;
+ return -1;
}
}
/* Otherwise parse the data in place */
if (parse_iso_8601_datetime(src, tmp - src,
d->dst_meta.base, NPY_SAME_KIND_CASTING,
&dts, NULL, NULL) < 0) {
- dt = NPY_DATETIME_NAT;
+ return -1;
}
}
if (dt != NPY_DATETIME_NAT &&
convert_datetimestruct_to_datetime(&d->dst_meta,
&dts, &dt) < 0) {
- dt = NPY_DATETIME_NAT;
+ return -1;
}
memcpy(dst, &dt, sizeof(dt));
src += src_stride;
--N;
}
+ return 0;
}
/*
* Assumes src_dtype and dst_dtype are both datetimes or both timedeltas
*/
-static int
+NPY_NO_EXPORT int
get_nbo_cast_datetime_transfer_function(int aligned,
- npy_intp src_stride, npy_intp dst_stride,
PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
PyArray_StridedUnaryOp **out_stransfer,
NpyAuxData **out_transferdata)
return NPY_SUCCEED;
}
-static int
-get_nbo_datetime_to_string_transfer_function(int aligned,
- npy_intp src_stride, npy_intp dst_stride,
- PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
- PyArray_StridedUnaryOp **out_stransfer,
- NpyAuxData **out_transferdata)
+NPY_NO_EXPORT int
+get_nbo_datetime_to_string_transfer_function(
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ PyArray_StridedUnaryOp **out_stransfer, NpyAuxData **out_transferdata)
{
PyArray_DatetimeMetaData *src_meta;
_strided_datetime_cast_data *data;
return NPY_SUCCEED;
}
-static int
+NPY_NO_EXPORT int
get_datetime_to_unicode_transfer_function(int aligned,
npy_intp src_stride, npy_intp dst_stride,
PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
PyArray_Descr *str_dtype;
/* Get an ASCII string data type, adapted to match the UNICODE one */
- str_dtype = PyArray_DescrFromType(NPY_STRING);
- str_dtype = PyArray_AdaptFlexibleDType(NULL, dst_dtype, str_dtype);
+ str_dtype = PyArray_DescrNewFromType(NPY_STRING);
+ str_dtype->elsize = dst_dtype->elsize / 4;
if (str_dtype == NULL) {
return NPY_FAIL;
}
}
/* Get the NBO datetime to string aligned contig function */
- if (get_nbo_datetime_to_string_transfer_function(1,
- src_dtype->elsize, str_dtype->elsize,
- src_dtype, str_dtype,
- &caststransfer, &castdata) != NPY_SUCCEED) {
+ if (get_nbo_datetime_to_string_transfer_function(
+ src_dtype, str_dtype,
+ &caststransfer, &castdata) != NPY_SUCCEED) {
Py_DECREF(str_dtype);
NPY_AUXDATA_FREE(todata);
return NPY_FAIL;
return NPY_SUCCEED;
}
-static int
-get_nbo_string_to_datetime_transfer_function(int aligned,
- npy_intp src_stride, npy_intp dst_stride,
- PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
- PyArray_StridedUnaryOp **out_stransfer,
- NpyAuxData **out_transferdata)
+NPY_NO_EXPORT int
+get_nbo_string_to_datetime_transfer_function(
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ PyArray_StridedUnaryOp **out_stransfer, NpyAuxData **out_transferdata)
{
PyArray_DatetimeMetaData *dst_meta;
_strided_datetime_cast_data *data;
return NPY_SUCCEED;
}
-static int
+NPY_NO_EXPORT int
get_unicode_to_datetime_transfer_function(int aligned,
npy_intp src_stride, npy_intp dst_stride,
PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
PyArray_Descr *str_dtype;
/* Get an ASCII string data type, adapted to match the UNICODE one */
- str_dtype = PyArray_DescrFromType(NPY_STRING);
- str_dtype = PyArray_AdaptFlexibleDType(NULL, src_dtype, str_dtype);
+ str_dtype = PyArray_DescrNewFromType(NPY_STRING);
if (str_dtype == NULL) {
return NPY_FAIL;
}
+ assert(src_dtype->type_num == NPY_UNICODE);
+ str_dtype->elsize = src_dtype->elsize / 4;
/* Get the cast operation from src */
if (PyArray_GetDTypeTransferFunction(aligned,
}
/* Get the string to NBO datetime aligned contig function */
- if (get_nbo_string_to_datetime_transfer_function(1,
- str_dtype->elsize, dst_dtype->elsize,
- str_dtype, dst_dtype,
- &caststransfer, &castdata) != NPY_SUCCEED) {
+ if (get_nbo_string_to_datetime_transfer_function(
+ str_dtype, dst_dtype,
+ &caststransfer, &castdata) != NPY_SUCCEED) {
Py_DECREF(str_dtype);
NPY_AUXDATA_FREE(todata);
return NPY_FAIL;
return NPY_SUCCEED;
}
-static int
-get_nbo_cast_transfer_function(int aligned,
- npy_intp src_stride, npy_intp dst_stride,
- PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
- int move_references,
- PyArray_StridedUnaryOp **out_stransfer,
- NpyAuxData **out_transferdata,
- int *out_needs_api,
- int *out_needs_wrap)
+
+NPY_NO_EXPORT int
+get_legacy_dtype_cast_function(
+ int aligned, npy_intp src_stride, npy_intp dst_stride,
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ int move_references,
+ PyArray_StridedUnaryOp **out_stransfer, NpyAuxData **out_transferdata,
+ int *out_needs_api, int *out_needs_wrap)
{
_strided_cast_data *data;
PyArray_VectorUnaryFunc *castfunc;
PyArray_Descr *tmp_dtype;
- npy_intp shape = 1, src_itemsize = src_dtype->elsize,
- dst_itemsize = dst_dtype->elsize;
-
- if (PyTypeNum_ISNUMBER(src_dtype->type_num) &&
- PyTypeNum_ISNUMBER(dst_dtype->type_num)) {
- *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder) ||
- !PyArray_ISNBO(dst_dtype->byteorder);
- return get_nbo_cast_numeric_transfer_function(aligned,
- src_stride, dst_stride,
- src_dtype->type_num, dst_dtype->type_num,
- out_stransfer, out_transferdata);
- }
-
- if (src_dtype->type_num == NPY_DATETIME ||
- src_dtype->type_num == NPY_TIMEDELTA ||
- dst_dtype->type_num == NPY_DATETIME ||
- dst_dtype->type_num == NPY_TIMEDELTA) {
- /* A parameterized type, datetime->datetime sometimes needs casting */
- if ((src_dtype->type_num == NPY_DATETIME &&
- dst_dtype->type_num == NPY_DATETIME) ||
- (src_dtype->type_num == NPY_TIMEDELTA &&
- dst_dtype->type_num == NPY_TIMEDELTA)) {
- *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder) ||
- !PyArray_ISNBO(dst_dtype->byteorder);
- return get_nbo_cast_datetime_transfer_function(aligned,
- src_stride, dst_stride,
- src_dtype, dst_dtype,
- out_stransfer, out_transferdata);
- }
-
- /*
- * Datetime <-> string conversions can be handled specially.
- * The functions may raise an error if the strings have no
- * space, or can't be parsed properly.
- */
- if (src_dtype->type_num == NPY_DATETIME) {
- switch (dst_dtype->type_num) {
- case NPY_STRING:
- *out_needs_api = 1;
- *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder);
- return get_nbo_datetime_to_string_transfer_function(
- aligned,
- src_stride, dst_stride,
- src_dtype, dst_dtype,
- out_stransfer, out_transferdata);
-
- case NPY_UNICODE:
- return get_datetime_to_unicode_transfer_function(
- aligned,
- src_stride, dst_stride,
- src_dtype, dst_dtype,
- out_stransfer, out_transferdata,
- out_needs_api);
- }
- }
- else if (dst_dtype->type_num == NPY_DATETIME) {
- switch (src_dtype->type_num) {
- case NPY_STRING:
- *out_needs_api = 1;
- *out_needs_wrap = !PyArray_ISNBO(dst_dtype->byteorder);
- return get_nbo_string_to_datetime_transfer_function(
- aligned,
- src_stride, dst_stride,
- src_dtype, dst_dtype,
- out_stransfer, out_transferdata);
-
- case NPY_UNICODE:
- return get_unicode_to_datetime_transfer_function(
- aligned,
- src_stride, dst_stride,
- src_dtype, dst_dtype,
- out_stransfer, out_transferdata,
- out_needs_api);
- }
- }
- }
+ npy_intp shape = 1;
+ npy_intp src_itemsize = src_dtype->elsize;
+ npy_intp dst_itemsize = dst_dtype->elsize;
*out_needs_wrap = !aligned ||
!PyArray_ISNBO(src_dtype->byteorder) ||
data->base.free = &_strided_cast_data_free;
data->base.clone = &_strided_cast_data_clone;
data->castfunc = castfunc;
+ data->needs_api = *out_needs_api;
/*
* TODO: This is a hack so the cast functions have an array.
* The cast functions shouldn't need that. Also, since we
return NPY_SUCCEED;
}
+
+static int
+get_nbo_cast_transfer_function(int aligned,
+ npy_intp src_stride, npy_intp dst_stride,
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ int move_references,
+ PyArray_StridedUnaryOp **out_stransfer,
+ NpyAuxData **out_transferdata,
+ int *out_needs_api,
+ int *out_needs_wrap)
+{
+ if (PyTypeNum_ISNUMBER(src_dtype->type_num) &&
+ PyTypeNum_ISNUMBER(dst_dtype->type_num)) {
+ *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder) ||
+ !PyArray_ISNBO(dst_dtype->byteorder);
+ return get_nbo_cast_numeric_transfer_function(aligned,
+ src_stride, dst_stride,
+ src_dtype->type_num, dst_dtype->type_num,
+ out_stransfer, out_transferdata);
+ }
+
+ if (src_dtype->type_num == NPY_DATETIME ||
+ src_dtype->type_num == NPY_TIMEDELTA ||
+ dst_dtype->type_num == NPY_DATETIME ||
+ dst_dtype->type_num == NPY_TIMEDELTA) {
+ /* A parameterized type, datetime->datetime sometimes needs casting */
+ if ((src_dtype->type_num == NPY_DATETIME &&
+ dst_dtype->type_num == NPY_DATETIME) ||
+ (src_dtype->type_num == NPY_TIMEDELTA &&
+ dst_dtype->type_num == NPY_TIMEDELTA)) {
+ *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder) ||
+ !PyArray_ISNBO(dst_dtype->byteorder);
+ return get_nbo_cast_datetime_transfer_function(aligned,
+ src_dtype, dst_dtype,
+ out_stransfer, out_transferdata);
+ }
+
+ /*
+ * Datetime <-> string conversions can be handled specially.
+ * The functions may raise an error if the strings have no
+ * space, or can't be parsed properly.
+ */
+ if (src_dtype->type_num == NPY_DATETIME) {
+ switch (dst_dtype->type_num) {
+ case NPY_STRING:
+ *out_needs_api = 1;
+ *out_needs_wrap = !PyArray_ISNBO(src_dtype->byteorder);
+ return get_nbo_datetime_to_string_transfer_function(
+ src_dtype, dst_dtype,
+ out_stransfer, out_transferdata);
+
+ case NPY_UNICODE:
+ return get_datetime_to_unicode_transfer_function(
+ aligned,
+ src_stride, dst_stride,
+ src_dtype, dst_dtype,
+ out_stransfer, out_transferdata,
+ out_needs_api);
+ }
+ }
+ else if (dst_dtype->type_num == NPY_DATETIME) {
+ switch (src_dtype->type_num) {
+ case NPY_STRING:
+ *out_needs_api = 1;
+ *out_needs_wrap = !PyArray_ISNBO(dst_dtype->byteorder);
+ return get_nbo_string_to_datetime_transfer_function(
+ src_dtype, dst_dtype,
+ out_stransfer, out_transferdata);
+
+ case NPY_UNICODE:
+ return get_unicode_to_datetime_transfer_function(
+ aligned,
+ src_stride, dst_stride,
+ src_dtype, dst_dtype,
+ out_stransfer, out_transferdata,
+ out_needs_api);
+ }
+ }
+ }
+
+ return get_legacy_dtype_cast_function(
+ aligned, src_stride, dst_stride, src_dtype, dst_dtype,
+ move_references, out_stransfer, out_transferdata,
+ out_needs_api, out_needs_wrap);
+}
+
+
+NPY_NO_EXPORT int
+wrap_aligned_contig_transfer_function_with_copyswapn(
+ int aligned, npy_intp src_stride, npy_intp dst_stride,
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ PyArray_StridedUnaryOp **out_stransfer, NpyAuxData **out_transferdata,
+ int *out_needs_api,
+ PyArray_StridedUnaryOp *caststransfer, NpyAuxData *castdata)
+{
+ NpyAuxData *todata = NULL, *fromdata = NULL;
+ PyArray_StridedUnaryOp *tobuffer = NULL, *frombuffer = NULL;
+ npy_intp src_itemsize = src_dtype->elsize;
+ npy_intp dst_itemsize = dst_dtype->elsize;
+
+ /* Get the copy/swap operation from src */
+ PyArray_GetDTypeCopySwapFn(
+ aligned, src_stride, src_itemsize, src_dtype, &tobuffer, &todata);
+
+ if (!PyDataType_REFCHK(dst_dtype)) {
+ /* Copying from buffer is a simple copy/swap operation */
+ PyArray_GetDTypeCopySwapFn(
+ aligned, dst_itemsize, dst_stride, dst_dtype,
+ &frombuffer, &fromdata);
+ }
+ else {
+ /*
+ * Since the buffer is initialized to NULL, need to move the
+ * references in order to DECREF the existing data.
+ */
+ /* Object types cannot be byte swapped */
+ assert(PyDataType_ISNOTSWAPPED(dst_dtype));
+ /* The loop already needs the python api if this is reached */
+ assert(*out_needs_api);
+
+ if (PyArray_GetDTypeTransferFunction(
+ aligned, dst_itemsize, dst_stride,
+ dst_dtype, dst_dtype, 1,
+ &frombuffer, &fromdata, out_needs_api) != NPY_SUCCEED) {
+ return NPY_FAIL;
+ }
+ }
+
+ if (frombuffer == NULL || tobuffer == NULL) {
+ NPY_AUXDATA_FREE(castdata);
+ NPY_AUXDATA_FREE(todata);
+ NPY_AUXDATA_FREE(fromdata);
+ return NPY_FAIL;
+ }
+
+ *out_stransfer = caststransfer;
+
+ /* Wrap it all up in a new transfer function + data */
+ if (wrap_aligned_contig_transfer_function(
+ src_itemsize, dst_itemsize,
+ tobuffer, todata,
+ frombuffer, fromdata,
+ caststransfer, castdata,
+ PyDataType_FLAGCHK(dst_dtype, NPY_NEEDS_INIT),
+ *out_needs_api,
+ out_stransfer, out_transferdata) != NPY_SUCCEED) {
+ NPY_AUXDATA_FREE(castdata);
+ NPY_AUXDATA_FREE(todata);
+ NPY_AUXDATA_FREE(fromdata);
+ return NPY_FAIL;
+ }
+
+ return NPY_SUCCEED;
+}
+
+
static int
get_cast_transfer_function(int aligned,
npy_intp src_stride, npy_intp dst_stride,
int *out_needs_api)
{
PyArray_StridedUnaryOp *caststransfer;
- NpyAuxData *castdata, *todata = NULL, *fromdata = NULL;
+ NpyAuxData *castdata;
int needs_wrap = 0;
- npy_intp src_itemsize = src_dtype->elsize,
- dst_itemsize = dst_dtype->elsize;
if (get_nbo_cast_transfer_function(aligned,
src_stride, dst_stride,
}
/* Otherwise, we have to copy and/or swap to aligned temporaries */
else {
- PyArray_StridedUnaryOp *tobuffer, *frombuffer;
-
- /* Get the copy/swap operation from src */
- PyArray_GetDTypeCopySwapFn(aligned,
- src_stride, src_itemsize,
- src_dtype,
- &tobuffer, &todata);
-
- if (!PyDataType_REFCHK(dst_dtype)) {
- /* Copying from buffer is a simple copy/swap operation */
- PyArray_GetDTypeCopySwapFn(aligned,
- dst_itemsize, dst_stride,
- dst_dtype,
- &frombuffer, &fromdata);
- }
- else {
- /*
- * Since the buffer is initialized to NULL, need to move the
- * references in order to DECREF the existing data.
- */
- /* Object types cannot be byte swapped */
- assert(PyDataType_ISNOTSWAPPED(dst_dtype));
- /* The loop already needs the python api if this is reached */
- assert(*out_needs_api);
-
- if (PyArray_GetDTypeTransferFunction(
- aligned, dst_itemsize, dst_stride,
- dst_dtype, dst_dtype, 1,
- &frombuffer, &fromdata, out_needs_api) != NPY_SUCCEED) {
- return NPY_FAIL;
- }
- }
-
- if (frombuffer == NULL || tobuffer == NULL) {
- NPY_AUXDATA_FREE(castdata);
- NPY_AUXDATA_FREE(todata);
- NPY_AUXDATA_FREE(fromdata);
- return NPY_FAIL;
- }
-
- *out_stransfer = caststransfer;
-
- /* Wrap it all up in a new transfer function + data */
- if (wrap_aligned_contig_transfer_function(
- src_itemsize, dst_itemsize,
- tobuffer, todata,
- frombuffer, fromdata,
- caststransfer, castdata,
- PyDataType_FLAGCHK(dst_dtype, NPY_NEEDS_INIT),
- *out_needs_api,
- out_stransfer, out_transferdata) != NPY_SUCCEED) {
- NPY_AUXDATA_FREE(castdata);
- NPY_AUXDATA_FREE(todata);
- NPY_AUXDATA_FREE(fromdata);
- return NPY_FAIL;
- }
-
- return NPY_SUCCEED;
+ return wrap_aligned_contig_transfer_function_with_copyswapn(
+ aligned, src_stride, dst_stride, src_dtype, dst_dtype,
+ out_stransfer, out_transferdata, out_needs_api,
+ caststransfer, castdata);
}
}
return (NpyAuxData *)newdata;
}
-static void
+static int
_strided_to_strided_one_to_n(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
npy_intp subN = d->N, dst_itemsize = d->dst_itemsize;
while (N > 0) {
- subtransfer(dst, dst_itemsize,
- src, 0,
- subN, src_itemsize,
- subdata);
+ if (subtransfer(
+ dst, dst_itemsize, src, 0, subN, src_itemsize, subdata) < 0) {
+ return -1;
+ }
src += src_stride;
dst += dst_stride;
--N;
}
+ return 0;
}
-static void
+static int
_strided_to_strided_one_to_n_with_finish(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
npy_intp subN = d->N, dst_itemsize = d->dst_itemsize;
while (N > 0) {
- subtransfer(dst, dst_itemsize,
- src, 0,
- subN, src_itemsize,
- subdata);
-
+ if (subtransfer(
+ dst, dst_itemsize, src, 0, subN, src_itemsize, subdata) < 0) {
+ return -1;
+ }
- stransfer_finish_src(NULL, 0,
- src, 0,
- 1, src_itemsize,
- data_finish_src);
+ if (stransfer_finish_src(
+ NULL, 0, src, 0, 1, src_itemsize, data_finish_src) < 0) {
+ return -1;
+ }
src += src_stride;
dst += dst_stride;
--N;
}
+ return 0;
}
/*
return (NpyAuxData *)newdata;
}
-static void
+static int
_strided_to_strided_n_to_n(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
dst_subitemsize = d->dst_itemsize;
while (N > 0) {
- subtransfer(dst, dst_subitemsize,
- src, src_subitemsize,
- subN, src_subitemsize,
- subdata);
-
+ if (subtransfer(
+ dst, dst_subitemsize, src, src_subitemsize,
+ subN, src_subitemsize, subdata) < 0) {
+ return -1;
+ }
src += src_stride;
dst += dst_stride;
--N;
}
+ return 0;
}
-static void
+static int
_contig_to_contig_n_to_n(char *dst, npy_intp NPY_UNUSED(dst_stride),
char *src, npy_intp NPY_UNUSED(src_stride),
npy_intp N, npy_intp NPY_UNUSED(src_itemsize),
npy_intp subN = d->N, src_subitemsize = d->src_itemsize,
dst_subitemsize = d->dst_itemsize;
- subtransfer(dst, dst_subitemsize,
- src, src_subitemsize,
- subN*N, src_subitemsize,
- subdata);
+ if (subtransfer(
+ dst, dst_subitemsize, src, src_subitemsize,
+ subN*N, src_subitemsize, subdata) < 0) {
+ return -1;
+ }
+ return 0;
}
/*
return (NpyAuxData *)newdata;
}
-static void
+static int
_strided_to_strided_subarray_broadcast(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp NPY_UNUSED(src_itemsize),
count = offsetruns[run].count;
dst_ptr = dst + loop_index*dst_subitemsize;
if (offset != -1) {
- subtransfer(dst_ptr, dst_subitemsize,
- src + offset, src_subitemsize,
- count, src_subitemsize,
- subdata);
+ if (subtransfer(
+ dst_ptr, dst_subitemsize, src + offset, src_subitemsize,
+ count, src_subitemsize, subdata) < 0) {
+ return -1;
+ }
}
else {
memset(dst_ptr, 0, count*dst_subitemsize);
dst += dst_stride;
--N;
}
+ return 0;
}
-static void
+static int
_strided_to_strided_subarray_broadcast_withrefs(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp NPY_UNUSED(src_itemsize),
count = offsetruns[run].count;
dst_ptr = dst + loop_index*dst_subitemsize;
if (offset != -1) {
- subtransfer(dst_ptr, dst_subitemsize,
- src + offset, src_subitemsize,
- count, src_subitemsize,
- subdata);
+ if (subtransfer(
+ dst_ptr, dst_subitemsize, src + offset, src_subitemsize,
+ count, src_subitemsize, subdata) < 0) {
+ return -1;
+ }
}
else {
if (stransfer_decdstref != NULL) {
- stransfer_decdstref(NULL, 0, dst_ptr, dst_subitemsize,
- count, dst_subitemsize,
- data_decdstref);
+ if (stransfer_decdstref(
+ NULL, 0, dst_ptr, dst_subitemsize,
+ count, dst_subitemsize, data_decdstref) < 0) {
+ return -1;
+ }
}
memset(dst_ptr, 0, count*dst_subitemsize);
}
}
if (stransfer_decsrcref != NULL) {
- stransfer_decsrcref(NULL, 0, src, src_subitemsize,
- src_subN, src_subitemsize,
- data_decsrcref);
+ if (stransfer_decsrcref(
+ NULL, 0, src, src_subitemsize,
+ src_subN, src_subitemsize, data_decsrcref) < 0) {
+ return -1;
+ }
}
src += src_stride;
dst += dst_stride;
--N;
}
+ return 0;
}
return (NpyAuxData *)newdata;
}
-static void
+static int
_strided_to_strided_field_transfer(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp NPY_UNUSED(src_itemsize),
field = &d->fields;
if (N > NPY_LOWLEVEL_BUFFER_BLOCKSIZE) {
for (i = 0; i < field_count; ++i, ++field) {
- field->stransfer(dst + field->dst_offset, dst_stride,
- src + field->src_offset, src_stride,
- NPY_LOWLEVEL_BUFFER_BLOCKSIZE,
- field->src_itemsize,
- field->data);
+ if (field->stransfer(
+ dst + field->dst_offset, dst_stride,
+ src + field->src_offset, src_stride,
+ NPY_LOWLEVEL_BUFFER_BLOCKSIZE,
+ field->src_itemsize, field->data) < 0) {
+ return -1;
+ }
}
N -= NPY_LOWLEVEL_BUFFER_BLOCKSIZE;
src += NPY_LOWLEVEL_BUFFER_BLOCKSIZE*src_stride;
}
else {
for (i = 0; i < field_count; ++i, ++field) {
- field->stransfer(dst + field->dst_offset, dst_stride,
- src + field->src_offset, src_stride,
- N,
- field->src_itemsize,
- field->data);
+ if (field->stransfer(
+ dst + field->dst_offset, dst_stride,
+ src + field->src_offset, src_stride,
+ N,
+ field->src_itemsize, field->data) < 0) {
+ return -1;
+ }
}
- return;
+ return 0;
}
}
}
return (NpyAuxData *)newdata;
}
-static void _strided_masked_wrapper_decsrcref_transfer_function(
+static int
+_strided_masked_wrapper_decsrcref_transfer_function(
char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_bool *mask, npy_intp mask_stride,
/* Skip masked values, still calling decsrcref for move_references */
mask = (npy_bool*)npy_memchr((char *)mask, 0, mask_stride, N,
&subloopsize, 1);
- decsrcref_stransfer(NULL, 0, src, src_stride,
- subloopsize, src_itemsize, decsrcref_transferdata);
+ if (decsrcref_stransfer(
+ NULL, 0, src, src_stride,
+ subloopsize, src_itemsize, decsrcref_transferdata) < 0) {
+ return -1;
+ }
dst += subloopsize * dst_stride;
src += subloopsize * src_stride;
N -= subloopsize;
/* Process unmasked values */
mask = (npy_bool*)npy_memchr((char *)mask, 0, mask_stride, N,
&subloopsize, 0);
- unmasked_stransfer(dst, dst_stride, src, src_stride,
- subloopsize, src_itemsize, unmasked_transferdata);
+ if (unmasked_stransfer(
+ dst, dst_stride, src, src_stride,
+ subloopsize, src_itemsize, unmasked_transferdata) < 0) {
+ return -1;
+ }
dst += subloopsize * dst_stride;
src += subloopsize * src_stride;
N -= subloopsize;
}
+ return 0;
}
-static void _strided_masked_wrapper_transfer_function(
+static int
+_strided_masked_wrapper_transfer_function(
char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_bool *mask, npy_intp mask_stride,
/* Process unmasked values */
mask = (npy_bool*)npy_memchr((char *)mask, 0, mask_stride, N,
&subloopsize, 0);
- unmasked_stransfer(dst, dst_stride, src, src_stride,
- subloopsize, src_itemsize, unmasked_transferdata);
+ if (unmasked_stransfer(
+ dst, dst_stride, src, src_stride,
+ subloopsize, src_itemsize, unmasked_transferdata) < 0) {
+ return -1;
+ }
dst += subloopsize * dst_stride;
src += subloopsize * src_stride;
N -= subloopsize;
}
+ return 0;
}
/************************* DEST BOOL SETONE *******************************/
-static void
+static int
_null_to_strided_set_bool_one(char *dst,
npy_intp dst_stride,
char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride),
dst += dst_stride;
--N;
}
+ return 0;
}
-static void
+static int
_null_to_contig_set_bool_one(char *dst,
npy_intp NPY_UNUSED(dst_stride),
char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride),
/* bool type is one byte, so can just use the char */
memset(dst, 1, N);
+ return 0;
}
/* Only for the bool type, sets the destination to 1 */
return (NpyAuxData *)newdata;
}
-static void
+static int
_null_to_strided_memset_zero(char *dst,
npy_intp dst_stride,
char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride),
dst += dst_stride;
--N;
}
+ return 0;
}
-static void
+static int
_null_to_contig_memset_zero(char *dst,
npy_intp dst_stride,
char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride),
npy_intp dst_itemsize = d->dst_itemsize;
memset(dst, 0, N*dst_itemsize);
+ return 0;
}
-static void
+static int
_null_to_strided_reference_setzero(char *dst,
npy_intp dst_stride,
char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride),
PyObject *dst_ref = NULL;
while (N > 0) {
- NPY_COPY_PYOBJECT_PTR(&dst_ref, dst);
+ memcpy(&dst_ref, dst, sizeof(dst_ref));
- /* Release the reference in dst */
+ /* Release the reference in dst and set it to NULL */
NPY_DT_DBG_REFTRACE("dec dest ref (to set zero)", dst_ref);
Py_XDECREF(dst_ref);
-
- /* Set it to zero */
- dst_ref = NULL;
- NPY_COPY_PYOBJECT_PTR(dst, &dst_ref);
+ memset(dst, 0, sizeof(PyObject *));
dst += dst_stride;
--N;
}
+ return 0;
}
NPY_NO_EXPORT int
return NPY_SUCCEED;
}
-static void
+static int
_dec_src_ref_nop(char *NPY_UNUSED(dst),
npy_intp NPY_UNUSED(dst_stride),
char *NPY_UNUSED(src), npy_intp NPY_UNUSED(src_stride),
NpyAuxData *NPY_UNUSED(data))
{
/* NOP */
+ return 0;
}
-static void
+static int
_strided_to_null_dec_src_ref_reference(char *NPY_UNUSED(dst),
npy_intp NPY_UNUSED(dst_stride),
char *src, npy_intp src_stride,
{
PyObject *src_ref = NULL;
while (N > 0) {
- NPY_COPY_PYOBJECT_PTR(&src_ref, src);
-
- /* Release the reference in src */
+ /* Release the reference in src and set it to NULL */
NPY_DT_DBG_REFTRACE("dec src ref (null dst)", src_ref);
+ memcpy(&src_ref, src, sizeof(src_ref));
Py_XDECREF(src_ref);
+ memset(src, 0, sizeof(PyObject *));
src += src_stride;
--N;
}
+ return 0;
}
out_needs_api);
}
+
+/*
+ * Basic version of PyArray_GetDTypeTransferFunction for legacy dtype
+ * support.
+ * It supports only wrapping the copyswapn functions and the legacy
+ * cast functions registered with `PyArray_RegisterCastFunc`.
+ * This function takes the easy way out: It does not wrap
+ */
+NPY_NO_EXPORT int
+PyArray_GetLegacyDTypeTransferFunction(int aligned,
+ npy_intp src_stride, npy_intp dst_stride,
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ int move_references,
+ PyArray_StridedUnaryOp **out_stransfer,
+ NpyAuxData **out_transferdata,
+ int *out_needs_api)
+{
+ /* Note: We ignore `needs_wrap`; needs-wrap is handled by another cast */
+ int needs_wrap = 0;
+
+ if (src_dtype->type_num == dst_dtype->type_num) {
+ /*
+ * This is a cast within the same dtype. For legacy user-dtypes,
+ * it is always valid to handle this using the copy swap function.
+ */
+ return wrap_copy_swap_function(aligned,
+ src_stride, dst_stride,
+ src_dtype,
+ PyArray_ISNBO(src_dtype->byteorder) !=
+ PyArray_ISNBO(dst_dtype->byteorder),
+ out_stransfer, out_transferdata);
+ }
+
+ if (get_legacy_dtype_cast_function(aligned,
+ src_stride, dst_stride,
+ src_dtype, dst_dtype,
+ move_references,
+ out_stransfer,
+ out_transferdata,
+ out_needs_api,
+ &needs_wrap) != NPY_SUCCEED) {
+ return NPY_FAIL;
+ }
+ return NPY_SUCCEED;
+}
+
+
NPY_NO_EXPORT int
PyArray_GetMaskedDTypeTransferFunction(int aligned,
npy_intp src_stride,
--- /dev/null
+/* Array Descr Object */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include "structmember.h"
+#include "assert.h"
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _MULTIARRAYMODULE
+#include <numpy/ndarraytypes.h>
+#include <numpy/arrayscalars.h>
+#include "npy_pycompat.h"
+
+#include "common.h"
+#include "dtypemeta.h"
+#include "_datetime.h"
+#include "array_coercion.h"
+#include "scalartypes.h"
+#include "convert_datatype.h"
+#include "usertypes.h"
+
+
+static void
+dtypemeta_dealloc(PyArray_DTypeMeta *self) {
+ /* Do not accidentally delete a statically defined DType: */
+ assert(((PyTypeObject *)self)->tp_flags & Py_TPFLAGS_HEAPTYPE);
+
+ Py_XDECREF(self->scalar_type);
+ Py_XDECREF(self->singleton);
+ Py_XDECREF(self->castingimpls);
+ PyType_Type.tp_dealloc((PyObject *) self);
+}
+
+static PyObject *
+dtypemeta_new(PyTypeObject *NPY_UNUSED(type),
+ PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds))
+{
+ PyErr_SetString(PyExc_TypeError,
+ "Preliminary-API: Cannot subclass DType.");
+ return NULL;
+}
+
+static int
+dtypemeta_init(PyTypeObject *NPY_UNUSED(type),
+ PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds))
+{
+ PyErr_SetString(PyExc_TypeError,
+ "Preliminary-API: Cannot __init__ DType class.");
+ return -1;
+}
+
+/**
+ * tp_is_gc slot of Python types. This is implemented only for documentation
+ * purposes to indicate and document the subtleties involved.
+ *
+ * Python Type objects are either statically created (typical C-Extension type)
+ * or HeapTypes (typically created in Python).
+ * HeapTypes have the Py_TPFLAGS_HEAPTYPE flag and are garbage collected.
+ * Our DTypeMeta instances (`np.dtype` and its subclasses) *may* be HeapTypes
+ * if the Py_TPFLAGS_HEAPTYPE flag is set (they are created from Python).
+ * They are not for legacy DTypes or np.dtype itself.
+ *
+ * @param self
+ * @return nonzero if the object is garbage collected
+ */
+static NPY_INLINE int
+dtypemeta_is_gc(PyObject *dtype_class)
+{
+ return PyType_Type.tp_is_gc(dtype_class);
+}
+
+
+static int
+dtypemeta_traverse(PyArray_DTypeMeta *type, visitproc visit, void *arg)
+{
+ /*
+ * We have to traverse the base class (if it is a HeapType).
+ * PyType_Type will handle this logic for us.
+ * This function is currently not used, but will probably be necessary
+ * in the future when we implement HeapTypes (python/dynamically
+ * defined types). It should be revised at that time.
+ */
+ assert(0);
+ assert(!type->legacy && (PyTypeObject *)type != &PyArrayDescr_Type);
+ Py_VISIT(type->singleton);
+ Py_VISIT(type->scalar_type);
+ return PyType_Type.tp_traverse((PyObject *)type, visit, arg);
+}
+
+
+static PyObject *
+legacy_dtype_default_new(PyArray_DTypeMeta *self,
+ PyObject *args, PyObject *kwargs)
+{
+ /* TODO: This should allow endianess and possibly metadata */
+ if (self->parametric) {
+ /* reject parametric ones since we would need to get unit, etc. info */
+ PyErr_Format(PyExc_TypeError,
+ "Preliminary-API: Flexible/Parametric legacy DType '%S' can "
+ "only be instantiated using `np.dtype(...)`", self);
+ return NULL;
+ }
+
+ if (PyTuple_GET_SIZE(args) != 0 ||
+ (kwargs != NULL && PyDict_Size(kwargs))) {
+ PyErr_Format(PyExc_TypeError,
+ "currently only the no-argument instantiation is supported; "
+ "use `np.dtype` instead.");
+ return NULL;
+ }
+ Py_INCREF(self->singleton);
+ return (PyObject *)self->singleton;
+}
+
+
+static PyArray_Descr *
+nonparametric_discover_descr_from_pyobject(
+ PyArray_DTypeMeta *cls, PyObject *obj)
+{
+ /* If the object is of the correct scalar type return our singleton */
+ assert(!cls->parametric);
+ Py_INCREF(cls->singleton);
+ return cls->singleton;
+}
+
+
+static PyArray_Descr *
+string_discover_descr_from_pyobject(
+ PyArray_DTypeMeta *cls, PyObject *obj)
+{
+ npy_intp itemsize = -1;
+ if (PyBytes_Check(obj)) {
+ itemsize = PyBytes_Size(obj);
+ }
+ else if (PyUnicode_Check(obj)) {
+ itemsize = PyUnicode_GetLength(obj);
+ }
+ if (itemsize != -1) {
+ if (cls->type_num == NPY_UNICODE) {
+ itemsize *= 4;
+ }
+ if (itemsize > NPY_MAX_INT) {
+ PyErr_SetString(PyExc_TypeError,
+ "string to large to store inside array.");
+ }
+ PyArray_Descr *res = PyArray_DescrNewFromType(cls->type_num);
+ res->elsize = (int)itemsize;
+ return res;
+ }
+ return PyArray_DTypeFromObjectStringDiscovery(obj, NULL, cls->type_num);
+}
+
+
+static PyArray_Descr *
+void_discover_descr_from_pyobject(
+ PyArray_DTypeMeta *NPY_UNUSED(cls), PyObject *obj)
+{
+ if (PyArray_IsScalar(obj, Void)) {
+ PyVoidScalarObject *void_obj = (PyVoidScalarObject *)obj;
+ Py_INCREF(void_obj->descr);
+ return void_obj->descr;
+ }
+ if (PyBytes_Check(obj)) {
+ PyArray_Descr *descr = PyArray_DescrNewFromType(NPY_VOID);
+ Py_ssize_t itemsize = (int)PyBytes_Size(obj);
+ if (itemsize > NPY_MAX_INT) {
+ PyErr_SetString(PyExc_TypeError,
+ "byte-like to large to store inside array.");
+ }
+ descr->elsize = itemsize;
+ return descr;
+ }
+ PyErr_Format(PyExc_TypeError,
+ "A bytes-like object is required, not '%s'", Py_TYPE(obj)->tp_name);
+ return NULL;
+}
+
+
+static PyArray_Descr *
+discover_datetime_and_timedelta_from_pyobject(
+ PyArray_DTypeMeta *cls, PyObject *obj) {
+ if (PyArray_IsScalar(obj, Datetime) ||
+ PyArray_IsScalar(obj, Timedelta)) {
+ PyArray_DatetimeMetaData *meta;
+ PyArray_Descr *descr = PyArray_DescrFromScalar(obj);
+ meta = get_datetime_metadata_from_dtype(descr);
+ if (meta == NULL) {
+ return NULL;
+ }
+ PyArray_Descr *new_descr = create_datetime_dtype(cls->type_num, meta);
+ Py_DECREF(descr);
+ return new_descr;
+ }
+ else {
+ return find_object_datetime_type(obj, cls->type_num);
+ }
+}
+
+
+static PyArray_Descr *
+nonparametric_default_descr(PyArray_DTypeMeta *cls)
+{
+ Py_INCREF(cls->singleton);
+ return cls->singleton;
+}
+
+
+/* Ensure a copy of the singleton (just in case we do adapt it somewhere) */
+static PyArray_Descr *
+datetime_and_timedelta_default_descr(PyArray_DTypeMeta *cls)
+{
+ return PyArray_DescrNew(cls->singleton);
+}
+
+
+static PyArray_Descr *
+void_default_descr(PyArray_DTypeMeta *cls)
+{
+ PyArray_Descr *res = PyArray_DescrNew(cls->singleton);
+ if (res == NULL) {
+ return NULL;
+ }
+ /*
+ * The legacy behaviour for `np.array([], dtype="V")` is to use "V8".
+ * This is because `[]` uses `float64` as dtype, and then that is used
+ * for the size of the requested void.
+ */
+ res->elsize = 8;
+ return res;
+}
+
+static PyArray_Descr *
+string_and_unicode_default_descr(PyArray_DTypeMeta *cls)
+{
+ PyArray_Descr *res = PyArray_DescrNewFromType(cls->type_num);
+ if (res == NULL) {
+ return NULL;
+ }
+ res->elsize = 1;
+ if (cls->type_num == NPY_UNICODE) {
+ res->elsize *= 4;
+ }
+ return res;
+}
+
+
+static PyArray_Descr *
+string_unicode_common_instance(PyArray_Descr *descr1, PyArray_Descr *descr2)
+{
+ if (descr1->elsize >= descr2->elsize) {
+ return ensure_dtype_nbo(descr1);
+ }
+ else {
+ return ensure_dtype_nbo(descr2);
+ }
+}
+
+
+static PyArray_Descr *
+void_common_instance(PyArray_Descr *descr1, PyArray_Descr *descr2)
+{
+ /*
+ * We currently do not support promotion of void types unless they
+ * are equivalent.
+ */
+ if (!PyArray_CanCastTypeTo(descr1, descr2, NPY_EQUIV_CASTING)) {
+ if (descr1->subarray == NULL && descr1->names == NULL &&
+ descr2->subarray == NULL && descr2->names == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid type promotion with void datatypes of different "
+ "lengths. Use the `np.bytes_` datatype instead to pad the "
+ "shorter value with trailing zero bytes.");
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "invalid type promotion with structured datatype(s).");
+ }
+ return NULL;
+ }
+ Py_INCREF(descr1);
+ return descr1;
+}
+
+static int
+python_builtins_are_known_scalar_types(
+ PyArray_DTypeMeta *NPY_UNUSED(cls), PyTypeObject *pytype)
+{
+ /*
+ * Always accept the common Python types, this ensures that we do not
+ * convert pyfloat->float64->integers. Subclasses are hopefully rejected
+ * as being discovered.
+ * This is necessary only for python scalar classes which we discover
+ * as valid DTypes.
+ */
+ if (pytype == &PyFloat_Type) {
+ return 1;
+ }
+ if (pytype == &PyLong_Type) {
+ return 1;
+ }
+ if (pytype == &PyBool_Type) {
+ return 1;
+ }
+ if (pytype == &PyComplex_Type) {
+ return 1;
+ }
+ if (pytype == &PyUnicode_Type) {
+ return 1;
+ }
+ if (pytype == &PyBytes_Type) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static int
+signed_integers_is_known_scalar_types(
+ PyArray_DTypeMeta *cls, PyTypeObject *pytype)
+{
+ if (python_builtins_are_known_scalar_types(cls, pytype)) {
+ return 1;
+ }
+ /* Convert our scalars (raise on too large unsigned and NaN, etc.) */
+ return PyType_IsSubtype(pytype, &PyGenericArrType_Type);
+}
+
+
+static int
+datetime_known_scalar_types(
+ PyArray_DTypeMeta *cls, PyTypeObject *pytype)
+{
+ if (python_builtins_are_known_scalar_types(cls, pytype)) {
+ return 1;
+ }
+ /*
+ * To be able to identify the descriptor from e.g. any string, datetime
+ * must take charge. Otherwise we would attempt casting which does not
+ * truly support this. Only object arrays are special cased in this way.
+ */
+ return (PyType_IsSubtype(pytype, &PyBytes_Type) ||
+ PyType_IsSubtype(pytype, &PyUnicode_Type));
+}
+
+
+static int
+string_known_scalar_types(
+ PyArray_DTypeMeta *cls, PyTypeObject *pytype) {
+ if (python_builtins_are_known_scalar_types(cls, pytype)) {
+ return 1;
+ }
+ if (PyType_IsSubtype(pytype, &PyDatetimeArrType_Type)) {
+ /*
+ * TODO: This should likely be deprecated or otherwise resolved.
+ * Deprecation has to occur in `String->setitem` unfortunately.
+ *
+ * Datetime currently do not cast to shorter strings, but string
+ * coercion for arbitrary values uses `str(obj)[:len]` so it works.
+ * This means `np.array(np.datetime64("2020-01-01"), "U9")`
+ * and `np.array(np.datetime64("2020-01-01")).astype("U9")` behave
+ * differently.
+ */
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * The following set of functions define the common dtype operator for
+ * the builtin types.
+ */
+static PyArray_DTypeMeta *
+default_builtin_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other)
+{
+ assert(cls->type_num < NPY_NTYPES);
+ if (!other->legacy || other->type_num > cls->type_num) {
+ /*
+ * Let the more generic (larger type number) DType handle this
+ * (note that half is after all others, which works out here.)
+ */
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_DTypeMeta *)Py_NotImplemented;
+ }
+
+ /*
+ * Note: The use of the promotion table should probably be revised at
+ * some point. It may be most useful to remove it entirely and then
+ * consider adding a fast path/cache `PyArray_CommonDType()` itself.
+ */
+ int common_num = _npy_type_promotion_table[cls->type_num][other->type_num];
+ if (common_num < 0) {
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_DTypeMeta *)Py_NotImplemented;
+ }
+ return PyArray_DTypeFromTypeNum(common_num);
+}
+
+
+static PyArray_DTypeMeta *
+string_unicode_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other)
+{
+ assert(cls->type_num < NPY_NTYPES && cls != other);
+ if (!other->legacy || (!PyTypeNum_ISNUMBER(other->type_num) &&
+ /* Not numeric so defer unless cls is unicode and other is string */
+ !(cls->type_num == NPY_UNICODE && other->type_num == NPY_STRING))) {
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_DTypeMeta *)Py_NotImplemented;
+ }
+ /*
+ * The builtin types are ordered by complexity (aside from object) here.
+ * Arguably, we should not consider numbers and strings "common", but
+ * we currently do.
+ */
+ Py_INCREF(cls);
+ return cls;
+}
+
+static PyArray_DTypeMeta *
+datetime_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other)
+{
+ if (cls->type_num == NPY_DATETIME && other->type_num == NPY_TIMEDELTA) {
+ /*
+ * TODO: We actually currently do allow promotion here. This is
+ * currently relied on within `np.add(datetime, timedelta)`,
+ * while for concatenation the cast step will fail.
+ */
+ Py_INCREF(cls);
+ return cls;
+ }
+ return default_builtin_common_dtype(cls, other);
+}
+
+
+
+static PyArray_DTypeMeta *
+object_common_dtype(
+ PyArray_DTypeMeta *cls, PyArray_DTypeMeta *NPY_UNUSED(other))
+{
+ /*
+ * The object DType is special in that it can represent everything,
+ * including all potential user DTypes.
+ * One reason to defer (or error) here might be if the other DType
+ * does not support scalars so that e.g. `arr1d[0]` returns a 0-D array
+ * and `arr.astype(object)` would fail. But object casts are special.
+ */
+ Py_INCREF(cls);
+ return cls;
+}
+
+
+/**
+ * This function takes a PyArray_Descr and replaces its base class with
+ * a newly created dtype subclass (DTypeMeta instances).
+ * There are some subtleties that need to be remembered when doing this,
+ * first for the class objects itself it could be either a HeapType or not.
+ * Since we are defining the DType from C, we will not make it a HeapType,
+ * thus making it identical to a typical *static* type (except that we
+ * malloc it). We could do it the other way, but there seems no reason to
+ * do so.
+ *
+ * The DType instances (the actual dtypes or descriptors), are based on
+ * prototypes which are passed in. These should not be garbage collected
+ * and thus Py_TPFLAGS_HAVE_GC is not set. (We could allow this, but than
+ * would have to allocate a new object, since the GC needs information before
+ * the actual struct).
+ *
+ * The above is the reason why we should works exactly like we would for a
+ * static type here.
+ * Otherwise, we blurry the lines between C-defined extension classes
+ * and Python subclasses. e.g. `class MyInt(int): pass` is very different
+ * from our `class Float64(np.dtype): pass`, because the latter should not
+ * be a HeapType and its instances should be exact PyArray_Descr structs.
+ *
+ * @param descr The descriptor that should be wrapped.
+ * @param name The name for the DType, if NULL the type character is used.
+ *
+ * @returns 0 on success, -1 on failure.
+ */
+NPY_NO_EXPORT int
+dtypemeta_wrap_legacy_descriptor(PyArray_Descr *descr)
+{
+ int has_type_set = Py_TYPE(descr) == &PyArrayDescr_Type;
+
+ if (!has_type_set) {
+ /* Accept if the type was filled in from an existing builtin dtype */
+ for (int i = 0; i < NPY_NTYPES; i++) {
+ PyArray_Descr *builtin = PyArray_DescrFromType(i);
+ has_type_set = Py_TYPE(descr) == Py_TYPE(builtin);
+ Py_DECREF(builtin);
+ if (has_type_set) {
+ break;
+ }
+ }
+ }
+ if (!has_type_set) {
+ PyErr_Format(PyExc_RuntimeError,
+ "During creation/wrapping of legacy DType, the original class "
+ "was not of PyArrayDescr_Type (it is replaced in this step). "
+ "The extension creating a custom DType for type %S must be "
+ "modified to ensure `Py_TYPE(descr) == &PyArrayDescr_Type` or "
+ "that of an existing dtype (with the assumption it is just "
+ "copied over and can be replaced).",
+ descr->typeobj, Py_TYPE(descr));
+ return -1;
+ }
+
+ /*
+ * Note: we have no intention of freeing the memory again since this
+ * behaves identically to static type definition (see comment above).
+ * This is seems cleaner for the legacy API, in the new API both static
+ * and heap types are possible (some difficulty arises from the fact that
+ * these are instances of DTypeMeta and not type).
+ * In particular our own DTypes can be true static declarations.
+ * However, this function remains necessary for legacy user dtypes.
+ */
+
+ const char *scalar_name = descr->typeobj->tp_name;
+ /*
+ * We have to take only the name, and ignore the module to get
+ * a reasonable __name__, since static types are limited in this regard
+ * (this is not ideal, but not a big issue in practice).
+ * This is what Python does to print __name__ for static types.
+ */
+ const char *dot = strrchr(scalar_name, '.');
+ if (dot) {
+ scalar_name = dot + 1;
+ }
+ ssize_t name_length = strlen(scalar_name) + 14;
+
+ char *tp_name = malloc(name_length);
+ if (tp_name == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ snprintf(tp_name, name_length, "numpy.dtype[%s]", scalar_name);
+
+ PyArray_DTypeMeta *dtype_class = malloc(sizeof(PyArray_DTypeMeta));
+ if (dtype_class == NULL) {
+ PyDataMem_FREE(tp_name);
+ return -1;
+ }
+ /*
+ * Initialize the struct fields identically to static code by copying
+ * a prototype instances for everything except our own fields which
+ * vary between the DTypes.
+ * In particular any Object initialization must be strictly copied from
+ * the untouched prototype to avoid complexities (e.g. with PyPy).
+ * Any Type slots need to be fixed before PyType_Ready, although most
+ * will be inherited automatically there.
+ */
+ static PyArray_DTypeMeta prototype = {
+ {{
+ PyVarObject_HEAD_INIT(&PyArrayDTypeMeta_Type, 0)
+ .tp_name = NULL, /* set below */
+ .tp_basicsize = sizeof(PyArray_Descr),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_base = &PyArrayDescr_Type,
+ .tp_new = (newfunc)legacy_dtype_default_new,
+ },},
+ .legacy = 1,
+ .abstract = 0, /* this is a concrete DType */
+ /* Further fields are not common between DTypes */
+ };
+ memcpy(dtype_class, &prototype, sizeof(PyArray_DTypeMeta));
+ /* Fix name of the Type*/
+ ((PyTypeObject *)dtype_class)->tp_name = tp_name;
+
+ /* Let python finish the initialization (probably unnecessary) */
+ if (PyType_Ready((PyTypeObject *)dtype_class) < 0) {
+ Py_DECREF(dtype_class);
+ return -1;
+ }
+ dtype_class->castingimpls = PyDict_New();
+ if (dtype_class->castingimpls == NULL) {
+ Py_DECREF(dtype_class);
+ return -1;
+ }
+
+ /*
+ * Fill DTypeMeta information that varies between DTypes, any variable
+ * type information would need to be set before PyType_Ready().
+ */
+ dtype_class->singleton = descr;
+ Py_INCREF(descr->typeobj);
+ dtype_class->scalar_type = descr->typeobj;
+ dtype_class->type_num = descr->type_num;
+ dtype_class->type = descr->type;
+ dtype_class->f = descr->f;
+ dtype_class->kind = descr->kind;
+
+ /* Set default functions (correct for most dtypes, override below) */
+ dtype_class->default_descr = nonparametric_default_descr;
+ dtype_class->discover_descr_from_pyobject = (
+ nonparametric_discover_descr_from_pyobject);
+ dtype_class->is_known_scalar_type = python_builtins_are_known_scalar_types;
+ dtype_class->common_dtype = default_builtin_common_dtype;
+ dtype_class->common_instance = NULL;
+
+ if (PyTypeNum_ISSIGNED(dtype_class->type_num)) {
+ /* Convert our scalars (raise on too large unsigned and NaN, etc.) */
+ dtype_class->is_known_scalar_type = signed_integers_is_known_scalar_types;
+ }
+
+ if (PyTypeNum_ISUSERDEF(descr->type_num)) {
+ dtype_class->common_dtype = legacy_userdtype_common_dtype_function;
+ }
+ else if (descr->type_num == NPY_OBJECT) {
+ dtype_class->common_dtype = object_common_dtype;
+ }
+ else if (PyTypeNum_ISDATETIME(descr->type_num)) {
+ /* Datetimes are flexible, but were not considered previously */
+ dtype_class->parametric = NPY_TRUE;
+ dtype_class->default_descr = datetime_and_timedelta_default_descr;
+ dtype_class->discover_descr_from_pyobject = (
+ discover_datetime_and_timedelta_from_pyobject);
+ dtype_class->common_dtype = datetime_common_dtype;
+ dtype_class->common_instance = datetime_type_promotion;
+ if (descr->type_num == NPY_DATETIME) {
+ dtype_class->is_known_scalar_type = datetime_known_scalar_types;
+ }
+ }
+ else if (PyTypeNum_ISFLEXIBLE(descr->type_num)) {
+ dtype_class->parametric = NPY_TRUE;
+ if (descr->type_num == NPY_VOID) {
+ dtype_class->default_descr = void_default_descr;
+ dtype_class->discover_descr_from_pyobject = (
+ void_discover_descr_from_pyobject);
+ dtype_class->common_instance = void_common_instance;
+ }
+ else {
+ dtype_class->default_descr = string_and_unicode_default_descr;
+ dtype_class->is_known_scalar_type = string_known_scalar_types;
+ dtype_class->discover_descr_from_pyobject = (
+ string_discover_descr_from_pyobject);
+ dtype_class->common_dtype = string_unicode_common_dtype;
+ dtype_class->common_instance = string_unicode_common_instance;
+ }
+ }
+
+ if (_PyArray_MapPyTypeToDType(dtype_class, descr->typeobj,
+ PyTypeNum_ISUSERDEF(dtype_class->type_num)) < 0) {
+ Py_DECREF(dtype_class);
+ return -1;
+ }
+
+ /* Finally, replace the current class of the descr */
+ Py_SET_TYPE(descr, (PyTypeObject *)dtype_class);
+
+ return 0;
+}
+
+
+/*
+ * Simple exposed information, defined for each DType (class). This is
+ * preliminary (the flags should also return bools).
+ */
+static PyMemberDef dtypemeta_members[] = {
+ {"_abstract",
+ T_BYTE, offsetof(PyArray_DTypeMeta, abstract), READONLY, NULL},
+ {"type",
+ T_OBJECT, offsetof(PyArray_DTypeMeta, scalar_type), READONLY, NULL},
+ {"_parametric",
+ T_BYTE, offsetof(PyArray_DTypeMeta, parametric), READONLY, NULL},
+ {NULL, 0, 0, 0, NULL},
+};
+
+
+NPY_NO_EXPORT PyTypeObject PyArrayDTypeMeta_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "numpy._DTypeMeta",
+ .tp_basicsize = sizeof(PyArray_DTypeMeta),
+ .tp_dealloc = (destructor)dtypemeta_dealloc,
+ /* Types are garbage collected (see dtypemeta_is_gc documentation) */
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+ .tp_doc = "Preliminary NumPy API: The Type of NumPy DTypes (metaclass)",
+ .tp_members = dtypemeta_members,
+ .tp_base = NULL, /* set to PyType_Type at import time */
+ .tp_init = (initproc)dtypemeta_init,
+ .tp_new = dtypemeta_new,
+ .tp_is_gc = dtypemeta_is_gc,
+ .tp_traverse = (traverseproc)dtypemeta_traverse,
+};
--- /dev/null
+#ifndef _NPY_DTYPEMETA_H
+#define _NPY_DTYPEMETA_H
+
+#define NPY_DTYPE(descr) ((PyArray_DTypeMeta *)Py_TYPE(descr))
+/*
+ * This function will hopefully be phased out or replaced, but was convenient
+ * for incremental implementation of new DTypes based on DTypeMeta.
+ * (Error checking is not required for DescrFromType, assuming that the
+ * type is valid.)
+ */
+static NPY_INLINE PyArray_DTypeMeta *
+PyArray_DTypeFromTypeNum(int typenum)
+{
+ PyArray_Descr *descr = PyArray_DescrFromType(typenum);
+ PyArray_DTypeMeta *dtype = NPY_DTYPE(descr);
+ Py_INCREF(dtype);
+ Py_DECREF(descr);
+ return dtype;
+}
+
+
+NPY_NO_EXPORT int
+dtypemeta_wrap_legacy_descriptor(PyArray_Descr *dtypem);
+
+#endif /*_NPY_DTYPEMETA_H */
#define _MULTIARRAYMODULE
#include <numpy/npy_common.h>
#include <numpy/arrayobject.h>
-#include <numpy/halffloat.h>
#include <npy_pycompat.h>
#include <ctype.h>
#include "common.h"
#include "ctors.h"
-#ifdef NPY_HAVE_SSE_INTRINSICS
-#define EINSUM_USE_SSE1 1
-#else
-#define EINSUM_USE_SSE1 0
-#endif
-
-/*
- * TODO: Only some SSE2 for float64 is implemented.
- */
-#ifdef NPY_HAVE_SSE2_INTRINSICS
-#define EINSUM_USE_SSE2 1
-#else
-#define EINSUM_USE_SSE2 0
-#endif
-
-#if EINSUM_USE_SSE1
-#include <xmmintrin.h>
-#endif
-
-#if EINSUM_USE_SSE2
-#include <emmintrin.h>
-#endif
-
-#define EINSUM_IS_SSE_ALIGNED(x) ((((npy_intp)x)&0xf) == 0)
-
-/********** PRINTF DEBUG TRACING **************/
-#define NPY_EINSUM_DBG_TRACING 0
-
-#if NPY_EINSUM_DBG_TRACING
-#define NPY_EINSUM_DBG_PRINT(s) printf("%s", s);
-#define NPY_EINSUM_DBG_PRINT1(s, p1) printf(s, p1);
-#define NPY_EINSUM_DBG_PRINT2(s, p1, p2) printf(s, p1, p2);
-#define NPY_EINSUM_DBG_PRINT3(s, p1, p2, p3) printf(s);
-#else
-#define NPY_EINSUM_DBG_PRINT(s)
-#define NPY_EINSUM_DBG_PRINT1(s, p1)
-#define NPY_EINSUM_DBG_PRINT2(s, p1, p2)
-#define NPY_EINSUM_DBG_PRINT3(s, p1, p2, p3)
-#endif
-/**********************************************/
-
-/**begin repeat
- * #name = byte, short, int, long, longlong,
- * ubyte, ushort, uint, ulong, ulonglong,
- * half, float, double, longdouble,
- * cfloat, cdouble, clongdouble#
- * #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong,
- * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong,
- * npy_half, npy_float, npy_double, npy_longdouble,
- * npy_cfloat, npy_cdouble, npy_clongdouble#
- * #temptype = npy_byte, npy_short, npy_int, npy_long, npy_longlong,
- * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong,
- * npy_float, npy_float, npy_double, npy_longdouble,
- * npy_float, npy_double, npy_longdouble#
- * #to = ,,,,,
- * ,,,,,
- * npy_float_to_half,,,,
- * ,,#
- * #from = ,,,,,
- * ,,,,,
- * npy_half_to_float,,,,
- * ,,#
- * #complex = 0*5,
- * 0*5,
- * 0*4,
- * 1*3#
- * #float32 = 0*5,
- * 0*5,
- * 0,1,0,0,
- * 0*3#
- * #float64 = 0*5,
- * 0*5,
- * 0,0,1,0,
- * 0*3#
- */
-
-/**begin repeat1
- * #nop = 1, 2, 3, 1000#
- * #noplabel = one, two, three, any#
- */
-static void
-@name@_sum_of_products_@noplabel@(int nop, char **dataptr,
- npy_intp const *strides, npy_intp count)
-{
-#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@)
- char *data0 = dataptr[0];
- npy_intp stride0 = strides[0];
-#endif
-#if (@nop@ == 2 || @nop@ == 3) && !@complex@
- char *data1 = dataptr[1];
- npy_intp stride1 = strides[1];
-#endif
-#if (@nop@ == 3) && !@complex@
- char *data2 = dataptr[2];
- npy_intp stride2 = strides[2];
-#endif
-#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@)
- char *data_out = dataptr[@nop@];
- npy_intp stride_out = strides[@nop@];
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_@noplabel@ (%d)\n", (int)count);
-
- while (count--) {
-#if !@complex@
-# if @nop@ == 1
- *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) +
- @from@(*(@type@ *)data_out));
- data0 += stride0;
- data_out += stride_out;
-# elif @nop@ == 2
- *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) *
- @from@(*(@type@ *)data1) +
- @from@(*(@type@ *)data_out));
- data0 += stride0;
- data1 += stride1;
- data_out += stride_out;
-# elif @nop@ == 3
- *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) *
- @from@(*(@type@ *)data1) *
- @from@(*(@type@ *)data2) +
- @from@(*(@type@ *)data_out));
- data0 += stride0;
- data1 += stride1;
- data2 += stride2;
- data_out += stride_out;
-# else
- @temptype@ temp = @from@(*(@type@ *)dataptr[0]);
- int i;
- for (i = 1; i < nop; ++i) {
- temp *= @from@(*(@type@ *)dataptr[i]);
- }
- *(@type@ *)dataptr[nop] = @to@(temp +
- @from@(*(@type@ *)dataptr[i]));
- for (i = 0; i <= nop; ++i) {
- dataptr[i] += strides[i];
- }
-# endif
-#else /* complex */
-# if @nop@ == 1
- ((@temptype@ *)data_out)[0] = ((@temptype@ *)data0)[0] +
- ((@temptype@ *)data_out)[0];
- ((@temptype@ *)data_out)[1] = ((@temptype@ *)data0)[1] +
- ((@temptype@ *)data_out)[1];
- data0 += stride0;
- data_out += stride_out;
-# else
-# if @nop@ <= 3
-#define _SUMPROD_NOP @nop@
-# else
-#define _SUMPROD_NOP nop
-# endif
- @temptype@ re, im, tmp;
- int i;
- re = ((@temptype@ *)dataptr[0])[0];
- im = ((@temptype@ *)dataptr[0])[1];
- for (i = 1; i < _SUMPROD_NOP; ++i) {
- tmp = re * ((@temptype@ *)dataptr[i])[0] -
- im * ((@temptype@ *)dataptr[i])[1];
- im = re * ((@temptype@ *)dataptr[i])[1] +
- im * ((@temptype@ *)dataptr[i])[0];
- re = tmp;
- }
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[0] = re +
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[0];
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[1] = im +
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[1];
-
- for (i = 0; i <= _SUMPROD_NOP; ++i) {
- dataptr[i] += strides[i];
- }
-#undef _SUMPROD_NOP
-# endif
-#endif
- }
-}
-
-#if @nop@ == 1
-
-static void
-@name@_sum_of_products_contig_one(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @type@ *data0 = (@type@ *)dataptr[0];
- @type@ *data_out = (@type@ *)dataptr[1];
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_one (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
-#if !@complex@
- data_out[@i@] = @to@(@from@(data0[@i@]) +
- @from@(data_out[@i@]));
-#else
- ((@temptype@ *)data_out + 2*@i@)[0] =
- ((@temptype@ *)data0 + 2*@i@)[0] +
- ((@temptype@ *)data_out + 2*@i@)[0];
- ((@temptype@ *)data_out + 2*@i@)[1] =
- ((@temptype@ *)data0 + 2*@i@)[1] +
- ((@temptype@ *)data_out + 2*@i@)[1];
-#endif
-/**end repeat2**/
- case 0:
- return;
- }
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
-#if !@complex@
- data_out[@i@] = @to@(@from@(data0[@i@]) +
- @from@(data_out[@i@]));
-#else /* complex */
- ((@temptype@ *)data_out + 2*@i@)[0] =
- ((@temptype@ *)data0 + 2*@i@)[0] +
- ((@temptype@ *)data_out + 2*@i@)[0];
- ((@temptype@ *)data_out + 2*@i@)[1] =
- ((@temptype@ *)data0 + 2*@i@)[1] +
- ((@temptype@ *)data_out + 2*@i@)[1];
-#endif
-/**end repeat2**/
- data0 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
-}
-
-#elif @nop@ == 2 && !@complex@
-
-static void
-@name@_sum_of_products_contig_two(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @type@ *data0 = (@type@ *)dataptr[0];
- @type@ *data1 = (@type@ *)dataptr[1];
- @type@ *data_out = (@type@ *)dataptr[2];
-
-#if EINSUM_USE_SSE1 && @float32@
- __m128 a, b;
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_two (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
- data_out[@i@] = @to@(@from@(data0[@i@]) *
- @from@(data1[@i@]) +
- @from@(data_out[@i@]));
-/**end repeat2**/
- case 0:
- return;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1) &&
- EINSUM_IS_SSE_ALIGNED(data_out)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 4#
- */
- a = _mm_mul_ps(_mm_load_ps(data0+@i@), _mm_load_ps(data1+@i@));
- b = _mm_add_ps(a, _mm_load_ps(data_out+@i@));
- _mm_store_ps(data_out+@i@, b);
-/**end repeat2**/
- data0 += 8;
- data1 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#endif
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-#if EINSUM_USE_SSE1 && @float32@
-/**begin repeat2
- * #i = 0, 4#
- */
- a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), _mm_loadu_ps(data1+@i@));
- b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@));
- _mm_storeu_ps(data_out+@i@, b);
-/**end repeat2**/
-#else
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- data_out[@i@] = @to@(@from@(data0[@i@]) *
- @from@(data1[@i@]) +
- @from@(data_out[@i@]));
-/**end repeat2**/
-#endif
- data0 += 8;
- data1 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
-}
-
-/* Some extra specializations for the two operand case */
-static void
-@name@_sum_of_products_stride0_contig_outcontig_two(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @temptype@ value0 = @from@(*(@type@ *)dataptr[0]);
- @type@ *data1 = (@type@ *)dataptr[1];
- @type@ *data_out = (@type@ *)dataptr[2];
-
-#if EINSUM_USE_SSE1 && @float32@
- __m128 a, b, value0_sse;
-#elif EINSUM_USE_SSE2 && @float64@
- __m128d a, b, value0_sse;
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_stride0_contig_outcontig_two (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
- data_out[@i@] = @to@(value0 *
- @from@(data1[@i@]) +
- @from@(data_out[@i@]));
-/**end repeat2**/
- case 0:
- return;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- value0_sse = _mm_set_ps1(value0);
-
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data1) && EINSUM_IS_SSE_ALIGNED(data_out)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 4#
- */
- a = _mm_mul_ps(value0_sse, _mm_load_ps(data1+@i@));
- b = _mm_add_ps(a, _mm_load_ps(data_out+@i@));
- _mm_store_ps(data_out+@i@, b);
-/**end repeat2**/
- data1 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- if (count > 0) {
- goto finish_after_unrolled_loop;
- }
- else {
- return;
- }
- }
-#elif EINSUM_USE_SSE2 && @float64@
- value0_sse = _mm_set1_pd(value0);
-
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data1) && EINSUM_IS_SSE_ALIGNED(data_out)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 2, 4, 6#
- */
- a = _mm_mul_pd(value0_sse, _mm_load_pd(data1+@i@));
- b = _mm_add_pd(a, _mm_load_pd(data_out+@i@));
- _mm_store_pd(data_out+@i@, b);
-/**end repeat2**/
- data1 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- if (count > 0) {
- goto finish_after_unrolled_loop;
- }
- else {
- return;
- }
- }
-#endif
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-#if EINSUM_USE_SSE1 && @float32@
-/**begin repeat2
- * #i = 0, 4#
- */
- a = _mm_mul_ps(value0_sse, _mm_loadu_ps(data1+@i@));
- b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@));
- _mm_storeu_ps(data_out+@i@, b);
-/**end repeat2**/
-#elif EINSUM_USE_SSE2 && @float64@
-/**begin repeat2
- * #i = 0, 2, 4, 6#
- */
- a = _mm_mul_pd(value0_sse, _mm_loadu_pd(data1+@i@));
- b = _mm_add_pd(a, _mm_loadu_pd(data_out+@i@));
- _mm_storeu_pd(data_out+@i@, b);
-/**end repeat2**/
-#else
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- data_out[@i@] = @to@(value0 *
- @from@(data1[@i@]) +
- @from@(data_out[@i@]));
-/**end repeat2**/
-#endif
- data1 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- if (count > 0) {
- goto finish_after_unrolled_loop;
- }
-}
-
-static void
-@name@_sum_of_products_contig_stride0_outcontig_two(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @type@ *data0 = (@type@ *)dataptr[0];
- @temptype@ value1 = @from@(*(@type@ *)dataptr[1]);
- @type@ *data_out = (@type@ *)dataptr[2];
-
-#if EINSUM_USE_SSE1 && @float32@
- __m128 a, b, value1_sse;
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_stride0_outcontig_two (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
- data_out[@i@] = @to@(@from@(data0[@i@])*
- value1 +
- @from@(data_out[@i@]));
-/**end repeat2**/
- case 0:
- return;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- value1_sse = _mm_set_ps1(value1);
-
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data_out)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 4#
- */
- a = _mm_mul_ps(_mm_load_ps(data0+@i@), value1_sse);
- b = _mm_add_ps(a, _mm_load_ps(data_out+@i@));
- _mm_store_ps(data_out+@i@, b);
-/**end repeat2**/
- data0 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#endif
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-#if EINSUM_USE_SSE1 && @float32@
-/**begin repeat2
- * #i = 0, 4#
- */
- a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), value1_sse);
- b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@));
- _mm_storeu_ps(data_out+@i@, b);
-/**end repeat2**/
-#else
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- data_out[@i@] = @to@(@from@(data0[@i@])*
- value1 +
- @from@(data_out[@i@]));
-/**end repeat2**/
-#endif
- data0 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
-}
-
-static void
-@name@_sum_of_products_contig_contig_outstride0_two(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @type@ *data0 = (@type@ *)dataptr[0];
- @type@ *data1 = (@type@ *)dataptr[1];
- @temptype@ accum = 0;
-
-#if EINSUM_USE_SSE1 && @float32@
- __m128 a, accum_sse = _mm_setzero_ps();
-#elif EINSUM_USE_SSE2 && @float64@
- __m128d a, accum_sse = _mm_setzero_pd();
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_contig_outstride0_two (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
- accum += @from@(data0[@i@]) * @from@(data1[@i@]);
-/**end repeat2**/
- case 0:
- *(@type@ *)dataptr[2] = @to@(@from@(*(@type@ *)dataptr[2]) + accum);
- return;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
- _mm_prefetch(data1 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- a = _mm_mul_ps(_mm_load_ps(data0+@i@), _mm_load_ps(data1+@i@));
- accum_sse = _mm_add_ps(accum_sse, a);
-/**end repeat2**/
- data0 += 8;
- data1 += 8;
- }
-
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#elif EINSUM_USE_SSE2 && @float64@
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
- _mm_prefetch(data1 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 2, 4, 6#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- a = _mm_mul_pd(_mm_load_pd(data0+@i@), _mm_load_pd(data1+@i@));
- accum_sse = _mm_add_pd(accum_sse, a);
-/**end repeat2**/
- data0 += 8;
- data1 += 8;
- }
-
- /* Add the two SSE2 values and put in accum */
- a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
- accum_sse = _mm_add_pd(a, accum_sse);
- _mm_store_sd(&accum, accum_sse);
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#endif
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-#if EINSUM_USE_SSE1 && @float32@
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
- _mm_prefetch(data1 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), _mm_loadu_ps(data1+@i@));
- accum_sse = _mm_add_ps(accum_sse, a);
-/**end repeat2**/
-#elif EINSUM_USE_SSE2 && @float64@
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
- _mm_prefetch(data1 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 2, 4, 6#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- a = _mm_mul_pd(_mm_loadu_pd(data0+@i@), _mm_loadu_pd(data1+@i@));
- accum_sse = _mm_add_pd(accum_sse, a);
-/**end repeat2**/
-#else
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- accum += @from@(data0[@i@]) * @from@(data1[@i@]);
-/**end repeat2**/
-#endif
- data0 += 8;
- data1 += 8;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-#elif EINSUM_USE_SSE2 && @float64@
- /* Add the two SSE2 values and put in accum */
- a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
- accum_sse = _mm_add_pd(a, accum_sse);
- _mm_store_sd(&accum, accum_sse);
-#endif
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
-}
-
-static void
-@name@_sum_of_products_stride0_contig_outstride0_two(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @temptype@ value0 = @from@(*(@type@ *)dataptr[0]);
- @type@ *data1 = (@type@ *)dataptr[1];
- @temptype@ accum = 0;
-
-#if EINSUM_USE_SSE1 && @float32@
- __m128 a, accum_sse = _mm_setzero_ps();
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_stride0_contig_outstride0_two (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
- accum += @from@(data1[@i@]);
-/**end repeat2**/
- case 0:
- *(@type@ *)dataptr[2] = @to@(@from@(*(@type@ *)dataptr[2]) + value0 * accum);
- return;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data1)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data1+@i@));
-/**end repeat2**/
- data1 += 8;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-#endif
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#endif
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-#if EINSUM_USE_SSE1 && @float32@
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data1+@i@));
-/**end repeat2**/
-#else
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- accum += @from@(data1[@i@]);
-/**end repeat2**/
-#endif
- data1 += 8;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-#endif
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
-}
-
-static void
-@name@_sum_of_products_contig_stride0_outstride0_two(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @type@ *data0 = (@type@ *)dataptr[0];
- @temptype@ value1 = @from@(*(@type@ *)dataptr[1]);
- @temptype@ accum = 0;
-
-#if EINSUM_USE_SSE1 && @float32@
- __m128 a, accum_sse = _mm_setzero_ps();
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_stride0_outstride0_two (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
- accum += @from@(data0[@i@]);
-/**end repeat2**/
- case 0:
- *(@type@ *)dataptr[2] = @to@(@from@(*(@type@ *)dataptr[2]) + accum * value1);
- return;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data0)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data0+@i@));
-/**end repeat2**/
- data0 += 8;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-#endif
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#endif
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-#if EINSUM_USE_SSE1 && @float32@
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data0+@i@));
-/**end repeat2**/
-#else
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- accum += @from@(data0[@i@]);
-/**end repeat2**/
-#endif
- data0 += 8;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-#endif
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
-}
-
-#elif @nop@ == 3 && !@complex@
-
-static void
-@name@_sum_of_products_contig_three(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- @type@ *data0 = (@type@ *)dataptr[0];
- @type@ *data1 = (@type@ *)dataptr[1];
- @type@ *data2 = (@type@ *)dataptr[2];
- @type@ *data_out = (@type@ *)dataptr[3];
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- data_out[@i@] = @to@(@from@(data0[@i@]) *
- @from@(data1[@i@]) *
- @from@(data2[@i@]) +
- @from@(data_out[@i@]));
-/**end repeat2**/
- data0 += 8;
- data1 += 8;
- data2 += 8;
- data_out += 8;
- }
-
- /* Finish off the loop */
-
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- if (count-- == 0) {
- return;
- }
- data_out[@i@] = @to@(@from@(data0[@i@]) *
- @from@(data1[@i@]) *
- @from@(data2[@i@]) +
- @from@(data_out[@i@]));
-/**end repeat2**/
-}
-
-#else /* @nop@ > 3 || @complex */
-
-static void
-@name@_sum_of_products_contig_@noplabel@(int nop, char **dataptr,
- npy_intp const *NPY_UNUSED(strides), npy_intp count)
-{
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_@noplabel@ (%d)\n",
- (int)count);
-
- while (count--) {
-#if !@complex@
- @temptype@ temp = @from@(*(@type@ *)dataptr[0]);
- int i;
- for (i = 1; i < nop; ++i) {
- temp *= @from@(*(@type@ *)dataptr[i]);
- }
- *(@type@ *)dataptr[nop] = @to@(temp +
- @from@(*(@type@ *)dataptr[i]));
- for (i = 0; i <= nop; ++i) {
- dataptr[i] += sizeof(@type@);
- }
-#else /* complex */
-# if @nop@ <= 3
-# define _SUMPROD_NOP @nop@
-# else
-# define _SUMPROD_NOP nop
-# endif
- @temptype@ re, im, tmp;
- int i;
- re = ((@temptype@ *)dataptr[0])[0];
- im = ((@temptype@ *)dataptr[0])[1];
- for (i = 1; i < _SUMPROD_NOP; ++i) {
- tmp = re * ((@temptype@ *)dataptr[i])[0] -
- im * ((@temptype@ *)dataptr[i])[1];
- im = re * ((@temptype@ *)dataptr[i])[1] +
- im * ((@temptype@ *)dataptr[i])[0];
- re = tmp;
- }
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[0] = re +
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[0];
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[1] = im +
- ((@temptype@ *)dataptr[_SUMPROD_NOP])[1];
-
- for (i = 0; i <= _SUMPROD_NOP; ++i) {
- dataptr[i] += sizeof(@type@);
- }
-# undef _SUMPROD_NOP
-#endif
- }
-}
-
-#endif /* functions for various @nop@ */
-
-#if @nop@ == 1
-
-static void
-@name@_sum_of_products_contig_outstride0_one(int nop, char **dataptr,
- npy_intp const *strides, npy_intp count)
-{
-#if @complex@
- @temptype@ accum_re = 0, accum_im = 0;
- @temptype@ *data0 = (@temptype@ *)dataptr[0];
-#else
- @temptype@ accum = 0;
- @type@ *data0 = (@type@ *)dataptr[0];
-#endif
-
-#if EINSUM_USE_SSE1 && @float32@
- __m128 a, accum_sse = _mm_setzero_ps();
-#elif EINSUM_USE_SSE2 && @float64@
- __m128d a, accum_sse = _mm_setzero_pd();
-#endif
-
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_outstride0_one (%d)\n",
- (int)count);
-
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat2
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
-#if !@complex@
- accum += @from@(data0[@i@]);
-#else /* complex */
- accum_re += data0[2*@i@+0];
- accum_im += data0[2*@i@+1];
-#endif
-/**end repeat2**/
- case 0:
-#if @complex@
- ((@temptype@ *)dataptr[1])[0] += accum_re;
- ((@temptype@ *)dataptr[1])[1] += accum_im;
-#else
- *((@type@ *)dataptr[1]) = @to@(accum +
- @from@(*((@type@ *)dataptr[1])));
-#endif
- return;
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data0)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data0+@i@));
-/**end repeat2**/
- data0 += 8;
- }
-
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#elif EINSUM_USE_SSE2 && @float64@
- /* Use aligned instructions if possible */
- if (EINSUM_IS_SSE_ALIGNED(data0)) {
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 2, 4, 6#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_pd(accum_sse, _mm_load_pd(data0+@i@));
-/**end repeat2**/
- data0 += 8;
- }
-
- /* Add the two SSE2 values and put in accum */
- a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
- accum_sse = _mm_add_pd(a, accum_sse);
- _mm_store_sd(&accum, accum_sse);
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
- }
-#endif
-
- /* Unroll the loop by 8 */
- while (count >= 8) {
- count -= 8;
-
-#if EINSUM_USE_SSE1 && @float32@
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 4#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data0+@i@));
-/**end repeat2**/
-#elif EINSUM_USE_SSE2 && @float64@
- _mm_prefetch(data0 + 512, _MM_HINT_T0);
-
-/**begin repeat2
- * #i = 0, 2, 4, 6#
- */
- /*
- * NOTE: This accumulation changes the order, so will likely
- * produce slightly different results.
- */
- accum_sse = _mm_add_pd(accum_sse, _mm_loadu_pd(data0+@i@));
-/**end repeat2**/
-#else
-/**begin repeat2
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
-# if !@complex@
- accum += @from@(data0[@i@]);
-# else /* complex */
- accum_re += data0[2*@i@+0];
- accum_im += data0[2*@i@+1];
-# endif
-/**end repeat2**/
-#endif
-
-#if !@complex@
- data0 += 8;
-#else
- data0 += 8*2;
-#endif
- }
-
-#if EINSUM_USE_SSE1 && @float32@
- /* Add the four SSE values and put in accum */
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
- accum_sse = _mm_add_ps(a, accum_sse);
- a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
- accum_sse = _mm_add_ps(a, accum_sse);
- _mm_store_ss(&accum, accum_sse);
-#elif EINSUM_USE_SSE2 && @float64@
- /* Add the two SSE2 values and put in accum */
- a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
- accum_sse = _mm_add_pd(a, accum_sse);
- _mm_store_sd(&accum, accum_sse);
-#endif
-
- /* Finish off the loop */
- goto finish_after_unrolled_loop;
-}
-
-#endif /* @nop@ == 1 */
-
-static void
-@name@_sum_of_products_outstride0_@noplabel@(int nop, char **dataptr,
- npy_intp const *strides, npy_intp count)
-{
-#if @complex@
- @temptype@ accum_re = 0, accum_im = 0;
-#else
- @temptype@ accum = 0;
-#endif
-
-#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@)
- char *data0 = dataptr[0];
- npy_intp stride0 = strides[0];
-#endif
-#if (@nop@ == 2 || @nop@ == 3) && !@complex@
- char *data1 = dataptr[1];
- npy_intp stride1 = strides[1];
-#endif
-#if (@nop@ == 3) && !@complex@
- char *data2 = dataptr[2];
- npy_intp stride2 = strides[2];
-#endif
-
- NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_outstride0_@noplabel@ (%d)\n",
- (int)count);
-
- while (count--) {
-#if !@complex@
-# if @nop@ == 1
- accum += @from@(*(@type@ *)data0);
- data0 += stride0;
-# elif @nop@ == 2
- accum += @from@(*(@type@ *)data0) *
- @from@(*(@type@ *)data1);
- data0 += stride0;
- data1 += stride1;
-# elif @nop@ == 3
- accum += @from@(*(@type@ *)data0) *
- @from@(*(@type@ *)data1) *
- @from@(*(@type@ *)data2);
- data0 += stride0;
- data1 += stride1;
- data2 += stride2;
-# else
- @temptype@ temp = @from@(*(@type@ *)dataptr[0]);
- int i;
- for (i = 1; i < nop; ++i) {
- temp *= @from@(*(@type@ *)dataptr[i]);
- }
- accum += temp;
- for (i = 0; i < nop; ++i) {
- dataptr[i] += strides[i];
- }
-# endif
-#else /* complex */
-# if @nop@ == 1
- accum_re += ((@temptype@ *)data0)[0];
- accum_im += ((@temptype@ *)data0)[1];
- data0 += stride0;
-# else
-# if @nop@ <= 3
-#define _SUMPROD_NOP @nop@
-# else
-#define _SUMPROD_NOP nop
-# endif
- @temptype@ re, im, tmp;
- int i;
- re = ((@temptype@ *)dataptr[0])[0];
- im = ((@temptype@ *)dataptr[0])[1];
- for (i = 1; i < _SUMPROD_NOP; ++i) {
- tmp = re * ((@temptype@ *)dataptr[i])[0] -
- im * ((@temptype@ *)dataptr[i])[1];
- im = re * ((@temptype@ *)dataptr[i])[1] +
- im * ((@temptype@ *)dataptr[i])[0];
- re = tmp;
- }
- accum_re += re;
- accum_im += im;
- for (i = 0; i < _SUMPROD_NOP; ++i) {
- dataptr[i] += strides[i];
- }
-#undef _SUMPROD_NOP
-# endif
-#endif
- }
-
-#if @complex@
-# if @nop@ <= 3
- ((@temptype@ *)dataptr[@nop@])[0] += accum_re;
- ((@temptype@ *)dataptr[@nop@])[1] += accum_im;
-# else
- ((@temptype@ *)dataptr[nop])[0] += accum_re;
- ((@temptype@ *)dataptr[nop])[1] += accum_im;
-# endif
-#else
-# if @nop@ <= 3
- *((@type@ *)dataptr[@nop@]) = @to@(accum +
- @from@(*((@type@ *)dataptr[@nop@])));
-# else
- *((@type@ *)dataptr[nop]) = @to@(accum +
- @from@(*((@type@ *)dataptr[nop])));
-# endif
-#endif
-
-}
-
-/**end repeat1**/
-
-/**end repeat**/
-
-
-/* Do OR of ANDs for the boolean type */
-
-/**begin repeat
- * #nop = 1, 2, 3, 1000#
- * #noplabel = one, two, three, any#
- */
-
-static void
-bool_sum_of_products_@noplabel@(int nop, char **dataptr,
- npy_intp const *strides, npy_intp count)
-{
-#if (@nop@ <= 3)
- char *data0 = dataptr[0];
- npy_intp stride0 = strides[0];
-#endif
-#if (@nop@ == 2 || @nop@ == 3)
- char *data1 = dataptr[1];
- npy_intp stride1 = strides[1];
-#endif
-#if (@nop@ == 3)
- char *data2 = dataptr[2];
- npy_intp stride2 = strides[2];
-#endif
-#if (@nop@ <= 3)
- char *data_out = dataptr[@nop@];
- npy_intp stride_out = strides[@nop@];
-#endif
-
- while (count--) {
-#if @nop@ == 1
- *(npy_bool *)data_out = *(npy_bool *)data0 ||
- *(npy_bool *)data_out;
- data0 += stride0;
- data_out += stride_out;
-#elif @nop@ == 2
- *(npy_bool *)data_out = (*(npy_bool *)data0 &&
- *(npy_bool *)data1) ||
- *(npy_bool *)data_out;
- data0 += stride0;
- data1 += stride1;
- data_out += stride_out;
-#elif @nop@ == 3
- *(npy_bool *)data_out = (*(npy_bool *)data0 &&
- *(npy_bool *)data1 &&
- *(npy_bool *)data2) ||
- *(npy_bool *)data_out;
- data0 += stride0;
- data1 += stride1;
- data2 += stride2;
- data_out += stride_out;
-#else
- npy_bool temp = *(npy_bool *)dataptr[0];
- int i;
- for (i = 1; i < nop; ++i) {
- temp = temp && *(npy_bool *)dataptr[i];
- }
- *(npy_bool *)dataptr[nop] = temp || *(npy_bool *)dataptr[i];
- for (i = 0; i <= nop; ++i) {
- dataptr[i] += strides[i];
- }
-#endif
- }
-}
-
-static void
-bool_sum_of_products_contig_@noplabel@(int nop, char **dataptr,
- npy_intp const *strides, npy_intp count)
-{
-#if (@nop@ <= 3)
- char *data0 = dataptr[0];
-#endif
-#if (@nop@ == 2 || @nop@ == 3)
- char *data1 = dataptr[1];
-#endif
-#if (@nop@ == 3)
- char *data2 = dataptr[2];
-#endif
-#if (@nop@ <= 3)
- char *data_out = dataptr[@nop@];
-#endif
-
-#if (@nop@ <= 3)
-/* This is placed before the main loop to make small counts faster */
-finish_after_unrolled_loop:
- switch (count) {
-/**begin repeat1
- * #i = 6, 5, 4, 3, 2, 1, 0#
- */
- case @i@+1:
-# if @nop@ == 1
- ((npy_bool *)data_out)[@i@] = ((npy_bool *)data0)[@i@] ||
- ((npy_bool *)data_out)[@i@];
-# elif @nop@ == 2
- ((npy_bool *)data_out)[@i@] =
- (((npy_bool *)data0)[@i@] &&
- ((npy_bool *)data1)[@i@]) ||
- ((npy_bool *)data_out)[@i@];
-# elif @nop@ == 3
- ((npy_bool *)data_out)[@i@] =
- (((npy_bool *)data0)[@i@] &&
- ((npy_bool *)data1)[@i@] &&
- ((npy_bool *)data2)[@i@]) ||
- ((npy_bool *)data_out)[@i@];
-# endif
-/**end repeat1**/
- case 0:
- return;
- }
-#endif
-
-/* Unroll the loop by 8 for fixed-size nop */
-#if (@nop@ <= 3)
- while (count >= 8) {
- count -= 8;
-#else
- while (count--) {
-#endif
-
-# if @nop@ == 1
-/**begin repeat1
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- *((npy_bool *)data_out + @i@) = (*((npy_bool *)data0 + @i@)) ||
- (*((npy_bool *)data_out + @i@));
-/**end repeat1**/
- data0 += 8*sizeof(npy_bool);
- data_out += 8*sizeof(npy_bool);
-# elif @nop@ == 2
-/**begin repeat1
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- *((npy_bool *)data_out + @i@) =
- ((*((npy_bool *)data0 + @i@)) &&
- (*((npy_bool *)data1 + @i@))) ||
- (*((npy_bool *)data_out + @i@));
-/**end repeat1**/
- data0 += 8*sizeof(npy_bool);
- data1 += 8*sizeof(npy_bool);
- data_out += 8*sizeof(npy_bool);
-# elif @nop@ == 3
-/**begin repeat1
- * #i = 0, 1, 2, 3, 4, 5, 6, 7#
- */
- *((npy_bool *)data_out + @i@) =
- ((*((npy_bool *)data0 + @i@)) &&
- (*((npy_bool *)data1 + @i@)) &&
- (*((npy_bool *)data2 + @i@))) ||
- (*((npy_bool *)data_out + @i@));
-/**end repeat1**/
- data0 += 8*sizeof(npy_bool);
- data1 += 8*sizeof(npy_bool);
- data2 += 8*sizeof(npy_bool);
- data_out += 8*sizeof(npy_bool);
-# else
- npy_bool temp = *(npy_bool *)dataptr[0];
- int i;
- for (i = 1; i < nop; ++i) {
- temp = temp && *(npy_bool *)dataptr[i];
- }
- *(npy_bool *)dataptr[nop] = temp || *(npy_bool *)dataptr[i];
- for (i = 0; i <= nop; ++i) {
- dataptr[i] += sizeof(npy_bool);
- }
-# endif
- }
-
- /* If the loop was unrolled, we need to finish it off */
-#if (@nop@ <= 3)
- goto finish_after_unrolled_loop;
-#endif
-}
-
-static void
-bool_sum_of_products_outstride0_@noplabel@(int nop, char **dataptr,
- npy_intp const *strides, npy_intp count)
-{
- npy_bool accum = 0;
-
-#if (@nop@ <= 3)
- char *data0 = dataptr[0];
- npy_intp stride0 = strides[0];
-#endif
-#if (@nop@ == 2 || @nop@ == 3)
- char *data1 = dataptr[1];
- npy_intp stride1 = strides[1];
-#endif
-#if (@nop@ == 3)
- char *data2 = dataptr[2];
- npy_intp stride2 = strides[2];
-#endif
-
- while (count--) {
-#if @nop@ == 1
- accum = *(npy_bool *)data0 || accum;
- data0 += stride0;
-#elif @nop@ == 2
- accum = (*(npy_bool *)data0 && *(npy_bool *)data1) || accum;
- data0 += stride0;
- data1 += stride1;
-#elif @nop@ == 3
- accum = (*(npy_bool *)data0 &&
- *(npy_bool *)data1 &&
- *(npy_bool *)data2) || accum;
- data0 += stride0;
- data1 += stride1;
- data2 += stride2;
-#else
- npy_bool temp = *(npy_bool *)dataptr[0];
- int i;
- for (i = 1; i < nop; ++i) {
- temp = temp && *(npy_bool *)dataptr[i];
- }
- accum = temp || accum;
- for (i = 0; i <= nop; ++i) {
- dataptr[i] += strides[i];
- }
-#endif
- }
-
-# if @nop@ <= 3
- *((npy_bool *)dataptr[@nop@]) = accum || *((npy_bool *)dataptr[@nop@]);
-# else
- *((npy_bool *)dataptr[nop]) = accum || *((npy_bool *)dataptr[nop]);
-# endif
-}
-
-/**end repeat**/
-
-typedef void (*sum_of_products_fn)(int, char **, npy_intp const*, npy_intp);
-
-/* These tables need to match up with the type enum */
-static sum_of_products_fn
-_contig_outstride0_unary_specialization_table[NPY_NTYPES] = {
-/**begin repeat
- * #name = bool,
- * byte, ubyte,
- * short, ushort,
- * int, uint,
- * long, ulong,
- * longlong, ulonglong,
- * float, double, longdouble,
- * cfloat, cdouble, clongdouble,
- * object, string, unicode, void,
- * datetime, timedelta, half#
- * #use = 0,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1, 1,
- * 1, 1, 1,
- * 0, 0, 0, 0,
- * 0, 0, 1#
- */
-#if @use@
- &@name@_sum_of_products_contig_outstride0_one,
-#else
- NULL,
-#endif
-/**end repeat**/
-}; /* End of _contig_outstride0_unary_specialization_table */
-
-static sum_of_products_fn _binary_specialization_table[NPY_NTYPES][5] = {
-/**begin repeat
- * #name = bool,
- * byte, ubyte,
- * short, ushort,
- * int, uint,
- * long, ulong,
- * longlong, ulonglong,
- * float, double, longdouble,
- * cfloat, cdouble, clongdouble,
- * object, string, unicode, void,
- * datetime, timedelta, half#
- * #use = 0,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1, 1,
- * 0, 0, 0,
- * 0, 0, 0, 0,
- * 0, 0, 1#
- */
-#if @use@
-{
- &@name@_sum_of_products_stride0_contig_outstride0_two,
- &@name@_sum_of_products_stride0_contig_outcontig_two,
- &@name@_sum_of_products_contig_stride0_outstride0_two,
- &@name@_sum_of_products_contig_stride0_outcontig_two,
- &@name@_sum_of_products_contig_contig_outstride0_two,
-},
-#else
- {NULL, NULL, NULL, NULL, NULL},
-#endif
-/**end repeat**/
-}; /* End of _binary_specialization_table */
-
-static sum_of_products_fn _outstride0_specialized_table[NPY_NTYPES][4] = {
-/**begin repeat
- * #name = bool,
- * byte, ubyte,
- * short, ushort,
- * int, uint,
- * long, ulong,
- * longlong, ulonglong,
- * float, double, longdouble,
- * cfloat, cdouble, clongdouble,
- * object, string, unicode, void,
- * datetime, timedelta, half#
- * #use = 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1, 1,
- * 1, 1, 1,
- * 0, 0, 0, 0,
- * 0, 0, 1#
- */
-#if @use@
-{
- &@name@_sum_of_products_outstride0_any,
- &@name@_sum_of_products_outstride0_one,
- &@name@_sum_of_products_outstride0_two,
- &@name@_sum_of_products_outstride0_three
-},
-#else
- {NULL, NULL, NULL, NULL},
-#endif
-/**end repeat**/
-}; /* End of _outstride0_specialized_table */
-
-static sum_of_products_fn _allcontig_specialized_table[NPY_NTYPES][4] = {
-/**begin repeat
- * #name = bool,
- * byte, ubyte,
- * short, ushort,
- * int, uint,
- * long, ulong,
- * longlong, ulonglong,
- * float, double, longdouble,
- * cfloat, cdouble, clongdouble,
- * object, string, unicode, void,
- * datetime, timedelta, half#
- * #use = 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1, 1,
- * 1, 1, 1,
- * 0, 0, 0, 0,
- * 0, 0, 1#
- */
-#if @use@
-{
- &@name@_sum_of_products_contig_any,
- &@name@_sum_of_products_contig_one,
- &@name@_sum_of_products_contig_two,
- &@name@_sum_of_products_contig_three
-},
-#else
- {NULL, NULL, NULL, NULL},
-#endif
-/**end repeat**/
-}; /* End of _allcontig_specialized_table */
-
-static sum_of_products_fn _unspecialized_table[NPY_NTYPES][4] = {
-/**begin repeat
- * #name = bool,
- * byte, ubyte,
- * short, ushort,
- * int, uint,
- * long, ulong,
- * longlong, ulonglong,
- * float, double, longdouble,
- * cfloat, cdouble, clongdouble,
- * object, string, unicode, void,
- * datetime, timedelta, half#
- * #use = 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1,
- * 1, 1, 1,
- * 1, 1, 1,
- * 0, 0, 0, 0,
- * 0, 0, 1#
- */
-#if @use@
-{
- &@name@_sum_of_products_any,
- &@name@_sum_of_products_one,
- &@name@_sum_of_products_two,
- &@name@_sum_of_products_three
-},
-#else
- {NULL, NULL, NULL, NULL},
-#endif
-/**end repeat**/
-}; /* End of _unnspecialized_table */
-
-static sum_of_products_fn
-get_sum_of_products_function(int nop, int type_num,
- npy_intp itemsize, npy_intp const *fixed_strides)
-{
- int iop;
-
- if (type_num >= NPY_NTYPES) {
- return NULL;
- }
-
- /* contiguous reduction */
- if (nop == 1 && fixed_strides[0] == itemsize && fixed_strides[1] == 0) {
- sum_of_products_fn ret =
- _contig_outstride0_unary_specialization_table[type_num];
- if (ret != NULL) {
- return ret;
- }
- }
-
- /* nop of 2 has more specializations */
- if (nop == 2) {
- /* Encode the zero/contiguous strides */
- int code;
- code = (fixed_strides[0] == 0) ? 0 :
- (fixed_strides[0] == itemsize) ? 2*2*1 : 8;
- code += (fixed_strides[1] == 0) ? 0 :
- (fixed_strides[1] == itemsize) ? 2*1 : 8;
- code += (fixed_strides[2] == 0) ? 0 :
- (fixed_strides[2] == itemsize) ? 1 : 8;
- if (code >= 2 && code < 7) {
- sum_of_products_fn ret =
- _binary_specialization_table[type_num][code-2];
- if (ret != NULL) {
- return ret;
- }
- }
- }
-
- /* Inner loop with an output stride of 0 */
- if (fixed_strides[nop] == 0) {
- return _outstride0_specialized_table[type_num][nop <= 3 ? nop : 0];
- }
-
- /* Check for all contiguous */
- for (iop = 0; iop < nop + 1; ++iop) {
- if (fixed_strides[iop] != itemsize) {
- break;
- }
- }
-
- /* Contiguous loop */
- if (iop == nop + 1) {
- return _allcontig_specialized_table[type_num][nop <= 3 ? nop : 0];
- }
-
- /* None of the above specializations caught it, general loops */
- return _unspecialized_table[type_num][nop <= 3 ? nop : 0];
-}
+#include "einsum_sumprod.h"
+#include "einsum_debug.h"
/*
op_axes[nop][idim] = idim;
}
for (idim = ndim_output; idim < ndim_iter; ++idim) {
- op_axes[nop][idim] = -1;
+ op_axes[nop][idim] = NPY_ITER_REDUCTION_AXIS(-1);
}
/* Set the iterator per-op flags */
op_flags[nop] = NPY_ITER_READWRITE|
NPY_ITER_NBO|
NPY_ITER_ALIGNED|
- NPY_ITER_ALLOCATE|
- NPY_ITER_NO_BROADCAST;
+ NPY_ITER_ALLOCATE;
iter_flags = NPY_ITER_EXTERNAL_LOOP|
NPY_ITER_BUFFERED|
NPY_ITER_DELAY_BUFALLOC|
NPY_ITER_GROWINNER|
- NPY_ITER_REDUCE_OK|
NPY_ITER_REFS_OK|
NPY_ITER_ZEROSIZE_OK;
if (out != NULL) {
--- /dev/null
+/*
+ * This file provides debug macros used by the other einsum files.
+ *
+ * Copyright (c) 2011 by Mark Wiebe (mwwiebe@gmail.com)
+ * The University of British Columbia
+ *
+ * See LICENSE.txt for the license.
+ */
+#ifndef _NPY_MULTIARRAY_EINSUM_DEBUG_H
+#define _NPY_MULTIARRAY_EINSUM_DEBUG_H
+
+/********** PRINTF DEBUG TRACING **************/
+#define NPY_EINSUM_DBG_TRACING 0
+
+#if NPY_EINSUM_DBG_TRACING
+#include <cstdio>
+#define NPY_EINSUM_DBG_PRINT(s) printf("%s", s);
+#define NPY_EINSUM_DBG_PRINT1(s, p1) printf(s, p1);
+#define NPY_EINSUM_DBG_PRINT2(s, p1, p2) printf(s, p1, p2);
+#define NPY_EINSUM_DBG_PRINT3(s, p1, p2, p3) printf(s);
+#else
+#define NPY_EINSUM_DBG_PRINT(s)
+#define NPY_EINSUM_DBG_PRINT1(s, p1)
+#define NPY_EINSUM_DBG_PRINT2(s, p1, p2)
+#define NPY_EINSUM_DBG_PRINT3(s, p1, p2, p3)
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file provides optimized sum of product implementations used internally
+ * by einsum.
+ *
+ * Copyright (c) 2011 by Mark Wiebe (mwwiebe@gmail.com)
+ * The University of British Columbia
+ *
+ * See LICENSE.txt for the license.
+ */
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _MULTIARRAYMODULE
+
+#include <numpy/npy_common.h>
+#include <numpy/ndarraytypes.h> /* for NPY_NTYPES */
+#include <numpy/halffloat.h>
+
+#include "einsum_sumprod.h"
+#include "einsum_debug.h"
+
+
+#ifdef NPY_HAVE_SSE_INTRINSICS
+#define EINSUM_USE_SSE1 1
+#else
+#define EINSUM_USE_SSE1 0
+#endif
+
+#ifdef NPY_HAVE_SSE2_INTRINSICS
+#define EINSUM_USE_SSE2 1
+#else
+#define EINSUM_USE_SSE2 0
+#endif
+
+#if EINSUM_USE_SSE1
+#include <xmmintrin.h>
+#endif
+
+#if EINSUM_USE_SSE2
+#include <emmintrin.h>
+#endif
+
+#define EINSUM_IS_SSE_ALIGNED(x) ((((npy_intp)x)&0xf) == 0)
+
+/**********************************************/
+
+/**begin repeat
+ * #name = byte, short, int, long, longlong,
+ * ubyte, ushort, uint, ulong, ulonglong,
+ * half, float, double, longdouble,
+ * cfloat, cdouble, clongdouble#
+ * #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong,
+ * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong,
+ * npy_half, npy_float, npy_double, npy_longdouble,
+ * npy_cfloat, npy_cdouble, npy_clongdouble#
+ * #temptype = npy_byte, npy_short, npy_int, npy_long, npy_longlong,
+ * npy_ubyte, npy_ushort, npy_uint, npy_ulong, npy_ulonglong,
+ * npy_float, npy_float, npy_double, npy_longdouble,
+ * npy_float, npy_double, npy_longdouble#
+ * #to = ,,,,,
+ * ,,,,,
+ * npy_float_to_half,,,,
+ * ,,#
+ * #from = ,,,,,
+ * ,,,,,
+ * npy_half_to_float,,,,
+ * ,,#
+ * #complex = 0*5,
+ * 0*5,
+ * 0*4,
+ * 1*3#
+ * #float32 = 0*5,
+ * 0*5,
+ * 0,1,0,0,
+ * 0*3#
+ * #float64 = 0*5,
+ * 0*5,
+ * 0,0,1,0,
+ * 0*3#
+ */
+
+/**begin repeat1
+ * #nop = 1, 2, 3, 1000#
+ * #noplabel = one, two, three, any#
+ */
+static void
+@name@_sum_of_products_@noplabel@(int nop, char **dataptr,
+ npy_intp const *strides, npy_intp count)
+{
+#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@)
+ char *data0 = dataptr[0];
+ npy_intp stride0 = strides[0];
+#endif
+#if (@nop@ == 2 || @nop@ == 3) && !@complex@
+ char *data1 = dataptr[1];
+ npy_intp stride1 = strides[1];
+#endif
+#if (@nop@ == 3) && !@complex@
+ char *data2 = dataptr[2];
+ npy_intp stride2 = strides[2];
+#endif
+#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@)
+ char *data_out = dataptr[@nop@];
+ npy_intp stride_out = strides[@nop@];
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_@noplabel@ (%d)\n", (int)count);
+
+ while (count--) {
+#if !@complex@
+# if @nop@ == 1
+ *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) +
+ @from@(*(@type@ *)data_out));
+ data0 += stride0;
+ data_out += stride_out;
+# elif @nop@ == 2
+ *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) *
+ @from@(*(@type@ *)data1) +
+ @from@(*(@type@ *)data_out));
+ data0 += stride0;
+ data1 += stride1;
+ data_out += stride_out;
+# elif @nop@ == 3
+ *(@type@ *)data_out = @to@(@from@(*(@type@ *)data0) *
+ @from@(*(@type@ *)data1) *
+ @from@(*(@type@ *)data2) +
+ @from@(*(@type@ *)data_out));
+ data0 += stride0;
+ data1 += stride1;
+ data2 += stride2;
+ data_out += stride_out;
+# else
+ @temptype@ temp = @from@(*(@type@ *)dataptr[0]);
+ int i;
+ for (i = 1; i < nop; ++i) {
+ temp *= @from@(*(@type@ *)dataptr[i]);
+ }
+ *(@type@ *)dataptr[nop] = @to@(temp +
+ @from@(*(@type@ *)dataptr[i]));
+ for (i = 0; i <= nop; ++i) {
+ dataptr[i] += strides[i];
+ }
+# endif
+#else /* complex */
+# if @nop@ == 1
+ ((@temptype@ *)data_out)[0] = ((@temptype@ *)data0)[0] +
+ ((@temptype@ *)data_out)[0];
+ ((@temptype@ *)data_out)[1] = ((@temptype@ *)data0)[1] +
+ ((@temptype@ *)data_out)[1];
+ data0 += stride0;
+ data_out += stride_out;
+# else
+# if @nop@ <= 3
+#define _SUMPROD_NOP @nop@
+# else
+#define _SUMPROD_NOP nop
+# endif
+ @temptype@ re, im, tmp;
+ int i;
+ re = ((@temptype@ *)dataptr[0])[0];
+ im = ((@temptype@ *)dataptr[0])[1];
+ for (i = 1; i < _SUMPROD_NOP; ++i) {
+ tmp = re * ((@temptype@ *)dataptr[i])[0] -
+ im * ((@temptype@ *)dataptr[i])[1];
+ im = re * ((@temptype@ *)dataptr[i])[1] +
+ im * ((@temptype@ *)dataptr[i])[0];
+ re = tmp;
+ }
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[0] = re +
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[0];
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[1] = im +
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[1];
+
+ for (i = 0; i <= _SUMPROD_NOP; ++i) {
+ dataptr[i] += strides[i];
+ }
+#undef _SUMPROD_NOP
+# endif
+#endif
+ }
+}
+
+#if @nop@ == 1
+
+static void
+@name@_sum_of_products_contig_one(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @type@ *data0 = (@type@ *)dataptr[0];
+ @type@ *data_out = (@type@ *)dataptr[1];
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_one (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+#if !@complex@
+ data_out[@i@] = @to@(@from@(data0[@i@]) +
+ @from@(data_out[@i@]));
+#else
+ ((@temptype@ *)data_out + 2*@i@)[0] =
+ ((@temptype@ *)data0 + 2*@i@)[0] +
+ ((@temptype@ *)data_out + 2*@i@)[0];
+ ((@temptype@ *)data_out + 2*@i@)[1] =
+ ((@temptype@ *)data0 + 2*@i@)[1] +
+ ((@temptype@ *)data_out + 2*@i@)[1];
+#endif
+/**end repeat2**/
+ case 0:
+ return;
+ }
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+#if !@complex@
+ data_out[@i@] = @to@(@from@(data0[@i@]) +
+ @from@(data_out[@i@]));
+#else /* complex */
+ ((@temptype@ *)data_out + 2*@i@)[0] =
+ ((@temptype@ *)data0 + 2*@i@)[0] +
+ ((@temptype@ *)data_out + 2*@i@)[0];
+ ((@temptype@ *)data_out + 2*@i@)[1] =
+ ((@temptype@ *)data0 + 2*@i@)[1] +
+ ((@temptype@ *)data_out + 2*@i@)[1];
+#endif
+/**end repeat2**/
+ data0 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+}
+
+#elif @nop@ == 2 && !@complex@
+
+static void
+@name@_sum_of_products_contig_two(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @type@ *data0 = (@type@ *)dataptr[0];
+ @type@ *data1 = (@type@ *)dataptr[1];
+ @type@ *data_out = (@type@ *)dataptr[2];
+
+#if EINSUM_USE_SSE1 && @float32@
+ __m128 a, b;
+#elif EINSUM_USE_SSE2 && @float64@
+ __m128d a, b;
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_two (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+ data_out[@i@] = @to@(@from@(data0[@i@]) *
+ @from@(data1[@i@]) +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+ case 0:
+ return;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1) &&
+ EINSUM_IS_SSE_ALIGNED(data_out)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ a = _mm_mul_ps(_mm_load_ps(data0+@i@), _mm_load_ps(data1+@i@));
+ b = _mm_add_ps(a, _mm_load_ps(data_out+@i@));
+ _mm_store_ps(data_out+@i@, b);
+/**end repeat2**/
+ data0 += 8;
+ data1 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1) &&
+ EINSUM_IS_SSE_ALIGNED(data_out)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ a = _mm_mul_pd(_mm_load_pd(data0+@i@), _mm_load_pd(data1+@i@));
+ b = _mm_add_pd(a, _mm_load_pd(data_out+@i@));
+ _mm_store_pd(data_out+@i@, b);
+/**end repeat2**/
+ data0 += 8;
+ data1 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#endif
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+#if EINSUM_USE_SSE1 && @float32@
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), _mm_loadu_ps(data1+@i@));
+ b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@));
+ _mm_storeu_ps(data_out+@i@, b);
+/**end repeat2**/
+#elif EINSUM_USE_SSE2 && @float64@
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ a = _mm_mul_pd(_mm_loadu_pd(data0+@i@), _mm_loadu_pd(data1+@i@));
+ b = _mm_add_pd(a, _mm_loadu_pd(data_out+@i@));
+ _mm_storeu_pd(data_out+@i@, b);
+/**end repeat2**/
+#else
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ data_out[@i@] = @to@(@from@(data0[@i@]) *
+ @from@(data1[@i@]) +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+#endif
+ data0 += 8;
+ data1 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+}
+
+/* Some extra specializations for the two operand case */
+static void
+@name@_sum_of_products_stride0_contig_outcontig_two(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @temptype@ value0 = @from@(*(@type@ *)dataptr[0]);
+ @type@ *data1 = (@type@ *)dataptr[1];
+ @type@ *data_out = (@type@ *)dataptr[2];
+
+#if EINSUM_USE_SSE1 && @float32@
+ __m128 a, b, value0_sse;
+#elif EINSUM_USE_SSE2 && @float64@
+ __m128d a, b, value0_sse;
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_stride0_contig_outcontig_two (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+ data_out[@i@] = @to@(value0 *
+ @from@(data1[@i@]) +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+ case 0:
+ return;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ value0_sse = _mm_set_ps1(value0);
+
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data1) && EINSUM_IS_SSE_ALIGNED(data_out)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ a = _mm_mul_ps(value0_sse, _mm_load_ps(data1+@i@));
+ b = _mm_add_ps(a, _mm_load_ps(data_out+@i@));
+ _mm_store_ps(data_out+@i@, b);
+/**end repeat2**/
+ data1 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ if (count > 0) {
+ goto finish_after_unrolled_loop;
+ }
+ else {
+ return;
+ }
+ }
+#elif EINSUM_USE_SSE2 && @float64@
+ value0_sse = _mm_set1_pd(value0);
+
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data1) && EINSUM_IS_SSE_ALIGNED(data_out)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ a = _mm_mul_pd(value0_sse, _mm_load_pd(data1+@i@));
+ b = _mm_add_pd(a, _mm_load_pd(data_out+@i@));
+ _mm_store_pd(data_out+@i@, b);
+/**end repeat2**/
+ data1 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ if (count > 0) {
+ goto finish_after_unrolled_loop;
+ }
+ else {
+ return;
+ }
+ }
+#endif
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+#if EINSUM_USE_SSE1 && @float32@
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ a = _mm_mul_ps(value0_sse, _mm_loadu_ps(data1+@i@));
+ b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@));
+ _mm_storeu_ps(data_out+@i@, b);
+/**end repeat2**/
+#elif EINSUM_USE_SSE2 && @float64@
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ a = _mm_mul_pd(value0_sse, _mm_loadu_pd(data1+@i@));
+ b = _mm_add_pd(a, _mm_loadu_pd(data_out+@i@));
+ _mm_storeu_pd(data_out+@i@, b);
+/**end repeat2**/
+#else
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ data_out[@i@] = @to@(value0 *
+ @from@(data1[@i@]) +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+#endif
+ data1 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ if (count > 0) {
+ goto finish_after_unrolled_loop;
+ }
+}
+
+static void
+@name@_sum_of_products_contig_stride0_outcontig_two(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @type@ *data0 = (@type@ *)dataptr[0];
+ @temptype@ value1 = @from@(*(@type@ *)dataptr[1]);
+ @type@ *data_out = (@type@ *)dataptr[2];
+
+#if EINSUM_USE_SSE1 && @float32@
+ __m128 a, b, value1_sse;
+#elif EINSUM_USE_SSE2 && @float64@
+ __m128d a, b, value1_sse;
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_stride0_outcontig_two (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+ data_out[@i@] = @to@(@from@(data0[@i@])*
+ value1 +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+ case 0:
+ return;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ value1_sse = _mm_set_ps1(value1);
+
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data_out)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ a = _mm_mul_ps(_mm_load_ps(data0+@i@), value1_sse);
+ b = _mm_add_ps(a, _mm_load_ps(data_out+@i@));
+ _mm_store_ps(data_out+@i@, b);
+/**end repeat2**/
+ data0 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#elif EINSUM_USE_SSE2 && @float64@
+ value1_sse = _mm_set1_pd(value1);
+
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data_out)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ a = _mm_mul_pd(_mm_load_pd(data0+@i@), value1_sse);
+ b = _mm_add_pd(a, _mm_load_pd(data_out+@i@));
+ _mm_store_pd(data_out+@i@, b);
+/**end repeat2**/
+ data0 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#endif
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+#if EINSUM_USE_SSE1 && @float32@
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), value1_sse);
+ b = _mm_add_ps(a, _mm_loadu_ps(data_out+@i@));
+ _mm_storeu_ps(data_out+@i@, b);
+/**end repeat2**/
+#elif EINSUM_USE_SSE2 && @float64@
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ a = _mm_mul_pd(_mm_loadu_pd(data0+@i@), value1_sse);
+ b = _mm_add_pd(a, _mm_loadu_pd(data_out+@i@));
+ _mm_storeu_pd(data_out+@i@, b);
+/**end repeat2**/
+#else
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ data_out[@i@] = @to@(@from@(data0[@i@])*
+ value1 +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+#endif
+ data0 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+}
+
+static void
+@name@_sum_of_products_contig_contig_outstride0_two(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @type@ *data0 = (@type@ *)dataptr[0];
+ @type@ *data1 = (@type@ *)dataptr[1];
+ @temptype@ accum = 0;
+
+#if EINSUM_USE_SSE1 && @float32@
+ __m128 a, accum_sse = _mm_setzero_ps();
+#elif EINSUM_USE_SSE2 && @float64@
+ __m128d a, accum_sse = _mm_setzero_pd();
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_contig_outstride0_two (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+ accum += @from@(data0[@i@]) * @from@(data1[@i@]);
+/**end repeat2**/
+ case 0:
+ *(@type@ *)dataptr[2] = @to@(@from@(*(@type@ *)dataptr[2]) + accum);
+ return;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+ _mm_prefetch(data1 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ a = _mm_mul_ps(_mm_load_ps(data0+@i@), _mm_load_ps(data1+@i@));
+ accum_sse = _mm_add_ps(accum_sse, a);
+/**end repeat2**/
+ data0 += 8;
+ data1 += 8;
+ }
+
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0) && EINSUM_IS_SSE_ALIGNED(data1)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+ _mm_prefetch(data1 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ a = _mm_mul_pd(_mm_load_pd(data0+@i@), _mm_load_pd(data1+@i@));
+ accum_sse = _mm_add_pd(accum_sse, a);
+/**end repeat2**/
+ data0 += 8;
+ data1 += 8;
+ }
+
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#endif
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+#if EINSUM_USE_SSE1 && @float32@
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+ _mm_prefetch(data1 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ a = _mm_mul_ps(_mm_loadu_ps(data0+@i@), _mm_loadu_ps(data1+@i@));
+ accum_sse = _mm_add_ps(accum_sse, a);
+/**end repeat2**/
+#elif EINSUM_USE_SSE2 && @float64@
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+ _mm_prefetch(data1 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ a = _mm_mul_pd(_mm_loadu_pd(data0+@i@), _mm_loadu_pd(data1+@i@));
+ accum_sse = _mm_add_pd(accum_sse, a);
+/**end repeat2**/
+#else
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ accum += @from@(data0[@i@]) * @from@(data1[@i@]);
+/**end repeat2**/
+#endif
+ data0 += 8;
+ data1 += 8;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+#endif
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+}
+
+static void
+@name@_sum_of_products_stride0_contig_outstride0_two(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @temptype@ value0 = @from@(*(@type@ *)dataptr[0]);
+ @type@ *data1 = (@type@ *)dataptr[1];
+ @temptype@ accum = 0;
+
+#if EINSUM_USE_SSE1 && @float32@
+ __m128 a, accum_sse = _mm_setzero_ps();
+#elif EINSUM_USE_SSE2 && @float64@
+ __m128d a, accum_sse = _mm_setzero_pd();
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_stride0_contig_outstride0_two (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+ accum += @from@(data1[@i@]);
+/**end repeat2**/
+ case 0:
+ *(@type@ *)dataptr[2] = @to@(@from@(*(@type@ *)dataptr[2]) + value0 * accum);
+ return;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data1)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data1+@i@));
+/**end repeat2**/
+ data1 += 8;
+ }
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data1)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_pd(accum_sse, _mm_load_pd(data1+@i@));
+/**end repeat2**/
+ data1 += 8;
+ }
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#endif
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+#if EINSUM_USE_SSE1 && @float32@
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data1+@i@));
+/**end repeat2**/
+#elif EINSUM_USE_SSE2 && @float64@
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_pd(accum_sse, _mm_loadu_pd(data1+@i@));
+/**end repeat2**/
+#else
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ accum += @from@(data1[@i@]);
+/**end repeat2**/
+#endif
+ data1 += 8;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+#endif
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+}
+
+static void
+@name@_sum_of_products_contig_stride0_outstride0_two(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @type@ *data0 = (@type@ *)dataptr[0];
+ @temptype@ value1 = @from@(*(@type@ *)dataptr[1]);
+ @temptype@ accum = 0;
+
+#if EINSUM_USE_SSE1 && @float32@
+ __m128 a, accum_sse = _mm_setzero_ps();
+#elif EINSUM_USE_SSE2 && @float64@
+ __m128d a, accum_sse = _mm_setzero_pd();
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_stride0_outstride0_two (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+ accum += @from@(data0[@i@]);
+/**end repeat2**/
+ case 0:
+ *(@type@ *)dataptr[2] = @to@(@from@(*(@type@ *)dataptr[2]) + accum * value1);
+ return;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data0+@i@));
+/**end repeat2**/
+ data0 += 8;
+ }
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_pd(accum_sse, _mm_load_pd(data0+@i@));
+/**end repeat2**/
+ data0 += 8;
+ }
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#endif
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+#if EINSUM_USE_SSE1 && @float32@
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data0+@i@));
+/**end repeat2**/
+#elif EINSUM_USE_SSE2 && @float64@
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_pd(accum_sse, _mm_loadu_pd(data0+@i@));
+/**end repeat2**/
+#else
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ accum += @from@(data0[@i@]);
+/**end repeat2**/
+#endif
+ data0 += 8;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+#endif
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+}
+
+#elif @nop@ == 3 && !@complex@
+
+static void
+@name@_sum_of_products_contig_three(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ @type@ *data0 = (@type@ *)dataptr[0];
+ @type@ *data1 = (@type@ *)dataptr[1];
+ @type@ *data2 = (@type@ *)dataptr[2];
+ @type@ *data_out = (@type@ *)dataptr[3];
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ data_out[@i@] = @to@(@from@(data0[@i@]) *
+ @from@(data1[@i@]) *
+ @from@(data2[@i@]) +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+ data0 += 8;
+ data1 += 8;
+ data2 += 8;
+ data_out += 8;
+ }
+
+ /* Finish off the loop */
+
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ if (count-- == 0) {
+ return;
+ }
+ data_out[@i@] = @to@(@from@(data0[@i@]) *
+ @from@(data1[@i@]) *
+ @from@(data2[@i@]) +
+ @from@(data_out[@i@]));
+/**end repeat2**/
+}
+
+#else /* @nop@ > 3 || @complex */
+
+static void
+@name@_sum_of_products_contig_@noplabel@(int nop, char **dataptr,
+ npy_intp const *NPY_UNUSED(strides), npy_intp count)
+{
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_@noplabel@ (%d)\n",
+ (int)count);
+
+ while (count--) {
+#if !@complex@
+ @temptype@ temp = @from@(*(@type@ *)dataptr[0]);
+ int i;
+ for (i = 1; i < nop; ++i) {
+ temp *= @from@(*(@type@ *)dataptr[i]);
+ }
+ *(@type@ *)dataptr[nop] = @to@(temp +
+ @from@(*(@type@ *)dataptr[i]));
+ for (i = 0; i <= nop; ++i) {
+ dataptr[i] += sizeof(@type@);
+ }
+#else /* complex */
+# if @nop@ <= 3
+# define _SUMPROD_NOP @nop@
+# else
+# define _SUMPROD_NOP nop
+# endif
+ @temptype@ re, im, tmp;
+ int i;
+ re = ((@temptype@ *)dataptr[0])[0];
+ im = ((@temptype@ *)dataptr[0])[1];
+ for (i = 1; i < _SUMPROD_NOP; ++i) {
+ tmp = re * ((@temptype@ *)dataptr[i])[0] -
+ im * ((@temptype@ *)dataptr[i])[1];
+ im = re * ((@temptype@ *)dataptr[i])[1] +
+ im * ((@temptype@ *)dataptr[i])[0];
+ re = tmp;
+ }
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[0] = re +
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[0];
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[1] = im +
+ ((@temptype@ *)dataptr[_SUMPROD_NOP])[1];
+
+ for (i = 0; i <= _SUMPROD_NOP; ++i) {
+ dataptr[i] += sizeof(@type@);
+ }
+# undef _SUMPROD_NOP
+#endif
+ }
+}
+
+#endif /* functions for various @nop@ */
+
+#if @nop@ == 1
+
+static void
+@name@_sum_of_products_contig_outstride0_one(int nop, char **dataptr,
+ npy_intp const *strides, npy_intp count)
+{
+#if @complex@
+ @temptype@ accum_re = 0, accum_im = 0;
+ @temptype@ *data0 = (@temptype@ *)dataptr[0];
+#else
+ @temptype@ accum = 0;
+ @type@ *data0 = (@type@ *)dataptr[0];
+#endif
+
+#if EINSUM_USE_SSE1 && @float32@
+ __m128 a, accum_sse = _mm_setzero_ps();
+#elif EINSUM_USE_SSE2 && @float64@
+ __m128d a, accum_sse = _mm_setzero_pd();
+#endif
+
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_contig_outstride0_one (%d)\n",
+ (int)count);
+
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat2
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+#if !@complex@
+ accum += @from@(data0[@i@]);
+#else /* complex */
+ accum_re += data0[2*@i@+0];
+ accum_im += data0[2*@i@+1];
+#endif
+/**end repeat2**/
+ case 0:
+#if @complex@
+ ((@temptype@ *)dataptr[1])[0] += accum_re;
+ ((@temptype@ *)dataptr[1])[1] += accum_im;
+#else
+ *((@type@ *)dataptr[1]) = @to@(accum +
+ @from@(*((@type@ *)dataptr[1])));
+#endif
+ return;
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_ps(accum_sse, _mm_load_ps(data0+@i@));
+/**end repeat2**/
+ data0 += 8;
+ }
+
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Use aligned instructions if possible */
+ if (EINSUM_IS_SSE_ALIGNED(data0)) {
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_pd(accum_sse, _mm_load_pd(data0+@i@));
+/**end repeat2**/
+ data0 += 8;
+ }
+
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+ }
+#endif
+
+ /* Unroll the loop by 8 */
+ while (count >= 8) {
+ count -= 8;
+
+#if EINSUM_USE_SSE1 && @float32@
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 4#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_ps(accum_sse, _mm_loadu_ps(data0+@i@));
+/**end repeat2**/
+#elif EINSUM_USE_SSE2 && @float64@
+ _mm_prefetch(data0 + 512, _MM_HINT_T0);
+
+/**begin repeat2
+ * #i = 0, 2, 4, 6#
+ */
+ /*
+ * NOTE: This accumulation changes the order, so will likely
+ * produce slightly different results.
+ */
+ accum_sse = _mm_add_pd(accum_sse, _mm_loadu_pd(data0+@i@));
+/**end repeat2**/
+#else
+/**begin repeat2
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+# if !@complex@
+ accum += @from@(data0[@i@]);
+# else /* complex */
+ accum_re += data0[2*@i@+0];
+ accum_im += data0[2*@i@+1];
+# endif
+/**end repeat2**/
+#endif
+
+#if !@complex@
+ data0 += 8;
+#else
+ data0 += 8*2;
+#endif
+ }
+
+#if EINSUM_USE_SSE1 && @float32@
+ /* Add the four SSE values and put in accum */
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(2,3,0,1));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ a = _mm_shuffle_ps(accum_sse, accum_sse, _MM_SHUFFLE(1,0,3,2));
+ accum_sse = _mm_add_ps(a, accum_sse);
+ _mm_store_ss(&accum, accum_sse);
+#elif EINSUM_USE_SSE2 && @float64@
+ /* Add the two SSE2 values and put in accum */
+ a = _mm_shuffle_pd(accum_sse, accum_sse, _MM_SHUFFLE2(0,1));
+ accum_sse = _mm_add_pd(a, accum_sse);
+ _mm_store_sd(&accum, accum_sse);
+#endif
+
+ /* Finish off the loop */
+ goto finish_after_unrolled_loop;
+}
+
+#endif /* @nop@ == 1 */
+
+static void
+@name@_sum_of_products_outstride0_@noplabel@(int nop, char **dataptr,
+ npy_intp const *strides, npy_intp count)
+{
+#if @complex@
+ @temptype@ accum_re = 0, accum_im = 0;
+#else
+ @temptype@ accum = 0;
+#endif
+
+#if (@nop@ == 1) || (@nop@ <= 3 && !@complex@)
+ char *data0 = dataptr[0];
+ npy_intp stride0 = strides[0];
+#endif
+#if (@nop@ == 2 || @nop@ == 3) && !@complex@
+ char *data1 = dataptr[1];
+ npy_intp stride1 = strides[1];
+#endif
+#if (@nop@ == 3) && !@complex@
+ char *data2 = dataptr[2];
+ npy_intp stride2 = strides[2];
+#endif
+
+ NPY_EINSUM_DBG_PRINT1("@name@_sum_of_products_outstride0_@noplabel@ (%d)\n",
+ (int)count);
+
+ while (count--) {
+#if !@complex@
+# if @nop@ == 1
+ accum += @from@(*(@type@ *)data0);
+ data0 += stride0;
+# elif @nop@ == 2
+ accum += @from@(*(@type@ *)data0) *
+ @from@(*(@type@ *)data1);
+ data0 += stride0;
+ data1 += stride1;
+# elif @nop@ == 3
+ accum += @from@(*(@type@ *)data0) *
+ @from@(*(@type@ *)data1) *
+ @from@(*(@type@ *)data2);
+ data0 += stride0;
+ data1 += stride1;
+ data2 += stride2;
+# else
+ @temptype@ temp = @from@(*(@type@ *)dataptr[0]);
+ int i;
+ for (i = 1; i < nop; ++i) {
+ temp *= @from@(*(@type@ *)dataptr[i]);
+ }
+ accum += temp;
+ for (i = 0; i < nop; ++i) {
+ dataptr[i] += strides[i];
+ }
+# endif
+#else /* complex */
+# if @nop@ == 1
+ accum_re += ((@temptype@ *)data0)[0];
+ accum_im += ((@temptype@ *)data0)[1];
+ data0 += stride0;
+# else
+# if @nop@ <= 3
+#define _SUMPROD_NOP @nop@
+# else
+#define _SUMPROD_NOP nop
+# endif
+ @temptype@ re, im, tmp;
+ int i;
+ re = ((@temptype@ *)dataptr[0])[0];
+ im = ((@temptype@ *)dataptr[0])[1];
+ for (i = 1; i < _SUMPROD_NOP; ++i) {
+ tmp = re * ((@temptype@ *)dataptr[i])[0] -
+ im * ((@temptype@ *)dataptr[i])[1];
+ im = re * ((@temptype@ *)dataptr[i])[1] +
+ im * ((@temptype@ *)dataptr[i])[0];
+ re = tmp;
+ }
+ accum_re += re;
+ accum_im += im;
+ for (i = 0; i < _SUMPROD_NOP; ++i) {
+ dataptr[i] += strides[i];
+ }
+#undef _SUMPROD_NOP
+# endif
+#endif
+ }
+
+#if @complex@
+# if @nop@ <= 3
+ ((@temptype@ *)dataptr[@nop@])[0] += accum_re;
+ ((@temptype@ *)dataptr[@nop@])[1] += accum_im;
+# else
+ ((@temptype@ *)dataptr[nop])[0] += accum_re;
+ ((@temptype@ *)dataptr[nop])[1] += accum_im;
+# endif
+#else
+# if @nop@ <= 3
+ *((@type@ *)dataptr[@nop@]) = @to@(accum +
+ @from@(*((@type@ *)dataptr[@nop@])));
+# else
+ *((@type@ *)dataptr[nop]) = @to@(accum +
+ @from@(*((@type@ *)dataptr[nop])));
+# endif
+#endif
+
+}
+
+/**end repeat1**/
+
+/**end repeat**/
+
+
+/* Do OR of ANDs for the boolean type */
+
+/**begin repeat
+ * #nop = 1, 2, 3, 1000#
+ * #noplabel = one, two, three, any#
+ */
+
+static void
+bool_sum_of_products_@noplabel@(int nop, char **dataptr,
+ npy_intp const *strides, npy_intp count)
+{
+#if (@nop@ <= 3)
+ char *data0 = dataptr[0];
+ npy_intp stride0 = strides[0];
+#endif
+#if (@nop@ == 2 || @nop@ == 3)
+ char *data1 = dataptr[1];
+ npy_intp stride1 = strides[1];
+#endif
+#if (@nop@ == 3)
+ char *data2 = dataptr[2];
+ npy_intp stride2 = strides[2];
+#endif
+#if (@nop@ <= 3)
+ char *data_out = dataptr[@nop@];
+ npy_intp stride_out = strides[@nop@];
+#endif
+
+ while (count--) {
+#if @nop@ == 1
+ *(npy_bool *)data_out = *(npy_bool *)data0 ||
+ *(npy_bool *)data_out;
+ data0 += stride0;
+ data_out += stride_out;
+#elif @nop@ == 2
+ *(npy_bool *)data_out = (*(npy_bool *)data0 &&
+ *(npy_bool *)data1) ||
+ *(npy_bool *)data_out;
+ data0 += stride0;
+ data1 += stride1;
+ data_out += stride_out;
+#elif @nop@ == 3
+ *(npy_bool *)data_out = (*(npy_bool *)data0 &&
+ *(npy_bool *)data1 &&
+ *(npy_bool *)data2) ||
+ *(npy_bool *)data_out;
+ data0 += stride0;
+ data1 += stride1;
+ data2 += stride2;
+ data_out += stride_out;
+#else
+ npy_bool temp = *(npy_bool *)dataptr[0];
+ int i;
+ for (i = 1; i < nop; ++i) {
+ temp = temp && *(npy_bool *)dataptr[i];
+ }
+ *(npy_bool *)dataptr[nop] = temp || *(npy_bool *)dataptr[i];
+ for (i = 0; i <= nop; ++i) {
+ dataptr[i] += strides[i];
+ }
+#endif
+ }
+}
+
+static void
+bool_sum_of_products_contig_@noplabel@(int nop, char **dataptr,
+ npy_intp const *strides, npy_intp count)
+{
+#if (@nop@ <= 3)
+ char *data0 = dataptr[0];
+#endif
+#if (@nop@ == 2 || @nop@ == 3)
+ char *data1 = dataptr[1];
+#endif
+#if (@nop@ == 3)
+ char *data2 = dataptr[2];
+#endif
+#if (@nop@ <= 3)
+ char *data_out = dataptr[@nop@];
+#endif
+
+#if (@nop@ <= 3)
+/* This is placed before the main loop to make small counts faster */
+finish_after_unrolled_loop:
+ switch (count) {
+/**begin repeat1
+ * #i = 6, 5, 4, 3, 2, 1, 0#
+ */
+ case @i@+1:
+# if @nop@ == 1
+ ((npy_bool *)data_out)[@i@] = ((npy_bool *)data0)[@i@] ||
+ ((npy_bool *)data_out)[@i@];
+# elif @nop@ == 2
+ ((npy_bool *)data_out)[@i@] =
+ (((npy_bool *)data0)[@i@] &&
+ ((npy_bool *)data1)[@i@]) ||
+ ((npy_bool *)data_out)[@i@];
+# elif @nop@ == 3
+ ((npy_bool *)data_out)[@i@] =
+ (((npy_bool *)data0)[@i@] &&
+ ((npy_bool *)data1)[@i@] &&
+ ((npy_bool *)data2)[@i@]) ||
+ ((npy_bool *)data_out)[@i@];
+# endif
+/**end repeat1**/
+ case 0:
+ return;
+ }
+#endif
+
+/* Unroll the loop by 8 for fixed-size nop */
+#if (@nop@ <= 3)
+ while (count >= 8) {
+ count -= 8;
+#else
+ while (count--) {
+#endif
+
+# if @nop@ == 1
+/**begin repeat1
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ *((npy_bool *)data_out + @i@) = (*((npy_bool *)data0 + @i@)) ||
+ (*((npy_bool *)data_out + @i@));
+/**end repeat1**/
+ data0 += 8*sizeof(npy_bool);
+ data_out += 8*sizeof(npy_bool);
+# elif @nop@ == 2
+/**begin repeat1
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ *((npy_bool *)data_out + @i@) =
+ ((*((npy_bool *)data0 + @i@)) &&
+ (*((npy_bool *)data1 + @i@))) ||
+ (*((npy_bool *)data_out + @i@));
+/**end repeat1**/
+ data0 += 8*sizeof(npy_bool);
+ data1 += 8*sizeof(npy_bool);
+ data_out += 8*sizeof(npy_bool);
+# elif @nop@ == 3
+/**begin repeat1
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+ *((npy_bool *)data_out + @i@) =
+ ((*((npy_bool *)data0 + @i@)) &&
+ (*((npy_bool *)data1 + @i@)) &&
+ (*((npy_bool *)data2 + @i@))) ||
+ (*((npy_bool *)data_out + @i@));
+/**end repeat1**/
+ data0 += 8*sizeof(npy_bool);
+ data1 += 8*sizeof(npy_bool);
+ data2 += 8*sizeof(npy_bool);
+ data_out += 8*sizeof(npy_bool);
+# else
+ npy_bool temp = *(npy_bool *)dataptr[0];
+ int i;
+ for (i = 1; i < nop; ++i) {
+ temp = temp && *(npy_bool *)dataptr[i];
+ }
+ *(npy_bool *)dataptr[nop] = temp || *(npy_bool *)dataptr[i];
+ for (i = 0; i <= nop; ++i) {
+ dataptr[i] += sizeof(npy_bool);
+ }
+# endif
+ }
+
+ /* If the loop was unrolled, we need to finish it off */
+#if (@nop@ <= 3)
+ goto finish_after_unrolled_loop;
+#endif
+}
+
+static void
+bool_sum_of_products_outstride0_@noplabel@(int nop, char **dataptr,
+ npy_intp const *strides, npy_intp count)
+{
+ npy_bool accum = 0;
+
+#if (@nop@ <= 3)
+ char *data0 = dataptr[0];
+ npy_intp stride0 = strides[0];
+#endif
+#if (@nop@ == 2 || @nop@ == 3)
+ char *data1 = dataptr[1];
+ npy_intp stride1 = strides[1];
+#endif
+#if (@nop@ == 3)
+ char *data2 = dataptr[2];
+ npy_intp stride2 = strides[2];
+#endif
+
+ while (count--) {
+#if @nop@ == 1
+ accum = *(npy_bool *)data0 || accum;
+ data0 += stride0;
+#elif @nop@ == 2
+ accum = (*(npy_bool *)data0 && *(npy_bool *)data1) || accum;
+ data0 += stride0;
+ data1 += stride1;
+#elif @nop@ == 3
+ accum = (*(npy_bool *)data0 &&
+ *(npy_bool *)data1 &&
+ *(npy_bool *)data2) || accum;
+ data0 += stride0;
+ data1 += stride1;
+ data2 += stride2;
+#else
+ npy_bool temp = *(npy_bool *)dataptr[0];
+ int i;
+ for (i = 1; i < nop; ++i) {
+ temp = temp && *(npy_bool *)dataptr[i];
+ }
+ accum = temp || accum;
+ for (i = 0; i <= nop; ++i) {
+ dataptr[i] += strides[i];
+ }
+#endif
+ }
+
+# if @nop@ <= 3
+ *((npy_bool *)dataptr[@nop@]) = accum || *((npy_bool *)dataptr[@nop@]);
+# else
+ *((npy_bool *)dataptr[nop]) = accum || *((npy_bool *)dataptr[nop]);
+# endif
+}
+
+/**end repeat**/
+
+/* These tables need to match up with the type enum */
+static sum_of_products_fn
+_contig_outstride0_unary_specialization_table[NPY_NTYPES] = {
+/**begin repeat
+ * #name = bool,
+ * byte, ubyte,
+ * short, ushort,
+ * int, uint,
+ * long, ulong,
+ * longlong, ulonglong,
+ * float, double, longdouble,
+ * cfloat, cdouble, clongdouble,
+ * object, string, unicode, void,
+ * datetime, timedelta, half#
+ * #use = 0,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1, 1,
+ * 1, 1, 1,
+ * 0, 0, 0, 0,
+ * 0, 0, 1#
+ */
+#if @use@
+ &@name@_sum_of_products_contig_outstride0_one,
+#else
+ NULL,
+#endif
+/**end repeat**/
+}; /* End of _contig_outstride0_unary_specialization_table */
+
+static sum_of_products_fn _binary_specialization_table[NPY_NTYPES][5] = {
+/**begin repeat
+ * #name = bool,
+ * byte, ubyte,
+ * short, ushort,
+ * int, uint,
+ * long, ulong,
+ * longlong, ulonglong,
+ * float, double, longdouble,
+ * cfloat, cdouble, clongdouble,
+ * object, string, unicode, void,
+ * datetime, timedelta, half#
+ * #use = 0,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1, 1,
+ * 0, 0, 0,
+ * 0, 0, 0, 0,
+ * 0, 0, 1#
+ */
+#if @use@
+{
+ &@name@_sum_of_products_stride0_contig_outstride0_two,
+ &@name@_sum_of_products_stride0_contig_outcontig_two,
+ &@name@_sum_of_products_contig_stride0_outstride0_two,
+ &@name@_sum_of_products_contig_stride0_outcontig_two,
+ &@name@_sum_of_products_contig_contig_outstride0_two,
+},
+#else
+ {NULL, NULL, NULL, NULL, NULL},
+#endif
+/**end repeat**/
+}; /* End of _binary_specialization_table */
+
+static sum_of_products_fn _outstride0_specialized_table[NPY_NTYPES][4] = {
+/**begin repeat
+ * #name = bool,
+ * byte, ubyte,
+ * short, ushort,
+ * int, uint,
+ * long, ulong,
+ * longlong, ulonglong,
+ * float, double, longdouble,
+ * cfloat, cdouble, clongdouble,
+ * object, string, unicode, void,
+ * datetime, timedelta, half#
+ * #use = 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1, 1,
+ * 1, 1, 1,
+ * 0, 0, 0, 0,
+ * 0, 0, 1#
+ */
+#if @use@
+{
+ &@name@_sum_of_products_outstride0_any,
+ &@name@_sum_of_products_outstride0_one,
+ &@name@_sum_of_products_outstride0_two,
+ &@name@_sum_of_products_outstride0_three
+},
+#else
+ {NULL, NULL, NULL, NULL},
+#endif
+/**end repeat**/
+}; /* End of _outstride0_specialized_table */
+
+static sum_of_products_fn _allcontig_specialized_table[NPY_NTYPES][4] = {
+/**begin repeat
+ * #name = bool,
+ * byte, ubyte,
+ * short, ushort,
+ * int, uint,
+ * long, ulong,
+ * longlong, ulonglong,
+ * float, double, longdouble,
+ * cfloat, cdouble, clongdouble,
+ * object, string, unicode, void,
+ * datetime, timedelta, half#
+ * #use = 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1, 1,
+ * 1, 1, 1,
+ * 0, 0, 0, 0,
+ * 0, 0, 1#
+ */
+#if @use@
+{
+ &@name@_sum_of_products_contig_any,
+ &@name@_sum_of_products_contig_one,
+ &@name@_sum_of_products_contig_two,
+ &@name@_sum_of_products_contig_three
+},
+#else
+ {NULL, NULL, NULL, NULL},
+#endif
+/**end repeat**/
+}; /* End of _allcontig_specialized_table */
+
+static sum_of_products_fn _unspecialized_table[NPY_NTYPES][4] = {
+/**begin repeat
+ * #name = bool,
+ * byte, ubyte,
+ * short, ushort,
+ * int, uint,
+ * long, ulong,
+ * longlong, ulonglong,
+ * float, double, longdouble,
+ * cfloat, cdouble, clongdouble,
+ * object, string, unicode, void,
+ * datetime, timedelta, half#
+ * #use = 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1,
+ * 1, 1, 1,
+ * 1, 1, 1,
+ * 0, 0, 0, 0,
+ * 0, 0, 1#
+ */
+#if @use@
+{
+ &@name@_sum_of_products_any,
+ &@name@_sum_of_products_one,
+ &@name@_sum_of_products_two,
+ &@name@_sum_of_products_three
+},
+#else
+ {NULL, NULL, NULL, NULL},
+#endif
+/**end repeat**/
+}; /* End of _unnspecialized_table */
+
+NPY_VISIBILITY_HIDDEN sum_of_products_fn
+get_sum_of_products_function(int nop, int type_num,
+ npy_intp itemsize, npy_intp const *fixed_strides)
+{
+ int iop;
+
+ if (type_num >= NPY_NTYPES) {
+ return NULL;
+ }
+
+ /* contiguous reduction */
+ if (nop == 1 && fixed_strides[0] == itemsize && fixed_strides[1] == 0) {
+ sum_of_products_fn ret =
+ _contig_outstride0_unary_specialization_table[type_num];
+ if (ret != NULL) {
+ return ret;
+ }
+ }
+
+ /* nop of 2 has more specializations */
+ if (nop == 2) {
+ /* Encode the zero/contiguous strides */
+ int code;
+ code = (fixed_strides[0] == 0) ? 0 :
+ (fixed_strides[0] == itemsize) ? 2*2*1 : 8;
+ code += (fixed_strides[1] == 0) ? 0 :
+ (fixed_strides[1] == itemsize) ? 2*1 : 8;
+ code += (fixed_strides[2] == 0) ? 0 :
+ (fixed_strides[2] == itemsize) ? 1 : 8;
+ if (code >= 2 && code < 7) {
+ sum_of_products_fn ret =
+ _binary_specialization_table[type_num][code-2];
+ if (ret != NULL) {
+ return ret;
+ }
+ }
+ }
+
+ /* Inner loop with an output stride of 0 */
+ if (fixed_strides[nop] == 0) {
+ return _outstride0_specialized_table[type_num][nop <= 3 ? nop : 0];
+ }
+
+ /* Check for all contiguous */
+ for (iop = 0; iop < nop + 1; ++iop) {
+ if (fixed_strides[iop] != itemsize) {
+ break;
+ }
+ }
+
+ /* Contiguous loop */
+ if (iop == nop + 1) {
+ return _allcontig_specialized_table[type_num][nop <= 3 ? nop : 0];
+ }
+
+ /* None of the above specializations caught it, general loops */
+ return _unspecialized_table[type_num][nop <= 3 ? nop : 0];
+}
--- /dev/null
+#ifndef _NPY_MULTIARRAY_EINSUM_SUMPROD_H
+#define _NPY_MULTIARRAY_EINSUM_SUMPROD_H
+
+#include <numpy/npy_common.h>
+
+typedef void (*sum_of_products_fn)(int, char **, npy_intp const*, npy_intp);
+
+NPY_VISIBILITY_HIDDEN sum_of_products_fn
+get_sum_of_products_function(int nop, int type_num,
+ npy_intp itemsize, npy_intp const *fixed_strides);
+
+#endif
static PyObject *
arrayflags_num_get(PyArrayFlagsObject *self)
{
- return PyInt_FromLong(self->flags);
+ return PyLong_FromLong(self->flags);
}
/* relies on setflags order being write, align, uic */
if (fl & NPY_ARRAY_WARN_ON_WRITE) {
_warn_on_write = " (with WARN_ON_WRITE=True)";
}
- return PyUString_FromFormat(
+ return PyUnicode_FromFormat(
" %s : %s\n %s : %s\n"
" %s : %s\n %s : %s%s\n"
" %s : %s\n %s : %s\n"
static PyObject *
array_ndim_get(PyArrayObject *self)
{
- return PyInt_FromLong(PyArray_NDIM(self));
+ return PyLong_FromLong(PyArray_NDIM(self));
}
static PyObject *
offset = PyArray_BYTES(self) - (char *)view.buf;
numbytes = view.len + offset;
PyBuffer_Release(&view);
- _dealloc_cached_buffer_info((PyObject*)new);
}
else {
PyErr_Clear();
if (dobj == NULL) {
return NULL;
}
- PyTuple_SET_ITEM(dobj, 0, PyString_FromString(""));
+ PyTuple_SET_ITEM(dobj, 0, PyUnicode_FromString(""));
PyTuple_SET_ITEM(dobj, 1, array_typestr_get(self));
res = PyList_New(1);
if (res == NULL) {
{
return Py_BuildValue("NO",
PyLong_FromVoidPtr(PyArray_DATA(self)),
- (PyArray_FLAGS(self) & NPY_ARRAY_WRITEABLE ? Py_False :
- Py_True));
+ ((PyArray_FLAGS(self) & NPY_ARRAY_WRITEABLE) &&
+ !(PyArray_FLAGS(self) & NPY_ARRAY_WARN_ON_WRITE)) ?
+ Py_False : Py_True);
}
static PyObject *
return NULL;
}
- if (array_might_be_written(self) < 0) {
- Py_DECREF(dict);
- return NULL;
- }
int ret;
/* dataptr */
return NULL;
}
- obj = PyInt_FromLong(3);
+ obj = PyLong_FromLong(3);
ret = PyDict_SetItemString(dict, "version", obj);
Py_DECREF(obj);
if (ret < 0) {
* sticks around after the release.
*/
PyBuffer_Release(&view);
- _dealloc_cached_buffer_info(op);
if (!PyArray_ISONESEGMENT(self)) {
PyErr_SetString(PyExc_AttributeError,
static PyObject *
array_itemsize_get(PyArrayObject *self)
{
- return PyInt_FromLong((long) PyArray_DESCR(self)->elsize);
+ return PyLong_FromLong((long) PyArray_DESCR(self)->elsize);
}
static PyObject *
{
npy_intp size=PyArray_SIZE(self);
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
- return PyInt_FromLong((long) size);
+ return PyLong_FromLong((long) size);
#else
if (size > NPY_MAX_LONG || size < NPY_MIN_LONG) {
return PyLong_FromLongLong(size);
}
else {
- return PyInt_FromLong((long) size);
+ return PyLong_FromLong((long) size);
}
#endif
}
{
npy_intp nbytes = PyArray_NBYTES(self);
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
- return PyInt_FromLong((long) nbytes);
+ return PyLong_FromLong((long) nbytes);
#else
if (nbytes > NPY_MAX_LONG || nbytes < NPY_MIN_LONG) {
return PyLong_FromLongLong(nbytes);
}
else {
- return PyInt_FromLong((long) nbytes);
+ return PyLong_FromLong((long) nbytes);
}
#endif
}
array_struct_get(PyArrayObject *self)
{
PyArrayInterface *inter;
- PyObject *ret;
- if (PyArray_ISWRITEABLE(self)) {
- if (array_might_be_written(self) < 0) {
- return NULL;
- }
- }
inter = (PyArrayInterface *)PyArray_malloc(sizeof(PyArrayInterface));
if (inter==NULL) {
return PyErr_NoMemory();
inter->typekind = PyArray_DESCR(self)->kind;
inter->itemsize = PyArray_DESCR(self)->elsize;
inter->flags = PyArray_FLAGS(self);
+ if (inter->flags & NPY_ARRAY_WARN_ON_WRITE) {
+ /* Export a warn-on-write array as read-only */
+ inter->flags = inter->flags & ~NPY_ARRAY_WARN_ON_WRITE;
+ inter->flags = inter->flags & ~NPY_ARRAY_WRITEABLE;
+ }
/* reset unused flags */
inter->flags &= ~(NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_UPDATEIFCOPY |NPY_ARRAY_OWNDATA);
if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NPY_ARRAY_NOTSWAPPED;
else {
inter->descr = NULL;
}
+ PyObject *ret = PyCapsule_New(inter, NULL, gentype_struct_free);
+ if (ret == NULL) {
+ return NULL;
+ }
Py_INCREF(self);
- ret = NpyCapsule_FromVoidPtrAndDesc(inter, self, gentype_struct_free);
+ if (PyCapsule_SetContext(ret, self) < 0) {
+ return NULL;
+ }
return ret;
}
"(Hash) names and fields inconsistent ???");
return -1;
}
- if (!PyUString_Check(key)) {
+ if (!PyUnicode_Check(key)) {
PyErr_SetString(PyExc_SystemError,
"(Hash) key of dtype dict not a string ???");
return -1;
}
foffset = PyTuple_GET_ITEM(value, 1);
- if (!PyInt_Check(foffset)) {
+ if (!PyLong_Check(foffset)) {
PyErr_SetString(PyExc_SystemError,
"(Hash) Second item in compound dtype tuple not an int ???");
return -1;
PyList_Append(l, item);
}
}
- else if (PyInt_Check(adescr->shape)) {
+ else if (PyLong_Check(adescr->shape)) {
PyList_Append(l, adescr->shape);
}
else {
#include "npy_binsearch.h"
#include "alloc.h"
#include "arraytypes.h"
-
+#include "array_coercion.h"
static NPY_GCC_OPT_3 NPY_INLINE int
data += ind * strides[idim];
}
- return PyArray_SETITEM(self, data, obj);
+ return PyArray_Pack(PyArray_DESCR(self), data, obj);
}
#include "iterators.h"
#include "ctors.h"
#include "common.h"
+#include "array_coercion.h"
#define NEWAXIS_INDEX -1
#define ELLIPSIS_INDEX -2
}
else if (PySlice_Check(op)) {
npy_intp stop;
- if (NpySlice_GetIndicesEx(op, max, &i, &stop, step_size, n_steps) < 0) {
+ if (PySlice_GetIndicesEx(op, max, &i, &stop, step_size, n_steps) < 0) {
goto fail;
}
if (*n_steps <= 0) {
}
/* Check for Integer or Slice */
- if (PyLong_Check(ind) || PyInt_Check(ind) || PySlice_Check(ind)) {
+ if (PyLong_Check(ind) || PySlice_Check(ind)) {
start = parse_index_entry(ind, &step_size, &n_steps,
self->size, 0, 1);
if (start == -1) {
if (PyBool_Check(ind)) {
retval = 0;
if (PyObject_IsTrue(ind)) {
- retval = PyArray_SETITEM(self->ao, self->dataptr, val);
+ retval = PyArray_Pack(PyArray_DESCR(self->ao), self->dataptr, val);
}
goto finish;
}
goto finish;
}
PyArray_ITER_GOTO1D(self, start);
- retval = type->f->setitem(val, self->dataptr, self->ao);
+ retval = PyArray_Pack(PyArray_DESCR(self->ao), self->dataptr, val);
PyArray_ITER_RESET(self);
if (retval < 0) {
PyErr_SetString(PyExc_ValueError,
arraymultiter_size_get(PyArrayMultiIterObject *self)
{
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
- return PyInt_FromLong((long) self->size);
+ return PyLong_FromLong((long) self->size);
#else
if (self->size < NPY_MAX_LONG) {
- return PyInt_FromLong((long) self->size);
+ return PyLong_FromLong((long) self->size);
}
else {
return PyLong_FromLongLong((npy_longlong) self->size);
arraymultiter_index_get(PyArrayMultiIterObject *self)
{
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
- return PyInt_FromLong((long) self->index);
+ return PyLong_FromLong((long) self->index);
#else
if (self->size < NPY_MAX_LONG) {
- return PyInt_FromLong((long) self->index);
+ return PyLong_FromLong((long) self->index);
}
else {
return PyLong_FromLongLong((npy_longlong) self->index);
--- /dev/null
+/*
+ * This file hosts legacy implementations of certain functions for
+ * which alternatives exists, but the old functions are still required
+ * in certain code paths, or until the code transition is finalized.
+ *
+ * This code should typically not require modification, and if modified
+ * similar changes may be necessary in the new version.
+ */
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _MULTIARRAYMODULE
+#include "numpy/arrayobject.h"
+#include "scalartypes.h"
+#include "_datetime.h"
+#include "datetime_strings.h"
+#include "convert_datatype.h"
+
+#include "legacy_dtype_implementation.h"
+
+
+/*
+ * Compare the field dictionaries for two types.
+ *
+ * Return 1 if the field types and field names of the two descrs are equal and
+ * in the same order, 0 if not.
+ */
+static int
+_equivalent_fields(PyArray_Descr *type1, PyArray_Descr *type2) {
+
+ int val;
+
+ if (type1->fields == type2->fields && type1->names == type2->names) {
+ return 1;
+ }
+ if (type1->fields == NULL || type2->fields == NULL) {
+ return 0;
+ }
+
+ val = PyObject_RichCompareBool(type1->fields, type2->fields, Py_EQ);
+ if (val != 1 || PyErr_Occurred()) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ val = PyObject_RichCompareBool(type1->names, type2->names, Py_EQ);
+ if (val != 1 || PyErr_Occurred()) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Compare the subarray data for two types.
+ * Return 1 if they are the same, 0 if not.
+ */
+static int
+_equivalent_subarrays(PyArray_ArrayDescr *sub1, PyArray_ArrayDescr *sub2)
+{
+ int val;
+
+ if (sub1 == sub2) {
+ return 1;
+
+ }
+ if (sub1 == NULL || sub2 == NULL) {
+ return 0;
+ }
+
+ val = PyObject_RichCompareBool(sub1->shape, sub2->shape, Py_EQ);
+ if (val != 1 || PyErr_Occurred()) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ return PyArray_EquivTypes(sub1->base, sub2->base);
+}
+
+
+NPY_NO_EXPORT unsigned char
+PyArray_LegacyEquivTypes(PyArray_Descr *type1, PyArray_Descr *type2)
+{
+ int type_num1, type_num2, size1, size2;
+
+ if (type1 == type2) {
+ return NPY_TRUE;
+ }
+
+ type_num1 = type1->type_num;
+ type_num2 = type2->type_num;
+ size1 = type1->elsize;
+ size2 = type2->elsize;
+
+ if (size1 != size2) {
+ return NPY_FALSE;
+ }
+ if (PyArray_ISNBO(type1->byteorder) != PyArray_ISNBO(type2->byteorder)) {
+ return NPY_FALSE;
+ }
+ if (type1->subarray || type2->subarray) {
+ return ((type_num1 == type_num2)
+ && _equivalent_subarrays(type1->subarray, type2->subarray));
+ }
+ if (type_num1 == NPY_VOID || type_num2 == NPY_VOID) {
+ return ((type_num1 == type_num2) && _equivalent_fields(type1, type2));
+ }
+ if (type_num1 == NPY_DATETIME
+ || type_num1 == NPY_TIMEDELTA
+ || type_num2 == NPY_DATETIME
+ || type_num2 == NPY_TIMEDELTA) {
+ return ((type_num1 == type_num2)
+ && has_equivalent_datetime_metadata(type1, type2));
+ }
+ return type1->kind == type2->kind;
+}
+
+
+NPY_NO_EXPORT unsigned char
+PyArray_LegacyEquivTypenums(int typenum1, int typenum2)
+{
+ PyArray_Descr *d1, *d2;
+ npy_bool ret;
+
+ if (typenum1 == typenum2) {
+ return NPY_SUCCEED;
+ }
+
+ d1 = PyArray_DescrFromType(typenum1);
+ d2 = PyArray_DescrFromType(typenum2);
+ ret = PyArray_LegacyEquivTypes(d1, d2);
+ Py_DECREF(d1);
+ Py_DECREF(d2);
+ return ret;
+}
+
+
+NPY_NO_EXPORT int
+PyArray_LegacyCanCastSafely(int fromtype, int totype)
+{
+ PyArray_Descr *from;
+
+ /* Fast table lookup for small type numbers */
+ if ((unsigned int)fromtype < NPY_NTYPES &&
+ (unsigned int)totype < NPY_NTYPES) {
+ return _npy_can_cast_safely_table[fromtype][totype];
+ }
+
+ /* Identity */
+ if (fromtype == totype) {
+ return 1;
+ }
+
+ from = PyArray_DescrFromType(fromtype);
+ /*
+ * cancastto is a NPY_NOTYPE terminated C-int-array of types that
+ * the data-type can be cast to safely.
+ */
+ if (from->f->cancastto) {
+ int *curtype = from->f->cancastto;
+
+ while (*curtype != NPY_NOTYPE) {
+ if (*curtype++ == totype) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+NPY_NO_EXPORT npy_bool
+PyArray_LegacyCanCastTo(PyArray_Descr *from, PyArray_Descr *to)
+{
+ int from_type_num = from->type_num;
+ int to_type_num = to->type_num;
+ npy_bool ret;
+
+ ret = (npy_bool) PyArray_LegacyCanCastSafely(from_type_num, to_type_num);
+ if (ret) {
+ /* Check String and Unicode more closely */
+ if (from_type_num == NPY_STRING) {
+ if (to_type_num == NPY_STRING) {
+ ret = (from->elsize <= to->elsize);
+ }
+ else if (to_type_num == NPY_UNICODE) {
+ ret = (from->elsize << 2 <= to->elsize);
+ }
+ }
+ else if (from_type_num == NPY_UNICODE) {
+ if (to_type_num == NPY_UNICODE) {
+ ret = (from->elsize <= to->elsize);
+ }
+ }
+ /*
+ * For datetime/timedelta, only treat casts moving towards
+ * more precision as safe.
+ */
+ else if (from_type_num == NPY_DATETIME && to_type_num == NPY_DATETIME) {
+ PyArray_DatetimeMetaData *meta1, *meta2;
+ meta1 = get_datetime_metadata_from_dtype(from);
+ if (meta1 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+ meta2 = get_datetime_metadata_from_dtype(to);
+ if (meta2 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ return can_cast_datetime64_metadata(meta1, meta2,
+ NPY_SAFE_CASTING);
+ }
+ else if (from_type_num == NPY_TIMEDELTA &&
+ to_type_num == NPY_TIMEDELTA) {
+ PyArray_DatetimeMetaData *meta1, *meta2;
+ meta1 = get_datetime_metadata_from_dtype(from);
+ if (meta1 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+ meta2 = get_datetime_metadata_from_dtype(to);
+ if (meta2 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ return can_cast_timedelta64_metadata(meta1, meta2,
+ NPY_SAFE_CASTING);
+ }
+ /*
+ * If to_type_num is STRING or unicode
+ * see if the length is long enough to hold the
+ * stringified value of the object.
+ */
+ else if (to_type_num == NPY_STRING || to_type_num == NPY_UNICODE) {
+ /*
+ * Boolean value cast to string type is 5 characters max
+ * for string 'False'.
+ */
+ int char_size = 1;
+ if (to_type_num == NPY_UNICODE) {
+ char_size = 4;
+ }
+
+ ret = 0;
+ if (PyDataType_ISUNSIZED(to)) {
+ ret = 1;
+ }
+ /*
+ * Need at least 5 characters to convert from boolean
+ * to 'True' or 'False'.
+ */
+ else if (from->kind == 'b' && to->elsize >= 5 * char_size) {
+ ret = 1;
+ }
+ else if (from->kind == 'u') {
+ /* Guard against unexpected integer size */
+ if (from->elsize > 8 || from->elsize < 0) {
+ ret = 0;
+ }
+ else if (to->elsize >=
+ REQUIRED_STR_LEN[from->elsize] * char_size) {
+ ret = 1;
+ }
+ }
+ else if (from->kind == 'i') {
+ /* Guard against unexpected integer size */
+ if (from->elsize > 8 || from->elsize < 0) {
+ ret = 0;
+ }
+ /* Extra character needed for sign */
+ else if (to->elsize >=
+ (REQUIRED_STR_LEN[from->elsize] + 1) * char_size) {
+ ret = 1;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Compare two field dictionaries for castability.
+ *
+ * Return 1 if 'field1' can be cast to 'field2' according to the rule
+ * 'casting', 0 if not.
+ *
+ * Castabiliy of field dictionaries is defined recursively: 'field1' and
+ * 'field2' must have the same field names (possibly in different
+ * orders), and the corresponding field types must be castable according
+ * to the given casting rule.
+ */
+static int
+can_cast_fields(PyObject *field1, PyObject *field2, NPY_CASTING casting)
+{
+ Py_ssize_t ppos;
+ PyObject *key;
+ PyObject *tuple1, *tuple2;
+
+ if (field1 == field2) {
+ return 1;
+ }
+ if (field1 == NULL || field2 == NULL) {
+ return 0;
+ }
+ if (PyDict_Size(field1) != PyDict_Size(field2)) {
+ return 0;
+ }
+
+ /* Iterate over all the fields and compare for castability */
+ ppos = 0;
+ while (PyDict_Next(field1, &ppos, &key, &tuple1)) {
+ if ((tuple2 = PyDict_GetItem(field2, key)) == NULL) {
+ return 0;
+ }
+ /* Compare the dtype of the field for castability */
+ if (!PyArray_CanCastTypeTo(
+ (PyArray_Descr *)PyTuple_GET_ITEM(tuple1, 0),
+ (PyArray_Descr *)PyTuple_GET_ITEM(tuple2, 0),
+ casting)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+NPY_NO_EXPORT npy_bool
+PyArray_LegacyCanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to,
+ NPY_CASTING casting)
+{
+ /*
+ * Fast paths for equality and for basic types.
+ */
+ if (from == to ||
+ ((NPY_LIKELY(PyDataType_ISNUMBER(from)) ||
+ PyDataType_ISOBJECT(from)) &&
+ NPY_LIKELY(from->type_num == to->type_num) &&
+ NPY_LIKELY(from->byteorder == to->byteorder))) {
+ return 1;
+ }
+ /*
+ * Cases with subarrays and fields need special treatment.
+ */
+ if (PyDataType_HASFIELDS(from)) {
+ /*
+ * If from is a structured data type, then it can be cast to a simple
+ * non-object one only for unsafe casting *and* if it has a single
+ * field; recurse just in case the single field is itself structured.
+ */
+ if (!PyDataType_HASFIELDS(to) && !PyDataType_ISOBJECT(to)) {
+ if (casting == NPY_UNSAFE_CASTING &&
+ PyDict_Size(from->fields) == 1) {
+ Py_ssize_t ppos = 0;
+ PyObject *tuple;
+ PyArray_Descr *field;
+ PyDict_Next(from->fields, &ppos, NULL, &tuple);
+ field = (PyArray_Descr *)PyTuple_GET_ITEM(tuple, 0);
+ /*
+ * For a subarray, we need to get the underlying type;
+ * since we already are casting unsafely, we can ignore
+ * the shape.
+ */
+ if (PyDataType_HASSUBARRAY(field)) {
+ field = field->subarray->base;
+ }
+ return PyArray_LegacyCanCastTypeTo(field, to, casting);
+ }
+ else {
+ return 0;
+ }
+ }
+ /*
+ * Casting from one structured data type to another depends on the fields;
+ * we pass that case on to the EquivTypenums case below.
+ *
+ * TODO: move that part up here? Need to check whether equivalent type
+ * numbers is an addition constraint that is needed.
+ *
+ * TODO/FIXME: For now, always allow structured to structured for unsafe
+ * casting; this is not correct, but needed since the treatment in can_cast
+ * below got out of sync with astype; see gh-13667.
+ */
+ if (casting == NPY_UNSAFE_CASTING) {
+ return 1;
+ }
+ }
+ else if (PyDataType_HASFIELDS(to)) {
+ /*
+ * If "from" is a simple data type and "to" has fields, then only
+ * unsafe casting works (and that works always, even to multiple fields).
+ */
+ return casting == NPY_UNSAFE_CASTING;
+ }
+ /*
+ * Everything else we consider castable for unsafe for now.
+ * FIXME: ensure what we do here is consistent with "astype",
+ * i.e., deal more correctly with subarrays and user-defined dtype.
+ */
+ else if (casting == NPY_UNSAFE_CASTING) {
+ return 1;
+ }
+ /*
+ * Equivalent simple types can be cast with any value of 'casting', but
+ * we need to be careful about structured to structured.
+ */
+ if (PyArray_LegacyEquivTypenums(from->type_num, to->type_num)) {
+ /* For complicated case, use EquivTypes (for now) */
+ if (PyTypeNum_ISUSERDEF(from->type_num) ||
+ from->subarray != NULL) {
+ int ret;
+
+ /* Only NPY_NO_CASTING prevents byte order conversion */
+ if ((casting != NPY_NO_CASTING) &&
+ (!PyArray_ISNBO(from->byteorder) ||
+ !PyArray_ISNBO(to->byteorder))) {
+ PyArray_Descr *nbo_from, *nbo_to;
+
+ nbo_from = PyArray_DescrNewByteorder(from, NPY_NATIVE);
+ nbo_to = PyArray_DescrNewByteorder(to, NPY_NATIVE);
+ if (nbo_from == NULL || nbo_to == NULL) {
+ Py_XDECREF(nbo_from);
+ Py_XDECREF(nbo_to);
+ PyErr_Clear();
+ return 0;
+ }
+ ret = PyArray_LegacyEquivTypes(nbo_from, nbo_to);
+ Py_DECREF(nbo_from);
+ Py_DECREF(nbo_to);
+ }
+ else {
+ ret = PyArray_LegacyEquivTypes(from, to);
+ }
+ return ret;
+ }
+
+ if (PyDataType_HASFIELDS(from)) {
+ switch (casting) {
+ case NPY_EQUIV_CASTING:
+ case NPY_SAFE_CASTING:
+ case NPY_SAME_KIND_CASTING:
+ /*
+ * `from' and `to' must have the same fields, and
+ * corresponding fields must be (recursively) castable.
+ */
+ return can_cast_fields(from->fields, to->fields, casting);
+
+ case NPY_NO_CASTING:
+ default:
+ return PyArray_LegacyEquivTypes(from, to);
+ }
+ }
+
+ switch (from->type_num) {
+ case NPY_DATETIME: {
+ PyArray_DatetimeMetaData *meta1, *meta2;
+ meta1 = get_datetime_metadata_from_dtype(from);
+ if (meta1 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+ meta2 = get_datetime_metadata_from_dtype(to);
+ if (meta2 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ if (casting == NPY_NO_CASTING) {
+ return PyArray_ISNBO(from->byteorder) ==
+ PyArray_ISNBO(to->byteorder) &&
+ can_cast_datetime64_metadata(meta1, meta2, casting);
+ }
+ else {
+ return can_cast_datetime64_metadata(meta1, meta2, casting);
+ }
+ }
+ case NPY_TIMEDELTA: {
+ PyArray_DatetimeMetaData *meta1, *meta2;
+ meta1 = get_datetime_metadata_from_dtype(from);
+ if (meta1 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+ meta2 = get_datetime_metadata_from_dtype(to);
+ if (meta2 == NULL) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ if (casting == NPY_NO_CASTING) {
+ return PyArray_ISNBO(from->byteorder) ==
+ PyArray_ISNBO(to->byteorder) &&
+ can_cast_timedelta64_metadata(meta1, meta2, casting);
+ }
+ else {
+ return can_cast_timedelta64_metadata(meta1, meta2, casting);
+ }
+ }
+ default:
+ switch (casting) {
+ case NPY_NO_CASTING:
+ return PyArray_LegacyEquivTypes(from, to);
+ case NPY_EQUIV_CASTING:
+ return (from->elsize == to->elsize);
+ case NPY_SAFE_CASTING:
+ return (from->elsize <= to->elsize);
+ default:
+ return 1;
+ }
+ break;
+ }
+ }
+ /* If safe or same-kind casts are allowed */
+ else if (casting == NPY_SAFE_CASTING || casting == NPY_SAME_KIND_CASTING) {
+ if (PyArray_LegacyCanCastTo(from, to)) {
+ return 1;
+ }
+ else if(casting == NPY_SAME_KIND_CASTING) {
+ /*
+ * Also allow casting from lower to higher kinds, according
+ * to the ordering provided by dtype_kind_to_ordering.
+ * Some kinds, like datetime, don't fit in the hierarchy,
+ * and are special cased as -1.
+ */
+ int from_order, to_order;
+
+ from_order = dtype_kind_to_ordering(from->kind);
+ to_order = dtype_kind_to_ordering(to->kind);
+
+ if (to->kind == 'm') {
+ /* both types being timedelta is already handled before. */
+ int integer_order = dtype_kind_to_ordering('i');
+ return (from_order != -1) && (from_order <= integer_order);
+ }
+
+ return (from_order != -1) && (from_order <= to_order);
+ }
+ else {
+ return 0;
+ }
+ }
+ /* NPY_NO_CASTING or NPY_EQUIV_CASTING was specified */
+ else {
+ return 0;
+ }
+}
+
+
+/*
+ * Legacy function to find the correct dtype when casting from any built-in
+ * dtype to NPY_STRING, NPY_UNICODE, NPY_VOID, and NPY_DATETIME with generic
+ * units.
+ *
+ * This function returns a dtype based on flex_dtype and the values in
+ * data_dtype. It also calls Py_DECREF on the flex_dtype. If the
+ * flex_dtype is not flexible, it returns it as-is.
+ *
+ * Usually, if data_obj is not an array, dtype should be the result
+ * given by the PyArray_GetArrayParamsFromObject function.
+ *
+ * If *flex_dtype is NULL, returns immediately, without setting an
+ * exception, leaving any previous error handling intact.
+ */
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_AdaptFlexibleDType(PyArray_Descr *data_dtype, PyArray_Descr *flex_dtype)
+{
+ PyArray_DatetimeMetaData *meta;
+ PyArray_Descr *retval = NULL;
+ int flex_type_num;
+
+ if (flex_dtype == NULL) {
+ return retval;
+ }
+
+ flex_type_num = flex_dtype->type_num;
+
+ /* Flexible types with expandable size */
+ if (PyDataType_ISUNSIZED(flex_dtype)) {
+ /* First replace the flex_dtype */
+ retval = PyArray_DescrNew(flex_dtype);
+ Py_DECREF(flex_dtype);
+ if (retval == NULL) {
+ return retval;
+ }
+
+ if (data_dtype->type_num == flex_type_num ||
+ flex_type_num == NPY_VOID) {
+ (retval)->elsize = data_dtype->elsize;
+ }
+ else if (flex_type_num == NPY_STRING || flex_type_num == NPY_UNICODE) {
+ npy_intp size = 8;
+
+ /*
+ * Get a string-size estimate of the input. These
+ * are generallly the size needed, rounded up to
+ * a multiple of eight.
+ */
+ switch (data_dtype->type_num) {
+ case NPY_BOOL:
+ case NPY_UBYTE:
+ case NPY_BYTE:
+ case NPY_USHORT:
+ case NPY_SHORT:
+ case NPY_UINT:
+ case NPY_INT:
+ case NPY_ULONG:
+ case NPY_LONG:
+ case NPY_ULONGLONG:
+ case NPY_LONGLONG:
+ if (data_dtype->kind == 'b') {
+ /* 5 chars needed for cast to 'True' or 'False' */
+ size = 5;
+ }
+ else if (data_dtype->elsize > 8 ||
+ data_dtype->elsize < 0) {
+ /*
+ * Element size should never be greater than 8 or
+ * less than 0 for integer type, but just in case...
+ */
+ break;
+ }
+ else if (data_dtype->kind == 'u') {
+ size = REQUIRED_STR_LEN[data_dtype->elsize];
+ }
+ else if (data_dtype->kind == 'i') {
+ /* Add character for sign symbol */
+ size = REQUIRED_STR_LEN[data_dtype->elsize] + 1;
+ }
+ break;
+ case NPY_HALF:
+ case NPY_FLOAT:
+ case NPY_DOUBLE:
+ size = 32;
+ break;
+ case NPY_LONGDOUBLE:
+ size = 48;
+ break;
+ case NPY_CFLOAT:
+ case NPY_CDOUBLE:
+ size = 2 * 32;
+ break;
+ case NPY_CLONGDOUBLE:
+ size = 2 * 48;
+ break;
+ case NPY_OBJECT:
+ size = 64;
+ break;
+ case NPY_STRING:
+ case NPY_VOID:
+ size = data_dtype->elsize;
+ break;
+ case NPY_UNICODE:
+ size = data_dtype->elsize / 4;
+ break;
+ case NPY_DATETIME:
+ meta = get_datetime_metadata_from_dtype(data_dtype);
+ if (meta == NULL) {
+ Py_DECREF(retval);
+ return NULL;
+ }
+ size = get_datetime_iso_8601_strlen(0, meta->base);
+ break;
+ case NPY_TIMEDELTA:
+ size = 21;
+ break;
+ }
+
+ if (flex_type_num == NPY_STRING) {
+ retval->elsize = size;
+ }
+ else if (flex_type_num == NPY_UNICODE) {
+ retval->elsize = size * 4;
+ }
+ }
+ else {
+ /*
+ * We should never get here, but just in case someone adds
+ * a new flex dtype...
+ */
+ PyErr_SetString(PyExc_TypeError,
+ "don't know how to adapt flex dtype");
+ Py_DECREF(retval);
+ return NULL;
+ }
+ }
+ /* Flexible type with generic time unit that adapts */
+ else if (flex_type_num == NPY_DATETIME ||
+ flex_type_num == NPY_TIMEDELTA) {
+ meta = get_datetime_metadata_from_dtype(flex_dtype);
+ retval = flex_dtype;
+ if (meta == NULL) {
+ return NULL;
+ }
+
+ if (meta->base == NPY_FR_GENERIC) {
+ if (data_dtype->type_num == NPY_DATETIME ||
+ data_dtype->type_num == NPY_TIMEDELTA) {
+ meta = get_datetime_metadata_from_dtype(data_dtype);
+ if (meta == NULL) {
+ return NULL;
+ }
+
+ retval = create_datetime_dtype(flex_type_num, meta);
+ Py_DECREF(flex_dtype);
+ }
+ }
+ }
+ else {
+ retval = flex_dtype;
+ }
+ return retval;
+}
--- /dev/null
+#ifndef _NPY_LEGACY_DTYPE_IMPLEMENTATION_H
+#define _NPY_LEGACY_DTYPE_IMPLEMENTATION_H
+
+
+NPY_NO_EXPORT unsigned char
+PyArray_LegacyEquivTypes(PyArray_Descr *type1, PyArray_Descr *type2);
+
+NPY_NO_EXPORT unsigned char
+PyArray_LegacyEquivTypenums(int typenum1, int typenum2);
+
+NPY_NO_EXPORT int
+PyArray_LegacyCanCastSafely(int fromtype, int totype);
+
+NPY_NO_EXPORT npy_bool
+PyArray_LegacyCanCastTo(PyArray_Descr *from, PyArray_Descr *to);
+
+NPY_NO_EXPORT npy_bool
+PyArray_LegacyCanCastTypeTo(PyArray_Descr *from, 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
+ * and data_obj. If the flex_dtype is not flexible, it returns it as-is.
+ *
+ * Usually, if data_obj is not an array, dtype should be the result
+ * given by the PyArray_GetArrayParamsFromObject function.
+ *
+ * The data_obj may be NULL if just a dtype is known for the source.
+ *
+ * If *flex_dtype is NULL, returns immediately, without setting an
+ * exception, leaving any previous error handling intact.
+ *
+ * The current flexible dtypes include NPY_STRING, NPY_UNICODE, NPY_VOID,
+ * and NPY_DATETIME with generic units.
+ */
+NPY_NO_EXPORT PyArray_Descr *
+PyArray_AdaptFlexibleDType(PyArray_Descr *data_dtype, PyArray_Descr *flex_dtype);
+
+#endif /*_NPY_LEGACY_DTYPE_IMPLEMENTATION_H*/
* if not it can decrease performance
* tested to improve performance on intel xeon 5x/7x, core2duo, amd phenom x4
*/
-static void
+static int
#if @is_aligned@ && @is_swap@ == 0 && @elsize@ <= NPY_SIZEOF_INTP
NPY_GCC_UNROLL_LOOPS
#endif
--N;
}
+ return 0;
}
#endif
* but it profits from vectorization enabled with -O3
*/
#if (@src_contig@ == 0) && @is_aligned@
-static NPY_GCC_OPT_3 void
+static NPY_GCC_OPT_3 int
@prefix@_@oper@_size@elsize@_srcstride0(char *dst,
npy_intp dst_stride,
char *src, npy_intp NPY_UNUSED(src_stride),
npy_uint64 temp0, temp1;
#endif
if (N == 0) {
- return;
+ return 0;
}
#if @is_aligned@ && @elsize@ != 16
/* sanity check */
--N;
}
#endif/* @elsize == 1 && @dst_contig@ -- else */
+ return 0;
}
#endif/* (@src_contig@ == 0) && @is_aligned@ */
/**end repeat1**/
/**end repeat**/
-static void
+static int
_strided_to_strided(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_swap_strided_to_strided(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_swap_pair_strided_to_strided(char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
npy_intp N, npy_intp src_itemsize,
src += src_stride;
--N;
}
+ return 0;
}
-static void
+static int
_contig_to_contig(char *dst, npy_intp NPY_UNUSED(dst_stride),
char *src, npy_intp NPY_UNUSED(src_stride),
npy_intp N, npy_intp src_itemsize,
NpyAuxData *NPY_UNUSED(data))
{
memmove(dst, src, src_itemsize*N);
+ return 0;
}
#endif
-static NPY_GCC_OPT_3 void
+static NPY_GCC_OPT_3 int
@prefix@_cast_@name1@_to_@name2@(
char *dst, npy_intp dst_stride,
char *src, npy_intp src_stride,
src += src_stride;
#endif
}
+ return 0;
}
#undef _CONVERT_FN
src_stride0 = src_strides[0];
N = shape0 - coord0;
if (N >= count) {
- stransfer(dst, dst_stride, src, src_stride0, count, src_itemsize, data);
- return 0;
+ return stransfer(dst, dst_stride, src, src_stride0,
+ count, src_itemsize, data);
+ }
+ int res = stransfer(dst, dst_stride, src, src_stride0,
+ N, src_itemsize, data);
+ if (res < 0) {
+ return -1;
}
- stransfer(dst, dst_stride, src, src_stride0, N, src_itemsize, data);
count -= N;
/* If it's 1-dimensional, there's no more to copy */
N = shape0*M;
for (i = 0; i < M; ++i) {
if (shape0 >= count) {
- stransfer(dst, dst_stride, src, src_stride0,
- count, src_itemsize, data);
- return 0;
+ return stransfer(dst, dst_stride, src, src_stride0,
+ count, src_itemsize, data);
}
else {
- stransfer(dst, dst_stride, src, src_stride0,
- shape0, src_itemsize, data);
+ res = stransfer(dst, dst_stride, src, src_stride0,
+ shape0, src_itemsize, data);
+ if (res < 0) {
+ return -1;
+ }
}
count -= shape0;
src += src_stride1;
/* A loop for dimensions 0 and 1 */
for (i = 0; i < shape1; ++i) {
if (shape0 >= count) {
- stransfer(dst, dst_stride, src, src_stride0,
- count, src_itemsize, data);
- return 0;
+ return stransfer(dst, dst_stride, src, src_stride0,
+ count, src_itemsize, data);
}
else {
- stransfer(dst, dst_stride, src, src_stride0,
- shape0, src_itemsize, data);
+ res = stransfer(dst, dst_stride, src, src_stride0,
+ shape0, src_itemsize, data);
+ if (res < 0) {
+ return -1;
+ }
}
count -= shape0;
src += src_stride1;
dst_stride0 = dst_strides[0];
N = shape0 - coord0;
if (N >= count) {
- stransfer(dst, dst_stride0, src, src_stride, count, src_itemsize, data);
- return 0;
+ return stransfer(dst, dst_stride0, src, src_stride,
+ count, src_itemsize, data);
+ }
+ int res = stransfer(dst, dst_stride0, src, src_stride,
+ N, src_itemsize, data);
+ if (res < 0) {
+ return -1;
}
- stransfer(dst, dst_stride0, src, src_stride, N, src_itemsize, data);
count -= N;
/* If it's 1-dimensional, there's no more to copy */
N = shape0*M;
for (i = 0; i < M; ++i) {
if (shape0 >= count) {
- stransfer(dst, dst_stride0, src, src_stride,
- count, src_itemsize, data);
- return 0;
+ return stransfer(dst, dst_stride0, src, src_stride,
+ count, src_itemsize, data);
}
else {
- stransfer(dst, dst_stride0, src, src_stride,
- shape0, src_itemsize, data);
+ res = stransfer(dst, dst_stride0, src, src_stride,
+ shape0, src_itemsize, data);
+ if (res < 0) {
+ return -1;
+ }
}
count -= shape0;
dst += dst_stride1;
/* A loop for dimensions 0 and 1 */
for (i = 0; i < shape1; ++i) {
if (shape0 >= count) {
- stransfer(dst, dst_stride0, src, src_stride,
- count, src_itemsize, data);
- return 0;
+ return stransfer(dst, dst_stride0, src, src_stride,
+ count, src_itemsize, data);
}
else {
- stransfer(dst, dst_stride0, src, src_stride,
- shape0, src_itemsize, data);
+ res = stransfer(dst, dst_stride0, src, src_stride,
+ shape0, src_itemsize, data);
+ if (res < 0) {
+ return -1;
+ }
}
count -= shape0;
dst += dst_stride1;
dst_stride0 = dst_strides[0];
N = shape0 - coord0;
if (N >= count) {
- stransfer(dst, dst_stride0,
- src, src_stride,
- mask, mask_stride,
- count, src_itemsize, data);
- return 0;
- }
- stransfer(dst, dst_stride0,
- src, src_stride,
+ return stransfer(
+ dst, dst_stride0, src, src_stride,
mask, mask_stride,
- N, src_itemsize, data);
+ count, src_itemsize, data);
+ }
+ int res = stransfer(
+ dst, dst_stride0, src, src_stride,
+ mask, mask_stride,
+ N, src_itemsize, data);
+ if (res < 0) {
+ return -1;
+ }
count -= N;
/* If it's 1-dimensional, there's no more to copy */
N = shape0*M;
for (i = 0; i < M; ++i) {
if (shape0 >= count) {
- stransfer(dst, dst_stride0,
- src, src_stride,
- mask, mask_stride,
- count, src_itemsize, data);
- return 0;
+ return stransfer(
+ dst, dst_stride0, src, src_stride,
+ mask, mask_stride,
+ count, src_itemsize, data);
}
else {
- stransfer(dst, dst_stride0,
- src, src_stride,
- mask, mask_stride,
- shape0, src_itemsize, data);
+ int res = stransfer(
+ dst, dst_stride0, src, src_stride,
+ mask, mask_stride,
+ shape0, src_itemsize, data);
+ if (res < 0) {
+ return -1;
+ }
}
count -= shape0;
dst += dst_stride1;
/* A loop for dimensions 0 and 1 */
for (i = 0; i < shape1; ++i) {
if (shape0 >= count) {
- stransfer(dst, dst_stride0,
- src, src_stride,
- mask, mask_stride,
- count, src_itemsize, data);
- return 0;
+ return stransfer(
+ dst, dst_stride0, src, src_stride,
+ mask, mask_stride,
+ count, src_itemsize, data);
}
else {
- stransfer(dst, dst_stride0,
- src, src_stride,
- mask, mask_stride,
- shape0, src_itemsize, data);
+ res = stransfer(
+ dst, dst_stride0, src, src_stride,
+ mask, mask_stride,
+ shape0, src_itemsize, data);
+ if (res < 0) {
+ return -1;
+ }
}
count -= shape0;
dst += dst_stride1;
do {
#if @isget@
- stransfer(subspace_ptrs[1], subspace_strides[1],
- subspace_ptrs[0], subspace_strides[0],
- *counter, src_itemsize, transferdata);
+ if (NPY_UNLIKELY(stransfer(
+ subspace_ptrs[1], subspace_strides[1],
+ subspace_ptrs[0], subspace_strides[0],
+ *counter, src_itemsize, transferdata) < 0)) {
+ NPY_END_THREADS;
+ NPY_AUXDATA_FREE(transferdata);
+ return -1;
+ }
#else
- stransfer(subspace_ptrs[0], subspace_strides[0],
- subspace_ptrs[1], subspace_strides[1],
- *counter, src_itemsize, transferdata);
+ if (NPY_UNLIKELY(stransfer(
+ subspace_ptrs[0], subspace_strides[0],
+ subspace_ptrs[1], subspace_strides[1],
+ *counter, src_itemsize, transferdata) < 0)) {
+ NPY_END_THREADS;
+ NPY_AUXDATA_FREE(transferdata);
+ return -1;
+ }
#endif
} while (mit->subspace_next(mit->subspace_iter));
#include "item_selection.h"
#include "mem_overlap.h"
#include "array_assign.h"
+#include "array_coercion.h"
#define HAS_INTEGER 1
|| PySlice_Check(index)
|| PyArray_Check(index)
|| !PySequence_Check(index)
- || PyBaseString_Check(index)) {
+ || PyUnicode_Check(index)) {
return unpack_scalar(index, result, result_n);
}
/*
* There are two types of boolean indices (which are equivalent,
* for the most part though). A single boolean index of matching
- * dimensionality and size is a boolean index.
- * If this is not the case, it is instead expanded into (multiple)
- * integer array indices.
+ * shape is a boolean index. If this is not the case, it is
+ * instead expanded into (multiple) integer array indices.
*/
PyArrayObject *nonzero_result[NPY_MAXDIMS];
if ((index_ndim == 1) && allow_boolean) {
/*
- * If ndim and size match, this can be optimized as a single
- * boolean index. The size check is necessary only to support
- * old non-matching sizes by using fancy indexing instead.
- * The reason for that is that fancy indexing uses nonzero,
- * and only the result of nonzero is checked for legality.
+ * If shapes match exactly, this can be optimized as a single
+ * boolean index. When the dimensions are identical but the shapes are not,
+ * this is always an error. The check ensures that these errors are raised
+ * and match those of the generic path.
*/
if ((PyArray_NDIM(arr) == PyArray_NDIM(self))
- && PyArray_SIZE(arr) == PyArray_SIZE(self)) {
+ && PyArray_CompareLists(PyArray_DIMS(arr),
+ PyArray_DIMS(self),
+ PyArray_NDIM(arr))) {
index_type = HAS_BOOL;
indices[curr_idx].type = HAS_BOOL;
}
break;
case HAS_SLICE:
- if (NpySlice_GetIndicesEx(indices[i].object,
- PyArray_DIMS(self)[orig_dim],
- &start, &stop, &step, &n_steps) < 0) {
+ if (PySlice_GetIndicesEx(indices[i].object,
+ PyArray_DIMS(self)[orig_dim],
+ &start, &stop, &step, &n_steps) < 0) {
return -1;
}
if (n_steps <= 0) {
self_stride = innerstrides[0];
bmask_stride = innerstrides[1];
+ int res = 0;
do {
innersize = *NpyIter_GetInnerLoopSizePtr(iter);
self_data = dataptrs[0];
/* Process unmasked values */
bmask_data = npy_memchr(bmask_data, 0, bmask_stride, innersize,
&subloopsize, 0);
- stransfer(ret_data, itemsize, self_data, self_stride,
- subloopsize, itemsize, transferdata);
+ res = stransfer(ret_data, itemsize, self_data, self_stride,
+ subloopsize, itemsize, transferdata);
+ if (res < 0) {
+ break;
+ }
innersize -= subloopsize;
self_data += subloopsize * self_stride;
ret_data += subloopsize * itemsize;
NPY_END_THREADS;
- NpyIter_Deallocate(iter);
+ if (!NpyIter_Deallocate(iter)) {
+ res = -1;
+ }
NPY_AUXDATA_FREE(transferdata);
+ if (res < 0) {
+ /* Should be practically impossible, since there is no cast */
+ Py_DECREF(ret);
+ return NULL;
+ }
}
if (!PyArray_CheckExact(self)) {
v_data = PyArray_DATA(v);
/* Create an iterator for the data */
+ int res = 0;
if (size > 0) {
NpyIter *iter;
PyArrayObject *op[2] = {self, bmask};
/* Get a dtype transfer function */
NpyIter_GetInnerFixedStrideArray(iter, fixed_strides);
if (PyArray_GetDTypeTransferFunction(
- IsUintAligned(self) && IsAligned(self) &&
+ IsUintAligned(self) && IsAligned(self) &&
IsUintAligned(v) && IsAligned(v),
v_stride, fixed_strides[0],
PyArray_DESCR(v), PyArray_DESCR(self),
/* Process unmasked values */
bmask_data = npy_memchr(bmask_data, 0, bmask_stride, innersize,
&subloopsize, 0);
- stransfer(self_data, self_stride, v_data, v_stride,
- subloopsize, src_itemsize, transferdata);
+ res = stransfer(self_data, self_stride, v_data, v_stride,
+ subloopsize, src_itemsize, transferdata);
+ if (res < 0) {
+ break;
+ }
innersize -= subloopsize;
self_data += subloopsize * self_stride;
v_data += subloopsize * v_stride;
}
NPY_AUXDATA_FREE(transferdata);
- NpyIter_Deallocate(iter);
- }
-
- if (needs_api) {
- /*
- * FIXME?: most assignment operations stop after the first occurrence
- * of an error. Boolean does not currently, but should at least
- * report the error. (This is only relevant for things like str->int
- * casts which call into python)
- */
- if (PyErr_Occurred()) {
- return -1;
+ if (!NpyIter_Deallocate(iter)) {
+ res = -1;
}
}
- return 0;
+ return res;
}
*view = NULL;
/* first check for a single field name */
- if (PyBaseString_Check(ind)) {
+ if (PyUnicode_Check(ind)) {
PyObject *tup;
PyArray_Descr *fieldtype;
npy_intp offset;
return 0;
}
else if (tup == NULL){
- PyObject *errmsg = PyUString_FromString("no field of name ");
- PyUString_Concat(&errmsg, ind);
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
+ PyErr_Format(PyExc_ValueError, "no field of name %S", ind);
return 0;
}
if (_unpack_field(tup, &fieldtype, &offset) < 0) {
PyErr_Clear();
return -1;
}
- is_string = PyBaseString_Check(item);
+ is_string = PyUnicode_Check(item);
Py_DECREF(item);
if (!is_string) {
return -1;
goto finish;
}
- if (mit->numiter > 1) {
+ if (mit->numiter > 1 || mit->size == 0) {
/*
* If it is one, the inner loop checks indices, otherwise
* check indices beforehand, because it is much faster if
- * broadcasting occurs and most likely no big overhead
+ * broadcasting occurs and most likely no big overhead.
+ * The inner loop optimization skips index checks for size == 0 though.
*/
if (PyArray_MapIterCheckIndices(mit) < 0) {
goto finish;
if (get_item_pointer(self, &item, indices, 1) < 0) {
return -1;
}
- if (PyArray_SETITEM(self, item, op) < 0) {
+ if (PyArray_Pack(PyArray_DESCR(self), item, op) < 0) {
return -1;
}
}
if (get_item_pointer(self, &item, indices, index_num) < 0) {
return -1;
}
- if (PyArray_SETITEM(self, item, op) < 0) {
+ if (PyArray_Pack(PyArray_DESCR(self), item, op) < 0) {
return -1;
}
/* integers do not store objects in indices */
* @param Number of indices
* @param The array that is being iterated
*
- * @return 0 on success -1 on failure
+ * @return 0 on success -1 on failure (broadcasting or too many fancy indices)
*/
static int
mapiter_fill_info(PyArrayMapIterObject *mit, npy_index_info *indices,
int consec_status = -1;
int axis, broadcast_axis;
npy_intp dimension;
- PyObject *errmsg, *tmp;
for (i = 0; i < mit->nd_fancy; i++) {
mit->dimensions[i] = 1;
}
}
+ /* Before contunuing, ensure that there are not too fancy indices */
+ if (indices[i].type & HAS_FANCY) {
+ if (NPY_UNLIKELY(j >= NPY_MAXDIMS)) {
+ PyErr_Format(PyExc_IndexError,
+ "too many advanced (array) indices. This probably "
+ "means you are indexing with too many booleans. "
+ "(more than %d found)", NPY_MAXDIMS);
+ return -1;
+ }
+ }
+
/* (iterating) fancy index, store the iterator */
if (indices[i].type == HAS_FANCY) {
mit->fancy_strides[j] = PyArray_STRIDE(arr, curr_dim);
return 0;
- broadcast_error:
+broadcast_error: ; // Declarations cannot follow labels, add empty statement.
/*
* Attempt to set a meaningful exception. Could also find out
* if a boolean index was converted.
*/
- errmsg = PyUString_FromString("shape mismatch: indexing arrays could not "
- "be broadcast together with shapes ");
+ PyObject *errmsg = PyUnicode_FromString("");
if (errmsg == NULL) {
return -1;
}
-
for (i = 0; i < index_num; i++) {
if (!(indices[i].type & HAS_FANCY)) {
continue;
}
- tmp = convert_shape_to_string(
- PyArray_NDIM((PyArrayObject *)indices[i].object),
- PyArray_SHAPE((PyArrayObject *)indices[i].object),
- " ");
+
+ int ndim = PyArray_NDIM((PyArrayObject *)indices[i].object);
+ npy_intp *shape = PyArray_SHAPE((PyArrayObject *)indices[i].object);
+ PyObject *tmp = convert_shape_to_string(ndim, shape, " ");
if (tmp == NULL) {
+ Py_DECREF(errmsg);
return -1;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
+
+ Py_SETREF(errmsg, PyUnicode_Concat(errmsg, tmp));
+ Py_DECREF(tmp);
if (errmsg == NULL) {
return -1;
}
}
- PyErr_SetObject(PyExc_IndexError, errmsg);
+ PyErr_Format(PyExc_IndexError,
+ "shape mismatch: indexing arrays could not "
+ "be broadcast together with shapes %S", errmsg);
Py_DECREF(errmsg);
return -1;
}
int i;
NPY_BEGIN_THREADS_DEF;
- if (mit->size == 0) {
- /* All indices got broadcast away, do *not* check as it always was */
+ if (NpyIter_GetIterSize(mit->outer) == 0) {
+ /*
+ * When the outer iteration is empty, the indices broadcast to an
+ * empty shape, and in this case we do not check if there are out
+ * of bounds indices.
+ * The code below does use the indices without broadcasting since
+ * broadcasting only repeats values.
+ */
return 0;
}
if (check_and_adjust_index(&indval,
outer_dim, outer_axis, _save) < 0) {
Py_DECREF(intp_type);
- return -1;
+ goto indexing_error;
}
data += stride;
}
op_iter = NpyIter_New(op,
NPY_ITER_BUFFERED | NPY_ITER_NBO | NPY_ITER_ALIGNED |
NPY_ITER_EXTERNAL_LOOP | NPY_ITER_GROWINNER |
- NPY_ITER_READONLY,
+ NPY_ITER_READONLY | NPY_ITER_ZEROSIZE_OK,
NPY_KEEPORDER, NPY_SAME_KIND_CASTING, intp_type);
if (op_iter == NULL) {
Py_DECREF(intp_type);
return -1;
}
+ if (NpyIter_GetIterSize(op_iter) == 0) {
+ NpyIter_Deallocate(op_iter);
+ continue;
+ }
op_iternext = NpyIter_GetIterNext(op_iter, NULL);
if (op_iternext == NULL) {
outer_dim, outer_axis, _save) < 0) {
Py_DECREF(intp_type);
NpyIter_Deallocate(op_iter);
- return -1;
+ goto indexing_error;
}
*iterptr += *iterstride;
}
NPY_END_THREADS;
Py_DECREF(intp_type);
return 0;
+
+indexing_error:
+
+ if (mit->size == 0) {
+ PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
+ PyErr_Fetch(&err_type, &err_value, &err_traceback);
+ /* 2020-05-27, NumPy 1.20 */
+ if (DEPRECATE(
+ "Out of bound index found. This was previously ignored "
+ "when the indexing result contained no elements. "
+ "In the future the index error will be raised. This error "
+ "occurs either due to an empty slice, or if an array has zero "
+ "elements even before indexing.\n"
+ "(Use `warnings.simplefilter('error')` to turn this "
+ "DeprecationWarning into an error and get more details on "
+ "the invalid index.)") < 0) {
+ npy_PyErr_ChainExceptions(err_type, err_value, err_traceback);
+ return -1;
+ }
+ Py_DECREF(err_type);
+ Py_DECREF(err_value);
+ Py_XDECREF(err_traceback);
+ return 0;
+ }
+
+ return -1;
}
npy_uint32 extra_op_flags, PyArrayObject *extra_op,
PyArray_Descr *extra_op_dtype)
{
- PyObject *errmsg, *tmp;
/* For shape reporting on error */
PyArrayObject *original_extra_op = extra_op;
+ /* NOTE: MAXARGS is the actual limit (2*NPY_MAXDIMS is index number one) */
PyArrayObject *index_arrays[NPY_MAXDIMS];
PyArray_Descr *intp_descr;
PyArray_Descr *dtypes[NPY_MAXDIMS]; /* borrowed references */
goto finish;
broadcast_error:
- errmsg = PyUString_FromString("shape mismatch: value array "
- "of shape ");
- if (errmsg == NULL) {
- goto finish;
- }
-
/* Report the shape of the original array if it exists */
if (original_extra_op == NULL) {
original_extra_op = extra_op;
}
- tmp = convert_shape_to_string(PyArray_NDIM(original_extra_op),
- PyArray_DIMS(original_extra_op), " ");
- if (tmp == NULL) {
- goto finish;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ int extra_ndim = PyArray_NDIM(original_extra_op);
+ npy_intp *extra_dims = PyArray_DIMS(original_extra_op);
+ PyObject *shape1 = convert_shape_to_string(extra_ndim, extra_dims, " ");
+ if (shape1 == NULL) {
goto finish;
}
- tmp = PyUString_FromString("could not be broadcast to indexing "
- "result of shape ");
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ PyObject *shape2 = convert_shape_to_string(mit->nd, mit->dimensions, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
goto finish;
}
- tmp = convert_shape_to_string(mit->nd, mit->dimensions, "");
- if (tmp == NULL) {
- goto finish;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- goto finish;
- }
+ PyErr_Format(PyExc_ValueError,
+ "shape mismatch: value array of shape %S could not be broadcast "
+ "to indexing result of shape %S", shape1, shape2);
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
finish:
Py_XDECREF(extra_op);
Py_XDECREF(a_copy);
Py_XDECREF(subspace);
Py_XDECREF((PyObject *)mit);
- for (i=0; i < index_num; i++) {
+ for (i = 0; i < index_num; i++) {
Py_XDECREF(indices[i].object);
}
return NULL;
#include "npy_pycompat.h"
#include "npy_import.h"
#include "ufunc_override.h"
+#include "array_coercion.h"
#include "common.h"
#include "templ_common.h" /* for npy_mul_with_overflow_intp */
#include "ctors.h"
return ret;
}
-static PyObject *
-get_forwarding_ndarray_method(const char *name)
-{
- PyObject *module_methods, *callable;
-
- /* Get a reference to the function we're calling */
- module_methods = PyImport_ImportModule("numpy.core._methods");
- if (module_methods == NULL) {
- return NULL;
- }
- callable = _PyDict_GetItemStringWithError(PyModule_GetDict(module_methods), name);
- if (callable == NULL && PyErr_Occurred()) {
- Py_DECREF(module_methods);
- return NULL;
- }
- if (callable == NULL) {
- Py_DECREF(module_methods);
- PyErr_Format(PyExc_RuntimeError,
- "NumPy internal error: could not find function "
- "numpy.core._methods.%s", name);
- }
- else {
- Py_INCREF(callable);
- }
- Py_DECREF(module_methods);
- return callable;
-}
/*
* Forwards an ndarray method to a the Python function
*/
#define NPY_FORWARD_NDARRAY_METHOD(name) \
static PyObject *callable = NULL; \
+ npy_cache_import("numpy.core._methods", name, &callable); \
if (callable == NULL) { \
- callable = get_forwarding_ndarray_method(name); \
- if (callable == NULL) { \
- return NULL; \
- } \
+ return NULL; \
} \
return forward_ndarray_method(self, args, kwds, callable)
PyArray_ClipmodeConverter, &mode))
return NULL;
- return PyArray_Return((PyArrayObject *)
- PyArray_TakeFrom(self, indices, dimension, out, mode));
+ PyObject *ret = PyArray_TakeFrom(self, indices, dimension, out, mode);
+
+ /* this matches the unpacking behavior of ufuncs */
+ if (out == NULL) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ else {
+ return ret;
+ }
}
static PyObject *
PyArray_OutputConverter, &out))
return NULL;
- return PyArray_Return((PyArrayObject *)PyArray_ArgMax(self, axis, out));
+ PyObject *ret = PyArray_ArgMax(self, axis, out);
+
+ /* this matches the unpacking behavior of ufuncs */
+ if (out == NULL) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ else {
+ return ret;
+ }
}
static PyObject *
PyArray_OutputConverter, &out))
return NULL;
- return PyArray_Return((PyArrayObject *)PyArray_ArgMin(self, axis, out));
+ PyObject *ret = PyArray_ArgMin(self, axis, out);
+
+ /* this matches the unpacking behavior of ufuncs */
+ if (out == NULL) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ else {
+ return ret;
+ }
}
static PyObject *
return NULL;
}
+ /* If it is not a concrete dtype instance find the best one for the array */
+ Py_SETREF(dtype, PyArray_AdaptDescriptorToArray(self, (PyObject *)dtype));
+ if (dtype == NULL) {
+ return NULL;
+ }
+
/*
* If the memory layout matches and, data types are equivalent,
* and it's not a subtype if subok is False, then we
else if (PyArray_CanCastArrayTo(self, dtype, casting)) {
PyArrayObject *ret;
- /* If the requested dtype is flexible, adapt it */
- dtype = PyArray_AdaptFlexibleDType((PyObject *)self,
- PyArray_DESCR(self), dtype);
- if (dtype == NULL) {
- return NULL;
- }
-
/* This steals the reference to dtype, so no DECREF of dtype */
ret = (PyArrayObject *)PyArray_NewLikeArray(
self, order, dtype, subok);
if (ret == NULL) {
return NULL;
}
+ /* NumPy 1.20, 2020-10-01 */
+ if ((PyArray_NDIM(self) != PyArray_NDIM(ret)) &&
+ DEPRECATE_FUTUREWARNING(
+ "casting an array to a subarray dtype "
+ "will not using broadcasting in the future, but cast each "
+ "element to the new dtype and then append the dtype's shape "
+ "to the new array. You can opt-in to the new behaviour, by "
+ "additional field to the cast: "
+ "`arr.astype(np.dtype([('f', dtype)]))['f']`.\n"
+ "This may lead to a different result or to current failures "
+ "succeeding. "
+ "(FutureWarning since NumPy 1.20)") < 0) {
+ Py_DECREF(ret);
+ return NULL;
+ }
if (PyArray_CopyInto(ret, self) < 0) {
Py_DECREF(ret);
return NULL;
}
- return PyArray_Return((PyArrayObject *)PyArray_Choose(self, choices, out, clipmode));
+ PyObject *ret = PyArray_Choose(self, choices, out, clipmode);
+
+ /* this matches the unpacking behavior of ufuncs */
+ if (out == NULL) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ else {
+ return ret;
+ }
}
static PyObject *
else {
PyObject *itemp, *otemp;
PyObject *res;
- NPY_COPY_PYOBJECT_PTR(&itemp, iptr);
- NPY_COPY_PYOBJECT_PTR(&otemp, optr);
+ memcpy(&itemp, iptr, sizeof(itemp));
+ memcpy(&otemp, optr, sizeof(otemp));
Py_XINCREF(itemp);
/* call deepcopy on this argument */
res = PyObject_CallFunctionObjArgs(deepcopy, itemp, visit, NULL);
Py_XDECREF(itemp);
Py_XDECREF(otemp);
- NPY_COPY_PYOBJECT_PTR(optr, &res);
+ memcpy(optr, &res, sizeof(res));
}
}
Py_BuildValue("ONc",
(PyObject *)Py_TYPE(self),
Py_BuildValue("(N)",
- PyInt_FromLong(0)),
+ PyLong_FromLong(0)),
/* dummy data-type */
'b'));
Py_DECREF(ret);
return NULL;
}
- PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version));
+ PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version));
PyTuple_SET_ITEM(state, 1, PyObject_GetAttrString((PyObject *)self,
"shape"));
descr = PyArray_DESCR(self);
#if PY_VERSION_HEX >= 0x03080000
/* we expect protocol 5 to be available in Python 3.8 */
pickle_module = PyImport_ImportModule("pickle");
-#elif PY_VERSION_HEX >= 0x03060000
+#else
pickle_module = PyImport_ImportModule("pickle5");
if (pickle_module == NULL) {
/* for protocol 5, raise a clear ImportError if pickle5 is not found
"requires the pickle5 module for Python >=3.6 and <3.8");
return NULL;
}
-#else
- PyErr_SetString(PyExc_ValueError, "pickle protocol 5 is not available "
- "for Python < 3.6");
- return NULL;
#endif
if (pickle_module == NULL){
return NULL;
array_sizeof(PyArrayObject *self)
{
/* object + dimension and strides */
- Py_ssize_t nbytes = NPY_SIZEOF_PYARRAYOBJECT +
+ Py_ssize_t nbytes = Py_TYPE(self)->tp_basicsize +
PyArray_NDIM(self) * sizeof(npy_intp) * 2;
if (PyArray_CHKFLAGS(self, NPY_ARRAY_OWNDATA)) {
nbytes += PyArray_NBYTES(self);
PyArray_OutputConverter, &out)) {
return NULL;
}
- return PyArray_Return(
- (PyArrayObject *)PyArray_Compress(self, condition, axis, out));
+
+ PyObject *ret = PyArray_Compress(self, condition, axis, out);
+
+ /* this matches the unpacking behavior of ufuncs */
+ if (out == NULL) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ else {
+ return ret;
+ }
}
rtype = _CHKTYPENUM(dtype);
Py_XDECREF(dtype);
- return PyArray_Return((PyArrayObject *)PyArray_Trace(self, offset, axis1, axis2, rtype, out));
+ PyObject *ret = PyArray_Trace(self, offset, axis1, axis2, rtype, out);
+
+ /* this matches the unpacking behavior of ufuncs */
+ if (out == NULL) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ else {
+ return ret;
+ }
}
#undef _CHKTYPENUM
PyArray_OutputConverter, &out)) {
return NULL;
}
- return PyArray_Return((PyArrayObject *)PyArray_Round(self, decimals, out));
+
+ PyObject *ret = PyArray_Round(self, decimals, out);
+
+ /* this matches the unpacking behavior of ufuncs */
+ if (out == NULL) {
+ return PyArray_Return((PyArrayObject *)ret);
+ }
+ else {
+ return ret;
+ }
}
PyArrayObject *arr;
PyArray_Descr *dtype;
PyObject *c;
+
if (PyArray_SIZE(self) != 1) {
- PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\
- "be converted to Python scalars");
+ PyErr_SetString(PyExc_TypeError,
+ "only length-1 arrays can be converted to Python scalars");
return NULL;
}
if (!PyArray_CanCastArrayTo(self, dtype, NPY_SAME_KIND_CASTING) &&
!(PyArray_TYPE(self) == NPY_OBJECT)) {
- PyObject *err, *msg_part;
+ PyObject *descr = (PyObject*)PyArray_DESCR(self);
+
Py_DECREF(dtype);
- err = PyString_FromString("unable to convert ");
- if (err == NULL) {
- return NULL;
- }
- msg_part = PyObject_Repr((PyObject*)PyArray_DESCR(self));
- if (msg_part == NULL) {
- Py_DECREF(err);
- return NULL;
- }
- PyString_ConcatAndDel(&err, msg_part);
- if (err == NULL) {
- return NULL;
- }
- msg_part = PyString_FromString(", to complex.");
- if (msg_part == NULL) {
- Py_DECREF(err);
- return NULL;
- }
- PyString_ConcatAndDel(&err, msg_part);
- if (err == NULL) {
- return NULL;
- }
- PyErr_SetObject(PyExc_TypeError, err);
- Py_DECREF(err);
+ PyErr_Format(PyExc_TypeError,
+ "Unable to convert %R to complex", descr);
return NULL;
}
if (PyArray_TYPE(self) == NPY_OBJECT) {
/* let python try calling __complex__ on the object. */
PyObject *args, *res;
+
Py_DECREF(dtype);
args = Py_BuildValue("(O)", *((PyObject**)PyArray_DATA(self)));
if (args == NULL) {
#include "npy_config.h"
#include "npy_pycompat.h"
#include "npy_import.h"
+#include "convert_datatype.h"
+#include "legacy_dtype_implementation.h"
NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0;
/* Internal APIs */
#include "alloc.h"
+#include "abstractdtypes.h"
+#include "array_coercion.h"
#include "arrayfunction_override.h"
#include "arraytypes.h"
#include "arrayobject.h"
#include "templ_common.h" /* for npy_mul_with_overflow_intp */
#include "compiled_base.h"
#include "mem_overlap.h"
-#include "alloc.h"
#include "typeinfo.h"
#include "get_attr_string.h"
*/
NPY_NO_EXPORT PyArrayObject *
PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis,
- PyArrayObject* ret)
+ PyArrayObject* ret, PyArray_Descr *dtype,
+ NPY_CASTING casting)
{
int iarrays, idim, ndim;
npy_intp shape[NPY_MAXDIMS];
}
if (ret != NULL) {
+ assert(dtype == NULL);
if (PyArray_NDIM(ret) != ndim) {
PyErr_SetString(PyExc_ValueError,
"Output array has wrong dimensionality");
/* Get the priority subtype for the array */
PyTypeObject *subtype = PyArray_GetSubType(narrays, arrays);
-
- /* Get the resulting dtype from combining all the arrays */
- PyArray_Descr *dtype = PyArray_ResultType(narrays, arrays, 0, NULL);
- if (dtype == NULL) {
+ PyArray_Descr *descr = PyArray_FindConcatenationDescriptor(
+ narrays, arrays, (PyObject *)dtype);
+ if (descr == NULL) {
return NULL;
}
* resolution rules matching that of the NpyIter.
*/
PyArray_CreateMultiSortedStridePerm(narrays, arrays, ndim, strideperm);
- s = dtype->elsize;
+ s = descr->elsize;
for (idim = ndim-1; idim >= 0; --idim) {
int iperm = strideperm[idim];
strides[iperm] = s;
}
/* Allocate the array for the result. This steals the 'dtype' reference. */
- ret = (PyArrayObject *)PyArray_NewFromDescr(subtype,
- dtype,
- ndim,
- shape,
- strides,
- NULL,
- 0,
- NULL);
+ ret = (PyArrayObject *)PyArray_NewFromDescr_int(
+ subtype, descr, ndim, shape, strides, NULL, 0, NULL,
+ NULL, 0, 1);
if (ret == NULL) {
return NULL;
}
+ assert(PyArray_DESCR(ret) == descr);
}
/*
/* Copy the data for this array */
if (PyArray_AssignArray((PyArrayObject *)sliding_view, arrays[iarrays],
- NULL, NPY_SAME_KIND_CASTING) < 0) {
+ NULL, casting) < 0) {
Py_DECREF(sliding_view);
Py_DECREF(ret);
return NULL;
*/
NPY_NO_EXPORT PyArrayObject *
PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays,
- NPY_ORDER order, PyArrayObject *ret)
+ NPY_ORDER order, PyArrayObject *ret,
+ PyArray_Descr *dtype, NPY_CASTING casting,
+ npy_bool casting_not_passed)
{
int iarrays;
npy_intp shape = 0;
}
}
+ int out_passed = 0;
if (ret != NULL) {
+ assert(dtype == NULL);
+ out_passed = 1;
if (PyArray_NDIM(ret) != 1) {
PyErr_SetString(PyExc_ValueError,
"Output array must be 1D");
/* Get the priority subtype for the array */
PyTypeObject *subtype = PyArray_GetSubType(narrays, arrays);
- /* Get the resulting dtype from combining all the arrays */
- PyArray_Descr *dtype = PyArray_ResultType(narrays, arrays, 0, NULL);
- if (dtype == NULL) {
+ PyArray_Descr *descr = PyArray_FindConcatenationDescriptor(
+ narrays, arrays, (PyObject *)dtype);
+ if (descr == NULL) {
return NULL;
}
- stride = dtype->elsize;
+ stride = descr->elsize;
/* Allocate the array for the result. This steals the 'dtype' reference. */
- ret = (PyArrayObject *)PyArray_NewFromDescr(subtype,
- dtype,
- 1,
- &shape,
- &stride,
- NULL,
- 0,
- NULL);
+ ret = (PyArrayObject *)PyArray_NewFromDescr_int(
+ subtype, descr, 1, &shape, &stride, NULL, 0, NULL,
+ NULL, 0, 1);
if (ret == NULL) {
return NULL;
}
+ assert(PyArray_DESCR(ret) == descr);
}
/*
return NULL;
}
+ int give_deprecation_warning = 1; /* To give warning for just one input array. */
for (iarrays = 0; iarrays < narrays; ++iarrays) {
/* Adjust the window dimensions for this array */
sliding_view->dimensions[0] = PyArray_SIZE(arrays[iarrays]);
+ if (!PyArray_CanCastArrayTo(
+ arrays[iarrays], PyArray_DESCR(ret), casting)) {
+ /* This should be an error, but was previously allowed here. */
+ if (casting_not_passed && out_passed) {
+ /* NumPy 1.20, 2020-09-03 */
+ if (give_deprecation_warning && DEPRECATE(
+ "concatenate() with `axis=None` will use same-kind "
+ "casting by default in the future. Please use "
+ "`casting='unsafe'` to retain the old behaviour. "
+ "In the future this will be a TypeError.") < 0) {
+ Py_DECREF(sliding_view);
+ Py_DECREF(ret);
+ return NULL;
+ }
+ give_deprecation_warning = 0;
+ }
+ else {
+ npy_set_invalid_cast_error(
+ PyArray_DESCR(arrays[iarrays]), PyArray_DESCR(ret),
+ casting, PyArray_NDIM(arrays[iarrays]) == 0);
+ Py_DECREF(sliding_view);
+ Py_DECREF(ret);
+ return NULL;
+ }
+ }
+
/* Copy the data for this array */
if (PyArray_CopyAsFlat((PyArrayObject *)sliding_view, arrays[iarrays],
order) < 0) {
return ret;
}
+
+/**
+ * Implementation for np.concatenate
+ *
+ * @param op Sequence of arrays to concatenate
+ * @param axis Axis to concatenate along
+ * @param ret output array to fill
+ * @param dtype Forced output array dtype (cannot be combined with ret)
+ * @param casting Casting mode used
+ * @param casting_not_passed Deprecation helper
+ */
NPY_NO_EXPORT PyObject *
-PyArray_ConcatenateInto(PyObject *op, int axis, PyArrayObject *ret)
+PyArray_ConcatenateInto(PyObject *op,
+ int axis, PyArrayObject *ret, PyArray_Descr *dtype,
+ NPY_CASTING casting, npy_bool casting_not_passed)
{
int iarrays, narrays;
PyArrayObject **arrays;
"The first input argument needs to be a sequence");
return NULL;
}
+ if (ret != NULL && dtype != NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "concatenate() only takes `out` or `dtype` as an "
+ "argument, but both were provided.");
+ return NULL;
+ }
/* Convert the input list into arrays */
narrays = PySequence_Size(op);
}
if (axis >= NPY_MAXDIMS) {
- ret = PyArray_ConcatenateFlattenedArrays(narrays, arrays, NPY_CORDER, ret);
+ ret = PyArray_ConcatenateFlattenedArrays(
+ narrays, arrays, NPY_CORDER, ret, dtype,
+ casting, casting_not_passed);
}
else {
- ret = PyArray_ConcatenateArrays(narrays, arrays, axis, ret);
+ ret = PyArray_ConcatenateArrays(
+ narrays, arrays, axis, ret, dtype, casting);
}
for (iarrays = 0; iarrays < narrays; ++iarrays) {
NPY_NO_EXPORT PyObject *
PyArray_Concatenate(PyObject *op, int axis)
{
- return PyArray_ConcatenateInto(op, axis, NULL);
+ /* retain legacy behaviour for casting */
+ NPY_CASTING casting;
+ if (axis >= NPY_MAXDIMS) {
+ casting = NPY_UNSAFE_CASTING;
+ }
+ else {
+ casting = NPY_SAME_KIND_CASTING;
+ }
+ return PyArray_ConcatenateInto(
+ op, axis, NULL, NULL, casting, 0);
}
static int
PyObject* ret = NULL;
typenum = PyArray_ObjectType(op1, 0);
+ if (typenum == NPY_NOTYPE && PyErr_Occurred()) {
+ return NULL;
+ }
typenum = PyArray_ObjectType(op2, typenum);
typec = PyArray_DescrFromType(typenum);
if (typec == NULL) {
NPY_BEGIN_THREADS_DEF;
typenum = PyArray_ObjectType(op1, 0);
+ if (typenum == NPY_NOTYPE && PyErr_Occurred()) {
+ return NULL;
+ }
typenum = PyArray_ObjectType(op2, typenum);
typec = PyArray_DescrFromType(typenum);
if (typec == NULL) {
return PyArray_PutMask((PyArrayObject *)array, values, mask);
}
-/*
- * Compare the field dictionaries for two types.
- *
- * Return 1 if the field types and field names of the two descrs are equal and
- * in the same order, 0 if not.
- */
-static int
-_equivalent_fields(PyArray_Descr *type1, PyArray_Descr *type2) {
-
- int val;
-
- if (type1->fields == type2->fields && type1->names == type2->names) {
- return 1;
- }
- if (type1->fields == NULL || type2->fields == NULL) {
- return 0;
- }
-
- val = PyObject_RichCompareBool(type1->fields, type2->fields, Py_EQ);
- if (val != 1 || PyErr_Occurred()) {
- PyErr_Clear();
- return 0;
- }
-
- val = PyObject_RichCompareBool(type1->names, type2->names, Py_EQ);
- if (val != 1 || PyErr_Occurred()) {
- PyErr_Clear();
- return 0;
- }
-
- return 1;
-}
-
-/*
- * Compare the subarray data for two types.
- * Return 1 if they are the same, 0 if not.
- */
-static int
-_equivalent_subarrays(PyArray_ArrayDescr *sub1, PyArray_ArrayDescr *sub2)
-{
- int val;
-
- if (sub1 == sub2) {
- return 1;
-
- }
- if (sub1 == NULL || sub2 == NULL) {
- return 0;
- }
-
- val = PyObject_RichCompareBool(sub1->shape, sub2->shape, Py_EQ);
- if (val != 1 || PyErr_Occurred()) {
- PyErr_Clear();
- return 0;
- }
-
- return PyArray_EquivTypes(sub1->base, sub2->base);
-}
-
/*NUMPY_API
*
NPY_NO_EXPORT unsigned char
PyArray_EquivTypes(PyArray_Descr *type1, PyArray_Descr *type2)
{
- int type_num1, type_num2, size1, size2;
-
- if (type1 == type2) {
- return NPY_TRUE;
- }
-
- type_num1 = type1->type_num;
- type_num2 = type2->type_num;
- size1 = type1->elsize;
- size2 = type2->elsize;
-
- if (size1 != size2) {
- return NPY_FALSE;
- }
- if (PyArray_ISNBO(type1->byteorder) != PyArray_ISNBO(type2->byteorder)) {
- return NPY_FALSE;
- }
- if (type1->subarray || type2->subarray) {
- return ((type_num1 == type_num2)
- && _equivalent_subarrays(type1->subarray, type2->subarray));
- }
- if (type_num1 == NPY_VOID || type_num2 == NPY_VOID) {
- return ((type_num1 == type_num2) && _equivalent_fields(type1, type2));
- }
- if (type_num1 == NPY_DATETIME
- || type_num1 == NPY_TIMEDELTA
- || type_num2 == NPY_DATETIME
- || type_num2 == NPY_TIMEDELTA) {
- return ((type_num1 == type_num2)
- && has_equivalent_datetime_metadata(type1, type2));
+#if NPY_USE_NEW_CASTINGIMPL
+ /*
+ * Do not use PyArray_CanCastTypeTo because it supports legacy flexible
+ * dtypes as input.
+ */
+ NPY_CASTING safety = PyArray_GetCastSafety(type1, type2, NULL);
+ if (safety < 0) {
+ PyErr_Clear();
+ return 0;
}
- return type1->kind == type2->kind;
+ /* If casting is "no casting" this dtypes are considered equivalent. */
+ return PyArray_MinCastSafety(safety, NPY_NO_CASTING) == NPY_NO_CASTING;
+#else
+ return PyArray_LegacyEquivTypes(type1, type2);
+#endif
}
+
/*NUMPY_API*/
NPY_NO_EXPORT unsigned char
PyArray_EquivTypenums(int typenum1, int typenum2)
npy_bool subok = NPY_FALSE;
npy_bool copy = NPY_TRUE;
int ndmin = 0, nd;
+ PyObject* like;
PyArray_Descr *type = NULL;
PyArray_Descr *oldtype = NULL;
NPY_ORDER order = NPY_KEEPORDER;
int flags = 0;
- static char *kwd[]= {"object", "dtype", "copy", "order", "subok",
- "ndmin", NULL};
+ PyObject* array_function_result = NULL;
+
+ static char *kwd[] = {"object", "dtype", "copy", "order", "subok",
+ "ndmin", "like", NULL};
if (PyTuple_GET_SIZE(args) > 2) {
PyErr_Format(PyExc_TypeError,
return NULL;
}
+ array_function_result = array_implement_c_array_function_creation(
+ "array", args, kws);
+ if (array_function_result != Py_NotImplemented) {
+ return array_function_result;
+ }
+
/* super-fast path for ndarray argument calls */
if (PyTuple_GET_SIZE(args) == 0) {
goto full_path;
}
full_path:
- if (!PyArg_ParseTupleAndKeywords(args, kws, "O|O&O&O&O&i:array", kwd,
+ if (!PyArg_ParseTupleAndKeywords(args, kws, "O|O&O&O&O&i$O:array", kwd,
&op,
PyArray_DescrConverter2, &type,
PyArray_BoolConverter, ©,
PyArray_OrderConverter, &order,
PyArray_BoolConverter, &subok,
- &ndmin)) {
+ &ndmin,
+ &like)) {
goto clean_type;
}
array_empty(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"shape", "dtype", "order", NULL};
+ static char *kwlist[] = {"shape", "dtype", "order", "like", NULL};
PyArray_Descr *typecode = NULL;
PyArray_Dims shape = {NULL, 0};
NPY_ORDER order = NPY_CORDER;
+ PyObject *like = NULL;
npy_bool is_f_order;
+ PyObject *array_function_result = NULL;
PyArrayObject *ret = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&:empty", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&$O:empty", kwlist,
PyArray_IntpConverter, &shape,
PyArray_DescrConverter, &typecode,
- PyArray_OrderConverter, &order)) {
+ PyArray_OrderConverter, &order,
+ &like)) {
goto fail;
}
+ array_function_result = array_implement_c_array_function_creation(
+ "empty", args, kwds);
+ if (array_function_result != Py_NotImplemented) {
+ return array_function_result;
+ }
+
switch (order) {
case NPY_CORDER:
is_f_order = NPY_FALSE;
int alloc = 0;
void *dptr;
PyObject *ret;
-
+ PyObject *base = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O:scalar", kwlist,
&PyArrayDescr_Type, &typecode, &obj)) {
return NULL;
}
if (PyDataType_FLAGCHK(typecode, NPY_LIST_PICKLE)) {
- if (!PySequence_Check(obj)) {
- PyErr_SetString(PyExc_TypeError,
- "found non-sequence while unpickling scalar with "
- "NPY_LIST_PICKLE set");
+ if (typecode->type_num == NPY_OBJECT) {
+ /* Deprecated 2020-11-24, NumPy 1.20 */
+ if (DEPRECATE(
+ "Unpickling a scalar with object dtype is deprecated. "
+ "Object scalars should never be created. If this was a "
+ "properly created pickle, please open a NumPy issue. In "
+ "a best effort this returns the original object.") < 0) {
+ return NULL;
+ }
+ Py_INCREF(obj);
+ return obj;
+ }
+ /* We store the full array to unpack it here: */
+ if (!PyArray_CheckExact(obj)) {
+ /* We pickle structured voids as arrays currently */
+ PyErr_SetString(PyExc_RuntimeError,
+ "Unpickling NPY_LIST_PICKLE (structured void) scalar "
+ "requires an array. The pickle file may be corrupted?");
return NULL;
}
- dptr = &obj;
+ if (!PyArray_EquivTypes(PyArray_DESCR((PyArrayObject *)obj), typecode)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Pickled array is not compatible with requested scalar "
+ "dtype. The pickle file may be corrupted?");
+ return NULL;
+ }
+ base = obj;
+ dptr = PyArray_BYTES((PyArrayObject *)obj);
}
else if (PyDataType_FLAGCHK(typecode, NPY_ITEM_IS_POINTER)) {
return NULL;
}
}
- if (!PyString_Check(obj)) {
+ if (!PyBytes_Check(obj)) {
PyErr_SetString(PyExc_TypeError,
- "initializing object must be a string");
+ "initializing object must be a bytes object");
Py_XDECREF(tmpobj);
return NULL;
}
- if (PyString_GET_SIZE(obj) < typecode->elsize) {
+ if (PyBytes_GET_SIZE(obj) < typecode->elsize) {
PyErr_SetString(PyExc_ValueError,
"initialization string is too small");
Py_XDECREF(tmpobj);
return NULL;
}
- dptr = PyString_AS_STRING(obj);
+ dptr = PyBytes_AS_STRING(obj);
}
}
- ret = PyArray_Scalar(dptr, typecode, NULL);
+ ret = PyArray_Scalar(dptr, typecode, base);
/* free dptr which contains zeros */
if (alloc) {
static PyObject *
array_zeros(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"shape", "dtype", "order", NULL};
+ static char *kwlist[] = {"shape", "dtype", "order", "like", NULL};
PyArray_Descr *typecode = NULL;
PyArray_Dims shape = {NULL, 0};
NPY_ORDER order = NPY_CORDER;
+ PyObject *like = NULL;
npy_bool is_f_order = NPY_FALSE;
+ PyObject *array_function_result = NULL;
PyArrayObject *ret = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&:zeros", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&$O:zeros", kwlist,
PyArray_IntpConverter, &shape,
PyArray_DescrConverter, &typecode,
- PyArray_OrderConverter, &order)) {
+ PyArray_OrderConverter, &order,
+ &like)) {
goto fail;
}
+ array_function_result = array_implement_c_array_function_creation(
+ "zeros", args, kwds);
+ if (array_function_result != Py_NotImplemented) {
+ return array_function_result;
+ }
+
switch (order) {
case NPY_CORDER:
is_f_order = NPY_FALSE;
Py_ssize_t nin = -1;
char *sep = NULL;
Py_ssize_t s;
- static char *kwlist[] = {"string", "dtype", "count", "sep", NULL};
+ static char *kwlist[] = {"string", "dtype", "count", "sep", "like", NULL};
+ PyObject *like = NULL;
PyArray_Descr *descr = NULL;
+ PyObject *array_function_result = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywds,
- "s#|O&" NPY_SSIZE_T_PYFMT "s:fromstring", kwlist,
- &data, &s, PyArray_DescrConverter, &descr, &nin, &sep)) {
+ "s#|O&" NPY_SSIZE_T_PYFMT "s$O:fromstring", kwlist,
+ &data, &s, PyArray_DescrConverter, &descr, &nin, &sep, &like)) {
Py_XDECREF(descr);
return NULL;
}
+ array_function_result = array_implement_c_array_function_creation(
+ "fromstring", args, keywds);
+ if (array_function_result != Py_NotImplemented) {
+ return array_function_result;
+ }
+
/* binary mode, condition copied from PyArray_FromString */
if (sep == NULL || strlen(sep) == 0) {
/* Numpy 1.14, 2017-10-19 */
PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
char *sep = "";
Py_ssize_t nin = -1;
- static char *kwlist[] = {"file", "dtype", "count", "sep", "offset", NULL};
+ static char *kwlist[] = {"file", "dtype", "count", "sep", "offset", "like", NULL};
+ PyObject *like = NULL;
PyArray_Descr *type = NULL;
+ PyObject *array_function_result = NULL;
int own;
npy_off_t orig_pos = 0, offset = 0;
FILE *fp;
if (!PyArg_ParseTupleAndKeywords(args, keywds,
- "O|O&" NPY_SSIZE_T_PYFMT "s" NPY_OFF_T_PYFMT ":fromfile", kwlist,
- &file, PyArray_DescrConverter, &type, &nin, &sep, &offset)) {
+ "O|O&" NPY_SSIZE_T_PYFMT "s" NPY_OFF_T_PYFMT "$O:fromfile", kwlist,
+ &file, PyArray_DescrConverter, &type, &nin, &sep, &offset, &like)) {
Py_XDECREF(type);
return NULL;
}
+ array_function_result = array_implement_c_array_function_creation(
+ "fromfile", args, keywds);
+ if (array_function_result != Py_NotImplemented) {
+ return array_function_result;
+ }
+
file = NpyPath_PathlikeToFspath(file);
if (file == NULL) {
return NULL;
Py_DECREF(file);
return NULL;
}
- if (PyString_Check(file) || PyUnicode_Check(file)) {
+ if (PyBytes_Check(file) || PyUnicode_Check(file)) {
Py_SETREF(file, npy_PyFile_OpenFile(file, "rb"));
if (file == NULL) {
Py_XDECREF(type);
{
PyObject *iter;
Py_ssize_t nin = -1;
- static char *kwlist[] = {"iter", "dtype", "count", NULL};
+ static char *kwlist[] = {"iter", "dtype", "count", "like", NULL};
+ PyObject *like = NULL;
PyArray_Descr *descr = NULL;
+ PyObject *array_function_result = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywds,
- "OO&|" NPY_SSIZE_T_PYFMT ":fromiter", kwlist,
- &iter, PyArray_DescrConverter, &descr, &nin)) {
+ "OO&|" NPY_SSIZE_T_PYFMT "$O:fromiter", kwlist,
+ &iter, PyArray_DescrConverter, &descr, &nin, &like)) {
Py_XDECREF(descr);
return NULL;
}
+
+ array_function_result = array_implement_c_array_function_creation(
+ "fromiter", args, keywds);
+ if (array_function_result != Py_NotImplemented) {
+ Py_DECREF(descr);
+ return array_function_result;
+ }
+
return PyArray_FromIter(iter, descr, (npy_intp)nin);
}
{
PyObject *obj = NULL;
Py_ssize_t nin = -1, offset = 0;
- static char *kwlist[] = {"buffer", "dtype", "count", "offset", NULL};
+ static char *kwlist[] = {"buffer", "dtype", "count", "offset", "like", NULL};
+ PyObject *like = NULL;
PyArray_Descr *type = NULL;
+ PyObject *array_function_result = NULL;
if (!PyArg_ParseTupleAndKeywords(args, keywds,
- "O|O&" NPY_SSIZE_T_PYFMT NPY_SSIZE_T_PYFMT ":frombuffer", kwlist,
- &obj, PyArray_DescrConverter, &type, &nin, &offset)) {
+ "O|O&" NPY_SSIZE_T_PYFMT NPY_SSIZE_T_PYFMT "$O:frombuffer", kwlist,
+ &obj, PyArray_DescrConverter, &type, &nin, &offset, &like)) {
Py_XDECREF(type);
return NULL;
}
+
+ array_function_result = array_implement_c_array_function_creation(
+ "frombuffer", args, keywds);
+ if (array_function_result != Py_NotImplemented) {
+ return array_function_result;
+ }
+
if (type == NULL) {
type = PyArray_DescrFromType(NPY_DEFAULT_TYPE);
}
{
PyObject *a0;
PyObject *out = NULL;
+ PyArray_Descr *dtype = NULL;
+ NPY_CASTING casting = NPY_SAME_KIND_CASTING;
+ PyObject *casting_obj = NULL;
+ PyObject *res;
int axis = 0;
- static char *kwlist[] = {"seq", "axis", "out", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O:concatenate", kwlist,
- &a0, PyArray_AxisConverter, &axis, &out)) {
+ static char *kwlist[] = {"seq", "axis", "out", "dtype", "casting", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O$O&O:concatenate", kwlist,
+ &a0, PyArray_AxisConverter, &axis, &out,
+ PyArray_DescrConverter2, &dtype, &casting_obj)) {
+ return NULL;
+ }
+ int casting_not_passed = 0;
+ if (casting_obj == NULL) {
+ /*
+ * Casting was not passed in, needed for deprecation only.
+ * This should be simplified once the deprecation is finished.
+ */
+ casting_not_passed = 1;
+ }
+ else if (!PyArray_CastingConverter(casting_obj, &casting)) {
+ Py_XDECREF(dtype);
return NULL;
}
if (out != NULL) {
}
else if (!PyArray_Check(out)) {
PyErr_SetString(PyExc_TypeError, "'out' must be an array");
+ Py_XDECREF(dtype);
return NULL;
}
}
- return PyArray_ConcatenateInto(a0, axis, (PyArrayObject *)out);
+ res = PyArray_ConcatenateInto(a0, axis, (PyArrayObject *)out, dtype,
+ casting, casting_not_passed);
+ Py_XDECREF(dtype);
+ return res;
}
static PyObject *
"subscript is not within the valid range [0, 52)");
Py_DECREF(obj);
return -1;
- }
+ }
}
-
+
}
Py_DECREF(obj);
arg0 = PyTuple_GET_ITEM(args, 0);
/* einsum('i,j', a, b), einsum('i,j->ij', a, b) */
- if (PyString_Check(arg0) || PyUnicode_Check(arg0)) {
+ if (PyBytes_Check(arg0) || PyUnicode_Check(arg0)) {
nop = einsum_sub_op_from_str(args, &str_obj, &subscripts, op);
}
/* einsum(a, [0], b, [1]), einsum(a, [0], b, [1], [0,1]) */
static PyObject *
array_arange(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) {
PyObject *o_start = NULL, *o_stop = NULL, *o_step = NULL, *range=NULL;
- static char *kwd[]= {"start", "stop", "step", "dtype", NULL};
+ PyObject *like = NULL;
+ PyObject *array_function_result = NULL;
+ static char *kwd[] = {"start", "stop", "step", "dtype", "like", NULL};
PyArray_Descr *typecode = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kws, "O|OOO&:arange", kwd,
+ if (!PyArg_ParseTupleAndKeywords(args, kws, "O|OOO&$O:arange", kwd,
&o_start,
&o_stop,
&o_step,
- PyArray_DescrConverter2, &typecode)) {
+ PyArray_DescrConverter2, &typecode,
+ &like)) {
Py_XDECREF(typecode);
return NULL;
}
+
+ array_function_result = array_implement_c_array_function_creation(
+ "arange", args, kws);
+ if (array_function_result != Py_NotImplemented) {
+ Py_XDECREF(typecode);
+ return array_function_result;
+ }
+
range = PyArray_ArangeObj(o_start, o_stop, o_step, typecode);
Py_XDECREF(typecode);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist )) {
return NULL;
}
- return PyInt_FromLong( (long) PyArray_GetNDArrayCVersion() );
+ return PyLong_FromLong( (long) PyArray_GetNDArrayCVersion() );
}
/*NUMPY_API
}
if (PyArray_TYPE(char_array) == NPY_STRING) {
- method = PyObject_GetAttr((PyObject *)&PyString_Type, method_name);
+ method = PyObject_GetAttr((PyObject *)&PyBytes_Type, method_name);
}
else if (PyArray_TYPE(char_array) == NPY_UNICODE) {
method = PyObject_GetAttr((PyObject *)&PyUnicode_Type, method_name);
return NULL;
}
- return PyInt_FromLong(axis);
+ return PyLong_FromLong(axis);
}
+
static struct PyMethodDef array_module_methods[] = {
{"_get_implementing_args",
(PyCFunction)array__get_implementing_args,
METH_VARARGS | METH_KEYWORDS, NULL},
{"set_legacy_print_mode", (PyCFunction)set_legacy_print_mode,
METH_VARARGS, NULL},
+ {"_discover_array_parameters", (PyCFunction)_discover_array_parameters,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"_get_castingimpl", (PyCFunction)_get_castingimpl,
+ METH_VARARGS | METH_KEYWORDS, NULL},
/* from umath */
{"frompyfunc",
(PyCFunction) ufunc_frompyfunc,
};
#include "__multiarray_api.c"
+#include "array_method.h"
/* Establish scalar-type hierarchy
*
if (PyType_Ready(&PyComplex_Type) < 0) {
return -1;
}
- if (PyType_Ready(&PyString_Type) < 0) {
+ if (PyType_Ready(&PyBytes_Type) < 0) {
return -1;
}
if (PyType_Ready(&PyUnicode_Type) < 0) {
/* Timedelta is an integer with an associated unit */
SINGLE_INHERIT(Timedelta, SignedInteger);
- /*
- fprintf(stderr,
- "tp_free = %p, PyObject_Del = %p, int_tp_free = %p, base.tp_free = %p\n",
- PyIntArrType_Type.tp_free, PyObject_Del, PyInt_Type.tp_free,
- PySignedIntegerArrType_Type.tp_free);
- */
SINGLE_INHERIT(UByte, UnsignedInteger);
SINGLE_INHERIT(UShort, UnsignedInteger);
SINGLE_INHERIT(UInt, UnsignedInteger);
newd = PyDict_New();
#define _addnew(key, val, one) \
- PyDict_SetItemString(newd, #key, s=PyInt_FromLong(val)); \
+ PyDict_SetItemString(newd, #key, s=PyLong_FromLong(val)); \
Py_DECREF(s); \
- PyDict_SetItemString(newd, #one, s=PyInt_FromLong(val)); \
+ PyDict_SetItemString(newd, #one, s=PyLong_FromLong(val)); \
Py_DECREF(s)
#define _addone(key, val) \
- PyDict_SetItemString(newd, #key, s=PyInt_FromLong(val)); \
+ PyDict_SetItemString(newd, #key, s=PyLong_FromLong(val)); \
Py_DECREF(s)
_addnew(OWNDATA, NPY_ARRAY_OWNDATA, O);
NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_ndmin = NULL;
NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_axis1 = NULL;
NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_axis2 = NULL;
+NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_like = NULL;
+NPY_VISIBILITY_HIDDEN PyObject * npy_ma_str_numpy = NULL;
static int
intern_strings(void)
{
- npy_ma_str_array = PyUString_InternFromString("__array__");
- npy_ma_str_array_prepare = PyUString_InternFromString("__array_prepare__");
- npy_ma_str_array_wrap = PyUString_InternFromString("__array_wrap__");
- npy_ma_str_array_finalize = PyUString_InternFromString("__array_finalize__");
- npy_ma_str_ufunc = PyUString_InternFromString("__array_ufunc__");
- npy_ma_str_implementation = PyUString_InternFromString("_implementation");
- npy_ma_str_order = PyUString_InternFromString("order");
- npy_ma_str_copy = PyUString_InternFromString("copy");
- npy_ma_str_dtype = PyUString_InternFromString("dtype");
- npy_ma_str_ndmin = PyUString_InternFromString("ndmin");
- npy_ma_str_axis1 = PyUString_InternFromString("axis1");
- npy_ma_str_axis2 = PyUString_InternFromString("axis2");
+ npy_ma_str_array = PyUnicode_InternFromString("__array__");
+ npy_ma_str_array_prepare = PyUnicode_InternFromString("__array_prepare__");
+ npy_ma_str_array_wrap = PyUnicode_InternFromString("__array_wrap__");
+ npy_ma_str_array_finalize = PyUnicode_InternFromString("__array_finalize__");
+ npy_ma_str_ufunc = PyUnicode_InternFromString("__array_ufunc__");
+ npy_ma_str_implementation = PyUnicode_InternFromString("_implementation");
+ npy_ma_str_order = PyUnicode_InternFromString("order");
+ npy_ma_str_copy = PyUnicode_InternFromString("copy");
+ npy_ma_str_dtype = PyUnicode_InternFromString("dtype");
+ npy_ma_str_ndmin = PyUnicode_InternFromString("ndmin");
+ npy_ma_str_axis1 = PyUnicode_InternFromString("axis1");
+ npy_ma_str_axis2 = PyUnicode_InternFromString("axis2");
+ npy_ma_str_like = PyUnicode_InternFromString("like");
+ npy_ma_str_numpy = PyUnicode_InternFromString("numpy");
return npy_ma_str_array && npy_ma_str_array_prepare &&
npy_ma_str_array_wrap && npy_ma_str_array_finalize &&
npy_ma_str_ufunc && npy_ma_str_implementation &&
npy_ma_str_order && npy_ma_str_copy && npy_ma_str_dtype &&
- npy_ma_str_ndmin && npy_ma_str_axis1 && npy_ma_str_axis2;
+ npy_ma_str_ndmin && npy_ma_str_axis1 && npy_ma_str_axis2 &&
+ npy_ma_str_like && npy_ma_str_numpy;
}
static struct PyModuleDef moduledef = {
if (set_matmul_flags(d) < 0) {
goto err;
}
+
+ PyArrayDTypeMeta_Type.tp_base = &PyType_Type;
+ if (PyType_Ready(&PyArrayDTypeMeta_Type) < 0) {
+ goto err;
+ }
+
+ PyArrayDescr_Type.tp_hash = PyArray_DescrHash;
+ Py_SET_TYPE(&PyArrayDescr_Type, &PyArrayDTypeMeta_Type);
+ if (PyType_Ready(&PyArrayDescr_Type) < 0) {
+ goto err;
+ }
+
initialize_casting_tables();
initialize_numeric_types();
if (initscalarmath(m) < 0) {
goto err;
}
- PyArrayDescr_Type.tp_hash = PyArray_DescrHash;
- if (PyType_Ready(&PyArrayDescr_Type) < 0) {
- goto err;
- }
if (PyType_Ready(&PyArrayFlags_Type) < 0) {
goto err;
}
goto err;
}
- c_api = NpyCapsule_FromVoidPtr((void *)PyArray_API, NULL);
+ c_api = PyCapsule_New((void *)PyArray_API, NULL, NULL);
if (c_api == NULL) {
goto err;
}
PyDict_SetItemString(d, "_ARRAY_API", c_api);
Py_DECREF(c_api);
- c_api = NpyCapsule_FromVoidPtr((void *)PyUFunc_API, NULL);
+ c_api = PyCapsule_New((void *)PyUFunc_API, NULL, NULL);
if (c_api == NULL) {
goto err;
}
*/
PyDict_SetItemString (d, "error", PyExc_Exception);
- s = PyInt_FromLong(NPY_TRACE_DOMAIN);
+ s = PyLong_FromLong(NPY_TRACE_DOMAIN);
PyDict_SetItemString(d, "tracemalloc_domain", s);
Py_DECREF(s);
- s = PyUString_FromString("3.1");
+ s = PyUnicode_FromString("3.1");
PyDict_SetItemString(d, "__version__", s);
Py_DECREF(s);
}
Py_DECREF(s);
- s = NpyCapsule_FromVoidPtr((void *)_datetime_strings, NULL);
+ s = npy_cpu_baseline_list();
+ if (s == NULL) {
+ goto err;
+ }
+ if (PyDict_SetItemString(d, "__cpu_baseline__", s) < 0) {
+ Py_DECREF(s);
+ goto err;
+ }
+ Py_DECREF(s);
+
+ s = npy_cpu_dispatch_list();
+ if (s == NULL) {
+ goto err;
+ }
+ if (PyDict_SetItemString(d, "__cpu_dispatch__", s) < 0) {
+ Py_DECREF(s);
+ goto err;
+ }
+ Py_DECREF(s);
+
+ s = PyCapsule_New((void *)_datetime_strings, NULL, NULL);
if (s == NULL) {
goto err;
}
Py_DECREF(s);
#define ADDCONST(NAME) \
- s = PyInt_FromLong(NPY_##NAME); \
+ s = PyLong_FromLong(NPY_##NAME); \
PyDict_SetItemString(d, #NAME, s); \
Py_DECREF(s)
if (set_typeinfo(d) != 0) {
goto err;
}
+ if (PyType_Ready(&PyArrayMethod_Type) < 0) {
+ goto err;
+ }
+ if (PyType_Ready(&PyBoundArrayMethod_Type) < 0) {
+ goto err;
+ }
+ if (initialize_and_map_pytypes_to_dtypes() < 0) {
+ goto err;
+ }
+
+ if (PyArray_InitializeCasts() < 0) {
+ goto err;
+ }
+
if (initumath(m) != 0) {
goto err;
}
NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_ndmin;
NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_axis1;
NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_axis2;
+NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_like;
+NPY_VISIBILITY_HIDDEN extern PyObject * npy_ma_str_numpy;
#endif
return NpyIter_Reset(iter, NULL);
}
+
+static char *_reset_cast_error = (
+ "Iterator reset failed due to a casting failure. "
+ "This error is set as a Python error.");
+
/*NUMPY_API
* Resets the iterator to its initial state
*
+ * The use of errmsg is discouraged, it cannot be guaranteed that the GIL
+ * will not be grabbed on casting errors even when this is passed.
+ *
* If errmsg is non-NULL, it should point to a variable which will
* receive the error message, and no Python exception will be set.
* This is so that the function can be called from code not holding
- * the GIL.
+ * the GIL. Note that cast errors may still lead to the GIL being
+ * grabbed temporarily.
*/
NPY_NO_EXPORT int
NpyIter_Reset(NpyIter *iter, char **errmsg)
/* If buffer allocation was delayed, do it now */
if (itflags&NPY_ITFLAG_DELAYBUF) {
if (!npyiter_allocate_buffers(iter, errmsg)) {
+ if (errmsg != NULL) {
+ *errmsg = _reset_cast_error;
+ }
return NPY_FAIL;
}
NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_DELAYBUF;
else {
/*
* If the iterindex is already right, no need to
- * do anything
+ * do anything (and no cast error has previously occurred).
*/
bufferdata = NIT_BUFFERDATA(iter);
if (NIT_ITERINDEX(iter) == NIT_ITERSTART(iter) &&
NBF_SIZE(bufferdata) > 0) {
return NPY_SUCCEED;
}
-
- /* Copy any data from the buffers back to the arrays */
- npyiter_copy_from_buffers(iter);
+ if (npyiter_copy_from_buffers(iter) < 0) {
+ if (errmsg != NULL) {
+ *errmsg = _reset_cast_error;
+ }
+ return NPY_FAIL;
+ }
}
}
if (itflags&NPY_ITFLAG_BUFFER) {
/* Prepare the next buffers and set iterend/size */
- npyiter_copy_to_buffers(iter, NULL);
+ if (npyiter_copy_to_buffers(iter, NULL) < 0) {
+ if (errmsg != NULL) {
+ *errmsg = _reset_cast_error;
+ }
+ return NPY_FAIL;
+ }
}
return NPY_SUCCEED;
* If errmsg is non-NULL, it should point to a variable which will
* receive the error message, and no Python exception will be set.
* This is so that the function can be called from code not holding
- * the GIL.
+ * the GIL. Note that cast errors may still lead to the GIL being
+ * grabbed temporarily.
*/
NPY_NO_EXPORT int
NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs, char **errmsg)
NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_DELAYBUF;
}
else {
- /* Copy any data from the buffers back to the arrays */
- npyiter_copy_from_buffers(iter);
+ if (npyiter_copy_from_buffers(iter) < 0) {
+ if (errmsg != NULL) {
+ *errmsg = _reset_cast_error;
+ }
+ return NPY_FAIL;
+ }
}
}
if (itflags&NPY_ITFLAG_BUFFER) {
/* Prepare the next buffers and set iterend/size */
- npyiter_copy_to_buffers(iter, NULL);
+ if (npyiter_copy_to_buffers(iter, NULL) < 0) {
+ if (errmsg != NULL) {
+ *errmsg = _reset_cast_error;
+ }
+ return NPY_FAIL;
+ }
}
return NPY_SUCCEED;
* If errmsg is non-NULL, it should point to a variable which will
* receive the error message, and no Python exception will be set.
* This is so that the function can be called from code not holding
- * the GIL.
+ * the GIL. Note that cast errors may still lead to the GIL being
+ * grabbed temporarily.
*/
NPY_NO_EXPORT int
NpyIter_ResetToIterIndexRange(NpyIter *iter,
/* Start the buffer at the provided iterindex */
else {
/* Write back to the arrays */
- npyiter_copy_from_buffers(iter);
+ if (npyiter_copy_from_buffers(iter) < 0) {
+ return NPY_FAIL;
+ }
npyiter_goto_iterindex(iter, iterindex);
/* Prepare the next buffers and set iterend/size */
- npyiter_copy_to_buffers(iter, NULL);
+ if (npyiter_copy_to_buffers(iter, NULL) < 0) {
+ return NPY_FAIL;
+ }
}
}
else {
if (itflags&NPY_ITFLAG_HASMULTIINDEX) {
perm = NIT_PERM(iter);
for(idim = 0; idim < ndim; ++idim) {
- npy_int8 p = perm[idim];
- if (p < 0) {
- outshape[ndim+p] = NAD_SHAPE(axisdata);
- }
- else {
- outshape[ndim-p-1] = NAD_SHAPE(axisdata);
- }
+ int axis = npyiter_undo_iter_axis_perm(idim, ndim, perm, NULL);
+ outshape[axis] = NAD_SHAPE(axisdata);
NIT_ADVANCE_AXISDATA(axisdata, 1);
}
perm = NIT_PERM(iter);
for(idim = 0; idim < ndim; ++idim) {
- npy_int8 p = perm[idim];
- if (p < 0) {
+ npy_bool flipped;
+ npy_int8 axis = npyiter_undo_iter_axis_perm(idim, ndim, perm, &flipped);
+ if (flipped) {
PyErr_SetString(PyExc_RuntimeError,
"Iterator CreateCompatibleStrides may only be called "
"if DONT_NEGATE_STRIDES was used to prevent reverse "
return NPY_FAIL;
}
else {
- outstrides[ndim-p-1] = itemsize;
+ outstrides[axis] = itemsize;
}
itemsize *= NAD_SHAPE(axisdata);
}
}
+
/*NUMPY_API
* For debugging
*/
* their data needs to be written back to the arrays. The multi-index
* must be positioned for the beginning of the buffer.
*/
-NPY_NO_EXPORT void
+NPY_NO_EXPORT int
npyiter_copy_from_buffers(NpyIter *iter)
{
npy_uint32 itflags = NIT_ITFLAGS(iter);
/* If we're past the end, nothing to copy */
if (NBF_SIZE(bufferdata) == 0) {
- return;
+ return 0;
}
NPY_IT_DBG_PRINT("Iterator: Copying buffers to outputs\n");
maskptr = (npy_bool *)ad_ptrs[maskop];
}
- PyArray_TransferMaskedStridedToNDim(ndim_transfer,
+ if (PyArray_TransferMaskedStridedToNDim(ndim_transfer,
ad_ptrs[iop], dst_strides, axisdata_incr,
buffer, src_stride,
maskptr, strides[maskop],
dst_shape, axisdata_incr,
op_transfersize, dtypes[iop]->elsize,
(PyArray_MaskedStridedUnaryOp *)stransfer,
- transferdata);
+ transferdata) < 0) {
+ return -1;
+ }
}
/* Regular operand */
else {
- PyArray_TransferStridedToNDim(ndim_transfer,
+ if (PyArray_TransferStridedToNDim(ndim_transfer,
ad_ptrs[iop], dst_strides, axisdata_incr,
buffer, src_stride,
dst_coords, axisdata_incr,
dst_shape, axisdata_incr,
op_transfersize, dtypes[iop]->elsize,
stransfer,
- transferdata);
+ transferdata) < 0) {
+ return -1;
+ }
}
}
/* If there's no copy back, we may have to decrement refs. In
NPY_IT_DBG_PRINT1("Iterator: Freeing refs and zeroing buffer "
"of operand %d\n", (int)iop);
/* Decrement refs */
- stransfer(NULL, 0, buffer, dtypes[iop]->elsize,
- transfersize, dtypes[iop]->elsize,
- transferdata);
+ if (stransfer(NULL, 0, buffer, dtypes[iop]->elsize,
+ transfersize, dtypes[iop]->elsize,
+ transferdata) < 0) {
+ /* Since this should only decrement, it should never error */
+ assert(0);
+ return -1;
+ }
/*
* Zero out the memory for safety. For instance,
* if during iteration some Python code copied an
}
NPY_IT_DBG_PRINT("Iterator: Finished copying buffers to outputs\n");
+ return 0;
}
/*
* for the start of a buffer. It decides which operands need a buffer,
* and copies the data into the buffers.
*/
-NPY_NO_EXPORT void
+NPY_NO_EXPORT int
npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs)
{
npy_uint32 itflags = NIT_ITFLAGS(iter);
NBF_BUFITEREND(bufferdata) = iterindex + reduce_innersize;
if (reduce_innersize == 0) {
NBF_REDUCE_OUTERSIZE(bufferdata) = 0;
- return;
+ return 0;
}
else {
NBF_REDUCE_OUTERSIZE(bufferdata) = transfersize/reduce_innersize;
"buffer (%d items)\n",
(int)iop, (int)op_transfersize);
- PyArray_TransferNDimToStrided(ndim_transfer,
- ptrs[iop], dst_stride,
- ad_ptrs[iop], src_strides, axisdata_incr,
- src_coords, axisdata_incr,
- src_shape, axisdata_incr,
- op_transfersize, src_itemsize,
- stransfer,
- transferdata);
+ if (PyArray_TransferNDimToStrided(
+ ndim_transfer, ptrs[iop], dst_stride,
+ ad_ptrs[iop], src_strides, axisdata_incr,
+ src_coords, axisdata_incr,
+ src_shape, axisdata_incr,
+ op_transfersize, src_itemsize,
+ stransfer, transferdata) < 0) {
+ return -1;
+ }
}
}
else if (ptrs[iop] == buffers[iop]) {
NPY_IT_DBG_PRINT1("Iterator: Finished copying inputs to buffers "
"(buffered size is %d)\n", (int)NBF_SIZE(bufferdata));
+ return 0;
}
+
+/**
+ * This function clears any references still held by the buffers and should
+ * only be used to discard buffers if an error occurred.
+ *
+ * @param iter Iterator
+ */
+NPY_NO_EXPORT void
+npyiter_clear_buffers(NpyIter *iter)
+{
+ int nop = iter->nop;
+ NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter);
+
+ if (NBF_SIZE(bufferdata) == 0) {
+ /* if the buffers are empty already, there is nothing to do */
+ return;
+ }
+
+ if (!(NIT_ITFLAGS(iter) & NPY_ITFLAG_NEEDSAPI)) {
+ /* Buffers do not require clearing, but should not be copied back */
+ NBF_SIZE(bufferdata) = 0;
+ return;
+ }
+
+ /*
+ * The iterator may be using a dtype with references, which always
+ * requires the API. In that case, further cleanup may be necessary.
+ *
+ * TODO: At this time, we assume that a dtype having references
+ * implies the need to hold the GIL at all times. In theory
+ * we could broaden this definition for a new
+ * `PyArray_Item_XDECREF` API and the assumption may become
+ * incorrect.
+ */
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+
+ /* Cleanup any buffers with references */
+ char **buffers = NBF_BUFFERS(bufferdata);
+ PyArray_Descr **dtypes = NIT_DTYPES(iter);
+ for (int iop = 0; iop < nop; ++iop, ++buffers) {
+ /*
+ * We may want to find a better way to do this, on the other hand,
+ * this cleanup seems rare and fairly special. A dtype using
+ * references (right now only us) must always keep the buffer in
+ * a well defined state (either NULL or owning the reference).
+ * Only we implement cleanup
+ */
+ if (!PyDataType_REFCHK(dtypes[iop])) {
+ continue;
+ }
+ if (*buffers == 0) {
+ continue;
+ }
+ int itemsize = dtypes[iop]->elsize;
+ for (npy_intp i = 0; i < NBF_SIZE(bufferdata); i++) {
+ /*
+ * See above comment, if this API is expanded the GIL assumption
+ * could become incorrect.
+ */
+ PyArray_Item_XDECREF(*buffers + (itemsize * i), dtypes[iop]);
+ }
+ /* Clear out the buffer just to be sure */
+ memset(*buffers, 0, NBF_SIZE(bufferdata) * itemsize);
+ }
+ /* Signal that the buffers are empty */
+ NBF_SIZE(bufferdata) = 0;
+ PyErr_Restore(type, value, traceback);
+}
+
+
/*
* This checks how much space can be buffered without encountering the
* same value twice, or for operands whose innermost stride is zero,
#include "nditer_impl.h"
#include "arrayobject.h"
+#include "array_coercion.h"
#include "templ_common.h"
#include "array_assign.h"
char **op_dataptr,
const npy_uint32 *op_flags, int **op_axes,
npy_intp const *itershape);
+static NPY_INLINE int
+npyiter_get_op_axis(int axis, npy_bool *reduction_axis);
static void
-npyiter_replace_axisdata(NpyIter *iter, int iop,
- PyArrayObject *op,
- int op_ndim, char *op_dataptr,
- int *op_axes);
+npyiter_replace_axisdata(
+ NpyIter *iter, int iop, PyArrayObject *op,
+ int orig_op_ndim, const int *op_axes);
static void
npyiter_compute_index_strides(NpyIter *iter, npy_uint32 flags);
static void
}
/* Prepare the next buffers and set iterend/size */
- npyiter_copy_to_buffers(iter, NULL);
+ if (npyiter_copy_to_buffers(iter, NULL) < 0) {
+ NpyIter_Deallocate(iter);
+ return NULL;
+ }
}
}
}
/*NUMPY_API
- * Deallocate an iterator
+ * Deallocate an iterator.
+ *
+ * To correctly work when an error is in progress, we have to check
+ * `PyErr_Occurred()`. This is necessary when buffers are not finalized
+ * or WritebackIfCopy is used. We could avoid that check by exposing a new
+ * function which is passed in whether or not a Python error is already set.
*/
NPY_NO_EXPORT int
NpyIter_Deallocate(NpyIter *iter)
{
+ int success = PyErr_Occurred() == NULL;
+
npy_uint32 itflags;
/*int ndim = NIT_NDIM(iter);*/
int iop, nop;
PyArray_Descr **dtype;
PyArrayObject **object;
npyiter_opitflags *op_itflags;
- npy_bool resolve = 1;
if (iter == NULL) {
- return NPY_SUCCEED;
+ return success;
}
itflags = NIT_ITFLAGS(iter);
/* Deallocate any buffers and buffering data */
if (itflags & NPY_ITFLAG_BUFFER) {
+ /* Ensure no data is held by the buffers before they are cleared */
+ if (success) {
+ if (npyiter_copy_from_buffers(iter) < 0) {
+ success = NPY_FAIL;
+ }
+ }
+ else {
+ npyiter_clear_buffers(iter);
+ }
+
NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter);
char **buffers;
NpyAuxData **transferdata;
/* buffers */
buffers = NBF_BUFFERS(bufferdata);
- for(iop = 0; iop < nop; ++iop, ++buffers) {
+ for (iop = 0; iop < nop; ++iop, ++buffers) {
PyArray_free(*buffers);
}
/* read bufferdata */
/*
* Deallocate all the dtypes and objects that were iterated and resolve
- * any writeback buffers created by the iterator
+ * any writeback buffers created by the iterator.
*/
- for(iop = 0; iop < nop; ++iop, ++dtype, ++object) {
+ for (iop = 0; iop < nop; ++iop, ++dtype, ++object) {
if (op_itflags[iop] & NPY_OP_ITFLAG_HAS_WRITEBACK) {
- if (resolve && PyArray_ResolveWritebackIfCopy(*object) < 0) {
- resolve = 0;
+ if (success && PyArray_ResolveWritebackIfCopy(*object) < 0) {
+ success = 0;
}
else {
PyArray_DiscardWritebackIfCopy(*object);
/* Deallocate the iterator memory */
PyObject_Free(iter);
- if (resolve == 0) {
- return NPY_FAIL;
- }
- return NPY_SUCCEED;
+ return success;
}
+
/* Checks 'flags' for (C|F)_ORDER_INDEX, MULTI_INDEX, and EXTERNAL_LOOP,
* setting the appropriate internal flags in 'itflags'.
*
if (axes != NULL) {
memset(axes_dupcheck, 0, NPY_MAXDIMS);
for (idim = 0; idim < oa_ndim; ++idim) {
- int i = axes[idim];
+ int i = npyiter_get_op_axis(axes[idim], NULL);
+
if (i >= 0) {
if (i >= NPY_MAXDIMS) {
PyErr_Format(PyExc_ValueError,
*/
if (op_request_dtype != NULL) {
/* We just have a borrowed reference to op_request_dtype */
- Py_INCREF(op_request_dtype);
- /* If the requested dtype is flexible, adapt it */
- op_request_dtype = PyArray_AdaptFlexibleDType((PyObject *)(*op), PyArray_DESCR(*op),
- op_request_dtype);
- if (op_request_dtype == NULL) {
+ Py_SETREF(*op_dtype, PyArray_AdaptDescriptorToArray(
+ *op, (PyObject *)op_request_dtype));
+ if (*op_dtype == NULL) {
return 0;
}
-
- /* Store the requested dtype */
- Py_DECREF(*op_dtype);
- *op_dtype = op_request_dtype;
}
/* Check if the operand is in the byte order requested */
return 1;
}
+/*
+ * Check whether a reduction is OK based on the flags and the operand being
+ * readwrite. This path is deprecated, since usually only specific axes
+ * should be reduced. If axes are specified explicitely, the flag is
+ * unnecessary.
+ */
+static int
+npyiter_check_reduce_ok_and_set_flags(
+ NpyIter *iter, npy_uint32 flags, npyiter_opitflags *op_itflags,
+ int dim) {
+ /* If it's writeable, this means a reduction */
+ if (*op_itflags & NPY_OP_ITFLAG_WRITE) {
+ if (!(flags & NPY_ITER_REDUCE_OK)) {
+ PyErr_Format(PyExc_ValueError,
+ "output operand requires a reduction along dimension %d, "
+ "but the reduction is not enabled. The dimension size of 1 "
+ "does not match the expected output shape.", dim);
+ return 0;
+ }
+ if (!(*op_itflags & NPY_OP_ITFLAG_READ)) {
+ PyErr_SetString(PyExc_ValueError,
+ "output operand requires a reduction, but is flagged as "
+ "write-only, not read-write");
+ return 0;
+ }
+ NPY_IT_DBG_PRINT("Iterator: Indicating that a reduction is"
+ "occurring\n");
+
+ NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE;
+ *op_itflags |= NPY_OP_ITFLAG_REDUCE;
+ }
+ return 1;
+}
+
+/**
+ * Removes the (additive) NPY_ITER_REDUCTION_AXIS indication and sets
+ * is_forced_broadcast to 1 if it is set. Otherwise to 0.
+ *
+ * @param axis The op_axes[i] to normalize.
+ * @param reduction_axis Output 1 if a reduction axis, otherwise 0.
+ * @returns The normalized axis (without reduce axis flag).
+ */
+static NPY_INLINE int
+npyiter_get_op_axis(int axis, npy_bool *reduction_axis) {
+ npy_bool forced_broadcast = axis >= NPY_ITER_REDUCTION_AXIS(-1);
+
+ if (reduction_axis != NULL) {
+ *reduction_axis = forced_broadcast;
+ }
+ if (forced_broadcast) {
+ return axis - NPY_ITER_REDUCTION_AXIS(0);
+ }
+ return axis;
+}
+
/*
* Fills in the AXISDATA for the 'nop' operands, broadcasting
* the dimensionas as necessary. Also fills
return 0;
}
for (idim = 0; idim < ondim; ++idim) {
- npy_intp bshape = broadcast_shape[idim+ndim-ondim],
- op_shape = shape[idim];
+ npy_intp bshape = broadcast_shape[idim+ndim-ondim];
+ npy_intp op_shape = shape[idim];
+
if (bshape == 1) {
broadcast_shape[idim+ndim-ondim] = op_shape;
}
else {
int *axes = op_axes[iop];
for (idim = 0; idim < ndim; ++idim) {
- int i = axes[idim];
+ int i = npyiter_get_op_axis(axes[idim], NULL);
+
if (i >= 0) {
if (i < ondim) {
- npy_intp bshape = broadcast_shape[idim],
- op_shape = shape[i];
+ npy_intp bshape = broadcast_shape[idim];
+ npy_intp op_shape = shape[i];
+
if (bshape == 1) {
broadcast_shape[idim] = op_shape;
}
}
else {
int *axes = op_axes[iop];
- int i = axes[ndim-idim-1];
- if (i >= 0) {
- if (bshape == 1 || op_cur == NULL) {
+ npy_bool reduction_axis;
+ int i;
+ i = npyiter_get_op_axis(axes[ndim - idim - 1], &reduction_axis);
+
+ if (reduction_axis) {
+ /* This is explicitly a reduction axis */
+ strides[iop] = 0;
+ NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE;
+ op_itflags[iop] |= NPY_OP_ITFLAG_REDUCE;
+
+ if (NPY_UNLIKELY((i >= 0) && (op_cur != NULL) &&
+ (PyArray_DIM(op_cur, i) != 1))) {
+ PyErr_Format(PyExc_ValueError,
+ "operand was set up as a reduction along axis "
+ "%d, but the length of the axis is %zd "
+ "(it has to be 1)",
+ i, (Py_ssize_t)PyArray_DIM(op_cur, i));
+ return 0;
+ }
+ }
+ else if (bshape == 1) {
+ /*
+ * If the full iterator shape is 1, zero always works.
+ * NOTE: We thus always allow broadcast dimensions (i = -1)
+ * if the shape is 1.
+ */
+ strides[iop] = 0;
+ }
+ else if (i >= 0) {
+ if (op_cur == NULL) {
+ /* stride is filled later, shape will match `bshape` */
strides[iop] = 0;
}
else if (PyArray_DIM(op_cur, i) == 1) {
if (op_flags[iop] & NPY_ITER_NO_BROADCAST) {
goto operand_different_than_broadcast;
}
- /* If it's writeable, this means a reduction */
- if (op_itflags[iop] & NPY_OP_ITFLAG_WRITE) {
- if (!(flags & NPY_ITER_REDUCE_OK)) {
- PyErr_SetString(PyExc_ValueError,
- "output operand requires a reduction, but "
- "reduction is not enabled");
- return 0;
- }
- if (!(op_itflags[iop] & NPY_OP_ITFLAG_READ)) {
- PyErr_SetString(PyExc_ValueError,
- "output operand requires a reduction, but "
- "is flagged as write-only, not "
- "read-write");
- return 0;
- }
- NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE;
- op_itflags[iop] |= NPY_OP_ITFLAG_REDUCE;
+ if (!npyiter_check_reduce_ok_and_set_flags(
+ iter, flags, &op_itflags[iop], i)) {
+ return 0;
}
}
else {
strides[iop] = PyArray_STRIDE(op_cur, i);
}
}
- else if (bshape == 1) {
- strides[iop] = 0;
- }
else {
strides[iop] = 0;
- /* If it's writeable, this means a reduction */
- if (op_itflags[iop] & NPY_OP_ITFLAG_WRITE) {
- if (!(flags & NPY_ITER_REDUCE_OK)) {
- PyErr_SetString(PyExc_ValueError,
- "output operand requires a reduction, but "
- "reduction is not enabled");
- return 0;
- }
- if (!(op_itflags[iop] & NPY_OP_ITFLAG_READ)) {
- PyErr_SetString(PyExc_ValueError,
- "output operand requires a reduction, but "
- "is flagged as write-only, not "
- "read-write");
- return 0;
- }
- NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE;
- op_itflags[iop] |= NPY_OP_ITFLAG_REDUCE;
+ if (!npyiter_check_reduce_ok_and_set_flags(
+ iter, flags, &op_itflags[iop], i)) {
+ return 0;
}
}
}
return 1;
broadcast_error: {
- PyObject *errmsg, *tmp;
npy_intp remdims[NPY_MAXDIMS];
- char *tmpstr;
if (op_axes == NULL) {
- errmsg = PyUString_FromString("operands could not be broadcast "
- "together with shapes ");
- if (errmsg == NULL) {
+ PyObject *shape1 = PyUnicode_FromString("");
+ if (shape1 == NULL) {
return 0;
}
for (iop = 0; iop < nop; ++iop) {
if (op[iop] != NULL) {
- tmp = convert_shape_to_string(PyArray_NDIM(op[iop]),
- PyArray_DIMS(op[iop]),
- " ");
+ int ndims = PyArray_NDIM(op[iop]);
+ npy_intp *dims = PyArray_DIMS(op[iop]);
+ PyObject *tmp = convert_shape_to_string(ndims, dims, " ");
if (tmp == NULL) {
- Py_DECREF(errmsg);
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ Py_SETREF(shape1, PyUnicode_Concat(shape1, tmp));
+ Py_DECREF(tmp);
+ if (shape1 == NULL) {
return 0;
}
}
}
- if (itershape != NULL) {
- tmp = PyUString_FromString("and requested shape ");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
- }
-
- tmp = convert_shape_to_string(ndim, itershape, "");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ if (itershape == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "shapes %S", shape1);
+ Py_DECREF(shape1);
+ return 0;
+ }
+ else {
+ PyObject *shape2 = convert_shape_to_string(ndim, itershape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
return 0;
}
-
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "shapes %S and requested shape %S", shape1, shape2);
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
+ return 0;
}
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
}
else {
- errmsg = PyUString_FromString("operands could not be broadcast "
- "together with remapped shapes "
- "[original->remapped]: ");
+ PyObject *shape1 = PyUnicode_FromString("");
+ if (shape1 == NULL) {
+ return 0;
+ }
for (iop = 0; iop < nop; ++iop) {
if (op[iop] != NULL) {
int *axes = op_axes[iop];
+ int ndims = PyArray_NDIM(op[iop]);
+ npy_intp *dims = PyArray_DIMS(op[iop]);
+ char *tmpstr = (axes == NULL) ? " " : "->";
- tmpstr = (axes == NULL) ? " " : "->";
- tmp = convert_shape_to_string(PyArray_NDIM(op[iop]),
- PyArray_DIMS(op[iop]),
- tmpstr);
+ PyObject *tmp = convert_shape_to_string(ndims, dims, tmpstr);
if (tmp == NULL) {
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ Py_SETREF(shape1, PyUnicode_Concat(shape1, tmp));
+ Py_DECREF(tmp);
+ if (shape1 == NULL) {
return 0;
}
if (axes != NULL) {
for (idim = 0; idim < ndim; ++idim) {
- npy_intp i = axes[idim];
+ int i = npyiter_get_op_axis(axes[idim], NULL);
if (i >= 0 && i < PyArray_NDIM(op[iop])) {
remdims[idim] = PyArray_DIM(op[iop], i);
remdims[idim] = -1;
}
}
- tmp = convert_shape_to_string(ndim, remdims, " ");
+ PyObject *tmp = convert_shape_to_string(ndim, remdims, " ");
if (tmp == NULL) {
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ Py_SETREF(shape1, PyUnicode_Concat(shape1, tmp));
+ Py_DECREF(tmp);
+ if (shape1 == NULL) {
return 0;
}
}
}
}
- if (itershape != NULL) {
- tmp = PyUString_FromString("and requested shape ");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
- }
-
- tmp = convert_shape_to_string(ndim, itershape, "");
- if (tmp == NULL) {
- Py_DECREF(errmsg);
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ if (itershape == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "remapped shapes [original->remapped]: %S", shape1);
+ Py_DECREF(shape1);
+ return 0;
+ }
+ else {
+ PyObject *shape2 = convert_shape_to_string(ndim, itershape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
return 0;
}
-
+ PyErr_Format(PyExc_ValueError,
+ "operands could not be broadcast together with "
+ "remapped shapes [original->remapped]: %S and "
+ "requested shape %S", shape1, shape2);
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
+ return 0;
}
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
}
-
- return 0;
}
operand_different_than_broadcast: {
- npy_intp remdims[NPY_MAXDIMS];
- PyObject *errmsg, *tmp;
-
- /* Start of error message */
- if (op_flags[iop] & NPY_ITER_READONLY) {
- errmsg = PyUString_FromString("non-broadcastable operand "
- "with shape ");
- }
- else {
- errmsg = PyUString_FromString("non-broadcastable output "
- "operand with shape ");
- }
- if (errmsg == NULL) {
+ /* operand shape */
+ int ndims = PyArray_NDIM(op[iop]);
+ npy_intp *dims = PyArray_DIMS(op[iop]);
+ PyObject *shape1 = convert_shape_to_string(ndims, dims, "");
+ if (shape1 == NULL) {
return 0;
}
- /* Operand shape */
- tmp = convert_shape_to_string(PyArray_NDIM(op[iop]),
- PyArray_DIMS(op[iop]), "");
- if (tmp == NULL) {
+ /* Broadcast shape */
+ PyObject *shape2 = convert_shape_to_string(ndim, broadcast_shape, "");
+ if (shape2 == NULL) {
+ Py_DECREF(shape1);
return 0;
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+
+ if (op_axes == NULL || op_axes[iop] == NULL) {
+ /* operand shape not remapped */
+
+ if (op_flags[iop] & NPY_ITER_READONLY) {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable operand with shape %S doesn't "
+ "match the broadcast shape %S", shape1, shape2);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable output operand with shape %S doesn't "
+ "match the broadcast shape %S", shape1, shape2);
+ }
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
return 0;
}
- /* Remapped operand shape */
- if (op_axes != NULL && op_axes[iop] != NULL) {
- int *axes = op_axes[iop];
+ else {
+ /* operand shape remapped */
+ npy_intp remdims[NPY_MAXDIMS];
+ int *axes = op_axes[iop];
for (idim = 0; idim < ndim; ++idim) {
- npy_intp i = axes[ndim-idim-1];
-
+ npy_intp i = axes[ndim - idim - 1];
if (i >= 0 && i < PyArray_NDIM(op[iop])) {
remdims[idim] = PyArray_DIM(op[iop], i);
}
}
}
- tmp = PyUString_FromString(" [remapped to ");
- if (tmp == NULL) {
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ PyObject *shape3 = convert_shape_to_string(ndim, remdims, "");
+ if (shape3 == NULL) {
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
return 0;
}
- tmp = convert_shape_to_string(ndim, remdims, "]");
- if (tmp == NULL) {
- return 0;
+ if (op_flags[iop] & NPY_ITER_READONLY) {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable operand with shape %S "
+ "[remapped to %S] doesn't match the broadcast shape %S",
+ shape1, shape3, shape2);
}
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
- }
- }
-
- tmp = PyUString_FromString(" doesn't match the broadcast shape ");
- if (tmp == NULL) {
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
- return 0;
- }
-
- /* Broadcast shape */
- tmp = convert_shape_to_string(ndim, broadcast_shape, "");
- if (tmp == NULL) {
- return 0;
- }
- PyUString_ConcatAndDel(&errmsg, tmp);
- if (errmsg == NULL) {
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "non-broadcastable output operand with shape %S "
+ "[remapped to %S] doesn't match the broadcast shape %S",
+ shape1, shape3, shape2);
+ }
+ Py_DECREF(shape1);
+ Py_DECREF(shape2);
+ Py_DECREF(shape3);
return 0;
}
-
- PyErr_SetObject(PyExc_ValueError, errmsg);
- Py_DECREF(errmsg);
-
- return 0;
}
}
* array.
*/
static void
-npyiter_replace_axisdata(NpyIter *iter, int iop,
- PyArrayObject *op,
- int op_ndim, char *op_dataptr,
- int *op_axes)
+npyiter_replace_axisdata(
+ NpyIter *iter, int iop, PyArrayObject *op,
+ int orig_op_ndim, const int *op_axes)
{
npy_uint32 itflags = NIT_ITFLAGS(iter);
int idim, ndim = NIT_NDIM(iter);
int nop = NIT_NOP(iter);
+ char *op_dataptr = PyArray_DATA(op);
NpyIter_AxisData *axisdata0, *axisdata;
npy_intp sizeof_axisdata;
if (op_axes != NULL) {
for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
- npy_int8 p;
int i;
+ npy_bool axis_flipped;
npy_intp shape;
- /* Apply the perm to get the original axis */
- p = perm[idim];
- if (p < 0) {
- i = op_axes[ndim+p];
- }
- else {
- i = op_axes[ndim-p-1];
- }
+ /* Apply perm to get the original axis, and check if its flipped */
+ i = npyiter_undo_iter_axis_perm(idim, ndim, perm, &axis_flipped);
- if (0 <= i && i < op_ndim) {
+ i = npyiter_get_op_axis(op_axes[i], NULL);
+ assert(i < orig_op_ndim);
+ if (i >= 0) {
shape = PyArray_DIM(op, i);
if (shape != 1) {
npy_intp stride = PyArray_STRIDE(op, i);
- if (p < 0) {
- /* If the perm entry is negative, flip the axis */
+ if (axis_flipped) {
NAD_STRIDES(axisdata)[iop] = -stride;
baseoffset += stride*(shape-1);
}
}
else {
for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
- npy_int8 p;
int i;
+ npy_bool axis_flipped;
npy_intp shape;
- /* Apply the perm to get the original axis */
- p = perm[idim];
- if (p < 0) {
- i = op_ndim+p;
- }
- else {
- i = op_ndim-p-1;
- }
+ i = npyiter_undo_iter_axis_perm(
+ idim, orig_op_ndim, perm, &axis_flipped);
if (i >= 0) {
shape = PyArray_DIM(op, i);
if (shape != 1) {
npy_intp stride = PyArray_STRIDE(op, i);
- if (p < 0) {
- /* If the perm entry is negative, flip the axis */
+ if (axis_flipped) {
NAD_STRIDES(axisdata)[iop] = -stride;
baseoffset += stride*(shape-1);
}
{
npy_uint32 itflags = NIT_ITFLAGS(iter);
int idim, ndim = NIT_NDIM(iter);
+ int used_op_ndim;
int nop = NIT_NOP(iter);
npy_int8 *perm = NIT_PERM(iter);
- npy_intp new_shape[NPY_MAXDIMS], strides[NPY_MAXDIMS],
- stride = op_dtype->elsize;
+ npy_intp new_shape[NPY_MAXDIMS], strides[NPY_MAXDIMS];
+ npy_intp stride = op_dtype->elsize;
NpyIter_AxisData *axisdata;
npy_intp sizeof_axisdata;
- npy_intp i;
+ int i;
PyArrayObject *ret;
sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop);
/* Initialize the strides to invalid values */
- for (i = 0; i < NPY_MAXDIMS; ++i) {
+ for (i = 0; i < op_ndim; ++i) {
strides[i] = NPY_MAX_INTP;
}
if (op_axes != NULL) {
+ used_op_ndim = 0;
for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
- npy_int8 p;
+ npy_bool reduction_axis;
/* Apply the perm to get the original axis */
- p = perm[idim];
- if (p < 0) {
- i = op_axes[ndim+p];
- }
- else {
- i = op_axes[ndim-p-1];
- }
+ i = npyiter_undo_iter_axis_perm(idim, ndim, perm, NULL);
+ i = npyiter_get_op_axis(op_axes[i], &reduction_axis);
if (i >= 0) {
NPY_IT_DBG_PRINT3("Iterator: Setting allocated stride %d "
"for iterator dimension %d to %d\n", (int)i,
(int)idim, (int)stride);
+ used_op_ndim += 1;
strides[i] = stride;
if (shape == NULL) {
- new_shape[i] = NAD_SHAPE(axisdata);
+ if (reduction_axis) {
+ /* reduction axes always have a length of 1 */
+ new_shape[i] = 1;
+ }
+ else {
+ new_shape[i] = NAD_SHAPE(axisdata);
+ }
stride *= new_shape[i];
if (i >= ndim) {
- PyErr_SetString(PyExc_ValueError,
+ PyErr_Format(PyExc_ValueError,
"automatically allocated output array "
- "specified with an inconsistent axis mapping");
+ "specified with an inconsistent axis mapping; "
+ "the axis mapping cannot include dimension %d "
+ "which is too large for the iterator dimension "
+ "of %d.", i, ndim);
return NULL;
}
}
else {
+ assert(!reduction_axis || shape[i] == 1);
stride *= shape[i];
}
}
if (shape == NULL) {
/*
* If deleting this axis produces a reduction, but
- * reduction wasn't enabled, throw an error
+ * reduction wasn't enabled, throw an error.
+ * NOTE: We currently always allow new-axis if the iteration
+ * size is 1 (thus allowing broadcasting sometimes).
*/
- if (NAD_SHAPE(axisdata) != 1) {
- if (!(flags & NPY_ITER_REDUCE_OK)) {
- PyErr_SetString(PyExc_ValueError,
- "output requires a reduction, but "
- "reduction is not enabled");
- return NULL;
- }
- if (!((*op_itflags) & NPY_OP_ITFLAG_READ)) {
- PyErr_SetString(PyExc_ValueError,
- "output requires a reduction, but "
- "is flagged as write-only, not read-write");
+ if (!reduction_axis && NAD_SHAPE(axisdata) != 1) {
+ if (!npyiter_check_reduce_ok_and_set_flags(
+ iter, flags, op_itflags, i)) {
return NULL;
}
-
- NPY_IT_DBG_PRINT("Iterator: Indicating that a "
- "reduction is occurring\n");
- /* Indicate that a reduction is occurring */
- NIT_ITFLAGS(iter) |= NPY_ITFLAG_REDUCE;
- (*op_itflags) |= NPY_OP_ITFLAG_REDUCE;
}
}
}
}
}
else {
+ used_op_ndim = ndim;
for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
- npy_int8 p;
-
/* Apply the perm to get the original axis */
- p = perm[idim];
- if (p < 0) {
- i = op_ndim + p;
- }
- else {
- i = op_ndim - p - 1;
- }
+ i = npyiter_undo_iter_axis_perm(idim, op_ndim, perm, NULL);
if (i >= 0) {
NPY_IT_DBG_PRINT3("Iterator: Setting allocated stride %d "
}
}
- /*
- * If custom axes were specified, some dimensions may not have been used.
- * Add the REDUCE itflag if this creates a reduction situation.
- */
if (shape == NULL) {
- /* Ensure there are no dimension gaps in op_axes, and find op_ndim */
- op_ndim = ndim;
- if (op_axes != NULL) {
- for (i = 0; i < ndim; ++i) {
- if (strides[i] == NPY_MAX_INTP) {
- if (op_ndim == ndim) {
- op_ndim = i;
- }
- }
- /*
- * If there's a gap in the array's dimensions, it's an error.
- * For example, op_axes of [0,2] for the automatically
- * allocated output.
- */
- else if (op_ndim != ndim) {
- PyErr_SetString(PyExc_ValueError,
- "automatically allocated output array "
- "specified with an inconsistent axis mapping");
- return NULL;
- }
+ /* If shape was NULL, use the shape we calculated */
+ op_ndim = used_op_ndim;
+ shape = new_shape;
+ /*
+ * If there's a gap in the array's dimensions, it's an error.
+ * For instance, if op_axes [0, 2] is specified, there will a place
+ * in the strides array where the value is not set.
+ */
+ for (i = 0; i < op_ndim; i++) {
+ if (strides[i] == NPY_MAX_INTP) {
+ PyErr_Format(PyExc_ValueError,
+ "automatically allocated output array "
+ "specified with an inconsistent axis mapping; "
+ "the axis mapping is missing an entry for "
+ "dimension %d.", i);
+ return NULL;
}
}
}
- else {
- for (i = 0; i < op_ndim; ++i) {
- if (strides[i] == NPY_MAX_INTP) {
- npy_intp factor, new_strides[NPY_MAXDIMS],
- itemsize;
-
- /* Fill in the missing strides in C order */
- factor = 1;
- itemsize = op_dtype->elsize;
- for (i = op_ndim-1; i >= 0; --i) {
- if (strides[i] == NPY_MAX_INTP) {
- new_strides[i] = factor * itemsize;
- factor *= shape[i];
- }
- }
-
- /*
- * Copy the missing strides, and multiply the existing strides
- * by the calculated factor. This way, the missing strides
- * are tighter together in memory, which is good for nested
- * loops.
- */
- for (i = 0; i < op_ndim; ++i) {
- if (strides[i] == NPY_MAX_INTP) {
- strides[i] = new_strides[i];
- }
- else {
- strides[i] *= factor;
- }
- }
+ else if (used_op_ndim < op_ndim) {
+ /*
+ * If custom axes were specified, some dimensions may not have
+ * been used. These are additional axes which are ignored in the
+ * iterator but need to be handled here.
+ */
+ npy_intp factor, itemsize, new_strides[NPY_MAXDIMS];
- break;
+ /* Fill in the missing strides in C order */
+ factor = 1;
+ itemsize = op_dtype->elsize;
+ for (i = op_ndim-1; i >= 0; --i) {
+ if (strides[i] == NPY_MAX_INTP) {
+ new_strides[i] = factor * itemsize;
+ factor *= shape[i];
}
}
- }
- /* If shape was NULL, set it to the shape we calculated */
- if (shape == NULL) {
- shape = new_shape;
+ /*
+ * Copy the missing strides, and multiply the existing strides
+ * by the calculated factor. This way, the missing strides
+ * are tighter together in memory, which is good for nested
+ * loops.
+ */
+ for (i = 0; i < op_ndim; ++i) {
+ if (strides[i] == NPY_MAX_INTP) {
+ strides[i] = new_strides[i];
+ }
+ else {
+ strides[i] *= factor;
+ }
+ }
}
/* Allocate the temporary array */
/* Double-check that the subtype didn't mess with the dimensions */
if (subtype != &PyArray_Type) {
+ /*
+ * TODO: the dtype could have a subarray, which adds new dimensions
+ * to `ret`, that should typically be fine, but will break
+ * in this branch.
+ */
if (PyArray_NDIM(ret) != op_ndim ||
!PyArray_CompareLists(shape, PyArray_DIMS(ret), op_ndim)) {
PyErr_SetString(PyExc_RuntimeError,
if (op[iop] == NULL) {
PyArrayObject *out;
PyTypeObject *op_subtype;
- int ondim = ndim;
/* Check whether the subtype was disabled */
op_subtype = (op_flags[iop] & NPY_ITER_NO_SUBTYPE) ?
&PyArray_Type : subtype;
- /* Allocate the output array */
+ /*
+ * Allocate the output array.
+ *
+ * Note that here, ndim is always correct if no op_axes was given
+ * (but the actual dimension of op can be larger). If op_axes
+ * is given, ndim is not actually used.
+ */
out = npyiter_new_temp_array(iter, op_subtype,
flags, &op_itflags[iop],
- ondim,
+ ndim,
NULL,
op_dtype[iop],
op_axes ? op_axes[iop] : NULL);
* Now we need to replace the pointers and strides with values
* from the new array.
*/
- npyiter_replace_axisdata(iter, iop, op[iop], ondim,
- PyArray_DATA(op[iop]), op_axes ? op_axes[iop] : NULL);
+ npyiter_replace_axisdata(iter, iop, op[iop], ndim,
+ op_axes ? op_axes[iop] : NULL);
/*
* New arrays are guaranteed true-aligned, but copy/cast code
* Now we need to replace the pointers and strides with values
* from the temporary array.
*/
- npyiter_replace_axisdata(iter, iop, op[iop], 0,
- PyArray_DATA(op[iop]), NULL);
+ npyiter_replace_axisdata(iter, iop, op[iop], 0, NULL);
/*
* New arrays are guaranteed true-aligned, but copy/cast code
* from the temporary array.
*/
npyiter_replace_axisdata(iter, iop, op[iop], ondim,
- PyArray_DATA(op[iop]), op_axes ? op_axes[iop] : NULL);
+ op_axes ? op_axes[iop] : NULL);
/*
* New arrays are guaranteed true-aligned, but copy/cast code
#define NAD_STRIDES(axisdata) ( \
&(axisdata)->ad_flexdata + 0)
#define NAD_PTRS(axisdata) ((char **) \
- &(axisdata)->ad_flexdata + 1*(nop+1))
+ (&(axisdata)->ad_flexdata + 1*(nop+1)))
#define NAD_NSTRIDES() \
((nop) + ((itflags&NPY_ITFLAG_HASINDEX) ? 1 : 0))
NIT_AXISDATA_SIZEOF(itflags, ndim, nop)*(ndim ? ndim : 1))
/* Internal helper functions shared between implementation files */
+
+/**
+ * Undo the axis permutation of the iterator. When the operand has fewer
+ * dimensions then the iterator, this can return negative values for
+ * inserted (broadcast) dimensions.
+ *
+ * @param axis Axis for which to undo the iterator axis permutation.
+ * @param ndim If `op_axes` is being used, this is the iterator dimension,
+ * otherwise this is the operand dimension.
+ * @param perm The iterator axis permutation NIT_PERM(iter)
+ * @param axis_flipped Will be set to true if this is a flipped axis
+ * (i.e. is iterated in reversed order) and otherwise false.
+ * Can be NULL if the information is not needed.
+ * @return The unpermuted axis. Without `op_axes` this is correct, with
+ * `op_axes` this indexes into `op_axes` (unpermuted iterator axis)
+ */
+static NPY_INLINE int
+npyiter_undo_iter_axis_perm(
+ int axis, int ndim, const npy_int8 *perm, npy_bool *axis_flipped)
+{
+ npy_int8 p = perm[axis];
+ /* The iterator treats axis reversed, thus adjust by ndim */
+ npy_bool flipped = p < 0;
+ if (axis_flipped != NULL) {
+ *axis_flipped = flipped;
+ }
+ if (flipped) {
+ axis = ndim + p;
+ }
+ else {
+ axis = ndim - p - 1;
+ }
+ return axis;
+}
+
NPY_NO_EXPORT void
npyiter_coalesce_axes(NpyIter *iter);
NPY_NO_EXPORT int
npyiter_allocate_buffers(NpyIter *iter, char **errmsg);
NPY_NO_EXPORT void
npyiter_goto_iterindex(NpyIter *iter, npy_intp iterindex);
-NPY_NO_EXPORT void
+NPY_NO_EXPORT int
npyiter_copy_from_buffers(NpyIter *iter);
-NPY_NO_EXPORT void
+NPY_NO_EXPORT int
npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs);
-
+NPY_NO_EXPORT void
+npyiter_clear_buffers(NpyIter *iter);
#endif
Py_DECREF(item);
return NULL;
}
- axis = PyInt_AsLong(v);
+ axis = PyLong_AsLong(v);
Py_DECREF(v);
if (axis < 0 || axis >= NPY_MAXDIMS) {
PyErr_SetString(PyExc_ValueError,
"results.", 1) < 0) {
PyObject *s;
- s = PyUString_FromString("npyiter_dealloc");
+ s = PyUnicode_FromString("npyiter_dealloc");
if (s) {
PyErr_WriteUnraisable(s);
Py_DECREF(s);
Py_RETURN_TRUE;
}
else {
+ if (PyErr_Occurred()) {
+ /* casting error, buffer cleanup will occur at reset or dealloc */
+ return NULL;
+ }
self->finished = 1;
Py_RETURN_FALSE;
}
*/
if (self->started) {
if (!self->iternext(self->iter)) {
+ /*
+ * A casting error may be set here (or no error causing a
+ * StopIteration). Buffers may only be cleaned up later.
+ */
self->finished = 1;
return NULL;
}
if (ret != NULL) {
for (idim = 0; idim < ndim; ++idim) {
PyTuple_SET_ITEM(ret, idim,
- PyInt_FromLong(shape[idim]));
+ PyLong_FromLong(shape[idim]));
}
return ret;
}
}
for (idim = 0; idim < ndim; ++idim) {
PyTuple_SET_ITEM(ret, idim,
- PyInt_FromLong(multi_index[idim]));
+ PyLong_FromLong(multi_index[idim]));
}
return ret;
}
}
for (idim = 0; idim < ndim; ++idim) {
PyObject *v = PySequence_GetItem(value, idim);
- multi_index[idim] = PyInt_AsLong(v);
+ multi_index[idim] = PyLong_AsLong(v);
if (error_converting(multi_index[idim])) {
Py_XDECREF(v);
return -1;
if (NpyIter_HasIndex(self->iter)) {
npy_intp ind = *NpyIter_GetIndexPtr(self->iter);
- return PyInt_FromLong(ind);
+ return PyLong_FromLong(ind);
}
else {
PyErr_SetString(PyExc_ValueError,
if (NpyIter_HasIndex(self->iter)) {
npy_intp ind;
- ind = PyInt_AsLong(value);
+ ind = PyLong_AsLong(value);
if (error_converting(ind)) {
return -1;
}
return NULL;
}
- return PyInt_FromLong(NpyIter_GetIterIndex(self->iter));
+ return PyLong_FromLong(NpyIter_GetIterIndex(self->iter));
}
static int npyiter_iterindex_set(NewNpyArrayIterObject *self, PyObject *value)
return -1;
}
- iterindex = PyInt_AsLong(value);
+ iterindex = PyLong_AsLong(value);
if (error_converting(iterindex)) {
return -1;
}
return NULL;
}
- PyTuple_SET_ITEM(ret, 0, PyInt_FromLong(istart));
- PyTuple_SET_ITEM(ret, 1, PyInt_FromLong(iend));
+ PyTuple_SET_ITEM(ret, 0, PyLong_FromLong(istart));
+ PyTuple_SET_ITEM(ret, 1, PyLong_FromLong(iend));
return ret;
}
return NULL;
}
- return PyInt_FromLong(NpyIter_GetNDim(self->iter));
+ return PyLong_FromLong(NpyIter_GetNDim(self->iter));
}
static PyObject *npyiter_nop_get(NewNpyArrayIterObject *self)
return NULL;
}
- return PyInt_FromLong(NpyIter_GetNOp(self->iter));
+ return PyLong_FromLong(NpyIter_GetNOp(self->iter));
}
static PyObject *npyiter_itersize_get(NewNpyArrayIterObject *self)
return NULL;
}
- return PyInt_FromLong(NpyIter_GetIterSize(self->iter));
+ return PyLong_FromLong(NpyIter_GetIterSize(self->iter));
}
static PyObject *npyiter_finished_get(NewNpyArrayIterObject *self)
return NULL;
}
- if (PyInt_Check(op) || PyLong_Check(op) ||
+ if (PyLong_Check(op) ||
(PyIndex_Check(op) && !PySequence_Check(op))) {
npy_intp i = PyArray_PyIntAsIntp(op);
if (error_converting(i)) {
}
else if (PySlice_Check(op)) {
Py_ssize_t istart = 0, iend = 0, istep = 0, islicelength;
- if (NpySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter),
- &istart, &iend, &istep, &islicelength) < 0) {
+ if (PySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter),
+ &istart, &iend, &istep, &islicelength) < 0) {
return NULL;
}
if (istep != 1) {
return -1;
}
- if (PyInt_Check(op) || PyLong_Check(op) ||
+ if (PyLong_Check(op) ||
(PyIndex_Check(op) && !PySequence_Check(op))) {
npy_intp i = PyArray_PyIntAsIntp(op);
if (error_converting(i)) {
}
else if (PySlice_Check(op)) {
Py_ssize_t istart = 0, iend = 0, istep = 0, islicelength = 0;
- if (NpySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter),
- &istart, &iend, &istep, &islicelength) < 0) {
+ if (PySlice_GetIndicesEx(op, NpyIter_GetNOp(self->iter),
+ &istart, &iend, &istep, &islicelength) < 0) {
return -1;
}
if (istep != 1) {
memcpy(prev_dataptrs, NAD_PTRS(axisdata), NPY_SIZEOF_INTP*nop);
/* Write back to the arrays */
- npyiter_copy_from_buffers(iter);
+ if (npyiter_copy_from_buffers(iter) < 0) {
+ npyiter_clear_buffers(iter);
+ return 0;
+ }
/* Check if we're past the end */
if (NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) {
}
/* Prepare the next buffers and set iterend/size */
- npyiter_copy_to_buffers(iter, prev_dataptrs);
+ if (npyiter_copy_to_buffers(iter, prev_dataptrs) < 0) {
+ npyiter_clear_buffers(iter);
+ return 0;
+ }
return 1;
}
}
/* Write back to the arrays */
- npyiter_copy_from_buffers(iter);
+ if (npyiter_copy_from_buffers(iter) < 0) {
+ npyiter_clear_buffers(iter);
+ return 0;
+ }
/* Check if we're past the end */
if (NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) {
}
/* Prepare the next buffers and set iterend/size */
- npyiter_copy_to_buffers(iter, NULL);
+ if (npyiter_copy_to_buffers(iter, NULL) < 0) {
+ npyiter_clear_buffers(iter);
+ return 0;
+ }
return 1;
}
extern NPY_NO_EXPORT PyBufferProcs array_as_buffer;
-NPY_NO_EXPORT void
-_dealloc_cached_buffer_info(PyObject *self);
+NPY_NO_EXPORT int
+_buffer_info_free(void *buffer_info, PyObject *obj);
NPY_NO_EXPORT PyArray_Descr*
_descriptor_from_pep3118_format(char const *s);
NPY_NO_EXPORT int
-gentype_getbuffer(PyObject *obj, Py_buffer *view, int flags);
+void_getbuffer(PyObject *obj, Py_buffer *view, int flags);
#endif
PyObject *temp;
const int optimize_fpexps = 1;
- if (PyInt_Check(o2)) {
- *out_exponent = (double)PyInt_AsLong(o2);
+ if (PyLong_Check(o2)) {
+ long tmp = PyLong_AsLong(o2);
+ if (error_converting(tmp)) {
+ PyErr_Clear();
+ return NPY_NOSCALAR;
+ }
+ *out_exponent = (double)tmp;
return NPY_INTPOS_SCALAR;
}
+
if (optimize_fpexps && PyFloat_Check(o2)) {
*out_exponent = PyFloat_AsDouble(o2);
return NPY_FLOAT_SCALAR;
}
+
if (PyArray_Check(o2)) {
if ((PyArray_NDIM((PyArrayObject *)o2) == 0) &&
((PyArray_ISINTEGER((PyArrayObject *)o2) ||
else if (PyIndex_Check(o2)) {
PyObject* value = PyNumber_Index(o2);
Py_ssize_t val;
- if (value==NULL) {
+ if (value == NULL) {
if (PyErr_Occurred()) {
PyErr_Clear();
}
return NPY_NOSCALAR;
}
- val = PyInt_AsSsize_t(value);
+ val = PyLong_AsSsize_t(value);
if (error_converting(val)) {
PyErr_Clear();
return NPY_NOSCALAR;
n = PyArray_SIZE(mp);
if (n == 1) {
int res;
- if (Npy_EnterRecursiveCall(" while converting array to bool")) {
+ if (Py_EnterRecursiveCall(" while converting array to bool")) {
return -1;
}
res = PyArray_DESCR(mp)->f->nonzero(PyArray_DATA(mp), mp);
/* Need to guard against recursion if our array holds references */
if (PyDataType_REFCHK(PyArray_DESCR(v))) {
PyObject *res;
- if (Npy_EnterRecursiveCall(where) != 0) {
+ if (Py_EnterRecursiveCall(where) != 0) {
Py_DECREF(scalar);
return NULL;
}
return;
}
if (descr->type_num == NPY_OBJECT) {
- NPY_COPY_PYOBJECT_PTR(&temp, data);
+ memcpy(&temp, data, sizeof(temp));
Py_XINCREF(temp);
}
else if (PyDataType_HASFIELDS(descr)) {
}
if (descr->type_num == NPY_OBJECT) {
- NPY_COPY_PYOBJECT_PTR(&temp, data);
+ memcpy(&temp, data, sizeof(temp));
Py_XDECREF(temp);
}
else if (PyDataType_HASFIELDS(descr)) {
}
else {
for( i = 0; i < n; i++, data++) {
- NPY_COPY_PYOBJECT_PTR(&temp, data);
+ memcpy(&temp, data, sizeof(temp));
Py_XINCREF(temp);
}
}
return -1;
}
while(it->index < it->size) {
- NPY_COPY_PYOBJECT_PTR(&temp, it->dataptr);
+ memcpy(&temp, it->dataptr, sizeof(temp));
Py_XINCREF(temp);
PyArray_ITER_NEXT(it);
}
}
else {
for (i = 0; i < n; i++, data++) {
- NPY_COPY_PYOBJECT_PTR(&temp, data);
+ memcpy(&temp, data, sizeof(temp));
Py_XDECREF(temp);
}
}
else { /* handles misaligned data too */
PyArray_RawIterBaseInit(&it, mp);
while(it.index < it.size) {
- NPY_COPY_PYOBJECT_PTR(&temp, it.dataptr);
+ memcpy(&temp, it.dataptr, sizeof(temp));
Py_XDECREF(temp);
PyArray_ITER_NEXT(&it);
}
_fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype)
{
if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) {
- if ((obj == Py_None) || (PyInt_Check(obj) && PyInt_AsLong(obj)==0)) {
+ PyObject *arr;
+
+ if ((obj == Py_None) ||
+ (PyLong_Check(obj) && PyLong_AsLong(obj) == 0)) {
return;
}
- else {
- PyObject *arr;
- Py_INCREF(dtype);
- arr = PyArray_NewFromDescr(&PyArray_Type, dtype,
- 0, NULL, NULL, NULL,
- 0, NULL);
- if (arr!=NULL) {
- dtype->f->setitem(obj, optr, arr);
- }
- Py_XDECREF(arr);
+ /* Clear possible long conversion error */
+ PyErr_Clear();
+ Py_INCREF(dtype);
+ arr = PyArray_NewFromDescr(&PyArray_Type, dtype,
+ 0, NULL, NULL, NULL,
+ 0, NULL);
+ if (arr!=NULL) {
+ dtype->f->setitem(obj, optr, arr);
}
+ Py_XDECREF(arr);
}
if (dtype->type_num == NPY_OBJECT) {
Py_XINCREF(obj);
- NPY_COPY_PYOBJECT_PTR(optr, &obj);
+ memcpy(optr, &obj, sizeof(obj));
}
else if (PyDataType_HASFIELDS(dtype)) {
PyObject *key, *value, *title = NULL;
{
int type_num;
int align;
- npy_intp memloc;
+ uintptr_t memloc;
if (descr == NULL) {
descr = PyArray_DescrFromScalar(scalar);
type_num = descr->type_num;
}
else if (_CHK(Flexible)) {
if (_CHK(String)) {
- return (void *)PyString_AS_STRING(scalar);
+ return (void *)PyBytes_AS_STRING(scalar);
}
if (_CHK(Unicode)) {
/* Treat this the same as the NPY_UNICODE base class */
* Use the alignment flag to figure out where the data begins
* after a PyObject_HEAD
*/
- memloc = (npy_intp)scalar;
+ memloc = (uintptr_t)scalar;
memloc += sizeof(PyObject);
/* now round-up to the nearest alignment value */
align = descr->alignment;
NPY_NO_EXPORT PyObject *
PyArray_FromScalar(PyObject *scalar, PyArray_Descr *outcode)
{
- PyArray_Descr *typecode;
- PyArrayObject *r;
- char *memptr;
- PyObject *ret;
-
/* convert to 0-dim array of scalar typecode */
- typecode = PyArray_DescrFromScalar(scalar);
+ PyArray_Descr *typecode = PyArray_DescrFromScalar(scalar);
if (typecode == NULL) {
+ Py_XDECREF(outcode);
return NULL;
}
if ((typecode->type_num == NPY_VOID) &&
NULL, (PyObject *)scalar);
}
- /* Need to INCREF typecode because PyArray_NewFromDescr steals a
- * reference below and we still need to access typecode afterwards. */
- Py_INCREF(typecode);
- r = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
+ PyArrayObject *r = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
typecode,
0, NULL,
NULL, NULL, 0, NULL);
- if (r==NULL) {
- Py_DECREF(typecode); Py_XDECREF(outcode);
+ if (r == NULL) {
+ Py_XDECREF(outcode);
return NULL;
}
+ /* the dtype used by the array may be different to the one requested */
+ typecode = PyArray_DESCR(r);
if (PyDataType_FLAGCHK(typecode, NPY_USE_SETITEM)) {
if (typecode->f->setitem(scalar, PyArray_DATA(r), r) < 0) {
- Py_DECREF(typecode); Py_XDECREF(outcode); Py_DECREF(r);
+ Py_DECREF(r);
+ Py_XDECREF(outcode);
return NULL;
}
- goto finish;
}
+ else {
+ char *memptr = scalar_value(scalar, typecode);
- memptr = scalar_value(scalar, typecode);
-
- memcpy(PyArray_DATA(r), memptr, PyArray_ITEMSIZE(r));
- if (PyDataType_FLAGCHK(typecode, NPY_ITEM_HASOBJECT)) {
- /* Need to INCREF just the PyObject portion */
- PyArray_Item_INCREF(memptr, typecode);
+ memcpy(PyArray_DATA(r), memptr, PyArray_ITEMSIZE(r));
+ if (PyDataType_FLAGCHK(typecode, NPY_ITEM_HASOBJECT)) {
+ /* Need to INCREF just the PyObject portion */
+ PyArray_Item_INCREF(memptr, typecode);
+ }
}
-finish:
if (outcode == NULL) {
- Py_DECREF(typecode);
return (PyObject *)r;
}
if (PyArray_EquivTypes(outcode, typecode)) {
if (!PyTypeNum_ISEXTENDED(typecode->type_num)
|| (outcode->elsize == typecode->elsize)) {
- Py_DECREF(typecode); Py_DECREF(outcode);
+ /*
+ * Since the type is equivalent, and we haven't handed the array
+ * to anyone yet, let's fix the dtype to be what was requested,
+ * even if it is equivalent to what was passed in.
+ */
+ Py_SETREF(((PyArrayObject_fields *)r)->descr, outcode);
+
return (PyObject *)r;
}
}
/* cast if necessary to desired output typecode */
- ret = PyArray_CastToType((PyArrayObject *)r, outcode, 0);
- Py_DECREF(typecode); Py_DECREF(r);
+ PyObject *ret = PyArray_CastToType(r, outcode, 0);
+ Py_DECREF(r);
return ret;
}
NPY_NO_EXPORT PyObject *
PyArray_ScalarFromObject(PyObject *object)
{
- PyObject *ret=NULL;
+ PyObject *ret = NULL;
+
if (PyArray_IsZeroDim(object)) {
return PyArray_ToScalar(PyArray_DATA((PyArrayObject *)object),
(PyArrayObject *)object);
}
/*
* Booleans in Python are implemented as a subclass of integers,
- * so PyBool_Check must be called before PyInt_Check.
+ * so PyBool_Check must be called before PyLong_Check.
*/
if (PyBool_Check(object)) {
if (object == Py_True) {
PyArrayScalar_RETURN_FALSE;
}
}
- else if (PyInt_Check(object)) {
- ret = PyArrayScalar_New(Long);
- if (ret == NULL) {
- return NULL;
+ else if (PyLong_Check(object)) {
+ /* Check if fits in long */
+ npy_long val_long = PyLong_AsLong(object);
+ if (!error_converting(val_long)) {
+ ret = PyArrayScalar_New(Long);
+ if (ret != NULL) {
+ PyArrayScalar_VAL(ret, Long) = val_long;
+ }
+ return ret;
+ }
+ PyErr_Clear();
+
+ /* Check if fits in long long */
+ npy_longlong val_longlong = PyLong_AsLongLong(object);
+ if (!error_converting(val_longlong)) {
+ ret = PyArrayScalar_New(LongLong);
+ if (ret != NULL) {
+ PyArrayScalar_VAL(ret, LongLong) = val_longlong;
+ }
+ return ret;
}
- PyArrayScalar_VAL(ret, Long) = PyInt_AS_LONG(object);
+ PyErr_Clear();
+
+ return NULL;
}
else if (PyFloat_Check(object)) {
ret = PyArrayScalar_New(Double);
- if (ret == NULL) {
- return NULL;
+ if (ret != NULL) {
+ PyArrayScalar_VAL(ret, Double) = PyFloat_AS_DOUBLE(object);
}
- PyArrayScalar_VAL(ret, Double) = PyFloat_AS_DOUBLE(object);
+ return ret;
}
else if (PyComplex_Check(object)) {
ret = PyArrayScalar_New(CDouble);
- if (ret == NULL) {
- return NULL;
+ if (ret != NULL) {
+ PyArrayScalar_VAL(ret, CDouble).real = PyComplex_RealAsDouble(object);
+ PyArrayScalar_VAL(ret, CDouble).imag = PyComplex_ImagAsDouble(object);
}
- PyArrayScalar_VAL(ret, CDouble).real = PyComplex_RealAsDouble(object);
- PyArrayScalar_VAL(ret, CDouble).imag = PyComplex_ImagAsDouble(object);
+ return ret;
}
- else if (PyLong_Check(object)) {
- npy_longlong val;
- val = PyLong_AsLongLong(object);
- if (error_converting(val)) {
- PyErr_Clear();
- return NULL;
- }
- ret = PyArrayScalar_New(LongLong);
- if (ret == NULL) {
- return NULL;
- }
- PyArrayScalar_VAL(ret, LongLong) = val;
+ else {
+ return NULL;
}
- return ret;
}
/*New reference */
PyArray_DESCR_REPLACE(descr);
type_num = descr->type_num;
if (type_num == NPY_STRING) {
- descr->elsize = PyString_GET_SIZE(sc);
+ descr->elsize = PyBytes_GET_SIZE(sc);
}
else if (type_num == NPY_UNICODE) {
descr->elsize = PyUnicode_GET_LENGTH(sc) * 4;
}
if (PyTypeNum_ISFLEXIBLE(type_num)) {
if (type_num == NPY_STRING) {
- destptr = PyString_AS_STRING(obj);
- ((PyStringObject *)obj)->ob_shash = -1;
+ destptr = PyBytes_AS_STRING(obj);
+ ((PyBytesObject *)obj)->ob_shash = -1;
memcpy(destptr, data, itemsize);
return obj;
}
const size_t size = _PyObject_VAR_SIZE(type, nitems + 1);
obj = (PyObject *)PyObject_Malloc(size);
+ if (obj == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
/*
- * Fixme. Need to check for no memory.
* If we don't need to zero memory, we could use
* PyObject_{New, NewVar} for this whole function.
*/
static void
gentype_dealloc(PyObject *v)
{
- _dealloc_cached_buffer_info(v);
Py_TYPE(v)->tp_free(v);
}
gentype_add(PyObject *m1, PyObject* m2)
{
/* special case str.__radd__, which should not call array_add */
- if (PyString_Check(m1) || PyUnicode_Check(m1)) {
+ if (PyBytes_Check(m1) || PyUnicode_Check(m1)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
}
memcpy(&retbuf[j], echars, strlen(echars));
- retval = PyUString_FromStringAndSize(retbuf, slen);
+ retval = PyUnicode_FromStringAndSize(retbuf, slen);
PyMem_Free(retbuf);
return retval;
*/
if ((scal->obmeta.num == 1 && scal->obmeta.base != NPY_FR_h) ||
scal->obmeta.base == NPY_FR_GENERIC) {
- ret = PyUString_FromString("numpy.datetime64('");
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString(iso));
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString("')"));
+ ret = PyUnicode_FromFormat("numpy.datetime64('%s')", iso);
}
else {
- ret = PyUString_FromString("numpy.datetime64('");
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString(iso));
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString("','"));
- ret = append_metastr_to_string(&scal->obmeta, 1, ret);
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString("')"));
+ PyObject *meta = metastr_to_unicode(&scal->obmeta, 1);
+ if (meta == NULL) {
+ return NULL;
+ }
+ ret = PyUnicode_FromFormat("numpy.datetime64('%s','%S')", iso, meta);
+ Py_DECREF(meta);
}
return ret;
timedeltatype_repr(PyObject *self)
{
PyTimedeltaScalarObject *scal;
- PyObject *ret;
+ PyObject *val, *ret;
if (!PyArray_IsScalar(self, Timedelta)) {
PyErr_SetString(PyExc_RuntimeError,
/* The value */
if (scal->obval == NPY_DATETIME_NAT) {
- ret = PyUString_FromString("numpy.timedelta64('NaT'");
+ val = PyUnicode_FromString("'NaT'");
}
else {
- /*
- * Can't use "%lld" if HAVE_LONG_LONG is not defined
- */
+ /* Can't use "%lld" if HAVE_LONG_LONG is not defined */
#if defined(HAVE_LONG_LONG)
- ret = PyUString_FromFormat("numpy.timedelta64(%lld",
- (long long)scal->obval);
+ val = PyUnicode_FromFormat("%lld", (long long)scal->obval);
#else
- ret = PyUString_FromFormat("numpy.timedelta64(%ld",
- (long)scal->obval);
+ val = PyUnicode_FromFormat("%ld", (long)scal->obval);
#endif
}
+ if (val == NULL) {
+ return NULL;
+ }
+
/* The metadata unit */
if (scal->obmeta.base == NPY_FR_GENERIC) {
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString(")"));
+ ret = PyUnicode_FromFormat("numpy.timedelta64(%S)", val);
}
else {
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString(",'"));
- ret = append_metastr_to_string(&scal->obmeta, 1, ret);
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString("')"));
+ PyObject *meta = metastr_to_unicode(&scal->obmeta, 1);
+ if (meta == NULL) {
+ Py_DECREF(val);
+ return NULL;
+ }
+ ret = PyUnicode_FromFormat("numpy.timedelta64(%S,'%S')", val, meta);
+ Py_DECREF(meta);
}
+ Py_DECREF(val);
return ret;
}
return NULL;
}
- return PyUString_FromString(iso);
+ return PyUnicode_FromString(iso);
}
static char *_datetime_verbose_strings[NPY_DATETIME_NUMUNITS] = {
}
if (scal->obval == NPY_DATETIME_NAT) {
- ret = PyUString_FromString("NaT");
+ ret = PyUnicode_FromString("NaT");
}
else {
/*
* Can't use "%lld" if HAVE_LONG_LONG is not defined
*/
#if defined(HAVE_LONG_LONG)
- ret = PyUString_FromFormat("%lld ",
- (long long)(scal->obval * scal->obmeta.num));
+ ret = PyUnicode_FromFormat("%lld %s",
+ (long long)(scal->obval * scal->obmeta.num), basestr);
#else
- ret = PyUString_FromFormat("%ld ",
- (long)(scal->obval * scal->obmeta.num));
+ ret = PyUnicode_FromFormat("%ld %s",
+ (long)(scal->obval * scal->obmeta.num), basestr);
#endif
- PyUString_ConcatAndDel(&ret,
- PyUString_FromString(basestr));
}
return ret;
PyOS_snprintf(buf, sizeof(buf), "(%s%sj)", re, im);
}
- return PyUString_FromString(buf);
+ return PyUnicode_FromString(buf);
}
#undef _FMT1
strcpy(&buf[cnt],".0");
}
- return PyUString_FromString(buf);
+ return PyUnicode_FromString(buf);
}
#undef _FMT1
static PyObject *
c@name@type_@kind@(PyObject *self)
{
- PyObject *rstr, *istr, *ret;
+ PyObject *rstr, *istr;
npy_c@name@ val = PyArrayScalar_VAL(self, C@Name@);
TrimMode trim = TrimMode_DptZeros;
if (istr == NULL) {
return NULL;
}
-
- PyUString_ConcatAndDel(&istr, PyUString_FromString("j"));
- return istr;
+ PyObject *ret = PyUnicode_FromFormat("%Sj", istr);
+ Py_DECREF(istr);
+ return ret;
}
if (npy_isfinite(val.real)) {
rstr = @name@type_@kind@_either(val.real, trim, trim, 0);
- if (rstr == NULL) {
- return NULL;
- }
}
else if (npy_isnan(val.real)) {
- rstr = PyUString_FromString("nan");
+ rstr = PyUnicode_FromString("nan");
}
else if (val.real > 0){
- rstr = PyUString_FromString("inf");
+ rstr = PyUnicode_FromString("inf");
}
else {
- rstr = PyUString_FromString("-inf");
+ rstr = PyUnicode_FromString("-inf");
+ }
+ if (rstr == NULL) {
+ return NULL;
}
if (npy_isfinite(val.imag)) {
istr = @name@type_@kind@_either(val.imag, trim, trim, 1);
- if (istr == NULL) {
- return NULL;
- }
}
else if (npy_isnan(val.imag)) {
- istr = PyUString_FromString("+nan");
+ istr = PyUnicode_FromString("+nan");
}
else if (val.imag > 0){
- istr = PyUString_FromString("+inf");
+ istr = PyUnicode_FromString("+inf");
}
else {
- istr = PyUString_FromString("-inf");
+ istr = PyUnicode_FromString("-inf");
+ }
+ if (istr == NULL) {
+ Py_DECREF(rstr);
+ return NULL;
}
- ret = PyUString_FromString("(");
- PyUString_ConcatAndDel(&ret, rstr);
- PyUString_ConcatAndDel(&ret, istr);
- PyUString_ConcatAndDel(&ret, PyUString_FromString("j)"));
+ PyObject *ret = PyUnicode_FromFormat("(%S%Sj)", rstr, istr);
+ Py_DECREF(rstr);
+ Py_DECREF(istr);
return ret;
}
static PyObject *
gentype_ndim_get(PyObject *NPY_UNUSED(self))
{
- return PyInt_FromLong(0);
+ return PyLong_FromLong(0);
}
static PyObject *
static PyObject *
inttype_denominator_get(PyObject *self)
{
- return PyInt_FromLong(1);
+ return PyLong_FromLong(1);
}
typecode = PyArray_DescrFromScalar(self);
elsize = typecode->elsize;
- ret = PyInt_FromLong((long) elsize);
+ ret = PyLong_FromLong((long) elsize);
Py_DECREF(typecode);
return ret;
}
static PyObject *
gentype_size_get(PyObject *NPY_UNUSED(self))
{
- return PyInt_FromLong(1);
+ return PyLong_FromLong(1);
}
static PyObject *
NPY_NO_EXPORT void
gentype_struct_free(PyObject *ptr)
{
- PyArrayInterface *arrif;
- PyObject *context;
-
- arrif = (PyArrayInterface*)PyCapsule_GetPointer(ptr, NULL);
- context = (PyObject *)PyCapsule_GetContext(ptr);
- Py_DECREF(context);
+ PyArrayInterface *arrif = (PyArrayInterface*)PyCapsule_GetPointer(ptr, NULL);
+ if (arrif == NULL) {
+ PyErr_WriteUnraisable(ptr);
+ return;
+ }
+ PyObject *context = (PyObject *)PyCapsule_GetContext(ptr);
+ if (context == NULL && PyErr_Occurred()) {
+ PyErr_WriteUnraisable(ptr);
+ }
+ Py_XDECREF(context);
Py_XDECREF(arrif->descr);
PyArray_free(arrif->shape);
PyArray_free(arrif);
ret = PyObject_GetAttrString(obj, "imag");
if (ret == NULL) {
PyErr_Clear();
- obj = PyInt_FromLong(0);
+ obj = PyLong_FromLong(0);
newtype = PyArray_DescrFromType(NPY_OBJECT);
ret = PyArray_Scalar((char *)&obj, newtype, NULL);
Py_DECREF(newtype);
static PyGetSetDef gentype_getsets[] = {
{"ndim",
(getter)gentype_ndim_get,
- (setter) 0,
- "number of array dimensions",
- NULL},
+ (setter) 0, NULL, NULL},
{"flags",
(getter)gentype_flags_get,
- (setter)0,
- "integer value of flags",
- NULL},
+ (setter)0, NULL, NULL},
{"shape",
(getter)gentype_shape_get,
- (setter)0,
- "tuple of array dimensions",
- NULL},
+ (setter)0, NULL, NULL},
{"strides",
(getter)gentype_shape_get,
- (setter) 0,
- "tuple of bytes steps in each dimension",
- NULL},
+ (setter) 0, NULL, NULL},
{"data",
(getter)gentype_data_get,
- (setter) 0,
- "pointer to start of data",
- NULL},
+ (setter) 0, NULL, NULL},
{"itemsize",
(getter)gentype_itemsize_get,
- (setter)0,
- "length of one element in bytes",
- NULL},
+ (setter)0, NULL, NULL},
{"size",
(getter)gentype_size_get,
- (setter)0,
- "number of elements in the gentype",
- NULL},
+ (setter)0, NULL, NULL},
{"nbytes",
(getter)gentype_itemsize_get,
- (setter)0,
- "length of item in bytes",
- NULL},
+ (setter)0, NULL, NULL},
{"base",
(getter)gentype_base_get,
- (setter)0,
- "base object",
- NULL},
+ (setter)0, NULL, NULL},
{"dtype",
(getter)gentype_typedescr_get,
- NULL,
- "get array data-descriptor",
- NULL},
+ NULL, NULL, NULL},
{"real",
(getter)gentype_real_get,
- (setter)0,
- "real part of scalar",
- NULL},
+ (setter)0, NULL, NULL},
{"imag",
(getter)gentype_imag_get,
- (setter)0,
- "imaginary part of scalar",
- NULL},
+ (setter)0, NULL, NULL},
{"flat",
(getter)gentype_flat_get,
- (setter)0,
- "a 1-d view of scalar",
- NULL},
+ (setter)0, NULL, NULL},
{"T",
(getter)gentype_transpose_get,
- (setter)0,
- "transpose",
- NULL},
+ (setter)0, NULL, NULL},
{"__array_interface__",
(getter)gentype_interface_get,
NULL,
* sticks around after the release.
*/
PyBuffer_Release(&view);
- _dealloc_cached_buffer_info(self);
}
else {
Py_DECREF(ret);
if (arr == NULL) {
return NULL;
}
- /* arr.item() */
- PyObject *val = PyArray_GETITEM(arr, PyArray_DATA(arr));
- Py_DECREF(arr);
- if (val == NULL) {
- return NULL;
- }
- PyObject *tup = Py_BuildValue("NN", obj, val);
+ /* Use the whole array which handles sturctured void correctly */
+ PyObject *tup = Py_BuildValue("NN", obj, arr);
if (tup == NULL) {
return NULL;
}
return -1;
}
- if (PyBaseString_Check(ind)) {
+ if (PyUnicode_Check(ind)) {
/*
* Much like in voidtype_setfield, we cannot simply use ndarray's
* __setitem__ since assignment to void scalars should not broadcast
};
-static PyBufferProcs gentype_as_buffer = {
- .bf_getbuffer = gentype_getbuffer,
- /* release buffer not defined (see buffer.c) */
+/*
+ * This function implements simple buffer export for user defined subclasses
+ * of `np.generic`. All other scalar types override the buffer export.
+ */
+static int
+gentype_arrtype_getbuffer(PyObject *self, Py_buffer *view, int flags)
+{
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
+ PyErr_Format(PyExc_TypeError,
+ "NumPy scalar %R can only exported as a buffer without format.",
+ self);
+ return -1;
+ }
+ if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) {
+ PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly");
+ return -1;
+ }
+ PyArray_Descr *descr = PyArray_DescrFromScalar(self);
+ if (descr == NULL) {
+ return -1;
+ }
+ if (!PyDataType_ISUSERDEF(descr)) {
+ /* This path would also reject the (hopefully) impossible "object" */
+ PyErr_Format(PyExc_TypeError,
+ "user-defined scalar %R registered for built-in dtype %S? "
+ "This should be impossible.",
+ self, descr);
+ return -1;
+ }
+ view->ndim = 0;
+ view->len = descr->elsize;
+ view->itemsize = descr->elsize;
+ view->shape = NULL;
+ view->strides = NULL;
+ view->suboffsets = NULL;
+ view->readonly = 1; /* assume general (user) scalars are readonly. */
+ Py_INCREF(self);
+ view->obj = self;
+ view->buf = scalar_value(self, descr);
+ Py_DECREF(descr);
+ view->format = NULL;
+ return 0;
+}
+
+
+static PyBufferProcs gentype_arrtype_as_buffer = {
+ .bf_getbuffer = (getbufferproc)gentype_arrtype_getbuffer,
+};
+
+
+/**begin repeat
+ * #name = bool, byte, short, int, long, longlong, ubyte, ushort, uint, ulong,
+ * ulonglong, half, float, double, longdouble, cfloat, cdouble,
+ * clongdouble#
+ * #Name = Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong,
+ * ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble,
+ * CLongDouble#
+ * #NAME = BOOL, BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG,
+ * ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE,
+ * CLONGDOUBLE#
+ * #fmt = ?, b, h, i, l, q, B, H, I, L, Q, e, f, d, g, Zf, Zd, Zg#
+ */
+
+static int
+@name@_getbuffer(PyObject *self, Py_buffer *view, int flags)
+{
+ if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) {
+ PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly");
+ return -1;
+ }
+ Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self;
+
+ static char fmt[3] = "@fmt@";
+
+ view->ndim = 0;
+ view->len = sizeof(scalar->obval);
+ view->itemsize = sizeof(scalar->obval);
+ view->shape = NULL;
+ view->strides = NULL;
+ view->suboffsets = NULL;
+ view->readonly = 1;
+ Py_INCREF(self);
+ view->obj = self;
+ view->buf = &(scalar->obval);
+
+ if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) {
+ /* It is unnecessary to find the correct format */
+ view->format = NULL;
+ return 0;
+ }
+
+ view->format = fmt;
+
+ return 0;
+}
+
+static PyBufferProcs @name@_arrtype_as_buffer = {
+ .bf_getbuffer = @name@_getbuffer,
+ /* No need to release the buffer */
+};
+
+/**end repeat**/
+
+static int
+unicode_getbuffer(PyObject *self, Py_buffer *view, int flags)
+{
+ if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) {
+ PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly");
+ return -1;
+ }
+ PyUnicodeScalarObject *scalar = (PyUnicodeScalarObject *)self;
+ Py_ssize_t length = PyUnicode_GetLength(self);
+
+ view->ndim = 0;
+ view->len = length * 4;
+ view->itemsize = length * 4;
+ view->shape = NULL;
+ view->strides = NULL;
+ view->suboffsets = NULL;
+ view->readonly = 1;
+ Py_INCREF(self);
+ view->obj = self;
+
+ if (scalar->obval == NULL) {
+ /*
+ * Unicode may not have the representation available, `scalar_value`
+ * ensures materialization.
+ */
+ PyArray_Descr *descr = PyArray_DescrFromType(NPY_UNICODE);
+ scalar_value(self, descr);
+ Py_DECREF(descr);
+ if (scalar->obval == NULL) {
+ /* allocating memory failed */
+ Py_SETREF(view->obj, NULL);
+ return -1;
+ }
+ }
+ view->buf = scalar->obval;
+
+ if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) {
+ /* It is unnecessary to find the correct format */
+ view->format = NULL;
+ return 0;
+ }
+
+ if (scalar->buffer_fmt != NULL) {
+ view->format = scalar->buffer_fmt;
+ }
+ else {
+ scalar->buffer_fmt = PyMem_Malloc(22);
+ if (scalar->buffer_fmt == NULL) {
+ Py_SETREF(view->obj, NULL);
+ return -1;
+ }
+ PyOS_snprintf(scalar->buffer_fmt, 22, "%" NPY_INTP_FMT "w", length);
+ view->format = scalar->buffer_fmt;
+ }
+
+ return 0;
+}
+
+static PyBufferProcs unicode_arrtype_as_buffer = {
+ .bf_getbuffer = unicode_getbuffer,
+ /* No need to release the buffer */
+};
+
+
+/**begin repeat
+ * #name = datetime, timedelta#
+ * #Name = Datetime, Timedelta#
+ */
+
+static int
+@name@_getbuffer(PyObject *self, Py_buffer *view, int flags)
+{
+ if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) {
+ PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly");
+ return -1;
+ }
+ Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self;
+
+ view->ndim = 1;
+ view->len = 8;
+ view->itemsize = 1;
+ static Py_ssize_t length = 8;
+ view->shape = &length;
+ view->strides = NULL;
+ view->suboffsets = NULL;
+ view->readonly = 1;
+ Py_INCREF(self);
+ view->obj = self;
+
+ view->buf = &(scalar->obval);
+
+ if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) {
+ /* It is unnecessary to find the correct format */
+ view->format = NULL;
+ return 0;
+ }
+
+ /* export datetime scalars as bytes (although arrays are not exported) */
+ view->format = "B";
+
+ return 0;
+}
+
+static PyBufferProcs @name@_arrtype_as_buffer = {
+ .bf_getbuffer = @name@_getbuffer,
+ /* No need to release the buffer */
+};
+
+/**end repeat**/
+
+static PyBufferProcs void_arrtype_as_buffer = {
+ .bf_getbuffer = void_getbuffer, /* defined in buffer.c */
+ /* No need to release the buffer */
};
.tp_basicsize = sizeof(PyObject),
};
+
static void
void_dealloc(PyVoidScalarObject *v)
{
- _dealloc_cached_buffer_info((PyObject *)v);
-
if (v->flags & NPY_ARRAY_OWNDATA) {
npy_free_cache(v->obval, Py_SIZE(v));
}
Py_XDECREF(v->descr);
Py_XDECREF(v->base);
+ if (_buffer_info_free(v->_buffer_info, (PyObject *)v) < 0) {
+ PyErr_WriteUnraisable(NULL);
+ }
Py_TYPE(v)->tp_free(v);
}
+
+static PyObject *
+object_arrtype_alloc(PyTypeObject *type, Py_ssize_t items)
+{
+ /*
+ * Object scalars should not actually exist, if they exist we should
+ * consider it to be a bug.
+ */
+ static PyObject *visibleDeprecationWarning = NULL;
+ npy_cache_import("numpy", "VisibleDeprecationWarning",
+ &visibleDeprecationWarning);
+ if (visibleDeprecationWarning == NULL) {
+ return NULL;
+ }
+ if (PyErr_WarnEx(visibleDeprecationWarning,
+ "Creating a NumPy object scalar. NumPy object scalars should "
+ "never be created. If you see this message please inform the "
+ "NumPy developers. Since this message should never be shown "
+ "this will raise a TypeError in the future.", 1) < 0) {
+ return NULL;
+ }
+ return gentype_alloc(type, items);
+}
+
+
static void
object_arrtype_dealloc(PyObject *v)
{
{
/* note: may be null if it was never requested */
PyMem_Free(PyArrayScalar_VAL(v, Unicode));
+ PyMem_Free(((PyUnicodeScalarObject *)v)->buffer_fmt);
/* delegate to the base class */
PyUnicode_Type.tp_dealloc(v);
}
* ulong, ulonglong#
* #Name = Byte, Short, Int, Long, UByte, UShort, LongLong, UInt,
* ULong, ULongLong#
- * #type = PyInt_FromLong*6, PyLong_FromLongLong*1,
+ * #type = PyLong_FromLong*6, PyLong_FromLongLong*1,
* PyLong_FromUnsignedLong*2, PyLong_FromUnsignedLongLong#
*/
static PyNumberMethods @name@_arrtype_as_number;
return NULL;
}
else {
- return PyInt_FromLong(PyArrayScalar_VAL(a, Bool));
+ return PyLong_FromLong(PyArrayScalar_VAL(a, Bool));
}
}
* For a VOID scalar first see if obj is an integer or long
* and create new memory of that size (filled with 0) for the scalar
*/
- if (PyLong_Check(obj) || PyInt_Check(obj) ||
+ if (PyLong_Check(obj) ||
PyArray_IsScalar(obj, Integer) ||
(PyArray_Check(obj) &&
PyArray_NDIM((PyArrayObject *)obj)==0 &&
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "numpy.object_",
.tp_basicsize = sizeof(PyObjectScalarObject),
+ .tp_alloc = object_arrtype_alloc,
.tp_dealloc = (destructor)object_arrtype_dealloc,
.tp_as_sequence = &object_arrtype_as_sequence,
.tp_as_mapping = &object_arrtype_as_mapping,
init_basetypes();
PyGenericArrType_Type.tp_dealloc = (destructor)gentype_dealloc;
PyGenericArrType_Type.tp_as_number = &gentype_as_number;
- PyGenericArrType_Type.tp_as_buffer = &gentype_as_buffer;
PyGenericArrType_Type.tp_as_mapping = &gentype_as_mapping;
PyGenericArrType_Type.tp_flags = BASEFLAGS;
PyGenericArrType_Type.tp_methods = gentype_methods;
PyGenericArrType_Type.tp_alloc = gentype_alloc;
PyGenericArrType_Type.tp_free = (freefunc)gentype_free;
PyGenericArrType_Type.tp_richcompare = gentype_richcompare;
+ PyGenericArrType_Type.tp_as_buffer = &gentype_arrtype_as_buffer;
PyBoolArrType_Type.tp_as_number = &bool_arrtype_as_number;
/*
Py@NAME@ArrType_Type.tp_new = @name@_arrtype_new;
Py@NAME@ArrType_Type.tp_richcompare = gentype_richcompare;
+#define _IS_@NAME@ /* inherit string buffer */
+#if !defined(_IS_String)
+ Py@NAME@ArrType_Type.tp_as_buffer = &@name@_arrtype_as_buffer;
+#endif
+#undef _IS_@NAME@
+
/**end repeat**/
PyUnicodeArrType_Type.tp_dealloc = unicode_arrtype_dealloc;
- PyUnicodeArrType_Type.tp_as_buffer = &gentype_as_buffer;
/**begin repeat
* #name = bool, byte, short, ubyte, ushort, uint, ulong, ulonglong,
return ret;
}
+static PyObject *
+array_concat(PyObject *self, PyObject *other)
+{
+ /*
+ * Throw a type error, when trying to concat NDArrays
+ * NOTE: This error is not Thrown when running with PyPy
+ */
+ PyErr_SetString(PyExc_TypeError,
+ "Concatenation operation is not implemented for NumPy arrays, "
+ "use np.concatenate() instead. Please do not rely on this error; "
+ "it may not be given on all Python implementations.");
+ return NULL;
+}
+
+
NPY_NO_EXPORT PySequenceMethods array_as_sequence = {
(lenfunc)array_length, /*sq_length*/
- (binaryfunc)NULL, /*sq_concat is handled by nb_add*/
+ (binaryfunc)array_concat, /*sq_concat for operator.concat*/
(ssizeargfunc)NULL,
(ssizeargfunc)array_item,
(ssizessizeargfunc)NULL,
if (newnbytes > oldnbytes && PyArray_ISWRITEABLE(self)) {
/* Fill new memory with zeros */
if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_ITEM_REFCOUNT)) {
- PyObject *zero = PyInt_FromLong(0);
+ PyObject *zero = PyLong_FromLong(0);
char *optr;
optr = PyArray_BYTES(self) + oldnbytes;
npy_intp n_new = newsize - oldsize;
for (i = 0; i < nsize; i++) {
Py_INCREF(zero);
- NPY_COPY_PYOBJECT_PTR(optr, &zero);
+ memcpy(optr, &zero, sizeof(zero));
optr += sizeof(zero);
}
}
static void
raise_reshape_size_mismatch(PyArray_Dims *newshape, PyArrayObject *arr)
{
- PyObject *msg = PyUString_FromFormat("cannot reshape array of size %zd "
- "into shape ", PyArray_SIZE(arr));
PyObject *tmp = convert_shape_to_string(newshape->len, newshape->ptr, "");
-
- PyUString_ConcatAndDel(&msg, tmp);
- if (msg != NULL) {
- PyErr_SetObject(PyExc_ValueError, msg);
- Py_DECREF(msg);
+ if (tmp != NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "cannot reshape array of size %zd into shape %S",
+ PyArray_SIZE(arr), tmp);
+ Py_DECREF(tmp);
}
}
return (PyObject *)ret;
}
-/* See shape.h for parameters documentation */
-NPY_NO_EXPORT PyObject *
-build_shape_string(npy_intp n, npy_intp const *vals)
-{
- npy_intp i;
- PyObject *ret, *tmp;
-
- /*
- * Negative dimension indicates "newaxis", which can
- * be discarded for printing if it's a leading dimension.
- * Find the first non-"newaxis" dimension.
- */
- i = 0;
- while (i < n && vals[i] < 0) {
- ++i;
- }
-
- if (i == n) {
- return PyUString_FromFormat("()");
- }
- else {
- ret = PyUString_FromFormat("(%" NPY_INTP_FMT, vals[i++]);
- if (ret == NULL) {
- return NULL;
- }
- }
-
- for (; i < n; ++i) {
- if (vals[i] < 0) {
- tmp = PyUString_FromString(",newaxis");
- }
- else {
- tmp = PyUString_FromFormat(",%" NPY_INTP_FMT, vals[i]);
- }
- if (tmp == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
-
- PyUString_ConcatAndDel(&ret, tmp);
- if (ret == NULL) {
- return NULL;
- }
- }
-
- tmp = PyUString_FromFormat(")");
- PyUString_ConcatAndDel(&ret, tmp);
- return ret;
-}
/*NUMPY_API
*
#ifndef _NPY_ARRAY_SHAPE_H_
#define _NPY_ARRAY_SHAPE_H_
-/*
- * Builds a string representation of the shape given in 'vals'.
- * A negative value in 'vals' gets interpreted as newaxis.
- */
-NPY_NO_EXPORT PyObject *
-build_shape_string(npy_intp n, npy_intp const *vals);
-
/*
* Creates a sorted stride perm matching the KEEPORDER behavior
* of the NpyIter object. Because this operates based on multiple
#include <Python.h>
#include <numpy/arrayobject.h>
-
#include "npy_pycompat.h"
-
+#include "npy_import.h"
#include "strfuncs.h"
static PyObject *PyArray_StrFunction = NULL;
static PyObject *PyArray_ReprFunction = NULL;
+
+static void
+npy_PyErr_SetStringChained(PyObject *type, const char *message)
+{
+ PyObject *exc, *val, *tb;
+
+ PyErr_Fetch(&exc, &val, &tb);
+ PyErr_SetString(type, message);
+ npy_PyErr_ChainExceptionsCause(exc, val, tb);
+}
+
+
/*NUMPY_API
* Set the array print function to be a Python function.
*/
}
-/*
- * Extend string. On failure, returns NULL and leaves *strp alone.
- * XXX we do this in multiple places; time for a string library?
- */
-static char *
-extend_str(char **strp, Py_ssize_t n, Py_ssize_t *maxp)
-{
- char *str = *strp;
- Py_ssize_t new_cap;
-
- if (n >= *maxp - 16) {
- new_cap = *maxp * 2;
-
- if (new_cap <= *maxp) { /* overflow */
- return NULL;
- }
- str = PyArray_realloc(*strp, new_cap);
- if (str != NULL) {
- *strp = str;
- *maxp = new_cap;
- }
- }
- return str;
-}
-
-
-static int
-dump_data(char **string, Py_ssize_t *n, Py_ssize_t *max_n, char *data, int nd,
- npy_intp const *dimensions, npy_intp const *strides, PyArrayObject* self)
-{
- PyObject *op = NULL, *sp = NULL;
- char *ostring;
- npy_intp i, N, ret = 0;
-
-#define CHECK_MEMORY do { \
- if (extend_str(string, *n, max_n) == NULL) { \
- ret = -1; \
- goto end; \
- } \
- } while (0)
-
- if (nd == 0) {
- if ((op = PyArray_GETITEM(self, data)) == NULL) {
- return -1;
- }
- sp = PyObject_Repr(op);
- if (sp == NULL) {
- ret = -1;
- goto end;
- }
- ostring = PyString_AsString(sp);
- N = PyString_Size(sp)*sizeof(char);
- *n += N;
- CHECK_MEMORY;
- memmove(*string + (*n - N), ostring, N);
- }
- else {
- CHECK_MEMORY;
- (*string)[*n] = '[';
- *n += 1;
- for (i = 0; i < dimensions[0]; i++) {
- if (dump_data(string, n, max_n,
- data + (*strides)*i,
- nd - 1, dimensions + 1,
- strides + 1, self) < 0) {
- return -1;
- }
- CHECK_MEMORY;
- if (i < dimensions[0] - 1) {
- (*string)[*n] = ',';
- (*string)[*n+1] = ' ';
- *n += 2;
- }
- }
- CHECK_MEMORY;
- (*string)[*n] = ']';
- *n += 1;
- }
-
-#undef CHECK_MEMORY
-
-end:
- Py_XDECREF(op);
- Py_XDECREF(sp);
- return ret;
-}
-
-
-static PyObject *
-array_repr_builtin(PyArrayObject *self, int repr)
-{
- PyObject *ret;
- char *string;
- /* max_n initial value is arbitrary, dump_data will extend it */
- Py_ssize_t n = 0, max_n = PyArray_NBYTES(self) * 4 + 7;
-
- if ((string = PyArray_malloc(max_n)) == NULL) {
- return PyErr_NoMemory();
- }
-
- if (dump_data(&string, &n, &max_n, PyArray_DATA(self),
- PyArray_NDIM(self), PyArray_DIMS(self),
- PyArray_STRIDES(self), self) < 0) {
- PyArray_free(string);
- return NULL;
- }
-
- if (repr) {
- if (PyArray_ISEXTENDED(self)) {
- ret = PyUString_FromFormat("array(%s, '%c%d')",
- string,
- PyArray_DESCR(self)->type,
- PyArray_DESCR(self)->elsize);
- }
- else {
- ret = PyUString_FromFormat("array(%s, '%c')",
- string,
- PyArray_DESCR(self)->type);
- }
- }
- else {
- ret = PyUString_FromStringAndSize(string, n);
- }
-
- PyArray_free(string);
- return ret;
-}
-
-
NPY_NO_EXPORT PyObject *
array_repr(PyArrayObject *self)
{
- PyObject *s;
+ static PyObject *repr = NULL;
- if (PyArray_ReprFunction == NULL) {
- s = array_repr_builtin(self, 1);
+ if (PyArray_ReprFunction != NULL) {
+ return PyObject_CallFunctionObjArgs(PyArray_ReprFunction, self, NULL);
}
- else {
- s = PyObject_CallFunctionObjArgs(PyArray_ReprFunction, self, NULL);
+
+ /*
+ * We need to do a delayed import here as initialization on module load
+ * leads to circular import problems.
+ */
+ npy_cache_import("numpy.core.arrayprint", "_default_array_repr", &repr);
+ if (repr == NULL) {
+ npy_PyErr_SetStringChained(PyExc_RuntimeError,
+ "Unable to configure default ndarray.__repr__");
+ return NULL;
}
- return s;
+ return PyObject_CallFunctionObjArgs(repr, self, NULL);
}
NPY_NO_EXPORT PyObject *
array_str(PyArrayObject *self)
{
- PyObject *s;
+ static PyObject *str = NULL;
- if (PyArray_StrFunction == NULL) {
- s = array_repr_builtin(self, 0);
+ if (PyArray_StrFunction != NULL) {
+ return PyObject_CallFunctionObjArgs(PyArray_StrFunction, self, NULL);
}
- else {
- s = PyObject_CallFunctionObjArgs(PyArray_StrFunction, self, NULL);
+
+ /*
+ * We need to do a delayed import here as initialization on module load leads
+ * to circular import problems.
+ */
+ npy_cache_import("numpy.core.arrayprint", "_default_array_str", &str);
+ if (str == NULL) {
+ npy_PyErr_SetStringChained(PyExc_RuntimeError,
+ "Unable to configure default ndarray.__str__");
+ return NULL;
}
- return s;
+ return PyObject_CallFunctionObjArgs(str, self, NULL);
}
+
NPY_NO_EXPORT PyObject *
array_format(PyArrayObject *self, PyObject *args)
{
);
}
}
-
#define NPY_ELIDE_DEBUG 0
#define NPY_MAX_STACKSIZE 10
-#if PY_VERSION_HEX >= 0x03060000
/* TODO can pep523 be used to somehow? */
#define PYFRAMEEVAL_FUNC "_PyEval_EvalFrameDefault"
-#else
-#define PYFRAMEEVAL_FUNC "PyEval_EvalFrameEx"
-#endif
/*
* Heuristic size of the array in bytes at which backtrace overhead generation
* becomes less than speed gained by in-place operations. Depends on stack depth
#include "npy_pycompat.h"
#include "usertypes.h"
+#include "dtypemeta.h"
+#include "scalartypes.h"
+#include "array_method.h"
+#include "convert_datatype.h"
+#include "legacy_dtype_implementation.h"
+
NPY_NO_EXPORT PyArray_Descr **userdescrs=NULL;
}
}
typenum = NPY_USERDEF + NPY_NUMUSERTYPES;
- descr->type_num = typenum;
+ descr->type_num = -1;
if (PyDataType_ISUNSIZED(descr)) {
PyErr_SetString(PyExc_ValueError, "cannot register a" \
"flexible data-type");
PyErr_SetString(PyExc_ValueError, "missing typeobject");
return -1;
}
+ if (descr->flags & (NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT)) {
+ /*
+ * User dtype can't actually do reference counting, however, there
+ * are existing hacks (e.g. xpress), which use a structured one:
+ * dtype((xpress.var, [('variable', 'O')]))
+ * so we have to support this. But such a structure must be constant
+ * (i.e. fixed at registration time, this is the case for `xpress`).
+ */
+ if (descr->names == NULL || descr->fields == NULL ||
+ !PyDict_CheckExact(descr->fields)) {
+ PyErr_Format(PyExc_ValueError,
+ "Failed to register dtype for %S: Legacy user dtypes "
+ "using `NPY_ITEM_IS_POINTER` or `NPY_ITEM_REFCOUNT` are"
+ "unsupported. It is possible to create such a dtype only "
+ "if it is a structured dtype with names and fields "
+ "hardcoded at registration time.\n"
+ "Please contact the NumPy developers if this used to work "
+ "but now fails.", descr->typeobj);
+ return -1;
+ }
+ }
if (test_deprecated_arrfuncs_members(f) < 0) {
return -1;
PyErr_SetString(PyExc_MemoryError, "RegisterDataType");
return -1;
}
+
userdescrs[NPY_NUMUSERTYPES++] = descr;
+
+ descr->type_num = typenum;
+ if (dtypemeta_wrap_legacy_descriptor(descr) < 0) {
+ descr->type_num = -1;
+ NPY_NUMUSERTYPES--;
+ return -1;
+ }
+
return typenum;
}
return -1;
}
}
- key = PyInt_FromLong(totype);
+ key = PyLong_FromLong(totype);
if (PyErr_Occurred()) {
return -1;
}
- cobj = NpyCapsule_FromVoidPtr((void *)castfunc, NULL);
+ cobj = PyCapsule_New((void *)castfunc, NULL, NULL);
if (cobj == NULL) {
Py_DECREF(key);
return -1;
if (!PyTypeNum_ISUSERDEF(descr->type_num) &&
!PyTypeNum_ISUSERDEF(totype)) {
PyErr_SetString(PyExc_ValueError,
- "At least one of the types provided to"
+ "At least one of the types provided to "
"RegisterCanCast must be user-defined.");
return -1;
}
return _append_new(&descr->f->cancastscalarkindto[scalar], totype);
}
}
+
+
+/*
+ * Legacy user DTypes implemented the common DType operation
+ * (as used in type promotion/result_type, and e.g. the type for
+ * concatenation), by using "safe cast" logic.
+ *
+ * New DTypes do have this behaviour generally, but we use can-cast
+ * when legacy user dtypes are involved.
+ */
+NPY_NO_EXPORT PyArray_DTypeMeta *
+legacy_userdtype_common_dtype_function(
+ PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other)
+{
+ int skind1 = NPY_NOSCALAR, skind2 = NPY_NOSCALAR, skind;
+
+ if (!other->legacy) {
+ /* legacy DTypes can always defer to new style ones */
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_DTypeMeta *)Py_NotImplemented;
+ }
+ /* Defer so that only one of the types handles the cast */
+ if (cls->type_num < other->type_num) {
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_DTypeMeta *)Py_NotImplemented;
+ }
+
+ /* Check whether casting is possible from one type to the other */
+ if (PyArray_CanCastSafely(cls->type_num, other->type_num)) {
+ Py_INCREF(other);
+ return other;
+ }
+ if (PyArray_CanCastSafely(other->type_num, cls->type_num)) {
+ Py_INCREF(cls);
+ return cls;
+ }
+
+ /*
+ * The following code used to be part of PyArray_PromoteTypes().
+ * We can expect that this code is never used.
+ * In principle, it allows for promotion of two different user dtypes
+ * to a single NumPy dtype of the same "kind". In practice
+ * using the same `kind` as NumPy was never possible due to an
+ * simplification where `PyArray_EquivTypes(descr1, descr2)` will
+ * return True if both kind and element size match (e.g. bfloat16 and
+ * float16 would be equivalent).
+ * The option is also very obscure and not used in the examples.
+ */
+
+ /* Convert the 'kind' char into a scalar kind */
+ switch (cls->kind) {
+ case 'b':
+ skind1 = NPY_BOOL_SCALAR;
+ break;
+ case 'u':
+ skind1 = NPY_INTPOS_SCALAR;
+ break;
+ case 'i':
+ skind1 = NPY_INTNEG_SCALAR;
+ break;
+ case 'f':
+ skind1 = NPY_FLOAT_SCALAR;
+ break;
+ case 'c':
+ skind1 = NPY_COMPLEX_SCALAR;
+ break;
+ }
+ switch (other->kind) {
+ case 'b':
+ skind2 = NPY_BOOL_SCALAR;
+ break;
+ case 'u':
+ skind2 = NPY_INTPOS_SCALAR;
+ break;
+ case 'i':
+ skind2 = NPY_INTNEG_SCALAR;
+ break;
+ case 'f':
+ skind2 = NPY_FLOAT_SCALAR;
+ break;
+ case 'c':
+ skind2 = NPY_COMPLEX_SCALAR;
+ break;
+ }
+
+ /* If both are scalars, there may be a promotion possible */
+ if (skind1 != NPY_NOSCALAR && skind2 != NPY_NOSCALAR) {
+
+ /* Start with the larger scalar kind */
+ skind = (skind1 > skind2) ? skind1 : skind2;
+ int ret_type_num = _npy_smallest_type_of_kind_table[skind];
+
+ for (;;) {
+
+ /* If there is no larger type of this kind, try a larger kind */
+ if (ret_type_num < 0) {
+ ++skind;
+ /* Use -1 to signal no promoted type found */
+ if (skind < NPY_NSCALARKINDS) {
+ ret_type_num = _npy_smallest_type_of_kind_table[skind];
+ }
+ else {
+ break;
+ }
+ }
+
+ /* If we found a type to which we can promote both, done! */
+ if (PyArray_CanCastSafely(cls->type_num, ret_type_num) &&
+ PyArray_CanCastSafely(other->type_num, ret_type_num)) {
+ return PyArray_DTypeFromTypeNum(ret_type_num);
+ }
+
+ /* Try the next larger type of this kind */
+ ret_type_num = _npy_next_larger_type_table[ret_type_num];
+ }
+ }
+
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_DTypeMeta *)Py_NotImplemented;
+}
+
+
+/**
+ * This function wraps a legacy cast into an array-method. This is mostly
+ * used for legacy user-dtypes, but for example numeric to/from datetime
+ * casts were only defined that way as well.
+ *
+ * @param from
+ * @param to
+ * @param casting If `NPY_NO_CASTING` will check the legacy registered cast,
+ * otherwise uses the provided cast.
+ */
+NPY_NO_EXPORT int
+PyArray_AddLegacyWrapping_CastingImpl(
+ PyArray_DTypeMeta *from, PyArray_DTypeMeta *to, NPY_CASTING casting)
+{
+ if (casting < 0) {
+ if (from == to) {
+ casting = NPY_NO_CASTING;
+ }
+ else if (PyArray_LegacyCanCastTypeTo(
+ from->singleton, to->singleton, NPY_SAFE_CASTING)) {
+ casting = NPY_SAFE_CASTING;
+ }
+ else if (PyArray_LegacyCanCastTypeTo(
+ from->singleton, to->singleton, NPY_SAME_KIND_CASTING)) {
+ casting = NPY_SAME_KIND_CASTING;
+ }
+ else {
+ casting = NPY_UNSAFE_CASTING;
+ }
+ }
+
+ PyArray_DTypeMeta *dtypes[2] = {from, to};
+ PyArrayMethod_Spec spec = {
+ /* Name is not actually used, but allows identifying these. */
+ .name = "legacy_cast",
+ .nin = 1,
+ .nout = 1,
+ .casting = casting,
+ .dtypes = dtypes,
+ };
+
+ if (from == to) {
+ spec.flags = NPY_METH_REQUIRES_PYAPI | NPY_METH_SUPPORTS_UNALIGNED;
+ PyType_Slot slots[] = {
+ {NPY_METH_get_loop, NULL},
+ {NPY_METH_resolve_descriptors, &legacy_same_dtype_resolve_descriptors},
+ {0, NULL}};
+ spec.slots = slots;
+ return PyArray_AddCastingImplementation_FromSpec(&spec, 1);
+ }
+ else {
+ spec.flags = NPY_METH_REQUIRES_PYAPI;
+ PyType_Slot slots[] = {
+ {NPY_METH_get_loop, NULL},
+ {NPY_METH_resolve_descriptors, &simple_cast_resolve_descriptors},
+ {0, NULL}};
+ spec.slots = slots;
+ return PyArray_AddCastingImplementation_FromSpec(&spec, 1);
+ }
+}
#ifndef _NPY_PRIVATE_USERTYPES_H_
#define _NPY_PRIVATE_USERTYPES_H_
+#include "array_method.h"
+
extern NPY_NO_EXPORT PyArray_Descr **userdescrs;
NPY_NO_EXPORT void
PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype,
PyArray_VectorUnaryFunc *castfunc);
+NPY_NO_EXPORT PyArray_DTypeMeta *
+legacy_userdtype_common_dtype_function(
+ PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other);
+
+NPY_NO_EXPORT int
+PyArray_AddLegacyWrapping_CastingImpl(
+ PyArray_DTypeMeta *from, PyArray_DTypeMeta *to, NPY_CASTING casting);
+
#endif
/**end repeat1**/
/**begin repeat1
- * #kind = atan2,hypot,pow,fmod,copysign#
- * #KIND = ATAN2,HYPOT,POW,FMOD,COPYSIGN#
+ * #kind = atan2,hypot,pow,copysign#
+ * #KIND = ATAN2,HYPOT,POW,COPYSIGN#
*/
#ifdef @kind@@c@
#undef @kind@@c@
#endif
/**end repeat1**/
+/**begin repeat1
+ * #kind = fmod#
+ * #KIND = FMOD#
+ */
+#ifdef @kind@@c@
+#undef @kind@@c@
+#endif
+#ifndef HAVE_MODF@C@
+NPY_INPLACE @type@
+npy_@kind@@c@(@type@ x, @type@ y)
+{
+ int are_inputs_inf = (npy_isinf(x) && npy_isinf(y));
+ /* force set invalid flag, doesnt raise by default on gcc < 8 */
+ if (npy_isnan(x) || npy_isnan(y)) {
+ npy_set_floatstatus_invalid();
+ }
+ if (are_inputs_inf || !y) {
+ if (!npy_isnan(x)) {
+ npy_set_floatstatus_invalid();
+ }
+ }
+ return (@type@) npy_@kind@((double)x, (double) y);
+}
+#endif
+/**end repeat1**/
+
#ifdef modf@c@
#undef modf@c@
#endif
/**end repeat1**/
/**begin repeat1
- * #kind = atan2,hypot,pow,fmod,copysign#
- * #KIND = ATAN2,HYPOT,POW,FMOD,COPYSIGN#
+ * #kind = atan2,hypot,pow,copysign#
+ * #KIND = ATAN2,HYPOT,POW,COPYSIGN#
*/
#ifdef HAVE_@KIND@@C@
NPY_INPLACE @type@ npy_@kind@@c@(@type@ x, @type@ y)
#endif
/**end repeat1**/
+/**begin repeat1
+ * #kind = fmod#
+ * #KIND = FMOD#
+ */
+#ifdef HAVE_FMOD@C@
+NPY_INPLACE @type@
+npy_@kind@@c@(@type@ x, @type@ y)
+{
+ int are_inputs_inf = (npy_isinf(x) && npy_isinf(y));
+ /* force set invalid flag, doesnt raise by default on gcc < 8 */
+ if (npy_isnan(x) || npy_isnan(y)) {
+ npy_set_floatstatus_invalid();
+ }
+ if (are_inputs_inf || !y) {
+ if (!npy_isnan(x)) {
+ npy_set_floatstatus_invalid();
+ }
+ }
+ return @kind@@c@(x, y);
+}
+#endif
+/**end repeat1**/
+
#ifdef HAVE_MODF@C@
NPY_INPLACE @type@ npy_modf@c@(@type@ x, @type@ *iptr)
{
}
}
+/*
+ * Wrapper function for remainder edge cases
+ * Internally calls npy_divmod*
+ */
+NPY_INPLACE @type@
+npy_remainder@c@(@type@ a, @type@ b)
+{
+ @type@ mod;
+ if (NPY_UNLIKELY(!b)) {
+ mod = npy_fmod@c@(a, b);
+ } else {
+ npy_divmod@c@(a, b, &mod);
+ }
+ return mod;
+}
+
+NPY_INPLACE @type@
+npy_floor_divide@c@(@type@ a, @type@ b) {
+ @type@ div, mod;
+ if (NPY_UNLIKELY(!b)) {
+ div = a / b;
+ if (!a || npy_isnan(a)) {
+ npy_set_floatstatus_invalid();
+ } else {
+ npy_set_floatstatus_divbyzero();
+ }
+ } else {
+ div = npy_divmod@c@(a, b, &mod);
+ }
+ return div;
+}
+
/*
* Python version of divmod.
*
{
@type@ div, mod, floordiv;
+ /* force set invalid flag, doesnt raise by default on gcc < 8 */
+ if (npy_isnan(a) || npy_isnan(b)) {
+ npy_set_floatstatus_invalid();
+ }
mod = npy_fmod@c@(a, b);
-
- if (!b) {
+ if (NPY_UNLIKELY(!b)) {
+ div = a / b;
+ if (a && !npy_isnan(a)) {
+ npy_set_floatstatus_divbyzero();
+ }
/* If b == 0, return result of fmod. For IEEE is nan */
*modulus = mod;
- return mod;
+ return div;
}
/* a - mod should be very nearly an integer multiple of b */
#include "npy_fpmath.h"
#include "numpy/npy_math.h"
-#include "numpy/npy_cpu.h"
#include "numpy/npy_endian.h"
#include "numpy/npy_common.h"
* #CMP = LT, LTE#
*/
-NPY_VISIBILITY_HIDDEN void
+NPY_NO_EXPORT void
binsearch_@side@_@suff@(const char *arr, const char *key, char *ret,
npy_intp arr_len, npy_intp key_len,
npy_intp arr_str, npy_intp key_str, npy_intp ret_str,
}
}
-NPY_VISIBILITY_HIDDEN int
+NPY_NO_EXPORT int
argbinsearch_@side@_@suff@(const char *arr, const char *key,
const char *sort, char *ret,
npy_intp arr_len, npy_intp key_len,
* #CMP = <, <=#
*/
-NPY_VISIBILITY_HIDDEN void
+NPY_NO_EXPORT void
npy_binsearch_@side@(const char *arr, const char *key, char *ret,
npy_intp arr_len, npy_intp key_len,
npy_intp arr_str, npy_intp key_str, npy_intp ret_str,
}
}
-NPY_VISIBILITY_HIDDEN int
+NPY_NO_EXPORT int
npy_argbinsearch_@side@(const char *arr, const char *key,
const char *sort, char *ret,
npy_intp arr_len, npy_intp key_len,
* npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta#
*/
-int
+NPY_NO_EXPORT int
heapsort_@suff@(void *start, npy_intp n, void *NOT_USED)
{
@type@ tmp, *a;
}
-int
+NPY_NO_EXPORT int
aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *NOT_USED)
{
@type@ *v = vv;
* #type = npy_char, npy_ucs4#
*/
-int
+NPY_NO_EXPORT int
heapsort_@suff@(void *start, npy_intp n, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *varr)
{
@type@ *v = vv;
*/
-int
+NPY_NO_EXPORT int
npy_heapsort(void *start, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
npy_aheapsort(void *vv, npy_intp *tosort, npy_intp n, void *varr)
{
char *v = vv;
}
-int
+NPY_NO_EXPORT int
mergesort_@suff@(void *start, npy_intp num, void *NOT_USED)
{
@type@ *pl, *pr, *pw;
}
-int
+NPY_NO_EXPORT int
amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *NOT_USED)
{
npy_intp *pl, *pr, *pw;
}
-int
+NPY_NO_EXPORT int
mergesort_@suff@(void *start, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
npy_mergesort(void *start, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
npy_amergesort(void *v, npy_intp *tosort, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
* npy_cdouble, npy_clongdouble, npy_datetime, npy_timedelta#
*/
-int
+NPY_NO_EXPORT int
quicksort_@suff@(void *start, npy_intp num, void *NOT_USED)
{
@type@ vp;
}
-int
+NPY_NO_EXPORT int
aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
@type@ *v = vv;
* #type = npy_char, npy_ucs4#
*/
-int
+NPY_NO_EXPORT int
quicksort_@suff@(void *start, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *varr)
{
@type@ *v = vv;
*/
-int
+NPY_NO_EXPORT int
npy_quicksort(void *start, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
npy_aquicksort(void *vv, npy_intp* tosort, npy_intp num, void *varr)
{
char *v = vv;
return (key >> (l << 3)) & 0xFF;
}
-@type@*
+static @type@*
radixsort0_@suff@(@type@ *arr, @type@ *aux, npy_intp num)
{
npy_intp cnt[sizeof(@type@)][1 << 8] = { { 0 } };
return arr;
}
-int
+NPY_NO_EXPORT int
radixsort_@suff@(void *start, npy_intp num, void *NPY_UNUSED(varr))
{
void *sorted;
return 0;
}
-npy_intp*
+static npy_intp*
aradixsort0_@suff@(@type@ *arr, npy_intp *aux, npy_intp *tosort, npy_intp num)
{
npy_intp cnt[sizeof(@type@)][1 << 8] = { { 0 } };
return tosort;
}
-int
+NPY_NO_EXPORT int
aradixsort_@suff@(void *start, npy_intp* tosort, npy_intp num, void *NPY_UNUSED(varr))
{
npy_intp *sorted;
* kth 8: 0 1 2 3 4 5 6 [8 7] -> stack []
*
*/
-int
+NPY_NO_EXPORT int
@name@introselect_@suff@(@type@ *v,
#if @arg@
npy_intp* tosort,
store_pivot(kth, kth, pivots, npiv);
return 0;
}
- else if (@inexact@ && kth == num - 1) {
+ // Parenthesis around @inexact@ tells clang dead code as intentional
+ else if ((@inexact@) && kth == num - 1) {
/* useful to check if NaN present via partition(d, (x, -1)) */
npy_intp k;
npy_intp maxidx = low;
-npy_intp compute_min_run(npy_intp num)
+static npy_intp compute_min_run(npy_intp num)
{
npy_intp r = 0;
}
-int
+NPY_NO_EXPORT int
timsort_@suff@(void *start, npy_intp num, void *NPY_UNUSED(varr))
{
int ret;
}
-int
+NPY_NO_EXPORT int
atimsort_@suff@(void *v, npy_intp *tosort, npy_intp num,
void *NPY_UNUSED(varr))
{
* run length to reduce the cost of insertion sort.
*/
-npy_intp compute_min_run_short(npy_intp num)
+static npy_intp compute_min_run_short(npy_intp num)
{
npy_intp r = 0;
}
-int
+NPY_NO_EXPORT int
timsort_@suff@(void *start, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
atimsort_@suff@(void *start, npy_intp *tosort, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
npy_timsort(void *start, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
}
-int
+NPY_NO_EXPORT int
npy_atimsort(void *start, npy_intp *tosort, npy_intp num, void *varr)
{
PyArrayObject *arr = varr;
Py_INCREF(x[0]);
return x[0];
}
- else if (PyString_Check(x[0])) {
- const char* s = PyString_AS_STRING(x[0]);
+ // TODO: allow construction from unicode strings
+ else if (PyBytes_Check(x[0])) {
+ const char* s = PyBytes_AS_STRING(x[0]);
rational x;
if (scan_rational(&s,&x)) {
const char* p;
PyObject* y;
int eq;
x[i] = PyTuple_GET_ITEM(args, i);
- n[i] = PyInt_AsLong(x[i]);
+ n[i] = PyLong_AsLong(x[i]);
if (error_converting(n[i])) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
PyErr_Format(PyExc_TypeError,
return 0;
}
/* Check that we had an exact integer */
- y = PyInt_FromLong(n[i]);
+ y = PyLong_FromLong(n[i]);
if (!y) {
return 0;
}
else { \
PyObject* y_; \
int eq_; \
- long n_ = PyInt_AsLong(object); \
+ long n_ = PyLong_AsLong(object); \
if (error_converting(n_)) { \
if (PyErr_ExceptionMatches(PyExc_TypeError)) { \
PyErr_Clear(); \
} \
return 0; \
} \
- y_ = PyInt_FromLong(n_); \
+ y_ = PyLong_FromLong(n_); \
if (!y_) { \
return 0; \
} \
pyrational_repr(PyObject* self) {
rational x = ((PyRational*)self)->r;
if (d(x)!=1) {
- return PyUString_FromFormat(
+ return PyUnicode_FromFormat(
"rational(%ld,%ld)",(long)x.n,(long)d(x));
}
else {
- return PyUString_FromFormat(
+ return PyUnicode_FromFormat(
"rational(%ld)",(long)x.n);
}
}
pyrational_str(PyObject* self) {
rational x = ((PyRational*)self)->r;
if (d(x)!=1) {
- return PyUString_FromFormat(
+ return PyUnicode_FromFormat(
"%ld/%ld",(long)x.n,(long)d(x));
}
else {
- return PyUString_FromFormat(
+ return PyUnicode_FromFormat(
"%ld",(long)x.n);
}
}
}
RATIONAL_UNOP(negative,rational,rational_negative(x),PyRational_FromRational)
RATIONAL_UNOP(absolute,rational,rational_abs(x),PyRational_FromRational)
-RATIONAL_UNOP(int,long,rational_int(x),PyInt_FromLong)
+RATIONAL_UNOP(int,long,rational_int(x),PyLong_FromLong)
RATIONAL_UNOP(float,double,rational_double(x),PyFloat_FromDouble)
static PyObject*
static PyObject*
pyrational_n(PyObject* self, void* closure) {
- return PyInt_FromLong(((PyRational*)self)->r.n);
+ return PyLong_FromLong(((PyRational*)self)->r.n);
}
static PyObject*
pyrational_d(PyObject* self, void* closure) {
- return PyInt_FromLong(d(((PyRational*)self)->r));
+ return PyLong_FromLong(d(((PyRational*)self)->r));
}
static PyGetSetDef pyrational_getset[] = {
static PyTypeObject PyRational_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "rational", /* tp_name */
+ "numpy.core._rational_tests.rational", /* tp_name */
sizeof(PyRational), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
r = ((PyRational*)item)->r;
}
else {
- long n = PyInt_AsLong(item);
+ long long n = PyLong_AsLongLong(item);
PyObject* y;
int eq;
if (error_converting(n)) {
return -1;
}
- y = PyInt_FromLong(n);
+ y = PyLong_FromLongLong(n);
if (!y) {
return -1;
}
- eq = PyObject_RichCompareBool(item,y,Py_EQ);
+ eq = PyObject_RichCompareBool(item, y, Py_EQ);
Py_DECREF(y);
if (eq<0) {
return -1;
}
r = make_rational_int(n);
}
- memcpy(data,&r,sizeof(rational));
+ memcpy(data, &r, sizeof(rational));
return 0;
}
if (PyErr_Occurred()) {
goto fail;
}
- numpy_str = PyUString_FromString("numpy");
+ numpy_str = PyUnicode_FromString("numpy");
if (!numpy_str) {
goto fail;
}
PyDict_SetItemString(dictionary, "cross1d", f);
Py_DECREF(f);
+ f = PyUFunc_FromFuncAndDataAndSignature(NULL, NULL,
+ NULL, 0, 0, 0, PyUFunc_None, "_pickleable_module_global.ufunc",
+ "A dotted name for pickle testing, does nothing.", 0, NULL);
+ if (f == NULL) {
+ return -1;
+ }
+ PyDict_SetItemString(dictionary, "_pickleable_module_global_ufunc", f);
+ Py_DECREF(f);
+
return 0;
}
return NULL;
}
- if (PyString_Check(signature)) {
+ if (PyBytes_Check(signature)) {
sig_str = signature;
} else if (PyUnicode_Check(signature)) {
sig_str = PyUnicode_AsUTF8String(signature);
NULL, NULL, NULL,
0, nin, nout, PyUFunc_None, "no name",
"doc:none",
- 1, PyString_AS_STRING(sig_str));
+ 1, PyBytes_AS_STRING(sig_str));
if (sig_str != signature) {
Py_DECREF(sig_str);
}
return NULL;
}
+// Testing the utilites of the CPU dispatcher
+#ifndef NPY_DISABLE_OPTIMIZATION
+ #include "_umath_tests.dispatch.h"
+#endif
+NPY_CPU_DISPATCH_DECLARE(extern const char *_umath_tests_dispatch_var)
+NPY_CPU_DISPATCH_DECLARE(const char *_umath_tests_dispatch_func, (void))
+NPY_CPU_DISPATCH_DECLARE(void _umath_tests_dispatch_attach, (PyObject *list))
+
+static PyObject *
+UMath_Tests_test_dispatch(PyObject *NPY_UNUSED(dummy), PyObject *NPY_UNUSED(dummy2))
+{
+ const char *highest_func, *highest_var;
+ NPY_CPU_DISPATCH_CALL(highest_func = _umath_tests_dispatch_func, ());
+ NPY_CPU_DISPATCH_CALL(highest_var = _umath_tests_dispatch_var);
+ const char *highest_func_xb = "nobase", *highest_var_xb = "nobase";
+ NPY_CPU_DISPATCH_CALL_XB(highest_func_xb = _umath_tests_dispatch_func, ());
+ NPY_CPU_DISPATCH_CALL_XB(highest_var_xb = _umath_tests_dispatch_var);
+
+ PyObject *dict = PyDict_New(), *item;
+ if (dict == NULL) {
+ return NULL;
+ }
+ /**begin repeat
+ * #str = func, var, func_xb, var_xb#
+ */
+ item = PyUnicode_FromString(highest_@str@);
+ if (item == NULL || PyDict_SetItemString(dict, "@str@", item) < 0) {
+ goto err;
+ }
+ /**end repeat**/
+ item = PyList_New(0);
+ if (item == NULL || PyDict_SetItemString(dict, "all", item) < 0) {
+ goto err;
+ }
+ NPY_CPU_DISPATCH_CALL_ALL(_umath_tests_dispatch_attach, (item));
+ if (PyErr_Occurred()) {
+ goto err;
+ }
+ return dict;
+err:
+ Py_XDECREF(item);
+ Py_DECREF(dict);
+ return NULL;
+}
+
static PyMethodDef UMath_TestsMethods[] = {
{"test_signature", UMath_Tests_test_signature, METH_VARARGS,
"Test signature parsing of ufunc. \n"
"If fails, it returns NULL. Otherwise it returns a tuple of ufunc "
"internals. \n",
},
+ {"test_dispatch", UMath_Tests_test_dispatch, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyObject *d;
PyObject *version;
+ // Initialize CPU features
+ if (npy_cpu_init() < 0) {
+ return NULL;
+ }
+
m = PyModule_Create(&moduledef);
if (m == NULL) {
return NULL;
d = PyModule_GetDict(m);
- version = PyString_FromString("0.1");
+ version = PyUnicode_FromString("0.1");
PyDict_SetItemString(d, "__version__", version);
Py_DECREF(version);
"cannot load _umath_tests module.");
return NULL;
}
-
return m;
}
--- /dev/null
+/**
+ * Testing the utilites of the CPU dispatcher
+ *
+ * @targets $werror baseline
+ * SSE2 SSE41 AVX2
+ * VSX VSX2 VSX3
+ * NEON ASIMD ASIMDHP
+ */
+#include <Python.h>
+#include "npy_cpu_dispatch.h"
+
+#ifndef NPY_DISABLE_OPTIMIZATION
+ #include "_umath_tests.dispatch.h"
+#endif
+
+NPY_CPU_DISPATCH_DECLARE(const char *_umath_tests_dispatch_func, (void))
+NPY_CPU_DISPATCH_DECLARE(extern const char *_umath_tests_dispatch_var)
+NPY_CPU_DISPATCH_DECLARE(void _umath_tests_dispatch_attach, (PyObject *list))
+
+const char *NPY_CPU_DISPATCH_CURFX(_umath_tests_dispatch_var) = NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(var));
+const char *NPY_CPU_DISPATCH_CURFX(_umath_tests_dispatch_func)(void)
+{
+ static const char *current = NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(func));
+ return current;
+}
+
+void NPY_CPU_DISPATCH_CURFX(_umath_tests_dispatch_attach)(PyObject *list)
+{
+ PyObject *item = PyUnicode_FromString(NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(func)));
+ if (item) {
+ PyList_Append(list, item);
+ }
+}
errtype, name);
goto fail;
}
- args = Py_BuildValue("NN", PyUString_FromString(errtype),
- PyInt_FromLong((long) retstatus));
+ args = Py_BuildValue("NN", PyUnicode_FromString(errtype),
+ PyLong_FromLong((long) retstatus));
if (args == NULL) {
goto fail;
}
}
if (bufsize != NULL) {
- *bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0));
+ *bufsize = PyLong_AsLong(PyList_GET_ITEM(ref, 0));
if (error_converting(*bufsize)) {
return -1;
}
}
if (errmask != NULL) {
- *errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1));
+ *errmask = PyLong_AsLong(PyList_GET_ITEM(ref, 1));
if (*errmask < 0) {
if (PyErr_Occurred()) {
return -1;
static PyObject *
Py_get_one(PyObject *NPY_UNUSED(o))
{
- return PyInt_FromLong(1);
+ return PyLong_FromLong(1);
}
static PyObject *
Py_reciprocal(PyObject *o)
{
- PyObject *one = PyInt_FromLong(1);
+ PyObject *one = PyLong_FromLong(1);
PyObject *result;
if (!one) {
*****************************************************************************
*/
-/**begin repeat
- * Float types
- * #type = npy_float, npy_double#
- * #TYPE = FLOAT, DOUBLE#
- * #scalarf = npy_sqrtf, npy_sqrt#
- */
-
-NPY_NO_EXPORT void
-@TYPE@_sqrt(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
-{
- if (!run_unary_simd_sqrt_@TYPE@(args, dimensions, steps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *(@type@ *)op1 = @scalarf@(in1);
- }
- }
-}
-
-/**end repeat**/
-
/**begin repeat
* #func = rint, ceil, floor, trunc#
* #scalarf = npy_rint, npy_ceil, npy_floor, npy_trunc#
*(npy_double *)op1 = npy_exp(in1);
}
}
+NPY_NO_EXPORT NPY_GCC_OPT_3 void
+DOUBLE_log(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
+{
+ UNARY_LOOP {
+ const npy_double in1 = *(npy_double *)ip1;
+ *(npy_double *)op1 = npy_log(in1);
+ }
+}
/**begin repeat
* #isa = avx512f, fma#
* #typesub = f, #
*/
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_sqrt_@isa@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- if (!run_unary_@isa@_sqrt_@TYPE@(args, dimensions, steps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *(@type@ *)op1 = npy_sqrt@typesub@(in1);
- }
- }
-}
-
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_absolute_@isa@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- if (!run_unary_@isa@_absolute_@TYPE@(args, dimensions, steps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- const @type@ tmp = in1 > 0 ? in1 : -in1;
- /* add 0 to clear -0.0 */
- *((@type@ *)op1) = tmp + 0;
- }
- }
- npy_clear_floatstatus_barrier((char*)dimensions);
-}
-
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_square_@isa@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- if (!run_unary_@isa@_square_@TYPE@(args, dimensions, steps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *(@type@ *)op1 = in1*in1;
- }
- }
-}
-
-NPY_NO_EXPORT NPY_GCC_OPT_3 void
-@TYPE@_reciprocal_@isa@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- if (!run_unary_@isa@_reciprocal_@TYPE@(args, dimensions, steps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *(@type@ *)op1 = 1.0f/in1;
- }
- }
-}
-
/**begin repeat2
* #func = rint, ceil, floor, trunc#
* #scalarf = npy_rint, npy_ceil, npy_floor, npy_trunc#
}
}
+NPY_NO_EXPORT NPY_GCC_OPT_3 void
+DOUBLE_log_avx512f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
+{
+ if (!run_unary_avx512f_log_DOUBLE(args, dimensions, steps)) {
+ UNARY_LOOP {
+ const npy_double in1 = *(npy_double *)ip1;
+ *(npy_double *)op1 = npy_log(in1);
+ }
+ }
+}
/**begin repeat
* Float types
* #kind = isnan, isinf, isfinite, signbit#
* #func = npy_isnan, npy_isinf, npy_isfinite, npy_signbit#
**/
+
+/**begin repeat2
+ * #ISA = , _avx512_skx#
+ * #isa = simd, avx512_skx#
+ **/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@@ISA@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
{
- if (!run_@kind@_simd_@TYPE@(args, dimensions, steps)) {
+ if (!run_@kind@_@isa@_@TYPE@(args, dimensions, steps)) {
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
*((npy_bool *)op1) = @func@(in1) != 0;
}
npy_clear_floatstatus_barrier((char*)dimensions);
}
+/**end repeat2**/
/**end repeat1**/
NPY_NO_EXPORT void
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
const @type@ in2 = *(@type@ *)ip2;
- @type@ mod;
- *((@type@ *)op1) = npy_divmod@c@(in1, in2, &mod);
+ *((@type@ *)op1) = npy_floor_divide@c@(in1, in2);
}
}
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
const @type@ in2 = *(@type@ *)ip2;
- npy_divmod@c@(in1, in2, (@type@ *)op1);
+ *((@type@ *) op1) = npy_remainder@c@(in1, in2);
}
}
}
}
-NPY_NO_EXPORT void
-@TYPE@_square(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- char * margs[] = {args[0], args[0], args[1]};
- npy_intp msteps[] = {steps[0], steps[0], steps[1]};
- if (!run_binary_simd_multiply_@TYPE@(margs, dimensions, msteps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *((@type@ *)op1) = in1*in1;
- }
- }
-}
-
-NPY_NO_EXPORT void
-@TYPE@_reciprocal(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
-{
- @type@ one = 1.@c@;
- char * margs[] = {(char*)&one, args[0], args[1]};
- npy_intp msteps[] = {0, steps[0], steps[1]};
- if (!run_binary_simd_divide_@TYPE@(margs, dimensions, msteps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- *((@type@ *)op1) = 1/in1;
- }
- }
-}
-
NPY_NO_EXPORT void
@TYPE@__ones_like(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
{
}
}
-NPY_NO_EXPORT void
-@TYPE@_absolute(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
-{
- if (!run_unary_simd_absolute_@TYPE@(args, dimensions, steps)) {
- UNARY_LOOP {
- const @type@ in1 = *(@type@ *)ip1;
- const @type@ tmp = in1 > 0 ? in1 : -in1;
- /* add 0 to clear -0.0 */
- *((@type@ *)op1) = tmp + 0;
- }
- }
- npy_clear_floatstatus_barrier((char*)dimensions);
-}
-
NPY_NO_EXPORT void
@TYPE@_negative(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
{
}
}
+NPY_NO_EXPORT void
+@TYPE@_frexp_avx512_skx(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
+{
+ if (!run_unary_two_out_avx512_skx_frexp_@TYPE@(args, dimensions, steps)) {
+ @TYPE@_frexp(args, dimensions, steps, func);
+ }
+}
+
NPY_NO_EXPORT void
@TYPE@_ldexp(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
{
}
}
+NPY_NO_EXPORT void
+@TYPE@_ldexp_avx512_skx(char **args, const npy_intp *dimensions, const npy_intp *steps, void *func)
+{
+ if (!run_binary_avx512_skx_ldexp_@TYPE@(args, dimensions, steps)) {
+ @TYPE@_ldexp(args, dimensions, steps, func);
+ }
+}
+
NPY_NO_EXPORT void
@TYPE@_ldexp_long(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
{
/**end repeat**/
+/*
+ *****************************************************************************
+ ** LONGDOUBLE LOOPS **
+ *****************************************************************************
+ */
+
+NPY_NO_EXPORT void
+LONGDOUBLE_reciprocal(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
+{
+ UNARY_LOOP {
+ const npy_longdouble in1 = *(npy_longdouble*)ip1;
+ *((npy_longdouble *)op1) = 1/in1;
+ }
+}
+
+NPY_NO_EXPORT void
+LONGDOUBLE_absolute(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
+{
+ UNARY_LOOP {
+ const npy_longdouble in1 = *(npy_longdouble *)ip1;
+ const npy_longdouble tmp = in1 > 0 ? in1 : -in1;
+ /* add 0 to clear -0.0 */
+ *((npy_longdouble *)op1) = tmp + 0;
+ }
+ npy_clear_floatstatus_barrier((char*)dimensions);
+}
+
+NPY_NO_EXPORT void
+LONGDOUBLE_square(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
+{
+ UNARY_LOOP {
+ const npy_longdouble in1 = *(npy_longdouble *)ip1;
+ *((npy_longdouble *)op1) = in1*in1;
+ }
+}
+
/*
*****************************************************************************
** HALF-FLOAT LOOPS **
BINARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
const npy_half in2 = *(npy_half *)ip2;
- npy_half mod;
- *((npy_half *)op1) = npy_half_divmod(in1, in2, &mod);
+
+ float fh1 = npy_half_to_float(in1);
+ float fh2 = npy_half_to_float(in2);
+ float div;
+
+ div = npy_floor_dividef(fh1, fh2);
+ *((npy_half *)op1) = npy_float_to_half(div);
}
}
BINARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
const npy_half in2 = *(npy_half *)ip2;
- npy_half_divmod(in1, in2, (npy_half *)op1);
+ float fh1 = npy_half_to_float(in1);
+ float fh2 = npy_half_to_float(in2);
+ float mod;
+ mod = npy_remainderf(fh1, fh2);
+ *((npy_half *)op1) = npy_float_to_half(mod);
}
}
NPY_NO_EXPORT void
@TYPE@_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
{
- if (IS_BINARY_REDUCE && @PW@) {
+ // Parenthesis around @PW@ tells clang dead code is intentional
+ if (IS_BINARY_REDUCE && (@PW@)) {
npy_intp n = dimensions[0];
@ftype@ * or = ((@ftype@ *)args[0]);
@ftype@ * oi = ((@ftype@ *)args[0]) + 1;
#ifndef _NPY_UMATH_LOOPS_H_
#define _NPY_UMATH_LOOPS_H_
+#ifndef NPY_NO_EXPORT
+ #define NPY_NO_EXPORT NPY_VISIBILITY_HIDDEN
+#endif
+
#define BOOL_invert BOOL_logical_not
#define BOOL_add BOOL_logical_or
#define BOOL_bitwise_and BOOL_logical_and
** FLOAT LOOPS **
*****************************************************************************
*/
-
+#ifndef NPY_DISABLE_OPTIMIZATION
+ #include "loops_unary_fp.dispatch.h"
+#endif
/**begin repeat
* #TYPE = FLOAT, DOUBLE#
*/
-NPY_NO_EXPORT void
-@TYPE@_sqrt(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
-
/**begin repeat1
- * #func = maximum, minimum#
+ * #kind = sqrt, absolute, square, reciprocal#
*/
-NPY_NO_EXPORT void
-@TYPE@_@func@_avx512f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
-
+NPY_CPU_DISPATCH_DECLARE(NPY_NO_EXPORT void @TYPE@_@kind@,
+ (char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data)))
/**end repeat1**/
+/**end repeat**/
-/**begin repeat1
- * #isa = avx512f, fma#
+/**begin repeat
+ * #TYPE = FLOAT, DOUBLE#
*/
-
-/**begin repeat2
- * #func = sqrt, absolute, square, reciprocal#
+/**begin repeat1
+ * #func = maximum, minimum#
*/
NPY_NO_EXPORT void
-@TYPE@_@func@_@isa@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+@TYPE@_@func@_avx512f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
-/**end repeat2**/
/**end repeat1**/
/**end repeat**/
NPY_NO_EXPORT void
DOUBLE_exp_avx512f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+NPY_NO_EXPORT void
+DOUBLE_log(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+
+NPY_NO_EXPORT void
+DOUBLE_log_avx512f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+
/**begin repeat
* #func = sin, cos, exp, log#
*/
* #kind = isnan, isinf, isfinite, signbit, copysign, nextafter, spacing#
* #func = npy_isnan, npy_isinf, npy_isfinite, npy_signbit, npy_copysign, nextafter, spacing#
**/
+
+/**begin repeat2
+ * #ISA = , _avx512_skx#
+ **/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+@TYPE@_@kind@@ISA@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+/**end repeat2**/
/**end repeat1**/
/**begin repeat1
NPY_NO_EXPORT void
@TYPE@_frexp(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+NPY_NO_EXPORT void
+@TYPE@_frexp_avx512_skx(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+
NPY_NO_EXPORT void
@TYPE@_ldexp(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+NPY_NO_EXPORT void
+@TYPE@_ldexp_avx512_skx(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+
NPY_NO_EXPORT void
@TYPE@_ldexp_long(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
--- /dev/null
+/*@targets
+ ** $maxopt baseline
+ ** sse2 vsx2 neon
+ **/
+/**
+ * Force use SSE only on x86, even if AVX2 or AVX512F are enabled
+ * through the baseline, since scatter(AVX512F) and gather very costly
+ * to handle non-contiguous memory access comparing with SSE for
+ * such small operations that this file covers.
+*/
+#define NPY_SIMD_FORCE_128
+#include "numpy/npy_math.h"
+#include "simd/simd.h"
+#include "loops_utils.h"
+#include "loops.h"
+/**********************************************************
+ ** Scalars
+ **********************************************************/
+#if !NPY_SIMD
+NPY_FINLINE float c_recip_f32(float a)
+{ return 1.0f / a; }
+NPY_FINLINE float c_abs_f32(float a)
+{
+ const float tmp = a > 0 ? a : -a;
+ /* add 0 to clear -0.0 */
+ return tmp + 0;
+}
+NPY_FINLINE float c_square_f32(float a)
+{ return a * a; }
+#endif // !NPY_SIMD
+
+#if !NPY_SIMD_F64
+NPY_FINLINE double c_recip_f64(double a)
+{ return 1.0 / a; }
+NPY_FINLINE double c_abs_f64(double a)
+{
+ const double tmp = a > 0 ? a : -a;
+ /* add 0 to clear -0.0 */
+ return tmp + 0;
+}
+NPY_FINLINE double c_square_f64(double a)
+{ return a * a; }
+#endif // !NPY_SIMD_F64
+/**
+ * MSVC(32-bit mode) requires a clarified contiguous loop
+ * in order to use SSE, otherwise it uses a soft version of square root
+ * that doesn't raise a domain error.
+ */
+#if defined(_MSC_VER) && defined(_M_IX86) && !NPY_SIMD
+ #include <emmintrin.h>
+ NPY_FINLINE float c_sqrt_f32(float _a)
+ {
+ __m128 a = _mm_load_ss(&_a);
+ __m128 lower = _mm_sqrt_ss(a);
+ return _mm_cvtss_f32(lower);
+ }
+ NPY_FINLINE double c_sqrt_f64(double _a)
+ {
+ __m128d a = _mm_load_sd(&_a);
+ __m128d lower = _mm_sqrt_pd(a);
+ return _mm_cvtsd_f64(lower);
+ }
+#else
+ #define c_sqrt_f32 npy_sqrtf
+ #define c_sqrt_f64 npy_sqrt
+#endif
+
+/********************************************************************************
+ ** Defining the SIMD kernels
+ ********************************************************************************/
+/** Notes:
+ * - avoid the use of libmath to unify fp/domain errors
+ * for both scalars and vectors among all compilers/architectures.
+ * - use intrinsic npyv_load_till_* instead of npyv_load_tillz_
+ * to fill the remind lanes with 1.0 to avoid divide by zero fp
+ * exception in reciprocal.
+ */
+#define CONTIG 0
+#define NCONTIG 1
+/**begin repeat
+ * #TYPE = FLOAT, DOUBLE#
+ * #sfx = f32, f64#
+ * #VCHK = NPY_SIMD, NPY_SIMD_F64#
+ */
+#if @VCHK@
+/**begin repeat1
+ * #kind = sqrt, absolute, square, reciprocal#
+ * #intr = sqrt, abs, square, recip#
+ * #repl_0w1 = 0, 0, 0, 1#
+ */
+/**begin repeat2
+ * #STYPE = CONTIG, NCONTIG, CONTIG, NCONTIG#
+ * #DTYPE = CONTIG, CONTIG, NCONTIG, NCONTIG#
+ * #unroll = 4, 4, 2, 2#
+ */
+static void simd_@TYPE@_@kind@_@STYPE@_@DTYPE@
+(const void *_src, npy_intp ssrc, void *_dst, npy_intp sdst, npy_intp len)
+{
+ const npyv_lanetype_@sfx@ *src = _src;
+ npyv_lanetype_@sfx@ *dst = _dst;
+
+ const int vstep = npyv_nlanes_@sfx@;
+ const int wstep = vstep * @unroll@;
+ for (; len >= wstep; len -= wstep, src += ssrc*wstep, dst += sdst*wstep) {
+ /**begin repeat3
+ * #N = 0, 1, 2, 3#
+ */
+ #if @unroll@ > @N@
+ #if @STYPE@ == CONTIG
+ npyv_@sfx@ v_src@N@ = npyv_load_@sfx@(src + vstep*@N@);
+ #else
+ npyv_@sfx@ v_src@N@ = npyv_loadn_@sfx@(src + ssrc*vstep*@N@, ssrc);
+ #endif
+ npyv_@sfx@ v_unary@N@ = npyv_@intr@_@sfx@(v_src@N@);
+ #endif
+ /**end repeat3**/
+ /**begin repeat3
+ * #N = 0, 1, 2, 3#
+ */
+ #if @unroll@ > @N@
+ #if @DTYPE@ == CONTIG
+ npyv_store_@sfx@(dst + vstep*@N@, v_unary@N@);
+ #else
+ npyv_storen_@sfx@(dst + sdst*vstep*@N@, sdst, v_unary@N@);
+ #endif
+ #endif
+ /**end repeat3**/
+ }
+ for (; len > 0; len -= vstep, src += ssrc*vstep, dst += sdst*vstep) {
+ #if @STYPE@ == CONTIG
+ #if @repl_0w1@
+ npyv_@sfx@ v_src0 = npyv_load_till_@sfx@(src, len, 1);
+ #else
+ npyv_@sfx@ v_src0 = npyv_load_tillz_@sfx@(src, len);
+ #endif
+ #else
+ #if @repl_0w1@
+ npyv_@sfx@ v_src0 = npyv_loadn_till_@sfx@(src, ssrc, len, 1);
+ #else
+ npyv_@sfx@ v_src0 = npyv_loadn_tillz_@sfx@(src, ssrc, len);
+ #endif
+ #endif
+ npyv_@sfx@ v_unary0 = npyv_@intr@_@sfx@(v_src0);
+ #if @DTYPE@ == CONTIG
+ npyv_store_till_@sfx@(dst, len, v_unary0);
+ #else
+ npyv_storen_till_@sfx@(dst, sdst, len, v_unary0);
+ #endif
+ }
+ npyv_cleanup();
+}
+/**end repeat2**/
+/**end repeat1**/
+#endif // @VCHK@
+/**end repeat**/
+
+/********************************************************************************
+ ** Defining ufunc inner functions
+ ********************************************************************************/
+/**begin repeat
+ * #TYPE = FLOAT, DOUBLE#
+ * #sfx = f32, f64#
+ * #VCHK = NPY_SIMD, NPY_SIMD_F64#
+ */
+/**begin repeat1
+ * #kind = sqrt, absolute, square, reciprocal#
+ * #intr = sqrt, abs, square, recip#
+ * #clear = 0, 1, 0, 0#
+ */
+NPY_NO_EXPORT void NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@)
+(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
+{
+ const char *src = args[0]; char *dst = args[1];
+ const npy_intp src_step = steps[0];
+ const npy_intp dst_step = steps[1];
+ npy_intp len = dimensions[0];
+#if @VCHK@
+ const int lsize = sizeof(npyv_lanetype_@sfx@);
+ assert(src_step % lsize == 0 && dst_step % lsize == 0);
+ if (is_mem_overlap(src, src_step, dst, dst_step, len)) {
+ goto no_unroll;
+ }
+ const npy_intp ssrc = src_step / lsize;
+ const npy_intp sdst = dst_step / lsize;
+ if (!npyv_loadable_stride_@sfx@(ssrc) || !npyv_storable_stride_@sfx@(sdst)) {
+ goto no_unroll;
+ }
+ if (ssrc == 1 && sdst == 1) {
+ simd_@TYPE@_@kind@_CONTIG_CONTIG(src, 1, dst, 1, len);
+ }
+ else if (sdst == 1) {
+ simd_@TYPE@_@kind@_NCONTIG_CONTIG(src, ssrc, dst, 1, len);
+ }
+ else if (ssrc == 1) {
+ simd_@TYPE@_@kind@_CONTIG_NCONTIG(src, 1, dst, sdst, len);
+ } else {
+ simd_@TYPE@_@kind@_NCONTIG_NCONTIG(src, ssrc, dst, sdst, len);
+ }
+ goto clear;
+no_unroll:
+#endif // @VCHK@
+ for (; len > 0; --len, src += src_step, dst += dst_step) {
+ #if @VCHK@
+ // to guarantee the same precsion and fp/domain errors for both scalars and vectors
+ simd_@TYPE@_@kind@_CONTIG_CONTIG(src, 0, dst, 0, 1);
+ #else
+ const npyv_lanetype_@sfx@ src0 = *(npyv_lanetype_@sfx@*)src;
+ *(npyv_lanetype_@sfx@*)dst = c_@intr@_@sfx@(src0);
+ #endif
+ }
+#if @VCHK@
+clear:;
+#endif
+#if @clear@
+ npy_clear_floatstatus_barrier((char*)dimensions);
+#endif
+}
+/**end repeat1**/
+/**end repeat**/
--- /dev/null
+#ifndef _NPY_UMATH_LOOPS_UTILS_H_
+#define _NPY_UMATH_LOOPS_UTILS_H_
+
+#include "numpy/npy_common.h" // NPY_FINLINE
+/*
+ * nomemoverlap - returns false if two strided arrays have an overlapping
+ * region in memory. ip_size/op_size = size of the arrays which can be negative
+ * indicating negative steps.
+ */
+NPY_FINLINE npy_bool
+nomemoverlap(char *ip, npy_intp ip_size, char *op, npy_intp op_size)
+{
+ char *ip_start, *ip_end, *op_start, *op_end;
+ if (ip_size < 0) {
+ ip_start = ip + ip_size;
+ ip_end = ip;
+ }
+ else {
+ ip_start = ip;
+ ip_end = ip + ip_size;
+ }
+ if (op_size < 0) {
+ op_start = op + op_size;
+ op_end = op;
+ }
+ else {
+ op_start = op;
+ op_end = op + op_size;
+ }
+ return (ip_start == op_start && op_end == ip_end) ||
+ (ip_start > op_end) || (op_start > ip_end);
+}
+
+// returns true if two strided arrays have an overlapping region in memory
+// same as `nomemoverlap()` but requires array length and step sizes
+NPY_FINLINE npy_bool
+is_mem_overlap(const void *src, npy_intp src_step, const void *dst, npy_intp dst_step, npy_intp len)
+{
+ return !(nomemoverlap((char*)src, src_step*len, (char*)dst, dst_step*len));
+}
+
+#endif // _NPY_UMATH_LOOPS_UTILS_H_
*****************************************************************************
*/
+#if defined(HAVE_CBLAS)
/*
* -1 to be conservative, in case blas internally uses a for loop with an
* inclusive upper bound
return NPY_FALSE;
}
-#if defined(HAVE_CBLAS)
static const npy_cdouble oneD = {1.0, 0.0}, zeroD = {0.0, 0.0};
static const npy_cfloat oneF = {1.0, 0.0}, zeroF = {0.0, 0.0};
#ifndef __NPY_SIMD_DATA_H_
#define __NPY_SIMD_DATA_H_
#if defined HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
+#if !(defined(__clang__) && (__clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 1)))
/*
* Constants used in vector implementation of float64 exp(x)
*/
0x3C99D3E12DD8A18B,
};
#endif
+#endif
/*
* Constants used in vector implementation of exp(x)
#define NPY_COEFF_INVF7_SINEf -0x1.a06bbap-13f
#define NPY_COEFF_INVF9_SINEf 0x1.7d3bbcp-19f
+/*
+ * Lookup table of log(c_k)
+ * Reference form: Tang, Ping-Tak Peter. "Table-driven implementation of the
+ * logarithm function in IEEE floating-point arithmetic." ACM Transactions
+ * on Mathematical Software (TOMS) 16.4 (1990): 378-400.
+ */
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
+#if !(defined(__clang__) && (__clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 1)))
+static npy_uint64 LOG_TABLE_TOP[64] = {
+ 0x0000000000000000,
+ 0x3F8FC0A8B1000000,
+ 0x3F9F829B0E780000,
+ 0x3FA77458F6340000,
+ 0x3FAF0A30C0100000,
+ 0x3FB341D7961C0000,
+ 0x3FB6F0D28AE60000,
+ 0x3FBA926D3A4A0000,
+ 0x3FBE27076E2A0000,
+ 0x3FC0D77E7CD10000,
+ 0x3FC29552F8200000,
+ 0x3FC44D2B6CCB0000,
+ 0x3FC5FF3070A80000,
+ 0x3FC7AB8902110000,
+ 0x3FC9525A9CF40000,
+ 0x3FCAF3C94E810000,
+ 0x3FCC8FF7C79B0000,
+ 0x3FCE27076E2B0000,
+ 0x3FCFB9186D5E0000,
+ 0x3FD0A324E2738000,
+ 0x3FD1675CABAB8000,
+ 0x3FD22941FBCF8000,
+ 0x3FD2E8E2BAE10000,
+ 0x3FD3A64C55698000,
+ 0x3FD4618BC21C8000,
+ 0x3FD51AAD872E0000,
+ 0x3FD5D1BDBF580000,
+ 0x3FD686C81E9B0000,
+ 0x3FD739D7F6BC0000,
+ 0x3FD7EAF83B828000,
+ 0x3FD89A3386C18000,
+ 0x3FD947941C210000,
+ 0x3FD9F323ECBF8000,
+ 0x3FDA9CEC9A9A0000,
+ 0x3FDB44F77BCC8000,
+ 0x3FDBEB4D9DA70000,
+ 0x3FDC8FF7C79A8000,
+ 0x3FDD32FE7E010000,
+ 0x3FDDD46A04C20000,
+ 0x3FDE744261D68000,
+ 0x3FDF128F5FAF0000,
+ 0x3FDFAF588F790000,
+ 0x3FE02552A5A5C000,
+ 0x3FE0723E5C1CC000,
+ 0x3FE0BE72E4254000,
+ 0x3FE109F39E2D4000,
+ 0x3FE154C3D2F4C000,
+ 0x3FE19EE6B467C000,
+ 0x3FE1E85F5E704000,
+ 0x3FE23130D7BEC000,
+ 0x3FE2795E1289C000,
+ 0x3FE2C0E9ED448000,
+ 0x3FE307D7334F0000,
+ 0x3FE34E289D9D0000,
+ 0x3FE393E0D3564000,
+ 0x3FE3D9026A714000,
+ 0x3FE41D8FE8468000,
+ 0x3FE4618BC21C4000,
+ 0x3FE4A4F85DB04000,
+ 0x3FE4E7D811B74000,
+ 0x3FE52A2D265BC000,
+ 0x3FE56BF9D5B40000,
+ 0x3FE5AD404C358000,
+ 0x3FE5EE02A9240000,
+};
+
+static npy_uint64 LOG_TABLE_TAIL[64] = {
+ 0x0000000000000000,
+ 0xBD5FE0E183092C59,
+ 0x3D2980267C7E09E4,
+ 0xBD62303B9CB0D5E1,
+ 0x3D662A6617CC9717,
+ 0xBD4717B6B33E44F8,
+ 0xBD62968C836CC8C2,
+ 0x3D6AAC6CA17A4554,
+ 0x3D6E5CBD3D50FFFC,
+ 0xBD6C69A65A23A170,
+ 0xBD35B967F4471DFC,
+ 0x3D6F4799F4F6543E,
+ 0xBD6B0B0DE3077D7E,
+ 0xBD537B720E4A694B,
+ 0x3D65AD1D904C1D4E,
+ 0xBD600349CC67F9B2,
+ 0xBD697794F689F843,
+ 0xBD3A342C2AF0003C,
+ 0x3D5F1546AAA3361C,
+ 0x3D50E35F73F7A018,
+ 0x3D630701CE63EAB9,
+ 0xBD3A6976F5EB0963,
+ 0x3D5D309C2CC91A85,
+ 0xBD6D0B1C68651946,
+ 0xBD609EC17A426426,
+ 0xBD3F4BD8DB0A7CC1,
+ 0x3D4394A11B1C1EE4,
+ 0x3D54AEC442BE1015,
+ 0xBD67FCB18ED9D603,
+ 0x3D67E1B259D2F3DA,
+ 0xBD6ED2A52C73BF78,
+ 0x3D56FABA4CDD147D,
+ 0x3D584BF2B68D766F,
+ 0x3D40931A909FEA5E,
+ 0x3D4EC5197DDB55D3,
+ 0x3D5B7BF7861D37AC,
+ 0x3D5A21AC25DB1EF3,
+ 0xBD542A9E21373414,
+ 0xBD6DAFA08CECADB1,
+ 0x3D3E1F8DF68DBCF3,
+ 0x3D3BB2CD720EC44C,
+ 0xBD49C24CA098362B,
+ 0x3D60FEC69C695D7F,
+ 0x3D6F404E57963891,
+ 0xBD657D49676844CC,
+ 0x3D592DFBC7D93617,
+ 0x3D65E9A98F33A396,
+ 0x3D52DD98B97BAEF0,
+ 0x3D1A07BD8B34BE7C,
+ 0xBD17AFA4392F1BA7,
+ 0xBD5DCA290F818480,
+ 0x3D5D1772F5386374,
+ 0x3D60BE1FB590A1F5,
+ 0xBD6E2CE9146D271A,
+ 0xBD65E6563BBD9FC9,
+ 0x3D66FAA404263D0B,
+ 0xBD5AA33736867A17,
+ 0x3D6EC27D0B7B37B3,
+ 0xBD244FDD840B8591,
+ 0x3D6BB09CB0985646,
+ 0x3D46ABB9DF22BC57,
+ 0xBD58CD7DC73BD194,
+ 0x3D6F2CFB29AAA5F0,
+ 0x3D66757006095FD2,
+};
+
+#define NPY_TANG_LOG_A1 0x1.55555555554e6p-4
+#define NPY_TANG_LOG_A2 0x1.9999999bac6d4p-7
+#define NPY_TANG_LOG_A3 0x1.2492307f1519fp-9
+#define NPY_TANG_LOG_A4 0x1.c8034c85dfffp-12
+
+#define NPY_TANG_LOG_LN2HI 0x1.62e42fefa4p-1
+#define NPY_TANG_LOG_LN2LO -0x1.8432a1b0e2634p-43
+#endif
+#endif
+
#endif
goto fail;
}
- method_name = PyUString_FromString(method);
+ method_name = PyUnicode_FromString(method);
if (method_name == NULL) {
goto fail;
}
#include "npy_config.h"
#include <numpy/arrayobject.h>
-#include "npy_config.h"
#include "npy_pycompat.h"
#include "ctors.h"
#include "reduction.h"
#include "extobj.h" /* for _check_ufunc_fperr */
-/*
- * Allocates a result array for a reduction operation, with
- * dimensions matching 'arr' except set to 1 with 0 stride
- * wherever axis_flags is True. Dropping the reduction axes
- * from the result must be done later by the caller once the
- * computation is complete.
- *
- * This function always allocates a base class ndarray.
- *
- * If 'dtype' isn't NULL, this function steals its reference.
- */
-static PyArrayObject *
-allocate_reduce_result(PyArrayObject *arr, const npy_bool *axis_flags,
- PyArray_Descr *dtype, int subok)
-{
- npy_intp strides[NPY_MAXDIMS], stride;
- npy_intp shape[NPY_MAXDIMS], *arr_shape = PyArray_DIMS(arr);
- npy_stride_sort_item strideperm[NPY_MAXDIMS];
- int idim, ndim = PyArray_NDIM(arr);
-
- if (dtype == NULL) {
- dtype = PyArray_DTYPE(arr);
- Py_INCREF(dtype);
- }
-
- PyArray_CreateSortedStridePerm(PyArray_NDIM(arr),
- PyArray_STRIDES(arr), strideperm);
-
- /* Build the new strides and shape */
- stride = dtype->elsize;
- if (ndim) {
- memcpy(shape, arr_shape, ndim * sizeof(shape[0]));
- }
- for (idim = ndim-1; idim >= 0; --idim) {
- npy_intp i_perm = strideperm[idim].perm;
- if (axis_flags[i_perm]) {
- strides[i_perm] = 0;
- shape[i_perm] = 1;
- }
- else {
- strides[i_perm] = stride;
- stride *= shape[i_perm];
- }
- }
-
- /* Finally, allocate the array */
- return (PyArrayObject *)PyArray_NewFromDescr(
- subok ? Py_TYPE(arr) : &PyArray_Type,
- dtype, ndim, shape, strides,
- NULL, 0, subok ? (PyObject *)arr : NULL);
-}
-
-/*
- * Conforms an output parameter 'out' to have 'ndim' dimensions
- * with dimensions of size one added in the appropriate places
- * indicated by 'axis_flags'.
- *
- * The return value is a view into 'out'.
- */
-static PyArrayObject *
-conform_reduce_result(PyArrayObject *in, const npy_bool *axis_flags,
- PyArrayObject *out, int keepdims, const char *funcname,
- int need_copy)
-{
- /* unpack shape information */
- int const ndim = PyArray_NDIM(in);
- npy_intp const *shape_in = PyArray_DIMS(in);
-
- int const ndim_out = PyArray_NDIM(out);
- npy_intp const *strides_out = PyArray_STRIDES(out);
- npy_intp const *shape_out = PyArray_DIMS(out);
-
- /*
- * If the 'keepdims' parameter is true, do a simpler validation and
- * return a new reference to 'out'.
- */
- if (keepdims) {
- if (PyArray_NDIM(out) != ndim) {
- PyErr_Format(PyExc_ValueError,
- "output parameter for reduction operation %s "
- "has the wrong number of dimensions (must match "
- "the operand's when keepdims=True)", funcname);
- return NULL;
- }
-
- for (int idim = 0; idim < ndim; ++idim) {
- if (axis_flags[idim]) {
- if (shape_out[idim] != 1) {
- PyErr_Format(PyExc_ValueError,
- "output parameter for reduction operation %s "
- "has a reduction dimension not equal to one "
- "(required when keepdims=True)", funcname);
- return NULL;
- }
- }
- else {
- if (shape_out[idim] != shape_in[idim]) {
- PyErr_Format(PyExc_ValueError,
- "output parameter for reduction operation %s "
- "has a non-reduction dimension not equal to "
- "the input one.", funcname);
- return NULL;
- }
- }
-
- }
-
- Py_INCREF(out);
- return out;
- }
-
- /* Construct the strides and shape */
- npy_intp strides[NPY_MAXDIMS], shape[NPY_MAXDIMS];
- int idim_out = 0;
- for (int idim = 0; idim < ndim; ++idim) {
- if (axis_flags[idim]) {
- strides[idim] = 0;
- shape[idim] = 1;
- }
- else {
- if (idim_out >= ndim_out) {
- PyErr_Format(PyExc_ValueError,
- "output parameter for reduction operation %s "
- "does not have enough dimensions", funcname);
- return NULL;
- }
- if (shape_out[idim_out] != shape_in[idim]) {
- PyErr_Format(PyExc_ValueError,
- "output parameter for reduction operation %s "
- "has a non-reduction dimension not equal to "
- "the input one.", funcname);
- return NULL;
- }
- strides[idim] = strides_out[idim_out];
- shape[idim] = shape_out[idim_out];
- ++idim_out;
- }
- }
-
- if (idim_out != ndim_out) {
- PyErr_Format(PyExc_ValueError,
- "output parameter for reduction operation %s "
- "has too many dimensions", funcname);
- return NULL;
- }
-
- /* Allocate the view */
- PyArray_Descr *dtype = PyArray_DESCR(out);
- Py_INCREF(dtype);
-
- PyArrayObject_fields *ret = (PyArrayObject_fields *)PyArray_NewFromDescrAndBase(
- &PyArray_Type, dtype,
- ndim, shape, strides, PyArray_DATA(out),
- PyArray_FLAGS(out), NULL, (PyObject *)out);
- if (ret == NULL) {
- return NULL;
- }
-
- if (need_copy) {
- PyArrayObject *ret_copy = (PyArrayObject *)PyArray_NewLikeArray(
- (PyArrayObject *)ret, NPY_ANYORDER, NULL, 0);
- if (ret_copy == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
-
- if (PyArray_CopyInto(ret_copy, (PyArrayObject *)ret) != 0) {
- Py_DECREF(ret);
- Py_DECREF(ret_copy);
- return NULL;
- }
-
- if (PyArray_SetWritebackIfCopyBase(ret_copy, (PyArrayObject *)ret) < 0) {
- Py_DECREF(ret_copy);
- return NULL;
- }
-
- return ret_copy;
- }
- else {
- return (PyArrayObject *)ret;
- }
-}
-
-/*
- * Creates a result for reducing 'operand' along the axes specified
- * in 'axis_flags'. If 'dtype' isn't NULL, this function steals a
- * reference to 'dtype'.
- *
- * If 'out' isn't NULL, this function creates a view conforming
- * to the number of dimensions of 'operand', adding a singleton dimension
- * for each reduction axis specified. In this case, 'dtype' is ignored
- * (but its reference is still stolen), and the caller must handle any
- * type conversion/validity check for 'out'
- *
- * If 'subok' is true, creates a result with the subtype of 'operand',
- * otherwise creates on with the base ndarray class.
- *
- * If 'out' is NULL, it allocates a new array whose shape matches that of
- * 'operand', except for at the reduction axes. If 'dtype' is NULL, the dtype
- * of 'operand' is used for the result.
- */
-NPY_NO_EXPORT PyArrayObject *
-PyArray_CreateReduceResult(PyArrayObject *operand, PyArrayObject *out,
- PyArray_Descr *dtype, npy_bool *axis_flags,
- int keepdims, int subok,
- const char *funcname)
-{
- PyArrayObject *result;
-
- if (out == NULL) {
- /* This function steals the reference to 'dtype' */
- result = allocate_reduce_result(operand, axis_flags, dtype, subok);
- }
- else {
- int need_copy = 0;
-
- if (solve_may_share_memory(operand, out, 1) != 0) {
- need_copy = 1;
- }
-
- /* Steal the dtype reference */
- Py_XDECREF(dtype);
- result = conform_reduce_result(operand, axis_flags,
- out, keepdims, funcname, need_copy);
- }
-
- return result;
-}
/*
* Count the number of dimensions selected in 'axis_flags'
/*
* This function initializes a result array for a reduction operation
* which has no identity. This means it needs to copy the first element
- * it sees along the reduction axes to result, then return a view of
- * the operand which excludes that element.
+ * it sees along the reduction axes to result.
*
* If a reduction has an identity, such as 0 or 1, the result should be
- * initialized by calling PyArray_AssignZero(result, NULL, NULL) or
- * PyArray_AssignOne(result, NULL, NULL), because this function raises an
- * exception when there are no elements to reduce (which appropriate iff the
- * reduction operation has no identity).
+ * fully initialized to the identity, because this function raises an
+ * exception when there are no elements to reduce (which is appropriate if,
+ * and only if, the reduction operation has no identity).
*
* This means it copies the subarray indexed at zero along each reduction axis
- * into 'result', then returns a view into 'operand' excluding those copied
- * elements.
+ * into 'result'.
*
* result : The array into which the result is computed. This must have
* the same number of dimensions as 'operand', but for each
* operand : The array being reduced.
* axis_flags : An array of boolean flags, one for each axis of 'operand'.
* When a flag is True, it indicates to reduce along that axis.
- * out_skip_first_count : This gets populated with the number of first-visit
- * elements that should be skipped during the
- * iteration loop.
* funcname : The name of the reduction operation, for the purpose of
* better quality error messages. For example, "numpy.max"
* would be a good name for NumPy's max function.
*
- * Returns a view which contains the remaining elements on which to do
- * the reduction.
+ * Returns -1 if an error occurred, and otherwise the reduce arrays size,
+ * which is the number of elements already initialized.
*/
-NPY_NO_EXPORT PyArrayObject *
-PyArray_InitializeReduceResult(
+NPY_NO_EXPORT int
+PyArray_CopyInitialReduceValues(
PyArrayObject *result, PyArrayObject *operand,
- const npy_bool *axis_flags,
- npy_intp *out_skip_first_count, const char *funcname)
+ const npy_bool *axis_flags, const char *funcname,
+ int keepdims)
{
- npy_intp *strides, *shape, shape_orig[NPY_MAXDIMS];
+ npy_intp shape[NPY_MAXDIMS], strides[NPY_MAXDIMS];
+ npy_intp *shape_orig = PyArray_SHAPE(operand);
+ npy_intp *strides_orig = PyArray_STRIDES(operand);
PyArrayObject *op_view = NULL;
- int idim, ndim, nreduce_axes;
- ndim = PyArray_NDIM(operand);
-
- /* Default to no skipping first-visit elements in the iteration */
- *out_skip_first_count = 0;
-
- /* Take a view into 'operand' which we can modify. */
- op_view = (PyArrayObject *)PyArray_View(operand, NULL, &PyArray_Type);
- if (op_view == NULL) {
- return NULL;
- }
+ int ndim = PyArray_NDIM(operand);
/*
- * Now copy the subarray of the first element along each reduction axis,
- * then return a view to the rest.
+ * Copy the subarray of the first element along each reduction axis.
*
* Adjust the shape to only look at the first element along
- * any of the reduction axes. We count the number of reduction axes
- * at the same time.
+ * any of the reduction axes. If keepdims is False remove the axes
+ * entirely.
*/
- shape = PyArray_SHAPE(op_view);
- nreduce_axes = 0;
- if (ndim) {
- memcpy(shape_orig, shape, ndim * sizeof(npy_intp));
- }
- for (idim = 0; idim < ndim; ++idim) {
+ int idim_out = 0;
+ npy_intp size = 1;
+ for (int idim = 0; idim < ndim; idim++) {
if (axis_flags[idim]) {
- if (shape[idim] == 0) {
+ if (NPY_UNLIKELY(shape_orig[idim] == 0)) {
PyErr_Format(PyExc_ValueError,
- "zero-size array to reduction operation %s "
- "which has no identity",
- funcname);
- Py_DECREF(op_view);
- return NULL;
+ "zero-size array to reduction operation %s "
+ "which has no identity", funcname);
+ return -1;
}
- shape[idim] = 1;
- ++nreduce_axes;
+ if (keepdims) {
+ shape[idim_out] = 1;
+ strides[idim_out] = 0;
+ idim_out++;
+ }
+ }
+ else {
+ size *= shape_orig[idim];
+ shape[idim_out] = shape_orig[idim];
+ strides[idim_out] = strides_orig[idim];
+ idim_out++;
}
}
- /*
- * Copy the elements into the result to start.
- */
- if (PyArray_CopyInto(result, op_view) < 0) {
- Py_DECREF(op_view);
- return NULL;
+ PyArray_Descr *descr = PyArray_DESCR(operand);
+ Py_INCREF(descr);
+ op_view = (PyArrayObject *)PyArray_NewFromDescr(
+ &PyArray_Type, descr, idim_out, shape, strides,
+ PyArray_DATA(operand), 0, NULL);
+ if (op_view == NULL) {
+ return -1;
}
/*
- * If there is one reduction axis, adjust the view's
- * shape to only look at the remaining elements
+ * Copy the elements into the result to start.
*/
- if (nreduce_axes == 1) {
- strides = PyArray_STRIDES(op_view);
- for (idim = 0; idim < ndim; ++idim) {
- if (axis_flags[idim]) {
- shape[idim] = shape_orig[idim] - 1;
- ((PyArrayObject_fields *)op_view)->data += strides[idim];
- }
- }
- }
- /* If there are zero reduction axes, make the view empty */
- else if (nreduce_axes == 0) {
- for (idim = 0; idim < ndim; ++idim) {
- shape[idim] = 0;
- }
+ int res = PyArray_CopyInto(result, op_view);
+ Py_DECREF(op_view);
+ if (res < 0) {
+ return -1;
}
+
/*
- * Otherwise iterate over the whole operand, but tell the inner loop
- * to skip the elements we already copied by setting the skip_first_count.
+ * If there were no reduction axes, we would already be done here.
+ * Note that if there is only a single reduction axis, in principle the
+ * iteration could be set up more efficiently here by removing that
+ * axis before setting up the iterator (simplifying the iteration since
+ * `skip_first_count` (the returned size) can be set to 0).
*/
- else {
- *out_skip_first_count = PyArray_SIZE(result);
-
- Py_DECREF(op_view);
- Py_INCREF(operand);
- op_view = operand;
- }
-
- return op_view;
+ return size;
}
/*
* with size one.
* subok : If true, the result uses the subclass of operand, otherwise
* it is always a base class ndarray.
- * identity : If Py_None, PyArray_InitializeReduceResult is used, otherwise
+ * identity : If Py_None, PyArray_CopyInitialReduceValues is used, otherwise
* this value is used to initialize the result to
* the reduction's unit.
* loop : The loop which does the reduction.
NPY_CASTING casting,
npy_bool *axis_flags, int reorderable,
int keepdims,
- int subok,
PyObject *identity,
PyArray_ReduceLoopFunc *loop,
void *data, npy_intp buffersize, const char *funcname,
int errormask)
{
- PyArrayObject *result = NULL, *op_view = NULL;
+ PyArrayObject *result = NULL;
npy_intp skip_first_count = 0;
/* Iterator parameters */
return NULL;
}
- /*
- * This either conforms 'out' to the ndim of 'operand', or allocates
- * a new array appropriate for this reduction.
- *
- * A new array with WRITEBACKIFCOPY is allocated if operand and out have memory
- * overlap.
- */
- Py_INCREF(result_dtype);
- result = PyArray_CreateReduceResult(operand, out,
- result_dtype, axis_flags,
- keepdims, subok, funcname);
- if (result == NULL) {
- goto fail;
- }
-
- /*
- * Initialize the result to the reduction unit if possible,
- * otherwise copy the initial values and get a view to the rest.
- */
- if (identity != Py_None) {
- if (PyArray_FillWithScalar(result, identity) < 0) {
- goto fail;
- }
- op_view = operand;
- Py_INCREF(op_view);
- }
- else {
- op_view = PyArray_InitializeReduceResult(
- result, operand, axis_flags, &skip_first_count, funcname);
- if (op_view == NULL) {
- goto fail;
- }
- /* empty op_view signals no reduction; but 0-d arrays cannot be empty */
- if ((PyArray_SIZE(op_view) == 0) || (PyArray_NDIM(operand) == 0)) {
- Py_DECREF(op_view);
- op_view = NULL;
- goto finish;
- }
- }
/* Set up the iterator */
- op[0] = result;
- op[1] = op_view;
+ op[0] = out;
+ op[1] = operand;
op_dtypes[0] = result_dtype;
op_dtypes[1] = operand_dtype;
NPY_ITER_GROWINNER |
NPY_ITER_DONT_NEGATE_STRIDES |
NPY_ITER_ZEROSIZE_OK |
- NPY_ITER_REDUCE_OK |
- NPY_ITER_REFS_OK;
+ NPY_ITER_REFS_OK |
+ NPY_ITER_DELAY_BUFALLOC |
+ NPY_ITER_COPY_IF_OVERLAP;
op_flags[0] = NPY_ITER_READWRITE |
NPY_ITER_ALIGNED |
+ NPY_ITER_ALLOCATE |
NPY_ITER_NO_SUBTYPE;
op_flags[1] = NPY_ITER_READONLY |
- NPY_ITER_ALIGNED;
+ NPY_ITER_ALIGNED |
+ NPY_ITER_NO_BROADCAST;
+
if (wheremask != NULL) {
op[2] = wheremask;
/* wheremask is guaranteed to be NPY_BOOL, so borrow its reference */
}
op_flags[2] = NPY_ITER_READONLY;
}
+ /* Set up result array axes mapping, operand and wheremask use default */
+ int result_axes[NPY_MAXDIMS];
+ int *op_axes[3] = {result_axes, NULL, NULL};
+
+ int curr_axis = 0;
+ for (int i = 0; i < PyArray_NDIM(operand); i++) {
+ if (axis_flags[i]) {
+ if (keepdims) {
+ result_axes[i] = NPY_ITER_REDUCTION_AXIS(curr_axis);
+ curr_axis++;
+ }
+ else {
+ result_axes[i] = NPY_ITER_REDUCTION_AXIS(-1);
+ }
+ }
+ else {
+ result_axes[i] = curr_axis;
+ curr_axis++;
+ }
+ }
+ if (out != NULL) {
+ /* NpyIter does not raise a good error message in this common case. */
+ if (NPY_UNLIKELY(curr_axis != PyArray_NDIM(out))) {
+ if (keepdims) {
+ PyErr_Format(PyExc_ValueError,
+ "output parameter for reduction operation %s has the "
+ "wrong number of dimensions: Found %d but expected %d "
+ "(must match the operand's when keepdims=True)",
+ funcname, PyArray_NDIM(out), curr_axis);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "output parameter for reduction operation %s has the "
+ "wrong number of dimensions: Found %d but expected %d",
+ funcname, PyArray_NDIM(out), curr_axis);
+ }
+ goto fail;
+ }
+ }
iter = NpyIter_AdvancedNew(wheremask == NULL ? 2 : 3, op, flags,
NPY_KEEPORDER, casting,
op_flags,
op_dtypes,
- -1, NULL, NULL, buffersize);
+ PyArray_NDIM(operand), op_axes, NULL, buffersize);
if (iter == NULL) {
goto fail;
}
+ result = NpyIter_GetOperandArray(iter)[0];
+
+ /*
+ * Initialize the result to the reduction unit if possible,
+ * otherwise copy the initial values and get a view to the rest.
+ */
+
+ if (identity != Py_None) {
+ if (PyArray_FillWithScalar(result, identity) < 0) {
+ goto fail;
+ }
+ }
+ else {
+ /*
+ * For 1-D skip_first_count could be optimized to 0, but no-identity
+ * reductions are not super common.
+ * (see also comment in CopyInitialReduceValues)
+ */
+ skip_first_count = PyArray_CopyInitialReduceValues(
+ result, operand, axis_flags, funcname, keepdims);
+ if (skip_first_count < 0) {
+ goto fail;
+ }
+ }
+
+ if (!NpyIter_Reset(iter, NULL)) {
+ goto fail;
+ }
+
/* Start with the floating-point exception flags cleared */
npy_clear_floatstatus_barrier((char*)&iter);
if (loop(iter, dataptr, strideptr, countptr,
iternext, needs_api, skip_first_count, data) < 0) {
-
goto fail;
}
}
goto fail;
}
- NpyIter_Deallocate(iter);
- Py_DECREF(op_view);
-
-finish:
- /* Strip out the extra 'one' dimensions in the result */
- if (out == NULL) {
- if (!keepdims) {
- PyArray_RemoveAxesInPlace(result, axis_flags);
- }
- }
- else {
- PyArray_ResolveWritebackIfCopy(result); /* prevent spurious warnings */
- Py_DECREF(result);
+ if (out != NULL) {
result = out;
- Py_INCREF(result);
}
+ Py_INCREF(result);
+ if (!NpyIter_Deallocate(iter)) {
+ Py_DECREF(result);
+ return NULL;
+ }
return result;
fail:
- PyArray_ResolveWritebackIfCopy(result); /* prevent spurious warnings */
- Py_XDECREF(result);
- Py_XDECREF(op_view);
if (iter != NULL) {
NpyIter_Deallocate(iter);
}
* of cache behavior or multithreading requirements.
* keepdims : If true, leaves the reduction dimensions in the result
* with size one.
- * subok : If true, the result uses the subclass of operand, otherwise
- * it is always a base class ndarray.
- * identity : If Py_None, PyArray_InitializeReduceResult is used, otherwise
+ * identity : If Py_None, PyArray_CopyInitialReduceValues is used, otherwise
* this value is used to initialize the result to
* the reduction's unit.
* loop : The loop which does the reduction.
NPY_CASTING casting,
npy_bool *axis_flags, int reorderable,
int keepdims,
- int subok,
PyObject *identity,
PyArray_ReduceLoopFunc *loop,
void *data, npy_intp buffersize, const char *funcname,
#include "numpy/ufuncobject.h"
#include "numpy/arrayscalars.h"
+#include "npy_import.h"
#include "npy_pycompat.h"
#include "numpy/halffloat.h"
@name@_ctype_floor_divide(@type@ a, @type@ b, @type@ *out) {
@type@ mod;
- *out = npy_divmod@c@(a, b, &mod);
+ if (!b) {
+ *out = a / b;
+ } else {
+ *out = npy_divmod@c@(a, b, &mod);
+ }
}
half_ctype_floor_divide(npy_half a, npy_half b, npy_half *out) {
npy_half mod;
- *out = npy_half_divmod(a, b, &mod);
+ if (!b) {
+ *out = a / b;
+ } else {
+ *out = npy_half_divmod(a, b, &mod);
+ }
}
{
PyObject *ret;
@type@ arg1, arg2;
- /*
- * NOTE: In gcc >= 4.1, the compiler will reorder floating point
- * operations and floating point error state checks. In
- * particular, the arithmetic operations were being reordered
- * so that the errors weren't caught. Declaring this output
- * variable volatile was the minimal fix for the issue.
- * (Ticket #1671)
- */
- volatile @otype@ out;
+ @otype@ out;
+
#if @twoout@
@otype@ out2;
PyObject *obj;
* Double, LongDouble,
* CFloat, CDouble, CLongDouble#
*
- * #isint = (1,0)*5,0*7#
+ * #isint = 1*10,0*7#
+ * #isuint = (0,1)*5,0*7#
* #cmplx = 0*14,1*3#
* #iszero = _IS_ZERO*10, npy_half_iszero, _IS_ZERO*6#
* #zero = 0*10, NPY_HALF_ZERO, 0*6#
* #one = 1*10, NPY_HALF_ONE, 1*6#
*/
-#if @cmplx@
-static PyObject *
-@name@_power(PyObject *a, PyObject *b, PyObject *modulo)
-{
- PyObject *ret;
- @type@ arg1, arg2;
- int retstatus;
- int first;
- @type@ out = {@zero@, @zero@};
-
- BINOP_GIVE_UP_IF_NEEDED(a, b, nb_power, @name@_power);
-
- switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) {
- case 0:
- break;
- case -1:
- /* can't cast both safely mixed-types? */
- return PyArray_Type.tp_as_number->nb_power(a,b,modulo);
- case -2:
- /* use default handling */
- if (PyErr_Occurred()) {
- return NULL;
- }
- return PyGenericArrType_Type.tp_as_number->nb_power(a,b,modulo);
- case -3:
- default:
- /*
- * special case for longdouble and clongdouble
- * because they have a recursive getitem in their dtype
- */
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
- }
-
- if (modulo != Py_None) {
- /* modular exponentiation is not implemented (gh-8804) */
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
- }
-
- npy_clear_floatstatus_barrier((char*)&out);
-
- /*
- * here we do the actual calculation with arg1 and arg2
- * as a function call.
- */
- if (@iszero@(arg2.real) && @iszero@(arg2.imag)) {
- out.real = @one@;
- out.imag = @zero@;
- }
- else {
- @name@_ctype_power(arg1, arg2, &out);
- }
-
- /* Check status flag. If it is set, then look up what to do */
- retstatus = npy_get_floatstatus_barrier((char*)&out);
- if (retstatus) {
- int bufsize, errmask;
- PyObject *errobj;
-
- if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask,
- &errobj) < 0) {
- return NULL;
- }
- first = 1;
- if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) {
- Py_XDECREF(errobj);
- return NULL;
- }
- Py_XDECREF(errobj);
- }
-
- ret = PyArrayScalar_New(@Name@);
- if (ret == NULL) {
- return NULL;
- }
- PyArrayScalar_ASSIGN(ret, @Name@, out);
-
- return ret;
-}
-
-#elif @isint@
-
static PyObject *
@name@_power(PyObject *a, PyObject *b, PyObject *modulo)
{
return Py_NotImplemented;
}
+#if !@isint@
npy_clear_floatstatus_barrier((char*)&out);
-
+#endif
/*
* here we do the actual calculation with arg1 and arg2
* as a function call.
*/
+#if @isint@ && !@isuint@
if (arg2 < 0) {
PyErr_SetString(PyExc_ValueError,
"Integers to negative integer powers are not allowed.");
return NULL;
}
+#endif
@name@_ctype_power(arg1, arg2, &out);
- ret = PyArrayScalar_New(@Name@);
- if (ret == NULL) {
- return NULL;
- }
- PyArrayScalar_ASSIGN(ret, @Name@, out);
-
- return ret;
-}
-
-#else
-
-static PyObject *
-@name@_power(PyObject *a, PyObject *b, PyObject *modulo)
-{
- PyObject *ret;
- @type@ arg1, arg2;
- int retstatus;
- int first;
-
- @type@ out = @zero@;
-
- BINOP_GIVE_UP_IF_NEEDED(a, b, nb_power, @name@_power);
-
- switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) {
- case 0:
- break;
- case -1:
- /* can't cast both safely mixed-types? */
- return PyArray_Type.tp_as_number->nb_power(a,b,modulo);
- case -2:
- /* use default handling */
- if (PyErr_Occurred()) {
- return NULL;
- }
- return PyGenericArrType_Type.tp_as_number->nb_power(a,b,modulo);
- case -3:
- default:
- /*
- * special case for longdouble and clongdouble
- * because they have a recursive getitem in their dtype
- */
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
- }
-
- if (modulo != Py_None) {
- /* modular exponentiation is not implemented (gh-8804) */
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
- }
-
- npy_clear_floatstatus_barrier((char*)&out);
-
- /*
- * here we do the actual calculation with arg1 and arg2
- * as a function call.
- */
- if (@iszero@(arg2)) {
- out = @one@;
- }
- else {
- @name@_ctype_power(arg1, arg2, &out);
- }
-
+#if !@isint@
/* Check status flag. If it is set, then look up what to do */
- retstatus = npy_get_floatstatus_barrier((char*)&out);
+ int retstatus = npy_get_floatstatus_barrier((char*)&out);
if (retstatus) {
int bufsize, errmask;
PyObject *errobj;
&errobj) < 0) {
return NULL;
}
- first = 1;
+ int first = 1;
if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) {
Py_XDECREF(errobj);
return NULL;
}
Py_XDECREF(errobj);
}
+#endif
ret = PyArrayScalar_New(@Name@);
if (ret == NULL) {
return ret;
}
-#endif
/**end repeat**/
#undef _IS_ZERO
emit_complexwarning(void)
{
static PyObject *cls = NULL;
+ npy_cache_import("numpy.core", "ComplexWarning", &cls);
if (cls == NULL) {
- PyObject *mod;
- mod = PyImport_ImportModule("numpy.core");
- assert(mod != NULL);
- cls = PyObject_GetAttrString(mod, "ComplexWarning");
- assert(cls != NULL);
- Py_DECREF(mod);
+ return -1;
}
return PyErr_WarnEx(cls,
"Casting complex values to real discards the imaginary part", 1);
-/* -*- c -*- */
+
/*
* This file is for the definitions of simd vectorized operations.
#undef __AVX512F__
#endif
#endif
+#include "simd/simd.h"
+#include "loops_utils.h" // nomemoverlap
#include <assert.h>
#include <stdlib.h>
#include <float.h>
*/
#define MAX_STEP_SIZE 2097152
-/*
- * nomemoverlap - returns true if two strided arrays have an overlapping
- * region in memory. ip_size/op_size = size of the arrays which can be negative
- * indicating negative steps.
- */
-static NPY_INLINE npy_bool
-nomemoverlap(char *ip,
- npy_intp ip_size,
- char *op,
- npy_intp op_size)
-{
- char *ip_start, *ip_end, *op_start, *op_end;
- if (ip_size < 0) {
- ip_start = ip + ip_size;
- ip_end = ip;
- }
- else {
- ip_start = ip;
- ip_end = ip + ip_size;
- }
- if (op_size < 0) {
- op_start = op + op_size;
- op_end = op;
- }
- else {
- op_start = op;
- op_end = op + op_size;
- }
- return (ip_start > op_end) | (op_start > ip_end);
-}
-
#define IS_BINARY_STRIDE_ONE(esize, vsize) \
((steps[0] == esize) && \
(steps[1] == esize) && \
* should have no overlap in memory.
*/
#define IS_BINARY_SMALL_STEPS_AND_NOMEMOVERLAP \
- ((abs(steps[0]) < MAX_STEP_SIZE) && \
- (abs(steps[1]) < MAX_STEP_SIZE) && \
- (abs(steps[2]) < MAX_STEP_SIZE) && \
+ ((labs(steps[0]) < MAX_STEP_SIZE) && \
+ (labs(steps[1]) < MAX_STEP_SIZE) && \
+ (labs(steps[2]) < MAX_STEP_SIZE) && \
(nomemoverlap(args[0], steps[0] * dimensions[0], args[2], steps[2] * dimensions[0])) && \
(nomemoverlap(args[1], steps[1] * dimensions[0], args[2], steps[2] * dimensions[0])))
+#define IS_UNARY_TWO_OUT_SMALL_STEPS_AND_NOMEMOVERLAP \
+ ((labs(steps[0]) < MAX_STEP_SIZE) && \
+ (labs(steps[1]) < MAX_STEP_SIZE) && \
+ (labs(steps[2]) < MAX_STEP_SIZE) && \
+ (nomemoverlap(args[0], steps[0] * dimensions[0], args[2], steps[2] * dimensions[0])) && \
+ (nomemoverlap(args[0], steps[0] * dimensions[0], args[1], steps[1] * dimensions[0])))
+
/*
* 1) Output should be contiguous, can handle strided input data
* 2) Input step should be smaller than MAX_STEP_SIZE for performance
* 3) Input and output arrays should have no overlap in memory
*/
-#define IS_OUTPUT_BLOCKABLE_UNARY(esize, vsize) \
- (steps[1] == (esize) && abs(steps[0]) < MAX_STEP_SIZE && \
+#define IS_OUTPUT_BLOCKABLE_UNARY(esizein, esizeout, vsize) \
+ ((steps[0] & (esizein-1)) == 0 && \
+ steps[1] == (esizeout) && labs(steps[0]) < MAX_STEP_SIZE && \
(nomemoverlap(args[1], steps[1] * dimensions[0], args[0], steps[0] * dimensions[0])))
#define IS_BLOCKABLE_REDUCE(esize, vsize) \
run_unary_avx512f_@func@_@TYPE@(char **args, const npy_intp *dimensions, const npy_intp *steps)
{
#if defined HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
- if ((IS_OUTPUT_BLOCKABLE_UNARY((npy_uint)(@esize@/@outsize@), 64)) &&
- (labs(steps[0]) < 2*@max_stride@*@esize@) &&
- ((steps[0] & (@esize@-1)) == 0)) {
+ if ((IS_OUTPUT_BLOCKABLE_UNARY(@esize@, (npy_uint)(@esize@/@outsize@), 64)) && (labs(steps[0]) < 2*@max_stride@*@esize@)) {
AVX512F_@func@_@TYPE@((@type@*)args[1], (@type@*)args[0], dimensions[0], steps[0]);
return 1;
}
}
+/**end repeat1**/
+
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS && @EXISTS@
+static NPY_INLINE NPY_GCC_TARGET_AVX512_SKX void
+AVX512_SKX_ldexp_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps);
+
+static NPY_INLINE NPY_GCC_TARGET_AVX512_SKX void
+AVX512_SKX_frexp_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps);
+#endif
+
+static NPY_INLINE int
+run_binary_avx512_skx_ldexp_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps)
+{
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS && @EXISTS@
+ if (IS_BINARY_SMALL_STEPS_AND_NOMEMOVERLAP) {
+ AVX512_SKX_ldexp_@TYPE@(args, dimensions, steps);
+ return 1;
+ }
+ else
+ return 0;
+#endif
+ return 0;
+}
+
+static NPY_INLINE int
+run_unary_two_out_avx512_skx_frexp_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps)
+{
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS && @EXISTS@
+ if (IS_UNARY_TWO_OUT_SMALL_STEPS_AND_NOMEMOVERLAP) {
+ AVX512_SKX_frexp_@TYPE@(args, dimensions, steps);
+ return 1;
+ }
+ else
+ return 0;
+#endif
+ return 0;
+}
+/**end repeat**/
+
+/**begin repeat
+ * #type = npy_float, npy_double, npy_longdouble#
+ * #TYPE = FLOAT, DOUBLE, LONGDOUBLE#
+ * #EXISTS = 1, 1, 0#
+ */
+
+/**begin repeat1
+ * #func = isnan, isfinite, isinf, signbit#
+ */
+
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS && @EXISTS@
+static NPY_INLINE NPY_GCC_TARGET_AVX512_SKX void
+AVX512_SKX_@func@_@TYPE@(npy_bool*, @type@*, const npy_intp n, const npy_intp stride);
+#endif
+
+static NPY_INLINE int
+run_@func@_avx512_skx_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps)
+{
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS && @EXISTS@
+ if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(@type@), sizeof(npy_bool), 64)) {
+ AVX512_SKX_@func@_@TYPE@((npy_bool*)args[1], (@type@*)args[0], dimensions[0], steps[0]);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+#endif
+ return 0;
+}
+
+
/**end repeat1**/
/**end repeat**/
*/
/**begin repeat2
- * #func = sqrt, absolute, square, reciprocal, rint, floor, ceil, trunc#
+ * #func = rint, floor, ceil, trunc#
*/
#if defined @CHK@ && defined NPY_HAVE_SSE2_INTRINSICS
run_unary_@isa@_@func@_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps)
{
#if defined @CHK@ && defined NPY_HAVE_SSE2_INTRINSICS
- if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(@type@), @REGISTER_SIZE@)) {
+ if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(@type@), sizeof(@type@), @REGISTER_SIZE@)) {
@ISA@_@func@_@TYPE@((@type@*)args[1], (@type@*)args[0], dimensions[0], steps[0]);
return 1;
}
run_unary_@isa@_@func@_FLOAT(char **args, npy_intp const *dimensions, npy_intp const *steps)
{
#if defined @CHK@ && defined NPY_HAVE_SSE2_INTRINSICS
- if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(npy_float), @REGISTER_SIZE@)) {
+ if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(npy_float), sizeof(npy_float), @REGISTER_SIZE@)) {
@ISA@_@func@_FLOAT((npy_float*)args[1], (npy_float*)args[0], dimensions[0], steps[0]);
return 1;
}
run_unary_@isa@_sincos_FLOAT(char **args, npy_intp const *dimensions, npy_intp const *steps, NPY_TRIG_OP my_trig_op)
{
#if defined @CHK@ && defined NPY_HAVE_SSE2_INTRINSICS
- if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(npy_float), @REGISTER_SIZE@)) {
+ if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(npy_float), sizeof(npy_float), @REGISTER_SIZE@)) {
@ISA@_sincos_FLOAT((npy_float*)args[1], (npy_float*)args[0], dimensions[0], steps[0], my_trig_op);
return 1;
}
{
#if defined HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
#if !(defined(__clang__) && (__clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 1)))
- if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(npy_double), 64)) {
+ if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(npy_double), sizeof(npy_double), 64)) {
AVX512F_exp_DOUBLE((npy_double*)args[1], (npy_double*)args[0], dimensions[0], steps[0]);
return 1;
}
return 0;
}
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
+static NPY_INLINE void
+AVX512F_log_DOUBLE(npy_double *, npy_double *, const npy_intp n, const npy_intp stride);
+#endif
+static NPY_INLINE int
+run_unary_avx512f_log_DOUBLE(char **args, npy_intp const *dimensions, npy_intp const *steps)
+{
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
+#if !(defined(__clang__) && (__clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 1)))
+ if (IS_OUTPUT_BLOCKABLE_UNARY(sizeof(npy_double), sizeof(npy_double), 64)) {
+ AVX512F_log_DOUBLE((npy_double*)args[1], (npy_double*)args[0], dimensions[0], steps[0]);
+ return 1;
+ }
+ else
+ return 0;
+#endif
+#endif
+ return 0;
+}
+
/**begin repeat
* Float types
* #type = npy_float, npy_double, npy_longdouble#
* #TYPE = FLOAT, DOUBLE, LONGDOUBLE#
* #vector = 1, 1, 0#
+ * #VECTOR = NPY_SIMD, NPY_SIMD_F64, 0 #
*/
/**begin repeat1
- * #func = sqrt, absolute, negative, minimum, maximum#
- * #check = IS_BLOCKABLE_UNARY*3, IS_BLOCKABLE_REDUCE*2 #
- * #name = unary*3, unary_reduce*2#
+ * #func = absolute, negative, minimum, maximum#
+ * #check = IS_BLOCKABLE_UNARY*2, IS_BLOCKABLE_REDUCE*2 #
+ * #name = unary*2, unary_reduce*2#
*/
#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS
sse2_binary_scalar2_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2,
npy_intp n);
+#elif @VECTOR@
+
+static void
+simd_binary_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2,
+ npy_intp n);
+static void
+simd_binary_scalar1_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2,
+ npy_intp n);
+static void
+simd_binary_scalar2_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2,
+ npy_intp n);
+
#endif
static NPY_INLINE int
sse2_binary_@kind@_@TYPE@(op, ip1, ip2, n);
return 1;
}
+#elif @VECTOR@
+ @type@ * ip1 = (@type@ *)args[0];
+ @type@ * ip2 = (@type@ *)args[1];
+ @type@ * op = (@type@ *)args[2];
+ npy_intp n = dimensions[0];
+ /* argument one scalar */
+ if (IS_BLOCKABLE_BINARY_SCALAR1(sizeof(@type@), NPY_SIMD_WIDTH)) {
+ simd_binary_scalar1_@kind@_@TYPE@(op, ip1, ip2, n);
+ return 1;
+ }
+ /* argument two scalar */
+ else if (IS_BLOCKABLE_BINARY_SCALAR2(sizeof(@type@), NPY_SIMD_WIDTH)) {
+ simd_binary_scalar2_@kind@_@TYPE@(op, ip1, ip2, n);
+ return 1;
+ }
+ else if (IS_BLOCKABLE_BINARY(sizeof(@type@), NPY_SIMD_WIDTH)) {
+ simd_binary_@kind@_@TYPE@(op, ip1, ip2, n);
+ return 1;
+ }
#endif
return 0;
}
}
/**end repeat1**/
-static void
-sse2_sqrt_@TYPE@(@type@ * op, @type@ * ip, const npy_intp n)
-{
- /* align output to VECTOR_SIZE_BYTES bytes */
- LOOP_BLOCK_ALIGN_VAR(op, @type@, VECTOR_SIZE_BYTES) {
- op[i] = @scalarf@(ip[i]);
- }
- assert((npy_uintp)n < (VECTOR_SIZE_BYTES / sizeof(@type@)) ||
- npy_is_aligned(&op[i], VECTOR_SIZE_BYTES));
- if (npy_is_aligned(&ip[i], VECTOR_SIZE_BYTES)) {
- LOOP_BLOCKED(@type@, VECTOR_SIZE_BYTES) {
- @vtype@ d = @vpre@_load_@vsuf@(&ip[i]);
- @vpre@_store_@vsuf@(&op[i], @vpre@_sqrt_@vsuf@(d));
- }
- }
- else {
- LOOP_BLOCKED(@type@, VECTOR_SIZE_BYTES) {
- @vtype@ d = @vpre@_loadu_@vsuf@(&ip[i]);
- @vpre@_store_@vsuf@(&op[i], @vpre@_sqrt_@vsuf@(d));
- }
- }
- LOOP_BLOCKED_END {
- op[i] = @scalarf@(ip[i]);
- }
-}
-
-
static NPY_INLINE
@type@ scalar_abs_@type@(@type@ v)
{
__m512d t3,
__m512i index)
{
-
- __mmask8 lut_mask = _mm512_cmp_epi64_mask(index, _mm512_set1_epi64(15),
- _MM_CMPINT_GT);
+ __mmask8 lut_mask = _mm512_cmp_epi64_mask(
+ _mm512_and_epi64(_mm512_set1_epi64(0x10ULL), index),
+ _mm512_set1_epi64(0), _MM_CMPINT_GT);
__m512d res1 = _mm512_permutex2var_pd(t0, index, t1);
__m512d res2 = _mm512_permutex2var_pd(t2, index, t3);
return _mm512_mask_blend_pd(lut_mask, res1, res2);
}
+static NPY_INLINE NPY_GCC_OPT_3 NPY_GCC_TARGET_AVX512F __m512d
+avx512_permute_x8var_pd(__m512d t0, __m512d t1, __m512d t2, __m512d t3,
+ __m512d t4, __m512d t5, __m512d t6, __m512d t7,
+ __m512i index)
+{
+ __mmask8 lut_mask = _mm512_cmp_epi64_mask(
+ _mm512_and_epi64(_mm512_set1_epi64(0x20ULL), index),
+ _mm512_set1_epi64(0), _MM_CMPINT_GT);
+ __m512d res1 = avx512_permute_x4var_pd(t0, t1, t2, t3, index);
+ __m512d res2 = avx512_permute_x4var_pd(t4, t5, t6, t7, index);
+ return _mm512_mask_blend_pd(lut_mask, res1, res2);
+}
+
/**begin repeat
* #vsub = ps, pd#
* #type= npy_float, npy_double#
* #vtype = __m512, __m512d#
* #scale = 4, 8#
* #vindextype = __m512i, __m256i#
+ * #vindexload = _mm512_loadu_si512, _mm256_loadu_si256#
+ * #episize = epi32, epi64#
+ */
+
+/**begin repeat1
+ * #func = isnan, isfinite, isinf, signbit#
+ * #IMM8 = 0x81, 0x99, 0x18, 0x04#
+ * #is_finite = 0, 1, 0, 0#
+ * #is_signbit = 0, 0, 0, 1#
+ */
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
+static NPY_INLINE NPY_GCC_TARGET_AVX512_SKX void
+AVX512_SKX_@func@_@TYPE@(npy_bool* op, @type@* ip, const npy_intp array_size, const npy_intp steps)
+{
+ const npy_intp stride_ip = steps/(npy_intp)sizeof(@type@);
+ npy_intp num_remaining_elements = array_size;
+
+ @mask@ load_mask = avx512_get_full_load_mask_@vsuffix@();
+#if @is_signbit@
+ @vtype@ signbit = _mm512_set1_@vsuffix@(-0.0);
+#endif
+
+ /*
+ * Note: while generally indices are npy_intp, we ensure that our maximum
+ * index will fit in an int32 as a precondition for this function via
+ * IS_OUTPUT_BLOCKABLE_UNARY
+ */
+
+ npy_int32 index_ip[@num_lanes@];
+ for (npy_int32 ii = 0; ii < @num_lanes@; ii++) {
+ index_ip[ii] = ii*stride_ip;
+ }
+ @vindextype@ vindex_ip = @vindexload@((@vindextype@*)&index_ip[0]);
+ @vtype@ zeros_f = _mm512_setzero_@vsuffix@();
+ __m512i ones = _mm512_set1_@episize@(1);
+
+ while (num_remaining_elements > 0) {
+ if (num_remaining_elements < @num_lanes@) {
+ load_mask = avx512_get_partial_load_mask_@vsuffix@(
+ num_remaining_elements, @num_lanes@);
+ }
+ @vtype@ x1;
+ if (stride_ip == 1) {
+ x1 = avx512_masked_load_@vsuffix@(load_mask, ip);
+ }
+ else {
+ x1 = avx512_masked_gather_@vsuffix@(zeros_f, ip, vindex_ip, load_mask);
+ }
+#if @is_signbit@
+ x1 = _mm512_and_@vsuffix@(x1,signbit);
+#endif
+
+ @mask@ fpclassmask = _mm512_fpclass_@vsuffix@_mask(x1, @IMM8@);
+#if @is_finite@
+ fpclassmask = _mm512_knot(fpclassmask);
+#endif
+
+ __m128i out =_mm512_maskz_cvts@episize@_epi8(fpclassmask, ones);
+ _mm_mask_storeu_epi8(op, load_mask, out);
+
+ ip += @num_lanes@*stride_ip;
+ op += @num_lanes@;
+ num_remaining_elements -= @num_lanes@;
+ }
+}
+#endif
+/**end repeat1**/
+/**end repeat**/
+
+/**begin repeat
+ * #type = npy_float, npy_double#
+ * #TYPE = FLOAT, DOUBLE#
+ * #num_lanes = 16, 8#
+ * #vsuffix = ps, pd#
+ * #mask = __mmask16, __mmask8#
+ * #vtype1 = __m512, __m512d#
+ * #vtype2 = __m512i, __m256i#
+ * #scale = 4, 8#
+ * #vindextype = __m512i, __m256i#
* #vindexsize = 512, 256#
* #vindexload = _mm512_loadu_si512, _mm256_loadu_si256#
+ * #vtype2_load = _mm512_maskz_loadu_epi32, _mm256_maskz_loadu_epi32#
+ * #vtype2_gather = _mm512_mask_i32gather_epi32, _mm256_mmask_i32gather_epi32#
+ * #vtype2_store = _mm512_mask_storeu_epi32, _mm256_mask_storeu_epi32#
+ * #vtype2_scatter = _mm512_mask_i32scatter_epi32, _mm256_mask_i32scatter_epi32#
+ * #setzero = _mm512_setzero_epi32, _mm256_setzero_si256#
*/
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512_SKX_WITH_INTRINSICS && defined NPY_HAVE_SSE2_INTRINSICS
+static NPY_INLINE NPY_GCC_TARGET_AVX512_SKX void
+AVX512_SKX_ldexp_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps)
+{
+ const npy_intp stride_ip1 = steps[0]/(npy_intp)sizeof(@type@);
+ const npy_intp stride_ip2 = steps[1]/(npy_intp)sizeof(int);
+ const npy_intp stride_op = steps[2]/(npy_intp)sizeof(@type@);
+ const npy_intp array_size = dimensions[0];
+ npy_intp num_remaining_elements = array_size;
+ @type@* ip1 = (@type@*) args[0];
+ int* ip2 = (int*) args[1];
+ @type@* op = (@type@*) args[2];
+
+ @mask@ load_mask = avx512_get_full_load_mask_@vsuffix@();
+
+ /*
+ * Note: while generally indices are npy_intp, we ensure that our maximum index
+ * will fit in an int32 as a precondition for this function via
+ * IS_BINARY_SMALL_STEPS_AND_NOMEMOVERLAP
+ */
+
+ npy_int32 index_ip1[@num_lanes@], index_ip2[@num_lanes@], index_op[@num_lanes@];
+ for (npy_int32 ii = 0; ii < @num_lanes@; ii++) {
+ index_ip1[ii] = ii*stride_ip1;
+ index_ip2[ii] = ii*stride_ip2;
+ index_op[ii] = ii*stride_op;
+ }
+ @vindextype@ vindex_ip1 = @vindexload@((@vindextype@*)&index_ip1[0]);
+ @vindextype@ vindex_ip2 = @vindexload@((@vindextype@*)&index_ip2[0]);
+ @vindextype@ vindex_op = @vindexload@((@vindextype@*)&index_op[0]);
+ @vtype1@ zeros_f = _mm512_setzero_@vsuffix@();
+ @vtype2@ zeros = @setzero@();
+
+ while (num_remaining_elements > 0) {
+ if (num_remaining_elements < @num_lanes@) {
+ load_mask = avx512_get_partial_load_mask_@vsuffix@(
+ num_remaining_elements, @num_lanes@);
+ }
+ @vtype1@ x1;
+ @vtype2@ x2;
+ if (stride_ip1 == 1) {
+ x1 = avx512_masked_load_@vsuffix@(load_mask, ip1);
+ }
+ else {
+ x1 = avx512_masked_gather_@vsuffix@(zeros_f, ip1, vindex_ip1, load_mask);
+ }
+ if (stride_ip2 == 1) {
+ x2 = @vtype2_load@(load_mask, ip2);
+ }
+ else {
+ x2 = @vtype2_gather@(zeros, load_mask, vindex_ip2, ip2, 4);
+ }
+
+ @vtype1@ out = _mm512_scalef_@vsuffix@(x1, _mm512_cvtepi32_@vsuffix@(x2));
+
+ if (stride_op == 1) {
+ _mm512_mask_storeu_@vsuffix@(op, load_mask, out);
+ }
+ else {
+ /* scatter! */
+ _mm512_mask_i32scatter_@vsuffix@(op, load_mask, vindex_op, out, @scale@);
+ }
+
+ ip1 += @num_lanes@*stride_ip1;
+ ip2 += @num_lanes@*stride_ip2;
+ op += @num_lanes@*stride_op;
+ num_remaining_elements -= @num_lanes@;
+ }
+}
+
+static NPY_INLINE NPY_GCC_TARGET_AVX512_SKX void
+AVX512_SKX_frexp_@TYPE@(char **args, npy_intp const *dimensions, npy_intp const *steps)
+{
+ const npy_intp stride_ip1 = steps[0]/(npy_intp)sizeof(@type@);
+ const npy_intp stride_op1 = steps[1]/(npy_intp)sizeof(@type@);
+ const npy_intp stride_op2 = steps[2]/(npy_intp)sizeof(int);
+ const npy_intp array_size = dimensions[0];
+ npy_intp num_remaining_elements = array_size;
+ @type@* ip1 = (@type@*) args[0];
+ @type@* op1 = (@type@*) args[1];
+ int* op2 = (int*) args[2];
+
+ @mask@ load_mask = avx512_get_full_load_mask_@vsuffix@();
+
+ /*
+ * Note: while generally indices are npy_intp, we ensure that our maximum index
+ * will fit in an int32 as a precondition for this function via
+ * IS_BINARY_SMALL_STEPS_AND_NOMEMOVERLAP
+ */
+
+ npy_int32 index_ip1[@num_lanes@], index_op1[@num_lanes@], index_op2[@num_lanes@];
+ for (npy_int32 ii = 0; ii < @num_lanes@; ii++) {
+ index_ip1[ii] = ii*stride_ip1;
+ index_op1[ii] = ii*stride_op1;
+ index_op2[ii] = ii*stride_op2;
+ }
+ @vindextype@ vindex_ip1 = @vindexload@((@vindextype@*)&index_ip1[0]);
+ @vindextype@ vindex_op1 = @vindexload@((@vindextype@*)&index_op1[0]);
+ @vindextype@ vindex_op2 = @vindexload@((@vindextype@*)&index_op2[0]);
+ @vtype1@ zeros_f = _mm512_setzero_@vsuffix@();
+
+ while (num_remaining_elements > 0) {
+ if (num_remaining_elements < @num_lanes@) {
+ load_mask = avx512_get_partial_load_mask_@vsuffix@(
+ num_remaining_elements, @num_lanes@);
+ }
+ @vtype1@ x1;
+ if (stride_ip1 == 1) {
+ x1 = avx512_masked_load_@vsuffix@(load_mask, ip1);
+ }
+ else {
+ x1 = avx512_masked_gather_@vsuffix@(zeros_f, ip1, vindex_ip1, load_mask);
+ }
+
+ /*
+ * The x86 instructions vpgetmant and vpgetexp do not conform
+ * with NumPy's output for special floating points: NAN, +/-INF, +/-0.0
+ * We mask these values with spmask to avoid invalid exceptions.
+ */
+ @mask@ spmask =_mm512_knot(_mm512_fpclass_@vsuffix@_mask(
+ x1, 0b10011111));
+ @vtype1@ out1 = _mm512_maskz_getmant_@vsuffix@(
+ spmask, x1, _MM_MANT_NORM_p5_1, _MM_MANT_SIGN_src);
+ out1 = _mm512_mask_mov_@vsuffix@(x1, spmask, out1);
+ @vtype2@ out2 = _mm512_cvt@vsuffix@_epi32(
+ _mm512_maskz_add_@vsuffix@(spmask, _mm512_set1_@vsuffix@(1.0),
+ _mm512_maskz_getexp_@vsuffix@(spmask, x1)));
+ if (stride_op1 == 1) {
+ _mm512_mask_storeu_@vsuffix@(op1, load_mask, out1);
+ }
+ else {
+ _mm512_mask_i32scatter_@vsuffix@(op1, load_mask, vindex_op1, out1, @scale@);
+ }
+ if (stride_op2 == 1) {
+ @vtype2_store@(op2, load_mask, out2);
+ }
+ else {
+ @vtype2_scatter@(op2, load_mask, vindex_op2, out2, 4);
+ }
+
+ ip1 += @num_lanes@*stride_ip1;
+ op1 += @num_lanes@*stride_op1;
+ op2 += @num_lanes@*stride_op2;
+ num_remaining_elements -= @num_lanes@;
+ }
+}
+#endif
+
/**begin repeat1
* #func = maximum, minimum#
* #vectorf = max, min#
@vindextype@ vindex_ip1 = @vindexload@((@vindextype@*)&index_ip1[0]);
@vindextype@ vindex_ip2 = @vindexload@((@vindextype@*)&index_ip2[0]);
@vindextype@ vindex_op = @vindexload@((@vindextype@*)&index_op[0]);
- @vtype@ zeros_f = _mm512_setzero_@vsuffix@();
+ @vtype1@ zeros_f = _mm512_setzero_@vsuffix@();
while (num_remaining_elements > 0) {
if (num_remaining_elements < @num_lanes@) {
load_mask = avx512_get_partial_load_mask_@vsuffix@(
num_remaining_elements, @num_lanes@);
}
- @vtype@ x1, x2;
+ @vtype1@ x1, x2;
if (stride_ip1 == 1) {
x1 = avx512_masked_load_@vsuffix@(load_mask, ip1);
}
* this issue to conform with NumPy behaviour.
*/
@mask@ nan_mask = _mm512_cmp_@vsuffix@_mask(x1, x1, _CMP_NEQ_UQ);
- @vtype@ out = _mm512_@vectorf@_@vsuffix@(x1, x2);
+ @vtype1@ out = _mm512_@vectorf@_@vsuffix@(x1, x2);
out = _mm512_mask_blend_@vsuffix@(nan_mask, out, x1);
if (stride_op == 1) {
}
}
#endif
-/**end repeat**/
/**end repeat1**/
+/**end repeat**/
/**begin repeat
* #ISA = FMA, AVX512F#
*/
/**begin repeat1
- * #func = sqrt, absolute, square, reciprocal, rint, ceil, floor, trunc#
- * #vectorf = sqrt, abs, square, reciprocal, rint, ceil, floor, trunc#
- * #replace_0_with_1 = 0, 0, 0, 1, 0, 0, 0, 0#
+ * #func = rint, ceil, floor, trunc#
+ * #vectorf = rint, ceil, floor, trunc#
*/
#if defined @CHK@
npy_intp num_remaining_elements = array_size;
@vtype@ ones_f = _mm@vsize@_set1_ps(1.0f);
@mask@ load_mask = @isa@_get_full_load_mask_ps();
-#if @replace_0_with_1@
- @mask@ inv_load_mask = @isa@_invert_mask_ps(load_mask);
-#endif
-
/*
* Note: while generally indices are npy_intp, we ensure that our maximum index
* will fit in an int32 as a precondition for this function via
if (num_remaining_elements < num_lanes) {
load_mask = @isa@_get_partial_load_mask_ps(num_remaining_elements,
num_lanes);
-#if @replace_0_with_1@
- inv_load_mask = @isa@_invert_mask_ps(load_mask);
-#endif
}
@vtype@ x;
if (stride == 1) {
x = @isa@_masked_load_ps(load_mask, ip);
-#if @replace_0_with_1@
- /*
- * Replace masked elements with 1.0f to avoid divide by zero fp
- * exception in reciprocal
- */
- x = @isa@_set_masked_lanes_ps(x, ones_f, inv_load_mask);
-#endif
}
else {
x = @isa@_masked_gather_ps(ones_f, ip, vindex, load_mask);
*/
/**begin repeat1
- * #func = sqrt, absolute, square, reciprocal, rint, ceil, floor, trunc#
- * #vectorf = sqrt, abs, square, reciprocal, rint, ceil, floor, trunc#
- * #replace_0_with_1 = 0, 0, 0, 1, 0, 0, 0, 0#
+ * #func = rint, ceil, floor, trunc#
+ * #vectorf = rint, ceil, floor, trunc#
*/
#if defined @CHK@
const npy_int num_lanes = @BYTES@/(npy_intp)sizeof(npy_double);
npy_intp num_remaining_elements = array_size;
@mask@ load_mask = @isa@_get_full_load_mask_pd();
-#if @replace_0_with_1@
- @mask@ inv_load_mask = @isa@_invert_mask_pd(load_mask);
-#endif
@vtype@ ones_d = _mm@vsize@_set1_pd(1.0f);
/*
if (num_remaining_elements < num_lanes) {
load_mask = @isa@_get_partial_load_mask_pd(num_remaining_elements,
num_lanes);
-#if @replace_0_with_1@
- inv_load_mask = @isa@_invert_mask_pd(load_mask);
-#endif
}
@vtype@ x;
if (stride == 1) {
x = @isa@_masked_load_pd(load_mask, ip);
-#if @replace_0_with_1@
- /*
- * Replace masked elements with 1.0f to avoid divide by zero fp
- * exception in reciprocal
- */
- x = @isa@_set_masked_lanes_pd(x, ones_d, @castmask@(inv_load_mask));
-#endif
}
else {
x = @isa@_masked_gather_pd(ones_d, ip, vindex, @castmask@(load_mask));
* #vtype = __m256, __m512#
* #vsize = 256, 512#
* #BYTES = 32, 64#
+ * #NUM_LANES = 8, 16#
* #mask = __m256, __mmask16#
* #vsub = , _mask#
* #or_masks =_mm256_or_ps, _mm512_kor#
NPY_TRIG_OP my_trig_op)
{
const npy_intp stride = steps/(npy_intp)sizeof(npy_float);
- const npy_int num_lanes = @BYTES@/(npy_intp)sizeof(npy_float);
+ const npy_int num_lanes = @NUM_LANES@;
npy_float large_number = 71476.0625f;
if (my_trig_op == npy_compute_sin) {
large_number = 117435.992f;
num_lanes);
}
- @vtype@ x;
+ @vtype@ x_in;
if (stride == 1) {
- x = @isa@_masked_load_ps(load_mask, ip);
+ x_in = @isa@_masked_load_ps(load_mask, ip);
}
else {
- x = @isa@_masked_gather_ps(zero_f, ip, vindex, load_mask);
+ x_in = @isa@_masked_gather_ps(zero_f, ip, vindex, load_mask);
}
/*
* these numbers
*/
- glibc_mask = @isa@_in_range_mask(x, large_number,-large_number);
+ glibc_mask = @isa@_in_range_mask(x_in, large_number,-large_number);
glibc_mask = @and_masks@(load_mask, glibc_mask);
- nan_mask = _mm@vsize@_cmp_ps@vsub@(x, x, _CMP_NEQ_UQ);
- x = @isa@_set_masked_lanes_ps(x, zero_f, @or_masks@(nan_mask, glibc_mask));
+ nan_mask = _mm@vsize@_cmp_ps@vsub@(x_in, x_in, _CMP_NEQ_UQ);
+ @vtype@ x = @isa@_set_masked_lanes_ps(x_in, zero_f, @or_masks@(nan_mask, glibc_mask));
npy_int iglibc_mask = @mask_to_int@(glibc_mask);
if (iglibc_mask != @full_mask@) {
}
/* process elements using glibc for large elements */
- if (my_trig_op == npy_compute_cos) {
- for (int ii = 0, jj = 0; iglibc_mask != 0; ii++, jj += stride) {
- if (iglibc_mask & 0x01) {
- op[ii] = npy_cosf(ip[jj]);
+ if (iglibc_mask != 0) {
+ float NPY_DECL_ALIGNED(@BYTES@) ip_fback[@NUM_LANES@];
+ _mm@vsize@_store_ps(ip_fback, x_in);
+
+ if (my_trig_op == npy_compute_cos) {
+ for (int ii = 0; ii < num_lanes; ++ii, iglibc_mask >>= 1) {
+ if (iglibc_mask & 0x01) {
+ op[ii] = npy_cosf(ip_fback[ii]);
+ }
}
- iglibc_mask = iglibc_mask >> 1;
}
- }
- else {
- for (int ii = 0, jj = 0; iglibc_mask != 0; ii++, jj += stride) {
- if (iglibc_mask & 0x01) {
- op[ii] = npy_sinf(ip[jj]);
+ else {
+ for (int ii = 0; ii < num_lanes; ++ii, iglibc_mask >>= 1) {
+ if (iglibc_mask & 0x01) {
+ op[ii] = npy_sinf(ip_fback[ii]);
+ }
}
- iglibc_mask = iglibc_mask >> 1;
}
}
ip += num_lanes*stride;
#endif
#endif
+/*
+ * Vectorized implementation of log double using AVX512
+ * Reference:
+ * [1] Tang, Ping Tak Peter. Table-lookup algorithms for elementary functions
+ * and their error analysis. No. CONF-9106103-1. Argonne National Lab.,
+ * IL (USA), 1991.
+ * [2] Tang, Ping-Tak Peter. "Table-driven implementation of the logarithm
+ * function in IEEE floating-point arithmetic." ACM Transactions on
+ * Mathematical Software (TOMS) 16.4 (1990): 378-400.
+ * [3] Muller, Jean-Michel. "Elementary functions: algorithms and
+ * implementation." (2016).
+ * 1) if x = 0; return -INF
+ * 2) if x < 0; return NAN
+ * 3) if x is INF; return INF
+ * 4) if x is NAN; return NAN
+ * 5) if x on (1.0 - 0x1p-4, 1.0 + 0x1.09p-4), calling npy_log()
+ * 6) Range reduction:
+ * log(x) = log(2^m * z)
+ * = mln2 + log(z)
+ * 7) log(z) = log(z / c_k) + log(c_k);
+ * where c_k = 1 + k/64, k = 0,1,...,64
+ * s.t. |x - c_k| <= 1/128 when x on[1,2].
+ * 8) r = 2(x - c_k)/(x + c_k)
+ * log(x/c_k) = log((1 + r/2) / (1 - r/2))
+ * = p(r)
+ * = 2((r/2) + 1/3*(r/2)^3 + 1/5*(r/2)^5 + ...)
+ */
+#if defined HAVE_ATTRIBUTE_TARGET_AVX512F_WITH_INTRINSICS
+#if !(defined(__clang__) && (__clang_major__ < 10 || (__clang_major__ == 10 && __clang_minor__ < 1)))
+static NPY_GCC_OPT_3 NPY_GCC_TARGET_AVX512F void
+AVX512F_log_DOUBLE(npy_double * op,
+ npy_double * ip,
+ const npy_intp array_size,
+ const npy_intp steps)
+{
+ npy_intp num_remaining_elements = array_size;
+ const npy_intp stride = steps / (npy_intp)sizeof(npy_double);
+ const npy_int num_lanes = 64 / (npy_intp)sizeof(npy_double);
+ npy_int32 indexarr[8];
+ for (npy_int32 ii = 0; ii < 8; ii++) {
+ indexarr[ii] = ii*stride;
+ }
+
+ __m512d zeros_d = _mm512_set1_pd(0.0f);
+ __m512d ones_d = _mm512_set1_pd(1.0f);
+ __m512d mInf = _mm512_set1_pd(NPY_INFINITY);
+ __m512d mInv64 = (__m512d)(_mm512_set1_epi64(0x3f90000000000000));
+ __m512d mNeg_nan = _mm512_set1_pd(-NPY_NAN);
+ __m512d mNan = _mm512_set1_pd(NPY_NAN);
+ __m512d mNeg_inf = _mm512_set1_pd(-NPY_INFINITY);
+ __m512d mA1 = _mm512_set1_pd(NPY_TANG_LOG_A1);
+ __m512d mA2 = _mm512_set1_pd(NPY_TANG_LOG_A2);
+ __m512d mA3 = _mm512_set1_pd(NPY_TANG_LOG_A3);
+ __m512d mA4 = _mm512_set1_pd(NPY_TANG_LOG_A4);
+ __m512d mLN2HI = _mm512_set1_pd(NPY_TANG_LOG_LN2HI);
+ __m512d mLN2LO = _mm512_set1_pd(NPY_TANG_LOG_LN2LO);
+
+ __m512d mTo_glibc_min = _mm512_set1_pd(1.0 - 0x1p-4);
+ __m512d mTo_glibc_max = _mm512_set1_pd(1.0 + 0x1.09p-4);
+ __m256i vindex = _mm256_loadu_si256((__m256i*)&indexarr[0]);
+
+ /* Load lookup table data */
+ /**begin repeat
+ * #i = 0, 1, 2, 3, 4, 5, 6, 7#
+ */
+
+ __m512d mLUT_TOP_@i@ = _mm512_loadu_pd(&(LOG_TABLE_TOP[8*@i@]));
+ __m512d mLUT_TAIL_@i@ = _mm512_loadu_pd(&(LOG_TABLE_TAIL[8*@i@]));
+
+ /**end repeat**/
+
+ __mmask8 load_mask = avx512_get_full_load_mask_pd();
+ __mmask8 invalid_mask = avx512_get_partial_load_mask_pd(0, num_lanes);
+ __mmask8 divide_by_zero_mask = invalid_mask;
+
+ __mmask8 inf_mask, nan_mask, zero_mask, negx_mask, denormal_mask,
+ glibc_mask;
+
+ __m512d x_in;
+ while (num_remaining_elements > 0) {
+ if (num_remaining_elements < num_lanes) {
+ load_mask = avx512_get_partial_load_mask_pd(num_remaining_elements,
+ num_lanes);
+ }
+
+ if (1 == stride) {
+ x_in = avx512_masked_load_pd(load_mask, ip);
+ }
+ else {
+ x_in = avx512_masked_gather_pd(zeros_d, ip, vindex, load_mask);
+ }
+
+ /* call glibc when x on [1.0 - 0x1p-4, 1.0 + 0x1.09p-4] */
+ __mmask8 m1 = _mm512_cmp_pd_mask(x_in, mTo_glibc_max, _CMP_LT_OQ);
+ __mmask8 m2 = _mm512_cmp_pd_mask(x_in, mTo_glibc_min, _CMP_GT_OQ);
+ glibc_mask = m1 & m2;
+
+ if (glibc_mask != 0xFF) {
+ zero_mask = _mm512_cmp_pd_mask(x_in, zeros_d, _CMP_EQ_OQ);
+ inf_mask = _mm512_cmp_pd_mask(x_in, mInf, _CMP_EQ_OQ);
+ negx_mask = _mm512_cmp_pd_mask(x_in, zeros_d, _CMP_LT_OQ);
+ nan_mask = _mm512_cmp_pd_mask(x_in, x_in, _CMP_NEQ_UQ);
+
+ divide_by_zero_mask = divide_by_zero_mask | (zero_mask & load_mask);
+ invalid_mask = invalid_mask | negx_mask;
+
+ __m512d x = avx512_set_masked_lanes_pd(x_in, zeros_d, negx_mask);
+ __m512i ix = (__m512i)x;
+
+ /* Normalize x when it is denormal */
+ __m512i top12 = _mm512_and_epi64(ix,
+ _mm512_set1_epi64(0xfff0000000000000));
+ denormal_mask = _mm512_cmp_epi64_mask(top12, _mm512_set1_epi64(0),
+ _CMP_EQ_OQ);
+ denormal_mask = (~zero_mask) & denormal_mask;
+ ix = (__m512i)_mm512_mask_mul_pd(x, denormal_mask,
+ x, _mm512_set1_pd(0x1p52));
+ ix = _mm512_mask_sub_epi64(ix, denormal_mask,
+ ix, _mm512_set1_epi64(52ULL << 52));
+
+ /*
+ * x = 2^k * z; where z in range [1,2]
+ */
+ __m512i tmp = _mm512_sub_epi64(ix,
+ _mm512_set1_epi64(0x3ff0000000000000));
+ __m512i i = _mm512_and_epi64(_mm512_srai_epi64(tmp, 52 - 6),
+ _mm512_set1_epi64(0x3fULL));
+ __m512i ik = _mm512_srai_epi64(tmp, 52);
+ __m512d z = (__m512d)(_mm512_sub_epi64(ix, _mm512_and_epi64(tmp,
+ _mm512_set1_epi64(0xfff0000000000000))));
+ /* c = i/64 + 1 */
+ __m256i i_32 = _mm512_cvtepi64_epi32(i);
+ __m512d c = _mm512_fmadd_pd(_mm512_cvtepi32_pd(i_32), mInv64, ones_d);
+
+ /* u = 2 * (z - c) / (z + c) */
+ __m512d u = _mm512_div_pd(_mm512_sub_pd(z, c), _mm512_add_pd(z, c));
+ u = _mm512_mul_pd(_mm512_set1_pd(2.0), u);
+
+ /* v = u * u */
+ __m512d v = _mm512_mul_pd(u,u);
+
+ /* log(z/c) = u + u*v*(A1 + v*(A2 + v*(A3 + v*A4))) */
+ __m512d res = _mm512_fmadd_pd(v, mA4, mA3);
+ res = _mm512_fmadd_pd(v, res, mA2);
+ res = _mm512_fmadd_pd(v, res, mA1);
+ res = _mm512_mul_pd(v, res);
+ res = _mm512_fmadd_pd(u, res, u);
+
+ /* Load lookup table data */
+ __m512d c_hi = avx512_permute_x8var_pd(mLUT_TOP_0, mLUT_TOP_1,
+ mLUT_TOP_2, mLUT_TOP_3, mLUT_TOP_4, mLUT_TOP_5,
+ mLUT_TOP_6, mLUT_TOP_7, i);
+ __m512d c_lo = avx512_permute_x8var_pd(mLUT_TAIL_0, mLUT_TAIL_1,
+ mLUT_TAIL_2, mLUT_TAIL_3, mLUT_TAIL_4, mLUT_TAIL_5,
+ mLUT_TAIL_6, mLUT_TAIL_7, i);
+
+ /*
+ * log(x) = k * ln2_hi + c_hi +
+ * k * ln2_lo + c_lo +
+ * log(z/c)
+ */
+ __m256i ik_32 = _mm512_cvtepi64_epi32(ik);
+ __m512d k = _mm512_cvtepi32_pd(ik_32);
+ __m512d tt = _mm512_fmadd_pd(k, mLN2HI, c_hi);
+ __m512d tt2 = _mm512_fmadd_pd(k, mLN2LO, c_lo);
+ tt = _mm512_add_pd(tt, tt2);
+ res = _mm512_add_pd(tt, res);
+
+ /* return special cases */
+ res = avx512_set_masked_lanes_pd(res, mNan, nan_mask);
+ res = avx512_set_masked_lanes_pd(res, mNeg_nan, negx_mask);
+ res = avx512_set_masked_lanes_pd(res, mNeg_inf, zero_mask);
+ res = avx512_set_masked_lanes_pd(res, mInf, inf_mask);
+
+ _mm512_mask_storeu_pd(op, load_mask, res);
+ }
+
+ /* call glibc's log func when x around 1.0f */
+ if (glibc_mask != 0) {
+ double NPY_DECL_ALIGNED(64) ip_fback[8];
+ _mm512_store_pd(ip_fback, x_in);
+
+ for (int ii = 0; ii < 8; ++ii, glibc_mask >>= 1) {
+ if (glibc_mask & 0x01) {
+ op[ii] = npy_log(ip_fback[ii]);
+ }
+ }
+ }
+ ip += num_lanes * stride;
+ op += num_lanes;
+ num_remaining_elements -= num_lanes;
+ }
+
+ if (invalid_mask) {
+ npy_set_floatstatus_invalid();
+ }
+ if (divide_by_zero_mask) {
+ npy_set_floatstatus_divbyzero();
+ }
+}
+#endif
+#endif
+
/**begin repeat
* #TYPE = CFLOAT, CDOUBLE#
* #type = npy_float, npy_double#
/**end repeat**/
#undef VECTOR_SIZE_BYTES
+#else /* NPY_HAVE_SSE2_INTRINSICS */
+
+/**begin repeat
+ * #type = npy_float, npy_double#
+ * #TYPE = FLOAT, DOUBLE#
+ * #sfx = f32, f64#
+ * #CHK = , _F64#
+ */
+
+#if NPY_SIMD@CHK@
+
+/**begin repeat1
+* Arithmetic
+* # kind = add, subtract, multiply, divide#
+* # OP = +, -, *, /#
+* # VOP = add, sub, mul, div#
+*/
+
+static void
+simd_binary_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, npy_intp n)
+{
+ LOOP_BLOCK_ALIGN_VAR(op, @type@, NPY_SIMD_WIDTH) {
+ op[i] = ip1[i] @OP@ ip2[i];
+ }
+ /* lots of specializations, to squeeze out max performance */
+ if (ip1 == ip2) {
+ LOOP_BLOCKED(@type@, NPY_SIMD_WIDTH) {
+ npyv_@sfx@ a = npyv_load_@sfx@(&ip1[i]);
+ npyv_@sfx@ c = npyv_@VOP@_@sfx@(a, a);
+ npyv_store_@sfx@(&op[i], c);
+ }
+ }
+ else {
+ LOOP_BLOCKED(@type@, NPY_SIMD_WIDTH) {
+ npyv_@sfx@ a = npyv_load_@sfx@(&ip1[i]);
+ npyv_@sfx@ b = npyv_load_@sfx@(&ip2[i]);
+ npyv_@sfx@ c = npyv_@VOP@_@sfx@(a, b);
+ npyv_store_@sfx@(&op[i], c);
+ }
+ }
+ LOOP_BLOCKED_END {
+ op[i] = ip1[i] @OP@ ip2[i];
+ }
+}
-#endif /* NPY_HAVE_SSE2_INTRINSICS */
+static void
+simd_binary_scalar1_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, npy_intp n)
+{
+ const npyv_@sfx@ v1 = npyv_setall_@sfx@(ip1[0]);
+ LOOP_BLOCK_ALIGN_VAR(op, @type@, NPY_SIMD_WIDTH) {
+ op[i] = ip1[0] @OP@ ip2[i];
+ }
+ LOOP_BLOCKED(@type@, NPY_SIMD_WIDTH) {
+ npyv_@sfx@ v2 = npyv_load_@sfx@(&ip2[i]);
+ npyv_@sfx@ v3 = npyv_@VOP@_@sfx@(v1, v2);
+ npyv_store_@sfx@(&op[i], v3);
+ }
+ LOOP_BLOCKED_END {
+ op[i] = ip1[0] @OP@ ip2[i];
+ }
+}
+static void
+simd_binary_scalar2_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, npy_intp n)
+{
+ const npyv_@sfx@ v2 = npyv_setall_@sfx@(ip2[0]);
+ LOOP_BLOCK_ALIGN_VAR(op, @type@, NPY_SIMD_WIDTH) {
+ op[i] = ip1[i] @OP@ ip2[0];
+ }
+ LOOP_BLOCKED(@type@, NPY_SIMD_WIDTH) {
+ npyv_@sfx@ v1 = npyv_load_@sfx@(&ip1[i]);
+ npyv_@sfx@ v3 = npyv_@VOP@_@sfx@(v1, v2);
+ npyv_store_@sfx@(&op[i], v3);
+ }
+ LOOP_BLOCKED_END {
+ op[i] = ip1[i] @OP@ ip2[0];
+ }
+}
+/**end repeat1**/
+#endif /* NPY_SIMD@CHK@ */
+/**end repeat**/
+#endif
#endif
NPY_END_THREADS;
}
- return NpyIter_Deallocate(iter);
+ /*
+ * Currently `innerloop` may leave an error set, in this case
+ * NpyIter_Deallocate will always return an error as well.
+ */
+ if (NpyIter_Deallocate(iter) == NPY_FAIL) {
+ return -1;
+ }
+ return 0;
}
/*
switch(ufunc->identity) {
case PyUFunc_One:
*reorderable = 1;
- return PyInt_FromLong(1);
+ return PyLong_FromLong(1);
case PyUFunc_Zero:
*reorderable = 1;
- return PyInt_FromLong(0);
+ return PyLong_FromLong(0);
case PyUFunc_MinusOne:
*reorderable = 1;
- return PyInt_FromLong(-1);
+ return PyLong_FromLong(-1);
case PyUFunc_ReorderableNone:
*reorderable = 1;
}
/*
* Figure out the number of iteration dimensions, which
- * is the broadcast result of all the input non-core
- * dimensions.
+ * is the broadcast result of all the non-core dimensions.
+ * (We do allow outputs to broadcast inputs currently, if they are given.
+ * This is in line with what normal ufuncs do.)
*/
broadcast_ndim = 0;
- for (i = 0; i < nin; ++i) {
+ for (i = 0; i < nop; ++i) {
+ if (op[i] == NULL) {
+ continue;
+ }
int n = PyArray_NDIM(op[i]) - op_core_num_dims[i];
if (n > broadcast_ndim) {
broadcast_ndim = n;
}
}
- /* Any output core dimensions shape should be ignored */
+ /*
+ * Any output core dimensions shape should be ignored, so we add
+ * it as a Reduce dimension (which can be broadcast with the rest).
+ * These will be removed before the actual iteration for gufuncs.
+ */
for (idim = broadcast_ndim; idim < iter_ndim; ++idim) {
- op_axes_arrays[i][idim] = -1;
+ op_axes_arrays[i][idim] = NPY_ITER_REDUCTION_AXIS(-1);
}
/* Except for when it belongs to this output */
*/
_ufunc_setup_flags(ufunc, NPY_ITER_COPY | NPY_UFUNC_DEFAULT_INPUT_FLAGS,
NPY_ITER_UPDATEIFCOPY |
- NPY_ITER_READWRITE |
+ NPY_ITER_WRITEONLY |
NPY_UFUNC_DEFAULT_OUTPUT_FLAGS,
op_flags);
/* For the generalized ufunc, we get the loop right away too */
iter_flags = ufunc->iter_flags |
NPY_ITER_MULTI_INDEX |
NPY_ITER_REFS_OK |
- NPY_ITER_REDUCE_OK |
NPY_ITER_ZEROSIZE_OK |
NPY_ITER_COPY_IF_OVERLAP;
goto fail;
}
- /* Check whether any errors occurred during the loop */
+ /*
+ * Check whether any errors occurred during the loop. The loops should
+ * indicate this in retval, but since the inner-loop currently does not
+ * report errors, this does not happen in all branches (at this time).
+ */
if (PyErr_Occurred() ||
- _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) {
+ _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) {
retval = -1;
goto fail;
}
void **out_innerloopdata)
{
int i;
- PyUFunc_Loop1d *funcdata;
NPY_UF_DBG_PRINT1("Getting binary op function for type number %d\n",
*otype);
/* If the type is custom and there are userloops, search for it here */
if (ufunc->userloops != NULL && PyTypeNum_ISUSERDEF(*otype)) {
PyObject *key, *obj;
- key = PyInt_FromLong(*otype);
+ key = PyLong_FromLong(*otype);
if (key == NULL) {
return -1;
}
return -1;
}
else if (obj != NULL) {
- funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
+ PyUFunc_Loop1d *funcdata = PyCapsule_GetPointer(obj, NULL);
+ if (funcdata == NULL) {
+ return -1;
+ }
while (funcdata != NULL) {
int *types = funcdata->arg_types;
result = PyUFunc_ReduceWrapper(arr, out, wheremask, dtype, dtype,
NPY_UNSAFE_CASTING,
axis_flags, reorderable,
- keepdims, 0,
+ keepdims,
initial,
reduce_loop,
ufunc, buffersize, ufunc_name, errormask);
finish:
Py_XDECREF(op_dtypes[0]);
- NpyIter_Deallocate(iter);
- NpyIter_Deallocate(iter_inner);
+ int res = 0;
+ if (!NpyIter_Deallocate(iter)) {
+ res = -1;
+ }
+ if (!NpyIter_Deallocate(iter_inner)) {
+ res = -1;
+ }
+ if (res < 0) {
+ Py_DECREF(out);
+ return NULL;
+ }
return (PyObject *)out;
finish:
Py_XDECREF(op_dtypes[0]);
- NpyIter_Deallocate(iter);
+ if (!NpyIter_Deallocate(iter)) {
+ Py_DECREF(out);
+ return NULL;
+ }
return (PyObject *)out;
Py_XDECREF(op_dtypes[0]);
NpyIter_Deallocate(iter);
-
return NULL;
}
if (res == NULL) {
return NULL;
}
- PyList_SET_ITEM(res, 0, PyInt_FromLong(NPY_BUFSIZE));
- PyList_SET_ITEM(res, 1, PyInt_FromLong(UFUNC_ERR_DEFAULT));
+ PyList_SET_ITEM(res, 0, PyLong_FromLong(NPY_BUFSIZE));
+ PyList_SET_ITEM(res, 1, PyLong_FromLong(UFUNC_ERR_DEFAULT));
PyList_SET_ITEM(res, 2, Py_None); Py_INCREF(Py_None);
return res;
}
return -1;
}
- key = PyInt_FromLong((long) user_dtype->type_num);
+ key = PyLong_FromLong((long) user_dtype->type_num);
if (key == NULL) {
return -1;
}
result = -1;
}
else {
- PyUFunc_Loop1d *current;
int cmp = 1;
- current = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(cobj);
+ PyUFunc_Loop1d *current = PyCapsule_GetPointer(cobj, NULL);
+ if (current == NULL) {
+ result = -1;
+ goto done;
+ }
while (current != NULL) {
cmp = cmp_arg_types(current->arg_types,
arg_typenums, ufunc->nargs);
}
}
+done:
PyArray_free(arg_typenums);
Py_DECREF(key);
if (ufunc->userloops == NULL) {
ufunc->userloops = PyDict_New();
}
- key = PyInt_FromLong((long) usertype);
+ key = PyLong_FromLong((long) usertype);
if (key == NULL) {
return -1;
}
}
/* If it's not there, then make one and return. */
else if (cobj == NULL) {
- cobj = NpyCapsule_FromVoidPtr((void *)funcdata, _loop1d_list_free);
+ cobj = PyCapsule_New((void *)funcdata, NULL, _loop1d_list_free);
if (cobj == NULL) {
goto fail;
}
* is exactly like this one, then just replace.
* Otherwise insert.
*/
- current = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(cobj);
+ current = PyCapsule_GetPointer(cobj, NULL);
+ if (current == NULL) {
+ goto fail;
+ }
while (current != NULL) {
cmp = cmp_arg_types(current->arg_types, newtypes, ufunc->nargs);
if (cmp >= 0) {
static PyObject *
ufunc_repr(PyUFuncObject *ufunc)
{
- return PyUString_FromFormat("<ufunc '%s'>", ufunc->name);
+ return PyUnicode_FromFormat("<ufunc '%s'>", ufunc->name);
}
static int
static PyObject *
ufunc_outer(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds)
{
- int i;
int errval;
PyObject *override = NULL;
PyObject *ret;
PyArrayObject *ap1 = NULL, *ap2 = NULL, *ap_new = NULL;
PyObject *new_args, *tmp;
- PyObject *shape1, *shape2, *newshape;
static PyObject *_numpy_matrix;
"matrix",
&_numpy_matrix);
+ const char *matrix_deprecation_msg = (
+ "%s.outer() was passed a numpy matrix as %s argument. "
+ "Special handling of matrix is deprecated and will result in an "
+ "error in most cases. Please convert the matrix to a NumPy "
+ "array to retain the old behaviour. You can use `matrix.A` "
+ "to achieve this.");
+
if (PyObject_IsInstance(tmp, _numpy_matrix)) {
+ /* DEPRECATED 2020-05-13, NumPy 1.20 */
+ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+ matrix_deprecation_msg, ufunc->name, "first") < 0) {
+ return NULL;
+ }
ap1 = (PyArrayObject *) PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0);
}
else {
return NULL;
}
if (PyObject_IsInstance(tmp, _numpy_matrix)) {
+ /* DEPRECATED 2020-05-13, NumPy 1.20 */
+ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+ matrix_deprecation_msg, ufunc->name, "second") < 0) {
+ Py_DECREF(ap1);
+ return NULL;
+ }
ap2 = (PyArrayObject *) PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0);
}
else {
Py_DECREF(ap1);
return NULL;
}
- /* Construct new shape tuple */
- shape1 = PyTuple_New(PyArray_NDIM(ap1));
- if (shape1 == NULL) {
- goto fail;
- }
- for (i = 0; i < PyArray_NDIM(ap1); i++) {
- PyTuple_SET_ITEM(shape1, i,
- PyLong_FromLongLong((npy_longlong)PyArray_DIMS(ap1)[i]));
- }
- shape2 = PyTuple_New(PyArray_NDIM(ap2));
- for (i = 0; i < PyArray_NDIM(ap2); i++) {
- PyTuple_SET_ITEM(shape2, i, PyInt_FromLong((long) 1));
+ /* Construct new shape from ap1 and ap2 and then reshape */
+ PyArray_Dims newdims;
+ npy_intp newshape[NPY_MAXDIMS];
+ newdims.len = PyArray_NDIM(ap1) + PyArray_NDIM(ap2);
+ newdims.ptr = newshape;
+
+ if (newdims.len > NPY_MAXDIMS) {
+ PyErr_Format(PyExc_ValueError,
+ "maximum supported dimension for an ndarray is %d, but "
+ "`%s.outer()` result would have %d.",
+ NPY_MAXDIMS, ufunc->name, newdims.len);
+ return NPY_FAIL;
}
- if (shape2 == NULL) {
- Py_DECREF(shape1);
+ if (newdims.ptr == NULL) {
goto fail;
}
- newshape = PyNumber_Add(shape1, shape2);
- Py_DECREF(shape1);
- Py_DECREF(shape2);
- if (newshape == NULL) {
- goto fail;
+ memcpy(newshape, PyArray_DIMS(ap1), PyArray_NDIM(ap1) * sizeof(npy_intp));
+ for (int i = PyArray_NDIM(ap1); i < newdims.len; i++) {
+ newshape[i] = 1;
}
- ap_new = (PyArrayObject *)PyArray_Reshape(ap1, newshape);
- Py_DECREF(newshape);
+
+ ap_new = (PyArrayObject *)PyArray_Newshape(ap1, &newdims, NPY_CORDER);
if (ap_new == NULL) {
goto fail;
}
+ if (PyArray_NDIM(ap_new) != newdims.len ||
+ !PyArray_CompareLists(PyArray_DIMS(ap_new), newshape, newdims.len)) {
+ PyErr_Format(PyExc_TypeError,
+ "%s.outer() called with ndarray-subclass of type '%s' "
+ "which modified its shape after a reshape. `outer()` relies "
+ "on reshaping the inputs and is for example not supported for "
+ "the 'np.matrix' class (the usage of matrix is generally "
+ "discouraged). "
+ "To work around this issue, please convert the inputs to "
+ "numpy arrays.",
+ ufunc->name, Py_TYPE(ap_new)->tp_name);
+ goto fail;
+ }
+
new_args = Py_BuildValue("(OO)", ap_new, ap2);
Py_DECREF(ap1);
Py_DECREF(ap2);
return ret;
}
+
static PyObject *
ufunc_get_doc(PyUFuncObject *ufunc)
{
* introspection on name and nin + nout to automate the first part
* of it the doc string shouldn't need the calling convention
*/
- doc = PyObject_CallFunctionObjArgs(
- _sig_formatter, (PyObject *)ufunc, NULL);
+ doc = PyObject_CallFunctionObjArgs(_sig_formatter,
+ (PyObject *)ufunc, NULL);
if (doc == NULL) {
return NULL;
}
if (ufunc->doc != NULL) {
- PyUString_ConcatAndDel(&doc,
- PyUString_FromFormat("\n\n%s", ufunc->doc));
+ Py_SETREF(doc, PyUnicode_FromFormat("%S\n\n%s", doc, ufunc->doc));
}
return doc;
}
+
static PyObject *
ufunc_get_nin(PyUFuncObject *ufunc)
{
- return PyInt_FromLong(ufunc->nin);
+ return PyLong_FromLong(ufunc->nin);
}
static PyObject *
ufunc_get_nout(PyUFuncObject *ufunc)
{
- return PyInt_FromLong(ufunc->nout);
+ return PyLong_FromLong(ufunc->nout);
}
static PyObject *
ufunc_get_nargs(PyUFuncObject *ufunc)
{
- return PyInt_FromLong(ufunc->nargs);
+ return PyLong_FromLong(ufunc->nargs);
}
static PyObject *
ufunc_get_ntypes(PyUFuncObject *ufunc)
{
- return PyInt_FromLong(ufunc->ntypes);
+ return PyLong_FromLong(ufunc->ntypes);
}
static PyObject *
t[ni + 2 + j] = _typecharfromnum(ufunc->types[n]);
n++;
}
- str = PyUString_FromStringAndSize(t, no + ni + 2);
+ str = PyUnicode_FromStringAndSize(t, no + ni + 2);
PyList_SET_ITEM(list, k, str);
}
PyArray_free(t);
static PyObject *
ufunc_get_name(PyUFuncObject *ufunc)
{
- return PyUString_FromString(ufunc->name);
+ return PyUnicode_FromString(ufunc->name);
}
static PyObject *
if (!ufunc->core_enabled) {
Py_RETURN_NONE;
}
- return PyUString_FromString(ufunc->core_signature);
+ return PyUnicode_FromString(ufunc->core_signature);
}
#undef _typecharfromnum
{
switch (casting) {
case NPY_NO_CASTING:
- return PyUString_FromString("no");
+ return PyUnicode_FromString("no");
case NPY_EQUIV_CASTING:
- return PyUString_FromString("equiv");
+ return PyUnicode_FromString("equiv");
case NPY_SAFE_CASTING:
- return PyUString_FromString("safe");
+ return PyUnicode_FromString("safe");
case NPY_SAME_KIND_CASTING:
- return PyUString_FromString("same_kind");
+ return PyUnicode_FromString("same_kind");
case NPY_UNSAFE_CASTING:
- return PyUString_FromString("unsafe");
+ return PyUnicode_FromString("unsafe");
default:
- return PyInt_FromLong(casting);
+ return PyLong_FromLong(casting);
}
}
return 0;
}
-/*
- * Returns a new reference to type if it is already NBO, otherwise
- * returns a copy converted to NBO.
- */
-static PyArray_Descr *
-ensure_dtype_nbo(PyArray_Descr *type)
-{
- if (PyArray_ISNBO(type->byteorder)) {
- Py_INCREF(type);
- return type;
- }
- else {
- return PyArray_DescrNewByteorder(type, NPY_NATIVE);
- }
-}
/*UFUNC_API
*
void **out_innerloopdata)
{
npy_intp i, nin = ufunc->nin, j, nargs = nin + ufunc->nout;
- PyUFunc_Loop1d *funcdata;
/* Use this to try to avoid repeating the same userdef loop search */
int last_userdef = -1;
last_userdef = type_num;
- key = PyInt_FromLong(type_num);
+ key = PyLong_FromLong(type_num);
if (key == NULL) {
return -1;
}
else if (obj == NULL) {
continue;
}
- for (funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
- funcdata != NULL;
- funcdata = funcdata->next) {
+ PyUFunc_Loop1d *funcdata = PyCapsule_GetPointer(obj, NULL);
+ if (funcdata == NULL) {
+ return -1;
+ }
+ for (; funcdata != NULL; funcdata = funcdata->next) {
int *types = funcdata->arg_types;
for (j = 0; j < nargs; ++j) {
char *out_err_dst_typecode)
{
npy_intp i, nop = self->nin + self->nout;
- PyUFunc_Loop1d *funcdata;
/* Use this to try to avoid repeating the same userdef loop search */
int last_userdef = -1;
last_userdef = type_num;
- key = PyInt_FromLong(type_num);
+ key = PyLong_FromLong(type_num);
if (key == NULL) {
return -1;
}
else if (obj == NULL) {
continue;
}
- for (funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
- funcdata != NULL;
- funcdata = funcdata->next) {
+ PyUFunc_Loop1d *funcdata = PyCapsule_GetPointer(obj, NULL);
+ if (funcdata == NULL) {
+ return -1;
+ }
+ for (; funcdata != NULL; funcdata = funcdata->next) {
int *types = funcdata->arg_types;
switch (ufunc_loop_matches(self, op,
input_casting, output_casting,
PyArray_Descr **out_dtype)
{
int i, j, nin = self->nin, nop = nin + self->nout;
- PyUFunc_Loop1d *funcdata;
/* Use this to try to avoid repeating the same userdef loop search */
int last_userdef = -1;
last_userdef = type_num;
- key = PyInt_FromLong(type_num);
+ key = PyLong_FromLong(type_num);
if (key == NULL) {
return -1;
}
continue;
}
- for (funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
- funcdata != NULL;
- funcdata = funcdata->next) {
+ PyUFunc_Loop1d *funcdata = PyCapsule_GetPointer(obj, NULL);
+ if (funcdata == NULL) {
+ return -1;
+ }
+ for (; funcdata != NULL; funcdata = funcdata->next) {
int *types = funcdata->arg_types;
int matched = 1;
int nin, nout, i, nargs;
PyUFunc_PyFuncData *fdata;
PyUFuncObject *self;
- char *fname, *str, *types, *doc;
+ const char *fname = NULL;
+ char *str, *types, *doc;
Py_ssize_t fname_len = -1;
void * ptr, **data;
int offset[2];
pyname = PyObject_GetAttrString(function, "__name__");
if (pyname) {
- (void) PyString_AsStringAndSize(pyname, &fname, &fname_len);
+ fname = PyUnicode_AsUTF8AndSize(pyname, &fname_len);
}
- if (PyErr_Occurred()) {
+ if (fname == NULL) {
+ PyErr_Clear();
fname = "?";
fname_len = 1;
- PyErr_Clear();
}
/*
add_newdoc_ufunc(PyObject *NPY_UNUSED(dummy), PyObject *args)
{
PyUFuncObject *ufunc;
- PyObject *str, *tmp;
- char *docstr, *newdocstr;
-
+ PyObject *str;
if (!PyArg_ParseTuple(args, "O!O!:_add_newdoc_ufunc", &PyUFunc_Type, &ufunc,
&PyUnicode_Type, &str)) {
return NULL;
}
- tmp = PyUnicode_AsUTF8String(str);
- if (tmp == NULL) {
+ if (ufunc->doc != NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "Cannot change docstring of ufunc with non-NULL docstring");
return NULL;
}
- docstr = PyBytes_AS_STRING(tmp);
- if (NULL != ufunc->doc) {
- PyErr_SetString(PyExc_ValueError,
- "Cannot change docstring of ufunc with non-NULL docstring");
- Py_DECREF(tmp);
+ PyObject *tmp = PyUnicode_AsUTF8String(str);
+ if (tmp == NULL) {
return NULL;
}
+ char *docstr = PyBytes_AS_STRING(tmp);
/*
* This introduces a memory leak, as the memory allocated for the doc
* this should not be a problem since the user would have to
* repeatedly create, document, and throw away ufuncs.
*/
- newdocstr = malloc(strlen(docstr) + 1);
+ char *newdocstr = malloc(strlen(docstr) + 1);
+ if (!newdocstr) {
+ Py_DECREF(tmp);
+ return PyErr_NoMemory();
+ }
strcpy(newdocstr, docstr);
ufunc->doc = newdocstr;
NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_ufunc = NULL;
NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_pyvals_name = NULL;
-/* intern some strings used in ufuncs */
+/* intern some strings used in ufuncs, returns 0 on success */
static int
intern_strings(void)
{
- npy_um_str_out = PyUString_InternFromString("out");
- npy_um_str_where = PyUString_InternFromString("where");
- npy_um_str_axes = PyUString_InternFromString("axes");
- npy_um_str_axis = PyUString_InternFromString("axis");
- npy_um_str_keepdims = PyUString_InternFromString("keepdims");
- npy_um_str_casting = PyUString_InternFromString("casting");
- npy_um_str_order = PyUString_InternFromString("order");
- npy_um_str_dtype = PyUString_InternFromString("dtype");
- npy_um_str_subok = PyUString_InternFromString("subok");
- npy_um_str_signature = PyUString_InternFromString("signature");
- npy_um_str_sig = PyUString_InternFromString("sig");
- npy_um_str_extobj = PyUString_InternFromString("extobj");
- npy_um_str_array_prepare = PyUString_InternFromString("__array_prepare__");
- npy_um_str_array_wrap = PyUString_InternFromString("__array_wrap__");
- npy_um_str_array_finalize = PyUString_InternFromString("__array_finalize__");
- npy_um_str_ufunc = PyUString_InternFromString("__array_ufunc__");
- npy_um_str_pyvals_name = PyUString_InternFromString(UFUNC_PYVALS_NAME);
-
- return npy_um_str_out && npy_um_str_subok && npy_um_str_array_prepare &&
- npy_um_str_array_wrap && npy_um_str_array_finalize && npy_um_str_ufunc;
+ if (!(npy_um_str_out = PyUnicode_InternFromString("out"))) return -1;
+ if (!(npy_um_str_where = PyUnicode_InternFromString("where"))) return -1;
+ if (!(npy_um_str_axes = PyUnicode_InternFromString("axes"))) return -1;
+ if (!(npy_um_str_axis = PyUnicode_InternFromString("axis"))) return -1;
+ if (!(npy_um_str_keepdims = PyUnicode_InternFromString("keepdims"))) return -1;
+ if (!(npy_um_str_casting = PyUnicode_InternFromString("casting"))) return -1;
+ if (!(npy_um_str_order = PyUnicode_InternFromString("order"))) return -1;
+ if (!(npy_um_str_dtype = PyUnicode_InternFromString("dtype"))) return -1;
+ if (!(npy_um_str_subok = PyUnicode_InternFromString("subok"))) return -1;
+ if (!(npy_um_str_signature = PyUnicode_InternFromString("signature"))) return -1;
+ if (!(npy_um_str_sig = PyUnicode_InternFromString("sig"))) return -1;
+ if (!(npy_um_str_extobj = PyUnicode_InternFromString("extobj"))) return -1;
+ if (!(npy_um_str_array_prepare = PyUnicode_InternFromString("__array_prepare__"))) return -1;
+ if (!(npy_um_str_array_wrap = PyUnicode_InternFromString("__array_wrap__"))) return -1;
+ if (!(npy_um_str_array_finalize = PyUnicode_InternFromString("__array_finalize__"))) return -1;
+ if (!(npy_um_str_ufunc = PyUnicode_InternFromString("__array_ufunc__"))) return -1;
+ if (!(npy_um_str_pyvals_name = PyUnicode_InternFromString(UFUNC_PYVALS_NAME))) return -1;
+ return 0;
}
/* Setup the umath part of the module */
PyDict_SetItemString(d, "conj", s);
PyDict_SetItemString(d, "mod", s2);
- if (!intern_strings()) {
+ if (intern_strings() < 0) {
PyErr_SetString(PyExc_RuntimeError,
"cannot intern umath strings while initializing _multiarray_umath.");
return -1;
np.float32,0x3f476b69,0xbe7fc2c6,4
np.float32,0x3f4884e8,0xbe7a214a,4
np.float32,0x3f486945,0xbe7aae76,4
+#float64
+## +ve denormal ##
+np.float64,0x0000000000000001,0xc0874385446d71c3,1
+np.float64,0x0001000000000000,0xc086395a2079b70c,1
+np.float64,0x000fffffffffffff,0xc086232bdd7abcd2,1
+np.float64,0x0007ad63e2168cb6,0xc086290bc0b2980f,1
+## -ve denormal ##
+np.float64,0x8000000000000001,0xfff8000000000001,1
+np.float64,0x8001000000000000,0xfff8000000000001,1
+np.float64,0x800fffffffffffff,0xfff8000000000001,1
+np.float64,0x8007ad63e2168cb6,0xfff8000000000001,1
+## +/-0.0f, MAX, MIN##
+np.float64,0x0000000000000000,0xfff0000000000000,1
+np.float64,0x8000000000000000,0xfff0000000000000,1
+np.float64,0x7fefffffffffffff,0x40862e42fefa39ef,1
+np.float64,0xffefffffffffffff,0xfff8000000000001,1
+## near 1.0f ##
+np.float64,0x3ff0000000000000,0x0000000000000000,1
+np.float64,0x3fe8000000000000,0xbfd269621134db92,1
+np.float64,0x3ff0000000000001,0x3cafffffffffffff,1
+np.float64,0x3ff0000020000000,0x3e7fffffe000002b,1
+np.float64,0x3ff0000000000001,0x3cafffffffffffff,1
+np.float64,0x3fefffffe0000000,0xbe70000008000005,1
+np.float64,0x3fefffffffffffff,0xbca0000000000000,1
+## random numbers ##
+np.float64,0x02500186f3d9da56,0xc0855b8abf135773,1
+np.float64,0x09200815a3951173,0xc082ff1ad7131bdc,1
+np.float64,0x0da029623b0243d4,0xc0816fc994695bb5,1
+np.float64,0x48703b8ac483a382,0x40579213a313490b,1
+np.float64,0x09207b74c87c9860,0xc082fee20ff349ef,1
+np.float64,0x62c077698e8df947,0x407821c996d110f0,1
+np.float64,0x2350b45e87c3cfb0,0xc073d6b16b51d072,1
+np.float64,0x3990a23f9ff2b623,0xc051aa60eadd8c61,1
+np.float64,0x0d011386a116c348,0xc081a6cc7ea3b8fb,1
+np.float64,0x1fe0f0303ebe273a,0xc0763870b78a81ca,1
+np.float64,0x0cd1260121d387da,0xc081b7668d61a9d1,1
+np.float64,0x1e6135a8f581d422,0xc077425ac10f08c2,1
+np.float64,0x622168db5fe52d30,0x4077b3c669b9fadb,1
+np.float64,0x69f188e1ec6d1718,0x407d1e2f18c63889,1
+np.float64,0x3aa1bf1d9c4dd1a3,0xc04d682e24bde479,1
+np.float64,0x6c81c4011ce4f683,0x407ee5190e8a8e6a,1
+np.float64,0x2191fa55aa5a5095,0xc0750c0c318b5e2d,1
+np.float64,0x32a1f602a32bf360,0xc06270caa493fc17,1
+np.float64,0x16023c90ba93249b,0xc07d0f88e0801638,1
+np.float64,0x1c525fe6d71fa9ff,0xc078af49c66a5d63,1
+np.float64,0x1a927675815d65b7,0xc079e5bdd7fe376e,1
+np.float64,0x41227b8fe70da028,0x402aa0c9f9a84c71,1
+np.float64,0x4962bb6e853fe87d,0x405a34aa04c83747,1
+np.float64,0x23d2cda00b26b5a4,0xc0737c13a06d00ea,1
+np.float64,0x2d13083fd62987fa,0xc06a25055aeb474e,1
+np.float64,0x10e31e4c9b4579a1,0xc0804e181929418e,1
+np.float64,0x26d3247d556a86a9,0xc0716774171da7e8,1
+np.float64,0x6603379398d0d4ac,0x407a64f51f8a887b,1
+np.float64,0x02d38af17d9442ba,0xc0852d955ac9dd68,1
+np.float64,0x6a2382b4818dd967,0x407d4129d688e5d4,1
+np.float64,0x2ee3c403c79b3934,0xc067a091fefaf8b6,1
+np.float64,0x6493a699acdbf1a4,0x4079663c8602bfc5,1
+np.float64,0x1c8413c4f0de3100,0xc0788c99697059b6,1
+np.float64,0x4573f1ed350d9622,0x404e9bd1e4c08920,1
+np.float64,0x2f34265c9200b69c,0xc067310cfea4e986,1
+np.float64,0x19b43e65fa22029b,0xc07a7f8877de22d6,1
+np.float64,0x0af48ab7925ed6bc,0xc0825c4fbc0e5ade,1
+np.float64,0x4fa49699cad82542,0x4065c76d2a318235,1
+np.float64,0x7204a15e56ade492,0x40815bb87484dffb,1
+np.float64,0x4734aa08a230982d,0x40542a4bf7a361a9,1
+np.float64,0x1ae4ed296c2fd749,0xc079ac4921f20abb,1
+np.float64,0x472514ea4370289c,0x4053ff372bd8f18f,1
+np.float64,0x53a54b3f73820430,0x406b5411fc5f2e33,1
+np.float64,0x64754de5a15684fa,0x407951592e99a5ab,1
+np.float64,0x69358e279868a7c3,0x407c9c671a882c31,1
+np.float64,0x284579ec61215945,0xc0706688e55f0927,1
+np.float64,0x68b5c58806447adc,0x407c43d6f4eff760,1
+np.float64,0x1945a83f98b0e65d,0xc07acc15eeb032cc,1
+np.float64,0x0fc5eb98a16578bf,0xc080b0d02eddca0e,1
+np.float64,0x6a75e208f5784250,0x407d7a7383bf8f05,1
+np.float64,0x0fe63a029c47645d,0xc080a59ca1e98866,1
+np.float64,0x37963ac53f065510,0xc057236281f7bdb6,1
+np.float64,0x135661bb07067ff7,0xc07ee924930c21e4,1
+np.float64,0x4b4699469d458422,0x405f73843756e887,1
+np.float64,0x1a66d73e4bf4881b,0xc07a039ba1c63adf,1
+np.float64,0x12a6b9b119a7da59,0xc07f62e49c6431f3,1
+np.float64,0x24c719aa8fd1bdb5,0xc072d26da4bf84d3,1
+np.float64,0x0fa6ff524ffef314,0xc080bb8514662e77,1
+np.float64,0x1db751d66fdd4a9a,0xc077b77cb50d7c92,1
+np.float64,0x4947374c516da82c,0x4059e9acfc7105bf,1
+np.float64,0x1b1771ab98f3afc8,0xc07989326b8e1f66,1
+np.float64,0x25e78805baac8070,0xc0720a818e6ef080,1
+np.float64,0x4bd7a148225d3687,0x406082d004ea3ee7,1
+np.float64,0x53d7d6b2bbbda00a,0x406b9a398967cbd5,1
+np.float64,0x6997fb9f4e1c685f,0x407ce0a703413eba,1
+np.float64,0x069802c2ff71b951,0xc083df39bf7acddc,1
+np.float64,0x4d683ac9890f66d8,0x4062ae21d8c2acf0,1
+np.float64,0x5a2825863ec14f4c,0x40722d718d549552,1
+np.float64,0x0398799a88f4db80,0xc084e93dab8e2158,1
+np.float64,0x5ed87a8b77e135a5,0x40756d7051777b33,1
+np.float64,0x5828cd6d79b9bede,0x4070cafb22fc6ca1,1
+np.float64,0x7b18ba2a5ec6f068,0x408481386b3ed6fe,1
+np.float64,0x4938fd60922198fe,0x4059c206b762ea7e,1
+np.float64,0x31b8f44fcdd1a46e,0xc063b2faa8b6434e,1
+np.float64,0x5729341c0d918464,0x407019cac0c4a7d7,1
+np.float64,0x13595e9228ee878e,0xc07ee7235a7d8088,1
+np.float64,0x17698b0dc9dd4135,0xc07c1627e3a5ad5f,1
+np.float64,0x63b977c283abb0cc,0x4078cf1ec6ed65be,1
+np.float64,0x7349cc0d4dc16943,0x4081cc697ce4cb53,1
+np.float64,0x4e49a80b732fb28d,0x4063e67e3c5cbe90,1
+np.float64,0x07ba14b848a8ae02,0xc0837ac032a094e0,1
+np.float64,0x3da9f17b691bfddc,0xc03929c25366acda,1
+np.float64,0x02ea39aa6c3ac007,0xc08525af6f21e1c4,1
+np.float64,0x3a6a42f04ed9563d,0xc04e98e825dca46b,1
+np.float64,0x1afa877cd7900be7,0xc0799d6648cb34a9,1
+np.float64,0x58ea986649e052c6,0x4071512e939ad790,1
+np.float64,0x691abbc04647f536,0x407c89aaae0fcb83,1
+np.float64,0x43aabc5063e6f284,0x4044b45d18106fd2,1
+np.float64,0x488b003c893e0bea,0x4057df012a2dafbe,1
+np.float64,0x77eb076ed67caee5,0x40836720de94769e,1
+np.float64,0x5c1b46974aba46f4,0x40738731ba256007,1
+np.float64,0x1a5b29ecb5d3c261,0xc07a0becc77040d6,1
+np.float64,0x5d8b6ccf868c6032,0x4074865c1865e2db,1
+np.float64,0x4cfb6690b4aaf5af,0x406216cd8c7e8ddb,1
+np.float64,0x76cbd8eb5c5fc39e,0x4083038dc66d682b,1
+np.float64,0x28bbd1fec5012814,0xc07014c2dd1b9711,1
+np.float64,0x33dc1b3a4fd6bf7a,0xc060bd0756e07d8a,1
+np.float64,0x52bbe89b37de99f3,0x406a10041aa7d343,1
+np.float64,0x07bc479d15eb2dd3,0xc0837a1a6e3a3b61,1
+np.float64,0x18fc5275711a901d,0xc07aff3e9d62bc93,1
+np.float64,0x114c9758e247dc71,0xc080299a7cf15b05,1
+np.float64,0x25ac8f6d60755148,0xc07233c4c0c511d4,1
+np.float64,0x260cae2bb9e9fd7e,0xc071f128c7e82eac,1
+np.float64,0x572ccdfe0241de82,0x40701bedc84bb504,1
+np.float64,0x0ddcef6c8d41f5ee,0xc0815a7e16d07084,1
+np.float64,0x6dad1d59c988af68,0x407fb4a0bc0142b1,1
+np.float64,0x025d200580d8b6d1,0xc08556c0bc32b1b2,1
+np.float64,0x7aad344b6aa74c18,0x40845bbc453f22be,1
+np.float64,0x5b5d9d6ad9d14429,0x4073036d2d21f382,1
+np.float64,0x49cd8d8dcdf19954,0x405b5c034f5c7353,1
+np.float64,0x63edb9483335c1e6,0x4078f2dd21378786,1
+np.float64,0x7b1dd64c9d2c26bd,0x408482b922017bc9,1
+np.float64,0x782e13e0b574be5f,0x40837e2a0090a5ad,1
+np.float64,0x592dfe18b9d6db2f,0x40717f777fbcb1ec,1
+np.float64,0x654e3232ac60d72c,0x4079e71a95a70446,1
+np.float64,0x7b8e42ad22091456,0x4084a9a6f1e61722,1
+np.float64,0x570e88dfd5860ae6,0x407006ae6c0d137a,1
+np.float64,0x294e98346cb98ef1,0xc06f5edaac12bd44,1
+np.float64,0x1adeaa4ab792e642,0xc079b1431d5e2633,1
+np.float64,0x7b6ead3377529ac8,0x40849eabc8c7683c,1
+np.float64,0x2b8eedae8a9b2928,0xc06c400054deef11,1
+np.float64,0x65defb45b2dcf660,0x407a4b53f181c05a,1
+np.float64,0x1baf582d475e7701,0xc07920bcad4a502c,1
+np.float64,0x461f39cf05a0f15a,0x405126368f984fa1,1
+np.float64,0x7e5f6f5dcfff005b,0x4085a37d610439b4,1
+np.float64,0x136f66e4d09bd662,0xc07ed8a2719f2511,1
+np.float64,0x65afd8983fb6ca1f,0x407a2a7f48bf7fc1,1
+np.float64,0x572fa7f95ed22319,0x40701d706cf82e6f,1
--- /dev/null
+"""
+Functions in this module give python-space wrappers for cython functions
+exposed in numpy/__init__.pxd, so they can be tested in test_cython.py
+"""
+cimport numpy as cnp
+cnp.import_array()
+
+
+def is_td64(obj):
+ return cnp.is_timedelta64_object(obj)
+
+
+def is_dt64(obj):
+ return cnp.is_datetime64_object(obj)
+
+
+def get_dt64_value(obj):
+ return cnp.get_datetime64_value(obj)
+
+
+def get_td64_value(obj):
+ return cnp.get_timedelta64_value(obj)
+
+
+def get_dt64_unit(obj):
+ return cnp.get_datetime64_unit(obj)
+
+
+def is_integer(obj):
+ return isinstance(obj, (cnp.integer, int))
--- /dev/null
+"""
+Provide python-space access to the functions exposed in numpy/__init__.pxd
+for testing.
+"""
+
+import numpy as np
+from distutils.core import setup
+from Cython.Build import cythonize
+from setuptools.extension import Extension
+import os
+
+macros = [("NPY_NO_DEPRECATED_API", 0)]
+
+checks = Extension(
+ "checks",
+ sources=[os.path.join('.', "checks.pyx")],
+ include_dirs=[np.get_include()],
+ define_macros=macros,
+)
+
+extensions = [checks]
+
+setup(
+ ext_modules=cythonize(extensions)
+)
a = np.array(1000, dtype='i4')
assert_raises(TypeError, a.astype, 'U1', casting='safe')
+
+@pytest.mark.parametrize("dt", ["d", "f", "S13", "U32"])
+def test_array_astype_to_void(dt):
+ dt = np.dtype(dt)
+ arr = np.array([], dtype=dt)
+ assert arr.astype("V").dtype.itemsize == dt.itemsize
+
+def test_object_array_astype_to_void():
+ # This is different to `test_array_astype_to_void` as object arrays
+ # are inspected. The default void is "V8" (8 is the length of double)
+ arr = np.array([], dtype="O").astype("V")
+ assert arr.dtype == "V8"
+
@pytest.mark.parametrize("t",
np.sctypes['uint'] + np.sctypes['int'] + np.sctypes['float']
)
@pytest.mark.parametrize(["dtype", "out_dtype"],
[(np.bytes_, np.bool_),
- (np.unicode, np.bool_),
+ (np.unicode_, np.bool_),
(np.dtype("S10,S9"), np.dtype("?,?"))])
def test_string_to_boolean_cast(dtype, out_dtype):
"""
@pytest.mark.parametrize(["dtype", "out_dtype"],
[(np.bytes_, np.bool_),
- (np.unicode, np.bool_),
+ (np.unicode_, np.bool_),
(np.dtype("S10,S9"), np.dtype("?,?"))])
def test_string_to_boolean_cast_errors(dtype, out_dtype):
"""
result = np.broadcast_arrays(a, b)
assert_equal(result[0], np.array([(1, 2, 3), (1, 2, 3), (1, 2, 3)], dtype='u4,u4,u4'))
assert_equal(result[1], np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype='u4,u4,u4'))
+
+@pytest.mark.parametrize(["shape", "fill_value", "expected_output"],
+ [((2, 2), [5.0, 6.0], np.array([[5.0, 6.0], [5.0, 6.0]])),
+ ((3, 2), [1.0, 2.0], np.array([[1.0, 2.0], [1.0, 2.0], [1.0, 2.0]]))])
+def test_full_from_list(shape, fill_value, expected_output):
+ output = np.full(shape, fill_value)
+ assert_equal(output, expected_output)
--- /dev/null
+"""
+Tests for array coercion, mainly through testing `np.array` results directly.
+Note that other such tests exist e.g. in `test_api.py` and many corner-cases
+are tested (sometimes indirectly) elsewhere.
+"""
+
+import pytest
+from pytest import param
+
+from itertools import product
+
+import numpy as np
+from numpy.core._rational_tests import rational
+from numpy.core._multiarray_umath import _discover_array_parameters
+
+from numpy.testing import (
+ assert_array_equal, assert_warns, IS_PYPY)
+
+
+def arraylikes():
+ """
+ Generator for functions converting an array into various array-likes.
+ If full is True (default) includes array-likes not capable of handling
+ all dtypes
+ """
+ # base array:
+ def ndarray(a):
+ return a
+
+ yield param(ndarray, id="ndarray")
+
+ # subclass:
+ class MyArr(np.ndarray):
+ pass
+
+ def subclass(a):
+ return a.view(MyArr)
+
+ yield subclass
+
+ class _SequenceLike():
+ # We are giving a warning that array-like's were also expected to be
+ # sequence-like in `np.array([array_like])`, this can be removed
+ # when the deprecation exired (started NumPy 1.20)
+ def __len__(self):
+ raise TypeError
+
+ def __getitem__(self):
+ raise TypeError
+
+ # Array-interface
+ class ArrayDunder(_SequenceLike):
+ def __init__(self, a):
+ self.a = a
+
+ def __array__(self, dtype=None):
+ return self.a
+
+ yield param(ArrayDunder, id="__array__")
+
+ # memory-view
+ yield param(memoryview, id="memoryview")
+
+ # Array-interface
+ class ArrayInterface(_SequenceLike):
+ def __init__(self, a):
+ self.a = a # need to hold on to keep interface valid
+ self.__array_interface__ = a.__array_interface__
+
+ yield param(ArrayInterface, id="__array_interface__")
+
+ # Array-Struct
+ class ArrayStruct(_SequenceLike):
+ def __init__(self, a):
+ self.a = a # need to hold on to keep struct valid
+ self.__array_struct__ = a.__array_struct__
+
+ yield param(ArrayStruct, id="__array_struct__")
+
+
+def scalar_instances(times=True, extended_precision=True, user_dtype=True):
+ # Hard-coded list of scalar instances.
+ # Floats:
+ yield param(np.sqrt(np.float16(5)), id="float16")
+ yield param(np.sqrt(np.float32(5)), id="float32")
+ yield param(np.sqrt(np.float64(5)), id="float64")
+ if extended_precision:
+ yield param(np.sqrt(np.longdouble(5)), id="longdouble")
+
+ # Complex:
+ yield param(np.sqrt(np.complex64(2+3j)), id="complex64")
+ yield param(np.sqrt(np.complex128(2+3j)), id="complex128")
+ if extended_precision:
+ yield param(np.sqrt(np.longcomplex(2+3j)), id="clongdouble")
+
+ # Bool:
+ # XFAIL: Bool should be added, but has some bad properties when it
+ # comes to strings, see also gh-9875
+ # yield param(np.bool_(0), id="bool")
+
+ # Integers:
+ yield param(np.int8(2), id="int8")
+ yield param(np.int16(2), id="int16")
+ yield param(np.int32(2), id="int32")
+ yield param(np.int64(2), id="int64")
+
+ yield param(np.uint8(2), id="uint8")
+ yield param(np.uint16(2), id="uint16")
+ yield param(np.uint32(2), id="uint32")
+ yield param(np.uint64(2), id="uint64")
+
+ # Rational:
+ if user_dtype:
+ yield param(rational(1, 2), id="rational")
+
+ # Cannot create a structured void scalar directly:
+ structured = np.array([(1, 3)], "i,i")[0]
+ assert isinstance(structured, np.void)
+ assert structured.dtype == np.dtype("i,i")
+ yield param(structured, id="structured")
+
+ if times:
+ # Datetimes and timedelta
+ yield param(np.timedelta64(2), id="timedelta64[generic]")
+ yield param(np.timedelta64(23, "s"), id="timedelta64[s]")
+ yield param(np.timedelta64("NaT", "s"), id="timedelta64[s](NaT)")
+
+ yield param(np.datetime64("NaT"), id="datetime64[generic](NaT)")
+ yield param(np.datetime64("2020-06-07 12:43", "ms"), id="datetime64[ms]")
+
+ # Strings and unstructured void:
+ yield param(np.bytes_(b"1234"), id="bytes")
+ yield param(np.unicode_("2345"), id="unicode")
+ yield param(np.void(b"4321"), id="unstructured_void")
+
+
+def is_parametric_dtype(dtype):
+ """Returns True if the the dtype is a parametric legacy dtype (itemsize
+ is 0, or a datetime without units)
+ """
+ if dtype.itemsize == 0:
+ return True
+ if issubclass(dtype.type, (np.datetime64, np.timedelta64)):
+ if dtype.name.endswith("64"):
+ # Generic time units
+ return True
+ return False
+
+
+class TestStringDiscovery:
+ @pytest.mark.parametrize("obj",
+ [object(), 1.2, 10**43, None, "string"],
+ ids=["object", "1.2", "10**43", "None", "string"])
+ def test_basic_stringlength(self, obj):
+ length = len(str(obj))
+ expected = np.dtype(f"S{length}")
+
+ assert np.array(obj, dtype="S").dtype == expected
+ assert np.array([obj], dtype="S").dtype == expected
+
+ # A nested array is also discovered correctly
+ arr = np.array(obj, dtype="O")
+ assert np.array(arr, dtype="S").dtype == expected
+ # Check that .astype() behaves identical
+ assert arr.astype("S").dtype == expected
+
+ @pytest.mark.parametrize("obj",
+ [object(), 1.2, 10**43, None, "string"],
+ ids=["object", "1.2", "10**43", "None", "string"])
+ def test_nested_arrays_stringlength(self, obj):
+ length = len(str(obj))
+ expected = np.dtype(f"S{length}")
+ arr = np.array(obj, dtype="O")
+ assert np.array([arr, arr], dtype="S").dtype == expected
+
+ @pytest.mark.parametrize("arraylike", arraylikes())
+ def test_unpack_first_level(self, arraylike):
+ # We unpack exactly one level of array likes
+ obj = np.array([None])
+ obj[0] = np.array(1.2)
+ # the length of the included item, not of the float dtype
+ length = len(str(obj[0]))
+ expected = np.dtype(f"S{length}")
+
+ obj = arraylike(obj)
+ # casting to string usually calls str(obj)
+ arr = np.array([obj], dtype="S")
+ assert arr.shape == (1, 1)
+ assert arr.dtype == expected
+
+
+class TestScalarDiscovery:
+ def test_void_special_case(self):
+ # Void dtypes with structures discover tuples as elements
+ arr = np.array((1, 2, 3), dtype="i,i,i")
+ assert arr.shape == ()
+ arr = np.array([(1, 2, 3)], dtype="i,i,i")
+ assert arr.shape == (1,)
+
+ def test_char_special_case(self):
+ arr = np.array("string", dtype="c")
+ assert arr.shape == (6,)
+ assert arr.dtype.char == "c"
+ arr = np.array(["string"], dtype="c")
+ assert arr.shape == (1, 6)
+ assert arr.dtype.char == "c"
+
+ def test_char_special_case_deep(self):
+ # Check that the character special case errors correctly if the
+ # array is too deep:
+ nested = ["string"] # 2 dimensions (due to string being sequence)
+ for i in range(np.MAXDIMS - 2):
+ nested = [nested]
+
+ arr = np.array(nested, dtype='c')
+ assert arr.shape == (1,) * (np.MAXDIMS - 1) + (6,)
+ with pytest.raises(ValueError):
+ np.array([nested], dtype="c")
+
+ def test_unknown_object(self):
+ arr = np.array(object())
+ assert arr.shape == ()
+ assert arr.dtype == np.dtype("O")
+
+ @pytest.mark.parametrize("scalar", scalar_instances())
+ def test_scalar(self, scalar):
+ arr = np.array(scalar)
+ assert arr.shape == ()
+ assert arr.dtype == scalar.dtype
+
+ arr = np.array([[scalar, scalar]])
+ assert arr.shape == (1, 2)
+ assert arr.dtype == scalar.dtype
+
+ # Additionally to string this test also runs into a corner case
+ # with datetime promotion (the difference is the promotion order).
+ def test_scalar_promotion(self):
+ for sc1, sc2 in product(scalar_instances(), scalar_instances()):
+ sc1, sc2 = sc1.values[0], sc2.values[0]
+ # test all combinations:
+ try:
+ arr = np.array([sc1, sc2])
+ except (TypeError, ValueError):
+ # The promotion between two times can fail
+ # XFAIL (ValueError): Some object casts are currently undefined
+ continue
+ assert arr.shape == (2,)
+ try:
+ dt1, dt2 = sc1.dtype, sc2.dtype
+ expected_dtype = np.promote_types(dt1, dt2)
+ assert arr.dtype == expected_dtype
+ except TypeError as e:
+ # Will currently always go to object dtype
+ assert arr.dtype == np.dtype("O")
+
+ @pytest.mark.parametrize("scalar", scalar_instances())
+ def test_scalar_coercion(self, scalar):
+ # This tests various scalar coercion paths, mainly for the numerical
+ # types. It includes some paths not directly related to `np.array`
+ if isinstance(scalar, np.inexact):
+ # Ensure we have a full-precision number if available
+ scalar = type(scalar)((scalar * 2)**0.5)
+
+ if type(scalar) is rational:
+ # Rational generally fails due to a missing cast. In the future
+ # object casts should automatically be defined based on `setitem`.
+ pytest.xfail("Rational to object cast is undefined currently.")
+
+ # Use casting from object:
+ arr = np.array(scalar, dtype=object).astype(scalar.dtype)
+
+ # Test various ways to create an array containing this scalar:
+ arr1 = np.array(scalar).reshape(1)
+ arr2 = np.array([scalar])
+ arr3 = np.empty(1, dtype=scalar.dtype)
+ arr3[0] = scalar
+ arr4 = np.empty(1, dtype=scalar.dtype)
+ arr4[:] = [scalar]
+ # All of these methods should yield the same results
+ assert_array_equal(arr, arr1)
+ assert_array_equal(arr, arr2)
+ assert_array_equal(arr, arr3)
+ assert_array_equal(arr, arr4)
+
+ @pytest.mark.xfail(IS_PYPY, reason="`int(np.complex128(3))` fails on PyPy")
+ @pytest.mark.filterwarnings("ignore::numpy.ComplexWarning")
+ @pytest.mark.parametrize("cast_to", scalar_instances())
+ def test_scalar_coercion_same_as_cast_and_assignment(self, cast_to):
+ """
+ Test that in most cases:
+ * `np.array(scalar, dtype=dtype)`
+ * `np.empty((), dtype=dtype)[()] = scalar`
+ * `np.array(scalar).astype(dtype)`
+ should behave the same. The only exceptions are paramteric dtypes
+ (mainly datetime/timedelta without unit) and void without fields.
+ """
+ dtype = cast_to.dtype # use to parametrize only the target dtype
+
+ for scalar in scalar_instances(times=False):
+ scalar = scalar.values[0]
+
+ if dtype.type == np.void:
+ if scalar.dtype.fields is not None and dtype.fields is None:
+ # Here, coercion to "V6" works, but the cast fails.
+ # Since the types are identical, SETITEM takes care of
+ # this, but has different rules than the cast.
+ with pytest.raises(TypeError):
+ np.array(scalar).astype(dtype)
+ np.array(scalar, dtype=dtype)
+ np.array([scalar], dtype=dtype)
+ continue
+
+ # The main test, we first try to use casting and if it succeeds
+ # continue below testing that things are the same, otherwise
+ # test that the alternative paths at least also fail.
+ try:
+ cast = np.array(scalar).astype(dtype)
+ except (TypeError, ValueError, RuntimeError):
+ # coercion should also raise (error type may change)
+ with pytest.raises(Exception):
+ np.array(scalar, dtype=dtype)
+
+ if (isinstance(scalar, rational) and
+ np.issubdtype(dtype, np.signedinteger)):
+ return
+
+ with pytest.raises(Exception):
+ np.array([scalar], dtype=dtype)
+ # assignment should also raise
+ res = np.zeros((), dtype=dtype)
+ with pytest.raises(Exception):
+ res[()] = scalar
+
+ return
+
+ # Non error path:
+ arr = np.array(scalar, dtype=dtype)
+ assert_array_equal(arr, cast)
+ # assignment behaves the same
+ ass = np.zeros((), dtype=dtype)
+ ass[()] = scalar
+ assert_array_equal(ass, cast)
+
+ @pytest.mark.parametrize("dtype_char", np.typecodes["All"])
+ def test_default_dtype_instance(self, dtype_char):
+ if dtype_char in "SU":
+ dtype = np.dtype(dtype_char + "1")
+ elif dtype_char == "V":
+ # Legacy behaviour was to use V8. The reason was float64 being the
+ # default dtype and that having 8 bytes.
+ dtype = np.dtype("V8")
+ else:
+ dtype = np.dtype(dtype_char)
+
+ discovered_dtype, _ = _discover_array_parameters([], type(dtype))
+
+ assert discovered_dtype == dtype
+ assert discovered_dtype.itemsize == dtype.itemsize
+
+ @pytest.mark.parametrize("dtype", np.typecodes["Integer"])
+ def test_scalar_to_int_coerce_does_not_cast(self, dtype):
+ """
+ Signed integers are currently different in that they do not cast other
+ NumPy scalar, but instead use scalar.__int__(). The harcoded
+ exception to this rule is `np.array(scalar, dtype=integer)`.
+ """
+ dtype = np.dtype(dtype)
+ invalid_int = np.ulonglong(-1)
+
+ float_nan = np.float64(np.nan)
+
+ for scalar in [float_nan, invalid_int]:
+ # This is a special case using casting logic and thus not failing:
+ coerced = np.array(scalar, dtype=dtype)
+ cast = np.array(scalar).astype(dtype)
+ assert_array_equal(coerced, cast)
+
+ # However these fail:
+ with pytest.raises((ValueError, OverflowError)):
+ np.array([scalar], dtype=dtype)
+ with pytest.raises((ValueError, OverflowError)):
+ cast[()] = scalar
+
+
+class TestTimeScalars:
+ @pytest.mark.parametrize("dtype", [np.int64, np.float32])
+ @pytest.mark.parametrize("scalar",
+ [param(np.timedelta64("NaT", "s"), id="timedelta64[s](NaT)"),
+ param(np.timedelta64(123, "s"), id="timedelta64[s]"),
+ param(np.datetime64("NaT", "generic"), id="datetime64[generic](NaT)"),
+ param(np.datetime64(1, "D"), id="datetime64[D]")],)
+ def test_coercion_basic(self, dtype, scalar):
+ # Note the `[scalar]` is there because np.array(scalar) uses stricter
+ # `scalar.__int__()` rules for backward compatibility right now.
+ arr = np.array(scalar, dtype=dtype)
+ cast = np.array(scalar).astype(dtype)
+ assert_array_equal(arr, cast)
+
+ ass = np.ones((), dtype=dtype)
+ if issubclass(dtype, np.integer):
+ with pytest.raises(TypeError):
+ # raises, as would np.array([scalar], dtype=dtype), this is
+ # conversion from times, but behaviour of integers.
+ ass[()] = scalar
+ else:
+ ass[()] = scalar
+ assert_array_equal(ass, cast)
+
+ @pytest.mark.parametrize("dtype", [np.int64, np.float32])
+ @pytest.mark.parametrize("scalar",
+ [param(np.timedelta64(123, "ns"), id="timedelta64[ns]"),
+ param(np.timedelta64(12, "generic"), id="timedelta64[generic]")])
+ def test_coercion_timedelta_convert_to_number(self, dtype, scalar):
+ # Only "ns" and "generic" timedeltas can be converted to numbers
+ # so these are slightly special.
+ arr = np.array(scalar, dtype=dtype)
+ cast = np.array(scalar).astype(dtype)
+ ass = np.ones((), dtype=dtype)
+ ass[()] = scalar # raises, as would np.array([scalar], dtype=dtype)
+
+ assert_array_equal(arr, cast)
+ assert_array_equal(cast, cast)
+
+ @pytest.mark.parametrize("dtype", ["S6", "U6"])
+ @pytest.mark.parametrize(["val", "unit"],
+ [param(123, "s", id="[s]"), param(123, "D", id="[D]")])
+ def test_coercion_assignment_datetime(self, val, unit, dtype):
+ # String from datetime64 assignment is currently special cased to
+ # never use casting. This is because casting will error in this
+ # case, and traditionally in most cases the behaviour is maintained
+ # like this. (`np.array(scalar, dtype="U6")` would have failed before)
+ # TODO: This discrepency _should_ be resolved, either by relaxing the
+ # cast, or by deprecating the first part.
+ scalar = np.datetime64(val, unit)
+ dtype = np.dtype(dtype)
+ cut_string = dtype.type(str(scalar)[:6])
+
+ arr = np.array(scalar, dtype=dtype)
+ assert arr[()] == cut_string
+ ass = np.ones((), dtype=dtype)
+ ass[()] = scalar
+ assert ass[()] == cut_string
+
+ with pytest.raises(RuntimeError):
+ # However, unlike the above assignment using `str(scalar)[:6]`
+ # due to being handled by the string DType and not be casting
+ # the explicit cast fails:
+ np.array(scalar).astype(dtype)
+
+
+ @pytest.mark.parametrize(["val", "unit"],
+ [param(123, "s", id="[s]"), param(123, "D", id="[D]")])
+ def test_coercion_assignment_timedelta(self, val, unit):
+ scalar = np.timedelta64(val, unit)
+
+ # Unlike datetime64, timedelta allows the unsafe cast:
+ np.array(scalar, dtype="S6")
+ cast = np.array(scalar).astype("S6")
+ ass = np.ones((), dtype="S6")
+ ass[()] = scalar
+ expected = scalar.astype("S")[:6]
+ assert cast[()] == expected
+ assert ass[()] == expected
+
+class TestNested:
+ def test_nested_simple(self):
+ initial = [1.2]
+ nested = initial
+ for i in range(np.MAXDIMS - 1):
+ nested = [nested]
+
+ arr = np.array(nested, dtype="float64")
+ assert arr.shape == (1,) * np.MAXDIMS
+ with pytest.raises(ValueError):
+ np.array([nested], dtype="float64")
+
+ # We discover object automatically at this time:
+ with assert_warns(np.VisibleDeprecationWarning):
+ arr = np.array([nested])
+ assert arr.dtype == np.dtype("O")
+ assert arr.shape == (1,) * np.MAXDIMS
+ assert arr.item() is initial
+
+ def test_pathological_self_containing(self):
+ # Test that this also works for two nested sequences
+ l = []
+ l.append(l)
+ arr = np.array([l, l, l], dtype=object)
+ assert arr.shape == (3,) + (1,) * (np.MAXDIMS - 1)
+
+ # Also check a ragged case:
+ arr = np.array([l, [None], l], dtype=object)
+ assert arr.shape == (3, 1)
+
+ @pytest.mark.parametrize("arraylike", arraylikes())
+ def test_nested_arraylikes(self, arraylike):
+ # We try storing an array like into an array, but the array-like
+ # will have too many dimensions. This means the shape discovery
+ # decides that the array-like must be treated as an object (a special
+ # case of ragged discovery). The result will be an array with one
+ # dimension less than the maximum dimensions, and the array being
+ # assigned to it (which does work for object or if `float(arraylike)`
+ # works).
+ initial = arraylike(np.ones((1, 1)))
+
+ nested = initial
+ for i in range(np.MAXDIMS - 1):
+ nested = [nested]
+
+ with pytest.warns(DeprecationWarning):
+ # It will refuse to assign the array into
+ np.array(nested, dtype="float64")
+
+ # If this is object, we end up assigning a (1, 1) array into (1,)
+ # (due to running out of dimensions), this is currently supported but
+ # a special case which is not ideal.
+ arr = np.array(nested, dtype=object)
+ assert arr.shape == (1,) * np.MAXDIMS
+ assert arr.item() == np.array(initial).item()
+
+ @pytest.mark.parametrize("arraylike", arraylikes())
+ def test_uneven_depth_ragged(self, arraylike):
+ arr = np.arange(4).reshape((2, 2))
+ arr = arraylike(arr)
+
+ # Array is ragged in the second dimension already:
+ out = np.array([arr, [arr]], dtype=object)
+ assert out.shape == (2,)
+ assert out[0] is arr
+ assert type(out[1]) is list
+
+ # Array is ragged in the third dimension:
+ with pytest.raises(ValueError):
+ # This is a broadcast error during assignment, because
+ # the array shape would be (2, 2, 2) but `arr[0, 0] = arr` fails.
+ np.array([arr, [arr, arr]], dtype=object)
+
+ def test_empty_sequence(self):
+ arr = np.array([[], [1], [[1]]], dtype=object)
+ assert arr.shape == (3,)
+
+ # The empty sequence stops further dimension discovery, so the
+ # result shape will be (0,) which leads to an error during:
+ with pytest.raises(ValueError):
+ np.array([[], np.empty((0, 1))], dtype=object)
+
+ def test_array_of_different_depths(self):
+ # When multiple arrays (or array-likes) are included in a
+ # sequences and have different depth, we currently discover
+ # as many dimensions as they share. (see also gh-17224)
+ arr = np.zeros((3, 2))
+ mismatch_first_dim = np.zeros((1, 2))
+ mismatch_second_dim = np.zeros((3, 3))
+
+ dtype, shape = _discover_array_parameters(
+ [arr, mismatch_second_dim], dtype=np.dtype("O"))
+ assert shape == (2, 3)
+
+ dtype, shape = _discover_array_parameters(
+ [arr, mismatch_first_dim], dtype=np.dtype("O"))
+ assert shape == (2,)
+ # The second case is currently supported because the arrays
+ # can be stored as objects:
+ res = np.asarray([arr, mismatch_first_dim], dtype=np.dtype("O"))
+ assert res[0] is arr
+ assert res[1] is mismatch_first_dim
+
+
+class TestBadSequences:
+ # These are tests for bad objects passed into `np.array`, in general
+ # these have undefined behaviour. In the old code they partially worked
+ # when now they will fail. We could (and maybe should) create a copy
+ # of all sequences to be safe against bad-actors.
+
+ def test_growing_list(self):
+ # List to coerce, `mylist` will append to it during coercion
+ obj = []
+ class mylist(list):
+ def __len__(self):
+ obj.append([1, 2])
+ return super().__len__()
+
+ obj.append(mylist([1, 2]))
+
+ with pytest.raises(RuntimeError):
+ np.array(obj)
+
+ # Note: We do not test a shrinking list. These do very evil things
+ # and the only way to fix them would be to copy all sequences.
+ # (which may be a real option in the future).
+
+ def test_mutated_list(self):
+ # List to coerce, `mylist` will mutate the first element
+ obj = []
+ class mylist(list):
+ def __len__(self):
+ obj[0] = [2, 3] # replace with a different list.
+ return super().__len__()
+
+ obj.append([2, 3])
+ obj.append(mylist([1, 2]))
+ with pytest.raises(RuntimeError):
+ np.array(obj)
+
+ def test_replace_0d_array(self):
+ # List to coerce, `mylist` will mutate the first element
+ obj = []
+ class baditem:
+ def __len__(self):
+ obj[0][0] = 2 # replace with a different list.
+ raise ValueError("not actually a sequence!")
+
+ def __getitem__(self):
+ pass
+
+ # Runs into a corner case in the new code, the `array(2)` is cached
+ # so replacing it invalidates the cache.
+ obj.append([np.array(2), baditem()])
+ with pytest.raises(RuntimeError):
+ np.array(obj)
+
+
+class TestArrayLikes:
+ @pytest.mark.parametrize("arraylike", arraylikes())
+ def test_0d_object_special_case(self, arraylike):
+ arr = np.array(0.)
+ obj = arraylike(arr)
+ # A single array-like is always converted:
+ res = np.array(obj, dtype=object)
+ assert_array_equal(arr, res)
+
+ # But a single 0-D nested array-like never:
+ res = np.array([obj], dtype=object)
+ assert res[0] is obj
+
+ def test_0d_generic_special_case(self):
+ class ArraySubclass(np.ndarray):
+ def __float__(self):
+ raise TypeError("e.g. quantities raise on this")
+
+ arr = np.array(0.)
+ obj = arr.view(ArraySubclass)
+ res = np.array(obj)
+ # The subclass is simply cast:
+ assert_array_equal(arr, res)
+
+ # If the 0-D array-like is included, __float__ is currently
+ # guaranteed to be used. We may want to change that, quantities
+ # and masked arrays half make use of this.
+ with pytest.raises(TypeError):
+ np.array([obj])
+
+ # The same holds for memoryview:
+ obj = memoryview(arr)
+ res = np.array(obj)
+ assert_array_equal(arr, res)
+ with pytest.raises(ValueError):
+ # The error type does not matter much here.
+ np.array([obj])
+
+ def test_arraylike_classes(self):
+ # The classes of array-likes should generally be acceptable to be
+ # stored inside a numpy (object) array. This tests all of the
+ # special attributes (since all are checked during coercion).
+ arr = np.array(np.int64)
+ assert arr[()] is np.int64
+ arr = np.array([np.int64])
+ assert arr[0] is np.int64
+
+ # This also works for properties/unbound methods:
+ class ArrayLike:
+ @property
+ def __array_interface__(self):
+ pass
+
+ @property
+ def __array_struct__(self):
+ pass
+
+ def __array__(self):
+ pass
+
+ arr = np.array(ArrayLike)
+ assert arr[()] is ArrayLike
+ arr = np.array([ArrayLike])
+ assert arr[0] is ArrayLike
+
+ @pytest.mark.skipif(
+ np.dtype(np.intp).itemsize < 8, reason="Needs 64bit platform")
+ def test_too_large_array_error_paths(self):
+ """Test the error paths, including for memory leaks"""
+ arr = np.array(0, dtype="uint8")
+ # Guarantees that a contiguous copy won't work:
+ arr = np.broadcast_to(arr, 2**62)
+
+ for i in range(5):
+ # repeat, to ensure caching cannot have an effect:
+ with pytest.raises(MemoryError):
+ np.array(arr)
+ with pytest.raises(MemoryError):
+ np.array([arr])
+
+ @pytest.mark.parametrize("attribute",
+ ["__array_interface__", "__array__", "__array_struct__"])
+ @pytest.mark.parametrize("error", [RecursionError, MemoryError])
+ def test_bad_array_like_attributes(self, attribute, error):
+ # RecursionError and MemoryError are considered fatal. All errors
+ # (except AttributeError) should probably be raised in the future,
+ # but shapely made use of it, so it will require a deprecation.
+
+ class BadInterface:
+ def __getattr__(self, attr):
+ if attr == attribute:
+ raise error
+ super().__getattr__(attr)
+
+ with pytest.raises(error):
+ np.array(BadInterface())
+
+ @pytest.mark.parametrize("error", [RecursionError, MemoryError])
+ def test_bad_array_like_bad_length(self, error):
+ # RecursionError and MemoryError are considered "critical" in
+ # sequences. We could expand this more generally though. (NumPy 1.20)
+ class BadSequence:
+ def __len__(self):
+ raise error
+ def __getitem__(self):
+ # must have getitem to be a Sequence
+ return 1
+
+ with pytest.raises(error):
+ np.array(BadSequence())
+
"[ 'xxxxx']"
)
+ def test_multiline_repr(self):
+ class MultiLine:
+ def __repr__(self):
+ return "Line 1\nLine 2"
+
+ a = np.array([[None, MultiLine()], [MultiLine(), None]])
+
+ assert_equal(
+ np.array2string(a),
+ '[[None Line 1\n'
+ ' Line 2]\n'
+ ' [Line 1\n'
+ ' Line 2 None]]'
+ )
+ assert_equal(
+ np.array2string(a, max_line_width=5),
+ '[[None\n'
+ ' Line 1\n'
+ ' Line 2]\n'
+ ' [Line 1\n'
+ ' Line 2\n'
+ ' None]]'
+ )
+ assert_equal(
+ repr(a),
+ 'array([[None, Line 1\n'
+ ' Line 2],\n'
+ ' [Line 1\n'
+ ' Line 2, None]], dtype=object)'
+ )
+
+ class MultiLineLong:
+ def __repr__(self):
+ return "Line 1\nLooooooooooongestLine2\nLongerLine 3"
+
+ a = np.array([[None, MultiLineLong()], [MultiLineLong(), None]])
+ assert_equal(
+ repr(a),
+ 'array([[None, Line 1\n'
+ ' LooooooooooongestLine2\n'
+ ' LongerLine 3 ],\n'
+ ' [Line 1\n'
+ ' LooooooooooongestLine2\n'
+ ' LongerLine 3 , None]], dtype=object)'
+ )
+ assert_equal(
+ np.array_repr(a, 20),
+ 'array([[None,\n'
+ ' Line 1\n'
+ ' LooooooooooongestLine2\n'
+ ' LongerLine 3 ],\n'
+ ' [Line 1\n'
+ ' LooooooooooongestLine2\n'
+ ' LongerLine 3 ,\n'
+ ' None]],\n'
+ ' dtype=object)'
+ )
+
+ def test_nested_array_repr(self):
+ a = np.empty((2, 2), dtype=object)
+ a[0, 0] = np.eye(2)
+ a[0, 1] = np.eye(3)
+ a[1, 0] = None
+ a[1, 1] = np.ones((3, 1))
+ assert_equal(
+ repr(a),
+ 'array([[array([[1., 0.],\n'
+ ' [0., 1.]]), array([[1., 0., 0.],\n'
+ ' [0., 1., 0.],\n'
+ ' [0., 0., 1.]])],\n'
+ ' [None, array([[1.],\n'
+ ' [1.],\n'
+ ' [1.]])]], dtype=object)'
+ )
+
@given(hynp.from_dtype(np.dtype("U")))
def test_any_text(self, text):
# This test checks that, given any value that can be represented in an
--- /dev/null
+"""
+The tests exercise the casting machinery in a more low-level manner.
+The reason is mostly to test a new implementation of the casting machinery.
+
+Unlike most tests in NumPy, these are closer to unit-tests rather
+than integration tests.
+"""
+
+import pytest
+import textwrap
+import enum
+
+import numpy as np
+
+from numpy.core._multiarray_umath import (
+ _get_castingimpl as get_castingimpl)
+from numpy.core._multiarray_tests import uses_new_casts
+
+
+# Simple skips object, parametric and long double (unsupported by struct)
+simple_dtypes = "?bhilqBHILQefdFD"
+if np.dtype("l").itemsize != np.dtype("q").itemsize:
+ # Remove l and L, the table was generated with 64bit linux in mind.
+ # TODO: Should have two tables or no a different solution.
+ simple_dtypes = simple_dtypes.replace("l", "").replace("L", "")
+simple_dtypes = [type(np.dtype(c)) for c in simple_dtypes]
+
+
+def simple_dtype_instances():
+ for dtype_class in simple_dtypes:
+ dt = dtype_class()
+ yield pytest.param(dt, id=str(dt))
+ if dt.byteorder != "|":
+ dt = dt.newbyteorder()
+ yield pytest.param(dt, id=str(dt))
+
+
+def get_expected_stringlength(dtype):
+ """Returns the string length when casting the basic dtypes to strings.
+ """
+ if dtype == np.bool_:
+ return 5
+ if dtype.kind in "iu":
+ if dtype.itemsize == 1:
+ length = 3
+ elif dtype.itemsize == 2:
+ length = 5
+ elif dtype.itemsize == 4:
+ length = 10
+ elif dtype.itemsize == 8:
+ length = 20
+ else:
+ raise AssertionError(f"did not find expected length for {dtype}")
+
+ if dtype.kind == "i":
+ length += 1 # adds one character for the sign
+
+ return length
+
+ # Note: Can't do dtype comparison for longdouble on windows
+ if dtype.char == "g":
+ return 48
+ elif dtype.char == "G":
+ return 48 * 2
+ elif dtype.kind == "f":
+ return 32 # also for half apparently.
+ elif dtype.kind == "c":
+ return 32 * 2
+
+ raise AssertionError(f"did not find expected length for {dtype}")
+
+
+class Casting(enum.IntEnum):
+ no = 0
+ equiv = 1
+ safe = 2
+ same_kind = 3
+ unsafe = 4
+ cast_is_view = 1 << 16
+
+
+def _get_cancast_table():
+ table = textwrap.dedent("""
+ X ? b h i l q B H I L Q e f d g F D G S U V O M m
+ ? # = = = = = = = = = = = = = = = = = = = = = . =
+ b . # = = = = . . . . . = = = = = = = = = = = . =
+ h . ~ # = = = . . . . . ~ = = = = = = = = = = . =
+ i . ~ ~ # = = . . . . . ~ ~ = = ~ = = = = = = . =
+ l . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
+ q . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
+ B . ~ = = = = # = = = = = = = = = = = = = = = . =
+ H . ~ ~ = = = ~ # = = = ~ = = = = = = = = = = . =
+ I . ~ ~ ~ = = ~ ~ # = = ~ ~ = = ~ = = = = = = . =
+ L . ~ ~ ~ ~ ~ ~ ~ ~ # # ~ ~ = = ~ = = = = = = . ~
+ Q . ~ ~ ~ ~ ~ ~ ~ ~ # # ~ ~ = = ~ = = = = = = . ~
+ e . . . . . . . . . . . # = = = = = = = = = = . .
+ f . . . . . . . . . . . ~ # = = = = = = = = = . .
+ d . . . . . . . . . . . ~ ~ # = ~ = = = = = = . .
+ g . . . . . . . . . . . ~ ~ ~ # ~ ~ = = = = = . .
+ F . . . . . . . . . . . . . . . # = = = = = = . .
+ D . . . . . . . . . . . . . . . ~ # = = = = = . .
+ G . . . . . . . . . . . . . . . ~ ~ # = = = = . .
+ S . . . . . . . . . . . . . . . . . . # = = = . .
+ U . . . . . . . . . . . . . . . . . . . # = = . .
+ V . . . . . . . . . . . . . . . . . . . . # = . .
+ O . . . . . . . . . . . . . . . . . . . . = # . .
+ M . . . . . . . . . . . . . . . . . . . . = = # .
+ m . . . . . . . . . . . . . . . . . . . . = = . #
+ """).strip().split("\n")
+ dtypes = [type(np.dtype(c)) for c in table[0][2::2]]
+
+ convert_cast = {".": Casting.unsafe, "~": Casting.same_kind,
+ "=": Casting.safe, "#": Casting.equiv,
+ " ": -1}
+
+ cancast = {}
+ for from_dt, row in zip(dtypes, table[1:]):
+ cancast[from_dt] = {}
+ for to_dt, c in zip(dtypes, row[2::2]):
+ cancast[from_dt][to_dt] = convert_cast[c]
+
+ return cancast
+
+CAST_TABLE = _get_cancast_table()
+
+
+class TestChanges:
+ """
+ These test cases excercise some behaviour changes
+ """
+ @pytest.mark.parametrize("string", ["S", "U"])
+ @pytest.mark.parametrize("floating", ["e", "f", "d", "g"])
+ def test_float_to_string(self, floating, string):
+ assert np.can_cast(floating, string)
+ # 100 is long enough to hold any formatted floating
+ if uses_new_casts():
+ assert np.can_cast(floating, f"{string}100")
+ else:
+ assert not np.can_cast(floating, f"{string}100")
+ assert np.can_cast(floating, f"{string}100", casting="same_kind")
+
+ def test_to_void(self):
+ # But in general, we do consider these safe:
+ assert np.can_cast("d", "V")
+ assert np.can_cast("S20", "V")
+
+ # Do not consider it a safe cast if the void is too smaller:
+ if uses_new_casts():
+ assert not np.can_cast("d", "V1")
+ assert not np.can_cast("S20", "V1")
+ assert not np.can_cast("U1", "V1")
+ # Structured to unstructured is just like any other:
+ assert np.can_cast("d,i", "V", casting="same_kind")
+ else:
+ assert np.can_cast("d", "V1")
+ assert np.can_cast("S20", "V1")
+ assert np.can_cast("U1", "V1")
+ assert not np.can_cast("d,i", "V", casting="same_kind")
+
+
+class TestCasting:
+ @pytest.mark.parametrize("from_Dt", simple_dtypes)
+ def test_simple_cancast(self, from_Dt):
+ for to_Dt in simple_dtypes:
+ cast = get_castingimpl(from_Dt, to_Dt)
+
+ for from_dt in [from_Dt(), from_Dt().newbyteorder()]:
+ default = cast._resolve_descriptors((from_dt, None))[1][1]
+ assert default == to_Dt()
+ del default
+
+ for to_dt in [to_Dt(), to_Dt().newbyteorder()]:
+ casting, (from_res, to_res) = cast._resolve_descriptors(
+ (from_dt, to_dt))
+ assert(type(from_res) == from_Dt)
+ assert(type(to_res) == to_Dt)
+ if casting & Casting.cast_is_view:
+ # If a view is acceptable, this is "no" casting
+ # and byte order must be matching.
+ assert casting == Casting.no | Casting.cast_is_view
+ # The above table lists this as "equivalent"
+ assert Casting.equiv == CAST_TABLE[from_Dt][to_Dt]
+ # Note that to_res may not be the same as from_dt
+ assert from_res.isnative == to_res.isnative
+ else:
+ if from_Dt == to_Dt:
+ # Note that to_res may not be the same as from_dt
+ assert from_res.isnative != to_res.isnative
+ assert casting == CAST_TABLE[from_Dt][to_Dt]
+
+ if from_Dt is to_Dt:
+ assert(from_dt is from_res)
+ assert(to_dt is to_res)
+
+
+ def string_with_modified_length(self, dtype, change_length):
+ fact = 1 if dtype.char == "S" else 4
+ length = dtype.itemsize // fact + change_length
+ return np.dtype(f"{dtype.byteorder}{dtype.char}{length}")
+
+ @pytest.mark.parametrize("other_DT", simple_dtypes)
+ @pytest.mark.parametrize("string_char", ["S", "U"])
+ def test_string_cancast(self, other_DT, string_char):
+ fact = 1 if string_char == "S" else 4
+
+ string_DT = type(np.dtype(string_char))
+ cast = get_castingimpl(other_DT, string_DT)
+
+ other_dt = other_DT()
+ expected_length = get_expected_stringlength(other_dt)
+ string_dt = np.dtype(f"{string_char}{expected_length}")
+
+ safety, (res_other_dt, res_dt) = cast._resolve_descriptors((other_dt, None))
+ assert res_dt.itemsize == expected_length * fact
+ assert safety == Casting.safe # we consider to string casts "safe"
+ assert isinstance(res_dt, string_DT)
+
+ # These casts currently implement changing the string length, so
+ # check the cast-safety for too long/fixed string lengths:
+ for change_length in [-1, 0, 1]:
+ if change_length >= 0:
+ expected_safety = Casting.safe
+ else:
+ expected_safety = Casting.same_kind
+
+ to_dt = self.string_with_modified_length(string_dt, change_length)
+ safety, (_, res_dt) = cast._resolve_descriptors((other_dt, to_dt))
+ assert res_dt is to_dt
+ assert safety == expected_safety
+
+ # The opposite direction is always considered unsafe:
+ cast = get_castingimpl(string_DT, other_DT)
+
+ safety, _ = cast._resolve_descriptors((string_dt, other_dt))
+ assert safety == Casting.unsafe
+
+ cast = get_castingimpl(string_DT, other_DT)
+ safety, (_, res_dt) = cast._resolve_descriptors((string_dt, None))
+ assert safety == Casting.unsafe
+ assert other_dt is res_dt # returns the singleton for simple dtypes
+
+ @pytest.mark.parametrize("other_dt", ["S8", "<U8", ">U8"])
+ @pytest.mark.parametrize("string_char", ["S", "U"])
+ def test_string_to_string_cancast(self, other_dt, string_char):
+ other_dt = np.dtype(other_dt)
+
+ fact = 1 if string_char == "S" else 4
+ div = 1 if other_dt.char == "S" else 4
+
+ string_DT = type(np.dtype(string_char))
+ cast = get_castingimpl(type(other_dt), string_DT)
+
+ expected_length = other_dt.itemsize // div
+ string_dt = np.dtype(f"{string_char}{expected_length}")
+
+ safety, (res_other_dt, res_dt) = cast._resolve_descriptors((other_dt, None))
+ assert res_dt.itemsize == expected_length * fact
+ assert isinstance(res_dt, string_DT)
+
+ if other_dt.char == string_char:
+ if other_dt.isnative:
+ expected_safety = Casting.no | Casting.cast_is_view
+ else:
+ expected_safety = Casting.equiv
+ elif string_char == "U":
+ expected_safety = Casting.safe
+ else:
+ expected_safety = Casting.unsafe
+
+ assert expected_safety == safety
+
+ for change_length in [-1, 0, 1]:
+ to_dt = self.string_with_modified_length(string_dt, change_length)
+ safety, (_, res_dt) = cast._resolve_descriptors((other_dt, to_dt))
+
+ assert res_dt is to_dt
+ if expected_safety == Casting.unsafe:
+ assert safety == expected_safety
+ elif change_length < 0:
+ assert safety == Casting.same_kind
+ elif change_length == 0:
+ assert safety == expected_safety
+ elif change_length > 0:
+ assert safety == Casting.safe
+
+ def test_void_to_string_special_case(self):
+ # Cover a small special case in void to string casting that could
+ # probably just as well be turned into an error (compare
+ # `test_object_to_parametric_internal_error` below).
+ assert np.array([], dtype="V5").astype("S").dtype.itemsize == 5
+ assert np.array([], dtype="V5").astype("U").dtype.itemsize == 4 * 5
+
+ def test_object_to_parametric_internal_error(self):
+ # We reject casting from object to a parametric type, without
+ # figuring out the correct instance first.
+ object_dtype = type(np.dtype(object))
+ other_dtype = type(np.dtype(str))
+ cast = get_castingimpl(object_dtype, other_dtype)
+ with pytest.raises(TypeError,
+ match="casting from object to the parametric DType"):
+ cast._resolve_descriptors((np.dtype("O"), None))
import numpy as np
import numpy.core._multiarray_tests as mt
+from numpy.testing import assert_warns
class StringConverterTestCase:
allow_bytes = True
case_insensitive = True
exact_match = False
+ warn = True
def _check_value_error(self, val):
pattern = r'\(got {}\)'.format(re.escape(repr(val)))
with pytest.raises(ValueError, match=pattern) as exc:
self.conv(val)
+ def _check_conv_assert_warn(self, val, expected):
+ if self.warn:
+ with assert_warns(DeprecationWarning) as exc:
+ assert self.conv(val) == expected
+ else:
+ assert self.conv(val) == expected
+
def _check(self, val, expected):
+ """Takes valid non-deprecated inputs for converters,
+ runs converters on inputs, checks correctness of outputs,
+ warnings and errors"""
assert self.conv(val) == expected
if self.allow_bytes:
self._check_value_error(val[:1])
self._check_value_error(val + '\0')
else:
- assert self.conv(val[:1]) == expected
+ self._check_conv_assert_warn(val[:1], expected)
if self.case_insensitive:
if val != val.lower():
- assert self.conv(val.lower()) == expected
+ self._check_conv_assert_warn(val.lower(), expected)
if val != val.upper():
- assert self.conv(val.upper()) == expected
+ self._check_conv_assert_warn(val.upper(), expected)
else:
if val != val.lower():
self._check_value_error(val.lower())
class TestByteorderConverter(StringConverterTestCase):
""" Tests of PyArray_ByteorderConverter """
conv = mt.run_byteorder_converter
+ warn = False
+
def test_valid(self):
for s in ['big', '>']:
self._check(s, 'NPY_BIG')
class TestSortkindConverter(StringConverterTestCase):
""" Tests of PyArray_SortkindConverter """
conv = mt.run_sortkind_converter
+ warn = False
+
def test_valid(self):
- self._check('quick', 'NPY_QUICKSORT')
- self._check('heap', 'NPY_HEAPSORT')
- self._check('merge', 'NPY_STABLESORT') # alias
+ self._check('quicksort', 'NPY_QUICKSORT')
+ self._check('heapsort', 'NPY_HEAPSORT')
+ self._check('mergesort', 'NPY_STABLESORT') # alias
self._check('stable', 'NPY_STABLESORT')
class TestOrderConverter(StringConverterTestCase):
""" Tests of PyArray_OrderConverter """
conv = mt.run_order_converter
+ warn = False
+
def test_valid(self):
self._check('c', 'NPY_CORDER')
self._check('f', 'NPY_FORTRANORDER')
self._check("safe", "NPY_SAFE_CASTING")
self._check("same_kind", "NPY_SAME_KIND_CASTING")
self._check("unsafe", "NPY_UNSAFE_CASTING")
+
+
+class TestIntpConverter:
+ """ Tests of PyArray_IntpConverter """
+ conv = mt.run_intp_converter
+
+ def test_basic(self):
+ assert self.conv(1) == (1,)
+ assert self.conv((1, 2)) == (1, 2)
+ assert self.conv([1, 2]) == (1, 2)
+ assert self.conv(()) == ()
+
+ def test_none(self):
+ # once the warning expires, this will raise TypeError
+ with pytest.warns(DeprecationWarning):
+ assert self.conv(None) == ()
+
+ def test_float(self):
+ with pytest.raises(TypeError):
+ self.conv(1.0)
+ with pytest.raises(TypeError):
+ self.conv([1, 1.0])
+
+ def test_too_large(self):
+ with pytest.raises(ValueError):
+ self.conv(2**64)
+
+ def test_too_many_dims(self):
+ assert self.conv([1]*32) == (1,)*32
+ with pytest.raises(ValueError):
+ self.conv([1]*33)
--- /dev/null
+from numpy.core._multiarray_umath import __cpu_features__, __cpu_baseline__, __cpu_dispatch__
+from numpy.core import _umath_tests
+from numpy.testing import assert_equal
+
+def test_dispatcher():
+ """
+ Testing the utilites of the CPU dispatcher
+ """
+ targets = (
+ "SSE2", "SSE41", "AVX2",
+ "VSX", "VSX2", "VSX3",
+ "NEON", "ASIMD", "ASIMDHP"
+ )
+ highest_sfx = "" # no suffix for the baseline
+ all_sfx = []
+ for feature in reversed(targets):
+ # skip baseline features, by the default `CCompilerOpt` do not generate separated objects
+ # for the baseline, just one object combined all of them via 'baseline' option
+ # within the configuration statments.
+ if feature in __cpu_baseline__:
+ continue
+ # check compiler and running machine support
+ if feature not in __cpu_dispatch__ or not __cpu_features__[feature]:
+ continue
+
+ if not highest_sfx:
+ highest_sfx = "_" + feature
+ all_sfx.append("func" + "_" + feature)
+
+ test = _umath_tests.test_dispatch()
+ assert_equal(test["func"], "func" + highest_sfx)
+ assert_equal(test["var"], "var" + highest_sfx)
+
+ if highest_sfx:
+ assert_equal(test["func_xb"], "func" + highest_sfx)
+ assert_equal(test["var_xb"], "var" + highest_sfx)
+ else:
+ assert_equal(test["func_xb"], "nobase")
+ assert_equal(test["var_xb"], "nobase")
+
+ all_sfx.append("func") # add the baseline
+ assert_equal(test["all"], all_sfx)
--- /dev/null
+import os
+import shutil
+import subprocess
+import sys
+import pytest
+
+import numpy as np
+
+# This import is copied from random.tests.test_extending
+try:
+ import cython
+ from Cython.Compiler.Version import version as cython_version
+except ImportError:
+ cython = None
+else:
+ from distutils.version import LooseVersion
+
+ # Cython 0.29.21 is required for Python 3.9 and there are
+ # other fixes in the 0.29 series that are needed even for earlier
+ # Python versions.
+ # Note: keep in sync with the one in pyproject.toml
+ required_version = LooseVersion("0.29.21")
+ if LooseVersion(cython_version) < required_version:
+ # too old or wrong cython, skip the test
+ cython = None
+
+pytestmark = pytest.mark.skipif(cython is None, reason="requires cython")
+
+
+@pytest.fixture
+def install_temp(request, tmp_path):
+ # Based in part on test_cython from random.tests.test_extending
+
+ here = os.path.dirname(__file__)
+ ext_dir = os.path.join(here, "examples")
+
+ cytest = str(tmp_path / "cytest")
+
+ shutil.copytree(ext_dir, cytest)
+ # build the examples and "install" them into a temporary directory
+
+ install_log = str(tmp_path / "tmp_install_log.txt")
+ subprocess.check_call(
+ [
+ sys.executable,
+ "setup.py",
+ "build",
+ "install",
+ "--prefix", str(tmp_path / "installdir"),
+ "--single-version-externally-managed",
+ "--record",
+ install_log,
+ ],
+ cwd=cytest,
+ )
+
+ # In order to import the built module, we need its path to sys.path
+ # so parse that out of the record
+ with open(install_log) as fid:
+ for line in fid:
+ if "checks" in line:
+ sys.path.append(os.path.dirname(line))
+ break
+ else:
+ raise RuntimeError(f'could not parse "{install_log}"')
+
+
+def test_is_timedelta64_object(install_temp):
+ import checks
+
+ assert checks.is_td64(np.timedelta64(1234))
+ assert checks.is_td64(np.timedelta64(1234, "ns"))
+ assert checks.is_td64(np.timedelta64("NaT", "ns"))
+
+ assert not checks.is_td64(1)
+ assert not checks.is_td64(None)
+ assert not checks.is_td64("foo")
+ assert not checks.is_td64(np.datetime64("now", "s"))
+
+
+def test_is_datetime64_object(install_temp):
+ import checks
+
+ assert checks.is_dt64(np.datetime64(1234, "ns"))
+ assert checks.is_dt64(np.datetime64("NaT", "ns"))
+
+ assert not checks.is_dt64(1)
+ assert not checks.is_dt64(None)
+ assert not checks.is_dt64("foo")
+ assert not checks.is_dt64(np.timedelta64(1234))
+
+
+def test_get_datetime64_value(install_temp):
+ import checks
+
+ dt64 = np.datetime64("2016-01-01", "ns")
+
+ result = checks.get_dt64_value(dt64)
+ expected = dt64.view("i8")
+
+ assert result == expected
+
+
+def test_get_timedelta64_value(install_temp):
+ import checks
+
+ td64 = np.timedelta64(12345, "h")
+
+ result = checks.get_td64_value(td64)
+ expected = td64.view("i8")
+
+ assert result == expected
+
+
+def test_get_datetime64_unit(install_temp):
+ import checks
+
+ dt64 = np.datetime64("2016-01-01", "ns")
+ result = checks.get_dt64_unit(dt64)
+ expected = 10
+ assert result == expected
+
+ td64 = np.timedelta64(12345, "h")
+ result = checks.get_dt64_unit(td64)
+ expected = 5
+ assert result == expected
+
+
+def test_abstract_scalars(install_temp):
+ import checks
+
+ assert checks.is_integer(1)
+ assert checks.is_integer(np.int8(1))
+ assert checks.is_integer(np.uint64(1))
def test_datetime_dtype_creation(self):
for unit in ['Y', 'M', 'W', 'D',
'h', 'm', 's', 'ms', 'us',
+ 'μs', # alias for us
'ns', 'ps', 'fs', 'as']:
dt1 = np.dtype('M8[750%s]' % unit)
assert_(dt1 == np.dtype('datetime64[750%s]' % unit))
np.dtype('m8[Y]'), np.dtype('m8[D]'))
assert_raises(TypeError, np.promote_types,
np.dtype('m8[M]'), np.dtype('m8[W]'))
+ # timedelta and float cannot be safely cast with each other
+ assert_raises(TypeError, np.promote_types, "float32", "m8")
+ assert_raises(TypeError, np.promote_types, "m8", "float32")
+ assert_raises(TypeError, np.promote_types, "uint64", "m8")
+ assert_raises(TypeError, np.promote_types, "m8", "uint64")
+
# timedelta <op> timedelta may overflow with big unit ranges
assert_raises(OverflowError, np.promote_types,
np.dtype('m8[W]'), np.dtype('m8[fs]'))
'1959-10-13T12:34:56')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'ms')),
'1959-10-13T12:34:56.789')
- assert_equal(np.datetime_as_string(np.datetime64(datetime, 'us')),
- '1959-10-13T12:34:56.789012')
+ for us in ['us', 'μs', b'us']: # check non-ascii and bytes too
+ assert_equal(np.datetime_as_string(np.datetime64(datetime, us)),
+ '1959-10-13T12:34:56.789012')
datetime = '1969-12-31T23:34:56.789012345678901234'
obj_arr = np.array([None])
obj_arr[0] = a
- # gh-11154: This shouldn't cause a C stack overflow
- assert_raises(RecursionError, obj_arr.astype, 'M8')
- assert_raises(RecursionError, obj_arr.astype, 'm8')
+ # At some point this caused a stack overflow (gh-11154). Now raises
+ # ValueError since the nested list cannot be converted to a datetime.
+ assert_raises(ValueError, obj_arr.astype, 'M8')
+ assert_raises(ValueError, obj_arr.astype, 'm8')
+
+ @pytest.mark.parametrize("shape", [(), (1,)])
+ def test_discovery_from_object_array(self, shape):
+ arr = np.array("2020-10-10", dtype=object).reshape(shape)
+ res = np.array("2020-10-10", dtype="M8").reshape(shape)
+ assert res.dtype == np.dtype("M8[D]")
+ assert_equal(arr.astype("M8"), res)
+ arr[...] = np.bytes_("2020-10-10") # try a numpy string type
+ assert_equal(arr.astype("M8"), res)
+ arr = arr.astype("S")
+ assert_equal(arr.astype("S").astype("M8"), res)
@pytest.mark.parametrize("time_unit", [
"Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps", "fs", "as",
def test_basic(self):
a = np.array(['1980-03-23'], dtype=np.datetime64)
assert_equal(np.datetime_data(a.dtype), ('D', 1))
+
+ def test_bytes(self):
+ # byte units are converted to unicode
+ dt = np.datetime64('2000', (b'ms', 5))
+ assert np.datetime_data(dt.dtype) == ('ms', 5)
+
+ dt = np.datetime64('2000', b'5ms')
+ assert np.datetime_data(dt.dtype) == ('ms', 5)
+
+ def test_non_ascii(self):
+ # μs is normalized to μ
+ dt = np.datetime64('2000', ('μs', 5))
+ assert np.datetime_data(dt.dtype) == ('us', 5)
+
+ dt = np.datetime64('2000', '5μs')
+ assert np.datetime_data(dt.dtype) == ('us', 5)
def test_less(self):
assert_array_equal((self.A < self.B), [[True, False], [False, False]])
+ def test_type(self):
+ out1 = np.char.equal(self.A, self.B)
+ out2 = np.char.equal('a', 'a')
+ assert_(isinstance(out1, np.ndarray))
+ assert_(isinstance(out2, np.ndarray))
+
class TestComparisonsMixed1(TestComparisons):
"""Ticket #1276"""
import pytest
import tempfile
import re
+import sys
import numpy as np
from numpy.testing import (
kwargs : dict
Keyword arguments for `function`
"""
+ __tracebackhide__ = True # Hide traceback for py.test
+
# reset the log
self.log[:] = []
class TestNumericStyleTypecodes(_DeprecationTestCase):
"""
- Deprecate the old numeric-style dtypes, which are especially
- confusing for complex types, e.g. Complex32 -> complex64. When the
- deprecation cycle is complete, the check for the strings should be
- removed from PyArray_DescrConverter in descriptor.c, and the
- deprecated keys should not be added as capitalized aliases in
- _add_aliases in numerictypes.py.
+ Most numeric style typecodes were previously deprecated (and removed)
+ in 1.20. This also deprecates the remaining ones.
"""
+ # 2020-06-09, NumPy 1.20
def test_all_dtypes(self):
- deprecated_types = [
- 'Bool', 'Complex32', 'Complex64', 'Float16', 'Float32', 'Float64',
- 'Int8', 'Int16', 'Int32', 'Int64', 'Object0', 'Timedelta64',
- 'UInt8', 'UInt16', 'UInt32', 'UInt64', 'Void0'
- ]
+ deprecated_types = ['Bytes0', 'Datetime64', 'Str0']
+ # Depending on intp size, either Uint32 or Uint64 is defined:
+ deprecated_types.append(f"U{np.dtype(np.intp).name}")
for dt in deprecated_types:
self.assert_deprecated(np.dtype, exceptions=(TypeError,),
args=(dt,))
self.assert_deprecated(np.sum, args=((i for i in range(5)),))
-class TestSctypeNA(_VisibleDeprecationTestCase):
- # 2018-06-24, 1.16
- def test_sctypeNA(self):
- self.assert_deprecated(lambda: np.sctypeNA['?'])
- self.assert_deprecated(lambda: np.typeNA['?'])
- self.assert_deprecated(lambda: np.typeNA.get('?'))
-
-
class TestPositiveOnNonNumerical(_DeprecationTestCase):
# 2018-06-28, 1.16.0
def test_positive_on_non_number(self):
np.array(arg)
+class TestTooDeepDeprecation(_VisibleDeprecationTestCase):
+ # NumPy 1.20, 2020-05-08
+ # This is a bit similar to the above ragged array deprecation case.
+ message = re.escape("Creating an ndarray from nested sequences exceeding")
+
+ def test_deprecation(self):
+ nested = [1]
+ for i in range(np.MAXDIMS - 1):
+ nested = [nested]
+ self.assert_not_deprecated(np.array, args=(nested,))
+ self.assert_not_deprecated(np.array,
+ args=(nested,), kwargs=dict(dtype=object))
+
+ self.assert_deprecated(np.array, args=([nested],))
+
+
class TestToString(_DeprecationTestCase):
# 2020-03-06 1.19.0
message = re.escape("tostring() is deprecated. Use tobytes() instead.")
self.assert_deprecated(round, args=(scalar,))
self.assert_deprecated(round, args=(scalar, 0))
self.assert_deprecated(round, args=(scalar,), kwargs={'ndigits': 0})
-
+
def test_not_deprecated(self):
for scalar_type in self.not_deprecated_types:
scalar = scalar_type(0)
self.assert_not_deprecated(round, args=(scalar,))
self.assert_not_deprecated(round, args=(scalar, 0))
self.assert_not_deprecated(round, args=(scalar,), kwargs={'ndigits': 0})
+
+
+class TestIncorrectAdvancedIndexWithEmptyResult(_DeprecationTestCase):
+ # 2020-05-27, NumPy 1.20.0
+ message = "Out of bound index found. This was previously ignored.*"
+
+ @pytest.mark.parametrize("index", [([3, 0],), ([0, 0], [3, 0])])
+ def test_empty_subspace(self, index):
+ # Test for both a single and two/multiple advanced indices. These
+ # This will raise an IndexError in the future.
+ arr = np.ones((2, 2, 0))
+ self.assert_deprecated(arr.__getitem__, args=(index,))
+ self.assert_deprecated(arr.__setitem__, args=(index, 0.))
+
+ # for this array, the subspace is only empty after applying the slice
+ arr2 = np.ones((2, 2, 1))
+ index2 = (slice(0, 0),) + index
+ self.assert_deprecated(arr2.__getitem__, args=(index2,))
+ self.assert_deprecated(arr2.__setitem__, args=(index2, 0.))
+
+ def test_empty_index_broadcast_not_deprecated(self):
+ arr = np.ones((2, 2, 2))
+
+ index = ([[3], [2]], []) # broadcast to an empty result.
+ self.assert_not_deprecated(arr.__getitem__, args=(index,))
+ self.assert_not_deprecated(arr.__setitem__,
+ args=(index, np.empty((2, 0, 2))))
+
+
+class TestNonExactMatchDeprecation(_DeprecationTestCase):
+ # 2020-04-22
+ def test_non_exact_match(self):
+ arr = np.array([[3, 6, 6], [4, 5, 1]])
+ # misspelt mode check
+ self.assert_deprecated(lambda: np.ravel_multi_index(arr, (7, 6), mode='Cilp'))
+ # using completely different word with first character as R
+ self.assert_deprecated(lambda: np.searchsorted(arr[0], 4, side='Random'))
+
+
+class TestDeprecatedGlobals(_DeprecationTestCase):
+ # 2020-06-06
+ @pytest.mark.skipif(
+ sys.version_info < (3, 7),
+ reason='module-level __getattr__ not supported')
+ def test_type_aliases(self):
+ # from builtins
+ self.assert_deprecated(lambda: np.bool)
+ self.assert_deprecated(lambda: np.int)
+ self.assert_deprecated(lambda: np.float)
+ self.assert_deprecated(lambda: np.complex)
+ self.assert_deprecated(lambda: np.object)
+ self.assert_deprecated(lambda: np.str)
+
+ # from np.compat
+ self.assert_deprecated(lambda: np.long)
+ self.assert_deprecated(lambda: np.unicode)
+
+
+class TestMatrixInOuter(_DeprecationTestCase):
+ # 2020-05-13 NumPy 1.20.0
+ message = (r"add.outer\(\) was passed a numpy matrix as "
+ r"(first|second) argument.")
+
+ def test_deprecated(self):
+ arr = np.array([1, 2, 3])
+ m = np.array([1, 2, 3]).view(np.matrix)
+ self.assert_deprecated(np.add.outer, args=(m, m), num=2)
+ self.assert_deprecated(np.add.outer, args=(arr, m))
+ self.assert_deprecated(np.add.outer, args=(m, arr))
+ self.assert_not_deprecated(np.add.outer, args=(arr, arr))
+
+
+class TestRaggedArray(_DeprecationTestCase):
+ # 2020-07-24, NumPy 1.20.0
+ message = "setting an array element with a sequence"
+
+ def test_deprecated(self):
+ arr = np.ones((1, 1))
+ # Deprecated if the array is a leave node:
+ self.assert_deprecated(lambda: np.array([arr, 0], dtype=np.float64))
+ self.assert_deprecated(lambda: np.array([0, arr], dtype=np.float64))
+ # And when it is an assignment into a lower dimensional subarray:
+ self.assert_deprecated(lambda: np.array([arr, [0]], dtype=np.float64))
+ self.assert_deprecated(lambda: np.array([[0], arr], dtype=np.float64))
+
+
+class FlatteningConcatenateUnsafeCast(_DeprecationTestCase):
+ # NumPy 1.20, 2020-09-03
+ message = "concatenate with `axis=None` will use same-kind casting"
+
+ def test_deprecated(self):
+ self.assert_deprecated(np.concatenate,
+ args=(([0.], [1.]),),
+ kwargs=dict(axis=None, out=np.empty(2, dtype=np.int64)))
+
+ def test_not_deprecated(self):
+ self.assert_not_deprecated(np.concatenate,
+ args=(([0.], [1.]),),
+ kwargs={'axis': None, 'out': np.empty(2, dtype=np.int64),
+ 'casting': "unsafe"})
+
+ with assert_raises(TypeError):
+ # Tests should notice if the deprecation warning is given first...
+ np.concatenate(([0.], [1.]), out=np.empty(2, dtype=np.int64),
+ casting="same_kind")
+
+
+class TestDeprecateSubarrayDTypeDuringArrayCoercion(_DeprecationTestCase):
+ warning_cls = FutureWarning
+ message = "(creating|casting) an array (with|to) a subarray dtype"
+
+ def test_deprecated_array(self):
+ # Arrays are more complex, since they "broadcast" on success:
+ arr = np.array([1, 2])
+
+ self.assert_deprecated(lambda: arr.astype("(2)i,"))
+ with pytest.warns(FutureWarning):
+ res = arr.astype("(2)i,")
+
+ assert_array_equal(res, [[1, 2], [1, 2]])
+
+ self.assert_deprecated(lambda: np.array(arr, dtype="(2)i,"))
+ with pytest.warns(FutureWarning):
+ res = np.array(arr, dtype="(2)i,")
+
+ assert_array_equal(res, [[1, 2], [1, 2]])
+
+ with pytest.warns(FutureWarning):
+ res = np.array([[(1,), (2,)], arr], dtype="(2)i,")
+
+ assert_array_equal(res, [[[1, 1], [2, 2]], [[1, 2], [1, 2]]])
+
+ def test_deprecated_and_error(self):
+ # These error paths do not give a warning, but will succeed in the
+ # future.
+ arr = np.arange(5 * 2).reshape(5, 2)
+ def check():
+ with pytest.raises(ValueError):
+ arr.astype("(2,2)f")
+
+ self.assert_deprecated(check)
+
+ def check():
+ with pytest.raises(ValueError):
+ np.array(arr, dtype="(2,2)f")
+
+ self.assert_deprecated(check)
+
+
+class TestFutureWarningArrayLikeNotIterable(_DeprecationTestCase):
+ # Deprecated 2020-12-09, NumPy 1.20
+ warning_cls = FutureWarning
+ message = "The input object of type.*but not a sequence"
+
+ @pytest.mark.parametrize("protocol",
+ ["__array__", "__array_interface__", "__array_struct__"])
+ def test_deprecated(self, protocol):
+ """Test that these objects give a warning since they are not 0-D,
+ not coerced at the top level `np.array(obj)`, but nested, and do
+ *not* define the sequence protocol.
+
+ NOTE: Tests for the versions including __len__ and __getitem__ exist
+ in `test_array_coercion.py` and they can be modified or ammended
+ when this deprecation expired.
+ """
+ blueprint = np.arange(10)
+ MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol)})
+ self.assert_deprecated(lambda: np.array([MyArr()], dtype=object))
+
+ @pytest.mark.parametrize("protocol",
+ ["__array__", "__array_interface__", "__array_struct__"])
+ def test_0d_not_deprecated(self, protocol):
+ # 0-D always worked (albeit it would use __float__ or similar for the
+ # conversion, which may not happen anymore)
+ blueprint = np.array(1.)
+ MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol)})
+ myarr = MyArr()
+
+ self.assert_not_deprecated(lambda: np.array([myarr], dtype=object))
+ res = np.array([myarr], dtype=object)
+ expected = np.empty(1, dtype=object)
+ expected[0] = myarr
+ assert_array_equal(res, expected)
+
+ @pytest.mark.parametrize("protocol",
+ ["__array__", "__array_interface__", "__array_struct__"])
+ def test_unnested_not_deprecated(self, protocol):
+ blueprint = np.arange(10)
+ MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol)})
+ myarr = MyArr()
+
+ self.assert_not_deprecated(lambda: np.array(myarr))
+ res = np.array(myarr)
+ assert_array_equal(res, blueprint)
+
+ @pytest.mark.parametrize("protocol",
+ ["__array__", "__array_interface__", "__array_struct__"])
+ def test_strange_dtype_handling(self, protocol):
+ """The old code would actually use the dtype from the array, but
+ then end up not using the array (for dimension discovery)
+ """
+ blueprint = np.arange(10).astype("f4")
+ MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol),
+ "__float__": lambda _: 0.5})
+ myarr = MyArr()
+
+ # Make sure we warn (and capture the FutureWarning)
+ with pytest.warns(FutureWarning, match=self.message):
+ res = np.array([[myarr]])
+
+ assert res.shape == (1, 1)
+ assert res.dtype == "f4"
+ assert res[0, 0] == 0.5
+
+ @pytest.mark.parametrize("protocol",
+ ["__array__", "__array_interface__", "__array_struct__"])
+ def test_assignment_not_deprecated(self, protocol):
+ # If the result is dtype=object we do not unpack a nested array or
+ # array-like, if it is nested at exactly the right depth.
+ # NOTE: We actually do still call __array__, etc. but ignore the result
+ # in the end. For `dtype=object` we could optimize that away.
+ blueprint = np.arange(10).astype("f4")
+ MyArr = type("MyArr", (), {protocol: getattr(blueprint, protocol),
+ "__float__": lambda _: 0.5})
+ myarr = MyArr()
+
+ res = np.empty(3, dtype=object)
+ def set():
+ res[:] = [myarr, myarr, myarr]
+ self.assert_not_deprecated(set)
+ assert res[0] is myarr
+ assert res[1] is myarr
+ assert res[2] is myarr
+
+
+class TestDeprecatedUnpickleObjectScalar(_DeprecationTestCase):
+ # Deprecated 2020-11-24, NumPy 1.20
+ """
+ Technically, it should be impossible to create numpy object scalars,
+ but there was an unpickle path that would in theory allow it. That
+ path is invalid and must lead to the warning.
+ """
+ message = "Unpickling a scalar with object dtype is deprecated."
+
+ def test_deprecated(self):
+ ctor = np.core.multiarray.scalar
+ self.assert_deprecated(lambda: ctor(np.dtype("O"), 1))
import numpy as np
from numpy.core._rational_tests import rational
+from numpy.core._multiarray_tests import create_custom_field_dtype
from numpy.testing import (
assert_, assert_equal, assert_array_equal, assert_raises, HAS_REFCOUNT)
from numpy.compat import pickle
assert_raises(TypeError, np.dtype, 'q8')
assert_raises(TypeError, np.dtype, 'Q8')
+ @pytest.mark.parametrize("dtype",
+ ['Bool', 'Complex32', 'Complex64', 'Float16', 'Float32', 'Float64',
+ 'Int8', 'Int16', 'Int32', 'Int64', 'Object0', 'Timedelta64',
+ 'UInt8', 'UInt16', 'UInt32', 'UInt64', 'Void0',
+ "Float128", "Complex128"])
+ def test_numeric_style_types_are_invalid(self, dtype):
+ with assert_raises(TypeError):
+ np.dtype(dtype)
+
@pytest.mark.parametrize(
'value',
['m8', 'M8', 'datetime64', 'timedelta64',
'formats': ['f4', 'i4'],
'offsets': [4, 0]})
assert_equal(x == y, False)
+ # But it is currently an equivalent cast:
+ assert np.can_cast(x, y, casting="equiv")
+
class TestRecord:
def test_equivalent_record(self):
'formats':['i1', 'O'],
'offsets':[np.dtype('intp').itemsize, 0]})
+ @pytest.mark.parametrize(["obj", "dtype", "expected"],
+ [([], ("(2)f4,"), np.empty((0, 2), dtype="f4")),
+ (3, "(3)f4,", [3, 3, 3]),
+ (np.float64(2), "(2)f4,", [2, 2]),
+ ([((0, 1), (1, 2)), ((2,),)], '(2,2)f4', None),
+ (["1", "2"], "(2)i,", None)])
+ def test_subarray_list(self, obj, dtype, expected):
+ dtype = np.dtype(dtype)
+ res = np.array(obj, dtype=dtype)
+
+ if expected is None:
+ # iterate the 1-d list to fill the array
+ expected = np.empty(len(obj), dtype=dtype)
+ for i in range(len(expected)):
+ expected[i] = obj[i]
+
+ assert_array_equal(res, expected)
+
def test_comma_datetime(self):
dt = np.dtype('M8[D],datetime64[Y],i8')
assert_equal(dt, np.dtype([('f0', 'M8[D]'),
('yi', np.dtype((a, (3, 2))))])
assert_dtype_equal(c, d)
+ def test_list_recursion(self):
+ l = list()
+ l.append(('f', l))
+ with pytest.raises(RecursionError):
+ np.dtype(l)
+
+ def test_tuple_recursion(self):
+ d = np.int32
+ for i in range(100000):
+ d = (d, (1,))
+ with pytest.raises(RecursionError):
+ np.dtype(d)
+
+ def test_dict_recursion(self):
+ d = dict(names=['self'], formats=[None], offsets=[0])
+ d['formats'][0] = d
+ with pytest.raises(RecursionError):
+ np.dtype(d)
+
+
class TestMetadata:
def test_no_metadata(self):
d = np.dtype(int)
assert_raises(TypeError, np.dtype, u'Fl\xfcgel')
+def test_keyword_argument():
+ # test for https://github.com/numpy/numpy/pull/16574#issuecomment-642660971
+ assert np.dtype(dtype=np.float64) == np.dtype(np.float64)
+
+
class TestFromDTypeAttribute:
def test_simple(self):
class dt:
with pytest.raises(RecursionError):
np.dtype(dt(1))
+
+class TestDTypeClasses:
+ @pytest.mark.parametrize("dtype", list(np.typecodes['All']) + [rational])
+ def test_basic_dtypes_subclass_properties(self, dtype):
+ # Note: Except for the isinstance and type checks, these attributes
+ # are considered currently private and may change.
+ dtype = np.dtype(dtype)
+ assert isinstance(dtype, np.dtype)
+ assert type(dtype) is not np.dtype
+ assert type(dtype).__name__ == f"dtype[{dtype.type.__name__}]"
+ assert type(dtype).__module__ == "numpy"
+ assert not type(dtype)._abstract
+
+ # the flexible dtypes and datetime/timedelta have additional parameters
+ # which are more than just storage information, these would need to be
+ # given when creating a dtype:
+ parametric = (np.void, np.str_, np.bytes_, np.datetime64, np.timedelta64)
+ if dtype.type not in parametric:
+ assert not type(dtype)._parametric
+ assert type(dtype)() is dtype
+ else:
+ assert type(dtype)._parametric
+ with assert_raises(TypeError):
+ type(dtype)()
+
+ def test_dtype_superclass(self):
+ assert type(np.dtype) is not type
+ assert isinstance(np.dtype, type)
+
+ assert type(np.dtype).__name__ == "_DTypeMeta"
+ assert type(np.dtype).__module__ == "numpy"
+ assert np.dtype._abstract
+
+
class TestFromCTypes:
@staticmethod
expected = np.dtype([('f0', pair[0]), ('f1', pair[1])])
assert_equal(pair_type, expected)
+
+class TestUserDType:
+ @pytest.mark.leaks_references(reason="dynamically creates custom dtype.")
+ def test_custom_structured_dtype(self):
+ class mytype:
+ pass
+
+ blueprint = np.dtype([("field", object)])
+ dt = create_custom_field_dtype(blueprint, mytype, 0)
+ assert dt.type == mytype
+ # We cannot (currently) *create* this dtype with `np.dtype` because
+ # mytype does not inherit from `np.generic`. This seems like an
+ # unnecessary restriction, but one that has been around forever:
+ assert np.dtype(mytype) == np.dtype("O")
+
+ def test_custom_structured_dtype_errors(self):
+ class mytype:
+ pass
+
+ blueprint = np.dtype([("field", object)])
+
+ with pytest.raises(ValueError):
+ # Tests what happens if fields are unset during creation
+ # which is currently rejected due to the containing object
+ # (see PyArray_RegisterDataType).
+ create_custom_field_dtype(blueprint, mytype, 1)
+
+ with pytest.raises(RuntimeError):
+ # Tests that a dtype must have its type field set up to np.dtype
+ # or in this case a builtin instance.
+ create_custom_field_dtype(blueprint, mytype, 2)
b = np.ones((3, 4, 5))
np.einsum('aabcb,abc', a, b)
+ # Check order kwarg, asanyarray allows 1d to pass through
+ assert_raises(ValueError, np.einsum, "i->i", np.arange(6).reshape(-1, 1),
+ optimize=do_opt, order='d')
+
def test_einsum_views(self):
# pass-through
for do_opt in [True, False]:
g = np.arange(64).reshape(2, 4, 8)
self.optimize_compare('obk,ijk->ioj', operands=[g, g])
+ def test_output_order(self):
+ # Ensure output order is respected for optimize cases, the below
+ # conraction should yield a reshaped tensor view
+ # gh-16415
+
+ a = np.ones((2, 3, 5), order='F')
+ b = np.ones((4, 3), order='F')
+
+ for opt in [True, False]:
+ tmp = np.einsum('...ft,mf->...mt', a, b, order='a', optimize=opt)
+ assert_(tmp.flags.f_contiguous)
+
+ tmp = np.einsum('...ft,mf->...mt', a, b, order='f', optimize=opt)
+ assert_(tmp.flags.f_contiguous)
+
+ tmp = np.einsum('...ft,mf->...mt', a, b, order='c', optimize=opt)
+ assert_(tmp.flags.c_contiguous)
+
+ tmp = np.einsum('...ft,mf->...mt', a, b, order='k', optimize=opt)
+ assert_(tmp.flags.c_contiguous is False)
+ assert_(tmp.flags.f_contiguous is False)
+
+ tmp = np.einsum('...ft,mf->...mt', a, b, optimize=opt)
+ assert_(tmp.flags.c_contiguous is False)
+ assert_(tmp.flags.f_contiguous is False)
+
+ c = np.ones((4, 3), order='C')
+ for opt in [True, False]:
+ tmp = np.einsum('...ft,mf->...mt', a, c, order='a', optimize=opt)
+ assert_(tmp.flags.c_contiguous)
+
+ d = np.ones((2, 3, 5), order='C')
+ for opt in [True, False]:
+ tmp = np.einsum('...ft,mf->...mt', d, c, order='a', optimize=opt)
+ assert_(tmp.flags.c_contiguous)
class TestEinsumPath:
def build_operands(self, string, size_dict=global_size_dict):
from numpy import (
logspace, linspace, geomspace, dtype, array, sctypes, arange, isnan,
- ndarray, sqrt, nextafter, stack
+ ndarray, sqrt, nextafter, stack, errstate
)
from numpy.testing import (
assert_, assert_equal, assert_raises, assert_array_equal, assert_allclose,
assert_array_equal(y, [-100, -10, -1])
assert_array_equal(y.imag, 0)
+ def test_boundaries_match_start_and_stop_exactly(self):
+ # make sure that the boundaries of the returned array exactly
+ # equal 'start' and 'stop' - this isn't obvious because
+ # np.exp(np.log(x)) isn't necessarily exactly equal to x
+ start = 0.3
+ stop = 20.3
+
+ y = geomspace(start, stop, num=1)
+ assert_equal(y[0], start)
+
+ y = geomspace(start, stop, num=1, endpoint=False)
+ assert_equal(y[0], start)
+
+ y = geomspace(start, stop, num=3)
+ assert_equal(y[0], start)
+ assert_equal(y[-1], stop)
+
+ y = geomspace(start, stop, num=3, endpoint=False)
+ assert_equal(y[0], start)
+
+ def test_nan_interior(self):
+ with errstate(invalid='ignore'):
+ y = geomspace(-3, 3, num=4)
+
+ assert_equal(y[0], -3.0)
+ assert_(isnan(y[1:-1]).all())
+ assert_equal(y[3], 3.0)
+
+ with errstate(invalid='ignore'):
+ y = geomspace(-3, 3, num=4, endpoint=False)
+
+ assert_equal(y[0], -3.0)
+ assert_(isnan(y[1:]).all())
+
def test_complex(self):
# Purely imaginary
y = geomspace(1j, 16j, num=5)
stop = array(2, dtype='O')
y = linspace(start, stop, 3)
assert_array_equal(y, array([1., 1.5, 2.]))
+
+ def test_round_negative(self):
+ y = linspace(-1, 3, num=8, dtype=int)
+ t = array([-1, -1, 0, 0, 1, 1, 2, 3], dtype=int)
+ assert_array_equal(y, t)
j = np.array(i_f16, dtype=int)
assert_equal(i_int, j)
+ @pytest.mark.parametrize("string_dt", ["S", "U"])
+ def test_half_conversion_to_string(self, string_dt):
+ # Currently uses S/U32 (which is sufficient for float32)
+ expected_dt = np.dtype(f"{string_dt}32")
+ assert np.promote_types(np.float16, string_dt) == expected_dt
+ assert np.promote_types(string_dt, np.float16) == expected_dt
+
+ arr = np.ones(3, dtype=np.float16).astype(string_dt)
+ assert arr.dtype == expected_dt
+
+ @pytest.mark.parametrize("string_dt", ["S", "U"])
+ def test_half_conversion_from_string(self, string_dt):
+ string = np.array("3.1416", dtype=string_dt)
+ assert string.astype(np.float16) == np.array(3.1416, dtype=np.float16)
+
@pytest.mark.parametrize("offset", [None, "up", "down"])
@pytest.mark.parametrize("shift", [None, "up", "down"])
@pytest.mark.parametrize("float_t", [np.float32, np.float64])
import functools
import operator
+import pytest
+
import numpy as np
from numpy.core._multiarray_tests import array_indexing
from itertools import product
from numpy.testing import (
- assert_, assert_equal, assert_raises, assert_array_equal, assert_warns,
- HAS_REFCOUNT,
+ assert_, assert_equal, assert_raises, assert_raises_regex,
+ assert_array_equal, assert_warns, HAS_REFCOUNT,
)
a[...] = s
assert_((a == 1).all())
+ def test_array_like_values(self):
+ # Similar to the above test, but use a memoryview instead
+ a = np.zeros((5, 5))
+ s = np.arange(25, dtype=np.float64).reshape(5, 5)
+
+ a[[0, 1, 2, 3, 4], :] = memoryview(s)
+ assert_array_equal(a, s)
+
+ a[:, [0, 1, 2, 3, 4]] = memoryview(s)
+ assert_array_equal(a, s)
+
+ a[...] = memoryview(s)
+ assert_array_equal(a, s)
+
def test_subclass_writeable(self):
d = np.rec.array([('NGC1001', 11), ('NGC1002', 1.), ('NGC1003', 1.)],
dtype=[('target', 'S20'), ('V_mag', '>f4')])
arr[slices] = 10
assert_array_equal(arr, 10.)
+ def test_character_assignment(self):
+ # This is an example a function going through CopyObject which
+ # used to have an untested special path for scalars
+ # (the character special dtype case, should be deprecated probably)
+ arr = np.zeros((1, 5), dtype="c")
+ arr[0] = np.str_("asdfg") # must assign as a sequence
+ assert_array_equal(arr[0], np.array("asdfg", dtype="c"))
+ assert arr[0, 1] == b"s" # make sure not all were set to "a" for both
+
+ @pytest.mark.parametrize("index",
+ [True, False, np.array([0])])
+ @pytest.mark.parametrize("num", [32, 40])
+ @pytest.mark.parametrize("original_ndim", [1, 32])
+ def test_too_many_advanced_indices(self, index, num, original_ndim):
+ # These are limitations based on the number of arguments we can process.
+ # For `num=32` (and all boolean cases), the result is actually define;
+ # but the use of NpyIter (NPY_MAXARGS) limits it for technical reasons.
+ arr = np.ones((1,) * original_ndim)
+ with pytest.raises(IndexError):
+ arr[(index,) * num]
+ with pytest.raises(IndexError):
+ arr[(index,) * num] = 1.
+
+
class TestFieldIndexing:
def test_scalar_return_type(self):
# Field access on an array should return an array, even if it
assert_raises(IndexError, lambda: a[False, [0, 1], ...])
+ def test_boolean_indexing_fast_path(self):
+ # These used to either give the wrong error, or incorrectly give no
+ # error.
+ a = np.ones((3, 3))
+
+ # This used to incorrectly work (and give an array of shape (0,))
+ idx1 = np.array([[False]*9])
+ assert_raises_regex(IndexError,
+ "boolean index did not match indexed array along dimension 0; "
+ "dimension is 3 but corresponding boolean dimension is 1",
+ lambda: a[idx1])
+
+ # This used to incorrectly give a ValueError: operands could not be broadcast together
+ idx2 = np.array([[False]*8 + [True]])
+ assert_raises_regex(IndexError,
+ "boolean index did not match indexed array along dimension 0; "
+ "dimension is 3 but corresponding boolean dimension is 1",
+ lambda: a[idx2])
+
+ # This is the same as it used to be. The above two should work like this.
+ idx3 = np.array([[False]*10])
+ assert_raises_regex(IndexError,
+ "boolean index did not match indexed array along dimension 0; "
+ "dimension is 3 but corresponding boolean dimension is 1",
+ lambda: a[idx3])
+
+ # This used to give ValueError: non-broadcastable operand
+ a = np.ones((1, 1, 2))
+ idx = np.array([[[True], [False]]])
+ assert_raises_regex(IndexError,
+ "boolean index did not match indexed array along dimension 1; "
+ "dimension is 1 but corresponding boolean dimension is 2",
+ lambda: a[idx])
+
+
class TestArrayToIndexDeprecation:
"""Creating an an index from array not 0-D is an error.
from numpy import arange, allclose, asarray
from numpy.testing import (
- assert_, assert_equal, assert_array_equal, suppress_warnings
+ assert_, assert_equal, assert_array_equal, suppress_warnings, IS_PYPY,
+ break_cycles
)
class TestMemmap:
def teardown(self):
self.tmpfp.close()
+ self.data = None
+ if IS_PYPY:
+ break_cycles()
+ break_cycles()
shutil.rmtree(self.tempdir)
def test_roundtrip(self):
from decimal import Decimal
import numpy as np
-from numpy.compat import strchar
import numpy.core._multiarray_tests as _multiarray_tests
+from numpy.core._rational_tests import rational
from numpy.testing import (
assert_, assert_raises, assert_warns, assert_equal, assert_almost_equal,
assert_array_equal, assert_raises_regex, assert_array_almost_equal,
a[2] = 10
# only warn once
assert_(len(w) == 1)
+
+ @pytest.mark.parametrize(["flag", "flag_value", "writeable"],
+ [("writeable", True, True),
+ # Delete _warn_on_write after deprecation and simplify
+ # the parameterization:
+ ("_warn_on_write", True, False),
+ ("writeable", False, False)])
+ def test_readonly_flag_protocols(self, flag, flag_value, writeable):
+ a = np.arange(10)
+ setattr(a.flags, flag, flag_value)
+
+ class MyArr():
+ __array_struct__ = a.__array_struct__
+
+ assert memoryview(a).readonly is not writeable
+ assert a.__array_interface__['data'][1] is not writeable
+ assert np.asarray(MyArr()).flags.writeable is writeable
def test_otherflags(self):
assert_equal(self.a.flags.carray, True)
assert_raises(ValueError, np.array, x())
- @pytest.mark.parametrize("error", [RecursionError, MemoryError])
- @pytest.mark.parametrize("attribute",
- ["__array_interface__", "__array__", "__array_struct__"])
- def test_bad_array_like_attributes(self, attribute, error):
- # Check that errors during attribute retrieval are raised unless
- # they are Attribute errors.
-
- class BadInterface:
- def __getattr__(self, attr):
- if attr == attribute:
- raise error
- super().__getattr__(attr)
-
- with pytest.raises(error):
- np.array(BadInterface())
-
- @pytest.mark.parametrize("error", [RecursionError, MemoryError])
- def test_bad_array_like_bad_length(self, error):
- # RecursionError and MemoryError are considered "critical" in
- # sequences. We could expand this more generally though. (NumPy 1.20)
- class BadSequence:
- def __len__(self):
- raise error
- def __getitem__(self):
- # must have getitem to be a Sequence
- return 1
-
- with pytest.raises(error):
- np.array(BadSequence())
-
-
def test_from_string(self):
types = np.typecodes['AllInteger'] + np.typecodes['Float']
nstr = ['123', '123']
def test_void(self):
arr = np.array([], dtype='V')
- assert_equal(arr.dtype.kind, 'V')
+ assert arr.dtype == 'V8' # current default
+ # Same length scalars (those that go to the same void) work:
+ arr = np.array([b"1234", b"1234"], dtype="V")
+ assert arr.dtype == "V4"
+
+ # Promoting different lengths will fail (pre 1.20 this worked)
+ # by going via S5 and casting to V5.
+ with pytest.raises(TypeError):
+ np.array([b"1234", b"12345"], dtype="V")
+ with pytest.raises(TypeError):
+ np.array([b"12345", b"1234"], dtype="V")
+
+ # Check the same for the casting path:
+ arr = np.array([b"1234", b"1234"], dtype="O").astype("V")
+ assert arr.dtype == "V4"
+ with pytest.raises(TypeError):
+ np.array([b"1234", b"12345"], dtype="O").astype("V")
+
+ @pytest.mark.parametrize("idx",
+ [pytest.param(Ellipsis, id="arr"), pytest.param((), id="scalar")])
+ def test_structured_void_promotion(self, idx):
+ arr = np.array(
+ [np.array(1, dtype="i,i")[idx], np.array(2, dtype='i,i')[idx]],
+ dtype="V")
+ assert_array_equal(arr, np.array([(1, 1), (2, 2)], dtype="i,i"))
+ # The following fails to promote the two dtypes, resulting in an error
+ with pytest.raises(TypeError):
+ np.array(
+ [np.array(1, dtype="i,i")[idx], np.array(2, dtype='i,i,i')[idx]],
+ dtype="V")
+
def test_too_big_error(self):
# 45341 is the smallest integer greater than sqrt(2**31 - 1).
d = np.empty(i, dtype='U')
str(d)
- def test_sequence_non_homogenous(self):
+ def test_sequence_non_homogeneous(self):
assert_equal(np.array([4, 2**80]).dtype, object)
assert_equal(np.array([4, 2**80, 4]).dtype, object)
assert_equal(np.array([2**80, 4]).dtype, object)
with assert_raises(ValueError):
a[:] = C() # Segfault!
+ np.array(C()) == list(C())
+
def test_failed_len_sequence(self):
# gh-7393
class A:
assert_raises(ValueError, lambda : a[['b','b']]) # field exists, but repeated
a[['b','c']] # no exception
+ def test_structured_asarray_is_view(self):
+ # A scalar viewing an array preserves its view even when creating a
+ # new array. This test documents behaviour, it may not be the best
+ # desired behaviour.
+ arr = np.array([1], dtype="i,i")
+ scalar = arr[0]
+ assert not scalar.flags.owndata # view into the array
+ assert np.asarray(scalar).base is scalar
+ # But never when a dtype is passed in:
+ assert np.asarray(scalar, dtype=scalar.dtype).base is None
+ # A scalar which owns its data does not have this property.
+ # It is not easy to create one, one method is to use pickle:
+ scalar = pickle.loads(pickle.dumps(scalar))
+ assert scalar.flags.owndata
+ assert np.asarray(scalar).base is None
class TestBool:
def test_test_interning(self):
sort_kinds = ['quicksort', 'heapsort', 'stable']
+ def test_all_where(self):
+ a = np.array([[True, False, True],
+ [False, False, False],
+ [True, True, True]])
+ wh_full = np.array([[True, False, True],
+ [False, False, False],
+ [True, False, True]])
+ wh_lower = np.array([[False],
+ [False],
+ [True]])
+ for _ax in [0, None]:
+ assert_equal(a.all(axis=_ax, where=wh_lower),
+ np.all(a[wh_lower[:,0],:], axis=_ax))
+ assert_equal(np.all(a, axis=_ax, where=wh_lower),
+ a[wh_lower[:,0],:].all(axis=_ax))
+
+ assert_equal(a.all(where=wh_full), True)
+ assert_equal(np.all(a, where=wh_full), True)
+ assert_equal(a.all(where=False), True)
+ assert_equal(np.all(a, where=False), True)
+
+ def test_any_where(self):
+ a = np.array([[True, False, True],
+ [False, False, False],
+ [True, True, True]])
+ wh_full = np.array([[False, True, False],
+ [True, True, True],
+ [False, False, False]])
+ wh_middle = np.array([[False],
+ [True],
+ [False]])
+ for _ax in [0, None]:
+ assert_equal(a.any(axis=_ax, where=wh_middle),
+ np.any(a[wh_middle[:,0],:], axis=_ax))
+ assert_equal(np.any(a, axis=_ax, where=wh_middle),
+ a[wh_middle[:,0],:].any(axis=_ax))
+ assert_equal(a.any(where=wh_full), False)
+ assert_equal(np.any(a, where=wh_full), False)
+ assert_equal(a.any(where=False), False)
+ assert_equal(np.any(a, where=False), False)
+
def test_compress(self):
tgt = [[5, 6, 7, 8, 9]]
arr = np.arange(10).reshape(2, 5)
# gh-12031, caused SEGFAULT
assert_raises(TypeError, oned.choose,np.void(0), [oned])
+ out = np.array(0)
+ ret = np.choose(np.array(1), [10, 20, 30], out=out)
+ assert out is ret
+ assert_equal(out[()], 20)
+
# gh-6272 check overlap on out
x = np.arange(5)
y = np.choose([0,0,0], [x[:3], x[:3], x[:3]], out=x[1:4], mode='wrap')
out = np.zeros_like(arr)
res = arr.round(*round_args, out=out)
assert_equal(out, expected)
- assert_equal(out, res)
+ assert out is res
check_round(np.array([1.2, 1.5]), [1, 2])
check_round(np.array(1.5), 2)
strtype = '>i2'
else:
strtype = '<i2'
- mydtype = [('name', strchar + '5'), ('col2', strtype)]
+ mydtype = [('name', 'U5'), ('col2', strtype)]
r = np.array([('a', 1), ('b', 255), ('c', 3), ('d', 258)],
dtype=mydtype)
r.sort(order='col2')
# check double
a = np.array([0, 1, np.nan])
msg = "Test real searchsorted with nans, side='l'"
- b = a.searchsorted(a, side='l')
+ b = a.searchsorted(a, side='left')
assert_equal(b, np.arange(3), msg)
msg = "Test real searchsorted with nans, side='r'"
- b = a.searchsorted(a, side='r')
+ b = a.searchsorted(a, side='right')
assert_equal(b, np.arange(1, 4), msg)
# check keyword arguments
a.searchsorted(v=1)
a.real += [0, 0, 1, 1, 0, 1, np.nan, np.nan, np.nan]
a.imag += [0, 1, 0, 1, np.nan, np.nan, 0, 1, np.nan]
msg = "Test complex searchsorted with nans, side='l'"
- b = a.searchsorted(a, side='l')
+ b = a.searchsorted(a, side='left')
assert_equal(b, np.arange(9), msg)
msg = "Test complex searchsorted with nans, side='r'"
- b = a.searchsorted(a, side='r')
+ b = a.searchsorted(a, side='right')
assert_equal(b, np.arange(1, 10), msg)
msg = "Test searchsorted with little endian, side='l'"
a = np.array([0, 128], dtype='<i4')
# Check 0 elements
a = np.ones(0)
- b = a.searchsorted([0, 1, 2], 'l')
+ b = a.searchsorted([0, 1, 2], 'left')
assert_equal(b, [0, 0, 0])
- b = a.searchsorted([0, 1, 2], 'r')
+ b = a.searchsorted([0, 1, 2], 'right')
assert_equal(b, [0, 0, 0])
a = np.ones(1)
# Check 1 element
- b = a.searchsorted([0, 1, 2], 'l')
+ b = a.searchsorted([0, 1, 2], 'left')
assert_equal(b, [0, 0, 1])
- b = a.searchsorted([0, 1, 2], 'r')
+ b = a.searchsorted([0, 1, 2], 'right')
assert_equal(b, [0, 1, 1])
# Check all elements equal
a = np.ones(2)
- b = a.searchsorted([0, 1, 2], 'l')
+ b = a.searchsorted([0, 1, 2], 'left')
assert_equal(b, [0, 0, 2])
- b = a.searchsorted([0, 1, 2], 'r')
+ b = a.searchsorted([0, 1, 2], 'right')
assert_equal(b, [0, 2, 2])
# Test searching unaligned array
unaligned = aligned[1:].view(a.dtype)
unaligned[:] = a
# Test searching unaligned array
- b = unaligned.searchsorted(a, 'l')
+ b = unaligned.searchsorted(a, 'left')
assert_equal(b, a)
- b = unaligned.searchsorted(a, 'r')
+ b = unaligned.searchsorted(a, 'right')
assert_equal(b, a + 1)
# Test searching for unaligned keys
- b = a.searchsorted(unaligned, 'l')
+ b = a.searchsorted(unaligned, 'left')
assert_equal(b, a)
- b = a.searchsorted(unaligned, 'r')
+ b = a.searchsorted(unaligned, 'right')
assert_equal(b, a + 1)
# Test smart resetting of binsearch indices
a = np.arange(5)
- b = a.searchsorted([6, 5, 4], 'l')
+ b = a.searchsorted([6, 5, 4], 'left')
assert_equal(b, [5, 5, 4])
- b = a.searchsorted([6, 5, 4], 'r')
+ b = a.searchsorted([6, 5, 4], 'right')
assert_equal(b, [5, 5, 5])
# Test all type specific binary search functions
else:
a = np.arange(0, 5, dtype=dt)
out = np.arange(5)
- b = a.searchsorted(a, 'l')
+ b = a.searchsorted(a, 'left')
assert_equal(b, out)
- b = a.searchsorted(a, 'r')
+ b = a.searchsorted(a, 'right')
assert_equal(b, out + 1)
# Test empty array, use a fresh array to get warnings in
# valgrind if access happens.
e = np.ndarray(shape=0, buffer=b'', dtype=dt)
- b = e.searchsorted(a, 'l')
+ b = e.searchsorted(a, 'left')
assert_array_equal(b, np.zeros(len(a), dtype=np.intp))
- b = a.searchsorted(e, 'l')
+ b = a.searchsorted(e, 'left')
assert_array_equal(b, np.zeros(0, dtype=np.intp))
def test_searchsorted_unicode(self):
s = a.argsort()
k = [0, 1, 2, 3, 5]
expected = [0, 20, 40, 60, 80]
- assert_equal(a.searchsorted(k, side='l', sorter=s), expected)
+ assert_equal(a.searchsorted(k, side='left', sorter=s), expected)
expected = [20, 40, 60, 80, 100]
- assert_equal(a.searchsorted(k, side='r', sorter=s), expected)
+ assert_equal(a.searchsorted(k, side='right', sorter=s), expected)
# Test searching unaligned array
keys = np.arange(10)
unaligned = aligned[1:].view(a.dtype)
# Test searching unaligned array
unaligned[:] = a
- b = unaligned.searchsorted(keys, 'l', s)
+ b = unaligned.searchsorted(keys, 'left', s)
assert_equal(b, keys)
- b = unaligned.searchsorted(keys, 'r', s)
+ b = unaligned.searchsorted(keys, 'right', s)
assert_equal(b, keys + 1)
# Test searching for unaligned keys
unaligned[:] = keys
- b = a.searchsorted(unaligned, 'l', s)
+ b = a.searchsorted(unaligned, 'left', s)
assert_equal(b, keys)
- b = a.searchsorted(unaligned, 'r', s)
+ b = a.searchsorted(unaligned, 'right', s)
assert_equal(b, keys + 1)
# Test all type specific indirect binary search functions
# from np.intp in all platforms, to check for #4698
s = np.array([4, 2, 3, 0, 1], dtype=np.int16)
out = np.array([3, 4, 1, 2, 0], dtype=np.intp)
- b = a.searchsorted(a, 'l', s)
+ b = a.searchsorted(a, 'left', s)
assert_equal(b, out)
- b = a.searchsorted(a, 'r', s)
+ b = a.searchsorted(a, 'right', s)
assert_equal(b, out + 1)
# Test empty array, use a fresh array to get warnings in
# valgrind if access happens.
e = np.ndarray(shape=0, buffer=b'', dtype=dt)
- b = e.searchsorted(a, 'l', s[:0])
+ b = e.searchsorted(a, 'left', s[:0])
assert_array_equal(b, np.zeros(len(a), dtype=np.intp))
- b = a.searchsorted(e, 'l', s)
+ b = a.searchsorted(e, 'left', s)
assert_array_equal(b, np.zeros(0, dtype=np.intp))
# Test non-contiguous sorter array
srt[::2] = [4, 2, 3, 0, 1]
s = srt[::2]
out = np.array([3, 4, 1, 2, 0], dtype=np.intp)
- b = a.searchsorted(a, 'l', s)
+ b = a.searchsorted(a, 'left', s)
assert_equal(b, out)
- b = a.searchsorted(a, 'r', s)
+ b = a.searchsorted(a, 'right', s)
assert_equal(b, out + 1)
def test_searchsorted_return_type(self):
a = np.arange(5).view(A)
b = np.arange(1, 3).view(A)
s = np.arange(5).view(A)
- assert_(not isinstance(a.searchsorted(b, 'l'), A))
- assert_(not isinstance(a.searchsorted(b, 'r'), A))
- assert_(not isinstance(a.searchsorted(b, 'l', s), A))
- assert_(not isinstance(a.searchsorted(b, 'r', s), A))
+ assert_(not isinstance(a.searchsorted(b, 'left'), A))
+ assert_(not isinstance(a.searchsorted(b, 'right'), A))
+ assert_(not isinstance(a.searchsorted(b, 'left', s), A))
+ assert_(not isinstance(a.searchsorted(b, 'right', s), A))
def test_argpartition_out_of_range(self):
# Test out of range values in kth raise an error, gh-5469
assert_equal(b.trace(0, 1, 2), [3, 11])
assert_equal(b.trace(offset=1, axis1=0, axis2=2), [1, 3])
+ out = np.array(1)
+ ret = a.trace(out=out)
+ assert ret is out
+
def test_trace_subclass(self):
# The class would need to overwrite trace to ensure single-element
# output also has the right subclass.
with pytest.raises(ImportError):
array.__reduce_ex__(5)
- elif sys.version_info[:2] < (3, 6):
- # when calling __reduce_ex__ explicitly with protocol=5 on python
- # raise a ValueError saying that protocol 5 is not available for
- # this python version
- with pytest.raises(ValueError):
- array.__reduce_ex__(5)
-
def test_record_array_with_object_dtype(self):
my_object = object()
a.argmax(-1, out=out)
assert_equal(out, a.argmax(-1))
+ @pytest.mark.parametrize('ndim', [0, 1])
+ def test_ret_is_out(self, ndim):
+ a = np.ones((4,) + (3,)*ndim)
+ out = np.empty((3,)*ndim, dtype=np.intp)
+ ret = a.argmax(axis=0, out=out)
+ assert ret is out
+
def test_argmax_unicode(self):
d = np.zeros(6031, dtype='<U9')
d[5942] = "as"
a.argmin(-1, out=out)
assert_equal(out, a.argmin(-1))
+ @pytest.mark.parametrize('ndim', [0, 1])
+ def test_ret_is_out(self, ndim):
+ a = np.ones((4,) + (3,)*ndim)
+ out = np.empty((3,)*ndim, dtype=np.intp)
+ ret = a.argmin(axis=0, out=out)
+ assert ret is out
+
def test_argmin_unicode(self):
d = np.ones(6031, dtype='<U9')
d[6001] = "0"
y = np.take(x, [1, 2, 3], out=x[2:5], mode='wrap')
assert_equal(y, np.array([1, 2, 3]))
+ @pytest.mark.parametrize('shape', [(1, 2), (1,), ()])
+ def test_ret_is_out(self, shape):
+ # 0d arrays should not be an exception to this rule
+ x = np.arange(5)
+ inds = np.zeros(shape, dtype=np.intp)
+ out = np.zeros(shape, dtype=x.dtype)
+ ret = np.take(x, inds, out=out)
+ assert ret is out
+
+
class TestLexsort:
@pytest.mark.parametrize('dtype',[
np.uint8, np.uint16, np.uint32, np.uint64,
e = np.array([-25041670086757, 104783749223640], dtype=np.int64)
assert_array_equal(d, e)
+ def test_fromstring_count0(self):
+ d = np.fromstring("1,2", sep=",", dtype=np.int64, count=0)
+ assert d.shape == (0,)
+
def test_empty_files_binary(self):
with open(self.filename, 'w') as f:
pass
with assert_raises(np.core._exceptions.AxisError):
np.arange(10).mean(axis=2)
+ def test_mean_where(self):
+ a = np.arange(16).reshape((4, 4))
+ wh_full = np.array([[False, True, False, True],
+ [True, False, True, False],
+ [True, True, False, False],
+ [False, False, True, True]])
+ wh_partial = np.array([[False],
+ [True],
+ [True],
+ [False]])
+ _cases = [(1, True, [1.5, 5.5, 9.5, 13.5]),
+ (0, wh_full, [6., 5., 10., 9.]),
+ (1, wh_full, [2., 5., 8.5, 14.5]),
+ (0, wh_partial, [6., 7., 8., 9.])]
+ for _ax, _wh, _res in _cases:
+ assert_allclose(a.mean(axis=_ax, where=_wh),
+ np.array(_res))
+ assert_allclose(np.mean(a, axis=_ax, where=_wh),
+ np.array(_res))
+ with pytest.warns(RuntimeWarning) as w:
+ assert_allclose(a.mean(axis=1, where=wh_partial),
+ np.array([np.nan, 5.5, 9.5, np.nan]))
+ with pytest.warns(RuntimeWarning) as w:
+ assert_equal(a.mean(where=False), np.nan)
+ with pytest.warns(RuntimeWarning) as w:
+ assert_equal(np.mean(a, where=False), np.nan)
+
def test_var_values(self):
for mat in [self.rmat, self.cmat, self.omat]:
for axis in [0, 1, None]:
with assert_raises(np.core._exceptions.AxisError):
np.arange(10).var(axis=2)
+ def test_var_where(self):
+ a = np.arange(25).reshape((5, 5))
+ wh_full = np.array([[False, True, False, True, True],
+ [True, False, True, True, False],
+ [True, True, False, False, True],
+ [False, True, True, False, True],
+ [True, False, True, True, False]])
+ wh_partial = np.array([[False],
+ [True],
+ [True],
+ [False],
+ [True]])
+ _cases = [(0, True, [50., 50., 50., 50., 50.]),
+ (1, True, [2., 2., 2., 2., 2.])]
+ for _ax, _wh, _res in _cases:
+ assert_allclose(a.var(axis=_ax, where=_wh),
+ np.array(_res))
+ assert_allclose(np.var(a, axis=_ax, where=_wh),
+ np.array(_res))
+ assert_allclose(np.var(a, axis=1, where=wh_full),
+ np.var(a[wh_full].reshape((5, 3)), axis=1))
+ assert_allclose(np.var(a, axis=0, where=wh_partial),
+ np.var(a[wh_partial[:,0]], axis=0))
+ with pytest.warns(RuntimeWarning) as w:
+ assert_equal(a.var(where=False), np.nan)
+ with pytest.warns(RuntimeWarning) as w:
+ assert_equal(np.var(a, where=False), np.nan)
+
def test_std_values(self):
for mat in [self.rmat, self.cmat, self.omat]:
for axis in [0, 1, None]:
res = _std(mat, axis=axis)
assert_almost_equal(res, tgt)
+ def test_std_where(self):
+ a = np.arange(25).reshape((5,5))[::-1]
+ whf = np.array([[False, True, False, True, True],
+ [True, False, True, False, True],
+ [True, True, False, True, False],
+ [True, False, True, True, False],
+ [False, True, False, True, True]])
+ whp = np.array([[False],
+ [False],
+ [True],
+ [True],
+ [False]])
+ _cases = [
+ (0, True, 7.07106781*np.ones((5))),
+ (1, True, 1.41421356*np.ones((5))),
+ (0, whf,
+ np.array([4.0824829 , 8.16496581, 5., 7.39509973, 8.49836586])),
+ (0, whp, 2.5*np.ones((5)))
+ ]
+ for _ax, _wh, _res in _cases:
+ assert_allclose(a.std(axis=_ax, where=_wh), _res)
+ assert_allclose(np.std(a, axis=_ax, where=_wh), _res)
+
+ assert_allclose(a.std(axis=1, where=whf),
+ np.std(a[whf].reshape((5,3)), axis=1))
+ assert_allclose(np.std(a, axis=1, where=whf),
+ (a[whf].reshape((5,3))).std(axis=1))
+ assert_allclose(a.std(axis=0, where=whp),
+ np.std(a[whp[:,0]], axis=0))
+ assert_allclose(np.std(a, axis=0, where=whp),
+ (a[whp[:,0]]).std(axis=0))
+ with pytest.warns(RuntimeWarning) as w:
+ assert_equal(a.std(where=False), np.nan)
+ with pytest.warns(RuntimeWarning) as w:
+ assert_equal(np.std(a, where=False), np.nan)
+
def test_subclass(self):
class TestArray(np.ndarray):
def __new__(cls, data, info):
assert_equal(np.dot(b, a), res)
assert_equal(np.dot(b, b), res)
- def test_accelerate_framework_sgemv_fix(self):
-
- def aligned_array(shape, align, dtype, order='C'):
- d = dtype(0)
- N = np.prod(shape)
- tmp = np.zeros(N * d.nbytes + align, dtype=np.uint8)
- address = tmp.__array_interface__["data"][0]
- for offset in range(align):
- if (address + offset) % align == 0:
- break
- tmp = tmp[offset:offset+N*d.nbytes].view(dtype=dtype)
- return tmp.reshape(shape, order=order)
-
- def as_aligned(arr, align, dtype, order='C'):
- aligned = aligned_array(arr.shape, align, dtype, order)
- aligned[:] = arr[:]
- return aligned
-
- def assert_dot_close(A, X, desired):
- assert_allclose(np.dot(A, X), desired, rtol=1e-5, atol=1e-7)
-
- m = aligned_array(100, 15, np.float32)
- s = aligned_array((100, 100), 15, np.float32)
- np.dot(s, m) # this will always segfault if the bug is present
-
- testdata = itertools.product((15,32), (10000,), (200,89), ('C','F'))
- for align, m, n, a_order in testdata:
- # Calculation in double precision
- A_d = np.random.rand(m, n)
- X_d = np.random.rand(n)
- desired = np.dot(A_d, X_d)
- # Calculation with aligned single precision
- A_f = as_aligned(A_d, align, np.float32, order=a_order)
- X_f = as_aligned(X_d, align, np.float32)
- assert_dot_close(A_f, X_f, desired)
- # Strided A rows
- A_d_2 = A_d[::2]
- desired = np.dot(A_d_2, X_d)
- A_f_2 = A_f[::2]
- assert_dot_close(A_f_2, X_f, desired)
- # Strided A columns, strided X vector
- A_d_22 = A_d_2[:, ::2]
- X_d_2 = X_d[::2]
- desired = np.dot(A_d_22, X_d_2)
- A_f_22 = A_f_2[:, ::2]
- X_f_2 = X_f[::2]
- assert_dot_close(A_f_22, X_f_2, desired)
- # Check the strides are as expected
- if a_order == 'F':
- assert_equal(A_f_22.strides, (8, 8 * m))
- else:
- assert_equal(A_f_22.strides, (8 * n, 8))
- assert_equal(X_f_2.strides, (8,))
- # Strides in A rows + cols only
- X_f_2c = as_aligned(X_f_2, align, np.float32)
- assert_dot_close(A_f_22, X_f_2c, desired)
- # Strides just in A cols
- A_d_12 = A_d[:, ::2]
- desired = np.dot(A_d_12, X_d_2)
- A_f_12 = A_f[:, ::2]
- assert_dot_close(A_f_12, X_f_2c, desired)
- # Strides in A cols and X
- assert_dot_close(A_f_12, X_f_2, desired)
-
class MatmulCommon:
"""Common tests for '@' operator and numpy.matmul.
_multiarray_tests.get_buffer_info,
np.arange(5)[::2], ('SIMPLE',))
+ @pytest.mark.parametrize(["obj", "error"], [
+ pytest.param(np.array([1, 2], dtype=rational), ValueError, id="array"),
+ pytest.param(rational(1, 2), TypeError, id="scalar")])
+ def test_export_and_pickle_user_dtype(self, obj, error):
+ # User dtypes should export successfully when FORMAT was not requested.
+ with pytest.raises(error):
+ _multiarray_tests.get_buffer_info(obj, ("STRIDED_RO", "FORMAT"))
+
+ _multiarray_tests.get_buffer_info(obj, ("STRIDED_RO",))
+
+ # This is currently also necessary to implement pickling:
+ pickle_obj = pickle.dumps(obj)
+ res = pickle.loads(pickle_obj)
+ assert_array_equal(res, obj)
+
def test_padding(self):
for j in range(8):
x = np.array([(1,), (2,)], dtype={'f0': (int, j)})
f.a = 3
assert_equal(arr['a'], 3)
+ @pytest.mark.parametrize("obj", [np.ones(3), np.ones(1, dtype="i,i")[()]])
+ def test_error_if_stored_buffer_info_is_corrupted(self, obj):
+ """
+ If a user extends a NumPy array before 1.20 and then runs it
+ on NumPy 1.20+. A C-subclassed array might in theory modify
+ the new buffer-info field. This checks that an error is raised
+ if this happens (for buffer export), an error is written on delete.
+ This is a sanity check to help users transition to safe code, it
+ may be deleted at any point.
+ """
+ # corrupt buffer info:
+ _multiarray_tests.corrupt_or_fix_bufferinfo(obj)
+ name = type(obj)
+ with pytest.raises(RuntimeError,
+ match=f".*{name} appears to be C subclassed"):
+ memoryview(obj)
+ # Fix buffer info again before we delete (or we lose the memory)
+ _multiarray_tests.corrupt_or_fix_bufferinfo(obj)
+
class TestArrayAttributeDeletion:
arr1 = np.asarray(DummyArray())
assert_equal(arr1, arr[1:])
+def test_array_interface_unicode_typestr():
+ arr = np.array([1, 2, 3], dtype='int32')
+ interface = dict(arr.__array_interface__)
+ interface['typestr'] = '\N{check mark}'
+
+ class DummyArray:
+ __array_interface__ = interface
+
+ # should not be UnicodeEncodeError
+ with pytest.raises(TypeError):
+ np.asarray(DummyArray())
+
def test_flat_element_deletion():
it = np.ones(3).flat
try:
[['readonly'], ['writeonly', 'allocate']],
op_dtypes=[None, np.dtype('f4')],
op_axes=[None, [0, 2, 1, 0]])
+ # Not all axes may be specified if a reduction. If there is a hole
+ # in op_axes, this is an error.
+ a = arange(24, dtype='i4').reshape(2, 3, 4)
+ assert_raises(ValueError, nditer, [a, None], ["reduce_ok"],
+ [['readonly'], ['readwrite', 'allocate']],
+ op_dtypes=[None, np.dtype('f4')],
+ op_axes=[None, [0, np.newaxis, 2]])
def test_iter_remove_axis():
a = arange(24).reshape(2, 3, 4)
b[1] = a + 1
assert_equal(it.operands[1], [[0, 2], [2, 4], [19, 21]])
+ # Check the same (less sensitive) thing when `op_axes` with -1 is given.
+ it = np.nditer(([[1, 3, 20]], None), op_dtypes=[None, ('i4', (2,))],
+ flags=["reduce_ok"], op_axes=[None, (-1, 0)])
+ for a, b in it:
+ b[0] = a - 1
+ b[1] = a + 1
+ assert_equal(it.operands[1], [[0, 2], [2, 4], [19, 21]])
+
# Make sure this works for scalars too
it = np.nditer((10, 2, None), op_dtypes=[None, None, ('i4', (2, 2))])
for a, b, c in it:
casting='equiv', op_dtypes=[np.dtype('f4')])
del it
assert len(sup.log) == 1
+
+
+@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
+@pytest.mark.parametrize(["in_dtype", "buf_dtype"],
+ [("i", "O"), ("O", "i"), # most simple cases
+ ("i,O", "O,O"), # structured partially only copying O
+ ("O,i", "i,O"), # structured casting to and from O
+ ])
+@pytest.mark.parametrize("steps", [1, 2, 3])
+def test_partial_iteration_cleanup(in_dtype, buf_dtype, steps):
+ value = 123 # relies on python cache (leak-check will still find it)
+ arr = np.full(int(np.BUFSIZE * 2.5), value).astype(in_dtype)
+ count = sys.getrefcount(value)
+
+ it = np.nditer(arr, op_dtypes=[np.dtype(buf_dtype)],
+ flags=["buffered", "external_loop", "refs_ok"], casting="unsafe")
+ for step in range(steps):
+ # The iteration finishes in 3 steps, the first two are partial
+ next(it)
+
+ # Note that resetting does not free references
+ del it
+ assert count == sys.getrefcount(value)
+
+ # Repeat the test with `iternext`
+ it = np.nditer(arr, op_dtypes=[np.dtype(buf_dtype)],
+ flags=["buffered", "external_loop", "refs_ok"], casting="unsafe")
+ for step in range(steps):
+ it.iternext()
+
+ del it # should ensure cleanup
+ assert count == sys.getrefcount(value)
+
+
+@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
+@pytest.mark.parametrize(["in_dtype", "buf_dtype"],
+ [("O", "i"), # most simple cases
+ ("O,i", "i,O"), # structured casting to and from O
+ ])
+def test_partial_iteration_error(in_dtype, buf_dtype):
+ value = 123 # relies on python cache (leak-check will still find it)
+ arr = np.full(int(np.BUFSIZE * 2.5), value).astype(in_dtype)
+ if in_dtype == "O":
+ arr[int(np.BUFSIZE * 1.5)] = None
+ else:
+ arr[int(np.BUFSIZE * 1.5)]["f0"] = None
+
+ count = sys.getrefcount(value)
+
+ it = np.nditer(arr, op_dtypes=[np.dtype(buf_dtype)],
+ flags=["buffered", "external_loop", "refs_ok"], casting="unsafe")
+ with pytest.raises(TypeError):
+ # pytest.raises seems to have issues with the error originating
+ # in the for loop, so manually unravel:
+ next(it)
+ next(it) # raises TypeError
+
+ # Repeat the test with `iternext` after resetting, the buffers should
+ # already be cleared from any references, so resetting is sufficient.
+ it.reset()
+ with pytest.raises(TypeError):
+ it.iternext()
+ it.iternext()
+
+ assert count == sys.getrefcount(value)
assert_array_equal, assert_almost_equal, assert_array_almost_equal,
assert_warns, assert_array_max_ulp, HAS_REFCOUNT
)
+from numpy.core._rational_tests import rational
from hypothesis import assume, given, strategies as st
from hypothesis.extra import numpy as hynp
Ar3 = np.array([[1, 2, 3], [4, 1, 2], [3, 4, 1], [2, 3, 4]])
assert_equal(np.resize(A, (4, 3)), Ar3)
+ def test_repeats(self):
+ A = np.array([1, 2, 3])
+ Ar1 = np.array([[1, 2, 3, 1], [2, 3, 1, 2]])
+ assert_equal(np.resize(A, (2, 4)), Ar1)
+
+ Ar2 = np.array([[1, 2], [3, 1], [2, 3], [1, 2]])
+ assert_equal(np.resize(A, (4, 2)), Ar2)
+
+ Ar3 = np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]])
+ assert_equal(np.resize(A, (4, 3)), Ar3)
+
def test_zeroresize(self):
A = np.array([[1, 2], [3, 4]])
Ar = np.resize(A, (0,))
assert_array_equal(Ar, np.zeros((2, 1), Ar.dtype))
assert_equal(A.dtype, Ar.dtype)
+ def test_negative_resize(self):
+ A = np.arange(0, 10, dtype=np.float32)
+ new_shape = (-10, -1)
+ with pytest.raises(ValueError, match=r"negative"):
+ np.resize(A, new_shape=new_shape)
+
+ def test_subclass(self):
+ class MyArray(np.ndarray):
+ __array_priority__ = 1.
+
+ my_arr = np.array([1]).view(MyArray)
+ assert type(np.resize(my_arr, 5)) is MyArray
+ assert type(np.resize(my_arr, 0)) is MyArray
+
+ my_arr = np.array([]).view(MyArray)
+ assert type(np.resize(my_arr, 5)) is MyArray
+
class TestNonarrayArgs:
# check that non-array arguments to functions wrap them in arrays
assert_equal(np.promote_types('<m8', '<m8'), np.dtype('m8'))
assert_equal(np.promote_types('>m8', '>m8'), np.dtype('m8'))
- def test_promote_types_strings(self):
- assert_equal(np.promote_types('bool', 'S'), np.dtype('S5'))
- assert_equal(np.promote_types('b', 'S'), np.dtype('S4'))
- assert_equal(np.promote_types('u1', 'S'), np.dtype('S3'))
- assert_equal(np.promote_types('u2', 'S'), np.dtype('S5'))
- assert_equal(np.promote_types('u4', 'S'), np.dtype('S10'))
- assert_equal(np.promote_types('u8', 'S'), np.dtype('S20'))
- assert_equal(np.promote_types('i1', 'S'), np.dtype('S4'))
- assert_equal(np.promote_types('i2', 'S'), np.dtype('S6'))
- assert_equal(np.promote_types('i4', 'S'), np.dtype('S11'))
- assert_equal(np.promote_types('i8', 'S'), np.dtype('S21'))
- assert_equal(np.promote_types('bool', 'U'), np.dtype('U5'))
- assert_equal(np.promote_types('b', 'U'), np.dtype('U4'))
- assert_equal(np.promote_types('u1', 'U'), np.dtype('U3'))
- assert_equal(np.promote_types('u2', 'U'), np.dtype('U5'))
- assert_equal(np.promote_types('u4', 'U'), np.dtype('U10'))
- assert_equal(np.promote_types('u8', 'U'), np.dtype('U20'))
- assert_equal(np.promote_types('i1', 'U'), np.dtype('U4'))
- assert_equal(np.promote_types('i2', 'U'), np.dtype('U6'))
- assert_equal(np.promote_types('i4', 'U'), np.dtype('U11'))
- assert_equal(np.promote_types('i8', 'U'), np.dtype('U21'))
- assert_equal(np.promote_types('bool', 'S1'), np.dtype('S5'))
- assert_equal(np.promote_types('bool', 'S30'), np.dtype('S30'))
- assert_equal(np.promote_types('b', 'S1'), np.dtype('S4'))
- assert_equal(np.promote_types('b', 'S30'), np.dtype('S30'))
- assert_equal(np.promote_types('u1', 'S1'), np.dtype('S3'))
- assert_equal(np.promote_types('u1', 'S30'), np.dtype('S30'))
- assert_equal(np.promote_types('u2', 'S1'), np.dtype('S5'))
- assert_equal(np.promote_types('u2', 'S30'), np.dtype('S30'))
- assert_equal(np.promote_types('u4', 'S1'), np.dtype('S10'))
- assert_equal(np.promote_types('u4', 'S30'), np.dtype('S30'))
- assert_equal(np.promote_types('u8', 'S1'), np.dtype('S20'))
- assert_equal(np.promote_types('u8', 'S30'), np.dtype('S30'))
+ def test_can_cast_and_promote_usertypes(self):
+ # The rational type defines safe casting for signed integers,
+ # boolean. Rational itself *does* cast safely to double.
+ # (rational does not actually cast to all signed integers, e.g.
+ # int64 can be both long and longlong and it registers only the first)
+ valid_types = ["int8", "int16", "int32", "int64", "bool"]
+ invalid_types = "BHILQP" + "FDG" + "mM" + "f" + "V"
+
+ rational_dt = np.dtype(rational)
+ for numpy_dtype in valid_types:
+ numpy_dtype = np.dtype(numpy_dtype)
+ assert np.can_cast(numpy_dtype, rational_dt)
+ assert np.promote_types(numpy_dtype, rational_dt) is rational_dt
+
+ for numpy_dtype in invalid_types:
+ numpy_dtype = np.dtype(numpy_dtype)
+ assert not np.can_cast(numpy_dtype, rational_dt)
+ with pytest.raises(TypeError):
+ np.promote_types(numpy_dtype, rational_dt)
+
+ double_dt = np.dtype("double")
+ assert np.can_cast(rational_dt, double_dt)
+ assert np.promote_types(double_dt, rational_dt) is double_dt
+
+ @pytest.mark.parametrize("swap", ["", "swap"])
+ @pytest.mark.parametrize("string_dtype", ["U", "S"])
+ def test_promote_types_strings(self, swap, string_dtype):
+ if swap == "swap":
+ promote_types = lambda a, b: np.promote_types(b, a)
+ else:
+ promote_types = np.promote_types
+
+ S = string_dtype
+ # Promote numeric with unsized string:
+ assert_equal(promote_types('bool', S), np.dtype(S+'5'))
+ assert_equal(promote_types('b', S), np.dtype(S+'4'))
+ assert_equal(promote_types('u1', S), np.dtype(S+'3'))
+ assert_equal(promote_types('u2', S), np.dtype(S+'5'))
+ assert_equal(promote_types('u4', S), np.dtype(S+'10'))
+ assert_equal(promote_types('u8', S), np.dtype(S+'20'))
+ assert_equal(promote_types('i1', S), np.dtype(S+'4'))
+ assert_equal(promote_types('i2', S), np.dtype(S+'6'))
+ assert_equal(promote_types('i4', S), np.dtype(S+'11'))
+ assert_equal(promote_types('i8', S), np.dtype(S+'21'))
+ # Promote numeric with sized string:
+ assert_equal(promote_types('bool', S+'1'), np.dtype(S+'5'))
+ assert_equal(promote_types('bool', S+'30'), np.dtype(S+'30'))
+ assert_equal(promote_types('b', S+'1'), np.dtype(S+'4'))
+ assert_equal(promote_types('b', S+'30'), np.dtype(S+'30'))
+ assert_equal(promote_types('u1', S+'1'), np.dtype(S+'3'))
+ assert_equal(promote_types('u1', S+'30'), np.dtype(S+'30'))
+ assert_equal(promote_types('u2', S+'1'), np.dtype(S+'5'))
+ assert_equal(promote_types('u2', S+'30'), np.dtype(S+'30'))
+ assert_equal(promote_types('u4', S+'1'), np.dtype(S+'10'))
+ assert_equal(promote_types('u4', S+'30'), np.dtype(S+'30'))
+ assert_equal(promote_types('u8', S+'1'), np.dtype(S+'20'))
+ assert_equal(promote_types('u8', S+'30'), np.dtype(S+'30'))
+ # Promote with object:
+ assert_equal(promote_types('O', S+'30'), np.dtype('O'))
+
+ @pytest.mark.parametrize(["dtype1", "dtype2"],
+ [[np.dtype("V6"), np.dtype("V10")],
+ [np.dtype([("name1", "i8")]), np.dtype([("name2", "i8")])],
+ [np.dtype("i8,i8"), np.dtype("i4,i4")],
+ ])
+ def test_invalid_void_promotion(self, dtype1, dtype2):
+ # Mainly test structured void promotion, which currently allows
+ # byte-swapping, but nothing else:
+ with pytest.raises(TypeError):
+ np.promote_types(dtype1, dtype2)
+
+ @pytest.mark.parametrize(["dtype1", "dtype2"],
+ [[np.dtype("V10"), np.dtype("V10")],
+ [np.dtype([("name1", "<i8")]), np.dtype([("name1", ">i8")])],
+ [np.dtype("i8,i8"), np.dtype("i8,>i8")],
+ ])
+ def test_valid_void_promotion(self, dtype1, dtype2):
+ assert np.promote_types(dtype1, dtype2) is dtype1
+
+ @pytest.mark.parametrize("dtype",
+ list(np.typecodes["All"]) +
+ ["i,i", "S3", "S100", "U3", "U100", rational])
+ def test_promote_identical_types_metadata(self, dtype):
+ # The same type passed in twice to promote types always
+ # preserves metadata
+ metadata = {1: 1}
+ dtype = np.dtype(dtype, metadata=metadata)
+
+ res = np.promote_types(dtype, dtype)
+ assert res.metadata == dtype.metadata
+
+ # byte-swapping preserves and makes the dtype native:
+ dtype = dtype.newbyteorder()
+ if dtype.isnative:
+ # The type does not have byte swapping
+ return
+
+ res = np.promote_types(dtype, dtype)
+ if res.char in "?bhilqpBHILQPefdgFDGOmM" or dtype.type is rational:
+ # Metadata is lost for simple promotions (they create a new dtype)
+ assert res.metadata is None
+ else:
+ assert res.metadata == metadata
+ if dtype.kind != "V":
+ # the result is native (except for structured void)
+ assert res.isnative
+
+ @pytest.mark.slow
+ @pytest.mark.parametrize(["dtype1", "dtype2"],
+ itertools.product(
+ list(np.typecodes["All"]) +
+ ["i,i", "S3", "S100", "U3", "U100", rational],
+ repeat=2))
+ def test_promote_types_metadata(self, dtype1, dtype2):
+ """Metadata handling in promotion does not appear formalized
+ right now in NumPy. This test should thus be considered to
+ document behaviour, rather than test the correct definition of it.
+
+ This test is very ugly, it was useful for rewriting part of the
+ promotion, but probably should eventually be replaced/deleted
+ (i.e. when metadata handling in promotion is better defined).
+ """
+ metadata1 = {1: 1}
+ metadata2 = {2: 2}
+ dtype1 = np.dtype(dtype1, metadata=metadata1)
+ dtype2 = np.dtype(dtype2, metadata=metadata2)
+
+ try:
+ res = np.promote_types(dtype1, dtype2)
+ except TypeError:
+ # Promotion failed, this test only checks metadata
+ return
+
+ if res.char in "?bhilqpBHILQPefdgFDGOmM" or res.type is rational:
+ # All simple types lose metadata (due to using promotion table):
+ assert res.metadata is None
+ elif res == dtype1:
+ # If one result is the result, it is usually returned unchanged:
+ assert res is dtype1
+ elif res == dtype2:
+ # dtype1 may have been cast to the same type/kind as dtype2.
+ # If the resulting dtype is identical we currently pick the cast
+ # version of dtype1, which lost the metadata:
+ if np.promote_types(dtype1, dtype2.kind) == dtype2:
+ res.metadata is None
+ else:
+ res.metadata == metadata2
+ else:
+ assert res.metadata is None
+
+ # Try again for byteswapped version
+ dtype1 = dtype1.newbyteorder()
+ assert dtype1.metadata == metadata1
+ res_bs = np.promote_types(dtype1, dtype2)
+ if res_bs.names is not None:
+ # Structured promotion doesn't remove byteswap:
+ assert res_bs.newbyteorder() == res
+ else:
+ assert res_bs == res
+ assert res_bs.metadata == res.metadata
+
+ @pytest.mark.parametrize(["dtype1", "dtype2"],
+ [[np.dtype("V6"), np.dtype("V10")],
+ [np.dtype([("name1", "i8")]), np.dtype([("name2", "i8")])],
+ [np.dtype("i8,i8"), np.dtype("i4,i4")],
+ ])
+ def test_invalid_void_promotion(self, dtype1, dtype2):
+ # Mainly test structured void promotion, which currently allows
+ # byte-swapping, but nothing else:
+ with pytest.raises(TypeError):
+ np.promote_types(dtype1, dtype2)
+
+ @pytest.mark.parametrize(["dtype1", "dtype2"],
+ [[np.dtype("V10"), np.dtype("V10")],
+ [np.dtype([("name1", "<i8")]), np.dtype([("name1", ">i8")])],
+ [np.dtype("i8,i8"), np.dtype("i8,>i8")],
+ ])
+ def test_valid_void_promotion(self, dtype1, dtype2):
+ assert np.promote_types(dtype1, dtype2) is dtype1
def test_can_cast(self):
assert_(np.can_cast(np.int32, np.int64))
self.check_function(np.zeros)
def test_ones(self):
- self.check_function(np.zeros)
+ self.check_function(np.ones)
def test_empty(self):
self.check_function(np.empty)
import inspect
import sys
+import tempfile
+from io import StringIO
from unittest import mock
import numpy as np
# note: the internal implementation of np.sum() calls the .sum() method
array = np.array(1).view(MyArray)
assert_equal(np.sum(array), 'summed')
+
+
+class TestArrayLike:
+ def setup(self):
+ class MyArray():
+ def __init__(self, function=None):
+ self.function = function
+
+ def __array_function__(self, func, types, args, kwargs):
+ try:
+ my_func = getattr(self, func.__name__)
+ except AttributeError:
+ return NotImplemented
+ return my_func(*args, **kwargs)
+
+ self.MyArray = MyArray
+
+ class MyNoArrayFunctionArray():
+ def __init__(self, function=None):
+ self.function = function
+
+ self.MyNoArrayFunctionArray = MyNoArrayFunctionArray
+
+ def add_method(self, name, arr_class, enable_value_error=False):
+ def _definition(*args, **kwargs):
+ # Check that `like=` isn't propagated downstream
+ assert 'like' not in kwargs
+
+ if enable_value_error and 'value_error' in kwargs:
+ raise ValueError
+
+ return arr_class(getattr(arr_class, name))
+ setattr(arr_class, name, _definition)
+
+ def func_args(*args, **kwargs):
+ return args, kwargs
+
+ @requires_array_function
+ def test_array_like_not_implemented(self):
+ self.add_method('array', self.MyArray)
+
+ ref = self.MyArray.array()
+
+ with assert_raises_regex(TypeError, 'no implementation found'):
+ array_like = np.asarray(1, like=ref)
+
+ _array_tests = [
+ ('array', *func_args((1,))),
+ ('asarray', *func_args((1,))),
+ ('asanyarray', *func_args((1,))),
+ ('ascontiguousarray', *func_args((2, 3))),
+ ('asfortranarray', *func_args((2, 3))),
+ ('require', *func_args((np.arange(6).reshape(2, 3),),
+ requirements=['A', 'F'])),
+ ('empty', *func_args((1,))),
+ ('full', *func_args((1,), 2)),
+ ('ones', *func_args((1,))),
+ ('zeros', *func_args((1,))),
+ ('arange', *func_args(3)),
+ ('frombuffer', *func_args(b'\x00' * 8, dtype=int)),
+ ('fromiter', *func_args(range(3), dtype=int)),
+ ('fromstring', *func_args('1,2', dtype=int, sep=',')),
+ ('loadtxt', *func_args(lambda: StringIO('0 1\n2 3'))),
+ ('genfromtxt', *func_args(lambda: StringIO(u'1,2.1'),
+ dtype=[('int', 'i8'), ('float', 'f8')],
+ delimiter=',')),
+ ]
+
+ @pytest.mark.parametrize('function, args, kwargs', _array_tests)
+ @pytest.mark.parametrize('numpy_ref', [True, False])
+ @requires_array_function
+ def test_array_like(self, function, args, kwargs, numpy_ref):
+ self.add_method('array', self.MyArray)
+ self.add_method(function, self.MyArray)
+ np_func = getattr(np, function)
+ my_func = getattr(self.MyArray, function)
+
+ if numpy_ref is True:
+ ref = np.array(1)
+ else:
+ ref = self.MyArray.array()
+
+ like_args = tuple(a() if callable(a) else a for a in args)
+ array_like = np_func(*like_args, **kwargs, like=ref)
+
+ if numpy_ref is True:
+ assert type(array_like) is np.ndarray
+
+ np_args = tuple(a() if callable(a) else a for a in args)
+ np_arr = np_func(*np_args, **kwargs)
+
+ # Special-case np.empty to ensure values match
+ if function == "empty":
+ np_arr.fill(1)
+ array_like.fill(1)
+
+ assert_equal(array_like, np_arr)
+ else:
+ assert type(array_like) is self.MyArray
+ assert array_like.function is my_func
+
+ @pytest.mark.parametrize('function, args, kwargs', _array_tests)
+ @pytest.mark.parametrize('ref', [1, [1], "MyNoArrayFunctionArray"])
+ @requires_array_function
+ def test_no_array_function_like(self, function, args, kwargs, ref):
+ self.add_method('array', self.MyNoArrayFunctionArray)
+ self.add_method(function, self.MyNoArrayFunctionArray)
+ np_func = getattr(np, function)
+
+ # Instantiate ref if it's the MyNoArrayFunctionArray class
+ if ref == "MyNoArrayFunctionArray":
+ ref = self.MyNoArrayFunctionArray.array()
+
+ like_args = tuple(a() if callable(a) else a for a in args)
+
+ with assert_raises_regex(TypeError,
+ 'The `like` argument must be an array-like that implements'):
+ np_func(*like_args, **kwargs, like=ref)
+
+ @pytest.mark.parametrize('numpy_ref', [True, False])
+ def test_array_like_fromfile(self, numpy_ref):
+ self.add_method('array', self.MyArray)
+ self.add_method("fromfile", self.MyArray)
+
+ if numpy_ref is True:
+ ref = np.array(1)
+ else:
+ ref = self.MyArray.array()
+
+ data = np.random.random(5)
+
+ fname = tempfile.mkstemp()[1]
+ data.tofile(fname)
+
+ array_like = np.fromfile(fname, like=ref)
+ if numpy_ref is True:
+ assert type(array_like) is np.ndarray
+ np_res = np.fromfile(fname, like=ref)
+ assert_equal(np_res, data)
+ assert_equal(array_like, np_res)
+ else:
+ assert type(array_like) is self.MyArray
+ assert array_like.function is self.MyArray.fromfile
+
+ @requires_array_function
+ def test_exception_handling(self):
+ self.add_method('array', self.MyArray, enable_value_error=True)
+
+ ref = self.MyArray.array()
+
+ with assert_raises(ValueError):
+ np.array(1, value_error=True, like=ref)
import collections.abc
import textwrap
+from io import BytesIO
from os import path
from pathlib import Path
import pytest
r1 = np.rec.fromfile(fd, formats='f8,i4,a5', shape=3, byteorder='big')
fd.seek(2880 * 2)
r2 = np.rec.array(fd, formats='f8,i4,a5', shape=3, byteorder='big')
+ fd.seek(2880 * 2)
+ bytes_array = BytesIO()
+ bytes_array.write(fd.read())
+ bytes_array.seek(0)
+ r3 = np.rec.fromfile(bytes_array, formats='f8,i4,a5', shape=3, byteorder='big')
fd.close()
assert_equal(r1, r2)
+ assert_equal(r2, r3)
def test_recarray_from_obj(self):
count = 10
# make sure we did not pickle the address
assert not isinstance(obj, bytes)
- assert_raises(TypeError, ctor, dtype, 13)
+ assert_raises(RuntimeError, ctor, dtype, 13)
+
+ # Test roundtrip:
+ dump = pickle.dumps(a[0])
+ unpickled = pickle.loads(dump)
+ assert a[0] == unpickled
+
+ # Also check the similar (impossible) "object scalar" path:
+ with pytest.warns(DeprecationWarning):
+ assert ctor(np.dtype("O"), data) is data
def test_objview_record(self):
# https://github.com/numpy/numpy/issues/2599
b = pickle.load(f)
assert_array_equal(a, b)
- def test_typeNA(self):
- # Issue gh-515
- with suppress_warnings() as sup:
- sup.filter(np.VisibleDeprecationWarning)
- assert_equal(np.typeNA[np.int64], 'Int64')
- assert_equal(np.typeNA[np.uint64], 'UInt64')
-
def test_dtype_names(self):
# Ticket #35
# Should succeed
test_type(t)
def test_buffer_hashlib(self):
- from hashlib import md5
+ from hashlib import sha256
x = np.array([1, 2, 3], dtype=np.dtype('<i4'))
- assert_equal(md5(x).hexdigest(), '2a1dd1e1e59d0a384c26951e316cd7e6')
+ assert_equal(sha256(x).hexdigest(), '4636993d3e1da4e9d6b8f87b79e8f7c6d018580d52661950eabc3845c5897a4d')
def test_0d_string_scalar(self):
# Bug #1436; the following should succeed
# allowed as a special case due to existing use, see gh-2798
a = np.ones(1, dtype=('O', [('name', 'O')]))
assert_equal(a[0], 1)
+ # In particular, the above union dtype (and union dtypes in general)
+ # should mainly behave like the main (object) dtype:
+ assert a[0] is a.item()
+ assert type(a[0]) is int
def test_correct_hash_dict(self):
# gh-8887 - __hash__ would be None despite tp_hash being set
class T:
__array_interface__ = {}
- np.array([T()])
+ with assert_raises(ValueError):
+ np.array([T()])
def test_2d__array__shape(self):
class T(object):
c_arr = np.ctypeslib.as_ctypes(arr)
assert_equal(c_arr._length_, arr.size)
+ def test_complex_conversion_error(self):
+ # gh-17068
+ with pytest.raises(TypeError, match=r"Unable to convert dtype.*"):
+ complex(np.array("now", np.datetime64))
+
+ def test__array_interface__descr(self):
+ # gh-17068
+ dt = np.dtype(dict(names=['a', 'b'],
+ offsets=[0, 0],
+ formats=[np.int64, np.int64]))
+ descr = np.array((1, 1), dtype=dt).__array_interface__['descr']
+ assert descr == [('', '|V8')] # instead of [(b'', '|V8')]
+
@pytest.mark.skipif(sys.maxsize < 2 ** 31 + 1, reason='overflows 32-bit python')
@requires_memory(free_bytes=9e9)
def test_dot_big_stride(self):
b[...] = 1
assert b.strides[0] > int32_max * b.dtype.itemsize
assert np.dot(b, b) == 2.0
+
+ def test_frompyfunc_name(self):
+ # name conversion was failing for python 3 strings
+ # resulting in the default '?' name. Also test utf-8
+ # encoding using non-ascii name.
+ def cassé(x):
+ return x
+
+ f = np.frompyfunc(cassé, 1, 1)
+ assert str(f) == "<ufunc 'cassé (vectorized)'>"
def test_bool(self):
with pytest.raises(TypeError):
- np.bool(False, garbage=True)
+ np.bool_(False, garbage=True)
def test_void(self):
with pytest.raises(TypeError):
def test_uint64_from_negative(self):
assert_equal(np.uint64(-2), np.uint64(18446744073709551614))
+
+
+int_types = [np.byte, np.short, np.intc, np.int_, np.longlong]
+uint_types = [np.ubyte, np.ushort, np.uintc, np.uint, np.ulonglong]
+float_types = [np.half, np.single, np.double, np.longdouble]
+cfloat_types = [np.csingle, np.cdouble, np.clongdouble]
+
+
+class TestArrayFromScalar:
+ """ gh-15467 """
+
+ def _do_test(self, t1, t2):
+ x = t1(2)
+ arr = np.array(x, dtype=t2)
+ # type should be preserved exactly
+ if t2 is None:
+ assert arr.dtype.type is t1
+ else:
+ assert arr.dtype.type is t2
+
+ @pytest.mark.parametrize('t1', int_types + uint_types)
+ @pytest.mark.parametrize('t2', int_types + uint_types + [None])
+ def test_integers(self, t1, t2):
+ return self._do_test(t1, t2)
+
+ @pytest.mark.parametrize('t1', float_types)
+ @pytest.mark.parametrize('t2', float_types + [None])
+ def test_reals(self, t1, t2):
+ return self._do_test(t1, t2)
+
+ @pytest.mark.parametrize('t1', cfloat_types)
+ @pytest.mark.parametrize('t2', cfloat_types + [None])
+ def test_complex(self, t1, t2):
+ return self._do_test(t1, t2)
Test scalar buffer interface adheres to PEP 3118
"""
import numpy as np
+from numpy.core._rational_tests import rational
+from numpy.core._multiarray_tests import get_buffer_info
import pytest
from numpy.testing import assert_, assert_equal, assert_raises
assert_equal(mv_x.suboffsets, ())
@pytest.mark.parametrize('scalar, code', scalars_and_codes, ids=codes_only)
- def test_scalar_known_code(self, scalar, code):
+ def test_scalar_code_and_properties(self, scalar, code):
x = scalar()
+ expected = dict(strides=(), itemsize=x.dtype.itemsize, ndim=0,
+ shape=(), format=code, readonly=True)
+
mv_x = memoryview(x)
- assert_equal(mv_x.format, code)
+ print(mv_x.readonly, self._as_dict(mv_x))
+ assert self._as_dict(mv_x) == expected
+
+ @pytest.mark.parametrize('scalar', scalars_only, ids=codes_only)
+ def test_scalar_buffers_readonly(self, scalar):
+ x = scalar()
+ with pytest.raises(BufferError, match="scalar buffer is readonly"):
+ get_buffer_info(x, ["WRITABLE"])
def test_void_scalar_structured_data(self):
dt = np.dtype([('name', np.unicode_, 16), ('grades', np.float64, (2,))])
assert_equal(mv_x.itemsize, mv_a.itemsize)
assert_equal(mv_x.format, mv_a.format)
+ # Check that we do not allow writeable buffer export (technically
+ # we could allow it sometimes here...)
+ with pytest.raises(BufferError, match="scalar buffer is readonly"):
+ get_buffer_info(x, ["WRITABLE"])
+
def _as_dict(self, m):
return dict(strides=m.strides, shape=m.shape, itemsize=m.itemsize,
- ndim=m.ndim, format=m.format)
+ ndim=m.ndim, format=m.format, readonly=m.readonly)
def test_datetime_memoryview(self):
# gh-11656
dt1 = np.datetime64('2016-01-01')
dt2 = np.datetime64('2017-01-01')
expected = dict(strides=(1,), itemsize=1, ndim=1, shape=(8,),
- format='B')
+ format='B', readonly=True)
v = memoryview(dt1)
assert self._as_dict(v) == expected
# Fails to create a PEP 3118 valid buffer
assert_raises((ValueError, BufferError), memoryview, a[0])
+ # Check that we do not allow writeable buffer export
+ with pytest.raises(BufferError, match="scalar buffer is readonly"):
+ get_buffer_info(dt1, ["WRITABLE"])
+
@pytest.mark.parametrize('s', [
pytest.param("\x32\x32", id="ascii"),
pytest.param("\uFE0F\uFE0F", id="basic multilingual"),
s = np.str_(s) # only our subclass implements the buffer protocol
# all the same, characters always encode as ucs4
- expected = dict(strides=(), itemsize=8, ndim=0, shape=(), format='2w')
+ expected = dict(strides=(), itemsize=8, ndim=0, shape=(), format='2w',
+ readonly=True)
v = memoryview(s)
assert self._as_dict(v) == expected
code_points = np.frombuffer(v, dtype='i4')
assert_equal(code_points, [ord(c) for c in s])
+
+ # Check that we do not allow writeable buffer export
+ with pytest.raises(BufferError, match="scalar buffer is readonly"):
+ get_buffer_info(s, ["WRITABLE"])
+
+ def test_user_scalar_fails_buffer(self):
+ r = rational(1)
+ with assert_raises(TypeError):
+ memoryview(r)
+
+ # Check that we do not allow writeable buffer export
+ with pytest.raises(BufferError, match="scalar buffer is readonly"):
+ get_buffer_info(r, ["WRITABLE"])
\ No newline at end of file
import pytest
import numpy as np
-from numpy.testing import assert_
+from numpy.testing import assert_, assert_raises
class A:
assert_(s + np_s == b'defabc')
assert_(u + np_u == u'defabc')
+ class MyStr(str, np.generic):
+ # would segfault
+ pass
+
+ with assert_raises(TypeError):
+ # Previously worked, but gave completely wrong result
+ ret = s + MyStr('abc')
- class Mystr(str, np.generic):
+ class MyBytes(bytes, np.generic):
# would segfault
pass
- ret = s + Mystr('abc')
- assert_(type(ret) is type(s))
+ ret = s + MyBytes(b'abc')
+ assert(type(ret) is type(s))
+ assert ret == b"defabc"
def test_char_repeat(self):
np_s = np.string_('abc')
# Check nans, inf
with suppress_warnings() as sup:
sup.filter(RuntimeWarning, "invalid value encountered in remainder")
+ sup.filter(RuntimeWarning, "divide by zero encountered in remainder")
+ sup.filter(RuntimeWarning, "divide by zero encountered in floor_divide")
+ sup.filter(RuntimeWarning, "divide by zero encountered in divmod")
+ sup.filter(RuntimeWarning, "invalid value encountered in divmod")
for dt in np.typecodes['Float']:
fone = np.array(1.0, dtype=dt)
fzer = np.array(0.0, dtype=dt)
assert_(np.isnan(rem), 'dt: %s' % dt)
rem = operator.mod(finf, fone)
assert_(np.isnan(rem), 'dt: %s' % dt)
+ for op in [floordiv_and_mod, divmod]:
+ div, mod = op(fone, fzer)
+ assert_(np.isinf(div)) and assert_(np.isnan(mod))
def test_inplace_floordiv_handling(self):
# issue gh-12927
_block_concatenate, _block_slicing)
from numpy.testing import (
assert_, assert_raises, assert_array_equal, assert_equal,
- assert_raises_regex, assert_warns
+ assert_raises_regex, assert_warns, IS_PYPY
)
assert_(out is rout)
assert_equal(res, rout)
+ @pytest.mark.skipif(IS_PYPY, reason="PYPY handles sq_concat, nb_add differently than cpython")
+ def test_operator_concat(self):
+ import operator
+ a = array([1, 2])
+ b = array([3, 4])
+ n = [1,2]
+ res = array([1, 2, 3, 4])
+ assert_raises(TypeError, operator.concat, a, b)
+ assert_raises(TypeError, operator.concat, a, n)
+ assert_raises(TypeError, operator.concat, n, a)
+ assert_raises(TypeError, operator.concat, a, 1)
+ assert_raises(TypeError, operator.concat, 1, a)
+
def test_bad_out_shape(self):
a = array([1, 2])
b = array([3, 4])
assert_raises(ValueError, concatenate, (a, b), out=np.empty((1,4)))
concatenate((a, b), out=np.empty(4))
- def test_out_dtype(self):
- out = np.empty(4, np.float32)
- res = concatenate((array([1, 2]), array([3, 4])), out=out)
- assert_(out is res)
-
- out = np.empty(4, np.complex64)
- res = concatenate((array([0.1, 0.2]), array([0.3, 0.4])), out=out)
- assert_(out is res)
-
- # invalid cast
- out = np.empty(4, np.int32)
- assert_raises(TypeError, concatenate,
- (array([0.1, 0.2]), array([0.3, 0.4])), out=out)
+ @pytest.mark.parametrize("axis", [None, 0])
+ @pytest.mark.parametrize("out_dtype", ["c8", "f4", "f8", ">f8", "i8", "S4"])
+ @pytest.mark.parametrize("casting",
+ ['no', 'equiv', 'safe', 'same_kind', 'unsafe'])
+ def test_out_and_dtype(self, axis, out_dtype, casting):
+ # Compare usage of `out=out` with `dtype=out.dtype`
+ out = np.empty(4, dtype=out_dtype)
+ to_concat = (array([1.1, 2.2]), array([3.3, 4.4]))
+
+ if not np.can_cast(to_concat[0], out_dtype, casting=casting):
+ with assert_raises(TypeError):
+ concatenate(to_concat, out=out, axis=axis, casting=casting)
+ with assert_raises(TypeError):
+ concatenate(to_concat, dtype=out.dtype,
+ axis=axis, casting=casting)
+ else:
+ res_out = concatenate(to_concat, out=out,
+ axis=axis, casting=casting)
+ res_dtype = concatenate(to_concat, dtype=out.dtype,
+ axis=axis, casting=casting)
+ assert res_out is out
+ assert_array_equal(out, res_dtype)
+ assert res_dtype.dtype == out_dtype
+
+ with assert_raises(TypeError):
+ concatenate(to_concat, out=out, dtype=out_dtype, axis=axis)
+
+ @pytest.mark.parametrize("axis", [None, 0])
+ @pytest.mark.parametrize("string_dt", ["S", "U", "S0", "U0"])
+ @pytest.mark.parametrize("arrs",
+ [([0.],), ([0.], [1]), ([0], ["string"], [1.])])
+ def test_dtype_with_promotion(self, arrs, string_dt, axis):
+ # Note that U0 and S0 should be deprecated eventually and changed to
+ # actually give the empty string result (together with `np.array`)
+ res = np.concatenate(arrs, axis=axis, dtype=string_dt, casting="unsafe")
+ assert res.dtype == np.promote_types("d", string_dt)
+
+ @pytest.mark.parametrize("axis", [None, 0])
+ def test_string_dtype_does_not_inspect(self, axis):
+ # The error here currently depends on NPY_USE_NEW_CASTINGIMPL as
+ # the new version rejects using the "default string length" of 64.
+ # The new behaviour is better, `np.array()` and `arr.astype()` would
+ # have to be used instead. (currently only raises due to unsafe cast)
+ with pytest.raises((ValueError, TypeError)):
+ np.concatenate(([None], [1]), dtype="S", axis=axis)
+ with pytest.raises((ValueError, TypeError)):
+ np.concatenate(([None], [1]), dtype="U", axis=axis)
+
+ @pytest.mark.parametrize("axis", [None, 0])
+ def test_subarray_error(self, axis):
+ with pytest.raises(TypeError, match=".*subarray dtype"):
+ np.concatenate(([1], [1]), dtype="(2,)i", axis=axis)
def test_stack():
--- /dev/null
+# NOTE: Please avoid the use of numpy.testing since NPYV intrinsics
+# may be involved in their functionality.
+import pytest, math
+from numpy.core._simd import targets
+
+class _Test_Utility:
+ # submodule of the desired SIMD extention, e.g. targets["AVX512F"]
+ npyv = None
+ # the current data type suffix e.g. 's8'
+ sfx = None
+
+ def __getattr__(self, attr):
+ """
+ To call NPV intrinsics without the attribute 'npyv' and
+ auto suffixing intrinsics according to class attribute 'sfx'
+ """
+ return getattr(self.npyv, attr + "_" + self.sfx)
+
+ def _data(self, start=None, count=None, reverse=False):
+ """
+ Create list of consecutive numbers according to number of vector's lanes.
+ """
+ if start is None:
+ start = 1
+ if count is None:
+ count = self.nlanes
+ rng = range(start, start + count)
+ if reverse:
+ rng = reversed(rng)
+ if self._is_fp():
+ return [x / 1.0 for x in rng]
+ return list(rng)
+
+ def _is_unsigned(self):
+ return self.sfx[0] == 'u'
+
+ def _is_signed(self):
+ return self.sfx[0] == 's'
+
+ def _is_fp(self):
+ return self.sfx[0] == 'f'
+
+ def _scalar_size(self):
+ return int(self.sfx[1:])
+
+ def _int_clip(self, seq):
+ if self._is_fp():
+ return seq
+ max_int = self._int_max()
+ min_int = self._int_min()
+ return [min(max(v, min_int), max_int) for v in seq]
+
+ def _int_max(self):
+ if self._is_fp():
+ return None
+ max_u = self._to_unsigned(self.setall(-1))[0]
+ if self._is_signed():
+ return max_u // 2
+ return max_u
+
+ def _int_min(self):
+ if self._is_fp():
+ return None
+ if self._is_unsigned():
+ return 0
+ return -(self._int_max() + 1)
+
+ def _true_mask(self):
+ max_unsig = getattr(self.npyv, "setall_u" + self.sfx[1:])(-1)
+ return max_unsig[0]
+
+ def _to_unsigned(self, vector):
+ if isinstance(vector, (list, tuple)):
+ return getattr(self.npyv, "load_u" + self.sfx[1:])(vector)
+ else:
+ sfx = vector.__name__.replace("npyv_", "")
+ if sfx[0] == "b":
+ cvt_intrin = "cvt_u{0}_b{0}"
+ else:
+ cvt_intrin = "reinterpret_u{0}_{1}"
+ return getattr(self.npyv, cvt_intrin.format(sfx[1:], sfx))(vector)
+
+ def _pinfinity(self):
+ v = self.npyv.setall_u32(0x7f800000)
+ return self.npyv.reinterpret_f32_u32(v)[0]
+
+ def _ninfinity(self):
+ v = self.npyv.setall_u32(0xff800000)
+ return self.npyv.reinterpret_f32_u32(v)[0]
+
+ def _nan(self):
+ v = self.npyv.setall_u32(0x7fc00000)
+ return self.npyv.reinterpret_f32_u32(v)[0]
+
+class _SIMD_INT(_Test_Utility):
+ """
+ To test all integer vector types at once
+ """
+ def test_operators_shift(self):
+ if self.sfx in ("u8", "s8"):
+ return
+
+ data_a = self._data(self._int_max() - self.nlanes)
+ data_b = self._data(self._int_min(), reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ for count in range(self._scalar_size()):
+ # load to cast
+ data_shl_a = self.load([a << count for a in data_a])
+ # left shift
+ shl = self.shl(vdata_a, count)
+ assert shl == data_shl_a
+ # load to cast
+ data_shr_a = self.load([a >> count for a in data_a])
+ # right shift
+ shr = self.shr(vdata_a, count)
+ assert shr == data_shr_a
+
+ # shift by zero or max or out-range immediate constant is not applicable and illogical
+ for count in range(1, self._scalar_size()):
+ # load to cast
+ data_shl_a = self.load([a << count for a in data_a])
+ # left shift by an immediate constant
+ shli = self.shli(vdata_a, count)
+ assert shli == data_shl_a
+ # load to cast
+ data_shr_a = self.load([a >> count for a in data_a])
+ # right shift by an immediate constant
+ shri = self.shri(vdata_a, count)
+ assert shri == data_shr_a
+
+ def test_arithmetic_subadd_saturated(self):
+ if self.sfx in ("u32", "s32", "u64", "s64"):
+ return
+
+ data_a = self._data(self._int_max() - self.nlanes)
+ data_b = self._data(self._int_min(), reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ data_adds = self._int_clip([a + b for a, b in zip(data_a, data_b)])
+ adds = self.adds(vdata_a, vdata_b)
+ assert adds == data_adds
+
+ data_subs = self._int_clip([a - b for a, b in zip(data_a, data_b)])
+ subs = self.subs(vdata_a, vdata_b)
+ assert subs == data_subs
+
+class _SIMD_FP(_Test_Utility):
+ """
+ To test all float vector types at once
+ """
+ def test_arithmetic_fused(self):
+ vdata_a, vdata_b, vdata_c = [self.load(self._data())]*3
+ vdata_cx2 = self.add(vdata_c, vdata_c)
+ # multiply and add, a*b + c
+ data_fma = self.load([a * b + c for a, b, c in zip(vdata_a, vdata_b, vdata_c)])
+ fma = self.muladd(vdata_a, vdata_b, vdata_c)
+ assert fma == data_fma
+ # multiply and subtract, a*b - c
+ fms = self.mulsub(vdata_a, vdata_b, vdata_c)
+ data_fms = self.sub(data_fma, vdata_cx2)
+ assert fms == data_fms
+ # negate multiply and add, -(a*b) + c
+ nfma = self.nmuladd(vdata_a, vdata_b, vdata_c)
+ data_nfma = self.sub(vdata_cx2, data_fma)
+ assert nfma == data_nfma
+ # negate multiply and subtract, -(a*b) - c
+ nfms = self.nmulsub(vdata_a, vdata_b, vdata_c)
+ data_nfms = self.mul(data_fma, self.setall(-1))
+ assert nfms == data_nfms
+
+ def test_abs(self):
+ pinf, ninf, nan = self._pinfinity(), self._ninfinity(), self._nan()
+ data = self._data()
+ vdata = self.load(self._data())
+
+ abs_cases = ((-0, 0), (ninf, pinf), (pinf, pinf), (nan, nan))
+ for case, desired in abs_cases:
+ data_abs = [desired]*self.nlanes
+ vabs = self.abs(self.setall(case))
+ assert vabs == pytest.approx(data_abs, nan_ok=True)
+
+ vabs = self.abs(self.mul(vdata, self.setall(-1)))
+ assert vabs == data
+
+ def test_sqrt(self):
+ pinf, ninf, nan = self._pinfinity(), self._ninfinity(), self._nan()
+ data = self._data()
+ vdata = self.load(self._data())
+
+ sqrt_cases = ((-0.0, -0.0), (0.0, 0.0), (-1.0, nan), (ninf, nan), (pinf, pinf))
+ for case, desired in sqrt_cases:
+ data_sqrt = [desired]*self.nlanes
+ sqrt = self.sqrt(self.setall(case))
+ assert sqrt == pytest.approx(data_sqrt, nan_ok=True)
+
+ data_sqrt = self.load([math.sqrt(x) for x in data]) # load to truncate precision
+ sqrt = self.sqrt(vdata)
+ assert sqrt == data_sqrt
+
+ def test_square(self):
+ pinf, ninf, nan = self._pinfinity(), self._ninfinity(), self._nan()
+ data = self._data()
+ vdata = self.load(self._data())
+ # square
+ square_cases = ((nan, nan), (pinf, pinf), (ninf, pinf))
+ for case, desired in square_cases:
+ data_square = [desired]*self.nlanes
+ square = self.square(self.setall(case))
+ assert square == pytest.approx(data_square, nan_ok=True)
+
+ data_square = [x*x for x in data]
+ square = self.square(vdata)
+ assert square == data_square
+
+ def test_reciprocal(self):
+ pinf, ninf, nan = self._pinfinity(), self._ninfinity(), self._nan()
+ data = self._data()
+ vdata = self.load(self._data())
+
+ recip_cases = ((nan, nan), (pinf, 0.0), (ninf, -0.0), (0.0, pinf), (-0.0, ninf))
+ for case, desired in recip_cases:
+ data_recip = [desired]*self.nlanes
+ recip = self.recip(self.setall(case))
+ assert recip == pytest.approx(data_recip, nan_ok=True)
+
+ data_recip = self.load([1/x for x in data]) # load to truncate precision
+ recip = self.recip(vdata)
+ assert recip == data_recip
+
+class _SIMD_ALL(_Test_Utility):
+ """
+ To test all vector types at once
+ """
+ def test_memory_load(self):
+ data = self._data()
+ # unaligned load
+ load_data = self.load(data)
+ assert load_data == data
+ # aligned load
+ loada_data = self.loada(data)
+ assert loada_data == data
+ # stream load
+ loads_data = self.loads(data)
+ assert loads_data == data
+ # load lower part
+ loadl = self.loadl(data)
+ loadl_half = list(loadl)[:self.nlanes//2]
+ data_half = data[:self.nlanes//2]
+ assert loadl_half == data_half
+ assert loadl != data # detect overflow
+
+ def test_memory_store(self):
+ data = self._data()
+ vdata = self.load(data)
+ # unaligned store
+ store = [0] * self.nlanes
+ self.store(store, vdata)
+ assert store == data
+ # aligned store
+ store_a = [0] * self.nlanes
+ self.storea(store_a, vdata)
+ assert store_a == data
+ # stream store
+ store_s = [0] * self.nlanes
+ self.stores(store_s, vdata)
+ assert store_s == data
+ # store lower part
+ store_l = [0] * self.nlanes
+ self.storel(store_l, vdata)
+ assert store_l[:self.nlanes//2] == data[:self.nlanes//2]
+ assert store_l != vdata # detect overflow
+ # store higher part
+ store_h = [0] * self.nlanes
+ self.storeh(store_h, vdata)
+ assert store_h[:self.nlanes//2] == data[self.nlanes//2:]
+ assert store_h != vdata # detect overflow
+
+ def test_memory_partial_load(self):
+ if self.sfx in ("u8", "s8", "u16", "s16"):
+ return
+
+ data = self._data()
+ lanes = list(range(1, self.nlanes + 1))
+ lanes += [self.nlanes**2, self.nlanes**4] # test out of range
+ for n in lanes:
+ load_till = self.load_till(data, n, 15)
+ data_till = data[:n] + [15] * (self.nlanes-n)
+ assert load_till == data_till
+ load_tillz = self.load_tillz(data, n)
+ data_tillz = data[:n] + [0] * (self.nlanes-n)
+ assert load_tillz == data_tillz
+
+ def test_memory_partial_store(self):
+ if self.sfx in ("u8", "s8", "u16", "s16"):
+ return
+
+ data = self._data()
+ data_rev = self._data(reverse=True)
+ vdata = self.load(data)
+ lanes = list(range(1, self.nlanes + 1))
+ lanes += [self.nlanes**2, self.nlanes**4]
+ for n in lanes:
+ data_till = data_rev.copy()
+ data_till[:n] = data[:n]
+ store_till = self._data(reverse=True)
+ self.store_till(store_till, n, vdata)
+ assert store_till == data_till
+
+ def test_memory_noncont_load(self):
+ if self.sfx in ("u8", "s8", "u16", "s16"):
+ return
+
+ for stride in range(1, 64):
+ data = self._data(count=stride*self.nlanes)
+ data_stride = data[::stride]
+ loadn = self.loadn(data, stride)
+ assert loadn == data_stride
+
+ for stride in range(-64, 0):
+ data = self._data(stride, -stride*self.nlanes)
+ data_stride = self.load(data[::stride]) # cast unsigned
+ loadn = self.loadn(data, stride)
+ assert loadn == data_stride
+
+ def test_memory_noncont_partial_load(self):
+ if self.sfx in ("u8", "s8", "u16", "s16"):
+ return
+
+ lanes = list(range(1, self.nlanes + 1))
+ lanes += [self.nlanes**2, self.nlanes**4]
+ for stride in range(1, 64):
+ data = self._data(count=stride*self.nlanes)
+ data_stride = data[::stride]
+ for n in lanes:
+ data_stride_till = data_stride[:n] + [15] * (self.nlanes-n)
+ loadn_till = self.loadn_till(data, stride, n, 15)
+ assert loadn_till == data_stride_till
+ data_stride_tillz = data_stride[:n] + [0] * (self.nlanes-n)
+ loadn_tillz = self.loadn_tillz(data, stride, n)
+ assert loadn_tillz == data_stride_tillz
+
+ for stride in range(-64, 0):
+ data = self._data(stride, -stride*self.nlanes)
+ data_stride = list(self.load(data[::stride])) # cast unsigned
+ for n in lanes:
+ data_stride_till = data_stride[:n] + [15] * (self.nlanes-n)
+ loadn_till = self.loadn_till(data, stride, n, 15)
+ assert loadn_till == data_stride_till
+ data_stride_tillz = data_stride[:n] + [0] * (self.nlanes-n)
+ loadn_tillz = self.loadn_tillz(data, stride, n)
+ assert loadn_tillz == data_stride_tillz
+
+ def test_memory_noncont_store(self):
+ if self.sfx in ("u8", "s8", "u16", "s16"):
+ return
+
+ vdata = self.load(self._data())
+ for stride in range(1, 64):
+ data = [15] * stride * self.nlanes
+ data[::stride] = vdata
+ storen = [15] * stride * self.nlanes
+ storen += [127]*64
+ self.storen(storen, stride, vdata)
+ assert storen[:-64] == data
+ assert storen[-64:] == [127]*64 # detect overflow
+
+ for stride in range(-64, 0):
+ data = [15] * -stride * self.nlanes
+ data[::stride] = vdata
+ storen = [127]*64
+ storen += [15] * -stride * self.nlanes
+ self.storen(storen, stride, vdata)
+ assert storen[64:] == data
+ assert storen[:64] == [127]*64 # detect overflow
+
+ def test_memory_noncont_partial_store(self):
+ if self.sfx in ("u8", "s8", "u16", "s16"):
+ return
+
+ data = self._data()
+ vdata = self.load(data)
+ lanes = list(range(1, self.nlanes + 1))
+ lanes += [self.nlanes**2, self.nlanes**4]
+ for stride in range(1, 64):
+ for n in lanes:
+ data_till = [15] * stride * self.nlanes
+ data_till[::stride] = data[:n] + [15] * (self.nlanes-n)
+ storen_till = [15] * stride * self.nlanes
+ storen_till += [127]*64
+ self.storen_till(storen_till, stride, n, vdata)
+ assert storen_till[:-64] == data_till
+ assert storen_till[-64:] == [127]*64 # detect overflow
+
+ for stride in range(-64, 0):
+ for n in lanes:
+ data_till = [15] * -stride * self.nlanes
+ data_till[::stride] = data[:n] + [15] * (self.nlanes-n)
+ storen_till = [127]*64
+ storen_till += [15] * -stride * self.nlanes
+ self.storen_till(storen_till, stride, n, vdata)
+ assert storen_till[64:] == data_till
+ assert storen_till[:64] == [127]*64 # detect overflow
+
+ def test_misc(self):
+ broadcast_zero = self.zero()
+ assert broadcast_zero == [0] * self.nlanes
+ for i in range(1, 10):
+ broadcasti = self.setall(i)
+ assert broadcasti == [i] * self.nlanes
+
+ data_a, data_b = self._data(), self._data(reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ # py level of npyv_set_* don't support ignoring the extra specified lanes or
+ # fill non-specified lanes with zero.
+ vset = self.set(*data_a)
+ assert vset == data_a
+ # py level of npyv_setf_* don't support ignoring the extra specified lanes or
+ # fill non-specified lanes with the specified scalar.
+ vsetf = self.setf(10, *data_a)
+ assert vsetf == data_a
+
+ # We're testing the sainty of _simd's type-vector,
+ # reinterpret* intrinsics itself are tested via compiler
+ # during the build of _simd module
+ sfxes = ["u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64", "f32"]
+ if self.npyv.simd_f64:
+ sfxes.append("f64")
+ for sfx in sfxes:
+ vec_name = getattr(self, "reinterpret_" + sfx)(vdata_a).__name__
+ assert vec_name == "npyv_" + sfx
+
+ # select & mask operations
+ select_a = self.select(self.cmpeq(self.zero(), self.zero()), vdata_a, vdata_b)
+ assert select_a == data_a
+ select_b = self.select(self.cmpneq(self.zero(), self.zero()), vdata_a, vdata_b)
+ assert select_b == data_b
+
+ # cleanup intrinsic is only used with AVX for
+ # zeroing registers to avoid the AVX-SSE transition penalty,
+ # so nothing to test here
+ self.npyv.cleanup()
+
+ def test_reorder(self):
+ data_a, data_b = self._data(), self._data(reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+ # lower half part
+ data_a_lo = data_a[:self.nlanes//2]
+ data_b_lo = data_b[:self.nlanes//2]
+ # higher half part
+ data_a_hi = data_a[self.nlanes//2:]
+ data_b_hi = data_b[self.nlanes//2:]
+ # combine two lower parts
+ combinel = self.combinel(vdata_a, vdata_b)
+ assert combinel == data_a_lo + data_b_lo
+ # combine two higher parts
+ combineh = self.combineh(vdata_a, vdata_b)
+ assert combineh == data_a_hi + data_b_hi
+ # combine x2
+ combine = self.combine(vdata_a, vdata_b)
+ assert combine == (data_a_lo + data_b_lo, data_a_hi + data_b_hi)
+ # zip(interleave)
+ data_zipl = [v for p in zip(data_a_lo, data_b_lo) for v in p]
+ data_ziph = [v for p in zip(data_a_hi, data_b_hi) for v in p]
+ vzip = self.zip(vdata_a, vdata_b)
+ assert vzip == (data_zipl, data_ziph)
+
+ def test_operators_comparison(self):
+ if self._is_fp():
+ data_a = self._data()
+ else:
+ data_a = self._data(self._int_max() - self.nlanes)
+ data_b = self._data(self._int_min(), reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ mask_true = self._true_mask()
+ def to_bool(vector):
+ return [lane == mask_true for lane in vector]
+ # equal
+ data_eq = [a == b for a, b in zip(data_a, data_b)]
+ cmpeq = to_bool(self.cmpeq(vdata_a, vdata_b))
+ assert cmpeq == data_eq
+ # not equal
+ data_neq = [a != b for a, b in zip(data_a, data_b)]
+ cmpneq = to_bool(self.cmpneq(vdata_a, vdata_b))
+ assert cmpneq == data_neq
+ # greater than
+ data_gt = [a > b for a, b in zip(data_a, data_b)]
+ cmpgt = to_bool(self.cmpgt(vdata_a, vdata_b))
+ assert cmpgt == data_gt
+ # greater than and equal
+ data_ge = [a >= b for a, b in zip(data_a, data_b)]
+ cmpge = to_bool(self.cmpge(vdata_a, vdata_b))
+ assert cmpge == data_ge
+ # less than
+ data_lt = [a < b for a, b in zip(data_a, data_b)]
+ cmplt = to_bool(self.cmplt(vdata_a, vdata_b))
+ assert cmplt == data_lt
+ # less than and equal
+ data_le = [a <= b for a, b in zip(data_a, data_b)]
+ cmple = to_bool(self.cmple(vdata_a, vdata_b))
+ assert cmple == data_le
+
+ def test_operators_logical(self):
+ if self._is_fp():
+ data_a = self._data()
+ else:
+ data_a = self._data(self._int_max() - self.nlanes)
+ data_b = self._data(self._int_min(), reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ if self._is_fp():
+ data_cast_a = self._to_unsigned(vdata_a)
+ data_cast_b = self._to_unsigned(vdata_b)
+ cast, cast_data = self._to_unsigned, self._to_unsigned
+ else:
+ data_cast_a, data_cast_b = data_a, data_b
+ cast, cast_data = lambda a: a, self.load
+
+ data_xor = cast_data([a ^ b for a, b in zip(data_cast_a, data_cast_b)])
+ vxor = cast(self.xor(vdata_a, vdata_b))
+ assert vxor == data_xor
+
+ data_or = cast_data([a | b for a, b in zip(data_cast_a, data_cast_b)])
+ vor = cast(getattr(self, "or")(vdata_a, vdata_b))
+ assert vor == data_or
+
+ data_and = cast_data([a & b for a, b in zip(data_cast_a, data_cast_b)])
+ vand = cast(getattr(self, "and")(vdata_a, vdata_b))
+ assert vand == data_and
+
+ data_not = cast_data([~a for a in data_cast_a])
+ vnot = cast(getattr(self, "not")(vdata_a))
+ assert vnot == data_not
+
+ def test_conversion_boolean(self):
+ bsfx = "b" + self.sfx[1:]
+ to_boolean = getattr(self.npyv, "cvt_%s_%s" % (bsfx, self.sfx))
+ from_boolean = getattr(self.npyv, "cvt_%s_%s" % (self.sfx, bsfx))
+
+ false_vb = to_boolean(self.setall(0))
+ true_vb = self.cmpeq(self.setall(0), self.setall(0))
+ assert false_vb != true_vb
+
+ false_vsfx = from_boolean(false_vb)
+ true_vsfx = from_boolean(true_vb)
+ assert false_vsfx != true_vsfx
+
+ def test_arithmetic_subadd(self):
+ if self._is_fp():
+ data_a = self._data()
+ else:
+ data_a = self._data(self._int_max() - self.nlanes)
+ data_b = self._data(self._int_min(), reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ # non-saturated
+ data_add = self.load([a + b for a, b in zip(data_a, data_b)]) # load to cast
+ add = self.add(vdata_a, vdata_b)
+ assert add == data_add
+ data_sub = self.load([a - b for a, b in zip(data_a, data_b)])
+ sub = self.sub(vdata_a, vdata_b)
+ assert sub == data_sub
+
+ def test_arithmetic_mul(self):
+ if self.sfx in ("u64", "s64"):
+ return
+
+ if self._is_fp():
+ data_a = self._data()
+ else:
+ data_a = self._data(self._int_max() - self.nlanes)
+ data_b = self._data(self._int_min(), reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ data_mul = self.load([a * b for a, b in zip(data_a, data_b)])
+ mul = self.mul(vdata_a, vdata_b)
+ assert mul == data_mul
+
+ def test_arithmetic_div(self):
+ if not self._is_fp():
+ return
+
+ data_a, data_b = self._data(), self._data(reverse=True)
+ vdata_a, vdata_b = self.load(data_a), self.load(data_b)
+
+ # load to truncate f64 to precision of f32
+ data_div = self.load([a / b for a, b in zip(data_a, data_b)])
+ div = self.div(vdata_a, vdata_b)
+ assert div == data_div
+
+ def test_arithmetic_reduce_sum(self):
+ if not self._is_fp():
+ return
+ # reduce sum
+ data = self._data()
+ vdata = self.load(data)
+
+ data_sum = sum(data)
+ vsum = self.sum(vdata)
+ assert vsum == data_sum
+
+int_sfx = ("u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64")
+fp_sfx = ("f32", "f64")
+all_sfx = int_sfx + fp_sfx
+tests_registry = {
+ int_sfx : _SIMD_INT,
+ fp_sfx : _SIMD_FP,
+ all_sfx : _SIMD_ALL
+}
+for target_name, npyv in targets.items():
+ simd_width = npyv.simd if npyv else ''
+ pretty_name = target_name.split('__') # multi-target separator
+ if len(pretty_name) > 1:
+ # multi-target
+ pretty_name = f"({' '.join(pretty_name)})"
+ else:
+ pretty_name = pretty_name[0]
+
+ skip = ""
+ skip_sfx = dict()
+ if not npyv:
+ skip = f"target '{pretty_name}' isn't supported by current machine"
+ elif not npyv.simd:
+ skip = f"target '{pretty_name}' isn't supported by NPYV"
+ elif not npyv.simd_f64:
+ skip_sfx["f64"] = f"target '{pretty_name}' doesn't support double-precision"
+
+ for sfxes, cls in tests_registry.items():
+ for sfx in sfxes:
+ skip_m = skip_sfx.get(sfx, skip)
+ inhr = (cls,)
+ attr = dict(npyv=targets[target_name], sfx=sfx)
+ tcls = type(f"Test{cls.__name__}_{simd_width}_{target_name}_{sfx}", inhr, attr)
+ if skip_m:
+ pytest.mark.skip(reason=skip_m)(tcls)
+ globals()[tcls.__name__] = tcls
--- /dev/null
+import pytest
+from numpy.core._simd import targets
+"""
+This testing unit only for checking the sanity of common functionality,
+therefore all we need is just to take one submodule that represents any
+of enabled SIMD extensions to run the test on it and the second submodule
+required to run only one check related to the possibility of mixing
+the data types among each submodule.
+"""
+npyvs = [npyv_mod for npyv_mod in targets.values() if npyv_mod and npyv_mod.simd]
+npyv, npyv2 = (npyvs + [None, None])[:2]
+
+unsigned_sfx = ["u8", "u16", "u32", "u64"]
+signed_sfx = ["s8", "s16", "s32", "s64"]
+fp_sfx = ["f32"]
+if npyv and npyv.simd_f64:
+ fp_sfx.append("f64")
+
+int_sfx = unsigned_sfx + signed_sfx
+all_sfx = unsigned_sfx + int_sfx
+
+@pytest.mark.skipif(not npyv, reason="could not find any SIMD extension with NPYV support")
+class Test_SIMD_MODULE:
+
+ @pytest.mark.parametrize('sfx', all_sfx)
+ def test_num_lanes(self, sfx):
+ nlanes = getattr(npyv, "nlanes_" + sfx)
+ vector = getattr(npyv, "setall_" + sfx)(1)
+ assert len(vector) == nlanes
+
+ @pytest.mark.parametrize('sfx', all_sfx)
+ def test_type_name(self, sfx):
+ vector = getattr(npyv, "setall_" + sfx)(1)
+ assert vector.__name__ == "npyv_" + sfx
+
+ def test_raises(self):
+ a, b = [npyv.setall_u32(1)]*2
+ for sfx in all_sfx:
+ vcb = lambda intrin: getattr(npyv, f"{intrin}_{sfx}")
+ pytest.raises(TypeError, vcb("add"), a)
+ pytest.raises(TypeError, vcb("add"), a, b, a)
+ pytest.raises(TypeError, vcb("setall"))
+ pytest.raises(TypeError, vcb("setall"), [1])
+ pytest.raises(TypeError, vcb("load"), 1)
+ pytest.raises(ValueError, vcb("load"), [1])
+ pytest.raises(ValueError, vcb("store"), [1], getattr(npyv, f"reinterpret_{sfx}_u32")(a))
+
+ @pytest.mark.skipif(not npyv2, reason=(
+ "could not find a second SIMD extension with NPYV support"
+ ))
+ def test_nomix(self):
+ # mix among submodules isn't allowed
+ a = npyv.setall_u32(1)
+ a2 = npyv2.setall_u32(1)
+ pytest.raises(TypeError, npyv.add_u32, a2, a2)
+ pytest.raises(TypeError, npyv2.add_u32, a, a)
+
+ @pytest.mark.parametrize('sfx', unsigned_sfx)
+ def test_unsigned_overflow(self, sfx):
+ nlanes = getattr(npyv, "nlanes_" + sfx)
+ maxu = (1 << int(sfx[1:])) - 1
+ maxu_72 = (1 << 72) - 1
+ lane = getattr(npyv, "setall_" + sfx)(maxu_72)[0]
+ assert lane == maxu
+ lanes = getattr(npyv, "load_" + sfx)([maxu_72] * nlanes)
+ assert lanes == [maxu] * nlanes
+ lane = getattr(npyv, "setall_" + sfx)(-1)[0]
+ assert lane == maxu
+ lanes = getattr(npyv, "load_" + sfx)([-1] * nlanes)
+ assert lanes == [maxu] * nlanes
+
+ @pytest.mark.parametrize('sfx', signed_sfx)
+ def test_signed_overflow(self, sfx):
+ nlanes = getattr(npyv, "nlanes_" + sfx)
+ maxs_72 = (1 << 71) - 1
+ lane = getattr(npyv, "setall_" + sfx)(maxs_72)[0]
+ assert lane == -1
+ lanes = getattr(npyv, "load_" + sfx)([maxs_72] * nlanes)
+ assert lanes == [-1] * nlanes
+ mins_72 = -1 << 71
+ lane = getattr(npyv, "setall_" + sfx)(mins_72)[0]
+ assert lane == 0
+ lanes = getattr(npyv, "load_" + sfx)([mins_72] * nlanes)
+ assert lanes == [0] * nlanes
+
+ def test_truncate_f32(self):
+ f32 = npyv.setall_f32(0.1)[0]
+ assert f32 != 0.1
+ assert round(f32, 1) == 0.1
+
+ def test_compare(self):
+ data_range = range(0, npyv.nlanes_u32)
+ vdata = npyv.load_u32(data_range)
+ assert vdata == list(data_range)
+ assert vdata == tuple(data_range)
+ for i in data_range:
+ assert vdata[i] == data_range[i]
import warnings
import itertools
+import sys
import pytest
from numpy.testing import (
assert_, assert_equal, assert_raises, assert_array_equal,
assert_almost_equal, assert_array_almost_equal, assert_no_warnings,
- assert_allclose,
+ assert_allclose, HAS_REFCOUNT,
)
from numpy.compat import pickle
assert_array_equal(res_num.astype("O"), res_obj)
+def _pickleable_module_global():
+ pass
+
+
class TestUfunc:
def test_pickle(self):
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
b"(S'numpy.core.umath'\np1\nS'cos'\np2\ntp3\nRp4\n.")
assert_(pickle.loads(astring) is np.cos)
+ def test_pickle_name_is_qualname(self):
+ # This tests that a simplification of our ufunc pickle code will
+ # lead to allowing qualnames as names. Future ufuncs should
+ # possible add a specific qualname, or a hook into pickling instead
+ # (dask+numba may benefit).
+ _pickleable_module_global.ufunc = umt._pickleable_module_global_ufunc
+ obj = pickle.loads(pickle.dumps(_pickleable_module_global.ufunc))
+ assert obj is umt._pickleable_module_global_ufunc
+
def test_reduceat_shifting_sum(self):
L = 6
x = np.arange(L)
warnings.simplefilter("always")
u += v
assert_equal(len(w), 1)
- assert_(x[0,0] != u[0, 0])
+ assert_(x[0, 0] != u[0, 0])
+
+ # Output reduction should not be allowed.
+ # See gh-15139
+ a = np.arange(6).reshape(3, 2)
+ b = np.ones(2)
+ out = np.empty(())
+ assert_raises(ValueError, umt.inner1d, a, b, out)
+ out2 = np.empty(3)
+ c = umt.inner1d(a, b, out2)
+ assert_(c is out2)
+
+ def test_out_broadcasts(self):
+ # For ufuncs and gufuncs (not for reductions), we currently allow
+ # the output to cause broadcasting of the input arrays.
+ # both along dimensions with shape 1 and dimensions which do not
+ # exist at all in the inputs.
+ arr = np.arange(3).reshape(1, 3)
+ out = np.empty((5, 4, 3))
+ np.add(arr, arr, out=out)
+ assert (out == np.arange(3) * 2).all()
+
+ # The same holds for gufuncs (gh-16484)
+ umt.inner1d(arr, arr, out=out)
+ # the result would be just a scalar `5`, but is broadcast fully:
+ assert (out == 5).all()
def test_type_cast(self):
msg = "type cast"
assert_array_equal(result, np.vstack((np.zeros(3), a[2], -a[1])))
assert_raises(ValueError, umt.cross1d, np.eye(4), np.eye(4))
assert_raises(ValueError, umt.cross1d, a, np.arange(4.))
+ # Wrong output core dimension.
assert_raises(ValueError, umt.cross1d, a, np.arange(3.), np.zeros((3, 4)))
+ # Wrong output broadcast dimension (see gh-15139).
+ assert_raises(ValueError, umt.cross1d, a, np.arange(3.), np.zeros(3))
def test_can_ignore_signature(self):
# Comparing the effects of ? in signature:
m = np.array([True], dtype=bool)
assert_equal(np.sqrt(a, where=m), [1])
+ def test_where_with_broadcasting(self):
+ # See gh-17198
+ a = np.random.random((5000, 4))
+ b = np.random.random((5000, 1))
+
+ where = a > 0.3
+ out = np.full_like(a, 0)
+ np.less(a, b, where=where, out=out)
+ b_where = np.broadcast_to(b, a.shape)[where]
+ assert_array_equal((a[where] < b_where), out[where].astype(bool))
+ assert not out[~where].any() # outside mask, out remains all 0
+
def check_identityless_reduction(self, a):
# np.minimum.reduce is an identityless reduction
assert_equal(y_base[1,:], y_base_copy[1,:])
assert_equal(y_base[3,:], y_base_copy[3,:])
- @pytest.mark.parametrize('output_shape',
- [(), (1,), (1, 1), (1, 3), (4, 3)])
+ @pytest.mark.parametrize('out_shape',
+ [(), (1,), (3,), (1, 1), (1, 3), (4, 3)])
+ @pytest.mark.parametrize('keepdims', [True, False])
@pytest.mark.parametrize('f_reduce', [np.add.reduce, np.minimum.reduce])
- def test_reduce_wrong_dimension_output(self, f_reduce, output_shape):
+ def test_reduce_wrong_dimension_output(self, f_reduce, keepdims, out_shape):
# Test that we're not incorrectly broadcasting dimensions.
# See gh-15144 (failed for np.add.reduce previously).
a = np.arange(12.).reshape(4, 3)
- out = np.empty(output_shape, a.dtype)
- assert_raises(ValueError, f_reduce, a, axis=0, out=out)
- if output_shape != (1, 3):
- assert_raises(ValueError, f_reduce, a, axis=0, out=out,
- keepdims=True)
+ out = np.empty(out_shape, a.dtype)
+
+ correct_out = f_reduce(a, axis=0, keepdims=keepdims)
+ if out_shape != correct_out.shape:
+ with assert_raises(ValueError):
+ f_reduce(a, axis=0, out=out, keepdims=keepdims)
else:
- check = f_reduce(a, axis=0, out=out, keepdims=True)
+ check = f_reduce(a, axis=0, out=out, keepdims=keepdims)
assert_(check is out)
- assert_array_equal(check, f_reduce(a, axis=0, keepdims=True))
+ assert_array_equal(check, correct_out)
+
+ def test_reduce_output_does_not_broadcast_input(self):
+ # Test that the output shape cannot broadcast an input dimension
+ # (it never can add dimensions, but it might expand an existing one)
+ a = np.ones((1, 10))
+ out_correct = (np.empty((1, 1)))
+ out_incorrect = np.empty((3, 1))
+ np.add.reduce(a, axis=-1, out=out_correct, keepdims=True)
+ np.add.reduce(a, axis=-1, out=out_correct[:, 0], keepdims=False)
+ with assert_raises(ValueError):
+ np.add.reduce(a, axis=-1, out=out_incorrect, keepdims=True)
+ with assert_raises(ValueError):
+ np.add.reduce(a, axis=-1, out=out_incorrect[:, 0], keepdims=False)
+
+ def test_reduce_output_subclass_ok(self):
+ class MyArr(np.ndarray):
+ pass
+
+ out = np.empty(())
+ np.add.reduce(np.ones(5), out=out) # no subclass, all fine
+ out = out.view(MyArr)
+ assert np.add.reduce(np.ones(5), out=out) is out
+ assert type(np.add.reduce(out)) is MyArr
def test_no_doc_string(self):
# gh-9337
else:
raise ValueError('ufunc with more than 2 inputs')
+
+@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
+def test_ufunc_casterrors():
+ # Tests that casting errors are correctly reported and buffers are
+ # cleared.
+ # The following array can be added to itself as an object array, but
+ # the result cannot be cast to an integer output:
+ value = 123 # relies on python cache (leak-check will still find it)
+ arr = np.array([value] * int(np.BUFSIZE * 1.5) +
+ ["string"] +
+ [value] * int(1.5 * np.BUFSIZE), dtype=object)
+ out = np.ones(len(arr), dtype=np.intp)
+
+ count = sys.getrefcount(value)
+ with pytest.raises(ValueError):
+ # Output casting failure:
+ np.add(arr, arr, out=out, casting="unsafe")
+
+ assert count == sys.getrefcount(value)
+ # output is unchanged after the error, this shows that the iteration
+ # was aborted (this is not necessarily defined behaviour)
+ assert out[-1] == 1
+
+ with pytest.raises(ValueError):
+ # Input casting failure:
+ np.add(arr, arr, out=out, dtype=np.intp, casting="unsafe")
+
+ assert count == sys.getrefcount(value)
+ # output is unchanged after the error, this shows that the iteration
+ # was aborted (this is not necessarily defined behaviour)
+ assert out[-1] == 1
+
+
+@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
+@pytest.mark.parametrize("offset",
+ [0, np.BUFSIZE//2, int(1.5*np.BUFSIZE)])
+def test_reduce_casterrors(offset):
+ # Test reporting of casting errors in reductions, we test various
+ # offsets to where the casting error will occur, since these may occur
+ # at different places during the reduction procedure. For example
+ # the first item may be special.
+ value = 123 # relies on python cache (leak-check will still find it)
+ arr = np.array([value] * offset +
+ ["string"] +
+ [value] * int(1.5 * np.BUFSIZE), dtype=object)
+ out = np.array(-1, dtype=np.intp)
+
+ count = sys.getrefcount(value)
+ with pytest.raises(ValueError):
+ # This is an unsafe cast, but we currently always allow that:
+ np.add.reduce(arr, dtype=np.intp, out=out)
+ assert count == sys.getrefcount(value)
+ # If an error occurred during casting, the operation is done at most until
+ # the error occurs (the result of which would be `value * offset`) and -1
+ # if the error happened immediately.
+ # This does not define behaviour, the output is invalid and thus undefined
+ assert out[()] < value * offset
import fnmatch
import itertools
import pytest
+import sys
from fractions import Fraction
import numpy.core.umath as ncu
assert_, assert_equal, assert_raises, assert_raises_regex,
assert_array_equal, assert_almost_equal, assert_array_almost_equal,
assert_array_max_ulp, assert_allclose, assert_no_warnings, suppress_warnings,
- _gen_alignment_data, assert_array_almost_equal_nulp
+ _gen_alignment_data, assert_array_almost_equal_nulp, assert_warns
)
def on_powerpc():
def bad_arcsinh():
- """The blacklisted trig functions are not accurate on aarch64 for
+ """The blocklisted trig functions are not accurate on aarch64 for
complex256. Rather than dig through the actual problem skip the
test. This should be fixed when we can move past glibc2.17
which is the version in manylinux2014
assert_equal(np.signbit(x//1), 0)
assert_equal(np.signbit((-x)//1), 1)
+ @pytest.mark.parametrize('dtype', np.typecodes['Float'])
+ def test_floor_division_errors(self, dtype):
+ fnan = np.array(np.nan, dtype=dtype)
+ fone = np.array(1.0, dtype=dtype)
+ fzer = np.array(0.0, dtype=dtype)
+ finf = np.array(np.inf, dtype=dtype)
+ # divide by zero error check
+ with np.errstate(divide='raise', invalid='ignore'):
+ assert_raises(FloatingPointError, np.floor_divide, fone, fzer)
+ with np.errstate(invalid='raise'):
+ assert_raises(FloatingPointError, np.floor_divide, fnan, fone)
+ assert_raises(FloatingPointError, np.floor_divide, fone, fnan)
+ assert_raises(FloatingPointError, np.floor_divide, fnan, fzer)
+
+ @pytest.mark.parametrize('dtype', np.typecodes['Float'])
+ def test_floor_division_corner_cases(self, dtype):
+ # test corner cases like 1.0//0.0 for errors and return vals
+ x = np.zeros(10, dtype=dtype)
+ y = np.ones(10, dtype=dtype)
+ fnan = np.array(np.nan, dtype=dtype)
+ fone = np.array(1.0, dtype=dtype)
+ fzer = np.array(0.0, dtype=dtype)
+ finf = np.array(np.inf, dtype=dtype)
+ with suppress_warnings() as sup:
+ sup.filter(RuntimeWarning, "invalid value encountered in floor_divide")
+ div = np.floor_divide(fnan, fone)
+ assert(np.isnan(div)), "dt: %s, div: %s" % (dt, div)
+ div = np.floor_divide(fone, fnan)
+ assert(np.isnan(div)), "dt: %s, div: %s" % (dt, div)
+ div = np.floor_divide(fnan, fzer)
+ assert(np.isnan(div)), "dt: %s, div: %s" % (dt, div)
+ # verify 1.0//0.0 computations return inf
+ with np.errstate(divide='ignore'):
+ z = np.floor_divide(y, x)
+ assert_(np.isinf(z).all())
+
def floor_divide_and_remainder(x, y):
return (np.floor_divide(x, y), np.remainder(x, y))
else:
assert_(b > rem >= 0, msg)
+ @pytest.mark.parametrize('dtype', np.typecodes['Float'])
+ def test_float_divmod_errors(self, dtype):
+ # Check valid errors raised for divmod and remainder
+ fzero = np.array(0.0, dtype=dtype)
+ fone = np.array(1.0, dtype=dtype)
+ finf = np.array(np.inf, dtype=dtype)
+ fnan = np.array(np.nan, dtype=dtype)
+ # since divmod is combination of both remainder and divide
+ # ops it will set both dividebyzero and invalid flags
+ with np.errstate(divide='raise', invalid='ignore'):
+ assert_raises(FloatingPointError, np.divmod, fone, fzero)
+ with np.errstate(divide='ignore', invalid='raise'):
+ assert_raises(FloatingPointError, np.divmod, fone, fzero)
+ with np.errstate(invalid='raise'):
+ assert_raises(FloatingPointError, np.divmod, fzero, fzero)
+ with np.errstate(invalid='raise'):
+ assert_raises(FloatingPointError, np.divmod, finf, finf)
+ with np.errstate(divide='ignore', invalid='raise'):
+ assert_raises(FloatingPointError, np.divmod, finf, fzero)
+ with np.errstate(divide='raise', invalid='ignore'):
+ assert_raises(FloatingPointError, np.divmod, finf, fzero)
+
+ @pytest.mark.parametrize('dtype', np.typecodes['Float'])
+ @pytest.mark.parametrize('fn', [np.fmod, np.remainder])
+ def test_float_remainder_errors(self, dtype, fn):
+ fzero = np.array(0.0, dtype=dtype)
+ fone = np.array(1.0, dtype=dtype)
+ finf = np.array(np.inf, dtype=dtype)
+ fnan = np.array(np.nan, dtype=dtype)
+ with np.errstate(invalid='raise'):
+ assert_raises(FloatingPointError, fn, fone, fzero)
+ assert_raises(FloatingPointError, fn, fnan, fzero)
+ assert_raises(FloatingPointError, fn, fone, fnan)
+ assert_raises(FloatingPointError, fn, fnan, fone)
+
+ def test_float_remainder_overflow(self):
+ a = np.finfo(np.float64).tiny
+ with np.errstate(over='ignore', invalid='ignore'):
+ div, mod = np.divmod(4, a)
+ np.isinf(div)
+ assert_(mod == 0)
+ with np.errstate(over='raise', invalid='ignore'):
+ assert_raises(FloatingPointError, np.divmod, 4, a)
+ with np.errstate(invalid='raise', over='ignore'):
+ assert_raises(FloatingPointError, np.divmod, 4, a)
+
+ def test_float_divmod_corner_cases(self):
+ # check nan cases
+ for dt in np.typecodes['Float']:
+ fnan = np.array(np.nan, dtype=dt)
+ fone = np.array(1.0, dtype=dt)
+ fzer = np.array(0.0, dtype=dt)
+ finf = np.array(np.inf, dtype=dt)
+ with suppress_warnings() as sup:
+ sup.filter(RuntimeWarning, "invalid value encountered in divmod")
+ sup.filter(RuntimeWarning, "divide by zero encountered in divmod")
+ div, rem = np.divmod(fone, fzer)
+ assert(np.isinf(div)), 'dt: %s, div: %s' % (dt, rem)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
+ div, rem = np.divmod(fzer, fzer)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
+ assert_(np.isnan(div)), 'dt: %s, rem: %s' % (dt, rem)
+ div, rem = np.divmod(finf, finf)
+ assert(np.isnan(div)), 'dt: %s, rem: %s' % (dt, rem)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
+ div, rem = np.divmod(finf, fzer)
+ assert(np.isinf(div)), 'dt: %s, rem: %s' % (dt, rem)
+ assert(np.isnan(rem)), 'dt: %s, rem: %s' % (dt, rem)
+ div, rem = np.divmod(fnan, fone)
+ assert(np.isnan(rem)), "dt: %s, rem: %s" % (dt, rem)
+ assert(np.isnan(div)), "dt: %s, rem: %s" % (dt, rem)
+ div, rem = np.divmod(fone, fnan)
+ assert(np.isnan(rem)), "dt: %s, rem: %s" % (dt, rem)
+ assert(np.isnan(div)), "dt: %s, rem: %s" % (dt, rem)
+ div, rem = np.divmod(fnan, fzer)
+ assert(np.isnan(rem)), "dt: %s, rem: %s" % (dt, rem)
+ assert(np.isnan(div)), "dt: %s, rem: %s" % (dt, rem)
+
def test_float_remainder_corner_cases(self):
# Check remainder magnitude.
for dt in np.typecodes['Float']:
+ fone = np.array(1.0, dtype=dt)
+ fzer = np.array(0.0, dtype=dt)
+ fnan = np.array(np.nan, dtype=dt)
b = np.array(1.0, dtype=dt)
a = np.nextafter(np.array(0.0, dtype=dt), -b)
rem = np.remainder(a, b)
# Check nans, inf
with suppress_warnings() as sup:
sup.filter(RuntimeWarning, "invalid value encountered in remainder")
+ sup.filter(RuntimeWarning, "invalid value encountered in fmod")
for dt in np.typecodes['Float']:
fone = np.array(1.0, dtype=dt)
fzer = np.array(0.0, dtype=dt)
# MSVC 2008 returns NaN here, so disable the check.
#rem = np.remainder(fone, finf)
#assert_(rem == fone, 'dt: %s, rem: %s' % (dt, rem))
+ rem = np.remainder(finf, fone)
+ fmod = np.fmod(finf, fone)
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, fmod))
+ assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ rem = np.remainder(finf, finf)
+ fmod = np.fmod(finf, fone)
+ assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, fmod))
+ rem = np.remainder(finf, fzer)
+ fmod = np.fmod(finf, fzer)
+ assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, fmod))
rem = np.remainder(fone, fnan)
+ fmod = np.fmod(fone, fnan)
assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
- rem = np.remainder(finf, fone)
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, fmod))
+ rem = np.remainder(fnan, fzer)
+ fmod = np.fmod(fnan, fzer)
+ assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, rem))
+ rem = np.remainder(fnan, fone)
+ fmod = np.fmod(fnan, fone)
assert_(np.isnan(rem), 'dt: %s, rem: %s' % (dt, rem))
+ assert_(np.isnan(fmod), 'dt: %s, fmod: %s' % (dt, rem))
class TestCbrt:
yf = np.array(y, dtype=dt)*log2_
assert_almost_equal(np.log(xf), yf)
+ # test aliasing(issue #17761)
+ x = np.array([2, 0.937500, 3, 0.947500, 1.054697])
+ xf = np.log(x)
+ assert_almost_equal(np.log(x, out=x), xf)
+
+ def test_log_strides(self):
+ np.random.seed(42)
+ strides = np.array([-4,-3,-2,-1,1,2,3,4])
+ sizes = np.arange(2,100)
+ for ii in sizes:
+ x_f64 = np.float64(np.random.uniform(low=0.01, high=100.0,size=ii))
+ x_special = x_f64.copy()
+ x_special[3:-1:4] = 1.0
+ y_true = np.log(x_f64)
+ y_special = np.log(x_special)
+ for jj in strides:
+ assert_array_almost_equal_nulp(np.log(x_f64[::jj]), y_true[::jj], nulp=2)
+ assert_array_almost_equal_nulp(np.log(x_special[::jj]), y_special[::jj], nulp=2)
class TestExp:
def test_exp_values(self):
for dt in ['f', 'd', 'g']:
assert_raises(FloatingPointError, np.reciprocal, np.array(-0.0, dtype=dt))
+class TestFPClass:
+ @pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])
+ def test_fpclass(self, stride):
+ arr_f64 = np.array([np.nan, -np.nan, np.inf, -np.inf, -1.0, 1.0, -0.0, 0.0, 2.2251e-308, -2.2251e-308], dtype='d')
+ arr_f32 = np.array([np.nan, -np.nan, np.inf, -np.inf, -1.0, 1.0, -0.0, 0.0, 1.4013e-045, -1.4013e-045], dtype='f')
+ nan = np.array([True, True, False, False, False, False, False, False, False, False])
+ inf = np.array([False, False, True, True, False, False, False, False, False, False])
+ sign = np.array([False, True, False, True, True, False, True, False, False, True])
+ finite = np.array([False, False, False, False, True, True, True, True, True, True])
+ assert_equal(np.isnan(arr_f32[::stride]), nan[::stride])
+ assert_equal(np.isnan(arr_f64[::stride]), nan[::stride])
+ assert_equal(np.isinf(arr_f32[::stride]), inf[::stride])
+ assert_equal(np.isinf(arr_f64[::stride]), inf[::stride])
+ assert_equal(np.signbit(arr_f32[::stride]), sign[::stride])
+ assert_equal(np.signbit(arr_f64[::stride]), sign[::stride])
+ assert_equal(np.isfinite(arr_f32[::stride]), finite[::stride])
+ assert_equal(np.isfinite(arr_f64[::stride]), finite[::stride])
+
+class TestLDExp:
+ @pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])
+ @pytest.mark.parametrize("dtype", ['f', 'd'])
+ def test_ldexp(self, dtype, stride):
+ mant = np.array([0.125, 0.25, 0.5, 1., 1., 2., 4., 8.], dtype=dtype)
+ exp = np.array([3, 2, 1, 0, 0, -1, -2, -3], dtype='i')
+ out = np.zeros(8, dtype=dtype)
+ assert_equal(np.ldexp(mant[::stride], exp[::stride], out=out[::stride]), np.ones(8, dtype=dtype)[::stride])
+ assert_equal(out[::stride], np.ones(8, dtype=dtype)[::stride])
+
+class TestFRExp:
+ @pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])
+ @pytest.mark.parametrize("dtype", ['f', 'd'])
+ @pytest.mark.skipif(not sys.platform.startswith('linux'),
+ reason="np.frexp gives different answers for NAN/INF on windows and linux")
+ def test_frexp(self, dtype, stride):
+ arr = np.array([np.nan, np.nan, np.inf, -np.inf, 0.0, -0.0, 1.0, -1.0], dtype=dtype)
+ mant_true = np.array([np.nan, np.nan, np.inf, -np.inf, 0.0, -0.0, 0.5, -0.5], dtype=dtype)
+ exp_true = np.array([0, 0, 0, 0, 0, 0, 1, 1], dtype='i')
+ out_mant = np.ones(8, dtype=dtype)
+ out_exp = 2*np.ones(8, dtype='i')
+ mant, exp = np.frexp(arr[::stride], out=(out_mant[::stride], out_exp[::stride]))
+ assert_equal(mant_true[::stride], mant)
+ assert_equal(exp_true[::stride], exp)
+ assert_equal(out_mant[::stride], mant_true[::stride])
+ assert_equal(out_exp[::stride], exp_true[::stride])
+
# func : [maxulperror, low, high]
avx_ufuncs = {'sqrt' :[1, 0., 100.],
'absolute' :[0, -100., 100.],
x_f64 = np.float64(x_f32)
assert_array_max_ulp(np.sin(x_f32), np.float32(np.sin(x_f64)), maxulp=2)
assert_array_max_ulp(np.cos(x_f32), np.float32(np.cos(x_f64)), maxulp=2)
+ # test aliasing(issue #17761)
+ tx_f32 = x_f32.copy()
+ assert_array_max_ulp(np.sin(x_f32, out=x_f32), np.float32(np.sin(x_f64)), maxulp=2)
+ assert_array_max_ulp(np.cos(tx_f32, out=tx_f32), np.float32(np.cos(x_f64)), maxulp=2)
def test_strided_float32(self):
np.random.seed(42)
assert_raises(ValueError, inner1d, a, a, out=())
def test_ufunc_override_with_super(self):
- # NOTE: this class is given as an example in doc/subclassing.py;
+ # NOTE: this class is used in doc/source/user/basics.subclassing.rst
# if you make any changes here, do update it there too.
class A(np.ndarray):
def __array_ufunc__(self, ufunc, method, *inputs, out=None, **kwargs):
class foo(np.ndarray): pass
actual = np.multiply.outer(arr.view(foo), arr.view(foo))
assert actual.__class__.__name__ == 'foo'
+
+def test_outer_bad_subclass():
+ class BadArr1(np.ndarray):
+ def __array_finalize__(self, obj):
+ # The outer call reshapes to 3 dims, try to do a bad reshape.
+ if self.ndim == 3:
+ self.shape = self.shape + (1,)
+
+ def __array_prepare__(self, obj, context=None):
+ return obj
+
+ class BadArr2(np.ndarray):
+ def __array_finalize__(self, obj):
+ if isinstance(obj, BadArr2):
+ # outer inserts 1-sized dims. In that case disturb them.
+ if self.shape[-1] == 1:
+ self.shape = self.shape[::-1]
+
+ def __array_prepare__(self, obj, context=None):
+ return obj
+
+ for cls in [BadArr1, BadArr2]:
+ arr = np.ones((2, 3)).view(cls)
+ with assert_raises(TypeError) as a:
+ # The first array gets reshaped (not the second one)
+ np.add.outer(arr, [1, 2])
+
+ # This actually works, since we only see the reshaping error:
+ arr = np.ones((2, 3)).view(cls)
+ assert type(np.add.outer([1, 2], arr)) is cls
+
+def test_outer_exceeds_maxdims():
+ deep = np.ones((1,) * 17)
+ with assert_raises(ValueError):
+ np.add.outer(deep, deep)
+
@pytest.mark.parametrize("stride", [-4,-2,-1,1,2,4])
@pytest.mark.parametrize("astype", [np.complex64, np.complex128])
def test_array(self, stride, astype):
- arr = np.array([np.complex(np.nan , np.nan),
- np.complex(np.nan , np.inf),
- np.complex(np.inf , np.nan),
- np.complex(np.inf , np.inf),
- np.complex(0. , np.inf),
- np.complex(np.inf , 0.),
- np.complex(0. , 0.),
- np.complex(0. , np.nan),
- np.complex(np.nan , 0.)], dtype=astype)
+ arr = np.array([complex(np.nan , np.nan),
+ complex(np.nan , np.inf),
+ complex(np.inf , np.nan),
+ complex(np.inf , np.inf),
+ complex(0. , np.inf),
+ complex(np.inf , 0.),
+ complex(0. , 0.),
+ complex(0. , np.nan),
+ complex(np.nan , 0.)], dtype=astype)
abs_true = np.array([np.nan, np.inf, np.inf, np.inf, np.inf, np.inf, 0., np.nan, np.nan], dtype=arr.real.dtype)
- sq_true = np.array([np.complex(np.nan, np.nan),
- np.complex(np.nan, np.nan),
- np.complex(np.nan, np.nan),
- np.complex(np.nan, np.inf),
- np.complex(-np.inf, np.nan),
- np.complex(np.inf, np.nan),
- np.complex(0., 0.),
- np.complex(np.nan, np.nan),
- np.complex(np.nan, np.nan)], dtype=astype)
+ sq_true = np.array([complex(np.nan, np.nan),
+ complex(np.nan, np.nan),
+ complex(np.nan, np.nan),
+ complex(np.nan, np.inf),
+ complex(-np.inf, np.nan),
+ complex(np.inf, np.nan),
+ complex(0., 0.),
+ complex(np.nan, np.nan),
+ complex(np.nan, np.nan)], dtype=astype)
assert_equal(np.abs(arr[::stride]), abs_true[::stride])
with np.errstate(invalid='ignore'):
assert_equal(np.square(arr[::stride]), sq_true[::stride])
>>> _lib.foo_func(out, len(out)) #doctest: +SKIP
"""
-__all__ = ['load_library', 'ndpointer', 'ctypes_load_library',
- 'c_intp', 'as_ctypes', 'as_array']
+__all__ = ['load_library', 'ndpointer', 'c_intp', 'as_ctypes', 'as_array']
import os
from numpy import (
- integer, ndarray, dtype as _dtype, deprecate, array, frombuffer
+ integer, ndarray, dtype as _dtype, array, frombuffer
)
from numpy.core.multiarray import _flagdict, flagsobj
"""
raise ImportError("ctypes is not available.")
- ctypes_load_library = _dummy
load_library = _dummy
as_ctypes = _dummy
as_array = _dummy
## if no successful return in the libname_ext loop:
raise OSError("no file with expected extension")
- ctypes_load_library = deprecate(load_library, 'ctypes_load_library',
- 'load_library')
def _num_fromflags(flaglist):
num = 0
if num is None:
try:
flags = [x.strip().upper() for x in flags]
- except Exception:
- raise TypeError("invalid flags specification")
+ except Exception as e:
+ raise TypeError("invalid flags specification") from e
num = _num_fromflags(flags)
# normalize shape to an Optional[tuple]
dtype_native = dtype.newbyteorder('=')
try:
ctype = _scalar_type_map[dtype_native]
- except KeyError:
+ except KeyError as e:
raise NotImplementedError(
"Converting {!r} to a ctypes type".format(dtype)
- )
+ ) from None
if dtype_with_endian.byteorder == '>':
ctype = ctype.__ctype_be__
--- /dev/null
+from typing import Any
+
+load_library: Any
+ndpointer: Any
+c_intp: Any
+as_ctypes: Any
+as_array: Any
--- /dev/null
+from typing import Any
+
+# TODO: remove when the full numpy namespace is defined
+def __getattr__(name: str) -> Any: ...
Printing is only done if the distutils log threshold is < 2.
"""
- if 0:
- for attrname in ['include_dirs', 'define', 'undef',
- 'libraries', 'library_dirs',
- 'rpath', 'link_objects']:
- attr = getattr(self, attrname, None)
- if not attr:
- continue
- log.info("compiler '%s' is set to %s" % (attrname, attr))
try:
self.get_version()
except Exception:
--- /dev/null
+"""Provides the `CCompilerOpt` class, used for handling the CPU/hardware
+optimization, starting from parsing the command arguments, to managing the
+relation between the CPU baseline and dispatch-able features,
+also generating the required C headers and ending with compiling
+the sources with proper compiler's flags.
+
+`CCompilerOpt` doesn't provide runtime detection for the CPU features,
+instead only focuses on the compiler side, but it creates abstract C headers
+that can be used later for the final runtime dispatching process."""
+
+import sys, io, os, re, textwrap, pprint, inspect, atexit, subprocess
+
+class _Config:
+ """An abstract class holds all configurable attributes of `CCompilerOpt`,
+ these class attributes can be used to change the default behavior
+ of `CCompilerOpt` in order to fit other requirements.
+
+ Attributes
+ ----------
+ conf_nocache : bool
+ Set True to disable memory and file cache.
+ Default is False.
+
+ conf_noopt : bool
+ Set True to forces the optimization to be disabled,
+ in this case `CCompilerOpt` tends to generate all
+ expected headers in order to 'not' break the build.
+ Default is False.
+
+ conf_cache_factors : list
+ Add extra factors to the primary caching factors. The caching factors
+ are utilized to determine if there are changes had happened that
+ requires to discard the cache and re-updating it. The primary factors
+ are the arguments of `CCompilerOpt` and `CCompiler`'s properties(type, flags, etc).
+ Default is list of two items, containing the time of last modification
+ of `ccompiler_opt` and value of attribute "conf_noopt"
+
+ conf_tmp_path : str,
+ The path of temporary directory. Default is auto-created
+ temporary directory via ``tempfile.mkdtemp()``.
+
+ conf_check_path : str
+ The path of testing files. Each added CPU feature must have a
+ **C** source file contains at least one intrinsic or instruction that
+ related to this feature, so it can be tested against the compiler.
+ Default is ``./distutils/checks``.
+
+ conf_target_groups : dict
+ Extra tokens that can be reached from dispatch-able sources through
+ the special mark ``@targets``. Default is an empty dictionary.
+
+ **Notes**:
+ - case-insensitive for tokens and group names
+ - sign '#' must stick in the begin of group name and only within ``@targets``
+
+ **Example**:
+ .. code-block:: console
+
+ $ "@targets #avx_group other_tokens" > group_inside.c
+
+ >>> CCompilerOpt.conf_target_groups["avx_group"] = \\
+ "$werror $maxopt avx2 avx512f avx512_skx"
+ >>> cco = CCompilerOpt(cc_instance)
+ >>> cco.try_dispatch(["group_inside.c"])
+
+ conf_c_prefix : str
+ The prefix of public C definitions. Default is ``"NPY_"``.
+
+ conf_c_prefix_ : str
+ The prefix of internal C definitions. Default is ``"NPY__"``.
+
+ conf_cc_flags : dict
+ Nested dictionaries defining several compiler flags
+ that linked to some major functions, the main key
+ represent the compiler name and sub-keys represent
+ flags names. Default is already covers all supported
+ **C** compilers.
+
+ Sub-keys explained as follows:
+
+ "native": str or None
+ used by argument option `native`, to detect the current
+ machine support via the compiler.
+ "werror": str or None
+ utilized to treat warning as errors during testing CPU features
+ against the compiler and also for target's policy `$werror`
+ via dispatch-able sources.
+ "maxopt": str or None
+ utilized for target's policy '$maxopt' and the value should
+ contains the maximum acceptable optimization by the compiler.
+ e.g. in gcc `'-O3'`
+
+ **Notes**:
+ * case-sensitive for compiler names and flags
+ * use space to separate multiple flags
+ * any flag will tested against the compiler and it will skipped
+ if it's not applicable.
+
+ conf_min_features : dict
+ A dictionary defines the used CPU features for
+ argument option `'min'`, the key represent the CPU architecture
+ name e.g. `'x86'`. Default values provide the best effort
+ on wide range of users platforms.
+
+ **Note**: case-sensitive for architecture names.
+
+ conf_features : dict
+ Nested dictionaries used for identifying the CPU features.
+ the primary key is represented as a feature name or group name
+ that gathers several features. Default values covers all
+ supported features but without the major options like "flags",
+ these undefined options handle it by method `conf_features_partial()`.
+ Default value is covers almost all CPU features for *X86*, *IBM/Power64*
+ and *ARM 7/8*.
+
+ Sub-keys explained as follows:
+
+ "implies" : str or list, optional,
+ List of CPU feature names to be implied by it,
+ the feature name must be defined within `conf_features`.
+ Default is None.
+
+ "flags": str or list, optional
+ List of compiler flags. Default is None.
+
+ "detect": str or list, optional
+ List of CPU feature names that required to be detected
+ in runtime. By default, its the feature name or features
+ in "group" if its specified.
+
+ "implies_detect": bool, optional
+ If True, all "detect" of implied features will be combined.
+ Default is True. see `feature_detect()`.
+
+ "group": str or list, optional
+ Same as "implies" but doesn't require the feature name to be
+ defined within `conf_features`.
+
+ "interest": int, required
+ a key for sorting CPU features
+
+ "headers": str or list, optional
+ intrinsics C header file
+
+ "disable": str, optional
+ force disable feature, the string value should contains the
+ reason of disabling.
+
+ "autovec": bool or None, optional
+ True or False to declare that CPU feature can be auto-vectorized
+ by the compiler.
+ By default(None), treated as True if the feature contains at
+ least one applicable flag. see `feature_can_autovec()`
+
+ "extra_checks": str or list, optional
+ Extra test case names for the CPU feature that need to be tested
+ against the compiler.
+
+ Each test case must have a C file named ``extra_xxxx.c``, where
+ ``xxxx`` is the case name in lower case, under 'conf_check_path'.
+ It should contain at least one intrinsic or function related to the test case.
+
+ If the compiler able to successfully compile the C file then `CCompilerOpt`
+ will add a C ``#define`` for it into the main dispatch header, e.g.
+ ```#define {conf_c_prefix}_XXXX`` where ``XXXX`` is the case name in upper case.
+
+ **NOTES**:
+ * space can be used as separator with options that supports "str or list"
+ * case-sensitive for all values and feature name must be in upper-case.
+ * if flags aren't applicable, its will skipped rather than disable the
+ CPU feature
+ * the CPU feature will disabled if the compiler fail to compile
+ the test file
+ """
+ conf_nocache = False
+ conf_noopt = False
+ conf_cache_factors = None
+ conf_tmp_path = None
+ conf_check_path = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "checks"
+ )
+ conf_target_groups = {}
+ conf_c_prefix = 'NPY_'
+ conf_c_prefix_ = 'NPY__'
+ conf_cc_flags = dict(
+ gcc = dict(
+ # native should always fail on arm and ppc64,
+ # native usually works only with x86
+ native = '-march=native',
+ opt = '-O3',
+ werror = '-Werror'
+ ),
+ clang = dict(
+ native = '-march=native',
+ opt = "-O3",
+ werror = '-Werror'
+ ),
+ icc = dict(
+ native = '-xHost',
+ opt = '-O3',
+ werror = '-Werror'
+ ),
+ iccw = dict(
+ native = '/QxHost',
+ opt = '/O3',
+ werror = '/Werror'
+ ),
+ msvc = dict(
+ native = None,
+ opt = '/O2',
+ werror = '/WX'
+ )
+ )
+ conf_min_features = dict(
+ x86 = "SSE SSE2",
+ x64 = "SSE SSE2 SSE3",
+ ppc64 = '', # play it safe
+ ppc64le = "VSX VSX2",
+ armhf = '', # play it safe
+ aarch64 = "NEON NEON_FP16 NEON_VFPV4 ASIMD"
+ )
+ conf_features = dict(
+ # X86
+ SSE = dict(
+ interest=1, headers="xmmintrin.h",
+ # enabling SSE without SSE2 is useless also
+ # it's non-optional for x86_64
+ implies="SSE2"
+ ),
+ SSE2 = dict(interest=2, implies="SSE", headers="emmintrin.h"),
+ SSE3 = dict(interest=3, implies="SSE2", headers="pmmintrin.h"),
+ SSSE3 = dict(interest=4, implies="SSE3", headers="tmmintrin.h"),
+ SSE41 = dict(interest=5, implies="SSSE3", headers="smmintrin.h"),
+ POPCNT = dict(interest=6, implies="SSE41", headers="popcntintrin.h"),
+ SSE42 = dict(interest=7, implies="POPCNT"),
+ AVX = dict(
+ interest=8, implies="SSE42", headers="immintrin.h",
+ implies_detect=False
+ ),
+ XOP = dict(interest=9, implies="AVX", headers="x86intrin.h"),
+ FMA4 = dict(interest=10, implies="AVX", headers="x86intrin.h"),
+ F16C = dict(interest=11, implies="AVX"),
+ FMA3 = dict(interest=12, implies="F16C"),
+ AVX2 = dict(interest=13, implies="F16C"),
+ AVX512F = dict(
+ interest=20, implies="FMA3 AVX2", implies_detect=False,
+ extra_checks="AVX512F_REDUCE"
+ ),
+ AVX512CD = dict(interest=21, implies="AVX512F"),
+ AVX512_KNL = dict(
+ interest=40, implies="AVX512CD", group="AVX512ER AVX512PF",
+ detect="AVX512_KNL", implies_detect=False
+ ),
+ AVX512_KNM = dict(
+ interest=41, implies="AVX512_KNL",
+ group="AVX5124FMAPS AVX5124VNNIW AVX512VPOPCNTDQ",
+ detect="AVX512_KNM", implies_detect=False
+ ),
+ AVX512_SKX = dict(
+ interest=42, implies="AVX512CD", group="AVX512VL AVX512BW AVX512DQ",
+ detect="AVX512_SKX", implies_detect=False,
+ extra_checks="AVX512BW_MASK AVX512DQ_MASK"
+ ),
+ AVX512_CLX = dict(
+ interest=43, implies="AVX512_SKX", group="AVX512VNNI",
+ detect="AVX512_CLX"
+ ),
+ AVX512_CNL = dict(
+ interest=44, implies="AVX512_SKX", group="AVX512IFMA AVX512VBMI",
+ detect="AVX512_CNL", implies_detect=False
+ ),
+ AVX512_ICL = dict(
+ interest=45, implies="AVX512_CLX AVX512_CNL",
+ group="AVX512VBMI2 AVX512BITALG AVX512VPOPCNTDQ",
+ detect="AVX512_ICL", implies_detect=False
+ ),
+ # IBM/Power
+ ## Power7/ISA 2.06
+ VSX = dict(interest=1, headers="altivec.h"),
+ ## Power8/ISA 2.07
+ VSX2 = dict(interest=2, implies="VSX", implies_detect=False),
+ ## Power9/ISA 3.00
+ VSX3 = dict(interest=3, implies="VSX2", implies_detect=False),
+ # ARM
+ NEON = dict(interest=1, headers="arm_neon.h"),
+ NEON_FP16 = dict(interest=2, implies="NEON"),
+ ## FMA
+ NEON_VFPV4 = dict(interest=3, implies="NEON_FP16"),
+ ## Advanced SIMD
+ ASIMD = dict(interest=4, implies="NEON_FP16 NEON_VFPV4", implies_detect=False),
+ ## ARMv8.2 half-precision & vector arithm
+ ASIMDHP = dict(interest=5, implies="ASIMD"),
+ ## ARMv8.2 dot product
+ ASIMDDP = dict(interest=6, implies="ASIMD"),
+ ## ARMv8.2 Single & half-precision Multiply
+ ASIMDFHM = dict(interest=7, implies="ASIMDHP"),
+ )
+ def conf_features_partial(self):
+ """Return a dictionary of supported CPU features by the platform,
+ and accumulate the rest of undefined options in `conf_features`,
+ the returned dict has same rules and notes in
+ class attribute `conf_features`, also its override
+ any options that been set in 'conf_features'.
+ """
+ if self.cc_noopt:
+ # optimization is disabled
+ return {}
+
+ on_x86 = self.cc_on_x86 or self.cc_on_x64
+ is_unix = self.cc_is_gcc or self.cc_is_clang
+
+ if on_x86 and is_unix: return dict(
+ SSE = dict(flags="-msse"),
+ SSE2 = dict(flags="-msse2"),
+ SSE3 = dict(flags="-msse3"),
+ SSSE3 = dict(flags="-mssse3"),
+ SSE41 = dict(flags="-msse4.1"),
+ POPCNT = dict(flags="-mpopcnt"),
+ SSE42 = dict(flags="-msse4.2"),
+ AVX = dict(flags="-mavx"),
+ F16C = dict(flags="-mf16c"),
+ XOP = dict(flags="-mxop"),
+ FMA4 = dict(flags="-mfma4"),
+ FMA3 = dict(flags="-mfma"),
+ AVX2 = dict(flags="-mavx2"),
+ AVX512F = dict(flags="-mavx512f"),
+ AVX512CD = dict(flags="-mavx512cd"),
+ AVX512_KNL = dict(flags="-mavx512er -mavx512pf"),
+ AVX512_KNM = dict(
+ flags="-mavx5124fmaps -mavx5124vnniw -mavx512vpopcntdq"
+ ),
+ AVX512_SKX = dict(flags="-mavx512vl -mavx512bw -mavx512dq"),
+ AVX512_CLX = dict(flags="-mavx512vnni"),
+ AVX512_CNL = dict(flags="-mavx512ifma -mavx512vbmi"),
+ AVX512_ICL = dict(
+ flags="-mavx512vbmi2 -mavx512bitalg -mavx512vpopcntdq"
+ )
+ )
+ if on_x86 and self.cc_is_icc: return dict(
+ SSE = dict(flags="-msse"),
+ SSE2 = dict(flags="-msse2"),
+ SSE3 = dict(flags="-msse3"),
+ SSSE3 = dict(flags="-mssse3"),
+ SSE41 = dict(flags="-msse4.1"),
+ POPCNT = {},
+ SSE42 = dict(flags="-msse4.2"),
+ AVX = dict(flags="-mavx"),
+ F16C = {},
+ XOP = dict(disable="Intel Compiler doesn't support it"),
+ FMA4 = dict(disable="Intel Compiler doesn't support it"),
+ # Intel Compiler doesn't support AVX2 or FMA3 independently
+ FMA3 = dict(
+ implies="F16C AVX2", flags="-march=core-avx2"
+ ),
+ AVX2 = dict(implies="FMA3", flags="-march=core-avx2"),
+ # Intel Compiler doesn't support AVX512F or AVX512CD independently
+ AVX512F = dict(
+ implies="AVX2 AVX512CD", flags="-march=common-avx512"
+ ),
+ AVX512CD = dict(
+ implies="AVX2 AVX512F", flags="-march=common-avx512"
+ ),
+ AVX512_KNL = dict(flags="-xKNL"),
+ AVX512_KNM = dict(flags="-xKNM"),
+ AVX512_SKX = dict(flags="-xSKYLAKE-AVX512"),
+ AVX512_CLX = dict(flags="-xCASCADELAKE"),
+ AVX512_CNL = dict(flags="-xCANNONLAKE"),
+ AVX512_ICL = dict(flags="-xICELAKE-CLIENT"),
+ )
+ if on_x86 and self.cc_is_iccw: return dict(
+ SSE = dict(flags="/arch:SSE"),
+ SSE2 = dict(flags="/arch:SSE2"),
+ SSE3 = dict(flags="/arch:SSE3"),
+ SSSE3 = dict(flags="/arch:SSSE3"),
+ SSE41 = dict(flags="/arch:SSE4.1"),
+ POPCNT = {},
+ SSE42 = dict(flags="/arch:SSE4.2"),
+ AVX = dict(flags="/arch:AVX"),
+ F16C = {},
+ XOP = dict(disable="Intel Compiler doesn't support it"),
+ FMA4 = dict(disable="Intel Compiler doesn't support it"),
+ # Intel Compiler doesn't support FMA3 or AVX2 independently
+ FMA3 = dict(
+ implies="F16C AVX2", flags="/arch:CORE-AVX2"
+ ),
+ AVX2 = dict(
+ implies="FMA3", flags="/arch:CORE-AVX2"
+ ),
+ # Intel Compiler doesn't support AVX512F or AVX512CD independently
+ AVX512F = dict(
+ implies="AVX2 AVX512CD", flags="/Qx:COMMON-AVX512"
+ ),
+ AVX512CD = dict(
+ implies="AVX2 AVX512F", flags="/Qx:COMMON-AVX512"
+ ),
+ AVX512_KNL = dict(flags="/Qx:KNL"),
+ AVX512_KNM = dict(flags="/Qx:KNM"),
+ AVX512_SKX = dict(flags="/Qx:SKYLAKE-AVX512"),
+ AVX512_CLX = dict(flags="/Qx:CASCADELAKE"),
+ AVX512_CNL = dict(flags="/Qx:CANNONLAKE"),
+ AVX512_ICL = dict(flags="/Qx:ICELAKE-CLIENT")
+ )
+ if on_x86 and self.cc_is_msvc: return dict(
+ SSE = dict(flags="/arch:SSE"),
+ SSE2 = dict(flags="/arch:SSE2"),
+ SSE3 = {},
+ SSSE3 = {},
+ SSE41 = {},
+ POPCNT = dict(headers="nmmintrin.h"),
+ SSE42 = {},
+ AVX = dict(flags="/arch:AVX"),
+ F16C = {},
+ XOP = dict(headers="ammintrin.h"),
+ FMA4 = dict(headers="ammintrin.h"),
+ # MSVC doesn't support FMA3 or AVX2 independently
+ FMA3 = dict(
+ implies="F16C AVX2", flags="/arch:AVX2"
+ ),
+ AVX2 = dict(
+ implies="F16C FMA3", flags="/arch:AVX2"
+ ),
+ # MSVC doesn't support AVX512F or AVX512CD independently,
+ # always generate instructions belong to (VL/VW/DQ)
+ AVX512F = dict(
+ implies="AVX2 AVX512CD AVX512_SKX", flags="/arch:AVX512"
+ ),
+ AVX512CD = dict(
+ implies="AVX512F AVX512_SKX", flags="/arch:AVX512"
+ ),
+ AVX512_KNL = dict(
+ disable="MSVC compiler doesn't support it"
+ ),
+ AVX512_KNM = dict(
+ disable="MSVC compiler doesn't support it"
+ ),
+ AVX512_SKX = dict(flags="/arch:AVX512"),
+ AVX512_CLX = {},
+ AVX512_CNL = {},
+ AVX512_ICL = {}
+ )
+
+ on_power = self.cc_on_ppc64le or self.cc_on_ppc64
+ if on_power:
+ partial = dict(
+ VSX = dict(
+ implies=("VSX2" if self.cc_on_ppc64le else ""),
+ flags="-mvsx"
+ ),
+ VSX2 = dict(
+ flags="-mcpu=power8", implies_detect=False
+ ),
+ VSX3 = dict(
+ flags="-mcpu=power9 -mtune=power9", implies_detect=False
+ )
+ )
+ if self.cc_is_clang:
+ partial["VSX"]["flags"] = "-maltivec -mvsx"
+ partial["VSX2"]["flags"] = "-mpower8-vector"
+ partial["VSX3"]["flags"] = "-mpower9-vector"
+
+ return partial
+
+ if self.cc_on_aarch64 and is_unix: return dict(
+ NEON = dict(
+ implies="NEON_FP16 NEON_VFPV4 ASIMD", autovec=True
+ ),
+ NEON_FP16 = dict(
+ implies="NEON NEON_VFPV4 ASIMD", autovec=True
+ ),
+ NEON_VFPV4 = dict(
+ implies="NEON NEON_FP16 ASIMD", autovec=True
+ ),
+ ASIMD = dict(
+ implies="NEON NEON_FP16 NEON_VFPV4", autovec=True
+ ),
+ ASIMDHP = dict(
+ flags="-march=armv8.2-a+fp16"
+ ),
+ ASIMDDP = dict(
+ flags="-march=armv8.2-a+dotprod"
+ ),
+ ASIMDFHM = dict(
+ flags="-march=armv8.2-a+fp16fml"
+ ),
+ )
+ if self.cc_on_armhf and is_unix: return dict(
+ NEON = dict(
+ flags="-mfpu=neon"
+ ),
+ NEON_FP16 = dict(
+ flags="-mfpu=neon-fp16 -mfp16-format=ieee"
+ ),
+ NEON_VFPV4 = dict(
+ flags="-mfpu=neon-vfpv4",
+ ),
+ ASIMD = dict(
+ flags="-mfpu=neon-fp-armv8 -march=armv8-a+simd",
+ ),
+ ASIMDHP = dict(
+ flags="-march=armv8.2-a+fp16"
+ ),
+ ASIMDDP = dict(
+ flags="-march=armv8.2-a+dotprod",
+ ),
+ ASIMDFHM = dict(
+ flags="-march=armv8.2-a+fp16fml"
+ )
+ )
+ # TODO: ARM MSVC
+ return {}
+
+ def __init__(self):
+ if self.conf_tmp_path is None:
+ import tempfile, shutil
+ tmp = tempfile.mkdtemp()
+ def rm_temp():
+ try:
+ shutil.rmtree(tmp)
+ except IOError:
+ pass
+ atexit.register(rm_temp)
+ self.conf_tmp_path = tmp
+
+ if self.conf_cache_factors is None:
+ self.conf_cache_factors = [
+ os.path.getmtime(__file__),
+ self.conf_nocache
+ ]
+
+class _Distutils:
+ """A helper class that provides a collection of fundamental methods
+ implemented in a top of Python and NumPy Distutils.
+
+ The idea behind this class is to gather all methods that it may
+ need to override in case of reuse 'CCompilerOpt' in environment
+ different than of what NumPy has.
+
+ Parameters
+ ----------
+ ccompiler : `CCompiler`
+ The generate instance that returned from `distutils.ccompiler.new_compiler()`.
+ """
+ def __init__(self, ccompiler):
+ self._ccompiler = ccompiler
+
+ def dist_compile(self, sources, flags, **kwargs):
+ """Wrap CCompiler.compile()"""
+ assert(isinstance(sources, list))
+ assert(isinstance(flags, list))
+ flags = kwargs.pop("extra_postargs", []) + flags
+ return self._ccompiler.compile(
+ sources, extra_postargs=flags, **kwargs
+ )
+
+ def dist_test(self, source, flags):
+ """Return True if 'CCompiler.compile()' able to compile
+ a source file with certain flags.
+ """
+ assert(isinstance(source, str))
+ from distutils.errors import CompileError
+ cc = self._ccompiler;
+ bk_spawn = getattr(cc, 'spawn', None)
+ if bk_spawn:
+ cc_type = getattr(self._ccompiler, "compiler_type", "")
+ if cc_type in ("msvc",):
+ setattr(cc, 'spawn', self._dist_test_spawn_paths)
+ else:
+ setattr(cc, 'spawn', self._dist_test_spawn)
+ test = False
+ try:
+ self.dist_compile(
+ [source], flags, output_dir=self.conf_tmp_path
+ )
+ test = True
+ except CompileError as e:
+ self.dist_log(str(e), stderr=True)
+ if bk_spawn:
+ setattr(cc, 'spawn', bk_spawn)
+ return test
+
+ def dist_info(self):
+ """
+ Return a tuple containing info about (platform, compiler, extra_args),
+ required by the abstract class '_CCompiler' for discovering the
+ platform environment. This is also used as a cache factor in order
+ to detect any changes happening from outside.
+ """
+ if hasattr(self, "_dist_info"):
+ return self._dist_info
+
+ cc_type = getattr(self._ccompiler, "compiler_type", '')
+ if cc_type in ("intelem", "intelemw"):
+ platform = "x86_64"
+ elif cc_type in ("intel", "intelw", "intele"):
+ platform = "x86"
+ else:
+ from distutils.util import get_platform
+ platform = get_platform()
+
+ cc_info = getattr(self._ccompiler, "compiler", getattr(self._ccompiler, "compiler_so", ''))
+ if not cc_type or cc_type == "unix":
+ if hasattr(cc_info, "__iter__"):
+ compiler = cc_info[0]
+ else:
+ compiler = str(cc_info)
+ else:
+ compiler = cc_type
+
+ if hasattr(cc_info, "__iter__") and len(cc_info) > 1:
+ extra_args = ' '.join(cc_info[1:])
+ else:
+ extra_args = os.environ.get("CFLAGS", "")
+ extra_args += os.environ.get("CPPFLAGS", "")
+
+ self._dist_info = (platform, compiler, extra_args)
+ return self._dist_info
+
+ @staticmethod
+ def dist_error(*args):
+ """Raise a compiler error"""
+ from distutils.errors import CompileError
+ raise CompileError(_Distutils._dist_str(*args))
+
+ @staticmethod
+ def dist_fatal(*args):
+ """Raise a distutils error"""
+ from distutils.errors import DistutilsError
+ raise DistutilsError(_Distutils._dist_str(*args))
+
+ @staticmethod
+ def dist_log(*args, stderr=False):
+ """Print a console message"""
+ from numpy.distutils import log
+ out = _Distutils._dist_str(*args)
+ if stderr:
+ log.warn(out)
+ else:
+ log.info(out)
+
+ @staticmethod
+ def dist_load_module(name, path):
+ """Load a module from file, required by the abstract class '_Cache'."""
+ from numpy.compat import npy_load_module
+ try:
+ return npy_load_module(name, path)
+ except Exception as e:
+ _Distutils.dist_log(e, stderr=True)
+ return None
+
+ @staticmethod
+ def _dist_str(*args):
+ """Return a string to print by log and errors."""
+ def to_str(arg):
+ if not isinstance(arg, str) and hasattr(arg, '__iter__'):
+ ret = []
+ for a in arg:
+ ret.append(to_str(a))
+ return '('+ ' '.join(ret) + ')'
+ return str(arg)
+
+ stack = inspect.stack()[2]
+ start = "CCompilerOpt.%s[%d] : " % (stack.function, stack.lineno)
+ out = ' '.join([
+ to_str(a)
+ for a in (*args,)
+ ])
+ return start + out
+
+ def _dist_test_spawn_paths(self, cmd, display=None):
+ """
+ Fix msvc SDK ENV path same as distutils do
+ without it we get c1: fatal error C1356: unable to find mspdbcore.dll
+ """
+ if not hasattr(self._ccompiler, "_paths"):
+ self._dist_test_spawn(cmd)
+ return
+ old_path = os.getenv("path")
+ try:
+ os.environ["path"] = self._ccompiler._paths
+ self._dist_test_spawn(cmd)
+ finally:
+ os.environ["path"] = old_path
+
+ _dist_warn_regex = re.compile(
+ # intel and msvc compilers don't raise
+ # fatal errors when flags are wrong or unsupported
+ ".*("
+ "warning D9002|" # msvc, it should be work with any language.
+ "invalid argument for option" # intel
+ ").*"
+ )
+ @staticmethod
+ def _dist_test_spawn(cmd, display=None):
+ from distutils.errors import CompileError
+ try:
+ o = subprocess.check_output(cmd, stderr=subprocess.STDOUT,
+ universal_newlines=True)
+ if o and re.match(_Distutils._dist_warn_regex, o):
+ _Distutils.dist_error(
+ "Flags in command", cmd ,"aren't supported by the compiler"
+ ", output -> \n%s" % o
+ )
+ except subprocess.CalledProcessError as exc:
+ o = exc.output
+ s = exc.returncode
+ except OSError:
+ o = b''
+ s = 127
+ else:
+ return None
+ _Distutils.dist_error(
+ "Command", cmd, "failed with exit status %d output -> \n%s" % (
+ s, o
+ ))
+
+_share_cache = {}
+class _Cache:
+ """An abstract class handles caching functionality, provides two
+ levels of caching, in-memory by share instances attributes among
+ each other and by store attributes into files.
+
+ **Note**:
+ any attributes that start with ``_`` or ``conf_`` will be ignored.
+
+ Parameters
+ ----------
+ cache_path: str or None
+ The path of cache file, if None then cache in file will disabled.
+
+ *factors:
+ The caching factors that need to utilize next to `conf_cache_factors`.
+
+ Attributes
+ ----------
+ cache_private: set
+ Hold the attributes that need be skipped from "in-memory cache".
+
+ cache_infile: bool
+ Utilized during initializing this class, to determine if the cache was able
+ to loaded from the specified cache path in 'cache_path'.
+ """
+
+ # skip attributes from cache
+ _cache_ignore = re.compile("^(_|conf_)")
+
+ def __init__(self, cache_path=None, *factors):
+ self.cache_me = {}
+ self.cache_private = set()
+ self.cache_infile = False
+
+ if self.conf_nocache:
+ self.dist_log("cache is disabled by `Config`")
+ return
+
+ chash = self.cache_hash(*factors, *self.conf_cache_factors)
+ if cache_path:
+ if os.path.exists(cache_path):
+ self.dist_log("load cache from file ->", cache_path)
+ cache_mod = self.dist_load_module("cache", cache_path)
+ if not cache_mod:
+ self.dist_log(
+ "unable to load the cache file as a module",
+ stderr=True
+ )
+ elif not hasattr(cache_mod, "hash") or \
+ not hasattr(cache_mod, "data"):
+ self.dist_log("invalid cache file", stderr=True)
+ elif chash == cache_mod.hash:
+ self.dist_log("hit the file cache")
+ for attr, val in cache_mod.data.items():
+ setattr(self, attr, val)
+ self.cache_infile = True
+ else:
+ self.dist_log("miss the file cache")
+
+ atexit.register(self._cache_write, cache_path, chash)
+
+ if not self.cache_infile:
+ other_cache = _share_cache.get(chash)
+ if other_cache:
+ self.dist_log("hit the memory cache")
+ for attr, val in other_cache.__dict__.items():
+ if attr in other_cache.cache_private or \
+ re.match(self._cache_ignore, attr):
+ continue
+ setattr(self, attr, val)
+
+ _share_cache[chash] = self
+
+ def __del__(self):
+ # TODO: remove the cache form share on del
+ pass
+
+ def _cache_write(self, cache_path, cache_hash):
+ # TODO: don't write if the cache doesn't change
+ self.dist_log("write cache to path ->", cache_path)
+ for attr in list(self.__dict__.keys()):
+ if re.match(self._cache_ignore, attr):
+ self.__dict__.pop(attr)
+
+ d = os.path.dirname(cache_path)
+ if not os.path.exists(d):
+ os.makedirs(d)
+
+ repr_dict = pprint.pformat(self.__dict__, compact=True)
+ with open(cache_path, "w") as f:
+ f.write(textwrap.dedent("""\
+ # AUTOGENERATED DON'T EDIT
+ # Please make changes to the code generator \
+ (distutils/ccompiler_opt.py)
+ hash = {}
+ data = \\
+ """).format(cache_hash))
+ f.write(repr_dict)
+
+ def cache_hash(self, *factors):
+ # is there a built-in non-crypto hash?
+ # sdbm
+ chash = 0
+ for f in factors:
+ for char in str(f):
+ chash = ord(char) + (chash << 6) + (chash << 16) - chash
+ chash &= 0xFFFFFFFF
+ return chash
+
+ @staticmethod
+ def me(cb):
+ """
+ A static method that can be treated as a decorator to
+ dynamically cache certain methods.
+ """
+ def cache_wrap_me(self, *args, **kwargs):
+ # good for normal args
+ cache_key = str((
+ cb.__name__, *args, *kwargs.keys(), *kwargs.values()
+ ))
+ if cache_key in self.cache_me:
+ return self.cache_me[cache_key]
+ ccb = cb(self, *args, **kwargs)
+ self.cache_me[cache_key] = ccb
+ return ccb
+ return cache_wrap_me
+
+class _CCompiler(object):
+ """A helper class for `CCompilerOpt` containing all utilities that
+ related to the fundamental compiler's functions.
+
+ Attributes
+ ----------
+ cc_on_x86 : bool
+ True when the target architecture is 32-bit x86
+ cc_on_x64 : bool
+ True when the target architecture is 64-bit x86
+ cc_on_ppc64 : bool
+ True when the target architecture is 64-bit big-endian PowerPC
+ cc_on_armhf : bool
+ True when the target architecture is 32-bit ARMv7+
+ cc_on_aarch64 : bool
+ True when the target architecture is 64-bit Armv8-a+
+ cc_on_noarch : bool
+ True when the target architecture is unknown or not supported
+ cc_is_gcc : bool
+ True if the compiler is GNU or
+ if the compiler is unknown
+ cc_is_clang : bool
+ True if the compiler is Clang
+ cc_is_icc : bool
+ True if the compiler is Intel compiler (unix like)
+ cc_is_iccw : bool
+ True if the compiler is Intel compiler (msvc like)
+ cc_is_nocc : bool
+ True if the compiler isn't supported directly,
+ Note: that cause a fail-back to gcc
+ cc_has_debug : bool
+ True if the compiler has debug flags
+ cc_has_native : bool
+ True if the compiler has native flags
+ cc_noopt : bool
+ True if the compiler has definition 'DISABLE_OPT*',
+ or 'cc_on_noarch' is True
+ cc_march : str
+ The target architecture name, or "unknown" if
+ the architecture isn't supported
+ cc_name : str
+ The compiler name, or "unknown" if the compiler isn't supported
+ cc_flags : dict
+ Dictionary containing the initialized flags of `_Config.conf_cc_flags`
+ """
+ def __init__(self):
+ if hasattr(self, "cc_is_cached"):
+ return
+ # attr regex
+ detect_arch = (
+ ("cc_on_x64", ".*(x|x86_|amd)64.*"),
+ ("cc_on_x86", ".*(win32|x86|i386|i686).*"),
+ ("cc_on_ppc64le", ".*(powerpc|ppc)64(el|le).*"),
+ ("cc_on_ppc64", ".*(powerpc|ppc)64.*"),
+ ("cc_on_aarch64", ".*(aarch64|arm64).*"),
+ ("cc_on_armhf", ".*arm.*"),
+ # undefined platform
+ ("cc_on_noarch", ""),
+ )
+ detect_compiler = (
+ ("cc_is_gcc", r".*(gcc|gnu\-g).*"),
+ ("cc_is_clang", ".*clang.*"),
+ ("cc_is_iccw", ".*(intelw|intelemw|iccw).*"), # intel msvc like
+ ("cc_is_icc", ".*(intel|icc).*"), # intel unix like
+ ("cc_is_msvc", ".*msvc.*"),
+ # undefined compiler will be treat it as gcc
+ ("cc_is_nocc", ""),
+ )
+ detect_args = (
+ ("cc_has_debug", ".*(O0|Od|ggdb|coverage|debug:full).*"),
+ ("cc_has_native", ".*(-march=native|-xHost|/QxHost).*"),
+ # in case if the class run with -DNPY_DISABLE_OPTIMIZATION
+ ("cc_noopt", ".*DISABLE_OPT.*"),
+ )
+
+ dist_info = self.dist_info()
+ platform, compiler_info, extra_args = dist_info
+ # set False to all attrs
+ for section in (detect_arch, detect_compiler, detect_args):
+ for attr, rgex in section:
+ setattr(self, attr, False)
+
+ for detect, searchin in ((detect_arch, platform), (detect_compiler, compiler_info)):
+ for attr, rgex in detect:
+ if rgex and not re.match(rgex, searchin, re.IGNORECASE):
+ continue
+ setattr(self, attr, True)
+ break
+
+ for attr, rgex in detect_args:
+ if rgex and not re.match(rgex, extra_args, re.IGNORECASE):
+ continue
+ setattr(self, attr, True)
+
+ if self.cc_on_noarch:
+ self.dist_log(
+ "unable to detect CPU architecture which lead to disable the optimization. "
+ f"check dist_info:<<\n{dist_info}\n>>",
+ stderr=True
+ )
+ self.cc_noopt = True
+
+ if self.conf_noopt:
+ self.dist_log("Optimization is disabled by the Config", stderr=True)
+ self.cc_noopt = True
+
+ if self.cc_is_nocc:
+ """
+ mingw can be treated as a gcc, and also xlc even if it based on clang,
+ but still has the same gcc optimization flags.
+ """
+ self.dist_log(
+ "unable to detect compiler type which leads to treating it as GCC. "
+ "this is a normal behavior if you're using gcc-like compiler such as MinGW or IBM/XLC."
+ f"check dist_info:<<\n{dist_info}\n>>",
+ stderr=True
+ )
+ self.cc_is_gcc = True
+
+ self.cc_march = "unknown"
+ for arch in ("x86", "x64", "ppc64", "ppc64le", "armhf", "aarch64"):
+ if getattr(self, "cc_on_" + arch):
+ self.cc_march = arch
+ break
+
+ self.cc_name = "unknown"
+ for name in ("gcc", "clang", "iccw", "icc", "msvc"):
+ if getattr(self, "cc_is_" + name):
+ self.cc_name = name
+ break
+
+ self.cc_flags = {}
+ compiler_flags = self.conf_cc_flags.get(self.cc_name)
+ if compiler_flags is None:
+ self.dist_fatal(
+ "undefined flag for compiler '%s', "
+ "leave an empty dict instead" % self.cc_name
+ )
+ for name, flags in compiler_flags.items():
+ self.cc_flags[name] = nflags = []
+ if flags:
+ assert(isinstance(flags, str))
+ flags = flags.split()
+ for f in flags:
+ if self.cc_test_flags([f]):
+ nflags.append(f)
+
+ self.cc_is_cached = True
+
+ @_Cache.me
+ def cc_test_flags(self, flags):
+ """
+ Returns True if the compiler supports 'flags'.
+ """
+ assert(isinstance(flags, list))
+ self.dist_log("testing flags", flags)
+ test_path = os.path.join(self.conf_check_path, "test_flags.c")
+ test = self.dist_test(test_path, flags)
+ if not test:
+ self.dist_log("testing failed", stderr=True)
+ return test
+
+ def cc_normalize_flags(self, flags):
+ """
+ Remove the conflicts that caused due gathering implied features flags.
+
+ Parameters
+ ----------
+ 'flags' list, compiler flags
+ flags should be sorted from the lowest to the highest interest.
+
+ Returns
+ -------
+ list, filtered from any conflicts.
+
+ Examples
+ --------
+ >>> self.cc_normalize_flags(['-march=armv8.2-a+fp16', '-march=armv8.2-a+dotprod'])
+ ['armv8.2-a+fp16+dotprod']
+
+ >>> self.cc_normalize_flags(
+ ['-msse', '-msse2', '-msse3', '-mssse3', '-msse4.1', '-msse4.2', '-mavx', '-march=core-avx2']
+ )
+ ['-march=core-avx2']
+ """
+ assert(isinstance(flags, list))
+ if self.cc_is_gcc or self.cc_is_clang or self.cc_is_icc:
+ return self._cc_normalize_unix(flags)
+
+ if self.cc_is_msvc or self.cc_is_iccw:
+ return self._cc_normalize_win(flags)
+ return flags
+
+ _cc_normalize_unix_mrgx = re.compile(
+ # 1- to check the highest of
+ r"^(-mcpu=|-march=|-x[A-Z0-9\-])"
+ )
+ _cc_normalize_unix_frgx = re.compile(
+ # 2- to remove any flags starts with
+ # -march, -mcpu, -x(INTEL) and '-m' without '='
+ r"^(?!(-mcpu=|-march=|-x[A-Z0-9\-]))(?!-m[a-z0-9\-\.]*.$)"
+ )
+ _cc_normalize_unix_krgx = re.compile(
+ # 3- keep only the highest of
+ r"^(-mfpu|-mtune)"
+ )
+ _cc_normalize_arch_ver = re.compile(
+ r"[0-9.]"
+ )
+ def _cc_normalize_unix(self, flags):
+ def ver_flags(f):
+ # arch ver subflag
+ # -march=armv8.2-a+fp16fml
+ tokens = f.split('+')
+ ver = float('0' + ''.join(
+ re.findall(self._cc_normalize_arch_ver, tokens[0])
+ ))
+ return ver, tokens[0], tokens[1:]
+
+ if len(flags) <= 1:
+ return flags
+ # get the highest matched flag
+ for i, cur_flag in enumerate(reversed(flags)):
+ if not re.match(self._cc_normalize_unix_mrgx, cur_flag):
+ continue
+ lower_flags = flags[:-(i+1)]
+ upper_flags = flags[-i:]
+ filterd = list(filter(
+ self._cc_normalize_unix_frgx.search, lower_flags
+ ))
+ # gather subflags
+ ver, arch, subflags = ver_flags(cur_flag)
+ if ver > 0 and len(subflags) > 0:
+ for xflag in lower_flags:
+ xver, _, xsubflags = ver_flags(xflag)
+ if ver == xver:
+ subflags = xsubflags + subflags
+ cur_flag = arch + '+' + '+'.join(subflags)
+
+ flags = filterd + [cur_flag]
+ if i > 0:
+ flags += upper_flags
+ break
+
+ # to remove overridable flags
+ final_flags = []
+ matched = set()
+ for f in reversed(flags):
+ match = re.match(self._cc_normalize_unix_krgx, f)
+ if not match:
+ pass
+ elif match[0] in matched:
+ continue
+ else:
+ matched.add(match[0])
+ final_flags.insert(0, f)
+ return final_flags
+
+ _cc_normalize_win_frgx = re.compile(
+ r"^(?!(/arch\:|/Qx\:))"
+ )
+ _cc_normalize_win_mrgx = re.compile(
+ r"^(/arch|/Qx:)"
+ )
+ def _cc_normalize_win(self, flags):
+ for i, f in enumerate(reversed(flags)):
+ if not re.match(self._cc_normalize_win_mrgx, f):
+ continue
+ i += 1
+ return list(filter(
+ self._cc_normalize_win_frgx.search, flags[:-i]
+ )) + flags[-i:]
+ return flags
+
+class _Feature:
+ """A helper class for `CCompilerOpt` that managing CPU features.
+
+ Attributes
+ ----------
+ feature_supported : dict
+ Dictionary containing all CPU features that supported
+ by the platform, according to the specified values in attribute
+ `_Config.conf_features` and `_Config.conf_features_partial()`
+
+ feature_min : set
+ The minimum support of CPU features, according to
+ the specified values in attribute `_Config.conf_min_features`.
+ """
+ def __init__(self):
+ if hasattr(self, "feature_is_cached"):
+ return
+ self.feature_supported = pfeatures = self.conf_features_partial()
+ for feature_name in list(pfeatures.keys()):
+ feature = pfeatures[feature_name]
+ cfeature = self.conf_features[feature_name]
+ feature.update({
+ k:v for k,v in cfeature.items() if k not in feature
+ })
+ disabled = feature.get("disable")
+ if disabled is not None:
+ pfeatures.pop(feature_name)
+ self.dist_log(
+ "feature '%s' is disabled," % feature_name,
+ disabled, stderr=True
+ )
+ continue
+ # list is used internally for these options
+ for option in (
+ "implies", "group", "detect", "headers", "flags", "extra_checks"
+ ) :
+ oval = feature.get(option)
+ if isinstance(oval, str):
+ feature[option] = oval.split()
+
+ self.feature_min = set()
+ min_f = self.conf_min_features.get(self.cc_march, "")
+ for F in min_f.upper().split():
+ if F in self.feature_supported:
+ self.feature_min.add(F)
+
+ self.feature_is_cached = True
+
+ def feature_names(self, names=None, force_flags=None):
+ """
+ Returns a set of CPU feature names that supported by platform and the **C** compiler.
+
+ Parameters
+ ----------
+ 'names': sequence or None, optional
+ Specify certain CPU features to test it against the **C** compiler.
+ if None(default), it will test all current supported features.
+ **Note**: feature names must be in upper-case.
+
+ 'force_flags': list or None, optional
+ If None(default), default compiler flags for every CPU feature will be used
+ during the test.
+ """
+ assert(
+ names is None or (
+ not isinstance(names, str) and
+ hasattr(names, "__iter__")
+ )
+ )
+ assert(force_flags is None or isinstance(force_flags, list))
+ if names is None:
+ names = self.feature_supported.keys()
+ supported_names = set()
+ for f in names:
+ if self.feature_is_supported(f, force_flags=force_flags):
+ supported_names.add(f)
+ return supported_names
+
+ def feature_is_exist(self, name):
+ """
+ Returns True if a certain feature is exist and covered within
+ `_Config.conf_features`.
+
+ Parameters
+ ----------
+ 'name': str
+ feature name in uppercase.
+ """
+ assert(name.isupper())
+ return name in self.conf_features
+
+ def feature_sorted(self, names, reverse=False):
+ """
+ Sort a list of CPU features ordered by the lowest interest.
+
+ Parameters
+ ----------
+ 'names': sequence
+ sequence of supported feature names in uppercase.
+ 'reverse': bool, optional
+ If true, the sorted features is reversed. (highest interest)
+
+ Returns
+ -------
+ list, sorted CPU features
+ """
+ def sort_cb(k):
+ if isinstance(k, str):
+ return self.feature_supported[k]["interest"]
+ # multiple features
+ rank = max([self.feature_supported[f]["interest"] for f in k])
+ # FIXME: that's not a safe way to increase the rank for
+ # multi targets
+ rank += len(k) -1
+ return rank
+ return sorted(names, reverse=reverse, key=sort_cb)
+
+ def feature_implies(self, names, keep_origins=False):
+ """
+ Return a set of CPU features that implied by 'names'
+
+ Parameters
+ ----------
+ names: str or sequence of str
+ CPU feature name(s) in uppercase.
+
+ keep_origins: bool
+ if False(default) then the returned set will not contain any
+ features from 'names'. This case happens only when two features
+ imply each other.
+
+ Examples
+ --------
+ >>> self.feature_implies("SSE3")
+ {'SSE', 'SSE2'}
+ >>> self.feature_implies("SSE2")
+ {'SSE'}
+ >>> self.feature_implies("SSE2", keep_origins=True)
+ # 'SSE2' found here since 'SSE' and 'SSE2' imply each other
+ {'SSE', 'SSE2'}
+ """
+ def get_implies(name, _caller=set()):
+ implies = set()
+ d = self.feature_supported[name]
+ for i in d.get("implies", []):
+ implies.add(i)
+ if i in _caller:
+ # infinity recursive guard since
+ # features can imply each other
+ continue
+ _caller.add(name)
+ implies = implies.union(get_implies(i, _caller))
+ return implies
+
+ if isinstance(names, str):
+ implies = get_implies(names)
+ names = [names]
+ else:
+ assert(hasattr(names, "__iter__"))
+ implies = set()
+ for n in names:
+ implies = implies.union(get_implies(n))
+ if not keep_origins:
+ implies.difference_update(names)
+ return implies
+
+ def feature_implies_c(self, names):
+ """same as feature_implies() but combining 'names'"""
+ if isinstance(names, str):
+ names = set((names,))
+ else:
+ names = set(names)
+ return names.union(self.feature_implies(names))
+
+ def feature_ahead(self, names):
+ """
+ Return list of features in 'names' after remove any
+ implied features and keep the origins.
+
+ Parameters
+ ----------
+ 'names': sequence
+ sequence of CPU feature names in uppercase.
+
+ Returns
+ -------
+ list of CPU features sorted as-is 'names'
+
+ Examples
+ --------
+ >>> self.feature_ahead(["SSE2", "SSE3", "SSE41"])
+ ["SSE41"]
+ # assume AVX2 and FMA3 implies each other and AVX2
+ # is the highest interest
+ >>> self.feature_ahead(["SSE2", "SSE3", "SSE41", "AVX2", "FMA3"])
+ ["AVX2"]
+ # assume AVX2 and FMA3 don't implies each other
+ >>> self.feature_ahead(["SSE2", "SSE3", "SSE41", "AVX2", "FMA3"])
+ ["AVX2", "FMA3"]
+ """
+ assert(
+ not isinstance(names, str)
+ and hasattr(names, '__iter__')
+ )
+ implies = self.feature_implies(names, keep_origins=True)
+ ahead = [n for n in names if n not in implies]
+ if len(ahead) == 0:
+ # return the highest interested feature
+ # if all features imply each other
+ ahead = self.feature_sorted(names, reverse=True)[:1]
+ return ahead
+
+ def feature_untied(self, names):
+ """
+ same as 'feature_ahead()' but if both features implied each other
+ and keep the highest interest.
+
+ Parameters
+ ----------
+ 'names': sequence
+ sequence of CPU feature names in uppercase.
+
+ Returns
+ -------
+ list of CPU features sorted as-is 'names'
+
+ Examples
+ --------
+ >>> self.feature_untied(["SSE2", "SSE3", "SSE41"])
+ ["SSE2", "SSE3", "SSE41"]
+ # assume AVX2 and FMA3 implies each other
+ >>> self.feature_untied(["SSE2", "SSE3", "SSE41", "FMA3", "AVX2"])
+ ["SSE2", "SSE3", "SSE41", "AVX2"]
+ """
+ assert(
+ not isinstance(names, str)
+ and hasattr(names, '__iter__')
+ )
+ final = []
+ for n in names:
+ implies = self.feature_implies(n)
+ tied = [
+ nn for nn in final
+ if nn in implies and n in self.feature_implies(nn)
+ ]
+ if tied:
+ tied = self.feature_sorted(tied + [n])
+ if n not in tied[1:]:
+ continue
+ final.remove(tied[:1][0])
+ final.append(n)
+ return final
+
+ def feature_get_til(self, names, keyisfalse):
+ """
+ same as `feature_implies_c()` but stop collecting implied
+ features when feature's option that provided through
+ parameter 'keyisfalse' is False, also sorting the returned
+ features.
+ """
+ def til(tnames):
+ # sort from highest to lowest interest then cut if "key" is False
+ tnames = self.feature_implies_c(tnames)
+ tnames = self.feature_sorted(tnames, reverse=True)
+ for i, n in enumerate(tnames):
+ if not self.feature_supported[n].get(keyisfalse, True):
+ tnames = tnames[:i+1]
+ break
+ return tnames
+
+ if isinstance(names, str) or len(names) <= 1:
+ names = til(names)
+ # normalize the sort
+ names.reverse()
+ return names
+
+ names = self.feature_ahead(names)
+ names = {t for n in names for t in til(n)}
+ return self.feature_sorted(names)
+
+ def feature_detect(self, names):
+ """
+ Return a list of CPU features that required to be detected
+ sorted from the lowest to highest interest.
+ """
+ names = self.feature_get_til(names, "implies_detect")
+ detect = []
+ for n in names:
+ d = self.feature_supported[n]
+ detect += d.get("detect", d.get("group", [n]))
+ return detect
+
+ @_Cache.me
+ def feature_flags(self, names):
+ """
+ Return a list of CPU features flags sorted from the lowest
+ to highest interest.
+ """
+ names = self.feature_sorted(self.feature_implies_c(names))
+ flags = []
+ for n in names:
+ d = self.feature_supported[n]
+ f = d.get("flags", [])
+ if not f or not self.cc_test_flags(f):
+ continue
+ flags += f
+ return self.cc_normalize_flags(flags)
+
+ @_Cache.me
+ def feature_test(self, name, force_flags=None):
+ """
+ Test a certain CPU feature against the compiler through its own
+ check file.
+
+ Parameters
+ ----------
+ 'name': str
+ Supported CPU feature name.
+
+ 'force_flags': list or None, optional
+ If None(default), the returned flags from `feature_flags()`
+ will be used.
+ """
+ if force_flags is None:
+ force_flags = self.feature_flags(name)
+
+ self.dist_log(
+ "testing feature '%s' with flags (%s)" % (
+ name, ' '.join(force_flags)
+ ))
+ # Each CPU feature must have C source code contains at
+ # least one intrinsic or instruction related to this feature.
+ test_path = os.path.join(
+ self.conf_check_path, "cpu_%s.c" % name.lower()
+ )
+ if not os.path.exists(test_path):
+ self.dist_fatal("feature test file is not exist", test_path)
+
+ test = self.dist_test(test_path, force_flags + self.cc_flags["werror"])
+ if not test:
+ self.dist_log("testing failed", stderr=True)
+ return test
+
+ @_Cache.me
+ def feature_is_supported(self, name, force_flags=None):
+ """
+ Check if a certain CPU feature is supported by the platform and compiler.
+
+ Parameters
+ ----------
+ 'name': str
+ CPU feature name in uppercase.
+
+ 'force_flags': list or None, optional
+ If None(default), default compiler flags for every CPU feature will be used
+ during test.
+ """
+ assert(name.isupper())
+ assert(force_flags is None or isinstance(force_flags, list))
+
+ supported = name in self.feature_supported
+ if supported:
+ for impl in self.feature_implies(name):
+ if not self.feature_test(impl, force_flags):
+ return False
+ if not self.feature_test(name, force_flags):
+ return False
+ return supported
+
+ @_Cache.me
+ def feature_can_autovec(self, name):
+ """
+ check if the feature can be auto-vectorized by the compiler
+ """
+ assert(isinstance(name, str))
+ d = self.feature_supported[name]
+ can = d.get("autovec", None)
+ if can is None:
+ valid_flags = [
+ self.cc_test_flags([f]) for f in d.get("flags", [])
+ ]
+ can = valid_flags and any(valid_flags)
+ return can
+
+ @_Cache.me
+ def feature_extra_checks(self, name):
+ """
+ Return a list of supported extra checks after testing them against
+ the compiler.
+
+ Parameters
+ ----------
+ names: str
+ CPU feature name in uppercase.
+ """
+ assert isinstance(name, str)
+ d = self.feature_supported[name]
+ extra_checks = d.get("extra_checks", [])
+ if not extra_checks:
+ return []
+
+ self.dist_log("Testing extra checks for feature '%s'" % name, extra_checks)
+ flags = self.feature_flags(name)
+ available = []
+ not_available = []
+ for chk in extra_checks:
+ test_path = os.path.join(
+ self.conf_check_path, "extra_%s.c" % chk.lower()
+ )
+ if not os.path.exists(test_path):
+ self.dist_fatal("extra check file does not exist", test_path)
+
+ is_supported = self.dist_test(test_path, flags + self.cc_flags["werror"])
+ if is_supported:
+ available.append(chk)
+ else:
+ not_available.append(chk)
+
+ if not_available:
+ self.dist_log("testing failed for checks", not_available, stderr=True)
+ return available
+
+
+ def feature_c_preprocessor(self, feature_name, tabs=0):
+ """
+ Generate C preprocessor definitions and include headers of a CPU feature.
+
+ Parameters
+ ----------
+ 'feature_name': str
+ CPU feature name in uppercase.
+ 'tabs': int
+ if > 0, align the generated strings to the right depend on number of tabs.
+
+ Returns
+ -------
+ str, generated C preprocessor
+
+ Examples
+ --------
+ >>> self.feature_c_preprocessor("SSE3")
+ /** SSE3 **/
+ #define NPY_HAVE_SSE3 1
+ #include <pmmintrin.h>
+ """
+ assert(feature_name.isupper())
+ feature = self.feature_supported.get(feature_name)
+ assert(feature is not None)
+
+ prepr = [
+ "/** %s **/" % feature_name,
+ "#define %sHAVE_%s 1" % (self.conf_c_prefix, feature_name)
+ ]
+ prepr += [
+ "#include <%s>" % h for h in feature.get("headers", [])
+ ]
+
+ extra_defs = feature.get("group", [])
+ extra_defs += self.feature_extra_checks(feature_name)
+ for edef in extra_defs:
+ # Guard extra definitions in case of duplicate with
+ # another feature
+ prepr += [
+ "#ifndef %sHAVE_%s" % (self.conf_c_prefix, edef),
+ "\t#define %sHAVE_%s 1" % (self.conf_c_prefix, edef),
+ "#endif",
+ ]
+
+ if tabs > 0:
+ prepr = [('\t'*tabs) + l for l in prepr]
+ return '\n'.join(prepr)
+
+class _Parse:
+ """A helper class that parsing main arguments of `CCompilerOpt`,
+ also parsing configuration statements in dispatch-able sources.
+
+ Parameters
+ ----------
+ cpu_baseline: str or None
+ minimal set of required CPU features or special options.
+
+ cpu_dispatch: str or None
+ dispatched set of additional CPU features or special options.
+
+ Special options can be:
+ - **MIN**: Enables the minimum CPU features that utilized via `_Config.conf_min_features`
+ - **MAX**: Enables all supported CPU features by the Compiler and platform.
+ - **NATIVE**: Enables all CPU features that supported by the current machine.
+ - **NONE**: Enables nothing
+ - **Operand +/-**: remove or add features, useful with options **MAX**, **MIN** and **NATIVE**.
+ NOTE: operand + is only added for nominal reason.
+
+ NOTES:
+ - Case-insensitive among all CPU features and special options.
+ - Comma or space can be used as a separator.
+ - If the CPU feature is not supported by the user platform or compiler,
+ it will be skipped rather than raising a fatal error.
+ - Any specified CPU features to 'cpu_dispatch' will be skipped if its part of CPU baseline features
+ - 'cpu_baseline' force enables implied features.
+
+ Attributes
+ ----------
+ parse_baseline_names : list
+ Final CPU baseline's feature names(sorted from low to high)
+ parse_baseline_flags : list
+ Compiler flags of baseline features
+ parse_dispatch_names : list
+ Final CPU dispatch-able feature names(sorted from low to high)
+ parse_target_groups : dict
+ Dictionary containing initialized target groups that configured
+ through class attribute `conf_target_groups`.
+
+ The key is represent the group name and value is a tuple
+ contains three items :
+ - bool, True if group has the 'baseline' option.
+ - list, list of CPU features.
+ - list, list of extra compiler flags.
+
+ """
+ def __init__(self, cpu_baseline, cpu_dispatch):
+ self._parse_policies = dict(
+ # POLICY NAME, (HAVE, NOT HAVE, [DEB])
+ KEEP_BASELINE = (
+ None, self._parse_policy_not_keepbase,
+ []
+ ),
+ KEEP_SORT = (
+ self._parse_policy_keepsort,
+ self._parse_policy_not_keepsort,
+ []
+ ),
+ MAXOPT = (
+ self._parse_policy_maxopt, None,
+ []
+ ),
+ WERROR = (
+ self._parse_policy_werror, None,
+ []
+ ),
+ AUTOVEC = (
+ self._parse_policy_autovec, None,
+ ["MAXOPT"]
+ )
+ )
+ if hasattr(self, "parse_is_cached"):
+ return
+
+ self.parse_baseline_names = []
+ self.parse_baseline_flags = []
+ self.parse_dispatch_names = []
+ self.parse_target_groups = {}
+
+ if self.cc_noopt:
+ # skip parsing baseline and dispatch args and keep parsing target groups
+ cpu_baseline = cpu_dispatch = None
+
+ self.dist_log("check requested baseline")
+ if cpu_baseline is not None:
+ cpu_baseline = self._parse_arg_features("cpu_baseline", cpu_baseline)
+ baseline_names = self.feature_names(cpu_baseline)
+ self.parse_baseline_flags = self.feature_flags(baseline_names)
+ self.parse_baseline_names = self.feature_sorted(
+ self.feature_implies_c(baseline_names)
+ )
+
+ self.dist_log("check requested dispatch-able features")
+ if cpu_dispatch is not None:
+ cpu_dispatch_ = self._parse_arg_features("cpu_dispatch", cpu_dispatch)
+ cpu_dispatch = {
+ f for f in cpu_dispatch_
+ if f not in self.parse_baseline_names
+ }
+ conflict_baseline = cpu_dispatch_.difference(cpu_dispatch)
+ self.parse_dispatch_names = self.feature_sorted(
+ self.feature_names(cpu_dispatch)
+ )
+ if len(conflict_baseline) > 0:
+ self.dist_log(
+ "skip features", conflict_baseline, "since its part of baseline"
+ )
+
+ self.dist_log("initialize targets groups")
+ for group_name, tokens in self.conf_target_groups.items():
+ self.dist_log("parse target group", group_name)
+ GROUP_NAME = group_name.upper()
+ if not tokens or not tokens.strip():
+ # allow empty groups, useful in case if there's a need
+ # to disable certain group since '_parse_target_tokens()'
+ # requires at least one valid target
+ self.parse_target_groups[GROUP_NAME] = (
+ False, [], []
+ )
+ continue
+ has_baseline, features, extra_flags = \
+ self._parse_target_tokens(tokens)
+ self.parse_target_groups[GROUP_NAME] = (
+ has_baseline, features, extra_flags
+ )
+
+ self.parse_is_cached = True
+
+ def parse_targets(self, source):
+ """
+ Fetch and parse configuration statements that required for
+ defining the targeted CPU features, statements should be declared
+ in the top of source in between **C** comment and start
+ with a special mark **@targets**.
+
+ Configuration statements are sort of keywords representing
+ CPU features names, group of statements and policies, combined
+ together to determine the required optimization.
+
+ Parameters
+ ----------
+ source: str
+ the path of **C** source file.
+
+ Returns
+ -------
+ - bool, True if group has the 'baseline' option
+ - list, list of CPU features
+ - list, list of extra compiler flags
+ """
+ self.dist_log("looking for '@targets' inside -> ", source)
+ # get lines between /*@targets and */
+ with open(source) as fd:
+ tokens = ""
+ max_to_reach = 1000 # good enough, isn't?
+ start_with = "@targets"
+ start_pos = -1
+ end_with = "*/"
+ end_pos = -1
+ for current_line, line in enumerate(fd):
+ if current_line == max_to_reach:
+ self.dist_fatal("reached the max of lines")
+ break
+ if start_pos == -1:
+ start_pos = line.find(start_with)
+ if start_pos == -1:
+ continue
+ start_pos += len(start_with)
+ tokens += line
+ end_pos = line.find(end_with)
+ if end_pos != -1:
+ end_pos += len(tokens) - len(line)
+ break
+
+ if start_pos == -1:
+ self.dist_fatal("expected to find '%s' within a C comment" % start_with)
+ if end_pos == -1:
+ self.dist_fatal("expected to end with '%s'" % end_with)
+
+ tokens = tokens[start_pos:end_pos]
+ return self._parse_target_tokens(tokens)
+
+ _parse_regex_arg = re.compile(r'\s|[,]|([+-])')
+ def _parse_arg_features(self, arg_name, req_features):
+ if not isinstance(req_features, str):
+ self.dist_fatal("expected a string in '%s'" % arg_name)
+
+ final_features = set()
+ # space and comma can be used as a separator
+ tokens = list(filter(None, re.split(self._parse_regex_arg, req_features)))
+ append = True # append is the default
+ for tok in tokens:
+ if tok[0] in ("#", "$"):
+ self.dist_fatal(
+ arg_name, "target groups and policies "
+ "aren't allowed from arguments, "
+ "only from dispatch-able sources"
+ )
+ if tok == '+':
+ append = True
+ continue
+ if tok == '-':
+ append = False
+ continue
+
+ TOK = tok.upper() # we use upper-case internally
+ features_to = set()
+ if TOK == "NONE":
+ pass
+ elif TOK == "NATIVE":
+ native = self.cc_flags["native"]
+ if not native:
+ self.dist_fatal(arg_name,
+ "native option isn't supported by the compiler"
+ )
+ features_to = self.feature_names(force_flags=native)
+ elif TOK == "MAX":
+ features_to = self.feature_supported.keys()
+ elif TOK == "MIN":
+ features_to = self.feature_min
+ else:
+ if TOK in self.feature_supported:
+ features_to.add(TOK)
+ else:
+ if not self.feature_is_exist(TOK):
+ self.dist_fatal(arg_name,
+ ", '%s' isn't a known feature or option" % tok
+ )
+ if append:
+ final_features = final_features.union(features_to)
+ else:
+ final_features = final_features.difference(features_to)
+
+ append = True # back to default
+
+ return final_features
+
+ _parse_regex_target = re.compile(r'\s|[*,/]|([()])')
+ def _parse_target_tokens(self, tokens):
+ assert(isinstance(tokens, str))
+ final_targets = [] # to keep it sorted as specified
+ extra_flags = []
+ has_baseline = False
+
+ skipped = set()
+ policies = set()
+ multi_target = None
+
+ tokens = list(filter(None, re.split(self._parse_regex_target, tokens)))
+ if not tokens:
+ self.dist_fatal("expected one token at least")
+
+ for tok in tokens:
+ TOK = tok.upper()
+ ch = tok[0]
+ if ch in ('+', '-'):
+ self.dist_fatal(
+ "+/- are 'not' allowed from target's groups or @targets, "
+ "only from cpu_baseline and cpu_dispatch parms"
+ )
+ elif ch == '$':
+ if multi_target is not None:
+ self.dist_fatal(
+ "policies aren't allowed inside multi-target '()'"
+ ", only CPU features"
+ )
+ policies.add(self._parse_token_policy(TOK))
+ elif ch == '#':
+ if multi_target is not None:
+ self.dist_fatal(
+ "target groups aren't allowed inside multi-target '()'"
+ ", only CPU features"
+ )
+ has_baseline, final_targets, extra_flags = \
+ self._parse_token_group(TOK, has_baseline, final_targets, extra_flags)
+ elif ch == '(':
+ if multi_target is not None:
+ self.dist_fatal("unclosed multi-target, missing ')'")
+ multi_target = set()
+ elif ch == ')':
+ if multi_target is None:
+ self.dist_fatal("multi-target opener '(' wasn't found")
+ targets = self._parse_multi_target(multi_target)
+ if targets is None:
+ skipped.add(tuple(multi_target))
+ else:
+ if len(targets) == 1:
+ targets = targets[0]
+ if targets and targets not in final_targets:
+ final_targets.append(targets)
+ multi_target = None # back to default
+ else:
+ if TOK == "BASELINE":
+ if multi_target is not None:
+ self.dist_fatal("baseline isn't allowed inside multi-target '()'")
+ has_baseline = True
+ continue
+
+ if multi_target is not None:
+ multi_target.add(TOK)
+ continue
+
+ if not self.feature_is_exist(TOK):
+ self.dist_fatal("invalid target name '%s'" % TOK)
+
+ is_enabled = (
+ TOK in self.parse_baseline_names or
+ TOK in self.parse_dispatch_names
+ )
+ if is_enabled:
+ if TOK not in final_targets:
+ final_targets.append(TOK)
+ continue
+
+ skipped.add(TOK)
+
+ if multi_target is not None:
+ self.dist_fatal("unclosed multi-target, missing ')'")
+ if skipped:
+ self.dist_log(
+ "skip targets", skipped,
+ "not part of baseline or dispatch-able features"
+ )
+
+ final_targets = self.feature_untied(final_targets)
+
+ # add polices dependencies
+ for p in list(policies):
+ _, _, deps = self._parse_policies[p]
+ for d in deps:
+ if d in policies:
+ continue
+ self.dist_log(
+ "policy '%s' force enables '%s'" % (
+ p, d
+ ))
+ policies.add(d)
+
+ # release policies filtrations
+ for p, (have, nhave, _) in self._parse_policies.items():
+ func = None
+ if p in policies:
+ func = have
+ self.dist_log("policy '%s' is ON" % p)
+ else:
+ func = nhave
+ if not func:
+ continue
+ has_baseline, final_targets, extra_flags = func(
+ has_baseline, final_targets, extra_flags
+ )
+
+ return has_baseline, final_targets, extra_flags
+
+ def _parse_token_policy(self, token):
+ """validate policy token"""
+ if len(token) <= 1 or token[-1:] == token[0]:
+ self.dist_fatal("'$' must stuck in the begin of policy name")
+ token = token[1:]
+ if token not in self._parse_policies:
+ self.dist_fatal(
+ "'%s' is an invalid policy name, available policies are" % token,
+ self._parse_policies.keys()
+ )
+ return token
+
+ def _parse_token_group(self, token, has_baseline, final_targets, extra_flags):
+ """validate group token"""
+ if len(token) <= 1 or token[-1:] == token[0]:
+ self.dist_fatal("'#' must stuck in the begin of group name")
+
+ token = token[1:]
+ ghas_baseline, gtargets, gextra_flags = self.parse_target_groups.get(
+ token, (False, None, [])
+ )
+ if gtargets is None:
+ self.dist_fatal(
+ "'%s' is an invalid target group name, " % token + \
+ "available target groups are",
+ self.parse_target_groups.keys()
+ )
+ if ghas_baseline:
+ has_baseline = True
+ # always keep sorting as specified
+ final_targets += [f for f in gtargets if f not in final_targets]
+ extra_flags += [f for f in gextra_flags if f not in extra_flags]
+ return has_baseline, final_targets, extra_flags
+
+ def _parse_multi_target(self, targets):
+ """validate multi targets that defined between parentheses()"""
+ # remove any implied features and keep the origins
+ if not targets:
+ self.dist_fatal("empty multi-target '()'")
+ if not all([
+ self.feature_is_exist(tar) for tar in targets
+ ]) :
+ self.dist_fatal("invalid target name in multi-target", targets)
+ if not all([
+ (
+ tar in self.parse_baseline_names or
+ tar in self.parse_dispatch_names
+ )
+ for tar in targets
+ ]) :
+ return None
+ targets = self.feature_ahead(targets)
+ if not targets:
+ return None
+ # force sort multi targets, so it can be comparable
+ targets = self.feature_sorted(targets)
+ targets = tuple(targets) # hashable
+ return targets
+
+ def _parse_policy_not_keepbase(self, has_baseline, final_targets, extra_flags):
+ """skip all baseline features"""
+ skipped = []
+ for tar in final_targets[:]:
+ is_base = False
+ if isinstance(tar, str):
+ is_base = tar in self.parse_baseline_names
+ else:
+ # multi targets
+ is_base = all([
+ f in self.parse_baseline_names
+ for f in tar
+ ])
+ if is_base:
+ skipped.append(tar)
+ final_targets.remove(tar)
+
+ if skipped:
+ self.dist_log("skip baseline features", skipped)
+
+ return has_baseline, final_targets, extra_flags
+
+ def _parse_policy_keepsort(self, has_baseline, final_targets, extra_flags):
+ """leave a notice that $keep_sort is on"""
+ self.dist_log(
+ "policy 'keep_sort' is on, dispatch-able targets", final_targets, "\n"
+ "are 'not' sorted depend on the highest interest but"
+ "as specified in the dispatch-able source or the extra group"
+ )
+ return has_baseline, final_targets, extra_flags
+
+ def _parse_policy_not_keepsort(self, has_baseline, final_targets, extra_flags):
+ """sorted depend on the highest interest"""
+ final_targets = self.feature_sorted(final_targets, reverse=True)
+ return has_baseline, final_targets, extra_flags
+
+ def _parse_policy_maxopt(self, has_baseline, final_targets, extra_flags):
+ """append the compiler optimization flags"""
+ if self.cc_has_debug:
+ self.dist_log("debug mode is detected, policy 'maxopt' is skipped.")
+ elif self.cc_noopt:
+ self.dist_log("optimization is disabled, policy 'maxopt' is skipped.")
+ else:
+ flags = self.cc_flags["opt"]
+ if not flags:
+ self.dist_log(
+ "current compiler doesn't support optimization flags, "
+ "policy 'maxopt' is skipped", stderr=True
+ )
+ else:
+ extra_flags += flags
+ return has_baseline, final_targets, extra_flags
+
+ def _parse_policy_werror(self, has_baseline, final_targets, extra_flags):
+ """force warnings to treated as errors"""
+ flags = self.cc_flags["werror"]
+ if not flags:
+ self.dist_log(
+ "current compiler doesn't support werror flags, "
+ "warnings will 'not' treated as errors", stderr=True
+ )
+ else:
+ self.dist_log("compiler warnings are treated as errors")
+ extra_flags += flags
+ return has_baseline, final_targets, extra_flags
+
+ def _parse_policy_autovec(self, has_baseline, final_targets, extra_flags):
+ """skip features that has no auto-vectorized support by compiler"""
+ skipped = []
+ for tar in final_targets[:]:
+ if isinstance(tar, str):
+ can = self.feature_can_autovec(tar)
+ else: # multiple target
+ can = all([
+ self.feature_can_autovec(t)
+ for t in tar
+ ])
+ if not can:
+ final_targets.remove(tar)
+ skipped.append(tar)
+
+ if skipped:
+ self.dist_log("skip non auto-vectorized features", skipped)
+
+ return has_baseline, final_targets, extra_flags
+
+class CCompilerOpt(_Config, _Distutils, _Cache, _CCompiler, _Feature, _Parse):
+ """
+ A helper class for `CCompiler` aims to provide extra build options
+ to effectively control of compiler optimizations that are directly
+ related to CPU features.
+ """
+ def __init__(self, ccompiler, cpu_baseline="min", cpu_dispatch="max", cache_path=None):
+ _Config.__init__(self)
+ _Distutils.__init__(self, ccompiler)
+ _Cache.__init__(self, cache_path, self.dist_info(), cpu_baseline, cpu_dispatch)
+ _CCompiler.__init__(self)
+ _Feature.__init__(self)
+ if not self.cc_noopt and self.cc_has_native:
+ self.dist_log(
+ "native flag is specified through environment variables. "
+ "force cpu-baseline='native'"
+ )
+ cpu_baseline = "native"
+ _Parse.__init__(self, cpu_baseline, cpu_dispatch)
+ # keep the requested features untouched, need it later for report
+ # and trace purposes
+ self._requested_baseline = cpu_baseline
+ self._requested_dispatch = cpu_dispatch
+ # key is the dispatch-able source and value is a tuple
+ # contains two items (has_baseline[boolean], dispatched-features[list])
+ self.sources_status = getattr(self, "sources_status", {})
+ # every instance should has a separate one
+ self.cache_private.add("sources_status")
+ # set it at the end to make sure the cache writing was done after init
+ # this class
+ self.hit_cache = hasattr(self, "hit_cache")
+
+ def is_cached(self):
+ """
+ Returns True if the class loaded from the cache file
+ """
+ return self.cache_infile and self.hit_cache
+
+ def cpu_baseline_flags(self):
+ """
+ Returns a list of final CPU baseline compiler flags
+ """
+ return self.parse_baseline_flags
+
+ def cpu_baseline_names(self):
+ """
+ return a list of final CPU baseline feature names
+ """
+ return self.parse_baseline_names
+
+ def cpu_dispatch_names(self):
+ """
+ return a list of final CPU dispatch feature names
+ """
+ return self.parse_dispatch_names
+
+ def try_dispatch(self, sources, src_dir=None, **kwargs):
+ """
+ Compile one or more dispatch-able sources and generates object files,
+ also generates abstract C config headers and macros that
+ used later for the final runtime dispatching process.
+
+ The mechanism behind it is to takes each source file that specified
+ in 'sources' and branching it into several files depend on
+ special configuration statements that must be declared in the
+ top of each source which contains targeted CPU features,
+ then it compiles every branched source with the proper compiler flags.
+
+ Parameters
+ ----------
+ sources : list
+ Must be a list of dispatch-able sources file paths,
+ and configuration statements must be declared inside
+ each file.
+
+ src_dir : str
+ Path of parent directory for the generated headers and wrapped sources.
+ If None(default) the files will generated in-place.
+
+ **kwargs : any
+ Arguments to pass on to the `CCompiler.compile()`
+
+ Returns
+ -------
+ list : generated object files
+
+ Raises
+ ------
+ CompileError
+ Raises by `CCompiler.compile()` on compiling failure.
+ DistutilsError
+ Some errors during checking the sanity of configuration statements.
+
+ See Also
+ --------
+ parse_targets :
+ Parsing the configuration statements of dispatch-able sources.
+ """
+ to_compile = {}
+ baseline_flags = self.cpu_baseline_flags()
+ include_dirs = kwargs.setdefault("include_dirs", [])
+
+ for src in sources:
+ output_dir = os.path.dirname(src)
+ if src_dir:
+ if not output_dir.startswith(src_dir):
+ output_dir = os.path.join(src_dir, output_dir)
+ if output_dir not in include_dirs:
+ # To allow including the generated config header(*.dispatch.h)
+ # by the dispatch-able sources
+ include_dirs.append(output_dir)
+
+ has_baseline, targets, extra_flags = self.parse_targets(src)
+ nochange = self._generate_config(output_dir, src, targets, has_baseline)
+ for tar in targets:
+ tar_src = self._wrap_target(output_dir, src, tar, nochange=nochange)
+ flags = tuple(extra_flags + self.feature_flags(tar))
+ to_compile.setdefault(flags, []).append(tar_src)
+
+ if has_baseline:
+ flags = tuple(extra_flags + baseline_flags)
+ to_compile.setdefault(flags, []).append(src)
+
+ self.sources_status[src] = (has_baseline, targets)
+
+ # For these reasons, the sources are compiled in a separate loop:
+ # - Gathering all sources with the same flags to benefit from
+ # the parallel compiling as much as possible.
+ # - To generate all config headers of the dispatchable sources,
+ # before the compilation in case if there are dependency relationships
+ # among them.
+ objects = []
+ for flags, srcs in to_compile.items():
+ objects += self.dist_compile(srcs, list(flags), **kwargs)
+ return objects
+
+ def generate_dispatch_header(self, header_path):
+ """
+ Generate the dispatch header which contains the #definitions and headers
+ for platform-specific instruction-sets for the enabled CPU baseline and
+ dispatch-able features.
+
+ Its highly recommended to take a look at the generated header
+ also the generated source files via `try_dispatch()`
+ in order to get the full picture.
+ """
+ self.dist_log("generate CPU dispatch header: (%s)" % header_path)
+
+ baseline_names = self.cpu_baseline_names()
+ dispatch_names = self.cpu_dispatch_names()
+ baseline_len = len(baseline_names)
+ dispatch_len = len(dispatch_names)
+
+ header_dir = os.path.dirname(header_path)
+ if not os.path.exists(header_dir):
+ self.dist_log(
+ f"dispatch header dir {header_dir} does not exist, creating it",
+ stderr=True
+ )
+ os.makedirs(header_dir)
+
+ with open(header_path, 'w') as f:
+ baseline_calls = ' \\\n'.join([
+ (
+ "\t%sWITH_CPU_EXPAND_(MACRO_TO_CALL(%s, __VA_ARGS__))"
+ ) % (self.conf_c_prefix, f)
+ for f in baseline_names
+ ])
+ dispatch_calls = ' \\\n'.join([
+ (
+ "\t%sWITH_CPU_EXPAND_(MACRO_TO_CALL(%s, __VA_ARGS__))"
+ ) % (self.conf_c_prefix, f)
+ for f in dispatch_names
+ ])
+ f.write(textwrap.dedent("""\
+ /*
+ * AUTOGENERATED DON'T EDIT
+ * Please make changes to the code generator (distutils/ccompiler_opt.py)
+ */
+ #define {pfx}WITH_CPU_BASELINE "{baseline_str}"
+ #define {pfx}WITH_CPU_DISPATCH "{dispatch_str}"
+ #define {pfx}WITH_CPU_BASELINE_N {baseline_len}
+ #define {pfx}WITH_CPU_DISPATCH_N {dispatch_len}
+ #define {pfx}WITH_CPU_EXPAND_(X) X
+ #define {pfx}WITH_CPU_BASELINE_CALL(MACRO_TO_CALL, ...) \\
+ {baseline_calls}
+ #define {pfx}WITH_CPU_DISPATCH_CALL(MACRO_TO_CALL, ...) \\
+ {dispatch_calls}
+ """).format(
+ pfx=self.conf_c_prefix, baseline_str=" ".join(baseline_names),
+ dispatch_str=" ".join(dispatch_names), baseline_len=baseline_len,
+ dispatch_len=dispatch_len, baseline_calls=baseline_calls,
+ dispatch_calls=dispatch_calls
+ ))
+ baseline_pre = ''
+ for name in baseline_names:
+ baseline_pre += self.feature_c_preprocessor(name, tabs=1) + '\n'
+
+ dispatch_pre = ''
+ for name in dispatch_names:
+ dispatch_pre += textwrap.dedent("""\
+ #ifdef {pfx}CPU_TARGET_{name}
+ {pre}
+ #endif /*{pfx}CPU_TARGET_{name}*/
+ """).format(
+ pfx=self.conf_c_prefix_, name=name, pre=self.feature_c_preprocessor(
+ name, tabs=1
+ ))
+
+ f.write(textwrap.dedent("""\
+ /******* baseline features *******/
+ {baseline_pre}
+ /******* dispatch features *******/
+ {dispatch_pre}
+ """).format(
+ pfx=self.conf_c_prefix_, baseline_pre=baseline_pre,
+ dispatch_pre=dispatch_pre
+ ))
+
+ def report(self, full=False):
+ report = []
+ platform_rows = []
+ baseline_rows = []
+ dispatch_rows = []
+ report.append(("Platform", platform_rows))
+ report.append(("", ""))
+ report.append(("CPU baseline", baseline_rows))
+ report.append(("", ""))
+ report.append(("CPU dispatch", dispatch_rows))
+
+ ########## platform ##########
+ platform_rows.append(("Architecture", (
+ "unsupported" if self.cc_on_noarch else self.cc_march)
+ ))
+ platform_rows.append(("Compiler", (
+ "unix-like" if self.cc_is_nocc else self.cc_name)
+ ))
+ ########## baseline ##########
+ if self.cc_noopt:
+ baseline_rows.append(("Requested", "optimization disabled"))
+ else:
+ baseline_rows.append(("Requested", repr(self._requested_baseline)))
+
+ baseline_names = self.cpu_baseline_names()
+ baseline_rows.append((
+ "Enabled", (' '.join(baseline_names) if baseline_names else "none")
+ ))
+ baseline_flags = self.cpu_baseline_flags()
+ baseline_rows.append((
+ "Flags", (' '.join(baseline_flags) if baseline_flags else "none")
+ ))
+ extra_checks = []
+ for name in baseline_names:
+ extra_checks += self.feature_extra_checks(name)
+ baseline_rows.append((
+ "Extra checks", (' '.join(extra_checks) if extra_checks else "none")
+ ))
+
+ ########## dispatch ##########
+ if self.cc_noopt:
+ baseline_rows.append(("Requested", "optimization disabled"))
+ else:
+ dispatch_rows.append(("Requested", repr(self._requested_dispatch)))
+
+ dispatch_names = self.cpu_dispatch_names()
+ dispatch_rows.append((
+ "Enabled", (' '.join(dispatch_names) if dispatch_names else "none")
+ ))
+ ########## Generated ##########
+ # TODO:
+ # - collect object names from 'try_dispatch()'
+ # then get size of each object and printed
+ # - give more details about the features that not
+ # generated due compiler support
+ # - find a better output's design.
+ #
+ target_sources = {}
+ for source, (_, targets) in self.sources_status.items():
+ for tar in targets:
+ target_sources.setdefault(tar, []).append(source)
+
+ if not full or not target_sources:
+ generated = ""
+ for tar in self.feature_sorted(target_sources):
+ sources = target_sources[tar]
+ name = tar if isinstance(tar, str) else '(%s)' % ' '.join(tar)
+ generated += name + "[%d] " % len(sources)
+ dispatch_rows.append(("Generated", generated[:-1] if generated else "none"))
+ else:
+ dispatch_rows.append(("Generated", ''))
+ for tar in self.feature_sorted(target_sources):
+ sources = target_sources[tar]
+ pretty_name = tar if isinstance(tar, str) else '(%s)' % ' '.join(tar)
+ flags = ' '.join(self.feature_flags(tar))
+ implies = ' '.join(self.feature_sorted(self.feature_implies(tar)))
+ detect = ' '.join(self.feature_detect(tar))
+ extra_checks = []
+ for name in ((tar,) if isinstance(tar, str) else tar):
+ extra_checks += self.feature_extra_checks(name)
+ extra_checks = (' '.join(extra_checks) if extra_checks else "none")
+
+ dispatch_rows.append(('', ''))
+ dispatch_rows.append((pretty_name, implies))
+ dispatch_rows.append(("Flags", flags))
+ dispatch_rows.append(("Extra checks", extra_checks))
+ dispatch_rows.append(("Detect", detect))
+ for src in sources:
+ dispatch_rows.append(("", src))
+
+ ###############################
+ # TODO: add support for 'markdown' format
+ text = []
+ secs_len = [len(secs) for secs, _ in report]
+ cols_len = [len(col) for _, rows in report for col, _ in rows]
+ tab = ' ' * 2
+ pad = max(max(secs_len), max(cols_len))
+ for sec, rows in report:
+ if not sec:
+ text.append("") # empty line
+ continue
+ sec += ' ' * (pad - len(sec))
+ text.append(sec + tab + ': ')
+ for col, val in rows:
+ col += ' ' * (pad - len(col))
+ text.append(tab + col + ': ' + val)
+
+ return '\n'.join(text)
+
+ def _wrap_target(self, output_dir, dispatch_src, target, nochange=False):
+ assert(isinstance(target, (str, tuple)))
+ if isinstance(target, str):
+ ext_name = target_name = target
+ else:
+ # multi-target
+ ext_name = '.'.join(target)
+ target_name = '__'.join(target)
+
+ wrap_path = os.path.join(output_dir, os.path.basename(dispatch_src))
+ wrap_path = "{0}.{2}{1}".format(*os.path.splitext(wrap_path), ext_name.lower())
+ if nochange and os.path.exists(wrap_path):
+ return wrap_path
+
+ self.dist_log("wrap dispatch-able target -> ", wrap_path)
+ # sorting for readability
+ features = self.feature_sorted(self.feature_implies_c(target))
+ target_join = "#define %sCPU_TARGET_" % self.conf_c_prefix_
+ target_defs = [target_join + f for f in features]
+ target_defs = '\n'.join(target_defs)
+
+ with open(wrap_path, "w") as fd:
+ fd.write(textwrap.dedent("""\
+ /**
+ * AUTOGENERATED DON'T EDIT
+ * Please make changes to the code generator \
+ (distutils/ccompiler_opt.py)
+ */
+ #define {pfx}CPU_TARGET_MODE
+ #define {pfx}CPU_TARGET_CURRENT {target_name}
+ {target_defs}
+ #include "{path}"
+ """).format(
+ pfx=self.conf_c_prefix_, target_name=target_name,
+ path=os.path.abspath(dispatch_src), target_defs=target_defs
+ ))
+ return wrap_path
+
+ def _generate_config(self, output_dir, dispatch_src, targets, has_baseline=False):
+ config_path = os.path.basename(dispatch_src).replace(".c", ".h")
+ config_path = os.path.join(output_dir, config_path)
+ # check if targets didn't change to avoid recompiling
+ cache_hash = self.cache_hash(targets, has_baseline)
+ try:
+ with open(config_path) as f:
+ last_hash = f.readline().split("cache_hash:")
+ if len(last_hash) == 2 and int(last_hash[1]) == cache_hash:
+ return True
+ except IOError:
+ pass
+
+ self.dist_log("generate dispatched config -> ", config_path)
+ dispatch_calls = []
+ for tar in targets:
+ if isinstance(tar, str):
+ target_name = tar
+ else: # multi target
+ target_name = '__'.join([t for t in tar])
+ req_detect = self.feature_detect(tar)
+ req_detect = '&&'.join([
+ "CHK(%s)" % f for f in req_detect
+ ])
+ dispatch_calls.append(
+ "\t%sCPU_DISPATCH_EXPAND_(CB((%s), %s, __VA_ARGS__))" % (
+ self.conf_c_prefix_, req_detect, target_name
+ ))
+ dispatch_calls = ' \\\n'.join(dispatch_calls)
+
+ if has_baseline:
+ baseline_calls = (
+ "\t%sCPU_DISPATCH_EXPAND_(CB(__VA_ARGS__))"
+ ) % self.conf_c_prefix_
+ else:
+ baseline_calls = ''
+
+ with open(config_path, "w") as fd:
+ fd.write(textwrap.dedent("""\
+ // cache_hash:{cache_hash}
+ /**
+ * AUTOGENERATED DON'T EDIT
+ * Please make changes to the code generator (distutils/ccompiler_opt.py)
+ */
+ #ifndef {pfx}CPU_DISPATCH_EXPAND_
+ #define {pfx}CPU_DISPATCH_EXPAND_(X) X
+ #endif
+ #undef {pfx}CPU_DISPATCH_BASELINE_CALL
+ #undef {pfx}CPU_DISPATCH_CALL
+ #define {pfx}CPU_DISPATCH_BASELINE_CALL(CB, ...) \\
+ {baseline_calls}
+ #define {pfx}CPU_DISPATCH_CALL(CHK, CB, ...) \\
+ {dispatch_calls}
+ """).format(
+ pfx=self.conf_c_prefix_, baseline_calls=baseline_calls,
+ dispatch_calls=dispatch_calls, cache_hash=cache_hash
+ ))
+ return False
+
+def new_ccompiler_opt(compiler, dispatch_hpath, **kwargs):
+ """
+ Create a new instance of 'CCompilerOpt' and generate the dispatch header
+ which contains the #definitions and headers of platform-specific instruction-sets for
+ the enabled CPU baseline and dispatch-able features.
+
+ Parameters
+ ----------
+ compiler : CCompiler instance
+ dispatch_hpath : str
+ path of the dispatch header
+
+ **kwargs: passed as-is to `CCompilerOpt(...)`
+ Returns
+ -------
+ new instance of CCompilerOpt
+ """
+ opt = CCompilerOpt(compiler, **kwargs)
+ if not os.path.exists(dispatch_hpath) or not opt.is_cached():
+ opt.generate_dispatch_header(dispatch_hpath)
+ return opt
--- /dev/null
+#ifdef _MSC_VER
+ #include <Intrin.h>
+#endif
+#include <arm_neon.h>
+
+int main(void)
+{
+ float32x4_t v1 = vdupq_n_f32(1.0f), v2 = vdupq_n_f32(2.0f);
+ /* MAXMIN */
+ int ret = (int)vgetq_lane_f32(vmaxnmq_f32(v1, v2), 0);
+ ret += (int)vgetq_lane_f32(vminnmq_f32(v1, v2), 0);
+ /* ROUNDING */
+ ret += (int)vgetq_lane_f32(vrndq_f32(v1), 0);
+#ifdef __aarch64__
+ {
+ float64x2_t vd1 = vdupq_n_f64(1.0), vd2 = vdupq_n_f64(2.0);
+ /* MAXMIN */
+ ret += (int)vgetq_lane_f64(vmaxnmq_f64(vd1, vd2), 0);
+ ret += (int)vgetq_lane_f64(vminnmq_f64(vd1, vd2), 0);
+ /* ROUNDING */
+ ret += (int)vgetq_lane_f64(vrndq_f64(vd1), 0);
+ }
+#endif
+ return ret;
+}
--- /dev/null
+#ifdef _MSC_VER
+ #include <Intrin.h>
+#endif
+#include <arm_neon.h>
+
+int main(void)
+{
+ uint8x16_t v1 = vdupq_n_u8((unsigned char)1), v2 = vdupq_n_u8((unsigned char)2);
+ uint32x4_t va = vdupq_n_u32(3);
+ int ret = (int)vgetq_lane_u32(vdotq_u32(va, v1, v2), 0);
+#ifdef __aarch64__
+ ret += (int)vgetq_lane_u32(vdotq_laneq_u32(va, v1, v2, 0), 0);
+#endif
+ return ret;
+}
--- /dev/null
+#ifdef _MSC_VER
+ #include <Intrin.h>
+#endif
+#include <arm_neon.h>
+
+int main(void)
+{
+ float16x8_t vhp = vdupq_n_f16((float16_t)1);
+ float16x4_t vlhp = vdup_n_f16((float16_t)1);
+ float32x4_t vf = vdupq_n_f32(1.0f);
+ float32x2_t vlf = vdup_n_f32(1.0f);
+
+ int ret = (int)vget_lane_f32(vfmlal_low_u32(vlf, vlhp, vlhp), 0);
+ ret += (int)vgetq_lane_f32(vfmlslq_high_u32(vf, vhp, vhp), 0);
+
+ return ret;
+}
--- /dev/null
+#ifdef _MSC_VER
+ #include <Intrin.h>
+#endif
+#include <arm_neon.h>
+
+int main(void)
+{
+ float16x8_t vhp = vdupq_n_f16((float16_t)-1);
+ float16x4_t vlhp = vdup_n_f16((float16_t)-1);
+
+ int ret = (int)vgetq_lane_f16(vabdq_f16(vhp, vhp), 0);
+ ret += (int)vget_lane_f16(vabd_f16(vlhp, vlhp), 0);
+ return ret;
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ __m256 a = _mm256_add_ps(_mm256_setzero_ps(), _mm256_setzero_ps());
+ return (int)_mm_cvtss_f32(_mm256_castps256_ps128(a));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ __m256i a = _mm256_abs_epi16(_mm256_setzero_si256());
+ return _mm_cvtsi128_si32(_mm256_castsi256_si128(a));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ /* VNNI */
+ __m512i a = _mm512_dpbusd_epi32(_mm512_setzero_si512(), _mm512_setzero_si512(), _mm512_setzero_si512());
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(a));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ /* IFMA */
+ __m512i a = _mm512_madd52hi_epu64(_mm512_setzero_si512(), _mm512_setzero_si512(), _mm512_setzero_si512());
+ /* VMBI */
+ a = _mm512_permutex2var_epi8(a, _mm512_setzero_si512(), _mm512_setzero_si512());
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(a));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ /* VBMI2 */
+ __m512i a = _mm512_shrdv_epi64(_mm512_setzero_si512(), _mm512_setzero_si512(), _mm512_setzero_si512());
+ /* BITLAG */
+ a = _mm512_popcnt_epi8(a);
+ /* VPOPCNTDQ */
+ a = _mm512_popcnt_epi64(a);
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(a));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ int base[128];
+ /* ER */
+ __m512i a = _mm512_castpd_si512(_mm512_exp2a23_pd(_mm512_setzero_pd()));
+ /* PF */
+ _mm512_mask_prefetch_i64scatter_pd(base, _mm512_cmpeq_epi64_mask(a, a), a, 1, _MM_HINT_T1);
+ return base[0];
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ __m512i a = _mm512_setzero_si512();
+ __m512 b = _mm512_setzero_ps();
+
+ /* 4FMAPS */
+ b = _mm512_4fmadd_ps(b, b, b, b, b, NULL);
+ /* 4VNNIW */
+ a = _mm512_4dpwssd_epi32(a, a, a, a, a, NULL);
+ /* VPOPCNTDQ */
+ a = _mm512_popcnt_epi64(a);
+
+ a = _mm512_add_epi32(a, _mm512_castps_si512(b));
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(a));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ /* VL */
+ __m256i a = _mm256_abs_epi64(_mm256_setzero_si256());
+ /* DQ */
+ __m512i b = _mm512_broadcast_i32x8(a);
+ /* BW */
+ b = _mm512_abs_epi16(b);
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(b));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ __m512i a = _mm512_lzcnt_epi32(_mm512_setzero_si512());
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(a));
+}
--- /dev/null
+#include <immintrin.h>
+
+int main(void)
+{
+ __m512i a = _mm512_abs_epi32(_mm512_setzero_si512());
+ return _mm_cvtsi128_si32(_mm512_castsi512_si128(a));
+}
--- /dev/null
+#include <emmintrin.h>
+#include <immintrin.h>
+
+int main(void)
+{
+ __m128 a = _mm_cvtph_ps(_mm_setzero_si128());
+ __m256 a8 = _mm256_cvtph_ps(_mm_setzero_si128());
+ return (int)(_mm_cvtss_f32(a) + _mm_cvtss_f32(_mm256_castps256_ps128(a8)));
+}
--- /dev/null
+#include <xmmintrin.h>
+#include <immintrin.h>
+
+int main(void)
+{
+ __m256 a = _mm256_fmadd_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _mm256_setzero_ps());
+ return (int)_mm_cvtss_f32(_mm256_castps256_ps128(a));
+}
--- /dev/null
+#include <immintrin.h>
+#ifdef _MSC_VER
+ #include <ammintrin.h>
+#else
+ #include <x86intrin.h>
+#endif
+
+int main(void)
+{
+ __m256 a = _mm256_macc_ps(_mm256_setzero_ps(), _mm256_setzero_ps(), _mm256_setzero_ps());
+ return (int)_mm_cvtss_f32(_mm256_castps256_ps128(a));
+}
--- /dev/null
+#ifdef _MSC_VER
+ #include <Intrin.h>
+#endif
+#include <arm_neon.h>
+
+int main(void)
+{
+ float32x4_t v1 = vdupq_n_f32(1.0f), v2 = vdupq_n_f32(2.0f);
+ int ret = (int)vgetq_lane_f32(vmulq_f32(v1, v2), 0);
+#ifdef __aarch64__
+ float64x2_t vd1 = vdupq_n_f64(1.0), vd2 = vdupq_n_f64(2.0);
+ ret += (int)vgetq_lane_f64(vmulq_f64(vd1, vd2), 0);
+#endif
+ return ret;
+}
--- /dev/null
+#ifdef _MSC_VER
+ #include <Intrin.h>
+#endif
+#include <arm_neon.h>
+
+int main(void)
+{
+ short z4[] = {0, 0, 0, 0, 0, 0, 0, 0};
+ float32x4_t v_z4 = vcvt_f32_f16((float16x4_t)vld1_s16((const short*)z4));
+ return (int)vgetq_lane_f32(v_z4, 0);
+}
--- /dev/null
+#ifdef _MSC_VER
+ #include <Intrin.h>
+#endif
+#include <arm_neon.h>
+
+int main(void)
+{
+ float32x4_t v1 = vdupq_n_f32(1.0f);
+ float32x4_t v2 = vdupq_n_f32(2.0f);
+ float32x4_t v3 = vdupq_n_f32(3.0f);
+ int ret = (int)vgetq_lane_f32(vfmaq_f32(v1, v2, v3), 0);
+#ifdef __aarch64__
+ float64x2_t vd1 = vdupq_n_f64(1.0);
+ float64x2_t vd2 = vdupq_n_f64(2.0);
+ float64x2_t vd3 = vdupq_n_f64(3.0);
+ ret += (int)vgetq_lane_f64(vfmaq_f64(vd1, vd2, vd3), 0);
+#endif
+ return ret;
+}
--- /dev/null
+#ifdef _MSC_VER
+ #include <nmmintrin.h>
+#else
+ #include <popcntintrin.h>
+#endif
+
+int main(void)
+{
+ long long a = 0;
+ int b;
+#ifdef _MSC_VER
+ #ifdef _M_X64
+ a = _mm_popcnt_u64(1);
+ #endif
+ b = _mm_popcnt_u32(1);
+#else
+ #ifdef __x86_64__
+ a = __builtin_popcountll(1);
+ #endif
+ b = __builtin_popcount(1);
+#endif
+ return (int)a + b;
+}
--- /dev/null
+#include <xmmintrin.h>
+
+int main(void)
+{
+ __m128 a = _mm_add_ps(_mm_setzero_ps(), _mm_setzero_ps());
+ return (int)_mm_cvtss_f32(a);
+}
--- /dev/null
+#include <emmintrin.h>
+
+int main(void)
+{
+ __m128i a = _mm_add_epi16(_mm_setzero_si128(), _mm_setzero_si128());
+ return _mm_cvtsi128_si32(a);
+}
--- /dev/null
+#include <pmmintrin.h>
+
+int main(void)
+{
+ __m128 a = _mm_hadd_ps(_mm_setzero_ps(), _mm_setzero_ps());
+ return (int)_mm_cvtss_f32(a);
+}
--- /dev/null
+#include <smmintrin.h>
+
+int main(void)
+{
+ __m128 a = _mm_floor_ps(_mm_setzero_ps());
+ return (int)_mm_cvtss_f32(a);
+}
--- /dev/null
+#include <smmintrin.h>
+
+int main(void)
+{
+ __m128 a = _mm_hadd_ps(_mm_setzero_ps(), _mm_setzero_ps());
+ return (int)_mm_cvtss_f32(a);
+}
--- /dev/null
+#include <tmmintrin.h>
+
+int main(void)
+{
+ __m128i a = _mm_hadd_epi16(_mm_setzero_si128(), _mm_setzero_si128());
+ return (int)_mm_cvtsi128_si32(a);
+}
--- /dev/null
+#ifndef __VSX__
+ #error "VSX is not supported"
+#endif
+#include <altivec.h>
+
+#if (defined(__GNUC__) && !defined(vec_xl)) || (defined(__clang__) && !defined(__IBMC__))
+ #define vsx_ld vec_vsx_ld
+ #define vsx_st vec_vsx_st
+#else
+ #define vsx_ld vec_xl
+ #define vsx_st vec_xst
+#endif
+
+int main(void)
+{
+ unsigned int zout[4];
+ unsigned int z4[] = {0, 0, 0, 0};
+ __vector unsigned int v_z4 = vsx_ld(0, z4);
+ vsx_st(v_z4, 0, zout);
+ return zout[0];
+}
--- /dev/null
+#ifndef __VSX__
+ #error "VSX is not supported"
+#endif
+#include <altivec.h>
+
+typedef __vector unsigned long long v_uint64x2;
+
+int main(void)
+{
+ v_uint64x2 z2 = (v_uint64x2){0, 0};
+ z2 = (v_uint64x2)vec_cmpeq(z2, z2);
+ return (int)vec_extract(z2, 0);
+}
--- /dev/null
+#ifndef __VSX__
+ #error "VSX is not supported"
+#endif
+#include <altivec.h>
+
+typedef __vector unsigned int v_uint32x4;
+
+int main(void)
+{
+ v_uint32x4 z4 = (v_uint32x4){0, 0, 0, 0};
+ z4 = vec_absd(z4, z4);
+ return (int)vec_extract(z4, 0);
+}
--- /dev/null
+#include <immintrin.h>
+#ifdef _MSC_VER
+ #include <ammintrin.h>
+#else
+ #include <x86intrin.h>
+#endif
+
+int main(void)
+{
+ __m128i a = _mm_comge_epu32(_mm_setzero_si128(), _mm_setzero_si128());
+ return _mm_cvtsi128_si32(a);
+}
--- /dev/null
+#include <immintrin.h>
+/**
+ * Test BW mask operations due to:
+ * - MSVC has supported it since vs2019 see,
+ * https://developercommunity.visualstudio.com/content/problem/518298/missing-avx512bw-mask-intrinsics.html
+ * - Clang >= v8.0
+ * - GCC >= v7.1
+ */
+int main(void)
+{
+ __mmask64 m64 = _mm512_cmpeq_epi8_mask(_mm512_set1_epi8((char)1), _mm512_set1_epi8((char)1));
+ m64 = _kor_mask64(m64, m64);
+ m64 = _kxor_mask64(m64, m64);
+ m64 = _cvtu64_mask64(_cvtmask64_u64(m64));
+ m64 = _mm512_kunpackd(m64, m64);
+ m64 = (__mmask64)_mm512_kunpackw((__mmask32)m64, (__mmask32)m64);
+ return (int)_cvtmask64_u64(m64);
+}
--- /dev/null
+#include <immintrin.h>
+/**
+ * Test DQ mask operations due to:
+ * - MSVC has supported it since vs2019 see,
+ * https://developercommunity.visualstudio.com/content/problem/518298/missing-avx512bw-mask-intrinsics.html
+ * - Clang >= v8.0
+ * - GCC >= v7.1
+ */
+int main(void)
+{
+ __mmask8 m8 = _mm512_cmpeq_epi64_mask(_mm512_set1_epi64(1), _mm512_set1_epi64(1));
+ m8 = _kor_mask8(m8, m8);
+ m8 = _kxor_mask8(m8, m8);
+ m8 = _cvtu32_mask8(_cvtmask8_u32(m8));
+ return (int)_cvtmask8_u32(m8);
+}
--- /dev/null
+#include <immintrin.h>
+/**
+ * The following intrinsics don't have direct native support but compilers
+ * tend to emulate them.
+ * They're usually supported by gcc >= 7.1, clang >= 4 and icc >= 19
+ */
+int main(void)
+{
+ __m512 one_ps = _mm512_set1_ps(1.0f);
+ __m512d one_pd = _mm512_set1_pd(1.0);
+ __m512i one_i64 = _mm512_set1_epi64(1.0);
+ // add
+ float sum_ps = _mm512_reduce_add_ps(one_ps);
+ double sum_pd = _mm512_reduce_add_pd(one_pd);
+ int sum_int = (int)_mm512_reduce_add_epi64(one_i64);
+ sum_int += (int)_mm512_reduce_add_epi32(one_i64);
+ // mul
+ sum_ps += _mm512_reduce_mul_ps(one_ps);
+ sum_pd += _mm512_reduce_mul_pd(one_pd);
+ sum_int += (int)_mm512_reduce_mul_epi64(one_i64);
+ sum_int += (int)_mm512_reduce_mul_epi32(one_i64);
+ // min
+ sum_ps += _mm512_reduce_min_ps(one_ps);
+ sum_pd += _mm512_reduce_min_pd(one_pd);
+ sum_int += (int)_mm512_reduce_min_epi32(one_i64);
+ sum_int += (int)_mm512_reduce_min_epu32(one_i64);
+ sum_int += (int)_mm512_reduce_min_epi64(one_i64);
+ // max
+ sum_ps += _mm512_reduce_max_ps(one_ps);
+ sum_pd += _mm512_reduce_max_pd(one_pd);
+ sum_int += (int)_mm512_reduce_max_epi32(one_i64);
+ sum_int += (int)_mm512_reduce_max_epu32(one_i64);
+ sum_int += (int)_mm512_reduce_max_epi64(one_i64);
+ // and
+ sum_int += (int)_mm512_reduce_and_epi32(one_i64);
+ sum_int += (int)_mm512_reduce_and_epi64(one_i64);
+ // or
+ sum_int += (int)_mm512_reduce_or_epi32(one_i64);
+ sum_int += (int)_mm512_reduce_or_epi64(one_i64);
+ return (int)sum_ps + (int)sum_pd + sum_int;
+}
--- /dev/null
+int test_flags;
"specify the Fortran compiler type"),
('warn-error', None,
"turn all warnings into errors (-Werror)"),
+ ('cpu-baseline=', None,
+ "specify a list of enabled baseline CPU optimizations"),
+ ('cpu-dispatch=', None,
+ "specify a list of dispatched CPU optimizations"),
+ ('disable-optimization', None,
+ "disable CPU optimized code(dispatch,simd,fast...)"),
+ ('simd-test=', None,
+ "specify a list of CPU optimizations to be tested against NumPy SIMD interface"),
]
help_options = old_build.help_options + [
old_build.initialize_options(self)
self.fcompiler = None
self.warn_error = False
+ self.cpu_baseline = "min"
+ self.cpu_dispatch = "max -xop -fma4" # drop AMD legacy features by default
+ self.disable_optimization = False
+ """
+ the '_simd' module is a very large. Adding more dispatched features
+ will increase binary size and compile time. By default we minimize
+ the targeted features to those most commonly used by the NumPy SIMD interface(NPYV),
+ NOTE: any specified features will be ignored if they're:
+ - part of the baseline(--cpu-baseline)
+ - not part of dispatch-able features(--cpu-dispatch)
+ - not supported by compiler or platform
+ """
+ self.simd_test = "BASELINE SSE2 SSE42 XOP FMA4 (FMA3 AVX2) AVX512F AVX512_SKX VSX VSX2 VSX3 NEON ASIMD"
def finalize_options(self):
build_scripts = self.build_scripts
filter_sources, get_lib_source_files, get_numpy_include_dirs,
has_cxx_sources, has_f_sources, is_sequence
)
+from numpy.distutils.ccompiler_opt import new_ccompiler_opt
# Fix Python distutils bug sf #1718574:
_l = old_build_clib.user_options
"number of parallel jobs"),
('warn-error', None,
"turn all warnings into errors (-Werror)"),
+ ('cpu-baseline=', None,
+ "specify a list of enabled baseline CPU optimizations"),
+ ('cpu-dispatch=', None,
+ "specify a list of dispatched CPU optimizations"),
+ ('disable-optimization', None,
+ "disable CPU optimized code(dispatch,simd,fast...)"),
]
- boolean_options = old_build_clib.boolean_options + ['inplace', 'warn-error']
+ boolean_options = old_build_clib.boolean_options + \
+ ['inplace', 'warn-error', 'disable-optimization']
def initialize_options(self):
old_build_clib.initialize_options(self)
self.inplace = 0
self.parallel = None
self.warn_error = None
+ self.cpu_baseline = None
+ self.cpu_dispatch = None
+ self.disable_optimization = None
+
def finalize_options(self):
if self.parallel:
self.set_undefined_options('build',
('parallel', 'parallel'),
('warn_error', 'warn_error'),
+ ('cpu_baseline', 'cpu_baseline'),
+ ('cpu_dispatch', 'cpu_dispatch'),
+ ('disable_optimization', 'disable_optimization')
)
def have_f_sources(self):
self.compiler.show_customization()
+ if not self.disable_optimization:
+ dispatch_hpath = os.path.join("numpy", "distutils", "include", "npy_cpu_dispatch_config.h")
+ dispatch_hpath = os.path.join(self.get_finalized_command("build_src").build_src, dispatch_hpath)
+ opt_cache_path = os.path.abspath(
+ os.path.join(self.build_temp, 'ccompiler_opt_cache_clib.py')
+ )
+ self.compiler_opt = new_ccompiler_opt(
+ compiler=self.compiler, dispatch_hpath=dispatch_hpath,
+ cpu_baseline=self.cpu_baseline, cpu_dispatch=self.cpu_dispatch,
+ cache_path=opt_cache_path
+ )
+ if not self.compiler_opt.is_cached():
+ log.info("Detected changes on compiler optimizations, force rebuilding")
+ self.force = True
+
+ import atexit
+ def report():
+ log.info("\n########### CLIB COMPILER OPTIMIZATION ###########")
+ log.info(self.compiler_opt.report(full=True))
+
+ atexit.register(report)
+
if self.have_f_sources():
from numpy.distutils.fcompiler import new_fcompiler
self._f_compiler = new_fcompiler(compiler=self.fcompiler,
'extra_f90_compile_args') or []
macros = build_info.get('macros')
+ if macros is None:
+ macros = []
include_dirs = build_info.get('include_dirs')
if include_dirs is None:
include_dirs = []
c_sources += cxx_sources
cxx_sources = []
+ # filtering C dispatch-table sources when optimization is not disabled,
+ # otherwise treated as normal sources.
+ copt_c_sources = []
+ copt_baseline_flags = []
+ copt_macros = []
+ if not self.disable_optimization:
+ bsrc_dir = self.get_finalized_command("build_src").build_src
+ dispatch_hpath = os.path.join("numpy", "distutils", "include")
+ dispatch_hpath = os.path.join(bsrc_dir, dispatch_hpath)
+ include_dirs.append(dispatch_hpath)
+
+ copt_build_src = None if self.inplace else bsrc_dir
+ copt_c_sources = [
+ c_sources.pop(c_sources.index(src))
+ for src in c_sources[:] if src.endswith(".dispatch.c")
+ ]
+ copt_baseline_flags = self.compiler_opt.cpu_baseline_flags()
+ else:
+ copt_macros.append(("NPY_DISABLE_OPTIMIZATION", 1))
+
objects = []
+ if copt_c_sources:
+ log.info("compiling C dispatch-able sources")
+ objects += self.compiler_opt.try_dispatch(copt_c_sources,
+ output_dir=self.build_temp,
+ src_dir=copt_build_src,
+ macros=macros + copt_macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_postargs)
+
if c_sources:
log.info("compiling C sources")
- objects = compiler.compile(c_sources,
- output_dir=self.build_temp,
- macros=macros,
- include_dirs=include_dirs,
- debug=self.debug,
- extra_postargs=extra_postargs)
+ objects += compiler.compile(c_sources,
+ output_dir=self.build_temp,
+ macros=macros + copt_macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_postargs + copt_baseline_flags)
if cxx_sources:
log.info("compiling C++ sources")
cxx_compiler = compiler.cxx_compiler()
cxx_objects = cxx_compiler.compile(cxx_sources,
output_dir=self.build_temp,
- macros=macros,
+ macros=macros + copt_macros,
include_dirs=include_dirs,
debug=self.debug,
- extra_postargs=extra_postargs)
+ extra_postargs=extra_postargs + copt_baseline_flags)
objects.extend(cxx_objects)
if f_sources or fmodule_sources:
has_cxx_sources, has_f_sources, is_sequence
)
from numpy.distutils.command.config_compiler import show_fortran_compilers
-
-
+from numpy.distutils.ccompiler_opt import new_ccompiler_opt, CCompilerOpt
class build_ext (old_build_ext):
"number of parallel jobs"),
('warn-error', None,
"turn all warnings into errors (-Werror)"),
+ ('cpu-baseline=', None,
+ "specify a list of enabled baseline CPU optimizations"),
+ ('cpu-dispatch=', None,
+ "specify a list of dispatched CPU optimizations"),
+ ('disable-optimization', None,
+ "disable CPU optimized code(dispatch,simd,fast...)"),
+ ('simd-test=', None,
+ "specify a list of CPU optimizations to be tested against NumPy SIMD interface"),
]
help_options = old_build_ext.help_options + [
show_fortran_compilers),
]
- boolean_options = old_build_ext.boolean_options + ['warn-error']
+ boolean_options = old_build_ext.boolean_options + ['warn-error', 'disable-optimization']
def initialize_options(self):
old_build_ext.initialize_options(self)
self.fcompiler = None
self.parallel = None
self.warn_error = None
+ self.cpu_baseline = None
+ self.cpu_dispatch = None
+ self.disable_optimization = None
+ self.simd_test = None
def finalize_options(self):
if self.parallel:
self.set_undefined_options('build',
('parallel', 'parallel'),
('warn_error', 'warn_error'),
+ ('cpu_baseline', 'cpu_baseline'),
+ ('cpu_dispatch', 'cpu_dispatch'),
+ ('disable_optimization', 'disable_optimization'),
+ ('simd_test', 'simd_test')
)
+ CCompilerOpt.conf_target_groups["simd_test"] = self.simd_test
def run(self):
if not self.extensions:
self.compiler.show_customization()
+ if not self.disable_optimization:
+ dispatch_hpath = os.path.join("numpy", "distutils", "include", "npy_cpu_dispatch_config.h")
+ dispatch_hpath = os.path.join(self.get_finalized_command("build_src").build_src, dispatch_hpath)
+ opt_cache_path = os.path.abspath(
+ os.path.join(self.build_temp, 'ccompiler_opt_cache_ext.py')
+ )
+ self.compiler_opt = new_ccompiler_opt(
+ compiler=self.compiler, dispatch_hpath=dispatch_hpath,
+ cpu_baseline=self.cpu_baseline, cpu_dispatch=self.cpu_dispatch,
+ cache_path=opt_cache_path
+ )
+ if not self.compiler_opt.is_cached():
+ log.info("Detected changes on compiler optimizations, force rebuilding")
+ self.force = True
+
+ import atexit
+ def report():
+ log.info("\n########### EXT COMPILER OPTIMIZATION ###########")
+ log.info(self.compiler_opt.report(full=True))
+ atexit.register(report)
+
# Setup directory for storing generated extra DLL files on Windows
self.extra_dll_dir = os.path.join(self.build_temp, '.libs')
if not os.path.isdir(self.extra_dll_dir):
include_dirs = ext.include_dirs + get_numpy_include_dirs()
+ # filtering C dispatch-table sources when optimization is not disabled,
+ # otherwise treated as normal sources.
+ copt_c_sources = []
+ copt_baseline_flags = []
+ copt_macros = []
+ if not self.disable_optimization:
+ bsrc_dir = self.get_finalized_command("build_src").build_src
+ dispatch_hpath = os.path.join("numpy", "distutils", "include")
+ dispatch_hpath = os.path.join(bsrc_dir, dispatch_hpath)
+ include_dirs.append(dispatch_hpath)
+
+ copt_build_src = None if self.inplace else bsrc_dir
+ copt_c_sources = [
+ c_sources.pop(c_sources.index(src))
+ for src in c_sources[:] if src.endswith(".dispatch.c")
+ ]
+ copt_baseline_flags = self.compiler_opt.cpu_baseline_flags()
+ else:
+ copt_macros.append(("NPY_DISABLE_OPTIMIZATION", 1))
+
c_objects = []
+ if copt_c_sources:
+ log.info("compiling C dispatch-able sources")
+ c_objects += self.compiler_opt.try_dispatch(copt_c_sources,
+ output_dir=output_dir,
+ src_dir=copt_build_src,
+ macros=macros + copt_macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_args,
+ **kws)
if c_sources:
log.info("compiling C sources")
- c_objects = self.compiler.compile(c_sources,
- output_dir=output_dir,
- macros=macros,
- include_dirs=include_dirs,
- debug=self.debug,
- extra_postargs=extra_args,
- **kws)
-
+ c_objects += self.compiler.compile(c_sources,
+ output_dir=output_dir,
+ macros=macros + copt_macros,
+ include_dirs=include_dirs,
+ debug=self.debug,
+ extra_postargs=extra_args + copt_baseline_flags,
+ **kws)
if cxx_sources:
log.info("compiling C++ sources")
c_objects += cxx_compiler.compile(cxx_sources,
output_dir=output_dir,
- macros=macros,
+ macros=macros + copt_macros,
include_dirs=include_dirs,
debug=self.debug,
- extra_postargs=extra_args,
+ extra_postargs=extra_args + copt_baseline_flags,
**kws)
extra_postargs = []
unlinkable_fobjects = list(unlinkable_fobjects)
# Expand possible fake static libraries to objects
- for lib in list(libraries):
+ for lib in libraries:
for libdir in library_dirs:
fake_lib = os.path.join(libdir, lib + '.fobjects')
if os.path.isfile(fake_lib):
import sys
import re
-from numpy.compat import open_latin1
-
from distutils.sysconfig import get_python_lib
from distutils.fancy_getopt import FancyGetopt
from distutils.errors import DistutilsModuleError, \
'intelvem', 'intelem', 'flang')),
('cygwin.*', ('gnu', 'intelv', 'absoft', 'compaqv', 'intelev', 'gnu95', 'g95')),
('linux.*', ('gnu95', 'intel', 'lahey', 'pg', 'nv', 'absoft', 'nag', 'vast', 'compaq',
- 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor')),
+ 'intele', 'intelem', 'gnu', 'g95', 'pathf95', 'nagfor', 'fujitsu')),
('darwin.*', ('gnu95', 'nag', 'absoft', 'ibm', 'intel', 'gnu', 'g95', 'pg')),
('sunos.*', ('sun', 'gnu', 'gnu95', 'g95')),
('irix.*', ('mips', 'gnu', 'gnu95',)),
# f90 allows both fixed and free format, assuming fixed unless
# signs of free format are detected.
result = 0
- f = open_latin1(file, 'r')
- line = f.readline()
- n = 10000 # the number of non-comment lines to scan for hints
- if _has_f_header(line):
- n = 0
- elif _has_f90_header(line):
- n = 0
- result = 1
- while n>0 and line:
- line = line.rstrip()
- if line and line[0]!='!':
- n -= 1
- if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-1:]=='&':
- result = 1
- break
+ with open(file, encoding='latin1') as f:
line = f.readline()
- f.close()
+ n = 10000 # the number of non-comment lines to scan for hints
+ if _has_f_header(line):
+ n = 0
+ elif _has_f90_header(line):
+ n = 0
+ result = 1
+ while n>0 and line:
+ line = line.rstrip()
+ if line and line[0]!='!':
+ n -= 1
+ if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-1:]=='&':
+ result = 1
+ break
+ line = f.readline()
return result
def has_f90_header(src):
- f = open_latin1(src, 'r')
- line = f.readline()
- f.close()
+ with open(src, encoding='latin1') as f:
+ line = f.readline()
return _has_f90_header(line) or _has_fix_header(line)
_f77flags_re = re.compile(r'(c|)f77flags\s*\(\s*(?P<fcname>\w+)\s*\)\s*=\s*(?P<fflags>.*)', re.I)
Return a dictionary {<fcompiler type>:<f77 flags>}.
"""
flags = {}
- f = open_latin1(src, 'r')
- i = 0
- for line in f:
- i += 1
- if i>20: break
- m = _f77flags_re.match(line)
- if not m: continue
- fcname = m.group('fcname').strip()
- fflags = m.group('fflags').strip()
- flags[fcname] = split_quoted(fflags)
- f.close()
+ with open(src, encoding='latin1') as f:
+ i = 0
+ for line in f:
+ i += 1
+ if i>20: break
+ m = _f77flags_re.match(line)
+ if not m: continue
+ fcname = m.group('fcname').strip()
+ fflags = m.group('fflags').strip()
+ flags[fcname] = split_quoted(fflags)
return flags
# TODO: implement get_f90flags and use it in _compile similarly to get_f77flags
try:
conf_desc = self._conf_keys[name]
except KeyError:
- raise AttributeError(name)
+ raise AttributeError(
+ f"'EnvironmentConfig' object has no attribute '{name}'"
+ ) from None
+
return self._get_var(name, conf_desc)
def get(self, name, default=None):
--- /dev/null
+"""
+fujitsu
+
+Supports Fujitsu compiler function.
+This compiler is developed by Fujitsu and is used in A64FX on Fugaku.
+"""
+from numpy.distutils.fcompiler import FCompiler
+
+compilers = ['FujitsuFCompiler']
+
+class FujitsuFCompiler(FCompiler):
+ compiler_type = 'fujitsu'
+ description = 'Fujitsu Fortran Compiler'
+
+ possible_executables = ['frt']
+ version_pattern = r'frt \(FRT\) (?P<version>[a-z\d.]+)'
+ # $ frt --version
+ # frt (FRT) x.x.x yyyymmdd
+
+ executables = {
+ 'version_cmd' : ["<F77>", "--version"],
+ 'compiler_f77' : ["frt", "-Fixed"],
+ 'compiler_fix' : ["frt", "-Fixed"],
+ 'compiler_f90' : ["frt"],
+ 'linker_so' : ["frt", "-shared"],
+ 'archiver' : ["ar", "-cr"],
+ 'ranlib' : ["ranlib"]
+ }
+ pic_flags = ['-KPIC']
+ module_dir_switch = '-M'
+ module_include_switch = '-I'
+
+ def get_flags_opt(self):
+ return ['-O3']
+ def get_flags_debug(self):
+ return ['-g']
+ def runtime_library_dir_option(self, dir):
+ return f'-Wl,-rpath={dir}'
+ def get_libraries(self):
+ return ['fj90f', 'fj90i', 'fjsrcinfo']
+
+if __name__ == '__main__':
+ from distutils import log
+ from numpy.distutils import customized_fcompiler
+ log.set_verbosity(2)
+ print(customized_fcompiler('fujitsu').get_version())
return sys.platform == "win32" and platform.architecture()[0] == "64bit"
-if is_win64():
- #_EXTRAFLAGS = ["-fno-leading-underscore"]
- _EXTRAFLAGS = []
-else:
- _EXTRAFLAGS = []
-
-
class GnuFCompiler(FCompiler):
compiler_type = 'gnu'
compiler_aliases = ('g77', )
target = '10.9'
s = f'Env. variable MACOSX_DEPLOYMENT_TARGET set to {target}'
warnings.warn(s, stacklevel=2)
- os.environ['MACOSX_DEPLOYMENT_TARGET'] = target
+ os.environ['MACOSX_DEPLOYMENT_TARGET'] = str(target)
opt.extend(['-undefined', 'dynamic_lookup', '-bundle'])
else:
opt.append("-shared")
def _c_arch_flags(self):
""" Return detected arch flags from CFLAGS """
- from distutils import sysconfig
+ import sysconfig
try:
cflags = sysconfig.get_config_vars()['CFLAGS']
except KeyError:
executables = {
'version_cmd' : ["<F90>", "-dumpversion"],
'compiler_f77' : [None, "-Wall", "-g", "-ffixed-form",
- "-fno-second-underscore"] + _EXTRAFLAGS,
+ "-fno-second-underscore"],
'compiler_f90' : [None, "-Wall", "-g",
- "-fno-second-underscore"] + _EXTRAFLAGS,
+ "-fno-second-underscore"],
'compiler_fix' : [None, "-Wall", "-g","-ffixed-form",
- "-fno-second-underscore"] + _EXTRAFLAGS,
+ "-fno-second-underscore"],
'linker_so' : ["<F90>", "-Wall", "-g"],
'archiver' : ["ar", "-cr"],
'ranlib' : ["ranlib"],
'compiler_f77': ["pgfortran"],
'compiler_fix': ["pgfortran", "-Mfixed"],
'compiler_f90': ["pgfortran"],
- 'linker_so': ["pgfortran"],
+ 'linker_so': ["<F90>"],
'archiver': ["ar", "-cr"],
'ranlib': ["ranlib"]
}
"""
import os
+import platform
import sys
import subprocess
import re
# search in the file system for possible candidates
major_version, minor_version = tuple(sys.version_info[:2])
- patterns = ['python%d%d.dll']
-
- for pat in patterns:
- dllname = pat % (major_version, minor_version)
- print("Looking for %s" % dllname)
- for folder in lib_dirs:
- dll = os.path.join(folder, dllname)
- if os.path.exists(dll):
- return dll
-
+ implementation = platform.python_implementation()
+ if implementation == 'CPython':
+ dllname = f'python{major_version}{minor_version}.dll'
+ elif implementation == 'PyPy':
+ dllname = f'libpypy{major_version}-c.dll'
+ else:
+ dllname = 'Unknown platform {implementation}'
+ print("Looking for %s" % dllname)
+ for folder in lib_dirs:
+ dll = os.path.join(folder, dllname)
+ if os.path.exists(dll):
+ return dll
+
raise ValueError("%s not found in %s" % (dllname, lib_dirs))
def dump_table(dll):
import shutil
import multiprocessing
import textwrap
+import importlib.util
import distutils
from distutils.errors import DistutilsError
revision0 = f.read().strip()
branch_map = {}
- for line in file(branch_cache_fn, 'r'):
- branch1, revision1 = line.split()[:2]
- if revision1==revision0:
- branch0 = branch1
- try:
- revision1 = int(revision1)
- except ValueError:
- continue
- branch_map[branch1] = revision1
+ with open(branch_cache_fn, 'r') as f:
+ for line in f:
+ branch1, revision1 = line.split()[:2]
+ if revision1==revision0:
+ branch0 = branch1
+ try:
+ revision1 = int(revision1)
+ except ValueError:
+ continue
+ branch_map[branch1] = revision1
return branch_map.get(branch0)
environment, and using them when cross-compiling.
"""
- # XXX: import here for bootstrapping reasons
- import numpy
d = os.environ.get('NPY_PKG_CONFIG_PATH')
if d is not None:
return d
- d = os.path.join(os.path.dirname(numpy.__file__),
+ spec = importlib.util.find_spec('numpy')
+ d = os.path.join(os.path.dirname(spec.origin),
'core', 'lib', 'npy-pkg-config')
return d
Examples
--------
+ >>> import numpy as np
>>> np.show_config()
blas_opt_info:
language = c
config.add_subpackage('tests')
config.add_data_files('site.cfg')
config.add_data_files('mingw/gfortran_vs2003_hack.c')
+ config.add_data_dir('checks')
+ config.add_data_files('*.pyi')
config.make_config_py()
return config
from distutils.errors import DistutilsError
from distutils.dist import Distribution
-import distutils.sysconfig
+import sysconfig
from numpy.distutils import log
from distutils.util import get_platform
import tempfile
import shutil
+__all__ = ['system_info']
# Determine number of bits
import platform
if sys.platform == 'win32':
default_lib_dirs = ['C:\\',
- os.path.join(distutils.sysconfig.EXEC_PREFIX,
+ os.path.join(sysconfig.get_config_var('exec_prefix'),
'libs')]
default_runtime_dirs = []
default_include_dirs = []
vcpkg = shutil.which('vcpkg')
if vcpkg:
vcpkg_dir = os.path.dirname(vcpkg)
- if platform.architecture() == '32bit':
+ if platform.architecture()[0] == '32bit':
specifier = 'x86'
else:
specifier = 'x64'
so_ext = get_shared_lib_extension()
+def is_symlink_to_accelerate(filename):
+ accelpath = '/System/Library/Frameworks/Accelerate.framework'
+ return (sys.platform == 'darwin' and os.path.islink(filename) and
+ os.path.realpath(filename).startswith(accelpath))
+
+
+_accel_msg = (
+ 'Found {filename}, but that file is a symbolic link to the '
+ 'MacOS Accelerate framework, which is not supported by NumPy. '
+ 'You must configure the build to use a different optimized library, '
+ 'or disable the use of optimized BLAS and LAPACK by setting the '
+ 'environment variables NPY_BLAS_ORDER="" and NPY_LAPACK_ORDER="" '
+ 'before building NumPy.'
+)
+
+
def get_standard_file(fname):
"""Returns a list of files named 'fname' from
1) System-wide directory (directory-location of this module)
return filenames
+def _parse_env_order(base_order, env):
+ """ Parse an environment variable `env` by splitting with "," and only returning elements from `base_order`
+
+ This method will sequence the environment variable and check for their invidual elements in `base_order`.
+
+ The items in the environment variable may be negated via '^item' or '!itema,itemb'.
+ It must start with ^/! to negate all options.
+
+ Raises
+ ------
+ ValueError: for mixed negated and non-negated orders or multiple negated orders
+
+ Parameters
+ ----------
+ base_order : list of str
+ the base list of orders
+ env : str
+ the environment variable to be parsed, if none is found, `base_order` is returned
+
+ Returns
+ -------
+ allow_order : list of str
+ allowed orders in lower-case
+ unknown_order : list of str
+ for values not overlapping with `base_order`
+ """
+ order_str = os.environ.get(env, None)
+
+ # ensure all base-orders are lower-case (for easier comparison)
+ base_order = [order.lower() for order in base_order]
+ if order_str is None:
+ return base_order, []
+
+ neg = order_str.startswith('^') or order_str.startswith('!')
+ # Check format
+ order_str_l = list(order_str)
+ sum_neg = order_str_l.count('^') + order_str_l.count('!')
+ if neg:
+ if sum_neg > 1:
+ raise ValueError(f"Environment variable '{env}' may only contain a single (prefixed) negation: {order_str}")
+ # remove prefix
+ order_str = order_str[1:]
+ elif sum_neg > 0:
+ raise ValueError(f"Environment variable '{env}' may not mix negated an non-negated items: {order_str}")
+
+ # Split and lower case
+ orders = order_str.lower().split(',')
+
+ # to inform callee about non-overlapping elements
+ unknown_order = []
+
+ # if negated, we have to remove from the order
+ if neg:
+ allow_order = base_order.copy()
+
+ for order in orders:
+ if not order:
+ continue
+
+ if order not in base_order:
+ unknown_order.append(order)
+ continue
+
+ if order in allow_order:
+ allow_order.remove(order)
+
+ else:
+ allow_order = []
+
+ for order in orders:
+ if not order:
+ continue
+
+ if order not in base_order:
+ unknown_order.append(order)
+ continue
+
+ if order not in allow_order:
+ allow_order.append(order)
+
+ return allow_order, unknown_order
+
+
def get_info(name, notfound_action=0):
"""
notfound_action:
'blis': blis_info, # use blas_opt instead
'lapack_mkl': lapack_mkl_info, # use lapack_opt instead
'blas_mkl': blas_mkl_info, # use blas_opt instead
- 'accelerate': accelerate_info, # use blas_opt instead
'openblas64_': openblas64__info,
'openblas64__lapack': openblas64__lapack_info,
'openblas_ilp64': openblas_ilp64_info,
AliasedOptionError :
in case more than one of the options are found
"""
- found = map(lambda opt: self.cp.has_option(self.section, opt), options)
- found = list(found)
+ found = [self.cp.has_option(self.section, opt) for opt in options]
if sum(found) == 1:
return options[found.index(True)]
elif sum(found) == 0:
for prefix in lib_prefixes:
p = self.combine_paths(lib_dir, prefix + lib + ext)
if p:
+ # p[0] is the full path to the binary library file.
+ if is_symlink_to_accelerate(p[0]):
+ raise RuntimeError(_accel_msg.format(filename=p[0]))
break
if p:
assert len(p) == 1
class lapack_opt_info(system_info):
notfounderror = LapackNotFoundError
- # List of all known BLAS libraries, in the default order
- lapack_order = ['mkl', 'openblas', 'flame', 'atlas', 'accelerate', 'lapack']
+ # List of all known LAPACK libraries, in the default order
+ lapack_order = ['mkl', 'openblas', 'flame', 'atlas', 'lapack']
order_env_var_name = 'NPY_LAPACK_ORDER'
def _calc_info_mkl(self):
return getattr(self, '_calc_info_{}'.format(name))()
def calc_info(self):
- user_order = os.environ.get(self.order_env_var_name, None)
- if user_order is None:
- lapack_order = self.lapack_order
- else:
- # the user has requested the order of the
- # check they are all in the available list, a COMMA SEPARATED list
- user_order = user_order.lower().split(',')
- non_existing = []
- lapack_order = []
- for order in user_order:
- if order in self.lapack_order:
- lapack_order.append(order)
- elif len(order) > 0:
- non_existing.append(order)
- if len(non_existing) > 0:
- raise ValueError("lapack_opt_info user defined "
- "LAPACK order has unacceptable "
- "values: {}".format(non_existing))
+ lapack_order, unknown_order = _parse_env_order(self.lapack_order, self.order_env_var_name)
+ if len(unknown_order) > 0:
+ raise ValueError("lapack_opt_info user defined "
+ "LAPACK order has unacceptable "
+ "values: {}".format(unknown_order))
for lapack in lapack_order:
if self._calc_info(lapack):
class blas_opt_info(system_info):
notfounderror = BlasNotFoundError
# List of all known BLAS libraries, in the default order
- blas_order = ['mkl', 'blis', 'openblas', 'atlas', 'accelerate', 'blas']
+ blas_order = ['mkl', 'blis', 'openblas', 'atlas', 'blas']
order_env_var_name = 'NPY_BLAS_ORDER'
def _calc_info_mkl(self):
return getattr(self, '_calc_info_{}'.format(name))()
def calc_info(self):
- user_order = os.environ.get(self.order_env_var_name, None)
- if user_order is None:
- blas_order = self.blas_order
- else:
- # the user has requested the order of the
- # check they are all in the available list
- user_order = user_order.lower().split(',')
- non_existing = []
- blas_order = []
- for order in user_order:
- if order in self.blas_order:
- blas_order.append(order)
- elif len(order) > 0:
- non_existing.append(order)
- if len(non_existing) > 0:
- raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(non_existing))
+ blas_order, unknown_order = _parse_env_order(self.blas_order, self.order_env_var_name)
+ if len(unknown_order) > 0:
+ raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(unknown_order))
for blas in blas_order:
if self._calc_info(blas):
symbol_suffix = '64_'
+class cblas_info(system_info):
+ section = 'cblas'
+ dir_env_var = 'CBLAS'
+ # No default as it's used only in blas_info
+ _lib_names = []
+ notfounderror = BlasNotFoundError
+
+
class blas_info(system_info):
section = 'blas'
dir_env_var = 'BLAS'
# often not installed when mingw is being used. This rough
# treatment is not desirable, but windows is tricky.
info['language'] = 'f77' # XXX: is it generally true?
+ # If cblas is given as an option, use those
+ cblas_info_obj = cblas_info()
+ cblas_opt = cblas_info_obj.get_option_single('cblas_libs', 'libraries')
+ cblas_libs = cblas_info_obj.get_libs(cblas_opt, None)
+ if cblas_libs:
+ info['libraries'] = cblas_libs + blas_libs
+ info['define_macros'] = [('HAVE_CBLAS', None)]
else:
lib = self.get_cblas_libs(info)
if lib is not None:
except AttributeError:
pass
- include_dirs.append(distutils.sysconfig.get_python_inc(
- prefix=os.sep.join(prefix)))
+ include_dirs.append(sysconfig.get_path('include'))
except ImportError:
pass
- py_incl_dir = distutils.sysconfig.get_python_inc()
+ py_incl_dir = sysconfig.get_path('include')
include_dirs.append(py_incl_dir)
- py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True)
+ py_pincl_dir = sysconfig.get_path('platinclude')
if py_pincl_dir not in include_dirs:
include_dirs.append(py_pincl_dir)
for d in default_include_dirs:
break
if not src_dir:
return
- py_incl_dirs = [distutils.sysconfig.get_python_inc()]
- py_pincl_dir = distutils.sysconfig.get_python_inc(plat_specific=True)
+ py_incl_dirs = [sysconfig.get_path('include')]
+ py_pincl_dir = sysconfig.get_path('platinclude')
if py_pincl_dir not in py_incl_dirs:
py_incl_dirs.append(py_pincl_dir)
srcs_dir = os.path.join(src_dir, 'libs', 'python', 'src')
--- /dev/null
+import re, textwrap, os
+from os import sys, path
+from distutils.errors import DistutilsError
+
+is_standalone = __name__ == '__main__' and __package__ is None
+if is_standalone:
+ import unittest, contextlib, tempfile, shutil
+ sys.path.append(path.abspath(path.join(path.dirname(__file__), "..")))
+ from ccompiler_opt import CCompilerOpt
+
+ # from numpy/testing/_private/utils.py
+ @contextlib.contextmanager
+ def tempdir(*args, **kwargs):
+ tmpdir = tempfile.mkdtemp(*args, **kwargs)
+ try:
+ yield tmpdir
+ finally:
+ shutil.rmtree(tmpdir)
+
+ def assert_(expr, msg=''):
+ if not expr:
+ raise AssertionError(msg)
+else:
+ from numpy.distutils.ccompiler_opt import CCompilerOpt
+ from numpy.testing import assert_, tempdir
+
+# architectures and compilers to test
+arch_compilers = dict(
+ x86 = ("gcc", "clang", "icc", "iccw", "msvc"),
+ x64 = ("gcc", "clang", "icc", "iccw", "msvc"),
+ ppc64 = ("gcc", "clang"),
+ ppc64le = ("gcc", "clang"),
+ armhf = ("gcc", "clang"),
+ aarch64 = ("gcc", "clang"),
+ noarch = ("gcc",)
+)
+
+class FakeCCompilerOpt(CCompilerOpt):
+ fake_info = ""
+ def __init__(self, trap_files="", trap_flags="", *args, **kwargs):
+ self.fake_trap_files = trap_files
+ self.fake_trap_flags = trap_flags
+ CCompilerOpt.__init__(self, None, **kwargs)
+
+ def __repr__(self):
+ return textwrap.dedent("""\
+ <<<<
+ march : {}
+ compiler : {}
+ ----------------
+ {}
+ >>>>
+ """).format(self.cc_march, self.cc_name, self.report())
+
+ def dist_compile(self, sources, flags, **kwargs):
+ assert(isinstance(sources, list))
+ assert(isinstance(flags, list))
+ if self.fake_trap_files:
+ for src in sources:
+ if re.match(self.fake_trap_files, src):
+ self.dist_error("source is trapped by a fake interface")
+ if self.fake_trap_flags:
+ for f in flags:
+ if re.match(self.fake_trap_flags, f):
+ self.dist_error("flag is trapped by a fake interface")
+ # fake objects
+ return zip(sources, [' '.join(flags)] * len(sources))
+
+ def dist_info(self):
+ return FakeCCompilerOpt.fake_info
+
+ @staticmethod
+ def dist_log(*args, stderr=False):
+ pass
+
+class _Test_CCompilerOpt(object):
+ arch = None # x86_64
+ cc = None # gcc
+
+ def setup(self):
+ FakeCCompilerOpt.conf_nocache = True
+ self._opt = None
+
+ def nopt(self, *args, **kwargs):
+ FakeCCompilerOpt.fake_info = (self.arch, self.cc, "")
+ return FakeCCompilerOpt(*args, **kwargs)
+
+ def opt(self):
+ if not self._opt:
+ self._opt = self.nopt()
+ return self._opt
+
+ def march(self):
+ return self.opt().cc_march
+
+ def cc_name(self):
+ return self.opt().cc_name
+
+ def get_targets(self, targets, groups, **kwargs):
+ FakeCCompilerOpt.conf_target_groups = groups
+ opt = self.nopt(
+ cpu_baseline=kwargs.get("baseline", "min"),
+ cpu_dispatch=kwargs.get("dispatch", "max"),
+ trap_files=kwargs.get("trap_files", ""),
+ trap_flags=kwargs.get("trap_flags", "")
+ )
+ with tempdir() as tmpdir:
+ file = os.path.join(tmpdir, "test_targets.c")
+ with open(file, 'w') as f:
+ f.write(targets)
+ gtargets = []
+ gflags = {}
+ fake_objects = opt.try_dispatch([file])
+ for source, flags in fake_objects:
+ gtar = source.split('.')[1:-1]
+ glen = len(gtar)
+ if glen == 0:
+ gtar = "baseline"
+ elif glen == 1:
+ gtar = gtar[0].upper()
+ else:
+ # converting multi-target into parentheses str format to be equivalent
+ # to the configuration statements syntax.
+ gtar = ('('+' '.join(gtar)+')').upper()
+ gtargets.append(gtar)
+ gflags[gtar] = flags
+
+ has_baseline, targets = opt.sources_status[file]
+ targets = targets + ["baseline"] if has_baseline else targets
+ # convert tuple that represent multi-target into parentheses str format
+ targets = [
+ '('+' '.join(tar)+')' if isinstance(tar, tuple) else tar
+ for tar in targets
+ ]
+ if len(targets) != len(gtargets) or not all(t in gtargets for t in targets):
+ raise AssertionError(
+ "'sources_status' returns different targets than the compiled targets\n"
+ "%s != %s" % (targets, gtargets)
+ )
+ # return targets from 'sources_status' since the order is matters
+ return targets, gflags
+
+ def arg_regex(self, **kwargs):
+ map2origin = dict(
+ x64 = "x86",
+ ppc64le = "ppc64",
+ aarch64 = "armhf",
+ clang = "gcc",
+ )
+ march = self.march(); cc_name = self.cc_name()
+ map_march = map2origin.get(march, march)
+ map_cc = map2origin.get(cc_name, cc_name)
+ for key in (
+ march, cc_name, map_march, map_cc,
+ march + '_' + cc_name,
+ map_march + '_' + cc_name,
+ march + '_' + map_cc,
+ map_march + '_' + map_cc,
+ ) :
+ regex = kwargs.pop(key, None)
+ if regex is not None:
+ break
+ if regex:
+ if isinstance(regex, dict):
+ for k, v in regex.items():
+ if v[-1:] not in ')}$?\\.+*':
+ regex[k] = v + '$'
+ else:
+ assert(isinstance(regex, str))
+ if regex[-1:] not in ')}$?\\.+*':
+ regex += '$'
+ return regex
+
+ def expect(self, dispatch, baseline="", **kwargs):
+ match = self.arg_regex(**kwargs)
+ if match is None:
+ return
+ opt = self.nopt(
+ cpu_baseline=baseline, cpu_dispatch=dispatch,
+ trap_files=kwargs.get("trap_files", ""),
+ trap_flags=kwargs.get("trap_flags", "")
+ )
+ features = ' '.join(opt.cpu_dispatch_names())
+ if not match:
+ if len(features) != 0:
+ raise AssertionError(
+ 'expected empty features, not "%s"' % features
+ )
+ return
+ if not re.match(match, features, re.IGNORECASE):
+ raise AssertionError(
+ 'dispatch features "%s" not match "%s"' % (features, match)
+ )
+
+ def expect_baseline(self, baseline, dispatch="", **kwargs):
+ match = self.arg_regex(**kwargs)
+ if match is None:
+ return
+ opt = self.nopt(
+ cpu_baseline=baseline, cpu_dispatch=dispatch,
+ trap_files=kwargs.get("trap_files", ""),
+ trap_flags=kwargs.get("trap_flags", "")
+ )
+ features = ' '.join(opt.cpu_baseline_names())
+ if not match:
+ if len(features) != 0:
+ raise AssertionError(
+ 'expected empty features, not "%s"' % features
+ )
+ return
+ if not re.match(match, features, re.IGNORECASE):
+ raise AssertionError(
+ 'baseline features "%s" not match "%s"' % (features, match)
+ )
+
+ def expect_flags(self, baseline, dispatch="", **kwargs):
+ match = self.arg_regex(**kwargs)
+ if match is None:
+ return
+ opt = self.nopt(
+ cpu_baseline=baseline, cpu_dispatch=dispatch,
+ trap_files=kwargs.get("trap_files", ""),
+ trap_flags=kwargs.get("trap_flags", "")
+ )
+ flags = ' '.join(opt.cpu_baseline_flags())
+ if not match:
+ if len(flags) != 0:
+ raise AssertionError(
+ 'expected empty flags not "%s"' % flags
+ )
+ return
+ if not re.match(match, flags):
+ raise AssertionError(
+ 'flags "%s" not match "%s"' % (flags, match)
+ )
+
+ def expect_targets(self, targets, groups={}, **kwargs):
+ match = self.arg_regex(**kwargs)
+ if match is None:
+ return
+ targets, _ = self.get_targets(targets=targets, groups=groups, **kwargs)
+ targets = ' '.join(targets)
+ if not match:
+ if len(targets) != 0:
+ raise AssertionError(
+ 'expected empty targets, not "%s"' % targets
+ )
+ return
+ if not re.match(match, targets, re.IGNORECASE):
+ raise AssertionError(
+ 'targets "%s" not match "%s"' % (targets, match)
+ )
+
+ def expect_target_flags(self, targets, groups={}, **kwargs):
+ match_dict = self.arg_regex(**kwargs)
+ if match_dict is None:
+ return
+ assert(isinstance(match_dict, dict))
+ _, tar_flags = self.get_targets(targets=targets, groups=groups)
+
+ for match_tar, match_flags in match_dict.items():
+ if match_tar not in tar_flags:
+ raise AssertionError(
+ 'expected to find target "%s"' % match_tar
+ )
+ flags = tar_flags[match_tar]
+ if not match_flags:
+ if len(flags) != 0:
+ raise AssertionError(
+ 'expected to find empty flags in target "%s"' % match_tar
+ )
+ if not re.match(match_flags, flags):
+ raise AssertionError(
+ '"%s" flags "%s" not match "%s"' % (match_tar, flags, match_flags)
+ )
+
+ def test_interface(self):
+ wrong_arch = "ppc64" if self.arch != "ppc64" else "x86"
+ wrong_cc = "clang" if self.cc != "clang" else "icc"
+ opt = self.opt()
+ assert_(getattr(opt, "cc_on_" + self.arch))
+ assert_(not getattr(opt, "cc_on_" + wrong_arch))
+ assert_(getattr(opt, "cc_is_" + self.cc))
+ assert_(not getattr(opt, "cc_is_" + wrong_cc))
+
+ def test_args_empty(self):
+ for baseline, dispatch in (
+ ("", "none"),
+ (None, ""),
+ ("none +none", "none - none"),
+ ("none -max", "min - max"),
+ ("+vsx2 -VSX2", "vsx avx2 avx512f -max"),
+ ("max -vsx - avx + avx512f neon -MAX ",
+ "min -min + max -max -vsx + avx2 -avx2 +NONE")
+ ) :
+ opt = self.nopt(cpu_baseline=baseline, cpu_dispatch=dispatch)
+ assert(len(opt.cpu_baseline_names()) == 0)
+ assert(len(opt.cpu_dispatch_names()) == 0)
+
+ def test_args_validation(self):
+ if self.march() == "unknown":
+ return
+ # check sanity of argument's validation
+ for baseline, dispatch in (
+ ("unkown_feature - max +min", "unknown max min"), # unknowing features
+ ("#avx2", "$vsx") # groups and polices aren't acceptable
+ ) :
+ try:
+ self.nopt(cpu_baseline=baseline, cpu_dispatch=dispatch)
+ raise AssertionError("excepted an exception for invalid arguments")
+ except DistutilsError:
+ pass
+
+ def test_skip(self):
+ # only takes what platform supports and skip the others
+ # without casing exceptions
+ self.expect(
+ "sse vsx neon",
+ x86="sse", ppc64="vsx", armhf="neon", unknown=""
+ )
+ self.expect(
+ "sse41 avx avx2 vsx2 vsx3 neon_vfpv4 asimd",
+ x86 = "sse41 avx avx2",
+ ppc64 = "vsx2 vsx3",
+ armhf = "neon_vfpv4 asimd",
+ unknown = ""
+ )
+ # any features in cpu_dispatch must be ignored if it's part of baseline
+ self.expect(
+ "sse neon vsx", baseline="sse neon vsx",
+ x86="", ppc64="", armhf=""
+ )
+ self.expect(
+ "avx2 vsx3 asimdhp", baseline="avx2 vsx3 asimdhp",
+ x86="", ppc64="", armhf=""
+ )
+
+ def test_implies(self):
+ # baseline combining implied features, so we count
+ # on it instead of testing 'feature_implies()'' directly
+ self.expect_baseline(
+ "fma3 avx2 asimd vsx3",
+ # .* between two spaces can validate features in between
+ x86 = "sse .* sse41 .* fma3.*avx2",
+ ppc64 = "vsx vsx2 vsx3",
+ armhf = "neon neon_fp16 neon_vfpv4 asimd"
+ )
+ """
+ special cases
+ """
+ # in icc and msvc, FMA3 and AVX2 can't be separated
+ # both need to implies each other, same for avx512f & cd
+ for f0, f1 in (
+ ("fma3", "avx2"),
+ ("avx512f", "avx512cd"),
+ ):
+ diff = ".* sse42 .* %s .*%s$" % (f0, f1)
+ self.expect_baseline(f0,
+ x86_gcc=".* sse42 .* %s$" % f0,
+ x86_icc=diff, x86_iccw=diff
+ )
+ self.expect_baseline(f1,
+ x86_gcc=".* avx .* %s$" % f1,
+ x86_icc=diff, x86_iccw=diff
+ )
+ # in msvc, following features can't be separated too
+ for f in (("fma3", "avx2"), ("avx512f", "avx512cd", "avx512_skx")):
+ for ff in f:
+ self.expect_baseline(ff,
+ x86_msvc=".*%s" % ' '.join(f)
+ )
+
+ # in ppc64le VSX and VSX2 can't be separated
+ self.expect_baseline("vsx", ppc64le="vsx vsx2")
+ # in aarch64 following features can't be separated
+ for f in ("neon", "neon_fp16", "neon_vfpv4", "asimd"):
+ self.expect_baseline(f, aarch64="neon neon_fp16 neon_vfpv4 asimd")
+
+ def test_args_options(self):
+ # max & native
+ for o in ("max", "native"):
+ if o == "native" and self.cc_name() == "msvc":
+ continue
+ self.expect(o,
+ trap_files=".*cpu_(sse|vsx|neon).c",
+ x86="", ppc64="", armhf=""
+ )
+ self.expect(o,
+ trap_files=".*cpu_(sse3|vsx2|neon_vfpv4).c",
+ x86="sse sse2", ppc64="vsx", armhf="neon neon_fp16",
+ aarch64="", ppc64le=""
+ )
+ self.expect(o,
+ trap_files=".*cpu_(popcnt|vsx3).c",
+ x86="sse .* sse41", ppc64="vsx vsx2",
+ armhf="neon neon_fp16 .* asimd .*"
+ )
+ self.expect(o,
+ x86_gcc=".* xop fma4 .* avx512f .* avx512_knl avx512_knm avx512_skx .*",
+ # in icc, xop and fam4 aren't supported
+ x86_icc=".* avx512f .* avx512_knl avx512_knm avx512_skx .*",
+ x86_iccw=".* avx512f .* avx512_knl avx512_knm avx512_skx .*",
+ # in msvc, avx512_knl avx512_knm aren't supported
+ x86_msvc=".* xop fma4 .* avx512f .* avx512_skx .*",
+ armhf=".* asimd asimdhp asimddp .*",
+ ppc64="vsx vsx2 vsx3.*"
+ )
+ # min
+ self.expect("min",
+ x86="sse sse2", x64="sse sse2 sse3",
+ armhf="", aarch64="neon neon_fp16 .* asimd",
+ ppc64="", ppc64le="vsx vsx2"
+ )
+ self.expect(
+ "min", trap_files=".*cpu_(sse2|vsx2).c",
+ x86="", ppc64le=""
+ )
+ # an exception must triggered if native flag isn't supported
+ # when option "native" is activated through the args
+ try:
+ self.expect("native",
+ trap_flags=".*(-march=native|-xHost|/QxHost).*",
+ x86=".*", ppc64=".*", armhf=".*"
+ )
+ if self.march() != "unknown":
+ raise AssertionError(
+ "excepted an exception for %s" % self.march()
+ )
+ except DistutilsError:
+ if self.march() == "unknown":
+ raise AssertionError("excepted no exceptions")
+
+ def test_flags(self):
+ self.expect_flags(
+ "sse sse2 vsx vsx2 neon neon_fp16",
+ x86_gcc="-msse -msse2", x86_icc="-msse -msse2",
+ x86_iccw="/arch:SSE2", x86_msvc="/arch:SSE2",
+ ppc64_gcc= "-mcpu=power8",
+ ppc64_clang="-maltivec -mvsx -mpower8-vector",
+ armhf_gcc="-mfpu=neon-fp16 -mfp16-format=ieee",
+ aarch64=""
+ )
+ # testing normalize -march
+ self.expect_flags(
+ "asimd",
+ aarch64="",
+ armhf_gcc=r"-mfp16-format=ieee -mfpu=neon-fp-armv8 -march=armv8-a\+simd"
+ )
+ self.expect_flags(
+ "asimdhp",
+ aarch64_gcc=r"-march=armv8.2-a\+fp16",
+ armhf_gcc=r"-mfp16-format=ieee -mfpu=neon-fp-armv8 -march=armv8.2-a\+fp16"
+ )
+ self.expect_flags(
+ "asimddp", aarch64_gcc=r"-march=armv8.2-a\+dotprod"
+ )
+ self.expect_flags(
+ # asimdfhm implies asimdhp
+ "asimdfhm", aarch64_gcc=r"-march=armv8.2-a\+fp16\+fp16fml"
+ )
+ self.expect_flags(
+ "asimddp asimdhp asimdfhm",
+ aarch64_gcc=r"-march=armv8.2-a\+dotprod\+fp16\+fp16fml"
+ )
+
+ def test_targets_exceptions(self):
+ for targets in (
+ "bla bla", "/*@targets",
+ "/*@targets */",
+ "/*@targets unknown */",
+ "/*@targets $unknown_policy avx2 */",
+ "/*@targets #unknown_group avx2 */",
+ "/*@targets $ */",
+ "/*@targets # vsx */",
+ "/*@targets #$ vsx */",
+ "/*@targets vsx avx2 ) */",
+ "/*@targets vsx avx2 (avx2 */",
+ "/*@targets vsx avx2 () */",
+ "/*@targets vsx avx2 ($autovec) */", # no features
+ "/*@targets vsx avx2 (xxx) */",
+ "/*@targets vsx avx2 (baseline) */",
+ ) :
+ try:
+ self.expect_targets(
+ targets,
+ x86="", armhf="", ppc64=""
+ )
+ if self.march() != "unknown":
+ raise AssertionError(
+ "excepted an exception for %s" % self.march()
+ )
+ except DistutilsError:
+ if self.march() == "unknown":
+ raise AssertionError("excepted no exceptions")
+
+ def test_targets_syntax(self):
+ for targets in (
+ "/*@targets $keep_baseline sse vsx neon*/",
+ "/*@targets,$keep_baseline,sse,vsx,neon*/",
+ "/*@targets*$keep_baseline*sse*vsx*neon*/",
+ """
+ /*
+ ** @targets
+ ** $keep_baseline, sse vsx,neon
+ */
+ """,
+ """
+ /*
+ ************@targets*************
+ ** $keep_baseline, sse vsx, neon
+ *********************************
+ */
+ """,
+ """
+ /*
+ /////////////@targets/////////////////
+ //$keep_baseline//sse//vsx//neon
+ /////////////////////////////////////
+ */
+ """,
+ """
+ /*
+ @targets
+ $keep_baseline
+ SSE VSX NEON*/
+ """
+ ) :
+ self.expect_targets(targets,
+ x86="sse", ppc64="vsx", armhf="neon", unknown=""
+ )
+
+ def test_targets(self):
+ # test skipping baseline features
+ self.expect_targets(
+ """
+ /*@targets
+ sse sse2 sse41 avx avx2 avx512f
+ vsx vsx2 vsx3
+ neon neon_fp16 asimdhp asimddp
+ */
+ """,
+ baseline="avx vsx2 asimd",
+ x86="avx512f avx2", armhf="asimddp asimdhp", ppc64="vsx3"
+ )
+ # test skipping non-dispatch features
+ self.expect_targets(
+ """
+ /*@targets
+ sse41 avx avx2 avx512f
+ vsx2 vsx3
+ asimd asimdhp asimddp
+ */
+ """,
+ baseline="", dispatch="sse41 avx2 vsx2 asimd asimddp",
+ x86="avx2 sse41", armhf="asimddp asimd", ppc64="vsx2"
+ )
+ # test skipping features that not supported
+ self.expect_targets(
+ """
+ /*@targets
+ sse2 sse41 avx2 avx512f
+ vsx2 vsx3
+ neon asimdhp asimddp
+ */
+ """,
+ baseline="",
+ trap_files=".*(avx2|avx512f|vsx3|asimddp).c",
+ x86="sse41 sse2", ppc64="vsx2", armhf="asimdhp neon"
+ )
+ # test skipping features that implies each other
+ self.expect_targets(
+ """
+ /*@targets
+ sse sse2 avx fma3 avx2 avx512f avx512cd
+ vsx vsx2 vsx3
+ neon neon_vfpv4 neon_fp16 neon_fp16 asimd asimdhp
+ asimddp asimdfhm
+ */
+ """,
+ baseline="",
+ x86_gcc="avx512cd avx512f avx2 fma3 avx sse2",
+ x86_msvc="avx512cd avx2 avx sse2",
+ x86_icc="avx512cd avx2 avx sse2",
+ x86_iccw="avx512cd avx2 avx sse2",
+ ppc64="vsx3 vsx2 vsx",
+ ppc64le="vsx3 vsx2",
+ armhf="asimdfhm asimddp asimdhp asimd neon_vfpv4 neon_fp16 neon",
+ aarch64="asimdfhm asimddp asimdhp asimd"
+ )
+
+ def test_targets_policies(self):
+ # 'keep_baseline', generate objects for baseline features
+ self.expect_targets(
+ """
+ /*@targets
+ $keep_baseline
+ sse2 sse42 avx2 avx512f
+ vsx2 vsx3
+ neon neon_vfpv4 asimd asimddp
+ */
+ """,
+ baseline="sse41 avx2 vsx2 asimd vsx3",
+ x86="avx512f avx2 sse42 sse2",
+ ppc64="vsx3 vsx2",
+ armhf="asimddp asimd neon_vfpv4 neon",
+ # neon, neon_vfpv4, asimd implies each other
+ aarch64="asimddp asimd"
+ )
+ # 'keep_sort', leave the sort as-is
+ self.expect_targets(
+ """
+ /*@targets
+ $keep_baseline $keep_sort
+ avx512f sse42 avx2 sse2
+ vsx2 vsx3
+ asimd neon neon_vfpv4 asimddp
+ */
+ """,
+ x86="avx512f sse42 avx2 sse2",
+ ppc64="vsx2 vsx3",
+ armhf="asimd neon neon_vfpv4 asimddp",
+ # neon, neon_vfpv4, asimd implies each other
+ aarch64="asimd asimddp"
+ )
+ # 'autovec', skipping features that can't be
+ # vectorized by the compiler
+ self.expect_targets(
+ """
+ /*@targets
+ $keep_baseline $keep_sort $autovec
+ avx512f avx2 sse42 sse41 sse2
+ vsx3 vsx2
+ asimddp asimd neon_vfpv4 neon
+ */
+ """,
+ x86_gcc="avx512f avx2 sse42 sse41 sse2",
+ x86_icc="avx512f avx2 sse42 sse41 sse2",
+ x86_iccw="avx512f avx2 sse42 sse41 sse2",
+ x86_msvc="avx512f avx2 sse2",
+ ppc64="vsx3 vsx2",
+ armhf="asimddp asimd neon_vfpv4 neon",
+ # neon, neon_vfpv4, asimd implies each other
+ aarch64="asimddp asimd"
+ )
+ for policy in ("$maxopt", "$autovec"):
+ # 'maxopt' and autovec set the max acceptable optimization flags
+ self.expect_target_flags(
+ "/*@targets baseline %s */" % policy,
+ gcc={"baseline":".*-O3.*"}, icc={"baseline":".*-O3.*"},
+ iccw={"baseline":".*/O3.*"}, msvc={"baseline":".*/O2.*"},
+ unknown={"baseline":".*"}
+ )
+
+ # 'werror', force compilers to treat warnings as errors
+ self.expect_target_flags(
+ "/*@targets baseline $werror */",
+ gcc={"baseline":".*-Werror.*"}, icc={"baseline":".*-Werror.*"},
+ iccw={"baseline":".*/Werror.*"}, msvc={"baseline":".*/WX.*"},
+ unknown={"baseline":".*"}
+ )
+
+ def test_targets_groups(self):
+ self.expect_targets(
+ """
+ /*@targets $keep_baseline baseline #test_group */
+ """,
+ groups=dict(
+ test_group=("""
+ $keep_baseline
+ asimddp sse2 vsx2 avx2 vsx3
+ avx512f asimdhp
+ """)
+ ),
+ x86="avx512f avx2 sse2 baseline",
+ ppc64="vsx3 vsx2 baseline",
+ armhf="asimddp asimdhp baseline"
+ )
+ # test skip duplicating and sorting
+ self.expect_targets(
+ """
+ /*@targets
+ * sse42 avx avx512f
+ * #test_group_1
+ * vsx2
+ * #test_group_2
+ * asimddp asimdfhm
+ */
+ """,
+ groups=dict(
+ test_group_1=("""
+ VSX2 vsx3 asimd avx2 SSE41
+ """),
+ test_group_2=("""
+ vsx2 vsx3 asImd aVx2 sse41
+ """)
+ ),
+ x86="avx512f avx2 avx sse42 sse41",
+ ppc64="vsx3 vsx2",
+ # vsx2 part of the default baseline of ppc64le, option ("min")
+ ppc64le="vsx3",
+ armhf="asimdfhm asimddp asimd",
+ # asimd part of the default baseline of aarch64, option ("min")
+ aarch64="asimdfhm asimddp"
+ )
+
+ def test_targets_multi(self):
+ self.expect_targets(
+ """
+ /*@targets
+ (avx512_clx avx512_cnl) (asimdhp asimddp)
+ */
+ """,
+ x86=r"\(avx512_clx avx512_cnl\)",
+ armhf=r"\(asimdhp asimddp\)",
+ )
+ # test skipping implied features and auto-sort
+ self.expect_targets(
+ """
+ /*@targets
+ f16c (sse41 avx sse42) (sse3 avx2 avx512f)
+ vsx2 (vsx vsx3 vsx2)
+ (neon neon_vfpv4 asimd asimdhp asimddp)
+ */
+ """,
+ x86="avx512f f16c avx",
+ ppc64="vsx3 vsx2",
+ ppc64le="vsx3", # vsx2 part of baseline
+ armhf=r"\(asimdhp asimddp\)",
+ )
+ # test skipping implied features and keep sort
+ self.expect_targets(
+ """
+ /*@targets $keep_sort
+ (sse41 avx sse42) (sse3 avx2 avx512f)
+ (vsx vsx3 vsx2)
+ (asimddp neon neon_vfpv4 asimd asimdhp)
+ */
+ """,
+ x86="avx avx512f",
+ ppc64="vsx3",
+ armhf=r"\(asimdhp asimddp\)",
+ )
+ # test compiler variety and avoiding duplicating
+ self.expect_targets(
+ """
+ /*@targets $keep_sort
+ fma3 avx2 (fma3 avx2) (avx2 fma3) avx2 fma3
+ */
+ """,
+ x86_gcc=r"fma3 avx2 \(fma3 avx2\)",
+ x86_icc="avx2", x86_iccw="avx2",
+ x86_msvc="avx2"
+ )
+
+def new_test(arch, cc):
+ if is_standalone: return textwrap.dedent("""\
+ class TestCCompilerOpt_{class_name}(_Test_CCompilerOpt, unittest.TestCase):
+ arch = '{arch}'
+ cc = '{cc}'
+ def __init__(self, methodName="runTest"):
+ unittest.TestCase.__init__(self, methodName)
+ self.setup()
+ """).format(
+ class_name=arch + '_' + cc, arch=arch, cc=cc
+ )
+ return textwrap.dedent("""\
+ class TestCCompilerOpt_{class_name}(_Test_CCompilerOpt):
+ arch = '{arch}'
+ cc = '{cc}'
+ """).format(
+ class_name=arch + '_' + cc, arch=arch, cc=cc
+ )
+"""
+if 1 and is_standalone:
+ FakeCCompilerOpt.fake_info = "x86_icc"
+ cco = FakeCCompilerOpt(None, cpu_baseline="avx2")
+ print(' '.join(cco.cpu_baseline_names()))
+ print(cco.cpu_baseline_flags())
+ unittest.main()
+ sys.exit()
+"""
+for arch, compilers in arch_compilers.items():
+ for cc in compilers:
+ exec(new_test(arch, cc))
+
+if is_standalone:
+ unittest.main()
--- /dev/null
+import unittest
+from os import sys, path
+
+is_standalone = __name__ == '__main__' and __package__ is None
+if is_standalone:
+ sys.path.append(path.abspath(path.join(path.dirname(__file__), "..")))
+ from ccompiler_opt import CCompilerOpt
+else:
+ from numpy.distutils.ccompiler_opt import CCompilerOpt
+
+arch_compilers = dict(
+ x86 = ("gcc", "clang", "icc", "iccw", "msvc"),
+ x64 = ("gcc", "clang", "icc", "iccw", "msvc"),
+ ppc64 = ("gcc", "clang"),
+ ppc64le = ("gcc", "clang"),
+ armhf = ("gcc", "clang"),
+ aarch64 = ("gcc", "clang"),
+ narch = ("gcc",)
+)
+
+class FakeCCompilerOpt(CCompilerOpt):
+ fake_info = ("arch", "compiler", "extra_args")
+ def __init__(self, *args, **kwargs):
+ CCompilerOpt.__init__(self, None, **kwargs)
+ def dist_compile(self, sources, flags, **kwargs):
+ return sources
+ def dist_info(self):
+ return FakeCCompilerOpt.fake_info
+ @staticmethod
+ def dist_log(*args, stderr=False):
+ pass
+
+class _TestConfFeatures(FakeCCompilerOpt):
+ """A hook to check the sanity of configured features
+- before it called by the abstract class '_Feature'
+ """
+
+ def conf_features_partial(self):
+ conf_all = self.conf_features
+ for feature_name, feature in conf_all.items():
+ self.test_feature(
+ "attribute conf_features",
+ conf_all, feature_name, feature
+ )
+
+ conf_partial = FakeCCompilerOpt.conf_features_partial(self)
+ for feature_name, feature in conf_partial.items():
+ self.test_feature(
+ "conf_features_partial()",
+ conf_partial, feature_name, feature
+ )
+ return conf_partial
+
+ def test_feature(self, log, search_in, feature_name, feature_dict):
+ error_msg = (
+ "during validate '{}' within feature '{}', "
+ "march '{}' and compiler '{}'\n>> "
+ ).format(log, feature_name, self.cc_march, self.cc_name)
+
+ if not feature_name.isupper():
+ raise AssertionError(error_msg + "feature name must be in uppercase")
+
+ for option, val in feature_dict.items():
+ self.test_option_types(error_msg, option, val)
+ self.test_duplicates(error_msg, option, val)
+
+ self.test_implies(error_msg, search_in, feature_name, feature_dict)
+ self.test_group(error_msg, search_in, feature_name, feature_dict)
+ self.test_extra_checks(error_msg, search_in, feature_name, feature_dict)
+
+ def test_option_types(self, error_msg, option, val):
+ for tp, available in (
+ ((str, list), (
+ "implies", "headers", "flags", "group", "detect", "extra_checks"
+ )),
+ ((str,), ("disable",)),
+ ((int,), ("interest",)),
+ ((bool,), ("implies_detect",)),
+ ((bool, type(None)), ("autovec",)),
+ ) :
+ found_it = option in available
+ if not found_it:
+ continue
+ if not isinstance(val, tp):
+ error_tp = [t.__name__ for t in (*tp,)]
+ error_tp = ' or '.join(error_tp)
+ raise AssertionError(error_msg +
+ "expected '%s' type for option '%s' not '%s'" % (
+ error_tp, option, type(val).__name__
+ ))
+ break
+
+ if not found_it:
+ raise AssertionError(error_msg + "invalid option name '%s'" % option)
+
+ def test_duplicates(self, error_msg, option, val):
+ if option not in (
+ "implies", "headers", "flags", "group", "detect", "extra_checks"
+ ) : return
+
+ if isinstance(val, str):
+ val = val.split()
+
+ if len(val) != len(set(val)):
+ raise AssertionError(error_msg + "duplicated values in option '%s'" % option)
+
+ def test_implies(self, error_msg, search_in, feature_name, feature_dict):
+ if feature_dict.get("disabled") is not None:
+ return
+ implies = feature_dict.get("implies", "")
+ if not implies:
+ return
+ if isinstance(implies, str):
+ implies = implies.split()
+
+ if feature_name in implies:
+ raise AssertionError(error_msg + "feature implies itself")
+
+ for impl in implies:
+ impl_dict = search_in.get(impl)
+ if impl_dict is not None:
+ if "disable" in impl_dict:
+ raise AssertionError(error_msg + "implies disabled feature '%s'" % impl)
+ continue
+ raise AssertionError(error_msg + "implies non-exist feature '%s'" % impl)
+
+ def test_group(self, error_msg, search_in, feature_name, feature_dict):
+ if feature_dict.get("disabled") is not None:
+ return
+ group = feature_dict.get("group", "")
+ if not group:
+ return
+ if isinstance(group, str):
+ group = group.split()
+
+ for f in group:
+ impl_dict = search_in.get(f)
+ if not impl_dict or "disable" in impl_dict:
+ continue
+ raise AssertionError(error_msg +
+ "in option 'group', '%s' already exists as a feature name" % f
+ )
+
+ def test_extra_checks(self, error_msg, search_in, feature_name, feature_dict):
+ if feature_dict.get("disabled") is not None:
+ return
+ extra_checks = feature_dict.get("extra_checks", "")
+ if not extra_checks:
+ return
+ if isinstance(extra_checks, str):
+ extra_checks = extra_checks.split()
+
+ for f in extra_checks:
+ impl_dict = search_in.get(f)
+ if not impl_dict or "disable" in impl_dict:
+ continue
+ raise AssertionError(error_msg +
+ "in option 'extra_checks', extra test case '%s' already exists as a feature name" % f
+ )
+
+class TestConfFeatures(unittest.TestCase):
+ def __init__(self, methodName="runTest"):
+ unittest.TestCase.__init__(self, methodName)
+ self.setup()
+
+ def setup(self):
+ FakeCCompilerOpt.conf_nocache = True
+
+ def test_features(self):
+ for arch, compilers in arch_compilers.items():
+ for cc in compilers:
+ FakeCCompilerOpt.fake_info = (arch, cc, "")
+ _TestConfFeatures()
+
+if is_standalone:
+ unittest.main()
assert info.get_lib_dirs() == lib_dirs
finally:
os.chdir(previousDir)
-
+
+
+def test_distutils_parse_env_order(monkeypatch):
+ from numpy.distutils.system_info import _parse_env_order
+ env = 'NPY_TESTS_DISTUTILS_PARSE_ENV_ORDER'
+
+ base_order = list('abcdef')
+
+ monkeypatch.setenv(env, 'b,i,e,f')
+ order, unknown = _parse_env_order(base_order, env)
+ assert len(order) == 3
+ assert order == list('bef')
+ assert len(unknown) == 1
+
+ # For when LAPACK/BLAS optimization is disabled
+ monkeypatch.setenv(env, '')
+ order, unknown = _parse_env_order(base_order, env)
+ assert len(order) == 0
+ assert len(unknown) == 0
+
+ for prefix in '^!':
+ monkeypatch.setenv(env, f'{prefix}b,i,e')
+ order, unknown = _parse_env_order(base_order, env)
+ assert len(order) == 4
+ assert order == list('acdf')
+ assert len(unknown) == 1
+
+ with pytest.raises(ValueError):
+ monkeypatch.setenv(env, 'b,^e,i')
+ _parse_env_order(base_order, env)
+
+ with pytest.raises(ValueError):
+ monkeypatch.setenv(env, '!b,^e,i')
+ _parse_env_order(base_order, env)
"""
import os
+import sys
+import subprocess
from distutils.errors import CompileError, DistutilsExecError, LibError
from distutils.unixccompiler import UnixCCompiler
self.compiler_so = ccomp
# ensure OPT environment variable is read
if 'OPT' in os.environ:
- from distutils.sysconfig import get_config_vars
+ # XXX who uses this?
+ from sysconfig import get_config_vars
opt = " ".join(os.environ['OPT'].split())
gcv_opt = " ".join(get_config_vars('OPT')[0].split())
ccomp_s = " ".join(self.compiler_so)
# add commandline flags to dependency file
if deps:
+ # After running the compiler, the file created will be in EBCDIC
+ # but will not be tagged as such. This tags it so the file does not
+ # have multiple different encodings being written to it
+ if sys.platform == 'zos':
+ subprocess.check_output(['chtag', '-tc', 'IBM1047', obj + '.d'])
with open(obj + '.d', 'a') as f:
f.write(_commandline_dep_string(cc_args, extra_postargs, pp_opts))
+++ /dev/null
-"""
-============
-Array basics
-============
-
-Array types and conversions between types
-=========================================
-
-NumPy supports a much greater variety of numerical types than Python does.
-This section shows which are available, and how to modify an array's data-type.
-
-The primitive types supported are tied closely to those in C:
-
-.. list-table::
- :header-rows: 1
-
- * - Numpy type
- - C type
- - Description
-
- * - `np.bool_`
- - ``bool``
- - Boolean (True or False) stored as a byte
-
- * - `np.byte`
- - ``signed char``
- - Platform-defined
-
- * - `np.ubyte`
- - ``unsigned char``
- - Platform-defined
-
- * - `np.short`
- - ``short``
- - Platform-defined
-
- * - `np.ushort`
- - ``unsigned short``
- - Platform-defined
-
- * - `np.intc`
- - ``int``
- - Platform-defined
-
- * - `np.uintc`
- - ``unsigned int``
- - Platform-defined
-
- * - `np.int_`
- - ``long``
- - Platform-defined
-
- * - `np.uint`
- - ``unsigned long``
- - Platform-defined
-
- * - `np.longlong`
- - ``long long``
- - Platform-defined
-
- * - `np.ulonglong`
- - ``unsigned long long``
- - Platform-defined
-
- * - `np.half` / `np.float16`
- -
- - Half precision float:
- sign bit, 5 bits exponent, 10 bits mantissa
-
- * - `np.single`
- - ``float``
- - Platform-defined single precision float:
- typically sign bit, 8 bits exponent, 23 bits mantissa
-
- * - `np.double`
- - ``double``
- - Platform-defined double precision float:
- typically sign bit, 11 bits exponent, 52 bits mantissa.
-
- * - `np.longdouble`
- - ``long double``
- - Platform-defined extended-precision float
-
- * - `np.csingle`
- - ``float complex``
- - Complex number, represented by two single-precision floats (real and imaginary components)
-
- * - `np.cdouble`
- - ``double complex``
- - Complex number, represented by two double-precision floats (real and imaginary components).
-
- * - `np.clongdouble`
- - ``long double complex``
- - Complex number, represented by two extended-precision floats (real and imaginary components).
-
-
-Since many of these have platform-dependent definitions, a set of fixed-size
-aliases are provided:
-
-.. list-table::
- :header-rows: 1
-
- * - Numpy type
- - C type
- - Description
-
- * - `np.int8`
- - ``int8_t``
- - Byte (-128 to 127)
-
- * - `np.int16`
- - ``int16_t``
- - Integer (-32768 to 32767)
-
- * - `np.int32`
- - ``int32_t``
- - Integer (-2147483648 to 2147483647)
-
- * - `np.int64`
- - ``int64_t``
- - Integer (-9223372036854775808 to 9223372036854775807)
-
- * - `np.uint8`
- - ``uint8_t``
- - Unsigned integer (0 to 255)
-
- * - `np.uint16`
- - ``uint16_t``
- - Unsigned integer (0 to 65535)
-
- * - `np.uint32`
- - ``uint32_t``
- - Unsigned integer (0 to 4294967295)
-
- * - `np.uint64`
- - ``uint64_t``
- - Unsigned integer (0 to 18446744073709551615)
-
- * - `np.intp`
- - ``intptr_t``
- - Integer used for indexing, typically the same as ``ssize_t``
-
- * - `np.uintp`
- - ``uintptr_t``
- - Integer large enough to hold a pointer
-
- * - `np.float32`
- - ``float``
- -
-
- * - `np.float64` / `np.float_`
- - ``double``
- - Note that this matches the precision of the builtin python `float`.
-
- * - `np.complex64`
- - ``float complex``
- - Complex number, represented by two 32-bit floats (real and imaginary components)
-
- * - `np.complex128` / `np.complex_`
- - ``double complex``
- - Note that this matches the precision of the builtin python `complex`.
-
-
-NumPy numerical types are instances of ``dtype`` (data-type) objects, each
-having unique characteristics. Once you have imported NumPy using
-
- ::
-
- >>> import numpy as np
-
-the dtypes are available as ``np.bool_``, ``np.float32``, etc.
-
-Advanced types, not listed in the table above, are explored in
-section :ref:`structured_arrays`.
-
-There are 5 basic numerical types representing booleans (bool), integers (int),
-unsigned integers (uint) floating point (float) and complex. Those with numbers
-in their name indicate the bitsize of the type (i.e. how many bits are needed
-to represent a single value in memory). Some types, such as ``int`` and
-``intp``, have differing bitsizes, dependent on the platforms (e.g. 32-bit
-vs. 64-bit machines). This should be taken into account when interfacing
-with low-level code (such as C or Fortran) where the raw memory is addressed.
-
-Data-types can be used as functions to convert python numbers to array scalars
-(see the array scalar section for an explanation), python sequences of numbers
-to arrays of that type, or as arguments to the dtype keyword that many numpy
-functions or methods accept. Some examples::
-
- >>> import numpy as np
- >>> x = np.float32(1.0)
- >>> x
- 1.0
- >>> y = np.int_([1,2,4])
- >>> y
- array([1, 2, 4])
- >>> z = np.arange(3, dtype=np.uint8)
- >>> z
- array([0, 1, 2], dtype=uint8)
-
-Array types can also be referred to by character codes, mostly to retain
-backward compatibility with older packages such as Numeric. Some
-documentation may still refer to these, for example::
-
- >>> np.array([1, 2, 3], dtype='f')
- array([ 1., 2., 3.], dtype=float32)
-
-We recommend using dtype objects instead.
-
-To convert the type of an array, use the .astype() method (preferred) or
-the type itself as a function. For example: ::
-
- >>> z.astype(float) #doctest: +NORMALIZE_WHITESPACE
- array([ 0., 1., 2.])
- >>> np.int8(z)
- array([0, 1, 2], dtype=int8)
-
-Note that, above, we use the *Python* float object as a dtype. NumPy knows
-that ``int`` refers to ``np.int_``, ``bool`` means ``np.bool_``,
-that ``float`` is ``np.float_`` and ``complex`` is ``np.complex_``.
-The other data-types do not have Python equivalents.
-
-To determine the type of an array, look at the dtype attribute::
-
- >>> z.dtype
- dtype('uint8')
-
-dtype objects also contain information about the type, such as its bit-width
-and its byte-order. The data type can also be used indirectly to query
-properties of the type, such as whether it is an integer::
-
- >>> d = np.dtype(int)
- >>> d
- dtype('int32')
-
- >>> np.issubdtype(d, np.integer)
- True
-
- >>> np.issubdtype(d, np.floating)
- False
-
-
-Array Scalars
-=============
-
-NumPy generally returns elements of arrays as array scalars (a scalar
-with an associated dtype). Array scalars differ from Python scalars, but
-for the most part they can be used interchangeably (the primary
-exception is for versions of Python older than v2.x, where integer array
-scalars cannot act as indices for lists and tuples). There are some
-exceptions, such as when code requires very specific attributes of a scalar
-or when it checks specifically whether a value is a Python scalar. Generally,
-problems are easily fixed by explicitly converting array scalars
-to Python scalars, using the corresponding Python type function
-(e.g., ``int``, ``float``, ``complex``, ``str``, ``unicode``).
-
-The primary advantage of using array scalars is that
-they preserve the array type (Python may not have a matching scalar type
-available, e.g. ``int16``). Therefore, the use of array scalars ensures
-identical behaviour between arrays and scalars, irrespective of whether the
-value is inside an array or not. NumPy scalars also have many of the same
-methods arrays do.
-
-Overflow Errors
-===============
-
-The fixed size of NumPy numeric types may cause overflow errors when a value
-requires more memory than available in the data type. For example,
-`numpy.power` evaluates ``100 * 10 ** 8`` correctly for 64-bit integers,
-but gives 1874919424 (incorrect) for a 32-bit integer.
-
- >>> np.power(100, 8, dtype=np.int64)
- 10000000000000000
- >>> np.power(100, 8, dtype=np.int32)
- 1874919424
-
-The behaviour of NumPy and Python integer types differs significantly for
-integer overflows and may confuse users expecting NumPy integers to behave
-similar to Python's ``int``. Unlike NumPy, the size of Python's ``int`` is
-flexible. This means Python integers may expand to accommodate any integer and
-will not overflow.
-
-NumPy provides `numpy.iinfo` and `numpy.finfo` to verify the
-minimum or maximum values of NumPy integer and floating point values
-respectively ::
-
- >>> np.iinfo(int) # Bounds of the default integer on this system.
- iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)
- >>> np.iinfo(np.int32) # Bounds of a 32-bit integer
- iinfo(min=-2147483648, max=2147483647, dtype=int32)
- >>> np.iinfo(np.int64) # Bounds of a 64-bit integer
- iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)
-
-If 64-bit integers are still too small the result may be cast to a
-floating point number. Floating point numbers offer a larger, but inexact,
-range of possible values.
-
- >>> np.power(100, 100, dtype=np.int64) # Incorrect even with 64-bit int
- 0
- >>> np.power(100, 100, dtype=np.float64)
- 1e+200
-
-Extended Precision
-==================
-
-Python's floating-point numbers are usually 64-bit floating-point numbers,
-nearly equivalent to ``np.float64``. In some unusual situations it may be
-useful to use floating-point numbers with more precision. Whether this
-is possible in numpy depends on the hardware and on the development
-environment: specifically, x86 machines provide hardware floating-point
-with 80-bit precision, and while most C compilers provide this as their
-``long double`` type, MSVC (standard for Windows builds) makes
-``long double`` identical to ``double`` (64 bits). NumPy makes the
-compiler's ``long double`` available as ``np.longdouble`` (and
-``np.clongdouble`` for the complex numbers). You can find out what your
-numpy provides with ``np.finfo(np.longdouble)``.
-
-NumPy does not provide a dtype with more precision than C's
-``long double``\\; in particular, the 128-bit IEEE quad precision
-data type (FORTRAN's ``REAL*16``\\) is not available.
-
-For efficient memory alignment, ``np.longdouble`` is usually stored
-padded with zero bits, either to 96 or 128 bits. Which is more efficient
-depends on hardware and development environment; typically on 32-bit
-systems they are padded to 96 bits, while on 64-bit systems they are
-typically padded to 128 bits. ``np.longdouble`` is padded to the system
-default; ``np.float96`` and ``np.float128`` are provided for users who
-want specific padding. In spite of the names, ``np.float96`` and
-``np.float128`` provide only as much precision as ``np.longdouble``,
-that is, 80 bits on most x86 machines and 64 bits in standard
-Windows builds.
-
-Be warned that even if ``np.longdouble`` offers more precision than
-python ``float``, it is easy to lose that extra precision, since
-python often forces values to pass through ``float``. For example,
-the ``%`` formatting operator requires its arguments to be converted
-to standard python types, and it is therefore impossible to preserve
-extended precision even if many decimal places are requested. It can
-be useful to test your code with the value
-``1 + np.finfo(np.longdouble).eps``.
-
-"""
+++ /dev/null
-"""
-========================
-Broadcasting over arrays
-========================
-
-.. note::
- See `this article
- <https://numpy.org/devdocs/user/theory.broadcasting.html>`_
- for illustrations of broadcasting concepts.
-
-
-The term broadcasting describes how numpy treats arrays with different
-shapes during arithmetic operations. Subject to certain constraints,
-the smaller array is "broadcast" across the larger array so that they
-have compatible shapes. Broadcasting provides a means of vectorizing
-array operations so that looping occurs in C instead of Python. It does
-this without making needless copies of data and usually leads to
-efficient algorithm implementations. There are, however, cases where
-broadcasting is a bad idea because it leads to inefficient use of memory
-that slows computation.
-
-NumPy operations are usually done on pairs of arrays on an
-element-by-element basis. In the simplest case, the two arrays must
-have exactly the same shape, as in the following example:
-
- >>> a = np.array([1.0, 2.0, 3.0])
- >>> b = np.array([2.0, 2.0, 2.0])
- >>> a * b
- array([ 2., 4., 6.])
-
-NumPy's broadcasting rule relaxes this constraint when the arrays'
-shapes meet certain constraints. The simplest broadcasting example occurs
-when an array and a scalar value are combined in an operation:
-
->>> a = np.array([1.0, 2.0, 3.0])
->>> b = 2.0
->>> a * b
-array([ 2., 4., 6.])
-
-The result is equivalent to the previous example where ``b`` was an array.
-We can think of the scalar ``b`` being *stretched* during the arithmetic
-operation into an array with the same shape as ``a``. The new elements in
-``b`` are simply copies of the original scalar. The stretching analogy is
-only conceptual. NumPy is smart enough to use the original scalar value
-without actually making copies so that broadcasting operations are as
-memory and computationally efficient as possible.
-
-The code in the second example is more efficient than that in the first
-because broadcasting moves less memory around during the multiplication
-(``b`` is a scalar rather than an array).
-
-General Broadcasting Rules
-==========================
-When operating on two arrays, NumPy compares their shapes element-wise.
-It starts with the trailing dimensions and works its way forward. Two
-dimensions are compatible when
-
-1) they are equal, or
-2) one of them is 1
-
-If these conditions are not met, a
-``ValueError: operands could not be broadcast together`` exception is
-thrown, indicating that the arrays have incompatible shapes. The size of
-the resulting array is the size that is not 1 along each axis of the inputs.
-
-Arrays do not need to have the same *number* of dimensions. For example,
-if you have a ``256x256x3`` array of RGB values, and you want to scale
-each color in the image by a different value, you can multiply the image
-by a one-dimensional array with 3 values. Lining up the sizes of the
-trailing axes of these arrays according to the broadcast rules, shows that
-they are compatible::
-
- Image (3d array): 256 x 256 x 3
- Scale (1d array): 3
- Result (3d array): 256 x 256 x 3
-
-When either of the dimensions compared is one, the other is
-used. In other words, dimensions with size 1 are stretched or "copied"
-to match the other.
-
-In the following example, both the ``A`` and ``B`` arrays have axes with
-length one that are expanded to a larger size during the broadcast
-operation::
-
- A (4d array): 8 x 1 x 6 x 1
- B (3d array): 7 x 1 x 5
- Result (4d array): 8 x 7 x 6 x 5
-
-Here are some more examples::
-
- A (2d array): 5 x 4
- B (1d array): 1
- Result (2d array): 5 x 4
-
- A (2d array): 5 x 4
- B (1d array): 4
- Result (2d array): 5 x 4
-
- A (3d array): 15 x 3 x 5
- B (3d array): 15 x 1 x 5
- Result (3d array): 15 x 3 x 5
-
- A (3d array): 15 x 3 x 5
- B (2d array): 3 x 5
- Result (3d array): 15 x 3 x 5
-
- A (3d array): 15 x 3 x 5
- B (2d array): 3 x 1
- Result (3d array): 15 x 3 x 5
-
-Here are examples of shapes that do not broadcast::
-
- A (1d array): 3
- B (1d array): 4 # trailing dimensions do not match
-
- A (2d array): 2 x 1
- B (3d array): 8 x 4 x 3 # second from last dimensions mismatched
-
-An example of broadcasting in practice::
-
- >>> x = np.arange(4)
- >>> xx = x.reshape(4,1)
- >>> y = np.ones(5)
- >>> z = np.ones((3,4))
-
- >>> x.shape
- (4,)
-
- >>> y.shape
- (5,)
-
- >>> x + y
- ValueError: operands could not be broadcast together with shapes (4,) (5,)
-
- >>> xx.shape
- (4, 1)
-
- >>> y.shape
- (5,)
-
- >>> (xx + y).shape
- (4, 5)
-
- >>> xx + y
- array([[ 1., 1., 1., 1., 1.],
- [ 2., 2., 2., 2., 2.],
- [ 3., 3., 3., 3., 3.],
- [ 4., 4., 4., 4., 4.]])
-
- >>> x.shape
- (4,)
-
- >>> z.shape
- (3, 4)
-
- >>> (x + z).shape
- (3, 4)
-
- >>> x + z
- array([[ 1., 2., 3., 4.],
- [ 1., 2., 3., 4.],
- [ 1., 2., 3., 4.]])
-
-Broadcasting provides a convenient way of taking the outer product (or
-any other outer operation) of two arrays. The following example shows an
-outer addition operation of two 1-d arrays::
-
- >>> a = np.array([0.0, 10.0, 20.0, 30.0])
- >>> b = np.array([1.0, 2.0, 3.0])
- >>> a[:, np.newaxis] + b
- array([[ 1., 2., 3.],
- [ 11., 12., 13.],
- [ 21., 22., 23.],
- [ 31., 32., 33.]])
-
-Here the ``newaxis`` index operator inserts a new axis into ``a``,
-making it a two-dimensional ``4x1`` array. Combining the ``4x1`` array
-with ``b``, which has shape ``(3,)``, yields a ``4x3`` array.
-
-"""
+++ /dev/null
-"""
-
-=============================
- Byteswapping and byte order
-=============================
-
-Introduction to byte ordering and ndarrays
-==========================================
-
-The ``ndarray`` is an object that provide a python array interface to data
-in memory.
-
-It often happens that the memory that you want to view with an array is
-not of the same byte ordering as the computer on which you are running
-Python.
-
-For example, I might be working on a computer with a little-endian CPU -
-such as an Intel Pentium, but I have loaded some data from a file
-written by a computer that is big-endian. Let's say I have loaded 4
-bytes from a file written by a Sun (big-endian) computer. I know that
-these 4 bytes represent two 16-bit integers. On a big-endian machine, a
-two-byte integer is stored with the Most Significant Byte (MSB) first,
-and then the Least Significant Byte (LSB). Thus the bytes are, in memory order:
-
-#. MSB integer 1
-#. LSB integer 1
-#. MSB integer 2
-#. LSB integer 2
-
-Let's say the two integers were in fact 1 and 770. Because 770 = 256 *
-3 + 2, the 4 bytes in memory would contain respectively: 0, 1, 3, 2.
-The bytes I have loaded from the file would have these contents:
-
->>> big_end_buffer = bytearray([0,1,3,2])
->>> big_end_buffer
-bytearray(b'\\x00\\x01\\x03\\x02')
-
-We might want to use an ``ndarray`` to access these integers. In that
-case, we can create an array around this memory, and tell numpy that
-there are two integers, and that they are 16 bit and big-endian:
-
->>> import numpy as np
->>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_buffer)
->>> big_end_arr[0]
-1
->>> big_end_arr[1]
-770
-
-Note the array ``dtype`` above of ``>i2``. The ``>`` means 'big-endian'
-(``<`` is little-endian) and ``i2`` means 'signed 2-byte integer'. For
-example, if our data represented a single unsigned 4-byte little-endian
-integer, the dtype string would be ``<u4``.
-
-In fact, why don't we try that?
-
->>> little_end_u4 = np.ndarray(shape=(1,),dtype='<u4', buffer=big_end_buffer)
->>> little_end_u4[0] == 1 * 256**1 + 3 * 256**2 + 2 * 256**3
-True
-
-Returning to our ``big_end_arr`` - in this case our underlying data is
-big-endian (data endianness) and we've set the dtype to match (the dtype
-is also big-endian). However, sometimes you need to flip these around.
-
-.. warning::
-
- Scalars currently do not include byte order information, so extracting
- a scalar from an array will return an integer in native byte order.
- Hence:
-
- >>> big_end_arr[0].dtype.byteorder == little_end_u4[0].dtype.byteorder
- True
-
-Changing byte ordering
-======================
-
-As you can imagine from the introduction, there are two ways you can
-affect the relationship between the byte ordering of the array and the
-underlying memory it is looking at:
-
-* Change the byte-ordering information in the array dtype so that it
- interprets the underlying data as being in a different byte order.
- This is the role of ``arr.newbyteorder()``
-* Change the byte-ordering of the underlying data, leaving the dtype
- interpretation as it was. This is what ``arr.byteswap()`` does.
-
-The common situations in which you need to change byte ordering are:
-
-#. Your data and dtype endianness don't match, and you want to change
- the dtype so that it matches the data.
-#. Your data and dtype endianness don't match, and you want to swap the
- data so that they match the dtype
-#. Your data and dtype endianness match, but you want the data swapped
- and the dtype to reflect this
-
-Data and dtype endianness don't match, change dtype to match data
------------------------------------------------------------------
-
-We make something where they don't match:
-
->>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='<i2', buffer=big_end_buffer)
->>> wrong_end_dtype_arr[0]
-256
-
-The obvious fix for this situation is to change the dtype so it gives
-the correct endianness:
-
->>> fixed_end_dtype_arr = wrong_end_dtype_arr.newbyteorder()
->>> fixed_end_dtype_arr[0]
-1
-
-Note the array has not changed in memory:
-
->>> fixed_end_dtype_arr.tobytes() == big_end_buffer
-True
-
-Data and type endianness don't match, change data to match dtype
-----------------------------------------------------------------
-
-You might want to do this if you need the data in memory to be a certain
-ordering. For example you might be writing the memory out to a file
-that needs a certain byte ordering.
-
->>> fixed_end_mem_arr = wrong_end_dtype_arr.byteswap()
->>> fixed_end_mem_arr[0]
-1
-
-Now the array *has* changed in memory:
-
->>> fixed_end_mem_arr.tobytes() == big_end_buffer
-False
-
-Data and dtype endianness match, swap data and dtype
-----------------------------------------------------
-
-You may have a correctly specified array dtype, but you need the array
-to have the opposite byte order in memory, and you want the dtype to
-match so the array values make sense. In this case you just do both of
-the previous operations:
-
->>> swapped_end_arr = big_end_arr.byteswap().newbyteorder()
->>> swapped_end_arr[0]
-1
->>> swapped_end_arr.tobytes() == big_end_buffer
-False
-
-An easier way of casting the data to a specific dtype and byte ordering
-can be achieved with the ndarray astype method:
-
->>> swapped_end_arr = big_end_arr.astype('<i2')
->>> swapped_end_arr[0]
-1
->>> swapped_end_arr.tobytes() == big_end_buffer
-False
-
-"""
"""
A convenient alias for None, useful for indexing arrays.
- See Also
- --------
- `numpy.doc.indexing`
-
Examples
--------
>>> newaxis is None
+++ /dev/null
-"""
-==============
-Array Creation
-==============
-
-Introduction
-============
-
-There are 5 general mechanisms for creating arrays:
-
-1) Conversion from other Python structures (e.g., lists, tuples)
-2) Intrinsic numpy array creation objects (e.g., arange, ones, zeros,
- etc.)
-3) Reading arrays from disk, either from standard or custom formats
-4) Creating arrays from raw bytes through the use of strings or buffers
-5) Use of special library functions (e.g., random)
-
-This section will not cover means of replicating, joining, or otherwise
-expanding or mutating existing arrays. Nor will it cover creating object
-arrays or structured arrays. Both of those are covered in their own sections.
-
-Converting Python array_like Objects to NumPy Arrays
-====================================================
-
-In general, numerical data arranged in an array-like structure in Python can
-be converted to arrays through the use of the array() function. The most
-obvious examples are lists and tuples. See the documentation for array() for
-details for its use. Some objects may support the array-protocol and allow
-conversion to arrays this way. A simple way to find out if the object can be
-converted to a numpy array using array() is simply to try it interactively and
-see if it works! (The Python Way).
-
-Examples: ::
-
- >>> x = np.array([2,3,1,0])
- >>> x = np.array([2, 3, 1, 0])
- >>> x = np.array([[1,2.0],[0,0],(1+1j,3.)]) # note mix of tuple and lists,
- and types
- >>> x = np.array([[ 1.+0.j, 2.+0.j], [ 0.+0.j, 0.+0.j], [ 1.+1.j, 3.+0.j]])
-
-Intrinsic NumPy Array Creation
-==============================
-
-NumPy has built-in functions for creating arrays from scratch:
-
-zeros(shape) will create an array filled with 0 values with the specified
-shape. The default dtype is float64. ::
-
- >>> np.zeros((2, 3))
- array([[ 0., 0., 0.], [ 0., 0., 0.]])
-
-ones(shape) will create an array filled with 1 values. It is identical to
-zeros in all other respects.
-
-arange() will create arrays with regularly incrementing values. Check the
-docstring for complete information on the various ways it can be used. A few
-examples will be given here: ::
-
- >>> np.arange(10)
- array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
- >>> np.arange(2, 10, dtype=float)
- array([ 2., 3., 4., 5., 6., 7., 8., 9.])
- >>> np.arange(2, 3, 0.1)
- array([ 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9])
-
-Note that there are some subtleties regarding the last usage that the user
-should be aware of that are described in the arange docstring.
-
-linspace() will create arrays with a specified number of elements, and
-spaced equally between the specified beginning and end values. For
-example: ::
-
- >>> np.linspace(1., 4., 6)
- array([ 1. , 1.6, 2.2, 2.8, 3.4, 4. ])
-
-The advantage of this creation function is that one can guarantee the
-number of elements and the starting and end point, which arange()
-generally will not do for arbitrary start, stop, and step values.
-
-indices() will create a set of arrays (stacked as a one-higher dimensioned
-array), one per dimension with each representing variation in that dimension.
-An example illustrates much better than a verbal description: ::
-
- >>> np.indices((3,3))
- array([[[0, 0, 0], [1, 1, 1], [2, 2, 2]], [[0, 1, 2], [0, 1, 2], [0, 1, 2]]])
-
-This is particularly useful for evaluating functions of multiple dimensions on
-a regular grid.
-
-Reading Arrays From Disk
-========================
-
-This is presumably the most common case of large array creation. The details,
-of course, depend greatly on the format of data on disk and so this section
-can only give general pointers on how to handle various formats.
-
-Standard Binary Formats
------------------------
-
-Various fields have standard formats for array data. The following lists the
-ones with known python libraries to read them and return numpy arrays (there
-may be others for which it is possible to read and convert to numpy arrays so
-check the last section as well)
-::
-
- HDF5: h5py
- FITS: Astropy
-
-Examples of formats that cannot be read directly but for which it is not hard to
-convert are those formats supported by libraries like PIL (able to read and
-write many image formats such as jpg, png, etc).
-
-Common ASCII Formats
-------------------------
-
-Comma Separated Value files (CSV) are widely used (and an export and import
-option for programs like Excel). There are a number of ways of reading these
-files in Python. There are CSV functions in Python and functions in pylab
-(part of matplotlib).
-
-More generic ascii files can be read using the io package in scipy.
-
-Custom Binary Formats
----------------------
-
-There are a variety of approaches one can use. If the file has a relatively
-simple format then one can write a simple I/O library and use the numpy
-fromfile() function and .tofile() method to read and write numpy arrays
-directly (mind your byteorder though!) If a good C or C++ library exists that
-read the data, one can wrap that library with a variety of techniques though
-that certainly is much more work and requires significantly more advanced
-knowledge to interface with C or C++.
-
-Use of Special Libraries
-------------------------
-
-There are libraries that can be used to generate arrays for special purposes
-and it isn't possible to enumerate all of them. The most common uses are use
-of the many array generation functions in random that can generate arrays of
-random values, and some utility functions to generate special matrices (e.g.
-diagonal).
-
-"""
+++ /dev/null
-""".. _dispatch_mechanism:
-
-Numpy's dispatch mechanism, introduced in numpy version v1.16 is the
-recommended approach for writing custom N-dimensional array containers that are
-compatible with the numpy API and provide custom implementations of numpy
-functionality. Applications include `dask <http://dask.pydata.org>`_ arrays, an
-N-dimensional array distributed across multiple nodes, and `cupy
-<https://docs-cupy.chainer.org/en/stable/>`_ arrays, an N-dimensional array on
-a GPU.
-
-To get a feel for writing custom array containers, we'll begin with a simple
-example that has rather narrow utility but illustrates the concepts involved.
-
->>> import numpy as np
->>> class DiagonalArray:
-... def __init__(self, N, value):
-... self._N = N
-... self._i = value
-... def __repr__(self):
-... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
-... def __array__(self):
-... return self._i * np.eye(self._N)
-...
-
-Our custom array can be instantiated like:
-
->>> arr = DiagonalArray(5, 1)
->>> arr
-DiagonalArray(N=5, value=1)
-
-We can convert to a numpy array using :func:`numpy.array` or
-:func:`numpy.asarray`, which will call its ``__array__`` method to obtain a
-standard ``numpy.ndarray``.
-
->>> np.asarray(arr)
-array([[1., 0., 0., 0., 0.],
- [0., 1., 0., 0., 0.],
- [0., 0., 1., 0., 0.],
- [0., 0., 0., 1., 0.],
- [0., 0., 0., 0., 1.]])
-
-If we operate on ``arr`` with a numpy function, numpy will again use the
-``__array__`` interface to convert it to an array and then apply the function
-in the usual way.
-
->>> np.multiply(arr, 2)
-array([[2., 0., 0., 0., 0.],
- [0., 2., 0., 0., 0.],
- [0., 0., 2., 0., 0.],
- [0., 0., 0., 2., 0.],
- [0., 0., 0., 0., 2.]])
-
-
-Notice that the return type is a standard ``numpy.ndarray``.
-
->>> type(arr)
-numpy.ndarray
-
-How can we pass our custom array type through this function? Numpy allows a
-class to indicate that it would like to handle computations in a custom-defined
-way through the interfaces ``__array_ufunc__`` and ``__array_function__``. Let's
-take one at a time, starting with ``_array_ufunc__``. This method covers
-:ref:`ufuncs`, a class of functions that includes, for example,
-:func:`numpy.multiply` and :func:`numpy.sin`.
-
-The ``__array_ufunc__`` receives:
-
-- ``ufunc``, a function like ``numpy.multiply``
-- ``method``, a string, differentiating between ``numpy.multiply(...)`` and
- variants like ``numpy.multiply.outer``, ``numpy.multiply.accumulate``, and so
- on. For the common case, ``numpy.multiply(...)``, ``method == '__call__'``.
-- ``inputs``, which could be a mixture of different types
-- ``kwargs``, keyword arguments passed to the function
-
-For this example we will only handle the method ``__call__``.
-
->>> from numbers import Number
->>> class DiagonalArray:
-... def __init__(self, N, value):
-... self._N = N
-... self._i = value
-... def __repr__(self):
-... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
-... def __array__(self):
-... return self._i * np.eye(self._N)
-... def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
-... if method == '__call__':
-... N = None
-... scalars = []
-... for input in inputs:
-... if isinstance(input, Number):
-... scalars.append(input)
-... elif isinstance(input, self.__class__):
-... scalars.append(input._i)
-... if N is not None:
-... if N != self._N:
-... raise TypeError("inconsistent sizes")
-... else:
-... N = self._N
-... else:
-... return NotImplemented
-... return self.__class__(N, ufunc(*scalars, **kwargs))
-... else:
-... return NotImplemented
-...
-
-Now our custom array type passes through numpy functions.
-
->>> arr = DiagonalArray(5, 1)
->>> np.multiply(arr, 3)
-DiagonalArray(N=5, value=3)
->>> np.add(arr, 3)
-DiagonalArray(N=5, value=4)
->>> np.sin(arr)
-DiagonalArray(N=5, value=0.8414709848078965)
-
-At this point ``arr + 3`` does not work.
-
->>> arr + 3
-TypeError: unsupported operand type(s) for *: 'DiagonalArray' and 'int'
-
-To support it, we need to define the Python interfaces ``__add__``, ``__lt__``,
-and so on to dispatch to the corresponding ufunc. We can achieve this
-conveniently by inheriting from the mixin
-:class:`~numpy.lib.mixins.NDArrayOperatorsMixin`.
-
->>> import numpy.lib.mixins
->>> class DiagonalArray(numpy.lib.mixins.NDArrayOperatorsMixin):
-... def __init__(self, N, value):
-... self._N = N
-... self._i = value
-... def __repr__(self):
-... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
-... def __array__(self):
-... return self._i * np.eye(self._N)
-... def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
-... if method == '__call__':
-... N = None
-... scalars = []
-... for input in inputs:
-... if isinstance(input, Number):
-... scalars.append(input)
-... elif isinstance(input, self.__class__):
-... scalars.append(input._i)
-... if N is not None:
-... if N != self._N:
-... raise TypeError("inconsistent sizes")
-... else:
-... N = self._N
-... else:
-... return NotImplemented
-... return self.__class__(N, ufunc(*scalars, **kwargs))
-... else:
-... return NotImplemented
-...
-
->>> arr = DiagonalArray(5, 1)
->>> arr + 3
-DiagonalArray(N=5, value=4)
->>> arr > 0
-DiagonalArray(N=5, value=True)
-
-Now let's tackle ``__array_function__``. We'll create dict that maps numpy
-functions to our custom variants.
-
->>> HANDLED_FUNCTIONS = {}
->>> class DiagonalArray(numpy.lib.mixins.NDArrayOperatorsMixin):
-... def __init__(self, N, value):
-... self._N = N
-... self._i = value
-... def __repr__(self):
-... return f"{self.__class__.__name__}(N={self._N}, value={self._i})"
-... def __array__(self):
-... return self._i * np.eye(self._N)
-... def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
-... if method == '__call__':
-... N = None
-... scalars = []
-... for input in inputs:
-... # In this case we accept only scalar numbers or DiagonalArrays.
-... if isinstance(input, Number):
-... scalars.append(input)
-... elif isinstance(input, self.__class__):
-... scalars.append(input._i)
-... if N is not None:
-... if N != self._N:
-... raise TypeError("inconsistent sizes")
-... else:
-... N = self._N
-... else:
-... return NotImplemented
-... return self.__class__(N, ufunc(*scalars, **kwargs))
-... else:
-... return NotImplemented
-... def __array_function__(self, func, types, args, kwargs):
-... if func not in HANDLED_FUNCTIONS:
-... return NotImplemented
-... # Note: this allows subclasses that don't override
-... # __array_function__ to handle DiagonalArray objects.
-... if not all(issubclass(t, self.__class__) for t in types):
-... return NotImplemented
-... return HANDLED_FUNCTIONS[func](*args, **kwargs)
-...
-
-A convenient pattern is to define a decorator ``implements`` that can be used
-to add functions to ``HANDLED_FUNCTIONS``.
-
->>> def implements(np_function):
-... "Register an __array_function__ implementation for DiagonalArray objects."
-... def decorator(func):
-... HANDLED_FUNCTIONS[np_function] = func
-... return func
-... return decorator
-...
-
-Now we write implementations of numpy functions for ``DiagonalArray``.
-For completeness, to support the usage ``arr.sum()`` add a method ``sum`` that
-calls ``numpy.sum(self)``, and the same for ``mean``.
-
->>> @implements(np.sum)
-... def sum(arr):
-... "Implementation of np.sum for DiagonalArray objects"
-... return arr._i * arr._N
-...
->>> @implements(np.mean)
-... def mean(arr):
-... "Implementation of np.mean for DiagonalArray objects"
-... return arr._i / arr._N
-...
->>> arr = DiagonalArray(5, 1)
->>> np.sum(arr)
-5
->>> np.mean(arr)
-0.2
-
-If the user tries to use any numpy functions not included in
-``HANDLED_FUNCTIONS``, a ``TypeError`` will be raised by numpy, indicating that
-this operation is not supported. For example, concatenating two
-``DiagonalArrays`` does not produce another diagonal array, so it is not
-supported.
-
->>> np.concatenate([arr, arr])
-TypeError: no implementation found for 'numpy.concatenate' on types that implement __array_function__: [<class '__main__.DiagonalArray'>]
-
-Additionally, our implementations of ``sum`` and ``mean`` do not accept the
-optional arguments that numpy's implementation does.
-
->>> np.sum(arr, axis=0)
-TypeError: sum() got an unexpected keyword argument 'axis'
-
-The user always has the option of converting to a normal ``numpy.ndarray`` with
-:func:`numpy.asarray` and using standard numpy from there.
-
->>> np.concatenate([np.asarray(arr), np.asarray(arr)])
-array([[1., 0., 0., 0., 0.],
- [0., 1., 0., 0., 0.],
- [0., 0., 1., 0., 0.],
- [0., 0., 0., 1., 0.],
- [0., 0., 0., 0., 1.],
- [1., 0., 0., 0., 0.],
- [0., 1., 0., 0., 0.],
- [0., 0., 1., 0., 0.],
- [0., 0., 0., 1., 0.],
- [0., 0., 0., 0., 1.]])
-
-Refer to the `dask source code <https://github.com/dask/dask>`_ and
-`cupy source code <https://github.com/cupy/cupy>`_ for more fully-worked
-examples of custom array containers.
-
-See also `NEP 18 <http://www.numpy.org/neps/nep-0018-array-function-protocol.html>`_.
-"""
+++ /dev/null
-"""
-========
-Glossary
-========
-
-.. glossary::
-
- along an axis
- Axes are defined for arrays with more than one dimension. A
- 2-dimensional array has two corresponding axes: the first running
- vertically downwards across rows (axis 0), and the second running
- horizontally across columns (axis 1).
-
- Many operations can take place along one of these axes. For example,
- we can sum each row of an array, in which case we operate along
- columns, or axis 1::
-
- >>> x = np.arange(12).reshape((3,4))
-
- >>> x
- array([[ 0, 1, 2, 3],
- [ 4, 5, 6, 7],
- [ 8, 9, 10, 11]])
-
- >>> x.sum(axis=1)
- array([ 6, 22, 38])
-
- array
- A homogeneous container of numerical elements. Each element in the
- array occupies a fixed amount of memory (hence homogeneous), and
- can be a numerical element of a single type (such as float, int
- or complex) or a combination (such as ``(float, int, float)``). Each
- array has an associated data-type (or ``dtype``), which describes
- the numerical type of its elements::
-
- >>> x = np.array([1, 2, 3], float)
-
- >>> x
- array([ 1., 2., 3.])
-
- >>> x.dtype # floating point number, 64 bits of memory per element
- dtype('float64')
-
-
- # More complicated data type: each array element is a combination of
- # and integer and a floating point number
- >>> np.array([(1, 2.0), (3, 4.0)], dtype=[('x', int), ('y', float)])
- array([(1, 2.0), (3, 4.0)],
- dtype=[('x', '<i4'), ('y', '<f8')])
-
- Fast element-wise operations, called a :term:`ufunc`, operate on arrays.
-
- array_like
- Any sequence that can be interpreted as an ndarray. This includes
- nested lists, tuples, scalars and existing arrays.
-
- attribute
- A property of an object that can be accessed using ``obj.attribute``,
- e.g., ``shape`` is an attribute of an array::
-
- >>> x = np.array([1, 2, 3])
- >>> x.shape
- (3,)
-
- big-endian
- When storing a multi-byte value in memory as a sequence of bytes, the
- sequence addresses/sends/stores the most significant byte first (lowest
- address) and the least significant byte last (highest address). Common in
- micro-processors and used for transmission of data over network protocols.
-
- BLAS
- `Basic Linear Algebra Subprograms <https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms>`_
-
- broadcast
- NumPy can do operations on arrays whose shapes are mismatched::
-
- >>> x = np.array([1, 2])
- >>> y = np.array([[3], [4]])
-
- >>> x
- array([1, 2])
-
- >>> y
- array([[3],
- [4]])
-
- >>> x + y
- array([[4, 5],
- [5, 6]])
-
- See `numpy.doc.broadcasting` for more information.
-
- C order
- See `row-major`
-
- column-major
- A way to represent items in a N-dimensional array in the 1-dimensional
- computer memory. In column-major order, the leftmost index "varies the
- fastest": for example the array::
-
- [[1, 2, 3],
- [4, 5, 6]]
-
- is represented in the column-major order as::
-
- [1, 4, 2, 5, 3, 6]
-
- Column-major order is also known as the Fortran order, as the Fortran
- programming language uses it.
-
- decorator
- An operator that transforms a function. For example, a ``log``
- decorator may be defined to print debugging information upon
- function execution::
-
- >>> def log(f):
- ... def new_logging_func(*args, **kwargs):
- ... print("Logging call with parameters:", args, kwargs)
- ... return f(*args, **kwargs)
- ...
- ... return new_logging_func
-
- Now, when we define a function, we can "decorate" it using ``log``::
-
- >>> @log
- ... def add(a, b):
- ... return a + b
-
- Calling ``add`` then yields:
-
- >>> add(1, 2)
- Logging call with parameters: (1, 2) {}
- 3
-
- dictionary
- Resembling a language dictionary, which provides a mapping between
- words and descriptions thereof, a Python dictionary is a mapping
- between two objects::
-
- >>> x = {1: 'one', 'two': [1, 2]}
-
- Here, `x` is a dictionary mapping keys to values, in this case
- the integer 1 to the string "one", and the string "two" to
- the list ``[1, 2]``. The values may be accessed using their
- corresponding keys::
-
- >>> x[1]
- 'one'
-
- >>> x['two']
- [1, 2]
-
- Note that dictionaries are not stored in any specific order. Also,
- most mutable (see *immutable* below) objects, such as lists, may not
- be used as keys.
-
- For more information on dictionaries, read the
- `Python tutorial <https://docs.python.org/tutorial/>`_.
-
- field
- In a :term:`structured data type`, each sub-type is called a `field`.
- The `field` has a name (a string), a type (any valid dtype), and
- an optional `title`. See :ref:`arrays.dtypes`
-
- Fortran order
- See `column-major`
-
- flattened
- Collapsed to a one-dimensional array. See `numpy.ndarray.flatten`
- for details.
-
- homogenous
- Describes a block of memory comprised of blocks, each block comprised of
- items and of the same size, and blocks are interpreted in exactly the
- same way. In the simplest case each block contains a single item, for
- instance int32 or float64.
-
- immutable
- An object that cannot be modified after execution is called
- immutable. Two common examples are strings and tuples.
-
- instance
- A class definition gives the blueprint for constructing an object::
-
- >>> class House:
- ... wall_colour = 'white'
-
- Yet, we have to *build* a house before it exists::
-
- >>> h = House() # build a house
-
- Now, ``h`` is called a ``House`` instance. An instance is therefore
- a specific realisation of a class.
-
- iterable
- A sequence that allows "walking" (iterating) over items, typically
- using a loop such as::
-
- >>> x = [1, 2, 3]
- >>> [item**2 for item in x]
- [1, 4, 9]
-
- It is often used in combination with ``enumerate``::
- >>> keys = ['a','b','c']
- >>> for n, k in enumerate(keys):
- ... print("Key %d: %s" % (n, k))
- ...
- Key 0: a
- Key 1: b
- Key 2: c
-
- itemsize
- The size of the dtype element in bytes.
-
- list
- A Python container that can hold any number of objects or items.
- The items do not have to be of the same type, and can even be
- lists themselves::
-
- >>> x = [2, 2.0, "two", [2, 2.0]]
-
- The list `x` contains 4 items, each which can be accessed individually::
-
- >>> x[2] # the string 'two'
- 'two'
-
- >>> x[3] # a list, containing an integer 2 and a float 2.0
- [2, 2.0]
-
- It is also possible to select more than one item at a time,
- using *slicing*::
-
- >>> x[0:2] # or, equivalently, x[:2]
- [2, 2.0]
-
- In code, arrays are often conveniently expressed as nested lists::
-
-
- >>> np.array([[1, 2], [3, 4]])
- array([[1, 2],
- [3, 4]])
-
- For more information, read the section on lists in the `Python
- tutorial <https://docs.python.org/tutorial/>`_. For a mapping
- type (key-value), see *dictionary*.
-
- little-endian
- When storing a multi-byte value in memory as a sequence of bytes, the
- sequence addresses/sends/stores the least significant byte first (lowest
- address) and the most significant byte last (highest address). Common in
- x86 processors.
-
- mask
- A boolean array, used to select only certain elements for an operation::
-
- >>> x = np.arange(5)
- >>> x
- array([0, 1, 2, 3, 4])
-
- >>> mask = (x > 2)
- >>> mask
- array([False, False, False, True, True])
-
- >>> x[mask] = -1
- >>> x
- array([ 0, 1, 2, -1, -1])
-
- masked array
- Array that suppressed values indicated by a mask::
-
- >>> x = np.ma.masked_array([np.nan, 2, np.nan], [True, False, True])
- >>> x
- masked_array(data = [-- 2.0 --],
- mask = [ True False True],
- fill_value = 1e+20)
-
- >>> x + [1, 2, 3]
- masked_array(data = [-- 4.0 --],
- mask = [ True False True],
- fill_value = 1e+20)
-
-
- Masked arrays are often used when operating on arrays containing
- missing or invalid entries.
-
- matrix
- A 2-dimensional ndarray that preserves its two-dimensional nature
- throughout operations. It has certain special operations, such as ``*``
- (matrix multiplication) and ``**`` (matrix power), defined::
-
- >>> x = np.mat([[1, 2], [3, 4]])
- >>> x
- matrix([[1, 2],
- [3, 4]])
-
- >>> x**2
- matrix([[ 7, 10],
- [15, 22]])
-
- method
- A function associated with an object. For example, each ndarray has a
- method called ``repeat``::
-
- >>> x = np.array([1, 2, 3])
- >>> x.repeat(2)
- array([1, 1, 2, 2, 3, 3])
-
- ndarray
- See *array*.
-
- record array
- An :term:`ndarray` with :term:`structured data type` which has been
- subclassed as ``np.recarray`` and whose dtype is of type ``np.record``,
- making the fields of its data type to be accessible by attribute.
-
- reference
- If ``a`` is a reference to ``b``, then ``(a is b) == True``. Therefore,
- ``a`` and ``b`` are different names for the same Python object.
-
- row-major
- A way to represent items in a N-dimensional array in the 1-dimensional
- computer memory. In row-major order, the rightmost index "varies
- the fastest": for example the array::
-
- [[1, 2, 3],
- [4, 5, 6]]
-
- is represented in the row-major order as::
-
- [1, 2, 3, 4, 5, 6]
-
- Row-major order is also known as the C order, as the C programming
- language uses it. New NumPy arrays are by default in row-major order.
-
- self
- Often seen in method signatures, ``self`` refers to the instance
- of the associated class. For example:
-
- >>> class Paintbrush:
- ... color = 'blue'
- ...
- ... def paint(self):
- ... print("Painting the city %s!" % self.color)
- ...
- >>> p = Paintbrush()
- >>> p.color = 'red'
- >>> p.paint() # self refers to 'p'
- Painting the city red!
-
- slice
- Used to select only certain elements from a sequence:
-
- >>> x = range(5)
- >>> x
- [0, 1, 2, 3, 4]
-
- >>> x[1:3] # slice from 1 to 3 (excluding 3 itself)
- [1, 2]
-
- >>> x[1:5:2] # slice from 1 to 5, but skipping every second element
- [1, 3]
-
- >>> x[::-1] # slice a sequence in reverse
- [4, 3, 2, 1, 0]
-
- Arrays may have more than one dimension, each which can be sliced
- individually:
-
- >>> x = np.array([[1, 2], [3, 4]])
- >>> x
- array([[1, 2],
- [3, 4]])
-
- >>> x[:, 1]
- array([2, 4])
-
- structure
- See :term:`structured data type`
-
- structured data type
- A data type composed of other datatypes
-
- subarray data type
- A :term:`structured data type` may contain a :term:`ndarray` with its
- own dtype and shape:
-
- >>> dt = np.dtype([('a', np.int32), ('b', np.float32, (3,))])
- >>> np.zeros(3, dtype=dt)
- array([(0, [0., 0., 0.]), (0, [0., 0., 0.]), (0, [0., 0., 0.])],
- dtype=[('a', '<i4'), ('b', '<f4', (3,))])
-
- title
- In addition to field names, structured array fields may have an
- associated :ref:`title <titles>` which is an alias to the name and is
- commonly used for plotting.
-
- tuple
- A sequence that may contain a variable number of types of any
- kind. A tuple is immutable, i.e., once constructed it cannot be
- changed. Similar to a list, it can be indexed and sliced::
-
- >>> x = (1, 'one', [1, 2])
- >>> x
- (1, 'one', [1, 2])
-
- >>> x[0]
- 1
-
- >>> x[:2]
- (1, 'one')
-
- A useful concept is "tuple unpacking", which allows variables to
- be assigned to the contents of a tuple::
-
- >>> x, y = (1, 2)
- >>> x, y = 1, 2
-
- This is often used when a function returns multiple values:
-
- >>> def return_many():
- ... return 1, 'alpha', None
-
- >>> a, b, c = return_many()
- >>> a, b, c
- (1, 'alpha', None)
-
- >>> a
- 1
- >>> b
- 'alpha'
-
- ufunc
- Universal function. A fast element-wise, :term:`vectorized
- <vectorization>` array operation. Examples include ``add``, ``sin`` and
- ``logical_or``.
-
- vectorization
- Optimizing a looping block by specialized code. In a traditional sense,
- vectorization performs the same operation on multiple elements with
- fixed strides between them via specialized hardware. Compilers know how
- to take advantage of well-constructed loops to implement such
- optimizations. NumPy uses :ref:`vectorization <whatis-vectorization>`
- to mean any optimization via specialized code performing the same
- operations on multiple elements, typically achieving speedups by
- avoiding some of the overhead in looking up and converting the elements.
-
- view
- An array that does not own its data, but refers to another array's
- data instead. For example, we may create a view that only shows
- every second element of another array::
-
- >>> x = np.arange(5)
- >>> x
- array([0, 1, 2, 3, 4])
-
- >>> y = x[::2]
- >>> y
- array([0, 2, 4])
-
- >>> x[0] = 3 # changing x changes y as well, since y is a view on x
- >>> y
- array([3, 2, 4])
-
- wrapper
- Python is a high-level (highly abstracted, or English-like) language.
- This abstraction comes at a price in execution speed, and sometimes
- it becomes necessary to use lower level languages to do fast
- computations. A wrapper is code that provides a bridge between
- high and the low level languages, allowing, e.g., Python to execute
- code written in C or Fortran.
-
- Examples include ctypes, SWIG and Cython (which wraps C and C++)
- and f2py (which wraps Fortran).
-
-"""
+++ /dev/null
-"""
-==============
-Array indexing
-==============
-
-Array indexing refers to any use of the square brackets ([]) to index
-array values. There are many options to indexing, which give numpy
-indexing great power, but with power comes some complexity and the
-potential for confusion. This section is just an overview of the
-various options and issues related to indexing. Aside from single
-element indexing, the details on most of these options are to be
-found in related sections.
-
-Assignment vs referencing
-=========================
-
-Most of the following examples show the use of indexing when
-referencing data in an array. The examples work just as well
-when assigning to an array. See the section at the end for
-specific examples and explanations on how assignments work.
-
-Single element indexing
-=======================
-
-Single element indexing for a 1-D array is what one expects. It work
-exactly like that for other standard Python sequences. It is 0-based,
-and accepts negative indices for indexing from the end of the array. ::
-
- >>> x = np.arange(10)
- >>> x[2]
- 2
- >>> x[-2]
- 8
-
-Unlike lists and tuples, numpy arrays support multidimensional indexing
-for multidimensional arrays. That means that it is not necessary to
-separate each dimension's index into its own set of square brackets. ::
-
- >>> x.shape = (2,5) # now x is 2-dimensional
- >>> x[1,3]
- 8
- >>> x[1,-1]
- 9
-
-Note that if one indexes a multidimensional array with fewer indices
-than dimensions, one gets a subdimensional array. For example: ::
-
- >>> x[0]
- array([0, 1, 2, 3, 4])
-
-That is, each index specified selects the array corresponding to the
-rest of the dimensions selected. In the above example, choosing 0
-means that the remaining dimension of length 5 is being left unspecified,
-and that what is returned is an array of that dimensionality and size.
-It must be noted that the returned array is not a copy of the original,
-but points to the same values in memory as does the original array.
-In this case, the 1-D array at the first position (0) is returned.
-So using a single index on the returned array, results in a single
-element being returned. That is: ::
-
- >>> x[0][2]
- 2
-
-So note that ``x[0,2] = x[0][2]`` though the second case is more
-inefficient as a new temporary array is created after the first index
-that is subsequently indexed by 2.
-
-Note to those used to IDL or Fortran memory order as it relates to
-indexing. NumPy uses C-order indexing. That means that the last
-index usually represents the most rapidly changing memory location,
-unlike Fortran or IDL, where the first index represents the most
-rapidly changing location in memory. This difference represents a
-great potential for confusion.
-
-Other indexing options
-======================
-
-It is possible to slice and stride arrays to extract arrays of the
-same number of dimensions, but of different sizes than the original.
-The slicing and striding works exactly the same way it does for lists
-and tuples except that they can be applied to multiple dimensions as
-well. A few examples illustrates best: ::
-
- >>> x = np.arange(10)
- >>> x[2:5]
- array([2, 3, 4])
- >>> x[:-7]
- array([0, 1, 2])
- >>> x[1:7:2]
- array([1, 3, 5])
- >>> y = np.arange(35).reshape(5,7)
- >>> y[1:5:2,::3]
- array([[ 7, 10, 13],
- [21, 24, 27]])
-
-Note that slices of arrays do not copy the internal array data but
-only produce new views of the original data. This is different from
-list or tuple slicing and an explicit ``copy()`` is recommended if
-the original data is not required anymore.
-
-It is possible to index arrays with other arrays for the purposes of
-selecting lists of values out of arrays into new arrays. There are
-two different ways of accomplishing this. One uses one or more arrays
-of index values. The other involves giving a boolean array of the proper
-shape to indicate the values to be selected. Index arrays are a very
-powerful tool that allow one to avoid looping over individual elements in
-arrays and thus greatly improve performance.
-
-It is possible to use special features to effectively increase the
-number of dimensions in an array through indexing so the resulting
-array acquires the shape needed for use in an expression or with a
-specific function.
-
-Index arrays
-============
-
-NumPy arrays may be indexed with other arrays (or any other sequence-
-like object that can be converted to an array, such as lists, with the
-exception of tuples; see the end of this document for why this is). The
-use of index arrays ranges from simple, straightforward cases to
-complex, hard-to-understand cases. For all cases of index arrays, what
-is returned is a copy of the original data, not a view as one gets for
-slices.
-
-Index arrays must be of integer type. Each value in the array indicates
-which value in the array to use in place of the index. To illustrate: ::
-
- >>> x = np.arange(10,1,-1)
- >>> x
- array([10, 9, 8, 7, 6, 5, 4, 3, 2])
- >>> x[np.array([3, 3, 1, 8])]
- array([7, 7, 9, 2])
-
-
-The index array consisting of the values 3, 3, 1 and 8 correspondingly
-create an array of length 4 (same as the index array) where each index
-is replaced by the value the index array has in the array being indexed.
-
-Negative values are permitted and work as they do with single indices
-or slices: ::
-
- >>> x[np.array([3,3,-3,8])]
- array([7, 7, 4, 2])
-
-It is an error to have index values out of bounds: ::
-
- >>> x[np.array([3, 3, 20, 8])]
- <type 'exceptions.IndexError'>: index 20 out of bounds 0<=index<9
-
-Generally speaking, what is returned when index arrays are used is
-an array with the same shape as the index array, but with the type
-and values of the array being indexed. As an example, we can use a
-multidimensional index array instead: ::
-
- >>> x[np.array([[1,1],[2,3]])]
- array([[9, 9],
- [8, 7]])
-
-Indexing Multi-dimensional arrays
-=================================
-
-Things become more complex when multidimensional arrays are indexed,
-particularly with multidimensional index arrays. These tend to be
-more unusual uses, but they are permitted, and they are useful for some
-problems. We'll start with the simplest multidimensional case (using
-the array y from the previous examples): ::
-
- >>> y[np.array([0,2,4]), np.array([0,1,2])]
- array([ 0, 15, 30])
-
-In this case, if the index arrays have a matching shape, and there is
-an index array for each dimension of the array being indexed, the
-resultant array has the same shape as the index arrays, and the values
-correspond to the index set for each position in the index arrays. In
-this example, the first index value is 0 for both index arrays, and
-thus the first value of the resultant array is y[0,0]. The next value
-is y[2,1], and the last is y[4,2].
-
-If the index arrays do not have the same shape, there is an attempt to
-broadcast them to the same shape. If they cannot be broadcast to the
-same shape, an exception is raised: ::
-
- >>> y[np.array([0,2,4]), np.array([0,1])]
- <type 'exceptions.ValueError'>: shape mismatch: objects cannot be
- broadcast to a single shape
-
-The broadcasting mechanism permits index arrays to be combined with
-scalars for other indices. The effect is that the scalar value is used
-for all the corresponding values of the index arrays: ::
-
- >>> y[np.array([0,2,4]), 1]
- array([ 1, 15, 29])
-
-Jumping to the next level of complexity, it is possible to only
-partially index an array with index arrays. It takes a bit of thought
-to understand what happens in such cases. For example if we just use
-one index array with y: ::
-
- >>> y[np.array([0,2,4])]
- array([[ 0, 1, 2, 3, 4, 5, 6],
- [14, 15, 16, 17, 18, 19, 20],
- [28, 29, 30, 31, 32, 33, 34]])
-
-What results is the construction of a new array where each value of
-the index array selects one row from the array being indexed and the
-resultant array has the resulting shape (number of index elements,
-size of row).
-
-An example of where this may be useful is for a color lookup table
-where we want to map the values of an image into RGB triples for
-display. The lookup table could have a shape (nlookup, 3). Indexing
-such an array with an image with shape (ny, nx) with dtype=np.uint8
-(or any integer type so long as values are with the bounds of the
-lookup table) will result in an array of shape (ny, nx, 3) where a
-triple of RGB values is associated with each pixel location.
-
-In general, the shape of the resultant array will be the concatenation
-of the shape of the index array (or the shape that all the index arrays
-were broadcast to) with the shape of any unused dimensions (those not
-indexed) in the array being indexed.
-
-Boolean or "mask" index arrays
-==============================
-
-Boolean arrays used as indices are treated in a different manner
-entirely than index arrays. Boolean arrays must be of the same shape
-as the initial dimensions of the array being indexed. In the
-most straightforward case, the boolean array has the same shape: ::
-
- >>> b = y>20
- >>> y[b]
- array([21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34])
-
-Unlike in the case of integer index arrays, in the boolean case, the
-result is a 1-D array containing all the elements in the indexed array
-corresponding to all the true elements in the boolean array. The
-elements in the indexed array are always iterated and returned in
-:term:`row-major` (C-style) order. The result is also identical to
-``y[np.nonzero(b)]``. As with index arrays, what is returned is a copy
-of the data, not a view as one gets with slices.
-
-The result will be multidimensional if y has more dimensions than b.
-For example: ::
-
- >>> b[:,5] # use a 1-D boolean whose first dim agrees with the first dim of y
- array([False, False, False, True, True])
- >>> y[b[:,5]]
- array([[21, 22, 23, 24, 25, 26, 27],
- [28, 29, 30, 31, 32, 33, 34]])
-
-Here the 4th and 5th rows are selected from the indexed array and
-combined to make a 2-D array.
-
-In general, when the boolean array has fewer dimensions than the array
-being indexed, this is equivalent to y[b, ...], which means
-y is indexed by b followed by as many : as are needed to fill
-out the rank of y.
-Thus the shape of the result is one dimension containing the number
-of True elements of the boolean array, followed by the remaining
-dimensions of the array being indexed.
-
-For example, using a 2-D boolean array of shape (2,3)
-with four True elements to select rows from a 3-D array of shape
-(2,3,5) results in a 2-D result of shape (4,5): ::
-
- >>> x = np.arange(30).reshape(2,3,5)
- >>> x
- array([[[ 0, 1, 2, 3, 4],
- [ 5, 6, 7, 8, 9],
- [10, 11, 12, 13, 14]],
- [[15, 16, 17, 18, 19],
- [20, 21, 22, 23, 24],
- [25, 26, 27, 28, 29]]])
- >>> b = np.array([[True, True, False], [False, True, True]])
- >>> x[b]
- array([[ 0, 1, 2, 3, 4],
- [ 5, 6, 7, 8, 9],
- [20, 21, 22, 23, 24],
- [25, 26, 27, 28, 29]])
-
-For further details, consult the numpy reference documentation on array indexing.
-
-Combining index arrays with slices
-==================================
-
-Index arrays may be combined with slices. For example: ::
-
- >>> y[np.array([0, 2, 4]), 1:3]
- array([[ 1, 2],
- [15, 16],
- [29, 30]])
-
-In effect, the slice and index array operation are independent.
-The slice operation extracts columns with index 1 and 2,
-(i.e. the 2nd and 3rd columns),
-followed by the index array operation which extracts rows with
-index 0, 2 and 4 (i.e the first, third and fifth rows).
-
-This is equivalent to::
-
- >>> y[:, 1:3][np.array([0, 2, 4]), :]
- array([[ 1, 2],
- [15, 16],
- [29, 30]])
-
-Likewise, slicing can be combined with broadcasted boolean indices: ::
-
- >>> b = y > 20
- >>> b
- array([[False, False, False, False, False, False, False],
- [False, False, False, False, False, False, False],
- [False, False, False, False, False, False, False],
- [ True, True, True, True, True, True, True],
- [ True, True, True, True, True, True, True]])
- >>> y[b[:,5],1:3]
- array([[22, 23],
- [29, 30]])
-
-Structural indexing tools
-=========================
-
-To facilitate easy matching of array shapes with expressions and in
-assignments, the np.newaxis object can be used within array indices
-to add new dimensions with a size of 1. For example: ::
-
- >>> y.shape
- (5, 7)
- >>> y[:,np.newaxis,:].shape
- (5, 1, 7)
-
-Note that there are no new elements in the array, just that the
-dimensionality is increased. This can be handy to combine two
-arrays in a way that otherwise would require explicitly reshaping
-operations. For example: ::
-
- >>> x = np.arange(5)
- >>> x[:,np.newaxis] + x[np.newaxis,:]
- array([[0, 1, 2, 3, 4],
- [1, 2, 3, 4, 5],
- [2, 3, 4, 5, 6],
- [3, 4, 5, 6, 7],
- [4, 5, 6, 7, 8]])
-
-The ellipsis syntax maybe used to indicate selecting in full any
-remaining unspecified dimensions. For example: ::
-
- >>> z = np.arange(81).reshape(3,3,3,3)
- >>> z[1,...,2]
- array([[29, 32, 35],
- [38, 41, 44],
- [47, 50, 53]])
-
-This is equivalent to: ::
-
- >>> z[1,:,:,2]
- array([[29, 32, 35],
- [38, 41, 44],
- [47, 50, 53]])
-
-Assigning values to indexed arrays
-==================================
-
-As mentioned, one can select a subset of an array to assign to using
-a single index, slices, and index and mask arrays. The value being
-assigned to the indexed array must be shape consistent (the same shape
-or broadcastable to the shape the index produces). For example, it is
-permitted to assign a constant to a slice: ::
-
- >>> x = np.arange(10)
- >>> x[2:7] = 1
-
-or an array of the right size: ::
-
- >>> x[2:7] = np.arange(5)
-
-Note that assignments may result in changes if assigning
-higher types to lower types (like floats to ints) or even
-exceptions (assigning complex to floats or ints): ::
-
- >>> x[1] = 1.2
- >>> x[1]
- 1
- >>> x[1] = 1.2j
- TypeError: can't convert complex to int
-
-
-Unlike some of the references (such as array and mask indices)
-assignments are always made to the original data in the array
-(indeed, nothing else would make sense!). Note though, that some
-actions may not work as one may naively expect. This particular
-example is often surprising to people: ::
-
- >>> x = np.arange(0, 50, 10)
- >>> x
- array([ 0, 10, 20, 30, 40])
- >>> x[np.array([1, 1, 3, 1])] += 1
- >>> x
- array([ 0, 11, 20, 31, 40])
-
-Where people expect that the 1st location will be incremented by 3.
-In fact, it will only be incremented by 1. The reason is because
-a new array is extracted from the original (as a temporary) containing
-the values at 1, 1, 3, 1, then the value 1 is added to the temporary,
-and then the temporary is assigned back to the original array. Thus
-the value of the array at x[1]+1 is assigned to x[1] three times,
-rather than being incremented 3 times.
-
-Dealing with variable numbers of indices within programs
-========================================================
-
-The index syntax is very powerful but limiting when dealing with
-a variable number of indices. For example, if you want to write
-a function that can handle arguments with various numbers of
-dimensions without having to write special case code for each
-number of possible dimensions, how can that be done? If one
-supplies to the index a tuple, the tuple will be interpreted
-as a list of indices. For example (using the previous definition
-for the array z): ::
-
- >>> indices = (1,1,1,1)
- >>> z[indices]
- 40
-
-So one can use code to construct tuples of any number of indices
-and then use these within an index.
-
-Slices can be specified within programs by using the slice() function
-in Python. For example: ::
-
- >>> indices = (1,1,1,slice(0,2)) # same as [1,1,1,0:2]
- >>> z[indices]
- array([39, 40])
-
-Likewise, ellipsis can be specified by code by using the Ellipsis
-object: ::
-
- >>> indices = (1, Ellipsis, 1) # same as [1,...,1]
- >>> z[indices]
- array([[28, 31, 34],
- [37, 40, 43],
- [46, 49, 52]])
-
-For this reason it is possible to use the output from the np.nonzero()
-function directly as an index since it always returns a tuple of index
-arrays.
-
-Because the special treatment of tuples, they are not automatically
-converted to an array as a list would be. As an example: ::
-
- >>> z[[1,1,1,1]] # produces a large array
- array([[[[27, 28, 29],
- [30, 31, 32], ...
- >>> z[(1,1,1,1)] # returns a single value
- 40
-
-"""
+++ /dev/null
-"""
-===============
-Array Internals
-===============
-
-Internal organization of numpy arrays
-=====================================
-
-It helps to understand a bit about how numpy arrays are handled under the covers to help understand numpy better. This section will not go into great detail. Those wishing to understand the full details are referred to Travis Oliphant's book "Guide to NumPy".
-
-NumPy arrays consist of two major components, the raw array data (from now on,
-referred to as the data buffer), and the information about the raw array data.
-The data buffer is typically what people think of as arrays in C or Fortran,
-a contiguous (and fixed) block of memory containing fixed sized data items.
-NumPy also contains a significant set of data that describes how to interpret
-the data in the data buffer. This extra information contains (among other things):
-
- 1) The basic data element's size in bytes
- 2) The start of the data within the data buffer (an offset relative to the
- beginning of the data buffer).
- 3) The number of dimensions and the size of each dimension
- 4) The separation between elements for each dimension (the 'stride'). This
- does not have to be a multiple of the element size
- 5) The byte order of the data (which may not be the native byte order)
- 6) Whether the buffer is read-only
- 7) Information (via the dtype object) about the interpretation of the basic
- data element. The basic data element may be as simple as a int or a float,
- or it may be a compound object (e.g., struct-like), a fixed character field,
- or Python object pointers.
- 8) Whether the array is to interpreted as C-order or Fortran-order.
-
-This arrangement allow for very flexible use of arrays. One thing that it allows
-is simple changes of the metadata to change the interpretation of the array buffer.
-Changing the byteorder of the array is a simple change involving no rearrangement
-of the data. The shape of the array can be changed very easily without changing
-anything in the data buffer or any data copying at all
-
-Among other things that are made possible is one can create a new array metadata
-object that uses the same data buffer
-to create a new view of that data buffer that has a different interpretation
-of the buffer (e.g., different shape, offset, byte order, strides, etc) but
-shares the same data bytes. Many operations in numpy do just this such as
-slices. Other operations, such as transpose, don't move data elements
-around in the array, but rather change the information about the shape and strides so that the indexing of the array changes, but the data in the doesn't move.
-
-Typically these new versions of the array metadata but the same data buffer are
-new 'views' into the data buffer. There is a different ndarray object, but it
-uses the same data buffer. This is why it is necessary to force copies through
-use of the .copy() method if one really wants to make a new and independent
-copy of the data buffer.
-
-New views into arrays mean the object reference counts for the data buffer
-increase. Simply doing away with the original array object will not remove the
-data buffer if other views of it still exist.
-
-Multidimensional Array Indexing Order Issues
-============================================
-
-What is the right way to index
-multi-dimensional arrays? Before you jump to conclusions about the one and
-true way to index multi-dimensional arrays, it pays to understand why this is
-a confusing issue. This section will try to explain in detail how numpy
-indexing works and why we adopt the convention we do for images, and when it
-may be appropriate to adopt other conventions.
-
-The first thing to understand is
-that there are two conflicting conventions for indexing 2-dimensional arrays.
-Matrix notation uses the first index to indicate which row is being selected and
-the second index to indicate which column is selected. This is opposite the
-geometrically oriented-convention for images where people generally think the
-first index represents x position (i.e., column) and the second represents y
-position (i.e., row). This alone is the source of much confusion;
-matrix-oriented users and image-oriented users expect two different things with
-regard to indexing.
-
-The second issue to understand is how indices correspond
-to the order the array is stored in memory. In Fortran the first index is the
-most rapidly varying index when moving through the elements of a two
-dimensional array as it is stored in memory. If you adopt the matrix
-convention for indexing, then this means the matrix is stored one column at a
-time (since the first index moves to the next row as it changes). Thus Fortran
-is considered a Column-major language. C has just the opposite convention. In
-C, the last index changes most rapidly as one moves through the array as
-stored in memory. Thus C is a Row-major language. The matrix is stored by
-rows. Note that in both cases it presumes that the matrix convention for
-indexing is being used, i.e., for both Fortran and C, the first index is the
-row. Note this convention implies that the indexing convention is invariant
-and that the data order changes to keep that so.
-
-But that's not the only way
-to look at it. Suppose one has large two-dimensional arrays (images or
-matrices) stored in data files. Suppose the data are stored by rows rather than
-by columns. If we are to preserve our index convention (whether matrix or
-image) that means that depending on the language we use, we may be forced to
-reorder the data if it is read into memory to preserve our indexing
-convention. For example if we read row-ordered data into memory without
-reordering, it will match the matrix indexing convention for C, but not for
-Fortran. Conversely, it will match the image indexing convention for Fortran,
-but not for C. For C, if one is using data stored in row order, and one wants
-to preserve the image index convention, the data must be reordered when
-reading into memory.
-
-In the end, which you do for Fortran or C depends on
-which is more important, not reordering data or preserving the indexing
-convention. For large images, reordering data is potentially expensive, and
-often the indexing convention is inverted to avoid that.
-
-The situation with
-numpy makes this issue yet more complicated. The internal machinery of numpy
-arrays is flexible enough to accept any ordering of indices. One can simply
-reorder indices by manipulating the internal stride information for arrays
-without reordering the data at all. NumPy will know how to map the new index
-order to the data without moving the data.
-
-So if this is true, why not choose
-the index order that matches what you most expect? In particular, why not define
-row-ordered images to use the image convention? (This is sometimes referred
-to as the Fortran convention vs the C convention, thus the 'C' and 'FORTRAN'
-order options for array ordering in numpy.) The drawback of doing this is
-potential performance penalties. It's common to access the data sequentially,
-either implicitly in array operations or explicitly by looping over rows of an
-image. When that is done, then the data will be accessed in non-optimal order.
-As the first index is incremented, what is actually happening is that elements
-spaced far apart in memory are being sequentially accessed, with usually poor
-memory access speeds. For example, for a two dimensional image 'im' defined so
-that im[0, 10] represents the value at x=0, y=10. To be consistent with usual
-Python behavior then im[0] would represent a column at x=0. Yet that data
-would be spread over the whole array since the data are stored in row order.
-Despite the flexibility of numpy's indexing, it can't really paper over the fact
-basic operations are rendered inefficient because of data order or that getting
-contiguous subarrays is still awkward (e.g., im[:,0] for the first row, vs
-im[0]), thus one can't use an idiom such as for row in im; for col in im does
-work, but doesn't yield contiguous column data.
-
-As it turns out, numpy is
-smart enough when dealing with ufuncs to determine which index is the most
-rapidly varying one in memory and uses that for the innermost loop. Thus for
-ufuncs there is no large intrinsic advantage to either approach in most cases.
-On the other hand, use of .flat with an FORTRAN ordered array will lead to
-non-optimal memory access as adjacent elements in the flattened array (iterator,
-actually) are not contiguous in memory.
-
-Indeed, the fact is that Python
-indexing on lists and other sequences naturally leads to an outside-to inside
-ordering (the first index gets the largest grouping, the next the next largest,
-and the last gets the smallest element). Since image data are normally stored
-by rows, this corresponds to position within rows being the last item indexed.
-
-If you do want to use Fortran ordering realize that
-there are two approaches to consider: 1) accept that the first index is just not
-the most rapidly changing in memory and have all your I/O routines reorder
-your data when going from memory to disk or visa versa, or use numpy's
-mechanism for mapping the first index to the most rapidly varying data. We
-recommend the former if possible. The disadvantage of the latter is that many
-of numpy's functions will yield arrays without Fortran ordering unless you are
-careful to use the 'order' keyword. Doing this would be highly inconvenient.
-
-Otherwise we recommend simply learning to reverse the usual order of indices
-when accessing elements of an array. Granted, it goes against the grain, but
-it is more in line with Python semantics and the natural order of the data.
-
-"""
+++ /dev/null
-"""
-=============
-Miscellaneous
-=============
-
-IEEE 754 Floating Point Special Values
---------------------------------------
-
-Special values defined in numpy: nan, inf,
-
-NaNs can be used as a poor-man's mask (if you don't care what the
-original value was)
-
-Note: cannot use equality to test NaNs. E.g.: ::
-
- >>> myarr = np.array([1., 0., np.nan, 3.])
- >>> np.nonzero(myarr == np.nan)
- (array([], dtype=int64),)
- >>> np.nan == np.nan # is always False! Use special numpy functions instead.
- False
- >>> myarr[myarr == np.nan] = 0. # doesn't work
- >>> myarr
- array([ 1., 0., NaN, 3.])
- >>> myarr[np.isnan(myarr)] = 0. # use this instead find
- >>> myarr
- array([ 1., 0., 0., 3.])
-
-Other related special value functions: ::
-
- isinf(): True if value is inf
- isfinite(): True if not nan or inf
- nan_to_num(): Map nan to 0, inf to max float, -inf to min float
-
-The following corresponds to the usual functions except that nans are excluded
-from the results: ::
-
- nansum()
- nanmax()
- nanmin()
- nanargmax()
- nanargmin()
-
- >>> x = np.arange(10.)
- >>> x[3] = np.nan
- >>> x.sum()
- nan
- >>> np.nansum(x)
- 42.0
-
-How numpy handles numerical exceptions
---------------------------------------
-
-The default is to ``'warn'`` for ``invalid``, ``divide``, and ``overflow``
-and ``'ignore'`` for ``underflow``. But this can be changed, and it can be
-set individually for different kinds of exceptions. The different behaviors
-are:
-
- - 'ignore' : Take no action when the exception occurs.
- - 'warn' : Print a `RuntimeWarning` (via the Python `warnings` module).
- - 'raise' : Raise a `FloatingPointError`.
- - 'call' : Call a function specified using the `seterrcall` function.
- - 'print' : Print a warning directly to ``stdout``.
- - 'log' : Record error in a Log object specified by `seterrcall`.
-
-These behaviors can be set for all kinds of errors or specific ones:
-
- - all : apply to all numeric exceptions
- - invalid : when NaNs are generated
- - divide : divide by zero (for integers as well!)
- - overflow : floating point overflows
- - underflow : floating point underflows
-
-Note that integer divide-by-zero is handled by the same machinery.
-These behaviors are set on a per-thread basis.
-
-Examples
---------
-
-::
-
- >>> oldsettings = np.seterr(all='warn')
- >>> np.zeros(5,dtype=np.float32)/0.
- invalid value encountered in divide
- >>> j = np.seterr(under='ignore')
- >>> np.array([1.e-100])**10
- >>> j = np.seterr(invalid='raise')
- >>> np.sqrt(np.array([-1.]))
- FloatingPointError: invalid value encountered in sqrt
- >>> def errorhandler(errstr, errflag):
- ... print("saw stupid error!")
- >>> np.seterrcall(errorhandler)
- <function err_handler at 0x...>
- >>> j = np.seterr(all='call')
- >>> np.zeros(5, dtype=np.int32)/0
- FloatingPointError: invalid value encountered in divide
- saw stupid error!
- >>> j = np.seterr(**oldsettings) # restore previous
- ... # error-handling settings
-
-Interfacing to C
-----------------
-Only a survey of the choices. Little detail on how each works.
-
-1) Bare metal, wrap your own C-code manually.
-
- - Plusses:
-
- - Efficient
- - No dependencies on other tools
-
- - Minuses:
-
- - Lots of learning overhead:
-
- - need to learn basics of Python C API
- - need to learn basics of numpy C API
- - need to learn how to handle reference counting and love it.
-
- - Reference counting often difficult to get right.
-
- - getting it wrong leads to memory leaks, and worse, segfaults
-
- - API will change for Python 3.0!
-
-2) Cython
-
- - Plusses:
-
- - avoid learning C API's
- - no dealing with reference counting
- - can code in pseudo python and generate C code
- - can also interface to existing C code
- - should shield you from changes to Python C api
- - has become the de-facto standard within the scientific Python community
- - fast indexing support for arrays
-
- - Minuses:
-
- - Can write code in non-standard form which may become obsolete
- - Not as flexible as manual wrapping
-
-3) ctypes
-
- - Plusses:
-
- - part of Python standard library
- - good for interfacing to existing sharable libraries, particularly
- Windows DLLs
- - avoids API/reference counting issues
- - good numpy support: arrays have all these in their ctypes
- attribute: ::
-
- a.ctypes.data a.ctypes.get_strides
- a.ctypes.data_as a.ctypes.shape
- a.ctypes.get_as_parameter a.ctypes.shape_as
- a.ctypes.get_data a.ctypes.strides
- a.ctypes.get_shape a.ctypes.strides_as
-
- - Minuses:
-
- - can't use for writing code to be turned into C extensions, only a wrapper
- tool.
-
-4) SWIG (automatic wrapper generator)
-
- - Plusses:
-
- - around a long time
- - multiple scripting language support
- - C++ support
- - Good for wrapping large (many functions) existing C libraries
-
- - Minuses:
-
- - generates lots of code between Python and the C code
- - can cause performance problems that are nearly impossible to optimize
- out
- - interface files can be hard to write
- - doesn't necessarily avoid reference counting issues or needing to know
- API's
-
-5) scipy.weave
-
- - Plusses:
-
- - can turn many numpy expressions into C code
- - dynamic compiling and loading of generated C code
- - can embed pure C code in Python module and have weave extract, generate
- interfaces and compile, etc.
-
- - Minuses:
-
- - Future very uncertain: it's the only part of Scipy not ported to Python 3
- and is effectively deprecated in favor of Cython.
-
-6) Psyco
-
- - Plusses:
-
- - Turns pure python into efficient machine code through jit-like
- optimizations
- - very fast when it optimizes well
-
- - Minuses:
-
- - Only on intel (windows?)
- - Doesn't do much for numpy?
-
-Interfacing to Fortran:
------------------------
-The clear choice to wrap Fortran code is
-`f2py <https://docs.scipy.org/doc/numpy/f2py/>`_.
-
-Pyfort is an older alternative, but not supported any longer.
-Fwrap is a newer project that looked promising but isn't being developed any
-longer.
-
-Interfacing to C++:
--------------------
- 1) Cython
- 2) CXX
- 3) Boost.python
- 4) SWIG
- 5) SIP (used mainly in PyQT)
-
-"""
+++ /dev/null
-"""
-=================
-Structured Arrays
-=================
-
-Introduction
-============
-
-Structured arrays are ndarrays whose datatype is a composition of simpler
-datatypes organized as a sequence of named :term:`fields <field>`. For example,
-::
-
- >>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)],
- ... dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
- >>> x
- array([('Rex', 9, 81.), ('Fido', 3, 27.)],
- dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
-
-Here ``x`` is a one-dimensional array of length two whose datatype is a
-structure with three fields: 1. A string of length 10 or less named 'name', 2.
-a 32-bit integer named 'age', and 3. a 32-bit float named 'weight'.
-
-If you index ``x`` at position 1 you get a structure::
-
- >>> x[1]
- ('Fido', 3, 27.0)
-
-You can access and modify individual fields of a structured array by indexing
-with the field name::
-
- >>> x['age']
- array([9, 3], dtype=int32)
- >>> x['age'] = 5
- >>> x
- array([('Rex', 5, 81.), ('Fido', 5, 27.)],
- dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
-
-Structured datatypes are designed to be able to mimic 'structs' in the C
-language, and share a similar memory layout. They are meant for interfacing with
-C code and for low-level manipulation of structured buffers, for example for
-interpreting binary blobs. For these purposes they support specialized features
-such as subarrays, nested datatypes, and unions, and allow control over the
-memory layout of the structure.
-
-Users looking to manipulate tabular data, such as stored in csv files, may find
-other pydata projects more suitable, such as xarray, pandas, or DataArray.
-These provide a high-level interface for tabular data analysis and are better
-optimized for that use. For instance, the C-struct-like memory layout of
-structured arrays in numpy can lead to poor cache behavior in comparison.
-
-.. _defining-structured-types:
-
-Structured Datatypes
-====================
-
-A structured datatype can be thought of as a sequence of bytes of a certain
-length (the structure's :term:`itemsize`) which is interpreted as a collection
-of fields. Each field has a name, a datatype, and a byte offset within the
-structure. The datatype of a field may be any numpy datatype including other
-structured datatypes, and it may also be a :term:`subarray data type` which
-behaves like an ndarray of a specified shape. The offsets of the fields are
-arbitrary, and fields may even overlap. These offsets are usually determined
-automatically by numpy, but can also be specified.
-
-Structured Datatype Creation
-----------------------------
-
-Structured datatypes may be created using the function :func:`numpy.dtype`.
-There are 4 alternative forms of specification which vary in flexibility and
-conciseness. These are further documented in the
-:ref:`Data Type Objects <arrays.dtypes.constructing>` reference page, and in
-summary they are:
-
-1. A list of tuples, one tuple per field
-
- Each tuple has the form ``(fieldname, datatype, shape)`` where shape is
- optional. ``fieldname`` is a string (or tuple if titles are used, see
- :ref:`Field Titles <titles>` below), ``datatype`` may be any object
- convertible to a datatype, and ``shape`` is a tuple of integers specifying
- subarray shape.
-
- >>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2, 2))])
- dtype([('x', '<f4'), ('y', '<f4'), ('z', '<f4', (2, 2))])
-
- If ``fieldname`` is the empty string ``''``, the field will be given a
- default name of the form ``f#``, where ``#`` is the integer index of the
- field, counting from 0 from the left::
-
- >>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')])
- dtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')])
-
- The byte offsets of the fields within the structure and the total
- structure itemsize are determined automatically.
-
-2. A string of comma-separated dtype specifications
-
- In this shorthand notation any of the :ref:`string dtype specifications
- <arrays.dtypes.constructing>` may be used in a string and separated by
- commas. The itemsize and byte offsets of the fields are determined
- automatically, and the field names are given the default names ``f0``,
- ``f1``, etc. ::
-
- >>> np.dtype('i8, f4, S3')
- dtype([('f0', '<i8'), ('f1', '<f4'), ('f2', 'S3')])
- >>> np.dtype('3int8, float32, (2, 3)float64')
- dtype([('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))])
-
-3. A dictionary of field parameter arrays
-
- This is the most flexible form of specification since it allows control
- over the byte-offsets of the fields and the itemsize of the structure.
-
- The dictionary has two required keys, 'names' and 'formats', and four
- optional keys, 'offsets', 'itemsize', 'aligned' and 'titles'. The values
- for 'names' and 'formats' should respectively be a list of field names and
- a list of dtype specifications, of the same length. The optional 'offsets'
- value should be a list of integer byte-offsets, one for each field within
- the structure. If 'offsets' is not given the offsets are determined
- automatically. The optional 'itemsize' value should be an integer
- describing the total size in bytes of the dtype, which must be large
- enough to contain all the fields.
- ::
-
- >>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']})
- dtype([('col1', '<i4'), ('col2', '<f4')])
- >>> np.dtype({'names': ['col1', 'col2'],
- ... 'formats': ['i4', 'f4'],
- ... 'offsets': [0, 4],
- ... 'itemsize': 12})
- dtype({'names':['col1','col2'], 'formats':['<i4','<f4'], 'offsets':[0,4], 'itemsize':12})
-
- Offsets may be chosen such that the fields overlap, though this will mean
- that assigning to one field may clobber any overlapping field's data. As
- an exception, fields of :class:`numpy.object` type cannot overlap with
- other fields, because of the risk of clobbering the internal object
- pointer and then dereferencing it.
-
- The optional 'aligned' value can be set to ``True`` to make the automatic
- offset computation use aligned offsets (see :ref:`offsets-and-alignment`),
- as if the 'align' keyword argument of :func:`numpy.dtype` had been set to
- True.
-
- The optional 'titles' value should be a list of titles of the same length
- as 'names', see :ref:`Field Titles <titles>` below.
-
-4. A dictionary of field names
-
- The use of this form of specification is discouraged, but documented here
- because older numpy code may use it. The keys of the dictionary are the
- field names and the values are tuples specifying type and offset::
-
- >>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)})
- dtype([('col1', 'i1'), ('col2', '<f4')])
-
- This form is discouraged because Python dictionaries do not preserve order
- in Python versions before Python 3.6, and the order of the fields in a
- structured dtype has meaning. :ref:`Field Titles <titles>` may be
- specified by using a 3-tuple, see below.
-
-Manipulating and Displaying Structured Datatypes
-------------------------------------------------
-
-The list of field names of a structured datatype can be found in the ``names``
-attribute of the dtype object::
-
- >>> d = np.dtype([('x', 'i8'), ('y', 'f4')])
- >>> d.names
- ('x', 'y')
-
-The field names may be modified by assigning to the ``names`` attribute using a
-sequence of strings of the same length.
-
-The dtype object also has a dictionary-like attribute, ``fields``, whose keys
-are the field names (and :ref:`Field Titles <titles>`, see below) and whose
-values are tuples containing the dtype and byte offset of each field. ::
-
- >>> d.fields
- mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})
-
-Both the ``names`` and ``fields`` attributes will equal ``None`` for
-unstructured arrays. The recommended way to test if a dtype is structured is
-with `if dt.names is not None` rather than `if dt.names`, to account for dtypes
-with 0 fields.
-
-The string representation of a structured datatype is shown in the "list of
-tuples" form if possible, otherwise numpy falls back to using the more general
-dictionary form.
-
-.. _offsets-and-alignment:
-
-Automatic Byte Offsets and Alignment
-------------------------------------
-
-Numpy uses one of two methods to automatically determine the field byte offsets
-and the overall itemsize of a structured datatype, depending on whether
-``align=True`` was specified as a keyword argument to :func:`numpy.dtype`.
-
-By default (``align=False``), numpy will pack the fields together such that
-each field starts at the byte offset the previous field ended, and the fields
-are contiguous in memory. ::
-
- >>> def print_offsets(d):
- ... print("offsets:", [d.fields[name][1] for name in d.names])
- ... print("itemsize:", d.itemsize)
- >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2'))
- offsets: [0, 1, 2, 6, 7, 15]
- itemsize: 17
-
-If ``align=True`` is set, numpy will pad the structure in the same way many C
-compilers would pad a C-struct. Aligned structures can give a performance
-improvement in some cases, at the cost of increased datatype size. Padding
-bytes are inserted between fields such that each field's byte offset will be a
-multiple of that field's alignment, which is usually equal to the field's size
-in bytes for simple datatypes, see :c:member:`PyArray_Descr.alignment`. The
-structure will also have trailing padding added so that its itemsize is a
-multiple of the largest field's alignment. ::
-
- >>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2', align=True))
- offsets: [0, 1, 4, 8, 16, 24]
- itemsize: 32
-
-Note that although almost all modern C compilers pad in this way by default,
-padding in C structs is C-implementation-dependent so this memory layout is not
-guaranteed to exactly match that of a corresponding struct in a C program. Some
-work may be needed, either on the numpy side or the C side, to obtain exact
-correspondence.
-
-If offsets were specified using the optional ``offsets`` key in the
-dictionary-based dtype specification, setting ``align=True`` will check that
-each field's offset is a multiple of its size and that the itemsize is a
-multiple of the largest field size, and raise an exception if not.
-
-If the offsets of the fields and itemsize of a structured array satisfy the
-alignment conditions, the array will have the ``ALIGNED`` :attr:`flag
-<numpy.ndarray.flags>` set.
-
-A convenience function :func:`numpy.lib.recfunctions.repack_fields` converts an
-aligned dtype or array to a packed one and vice versa. It takes either a dtype
-or structured ndarray as an argument, and returns a copy with fields re-packed,
-with or without padding bytes.
-
-.. _titles:
-
-Field Titles
-------------
-
-In addition to field names, fields may also have an associated :term:`title`,
-an alternate name, which is sometimes used as an additional description or
-alias for the field. The title may be used to index an array, just like a
-field name.
-
-To add titles when using the list-of-tuples form of dtype specification, the
-field name may be specified as a tuple of two strings instead of a single
-string, which will be the field's title and field name respectively. For
-example::
-
- >>> np.dtype([(('my title', 'name'), 'f4')])
- dtype([(('my title', 'name'), '<f4')])
-
-When using the first form of dictionary-based specification, the titles may be
-supplied as an extra ``'titles'`` key as described above. When using the second
-(discouraged) dictionary-based specification, the title can be supplied by
-providing a 3-element tuple ``(datatype, offset, title)`` instead of the usual
-2-element tuple::
-
- >>> np.dtype({'name': ('i4', 0, 'my title')})
- dtype([(('my title', 'name'), '<i4')])
-
-The ``dtype.fields`` dictionary will contain titles as keys, if any
-titles are used. This means effectively that a field with a title will be
-represented twice in the fields dictionary. The tuple values for these fields
-will also have a third element, the field title. Because of this, and because
-the ``names`` attribute preserves the field order while the ``fields``
-attribute may not, it is recommended to iterate through the fields of a dtype
-using the ``names`` attribute of the dtype, which will not list titles, as
-in::
-
- >>> for name in d.names:
- ... print(d.fields[name][:2])
- (dtype('int64'), 0)
- (dtype('float32'), 8)
-
-Union types
------------
-
-Structured datatypes are implemented in numpy to have base type
-:class:`numpy.void` by default, but it is possible to interpret other numpy
-types as structured types using the ``(base_dtype, dtype)`` form of dtype
-specification described in
-:ref:`Data Type Objects <arrays.dtypes.constructing>`. Here, ``base_dtype`` is
-the desired underlying dtype, and fields and flags will be copied from
-``dtype``. This dtype is similar to a 'union' in C.
-
-Indexing and Assignment to Structured arrays
-============================================
-
-Assigning data to a Structured Array
-------------------------------------
-
-There are a number of ways to assign values to a structured array: Using python
-tuples, using scalar values, or using other structured arrays.
-
-Assignment from Python Native Types (Tuples)
-````````````````````````````````````````````
-
-The simplest way to assign values to a structured array is using python tuples.
-Each assigned value should be a tuple of length equal to the number of fields
-in the array, and not a list or array as these will trigger numpy's
-broadcasting rules. The tuple's elements are assigned to the successive fields
-of the array, from left to right::
-
- >>> x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8, f4, f8')
- >>> x[1] = (7, 8, 9)
- >>> x
- array([(1, 2., 3.), (7, 8., 9.)],
- dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '<f8')])
-
-Assignment from Scalars
-```````````````````````
-
-A scalar assigned to a structured element will be assigned to all fields. This
-happens when a scalar is assigned to a structured array, or when an
-unstructured array is assigned to a structured array::
-
- >>> x = np.zeros(2, dtype='i8, f4, ?, S1')
- >>> x[:] = 3
- >>> x
- array([(3, 3., True, b'3'), (3, 3., True, b'3')],
- dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
- >>> x[:] = np.arange(2)
- >>> x
- array([(0, 0., False, b'0'), (1, 1., True, b'1')],
- dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
-
-Structured arrays can also be assigned to unstructured arrays, but only if the
-structured datatype has just a single field::
-
- >>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')])
- >>> onefield = np.zeros(2, dtype=[('A', 'i4')])
- >>> nostruct = np.zeros(2, dtype='i4')
- >>> nostruct[:] = twofield
- Traceback (most recent call last):
- ...
- TypeError: Cannot cast array data from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'
-
-Assignment from other Structured Arrays
-```````````````````````````````````````
-
-Assignment between two structured arrays occurs as if the source elements had
-been converted to tuples and then assigned to the destination elements. That
-is, the first field of the source array is assigned to the first field of the
-destination array, and the second field likewise, and so on, regardless of
-field names. Structured arrays with a different number of fields cannot be
-assigned to each other. Bytes of the destination structure which are not
-included in any of the fields are unaffected. ::
-
- >>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')])
- >>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')])
- >>> b[:] = a
- >>> b
- array([(0., b'0.0', b''), (0., b'0.0', b''), (0., b'0.0', b'')],
- dtype=[('x', '<f4'), ('y', 'S3'), ('z', 'O')])
-
-
-Assignment involving subarrays
-``````````````````````````````
-
-When assigning to fields which are subarrays, the assigned value will first be
-broadcast to the shape of the subarray.
-
-Indexing Structured Arrays
---------------------------
-
-Accessing Individual Fields
-```````````````````````````
-
-Individual fields of a structured array may be accessed and modified by indexing
-the array with the field name. ::
-
- >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
- >>> x['foo']
- array([1, 3])
- >>> x['foo'] = 10
- >>> x
- array([(10, 2.), (10, 4.)],
- dtype=[('foo', '<i8'), ('bar', '<f4')])
-
-The resulting array is a view into the original array. It shares the same
-memory locations and writing to the view will modify the original array. ::
-
- >>> y = x['bar']
- >>> y[:] = 11
- >>> x
- array([(10, 11.), (10, 11.)],
- dtype=[('foo', '<i8'), ('bar', '<f4')])
-
-This view has the same dtype and itemsize as the indexed field, so it is
-typically a non-structured array, except in the case of nested structures.
-
- >>> y.dtype, y.shape, y.strides
- (dtype('float32'), (2,), (12,))
-
-If the accessed field is a subarray, the dimensions of the subarray
-are appended to the shape of the result::
-
- >>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])
- >>> x['a'].shape
- (2, 2)
- >>> x['b'].shape
- (2, 2, 3, 3)
-
-Accessing Multiple Fields
-```````````````````````````
-
-One can index and assign to a structured array with a multi-field index, where
-the index is a list of field names.
-
-.. warning::
- The behavior of multi-field indexes changed from Numpy 1.15 to Numpy 1.16.
-
-The result of indexing with a multi-field index is a view into the original
-array, as follows::
-
- >>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')])
- >>> a[['a', 'c']]
- array([(0, 0.), (0, 0.), (0, 0.)],
- dtype={'names':['a','c'], 'formats':['<i4','<f4'], 'offsets':[0,8], 'itemsize':12})
-
-Assignment to the view modifies the original array. The view's fields will be
-in the order they were indexed. Note that unlike for single-field indexing, the
-dtype of the view has the same itemsize as the original array, and has fields
-at the same offsets as in the original array, and unindexed fields are merely
-missing.
-
-.. warning::
- In Numpy 1.15, indexing an array with a multi-field index returned a copy of
- the result above, but with fields packed together in memory as if
- passed through :func:`numpy.lib.recfunctions.repack_fields`.
-
- The new behavior as of Numpy 1.16 leads to extra "padding" bytes at the
- location of unindexed fields compared to 1.15. You will need to update any
- code which depends on the data having a "packed" layout. For instance code
- such as::
-
- >>> a[['a', 'c']].view('i8') # Fails in Numpy 1.16
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype
-
- will need to be changed. This code has raised a ``FutureWarning`` since
- Numpy 1.12, and similar code has raised ``FutureWarning`` since 1.7.
-
- In 1.16 a number of functions have been introduced in the
- :mod:`numpy.lib.recfunctions` module to help users account for this
- change. These are
- :func:`numpy.lib.recfunctions.repack_fields`.
- :func:`numpy.lib.recfunctions.structured_to_unstructured`,
- :func:`numpy.lib.recfunctions.unstructured_to_structured`,
- :func:`numpy.lib.recfunctions.apply_along_fields`,
- :func:`numpy.lib.recfunctions.assign_fields_by_name`, and
- :func:`numpy.lib.recfunctions.require_fields`.
-
- The function :func:`numpy.lib.recfunctions.repack_fields` can always be
- used to reproduce the old behavior, as it will return a packed copy of the
- structured array. The code above, for example, can be replaced with:
-
- >>> from numpy.lib.recfunctions import repack_fields
- >>> repack_fields(a[['a', 'c']]).view('i8') # supported in 1.16
- array([0, 0, 0])
-
- Furthermore, numpy now provides a new function
- :func:`numpy.lib.recfunctions.structured_to_unstructured` which is a safer
- and more efficient alternative for users who wish to convert structured
- arrays to unstructured arrays, as the view above is often indeded to do.
- This function allows safe conversion to an unstructured type taking into
- account padding, often avoids a copy, and also casts the datatypes
- as needed, unlike the view. Code such as:
-
- >>> b = np.zeros(3, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
- >>> b[['x', 'z']].view('f4')
- array([0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
-
- can be made safer by replacing with:
-
- >>> from numpy.lib.recfunctions import structured_to_unstructured
- >>> structured_to_unstructured(b[['x', 'z']])
- array([0, 0, 0])
-
-
-Assignment to an array with a multi-field index modifies the original array::
-
- >>> a[['a', 'c']] = (2, 3)
- >>> a
- array([(2, 0, 3.), (2, 0, 3.), (2, 0, 3.)],
- dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')])
-
-This obeys the structured array assignment rules described above. For example,
-this means that one can swap the values of two fields using appropriate
-multi-field indexes::
-
- >>> a[['a', 'c']] = a[['c', 'a']]
-
-Indexing with an Integer to get a Structured Scalar
-```````````````````````````````````````````````````
-
-Indexing a single element of a structured array (with an integer index) returns
-a structured scalar::
-
- >>> x = np.array([(1, 2., 3.)], dtype='i, f, f')
- >>> scalar = x[0]
- >>> scalar
- (1, 2., 3.)
- >>> type(scalar)
- <class 'numpy.void'>
-
-Unlike other numpy scalars, structured scalars are mutable and act like views
-into the original array, such that modifying the scalar will modify the
-original array. Structured scalars also support access and assignment by field
-name::
-
- >>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
- >>> s = x[0]
- >>> s['bar'] = 100
- >>> x
- array([(1, 100.), (3, 4.)],
- dtype=[('foo', '<i8'), ('bar', '<f4')])
-
-Similarly to tuples, structured scalars can also be indexed with an integer::
-
- >>> scalar = np.array([(1, 2., 3.)], dtype='i, f, f')[0]
- >>> scalar[0]
- 1
- >>> scalar[1] = 4
-
-Thus, tuples might be thought of as the native Python equivalent to numpy's
-structured types, much like native python integers are the equivalent to
-numpy's integer types. Structured scalars may be converted to a tuple by
-calling :func:`ndarray.item`::
-
- >>> scalar.item(), type(scalar.item())
- ((1, 4.0, 3.0), <class 'tuple'>)
-
-Viewing Structured Arrays Containing Objects
---------------------------------------------
-
-In order to prevent clobbering object pointers in fields of
-:class:`numpy.object` type, numpy currently does not allow views of structured
-arrays containing objects.
-
-Structure Comparison
---------------------
-
-If the dtypes of two void structured arrays are equal, testing the equality of
-the arrays will result in a boolean array with the dimensions of the original
-arrays, with elements set to ``True`` where all fields of the corresponding
-structures are equal. Structured dtypes are equal if the field names,
-dtypes and titles are the same, ignoring endianness, and the fields are in
-the same order::
-
- >>> a = np.zeros(2, dtype=[('a', 'i4'), ('b', 'i4')])
- >>> b = np.ones(2, dtype=[('a', 'i4'), ('b', 'i4')])
- >>> a == b
- array([False, False])
-
-Currently, if the dtypes of two void structured arrays are not equivalent the
-comparison fails, returning the scalar value ``False``. This behavior is
-deprecated as of numpy 1.10 and will raise an error or perform elementwise
-comparison in the future.
-
-The ``<`` and ``>`` operators always return ``False`` when comparing void
-structured arrays, and arithmetic and bitwise operations are not supported.
-
-Record Arrays
-=============
-
-As an optional convenience numpy provides an ndarray subclass,
-:class:`numpy.recarray`, and associated helper functions in the
-:mod:`numpy.rec` submodule, that allows access to fields of structured arrays
-by attribute instead of only by index. Record arrays also use a special
-datatype, :class:`numpy.record`, that allows field access by attribute on the
-structured scalars obtained from the array.
-
-The simplest way to create a record array is with :func:`numpy.rec.array`::
-
- >>> recordarr = np.rec.array([(1, 2., 'Hello'), (2, 3., "World")],
- ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])
- >>> recordarr.bar
- array([ 2., 3.], dtype=float32)
- >>> recordarr[1:2]
- rec.array([(2, 3., b'World')],
- dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])
- >>> recordarr[1:2].foo
- array([2], dtype=int32)
- >>> recordarr.foo[1:2]
- array([2], dtype=int32)
- >>> recordarr[1].baz
- b'World'
-
-:func:`numpy.rec.array` can convert a wide variety of arguments into record
-arrays, including structured arrays::
-
- >>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
- ... dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')])
- >>> recordarr = np.rec.array(arr)
-
-The :mod:`numpy.rec` module provides a number of other convenience functions for
-creating record arrays, see :ref:`record array creation routines
-<routines.array-creation.rec>`.
-
-A record array representation of a structured array can be obtained using the
-appropriate `view <numpy-ndarray-view>`_::
-
- >>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
- ... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'a10')])
- >>> recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)),
- ... type=np.recarray)
-
-For convenience, viewing an ndarray as type :class:`np.recarray` will
-automatically convert to :class:`np.record` datatype, so the dtype can be left
-out of the view::
-
- >>> recordarr = arr.view(np.recarray)
- >>> recordarr.dtype
- dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))
-
-To get back to a plain ndarray both the dtype and type must be reset. The
-following view does so, taking into account the unusual case that the
-recordarr was not a structured type::
-
- >>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray)
-
-Record array fields accessed by index or by attribute are returned as a record
-array if the field has a structured type but as a plain ndarray otherwise. ::
-
- >>> recordarr = np.rec.array([('Hello', (1, 2)), ("World", (3, 4))],
- ... dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])])
- >>> type(recordarr.foo)
- <class 'numpy.ndarray'>
- >>> type(recordarr.bar)
- <class 'numpy.recarray'>
-
-Note that if a field has the same name as an ndarray attribute, the ndarray
-attribute takes precedence. Such fields will be inaccessible by attribute but
-will still be accessible by index.
-
-"""
+++ /dev/null
-"""=============================
-Subclassing ndarray in python
-=============================
-
-Introduction
-------------
-
-Subclassing ndarray is relatively simple, but it has some complications
-compared to other Python objects. On this page we explain the machinery
-that allows you to subclass ndarray, and the implications for
-implementing a subclass.
-
-ndarrays and object creation
-============================
-
-Subclassing ndarray is complicated by the fact that new instances of
-ndarray classes can come about in three different ways. These are:
-
-#. Explicit constructor call - as in ``MySubClass(params)``. This is
- the usual route to Python instance creation.
-#. View casting - casting an existing ndarray as a given subclass
-#. New from template - creating a new instance from a template
- instance. Examples include returning slices from a subclassed array,
- creating return types from ufuncs, and copying arrays. See
- :ref:`new-from-template` for more details
-
-The last two are characteristics of ndarrays - in order to support
-things like array slicing. The complications of subclassing ndarray are
-due to the mechanisms numpy has to support these latter two routes of
-instance creation.
-
-.. _view-casting:
-
-View casting
-------------
-
-*View casting* is the standard ndarray mechanism by which you take an
-ndarray of any subclass, and return a view of the array as another
-(specified) subclass:
-
->>> import numpy as np
->>> # create a completely useless ndarray subclass
->>> class C(np.ndarray): pass
->>> # create a standard ndarray
->>> arr = np.zeros((3,))
->>> # take a view of it, as our useless subclass
->>> c_arr = arr.view(C)
->>> type(c_arr)
-<class 'C'>
-
-.. _new-from-template:
-
-Creating new from template
---------------------------
-
-New instances of an ndarray subclass can also come about by a very
-similar mechanism to :ref:`view-casting`, when numpy finds it needs to
-create a new instance from a template instance. The most obvious place
-this has to happen is when you are taking slices of subclassed arrays.
-For example:
-
->>> v = c_arr[1:]
->>> type(v) # the view is of type 'C'
-<class 'C'>
->>> v is c_arr # but it's a new instance
-False
-
-The slice is a *view* onto the original ``c_arr`` data. So, when we
-take a view from the ndarray, we return a new ndarray, of the same
-class, that points to the data in the original.
-
-There are other points in the use of ndarrays where we need such views,
-such as copying arrays (``c_arr.copy()``), creating ufunc output arrays
-(see also :ref:`array-wrap`), and reducing methods (like
-``c_arr.mean()``).
-
-Relationship of view casting and new-from-template
---------------------------------------------------
-
-These paths both use the same machinery. We make the distinction here,
-because they result in different input to your methods. Specifically,
-:ref:`view-casting` means you have created a new instance of your array
-type from any potential subclass of ndarray. :ref:`new-from-template`
-means you have created a new instance of your class from a pre-existing
-instance, allowing you - for example - to copy across attributes that
-are particular to your subclass.
-
-Implications for subclassing
-----------------------------
-
-If we subclass ndarray, we need to deal not only with explicit
-construction of our array type, but also :ref:`view-casting` or
-:ref:`new-from-template`. NumPy has the machinery to do this, and this
-machinery that makes subclassing slightly non-standard.
-
-There are two aspects to the machinery that ndarray uses to support
-views and new-from-template in subclasses.
-
-The first is the use of the ``ndarray.__new__`` method for the main work
-of object initialization, rather then the more usual ``__init__``
-method. The second is the use of the ``__array_finalize__`` method to
-allow subclasses to clean up after the creation of views and new
-instances from templates.
-
-A brief Python primer on ``__new__`` and ``__init__``
-=====================================================
-
-``__new__`` is a standard Python method, and, if present, is called
-before ``__init__`` when we create a class instance. See the `python
-__new__ documentation
-<https://docs.python.org/reference/datamodel.html#object.__new__>`_ for more detail.
-
-For example, consider the following Python code:
-
-.. testcode::
-
- class C:
- def __new__(cls, *args):
- print('Cls in __new__:', cls)
- print('Args in __new__:', args)
- # The `object` type __new__ method takes a single argument.
- return object.__new__(cls)
-
- def __init__(self, *args):
- print('type(self) in __init__:', type(self))
- print('Args in __init__:', args)
-
-meaning that we get:
-
->>> c = C('hello')
-Cls in __new__: <class 'C'>
-Args in __new__: ('hello',)
-type(self) in __init__: <class 'C'>
-Args in __init__: ('hello',)
-
-When we call ``C('hello')``, the ``__new__`` method gets its own class
-as first argument, and the passed argument, which is the string
-``'hello'``. After python calls ``__new__``, it usually (see below)
-calls our ``__init__`` method, with the output of ``__new__`` as the
-first argument (now a class instance), and the passed arguments
-following.
-
-As you can see, the object can be initialized in the ``__new__``
-method or the ``__init__`` method, or both, and in fact ndarray does
-not have an ``__init__`` method, because all the initialization is
-done in the ``__new__`` method.
-
-Why use ``__new__`` rather than just the usual ``__init__``? Because
-in some cases, as for ndarray, we want to be able to return an object
-of some other class. Consider the following:
-
-.. testcode::
-
- class D(C):
- def __new__(cls, *args):
- print('D cls is:', cls)
- print('D args in __new__:', args)
- return C.__new__(C, *args)
-
- def __init__(self, *args):
- # we never get here
- print('In D __init__')
-
-meaning that:
-
->>> obj = D('hello')
-D cls is: <class 'D'>
-D args in __new__: ('hello',)
-Cls in __new__: <class 'C'>
-Args in __new__: ('hello',)
->>> type(obj)
-<class 'C'>
-
-The definition of ``C`` is the same as before, but for ``D``, the
-``__new__`` method returns an instance of class ``C`` rather than
-``D``. Note that the ``__init__`` method of ``D`` does not get
-called. In general, when the ``__new__`` method returns an object of
-class other than the class in which it is defined, the ``__init__``
-method of that class is not called.
-
-This is how subclasses of the ndarray class are able to return views
-that preserve the class type. When taking a view, the standard
-ndarray machinery creates the new ndarray object with something
-like::
-
- obj = ndarray.__new__(subtype, shape, ...
-
-where ``subdtype`` is the subclass. Thus the returned view is of the
-same class as the subclass, rather than being of class ``ndarray``.
-
-That solves the problem of returning views of the same type, but now
-we have a new problem. The machinery of ndarray can set the class
-this way, in its standard methods for taking views, but the ndarray
-``__new__`` method knows nothing of what we have done in our own
-``__new__`` method in order to set attributes, and so on. (Aside -
-why not call ``obj = subdtype.__new__(...`` then? Because we may not
-have a ``__new__`` method with the same call signature).
-
-The role of ``__array_finalize__``
-==================================
-
-``__array_finalize__`` is the mechanism that numpy provides to allow
-subclasses to handle the various ways that new instances get created.
-
-Remember that subclass instances can come about in these three ways:
-
-#. explicit constructor call (``obj = MySubClass(params)``). This will
- call the usual sequence of ``MySubClass.__new__`` then (if it exists)
- ``MySubClass.__init__``.
-#. :ref:`view-casting`
-#. :ref:`new-from-template`
-
-Our ``MySubClass.__new__`` method only gets called in the case of the
-explicit constructor call, so we can't rely on ``MySubClass.__new__`` or
-``MySubClass.__init__`` to deal with the view casting and
-new-from-template. It turns out that ``MySubClass.__array_finalize__``
-*does* get called for all three methods of object creation, so this is
-where our object creation housekeeping usually goes.
-
-* For the explicit constructor call, our subclass will need to create a
- new ndarray instance of its own class. In practice this means that
- we, the authors of the code, will need to make a call to
- ``ndarray.__new__(MySubClass,...)``, a class-hierarchy prepared call to
- ``super(MySubClass, cls).__new__(cls, ...)``, or do view casting of an
- existing array (see below)
-* For view casting and new-from-template, the equivalent of
- ``ndarray.__new__(MySubClass,...`` is called, at the C level.
-
-The arguments that ``__array_finalize__`` receives differ for the three
-methods of instance creation above.
-
-The following code allows us to look at the call sequences and arguments:
-
-.. testcode::
-
- import numpy as np
-
- class C(np.ndarray):
- def __new__(cls, *args, **kwargs):
- print('In __new__ with class %s' % cls)
- return super(C, cls).__new__(cls, *args, **kwargs)
-
- def __init__(self, *args, **kwargs):
- # in practice you probably will not need or want an __init__
- # method for your subclass
- print('In __init__ with class %s' % self.__class__)
-
- def __array_finalize__(self, obj):
- print('In array_finalize:')
- print(' self type is %s' % type(self))
- print(' obj type is %s' % type(obj))
-
-
-Now:
-
->>> # Explicit constructor
->>> c = C((10,))
-In __new__ with class <class 'C'>
-In array_finalize:
- self type is <class 'C'>
- obj type is <type 'NoneType'>
-In __init__ with class <class 'C'>
->>> # View casting
->>> a = np.arange(10)
->>> cast_a = a.view(C)
-In array_finalize:
- self type is <class 'C'>
- obj type is <type 'numpy.ndarray'>
->>> # Slicing (example of new-from-template)
->>> cv = c[:1]
-In array_finalize:
- self type is <class 'C'>
- obj type is <class 'C'>
-
-The signature of ``__array_finalize__`` is::
-
- def __array_finalize__(self, obj):
-
-One sees that the ``super`` call, which goes to
-``ndarray.__new__``, passes ``__array_finalize__`` the new object, of our
-own class (``self``) as well as the object from which the view has been
-taken (``obj``). As you can see from the output above, the ``self`` is
-always a newly created instance of our subclass, and the type of ``obj``
-differs for the three instance creation methods:
-
-* When called from the explicit constructor, ``obj`` is ``None``
-* When called from view casting, ``obj`` can be an instance of any
- subclass of ndarray, including our own.
-* When called in new-from-template, ``obj`` is another instance of our
- own subclass, that we might use to update the new ``self`` instance.
-
-Because ``__array_finalize__`` is the only method that always sees new
-instances being created, it is the sensible place to fill in instance
-defaults for new object attributes, among other tasks.
-
-This may be clearer with an example.
-
-Simple example - adding an extra attribute to ndarray
------------------------------------------------------
-
-.. testcode::
-
- import numpy as np
-
- class InfoArray(np.ndarray):
-
- def __new__(subtype, shape, dtype=float, buffer=None, offset=0,
- strides=None, order=None, info=None):
- # Create the ndarray instance of our type, given the usual
- # ndarray input arguments. This will call the standard
- # ndarray constructor, but return an object of our type.
- # It also triggers a call to InfoArray.__array_finalize__
- obj = super(InfoArray, subtype).__new__(subtype, shape, dtype,
- buffer, offset, strides,
- order)
- # set the new 'info' attribute to the value passed
- obj.info = info
- # Finally, we must return the newly created object:
- return obj
-
- def __array_finalize__(self, obj):
- # ``self`` is a new object resulting from
- # ndarray.__new__(InfoArray, ...), therefore it only has
- # attributes that the ndarray.__new__ constructor gave it -
- # i.e. those of a standard ndarray.
- #
- # We could have got to the ndarray.__new__ call in 3 ways:
- # From an explicit constructor - e.g. InfoArray():
- # obj is None
- # (we're in the middle of the InfoArray.__new__
- # constructor, and self.info will be set when we return to
- # InfoArray.__new__)
- if obj is None: return
- # From view casting - e.g arr.view(InfoArray):
- # obj is arr
- # (type(obj) can be InfoArray)
- # From new-from-template - e.g infoarr[:3]
- # type(obj) is InfoArray
- #
- # Note that it is here, rather than in the __new__ method,
- # that we set the default value for 'info', because this
- # method sees all creation of default objects - with the
- # InfoArray.__new__ constructor, but also with
- # arr.view(InfoArray).
- self.info = getattr(obj, 'info', None)
- # We do not need to return anything
-
-
-Using the object looks like this:
-
- >>> obj = InfoArray(shape=(3,)) # explicit constructor
- >>> type(obj)
- <class 'InfoArray'>
- >>> obj.info is None
- True
- >>> obj = InfoArray(shape=(3,), info='information')
- >>> obj.info
- 'information'
- >>> v = obj[1:] # new-from-template - here - slicing
- >>> type(v)
- <class 'InfoArray'>
- >>> v.info
- 'information'
- >>> arr = np.arange(10)
- >>> cast_arr = arr.view(InfoArray) # view casting
- >>> type(cast_arr)
- <class 'InfoArray'>
- >>> cast_arr.info is None
- True
-
-This class isn't very useful, because it has the same constructor as the
-bare ndarray object, including passing in buffers and shapes and so on.
-We would probably prefer the constructor to be able to take an already
-formed ndarray from the usual numpy calls to ``np.array`` and return an
-object.
-
-Slightly more realistic example - attribute added to existing array
--------------------------------------------------------------------
-
-Here is a class that takes a standard ndarray that already exists, casts
-as our type, and adds an extra attribute.
-
-.. testcode::
-
- import numpy as np
-
- class RealisticInfoArray(np.ndarray):
-
- def __new__(cls, input_array, info=None):
- # Input array is an already formed ndarray instance
- # We first cast to be our class type
- obj = np.asarray(input_array).view(cls)
- # add the new attribute to the created instance
- obj.info = info
- # Finally, we must return the newly created object:
- return obj
-
- def __array_finalize__(self, obj):
- # see InfoArray.__array_finalize__ for comments
- if obj is None: return
- self.info = getattr(obj, 'info', None)
-
-
-So:
-
- >>> arr = np.arange(5)
- >>> obj = RealisticInfoArray(arr, info='information')
- >>> type(obj)
- <class 'RealisticInfoArray'>
- >>> obj.info
- 'information'
- >>> v = obj[1:]
- >>> type(v)
- <class 'RealisticInfoArray'>
- >>> v.info
- 'information'
-
-.. _array-ufunc:
-
-``__array_ufunc__`` for ufuncs
-------------------------------
-
- .. versionadded:: 1.13
-
-A subclass can override what happens when executing numpy ufuncs on it by
-overriding the default ``ndarray.__array_ufunc__`` method. This method is
-executed *instead* of the ufunc and should return either the result of the
-operation, or :obj:`NotImplemented` if the operation requested is not
-implemented.
-
-The signature of ``__array_ufunc__`` is::
-
- def __array_ufunc__(ufunc, method, *inputs, **kwargs):
-
- - *ufunc* is the ufunc object that was called.
- - *method* is a string indicating how the Ufunc was called, either
- ``"__call__"`` to indicate it was called directly, or one of its
- :ref:`methods<ufuncs.methods>`: ``"reduce"``, ``"accumulate"``,
- ``"reduceat"``, ``"outer"``, or ``"at"``.
- - *inputs* is a tuple of the input arguments to the ``ufunc``
- - *kwargs* contains any optional or keyword arguments passed to the
- function. This includes any ``out`` arguments, which are always
- contained in a tuple.
-
-A typical implementation would convert any inputs or outputs that are
-instances of one's own class, pass everything on to a superclass using
-``super()``, and finally return the results after possible
-back-conversion. An example, taken from the test case
-``test_ufunc_override_with_super`` in ``core/tests/test_umath.py``, is the
-following.
-
-.. testcode::
-
- input numpy as np
-
- class A(np.ndarray):
- def __array_ufunc__(self, ufunc, method, *inputs, out=None, **kwargs):
- args = []
- in_no = []
- for i, input_ in enumerate(inputs):
- if isinstance(input_, A):
- in_no.append(i)
- args.append(input_.view(np.ndarray))
- else:
- args.append(input_)
-
- outputs = out
- out_no = []
- if outputs:
- out_args = []
- for j, output in enumerate(outputs):
- if isinstance(output, A):
- out_no.append(j)
- out_args.append(output.view(np.ndarray))
- else:
- out_args.append(output)
- kwargs['out'] = tuple(out_args)
- else:
- outputs = (None,) * ufunc.nout
-
- info = {}
- if in_no:
- info['inputs'] = in_no
- if out_no:
- info['outputs'] = out_no
-
- results = super(A, self).__array_ufunc__(ufunc, method,
- *args, **kwargs)
- if results is NotImplemented:
- return NotImplemented
-
- if method == 'at':
- if isinstance(inputs[0], A):
- inputs[0].info = info
- return
-
- if ufunc.nout == 1:
- results = (results,)
-
- results = tuple((np.asarray(result).view(A)
- if output is None else output)
- for result, output in zip(results, outputs))
- if results and isinstance(results[0], A):
- results[0].info = info
-
- return results[0] if len(results) == 1 else results
-
-So, this class does not actually do anything interesting: it just
-converts any instances of its own to regular ndarray (otherwise, we'd
-get infinite recursion!), and adds an ``info`` dictionary that tells
-which inputs and outputs it converted. Hence, e.g.,
-
->>> a = np.arange(5.).view(A)
->>> b = np.sin(a)
->>> b.info
-{'inputs': [0]}
->>> b = np.sin(np.arange(5.), out=(a,))
->>> b.info
-{'outputs': [0]}
->>> a = np.arange(5.).view(A)
->>> b = np.ones(1).view(A)
->>> c = a + b
->>> c.info
-{'inputs': [0, 1]}
->>> a += b
->>> a.info
-{'inputs': [0, 1], 'outputs': [0]}
-
-Note that another approach would be to to use ``getattr(ufunc,
-methods)(*inputs, **kwargs)`` instead of the ``super`` call. For this example,
-the result would be identical, but there is a difference if another operand
-also defines ``__array_ufunc__``. E.g., lets assume that we evalulate
-``np.add(a, b)``, where ``b`` is an instance of another class ``B`` that has
-an override. If you use ``super`` as in the example,
-``ndarray.__array_ufunc__`` will notice that ``b`` has an override, which
-means it cannot evaluate the result itself. Thus, it will return
-`NotImplemented` and so will our class ``A``. Then, control will be passed
-over to ``b``, which either knows how to deal with us and produces a result,
-or does not and returns `NotImplemented`, raising a ``TypeError``.
-
-If instead, we replace our ``super`` call with ``getattr(ufunc, method)``, we
-effectively do ``np.add(a.view(np.ndarray), b)``. Again, ``B.__array_ufunc__``
-will be called, but now it sees an ``ndarray`` as the other argument. Likely,
-it will know how to handle this, and return a new instance of the ``B`` class
-to us. Our example class is not set up to handle this, but it might well be
-the best approach if, e.g., one were to re-implement ``MaskedArray`` using
-``__array_ufunc__``.
-
-As a final note: if the ``super`` route is suited to a given class, an
-advantage of using it is that it helps in constructing class hierarchies.
-E.g., suppose that our other class ``B`` also used the ``super`` in its
-``__array_ufunc__`` implementation, and we created a class ``C`` that depended
-on both, i.e., ``class C(A, B)`` (with, for simplicity, not another
-``__array_ufunc__`` override). Then any ufunc on an instance of ``C`` would
-pass on to ``A.__array_ufunc__``, the ``super`` call in ``A`` would go to
-``B.__array_ufunc__``, and the ``super`` call in ``B`` would go to
-``ndarray.__array_ufunc__``, thus allowing ``A`` and ``B`` to collaborate.
-
-.. _array-wrap:
-
-``__array_wrap__`` for ufuncs and other functions
--------------------------------------------------
-
-Prior to numpy 1.13, the behaviour of ufuncs could only be tuned using
-``__array_wrap__`` and ``__array_prepare__``. These two allowed one to
-change the output type of a ufunc, but, in contrast to
-``__array_ufunc__``, did not allow one to make any changes to the inputs.
-It is hoped to eventually deprecate these, but ``__array_wrap__`` is also
-used by other numpy functions and methods, such as ``squeeze``, so at the
-present time is still needed for full functionality.
-
-Conceptually, ``__array_wrap__`` "wraps up the action" in the sense of
-allowing a subclass to set the type of the return value and update
-attributes and metadata. Let's show how this works with an example. First
-we return to the simpler example subclass, but with a different name and
-some print statements:
-
-.. testcode::
-
- import numpy as np
-
- class MySubClass(np.ndarray):
-
- def __new__(cls, input_array, info=None):
- obj = np.asarray(input_array).view(cls)
- obj.info = info
- return obj
-
- def __array_finalize__(self, obj):
- print('In __array_finalize__:')
- print(' self is %s' % repr(self))
- print(' obj is %s' % repr(obj))
- if obj is None: return
- self.info = getattr(obj, 'info', None)
-
- def __array_wrap__(self, out_arr, context=None):
- print('In __array_wrap__:')
- print(' self is %s' % repr(self))
- print(' arr is %s' % repr(out_arr))
- # then just call the parent
- return super(MySubClass, self).__array_wrap__(self, out_arr, context)
-
-We run a ufunc on an instance of our new array:
-
->>> obj = MySubClass(np.arange(5), info='spam')
-In __array_finalize__:
- self is MySubClass([0, 1, 2, 3, 4])
- obj is array([0, 1, 2, 3, 4])
->>> arr2 = np.arange(5)+1
->>> ret = np.add(arr2, obj)
-In __array_wrap__:
- self is MySubClass([0, 1, 2, 3, 4])
- arr is array([1, 3, 5, 7, 9])
-In __array_finalize__:
- self is MySubClass([1, 3, 5, 7, 9])
- obj is MySubClass([0, 1, 2, 3, 4])
->>> ret
-MySubClass([1, 3, 5, 7, 9])
->>> ret.info
-'spam'
-
-Note that the ufunc (``np.add``) has called the ``__array_wrap__`` method
-with arguments ``self`` as ``obj``, and ``out_arr`` as the (ndarray) result
-of the addition. In turn, the default ``__array_wrap__``
-(``ndarray.__array_wrap__``) has cast the result to class ``MySubClass``,
-and called ``__array_finalize__`` - hence the copying of the ``info``
-attribute. This has all happened at the C level.
-
-But, we could do anything we wanted:
-
-.. testcode::
-
- class SillySubClass(np.ndarray):
-
- def __array_wrap__(self, arr, context=None):
- return 'I lost your data'
-
->>> arr1 = np.arange(5)
->>> obj = arr1.view(SillySubClass)
->>> arr2 = np.arange(5)
->>> ret = np.multiply(obj, arr2)
->>> ret
-'I lost your data'
-
-So, by defining a specific ``__array_wrap__`` method for our subclass,
-we can tweak the output from ufuncs. The ``__array_wrap__`` method
-requires ``self``, then an argument - which is the result of the ufunc -
-and an optional parameter *context*. This parameter is returned by
-ufuncs as a 3-element tuple: (name of the ufunc, arguments of the ufunc,
-domain of the ufunc), but is not set by other numpy functions. Though,
-as seen above, it is possible to do otherwise, ``__array_wrap__`` should
-return an instance of its containing class. See the masked array
-subclass for an implementation.
-
-In addition to ``__array_wrap__``, which is called on the way out of the
-ufunc, there is also an ``__array_prepare__`` method which is called on
-the way into the ufunc, after the output arrays are created but before any
-computation has been performed. The default implementation does nothing
-but pass through the array. ``__array_prepare__`` should not attempt to
-access the array data or resize the array, it is intended for setting the
-output array type, updating attributes and metadata, and performing any
-checks based on the input that may be desired before computation begins.
-Like ``__array_wrap__``, ``__array_prepare__`` must return an ndarray or
-subclass thereof or raise an error.
-
-Extra gotchas - custom ``__del__`` methods and ndarray.base
------------------------------------------------------------
-
-One of the problems that ndarray solves is keeping track of memory
-ownership of ndarrays and their views. Consider the case where we have
-created an ndarray, ``arr`` and have taken a slice with ``v = arr[1:]``.
-The two objects are looking at the same memory. NumPy keeps track of
-where the data came from for a particular array or view, with the
-``base`` attribute:
-
->>> # A normal ndarray, that owns its own data
->>> arr = np.zeros((4,))
->>> # In this case, base is None
->>> arr.base is None
-True
->>> # We take a view
->>> v1 = arr[1:]
->>> # base now points to the array that it derived from
->>> v1.base is arr
-True
->>> # Take a view of a view
->>> v2 = v1[1:]
->>> # base points to the view it derived from
->>> v2.base is v1
-True
-
-In general, if the array owns its own memory, as for ``arr`` in this
-case, then ``arr.base`` will be None - there are some exceptions to this
-- see the numpy book for more details.
-
-The ``base`` attribute is useful in being able to tell whether we have
-a view or the original array. This in turn can be useful if we need
-to know whether or not to do some specific cleanup when the subclassed
-array is deleted. For example, we may only want to do the cleanup if
-the original array is deleted, but not the views. For an example of
-how this can work, have a look at the ``memmap`` class in
-``numpy.core``.
-
-Subclassing and Downstream Compatibility
-----------------------------------------
-
-When sub-classing ``ndarray`` or creating duck-types that mimic the ``ndarray``
-interface, it is your responsibility to decide how aligned your APIs will be
-with those of numpy. For convenience, many numpy functions that have a corresponding
-``ndarray`` method (e.g., ``sum``, ``mean``, ``take``, ``reshape``) work by checking
-if the first argument to a function has a method of the same name. If it exists, the
-method is called instead of coercing the arguments to a numpy array.
-
-For example, if you want your sub-class or duck-type to be compatible with
-numpy's ``sum`` function, the method signature for this object's ``sum`` method
-should be the following:
-
-.. testcode::
-
- def sum(self, axis=None, dtype=None, out=None, keepdims=False):
- ...
-
-This is the exact same method signature for ``np.sum``, so now if a user calls
-``np.sum`` on this object, numpy will call the object's own ``sum`` method and
-pass in these arguments enumerated above in the signature, and no errors will
-be raised because the signatures are completely compatible with each other.
-
-If, however, you decide to deviate from this signature and do something like this:
-
-.. testcode::
-
- def sum(self, axis=None, dtype=None):
- ...
-
-This object is no longer compatible with ``np.sum`` because if you call ``np.sum``,
-it will pass in unexpected arguments ``out`` and ``keepdims``, causing a TypeError
-to be raised.
-
-If you wish to maintain compatibility with numpy and its subsequent versions (which
-might add new keyword arguments) but do not want to surface all of numpy's arguments,
-your function's signature should accept ``**kwargs``. For example:
-
-.. testcode::
-
- def sum(self, axis=None, dtype=None, **unused_kwargs):
- ...
-
-This object is now compatible with ``np.sum`` again because any extraneous arguments
-(i.e. keywords that are not ``axis`` or ``dtype``) will be hidden away in the
-``**unused_kwargs`` parameter.
-
-"""
"""
-Aliases for functions which may be accelerated by Scipy.
+.. deprecated:: 1.20
-Scipy_ can be built to use accelerated or otherwise improved libraries
+*This module is deprecated. Instead of importing functions from*
+``numpy.dual``, *the functions should be imported directly from NumPy
+or SciPy*.
+
+Aliases for functions which may be accelerated by SciPy.
+
+SciPy_ can be built to use accelerated or otherwise improved libraries
for FFTs, linear algebra, and special functions. This module allows
developers to transparently support these accelerated functions when
-scipy is available but still support users who have only installed
+SciPy is available but still support users who have only installed
NumPy.
-.. _Scipy : https://www.scipy.org
+.. _SciPy : https://www.scipy.org
"""
+import warnings
+
+
+warnings.warn('The module numpy.dual is deprecated. Instead of using dual, '
+ 'use the functions directly from numpy or scipy.',
+ category=DeprecationWarning,
+ stacklevel=2)
+
# This module should be used for functions both in numpy and scipy if
# you want to use the numpy version if available but the scipy version
# otherwise.
--- /dev/null
+from typing import Any
+
+sqrt: Any
+log: Any
+log2: Any
+logn: Any
+log10: Any
+power: Any
+arccos: Any
+arcsin: Any
+arctanh: Any
import os
from . import f2py2e
-from . import f2py_testing
from . import diagnose
run_main = f2py2e.run_main
extra_args='',
verbose=True,
source_fn=None,
- extension='.f'
+ extension='.f',
+ full_output=False
):
"""
Build extension module from a Fortran 77 source string with f2py.
.. versionadded:: 1.11.0
+ full_output : bool, optional
+ If True, return a `subprocess.CompletedProcess` containing
+ the stdout and stderr of the compile process, instead of just
+ the status code.
+
+ .. versionadded:: 1.20.0
+
+
Returns
-------
- result : int
- 0 on success
+ result : int or `subprocess.CompletedProcess`
+ 0 on success, or a `subprocess.CompletedProcess` if
+ ``full_output=True``
Examples
--------
'-c',
'import numpy.f2py as f2py2e;f2py2e.main()'] + args
try:
- output = subprocess.check_output(c)
- except subprocess.CalledProcessError as exc:
- status = exc.returncode
- output = ''
+ cp = subprocess.run(c, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
except OSError:
# preserve historic status code used by exec_command()
- status = 127
- output = ''
+ cp = subprocess.CompletedProcess(c, 127, stdout=b'', stderr=b'')
else:
- status = 0
- output = output.decode()
- if verbose:
- print(output)
+ if verbose:
+ print(cp.stdout.decode())
finally:
if source_fn is None:
os.remove(fname)
- return status
-from numpy._pytesttester import PytestTester
-test = PytestTester(__name__)
-del PytestTester
+ if full_output:
+ return cp
+ else:
+ return cp.returncode
+
+
+if sys.version_info[:2] >= (3, 7):
+ # module level getattr is only supported in 3.7 onwards
+ # https://www.python.org/dev/peps/pep-0562/
+ def __getattr__(attr):
+
+ # Avoid importing things that aren't needed for building
+ # which might import the main numpy module
+ if attr == "f2py_testing":
+ import numpy.f2py.f2py_testing as f2py_testing
+ return f2py_testing
+
+ elif attr == "test":
+ from numpy._pytesttester import PytestTester
+ test = PytestTester(__name__)
+ return test
+
+ else:
+ raise AttributeError("module {!r} has no attribute "
+ "{!r}".format(__name__, attr))
+
+ def __dir__():
+ return list(globals().keys() | {"f2py_testing", "test"})
+
+else:
+ from . import f2py_testing
+
+ from numpy._pytesttester import PytestTester
+ test = PytestTester(__name__)
+ del PytestTester
--- /dev/null
+from typing import Any
+
+run_main: Any
+compile: Any
+f2py_testing: Any
'cbtypedefs': 'typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);',
'body': """
#begintitle#
-PyObject *#name#_capi = NULL;/*was Py_None*/
-PyTupleObject *#name#_args_capi = NULL;
-int #name#_nofargs = 0;
-jmp_buf #name#_jmpbuf;
+typedef struct {
+ PyObject *capi;
+ PyTupleObject *args_capi;
+ int nofargs;
+ jmp_buf jmpbuf;
+} #name#_t;
+
+#if defined(F2PY_THREAD_LOCAL_DECL) && !defined(F2PY_USE_PYTHON_TLS)
+
+static F2PY_THREAD_LOCAL_DECL #name#_t *_active_#name# = NULL;
+
+static #name#_t *swap_active_#name#(#name#_t *ptr) {
+ #name#_t *prev = _active_#name#;
+ _active_#name# = ptr;
+ return prev;
+}
+
+static #name#_t *get_active_#name#(void) {
+ return _active_#name#;
+}
+
+#else
+
+static #name#_t *swap_active_#name#(#name#_t *ptr) {
+ char *key = "__f2py_cb_#name#";
+ return (#name#_t *)F2PySwapThreadLocalCallbackPtr(key, ptr);
+}
+
+static #name#_t *get_active_#name#(void) {
+ char *key = "__f2py_cb_#name#";
+ return (#name#_t *)F2PyGetThreadLocalCallbackPtr(key);
+}
+
+#endif
+
/*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/
#static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) {
-\tPyTupleObject *capi_arglist = #name#_args_capi;
-\tPyObject *capi_return = NULL;
-\tPyObject *capi_tmp = NULL;
-\tPyObject *capi_arglist_list = NULL;
-\tint capi_j,capi_i = 0;
-\tint capi_longjmp_ok = 1;
+ #name#_t *cb;
+ PyTupleObject *capi_arglist = NULL;
+ PyObject *capi_return = NULL;
+ PyObject *capi_tmp = NULL;
+ PyObject *capi_arglist_list = NULL;
+ int capi_j,capi_i = 0;
+ int capi_longjmp_ok = 1;
#decl#
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_start_clock();
#endif
-\tCFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\");
-\tCFUNCSMESSPY(\"cb:#name#_capi=\",#name#_capi);
-\tif (#name#_capi==NULL) {
-\t\tcapi_longjmp_ok = 0;
-\t\t#name#_capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\");
-\t}
-\tif (#name#_capi==NULL) {
-\t\tPyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\");
-\t\tgoto capi_fail;
-\t}
-\tif (F2PyCapsule_Check(#name#_capi)) {
-\t#name#_typedef #name#_cptr;
-\t#name#_cptr = F2PyCapsule_AsVoidPtr(#name#_capi);
-\t#returncptr#(*#name#_cptr)(#optargs_nm##args_nm##strarglens_nm#);
-\t#return#
-\t}
-\tif (capi_arglist==NULL) {
-\t\tcapi_longjmp_ok = 0;
-\t\tcapi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\");
-\t\tif (capi_tmp) {
-\t\t\tcapi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp);
-\t\t\tif (capi_arglist==NULL) {
-\t\t\t\tPyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\");
-\t\t\t\tgoto capi_fail;
-\t\t\t}
-\t\t} else {
-\t\t\tPyErr_Clear();
-\t\t\tcapi_arglist = (PyTupleObject *)Py_BuildValue(\"()\");
-\t\t}
-\t}
-\tif (capi_arglist == NULL) {
-\t\tPyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\");
-\t\tgoto capi_fail;
-\t}
+ cb = get_active_#name#();
+ capi_arglist = cb->args_capi;
+ CFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\");
+ CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
+ if (cb->capi==NULL) {
+ capi_longjmp_ok = 0;
+ cb->capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\");
+ }
+ if (cb->capi==NULL) {
+ PyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\");
+ goto capi_fail;
+ }
+ if (F2PyCapsule_Check(cb->capi)) {
+ #name#_typedef #name#_cptr;
+ #name#_cptr = F2PyCapsule_AsVoidPtr(cb->capi);
+ #returncptr#(*#name#_cptr)(#optargs_nm##args_nm##strarglens_nm#);
+ #return#
+ }
+ if (capi_arglist==NULL) {
+ capi_longjmp_ok = 0;
+ capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\");
+ if (capi_tmp) {
+ capi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp);
+ if (capi_arglist==NULL) {
+ PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\");
+ goto capi_fail;
+ }
+ } else {
+ PyErr_Clear();
+ capi_arglist = (PyTupleObject *)Py_BuildValue(\"()\");
+ }
+ }
+ if (capi_arglist == NULL) {
+ PyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\");
+ goto capi_fail;
+ }
#setdims#
#ifdef PYPY_VERSION
#define CAPI_ARGLIST_SETITEM(idx, value) PyList_SetItem((PyObject *)capi_arglist_list, idx, value)
-\tcapi_arglist_list = PySequence_List(capi_arglist);
-\tif (capi_arglist_list == NULL) goto capi_fail;
+ capi_arglist_list = PySequence_List(capi_arglist);
+ if (capi_arglist_list == NULL) goto capi_fail;
#else
#define CAPI_ARGLIST_SETITEM(idx, value) PyTuple_SetItem((PyObject *)capi_arglist, idx, value)
#endif
#pyobjfrom#
#undef CAPI_ARGLIST_SETITEM
#ifdef PYPY_VERSION
-\tCFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist_list);
+ CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist_list);
#else
-\tCFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist);
+ CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist);
#endif
-\tCFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\");
+ CFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\");
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_start_call_clock();
#endif
#ifdef PYPY_VERSION
-\tcapi_return = PyObject_CallObject(#name#_capi,(PyObject *)capi_arglist_list);
-\tPy_DECREF(capi_arglist_list);
-\tcapi_arglist_list = NULL;
+ capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist_list);
+ Py_DECREF(capi_arglist_list);
+ capi_arglist_list = NULL;
#else
-\tcapi_return = PyObject_CallObject(#name#_capi,(PyObject *)capi_arglist);
+ capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist);
#endif
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_stop_call_clock();
#endif
-\tCFUNCSMESSPY(\"cb:capi_return=\",capi_return);
-\tif (capi_return == NULL) {
-\t\tfprintf(stderr,\"capi_return is NULL\\n\");
-\t\tgoto capi_fail;
-\t}
-\tif (capi_return == Py_None) {
-\t\tPy_DECREF(capi_return);
-\t\tcapi_return = Py_BuildValue(\"()\");
-\t}
-\telse if (!PyTuple_Check(capi_return)) {
-\t\tcapi_return = Py_BuildValue(\"(N)\",capi_return);
-\t}
-\tcapi_j = PyTuple_Size(capi_return);
-\tcapi_i = 0;
+ CFUNCSMESSPY(\"cb:capi_return=\",capi_return);
+ if (capi_return == NULL) {
+ fprintf(stderr,\"capi_return is NULL\\n\");
+ goto capi_fail;
+ }
+ if (capi_return == Py_None) {
+ Py_DECREF(capi_return);
+ capi_return = Py_BuildValue(\"()\");
+ }
+ else if (!PyTuple_Check(capi_return)) {
+ capi_return = Py_BuildValue(\"(N)\",capi_return);
+ }
+ capi_j = PyTuple_Size(capi_return);
+ capi_i = 0;
#frompyobj#
-\tCFUNCSMESS(\"cb:#name#:successful\\n\");
-\tPy_DECREF(capi_return);
+ CFUNCSMESS(\"cb:#name#:successful\\n\");
+ Py_DECREF(capi_return);
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_stop_clock();
#endif
-\tgoto capi_return_pt;
+ goto capi_return_pt;
capi_fail:
-\tfprintf(stderr,\"Call-back #name# failed.\\n\");
-\tPy_XDECREF(capi_return);
-\tPy_XDECREF(capi_arglist_list);
-\tif (capi_longjmp_ok)
-\t\tlongjmp(#name#_jmpbuf,-1);
+ fprintf(stderr,\"Call-back #name# failed.\\n\");
+ Py_XDECREF(capi_return);
+ Py_XDECREF(capi_arglist_list);
+ if (capi_longjmp_ok) {
+ longjmp(cb->jmpbuf,-1);
+ }
capi_return_pt:
-\t;
+ ;
#return#
}
#endtitle#
""",
- 'need': ['setjmp.h', 'CFUNCSMESS'],
+ 'need': ['setjmp.h', 'CFUNCSMESS', 'F2PY_THREAD_LOCAL_DECL'],
'maxnofargs': '#maxnofargs#',
'nofoptargs': '#nofoptargs#',
'docstr': """\
'latexdocstrcbs': '\\noindent Call-back functions:',
'routnote': {hasnote: '--- #note#', l_not(hasnote): ''},
}, { # Function
- 'decl': '\t#ctype# return_value;',
- 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting return_value->");'},
- '\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n");',
+ 'decl': ' #ctype# return_value;',
+ 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
+ ' if (capi_j>capi_i)\n GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n");',
{debugcapi:
- '\tfprintf(stderr,"#showvalueformat#.\\n",return_value);'}
+ ' fprintf(stderr,"#showvalueformat#.\\n",return_value);'}
],
'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'}, 'GETSCALARFROMPYTUPLE'],
- 'return': '\treturn return_value;',
+ 'return': ' return return_value;',
'_check': l_and(isfunction, l_not(isstringfunction), l_not(iscomplexfunction))
},
{ # String function
- 'pyobjfrom': {debugcapi: '\tfprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'},
+ 'pyobjfrom': {debugcapi: ' fprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'},
'args': '#ctype# return_value,int return_value_len',
'args_nm': 'return_value,&return_value_len',
'args_td': '#ctype# ,int',
- 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting return_value->\\"");'},
- """\tif (capi_j>capi_i)
-\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);""",
+ 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting return_value->\\"");'},
+ """ if (capi_j>capi_i)
+ GETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);""",
{debugcapi:
- '\tfprintf(stderr,"#showvalueformat#\\".\\n",return_value);'}
+ ' fprintf(stderr,"#showvalueformat#\\".\\n",return_value);'}
],
'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
'string.h', 'GETSTRFROMPYTUPLE'],
""",
'decl': """
#ifdef F2PY_CB_RETURNCOMPLEX
-\t#ctype# return_value;
+ #ctype# return_value;
#endif
""",
- 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting return_value->");'},
+ 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
"""\
-\tif (capi_j>capi_i)
+ if (capi_j>capi_i)
#ifdef F2PY_CB_RETURNCOMPLEX
-\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\");
+ GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\");
#else
-\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\");
+ GETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\");
#endif
""",
{debugcapi: """
#ifdef F2PY_CB_RETURNCOMPLEX
-\tfprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i);
+ fprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i);
#else
-\tfprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i);
+ fprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i);
#endif
"""}
],
'return': """
#ifdef F2PY_CB_RETURNCOMPLEX
-\treturn return_value;
+ return return_value;
#else
-\treturn;
+ return;
#endif
""",
'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
'strarglens_nm': {isstring: ',#varname_i#_cb_len'},
},
{ # Scalars
- 'decl': {l_not(isintent_c): '\t#ctype# #varname_i#=(*#varname_i#_cb_capi);'},
+ 'decl': {l_not(isintent_c): ' #ctype# #varname_i#=(*#varname_i#_cb_capi);'},
'error': {l_and(isintent_c, isintent_out,
throw_error('intent(c,out) is forbidden for callback scalar arguments')):
''},
- 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting #varname#->");'},
+ 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
{isintent_out:
- '\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname_i#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'},
+ ' if (capi_j>capi_i)\n GETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname_i#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'},
{l_and(debugcapi, l_and(l_not(iscomplex), isintent_c)):
- '\tfprintf(stderr,"#showvalueformat#.\\n",#varname_i#);'},
+ ' fprintf(stderr,"#showvalueformat#.\\n",#varname_i#);'},
{l_and(debugcapi, l_and(l_not(iscomplex), l_not( isintent_c))):
- '\tfprintf(stderr,"#showvalueformat#.\\n",*#varname_i#_cb_capi);'},
+ ' fprintf(stderr,"#showvalueformat#.\\n",*#varname_i#_cb_capi);'},
{l_and(debugcapi, l_and(iscomplex, isintent_c)):
- '\tfprintf(stderr,"#showvalueformat#.\\n",(#varname_i#).r,(#varname_i#).i);'},
+ ' fprintf(stderr,"#showvalueformat#.\\n",(#varname_i#).r,(#varname_i#).i);'},
{l_and(debugcapi, l_and(iscomplex, l_not( isintent_c))):
- '\tfprintf(stderr,"#showvalueformat#.\\n",(*#varname_i#_cb_capi).r,(*#varname_i#_cb_capi).i);'},
+ ' fprintf(stderr,"#showvalueformat#.\\n",(*#varname_i#_cb_capi).r,(*#varname_i#_cb_capi).i);'},
],
'need': [{isintent_out: ['#ctype#_from_pyobj', 'GETSCALARFROMPYTUPLE']},
{debugcapi: 'CFUNCSMESS'}],
'_check': isscalar
}, {
'pyobjfrom': [{isintent_in: """\
-\tif (#name#_nofargs>capi_i)
-\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1(#varname_i#)))
-\t\t\tgoto capi_fail;"""},
+ if (cb->nofargs>capi_i)
+ if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1(#varname_i#)))
+ goto capi_fail;"""},
{isintent_inout: """\
-\tif (#name#_nofargs>capi_i)
-\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#_cb_capi)))
-\t\t\tgoto capi_fail;"""}],
+ if (cb->nofargs>capi_i)
+ if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#_cb_capi)))
+ goto capi_fail;"""}],
'need': [{isintent_in: 'pyobj_from_#ctype#1'},
{isintent_inout: 'pyarr_from_p_#ctype#1'},
{iscomplex: '#ctype#'}],
'_check': l_and(isscalar, isintent_nothide),
'_optional': ''
}, { # String
- 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting #varname#->\\"");'},
- """\tif (capi_j>capi_i)
-\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,#varname_i#,#varname_i#_cb_len);""",
+ 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->\\"");'},
+ """ if (capi_j>capi_i)
+ GETSTRFROMPYTUPLE(capi_return,capi_i++,#varname_i#,#varname_i#_cb_len);""",
{debugcapi:
- '\tfprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname_i#,#varname_i#_cb_len);'},
+ ' fprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname_i#,#varname_i#_cb_len);'},
],
'need': ['#ctype#', 'GETSTRFROMPYTUPLE',
{debugcapi: 'CFUNCSMESS'}, 'string.h'],
'_check': l_and(isstring, isintent_out)
}, {
- 'pyobjfrom': [{debugcapi: '\tfprintf(stderr,"debug-capi:cb:#varname#=\\"#showvalueformat#\\":%d:\\n",#varname_i#,#varname_i#_cb_len);'},
+ 'pyobjfrom': [{debugcapi: ' fprintf(stderr,"debug-capi:cb:#varname#=\\"#showvalueformat#\\":%d:\\n",#varname_i#,#varname_i#_cb_len);'},
{isintent_in: """\
-\tif (#name#_nofargs>capi_i)
-\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1size(#varname_i#,#varname_i#_cb_len)))
-\t\t\tgoto capi_fail;"""},
+ if (cb->nofargs>capi_i)
+ if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1size(#varname_i#,#varname_i#_cb_len)))
+ goto capi_fail;"""},
{isintent_inout: """\
-\tif (#name#_nofargs>capi_i) {
-\t\tint #varname_i#_cb_dims[] = {#varname_i#_cb_len};
-\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#,#varname_i#_cb_dims)))
-\t\t\tgoto capi_fail;
-\t}"""}],
+ if (cb->nofargs>capi_i) {
+ int #varname_i#_cb_dims[] = {#varname_i#_cb_len};
+ if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#,#varname_i#_cb_dims)))
+ goto capi_fail;
+ }"""}],
'need': [{isintent_in: 'pyobj_from_#ctype#1size'},
{isintent_inout: 'pyarr_from_p_#ctype#1'}],
'_check': l_and(isstring, isintent_nothide),
},
# Array ...
{
- 'decl': '\tnpy_intp #varname_i#_Dims[#rank#] = {#rank*[-1]#};',
- 'setdims': '\t#cbsetdims#;',
+ 'decl': ' npy_intp #varname_i#_Dims[#rank#] = {#rank*[-1]#};',
+ 'setdims': ' #cbsetdims#;',
'_check': isarray,
'_depend': ''
},
{
- 'pyobjfrom': [{debugcapi: '\tfprintf(stderr,"debug-capi:cb:#varname#\\n");'},
+ 'pyobjfrom': [{debugcapi: ' fprintf(stderr,"debug-capi:cb:#varname#\\n");'},
{isintent_c: """\
-\tif (#name#_nofargs>capi_i) {
-\t\tint itemsize_ = #atype# == NPY_STRING ? 1 : 0;
-\t\t/*XXX: Hmm, what will destroy this array??? */
-\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,itemsize_,NPY_ARRAY_CARRAY,NULL);
+ if (cb->nofargs>capi_i) {
+ int itemsize_ = #atype# == NPY_STRING ? 1 : 0;
+ /*XXX: Hmm, what will destroy this array??? */
+ PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,itemsize_,NPY_ARRAY_CARRAY,NULL);
""",
l_not(isintent_c): """\
-\tif (#name#_nofargs>capi_i) {
-\t\tint itemsize_ = #atype# == NPY_STRING ? 1 : 0;
-\t\t/*XXX: Hmm, what will destroy this array??? */
-\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,itemsize_,NPY_ARRAY_FARRAY,NULL);
+ if (cb->nofargs>capi_i) {
+ int itemsize_ = #atype# == NPY_STRING ? 1 : 0;
+ /*XXX: Hmm, what will destroy this array??? */
+ PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,itemsize_,NPY_ARRAY_FARRAY,NULL);
""",
},
"""
-\t\tif (tmp_arr==NULL)
-\t\t\tgoto capi_fail;
-\t\tif (CAPI_ARGLIST_SETITEM(capi_i++,(PyObject *)tmp_arr))
-\t\t\tgoto capi_fail;
+ if (tmp_arr==NULL)
+ goto capi_fail;
+ if (CAPI_ARGLIST_SETITEM(capi_i++,(PyObject *)tmp_arr))
+ goto capi_fail;
}"""],
'_check': l_and(isarray, isintent_nothide, l_or(isintent_in, isintent_inout)),
'_optional': '',
}, {
- 'frompyobj': [{debugcapi: '\tCFUNCSMESS("cb:Getting #varname#->");'},
- """\tif (capi_j>capi_i) {
-\t\tPyArrayObject *rv_cb_arr = NULL;
-\t\tif ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail;
-\t\trv_cb_arr = array_from_pyobj(#atype#,#varname_i#_Dims,#rank#,F2PY_INTENT_IN""",
+ 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
+ """ if (capi_j>capi_i) {
+ PyArrayObject *rv_cb_arr = NULL;
+ if ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail;
+ rv_cb_arr = array_from_pyobj(#atype#,#varname_i#_Dims,#rank#,F2PY_INTENT_IN""",
{isintent_c: '|F2PY_INTENT_C'},
""",capi_tmp);
-\t\tif (rv_cb_arr == NULL) {
-\t\t\tfprintf(stderr,\"rv_cb_arr is NULL\\n\");
-\t\t\tgoto capi_fail;
-\t\t}
-\t\tMEMCOPY(#varname_i#,PyArray_DATA(rv_cb_arr),PyArray_NBYTES(rv_cb_arr));
-\t\tif (capi_tmp != (PyObject *)rv_cb_arr) {
-\t\t\tPy_DECREF(rv_cb_arr);
-\t\t}
-\t}""",
- {debugcapi: '\tfprintf(stderr,"<-.\\n");'},
+ if (rv_cb_arr == NULL) {
+ fprintf(stderr,\"rv_cb_arr is NULL\\n\");
+ goto capi_fail;
+ }
+ MEMCOPY(#varname_i#,PyArray_DATA(rv_cb_arr),PyArray_NBYTES(rv_cb_arr));
+ if (capi_tmp != (PyObject *)rv_cb_arr) {
+ Py_DECREF(rv_cb_arr);
+ }
+ }""",
+ {debugcapi: ' fprintf(stderr,"<-.\\n");'},
],
'need': ['MEMCOPY', {iscomplexarray: '#ctype#'}],
'_check': l_and(isarray, isintent_out)
"""
cppmacros[
- 'pyobj_from_char1'] = '#define pyobj_from_char1(v) (PyInt_FromLong(v))'
+ 'pyobj_from_char1'] = '#define pyobj_from_char1(v) (PyLong_FromLong(v))'
cppmacros[
- 'pyobj_from_short1'] = '#define pyobj_from_short1(v) (PyInt_FromLong(v))'
+ 'pyobj_from_short1'] = '#define pyobj_from_short1(v) (PyLong_FromLong(v))'
needs['pyobj_from_int1'] = ['signed_char']
-cppmacros['pyobj_from_int1'] = '#define pyobj_from_int1(v) (PyInt_FromLong(v))'
+cppmacros['pyobj_from_int1'] = '#define pyobj_from_int1(v) (PyLong_FromLong(v))'
cppmacros[
'pyobj_from_long1'] = '#define pyobj_from_long1(v) (PyLong_FromLong(v))'
needs['pyobj_from_long_long1'] = ['long_long']
'pyobj_from_complex_float1'] = '#define pyobj_from_complex_float1(v) (PyComplex_FromDoubles(v.r,v.i))'
needs['pyobj_from_string1'] = ['string']
cppmacros[
- 'pyobj_from_string1'] = '#define pyobj_from_string1(v) (PyString_FromString((char *)v))'
+ 'pyobj_from_string1'] = '#define pyobj_from_string1(v) (PyUnicode_FromString((char *)v))'
needs['pyobj_from_string1size'] = ['string']
cppmacros[
- 'pyobj_from_string1size'] = '#define pyobj_from_string1size(v,len) (PyUString_FromStringAndSize((char *)v, len))'
+ 'pyobj_from_string1size'] = '#define pyobj_from_string1size(v,len) (PyUnicode_FromStringAndSize((char *)v, len))'
needs['TRYPYARRAYTEMPLATE'] = ['PRINTPYOBJERR']
cppmacros['TRYPYARRAYTEMPLATE'] = """\
/* New SciPy */
PyObject *rv_cb_str = PyTuple_GetItem((tuple),(index));\\
if (rv_cb_str == NULL)\\
goto capi_fail;\\
- if (PyString_Check(rv_cb_str)) {\\
+ if (PyBytes_Check(rv_cb_str)) {\\
str[len-1]='\\0';\\
- STRINGCOPYN((str),PyString_AS_STRING((PyStringObject*)rv_cb_str),(len));\\
+ STRINGCOPYN((str),PyBytes_AS_STRING((PyBytesObject*)rv_cb_str),(len));\\
} else {\\
PRINTPYOBJERR(rv_cb_str);\\
PyErr_SetString(#modulename#_error,\"string object expected\");\\
#error You need to install NumPy version 0.13 or higher. See https://scipy.org/install.html
#endif
"""
+cppmacros["F2PY_THREAD_LOCAL_DECL"] = """\
+#ifndef F2PY_THREAD_LOCAL_DECL
+#if defined(_MSC_VER)
+#define F2PY_THREAD_LOCAL_DECL __declspec(thread)
+#elif defined(__STDC_VERSION__) \\
+ && (__STDC_VERSION__ >= 201112L) \\
+ && !defined(__STDC_NO_THREADS__)
+#include <threads.h>
+#define F2PY_THREAD_LOCAL_DECL thread_local
+#elif defined(__GNUC__) \\
+ && (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)))
+#define F2PY_THREAD_LOCAL_DECL __thread
+#endif
+#endif
+"""
################# C functions ###############
cfuncs['calcarrindex'] = """\
"""
needs['string_from_pyobj'] = ['string', 'STRINGMALLOC', 'STRINGCOPYN']
cfuncs['string_from_pyobj'] = """\
-static int string_from_pyobj(string *str,int *len,const string inistr,PyObject *obj,const char *errmess) {
+static int
+string_from_pyobj(string *str,int *len,const string inistr,PyObject *obj,const char *errmess)
+{
PyArrayObject *arr = NULL;
PyObject *tmp = NULL;
#ifdef DEBUGCFUNCS
STRINGCOPYN(*str,PyArray_DATA(arr),*len+1);
return 1;
}
- if (PyString_Check(obj)) {
+ if (PyBytes_Check(obj)) {
tmp = obj;
Py_INCREF(tmp);
}
}
if (tmp == NULL) goto capi_fail;
if (*len == -1)
- *len = PyString_GET_SIZE(tmp);
+ *len = PyBytes_GET_SIZE(tmp);
STRINGMALLOC(*str,*len);
- STRINGCOPYN(*str,PyString_AS_STRING(tmp),*len+1);
+ STRINGCOPYN(*str,PyBytes_AS_STRING(tmp),*len+1);
Py_DECREF(tmp);
return 1;
capi_fail:
Py_XDECREF(tmp);
{
PyObject* err = PyErr_Occurred();
- if (err==NULL) err = #modulename#_error;
- PyErr_SetString(err,errmess);
+ if (err == NULL) {
+ err = #modulename#_error;
+ }
+ PyErr_SetString(err, errmess);
}
return 0;
}
"""
+
+
needs['char_from_pyobj'] = ['int_from_pyobj']
cfuncs['char_from_pyobj'] = """\
-static int char_from_pyobj(char* v,PyObject *obj,const char *errmess) {
- int i=0;
- if (int_from_pyobj(&i,obj,errmess)) {
+static int
+char_from_pyobj(char* v, PyObject *obj, const char *errmess) {
+ int i = 0;
+ if (int_from_pyobj(&i, obj, errmess)) {
*v = (char)i;
return 1;
}
return 0;
}
"""
+
+
needs['signed_char_from_pyobj'] = ['int_from_pyobj', 'signed_char']
cfuncs['signed_char_from_pyobj'] = """\
-static int signed_char_from_pyobj(signed_char* v,PyObject *obj,const char *errmess) {
- int i=0;
- if (int_from_pyobj(&i,obj,errmess)) {
+static int
+signed_char_from_pyobj(signed_char* v, PyObject *obj, const char *errmess) {
+ int i = 0;
+ if (int_from_pyobj(&i, obj, errmess)) {
*v = (signed_char)i;
return 1;
}
return 0;
}
"""
+
+
needs['short_from_pyobj'] = ['int_from_pyobj']
cfuncs['short_from_pyobj'] = """\
-static int short_from_pyobj(short* v,PyObject *obj,const char *errmess) {
- int i=0;
- if (int_from_pyobj(&i,obj,errmess)) {
+static int
+short_from_pyobj(short* v, PyObject *obj, const char *errmess) {
+ int i = 0;
+ if (int_from_pyobj(&i, obj, errmess)) {
*v = (short)i;
return 1;
}
return 0;
}
"""
+
+
cfuncs['int_from_pyobj'] = """\
-static int int_from_pyobj(int* v,PyObject *obj,const char *errmess) {
+static int
+int_from_pyobj(int* v, PyObject *obj, const char *errmess)
+{
PyObject* tmp = NULL;
- if (PyInt_Check(obj)) {
- *v = (int)PyInt_AS_LONG(obj);
- return 1;
+
+ if (PyLong_Check(obj)) {
+ *v = Npy__PyLong_AsInt(obj);
+ return !(*v == -1 && PyErr_Occurred());
}
- tmp = PyNumber_Int(obj);
+
+ tmp = PyNumber_Long(obj);
if (tmp) {
- *v = PyInt_AS_LONG(tmp);
+ *v = Npy__PyLong_AsInt(tmp);
Py_DECREF(tmp);
- return 1;
+ return !(*v == -1 && PyErr_Occurred());
}
+
if (PyComplex_Check(obj))
tmp = PyObject_GetAttrString(obj,\"real\");
- else if (PyString_Check(obj) || PyUnicode_Check(obj))
+ else if (PyBytes_Check(obj) || PyUnicode_Check(obj))
/*pass*/;
else if (PySequence_Check(obj))
- tmp = PySequence_GetItem(obj,0);
+ tmp = PySequence_GetItem(obj, 0);
if (tmp) {
PyErr_Clear();
- if (int_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;}
+ if (int_from_pyobj(v, tmp, errmess)) {
+ Py_DECREF(tmp);
+ return 1;
+ }
Py_DECREF(tmp);
}
{
PyObject* err = PyErr_Occurred();
- if (err==NULL) err = #modulename#_error;
- PyErr_SetString(err,errmess);
+ if (err == NULL) {
+ err = #modulename#_error;
+ }
+ PyErr_SetString(err, errmess);
}
return 0;
}
"""
+
+
cfuncs['long_from_pyobj'] = """\
-static int long_from_pyobj(long* v,PyObject *obj,const char *errmess) {
+static int
+long_from_pyobj(long* v, PyObject *obj, const char *errmess) {
PyObject* tmp = NULL;
- if (PyInt_Check(obj)) {
- *v = PyInt_AS_LONG(obj);
- return 1;
+
+ if (PyLong_Check(obj)) {
+ *v = PyLong_AsLong(obj);
+ return !(*v == -1 && PyErr_Occurred());
}
- tmp = PyNumber_Int(obj);
+
+ tmp = PyNumber_Long(obj);
if (tmp) {
- *v = PyInt_AS_LONG(tmp);
+ *v = PyLong_AsLong(tmp);
Py_DECREF(tmp);
- return 1;
+ return !(*v == -1 && PyErr_Occurred());
}
+
if (PyComplex_Check(obj))
tmp = PyObject_GetAttrString(obj,\"real\");
- else if (PyString_Check(obj) || PyUnicode_Check(obj))
+ else if (PyBytes_Check(obj) || PyUnicode_Check(obj))
/*pass*/;
else if (PySequence_Check(obj))
tmp = PySequence_GetItem(obj,0);
+
if (tmp) {
PyErr_Clear();
- if (long_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;}
+ if (long_from_pyobj(v, tmp, errmess)) {
+ Py_DECREF(tmp);
+ return 1;
+ }
Py_DECREF(tmp);
}
{
PyObject* err = PyErr_Occurred();
- if (err==NULL) err = #modulename#_error;
- PyErr_SetString(err,errmess);
+ if (err == NULL) {
+ err = #modulename#_error;
+ }
+ PyErr_SetString(err, errmess);
}
return 0;
}
"""
+
+
needs['long_long_from_pyobj'] = ['long_long']
cfuncs['long_long_from_pyobj'] = """\
-static int long_long_from_pyobj(long_long* v,PyObject *obj,const char *errmess) {
+static int
+long_long_from_pyobj(long_long* v, PyObject *obj, const char *errmess)
+{
PyObject* tmp = NULL;
+
if (PyLong_Check(obj)) {
*v = PyLong_AsLongLong(obj);
- return (!PyErr_Occurred());
- }
- if (PyInt_Check(obj)) {
- *v = (long_long)PyInt_AS_LONG(obj);
- return 1;
+ return !(*v == -1 && PyErr_Occurred());
}
+
tmp = PyNumber_Long(obj);
if (tmp) {
*v = PyLong_AsLongLong(tmp);
Py_DECREF(tmp);
- return (!PyErr_Occurred());
+ return !(*v == -1 && PyErr_Occurred());
}
+
if (PyComplex_Check(obj))
tmp = PyObject_GetAttrString(obj,\"real\");
- else if (PyString_Check(obj) || PyUnicode_Check(obj))
+ else if (PyBytes_Check(obj) || PyUnicode_Check(obj))
/*pass*/;
else if (PySequence_Check(obj))
tmp = PySequence_GetItem(obj,0);
if (tmp) {
PyErr_Clear();
- if (long_long_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;}
+ if (long_long_from_pyobj(v, tmp, errmess)) {
+ Py_DECREF(tmp);
+ return 1;
+ }
Py_DECREF(tmp);
}
{
PyObject* err = PyErr_Occurred();
- if (err==NULL) err = #modulename#_error;
+ if (err == NULL) {
+ err = #modulename#_error;
+ }
PyErr_SetString(err,errmess);
}
return 0;
}
"""
+
+
needs['long_double_from_pyobj'] = ['double_from_pyobj', 'long_double']
cfuncs['long_double_from_pyobj'] = """\
-static int long_double_from_pyobj(long_double* v,PyObject *obj,const char *errmess) {
+static int
+long_double_from_pyobj(long_double* v, PyObject *obj, const char *errmess)
+{
double d=0;
if (PyArray_CheckScalar(obj)){
if PyArray_IsScalar(obj, LongDouble) {
PyArray_ScalarAsCtype(obj, v);
return 1;
}
- else if (PyArray_Check(obj) && PyArray_TYPE(obj)==NPY_LONGDOUBLE) {
+ else if (PyArray_Check(obj) && PyArray_TYPE(obj) == NPY_LONGDOUBLE) {
(*v) = *((npy_longdouble *)PyArray_DATA(obj));
return 1;
}
}
- if (double_from_pyobj(&d,obj,errmess)) {
+ if (double_from_pyobj(&d, obj, errmess)) {
*v = (long_double)d;
return 1;
}
return 0;
}
"""
+
+
cfuncs['double_from_pyobj'] = """\
-static int double_from_pyobj(double* v,PyObject *obj,const char *errmess) {
+static int
+double_from_pyobj(double* v, PyObject *obj, const char *errmess)
+{
PyObject* tmp = NULL;
if (PyFloat_Check(obj)) {
-#ifdef __sgi
*v = PyFloat_AsDouble(obj);
-#else
- *v = PyFloat_AS_DOUBLE(obj);
-#endif
- return 1;
+ return !(*v == -1.0 && PyErr_Occurred());
}
+
tmp = PyNumber_Float(obj);
if (tmp) {
-#ifdef __sgi
*v = PyFloat_AsDouble(tmp);
-#else
- *v = PyFloat_AS_DOUBLE(tmp);
-#endif
Py_DECREF(tmp);
- return 1;
+ return !(*v == -1.0 && PyErr_Occurred());
}
if (PyComplex_Check(obj))
tmp = PyObject_GetAttrString(obj,\"real\");
- else if (PyString_Check(obj) || PyUnicode_Check(obj))
+ else if (PyBytes_Check(obj) || PyUnicode_Check(obj))
/*pass*/;
else if (PySequence_Check(obj))
tmp = PySequence_GetItem(obj,0);
return 0;
}
"""
+
+
needs['float_from_pyobj'] = ['double_from_pyobj']
cfuncs['float_from_pyobj'] = """\
-static int float_from_pyobj(float* v,PyObject *obj,const char *errmess) {
+static int
+float_from_pyobj(float* v, PyObject *obj, const char *errmess)
+{
double d=0.0;
if (double_from_pyobj(&d,obj,errmess)) {
*v = (float)d;
return 0;
}
"""
+
+
needs['complex_long_double_from_pyobj'] = ['complex_long_double', 'long_double',
'complex_double_from_pyobj']
cfuncs['complex_long_double_from_pyobj'] = """\
-static int complex_long_double_from_pyobj(complex_long_double* v,PyObject *obj,const char *errmess) {
- complex_double cd={0.0,0.0};
+static int
+complex_long_double_from_pyobj(complex_long_double* v, PyObject *obj, const char *errmess)
+{
+ complex_double cd = {0.0,0.0};
if (PyArray_CheckScalar(obj)){
if PyArray_IsScalar(obj, CLongDouble) {
PyArray_ScalarAsCtype(obj, v);
return 0;
}
"""
+
+
needs['complex_double_from_pyobj'] = ['complex_double']
cfuncs['complex_double_from_pyobj'] = """\
-static int complex_double_from_pyobj(complex_double* v,PyObject *obj,const char *errmess) {
+static int
+complex_double_from_pyobj(complex_double* v, PyObject *obj, const char *errmess) {
Py_complex c;
if (PyComplex_Check(obj)) {
- c=PyComplex_AsCComplex(obj);
- (*v).r=c.real, (*v).i=c.imag;
+ c = PyComplex_AsCComplex(obj);
+ (*v).r = c.real;
+ (*v).i = c.imag;
return 1;
}
if (PyArray_IsScalar(obj, ComplexFloating)) {
else {
arr = PyArray_FromScalar(obj, PyArray_DescrFromType(NPY_CDOUBLE));
}
- if (arr==NULL) return 0;
+ if (arr == NULL) {
+ return 0;
+ }
(*v).r = ((npy_cdouble *)PyArray_DATA(arr))->real;
(*v).i = ((npy_cdouble *)PyArray_DATA(arr))->imag;
return 1;
}
/* Python does not provide PyNumber_Complex function :-( */
- (*v).i=0.0;
+ (*v).i = 0.0;
if (PyFloat_Check(obj)) {
-#ifdef __sgi
(*v).r = PyFloat_AsDouble(obj);
-#else
- (*v).r = PyFloat_AS_DOUBLE(obj);
-#endif
- return 1;
- }
- if (PyInt_Check(obj)) {
- (*v).r = (double)PyInt_AS_LONG(obj);
- return 1;
+ return !((*v).r == -1.0 && PyErr_Occurred());
}
if (PyLong_Check(obj)) {
(*v).r = PyLong_AsDouble(obj);
- return (!PyErr_Occurred());
+ return !((*v).r == -1.0 && PyErr_Occurred());
}
- if (PySequence_Check(obj) && !(PyString_Check(obj) || PyUnicode_Check(obj))) {
+ if (PySequence_Check(obj) && !(PyBytes_Check(obj) || PyUnicode_Check(obj))) {
PyObject *tmp = PySequence_GetItem(obj,0);
if (tmp) {
if (complex_double_from_pyobj(v,tmp,errmess)) {
return 0;
}
"""
+
+
needs['complex_float_from_pyobj'] = [
'complex_float', 'complex_double_from_pyobj']
cfuncs['complex_float_from_pyobj'] = """\
-static int complex_float_from_pyobj(complex_float* v,PyObject *obj,const char *errmess) {
+static int
+complex_float_from_pyobj(complex_float* v,PyObject *obj,const char *errmess)
+{
complex_double cd={0.0,0.0};
if (complex_double_from_pyobj(&cd,obj,errmess)) {
(*v).r = (float)cd.r;
return 0;
}
"""
+
+
needs['try_pyarr_from_char'] = ['pyobj_from_char1', 'TRYPYARRAYTEMPLATE']
cfuncs[
'try_pyarr_from_char'] = 'static int try_pyarr_from_char(PyObject* obj,char* v) {\n TRYPYARRAYTEMPLATE(char,\'c\');\n}\n'
cfuncs[
'try_pyarr_from_complex_double'] = 'static int try_pyarr_from_complex_double(PyObject* obj,complex_double* v) {\n TRYCOMPLEXPYARRAYTEMPLATE(double,\'D\');\n}\n'
-needs['create_cb_arglist'] = ['CFUNCSMESS', 'PRINTPYOBJERR', 'MINMAX']
+needs['create_cb_arglist'] = ['CFUNCSMESS', 'PRINTPYOBJERR', 'MINMAX']
# create the list of arguments to be used when calling back to python
cfuncs['create_cb_arglist'] = """\
-static int create_cb_arglist(PyObject* fun,PyTupleObject* xa,const int maxnofargs,const int nofoptargs,int *nofargs,PyTupleObject **args,const char *errmess) {
+static int
+create_cb_arglist(PyObject* fun, PyTupleObject* xa , const int maxnofargs,
+ const int nofoptargs, int *nofargs, PyTupleObject **args,
+ const char *errmess)
+{
PyObject *tmp = NULL;
PyObject *tmp_fun = NULL;
- int tot,opt,ext,siz,i,di=0;
+ Py_ssize_t tot, opt, ext, siz, i, di = 0;
CFUNCSMESS(\"create_cb_arglist\\n\");
tot=opt=ext=siz=0;
/* Get the total number of arguments */
Py_INCREF(tmp_fun);
}
}
-if (tmp_fun==NULL) {
-fprintf(stderr,\"Call-back argument must be function|instance|instance.__call__|f2py-function but got %s.\\n\",(fun==NULL?\"NULL\":Py_TYPE(fun)->tp_name));
-goto capi_fail;
-}
+
+ if (tmp_fun == NULL) {
+ fprintf(stderr,
+ \"Call-back argument must be function|instance|instance.__call__|f2py-function \"
+ \"but got %s.\\n\",
+ ((fun == NULL) ? \"NULL\" : Py_TYPE(fun)->tp_name));
+ goto capi_fail;
+ }
+
if (PyObject_HasAttrString(tmp_fun,\"__code__\")) {
if (PyObject_HasAttrString(tmp = PyObject_GetAttrString(tmp_fun,\"__code__\"),\"co_argcount\")) {
PyObject *tmp_argcount = PyObject_GetAttrString(tmp,\"co_argcount\");
if (tmp_argcount == NULL) {
goto capi_fail;
}
- tot = PyInt_AsLong(tmp_argcount) - di;
+ tot = PyLong_AsSsize_t(tmp_argcount) - di;
Py_DECREF(tmp_argcount);
}
}
/* Calculate the size of call-backs argument list */
siz = MIN(maxnofargs+ext,tot);
*nofargs = MAX(0,siz-ext);
+
#ifdef DEBUGCFUNCS
- fprintf(stderr,\"debug-capi:create_cb_arglist:maxnofargs(-nofoptargs),tot,opt,ext,siz,nofargs=%d(-%d),%d,%d,%d,%d,%d\\n\",maxnofargs,nofoptargs,tot,opt,ext,siz,*nofargs);
+ fprintf(stderr,
+ \"debug-capi:create_cb_arglist:maxnofargs(-nofoptargs),\"
+ \"tot,opt,ext,siz,nofargs = %d(-%d), %zd, %zd, %zd, %zd, %d\\n\",
+ maxnofargs, nofoptargs, tot, opt, ext, siz, *nofargs);
#endif
- if (siz<tot-opt) {
- fprintf(stderr,\"create_cb_arglist: Failed to build argument list (siz) with enough arguments (tot-opt) required by user-supplied function (siz,tot,opt=%d,%d,%d).\\n\",siz,tot,opt);
+
+ if (siz < tot-opt) {
+ fprintf(stderr,
+ \"create_cb_arglist: Failed to build argument list \"
+ \"(siz) with enough arguments (tot-opt) required by \"
+ \"user-supplied function (siz,tot,opt=%zd, %zd, %zd).\\n\",
+ siz, tot, opt);
goto capi_fail;
}
+
/* Initialize argument list */
*args = (PyTupleObject *)PyTuple_New(siz);
for (i=0;i<*nofargs;i++) {
CFUNCSMESS(\"create_cb_arglist-end\\n\");
Py_DECREF(tmp_fun);
return 1;
+
capi_fail:
- if ((PyErr_Occurred())==NULL)
- PyErr_SetString(#modulename#_error,errmess);
+ if (PyErr_Occurred() == NULL)
+ PyErr_SetString(#modulename#_error, errmess);
Py_XDECREF(tmp_fun);
return 0;
}
def myeval(e, g=None, l=None):
+ """ Like `eval` but returns only integers and floats """
r = eval(e, g, l)
- if type(r) in [type(0), type(0.0)]:
+ if type(r) in [int, float]:
return r
raise ValueError('r=%r' % (r))
def getlincoef(e, xset): # e = a*x+b ; x in xset
+ """
+ Obtain ``a`` and ``b`` when ``e == "a*x+b"``, where ``x`` is a symbol in
+ xset.
+
+ >>> getlincoef('2*x + 1', {'x'})
+ (2, 1, 'x')
+ >>> getlincoef('3*x + x*2 + 2 + 1', {'x'})
+ (5, 3, 'x')
+ >>> getlincoef('0', {'x'})
+ (0, 0, None)
+ >>> getlincoef('0*x', {'x'})
+ (0, 0, 'x')
+ >>> getlincoef('x*x', {'x'})
+ (None, None, None)
+
+ This can be tricked by sufficiently complex expressions
+
+ >>> getlincoef('(x - 0.5)*(x - 1.5)*(x - 1)*x + 2*x + 3', {'x'})
+ (2.0, 3.0, 'x')
+ """
try:
c = int(myeval(e, {}, {}))
return 0, c, None
def getarrlen(dl, args, star='*'):
+ """
+ Parameters
+ ----------
+ dl : sequence of two str objects
+ dimensions of the array
+ args : Iterable[str]
+ symbols used in the expression
+ star : Any
+ unused
+
+ Returns
+ -------
+ expr : str
+ Some numeric expression as a string
+ arg : Optional[str]
+ If understood, the argument from `args` present in `expr`
+ expr2 : Optional[str]
+ If understood, an expression fragment that should be used as
+ ``"(%s%s".format(something, expr2)``.
+
+ Examples
+ --------
+ >>> getarrlen(['10*x + 20', '40*x'], {'x'})
+ ('30 * x - 19', 'x', '+19)/(30)')
+ >>> getarrlen(['1', '10*x + 20'], {'x'})
+ ('10 * x + 20', 'x', '-20)/(10)')
+ >>> getarrlen(['10*x + 20', '1'], {'x'})
+ ('-10 * x - 18', 'x', '+18)/(-10)')
+ >>> getarrlen(['20', '1'], {'x'})
+ ('-18', None, None)
+ """
edl = []
try:
edl.append(myeval(dl[0], {}, {}))
if modulename:
break
- extra_objects, sources = filter_files('', '[.](o|a|so)', sources)
+ extra_objects, sources = filter_files('', '[.](o|a|so|dylib)', sources)
include_dirs, sources = filter_files('-I', '', sources, remove_prefix=1)
library_dirs, sources = filter_files('-L', '', sources, remove_prefix=1)
libraries, sources = filter_files('-l', '', sources, remove_prefix=1)
sys.argv.extend(['build',
'--build-temp', build_dir,
'--build-base', build_dir,
- '--build-platlib', '.'])
+ '--build-platlib', '.',
+ # disable CCompilerOpt
+ '--disable-optimization'])
if fc_flags:
sys.argv.extend(['config_fc'] + fc_flags)
if flib_flags:
from . import __version__
f2py_version = __version__.version
+from .. import version as _numpy_version
+numpy_version = _numpy_version.version
+
import os
import time
import copy
\tif (PyErr_Occurred())
\t\t{PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return m;}
\td = PyModule_GetDict(m);
-\ts = PyString_FromString(\"$R""" + """evision: $\");
+\ts = PyUnicode_FromString(\"$R""" + """evision: $\");
\tPyDict_SetItemString(d, \"__version__\", s);
\tPy_DECREF(s);
\ts = PyUnicode_FromString(
\t\t\"This module '#modulename#' is auto-generated with f2py (version:#f2py_version#).\\nFunctions:\\n\"\n#docs#\".\");
\tPyDict_SetItemString(d, \"__doc__\", s);
\tPy_DECREF(s);
+\ts = PyUnicode_FromString(\"""" + numpy_version + """\");
+\tPyDict_SetItemString(d, \"__f2py_numpy_version__\", s);
+\tPy_DECREF(s);
\t#modulename#_error = PyErr_NewException (\"#modulename#.error\", NULL, NULL);
\t/*
\t * Store the error object inside the dict, so that it could get deallocated.
PyObject *capi_args,
PyObject *capi_keywds,
#functype# (*f2py_func)(#callprotoargument#)) {
-\tPyObject * volatile capi_buildvalue = NULL;
-\tvolatile int f2py_success = 1;
+ PyObject * volatile capi_buildvalue = NULL;
+ volatile int f2py_success = 1;
#decl#
-\tstatic char *capi_kwlist[] = {#kwlist##kwlistopt##kwlistxa#NULL};
+ static char *capi_kwlist[] = {#kwlist##kwlistopt##kwlistxa#NULL};
#usercode#
#routdebugenter#
#ifdef F2PY_REPORT_ATEXIT
f2py_start_clock();
#endif
-\tif (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\\
-\t\t\"#argformat#|#keyformat##xaformat#:#pyname#\",\\
-\t\tcapi_kwlist#args_capi##keys_capi##keys_xa#))\n\t\treturn NULL;
+ if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\\
+ \"#argformat#|#keyformat##xaformat#:#pyname#\",\\
+ capi_kwlist#args_capi##keys_capi##keys_xa#))\n return NULL;
#frompyobj#
/*end of frompyobj*/
#ifdef F2PY_REPORT_ATEXIT
f2py_stop_call_clock();
#endif
/*end of callfortranroutine*/
-\t\tif (f2py_success) {
+ if (f2py_success) {
#pyobjfrom#
/*end of pyobjfrom*/
-\t\tCFUNCSMESS(\"Building return value.\\n\");
-\t\tcapi_buildvalue = Py_BuildValue(\"#returnformat#\"#return#);
+ CFUNCSMESS(\"Building return value.\\n\");
+ capi_buildvalue = Py_BuildValue(\"#returnformat#\"#return#);
/*closepyobjfrom*/
#closepyobjfrom#
-\t\t} /*if (f2py_success) after callfortranroutine*/
+ } /*if (f2py_success) after callfortranroutine*/
/*cleanupfrompyobj*/
#cleanupfrompyobj#
-\tif (capi_buildvalue == NULL) {
+ if (capi_buildvalue == NULL) {
#routdebugfailure#
-\t} else {
+ } else {
#routdebugleave#
-\t}
-\tCFUNCSMESS(\"Freeing memory.\\n\");
+ }
+ CFUNCSMESS(\"Freeing memory.\\n\");
#freemem#
#ifdef F2PY_REPORT_ATEXIT
f2py_stop_clock();
#endif
-\treturn capi_buildvalue;
+ return capi_buildvalue;
}
#endtitle#
""",
'docstrcbs': '#cbdocstr#',
'latexdocstrcbs': '\\item[] #cblatexdocstr#',
'latexdocstropt': {isintent_nothide: '\\item[]{{}\\verb@#varname#_extra_args := () input tuple@{}} --- Extra arguments for call-back function {{}\\verb@#varname#@{}}.'},
- 'decl': ['\tPyObject *#varname#_capi = Py_None;',
- '\tPyTupleObject *#varname#_xa_capi = NULL;',
- '\tPyTupleObject *#varname#_args_capi = NULL;',
- '\tint #varname#_nofargs_capi = 0;',
+ 'decl': [' #cbname#_t #varname#_cb = { Py_None, NULL, 0 };',
+ ' #cbname#_t *#varname#_cb_ptr = &#varname#_cb;',
+ ' PyTupleObject *#varname#_xa_capi = NULL;',
{l_not(isintent_callback):
- '\t#cbname#_typedef #varname#_cptr;'}
+ ' #cbname#_typedef #varname#_cptr;'}
],
'kwlistxa': {isintent_nothide: '"#varname#_extra_args",'},
'argformat': {isrequired: 'O'},
'keyformat': {isoptional: 'O'},
'xaformat': {isintent_nothide: 'O!'},
- 'args_capi': {isrequired: ',&#varname#_capi'},
- 'keys_capi': {isoptional: ',&#varname#_capi'},
+ 'args_capi': {isrequired: ',&#varname#_cb.capi'},
+ 'keys_capi': {isoptional: ',&#varname#_cb.capi'},
'keys_xa': ',&PyTuple_Type,&#varname#_xa_capi',
- 'setjmpbuf': '(setjmp(#cbname#_jmpbuf))',
+ 'setjmpbuf': '(setjmp(#varname#_cb.jmpbuf))',
'callfortran': {l_not(isintent_callback): '#varname#_cptr,'},
'need': ['#cbname#', 'setjmp.h'],
'_check':isexternal
},
{
'frompyobj': [{l_not(isintent_callback): """\
-if(F2PyCapsule_Check(#varname#_capi)) {
- #varname#_cptr = F2PyCapsule_AsVoidPtr(#varname#_capi);
+if(F2PyCapsule_Check(#varname#_cb.capi)) {
+ #varname#_cptr = F2PyCapsule_AsVoidPtr(#varname#_cb.capi);
} else {
#varname#_cptr = #cbname#;
}
"""}, {isintent_callback: """\
-if (#varname#_capi==Py_None) {
- #varname#_capi = PyObject_GetAttrString(#modulename#_module,\"#varname#\");
- if (#varname#_capi) {
+if (#varname#_cb.capi==Py_None) {
+ #varname#_cb.capi = PyObject_GetAttrString(#modulename#_module,\"#varname#\");
+ if (#varname#_cb.capi) {
if (#varname#_xa_capi==NULL) {
if (PyObject_HasAttrString(#modulename#_module,\"#varname#_extra_args\")) {
PyObject* capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#varname#_extra_args\");
}
}
}
- if (#varname#_capi==NULL) {
+ if (#varname#_cb.capi==NULL) {
PyErr_SetString(#modulename#_error,\"Callback #varname# not defined (as an argument or module #modulename# attribute).\\n\");
return NULL;
}
}
"""},
"""\
-\t#varname#_nofargs_capi = #cbname#_nofargs;
-\tif (create_cb_arglist(#varname#_capi,#varname#_xa_capi,#maxnofargs#,#nofoptargs#,&#cbname#_nofargs,&#varname#_args_capi,\"failed in processing argument list for call-back #varname#.\")) {
-\t\tjmp_buf #varname#_jmpbuf;""",
+ if (create_cb_arglist(#varname#_cb.capi,#varname#_xa_capi,#maxnofargs#,#nofoptargs#,&#varname#_cb.nofargs,&#varname#_cb.args_capi,\"failed in processing argument list for call-back #varname#.\")) {
+""",
{debugcapi: ["""\
-\t\tfprintf(stderr,\"debug-capi:Assuming %d arguments; at most #maxnofargs#(-#nofoptargs#) is expected.\\n\",#cbname#_nofargs);
-\t\tCFUNCSMESSPY(\"for #varname#=\",#cbname#_capi);""",
- {l_not(isintent_callback): """\t\tfprintf(stderr,\"#vardebugshowvalue# (call-back in C).\\n\",#cbname#);"""}]},
+ fprintf(stderr,\"debug-capi:Assuming %d arguments; at most #maxnofargs#(-#nofoptargs#) is expected.\\n\",#varname#_cb.nofargs);
+ CFUNCSMESSPY(\"for #varname#=\",#cbname#_capi);""",
+ {l_not(isintent_callback): """ fprintf(stderr,\"#vardebugshowvalue# (call-back in C).\\n\",#cbname#);"""}]},
"""\
-\t\tCFUNCSMESS(\"Saving jmpbuf for `#varname#`.\\n\");
-\t\tSWAP(#varname#_capi,#cbname#_capi,PyObject);
-\t\tSWAP(#varname#_args_capi,#cbname#_args_capi,PyTupleObject);
-\t\tmemcpy(&#varname#_jmpbuf,&#cbname#_jmpbuf,sizeof(jmp_buf));""",
+ CFUNCSMESS(\"Saving callback variables for `#varname#`.\\n\");
+ #varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);""",
],
'cleanupfrompyobj':
"""\
-\t\tCFUNCSMESS(\"Restoring jmpbuf for `#varname#`.\\n\");
-\t\t#cbname#_capi = #varname#_capi;
-\t\tPy_DECREF(#cbname#_args_capi);
-\t\t#cbname#_args_capi = #varname#_args_capi;
-\t\t#cbname#_nofargs = #varname#_nofargs_capi;
-\t\tmemcpy(&#cbname#_jmpbuf,&#varname#_jmpbuf,sizeof(jmp_buf));
-\t}""",
+ CFUNCSMESS(\"Restoring callback variables for `#varname#`.\\n\");
+ #varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);
+ Py_DECREF(#varname#_cb.args_capi);
+ }""",
'need': ['SWAP', 'create_cb_arglist'],
'_check':isexternal,
'_depend':''
config.add_data_files(
'src/fortranobject.c',
'src/fortranobject.h')
+ config.add_data_files('*.pyi')
return config
return PyDict_SetItemString(dict, name, obj);
}
+/*
+ * Python-only fallback for thread-local callback pointers
+ */
+void *F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
+{
+ PyObject *local_dict, *value;
+ void *prev;
+
+ local_dict = PyThreadState_GetDict();
+ if (local_dict == NULL) {
+ Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyThreadState_GetDict failed");
+ }
+
+ value = PyDict_GetItemString(local_dict, key);
+ if (value != NULL) {
+ prev = PyLong_AsVoidPtr(value);
+ if (PyErr_Occurred()) {
+ Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
+ }
+ }
+ else {
+ prev = NULL;
+ }
+
+ value = PyLong_FromVoidPtr((void *)ptr);
+ if (value == NULL) {
+ Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyLong_FromVoidPtr failed");
+ }
+
+ if (PyDict_SetItemString(local_dict, key, value) != 0) {
+ Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyDict_SetItemString failed");
+ }
+
+ Py_DECREF(value);
+
+ return prev;
+}
+
+void *F2PyGetThreadLocalCallbackPtr(char *key)
+{
+ PyObject *local_dict, *value;
+ void *prev;
+
+ local_dict = PyThreadState_GetDict();
+ if (local_dict == NULL) {
+ Py_FatalError("F2PyGetThreadLocalCallbackPtr: PyThreadState_GetDict failed");
+ }
+
+ value = PyDict_GetItemString(local_dict, key);
+ if (value != NULL) {
+ prev = PyLong_AsVoidPtr(value);
+ if (PyErr_Occurred()) {
+ Py_FatalError("F2PyGetThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
+ }
+ }
+ else {
+ prev = NULL;
+ }
+
+ return prev;
+}
+
/************************* FortranObject *******************************/
typedef PyObject *(*fortranfunc)(PyObject *,PyObject *,PyObject *,void *);
return -1;
}
memcpy(p, notalloc, sizeof(notalloc));
+ p += sizeof(notalloc);
+ size -= sizeof(notalloc);
}
return p - buf;
}
else {
PyArray_Descr *d = PyArray_DescrFromType(def.type);
- n = PyOS_snprintf(p, size, "'%c'-", d->type);
+ n = PyOS_snprintf(p, size, "%s : '%c'-", def.name, d->type);
Py_DECREF(d);
if (n < 0 || n >= size) {
goto fail;
size -= n;
if (def.data == NULL) {
- n = format_def(p, size, def) == -1;
+ n = format_def(p, size, def);
if (n < 0) {
goto fail;
}
p += n;
size -= n;
}
+
}
if (size <= 1) {
goto fail;
void * F2PyCapsule_AsVoidPtr(PyObject *obj);
int F2PyCapsule_Check(PyObject *ptr);
+extern void *F2PySwapThreadLocalCallbackPtr(char *key, void *ptr);
+extern void *F2PyGetThreadLocalCallbackPtr(char *key);
+
#define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & NPY_ARRAY_C_CONTIGUOUS)
#define F2PY_INTENT_IN 1
#define F2PY_INTENT_INOUT 2
m = Py_InitModule("foo", foo_module_methods);
d = PyModule_GetDict(m);
- s = PyString_FromString("This module 'foo' demonstrates the usage of fortranobject.");
+ s = PyUnicode_FromString("This module 'foo' demonstrates the usage of fortranobject.");
PyDict_SetItemString(d, "__doc__", s);
/* Fortran objects: */
-/* File: wrapmodule.c
- * This file is auto-generated with f2py (version:2_1330).
- * Hand edited by Pearu.
- * f2py is a Fortran to Python Interface Generator (FPIG), Second Edition,
- * written by Pearu Peterson <pearu@cens.ioc.ee>.
- * See http://cens.ioc.ee/projects/f2py2e/
- * Generation date: Fri Oct 21 22:41:12 2005
- * $Revision:$
- * $Date:$
- * Do not edit this file directly unless you know what you are doing!!!
+/*
+ * This file was auto-generated with f2py (version:2_1330) and hand edited by
+ * Pearu for testing purposes. Do not edit this file unless you know what you
+ * are doing!!!
*/
+
#ifdef __cplusplus
extern "C" {
#endif
if (tmp == NULL) {
goto fail;
}
- dims[i] = (npy_intp)PyInt_AsLong(tmp);
+ dims[i] = (npy_intp)PyLong_AsLong(tmp);
Py_DECREF(tmp);
if (dims[i] == -1 && PyErr_Occurred()) {
goto fail;
dimensions = PyTuple_New(PyArray_NDIM(arr));
strides = PyTuple_New(PyArray_NDIM(arr));
for (i=0;i<PyArray_NDIM(arr);++i) {
- PyTuple_SetItem(dimensions,i,PyInt_FromLong(PyArray_DIM(arr,i)));
- PyTuple_SetItem(strides,i,PyInt_FromLong(PyArray_STRIDE(arr,i)));
+ PyTuple_SetItem(dimensions,i,PyLong_FromLong(PyArray_DIM(arr,i)));
+ PyTuple_SetItem(strides,i,PyLong_FromLong(PyArray_STRIDE(arr,i)));
}
return Py_BuildValue("siNNO(cciii)ii",s,PyArray_NDIM(arr),
dimensions,strides,
if (PyErr_Occurred())
Py_FatalError("can't initialize module wrap (failed to import numpy)");
d = PyModule_GetDict(m);
- s = PyString_FromString("This module 'wrap' is auto-generated with f2py (version:2_1330).\nFunctions:\n"
-" arr = call(type_num,dims,intent,obj)\n"
-".");
+ s = PyUnicode_FromString("This module 'wrap' is auto-generated with f2py (version:2_1330).\nFunctions:\n"
+ " arr = call(type_num,dims,intent,obj)\n"
+ ".");
PyDict_SetItemString(d, "__doc__", s);
wrap_error = PyErr_NewException ("wrap.error", NULL, NULL);
Py_DECREF(s);
#define ADDCONST(NAME, CONST) \
- s = PyInt_FromLong(CONST); \
+ s = PyLong_FromLong(CONST); \
PyDict_SetItemString(d, NAME, s); \
Py_DECREF(s)
--- /dev/null
+module mod
+ integer :: i
+ integer :: x(4)
+ real, dimension(2,3) :: a
+ real, allocatable, dimension(:,:) :: b
+contains
+ subroutine foo
+ integer :: k
+ k = 1
+ a(1,2) = a(1,2)+3
+ end subroutine foo
+end module mod
@pytest.mark.xfail(IS_PYPY,
reason="PyPy cannot modify tp_doc after PyType_Ready")
def test_block_docstring(self):
- expected = "'i'-array(2,3)\n"
+ expected = "bar : 'i'-array(2,3)\n"
assert_equal(self.module.block.__doc__, expected)
import textwrap
import sys
import pytest
+import threading
+import traceback
+import time
+import random
import numpy as np
from numpy.testing import assert_, assert_equal, IS_PYPY
f = getattr(self.module, 'string_callback_array')
res = f(callback, cu, len(cu))
assert_(res == 0, repr(res))
+
+ def test_threadsafety(self):
+ # Segfaults if the callback handling is not threadsafe
+
+ errors = []
+
+ def cb():
+ # Sleep here to make it more likely for another thread
+ # to call their callback at the same time.
+ time.sleep(1e-3)
+
+ # Check reentrancy
+ r = self.module.t(lambda: 123)
+ assert_(r == 123)
+
+ return 42
+
+ def runner(name):
+ try:
+ for j in range(50):
+ r = self.module.t(cb)
+ assert_(r == 42)
+ self.check_function(name)
+ except Exception:
+ errors.append(traceback.format_exc())
+
+ threads = [threading.Thread(target=runner, args=(arg,))
+ for arg in ("t", "t2") for n in range(20)]
+
+ for t in threads:
+ t.start()
+
+ for t in threads:
+ t.join()
+
+ errors = "\n\n".join(errors)
+ if errors:
+ raise AssertionError(errors)
+
+
+class TestF77CallbackPythonTLS(TestF77Callback):
+ """
+ Callback tests using Python thread-local storage instead of
+ compiler-provided
+ """
+ options = ["-DF2PY_USE_PYTHON_TLS"]
--- /dev/null
+import os
+import sys
+import pytest
+import textwrap
+
+from . import util
+from numpy.testing import assert_equal, IS_PYPY
+
+
+def _path(*a):
+ return os.path.join(*((os.path.dirname(__file__),) + a))
+
+
+class TestModuleDocString(util.F2PyTest):
+ sources = [_path('src', 'module_data', 'module_data_docstring.f90')]
+
+ @pytest.mark.skipif(sys.platform=='win32',
+ reason='Fails with MinGW64 Gfortran (Issue #9673)')
+ @pytest.mark.xfail(IS_PYPY,
+ reason="PyPy cannot modify tp_doc after PyType_Ready")
+ def test_module_docstring(self):
+ assert_equal(self.module.mod.__doc__,
+ textwrap.dedent('''\
+ i : 'i'-scalar
+ x : 'i'-array(4)
+ a : 'f'-array(2,3)
+ b : 'f'-array(-1,-1), not allocated\x00
+ foo()\n
+ Wrapper for ``foo``.\n\n''')
+ )
import pytest
import numpy as np
-from numpy.testing import assert_raises, assert_equal
+from numpy.testing import assert_, assert_raises, assert_equal, assert_string_equal
from . import util
x = np.arange(3, dtype=np.float32)
self.module.foo(x)
assert_equal(x, [3, 1, 2])
+
+
+class TestNumpyVersionAttribute(util.F2PyTest):
+ # Check that th attribute __f2py_numpy_version__ is present
+ # in the compiled module and that has the value np.__version__.
+ sources = [_path('src', 'regression', 'inout.f90')]
+
+ @pytest.mark.slow
+ def test_numpy_version_attribute(self):
+
+ # Check that self.module has an attribute named "__f2py_numpy_version__"
+ assert_(hasattr(self.module, "__f2py_numpy_version__"),
+ msg="Fortran module does not have __f2py_numpy_version__")
+
+ # Check that the attribute __f2py_numpy_version__ is a string
+ assert_(isinstance(self.module.__f2py_numpy_version__, str),
+ msg="__f2py_numpy_version__ is not a string")
+
+ # Check that __f2py_numpy_version__ has the value numpy.__version__
+ assert_string_equal(np.__version__, self.module.__f2py_numpy_version__)
from numpy.testing import temppath
from importlib import import_module
-from hashlib import md5
-
#
# Maintaining a temporary module directory
#
.. currentmodule:: numpy.fft
+The SciPy module `scipy.fft` is a more comprehensive superset
+of ``numpy.fft``, which includes only a basic set of routines.
+
Standard FFTs
-------------
Normalization
-------------
-The default normalization has the direct transforms unscaled and the inverse
-transforms are scaled by :math:`1/n`. It is possible to obtain unitary
-transforms by setting the keyword argument ``norm`` to ``"ortho"`` (default is
-`None`) so that both direct and inverse transforms will be scaled by
-:math:`1/\\sqrt{n}`.
+The argument ``norm`` indicates which direction of the pair of direct/inverse
+transforms is scaled and with what normalization factor.
+The default normalization (``"backward"``) has the direct (forward) transforms
+unscaled and the inverse (backward) transforms scaled by :math:`1/n`. It is
+possible to obtain unitary transforms by setting the keyword argument ``norm``
+to ``"ortho"`` so that both direct and inverse transforms are scaled by
+:math:`1/\\sqrt{n}`. Finally, setting the keyword argument ``norm`` to
+``"forward"`` has the direct transforms scaled by :math:`1/n` and the inverse
+transforms unscaled (i.e. exactly opposite to the default ``"backward"``).
+`None` is an alias of the default option ``"backward"`` for backward
+compatibility.
Real and Hermitian transforms
-----------------------------
--- /dev/null
+from typing import Any
+
+fft: Any
+ifft: Any
+rfft: Any
+irfft: Any
+hfft: Any
+ihfft: Any
+rfftn: Any
+irfftn: Any
+rfft2: Any
+irfft2: Any
+fft2: Any
+ifft2: Any
+fftn: Any
+ifftn: Any
+fftshift: Any
+ifftshift: Any
+fftfreq: Any
+rfftfreq: Any
Routines in this module:
-fft(a, n=None, axis=-1)
-ifft(a, n=None, axis=-1)
-rfft(a, n=None, axis=-1)
-irfft(a, n=None, axis=-1)
-hfft(a, n=None, axis=-1)
-ihfft(a, n=None, axis=-1)
-fftn(a, s=None, axes=None)
-ifftn(a, s=None, axes=None)
-rfftn(a, s=None, axes=None)
-irfftn(a, s=None, axes=None)
-fft2(a, s=None, axes=(-2,-1))
-ifft2(a, s=None, axes=(-2, -1))
-rfft2(a, s=None, axes=(-2,-1))
-irfft2(a, s=None, axes=(-2, -1))
+fft(a, n=None, axis=-1, norm="backward")
+ifft(a, n=None, axis=-1, norm="backward")
+rfft(a, n=None, axis=-1, norm="backward")
+irfft(a, n=None, axis=-1, norm="backward")
+hfft(a, n=None, axis=-1, norm="backward")
+ihfft(a, n=None, axis=-1, norm="backward")
+fftn(a, s=None, axes=None, norm="backward")
+ifftn(a, s=None, axes=None, norm="backward")
+rfftn(a, s=None, axes=None, norm="backward")
+irfftn(a, s=None, axes=None, norm="backward")
+fft2(a, s=None, axes=(-2,-1), norm="backward")
+ifft2(a, s=None, axes=(-2, -1), norm="backward")
+rfft2(a, s=None, axes=(-2,-1), norm="backward")
+irfft2(a, s=None, axes=(-2, -1), norm="backward")
i = inverse transform
r = transform of purely real data
if n is None:
n = a.shape[axis]
- if n < 1:
- raise ValueError("Invalid number of FFT data points (%d) specified."
- % n)
-
fct = 1/inv_norm
if a.shape[axis] != n:
return r
-def _unitary(norm):
- if norm is None:
- return False
- if norm=="ortho":
- return True
- raise ValueError("Invalid norm value %s, should be None or \"ortho\"."
- % norm)
+def _get_forward_norm(n, norm):
+ if n < 1:
+ raise ValueError(f"Invalid number of FFT data points ({n}) specified.")
+
+ if norm is None or norm == "backward":
+ return 1
+ elif norm == "ortho":
+ return sqrt(n)
+ elif norm == "forward":
+ return n
+ raise ValueError(f'Invalid norm value {norm}; should be "backward",'
+ '"ortho" or "forward".')
+
+
+def _get_backward_norm(n, norm):
+ if n < 1:
+ raise ValueError(f"Invalid number of FFT data points ({n}) specified.")
+
+ if norm is None or norm == "backward":
+ return n
+ elif norm == "ortho":
+ return sqrt(n)
+ elif norm == "forward":
+ return 1
+ raise ValueError(f'Invalid norm value {norm}; should be "backward", '
+ '"ortho" or "forward".')
+
+
+_SWAP_DIRECTION_MAP = {"backward": "forward", None: "forward",
+ "ortho": "ortho", "forward": "backward"}
+
+
+def _swap_direction(norm):
+ try:
+ return _SWAP_DIRECTION_MAP[norm]
+ except KeyError:
+ raise ValueError(f'Invalid norm value {norm}; should be "backward", '
+ '"ortho" or "forward".')
def _fft_dispatcher(a, n=None, axis=None, norm=None):
axis : int, optional
Axis over which to compute the FFT. If not given, the last axis is
used.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
>>> plt.show()
"""
-
a = asarray(a)
if n is None:
n = a.shape[axis]
- inv_norm = 1
- if norm is not None and _unitary(norm):
- inv_norm = sqrt(n)
+ inv_norm = _get_forward_norm(n, norm)
output = _raw_fft(a, n, axis, False, True, inv_norm)
return output
axis : int, optional
Axis over which to compute the inverse DFT. If not given, the last
axis is used.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
a = asarray(a)
if n is None:
n = a.shape[axis]
- if norm is not None and _unitary(norm):
- inv_norm = sqrt(max(n, 1))
- else:
- inv_norm = n
+ inv_norm = _get_backward_norm(n, norm)
output = _raw_fft(a, n, axis, False, False, inv_norm)
return output
-
@array_function_dispatch(_fft_dispatcher)
def rfft(a, n=None, axis=-1, norm=None):
"""
axis : int, optional
Axis over which to compute the FFT. If not given, the last axis is
used.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
"""
a = asarray(a)
- inv_norm = 1
- if norm is not None and _unitary(norm):
- if n is None:
- n = a.shape[axis]
- inv_norm = sqrt(n)
+ if n is None:
+ n = a.shape[axis]
+ inv_norm = _get_forward_norm(n, norm)
output = _raw_fft(a, n, axis, True, True, inv_norm)
return output
@array_function_dispatch(_fft_dispatcher)
def irfft(a, n=None, axis=-1, norm=None):
"""
- Compute the inverse of the n-point DFT for real input.
+ Computes the inverse of `rfft`.
This function computes the inverse of the one-dimensional *n*-point
discrete Fourier Transform of real input computed by `rfft`.
axis : int, optional
Axis over which to compute the inverse FFT. If not given, the last
axis is used.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
a = asarray(a)
if n is None:
n = (a.shape[axis] - 1) * 2
- inv_norm = n
- if norm is not None and _unitary(norm):
- inv_norm = sqrt(n)
+ inv_norm = _get_backward_norm(n, norm)
output = _raw_fft(a, n, axis, True, False, inv_norm)
return output
axis : int, optional
Axis over which to compute the FFT. If not given, the last
axis is used.
- norm : {None, "ortho"}, optional
- Normalization mode (see `numpy.fft`). Default is None.
-
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
+
Returns
-------
out : ndarray
a = asarray(a)
if n is None:
n = (a.shape[axis] - 1) * 2
- unitary = _unitary(norm)
- return irfft(conjugate(a), n, axis) * (sqrt(n) if unitary else n)
+ new_norm = _swap_direction(norm)
+ output = irfft(conjugate(a), n, axis, norm=new_norm)
+ return output
@array_function_dispatch(_fft_dispatcher)
axis : int, optional
Axis over which to compute the inverse FFT. If not given, the last
axis is used.
- norm : {None, "ortho"}, optional
- Normalization mode (see `numpy.fft`). Default is None.
-
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
+
Returns
-------
out : complex ndarray
a = asarray(a)
if n is None:
n = a.shape[axis]
- unitary = _unitary(norm)
- output = conjugate(rfft(a, n, axis))
- return output * (1 / (sqrt(n) if unitary else n))
+ new_norm = _swap_direction(norm)
+ output = conjugate(rfft(a, n, axis, norm=new_norm))
+ return output
def _cook_nd_args(a, s=None, axes=None, invreal=0):
axes are used, or all axes if `s` is also not specified.
Repeated indices in `axes` means that the transform over that axis is
performed multiple times.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
>>> plt.show()
"""
-
return _raw_fftnd(a, s, axes, fft, norm)
axes are used, or all axes if `s` is also not specified.
Repeated indices in `axes` means that the inverse transform over that
axis is performed multiple times.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
>>> plt.show()
"""
-
return _raw_fftnd(a, s, axes, ifft, norm)
@array_function_dispatch(_fftn_dispatcher)
def fft2(a, s=None, axes=(-2, -1), norm=None):
"""
- Compute the 2-dimensional discrete Fourier Transform
+ Compute the 2-dimensional discrete Fourier Transform.
This function computes the *n*-dimensional discrete Fourier Transform
over any axes in an *M*-dimensional array by means of the
axes are used. A repeated index in `axes` means the transform over
that axis is performed multiple times. A one-element sequence means
that a one-dimensional FFT is performed.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
0. +0.j , 0. +0.j ]])
"""
-
return _raw_fftnd(a, s, axes, fft, norm)
axes are used. A repeated index in `axes` means the transform over
that axis is performed multiple times. A one-element sequence means
that a one-dimensional FFT is performed.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]])
"""
-
return _raw_fftnd(a, s, axes, ifft, norm)
axes : sequence of ints, optional
Axes over which to compute the FFT. If not given, the last ``len(s)``
axes are used, or all axes if `s` is also not specified.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
Shape of the FFT.
axes : sequence of ints, optional
Axes over which to compute the FFT.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
For more details see `rfftn`.
"""
-
return rfftn(a, s, axes, norm)
@array_function_dispatch(_fftn_dispatcher)
def irfftn(a, s=None, axes=None, norm=None):
"""
- Compute the inverse of the N-dimensional FFT of real input.
+ Computes the inverse of `rfftn`.
This function computes the inverse of the N-dimensional discrete
Fourier Transform for real input over any number of axes in an
Along any axis, if the shape indicated by `s` is smaller than that of
the input, the input is cropped. If it is larger, the input is padded
with zeros. If `s` is not given, the shape of the input along the axes
- specified by axes is used. Except for the last axis which is taken to be
- ``2*(m-1)`` where ``m`` is the length of the input along that axis.
+ specified by axes is used. Except for the last axis which is taken to
+ be ``2*(m-1)`` where ``m`` is the length of the input along that axis.
axes : sequence of ints, optional
Axes over which to compute the inverse FFT. If not given, the last
`len(s)` axes are used, or all axes if `s` is also not specified.
Repeated indices in `axes` means that the inverse transform over that
axis is performed multiple times.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
@array_function_dispatch(_fftn_dispatcher)
def irfft2(a, s=None, axes=(-2, -1), norm=None):
"""
- Compute the 2-dimensional inverse FFT of a real array.
+ Computes the inverse of `rfft2`.
Parameters
----------
axes : sequence of ints, optional
The axes over which to compute the inverse fft.
Default is the last two axes.
- norm : {None, "ortho"}, optional
+ norm : {"backward", "ortho", "forward"}, optional
.. versionadded:: 1.10.0
- Normalization mode (see `numpy.fft`). Default is None.
+ Normalization mode (see `numpy.fft`). Default is "backward".
+ Indicates which direction of the forward/backward pair of transforms
+ is scaled and with what normalization factor.
+
+ .. versionadded:: 1.20.0
+
+ The "backward", "forward" values were added.
Returns
-------
See Also
--------
+ rfft2 : The forward two-dimensional FFT of real input,
+ of which `irfft2` is the inverse.
+ rfft : The one-dimensional FFT for real input.
+ irfft : The inverse of the one-dimensional FFT of real input.
irfftn : Compute the inverse of the N-dimensional FFT of real input.
Notes
For more details see `irfftn`.
"""
-
return irfftn(a, s, axes, norm)
Discrete Fourier Transforms - helper.py
"""
-from numpy.compat import integer_types
from numpy.core import integer, empty, arange, asarray, roll
from numpy.core.overrides import array_function_dispatch, set_module
__all__ = ['fftshift', 'ifftshift', 'fftfreq', 'rfftfreq']
-integer_types = integer_types + (integer,)
+integer_types = (int, integer)
def _fftshift_dispatcher(x, axes=None):
define_macros=defs,
)
+ config.add_data_files('*.pyi')
return config
if __name__ == '__main__':
def test_equal_to_original(self):
""" Test that the new (>=v1.15) implementation (see #10073) is equal to the original (<=v1.14) """
- from numpy.compat import integer_types
from numpy.core import asarray, concatenate, arange, take
def original_fftshift(x, axes=None):
ndim = tmp.ndim
if axes is None:
axes = list(range(ndim))
- elif isinstance(axes, integer_types):
+ elif isinstance(axes, int):
axes = (axes,)
y = tmp
for k in axes:
ndim = tmp.ndim
if axes is None:
axes = list(range(ndim))
- elif isinstance(axes, integer_types):
+ elif isinstance(axes, int):
axes = (axes,)
y = tmp
for k in axes:
maxlen = 512
x = random(maxlen) + 1j*random(maxlen)
xr = random(maxlen)
- for i in range(1,maxlen):
+ for i in range(1, maxlen):
assert_allclose(np.fft.ifft(np.fft.fft(x[0:i])), x[0:i],
atol=1e-12)
- assert_allclose(np.fft.irfft(np.fft.rfft(xr[0:i]),i),
+ assert_allclose(np.fft.irfft(np.fft.rfft(xr[0:i]), i),
xr[0:i], atol=1e-12)
def test_fft(self):
x = random(30) + 1j*random(30)
assert_allclose(fft1(x), np.fft.fft(x), atol=1e-6)
+ assert_allclose(fft1(x), np.fft.fft(x, norm="backward"), atol=1e-6)
assert_allclose(fft1(x) / np.sqrt(30),
np.fft.fft(x, norm="ortho"), atol=1e-6)
+ assert_allclose(fft1(x) / 30.,
+ np.fft.fft(x, norm="forward"), atol=1e-6)
- @pytest.mark.parametrize('norm', (None, 'ortho'))
+ @pytest.mark.parametrize('norm', (None, 'backward', 'ortho', 'forward'))
def test_ifft(self, norm):
x = random(30) + 1j*random(30)
assert_allclose(
x = random((30, 20)) + 1j*random((30, 20))
assert_allclose(np.fft.fft(np.fft.fft(x, axis=1), axis=0),
np.fft.fft2(x), atol=1e-6)
+ assert_allclose(np.fft.fft2(x),
+ np.fft.fft2(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.fft2(x) / np.sqrt(30 * 20),
np.fft.fft2(x, norm="ortho"), atol=1e-6)
+ assert_allclose(np.fft.fft2(x) / (30. * 20.),
+ np.fft.fft2(x, norm="forward"), atol=1e-6)
def test_ifft2(self):
x = random((30, 20)) + 1j*random((30, 20))
assert_allclose(np.fft.ifft(np.fft.ifft(x, axis=1), axis=0),
np.fft.ifft2(x), atol=1e-6)
+ assert_allclose(np.fft.ifft2(x),
+ np.fft.ifft2(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.ifft2(x) * np.sqrt(30 * 20),
np.fft.ifft2(x, norm="ortho"), atol=1e-6)
+ assert_allclose(np.fft.ifft2(x) * (30. * 20.),
+ np.fft.ifft2(x, norm="forward"), atol=1e-6)
def test_fftn(self):
x = random((30, 20, 10)) + 1j*random((30, 20, 10))
assert_allclose(
np.fft.fft(np.fft.fft(np.fft.fft(x, axis=2), axis=1), axis=0),
np.fft.fftn(x), atol=1e-6)
+ assert_allclose(np.fft.fftn(x),
+ np.fft.fftn(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.fftn(x) / np.sqrt(30 * 20 * 10),
np.fft.fftn(x, norm="ortho"), atol=1e-6)
+ assert_allclose(np.fft.fftn(x) / (30. * 20. * 10.),
+ np.fft.fftn(x, norm="forward"), atol=1e-6)
def test_ifftn(self):
x = random((30, 20, 10)) + 1j*random((30, 20, 10))
assert_allclose(
np.fft.ifft(np.fft.ifft(np.fft.ifft(x, axis=2), axis=1), axis=0),
np.fft.ifftn(x), atol=1e-6)
+ assert_allclose(np.fft.ifftn(x),
+ np.fft.ifftn(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.ifftn(x) * np.sqrt(30 * 20 * 10),
np.fft.ifftn(x, norm="ortho"), atol=1e-6)
+ assert_allclose(np.fft.ifftn(x) * (30. * 20. * 10.),
+ np.fft.ifftn(x, norm="forward"), atol=1e-6)
def test_rfft(self):
x = random(30)
for n in [x.size, 2*x.size]:
- for norm in [None, 'ortho']:
+ for norm in [None, 'backward', 'ortho', 'forward']:
assert_allclose(
np.fft.fft(x, n=n, norm=norm)[:(n//2 + 1)],
np.fft.rfft(x, n=n, norm=norm), atol=1e-6)
+ assert_allclose(
+ np.fft.rfft(x, n=n),
+ np.fft.rfft(x, n=n, norm="backward"), atol=1e-6)
assert_allclose(
np.fft.rfft(x, n=n) / np.sqrt(n),
np.fft.rfft(x, n=n, norm="ortho"), atol=1e-6)
+ assert_allclose(
+ np.fft.rfft(x, n=n) / n,
+ np.fft.rfft(x, n=n, norm="forward"), atol=1e-6)
def test_irfft(self):
x = random(30)
assert_allclose(x, np.fft.irfft(np.fft.rfft(x)), atol=1e-6)
- assert_allclose(
- x, np.fft.irfft(np.fft.rfft(x, norm="ortho"), norm="ortho"), atol=1e-6)
+ assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="backward"),
+ norm="backward"), atol=1e-6)
+ assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="ortho"),
+ norm="ortho"), atol=1e-6)
+ assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="forward"),
+ norm="forward"), atol=1e-6)
def test_rfft2(self):
x = random((30, 20))
assert_allclose(np.fft.fft2(x)[:, :11], np.fft.rfft2(x), atol=1e-6)
+ assert_allclose(np.fft.rfft2(x),
+ np.fft.rfft2(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.rfft2(x) / np.sqrt(30 * 20),
np.fft.rfft2(x, norm="ortho"), atol=1e-6)
+ assert_allclose(np.fft.rfft2(x) / (30. * 20.),
+ np.fft.rfft2(x, norm="forward"), atol=1e-6)
def test_irfft2(self):
x = random((30, 20))
assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x)), atol=1e-6)
- assert_allclose(
- x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"), norm="ortho"), atol=1e-6)
+ assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="backward"),
+ norm="backward"), atol=1e-6)
+ assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"),
+ norm="ortho"), atol=1e-6)
+ assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="forward"),
+ norm="forward"), atol=1e-6)
def test_rfftn(self):
x = random((30, 20, 10))
assert_allclose(np.fft.fftn(x)[:, :, :6], np.fft.rfftn(x), atol=1e-6)
+ assert_allclose(np.fft.rfftn(x),
+ np.fft.rfftn(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.rfftn(x) / np.sqrt(30 * 20 * 10),
np.fft.rfftn(x, norm="ortho"), atol=1e-6)
+ assert_allclose(np.fft.rfftn(x) / (30. * 20. * 10.),
+ np.fft.rfftn(x, norm="forward"), atol=1e-6)
def test_irfftn(self):
x = random((30, 20, 10))
assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x)), atol=1e-6)
- assert_allclose(
- x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"), norm="ortho"), atol=1e-6)
+ assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="backward"),
+ norm="backward"), atol=1e-6)
+ assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"),
+ norm="ortho"), atol=1e-6)
+ assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="forward"),
+ norm="forward"), atol=1e-6)
def test_hfft(self):
x = random(14) + 1j*random(14)
x_herm = np.concatenate((random(1), x, random(1)))
x = np.concatenate((x_herm, x[::-1].conj()))
assert_allclose(np.fft.fft(x), np.fft.hfft(x_herm), atol=1e-6)
+ assert_allclose(np.fft.hfft(x_herm),
+ np.fft.hfft(x_herm, norm="backward"), atol=1e-6)
assert_allclose(np.fft.hfft(x_herm) / np.sqrt(30),
np.fft.hfft(x_herm, norm="ortho"), atol=1e-6)
+ assert_allclose(np.fft.hfft(x_herm) / 30.,
+ np.fft.hfft(x_herm, norm="forward"), atol=1e-6)
- def test_ihttf(self):
+ def test_ihfft(self):
x = random(14) + 1j*random(14)
x_herm = np.concatenate((random(1), x, random(1)))
x = np.concatenate((x_herm, x[::-1].conj()))
assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm)), atol=1e-6)
- assert_allclose(
- x_herm, np.fft.ihfft(np.fft.hfft(x_herm, norm="ortho"),
- norm="ortho"), atol=1e-6)
+ assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
+ norm="backward"), norm="backward"), atol=1e-6)
+ assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
+ norm="ortho"), norm="ortho"), atol=1e-6)
+ assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
+ norm="forward"), norm="forward"), atol=1e-6)
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
np.fft.rfftn, np.fft.irfftn])
]
for forw, back in func_pairs:
for n in [x.size, 2*x.size]:
- for norm in [None, 'ortho']:
+ for norm in [None, 'backward', 'ortho', 'forward']:
tmp = forw(x, n=n, norm=norm)
tmp = back(tmp, n=n, norm=norm)
assert_allclose(x_norm,
from .utils import *
from .arraysetops import *
from .npyio import *
-from .financial import *
from .arrayterator import Arrayterator
from .arraypad import *
from ._version import *
__all__ += utils.__all__
__all__ += arraysetops.__all__
__all__ += npyio.__all__
-__all__ += financial.__all__
__all__ += nanfunctions.__all__
__all__ += histograms.__all__
--- /dev/null
+from typing import Any
+
+emath: Any
+math: Any
+tracemalloc_domain: Any
+Arrayterator: Any
+iscomplexobj: Any
+isrealobj: Any
+imag: Any
+iscomplex: Any
+isreal: Any
+nan_to_num: Any
+real: Any
+real_if_close: Any
+typename: Any
+asfarray: Any
+mintypecode: Any
+asscalar: Any
+common_type: Any
+ravel_multi_index: Any
+unravel_index: Any
+mgrid: Any
+ogrid: Any
+r_: Any
+c_: Any
+s_: Any
+index_exp: Any
+ix_: Any
+ndenumerate: Any
+ndindex: Any
+fill_diagonal: Any
+diag_indices: Any
+diag_indices_from: Any
+select: Any
+piecewise: Any
+trim_zeros: Any
+copy: Any
+iterable: Any
+percentile: Any
+diff: Any
+gradient: Any
+angle: Any
+unwrap: Any
+sort_complex: Any
+disp: Any
+flip: Any
+rot90: Any
+extract: Any
+place: Any
+vectorize: Any
+asarray_chkfinite: Any
+average: Any
+bincount: Any
+digitize: Any
+cov: Any
+corrcoef: Any
+msort: Any
+median: Any
+sinc: Any
+hamming: Any
+hanning: Any
+bartlett: Any
+blackman: Any
+kaiser: Any
+trapz: Any
+i0: Any
+add_newdoc: Any
+add_docstring: Any
+meshgrid: Any
+delete: Any
+insert: Any
+append: Any
+interp: Any
+add_newdoc_ufunc: Any
+quantile: Any
+column_stack: Any
+row_stack: Any
+dstack: Any
+array_split: Any
+split: Any
+hsplit: Any
+vsplit: Any
+dsplit: Any
+apply_over_axes: Any
+expand_dims: Any
+apply_along_axis: Any
+kron: Any
+tile: Any
+get_array_wrap: Any
+take_along_axis: Any
+put_along_axis: Any
+broadcast_to: Any
+broadcast_arrays: Any
+diag: Any
+diagflat: Any
+eye: Any
+fliplr: Any
+flipud: Any
+tri: Any
+triu: Any
+tril: Any
+vander: Any
+histogram2d: Any
+mask_indices: Any
+tril_indices: Any
+tril_indices_from: Any
+triu_indices: Any
+triu_indices_from: Any
+fix: Any
+isneginf: Any
+isposinf: Any
+pad: Any
+poly: Any
+roots: Any
+polyint: Any
+polyder: Any
+polyadd: Any
+polysub: Any
+polymul: Any
+polydiv: Any
+polyval: Any
+poly1d: Any
+polyfit: Any
+RankWarning: Any
+issubclass_: Any
+issubsctype: Any
+issubdtype: Any
+deprecate: Any
+deprecate_with_doc: Any
+get_include: Any
+info: Any
+source: Any
+who: Any
+lookfor: Any
+byte_bounds: Any
+safe_eval: Any
+ediff1d: Any
+intersect1d: Any
+setxor1d: Any
+union1d: Any
+setdiff1d: Any
+unique: Any
+in1d: Any
+isin: Any
+savetxt: Any
+loadtxt: Any
+genfromtxt: Any
+ndfromtxt: Any
+mafromtxt: Any
+recfromtxt: Any
+recfromcsv: Any
+load: Any
+loads: Any
+save: Any
+savez: Any
+savez_compressed: Any
+packbits: Any
+unpackbits: Any
+fromregex: Any
+DataSource: Any
+nansum: Any
+nanmax: Any
+nanmin: Any
+nanargmax: Any
+nanargmin: Any
+nanmean: Any
+nanmedian: Any
+nanpercentile: Any
+nanvar: Any
+nanstd: Any
+nanprod: Any
+nancumsum: Any
+nancumprod: Any
+nanquantile: Any
+histogram: Any
+histogramdd: Any
+histogram_bin_edges: Any
import os
import shutil
import io
-from contextlib import closing
from numpy.core.overrides import set_module
# TODO: Doesn't handle compressed files!
if self._isurl(path):
- try:
- with closing(urlopen(path)) as openedurl:
- with _open(upath, 'wb') as f:
- shutil.copyfileobj(openedurl, f)
- except URLError:
- raise URLError("URL not found: %s" % path)
+ with urlopen(path) as openedurl:
+ with _open(upath, 'wb') as f:
+ shutil.copyfileobj(openedurl, f)
else:
shutil.copyfile(path, upath)
return upath
import numpy as np
import numpy.core.numeric as nx
-from numpy.compat import asbytes, asunicode, bytes
+from numpy.compat import asbytes, asunicode
def _decode_line(line, encoding=None):
----------
line : str or bytes
Line to be decoded.
+ encoding : str
+ Encoding used to decode `line`.
Returns
-------
"""
if type(line) is bytes:
if encoding is None:
- line = line.decode('latin1')
- else:
- line = line.decode(encoding)
+ encoding = "latin1"
+ line = line.decode(encoding)
return line
"""
edge_pair = _get_edges(padded, axis, width_pair)
- left_ramp = np.linspace(
- start=end_value_pair[0],
- stop=edge_pair[0].squeeze(axis), # Dimensions is replaced by linspace
- num=width_pair[0],
- endpoint=False,
- dtype=padded.dtype,
- axis=axis,
- )
-
- right_ramp = np.linspace(
- start=end_value_pair[1],
- stop=edge_pair[1].squeeze(axis), # Dimension is replaced by linspace
- num=width_pair[1],
- endpoint=False,
- dtype=padded.dtype,
- axis=axis,
+ left_ramp, right_ramp = (
+ np.linspace(
+ start=end_value,
+ stop=edge.squeeze(axis), # Dimension is replaced by linspace
+ num=width,
+ endpoint=False,
+ dtype=padded.dtype,
+ axis=axis
+ )
+ for end_value, edge, width in zip(
+ end_value_pair, edge_pair, width_pair
+ )
)
+
# Reverse linear space in appropriate dimension
right_ramp = right_ramp[_slice_at_axis(slice(None, None, -1), axis)]
try:
unsupported_kwargs = set(kwargs) - set(allowed_kwargs[mode])
except KeyError:
- raise ValueError("mode '{}' is not supported".format(mode))
+ raise ValueError("mode '{}' is not supported".format(mode)) from None
if unsupported_kwargs:
raise ValueError("unsupported keyword arguments for mode '{}': {}"
.format(mode, unsupported_kwargs))
"""
Set operations for arrays based on sorting.
-:Contains:
- unique,
- isin,
- ediff1d,
- intersect1d,
- setxor1d,
- in1d,
- union1d,
- setdiff1d
-
-:Notes:
+Notes
+-----
For floating point arrays, inaccurate results may appear due to usual round-off
and floating point comparison issues.
Speed could be gained in some operations by an implementation of
-sort(), that can provide directly the permutation vectors, avoiding
-thus calls to argsort().
+`numpy.sort`, that can provide directly the permutation vectors, thus avoiding
+calls to `numpy.argsort`.
-To do: Optionally return indices analogously to unique for all functions.
-
-:Author: Robert Cimrman
+Original author: Robert Cimrman
"""
import functools
else:
to_begin = np.asanyarray(to_begin)
if not np.can_cast(to_begin, dtype_req, casting="same_kind"):
- raise TypeError("dtype of `to_end` must be compatible "
+ raise TypeError("dtype of `to_begin` must be compatible "
"with input `ary` under the `same_kind` rule.")
to_begin = to_begin.ravel()
--------
numpy.lib.arraysetops : Module with a number of other functions for
performing set operations on arrays.
+ repeat : Repeat elements of an array.
Notes
-----
>>> a[indices]
array(['a', 'b', 'c'], dtype='<U1')
- Reconstruct the input array from the unique values:
+ Reconstruct the input array from the unique values and inverse:
>>> a = np.array([1, 2, 6, 4, 2, 3, 2])
>>> u, indices = np.unique(a, return_inverse=True)
>>> u[indices]
array([1, 2, 6, 4, 2, 3, 2])
+ Reconstruct the input values from the unique values and counts:
+
+ >>> a = np.array([1, 2, 6, 4, 2, 3, 2])
+ >>> values, counts = np.unique(a, return_counts=True)
+ >>> values
+ array([1, 2, 3, 4, 6])
+ >>> counts
+ array([1, 3, 1, 1, 1])
+ >>> np.repeat(values, counts)
+ array([1, 2, 2, 2, 3, 4, 6]) # original order not preserved
+
"""
ar = np.asanyarray(ar)
if axis is None:
ar = np.moveaxis(ar, axis, 0)
except np.AxisError:
# this removes the "axis1" or "axis2" prefix from the error message
- raise np.AxisError(axis, ar.ndim)
+ raise np.AxisError(axis, ar.ndim) from None
# Must reshape to a contiguous 2D array for this to work...
orig_shape, orig_dtype = ar.shape, ar.dtype
# array with shape `(len(ar),)`. Because `dtype` in this case has
# itemsize 0, the total size of the result is still 0 bytes.
consolidated = np.empty(len(ar), dtype=dtype)
- except TypeError:
+ except TypeError as e:
# There's no good way to do this for object arrays, etc...
msg = 'The axis argument to unique is not supported for dtype {dt}'
- raise TypeError(msg.format(dt=ar.dtype))
+ raise TypeError(msg.format(dt=ar.dtype)) from e
def reshape_uniq(uniq):
n = len(uniq)
Input arrays. Will be flattened if not already 1D.
assume_unique : bool
If True, the input arrays are both assumed to be unique, which
- can speed up the calculation. Default is False.
+ can speed up the calculation. If True but ``ar1`` or ``ar2`` are not
+ unique, incorrect results and out-of-bounds indices could result.
+ Default is False.
return_indices : bool
If True, the indices which correspond to the intersection of the two
arrays are returned. The first instance of a value is used if there are
+++ /dev/null
-"""Some simple financial calculations
-
-patterned after spreadsheet computations.
-
-There is some complexity in each function
-so that the functions behave like ufuncs with
-broadcasting and being able to be called with scalars
-or arrays (or other sequences).
-
-Functions support the :class:`decimal.Decimal` type unless
-otherwise stated.
-"""
-import warnings
-from decimal import Decimal
-import functools
-
-import numpy as np
-from numpy.core import overrides
-
-
-_depmsg = ("numpy.{name} is deprecated and will be removed from NumPy 1.20. "
- "Use numpy_financial.{name} instead "
- "(https://pypi.org/project/numpy-financial/).")
-
-array_function_dispatch = functools.partial(
- overrides.array_function_dispatch, module='numpy')
-
-
-__all__ = ['fv', 'pmt', 'nper', 'ipmt', 'ppmt', 'pv', 'rate',
- 'irr', 'npv', 'mirr']
-
-_when_to_num = {'end':0, 'begin':1,
- 'e':0, 'b':1,
- 0:0, 1:1,
- 'beginning':1,
- 'start':1,
- 'finish':0}
-
-def _convert_when(when):
- #Test to see if when has already been converted to ndarray
- #This will happen if one function calls another, for example ppmt
- if isinstance(when, np.ndarray):
- return when
- try:
- return _when_to_num[when]
- except (KeyError, TypeError):
- return [_when_to_num[x] for x in when]
-
-
-def _fv_dispatcher(rate, nper, pmt, pv, when=None):
- warnings.warn(_depmsg.format(name='fv'),
- DeprecationWarning, stacklevel=3)
- return (rate, nper, pmt, pv)
-
-
-@array_function_dispatch(_fv_dispatcher)
-def fv(rate, nper, pmt, pv, when='end'):
- """
- Compute the future value.
-
- .. deprecated:: 1.18
-
- `fv` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Given:
- * a present value, `pv`
- * an interest `rate` compounded once per period, of which
- there are
- * `nper` total
- * a (fixed) payment, `pmt`, paid either
- * at the beginning (`when` = {'begin', 1}) or the end
- (`when` = {'end', 0}) of each period
-
- Return:
- the value at the end of the `nper` periods
-
- Parameters
- ----------
- rate : scalar or array_like of shape(M, )
- Rate of interest as decimal (not per cent) per period
- nper : scalar or array_like of shape(M, )
- Number of compounding periods
- pmt : scalar or array_like of shape(M, )
- Payment
- pv : scalar or array_like of shape(M, )
- Present value
- when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
- When payments are due ('begin' (1) or 'end' (0)).
- Defaults to {'end', 0}.
-
- Returns
- -------
- out : ndarray
- Future values. If all input is scalar, returns a scalar float. If
- any input is array_like, returns future values for each input element.
- If multiple inputs are array_like, they all must have the same shape.
-
- Notes
- -----
- The future value is computed by solving the equation::
-
- fv +
- pv*(1+rate)**nper +
- pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
-
- or, when ``rate == 0``::
-
- fv + pv + pmt * nper == 0
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
- .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
- Open Document Format for Office Applications (OpenDocument)v1.2,
- Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
- Pre-Draft 12. Organization for the Advancement of Structured Information
- Standards (OASIS). Billerica, MA, USA. [ODT Document].
- Available:
- http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
- OpenDocument-formula-20090508.odt
-
-
- Examples
- --------
- What is the future value after 10 years of saving $100 now, with
- an additional monthly savings of $100. Assume the interest rate is
- 5% (annually) compounded monthly?
-
- >>> np.fv(0.05/12, 10*12, -100, -100)
- 15692.928894335748
-
- By convention, the negative sign represents cash flow out (i.e. money not
- available today). Thus, saving $100 a month at 5% annual interest leads
- to $15,692.93 available to spend in 10 years.
-
- If any input is array_like, returns an array of equal shape. Let's
- compare different interest rates from the example above.
-
- >>> a = np.array((0.05, 0.06, 0.07))/12
- >>> np.fv(a, 10*12, -100, -100)
- array([ 15692.92889434, 16569.87435405, 17509.44688102]) # may vary
-
- """
- when = _convert_when(when)
- (rate, nper, pmt, pv, when) = map(np.asarray, [rate, nper, pmt, pv, when])
- temp = (1+rate)**nper
- fact = np.where(rate == 0, nper,
- (1 + rate*when)*(temp - 1)/rate)
- return -(pv*temp + pmt*fact)
-
-
-def _pmt_dispatcher(rate, nper, pv, fv=None, when=None):
- warnings.warn(_depmsg.format(name='pmt'),
- DeprecationWarning, stacklevel=3)
- return (rate, nper, pv, fv)
-
-
-@array_function_dispatch(_pmt_dispatcher)
-def pmt(rate, nper, pv, fv=0, when='end'):
- """
- Compute the payment against loan principal plus interest.
-
- .. deprecated:: 1.18
-
- `pmt` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Given:
- * a present value, `pv` (e.g., an amount borrowed)
- * a future value, `fv` (e.g., 0)
- * an interest `rate` compounded once per period, of which
- there are
- * `nper` total
- * and (optional) specification of whether payment is made
- at the beginning (`when` = {'begin', 1}) or the end
- (`when` = {'end', 0}) of each period
-
- Return:
- the (fixed) periodic payment.
-
- Parameters
- ----------
- rate : array_like
- Rate of interest (per period)
- nper : array_like
- Number of compounding periods
- pv : array_like
- Present value
- fv : array_like, optional
- Future value (default = 0)
- when : {{'begin', 1}, {'end', 0}}, {string, int}
- When payments are due ('begin' (1) or 'end' (0))
-
- Returns
- -------
- out : ndarray
- Payment against loan plus interest. If all input is scalar, returns a
- scalar float. If any input is array_like, returns payment for each
- input element. If multiple inputs are array_like, they all must have
- the same shape.
-
- Notes
- -----
- The payment is computed by solving the equation::
-
- fv +
- pv*(1 + rate)**nper +
- pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0
-
- or, when ``rate == 0``::
-
- fv + pv + pmt * nper == 0
-
- for ``pmt``.
-
- Note that computing a monthly mortgage payment is only
- one use for this function. For example, pmt returns the
- periodic deposit one must make to achieve a specified
- future balance given an initial deposit, a fixed,
- periodically compounded interest rate, and the total
- number of periods.
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
- .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
- Open Document Format for Office Applications (OpenDocument)v1.2,
- Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
- Pre-Draft 12. Organization for the Advancement of Structured Information
- Standards (OASIS). Billerica, MA, USA. [ODT Document].
- Available:
- http://www.oasis-open.org/committees/documents.php
- ?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
-
- Examples
- --------
- What is the monthly payment needed to pay off a $200,000 loan in 15
- years at an annual interest rate of 7.5%?
-
- >>> np.pmt(0.075/12, 12*15, 200000)
- -1854.0247200054619
-
- In order to pay-off (i.e., have a future-value of 0) the $200,000 obtained
- today, a monthly payment of $1,854.02 would be required. Note that this
- example illustrates usage of `fv` having a default value of 0.
-
- """
- when = _convert_when(when)
- (rate, nper, pv, fv, when) = map(np.array, [rate, nper, pv, fv, when])
- temp = (1 + rate)**nper
- mask = (rate == 0)
- masked_rate = np.where(mask, 1, rate)
- fact = np.where(mask != 0, nper,
- (1 + masked_rate*when)*(temp - 1)/masked_rate)
- return -(fv + pv*temp) / fact
-
-
-def _nper_dispatcher(rate, pmt, pv, fv=None, when=None):
- warnings.warn(_depmsg.format(name='nper'),
- DeprecationWarning, stacklevel=3)
- return (rate, pmt, pv, fv)
-
-
-@array_function_dispatch(_nper_dispatcher)
-def nper(rate, pmt, pv, fv=0, when='end'):
- """
- Compute the number of periodic payments.
-
- .. deprecated:: 1.18
-
- `nper` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- :class:`decimal.Decimal` type is not supported.
-
- Parameters
- ----------
- rate : array_like
- Rate of interest (per period)
- pmt : array_like
- Payment
- pv : array_like
- Present value
- fv : array_like, optional
- Future value
- when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
- When payments are due ('begin' (1) or 'end' (0))
-
- Notes
- -----
- The number of periods ``nper`` is computed by solving the equation::
-
- fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate*((1+rate)**nper-1) = 0
-
- but if ``rate = 0`` then::
-
- fv + pv + pmt*nper = 0
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
-
- Examples
- --------
- If you only had $150/month to pay towards the loan, how long would it take
- to pay-off a loan of $8,000 at 7% annual interest?
-
- >>> print(np.round(np.nper(0.07/12, -150, 8000), 5))
- 64.07335
-
- So, over 64 months would be required to pay off the loan.
-
- The same analysis could be done with several different interest rates
- and/or payments and/or total amounts to produce an entire table.
-
- >>> np.nper(*(np.ogrid[0.07/12: 0.08/12: 0.01/12,
- ... -150 : -99 : 50 ,
- ... 8000 : 9001 : 1000]))
- array([[[ 64.07334877, 74.06368256],
- [108.07548412, 127.99022654]],
- [[ 66.12443902, 76.87897353],
- [114.70165583, 137.90124779]]])
-
- """
- when = _convert_when(when)
- (rate, pmt, pv, fv, when) = map(np.asarray, [rate, pmt, pv, fv, when])
-
- use_zero_rate = False
- with np.errstate(divide="raise"):
- try:
- z = pmt*(1+rate*when)/rate
- except FloatingPointError:
- use_zero_rate = True
-
- if use_zero_rate:
- return (-fv + pv) / pmt
- else:
- A = -(fv + pv)/(pmt+0)
- B = np.log((-fv+z) / (pv+z))/np.log(1+rate)
- return np.where(rate == 0, A, B)
-
-
-def _ipmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
- warnings.warn(_depmsg.format(name='ipmt'),
- DeprecationWarning, stacklevel=3)
- return (rate, per, nper, pv, fv)
-
-
-@array_function_dispatch(_ipmt_dispatcher)
-def ipmt(rate, per, nper, pv, fv=0, when='end'):
- """
- Compute the interest portion of a payment.
-
- .. deprecated:: 1.18
-
- `ipmt` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Parameters
- ----------
- rate : scalar or array_like of shape(M, )
- Rate of interest as decimal (not per cent) per period
- per : scalar or array_like of shape(M, )
- Interest paid against the loan changes during the life or the loan.
- The `per` is the payment period to calculate the interest amount.
- nper : scalar or array_like of shape(M, )
- Number of compounding periods
- pv : scalar or array_like of shape(M, )
- Present value
- fv : scalar or array_like of shape(M, ), optional
- Future value
- when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
- When payments are due ('begin' (1) or 'end' (0)).
- Defaults to {'end', 0}.
-
- Returns
- -------
- out : ndarray
- Interest portion of payment. If all input is scalar, returns a scalar
- float. If any input is array_like, returns interest payment for each
- input element. If multiple inputs are array_like, they all must have
- the same shape.
-
- See Also
- --------
- ppmt, pmt, pv
-
- Notes
- -----
- The total payment is made up of payment against principal plus interest.
-
- ``pmt = ppmt + ipmt``
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
-
- Examples
- --------
- What is the amortization schedule for a 1 year loan of $2500 at
- 8.24% interest per year compounded monthly?
-
- >>> principal = 2500.00
-
- The 'per' variable represents the periods of the loan. Remember that
- financial equations start the period count at 1!
-
- >>> per = np.arange(1*12) + 1
- >>> ipmt = np.ipmt(0.0824/12, per, 1*12, principal)
- >>> ppmt = np.ppmt(0.0824/12, per, 1*12, principal)
-
- Each element of the sum of the 'ipmt' and 'ppmt' arrays should equal
- 'pmt'.
-
- >>> pmt = np.pmt(0.0824/12, 1*12, principal)
- >>> np.allclose(ipmt + ppmt, pmt)
- True
-
- >>> fmt = '{0:2d} {1:8.2f} {2:8.2f} {3:8.2f}'
- >>> for payment in per:
- ... index = payment - 1
- ... principal = principal + ppmt[index]
- ... print(fmt.format(payment, ppmt[index], ipmt[index], principal))
- 1 -200.58 -17.17 2299.42
- 2 -201.96 -15.79 2097.46
- 3 -203.35 -14.40 1894.11
- 4 -204.74 -13.01 1689.37
- 5 -206.15 -11.60 1483.22
- 6 -207.56 -10.18 1275.66
- 7 -208.99 -8.76 1066.67
- 8 -210.42 -7.32 856.25
- 9 -211.87 -5.88 644.38
- 10 -213.32 -4.42 431.05
- 11 -214.79 -2.96 216.26
- 12 -216.26 -1.49 -0.00
-
- >>> interestpd = np.sum(ipmt)
- >>> np.round(interestpd, 2)
- -112.98
-
- """
- when = _convert_when(when)
- rate, per, nper, pv, fv, when = np.broadcast_arrays(rate, per, nper,
- pv, fv, when)
- total_pmt = pmt(rate, nper, pv, fv, when)
- ipmt = _rbl(rate, per, total_pmt, pv, when)*rate
- try:
- ipmt = np.where(when == 1, ipmt/(1 + rate), ipmt)
- ipmt = np.where(np.logical_and(when == 1, per == 1), 0, ipmt)
- except IndexError:
- pass
- return ipmt
-
-
-def _rbl(rate, per, pmt, pv, when):
- """
- This function is here to simply have a different name for the 'fv'
- function to not interfere with the 'fv' keyword argument within the 'ipmt'
- function. It is the 'remaining balance on loan' which might be useful as
- its own function, but is easily calculated with the 'fv' function.
- """
- return fv(rate, (per - 1), pmt, pv, when)
-
-
-def _ppmt_dispatcher(rate, per, nper, pv, fv=None, when=None):
- warnings.warn(_depmsg.format(name='ppmt'),
- DeprecationWarning, stacklevel=3)
- return (rate, per, nper, pv, fv)
-
-
-@array_function_dispatch(_ppmt_dispatcher)
-def ppmt(rate, per, nper, pv, fv=0, when='end'):
- """
- Compute the payment against loan principal.
-
- .. deprecated:: 1.18
-
- `ppmt` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Parameters
- ----------
- rate : array_like
- Rate of interest (per period)
- per : array_like, int
- Amount paid against the loan changes. The `per` is the period of
- interest.
- nper : array_like
- Number of compounding periods
- pv : array_like
- Present value
- fv : array_like, optional
- Future value
- when : {{'begin', 1}, {'end', 0}}, {string, int}
- When payments are due ('begin' (1) or 'end' (0))
-
- See Also
- --------
- pmt, pv, ipmt
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
-
- """
- total = pmt(rate, nper, pv, fv, when)
- return total - ipmt(rate, per, nper, pv, fv, when)
-
-
-def _pv_dispatcher(rate, nper, pmt, fv=None, when=None):
- warnings.warn(_depmsg.format(name='pv'),
- DeprecationWarning, stacklevel=3)
- return (rate, nper, nper, pv, fv)
-
-
-@array_function_dispatch(_pv_dispatcher)
-def pv(rate, nper, pmt, fv=0, when='end'):
- """
- Compute the present value.
-
- .. deprecated:: 1.18
-
- `pv` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Given:
- * a future value, `fv`
- * an interest `rate` compounded once per period, of which
- there are
- * `nper` total
- * a (fixed) payment, `pmt`, paid either
- * at the beginning (`when` = {'begin', 1}) or the end
- (`when` = {'end', 0}) of each period
-
- Return:
- the value now
-
- Parameters
- ----------
- rate : array_like
- Rate of interest (per period)
- nper : array_like
- Number of compounding periods
- pmt : array_like
- Payment
- fv : array_like, optional
- Future value
- when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
- When payments are due ('begin' (1) or 'end' (0))
-
- Returns
- -------
- out : ndarray, float
- Present value of a series of payments or investments.
-
- Notes
- -----
- The present value is computed by solving the equation::
-
- fv +
- pv*(1 + rate)**nper +
- pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) = 0
-
- or, when ``rate = 0``::
-
- fv + pv + pmt * nper = 0
-
- for `pv`, which is then returned.
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
- .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
- Open Document Format for Office Applications (OpenDocument)v1.2,
- Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
- Pre-Draft 12. Organization for the Advancement of Structured Information
- Standards (OASIS). Billerica, MA, USA. [ODT Document].
- Available:
- http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
- OpenDocument-formula-20090508.odt
-
- Examples
- --------
- What is the present value (e.g., the initial investment)
- of an investment that needs to total $15692.93
- after 10 years of saving $100 every month? Assume the
- interest rate is 5% (annually) compounded monthly.
-
- >>> np.pv(0.05/12, 10*12, -100, 15692.93)
- -100.00067131625819
-
- By convention, the negative sign represents cash flow out
- (i.e., money not available today). Thus, to end up with
- $15,692.93 in 10 years saving $100 a month at 5% annual
- interest, one's initial deposit should also be $100.
-
- If any input is array_like, ``pv`` returns an array of equal shape.
- Let's compare different interest rates in the example above:
-
- >>> a = np.array((0.05, 0.04, 0.03))/12
- >>> np.pv(a, 10*12, -100, 15692.93)
- array([ -100.00067132, -649.26771385, -1273.78633713]) # may vary
-
- So, to end up with the same $15692.93 under the same $100 per month
- "savings plan," for annual interest rates of 4% and 3%, one would
- need initial investments of $649.27 and $1273.79, respectively.
-
- """
- when = _convert_when(when)
- (rate, nper, pmt, fv, when) = map(np.asarray, [rate, nper, pmt, fv, when])
- temp = (1+rate)**nper
- fact = np.where(rate == 0, nper, (1+rate*when)*(temp-1)/rate)
- return -(fv + pmt*fact)/temp
-
-# Computed with Sage
-# (y + (r + 1)^n*x + p*((r + 1)^n - 1)*(r*w + 1)/r)/(n*(r + 1)^(n - 1)*x -
-# p*((r + 1)^n - 1)*(r*w + 1)/r^2 + n*p*(r + 1)^(n - 1)*(r*w + 1)/r +
-# p*((r + 1)^n - 1)*w/r)
-
-def _g_div_gp(r, n, p, x, y, w):
- t1 = (r+1)**n
- t2 = (r+1)**(n-1)
- return ((y + t1*x + p*(t1 - 1)*(r*w + 1)/r) /
- (n*t2*x - p*(t1 - 1)*(r*w + 1)/(r**2) + n*p*t2*(r*w + 1)/r +
- p*(t1 - 1)*w/r))
-
-
-def _rate_dispatcher(nper, pmt, pv, fv, when=None, guess=None, tol=None,
- maxiter=None):
- warnings.warn(_depmsg.format(name='rate'),
- DeprecationWarning, stacklevel=3)
- return (nper, pmt, pv, fv)
-
-
-# Use Newton's iteration until the change is less than 1e-6
-# for all values or a maximum of 100 iterations is reached.
-# Newton's rule is
-# r_{n+1} = r_{n} - g(r_n)/g'(r_n)
-# where
-# g(r) is the formula
-# g'(r) is the derivative with respect to r.
-@array_function_dispatch(_rate_dispatcher)
-def rate(nper, pmt, pv, fv, when='end', guess=None, tol=None, maxiter=100):
- """
- Compute the rate of interest per period.
-
- .. deprecated:: 1.18
-
- `rate` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Parameters
- ----------
- nper : array_like
- Number of compounding periods
- pmt : array_like
- Payment
- pv : array_like
- Present value
- fv : array_like
- Future value
- when : {{'begin', 1}, {'end', 0}}, {string, int}, optional
- When payments are due ('begin' (1) or 'end' (0))
- guess : Number, optional
- Starting guess for solving the rate of interest, default 0.1
- tol : Number, optional
- Required tolerance for the solution, default 1e-6
- maxiter : int, optional
- Maximum iterations in finding the solution
-
- Notes
- -----
- The rate of interest is computed by iteratively solving the
- (non-linear) equation::
-
- fv + pv*(1+rate)**nper + pmt*(1+rate*when)/rate * ((1+rate)**nper - 1) = 0
-
- for ``rate``.
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
- .. [2] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
- Open Document Format for Office Applications (OpenDocument)v1.2,
- Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
- Pre-Draft 12. Organization for the Advancement of Structured Information
- Standards (OASIS). Billerica, MA, USA. [ODT Document].
- Available:
- http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
- OpenDocument-formula-20090508.odt
-
- """
- when = _convert_when(when)
- default_type = Decimal if isinstance(pmt, Decimal) else float
-
- # Handle casting defaults to Decimal if/when pmt is a Decimal and
- # guess and/or tol are not given default values
- if guess is None:
- guess = default_type('0.1')
-
- if tol is None:
- tol = default_type('1e-6')
-
- (nper, pmt, pv, fv, when) = map(np.asarray, [nper, pmt, pv, fv, when])
-
- rn = guess
- iterator = 0
- close = False
- while (iterator < maxiter) and not close:
- rnp1 = rn - _g_div_gp(rn, nper, pmt, pv, fv, when)
- diff = abs(rnp1-rn)
- close = np.all(diff < tol)
- iterator += 1
- rn = rnp1
- if not close:
- # Return nan's in array of the same shape as rn
- return np.nan + rn
- else:
- return rn
-
-
-def _irr_dispatcher(values):
- warnings.warn(_depmsg.format(name='irr'),
- DeprecationWarning, stacklevel=3)
- return (values,)
-
-
-@array_function_dispatch(_irr_dispatcher)
-def irr(values):
- """
- Return the Internal Rate of Return (IRR).
-
- .. deprecated:: 1.18
-
- `irr` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- This is the "average" periodically compounded rate of return
- that gives a net present value of 0.0; for a more complete explanation,
- see Notes below.
-
- :class:`decimal.Decimal` type is not supported.
-
- Parameters
- ----------
- values : array_like, shape(N,)
- Input cash flows per time period. By convention, net "deposits"
- are negative and net "withdrawals" are positive. Thus, for
- example, at least the first element of `values`, which represents
- the initial investment, will typically be negative.
-
- Returns
- -------
- out : float
- Internal Rate of Return for periodic input values.
-
- Notes
- -----
- The IRR is perhaps best understood through an example (illustrated
- using np.irr in the Examples section below). Suppose one invests 100
- units and then makes the following withdrawals at regular (fixed)
- intervals: 39, 59, 55, 20. Assuming the ending value is 0, one's 100
- unit investment yields 173 units; however, due to the combination of
- compounding and the periodic withdrawals, the "average" rate of return
- is neither simply 0.73/4 nor (1.73)^0.25-1. Rather, it is the solution
- (for :math:`r`) of the equation:
-
- .. math:: -100 + \\frac{39}{1+r} + \\frac{59}{(1+r)^2}
- + \\frac{55}{(1+r)^3} + \\frac{20}{(1+r)^4} = 0
-
- In general, for `values` :math:`= [v_0, v_1, ... v_M]`,
- irr is the solution of the equation: [2]_
-
- .. math:: \\sum_{t=0}^M{\\frac{v_t}{(1+irr)^{t}}} = 0
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
- .. [2] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
- Addison-Wesley, 2003, pg. 348.
-
- Examples
- --------
- >>> round(np.irr([-100, 39, 59, 55, 20]), 5)
- 0.28095
- >>> round(np.irr([-100, 0, 0, 74]), 5)
- -0.0955
- >>> round(np.irr([-100, 100, 0, -7]), 5)
- -0.0833
- >>> round(np.irr([-100, 100, 0, 7]), 5)
- 0.06206
- >>> round(np.irr([-5, 10.5, 1, -8, 1]), 5)
- 0.0886
-
- """
- # `np.roots` call is why this function does not support Decimal type.
- #
- # Ultimately Decimal support needs to be added to np.roots, which has
- # greater implications on the entire linear algebra module and how it does
- # eigenvalue computations.
- res = np.roots(values[::-1])
- mask = (res.imag == 0) & (res.real > 0)
- if not mask.any():
- return np.nan
- res = res[mask].real
- # NPV(rate) = 0 can have more than one solution so we return
- # only the solution closest to zero.
- rate = 1/res - 1
- rate = rate.item(np.argmin(np.abs(rate)))
- return rate
-
-
-def _npv_dispatcher(rate, values):
- warnings.warn(_depmsg.format(name='npv'),
- DeprecationWarning, stacklevel=3)
- return (values,)
-
-
-@array_function_dispatch(_npv_dispatcher)
-def npv(rate, values):
- """
- Returns the NPV (Net Present Value) of a cash flow series.
-
- .. deprecated:: 1.18
-
- `npv` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Parameters
- ----------
- rate : scalar
- The discount rate.
- values : array_like, shape(M, )
- The values of the time series of cash flows. The (fixed) time
- interval between cash flow "events" must be the same as that for
- which `rate` is given (i.e., if `rate` is per year, then precisely
- a year is understood to elapse between each cash flow event). By
- convention, investments or "deposits" are negative, income or
- "withdrawals" are positive; `values` must begin with the initial
- investment, thus `values[0]` will typically be negative.
-
- Returns
- -------
- out : float
- The NPV of the input cash flow series `values` at the discount
- `rate`.
-
- Warnings
- --------
- ``npv`` considers a series of cashflows starting in the present (t = 0).
- NPV can also be defined with a series of future cashflows, paid at the
- end, rather than the start, of each period. If future cashflows are used,
- the first cashflow `values[0]` must be zeroed and added to the net
- present value of the future cashflows. This is demonstrated in the
- examples.
-
- Notes
- -----
- Returns the result of: [2]_
-
- .. math :: \\sum_{t=0}^{M-1}{\\frac{values_t}{(1+rate)^{t}}}
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
- .. [2] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
- Addison-Wesley, 2003, pg. 346.
-
- Examples
- --------
- Consider a potential project with an initial investment of $40 000 and
- projected cashflows of $5 000, $8 000, $12 000 and $30 000 at the end of
- each period discounted at a rate of 8% per period. To find the project's
- net present value:
-
- >>> rate, cashflows = 0.08, [-40_000, 5_000, 8_000, 12_000, 30_000]
- >>> np.npv(rate, cashflows).round(5)
- 3065.22267
-
- It may be preferable to split the projected cashflow into an initial
- investment and expected future cashflows. In this case, the value of
- the initial cashflow is zero and the initial investment is later added
- to the future cashflows net present value:
-
- >>> initial_cashflow = cashflows[0]
- >>> cashflows[0] = 0
- >>> np.round(np.npv(rate, cashflows) + initial_cashflow, 5)
- 3065.22267
-
- """
- values = np.asarray(values)
- return (values / (1+rate)**np.arange(0, len(values))).sum(axis=0)
-
-
-def _mirr_dispatcher(values, finance_rate, reinvest_rate):
- warnings.warn(_depmsg.format(name='mirr'),
- DeprecationWarning, stacklevel=3)
- return (values,)
-
-
-@array_function_dispatch(_mirr_dispatcher)
-def mirr(values, finance_rate, reinvest_rate):
- """
- Modified internal rate of return.
-
- .. deprecated:: 1.18
-
- `mirr` is deprecated; for details, see NEP 32 [1]_.
- Use the corresponding function in the numpy-financial library,
- https://pypi.org/project/numpy-financial.
-
- Parameters
- ----------
- values : array_like
- Cash flows (must contain at least one positive and one negative
- value) or nan is returned. The first value is considered a sunk
- cost at time zero.
- finance_rate : scalar
- Interest rate paid on the cash flows
- reinvest_rate : scalar
- Interest rate received on the cash flows upon reinvestment
-
- Returns
- -------
- out : float
- Modified internal rate of return
-
- References
- ----------
- .. [1] NumPy Enhancement Proposal (NEP) 32,
- https://numpy.org/neps/nep-0032-remove-financial-functions.html
- """
- values = np.asarray(values)
- n = values.size
-
- # Without this explicit cast the 1/(n - 1) computation below
- # becomes a float, which causes TypeError when using Decimal
- # values.
- if isinstance(finance_rate, Decimal):
- n = Decimal(n)
-
- pos = values > 0
- neg = values < 0
- if not (pos.any() and neg.any()):
- return np.nan
- numer = np.abs(npv(reinvest_rate, values*pos))
- denom = np.abs(npv(finance_rate, values*neg))
- return (numer/denom)**(1/(n - 1))*(1 + reinvest_rate) - 1
- Is straightforward to reverse engineer. Datasets often live longer than
the programs that created them. A competent developer should be
able to create a solution in their preferred programming language to
- read most ``.npy`` files that he has been given without much
+ read most ``.npy`` files that they have been given without much
documentation.
- Allows memory-mapping of the data. See `open_memmep`.
Notes
-----
The ``.npy`` format, including motivation for creating it and a comparison of
-alternatives, is described in the `"npy-format" NEP
-<https://www.numpy.org/neps/nep-0001-npy-format.html>`_, however details have
+alternatives, is described in the
+:doc:`"npy-format" NEP <neps:nep-0001-npy-format>`, however details have
evolved with time and this document is more current.
"""
return dtype.str
def descr_to_dtype(descr):
- '''
- descr may be stored as dtype.descr, which is a list of
- (name, format, [shape]) tuples where format may be a str or a tuple.
- Offsets are not explicitly saved, rather empty fields with
- name, format == '', '|Vn' are added as padding.
-
- This function reverses the process, eliminating the empty padding fields.
- '''
+ """
+ Returns a dtype based off the given description.
+
+ This is essentially the reverse of `dtype_to_descr()`. It will remove
+ the valueless padding fields created by, i.e. simple fields like
+ dtype('float32'), and then convert the description to its corresponding
+ dtype.
+
+ Parameters
+ ----------
+ descr : object
+ The object retreived by dtype.descr. Can be passed to
+ `numpy.dtype()` in order to replicate the input dtype.
+
+ Returns
+ -------
+ dtype : dtype
+ The dtype constructed by the description.
+
+ """
if isinstance(descr, str):
# No padding removal needed
return numpy.dtype(descr)
# Friendlier error message
raise UnicodeError("Unpickling a python object failed: %r\n"
"You may need to pass the encoding= option "
- "to numpy.load" % (err,))
+ "to numpy.load" % (err,)) from err
else:
if isfileobj(fp):
# We can use the fast fromfile() function.
See Also
--------
- memmap
+ numpy.memmap
"""
if isfileobj(filename):
of lists and ndarrays. Success requires no NaNs or Infs.
dtype : data-type, optional
By default, the data-type is inferred from the input data.
- order : {'C', 'F'}, optional
- Whether to use row-major (C-style) or
- column-major (Fortran-style) memory representation.
- Defaults to 'C'.
+ order : {'C', 'F', 'A', 'K'}, optional
+ Memory layout. 'A' and 'K' depend on the order of input array a.
+ 'C' row-major (C-style),
+ 'F' column-major (Fortran-style) memory representation.
+ 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
+ 'K' (keep) preserve input order
+ Defaults to 'C'.
Returns
-------
)
y = zeros(x.shape, x.dtype)
- for k in range(n):
- item = funclist[k]
- if not isinstance(item, collections.abc.Callable):
- y[condlist[k]] = item
+ for cond, func in zip(condlist, funclist):
+ if not isinstance(func, collections.abc.Callable):
+ y[cond] = func
else:
- vals = x[condlist[k]]
+ vals = x[cond]
if vals.size > 0:
- y[condlist[k]] = item(vals, *args, **kw)
+ y[cond] = func(vals, *args, **kw)
return y
choicelist = np.broadcast_arrays(*choicelist)
# If cond array is not an ndarray in boolean format or scalar bool, abort.
- for i in range(len(condlist)):
- cond = condlist[i]
+ for i, cond in enumerate(condlist):
if cond.dtype.type is not np.bool_:
raise TypeError(
'invalid entry {} in condlist: should be boolean ndarray'.format(i))
If `xp` or `fp` are not 1-D sequences
If `period == 0`
+ See Also
+ --------
+ scipy.interpolate
+
Notes
-----
The x-coordinate sequence is expected to be increasing, but this is not
The counterclockwise angle from the positive real axis on the complex
plane in the range ``(-pi, pi]``, with dtype as numpy.float64.
- ..versionchanged:: 1.16.0
+ .. versionchanged:: 1.16.0
This function works on subclasses of ndarray like `ma.array`.
See Also
[1, 2]
"""
+
first = 0
trim = trim.upper()
if 'F' in trim:
.. versionadded:: 1.7.0
cache : bool, optional
- If `True`, then cache the first function call that determines the number
- of outputs if `otypes` is not provided.
+ If `True`, then cache the first function call that determines the number
+ of outputs if `otypes` is not provided.
.. versionadded:: 1.7.0
References
----------
- .. [1] NumPy Reference, section `Generalized Universal Function API
- <https://docs.scipy.org/doc/numpy/reference/c-api.generalized-ufuncs.html>`_.
+ .. [1] :doc:`/reference/c-api/generalized-ufuncs`
Examples
--------
def _cov_dispatcher(m, y=None, rowvar=None, bias=None, ddof=None,
- fweights=None, aweights=None):
+ fweights=None, aweights=None, *, dtype=None):
return (m, y, fweights, aweights)
@array_function_dispatch(_cov_dispatcher)
def cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None,
- aweights=None):
+ aweights=None, *, dtype=None):
"""
Estimate a covariance matrix, given data and weights.
weights can be used to assign probabilities to observation vectors.
.. versionadded:: 1.10
+ dtype : data-type, optional
+ Data-type of the result. By default, the return data-type will have
+ at least `numpy.float64` precision.
+
+ .. versionadded:: 1.20
Returns
-------
if m.ndim > 2:
raise ValueError("m has more than 2 dimensions")
- if y is None:
- dtype = np.result_type(m, np.float64)
- else:
+ if y is not None:
y = np.asarray(y)
if y.ndim > 2:
raise ValueError("y has more than 2 dimensions")
- dtype = np.result_type(m, y, np.float64)
+
+ if dtype is None:
+ if y is None:
+ dtype = np.result_type(m, np.float64)
+ else:
+ dtype = np.result_type(m, y, np.float64)
X = array(m, ndmin=2, dtype=dtype)
if not rowvar and X.shape[0] != 1:
return c.squeeze()
-def _corrcoef_dispatcher(x, y=None, rowvar=None, bias=None, ddof=None):
+def _corrcoef_dispatcher(x, y=None, rowvar=None, bias=None, ddof=None, *,
+ dtype=None):
return (x, y)
@array_function_dispatch(_corrcoef_dispatcher)
-def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, ddof=np._NoValue):
+def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, ddof=np._NoValue, *,
+ dtype=None):
"""
Return Pearson product-moment correlation coefficients.
Has no effect, do not use.
.. deprecated:: 1.10.0
+ dtype : data-type, optional
+ Data-type of the result. By default, the return data-type will have
+ at least `numpy.float64` precision.
+
+ .. versionadded:: 1.20
Returns
-------
arguments had no effect on the return values of the function and can be
safely ignored in this and previous versions of numpy.
+ Examples
+ --------
+ In this example we generate two random arrays, ``xarr`` and ``yarr``, and
+ compute the row-wise and column-wise Pearson correlation coefficients,
+ ``R``. Since ``rowvar`` is true by default, we first find the row-wise
+ Pearson correlation coefficients between the variables of ``xarr``.
+
+ >>> import numpy as np
+ >>> rng = np.random.default_rng(seed=42)
+ >>> xarr = rng.random((3, 3))
+ >>> xarr
+ array([[0.77395605, 0.43887844, 0.85859792],
+ [0.69736803, 0.09417735, 0.97562235],
+ [0.7611397 , 0.78606431, 0.12811363]])
+ >>> R1 = np.corrcoef(xarr)
+ >>> R1
+ array([[ 1. , 0.99256089, -0.68080986],
+ [ 0.99256089, 1. , -0.76492172],
+ [-0.68080986, -0.76492172, 1. ]])
+
+ If we add another set of variables and observations ``yarr``, we can
+ compute the row-wise Pearson correlation coefficients between the
+ variables in ``xarr`` and ``yarr``.
+
+ >>> yarr = rng.random((3, 3))
+ >>> yarr
+ array([[0.45038594, 0.37079802, 0.92676499],
+ [0.64386512, 0.82276161, 0.4434142 ],
+ [0.22723872, 0.55458479, 0.06381726]])
+ >>> R2 = np.corrcoef(xarr, yarr)
+ >>> R2
+ array([[ 1. , 0.99256089, -0.68080986, 0.75008178, -0.934284 ,
+ -0.99004057],
+ [ 0.99256089, 1. , -0.76492172, 0.82502011, -0.97074098,
+ -0.99981569],
+ [-0.68080986, -0.76492172, 1. , -0.99507202, 0.89721355,
+ 0.77714685],
+ [ 0.75008178, 0.82502011, -0.99507202, 1. , -0.93657855,
+ -0.83571711],
+ [-0.934284 , -0.97074098, 0.89721355, -0.93657855, 1. ,
+ 0.97517215],
+ [-0.99004057, -0.99981569, 0.77714685, -0.83571711, 0.97517215,
+ 1. ]])
+
+ Finally if we use the option ``rowvar=False``, the columns are now
+ being treated as the variables and we will find the column-wise Pearson
+ correlation coefficients between variables in ``xarr`` and ``yarr``.
+
+ >>> R3 = np.corrcoef(xarr, yarr, rowvar=False)
+ >>> R3
+ array([[ 1. , 0.77598074, -0.47458546, -0.75078643, -0.9665554 ,
+ 0.22423734],
+ [ 0.77598074, 1. , -0.92346708, -0.99923895, -0.58826587,
+ -0.44069024],
+ [-0.47458546, -0.92346708, 1. , 0.93773029, 0.23297648,
+ 0.75137473],
+ [-0.75078643, -0.99923895, 0.93773029, 1. , 0.55627469,
+ 0.47536961],
+ [-0.9665554 , -0.58826587, 0.23297648, 0.55627469, 1. ,
+ -0.46666491],
+ [ 0.22423734, -0.44069024, 0.75137473, 0.47536961, -0.46666491,
+ 1. ]])
+
"""
if bias is not np._NoValue or ddof is not np._NoValue:
# 2015-03-15, 1.10
warnings.warn('bias and ddof have no effect and are deprecated',
DeprecationWarning, stacklevel=3)
- c = cov(x, y, rowvar)
+ c = cov(x, y, rowvar, dtype=dtype)
try:
d = diag(c)
except ValueError:
return array([])
if M == 1:
return ones(1, float)
- n = arange(0, M)
- return 0.42 - 0.5*cos(2.0*pi*n/(M-1)) + 0.08*cos(4.0*pi*n/(M-1))
+ n = arange(1-M, M, 2)
+ return 0.42 + 0.5*cos(pi*n/(M-1)) + 0.08*cos(2.0*pi*n/(M-1))
@set_module('numpy')
return array([])
if M == 1:
return ones(1, float)
- n = arange(0, M)
- return where(less_equal(n, (M-1)/2.0), 2.0*n/(M-1), 2.0 - 2.0*n/(M-1))
+ n = arange(1-M, M, 2)
+ return where(less_equal(n, 0), 1 + n/(M-1), 1 - n/(M-1))
@set_module('numpy')
return array([])
if M == 1:
return ones(1, float)
- n = arange(0, M)
- return 0.5 - 0.5*cos(2.0*pi*n/(M-1))
+ n = arange(1-M, M, 2)
+ return 0.5 + 0.5*cos(pi*n/(M-1))
@set_module('numpy')
return array([])
if M == 1:
return ones(1, float)
- n = arange(0, M)
- return 0.54 - 0.46*cos(2.0*pi*n/(M-1))
+ n = arange(1-M, M, 2)
+ return 0.54 + 0.46*cos(pi*n/(M-1))
## Code from cephes for i0
"""
Modified Bessel function of the first kind, order 0.
- Usually denoted :math:`I_0`. This function does broadcast, but will *not*
- "up-cast" int dtype arguments unless accompanied by at least one float or
- complex dtype argument (see Raises below).
+ Usually denoted :math:`I_0`.
Parameters
----------
- x : array_like, dtype float or complex
+ x : array_like of float
Argument of the Bessel function.
Returns
-------
- out : ndarray, shape = x.shape, dtype = x.dtype
+ out : ndarray, shape = x.shape, dtype = float
The modified Bessel function evaluated at each of the elements of `x`.
- Raises
- ------
- TypeError: array cannot be safely cast to required type
- If argument consists exclusively of int dtypes.
-
See Also
--------
scipy.special.i0, scipy.special.iv, scipy.special.ive
.. [2] M. Abramowitz and I. A. Stegun, *Handbook of Mathematical
Functions*, 10th printing, New York: Dover, 1964, pp. 379.
http://www.math.sfu.ca/~cbm/aands/page_379.htm
- .. [3] http://kobesearch.cpan.org/htdocs/Math-Cephes/Math/Cephes.html
+ .. [3] https://metacpan.org/pod/distribution/Math-Cephes/lib/Math/Cephes.pod#i0:-Modified-Bessel-function-of-order-zero
Examples
--------
>>> np.i0(0.)
- array(1.0) # may vary
- >>> np.i0([0., 1. + 2j])
- array([ 1.00000000+0.j , 0.18785373+0.64616944j]) # may vary
+ array(1.0)
+ >>> np.i0([0, 1, 2, 3])
+ array([1. , 1.26606588, 2.2795853 , 4.88079259])
"""
x = np.asanyarray(x)
+ if x.dtype.kind == 'c':
+ raise TypeError("i0 not supported for complex values")
+ if x.dtype.kind != 'f':
+ x = x.astype(float)
x = np.abs(x)
return piecewise(x, [x <= 8.0], [_i0_1, _i0_2])
>>> plt.show()
"""
- from numpy.dual import i0
if M == 1:
return np.array([1.])
n = arange(0, M)
@array_function_dispatch(_sinc_dispatcher)
def sinc(x):
- """
- Return the sinc function.
+ r"""
+ Return the normalized sinc function.
+
+ The sinc function is :math:`\sin(\pi x)/(\pi x)`.
- The sinc function is :math:`\\sin(\\pi x)/(\\pi x)`.
+ .. note::
+
+ Note the normalization factor of ``pi`` used in the definition.
+ This is the most commonly used definition in signal processing.
+ Use ``sinc(x / np.pi)`` to obtain the unnormalized sinc function
+ :math:`\sin(x)/(x)` that is more common in mathematics.
Parameters
----------
return True
+def _lerp(a, b, t, out=None):
+ """ Linearly interpolate from a to b by a factor of t """
+ diff_b_a = subtract(b, a)
+ # asanyarray is a stop-gap until gh-13105
+ lerp_interpolation = asanyarray(add(a, diff_b_a*t, out=out))
+ subtract(b, diff_b_a * (1 - t), out=lerp_interpolation, where=t>=0.5)
+ if lerp_interpolation.ndim == 0 and out is None:
+ lerp_interpolation = lerp_interpolation[()] # unpack 0d arrays
+ return lerp_interpolation
+
+
def _quantile_ureduce_func(a, q, axis=None, out=None, overwrite_input=False,
interpolation='linear', keepdims=False):
a = asarray(a)
- if q.ndim == 0:
- # Do not allow 0-d arrays because following code fails for scalar
- zerod = True
- q = q[None]
- else:
- zerod = False
+
+ # ufuncs cause 0d array results to decay to scalars (see gh-13105), which
+ # makes them problematic for __setitem__ and attribute access. As a
+ # workaround, we call this on the result of every ufunc on a possibly-0d
+ # array.
+ not_scalar = np.asanyarray
# prepare a for partitioning
if overwrite_input:
if axis is None:
axis = 0
- Nx = ap.shape[axis]
- indices = q * (Nx - 1)
+ if q.ndim > 2:
+ # The code below works fine for nd, but it might not have useful
+ # semantics. For now, keep the supported dimensions the same as it was
+ # before.
+ raise ValueError("q must be a scalar or 1d")
+ Nx = ap.shape[axis]
+ indices = not_scalar(q * (Nx - 1))
# round fractional indices according to interpolation method
if interpolation == 'lower':
indices = floor(indices).astype(intp)
"interpolation can only be 'linear', 'lower' 'higher', "
"'midpoint', or 'nearest'")
- n = np.array(False, dtype=bool) # check for nan's flag
- if np.issubdtype(indices.dtype, np.integer): # take the points along axis
- # Check if the array contains any nan's
- if np.issubdtype(a.dtype, np.inexact):
- indices = concatenate((indices, [-1]))
-
- ap.partition(indices, axis=axis)
- # ensure axis with q-th is first
- ap = np.moveaxis(ap, axis, 0)
- axis = 0
-
- # Check if the array contains any nan's
- if np.issubdtype(a.dtype, np.inexact):
- indices = indices[:-1]
- n = np.isnan(ap[-1:, ...])
-
- if zerod:
- indices = indices[0]
- r = take(ap, indices, axis=axis, out=out)
+ # The dimensions of `q` are prepended to the output shape, so we need the
+ # axis being sampled from `ap` to be first.
+ ap = np.moveaxis(ap, axis, 0)
+ del axis
- else: # weight the points above and below the indices
- indices_below = floor(indices).astype(intp)
- indices_above = indices_below + 1
- indices_above[indices_above > Nx - 1] = Nx - 1
+ if np.issubdtype(indices.dtype, np.integer):
+ # take the points along axis
- # Check if the array contains any nan's
if np.issubdtype(a.dtype, np.inexact):
- indices_above = concatenate((indices_above, [-1]))
-
- weights_above = indices - indices_below
- weights_below = 1 - weights_above
+ # may contain nan, which would sort to the end
+ ap.partition(concatenate((indices.ravel(), [-1])), axis=0)
+ n = np.isnan(ap[-1])
+ else:
+ # cannot contain nan
+ ap.partition(indices.ravel(), axis=0)
+ n = np.array(False, dtype=bool)
- weights_shape = [1, ] * ap.ndim
- weights_shape[axis] = len(indices)
- weights_below.shape = weights_shape
- weights_above.shape = weights_shape
+ r = take(ap, indices, axis=0, out=out)
- ap.partition(concatenate((indices_below, indices_above)), axis=axis)
+ else:
+ # weight the points above and below the indices
- # ensure axis with q-th is first
- ap = np.moveaxis(ap, axis, 0)
- weights_below = np.moveaxis(weights_below, axis, 0)
- weights_above = np.moveaxis(weights_above, axis, 0)
- axis = 0
+ indices_below = not_scalar(floor(indices)).astype(intp)
+ indices_above = not_scalar(indices_below + 1)
+ indices_above[indices_above > Nx - 1] = Nx - 1
- # Check if the array contains any nan's
if np.issubdtype(a.dtype, np.inexact):
- indices_above = indices_above[:-1]
- n = np.isnan(ap[-1:, ...])
-
- x1 = take(ap, indices_below, axis=axis) * weights_below
- x2 = take(ap, indices_above, axis=axis) * weights_above
+ # may contain nan, which would sort to the end
+ ap.partition(concatenate((
+ indices_below.ravel(), indices_above.ravel(), [-1]
+ )), axis=0)
+ n = np.isnan(ap[-1])
+ else:
+ # cannot contain nan
+ ap.partition(concatenate((
+ indices_below.ravel(), indices_above.ravel()
+ )), axis=0)
+ n = np.array(False, dtype=bool)
- # ensure axis with q-th is first
- x1 = np.moveaxis(x1, axis, 0)
- x2 = np.moveaxis(x2, axis, 0)
+ weights_shape = indices.shape + (1,) * (ap.ndim - 1)
+ weights_above = not_scalar(indices - indices_below).reshape(weights_shape)
- if zerod:
- x1 = x1.squeeze(0)
- x2 = x2.squeeze(0)
+ x_below = take(ap, indices_below, axis=0)
+ x_above = take(ap, indices_above, axis=0)
- if out is not None:
- r = add(x1, x2, out=out)
- else:
- r = add(x1, x2)
+ r = _lerp(x_below, x_above, weights_above, out=out)
+ # if any slice contained a nan, then all results on that slice are also nan
if np.any(n):
- if zerod:
- if ap.ndim == 1:
- if out is not None:
- out[...] = a.dtype.type(np.nan)
- r = out
- else:
- r = a.dtype.type(np.nan)
- else:
- r[..., n.squeeze(0)] = a.dtype.type(np.nan)
+ if r.ndim == 0 and out is None:
+ # can't write to a scalar
+ r = a.dtype.type(np.nan)
else:
- if r.ndim == 1:
- r[:] = a.dtype.type(np.nan)
- else:
- r[..., n.repeat(q.size, 0)] = a.dtype.type(np.nan)
+ r[..., n] = a.dtype.type(np.nan)
return r
See Also
--------
- index_tricks.mgrid : Construct a multi-dimensional "meshgrid"
- using indexing notation.
- index_tricks.ogrid : Construct an open multi-dimensional "meshgrid"
- using indexing notation.
+ mgrid : Construct a multi-dimensional "meshgrid" using indexing notation.
+ ogrid : Construct an open multi-dimensional "meshgrid" using indexing
+ notation.
Examples
--------
import functools
import sys
import math
+import warnings
import numpy.core.numeric as _nx
from numpy.core.numeric import (
start = 0
if step is None:
step = 1
- if isinstance(step, complex):
+ if isinstance(step, (_nx.complexfloating, complex)):
size.append(int(abs(step)))
typ = float
else:
size.append(
int(math.ceil((key[k].stop - start)/(step*1.0))))
- if (isinstance(step, float) or
- isinstance(start, float) or
- isinstance(key[k].stop, float)):
+ if (isinstance(step, (_nx.floating, float)) or
+ isinstance(start, (_nx.floating, float)) or
+ isinstance(key[k].stop, (_nx.floating, float))):
typ = float
if self.sparse:
nn = [_nx.arange(_x, dtype=_t)
start = 0
if step is None:
step = 1
- if isinstance(step, complex):
+ if isinstance(step, (_nx.complexfloating, complex)):
step = int(abs(step))
if step != 1:
step = (key[k].stop - start)/float(step-1)
start = key.start
if start is None:
start = 0
- if isinstance(step, complex):
+ if isinstance(step, (_nx.complexfloating, complex)):
step = abs(step)
length = int(step)
if step != 1:
the stop value **is inclusive**.
Returns
- ----------
+ -------
mesh-grid `ndarrays` all of the same dimensions
See Also
start = 0
if step is None:
step = 1
- if isinstance(step, complex):
+ if isinstance(step, (_nx.complexfloating, complex)):
size = int(abs(step))
newobj = linspace(start, stop, num=size)
else:
Parameters
----------
- `*args` : ints
- The size of each dimension of the array.
+ shape : ints, or a single tuple of ints
+ The size of each dimension of the array can be passed as
+ individual parameters or as the elements of a tuple.
See Also
--------
Examples
--------
+ # dimensions as individual arguments
>>> for index in np.ndindex(3, 2, 1):
... print(index)
(0, 0, 0)
(2, 0, 0)
(2, 1, 0)
+ # same dimensions - but in a tuple (3, 2, 1)
+ >>> for index in np.ndindex((3, 2, 1)):
+ ... print(index)
+ (0, 0, 0)
+ (0, 1, 0)
+ (1, 0, 0)
+ (1, 1, 0)
+ (2, 0, 0)
+ (2, 1, 0)
+
"""
def __init__(self, *shape):
Increment the multi-dimensional index by one.
This method is for backward compatibility only: do not use.
+
+ .. deprecated:: 1.20.0
+ This method has been advised against since numpy 1.8.0, but only
+ started emitting DeprecationWarning as of this version.
"""
+ # NumPy 1.20.0, 2020-09-08
+ warnings.warn(
+ "`ndindex.ndincr()` is deprecated, use `next(ndindex)` instead",
+ DeprecationWarning, stacklevel=2)
next(self)
def __next__(self):
a : array, at least 2-D.
Array whose diagonal is to be filled, it gets modified in-place.
- val : scalar
- Value to be written on the diagonal, its type must be compatible with
- that of the array a.
+ val : scalar or array_like
+ Value(s) to write on the diagonal. If `val` is scalar, the value is
+ written along the diagonal. If array-like, the flattened `val` is
+ written along the diagonal, repeating if necessary to fill all
+ diagonal entries.
wrap : bool
For tall matrices in NumPy version up to 1.6.2, the
ndim : int, optional
The number of dimensions.
- See also
+ See Also
--------
diag_indices_from
It is useful for writing classes that do not inherit from `numpy.ndarray`,
but that should support arithmetic and numpy universal functions like
arrays as described in `A Mechanism for Overriding Ufuncs
- <../../neps/nep-0013-ufunc-overrides.html>`_.
+ <https://numpy.org/neps/nep-0013-ufunc-overrides.html>`_.
As an trivial example, consider this implementation of an ``ArrayLike``
class that simply wraps a NumPy array and ensures that the result of any
Alternate output array in which to place the result. The default
is ``None``; if provided, it must have the same shape as the
expected output, but the type will be cast if necessary. See
- `ufuncs-output-type` for more details.
+ :ref:`ufuncs-output-type` for more details.
.. versionadded:: 1.8.0
keepdims : bool, optional
Alternate output array in which to place the result. The default
is ``None``; if provided, it must have the same shape as the
expected output, but the type will be cast if necessary. See
- `ufuncs-output-type` for more details.
+ :ref:`ufuncs-output-type` for more details.
.. versionadded:: 1.8.0
keepdims : bool, optional
Alternate output array in which to place the result. The default
is ``None``. If provided, it must have the same shape as the
expected output, but the type will be cast if necessary. See
- `ufuncs-output-type` for more details. The casting of NaN to integer
+ :ref:`ufuncs-output-type` for more details. The casting of NaN to integer
can yield unexpected results.
.. versionadded:: 1.8.0
Alternate output array in which to place the result. The default
is ``None``. If provided, it must have the same shape as the
expected output, but the type will be cast if necessary. See
- `ufuncs-output-type` for more details. The casting of NaN to integer
+ :ref:`ufuncs-output-type` for more details. The casting of NaN to integer
can yield unexpected results.
keepdims : bool, optional
If True, the axes which are reduced are left in the result as
out : ndarray, optional
Alternative output array in which to place the result. It must
have the same shape and buffer length as the expected output
- but the type will be cast if necessary. See `ufuncs-output-type` for
+ but the type will be cast if necessary. See :ref:`ufuncs-output-type` for
more details.
Returns
Alternate output array in which to place the result. The default
is ``None``; if provided, it must have the same shape as the
expected output, but the type will be cast if necessary. See
- `ufuncs-output-type` for more details.
+ :ref:`ufuncs-output-type` for more details.
keepdims : bool, optional
If this is set to True, the axes which are reduced are left
in the result as dimensions with size one. With this option,
Compute the qth quantile of the data along the specified axis,
while ignoring nan values.
Returns the qth quantile(s) of the array elements.
-
+
.. versionadded:: 1.15.0
Parameters
mean : Average
var : Variance while not ignoring NaNs
nanstd, nanmean
- ufuncs-output-type
+ :ref:`ufuncs-output-type`
Notes
-----
--------
var, mean, std
nanvar, nanmean
- ufuncs-output-type
+ :ref:`ufuncs-output-type`
Notes
-----
from ._datasource import DataSource
from numpy.core import overrides
from numpy.core.multiarray import packbits, unpackbits
-from numpy.core.overrides import set_module
+from numpy.core.overrides import set_array_function_like_doc, set_module
from numpy.core._internal import recursive
from ._iotools import (
LineSplitter, NameValidator, StringConverter, ConverterError,
)
from numpy.compat import (
- asbytes, asstr, asunicode, bytes, os_fspath, os_PathLike,
+ asbytes, asstr, asunicode, os_fspath, os_PathLike,
pickle, contextlib_nullcontext
)
try:
return object.__getattribute__(self, '_obj')[key]
except KeyError:
- raise AttributeError(key)
+ raise AttributeError(key) from None
def __dir__(self):
"""
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
"""
+ # Make __exit__ safe if zipfile_factory raises an exception
+ zip = None
+ fid = None
def __init__(self, fid, own_fid=False, allow_pickle=False,
pickle_kwargs=None):
self.f = BagObj(self)
if own_fid:
self.fid = fid
- else:
- self.fid = None
def __enter__(self):
return self
"when allow_pickle=False")
try:
return pickle.load(fid, **pickle_kwargs)
- except Exception:
+ except Exception as e:
raise IOError(
- "Failed to interpret file %s as a pickle" % repr(file))
+ "Failed to interpret file %s as a pickle" % repr(file)) from e
def _save_dispatcher(file, arr, allow_pickle=None, fix_imports=None):
zipf = zipfile_factory(file, mode="w", compression=compression)
- if sys.version_info >= (3, 6):
- # Since Python 3.6 it is possible to write directly to a ZIP file.
- for key, val in namedict.items():
- fname = key + '.npy'
- val = np.asanyarray(val)
- # always force zip64, gh-10776
- with zipf.open(fname, 'w', force_zip64=True) as fid:
- format.write_array(fid, val,
- allow_pickle=allow_pickle,
- pickle_kwargs=pickle_kwargs)
- else:
- # Stage arrays in a temporary file on disk, before writing to zip.
-
- # Import deferred for startup time improvement
- import tempfile
- # Since target file might be big enough to exceed capacity of a global
- # temporary directory, create temp file side-by-side with the target file.
- file_dir, file_prefix = os.path.split(file) if _is_string_like(file) else (None, 'tmp')
- fd, tmpfile = tempfile.mkstemp(prefix=file_prefix, dir=file_dir, suffix='-numpy.npy')
- os.close(fd)
- try:
- for key, val in namedict.items():
- fname = key + '.npy'
- fid = open(tmpfile, 'wb')
- try:
- format.write_array(fid, np.asanyarray(val),
- allow_pickle=allow_pickle,
- pickle_kwargs=pickle_kwargs)
- fid.close()
- fid = None
- zipf.write(tmpfile, arcname=fname)
- except IOError as exc:
- raise IOError("Failed to write to %s: %s" % (tmpfile, exc))
- finally:
- if fid:
- fid.close()
- finally:
- os.remove(tmpfile)
+ for key, val in namedict.items():
+ fname = key + '.npy'
+ val = np.asanyarray(val)
+ # always force zip64, gh-10776
+ with zipf.open(fname, 'w', force_zip64=True) as fid:
+ format.write_array(fid, val,
+ allow_pickle=allow_pickle,
+ pickle_kwargs=pickle_kwargs)
zipf.close()
else:
return asstr
+
# amount of lines loadtxt reads in one chunk, can be overridden for testing
_loadtxt_chunksize = 50000
+def _loadtxt_dispatcher(fname, dtype=None, comments=None, delimiter=None,
+ converters=None, skiprows=None, usecols=None, unpack=None,
+ ndmin=None, encoding=None, max_rows=None, *, like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
def loadtxt(fname, dtype=float, comments='#', delimiter=None,
converters=None, skiprows=0, usecols=None, unpack=False,
- ndmin=0, encoding='bytes', max_rows=None):
+ ndmin=0, encoding='bytes', max_rows=None, *, like=None):
r"""
Load data from a text file.
fourth column the same way as ``usecols = (3,)`` would.
unpack : bool, optional
If True, the returned array is transposed, so that arguments may be
- unpacked using ``x, y, z = loadtxt(...)``. When used with a structured
- data-type, arrays are returned for each field. Default is False.
+ unpacked using ``x, y, z = loadtxt(...)``. When used with a
+ structured data-type, arrays are returned for each field.
+ Default is False.
ndmin : int, optional
The returned array will have at least `ndmin` dimensions.
Otherwise mono-dimensional axes will be squeezed.
is to read all the lines.
.. versionadded:: 1.16.0
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
[ 19.22, 64.31],
[-17.57, 63.94]])
"""
- # Type conversions for Py3 convenience
- if comments is not None:
- if isinstance(comments, (str, bytes)):
- comments = [comments]
- comments = [_decode_line(x) for x in comments]
- # Compile regex for comments beforehand
- comments = (re.escape(comment) for comment in comments)
- regex_comments = re.compile('|'.join(comments))
-
- if delimiter is not None:
- delimiter = _decode_line(delimiter)
-
- user_converters = converters
-
- if encoding == 'bytes':
- encoding = None
- byte_converters = True
- else:
- byte_converters = False
-
- if usecols is not None:
- # Allow usecols to be a single int or a sequence of ints
- try:
- usecols_as_list = list(usecols)
- except TypeError:
- usecols_as_list = [usecols]
- for col_idx in usecols_as_list:
- try:
- opindex(col_idx)
- except TypeError as e:
- e.args = (
- "usecols must be an int or a sequence of ints but "
- "it contains at least one element of type %s" %
- type(col_idx),
- )
- raise
- # Fall back to existing code
- usecols = usecols_as_list
- fown = False
- try:
- if isinstance(fname, os_PathLike):
- fname = os_fspath(fname)
- if _is_string_like(fname):
- fh = np.lib._datasource.open(fname, 'rt', encoding=encoding)
- fencoding = getattr(fh, 'encoding', 'latin1')
- fh = iter(fh)
- fown = True
- else:
- fh = iter(fname)
- fencoding = getattr(fname, 'encoding', 'latin1')
- except TypeError:
- raise ValueError('fname must be a string, file handle, or generator')
+ if like is not None:
+ return _loadtxt_with_like(
+ fname, dtype=dtype, comments=comments, delimiter=delimiter,
+ converters=converters, skiprows=skiprows, usecols=usecols,
+ unpack=unpack, ndmin=ndmin, encoding=encoding,
+ max_rows=max_rows, like=like
+ )
- # input may be a python2 io stream
- if encoding is not None:
- fencoding = encoding
- # we must assume local encoding
- # TODO emit portability warning?
- elif fencoding is None:
- import locale
- fencoding = locale.getpreferredencoding()
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ # Nested functions used by loadtxt.
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# not to be confused with the flatten_dtype we import...
@recursive
if comments is not None:
line = regex_comments.split(line, maxsplit=1)[0]
line = line.strip('\r\n')
- if line:
- return line.split(delimiter)
- else:
- return []
+ return line.split(delimiter) if line else []
def read_data(chunk_size):
"""Parse each line, including the first.
if X:
yield X
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ # Main body of loadtxt.
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ # Check correctness of the values of `ndmin`
+ if ndmin not in [0, 1, 2]:
+ raise ValueError('Illegal value of ndmin keyword: %s' % ndmin)
+
+ # Type conversions for Py3 convenience
+ if comments is not None:
+ if isinstance(comments, (str, bytes)):
+ comments = [comments]
+ comments = [_decode_line(x) for x in comments]
+ # Compile regex for comments beforehand
+ comments = (re.escape(comment) for comment in comments)
+ regex_comments = re.compile('|'.join(comments))
+
+ if delimiter is not None:
+ delimiter = _decode_line(delimiter)
+
+ user_converters = converters
+
+ byte_converters = False
+ if encoding == 'bytes':
+ encoding = None
+ byte_converters = True
+
+ if usecols is not None:
+ # Allow usecols to be a single int or a sequence of ints
+ try:
+ usecols_as_list = list(usecols)
+ except TypeError:
+ usecols_as_list = [usecols]
+ for col_idx in usecols_as_list:
+ try:
+ opindex(col_idx)
+ except TypeError as e:
+ e.args = (
+ "usecols must be an int or a sequence of ints but "
+ "it contains at least one element of type %s" %
+ type(col_idx),
+ )
+ raise
+ # Fall back to existing code
+ usecols = usecols_as_list
+
+ # Make sure we're dealing with a proper dtype
+ dtype = np.dtype(dtype)
+ defconv = _getconv(dtype)
+
+ dtype_types, packing = flatten_dtype_internal(dtype)
+
+ fown = False
try:
- # Make sure we're dealing with a proper dtype
- dtype = np.dtype(dtype)
- defconv = _getconv(dtype)
+ if isinstance(fname, os_PathLike):
+ fname = os_fspath(fname)
+ if _is_string_like(fname):
+ fh = np.lib._datasource.open(fname, 'rt', encoding=encoding)
+ fencoding = getattr(fh, 'encoding', 'latin1')
+ fh = iter(fh)
+ fown = True
+ else:
+ fh = iter(fname)
+ fencoding = getattr(fname, 'encoding', 'latin1')
+ except TypeError as e:
+ raise ValueError(
+ 'fname must be a string, file handle, or generator'
+ ) from e
+ # input may be a python2 io stream
+ if encoding is not None:
+ fencoding = encoding
+ # we must assume local encoding
+ # TODO emit portability warning?
+ elif fencoding is None:
+ import locale
+ fencoding = locale.getpreferredencoding()
+
+ try:
# Skip the first `skiprows` lines
for i in range(skiprows):
next(fh)
# End of lines reached
first_line = ''
first_vals = []
- warnings.warn('loadtxt: Empty input file: "%s"' % fname, stacklevel=2)
+ warnings.warn('loadtxt: Empty input file: "%s"' % fname,
+ stacklevel=2)
N = len(usecols or first_vals)
- dtype_types, packing = flatten_dtype_internal(dtype)
+ # Now that we know N, create the default converters list, and
+ # set packing, if necessary.
if len(dtype_types) > 1:
# We're dealing with a structured array, each field of
# the dtype matches a column
# Unused converter specified
continue
if byte_converters:
- # converters may use decode to workaround numpy's old behaviour,
- # so encode the string again before passing to the user converter
+ # converters may use decode to workaround numpy's old
+ # behaviour, so encode the string again before passing to
+ # the user converter
def tobytes_first(x, conv):
if type(x) is bytes:
return conv(x)
X.shape = (1, -1)
# Verify that the array has at least dimensions `ndmin`.
- # Check correctness of the values of `ndmin`
- if ndmin not in [0, 1, 2]:
- raise ValueError('Illegal value of ndmin keyword: %s' % ndmin)
# Tweak the size and shape of the arrays - remove extraneous dimensions
if X.ndim > ndmin:
X = np.squeeze(X)
return X
+_loadtxt_with_like = array_function_dispatch(
+ _loadtxt_dispatcher
+)(loadtxt)
+
+
def _savetxt_dispatcher(fname, X, fmt=None, delimiter=None, newline=None,
header=None, footer=None, comments=None,
encoding=None):
for row in X:
try:
v = format % tuple(row) + newline
- except TypeError:
+ except TypeError as e:
raise TypeError("Mismatch between array dtype ('%s') and "
"format specifier ('%s')"
- % (str(X.dtype), format))
+ % (str(X.dtype), format)) from e
fh.write(v)
if len(footer) > 0:
-----
Dtypes for structured arrays can be specified in several forms, but all
forms specify at least the data type and field name. For details see
- `doc.structured_arrays`.
+ `basics.rec`.
Examples
--------
#####--------------------------------------------------------------------------
+def _genfromtxt_dispatcher(fname, dtype=None, comments=None, delimiter=None,
+ skip_header=None, skip_footer=None, converters=None,
+ missing_values=None, filling_values=None, usecols=None,
+ names=None, excludelist=None, deletechars=None,
+ replace_space=None, autostrip=None, case_sensitive=None,
+ defaultfmt=None, unpack=None, usemask=None, loose=None,
+ invalid_raise=None, max_rows=None, encoding=None, *,
+ like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
skip_header=0, skip_footer=0, converters=None,
deletechars=''.join(sorted(NameValidator.defaultdeletechars)),
replace_space='_', autostrip=False, case_sensitive=True,
defaultfmt="f%i", unpack=None, usemask=False, loose=True,
- invalid_raise=True, max_rows=None, encoding='bytes'):
+ invalid_raise=True, max_rows=None, encoding='bytes', *,
+ like=None):
"""
Load data from a text file, with missing values handled as specified.
If 'lower', field names are converted to lower case.
unpack : bool, optional
If True, the returned array is transposed, so that arguments may be
- unpacked using ``x, y, z = loadtxt(...)``
+ unpacked using ``x, y, z = genfromtxt(...)``. When used with a
+ structured data-type, arrays are returned for each field.
+ Default is False.
usemask : bool, optional
If True, return a masked array.
If False, return a regular array.
to None the system default is used. The default value is 'bytes'.
.. versionadded:: 1.14.0
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
<https://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html>`_.
Examples
- ---------
+ --------
>>> from io import StringIO
>>> import numpy as np
dtype=[('f0', 'S12'), ('f1', 'S12')])
"""
+
+ if like is not None:
+ return _genfromtxt_with_like(
+ fname, dtype=dtype, comments=comments, delimiter=delimiter,
+ skip_header=skip_header, skip_footer=skip_footer,
+ converters=converters, missing_values=missing_values,
+ filling_values=filling_values, usecols=usecols, names=names,
+ excludelist=excludelist, deletechars=deletechars,
+ replace_space=replace_space, autostrip=autostrip,
+ case_sensitive=case_sensitive, defaultfmt=defaultfmt,
+ unpack=unpack, usemask=usemask, loose=loose,
+ invalid_raise=invalid_raise, max_rows=max_rows, encoding=encoding,
+ like=like
+ )
+
if max_rows is not None:
if skip_footer:
raise ValueError(
fid = fname
fid_ctx = contextlib_nullcontext(fid)
fhd = iter(fid)
- except TypeError:
+ except TypeError as e:
raise TypeError(
"fname must be a string, filehandle, list of strings, "
- "or generator. Got %s instead." % type(fname))
+ "or generator. Got %s instead." % type(fname)) from e
with fid_ctx:
split_line = LineSplitter(delimiter=delimiter, comments=comments,
if usemask:
output = output.view(MaskedArray)
output._mask = outputmask
+ output = np.squeeze(output)
if unpack:
- return output.squeeze().T
- return output.squeeze()
+ if names is None:
+ return output.T
+ elif len(names) == 1:
+ # squeeze single-name dtypes too
+ return output[names[0]]
+ else:
+ # For structured arrays with multiple fields,
+ # return an array for each field.
+ return [output[field] for field in names]
+ return output
+
+
+_genfromtxt_with_like = array_function_dispatch(
+ _genfromtxt_dispatcher
+)(genfromtxt)
def ndfromtxt(fname, **kwargs):
"""
Find the coefficients of a polynomial with the given sequence of roots.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
Returns the coefficients of the polynomial whose leading coefficient
is one for the given sequence of zeros (multiple roots must be included
in the sequence as many times as their multiplicity; see Examples).
"""
Return the roots of a polynomial with coefficients given in p.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
The values in the rank-1 array `p` are coefficients of a polynomial.
If the length of `p` is n+1 then the polynomial is described by::
"""
Return an antiderivative (indefinite integral) of a polynomial.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
The returned order `m` antiderivative `P` of polynomial `p` satisfies
:math:`\\frac{d^m}{dx^m}P(x) = p(x)` and is defined up to `m - 1`
integration constants `k`. The constants determine the low-order
"""
Return the derivative of the specified order of a polynomial.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
Parameters
----------
p : poly1d or sequence
>>> np.polyder(p, 3)
poly1d([6])
>>> np.polyder(p, 4)
- poly1d([0.])
+ poly1d([0])
"""
m = int(m)
"""
Least squares polynomial fit.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
Fit a polynomial ``p(x) = p[0] * x**deg + ... + p[deg]`` of degree `deg`
to points `(x, y)`. Returns a vector of coefficients `p` that minimises
the squared error in the order `deg`, `deg-1`, ... `0`.
cov : bool or str, optional
If given and not `False`, return not just the estimate but also its
covariance matrix. By default, the covariance are scaled by
- chi2/sqrt(N-dof), i.e., the weights are presumed to be unreliable
- except in a relative sense and everything is scaled such that the
- reduced chi2 is unity. This scaling is omitted if ``cov='unscaled'``,
- as is relevant for the case that the weights are 1/sigma**2, with
- sigma known to be a reliable estimate of the uncertainty.
+ chi2/dof, where dof = M - (deg + 1), i.e., the weights are presumed
+ to be unreliable except in a relative sense and everything is scaled
+ such that the reduced chi2 is unity. This scaling is omitted if
+ ``cov='unscaled'``, as is relevant for the case that the weights are
+ 1/sigma**2, with sigma known to be a reliable estimate of the
+ uncertainty.
Returns
-------
"""
Evaluate a polynomial at specific values.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
If `p` is of length N, this function returns the value:
``p[0]*x**(N-1) + p[1]*x**(N-2) + ... + p[N-2]*x + p[N-1]``
>>> np.polyval([3,0,1], 5) # 3 * 5**2 + 0 * 5**1 + 1
76
>>> np.polyval([3,0,1], np.poly1d(5))
- poly1d([76.])
+ poly1d([76])
>>> np.polyval(np.poly1d([3,0,1]), 5)
76
>>> np.polyval(np.poly1d([3,0,1]), np.poly1d(5))
- poly1d([76.])
+ poly1d([76])
"""
p = NX.asarray(p)
"""
Find the sum of two polynomials.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
Returns the polynomial resulting from the sum of two input polynomials.
Each input must be either a poly1d object or a 1D sequence of polynomial
coefficients, from highest to lowest degree.
"""
Difference (subtraction) of two polynomials.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
Given two polynomials `a1` and `a2`, returns ``a1 - a2``.
`a1` and `a2` can be either array_like sequences of the polynomials'
coefficients (including coefficients equal to zero), or `poly1d` objects.
"""
Find the product of two polynomials.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
Finds the polynomial resulting from the multiplication of the two input
polynomials. Each input must be either a poly1d object or a 1D sequence
of polynomial coefficients, from highest to lowest degree.
"""
Returns the quotient and remainder of polynomial division.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
The input arrays are the coefficients (including any coefficients
equal to zero) of the "numerator" (dividend) and "denominator"
(divisor) polynomials, respectively.
(array([1.5 , 1.75]), array([0.25]))
"""
- truepoly = (isinstance(u, poly1d) or isinstance(u, poly1d))
+ truepoly = (isinstance(u, poly1d) or isinstance(v, poly1d))
u = atleast_1d(u) + 0.0
v = atleast_1d(v) + 0.0
# w has the common type
"""
A one-dimensional polynomial class.
+ .. note::
+ This forms part of the old polynomial API. Since version 1.4, the
+ new polynomial API defined in `numpy.polynomial` is preferred.
+ A summary of the differences can be found in the
+ :doc:`transition guide </reference/routines.polynomials>`.
+
A convenience class, used to encapsulate "natural" operations on
polynomials so that said operations may take on their customary
form in code (see Examples).
raise ValueError("Polynomial must be 1d only.")
c_or_r = trim_zeros(c_or_r, trim='f')
if len(c_or_r) == 0:
- c_or_r = NX.array([0.])
+ c_or_r = NX.array([0], dtype=c_or_r.dtype)
self._coeffs = c_or_r
if variable is None:
variable = 'x'
Nested fields are supported.
- ..versionchanged: 1.18.0
+ .. versionchanged:: 1.18.0
`drop_fields` returns an array with 0 fields if all fields are dropped,
rather than returning ``None`` as it did previously.
@array_function_dispatch(_structured_to_unstructured_dispatcher)
def structured_to_unstructured(arr, dtype=None, copy=False, casting='unsafe'):
"""
- Converts and n-D structured array into an (n+1)-D unstructured array.
+ Converts an n-D structured array into an (n+1)-D unstructured array.
The new array will have a new last dimension equal in size to the
number of field-elements of the input array. If not supplied, the output
def unstructured_to_structured(arr, dtype=None, names=None, align=False,
copy=False, casting='unsafe'):
"""
- Converts and n-D unstructured array into an (n-1)-D structured array.
+ Converts an n-D unstructured array into an (n-1)-D structured array.
The last dimension of the input array is converted into a structure, with
number of field-elements equal to the size of the last dimension of the
Similarly, `sqrt`, other base logarithms, `power` and trig functions are
correctly handled. See their respective docstrings for specific examples.
+Functions
+---------
+
+.. autosummary::
+ :toctree: generated/
+
+ sqrt
+ log
+ log2
+ logn
+ log10
+ power
+ arccos
+ arcsin
+ arctanh
+
"""
import numpy.core.numeric as nx
import numpy.core.numerictypes as nt
config = Configuration('lib', parent_package, top_path)
config.add_subpackage('tests')
config.add_data_dir('tests/data')
+ config.add_data_files('*.pyi')
return config
if __name__ == '__main__':
Apply a function to 1-D slices of an array along the given axis.
Notes
- ------
+ -----
This function is equivalent to tuple axis arguments to reorderable ufuncs
with keepdims=True. Tuple axis arguments to ufuncs have been available since
version 1.7.0.
--------
>>> x = np.arange(8.0)
>>> np.array_split(x, 3)
- [array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7.])]
+ [array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7.])]
- >>> x = np.arange(7.0)
- >>> np.array_split(x, 3)
- [array([0., 1., 2.]), array([3., 4.]), array([5., 6.])]
+ >>> x = np.arange(9)
+ >>> np.array_split(x, 4)
+ [array([0, 1, 2]), array([3, 4]), array([5, 6]), array([7, 8])]
"""
try:
N = ary.shape[axis]
if N % sections:
raise ValueError(
- 'array split does not result in an equal division')
+ 'array split does not result in an equal division') from None
return array_split(ary, indices_or_sections, axis)
"""
import numpy as np
-from numpy.core.overrides import array_function_dispatch
+from numpy.core.numeric import normalize_axis_tuple
+from numpy.core.overrides import array_function_dispatch, set_module
-__all__ = ['broadcast_to', 'broadcast_arrays']
+__all__ = ['broadcast_to', 'broadcast_arrays', 'broadcast_shapes']
class DummyArray:
See also
--------
- broadcast_to: broadcast an array to a given shape.
+ broadcast_to : broadcast an array to a given shape.
reshape : reshape an array.
+ lib.stride_tricks.sliding_window_view :
+ userfriendly and safe function for the creation of sliding window views.
Notes
-----
return view
+def _sliding_window_view_dispatcher(x, window_shape, axis=None, *,
+ subok=None, writeable=None):
+ return (x,)
+
+
+@array_function_dispatch(_sliding_window_view_dispatcher)
+def sliding_window_view(x, window_shape, axis=None, *,
+ subok=False, writeable=False):
+ """
+ Create a sliding window view into the array with the given window shape.
+
+ Also known as rolling or moving window, the window slides across all
+ dimensions of the array and extracts subsets of the array at all window
+ positions.
+
+ .. versionadded:: 1.20.0
+
+ Parameters
+ ----------
+ x : array_like
+ Array to create the sliding window view from.
+ window_shape : int or tuple of int
+ Size of window over each axis that takes part in the sliding window.
+ If `axis` is not present, must have same length as the number of input
+ array dimensions. Single integers `i` are treated as if they were the
+ tuple `(i,)`.
+ axis : int or tuple of int, optional
+ Axis or axes along which the sliding window is applied.
+ By default, the sliding window is applied to all axes and
+ `window_shape[i]` will refer to axis `i` of `x`.
+ If `axis` is given as a `tuple of int`, `window_shape[i]` will refer to
+ the axis `axis[i]` of `x`.
+ Single integers `i` are treated as if they were the tuple `(i,)`.
+ subok : bool, optional
+ If True, sub-classes will be passed-through, otherwise the returned
+ array will be forced to be a base-class array (default).
+ writeable : bool, optional
+ When true, allow writing to the returned view. The default is false,
+ as this should be used with caution: the returned view contains the
+ same memory location multiple times, so writing to one location will
+ cause others to change.
+
+ Returns
+ -------
+ view : ndarray
+ Sliding window view of the array. The sliding window dimensions are
+ inserted at the end, and the original dimensions are trimmed as
+ required by the size of the sliding window.
+ That is, ``view.shape = x_shape_trimmed + window_shape``, where
+ ``x_shape_trimmed`` is ``x.shape`` with every entry reduced by one less
+ than the corresponding window size.
+
+ See Also
+ --------
+ lib.stride_tricks.as_strided: A lower-level and less safe routine for
+ creating arbitrary views from custom shape and strides.
+ broadcast_to: broadcast an array to a given shape.
+
+ Notes
+ -----
+ For many applications using a sliding window view can be convenient, but
+ potentially very slow. Often specialized solutions exist, for example:
+
+ - `scipy.signal.fftconvolve`
+
+ - filtering functions in `scipy.ndimage`
+
+ - moving window functions provided by
+ `bottleneck <https://github.com/pydata/bottleneck>`_.
+
+ As a rough estimate, a sliding window approach with an input size of `N`
+ and a window size of `W` will scale as `O(N*W)` where frequently a special
+ algorithm can achieve `O(N)`. That means that the sliding window variant
+ for a window size of 100 can be a 100 times slower than a more specialized
+ version.
+
+ Nevertheless, for small window sizes, when no custom algorithm exists, or
+ as a prototyping and developing tool, this function can be a good solution.
+
+ Examples
+ --------
+ >>> x = np.arange(6)
+ >>> x.shape
+ (6,)
+ >>> v = sliding_window_view(x, 3)
+ >>> v.shape
+ (4, 3)
+ >>> v
+ array([[0, 1, 2],
+ [1, 2, 3],
+ [2, 3, 4],
+ [3, 4, 5]])
+
+ This also works in more dimensions, e.g.
+
+ >>> i, j = np.ogrid[:3, :4]
+ >>> x = 10*i + j
+ >>> x.shape
+ (3, 4)
+ >>> x
+ array([[ 0, 1, 2, 3],
+ [10, 11, 12, 13],
+ [20, 21, 22, 23]])
+ >>> shape = (2,2)
+ >>> v = sliding_window_view(x, shape)
+ >>> v.shape
+ (2, 3, 2, 2)
+ >>> v
+ array([[[[ 0, 1],
+ [10, 11]],
+ [[ 1, 2],
+ [11, 12]],
+ [[ 2, 3],
+ [12, 13]]],
+ [[[10, 11],
+ [20, 21]],
+ [[11, 12],
+ [21, 22]],
+ [[12, 13],
+ [22, 23]]]])
+
+ The axis can be specified explicitly:
+
+ >>> v = sliding_window_view(x, 3, 0)
+ >>> v.shape
+ (1, 4, 3)
+ >>> v
+ array([[[ 0, 10, 20],
+ [ 1, 11, 21],
+ [ 2, 12, 22],
+ [ 3, 13, 23]]])
+
+ The same axis can be used several times. In that case, every use reduces
+ the corresponding original dimension:
+
+ >>> v = sliding_window_view(x, (2, 3), (1, 1))
+ >>> v.shape
+ (3, 1, 2, 3)
+ >>> v
+ array([[[[ 0, 1, 2],
+ [ 1, 2, 3]]],
+ [[[10, 11, 12],
+ [11, 12, 13]]],
+ [[[20, 21, 22],
+ [21, 22, 23]]]])
+
+ Combining with stepped slicing (`::step`), this can be used to take sliding
+ views which skip elements:
+
+ >>> x = np.arange(7)
+ >>> sliding_window_view(x, 5)[:, ::2]
+ array([[0, 2, 4],
+ [1, 3, 5],
+ [2, 4, 6]])
+
+ or views which move by multiple elements
+
+ >>> x = np.arange(7)
+ >>> sliding_window_view(x, 3)[::2, :]
+ array([[0, 1, 2],
+ [2, 3, 4],
+ [4, 5, 6]])
+
+ A common application of `sliding_window_view` is the calculation of running
+ statistics. The simplest example is the
+ `moving average <https://en.wikipedia.org/wiki/Moving_average>`_:
+
+ >>> x = np.arange(6)
+ >>> x.shape
+ (6,)
+ >>> v = sliding_window_view(x, 3)
+ >>> v.shape
+ (4, 3)
+ >>> v
+ array([[0, 1, 2],
+ [1, 2, 3],
+ [2, 3, 4],
+ [3, 4, 5]])
+ >>> moving_average = v.mean(axis=-1)
+ >>> moving_average
+ array([1., 2., 3., 4.])
+
+ Note that a sliding window approach is often **not** optimal (see Notes).
+ """
+ window_shape = (tuple(window_shape)
+ if np.iterable(window_shape)
+ else (window_shape,))
+ # first convert input to array, possibly keeping subclass
+ x = np.array(x, copy=False, subok=subok)
+
+ window_shape_array = np.array(window_shape)
+ if np.any(window_shape_array < 0):
+ raise ValueError('`window_shape` cannot contain negative values')
+
+ if axis is None:
+ axis = tuple(range(x.ndim))
+ if len(window_shape) != len(axis):
+ raise ValueError(f'Since axis is `None`, must provide '
+ f'window_shape for all dimensions of `x`; '
+ f'got {len(window_shape)} window_shape elements '
+ f'and `x.ndim` is {x.ndim}.')
+ else:
+ axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True)
+ if len(window_shape) != len(axis):
+ raise ValueError(f'Must provide matching length window_shape and '
+ f'axis; got {len(window_shape)} window_shape '
+ f'elements and {len(axis)} axes elements.')
+
+ out_strides = x.strides + tuple(x.strides[ax] for ax in axis)
+
+ # note: same axis can be windowed repeatedly
+ x_shape_trimmed = list(x.shape)
+ for ax, dim in zip(axis, window_shape):
+ if x_shape_trimmed[ax] < dim:
+ raise ValueError(
+ 'window shape cannot be larger than input array shape')
+ x_shape_trimmed[ax] -= dim - 1
+ out_shape = tuple(x_shape_trimmed) + window_shape
+ return as_strided(x, strides=out_strides, shape=out_shape,
+ subok=subok, writeable=writeable)
+
+
def _broadcast_to(array, shape, subok, readonly):
shape = tuple(shape) if np.iterable(shape) else (shape,)
array = np.array(array, copy=False, subok=subok)
If the array is not compatible with the new shape according to NumPy's
broadcasting rules.
+ See Also
+ --------
+ broadcast
+ broadcast_arrays
+ broadcast_shapes
+
Notes
-----
.. versionadded:: 1.10.0
return b.shape
+@set_module('numpy')
+def broadcast_shapes(*args):
+ """
+ Broadcast the input shapes into a single shape.
+
+ :ref:`Learn more about broadcasting here <basics.broadcasting>`.
+
+ .. versionadded:: 1.20.0
+
+ Parameters
+ ----------
+ `*args` : tuples of ints, or ints
+ The shapes to be broadcast against each other.
+
+ Returns
+ -------
+ tuple
+ Broadcasted shape.
+
+ Raises
+ ------
+ ValueError
+ If the shapes are not compatible and cannot be broadcast according
+ to NumPy's broadcasting rules.
+
+ See Also
+ --------
+ broadcast
+ broadcast_arrays
+ broadcast_to
+
+ Examples
+ --------
+ >>> np.broadcast_shapes((1, 2), (3, 1), (3, 2))
+ (3, 2)
+
+ >>> np.broadcast_shapes((6, 7), (5, 6, 1), (7,), (5, 1, 7))
+ (5, 6, 7)
+ """
+ arrays = [np.empty(x, dtype=[]) for x in args]
+ return _broadcast_shape(*arrays)
+
+
def _broadcast_arrays_dispatcher(*args, subok=None):
return args
warning will be emitted. A future version will set the
``writable`` flag False so writing to it will raise an error.
+ See Also
+ --------
+ broadcast
+ broadcast_to
+ broadcast_shapes
+
Examples
--------
>>> x = np.array([[1,2,3]])
assert_array_equal([7, 1], ediff1d(two_elem, to_begin=7))
assert_array_equal([5, 6, 1], ediff1d(two_elem, to_begin=[5, 6]))
- @pytest.mark.parametrize("ary, prepend, append", [
+ @pytest.mark.parametrize("ary, prepend, append, expected", [
# should fail because trying to cast
# np.nan standard floating point value
# into an integer array:
(np.array([1, 2, 3], dtype=np.int64),
None,
- np.nan),
+ np.nan,
+ 'to_end'),
# should fail because attempting
# to downcast to int type:
(np.array([1, 2, 3], dtype=np.int64),
np.array([5, 7, 2], dtype=np.float32),
- None),
+ None,
+ 'to_begin'),
# should fail because attempting to cast
# two special floating point values
- # to integers (on both sides of ary):
+ # to integers (on both sides of ary),
+ # `to_begin` is in the error message as the impl checks this first:
(np.array([1., 3., 9.], dtype=np.int8),
np.nan,
- np.nan),
+ np.nan,
+ 'to_begin'),
])
- def test_ediff1d_forbidden_type_casts(self, ary, prepend, append):
+ def test_ediff1d_forbidden_type_casts(self, ary, prepend, append, expected):
# verify resolution of gh-11490
# specifically, raise an appropriate
# Exception when attempting to append or
# prepend with an incompatible type
- msg = 'must be compatible'
+ msg = 'dtype of `{}` must be compatible'.format(expected)
with assert_raises_regex(TypeError, msg):
ediff1d(ary=ary,
to_end=append,
+++ /dev/null
-import warnings
-from decimal import Decimal
-
-import numpy as np
-from numpy.testing import (
- assert_, assert_almost_equal, assert_allclose, assert_equal, assert_raises
- )
-
-
-def filter_deprecation(func):
- def newfunc(*args, **kwargs):
- with warnings.catch_warnings(record=True) as ws:
- warnings.filterwarnings('always', category=DeprecationWarning)
- func(*args, **kwargs)
- assert_(all(w.category is DeprecationWarning for w in ws))
- return newfunc
-
-
-class TestFinancial:
- @filter_deprecation
- def test_npv_irr_congruence(self):
- # IRR is defined as the rate required for the present value of a
- # a series of cashflows to be zero i.e. NPV(IRR(x), x) = 0
- cashflows = np.array([-40000, 5000, 8000, 12000, 30000])
- assert_allclose(np.npv(np.irr(cashflows), cashflows), 0, atol=1e-10, rtol=0)
-
- @filter_deprecation
- def test_rate(self):
- assert_almost_equal(
- np.rate(10, 0, -3500, 10000),
- 0.1107, 4)
-
- @filter_deprecation
- def test_rate_decimal(self):
- rate = np.rate(Decimal('10'), Decimal('0'), Decimal('-3500'), Decimal('10000'))
- assert_equal(Decimal('0.1106908537142689284704528100'), rate)
-
- @filter_deprecation
- def test_irr(self):
- v = [-150000, 15000, 25000, 35000, 45000, 60000]
- assert_almost_equal(np.irr(v), 0.0524, 2)
- v = [-100, 0, 0, 74]
- assert_almost_equal(np.irr(v), -0.0955, 2)
- v = [-100, 39, 59, 55, 20]
- assert_almost_equal(np.irr(v), 0.28095, 2)
- v = [-100, 100, 0, -7]
- assert_almost_equal(np.irr(v), -0.0833, 2)
- v = [-100, 100, 0, 7]
- assert_almost_equal(np.irr(v), 0.06206, 2)
- v = [-5, 10.5, 1, -8, 1]
- assert_almost_equal(np.irr(v), 0.0886, 2)
-
- # Test that if there is no solution then np.irr returns nan
- # Fixes gh-6744
- v = [-1, -2, -3]
- assert_equal(np.irr(v), np.nan)
-
- @filter_deprecation
- def test_pv(self):
- assert_almost_equal(np.pv(0.07, 20, 12000, 0), -127128.17, 2)
-
- @filter_deprecation
- def test_pv_decimal(self):
- assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0')),
- Decimal('-127128.1709461939327295222005'))
-
- @filter_deprecation
- def test_fv(self):
- assert_equal(np.fv(0.075, 20, -2000, 0, 0), 86609.362673042924)
-
- @filter_deprecation
- def test_fv_decimal(self):
- assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), 0, 0),
- Decimal('86609.36267304300040536731624'))
-
- @filter_deprecation
- def test_pmt(self):
- res = np.pmt(0.08 / 12, 5 * 12, 15000)
- tgt = -304.145914
- assert_allclose(res, tgt)
- # Test the edge case where rate == 0.0
- res = np.pmt(0.0, 5 * 12, 15000)
- tgt = -250.0
- assert_allclose(res, tgt)
- # Test the case where we use broadcast and
- # the arguments passed in are arrays.
- res = np.pmt([[0.0, 0.8], [0.3, 0.8]], [12, 3], [2000, 20000])
- tgt = np.array([[-166.66667, -19311.258], [-626.90814, -19311.258]])
- assert_allclose(res, tgt)
-
- @filter_deprecation
- def test_pmt_decimal(self):
- res = np.pmt(Decimal('0.08') / Decimal('12'), 5 * 12, 15000)
- tgt = Decimal('-304.1459143262052370338701494')
- assert_equal(res, tgt)
- # Test the edge case where rate == 0.0
- res = np.pmt(Decimal('0'), Decimal('60'), Decimal('15000'))
- tgt = -250
- assert_equal(res, tgt)
- # Test the case where we use broadcast and
- # the arguments passed in are arrays.
- res = np.pmt([[Decimal('0'), Decimal('0.8')], [Decimal('0.3'), Decimal('0.8')]],
- [Decimal('12'), Decimal('3')], [Decimal('2000'), Decimal('20000')])
- tgt = np.array([[Decimal('-166.6666666666666666666666667'), Decimal('-19311.25827814569536423841060')],
- [Decimal('-626.9081401700757748402586600'), Decimal('-19311.25827814569536423841060')]])
-
- # Cannot use the `assert_allclose` because it uses isfinite under the covers
- # which does not support the Decimal type
- # See issue: https://github.com/numpy/numpy/issues/9954
- assert_equal(res[0][0], tgt[0][0])
- assert_equal(res[0][1], tgt[0][1])
- assert_equal(res[1][0], tgt[1][0])
- assert_equal(res[1][1], tgt[1][1])
-
- @filter_deprecation
- def test_ppmt(self):
- assert_equal(np.round(np.ppmt(0.1 / 12, 1, 60, 55000), 2), -710.25)
-
- @filter_deprecation
- def test_ppmt_decimal(self):
- assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000')),
- Decimal('-710.2541257864217612489830917'))
-
- # Two tests showing how Decimal is actually getting at a more exact result
- # .23 / 12 does not come out nicely as a float but does as a decimal
- @filter_deprecation
- def test_ppmt_special_rate(self):
- assert_equal(np.round(np.ppmt(0.23 / 12, 1, 60, 10000000000), 8), -90238044.232277036)
-
- @filter_deprecation
- def test_ppmt_special_rate_decimal(self):
- # When rounded out to 8 decimal places like the float based test, this should not equal the same value
- # as the float, substituted for the decimal
- def raise_error_because_not_equal():
- assert_equal(
- round(np.ppmt(Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')), 8),
- Decimal('-90238044.232277036'))
-
- assert_raises(AssertionError, raise_error_because_not_equal)
- assert_equal(np.ppmt(Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')),
- Decimal('-90238044.2322778884413969909'))
-
- @filter_deprecation
- def test_ipmt(self):
- assert_almost_equal(np.round(np.ipmt(0.1 / 12, 1, 24, 2000), 2), -16.67)
-
- @filter_deprecation
- def test_ipmt_decimal(self):
- result = np.ipmt(Decimal('0.1') / Decimal('12'), 1, 24, 2000)
- assert_equal(result.flat[0], Decimal('-16.66666666666666666666666667'))
-
- @filter_deprecation
- def test_nper(self):
- assert_almost_equal(np.nper(0.075, -2000, 0, 100000.),
- 21.54, 2)
-
- @filter_deprecation
- def test_nper2(self):
- assert_almost_equal(np.nper(0.0, -2000, 0, 100000.),
- 50.0, 1)
-
- @filter_deprecation
- def test_npv(self):
- assert_almost_equal(
- np.npv(0.05, [-15000, 1500, 2500, 3500, 4500, 6000]),
- 122.89, 2)
-
- @filter_deprecation
- def test_npv_decimal(self):
- assert_equal(
- np.npv(Decimal('0.05'), [-15000, 1500, 2500, 3500, 4500, 6000]),
- Decimal('122.894854950942692161628715'))
-
- @filter_deprecation
- def test_mirr(self):
- val = [-4500, -800, 800, 800, 600, 600, 800, 800, 700, 3000]
- assert_almost_equal(np.mirr(val, 0.08, 0.055), 0.0666, 4)
-
- val = [-120000, 39000, 30000, 21000, 37000, 46000]
- assert_almost_equal(np.mirr(val, 0.10, 0.12), 0.126094, 6)
-
- val = [100, 200, -50, 300, -200]
- assert_almost_equal(np.mirr(val, 0.05, 0.06), 0.3428, 4)
-
- val = [39000, 30000, 21000, 37000, 46000]
- assert_(np.isnan(np.mirr(val, 0.10, 0.12)))
-
- @filter_deprecation
- def test_mirr_decimal(self):
- val = [Decimal('-4500'), Decimal('-800'), Decimal('800'), Decimal('800'),
- Decimal('600'), Decimal('600'), Decimal('800'), Decimal('800'),
- Decimal('700'), Decimal('3000')]
- assert_equal(np.mirr(val, Decimal('0.08'), Decimal('0.055')),
- Decimal('0.066597175031553548874239618'))
-
- val = [Decimal('-120000'), Decimal('39000'), Decimal('30000'),
- Decimal('21000'), Decimal('37000'), Decimal('46000')]
- assert_equal(np.mirr(val, Decimal('0.10'), Decimal('0.12')), Decimal('0.126094130365905145828421880'))
-
- val = [Decimal('100'), Decimal('200'), Decimal('-50'),
- Decimal('300'), Decimal('-200')]
- assert_equal(np.mirr(val, Decimal('0.05'), Decimal('0.06')), Decimal('0.342823387842176663647819868'))
-
- val = [Decimal('39000'), Decimal('30000'), Decimal('21000'), Decimal('37000'), Decimal('46000')]
- assert_(np.isnan(np.mirr(val, Decimal('0.10'), Decimal('0.12'))))
-
- @filter_deprecation
- def test_when(self):
- # begin
- assert_equal(np.rate(10, 20, -3500, 10000, 1),
- np.rate(10, 20, -3500, 10000, 'begin'))
- # end
- assert_equal(np.rate(10, 20, -3500, 10000),
- np.rate(10, 20, -3500, 10000, 'end'))
- assert_equal(np.rate(10, 20, -3500, 10000, 0),
- np.rate(10, 20, -3500, 10000, 'end'))
-
- # begin
- assert_equal(np.pv(0.07, 20, 12000, 0, 1),
- np.pv(0.07, 20, 12000, 0, 'begin'))
- # end
- assert_equal(np.pv(0.07, 20, 12000, 0),
- np.pv(0.07, 20, 12000, 0, 'end'))
- assert_equal(np.pv(0.07, 20, 12000, 0, 0),
- np.pv(0.07, 20, 12000, 0, 'end'))
-
- # begin
- assert_equal(np.fv(0.075, 20, -2000, 0, 1),
- np.fv(0.075, 20, -2000, 0, 'begin'))
- # end
- assert_equal(np.fv(0.075, 20, -2000, 0),
- np.fv(0.075, 20, -2000, 0, 'end'))
- assert_equal(np.fv(0.075, 20, -2000, 0, 0),
- np.fv(0.075, 20, -2000, 0, 'end'))
-
- # begin
- assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0, 1),
- np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'begin'))
- # end
- assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0),
- np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'end'))
- assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0, 0),
- np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'end'))
-
- # begin
- assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 1),
- np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'begin'))
- # end
- assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0),
- np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end'))
- assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 0),
- np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end'))
-
- # begin
- assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 1),
- np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'begin'))
- # end
- assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0),
- np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'end'))
- assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 0),
- np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'end'))
-
- # begin
- assert_equal(np.nper(0.075, -2000, 0, 100000., 1),
- np.nper(0.075, -2000, 0, 100000., 'begin'))
- # end
- assert_equal(np.nper(0.075, -2000, 0, 100000.),
- np.nper(0.075, -2000, 0, 100000., 'end'))
- assert_equal(np.nper(0.075, -2000, 0, 100000., 0),
- np.nper(0.075, -2000, 0, 100000., 'end'))
-
- @filter_deprecation
- def test_decimal_with_when(self):
- """Test that decimals are still supported if the when argument is passed"""
- # begin
- assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), Decimal('1')),
- np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'begin'))
- # end
- assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000')),
- np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'end'))
- assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), Decimal('0')),
- np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'end'))
-
- # begin
- assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), Decimal('1')),
- np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'begin'))
- # end
- assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0')),
- np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'end'))
- assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), Decimal('0')),
- np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'end'))
-
- # begin
- assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), Decimal('1')),
- np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'begin'))
- # end
- assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0')),
- np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'end'))
- assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), Decimal('0')),
- np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'end'))
-
- # begin
- assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
- Decimal('0'), Decimal('1')),
- np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
- Decimal('0'), 'begin'))
- # end
- assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
- Decimal('0')),
- np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
- Decimal('0'), 'end'))
- assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
- Decimal('0'), Decimal('0')),
- np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'),
- Decimal('0'), 'end'))
-
- # begin
- assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
- Decimal('0'), Decimal('1')),
- np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
- Decimal('0'), 'begin'))
- # end
- assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
- Decimal('0')),
- np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
- Decimal('0'), 'end'))
- assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
- Decimal('0'), Decimal('0')),
- np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'),
- Decimal('0'), 'end'))
-
- # begin
- assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
- Decimal('0'), Decimal('1')).flat[0],
- np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
- Decimal('0'), 'begin').flat[0])
- # end
- assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
- Decimal('0')).flat[0],
- np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
- Decimal('0'), 'end').flat[0])
- assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
- Decimal('0'), Decimal('0')).flat[0],
- np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'),
- Decimal('0'), 'end').flat[0])
-
- @filter_deprecation
- def test_broadcast(self):
- assert_almost_equal(np.nper(0.075, -2000, 0, 100000., [0, 1]),
- [21.5449442, 20.76156441], 4)
-
- assert_almost_equal(np.ipmt(0.1 / 12, list(range(5)), 24, 2000),
- [-17.29165168, -16.66666667, -16.03647345,
- -15.40102862, -14.76028842], 4)
-
- assert_almost_equal(np.ppmt(0.1 / 12, list(range(5)), 24, 2000),
- [-74.998201, -75.62318601, -76.25337923,
- -76.88882405, -77.52956425], 4)
-
- assert_almost_equal(np.ppmt(0.1 / 12, list(range(5)), 24, 2000, 0,
- [0, 0, 1, 'end', 'begin']),
- [-74.998201, -75.62318601, -75.62318601,
- -76.88882405, -76.88882405], 4)
-
- @filter_deprecation
- def test_broadcast_decimal(self):
- # Use almost equal because precision is tested in the explicit tests, this test is to ensure
- # broadcast with Decimal is not broken.
- assert_almost_equal(np.ipmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000')),
- [Decimal('-17.29165168'), Decimal('-16.66666667'), Decimal('-16.03647345'),
- Decimal('-15.40102862'), Decimal('-14.76028842')], 4)
-
- assert_almost_equal(np.ppmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000')),
- [Decimal('-74.998201'), Decimal('-75.62318601'), Decimal('-76.25337923'),
- Decimal('-76.88882405'), Decimal('-77.52956425')], 4)
-
- assert_almost_equal(np.ppmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000'),
- Decimal('0'), [Decimal('0'), Decimal('0'), Decimal('1'), 'end', 'begin']),
- [Decimal('-74.998201'), Decimal('-75.62318601'), Decimal('-75.62318601'),
- Decimal('-76.88882405'), Decimal('-76.88882405')], 4)
--- /dev/null
+import sys
+import pytest
+import numpy as np
+
+
+@pytest.mark.skipif(sys.version_info[:2] < (3, 7),
+ reason="requires python 3.7 or higher")
+def test_financial_expired():
+ match = 'NEP 32'
+ with pytest.warns(DeprecationWarning, match=match):
+ func = np.fv
+ with pytest.raises(RuntimeError, match=match):
+ func(1, 2, 3)
import numpy as np
from numpy.testing import (
assert_, assert_array_equal, assert_raises, assert_raises_regex,
- assert_warns
+ assert_warns,
)
from numpy.lib import format
-tempdir = None
-
-# Module-level setup.
-
-
-def setup_module():
- global tempdir
- tempdir = tempfile.mkdtemp()
-
-
-def teardown_module():
- global tempdir
- if tempdir is not None and os.path.isdir(tempdir):
- shutil.rmtree(tempdir)
- tempdir = None
-
-
# Generate some basic arrays to test with.
scalars = [
np.uint8,
assert_array_equal(long_str_arr, long_str_arr2)
-@pytest.mark.slow
-def test_memmap_roundtrip():
- # Fixme: used to crash on windows
- if not (sys.platform == 'win32' or sys.platform == 'cygwin'):
- for arr in basic_arrays + record_arrays:
- if arr.dtype.hasobject:
- # Skip these since they can't be mmap'ed.
- continue
- # Write it out normally and through mmap.
- nfn = os.path.join(tempdir, 'normal.npy')
- mfn = os.path.join(tempdir, 'memmap.npy')
- fp = open(nfn, 'wb')
- try:
- format.write_array(fp, arr)
- finally:
- fp.close()
-
- fortran_order = (
- arr.flags.f_contiguous and not arr.flags.c_contiguous)
- ma = format.open_memmap(mfn, mode='w+', dtype=arr.dtype,
- shape=arr.shape, fortran_order=fortran_order)
- ma[...] = arr
- del ma
-
- # Check that both of these files' contents are the same.
- fp = open(nfn, 'rb')
+def test_memmap_roundtrip(tmpdir):
+ for i, arr in enumerate(basic_arrays + record_arrays):
+ if arr.dtype.hasobject:
+ # Skip these since they can't be mmap'ed.
+ continue
+ # Write it out normally and through mmap.
+ nfn = os.path.join(tmpdir, f'normal{i}.npy')
+ mfn = os.path.join(tmpdir, f'memmap{i}.npy')
+ with open(nfn, 'wb') as fp:
+ format.write_array(fp, arr)
+
+ fortran_order = (
+ arr.flags.f_contiguous and not arr.flags.c_contiguous)
+ ma = format.open_memmap(mfn, mode='w+', dtype=arr.dtype,
+ shape=arr.shape, fortran_order=fortran_order)
+ ma[...] = arr
+ ma.flush()
+
+ # Check that both of these files' contents are the same.
+ with open(nfn, 'rb') as fp:
normal_bytes = fp.read()
- fp.close()
- fp = open(mfn, 'rb')
+ with open(mfn, 'rb') as fp:
memmap_bytes = fp.read()
- fp.close()
- assert_equal_(normal_bytes, memmap_bytes)
+ assert_equal_(normal_bytes, memmap_bytes)
- # Check that reading the file using memmap works.
- ma = format.open_memmap(nfn, mode='r')
- del ma
+ # Check that reading the file using memmap works.
+ ma = format.open_memmap(nfn, mode='r')
+ ma.flush()
-def test_compressed_roundtrip():
+def test_compressed_roundtrip(tmpdir):
arr = np.random.rand(200, 200)
- npz_file = os.path.join(tempdir, 'compressed.npz')
+ npz_file = os.path.join(tmpdir, 'compressed.npz')
np.savez_compressed(npz_file, arr=arr)
- arr1 = np.load(npz_file)['arr']
+ with np.load(npz_file) as npz:
+ arr1 = npz['arr']
assert_array_equal(arr, arr1)
dt6 = np.dtype({'names': [], 'formats': [], 'itemsize': 8})
@pytest.mark.parametrize("dt", [dt1, dt2, dt3, dt4, dt5, dt6])
-def test_load_padded_dtype(dt):
+def test_load_padded_dtype(tmpdir, dt):
arr = np.zeros(3, dt)
for i in range(3):
arr[i] = i + 5
- npz_file = os.path.join(tempdir, 'aligned.npz')
+ npz_file = os.path.join(tmpdir, 'aligned.npz')
np.savez(npz_file, arr=arr)
- arr1 = np.load(npz_file)['arr']
+ with np.load(npz_file) as npz:
+ arr1 = npz['arr']
assert_array_equal(arr, arr1)
encoding='latin1')
-def test_pickle_disallow():
+def test_pickle_disallow(tmpdir):
data_dir = os.path.join(os.path.dirname(__file__), 'data')
path = os.path.join(data_dir, 'py2-objarr.npy')
allow_pickle=False, encoding='latin1')
path = os.path.join(data_dir, 'py2-objarr.npz')
- f = np.load(path, allow_pickle=False, encoding='latin1')
- assert_raises(ValueError, f.__getitem__, 'x')
+ with np.load(path, allow_pickle=False, encoding='latin1') as f:
+ assert_raises(ValueError, f.__getitem__, 'x')
- path = os.path.join(tempdir, 'pickle-disabled.npy')
+ path = os.path.join(tmpdir, 'pickle-disabled.npy')
assert_raises(ValueError, np.save, path, np.array([None], dtype=object),
allow_pickle=False)
assert_raises(ValueError, format.write_array, f, d, (1, 0))
-@pytest.mark.slow
-def test_version_2_0_memmap():
+def test_version_2_0_memmap(tmpdir):
# requires more than 2 byte for header
dt = [(("%d" % i) * 100, float) for i in range(500)]
d = np.ones(1000, dtype=dt)
- tf = tempfile.mktemp('', 'mmap', dir=tempdir)
+ tf1 = os.path.join(tmpdir, f'version2_01.npy')
+ tf2 = os.path.join(tmpdir, f'version2_02.npy')
# 1.0 requested but data cannot be saved this way
- assert_raises(ValueError, format.open_memmap, tf, mode='w+', dtype=d.dtype,
+ assert_raises(ValueError, format.open_memmap, tf1, mode='w+', dtype=d.dtype,
shape=d.shape, version=(1, 0))
- ma = format.open_memmap(tf, mode='w+', dtype=d.dtype,
+ ma = format.open_memmap(tf1, mode='w+', dtype=d.dtype,
shape=d.shape, version=(2, 0))
ma[...] = d
- del ma
+ ma.flush()
+ ma = format.open_memmap(tf1, mode='r')
+ assert_array_equal(ma, d)
with warnings.catch_warnings(record=True) as w:
warnings.filterwarnings('always', '', UserWarning)
- ma = format.open_memmap(tf, mode='w+', dtype=d.dtype,
+ ma = format.open_memmap(tf2, mode='w+', dtype=d.dtype,
shape=d.shape, version=None)
assert_(w[0].category is UserWarning)
ma[...] = d
- del ma
+ ma.flush()
- ma = format.open_memmap(tf, mode='r')
+ ma = format.open_memmap(tf2, mode='r')
assert_array_equal(ma, d)
assert_raises(ValueError, format.read_array_header_1_0, s)
-def test_large_file_support():
+def test_large_file_support(tmpdir):
if (sys.platform == 'win32' or sys.platform == 'cygwin'):
pytest.skip("Unknown if Windows has sparse filesystems")
# try creating a large sparse file
- tf_name = os.path.join(tempdir, 'sparse_file')
+ tf_name = os.path.join(tmpdir, 'sparse_file')
try:
# seek past end would work too, but linux truncate somewhat
# increases the chances that we have a sparse filesystem and can
@pytest.mark.skipif(np.dtype(np.intp).itemsize < 8,
reason="test requires 64-bit system")
@pytest.mark.slow
-def test_large_archive():
+def test_large_archive(tmpdir):
# Regression test for product of saving arrays with dimensions of array
# having a product that doesn't fit in int32. See gh-7598 for details.
try:
except MemoryError:
pytest.skip("Could not create large file")
- fname = os.path.join(tempdir, "large_archive")
+ fname = os.path.join(tmpdir, "large_archive")
with open(fname, "wb") as f:
np.savez(f, arr=a)
assert_(a.shape == new_a.shape)
-def test_empty_npz():
+def test_empty_npz(tmpdir):
# Test for gh-9989
- fname = os.path.join(tempdir, "nothing.npz")
+ fname = os.path.join(tmpdir, "nothing.npz")
np.savez(fname)
- np.load(fname)
+ with np.load(fname) as nps:
+ pass
-def test_unicode_field_names():
+def test_unicode_field_names(tmpdir):
# gh-7391
arr = np.array([
(1, 3),
('int', int),
(u'\N{CJK UNIFIED IDEOGRAPH-6574}\N{CJK UNIFIED IDEOGRAPH-5F62}', int)
])
- fname = os.path.join(tempdir, "unicode.npy")
+ fname = os.path.join(tmpdir, "unicode.npy")
with open(fname, 'wb') as f:
format.write_array(f, arr, version=(3, 0))
with open(fname, 'rb') as f:
from fractions import Fraction
import math
import pytest
+import hypothesis
+from hypothesis.extra.numpy import arrays
+import hypothesis.strategies as st
+
import numpy as np
from numpy import ma
class TestTrimZeros:
- """
- Only testing for integer splits.
+ a = np.array([0, 0, 1, 0, 2, 3, 4, 0])
+ b = a.astype(float)
+ c = a.astype(complex)
+ d = a.astype(object)
- """
+ def values(self):
+ attr_names = ('a', 'b', 'c', 'd')
+ return (getattr(self, name) for name in attr_names)
def test_basic(self):
- a = np.array([0, 0, 1, 2, 3, 4, 0])
- res = trim_zeros(a)
- assert_array_equal(res, np.array([1, 2, 3, 4]))
+ slc = np.s_[2:-1]
+ for arr in self.values():
+ res = trim_zeros(arr)
+ assert_array_equal(res, arr[slc])
def test_leading_skip(self):
- a = np.array([0, 0, 1, 0, 2, 3, 4, 0])
- res = trim_zeros(a)
- assert_array_equal(res, np.array([1, 0, 2, 3, 4]))
+ slc = np.s_[:-1]
+ for arr in self.values():
+ res = trim_zeros(arr, trim='b')
+ assert_array_equal(res, arr[slc])
def test_trailing_skip(self):
- a = np.array([0, 0, 1, 0, 2, 3, 0, 4, 0])
- res = trim_zeros(a)
- assert_array_equal(res, np.array([1, 0, 2, 3, 0, 4]))
+ slc = np.s_[2:]
+ for arr in self.values():
+ res = trim_zeros(arr, trim='F')
+ assert_array_equal(res, arr[slc])
+
+ def test_all_zero(self):
+ for _arr in self.values():
+ arr = np.zeros_like(_arr, dtype=_arr.dtype)
+
+ res1 = trim_zeros(arr, trim='B')
+ assert len(res1) == 0
+
+ res2 = trim_zeros(arr, trim='f')
+ assert len(res2) == 0
+
+ def test_size_zero(self):
+ arr = np.zeros(0)
+ res = trim_zeros(arr)
+ assert_array_equal(arr, res)
+
+ @pytest.mark.parametrize(
+ 'arr',
+ [np.array([0, 2**62, 0]),
+ np.array([0, 2**63, 0]),
+ np.array([0, 2**64, 0])]
+ )
+ def test_overflow(self, arr):
+ slc = np.s_[1:2]
+ res = trim_zeros(arr)
+ assert_array_equal(res, arr[slc])
+
+ def test_no_trim(self):
+ arr = np.array([None, 1, None])
+ res = trim_zeros(arr)
+ assert_array_equal(arr, res)
+
+ def test_list_to_list(self):
+ res = trim_zeros(self.a.tolist())
+ assert isinstance(res, list)
class TestExtins:
def test_hanning(self):
# check symmetry
w = hanning(10)
- assert_array_almost_equal(w, flipud(w), 7)
+ assert_equal(w, flipud(w))
# check known value
assert_almost_equal(np.sum(w, axis=0), 4.500, 4)
def test_hamming(self):
# check symmetry
w = hamming(10)
- assert_array_almost_equal(w, flipud(w), 7)
+ assert_equal(w, flipud(w))
# check known value
assert_almost_equal(np.sum(w, axis=0), 4.9400, 4)
def test_bartlett(self):
# check symmetry
w = bartlett(10)
- assert_array_almost_equal(w, flipud(w), 7)
+ assert_equal(w, flipud(w))
# check known value
assert_almost_equal(np.sum(w, axis=0), 4.4444, 4)
def test_blackman(self):
# check symmetry
w = blackman(10)
- assert_array_almost_equal(w, flipud(w), 7)
+ assert_equal(w, flipud(w))
# check known value
assert_almost_equal(np.sum(w, axis=0), 3.7800, 4)
assert_array_almost_equal(c, np.array([[1., -1.], [-1., 1.]]))
assert_(np.all(np.abs(c) <= 1.0))
+ @pytest.mark.parametrize("test_type", [np.half, np.single, np.double, np.longdouble])
+ def test_corrcoef_dtype(self, test_type):
+ cast_A = self.A.astype(test_type)
+ res = corrcoef(cast_A, dtype=test_type)
+ assert test_type == res.dtype
+
class TestCov:
x1 = np.array([[0, 2], [1, 1], [2, 0]]).T
aweights=self.unit_weights),
self.res1)
+ @pytest.mark.parametrize("test_type", [np.half, np.single, np.double, np.longdouble])
+ def test_cov_dtype(self, test_type):
+ cast_x1 = self.x1.astype(test_type)
+ res = cov(cast_x1, dtype=test_type)
+ assert test_type == res.dtype
+
class Test_I0:
i0(0.5),
np.array(1.0634833707413234))
- A = np.array([0.49842636, 0.6969809, 0.22011976, 0.0155549])
- expected = np.array([1.06307822, 1.12518299, 1.01214991, 1.00006049])
+ # need at least one test above 8, as the implementation is piecewise
+ A = np.array([0.49842636, 0.6969809, 0.22011976, 0.0155549, 10.0])
+ expected = np.array([1.06307822, 1.12518299, 1.01214991, 1.00006049, 2815.71662847])
assert_almost_equal(i0(A), expected)
assert_almost_equal(i0(-A), expected)
assert_array_equal(exp, res)
+ def test_complex(self):
+ a = np.array([0, 1 + 2j])
+ with pytest.raises(TypeError, match="i0 not supported for complex values"):
+ res = i0(a)
class TestKaiser:
np.quantile(np.arange(100.), p, interpolation="midpoint")
assert_array_equal(p, p0)
+ def test_quantile_monotonic(self):
+ # GH 14685
+ # test that the return value of quantile is monotonic if p0 is ordered
+ p0 = np.arange(0, 1, 0.01)
+ quantile = np.quantile(np.array([0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 1, 1, 9, 9, 9,
+ 8, 8, 7]) * 0.1, p0)
+ assert_equal(np.sort(quantile), quantile)
+
+ @hypothesis.given(
+ arr=arrays(dtype=np.float64,
+ shape=st.integers(min_value=3, max_value=1000),
+ elements=st.floats(allow_infinity=False, allow_nan=False,
+ min_value=-1e300, max_value=1e300)))
+ def test_quantile_monotonic_hypo(self, arr):
+ p0 = np.arange(0, 1, 0.01)
+ quantile = np.quantile(arr, p0)
+ assert_equal(np.sort(quantile), quantile)
+
+
+class TestLerp:
+ @hypothesis.given(t0=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=0, max_value=1),
+ t1=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=0, max_value=1),
+ a = st.floats(allow_nan=False, allow_infinity=False,
+ min_value=-1e300, max_value=1e300),
+ b = st.floats(allow_nan=False, allow_infinity=False,
+ min_value=-1e300, max_value=1e300))
+ def test_lerp_monotonic(self, t0, t1, a, b):
+ l0 = np.lib.function_base._lerp(a, b, t0)
+ l1 = np.lib.function_base._lerp(a, b, t1)
+ if t0 == t1 or a == b:
+ assert l0 == l1 # uninteresting
+ elif (t0 < t1) == (a < b):
+ assert l0 <= l1
+ else:
+ assert l0 >= l1
+
+ @hypothesis.given(t=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=0, max_value=1),
+ a=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=-1e300, max_value=1e300),
+ b=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=-1e300, max_value=1e300))
+ def test_lerp_bounded(self, t, a, b):
+ if a <= b:
+ assert a <= np.lib.function_base._lerp(a, b, t) <= b
+ else:
+ assert b <= np.lib.function_base._lerp(a, b, t) <= a
+
+ @hypothesis.given(t=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=0, max_value=1),
+ a=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=-1e300, max_value=1e300),
+ b=st.floats(allow_nan=False, allow_infinity=False,
+ min_value=-1e300, max_value=1e300))
+ def test_lerp_symmetric(self, t, a, b):
+ # double subtraction is needed to remove the extra precision of t < 0.5
+ left = np.lib.function_base._lerp(a, b, 1 - (1 - t))
+ right = np.lib.function_base._lerp(b, a, 1 - t)
+ assert left == right
+
+ def test_lerp_0d_inputs(self):
+ a = np.array(2)
+ b = np.array(5)
+ t = np.array(0.2)
+ assert np.lib.function_base._lerp(a, b, t) == 2.6
+
class TestMedian:
@pytest.mark.skipif(sys.flags.optimize == 2, reason="Python running -OO")
@pytest.mark.xfail(IS_PYPY, reason="PyPy does not modify tp_doc")
def test_add_doc(self):
- # test np.add_newdoc
+ # test that np.add_newdoc did attach a docstring successfully:
tgt = "Current flat index into the array."
assert_equal(np.core.flatiter.index.__doc__[:len(tgt)], tgt)
assert_(len(np.core.ufunc.identity.__doc__) > 300)
assert_(len(np.lib.index_tricks.mgrid.__doc__) > 300)
+ @pytest.mark.skipif(sys.flags.optimize == 2, reason="Python running -OO")
+ def test_errors_are_ignored(self):
+ prev_doc = np.core.flatiter.index.__doc__
+ # nothing changed, but error ignored, this should probably
+ # give a warning (or even error) in the future.
+ np.add_newdoc("numpy.core", "flatiter", ("index", "bad docstring"))
+ assert prev_doc == np.core.flatiter.index.__doc__
+
+
+class TestAddDocstring():
+ # Test should possibly be moved, but it also fits to be close to
+ # the newdoc tests...
+ @pytest.mark.skipif(sys.flags.optimize == 2, reason="Python running -OO")
+ @pytest.mark.skipif(IS_PYPY, reason="PyPy does not modify tp_doc")
+ def test_add_same_docstring(self):
+ # test for attributes (which are C-level defined)
+ np.add_docstring(np.ndarray.flat, np.ndarray.flat.__doc__)
+ # And typical functions:
+ def func():
+ """docstring"""
+ return
+
+ np.add_docstring(func, func.__doc__)
+
+ @pytest.mark.skipif(sys.flags.optimize == 2, reason="Python running -OO")
+ def test_different_docstring_fails(self):
+ # test for attributes (which are C-level defined)
+ with assert_raises(RuntimeError):
+ np.add_docstring(np.ndarray.flat, "different docstring")
+ # And typical functions:
+ def func():
+ """docstring"""
+ return
+
+ with assert_raises(RuntimeError):
+ np.add_docstring(func, "different docstring")
+
+
class TestSortComplex:
@pytest.mark.parametrize("type_in, type_out", [
assert_equal(grid.size, expected[0])
assert_equal(grid_small.size, expected[1])
+ def test_accepts_npfloating(self):
+ # regression test for #16466
+ grid64 = mgrid[0.1:0.33:0.1, ]
+ grid32 = mgrid[np.float32(0.1):np.float32(0.33):np.float32(0.1), ]
+ assert_(grid32.dtype == np.float64)
+ assert_array_almost_equal(grid64, grid32)
+
+ # different code path for single slice
+ grid64 = mgrid[0.1:0.33:0.1]
+ grid32 = mgrid[np.float32(0.1):np.float32(0.33):np.float32(0.1)]
+ assert_(grid32.dtype == np.float64)
+ assert_array_almost_equal(grid64, grid32)
+
+ def test_accepts_npcomplexfloating(self):
+ # Related to #16466
+ assert_array_almost_equal(
+ mgrid[0.1:0.3:3j, ], mgrid[0.1:0.3:np.complex64(3j), ]
+ )
+
+ # different code path for single slice
+ assert_array_almost_equal(
+ mgrid[0.1:0.3:3j], mgrid[0.1:0.3:np.complex64(3j)]
+ )
class TestConcatenator:
def test_1d(self):
g = r_[0:36:100j]
assert_(g.shape == (100,))
+ # Related to #16466
+ g = r_[0:36:np.complex64(100j)]
+ assert_(g.shape == (100,))
+
def test_2d(self):
b = np.random.rand(5, 5)
c = np.random.rand(5, 5)
import numpy as np
import numpy.ma as ma
from numpy.lib._iotools import ConverterError, ConversionWarning
-from numpy.compat import asbytes, bytes
+from numpy.compat import asbytes
from numpy.ma.testutils import assert_equal
from numpy.testing import (
assert_warns, assert_, assert_raises_regex, assert_raises,
assert_allclose, assert_array_equal, temppath, tempdir, IS_PYPY,
- HAS_REFCOUNT, suppress_warnings, assert_no_gc_cycles, assert_no_warnings
+ HAS_REFCOUNT, suppress_warnings, assert_no_gc_cycles, assert_no_warnings,
+ break_cycles
)
from numpy.testing._private.utils import requires_memory
a = np.array([b'start ', b' ', b''])
assert_array_equal(x['comment'], a)
- def test_structure_unpack(self):
+ def test_unpack_structured(self):
txt = TextIO("M 21 72\nF 35 58")
dt = {'names': ('a', 'b', 'c'), 'formats': ('|S1', '<i4', '<f4')}
a, b, c = np.loadtxt(txt, dtype=dt, unpack=True)
data[10 * i] = "2, 2, 2, 2 2"
data.insert(0, "a, b, c, d, e")
mdata = TextIO("\n".join(data))
- #
+
kwargs = dict(delimiter=",", dtype=None, names=True)
- # XXX: is there a better way to get the return value of the
- # callable in assert_warns ?
- ret = {}
-
- def f(_ret={}):
- _ret['mtest'] = np.genfromtxt(mdata, invalid_raise=False, **kwargs)
- assert_warns(ConversionWarning, f, _ret=ret)
- mtest = ret['mtest']
+ def f():
+ return np.genfromtxt(mdata, invalid_raise=False, **kwargs)
+ mtest = assert_warns(ConversionWarning, f)
assert_equal(len(mtest), 45)
assert_equal(mtest, np.ones(45, dtype=[(_, int) for _ in 'abcde']))
#
data[10 * i] = "2, 2, 2, 2 2"
data.insert(0, "a, b, c, d, e")
mdata = TextIO("\n".join(data))
+
kwargs = dict(delimiter=",", dtype=None, names=True,
invalid_raise=False)
- # XXX: is there a better way to get the return value of the
- # callable in assert_warns ?
- ret = {}
-
- def f(_ret={}):
- _ret['mtest'] = np.genfromtxt(mdata, usecols=(0, 4), **kwargs)
- assert_warns(ConversionWarning, f, _ret=ret)
- mtest = ret['mtest']
+ def f():
+ return np.genfromtxt(mdata, usecols=(0, 4), **kwargs)
+ mtest = assert_warns(ConversionWarning, f)
assert_equal(len(mtest), 45)
assert_equal(mtest, np.ones(45, dtype=[(_, int) for _ in 'ae']))
#
assert_equal(test['f1'], 17179869184)
assert_equal(test['f2'], 1024)
+ def test_unpack_structured(self):
+ # Regression test for gh-4341
+ # Unpacking should work on structured arrays
+ txt = TextIO("M 21 72\nF 35 58")
+ dt = {'names': ('a', 'b', 'c'), 'formats': ('S1', 'i4', 'f4')}
+ a, b, c = np.genfromtxt(txt, dtype=dt, unpack=True)
+ assert_equal(a.dtype, np.dtype('S1'))
+ assert_equal(b.dtype, np.dtype('i4'))
+ assert_equal(c.dtype, np.dtype('f4'))
+ assert_array_equal(a, np.array([b'M', b'F']))
+ assert_array_equal(b, np.array([21, 35]))
+ assert_array_equal(c, np.array([72., 58.]))
+
+ def test_unpack_auto_dtype(self):
+ # Regression test for gh-4341
+ # Unpacking should work when dtype=None
+ txt = TextIO("M 21 72.\nF 35 58.")
+ expected = (np.array(["M", "F"]), np.array([21, 35]), np.array([72., 58.]))
+ test = np.genfromtxt(txt, dtype=None, unpack=True, encoding="utf-8")
+ for arr, result in zip(expected, test):
+ assert_array_equal(arr, result)
+ assert_equal(arr.dtype, result.dtype)
+
+ def test_unpack_single_name(self):
+ # Regression test for gh-4341
+ # Unpacking should work when structured dtype has only one field
+ txt = TextIO("21\n35")
+ dt = {'names': ('a',), 'formats': ('i4',)}
+ expected = np.array([21, 35], dtype=np.int32)
+ test = np.genfromtxt(txt, dtype=dt, unpack=True)
+ assert_array_equal(expected, test)
+ assert_equal(expected.dtype, test.dtype)
+
+ def test_squeeze_scalar(self):
+ # Regression test for gh-4341
+ # Unpacking a scalar should give zero-dim output,
+ # even if dtype is structured
+ txt = TextIO("1")
+ dt = {'names': ('a',), 'formats': ('i4',)}
+ expected = np.array((1,), dtype=np.int32)
+ test = np.genfromtxt(txt, dtype=dt, unpack=True)
+ assert_array_equal(expected, test)
+ assert_equal((), test.shape)
+ assert_equal(expected.dtype, test.dtype)
+
class TestPathUsage:
# Test that pathlib.Path can be used
assert_array_equal(data, a)
# close the mem-mapped file
del data
+ if IS_PYPY:
+ break_cycles()
+ break_cycles()
def test_save_load_memmap_readwrite(self):
# Test that pathlib.Path instances can be written mem-mapped.
a[0][0] = 5
b[0][0] = 5
del b # closes the file
+ if IS_PYPY:
+ break_cycles()
+ break_cycles()
data = np.load(path)
assert_array_equal(data, a)
""" Test that _replace_nan returns the original array if there are no
NaNs, not a copy.
"""
- for dtype in [np.bool, np.int32, np.int64]:
+ for dtype in [np.bool_, np.int32, np.int64]:
arr = np.array([0, 1], dtype=dtype)
result, mask = _replace_nan(arr, 0)
assert mask is None
v = np.arange(1, 21)
assert_almost_equal(np.poly(v), np.poly(np.diag(v)))
+ def test_zero_poly_dtype(self):
+ """
+ Regression test for gh-16354.
+ """
+ z = np.array([0, 0, 0])
+ p = np.poly1d(z.astype(np.int64))
+ assert_equal(p.coeffs.dtype, np.int64)
+
+ p = np.poly1d(z.astype(np.float32))
+ assert_equal(p.coeffs.dtype, np.float32)
+
+ p = np.poly1d(z.astype(np.complex64))
+ assert_equal(p.coeffs.dtype, np.complex64)
+
def test_poly_eq(self):
p = np.poly1d([1, 2, 3])
p2 = np.poly1d([1, 2, 4])
assert_equal(q.coeffs.dtype, np.complex128)
assert_equal(r.coeffs.dtype, np.complex128)
assert_equal(q*a + r, b)
+
+ c = [1, 2, 3]
+ d = np.poly1d([1, 2, 3])
+ s, t = np.polydiv(c, d)
+ assert isinstance(s, np.poly1d)
+ assert isinstance(t, np.poly1d)
+ u, v = np.polydiv(d, c)
+ assert isinstance(u, np.poly1d)
+ assert isinstance(v, np.poly1d)
def test_poly_coeffs_mutable(self):
""" Coefficients should be modifiable """
assert_raises_regex, assert_warns,
)
from numpy.lib.stride_tricks import (
- as_strided, broadcast_arrays, _broadcast_shape, broadcast_to
+ as_strided, broadcast_arrays, _broadcast_shape, broadcast_to,
+ broadcast_shapes, sliding_window_view,
)
+import pytest
+
def assert_shapes_correct(input_shapes, expected_shape):
# Broadcast a list of arrays with the given input shapes and check the
def test_broadcast_shape():
- # broadcast_shape is already exercized indirectly by broadcast_arrays
+ # tests internal _broadcast_shape
+ # _broadcast_shape is already exercised indirectly by broadcast_arrays
+ # _broadcast_shape is also exercised by the public broadcast_shapes function
assert_equal(_broadcast_shape(), ())
assert_equal(_broadcast_shape([1, 2]), (2,))
assert_equal(_broadcast_shape(np.ones((1, 1))), (1, 1))
assert_raises(ValueError, lambda: _broadcast_shape(*bad_args))
+def test_broadcast_shapes_succeeds():
+ # tests public broadcast_shapes
+ data = [
+ [[], ()],
+ [[()], ()],
+ [[(7,)], (7,)],
+ [[(1, 2), (2,)], (1, 2)],
+ [[(1, 1)], (1, 1)],
+ [[(1, 1), (3, 4)], (3, 4)],
+ [[(6, 7), (5, 6, 1), (7,), (5, 1, 7)], (5, 6, 7)],
+ [[(5, 6, 1)], (5, 6, 1)],
+ [[(1, 3), (3, 1)], (3, 3)],
+ [[(1, 0), (0, 0)], (0, 0)],
+ [[(0, 1), (0, 0)], (0, 0)],
+ [[(1, 0), (0, 1)], (0, 0)],
+ [[(1, 1), (0, 0)], (0, 0)],
+ [[(1, 1), (1, 0)], (1, 0)],
+ [[(1, 1), (0, 1)], (0, 1)],
+ [[(), (0,)], (0,)],
+ [[(0,), (0, 0)], (0, 0)],
+ [[(0,), (0, 1)], (0, 0)],
+ [[(1,), (0, 0)], (0, 0)],
+ [[(), (0, 0)], (0, 0)],
+ [[(1, 1), (0,)], (1, 0)],
+ [[(1,), (0, 1)], (0, 1)],
+ [[(1,), (1, 0)], (1, 0)],
+ [[(), (1, 0)], (1, 0)],
+ [[(), (0, 1)], (0, 1)],
+ [[(1,), (3,)], (3,)],
+ [[2, (3, 2)], (3, 2)],
+ ]
+ for input_shapes, target_shape in data:
+ assert_equal(broadcast_shapes(*input_shapes), target_shape)
+
+ assert_equal(broadcast_shapes(*([(1, 2)] * 32)), (1, 2))
+ assert_equal(broadcast_shapes(*([(1, 2)] * 100)), (1, 2))
+
+ # regression tests for gh-5862
+ assert_equal(broadcast_shapes(*([(2,)] * 32)), (2,))
+
+
+def test_broadcast_shapes_raises():
+ # tests public broadcast_shapes
+ data = [
+ [(3,), (4,)],
+ [(2, 3), (2,)],
+ [(3,), (3,), (4,)],
+ [(1, 3, 4), (2, 3, 3)],
+ [(1, 2), (3,1), (3,2), (10, 5)],
+ [2, (2, 3)],
+ ]
+ for input_shapes in data:
+ assert_raises(ValueError, lambda: broadcast_shapes(*input_shapes))
+
+ bad_args = [(2,)] * 32 + [(3,)] * 32
+ assert_raises(ValueError, lambda: broadcast_shapes(*bad_args))
+
+
def test_as_strided():
a = np.array([None])
a_view = as_strided(a)
assert_equal(a.dtype, a_view.dtype)
assert_array_equal([r] * 3, a_view)
+
+class TestSlidingWindowView:
+ def test_1d(self):
+ arr = np.arange(5)
+ arr_view = sliding_window_view(arr, 2)
+ expected = np.array([[0, 1],
+ [1, 2],
+ [2, 3],
+ [3, 4]])
+ assert_array_equal(arr_view, expected)
+
+ def test_2d(self):
+ i, j = np.ogrid[:3, :4]
+ arr = 10*i + j
+ shape = (2, 2)
+ arr_view = sliding_window_view(arr, shape)
+ expected = np.array([[[[0, 1], [10, 11]],
+ [[1, 2], [11, 12]],
+ [[2, 3], [12, 13]]],
+ [[[10, 11], [20, 21]],
+ [[11, 12], [21, 22]],
+ [[12, 13], [22, 23]]]])
+ assert_array_equal(arr_view, expected)
+
+ def test_2d_with_axis(self):
+ i, j = np.ogrid[:3, :4]
+ arr = 10*i + j
+ arr_view = sliding_window_view(arr, 3, 0)
+ expected = np.array([[[0, 10, 20],
+ [1, 11, 21],
+ [2, 12, 22],
+ [3, 13, 23]]])
+ assert_array_equal(arr_view, expected)
+
+ def test_2d_repeated_axis(self):
+ i, j = np.ogrid[:3, :4]
+ arr = 10*i + j
+ arr_view = sliding_window_view(arr, (2, 3), (1, 1))
+ expected = np.array([[[[0, 1, 2],
+ [1, 2, 3]]],
+ [[[10, 11, 12],
+ [11, 12, 13]]],
+ [[[20, 21, 22],
+ [21, 22, 23]]]])
+ assert_array_equal(arr_view, expected)
+
+ def test_2d_without_axis(self):
+ i, j = np.ogrid[:4, :4]
+ arr = 10*i + j
+ shape = (2, 3)
+ arr_view = sliding_window_view(arr, shape)
+ expected = np.array([[[[0, 1, 2], [10, 11, 12]],
+ [[1, 2, 3], [11, 12, 13]]],
+ [[[10, 11, 12], [20, 21, 22]],
+ [[11, 12, 13], [21, 22, 23]]],
+ [[[20, 21, 22], [30, 31, 32]],
+ [[21, 22, 23], [31, 32, 33]]]])
+ assert_array_equal(arr_view, expected)
+
+ def test_errors(self):
+ i, j = np.ogrid[:4, :4]
+ arr = 10*i + j
+ with pytest.raises(ValueError, match='cannot contain negative values'):
+ sliding_window_view(arr, (-1, 3))
+ with pytest.raises(
+ ValueError,
+ match='must provide window_shape for all dimensions of `x`'):
+ sliding_window_view(arr, (1,))
+ with pytest.raises(
+ ValueError,
+ match='Must provide matching length window_shape and axis'):
+ sliding_window_view(arr, (1, 3, 4), axis=(0, 1))
+ with pytest.raises(
+ ValueError,
+ match='window shape cannot be larger than input array'):
+ sliding_window_view(arr, (5, 5))
+
+ def test_writeable(self):
+ arr = np.arange(5)
+ view = sliding_window_view(arr, 2, writeable=False)
+ assert_(not view.flags.writeable)
+ with pytest.raises(
+ ValueError,
+ match='assignment destination is read-only'):
+ view[0, 0] = 3
+ view = sliding_window_view(arr, 2, writeable=True)
+ assert_(view.flags.writeable)
+ view[0, 1] = 3
+ assert_array_equal(arr, np.array([0, 3, 2, 3, 4]))
+
+ def test_subok(self):
+ class MyArray(np.ndarray):
+ pass
+
+ arr = np.arange(5).view(MyArray)
+ assert_(not isinstance(sliding_window_view(arr, 2,
+ subok=False),
+ MyArray))
+ assert_(isinstance(sliding_window_view(arr, 2, subok=True), MyArray))
+ # Default behavior
+ assert_(not isinstance(sliding_window_view(arr, 2), MyArray))
+
+
def as_strided_writeable():
arr = np.ones(10)
view = as_strided(arr, writeable=False)
# check: no warning emitted
assert_equal(result.flags.writeable, True)
result[:] = 0
-
+
# keep readonly input readonly
original.flags.writeable = False
_, result = broadcast_arrays(0, original)
def test_assert_raises_regex_context_manager():
with assert_raises_regex(ValueError, 'no deprecation warning'):
raise ValueError('no deprecation warning')
+
+
+def test_info_method_heading():
+ # info(class) should only print "Methods:" heading if methods exist
+
+ class NoPublicMethods:
+ pass
+
+ class WithPublicMethods:
+ def first_method():
+ pass
+
+ def _has_method_heading(cls):
+ out = StringIO()
+ utils.info(cls, output=out)
+ return 'Methods:' in out.getvalue()
+
+ assert _has_method_heading(WithPublicMethods)
+ assert not _has_method_heading(NoPublicMethods)
asarray, where, int8, int16, int32, int64, empty, promote_types, diagonal,
nonzero
)
-from numpy.core.overrides import set_module
+from numpy.core.overrides import set_array_function_like_doc, set_module
from numpy.core import overrides
from numpy.core import iinfo
return m[::-1, ...]
+def _eye_dispatcher(N, M=None, k=None, dtype=None, order=None, *, like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def eye(N, M=None, k=0, dtype=float, order='C'):
+def eye(N, M=None, k=0, dtype=float, order='C', *, like=None):
"""
Return a 2-D array with ones on the diagonal and zeros elsewhere.
column-major (Fortran-style) order in memory.
.. versionadded:: 1.14.0
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
[0., 0., 0.]])
"""
+ if like is not None:
+ return _eye_with_like(N, M=M, k=k, dtype=dtype, order=order, like=like)
if M is None:
M = N
m = zeros((N, M), dtype=dtype, order=order)
return m
+_eye_with_like = array_function_dispatch(
+ _eye_dispatcher
+)(eye)
+
+
def _diag_dispatcher(v, k=None):
return (v,)
return wrap(res)
+def _tri_dispatcher(N, M=None, k=None, dtype=None, *, like=None):
+ return (like,)
+
+
+@set_array_function_like_doc
@set_module('numpy')
-def tri(N, M=None, k=0, dtype=float):
+def tri(N, M=None, k=0, dtype=float, *, like=None):
"""
An array with ones at and below the given diagonal and zeros elsewhere.
and `k` > 0 is above. The default is 0.
dtype : dtype, optional
Data type of the returned array. The default is float.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
Returns
-------
[1., 1., 0., 0., 0.]])
"""
+ if like is not None:
+ return _tri_with_like(N, M=M, k=k, dtype=dtype, like=like)
+
if M is None:
M = N
return m
+_tri_with_like = array_function_dispatch(
+ _tri_dispatcher
+)(tri)
+
+
def _trilu_dispatcher(m, k=None):
return (m,)
"""
Upper triangle of an array.
- Return a copy of a matrix with the elements below the `k`-th diagonal
+ Return a copy of an array with the elements below the `k`-th diagonal
zeroed.
Please refer to the documentation for `tril` for further details.
from numpy.core import ndarray, ufunc, asarray
import numpy as np
-# getargspec and formatargspec were removed in Python 3.6
-from numpy.compat import getargspec, formatargspec
-
__all__ = [
'issubclass_', 'issubsctype', 'issubdtype', 'deprecate',
'deprecate_with_doc', 'get_include', 'info', 'source', 'who',
file=output
)
- elif inspect.isfunction(object):
+ elif inspect.isfunction(object) or inspect.ismethod(object):
name = object.__name__
- arguments = formatargspec(*getargspec(object))
+ try:
+ arguments = str(inspect.signature(object))
+ except Exception:
+ arguments = "()"
if len(name+arguments) > maxwidth:
argstr = _split_line(name, arguments, maxwidth)
elif inspect.isclass(object):
name = object.__name__
- arguments = "()"
try:
- if hasattr(object, '__init__'):
- arguments = formatargspec(
- *getargspec(object.__init__.__func__)
- )
- arglist = arguments.split(', ')
- if len(arglist) > 1:
- arglist[1] = "("+arglist[1]
- arguments = ", ".join(arglist[1:])
+ arguments = str(inspect.signature(object))
except Exception:
- pass
+ arguments = "()"
if len(name+arguments) > maxwidth:
argstr = _split_line(name, arguments, maxwidth)
print(inspect.getdoc(object), file=output)
methods = pydoc.allmethods(object)
- if methods != []:
+
+ public_methods = [meth for meth in methods if meth[0] != '_']
+ if public_methods:
print("\n\nMethods:\n", file=output)
- for meth in methods:
- if meth[0] == '_':
- continue
+ for meth in public_methods:
thisobj = getattr(object, meth, None)
if thisobj is not None:
methstr, other = pydoc.splitdoc(
)
print(" %s -- %s" % (meth, methstr), file=output)
- elif inspect.ismethod(object):
- name = object.__name__
- arguments = formatargspec(
- *getargspec(object.__func__)
- )
- arglist = arguments.split(', ')
- if len(arglist) > 1:
- arglist[1] = "("+arglist[1]
- arguments = ", ".join(arglist[1:])
- else:
- arguments = "()"
-
- if len(name+arguments) > maxwidth:
- argstr = _split_line(name, arguments, maxwidth)
- else:
- argstr = name + arguments
-
- print(" " + argstr + "\n", file=output)
- print(inspect.getdoc(object), file=output)
-
elif hasattr(object, '__doc__'):
print(inspect.getdoc(object), file=output)
--- /dev/null
+from typing import Any
+
+matrix_power: Any
+solve: Any
+tensorsolve: Any
+tensorinv: Any
+inv: Any
+cholesky: Any
+eigvals: Any
+eigvalsh: Any
+pinv: Any
+slogdet: Any
+det: Any
+svd: Any
+eig: Any
+eigh: Any
+lstsq: Any
+norm: Any
+qr: Any
+cond: Any
+matrix_rank: Any
+LinAlgError: Any
+multi_dot: Any
return self._dependencies
def __repr__(self):
- return "FortranRoutine({!r}, filename={!r})".format(self.name, self.filename)
+ return f'FortranRoutine({self.name!r}, filename={self.filename!r})'
class UnknownFortranRoutine(FortranRoutine):
"""Wrapper for a Fortran routine for which the corresponding file
def printRoutineNames(desc, routines):
print(desc)
for r in routines:
- print('\t%s' % r.name)
+ print(f'\t{r.name}')
def getLapackRoutines(wrapped_routines, ignores, lapack_dir):
blas_src_dir = os.path.join(lapack_dir, 'BLAS', 'SRC')
with open(filename, 'w') as fo:
for r in routines:
deps = r.dependencies()
- fo.write('%s: %s\n' % (r.name, ' '.join(deps)))
+ fo.write(f"{r.name}: {' '.join(deps)}\n")
def concatenateRoutines(routines, output_file):
with open(output_file, 'w') as output_fo:
# Rename BLAS/LAPACK symbols
for name in sorted(symbols):
- f.write("#define %s_ BLAS_FUNC(%s)\n" % (name, name))
+ f.write(f'#define {name}_ BLAS_FUNC({name})\n')
# Rename also symbols that f2c exports itself
f.write("\n"
"/* Symbols exported by f2c.c */\n")
for name in sorted(f2c_symbols):
- f.write("#define %s numpy_lapack_lite_%s\n" % (name, name))
+ f.write(f'#define {name} numpy_lapack_lite_{name}\n')
def main():
if len(sys.argv) != 3:
dumpRoutineNames(library, output_dir)
for typename in types:
- fortran_file = os.path.join(output_dir, 'f2c_%s.f' % typename)
+ fortran_file = os.path.join(output_dir, f'f2c_{typename}.f')
c_file = fortran_file[:-2] + '.c'
- print('creating %s ...' % c_file)
+ print(f'creating {c_file} ...')
routines = library.allRoutinesByType(typename)
concatenateRoutines(routines, fortran_file)
patch_file = os.path.basename(fortran_file) + '.patch'
if os.path.exists(patch_file):
subprocess.check_call(['patch', '-u', fortran_file, patch_file])
- print("Patched {}".format(fortran_file))
+ print(f'Patched {fortran_file}')
try:
runF2C(fortran_file, output_dir)
except F2CError:
- print('f2c failed on %s' % fortran_file)
+ print(f'f2c failed on {fortran_file}')
break
scrubF2CSource(c_file)
def _fastCopyAndTranspose(type, *arrays):
cast_arrays = ()
for a in arrays:
- if a.dtype.type is type:
- cast_arrays = cast_arrays + (_fastCT(a),)
- else:
- cast_arrays = cast_arrays + (_fastCT(a.astype(type)),)
+ if a.dtype.type is not type:
+ a = a.astype(type)
+ cast_arrays = cast_arrays + (_fastCT(a),)
if len(cast_arrays) == 1:
return cast_arrays[0]
else:
Examples
--------
- Solve the system of equations ``3 * x0 + x1 = 9`` and ``x0 + 2 * x1 = 8``:
+ Solve the system of equations ``x0 + 2 * x1 = 1`` and ``3 * x0 + 5 * x1 = 2``:
- >>> a = np.array([[3,1], [1,2]])
- >>> b = np.array([9,8])
+ >>> a = np.array([[1, 2], [3, 5]])
+ >>> b = np.array([1, 2])
>>> x = np.linalg.solve(a, b)
>>> x
- array([2., 3.])
+ array([-1., 1.])
Check that the solution is correct:
warnings.warn(msg, DeprecationWarning, stacklevel=3)
mode = 'economic'
else:
- raise ValueError("Unrecognized mode '%s'" % mode)
+ raise ValueError(f"Unrecognized mode '{mode}'")
a, wrap = _makearray(a)
_assert_2d(a)
Least-squares solution. If `b` is two-dimensional,
the solutions are in the `K` columns of `x`.
residuals : {(1,), (K,), (0,)} ndarray
- Sums of residuals; squared Euclidean 2-norm for each column in
- ``b - a*x``.
+ Sums of squared residuals: Squared Euclidean 2-norm for each column in
+ ``b - a @ x``.
If the rank of `a` is < N or M <= N, this is an empty array.
If `b` is 1-dimensional, this is a (1,) shape array.
Otherwise the shape is (K,).
# special case for speedup
s = (x.conj() * x).real
return sqrt(add.reduce(s, axis=axis, keepdims=keepdims))
- # None of the str-type keywords for ord ('fro', 'nuc')
+ # None of the str-type keywords for ord ('fro', 'nuc')
# are valid for vectors
elif isinstance(ord, str):
raise ValueError(f"Invalid norm order '{ord}' for vectors")
See Also
--------
- dot : dot multiplication with two arguments.
+ numpy.dot : dot multiplication with two arguments.
References
----------
def configuration(parent_package='', top_path=None):
from numpy.distutils.misc_util import Configuration
- from numpy.distutils.system_info import get_info, system_info
+ from numpy.distutils.system_info import (
+ get_info, system_info, lapack_opt_info, blas_opt_info)
config = Configuration('linalg', parent_package, top_path)
config.add_subpackage('tests')
+ # Accelerate is buggy, disallow it. See also numpy/core/setup.py
+ for opt_order in (blas_opt_info.blas_order, lapack_opt_info.lapack_order):
+ if 'accelerate' in opt_order:
+ opt_order.remove('accelerate')
+
# Configure lapack_lite
src_dir = 'lapack_lite'
extra_info=lapack_info,
libraries=['npymath'],
)
+ config.add_data_files('*.pyi')
return config
if __name__ == '__main__':
p = Popen(self.cmd, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
except OSError:
- raise RuntimeError("command %s cannot be run" % self.cmd)
+ raise RuntimeError(f'command {self.cmd} cannot be run')
def get_dependencies(self, lfile):
p = Popen(self.cmd + [lfile], stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate()
if not (p.returncode == 0):
- raise RuntimeError("failed dependencies check for %s" % lfile)
+ raise RuntimeError(f'failed dependencies check for {lfile}')
return stdout
do(self.a, self.b, tags=self.tags)
def __repr__(self):
- return "<LinalgCase: %s>" % (self.name,)
+ return f'<LinalgCase: {self.name}>'
def apply_tag(tag, cases):
try:
case.check(self.do)
except Exception:
- msg = "In test case: %r\n\n" % case
+ msg = f'In test case: {case!r}\n\n'
msg += traceback.format_exc()
raise AssertionError(msg)
b = np.matmul(c, c.transpose(t).conj())
assert_allclose(b, a,
- err_msg="{} {}\n{}\n{}".format(shape, dtype, a, c),
+ err_msg=f'{shape} {dtype}\n{a}\n{c}',
atol=500 * a.shape[0] * np.finfo(dtype).eps)
def test_0_size(self):
return NULL;
}
- version = PyString_FromString(umath_linalg_version_string);
+ version = PyUnicode_FromString(umath_linalg_version_string);
if (version == NULL) {
return NULL;
}
--- /dev/null
+from typing import Any
+
+core: Any
+extras: Any
+MAError: Any
+MaskError: Any
+MaskType: Any
+MaskedArray: Any
+abs: Any
+absolute: Any
+add: Any
+all: Any
+allclose: Any
+allequal: Any
+alltrue: Any
+amax: Any
+amin: Any
+angle: Any
+anom: Any
+anomalies: Any
+any: Any
+append: Any
+arange: Any
+arccos: Any
+arccosh: Any
+arcsin: Any
+arcsinh: Any
+arctan: Any
+arctan2: Any
+arctanh: Any
+argmax: Any
+argmin: Any
+argsort: Any
+around: Any
+array: Any
+asanyarray: Any
+asarray: Any
+bitwise_and: Any
+bitwise_or: Any
+bitwise_xor: Any
+bool_: Any
+ceil: Any
+choose: Any
+clip: Any
+common_fill_value: Any
+compress: Any
+compressed: Any
+concatenate: Any
+conjugate: Any
+convolve: Any
+copy: Any
+correlate: Any
+cos: Any
+cosh: Any
+count: Any
+cumprod: Any
+cumsum: Any
+default_fill_value: Any
+diag: Any
+diagonal: Any
+diff: Any
+divide: Any
+empty: Any
+empty_like: Any
+equal: Any
+exp: Any
+expand_dims: Any
+fabs: Any
+filled: Any
+fix_invalid: Any
+flatten_mask: Any
+flatten_structured_array: Any
+floor: Any
+floor_divide: Any
+fmod: Any
+frombuffer: Any
+fromflex: Any
+fromfunction: Any
+getdata: Any
+getmask: Any
+getmaskarray: Any
+greater: Any
+greater_equal: Any
+harden_mask: Any
+hypot: Any
+identity: Any
+ids: Any
+indices: Any
+inner: Any
+innerproduct: Any
+isMA: Any
+isMaskedArray: Any
+is_mask: Any
+is_masked: Any
+isarray: Any
+left_shift: Any
+less: Any
+less_equal: Any
+log: Any
+log10: Any
+log2: Any
+logical_and: Any
+logical_not: Any
+logical_or: Any
+logical_xor: Any
+make_mask: Any
+make_mask_descr: Any
+make_mask_none: Any
+mask_or: Any
+masked: Any
+masked_array: Any
+masked_equal: Any
+masked_greater: Any
+masked_greater_equal: Any
+masked_inside: Any
+masked_invalid: Any
+masked_less: Any
+masked_less_equal: Any
+masked_not_equal: Any
+masked_object: Any
+masked_outside: Any
+masked_print_option: Any
+masked_singleton: Any
+masked_values: Any
+masked_where: Any
+max: Any
+maximum: Any
+maximum_fill_value: Any
+mean: Any
+min: Any
+minimum: Any
+minimum_fill_value: Any
+mod: Any
+multiply: Any
+mvoid: Any
+ndim: Any
+negative: Any
+nomask: Any
+nonzero: Any
+not_equal: Any
+ones: Any
+outer: Any
+outerproduct: Any
+power: Any
+prod: Any
+product: Any
+ptp: Any
+put: Any
+putmask: Any
+ravel: Any
+remainder: Any
+repeat: Any
+reshape: Any
+resize: Any
+right_shift: Any
+round: Any
+round_: Any
+set_fill_value: Any
+shape: Any
+sin: Any
+sinh: Any
+size: Any
+soften_mask: Any
+sometrue: Any
+sort: Any
+sqrt: Any
+squeeze: Any
+std: Any
+subtract: Any
+sum: Any
+swapaxes: Any
+take: Any
+tan: Any
+tanh: Any
+trace: Any
+transpose: Any
+true_divide: Any
+var: Any
+where: Any
+zeros: Any
+apply_along_axis: Any
+apply_over_axes: Any
+atleast_1d: Any
+atleast_2d: Any
+atleast_3d: Any
+average: Any
+clump_masked: Any
+clump_unmasked: Any
+column_stack: Any
+compress_cols: Any
+compress_nd: Any
+compress_rowcols: Any
+compress_rows: Any
+count_masked: Any
+corrcoef: Any
+cov: Any
+diagflat: Any
+dot: Any
+dstack: Any
+ediff1d: Any
+flatnotmasked_contiguous: Any
+flatnotmasked_edges: Any
+hsplit: Any
+hstack: Any
+isin: Any
+in1d: Any
+intersect1d: Any
+mask_cols: Any
+mask_rowcols: Any
+mask_rows: Any
+masked_all: Any
+masked_all_like: Any
+median: Any
+mr_: Any
+notmasked_contiguous: Any
+notmasked_edges: Any
+polyfit: Any
+row_stack: Any
+setdiff1d: Any
+setxor1d: Any
+stack: Any
+unique: Any
+union1d: Any
+vander: Any
+vstack: Any
xs=xs, nmxs=nmxs, xl=xl, nmxl=nmxl):
funcname = func.__name__
print("-"*50)
- print("%s on small arrays" % funcname)
+ print(f'{funcname} on small arrays')
module, data = "numpy.ma", "nmxs"
timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop)
def compare_methods(methodname, args, vars='x', nloop=500, test=True,
xs=xs, nmxs=nmxs, xl=xl, nmxl=nmxl):
print("-"*50)
- print("%s on small arrays" % methodname)
- data, ver = "nm%ss" % vars, 'numpy.ma'
+ print(f'{methodname} on small arrays')
+ data, ver = f'nm{vars}l', 'numpy.ma'
timer("%(data)s.%(methodname)s(%(args)s)" % locals(), v=ver, nloop=nloop)
print("%s on large arrays" % methodname)
yl=yl, nmyl=nmyl):
funcname = func.__name__
print("-"*50)
- print("%s on small arrays" % funcname)
+ print(f'{funcname} on small arrays')
module, data = "numpy.ma", "nmxs,nmys"
timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop)
- print("%s on large arrays" % funcname)
+ print(f'{funcname} on large arrays')
module, data = "numpy.ma", "nmxl,nmyl"
timer("%(module)s.%(funcname)s(%(data)s)" % locals(), v="%11s" % module, nloop=nloop)
return
"""
# pylint: disable-msg=E1002
import builtins
+import inspect
import operator
import warnings
import textwrap
if note is None:
return initialdoc
- notesplit = re.split(r'\n\s*?Notes\n\s*?-----', initialdoc)
-
- notedoc = """\
-Notes
- -----
- %s""" % note
-
- if len(notesplit) > 1:
- notedoc = '\n\n ' + notedoc + '\n'
+ notesplit = re.split(r'\n\s*?Notes\n\s*?-----', inspect.cleandoc(initialdoc))
+ notedoc = "\n\nNotes\n-----\n%s\n" % inspect.cleandoc(note)
return ''.join(notesplit[:1] + [notedoc] + notesplit[1:])
if isinstance(fill_value, (ndarray, np.void)):
try:
fill_value = np.array(fill_value, copy=False, dtype=ndtype)
- except ValueError:
+ except ValueError as e:
err_msg = "Unable to transform %s to dtype %s"
- raise ValueError(err_msg % (fill_value, ndtype))
+ raise ValueError(err_msg % (fill_value, ndtype)) from e
else:
fill_value = np.asarray(fill_value, dtype=object)
fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype),
# Also in case of converting string arrays.
try:
fill_value = np.array(fill_value, copy=False, dtype=ndtype)
- except (OverflowError, ValueError):
+ except (OverflowError, ValueError) as e:
# Raise TypeError instead of OverflowError or ValueError.
# OverflowError is seldom used, and the real problem here is
# that the passed fill_value is not compatible with the ndtype.
err_msg = "Cannot convert fill_value %s to dtype %s"
- raise TypeError(err_msg % (fill_value, ndtype))
+ raise TypeError(err_msg % (fill_value, ndtype)) from e
return np.array(fill_value)
See Also
--------
- isMaskedArray : Test whether input is an instance of MaskedArray.
+ ma.isMaskedArray : Test whether input is an instance of MaskedArray.
Examples
--------
def __new__(cls, data=None, mask=nomask, dtype=None, copy=False,
subok=True, ndmin=0, fill_value=None, keep_mask=True,
- hard_mask=None, shrink=True, order=None, **options):
+ hard_mask=None, shrink=True, order=None):
"""
Create a new masked array from scratch.
Force the mask to hard.
Whether the mask of a masked array is hard or soft is determined by
- its `hardmask` property. `harden_mask` sets `hardmask` to True.
+ its `~ma.MaskedArray.hardmask` property. `harden_mask` sets
+ `~ma.MaskedArray.hardmask` to ``True``.
See Also
--------
- hardmask
+ ma.MaskedArray.hardmask
"""
self._hardmask = True
Force the mask to soft.
Whether the mask of a masked array is hard or soft is determined by
- its `hardmask` property. `soften_mask` sets `hardmask` to False.
+ its `~ma.MaskedArray.hardmask` property. `soften_mask` sets
+ `~ma.MaskedArray.hardmask` to ``False``.
See Also
--------
- hardmask
+ ma.MaskedArray.hardmask
"""
self._hardmask = False
"""
Return `a` where condition is ``True``.
- If condition is a `MaskedArray`, missing values are considered
+ If condition is a `~ma.MaskedArray`, missing values are considered
as ``False``.
Parameters
Returns
-------
result : MaskedArray
- A :class:`MaskedArray` object.
+ A :class:`~ma.MaskedArray` object.
Notes
-----
See Also
--------
- count_masked : Count masked elements in array or along a given axis.
+ ma.count_masked : Count masked elements in array or along a given axis.
Examples
--------
Notes
-----
- The mask is lost if `out` is not a valid :class:`MaskedArray` !
+ The mask is lost if `out` is not a valid :class:`ma.MaskedArray` !
Arithmetic is modular when using integer types, and no error is
raised on overflow.
See Also
--------
- numpy.ndarray.around : corresponding function for ndarrays
+ numpy.ndarray.round : corresponding function for ndarrays
numpy.around : equivalent function
"""
result = self._data.round(decimals=decimals, out=out).view(type(self))
See Also
--------
- MaskedArray.sort : Describes sorting algorithms used.
+ ma.MaskedArray.sort : Describes sorting algorithms used.
lexsort : Indirect stable sort with multiple keys.
numpy.ndarray.sort : Inplace sort.
See Also
--------
- minimum_fill_value
+ ma.minimum_fill_value
Returns the minimum filling value for a given datatype.
"""
See Also
--------
- maximum_fill_value
+ ma.maximum_fill_value
Returns the maximum filling value for a given datatype.
"""
Return all the non-masked data as a 1-D array.
This function is equivalent to calling the "compressed" method of a
- `MaskedArray`, see `MaskedArray.compressed` for details.
+ `ma.MaskedArray`, see `ma.MaskedArray.compressed` for details.
See Also
--------
- MaskedArray.compressed
+ ma.MaskedArray.compressed
Equivalent method.
"""
the new masked array version of the function. A note on application
of the function to the mask is appended.
- .. warning::
- If the function docstring already contained a Notes section, the
- new docstring will have two Notes sections instead of appending a note
- to the existing section.
-
Parameters
----------
None
doc = getattr(npfunc, '__doc__', None)
if doc:
sig = self.__name__ + ma.get_object_signature(npfunc)
- locdoc = "Notes\n-----\nThe function is applied to both the _data"\
- " and the _mask, if any."
- return '\n'.join((sig, doc, locdoc))
+ doc = ma.doc_note(doc, "The function is applied to both the _data "
+ "and the _mask, if any.")
+ return '\n\n'.join((sig, doc))
return
def __call__(self, *args, **params):
Suppress whole rows of a 2-D array that contain masked values.
This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see
- `extras.compress_rowcols` for details.
+ `compress_rowcols` for details.
See Also
--------
- extras.compress_rowcols
+ compress_rowcols
"""
a = asarray(a)
Suppress whole columns of a 2-D array that contain masked values.
This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see
- `extras.compress_rowcols` for details.
+ `compress_rowcols` for details.
See Also
--------
- extras.compress_rowcols
+ compress_rowcols
"""
a = asarray(a)
slice_list : list
A sorted sequence of `slice` objects (start index, end index).
- ..versionchanged:: 1.15.0
+ .. versionchanged:: 1.15.0
Now returns an empty list instead of None for a fully masked array
See Also
elif isinstance(names, str):
new_names = names.split(',')
else:
- raise NameError("illegal input names %s" % repr(names))
+ raise NameError(f'illegal input names {names!r}')
nnames = len(new_names)
if nnames < ndescr:
new_names += default_names[nnames:]
fielddict = ndarray.__getattribute__(self, 'dtype').fields
try:
res = fielddict[attr][:2]
- except (TypeError, KeyError):
- raise AttributeError("record array has no attribute %s" % attr)
+ except (TypeError, KeyError) as e:
+ raise AttributeError(f'record array has no attribute {attr}') from e
# So far, so good
_localdict = ndarray.__getattribute__(self, '__dict__')
_data = ndarray.view(self, _localdict['_baseclass'])
try:
res = fielddict[attr][:2]
except (TypeError, KeyError):
- raise AttributeError("record array has no attribute %s" % attr)
+ raise AttributeError(f'record array has no attribute {attr}')
if val is masked:
_fill_value = _localdict['_fill_value']
"""
if self.size > 1:
- mstr = ["(%s)" % ",".join([str(i) for i in s])
+ mstr = [f"({','.join([str(i) for i in s])})"
for s in zip(*[getattr(self, f) for f in self.dtype.names])]
- return "[%s]" % ", ".join(mstr)
+ return f"[{', '.join(mstr)}]"
else:
- mstr = ["%s" % ",".join([str(i) for i in s])
+ mstr = [f"{','.join([str(i) for i in s])}"
for s in zip([getattr(self, f) for f in self.dtype.names])]
- return "(%s)" % ", ".join(mstr)
+ return f"({', '.join(mstr)})"
def __repr__(self):
"""
try:
f = open(fname)
except IOError:
- raise IOError("No such file: '%s'" % fname)
+ raise IOError(f"No such file: '{fname}'")
if f.readline()[:2] != "\\x":
f.seek(0, 0)
return f
from numpy.distutils.misc_util import Configuration
config = Configuration('ma', parent_package, top_path)
config.add_subpackage('tests')
+ config.add_data_files('*.pyi')
return config
if __name__ == "__main__":
MAError, MaskError, MaskType, MaskedArray, abs, absolute, add, all,
allclose, allequal, alltrue, angle, anom, arange, arccos, arccosh, arctan2,
arcsin, arctan, argsort, array, asarray, choose, concatenate,
- conjugate, cos, cosh, count, default_fill_value, diag, divide, empty,
- empty_like, equal, exp, flatten_mask, filled, fix_invalid,
+ conjugate, cos, cosh, count, default_fill_value, diag, divide, doc_note,
+ empty, empty_like, equal, exp, flatten_mask, filled, fix_invalid,
flatten_structured_array, fromflex, getmask, getmaskarray, greater,
greater_equal, identity, inner, isMaskedArray, less, less_equal, log,
log10, make_mask, make_mask_descr, mask_or, masked, masked_array,
y = array([1, 2, 3], mask=x._mask, copy=True)
assert_(not np.may_share_memory(x.mask, y.mask))
+ def test_masked_singleton_array_creation_warns(self):
+ # The first works, but should not (ideally), there may be no way
+ # to solve this, however, as long as `np.ma.masked` is an ndarray.
+ np.array(np.ma.masked)
+ with pytest.warns(UserWarning):
+ # Tries to create a float array, using `float(np.ma.masked)`.
+ # We may want to define this is invalid behaviour in the future!
+ # (requiring np.ma.masked to be a known NumPy scalar probably
+ # with a DType.)
+ np.array([3., np.ma.masked])
+
def test_creation_with_list_of_maskedarrays(self):
# Tests creating a masked array from a list of masked arrays.
x = array(np.arange(5), mask=[1, 0, 0, 0, 0])
'offsets':[0,8]})
array(x) # used to fail due to 'V' padding field in x.dtype.descr
+ def test_unknown_keyword_parameter(self):
+ with pytest.raises(TypeError, match="unexpected keyword argument"):
+ MaskedArray([1, 2, 3], maks=[0, 1, 0]) # `mask` is misspelled.
+
def test_asarray(self):
(x, y, a10, m1, m2, xm, ym, z, zm, xf) = self.d
xm.fill_value = -9999
xm += t(1)
assert_equal(xm, y + t(1))
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
def test_inplace_addition_array_type(self):
# Test of inplace additions
assert_equal(xm, y + a)
assert_equal(xm.mask, mask_or(m, a.mask))
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
def test_inplace_subtraction_scalar_type(self):
# Test of inplace subtractions
xm -= t(1)
assert_equal(xm, y - t(1))
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
def test_inplace_subtraction_array_type(self):
# Test of inplace subtractions
assert_equal(xm, y - a)
assert_equal(xm.mask, mask_or(m, a.mask))
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
def test_inplace_multiplication_scalar_type(self):
# Test of inplace multiplication
xm *= t(2)
assert_equal(xm, y * t(2))
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
def test_inplace_multiplication_array_type(self):
# Test of inplace multiplication
assert_equal(xm, y * a)
assert_equal(xm.mask, mask_or(m, a.mask))
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
def test_inplace_floor_division_scalar_type(self):
# Test of inplace division
mask_or(mask_or(m, a.mask), (a == t(0)))
)
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
def test_inplace_division_scalar_type(self):
# Test of inplace division
warnings.warn(str(e), stacklevel=1)
if issubclass(t, np.integer):
- assert_equal(len(sup.log), 2, "Failed on type=%s." % t)
+ assert_equal(len(sup.log), 2, f'Failed on type={t}.')
else:
- assert_equal(len(sup.log), 0, "Failed on type=%s." % t)
+ assert_equal(len(sup.log), 0, f'Failed on type={t}.')
def test_inplace_division_array_type(self):
# Test of inplace division
warnings.warn(str(e), stacklevel=1)
if issubclass(t, np.integer):
- assert_equal(len(sup.log), 2, "Failed on type=%s." % t)
+ assert_equal(len(sup.log), 2, f'Failed on type={t}.')
else:
- assert_equal(len(sup.log), 0, "Failed on type=%s." % t)
+ assert_equal(len(sup.log), 0, f'Failed on type={t}.')
def test_inplace_pow_type(self):
# Test keeping data w/ (inplace) power
assert_equal(x.data, xx_r.data)
assert_equal(x.mask, xx_r.mask)
- assert_equal(len(w), 0, "Failed on type=%s." % t)
+ assert_equal(len(w), 0, f'Failed on type={t}.')
class TestMaskedArrayMethods:
assert_almost_equal(np.sqrt(mXvar0[k]),
mX[:, k].compressed().std())
- @pytest.mark.skipif(sys.platform=='win32' and sys.version_info < (3, 6),
- reason='Fails on Python < 3.6 on Windows, gh-9671')
@suppress_copy_mask_on_assignment
def test_varstd_specialcases(self):
# Test a special case for var
class M(MaskedArray):
pass
- test = np.ma.compressed(M(shape=(0,1,2)))
+ test = np.ma.compressed(M([[[]], [[]]]))
assert_equal(test.ndim, 1)
# with .compressed() overridden
def compressed(self):
return 42
- test = np.ma.compressed(M(shape=(0,1,2)))
+ test = np.ma.compressed(M([[[]], [[]]]))
assert_equal(test, 42)
def test_convolve(self):
b = np.ma.array(1, mask=a.mask)
b.shape = (1,)
assert_equal(a.mask.shape, ())
+
+@pytest.mark.skipif(sys.flags.optimize > 1,
+ reason="no docstrings present to inspect when PYTHONOPTIMIZE/Py_OptimizeFlag > 1")
+def test_doc_note():
+ def method(self):
+ """This docstring
+
+ Has multiple lines
+
+ And notes
+
+ Notes
+ -----
+ original note
+ """
+ pass
+
+ expected_doc = """This docstring
+
+Has multiple lines
+
+And notes
+
+Notes
+-----
+note
+
+original note"""
+
+ assert_equal(np.ma.core.doc_note(method.__doc__, "note"), expected_doc)
def eq(v, w, msg=''):
result = allclose(v, w)
if not result:
- print("Not eq:%s\n%s\n----%s" % (msg, str(v), str(w)))
+ print(f'Not eq:{msg}\n{v}\n----{w}')
return result
class ComplicatedSubArray(SubArray):
def __str__(self):
- return 'myprefix {0} mypostfix'.format(self.view(SubArray))
+ return f'myprefix {self.view(SubArray)} mypostfix'
def __repr__(self):
# Return a repr that does not start with 'name('
- return '<{0} {1}>'.format(self.__class__.__name__, self)
+ return f'<{self.__class__.__name__} {self}>'
def _validate_input(self, value):
if not isinstance(value, ComplicatedSubArray):
assert_startswith(repr(mx), 'masked_array')
xsub = SubArray(x)
mxsub = masked_array(xsub, mask=[True, False, True, False, False])
- assert_startswith(repr(mxsub),
- 'masked_{0}(data=[--, 1, --, 3, 4]'.format(SubArray.__name__))
+ assert_startswith(repr(mxsub),
+ f'masked_{SubArray.__name__}(data=[--, 1, --, 3, 4]')
def test_subclass_str(self):
"""test str with subclass that has overridden str, setitem"""
"""
assert_equal(len(actual), len(desired), err_msg)
for k in range(len(desired)):
- assert_equal(actual[k], desired[k], 'item=%r\n%s' % (k, err_msg))
+ assert_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}')
return
assert_equal(len(actual), len(desired), err_msg)
for k, i in desired.items():
if k not in actual:
- raise AssertionError("%s not in %s" % (k, actual))
- assert_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg))
+ raise AssertionError(f"{k} not in {actual}")
+ assert_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}')
return
# Case #2: lists .....
if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)):
for k, i in desired.items():
if k not in actual:
raise AssertionError(repr(k))
- fail_if_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg))
+ fail_if_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}')
return
if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)):
fail_if_equal(len(actual), len(desired), err_msg)
for k in range(len(desired)):
- fail_if_equal(actual[k], desired[k], 'item=%r\n%s' % (k, err_msg))
+ fail_if_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}')
return
if isinstance(actual, np.ndarray) or isinstance(desired, np.ndarray):
return fail_if_array_equal(actual, desired, err_msg)
from numpy.testing import build_err_msg
-# Fixme: this does not look right.
-np.seterr(all='ignore')
pi = np.pi
-
class ModuleTester:
def __init__(self, module):
self.module = module
if not cond:
msg = build_err_msg([x, y],
err_msg
- + '\n(shapes %s, %s mismatch)' % (x.shape,
- y.shape),
+ + f'\n(shapes {x.shape}, {y.shape} mismatch)',
header=header,
names=('x', 'y'))
assert cond, msg
header=header,
names=('x', 'y'))
assert cond, msg
- except ValueError:
+ except ValueError as e:
msg = build_err_msg([x, y], err_msg, header=header, names=('x', 'y'))
- raise ValueError(msg)
+ raise ValueError(msg) from e
def assert_array_equal(self, x, y, err_msg=''):
"""
self.assert_array_compare(self.equal, x, y, err_msg=err_msg,
header='Arrays are not equal')
+ @np.errstate(all='ignore')
def test_0(self):
"""
Tests creation
xm = self.masked_array(x, mask=m)
xm[0]
+ @np.errstate(all='ignore')
def test_1(self):
"""
Tests creation
xf.shape = s
assert(self.count(xm) == len(m1) - reduce(lambda x, y:x+y, m1))
+ @np.errstate(all='ignore')
def test_2(self):
"""
Tests conversions and indexing.
m3 = self.make_mask(m, copy=1)
assert(m is not m3)
+ @np.errstate(all='ignore')
def test_3(self):
"""
Tests resize/repeat
y8 = x4.repeat(2, 0)
assert self.allequal(y5, y8)
+ @np.errstate(all='ignore')
def test_4(self):
"""
Test of take, transpose, inner, outer products.
assert t[1] == 2
assert t[2] == 3
+ @np.errstate(all='ignore')
def test_5(self):
"""
Tests inplace w/ scalar
x += 1.
assert self.allequal(x, y + 1.)
+ @np.errstate(all='ignore')
def test_6(self):
"""
Tests inplace w/ array
x /= a
xm /= a
+ @np.errstate(all='ignore')
def test_7(self):
"Tests ufunc"
d = (self.array([1.0, 0, -1, pi/2]*2, mask=[0, 1]+[0]*6),
self.assert_array_equal(ur.filled(0), mr.filled(0), f)
self.assert_array_equal(ur._mask, mr._mask)
+ @np.errstate(all='ignore')
def test_99(self):
# test average
ott = self.array([0., 1., 2., 3.], mask=[1, 0, 0, 0])
self.assert_array_equal(self.average(z, axis=1), [2.5, 5.0])
self.assert_array_equal(self.average(z, axis=0, weights=w2), [0., 1., 99., 99., 4.0, 10.0])
+ @np.errstate(all='ignore')
def test_A(self):
x = self.arange(24)
x[5:6] = self.masked
cur = np.sort(cur)
print("#%i" % i + 50*'.')
print(eval("ModuleTester.test_%i.__doc__" % i))
- print("core_current : %.3f - %.3f" % (cur[0], cur[1]))
+ print(f'core_current : {cur[0]:.3f} - {cur[1]:.3f}')
--- /dev/null
+from typing import Any
+
+matrix: Any
+bmat: Any
+mat: Any
+asmatrix: Any
Parameters
----------
axis : None or int or tuple of ints, optional
- Selects a subset of the single-dimensional entries in the shape.
+ Selects a subset of the axes of length one in the shape.
If an axis is selected with shape entry greater than one,
an error is raised.
"""
M, N = self.shape
if M == N:
- from numpy.dual import inv as func
+ from numpy.linalg import inv as func
else:
- from numpy.dual import pinv as func
+ from numpy.linalg import pinv as func
return asmatrix(func(self))
@property
from numpy.distutils.misc_util import Configuration
config = Configuration('matrixlib', parent_package, top_path)
config.add_subpackage('tests')
+ config.add_data_files('*.pyi')
return config
if __name__ == "__main__":
import numpy as np
+from numpy.testing import assert_warns
from numpy.ma.testutils import (assert_, assert_equal, assert_raises,
assert_array_equal)
from numpy.ma.core import (masked_array, masked_values, masked, allequal,
# Result should work
assert_equal(add(mx, x), mx+x)
assert_(isinstance(add(mx, mx)._data, np.matrix))
- assert_(isinstance(add.outer(mx, mx), MMatrix))
+ with assert_warns(DeprecationWarning):
+ assert_(isinstance(add.outer(mx, mx), MMatrix))
assert_(isinstance(hypot(mx, mx), MMatrix))
assert_(isinstance(hypot(mx, x), MMatrix))
implemented as operations on the coefficients. Additional (module-specific)
information can be found in the docstring for the module of interest.
+This package provides *convenience classes* for each of six different kinds
+of polynomials:
+
+ ============ ================
+ **Name** **Provides**
+ ============ ================
+ Polynomial Power series
+ Chebyshev Chebyshev series
+ Legendre Legendre series
+ Laguerre Laguerre series
+ Hermite Hermite series
+ HermiteE HermiteE series
+ ============ ================
+
+These *convenience classes* provide a consistent interface for creating,
+manipulating, and fitting data with polynomials of different bases.
+The convenience classes are the preferred interface for the `~numpy.polynomial`
+package, and are available from the `numpy.polynomial` namespace.
+This eliminates the need to
+navigate to the corresponding submodules, e.g. ``np.polynomial.Polynomial``
+or ``np.polynomial.Chebyshev`` instead of
+``np.polynomial.polynomial.Polynomial`` or
+``np.polynomial.chebyshev.Chebyshev``, respectively.
+The classes provide a more consistent and concise interface than the
+type-specific functions defined in the submodules for each type of polynomial.
+For example, to fit a Chebyshev polynomial with degree ``1`` to data given
+by arrays ``xdata`` and ``ydata``, the
+`~chebyshev.Chebyshev.fit` class method::
+
+ >>> from numpy.polynomial import Chebyshev
+ >>> c = Chebyshev.fit(xdata, ydata, deg=1)
+
+is preferred over the `chebyshev.chebfit` function from the
+`numpy.polynomial.chebyshev` module::
+
+ >>> from numpy.polynomial.chebyshev import chebfit
+ >>> c = chebfit(xdata, ydata, deg=1)
+
+See :doc:`routines.polynomials.classes` for more details.
+
+Convenience Classes
+===================
+
+The following lists the various constants and methods common to all of
+the classes representing the various kinds of polynomials. In the following,
+the term ``Poly`` represents any one of the convenience classes (e.g.
+``Polynomial``, ``Chebyshev``, ``Hermite``, etc.) while the lowercase ``p``
+represents an **instance** of a polynomial class.
+
+Constants
+---------
+
+- ``Poly.domain`` -- Default domain
+- ``Poly.window`` -- Default window
+- ``Poly.basis_name`` -- String used to represent the basis
+- ``Poly.maxpower`` -- Maximum value ``n`` such that ``p**n`` is allowed
+- ``Poly.nickname`` -- String used in printing
+
+Creation
+--------
+
+Methods for creating polynomial instances.
+
+- ``Poly.basis(degree)`` -- Basis polynomial of given degree
+- ``Poly.identity()`` -- ``p`` where ``p(x) = x`` for all ``x``
+- ``Poly.fit(x, y, deg)`` -- ``p`` of degree ``deg`` with coefficients
+ determined by the least-squares fit to the data ``x``, ``y``
+- ``Poly.fromroots(roots)`` -- ``p`` with specified roots
+- ``p.copy()`` -- Create a copy of ``p``
+
+Conversion
+----------
+
+Methods for converting a polynomial instance of one kind to another.
+
+- ``p.cast(Poly)`` -- Convert ``p`` to instance of kind ``Poly``
+- ``p.convert(Poly)`` -- Convert ``p`` to instance of kind ``Poly`` or map
+ between ``domain`` and ``window``
+
+Calculus
+--------
+- ``p.deriv()`` -- Take the derivative of ``p``
+- ``p.integ()`` -- Integrate ``p``
+
+Validation
+----------
+- ``Poly.has_samecoef(p1, p2)`` -- Check if coefficients match
+- ``Poly.has_samedomain(p1, p2)`` -- Check if domains match
+- ``Poly.has_sametype(p1, p2)`` -- Check if types match
+- ``Poly.has_samewindow(p1, p2)`` -- Check if windows match
+
+Misc
+----
+- ``p.linspace()`` -- Return ``x, p(x)`` at equally-spaced points in ``domain``
+- ``p.mapparms()`` -- Return the parameters for the linear mapping between
+ ``domain`` and ``window``.
+- ``p.roots()`` -- Return the roots of `p`.
+- ``p.trim()`` -- Remove trailing coefficients.
+- ``p.cutdeg(degree)`` -- Truncate p to given degree
+- ``p.truncate(size)`` -- Truncate p to given size
+
"""
from .polynomial import Polynomial
from .chebyshev import Chebyshev
from .hermite_e import HermiteE
from .laguerre import Laguerre
+
+def set_default_printstyle(style):
+ """
+ Set the default format for the string representation of polynomials.
+
+ Values for ``style`` must be valid inputs to ``__format__``, i.e. 'ascii'
+ or 'unicode'.
+
+ Parameters
+ ----------
+ style : str
+ Format string for default printing style. Must be either 'ascii' or
+ 'unicode'.
+
+ Notes
+ -----
+ The default format depends on the platform: 'unicode' is used on
+ Unix-based systems and 'ascii' on Windows. This determination is based on
+ default font support for the unicode superscript and subscript ranges.
+
+ Examples
+ --------
+ >>> p = np.polynomial.Polynomial([1, 2, 3])
+ >>> c = np.polynomial.Chebyshev([1, 2, 3])
+ >>> np.polynomial.set_default_printstyle('unicode')
+ >>> print(p)
+ 1.0 + 2.0·x¹ + 3.0·x²
+ >>> print(c)
+ 1.0 + 2.0·T₁(x) + 3.0·T₂(x)
+ >>> np.polynomial.set_default_printstyle('ascii')
+ >>> print(p)
+ 1.0 + 2.0 x**1 + 3.0 x**2
+ >>> print(c)
+ 1.0 + 2.0 T_1(x) + 3.0 T_2(x)
+ >>> # Formatting supercedes all class/package-level defaults
+ >>> print(f"{p:unicode}")
+ 1.0 + 2.0·x¹ + 3.0·x²
+ """
+ if style not in ('unicode', 'ascii'):
+ raise ValueError(
+ f"Unsupported format string '{style}'. Valid options are 'ascii' "
+ f"and 'unicode'"
+ )
+ _use_unicode = True
+ if style == 'ascii':
+ _use_unicode = False
+ from ._polybase import ABCPolyBase
+ ABCPolyBase._use_unicode = _use_unicode
+
+
from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
del PytestTester
--- /dev/null
+from typing import Any
+
+Polynomial: Any
+Chebyshev: Any
+Legendre: Any
+Hermite: Any
+HermiteE: Any
+Laguerre: Any
+set_default_printstyle: Any
abc module from the stdlib, hence it is only available for Python >= 2.6.
"""
+import os
import abc
import numbers
# Limit runaway size. T_n^m has degree n*m
maxpower = 100
+ # Unicode character mappings for improved __str__
+ _superscript_mapping = str.maketrans({
+ "0": "⁰",
+ "1": "¹",
+ "2": "²",
+ "3": "³",
+ "4": "⁴",
+ "5": "⁵",
+ "6": "⁶",
+ "7": "⁷",
+ "8": "⁸",
+ "9": "⁹"
+ })
+ _subscript_mapping = str.maketrans({
+ "0": "₀",
+ "1": "₁",
+ "2": "₂",
+ "3": "₃",
+ "4": "₄",
+ "5": "₅",
+ "6": "₆",
+ "7": "₇",
+ "8": "₈",
+ "9": "₉"
+ })
+ # Some fonts don't support full unicode character ranges necessary for
+ # the full set of superscripts and subscripts, including common/default
+ # fonts in Windows shells/terminals. Therefore, default to ascii-only
+ # printing on windows.
+ _use_unicode = not os.name == 'nt'
+
@property
@abc.abstractmethod
def domain(self):
def window(self):
pass
- @property
- @abc.abstractmethod
- def nickname(self):
- pass
-
@property
@abc.abstractmethod
def basis_name(self):
name = self.__class__.__name__
return f"{name}({coef}, domain={domain}, window={window})"
+ def __format__(self, fmt_str):
+ if fmt_str == '':
+ return self.__str__()
+ if fmt_str not in ('ascii', 'unicode'):
+ raise ValueError(
+ f"Unsupported format string '{fmt_str}' passed to "
+ f"{self.__class__}.__format__. Valid options are "
+ f"'ascii' and 'unicode'"
+ )
+ if fmt_str == 'ascii':
+ return self._generate_string(self._str_term_ascii)
+ return self._generate_string(self._str_term_unicode)
+
def __str__(self):
- coef = str(self.coef)
- name = self.nickname
- return f"{name}({coef})"
+ if self._use_unicode:
+ return self._generate_string(self._str_term_unicode)
+ return self._generate_string(self._str_term_ascii)
+
+ def _generate_string(self, term_method):
+ """
+ Generate the full string representation of the polynomial, using
+ ``term_method`` to generate each polynomial term.
+ """
+ # Get configuration for line breaks
+ linewidth = np.get_printoptions().get('linewidth', 75)
+ if linewidth < 1:
+ linewidth = 1
+ out = f"{self.coef[0]}"
+ for i, coef in enumerate(self.coef[1:]):
+ out += " "
+ power = str(i + 1)
+ # Polynomial coefficient
+ # The coefficient array can be an object array with elements that
+ # will raise a TypeError with >= 0 (e.g. strings or Python
+ # complex). In this case, represent the coeficient as-is.
+ try:
+ if coef >= 0:
+ next_term = f"+ {coef}"
+ else:
+ next_term = f"- {-coef}"
+ except TypeError:
+ next_term = f"+ {coef}"
+ # Polynomial term
+ next_term += term_method(power, "x")
+ # Length of the current line with next term added
+ line_len = len(out.split('\n')[-1]) + len(next_term)
+ # If not the last term in the polynomial, it will be two
+ # characters longer due to the +/- with the next term
+ if i < len(self.coef[1:]) - 1:
+ line_len += 2
+ # Handle linebreaking
+ if line_len >= linewidth:
+ next_term = next_term.replace(" ", "\n", 1)
+ out += next_term
+ return out
+
+ @classmethod
+ def _str_term_unicode(cls, i, arg_str):
+ """
+ String representation of single polynomial term using unicode
+ characters for superscripts and subscripts.
+ """
+ if cls.basis_name is None:
+ raise NotImplementedError(
+ "Subclasses must define either a basis_name, or override "
+ "_str_term_unicode(cls, i, arg_str)"
+ )
+ return (f"·{cls.basis_name}{i.translate(cls._subscript_mapping)}"
+ f"({arg_str})")
+
+ @classmethod
+ def _str_term_ascii(cls, i, arg_str):
+ """
+ String representation of a single polynomial term using ** and _ to
+ represent superscripts and subscripts, respectively.
+ """
+ if cls.basis_name is None:
+ raise NotImplementedError(
+ "Subclasses must define either a basis_name, or override "
+ "_str_term_ascii(cls, i, arg_str)"
+ )
+ return f" {cls.basis_name}_{i}({arg_str})"
@classmethod
def _repr_latex_term(cls, i, arg_str, needs_parens):
othercoef = self._get_coefficients(other)
try:
quo, rem = self._div(self.coef, othercoef)
- except ZeroDivisionError as e:
- raise e
+ except ZeroDivisionError:
+ raise
except Exception:
return NotImplemented
quo = self.__class__(quo, self.domain, self.window)
def __rdivmod__(self, other):
try:
quo, rem = self._div(other, self.coef)
- except ZeroDivisionError as e:
- raise e
+ except ZeroDivisionError:
+ raise
except Exception:
return NotImplemented
quo = self.__class__(quo, self.domain, self.window)
----------
x : array_like, shape (M,)
x-coordinates of the M sample points ``(x[i], y[i])``.
- y : array_like, shape (M,) or (M, K)
- y-coordinates of the sample points. Several data sets of sample
- points sharing the same x-coordinates can be fitted at once by
- passing in a 2D-array that contains one dataset per column.
+ y : array_like, shape (M,)
+ y-coordinates of the M sample points ``(x[i], y[i])``.
deg : int or 1-D array_like
Degree(s) of the fitting polynomials. If `deg` is a single integer
all terms up to and including the `deg`'th term are included in the
----------
.. [1] A. T. Benjamin, et al., "Combinatorial Trigonometry with Chebyshev
Polynomials," *Journal of Statistical Planning and Inference 14*, 2008
- (preprint: https://www.math.hmc.edu/~benjamin/papers/CombTrig.pdf, pg. 4)
+ (https://web.archive.org/web/20080221202153/https://www.math.hmc.edu/~benjamin/papers/CombTrig.pdf, pg. 4)
"""
import numpy as np
"""
Chebyshev series whose graph is a straight line.
-
-
Parameters
----------
off, scl : scalars
See Also
--------
- polyline
+ numpy.polynomial.polynomial.polyline
+ numpy.polynomial.legendre.legline
+ numpy.polynomial.laguerre.lagline
+ numpy.polynomial.hermite.hermline
+ numpy.polynomial.hermite_e.hermeline
Examples
--------
See Also
--------
- polyfromroots, legfromroots, lagfromroots, hermfromroots, hermefromroots
+ numpy.polynomial.polynomial.polyfromroots
+ numpy.polynomial.legendre.legfromroots
+ numpy.polynomial.laguerre.lagfromroots
+ numpy.polynomial.hermite.hermfromroots
+ numpy.polynomial.hermite_e.hermefromroots
Examples
--------
See Also
--------
- chebadd, chebsub, chemulx, chebmul, chebpow
+ chebadd, chebsub, chebmulx, chebmul, chebpow
Notes
-----
sv -- singular values of the scaled Vandermonde matrix
rcond -- value of `rcond`.
- For more details, see `linalg.lstsq`.
+ For more details, see `numpy.linalg.lstsq`.
Warns
-----
See Also
--------
- polyfit, legfit, lagfit, hermfit, hermefit
+ numpy.polynomial.polynomial.polyfit
+ numpy.polynomial.legendre.legfit
+ numpy.polynomial.laguerre.lagfit
+ numpy.polynomial.hermite.hermfit
+ numpy.polynomial.hermite_e.hermefit
chebval : Evaluates a Chebyshev series.
chebvander : Vandermonde matrix of Chebyshev series.
chebweight : Chebyshev weight function.
- linalg.lstsq : Computes a least-squares fit from the matrix.
+ numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
scipy.interpolate.UnivariateSpline : Computes spline fits.
Notes
See Also
--------
- polyroots, legroots, lagroots, hermroots, hermeroots
+ numpy.polynomial.polynomial.polyroots
+ numpy.polynomial.legendre.legroots
+ numpy.polynomial.laguerre.lagroots
+ numpy.polynomial.hermite.hermroots
+ numpy.polynomial.hermite_e.hermeroots
Notes
-----
return cls(coef, domain=domain)
# Virtual properties
- nickname = 'cheb'
domain = np.array(chebdomain)
window = np.array(chebdomain)
basis_name = 'T'
See Also
--------
- polyline, chebline
+ numpy.polynomial.polynomial.polyline
+ numpy.polynomial.chebyshev.chebline
+ numpy.polynomial.legendre.legline
+ numpy.polynomial.laguerre.lagline
+ numpy.polynomial.hermite_e.hermeline
Examples
--------
See Also
--------
- polyfromroots, legfromroots, lagfromroots, chebfromroots, hermefromroots
+ numpy.polynomial.polynomial.polyfromroots
+ numpy.polynomial.legendre.legfromroots
+ numpy.polynomial.laguerre.lagfromroots
+ numpy.polynomial.chebyshev.chebfromroots
+ numpy.polynomial.hermite_e.hermefromroots
Examples
--------
sv -- singular values of the scaled Vandermonde matrix
rcond -- value of `rcond`.
- For more details, see `linalg.lstsq`.
+ For more details, see `numpy.linalg.lstsq`.
Warns
-----
See Also
--------
- chebfit, legfit, lagfit, polyfit, hermefit
+ numpy.polynomial.chebyshev.chebfit
+ numpy.polynomial.legendre.legfit
+ numpy.polynomial.laguerre.lagfit
+ numpy.polynomial.polynomial.polyfit
+ numpy.polynomial.hermite_e.hermefit
hermval : Evaluates a Hermite series.
hermvander : Vandermonde matrix of Hermite series.
hermweight : Hermite weight function
- linalg.lstsq : Computes a least-squares fit from the matrix.
+ numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
scipy.interpolate.UnivariateSpline : Computes spline fits.
Notes
See Also
--------
- polyroots, legroots, lagroots, chebroots, hermeroots
+ numpy.polynomial.polynomial.polyroots
+ numpy.polynomial.legendre.legroots
+ numpy.polynomial.laguerre.lagroots
+ numpy.polynomial.chebyshev.chebroots
+ numpy.polynomial.hermite_e.hermeroots
Notes
-----
_fromroots = staticmethod(hermfromroots)
# Virtual properties
- nickname = 'herm'
domain = np.array(hermdomain)
window = np.array(hermdomain)
basis_name = 'H'
"""
Hermite series whose graph is a straight line.
-
-
Parameters
----------
off, scl : scalars
See Also
--------
- polyline, chebline
+ numpy.polynomial.polynomial.polyline
+ numpy.polynomial.chebyshev.chebline
+ numpy.polynomial.legendre.legline
+ numpy.polynomial.laguerre.lagline
+ numpy.polynomial.hermite.hermline
Examples
--------
See Also
--------
- polyfromroots, legfromroots, lagfromroots, hermfromroots, chebfromroots
+ numpy.polynomial.polynomial.polyfromroots
+ numpy.polynomial.legendre.legfromroots
+ numpy.polynomial.laguerre.lagfromroots
+ numpy.polynomial.hermite.hermfromroots
+ numpy.polynomial.chebyshev.chebfromroots
Examples
--------
sv -- singular values of the scaled Vandermonde matrix
rcond -- value of `rcond`.
- For more details, see `linalg.lstsq`.
+ For more details, see `numpy.linalg.lstsq`.
Warns
-----
See Also
--------
- chebfit, legfit, polyfit, hermfit, polyfit
+ numpy.polynomial.chebyshev.chebfit
+ numpy.polynomial.legendre.legfit
+ numpy.polynomial.polynomial.polyfit
+ numpy.polynomial.hermite.hermfit
+ numpy.polynomial.laguerre.lagfit
hermeval : Evaluates a Hermite series.
hermevander : pseudo Vandermonde matrix of Hermite series.
hermeweight : HermiteE weight function.
- linalg.lstsq : Computes a least-squares fit from the matrix.
+ numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
scipy.interpolate.UnivariateSpline : Computes spline fits.
Notes
See Also
--------
- polyroots, legroots, lagroots, hermroots, chebroots
+ numpy.polynomial.polynomial.polyroots
+ numpy.polynomial.legendre.legroots
+ numpy.polynomial.laguerre.lagroots
+ numpy.polynomial.hermite.hermroots
+ numpy.polynomial.chebyshev.chebroots
Notes
-----
_fromroots = staticmethod(hermefromroots)
# Virtual properties
- nickname = 'herme'
domain = np.array(hermedomain)
window = np.array(hermedomain)
basis_name = 'He'
"""
[pol] = pu.as_series([pol])
- deg = len(pol) - 1
res = 0
- for i in range(deg, -1, -1):
- res = lagadd(lagmulx(res), pol[i])
+ for p in pol[::-1]:
+ res = lagadd(lagmulx(res), p)
return res
"""
Laguerre series whose graph is a straight line.
-
-
Parameters
----------
off, scl : scalars
See Also
--------
- polyline, chebline
+ numpy.polynomial.polynomial.polyline
+ numpy.polynomial.chebyshev.chebline
+ numpy.polynomial.legendre.legline
+ numpy.polynomial.hermite.hermline
+ numpy.polynomial.hermite_e.hermeline
Examples
--------
See Also
--------
- polyfromroots, legfromroots, chebfromroots, hermfromroots, hermefromroots
+ numpy.polynomial.polynomial.polyfromroots
+ numpy.polynomial.legendre.legfromroots
+ numpy.polynomial.chebyshev.chebfromroots
+ numpy.polynomial.hermite.hermfromroots
+ numpy.polynomial.hermite_e.hermefromroots
Examples
--------
sv -- singular values of the scaled Vandermonde matrix
rcond -- value of `rcond`.
- For more details, see `linalg.lstsq`.
+ For more details, see `numpy.linalg.lstsq`.
Warns
-----
See Also
--------
- chebfit, legfit, polyfit, hermfit, hermefit
+ numpy.polynomial.polynomial.polyfit
+ numpy.polynomial.legendre.legfit
+ numpy.polynomial.chebyshev.chebfit
+ numpy.polynomial.hermite.hermfit
+ numpy.polynomial.hermite_e.hermefit
lagval : Evaluates a Laguerre series.
lagvander : pseudo Vandermonde matrix of Laguerre series.
lagweight : Laguerre weight function.
- linalg.lstsq : Computes a least-squares fit from the matrix.
+ numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
scipy.interpolate.UnivariateSpline : Computes spline fits.
Notes
See Also
--------
- polyroots, legroots, chebroots, hermroots, hermeroots
+ numpy.polynomial.polynomial.polyroots
+ numpy.polynomial.legendre.legroots
+ numpy.polynomial.chebyshev.chebroots
+ numpy.polynomial.hermite.hermroots
+ numpy.polynomial.hermite_e.hermeroots
Notes
-----
_fromroots = staticmethod(lagfromroots)
# Virtual properties
- nickname = 'lag'
domain = np.array(lagdomain)
window = np.array(lagdomain)
basis_name = 'L'
See Also
--------
- polyline, chebline
+ numpy.polynomial.polynomial.polyline
+ numpy.polynomial.chebyshev.chebline
+ numpy.polynomial.laguerre.lagline
+ numpy.polynomial.hermite.hermline
+ numpy.polynomial.hermite_e.hermeline
Examples
--------
See Also
--------
- polyfromroots, chebfromroots, lagfromroots, hermfromroots, hermefromroots
+ numpy.polynomial.polynomial.polyfromroots
+ numpy.polynomial.chebyshev.chebfromroots
+ numpy.polynomial.laguerre.lagfromroots
+ numpy.polynomial.hermite.hermfromroots
+ numpy.polynomial.hermite_e.hermefromroots
Examples
--------
sv -- singular values of the scaled Vandermonde matrix
rcond -- value of `rcond`.
- For more details, see `linalg.lstsq`.
+ For more details, see `numpy.linalg.lstsq`.
Warns
-----
See Also
--------
- chebfit, polyfit, lagfit, hermfit, hermefit
+ numpy.polynomial.polynomial.polyfit
+ numpy.polynomial.chebyshev.chebfit
+ numpy.polynomial.laguerre.lagfit
+ numpy.polynomial.hermite.hermfit
+ numpy.polynomial.hermite_e.hermefit
legval : Evaluates a Legendre series.
legvander : Vandermonde matrix of Legendre series.
legweight : Legendre weight function (= 1).
- linalg.lstsq : Computes a least-squares fit from the matrix.
+ numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
scipy.interpolate.UnivariateSpline : Computes spline fits.
Notes
See Also
--------
- polyroots, chebroots, lagroots, hermroots, hermeroots
+ numpy.polynomial.polynomial.polyroots
+ numpy.polynomial.chebyshev.chebroots
+ numpy.polynomial.laguerre.lagroots
+ numpy.polynomial.hermite.hermroots
+ numpy.polynomial.hermite_e.hermeroots
Notes
-----
_fromroots = staticmethod(legfromroots)
# Virtual properties
- nickname = 'leg'
domain = np.array(legdomain)
window = np.array(legdomain)
basis_name = 'P'
See Also
--------
- chebline
+ numpy.polynomial.chebyshev.chebline
+ numpy.polynomial.legendre.legline
+ numpy.polynomial.laguerre.lagline
+ numpy.polynomial.hermite.hermline
+ numpy.polynomial.hermite_e.hermeline
Examples
--------
See Also
--------
- chebfromroots, legfromroots, lagfromroots, hermfromroots
- hermefromroots
+ numpy.polynomial.chebyshev.chebfromroots
+ numpy.polynomial.legendre.legfromroots
+ numpy.polynomial.laguerre.lagfromroots
+ numpy.polynomial.hermite.hermfromroots
+ numpy.polynomial.hermite_e.hermefromroots
Notes
-----
sv -- singular values of the scaled Vandermonde matrix
rcond -- value of `rcond`.
- For more details, see `linalg.lstsq`.
+ For more details, see `numpy.linalg.lstsq`.
Raises
------
See Also
--------
- chebfit, legfit, lagfit, hermfit, hermefit
+ numpy.polynomial.chebyshev.chebfit
+ numpy.polynomial.legendre.legfit
+ numpy.polynomial.laguerre.lagfit
+ numpy.polynomial.hermite.hermfit
+ numpy.polynomial.hermite_e.hermefit
polyval : Evaluates a polynomial.
polyvander : Vandermonde matrix for powers.
- linalg.lstsq : Computes a least-squares fit from the matrix.
+ numpy.linalg.lstsq : Computes a least-squares fit from the matrix.
scipy.interpolate.UnivariateSpline : Computes spline fits.
Notes
See Also
--------
- chebroots
+ numpy.polynomial.chebyshev.chebroots
+ numpy.polynomial.legendre.legroots
+ numpy.polynomial.laguerre.lagroots
+ numpy.polynomial.hermite.hermroots
+ numpy.polynomial.hermite_e.hermeroots
Notes
-----
_fromroots = staticmethod(polyfromroots)
# Virtual properties
- nickname = 'poly'
domain = np.array(polydomain)
window = np.array(polydomain)
basis_name = None
+ @classmethod
+ def _str_term_unicode(cls, i, arg_str):
+ return f"·{arg_str}{i.translate(cls._superscript_mapping)}"
+
+ @staticmethod
+ def _str_term_ascii(i, arg_str):
+ return f" {arg_str}**{i}"
+
@staticmethod
def _repr_latex_term(i, arg_str, needs_parens):
if needs_parens:
arrays = [np.array(a, ndmin=1, copy=False) for a in alist]
if min([a.size for a in arrays]) == 0:
raise ValueError("Coefficient array is empty")
- if any([a.ndim != 1 for a in arrays]):
+ if any(a.ndim != 1 for a in arrays):
raise ValueError("Coefficient array is not 1-d")
if trim:
arrays = [trimseq(a) for a in arrays]
- if any([a.dtype == np.dtype(object) for a in arrays]):
+ if any(a.dtype == np.dtype(object) for a in arrays):
ret = []
for a in arrays:
if a.dtype != np.dtype(object):
from numpy.distutils.misc_util import Configuration
config = Configuration('polynomial', parent_package, top_path)
config.add_subpackage('tests')
+ config.add_data_files('*.pyi')
return config
if __name__ == '__main__':
+import pytest
+from numpy.core import array, arange, printoptions
import numpy.polynomial as poly
-from numpy.testing import assert_equal
+from numpy.testing import assert_equal, assert_
+# For testing polynomial printing with object arrays
+from fractions import Fraction
+from decimal import Decimal
-class TestStr:
- def test_polynomial_str(self):
- res = str(poly.Polynomial([0, 1]))
- tgt = 'poly([0. 1.])'
+
+class TestStrUnicodeSuperSubscripts:
+
+ @pytest.fixture(scope='class', autouse=True)
+ def use_unicode(self):
+ poly.set_default_printstyle('unicode')
+
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0·x¹ + 3.0·x²"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0·x¹ + 3.0·x² - 1.0·x³"),
+ (arange(12), ("0.0 + 1.0·x¹ + 2.0·x² + 3.0·x³ + 4.0·x⁴ + 5.0·x⁵ + "
+ "6.0·x⁶ + 7.0·x⁷ +\n8.0·x⁸ + 9.0·x⁹ + 10.0·x¹⁰ + "
+ "11.0·x¹¹")),
+ ))
+ def test_polynomial_str(self, inp, tgt):
+ res = str(poly.Polynomial(inp))
assert_equal(res, tgt)
- def test_chebyshev_str(self):
- res = str(poly.Chebyshev([0, 1]))
- tgt = 'cheb([0. 1.])'
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0·T₁(x) + 3.0·T₂(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0·T₁(x) + 3.0·T₂(x) - 1.0·T₃(x)"),
+ (arange(12), ("0.0 + 1.0·T₁(x) + 2.0·T₂(x) + 3.0·T₃(x) + 4.0·T₄(x) + "
+ "5.0·T₅(x) +\n6.0·T₆(x) + 7.0·T₇(x) + 8.0·T₈(x) + "
+ "9.0·T₉(x) + 10.0·T₁₀(x) + 11.0·T₁₁(x)")),
+ ))
+ def test_chebyshev_str(self, inp, tgt):
+ res = str(poly.Chebyshev(inp))
assert_equal(res, tgt)
- def test_legendre_str(self):
- res = str(poly.Legendre([0, 1]))
- tgt = 'leg([0. 1.])'
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0·P₁(x) + 3.0·P₂(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0·P₁(x) + 3.0·P₂(x) - 1.0·P₃(x)"),
+ (arange(12), ("0.0 + 1.0·P₁(x) + 2.0·P₂(x) + 3.0·P₃(x) + 4.0·P₄(x) + "
+ "5.0·P₅(x) +\n6.0·P₆(x) + 7.0·P₇(x) + 8.0·P₈(x) + "
+ "9.0·P₉(x) + 10.0·P₁₀(x) + 11.0·P₁₁(x)")),
+ ))
+ def test_legendre_str(self, inp, tgt):
+ res = str(poly.Legendre(inp))
assert_equal(res, tgt)
- def test_hermite_str(self):
- res = str(poly.Hermite([0, 1]))
- tgt = 'herm([0. 1.])'
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0·H₁(x) + 3.0·H₂(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0·H₁(x) + 3.0·H₂(x) - 1.0·H₃(x)"),
+ (arange(12), ("0.0 + 1.0·H₁(x) + 2.0·H₂(x) + 3.0·H₃(x) + 4.0·H₄(x) + "
+ "5.0·H₅(x) +\n6.0·H₆(x) + 7.0·H₇(x) + 8.0·H₈(x) + "
+ "9.0·H₉(x) + 10.0·H₁₀(x) + 11.0·H₁₁(x)")),
+ ))
+ def test_hermite_str(self, inp, tgt):
+ res = str(poly.Hermite(inp))
assert_equal(res, tgt)
- def test_hermiteE_str(self):
- res = str(poly.HermiteE([0, 1]))
- tgt = 'herme([0. 1.])'
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0·He₁(x) + 3.0·He₂(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0·He₁(x) + 3.0·He₂(x) - 1.0·He₃(x)"),
+ (arange(12), ("0.0 + 1.0·He₁(x) + 2.0·He₂(x) + 3.0·He₃(x) + "
+ "4.0·He₄(x) + 5.0·He₅(x) +\n6.0·He₆(x) + 7.0·He₇(x) + "
+ "8.0·He₈(x) + 9.0·He₉(x) + 10.0·He₁₀(x) +\n"
+ "11.0·He₁₁(x)")),
+ ))
+ def test_hermiteE_str(self, inp, tgt):
+ res = str(poly.HermiteE(inp))
assert_equal(res, tgt)
- def test_laguerre_str(self):
- res = str(poly.Laguerre([0, 1]))
- tgt = 'lag([0. 1.])'
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0·L₁(x) + 3.0·L₂(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0·L₁(x) + 3.0·L₂(x) - 1.0·L₃(x)"),
+ (arange(12), ("0.0 + 1.0·L₁(x) + 2.0·L₂(x) + 3.0·L₃(x) + 4.0·L₄(x) + "
+ "5.0·L₅(x) +\n6.0·L₆(x) + 7.0·L₇(x) + 8.0·L₈(x) + "
+ "9.0·L₉(x) + 10.0·L₁₀(x) + 11.0·L₁₁(x)")),
+ ))
+ def test_laguerre_str(self, inp, tgt):
+ res = str(poly.Laguerre(inp))
assert_equal(res, tgt)
+class TestStrAscii:
+
+ @pytest.fixture(scope='class', autouse=True)
+ def use_ascii(self):
+ poly.set_default_printstyle('ascii')
+
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0 x**1 + 3.0 x**2"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0 x**1 + 3.0 x**2 - 1.0 x**3"),
+ (arange(12), ("0.0 + 1.0 x**1 + 2.0 x**2 + 3.0 x**3 + 4.0 x**4 + "
+ "5.0 x**5 + 6.0 x**6 +\n7.0 x**7 + 8.0 x**8 + "
+ "9.0 x**9 + 10.0 x**10 + 11.0 x**11")),
+ ))
+ def test_polynomial_str(self, inp, tgt):
+ res = str(poly.Polynomial(inp))
+ assert_equal(res, tgt)
+
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0 T_1(x) + 3.0 T_2(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0 T_1(x) + 3.0 T_2(x) - 1.0 T_3(x)"),
+ (arange(12), ("0.0 + 1.0 T_1(x) + 2.0 T_2(x) + 3.0 T_3(x) + "
+ "4.0 T_4(x) + 5.0 T_5(x) +\n6.0 T_6(x) + 7.0 T_7(x) + "
+ "8.0 T_8(x) + 9.0 T_9(x) + 10.0 T_10(x) +\n"
+ "11.0 T_11(x)")),
+ ))
+ def test_chebyshev_str(self, inp, tgt):
+ res = str(poly.Chebyshev(inp))
+ assert_equal(res, tgt)
+
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0 P_1(x) + 3.0 P_2(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0 P_1(x) + 3.0 P_2(x) - 1.0 P_3(x)"),
+ (arange(12), ("0.0 + 1.0 P_1(x) + 2.0 P_2(x) + 3.0 P_3(x) + "
+ "4.0 P_4(x) + 5.0 P_5(x) +\n6.0 P_6(x) + 7.0 P_7(x) + "
+ "8.0 P_8(x) + 9.0 P_9(x) + 10.0 P_10(x) +\n"
+ "11.0 P_11(x)")),
+ ))
+ def test_legendre_str(self, inp, tgt):
+ res = str(poly.Legendre(inp))
+ assert_equal(res, tgt)
+
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0 H_1(x) + 3.0 H_2(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0 H_1(x) + 3.0 H_2(x) - 1.0 H_3(x)"),
+ (arange(12), ("0.0 + 1.0 H_1(x) + 2.0 H_2(x) + 3.0 H_3(x) + "
+ "4.0 H_4(x) + 5.0 H_5(x) +\n6.0 H_6(x) + 7.0 H_7(x) + "
+ "8.0 H_8(x) + 9.0 H_9(x) + 10.0 H_10(x) +\n"
+ "11.0 H_11(x)")),
+ ))
+ def test_hermite_str(self, inp, tgt):
+ res = str(poly.Hermite(inp))
+ assert_equal(res, tgt)
+
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0 He_1(x) + 3.0 He_2(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0 He_1(x) + 3.0 He_2(x) - 1.0 He_3(x)"),
+ (arange(12), ("0.0 + 1.0 He_1(x) + 2.0 He_2(x) + 3.0 He_3(x) + "
+ "4.0 He_4(x) +\n5.0 He_5(x) + 6.0 He_6(x) + "
+ "7.0 He_7(x) + 8.0 He_8(x) + 9.0 He_9(x) +\n"
+ "10.0 He_10(x) + 11.0 He_11(x)")),
+ ))
+ def test_hermiteE_str(self, inp, tgt):
+ res = str(poly.HermiteE(inp))
+ assert_equal(res, tgt)
+
+ @pytest.mark.parametrize(('inp', 'tgt'), (
+ ([1, 2, 3], "1.0 + 2.0 L_1(x) + 3.0 L_2(x)"),
+ ([-1, 0, 3, -1], "-1.0 + 0.0 L_1(x) + 3.0 L_2(x) - 1.0 L_3(x)"),
+ (arange(12), ("0.0 + 1.0 L_1(x) + 2.0 L_2(x) + 3.0 L_3(x) + "
+ "4.0 L_4(x) + 5.0 L_5(x) +\n6.0 L_6(x) + 7.0 L_7(x) + "
+ "8.0 L_8(x) + 9.0 L_9(x) + 10.0 L_10(x) +\n"
+ "11.0 L_11(x)")),
+ ))
+ def test_laguerre_str(self, inp, tgt):
+ res = str(poly.Laguerre(inp))
+ assert_equal(res, tgt)
+
+
+class TestLinebreaking:
+
+ @pytest.fixture(scope='class', autouse=True)
+ def use_ascii(self):
+ poly.set_default_printstyle('ascii')
+
+ def test_single_line_one_less(self):
+ # With 'ascii' style, len(str(p)) is default linewidth - 1 (i.e. 74)
+ p = poly.Polynomial([123456789, 123456789, 123456789, 1234, 1])
+ assert_equal(len(str(p)), 74)
+ assert_equal(str(p), (
+ '123456789.0 + 123456789.0 x**1 + 123456789.0 x**2 + '
+ '1234.0 x**3 + 1.0 x**4'
+ ))
+
+ def test_num_chars_is_linewidth(self):
+ # len(str(p)) == default linewidth == 75
+ p = poly.Polynomial([123456789, 123456789, 123456789, 1234, 10])
+ assert_equal(len(str(p)), 75)
+ assert_equal(str(p), (
+ '123456789.0 + 123456789.0 x**1 + 123456789.0 x**2 + '
+ '1234.0 x**3 +\n10.0 x**4'
+ ))
+
+ def test_first_linebreak_multiline_one_less_than_linewidth(self):
+ # Multiline str where len(first_line) + len(next_term) == lw - 1 == 74
+ p = poly.Polynomial(
+ [123456789, 123456789, 123456789, 12, 1, 123456789]
+ )
+ assert_equal(len(str(p).split('\n')[0]), 74)
+ assert_equal(str(p), (
+ '123456789.0 + 123456789.0 x**1 + 123456789.0 x**2 + '
+ '12.0 x**3 + 1.0 x**4 +\n123456789.0 x**5'
+ ))
+
+ def test_first_linebreak_multiline_on_linewidth(self):
+ # First line is one character longer than previous test
+ p = poly.Polynomial(
+ [123456789, 123456789, 123456789, 123, 1, 123456789]
+ )
+ assert_equal(str(p), (
+ '123456789.0 + 123456789.0 x**1 + 123456789.0 x**2 + '
+ '123.0 x**3 +\n1.0 x**4 + 123456789.0 x**5'
+ ))
+
+ @pytest.mark.parametrize(('lw', 'tgt'), (
+ (75, ('0.0 + 10.0 x**1 + 200.0 x**2 + 3000.0 x**3 + 40000.0 x**4 +\n'
+ '500000.0 x**5 + 600000.0 x**6 + 70000.0 x**7 + 8000.0 x**8 + '
+ '900.0 x**9')),
+ (45, ('0.0 + 10.0 x**1 + 200.0 x**2 + 3000.0 x**3 +\n40000.0 x**4 + '
+ '500000.0 x**5 +\n600000.0 x**6 + 70000.0 x**7 + 8000.0 x**8 +\n'
+ '900.0 x**9')),
+ (132, ('0.0 + 10.0 x**1 + 200.0 x**2 + 3000.0 x**3 + 40000.0 x**4 + '
+ '500000.0 x**5 + 600000.0 x**6 + 70000.0 x**7 + 8000.0 x**8 + '
+ '900.0 x**9')),
+ ))
+ def test_linewidth_printoption(self, lw, tgt):
+ p = poly.Polynomial(
+ [0, 10, 200, 3000, 40000, 500000, 600000, 70000, 8000, 900]
+ )
+ with printoptions(linewidth=lw):
+ assert_equal(str(p), tgt)
+ for line in str(p).split('\n'):
+ assert_(len(line) < lw)
+
+
+def test_set_default_printoptions():
+ p = poly.Polynomial([1, 2, 3])
+ c = poly.Chebyshev([1, 2, 3])
+ poly.set_default_printstyle('ascii')
+ assert_equal(str(p), "1.0 + 2.0 x**1 + 3.0 x**2")
+ assert_equal(str(c), "1.0 + 2.0 T_1(x) + 3.0 T_2(x)")
+ poly.set_default_printstyle('unicode')
+ assert_equal(str(p), "1.0 + 2.0·x¹ + 3.0·x²")
+ assert_equal(str(c), "1.0 + 2.0·T₁(x) + 3.0·T₂(x)")
+ with pytest.raises(ValueError):
+ poly.set_default_printstyle('invalid_input')
+
+
+def test_complex_coefficients():
+ """Test both numpy and built-in complex."""
+ coefs = [0+1j, 1+1j, -2+2j, 3+0j]
+ # numpy complex
+ p1 = poly.Polynomial(coefs)
+ # Python complex
+ p2 = poly.Polynomial(array(coefs, dtype=object))
+ poly.set_default_printstyle('unicode')
+ assert_equal(str(p1), "1j + (1+1j)·x¹ - (2-2j)·x² + (3+0j)·x³")
+ assert_equal(str(p2), "1j + (1+1j)·x¹ + (-2+2j)·x² + (3+0j)·x³")
+ poly.set_default_printstyle('ascii')
+ assert_equal(str(p1), "1j + (1+1j) x**1 - (2-2j) x**2 + (3+0j) x**3")
+ assert_equal(str(p2), "1j + (1+1j) x**1 + (-2+2j) x**2 + (3+0j) x**3")
+
+
+@pytest.mark.parametrize(('coefs', 'tgt'), (
+ (array([Fraction(1, 2), Fraction(3, 4)], dtype=object), (
+ "1/2 + 3/4·x¹"
+ )),
+ (array([1, 2, Fraction(5, 7)], dtype=object), (
+ "1 + 2·x¹ + 5/7·x²"
+ )),
+ (array([Decimal('1.00'), Decimal('2.2'), 3], dtype=object), (
+ "1.00 + 2.2·x¹ + 3·x²"
+ )),
+))
+def test_numeric_object_coefficients(coefs, tgt):
+ p = poly.Polynomial(coefs)
+ poly.set_default_printstyle('unicode')
+ assert_equal(str(p), tgt)
+
+
+@pytest.mark.parametrize(('coefs', 'tgt'), (
+ (array([1, 2, 'f'], dtype=object), '1 + 2·x¹ + f·x²'),
+ (array([1, 2, [3, 4]], dtype=object), '1 + 2·x¹ + [3, 4]·x²'),
+))
+def test_nonnumeric_object_coefficients(coefs, tgt):
+ """
+ Test coef fallback for object arrays of non-numeric coefficients.
+ """
+ p = poly.Polynomial(coefs)
+ poly.set_default_printstyle('unicode')
+ assert_equal(str(p), tgt)
+
+
+class TestFormat:
+ def test_format_unicode(self):
+ poly.set_default_printstyle('ascii')
+ p = poly.Polynomial([1, 2, 0, -1])
+ assert_equal(format(p, 'unicode'), "1.0 + 2.0·x¹ + 0.0·x² - 1.0·x³")
+
+ def test_format_ascii(self):
+ poly.set_default_printstyle('unicode')
+ p = poly.Polynomial([1, 2, 0, -1])
+ assert_equal(
+ format(p, 'ascii'), "1.0 + 2.0 x**1 + 0.0 x**2 - 1.0 x**3"
+ )
+
+ def test_empty_formatstr(self):
+ poly.set_default_printstyle('ascii')
+ p = poly.Polynomial([1, 2, 3])
+ assert_equal(format(p), "1.0 + 2.0 x**1 + 3.0 x**2")
+ assert_equal(f"{p}", "1.0 + 2.0 x**1 + 3.0 x**2")
+
+ def test_bad_formatstr(self):
+ p = poly.Polynomial([1, 2, 0, -1])
+ with pytest.raises(ValueError):
+ format(p, '.2f')
+
+
class TestRepr:
def test_polynomial_str(self):
res = repr(poly.Polynomial([0, 1]))
--- /dev/null
+from typing import Any
+
+beta: Any
+binomial: Any
+bytes: Any
+chisquare: Any
+choice: Any
+dirichlet: Any
+exponential: Any
+f: Any
+gamma: Any
+geometric: Any
+get_state: Any
+gumbel: Any
+hypergeometric: Any
+laplace: Any
+logistic: Any
+lognormal: Any
+logseries: Any
+multinomial: Any
+multivariate_normal: Any
+negative_binomial: Any
+noncentral_chisquare: Any
+noncentral_f: Any
+normal: Any
+pareto: Any
+permutation: Any
+poisson: Any
+power: Any
+rand: Any
+randint: Any
+randn: Any
+random: Any
+random_integers: Any
+random_sample: Any
+ranf: Any
+rayleigh: Any
+sample: Any
+seed: Any
+set_state: Any
+shuffle: Any
+standard_cauchy: Any
+standard_exponential: Any
+standard_gamma: Any
+standard_normal: Any
+standard_t: Any
+triangular: Any
+uniform: Any
+vonmises: Any
+wald: Any
+weibull: Any
+zipf: Any
+Generator: Any
+RandomState: Any
+SeedSequence: Any
+MT19937: Any
+Philox: Any
+PCG64: Any
+SFC64: Any
+default_rng: Any
+BitGenerator: Any
cdef validate_output_shape(iter_shape, np.ndarray output):
cdef np.npy_intp *shape
- cdef np.npy_intp ndim, i
+ cdef ndim, i
cdef bint error
dims = np.PyArray_DIMS(output)
ndim = np.PyArray_NDIM(output)
assert r1.shape == r2.shape
t1 = timeit(numbacall, number=1000)
-print('{:.2f} secs for {} PCG64 (Numba/PCG64) gaussian randoms'.format(t1, n))
+print(f'{t1:.2f} secs for {n} PCG64 (Numba/PCG64) gaussian randoms')
t2 = timeit(numpycall, number=1000)
-print('{:.2f} secs for {} PCG64 (NumPy/PCG64) gaussian randoms'.format(t2, n))
+print(f'{t2:.2f} secs for {n} PCG64 (NumPy/PCG64) gaussian randoms')
# example 2
#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3
import operator
import warnings
+from collections.abc import MutableSequence
from cpython.pycapsule cimport PyCapsule_IsValid, PyCapsule_GetPointer
from cpython cimport (Py_INCREF, PyFloat_AsDouble)
+from cpython.mem cimport PyMem_Malloc, PyMem_Free
cimport cython
import numpy as np
validate_output_shape
)
+cdef extern from "numpy/arrayobject.h":
+ int PyArray_ResolveWritebackIfCopy(np.ndarray)
+ object PyArray_FromArray(np.PyArrayObject *, np.PyArray_Descr *, int)
+
+ enum:
+ NPY_ARRAY_WRITEBACKIFCOPY
+
np.import_array()
cdef int64_t _safe_sum_nonneg_int64(size_t num_colors, int64_t *colors):
return sum
+cdef inline void _shuffle_raw_wrap(bitgen_t *bitgen, np.npy_intp n,
+ np.npy_intp first, np.npy_intp itemsize,
+ np.npy_intp stride,
+ char* data, char* buf) nogil:
+ # We trick gcc into providing a specialized implementation for
+ # the most common case, yielding a ~33% performance improvement.
+ # Note that apparently, only one branch can ever be specialized.
+ if itemsize == sizeof(np.npy_intp):
+ _shuffle_raw(bitgen, n, first, sizeof(np.npy_intp), stride, data, buf)
+ else:
+ _shuffle_raw(bitgen, n, first, itemsize, stride, data, buf)
+
+
+cdef inline void _shuffle_raw(bitgen_t *bitgen, np.npy_intp n,
+ np.npy_intp first, np.npy_intp itemsize,
+ np.npy_intp stride,
+ char* data, char* buf) nogil:
+ """
+ Parameters
+ ----------
+ bitgen
+ Pointer to a bitgen_t instance.
+ n
+ Number of elements in data
+ first
+ First observation to shuffle. Shuffles n-1,
+ n-2, ..., first, so that when first=1 the entire
+ array is shuffled
+ itemsize
+ Size in bytes of item
+ stride
+ Array stride
+ data
+ Location of data
+ buf
+ Location of buffer (itemsize)
+ """
+ cdef np.npy_intp i, j
+
+ for i in reversed(range(first, n)):
+ j = random_interval(bitgen, i)
+ string.memcpy(buf, data + j * stride, itemsize)
+ string.memcpy(data + j * stride, data + i * stride, itemsize)
+ string.memcpy(data + i * stride, buf, itemsize)
+
+
+cdef inline void _shuffle_int(bitgen_t *bitgen, np.npy_intp n,
+ np.npy_intp first, int64_t* data) nogil:
+ """
+ Parameters
+ ----------
+ bitgen
+ Pointer to a bitgen_t instance.
+ n
+ Number of elements in data
+ first
+ First observation to shuffle. Shuffles n-1,
+ n-2, ..., first, so that when first=1 the entire
+ array is shuffled
+ data
+ Location of data
+ """
+ cdef np.npy_intp i, j
+ cdef int64_t temp
+ for i in reversed(range(first, n)):
+ j = random_bounded_uint64(bitgen, 0, i, 0, 0)
+ temp = data[j]
+ data[j] = data[i]
+ data[i] = temp
+
+
cdef bint _check_bit_generator(object bitgen):
"""Check if an object satisfies the BitGenerator interface.
"""
if abs(p_sum - 1.) > atol:
raise ValueError("probabilities do not sum to 1")
- shape = size
- if shape is not None:
+ # `shape == None` means `shape == ()`, but with scalar unpacking at the
+ # end
+ is_scalar = size is None
+ if not is_scalar:
+ shape = size
size = np.prod(shape, dtype=np.intp)
else:
+ shape = ()
size = 1
# Actual sampling
idx = np.PyArray_Arange(0, pop_size_i, 1, np.NPY_INT64)
idx_data = <int64_t*>(<np.ndarray>idx).data
with self.lock, nogil:
- self._shuffle_int(pop_size_i, max(pop_size_i - size_i, 1),
- idx_data)
+ _shuffle_int(&self._bitgen, pop_size_i,
+ max(pop_size_i - size_i, 1), idx_data)
# Copy to allow potentially large array backing idx to be gc
idx = idx[(pop_size - size):].copy()
else:
hash_set[loc] = j
idx_data[j - pop_size_i + size_i] = j
if shuffle:
- self._shuffle_int(size_i, 1, idx_data)
- if shape is not None:
- idx.shape = shape
+ _shuffle_int(&self._bitgen, size_i, 1, idx_data)
+ idx.shape = shape
- if shape is None and isinstance(idx, np.ndarray):
+ if is_scalar and isinstance(idx, np.ndarray):
# In most cases a scalar will have been made an array
idx = idx.item(0)
if a.ndim == 0:
return idx
- if shape is not None and idx.ndim == 0:
+ if not is_scalar and idx.ndim == 0:
# If size == () then the user requested a 0-d array as opposed to
# a scalar object when size is None. However a[idx] is always a
# scalar and not an array. So this makes sure the result is an
generate zero positive results.
>>> sum(rng.binomial(9, 0.1, 20000) == 0)/20000.
- # answer = 0.38885, or 38%.
+ # answer = 0.38885, or 39%.
"""
def multivariate_normal(self, mean, cov, size=None, check_valid='warn',
tol=1e-8, *, method='svd'):
"""
- multivariate_normal(mean, cov, size=None, check_valid='warn', tol=1e-8)
+ multivariate_normal(mean, cov, size=None, check_valid='warn',
+ tol=1e-8, *, method='svd')
Draw random samples from a multivariate normal distribution.
# GH10839, ensure double to make tol meaningful
cov = cov.astype(np.double)
if method == 'svd':
- from numpy.dual import svd
+ from numpy.linalg import svd
(u, s, vh) = svd(cov)
elif method == 'eigh':
- from numpy.dual import eigh
+ from numpy.linalg import eigh
# could call linalg.svd(hermitian=True), but that calculates a vh we don't need
(s, u) = eigh(cov)
else:
- from numpy.dual import cholesky
+ from numpy.linalg import cholesky
l = cholesky(cov)
# make sure check_valid is ignored whe method == 'cholesky'
return diric
- # Shuffling and permutations:
+ def permuted(self, object x, *, axis=None, out=None):
+ """
+ permuted(x, axis=None, out=None)
+
+ Randomly permute `x` along axis `axis`.
+
+ Unlike `shuffle`, each slice along the given axis is shuffled
+ independently of the others.
+
+ Parameters
+ ----------
+ x : array_like, at least one-dimensional
+ Array to be shuffled.
+ axis : int, optional
+ Slices of `x` in this axis are shuffled. Each slice
+ is shuffled independently of the others. If `axis` is
+ None, the flattened array is shuffled.
+ out : ndarray, optional
+ If given, this is the destinaton of the shuffled array.
+ If `out` is None, a shuffled copy of the array is returned.
+
+ Returns
+ -------
+ ndarray
+ If `out` is None, a shuffled copy of `x` is returned.
+ Otherwise, the shuffled array is stored in `out`,
+ and `out` is returned
+
+ See Also
+ --------
+ shuffle
+ permutation
+
+ Examples
+ --------
+ Create a `numpy.random.Generator` instance:
+
+ >>> rng = np.random.default_rng()
+
+ Create a test array:
+
+ >>> x = np.arange(24).reshape(3, 8)
+ >>> x
+ array([[ 0, 1, 2, 3, 4, 5, 6, 7],
+ [ 8, 9, 10, 11, 12, 13, 14, 15],
+ [16, 17, 18, 19, 20, 21, 22, 23]])
+
+ Shuffle the rows of `x`:
+
+ >>> y = rng.permuted(x, axis=1)
+ >>> y
+ array([[ 4, 3, 6, 7, 1, 2, 5, 0], # random
+ [15, 10, 14, 9, 12, 11, 8, 13],
+ [17, 16, 20, 21, 18, 22, 23, 19]])
+
+ `x` has not been modified:
+
+ >>> x
+ array([[ 0, 1, 2, 3, 4, 5, 6, 7],
+ [ 8, 9, 10, 11, 12, 13, 14, 15],
+ [16, 17, 18, 19, 20, 21, 22, 23]])
+
+ To shuffle the rows of `x` in-place, pass `x` as the `out`
+ parameter:
+
+ >>> y = rng.permuted(x, axis=1, out=x)
+ >>> x
+ array([[ 3, 0, 4, 7, 1, 6, 2, 5], # random
+ [ 8, 14, 13, 9, 12, 11, 15, 10],
+ [17, 18, 16, 22, 19, 23, 20, 21]])
+
+ Note that when the ``out`` parameter is given, the return
+ value is ``out``:
+
+ >>> y is x
+ True
+ """
+
+ cdef int ax
+ cdef np.npy_intp axlen, axstride, itemsize
+ cdef void *buf
+ cdef np.flatiter it
+ cdef np.ndarray to_shuffle
+ cdef int status
+ cdef int flags
+
+ x = np.asarray(x)
+
+ if out is None:
+ out = x.copy(order='K')
+ else:
+ if type(out) is not np.ndarray:
+ raise TypeError('out must be a numpy array')
+ if out.shape != x.shape:
+ raise ValueError('out must have the same shape as x')
+ np.copyto(out, x, casting='safe')
+
+ if axis is None:
+ if x.ndim > 1:
+ if not (np.PyArray_FLAGS(out) & (np.NPY_ARRAY_C_CONTIGUOUS |
+ np.NPY_ARRAY_F_CONTIGUOUS)):
+ flags = (np.NPY_ARRAY_C_CONTIGUOUS |
+ NPY_ARRAY_WRITEBACKIFCOPY)
+ to_shuffle = PyArray_FromArray(<np.PyArrayObject *>out,
+ <np.PyArray_Descr *>NULL, flags)
+ self.shuffle(to_shuffle.ravel(order='K'))
+ # Because we only execute this block if out is not
+ # contiguous, we know this call will always result in a
+ # copy of to_shuffle back to out. I.e. status will be 1.
+ status = PyArray_ResolveWritebackIfCopy(to_shuffle)
+ assert status == 1
+ else:
+ # out is n-d with n > 1, but is either C- or F-contiguous,
+ # so we know out.ravel(order='A') is a view.
+ self.shuffle(out.ravel(order='A'))
+ else:
+ # out is 1-d
+ self.shuffle(out)
+ return out
+
+ ax = normalize_axis_index(axis, np.ndim(out))
+ itemsize = out.itemsize
+ axlen = out.shape[ax]
+ axstride = out.strides[ax]
+
+ it = np.PyArray_IterAllButAxis(out, &ax)
+
+ buf = PyMem_Malloc(itemsize)
+ if buf == NULL:
+ raise MemoryError('memory allocation failed in permuted')
+
+ if out.dtype.hasobject:
+ # Keep the GIL when shuffling an object array.
+ with self.lock:
+ while np.PyArray_ITER_NOTDONE(it):
+ _shuffle_raw_wrap(&self._bitgen, axlen, 0, itemsize,
+ axstride,
+ <char *>np.PyArray_ITER_DATA(it),
+ <char *>buf)
+ np.PyArray_ITER_NEXT(it)
+ else:
+ # out is not an object array, so we can release the GIL.
+ with self.lock, nogil:
+ while np.PyArray_ITER_NOTDONE(it):
+ _shuffle_raw_wrap(&self._bitgen, axlen, 0, itemsize,
+ axstride,
+ <char *>np.PyArray_ITER_DATA(it),
+ <char *>buf)
+ np.PyArray_ITER_NEXT(it)
+
+ PyMem_Free(buf)
+ return out
+
def shuffle(self, object x, axis=0):
"""
shuffle(x, axis=0)
- Modify a sequence in-place by shuffling its contents.
+ Modify an array or sequence in-place by shuffling its contents.
The order of sub-arrays is changed but their contents remains the same.
Parameters
----------
- x : array_like
- The array or list to be shuffled.
+ x : ndarray or MutableSequence
+ The array, list or mutable sequence to be shuffled.
axis : int, optional
The axis which `x` is shuffled along. Default is 0.
It is only supported on `ndarray` objects.
# when the function exits.
buf = np.empty(itemsize, dtype=np.int8) # GC'd at function exit
buf_ptr = <char*><size_t>np.PyArray_DATA(buf)
- with self.lock:
- # We trick gcc into providing a specialized implementation for
- # the most common case, yielding a ~33% performance improvement.
- # Note that apparently, only one branch can ever be specialized.
- if itemsize == sizeof(np.npy_intp):
- self._shuffle_raw(n, 1, sizeof(np.npy_intp), stride, x_ptr, buf_ptr)
- else:
- self._shuffle_raw(n, 1, itemsize, stride, x_ptr, buf_ptr)
- elif isinstance(x, np.ndarray) and x.ndim and x.size:
+ if x.dtype.hasobject:
+ with self.lock:
+ _shuffle_raw_wrap(&self._bitgen, n, 1, itemsize, stride,
+ x_ptr, buf_ptr)
+ else:
+ # Same as above, but the GIL is released.
+ with self.lock, nogil:
+ _shuffle_raw_wrap(&self._bitgen, n, 1, itemsize, stride,
+ x_ptr, buf_ptr)
+ elif isinstance(x, np.ndarray):
+ if x.size == 0:
+ # shuffling is a no-op
+ return
+
x = np.swapaxes(x, 0, axis)
buf = np.empty_like(x[0, ...])
with self.lock:
x[i] = buf
else:
# Untyped path.
+ if not isinstance(x, MutableSequence):
+ # See gh-18206. We may decide to deprecate here in the future.
+ warnings.warn(
+ "`x` isn't a recognized object; `shuffle` is not guaranteed "
+ "to behave correctly. E.g., non-numpy array/tensor objects "
+ "with view semantics may contain duplicates after shuffling.",
+ UserWarning, stacklevel=2
+ )
+
if axis != 0:
raise NotImplementedError("Axis argument is only supported "
"on ndarray objects")
j = random_interval(&self._bitgen, i)
x[i], x[j] = x[j], x[i]
- cdef inline _shuffle_raw(self, np.npy_intp n, np.npy_intp first,
- np.npy_intp itemsize, np.npy_intp stride,
- char* data, char* buf):
- """
- Parameters
- ----------
- n
- Number of elements in data
- first
- First observation to shuffle. Shuffles n-1,
- n-2, ..., first, so that when first=1 the entire
- array is shuffled
- itemsize
- Size in bytes of item
- stride
- Array stride
- data
- Location of data
- buf
- Location of buffer (itemsize)
- """
- cdef np.npy_intp i, j
- for i in reversed(range(first, n)):
- j = random_interval(&self._bitgen, i)
- string.memcpy(buf, data + j * stride, itemsize)
- string.memcpy(data + j * stride, data + i * stride, itemsize)
- string.memcpy(data + i * stride, buf, itemsize)
-
- cdef inline void _shuffle_int(self, np.npy_intp n, np.npy_intp first,
- int64_t* data) nogil:
- """
- Parameters
- ----------
- n
- Number of elements in data
- first
- First observation to shuffle. Shuffles n-1,
- n-2, ..., first, so that when first=1 the entire
- array is shuffled
- data
- Location of data
- """
- cdef np.npy_intp i, j
- cdef int64_t temp
- for i in reversed(range(first, n)):
- j = random_bounded_uint64(&self._bitgen, 0, i, 0, 0)
- temp = data[j]
- data[j] = data[i]
- data[i] = temp
-
def permutation(self, object x, axis=0):
"""
permutation(x, axis=0)
unpredictable entropy will be pulled from the OS. If an ``int`` or
``array_like[ints]`` is passed, then it will be passed to
`SeedSequence` to derive the initial `BitGenerator` state. One may also
- pass in a`SeedSequence` instance
+ pass in a `SeedSequence` instance.
Additionally, when passed a `BitGenerator`, it will be wrapped by
`Generator`. If passed a `Generator`, it will be returned unaltered.
-----
If ``seed`` is not a `BitGenerator` or a `Generator`, a new `BitGenerator`
is instantiated. This function does not manage a default global instance.
+
+ Examples
+ --------
+ ``default_rng`` is the reccomended constructor for the random number class
+ ``Generator``. Here are several ways we can construct a random
+ number generator using ``default_rng`` and the ``Generator`` class.
+
+ Here we use ``default_rng`` to generate a random float:
+
+ >>> import numpy as np
+ >>> rng = np.random.default_rng(12345)
+ >>> print(rng)
+ Generator(PCG64)
+ >>> rfloat = rng.random()
+ >>> rfloat
+ 0.22733602246716966
+ >>> type(rfloat)
+ <class 'float'>
+
+ Here we use ``default_rng`` to generate 3 random integers between 0
+ (inclusive) and 10 (exclusive):
+
+ >>> import numpy as np
+ >>> rng = np.random.default_rng(12345)
+ >>> rints = rng.integers(low=0, high=10, size=3)
+ >>> rints
+ array([6, 2, 7])
+ >>> type(rints[0])
+ <class 'numpy.int64'>
+
+ Here we specify a seed so that we have reproducible results:
+
+ >>> import numpy as np
+ >>> rng = np.random.default_rng(seed=42)
+ >>> print(rng)
+ Generator(PCG64)
+ >>> arr1 = rng.random((3, 3))
+ >>> arr1
+ array([[0.77395605, 0.43887844, 0.85859792],
+ [0.69736803, 0.09417735, 0.97562235],
+ [0.7611397 , 0.78606431, 0.12811363]])
+
+ If we exit and restart our Python interpreter, we'll see that we
+ generate the same random numbers again:
+
+ >>> import numpy as np
+ >>> rng = np.random.default_rng(seed=42)
+ >>> arr2 = rng.random((3, 3))
+ >>> arr2
+ array([[0.77395605, 0.43887844, 0.85859792],
+ [0.69736803, 0.09417735, 0.97562235],
+ [0.7611397 , 0.78606431, 0.12811363]])
+
"""
if _check_bit_generator(seed):
# We were passed a BitGenerator, so just wrap it up.
cdef class SeedSequence():
cdef readonly object entropy
cdef readonly tuple spawn_key
- cdef readonly uint32_t pool_size
+ cdef readonly Py_ssize_t pool_size
cdef readonly object pool
cdef readonly uint32_t n_children_spawned
lock.
See Also
- -------
+ --------
SeedSequence
"""
#cython: wraparound=False, nonecheck=False, boundscheck=False, cdivision=True, language_level=3
import operator
import warnings
+from collections.abc import MutableSequence
import numpy as np
if abs(p_sum - 1.) > atol:
raise ValueError("probabilities do not sum to 1")
- shape = size
- if shape is not None:
+ # `shape == None` means `shape == ()`, but with scalar unpacking at the
+ # end
+ is_scalar = size is None
+ if not is_scalar:
+ shape = size
size = np.prod(shape, dtype=np.intp)
else:
+ shape = ()
size = 1
# Actual sampling
idx = found
else:
idx = self.permutation(pop_size)[:size]
- if shape is not None:
- idx.shape = shape
+ idx.shape = shape
- if shape is None and isinstance(idx, np.ndarray):
+ if is_scalar and isinstance(idx, np.ndarray):
# In most cases a scalar will have been made an array
idx = idx.item(0)
if a.ndim == 0:
return idx
- if shape is not None and idx.ndim == 0:
+ if not is_scalar and idx.ndim == 0:
# If size == () then the user requested a 0-d array as opposed to
# a scalar object when size is None. However a[idx] is always a
# scalar and not an array. So this makes sure the result is an
[True, True] # random
"""
- from numpy.dual import svd
+ from numpy.linalg import svd
# Check preconditions on arguments
mean = np.array(mean)
Parameters
----------
- x : array_like
- The array or list to be shuffled.
+ x : ndarray or MutableSequence
+ The array, list or mutable sequence to be shuffled.
Returns
-------
self._shuffle_raw(n, sizeof(np.npy_intp), stride, x_ptr, buf_ptr)
else:
self._shuffle_raw(n, itemsize, stride, x_ptr, buf_ptr)
- elif isinstance(x, np.ndarray) and x.ndim and x.size:
+ elif isinstance(x, np.ndarray):
+ if x.size == 0:
+ # shuffling is a no-op
+ return
+
buf = np.empty_like(x[0, ...])
with self.lock:
for i in reversed(range(1, n)):
x[i] = buf
else:
# Untyped path.
+ if not isinstance(x, MutableSequence):
+ # See gh-18206. We may decide to deprecate here in the future.
+ warnings.warn(
+ "`x` isn't a recognized object; `shuffle` is not guaranteed "
+ "to behave correctly. E.g., non-numpy array/tensor objects "
+ "with view semantics may contain duplicates after shuffling.",
+ UserWarning, stacklevel=2
+ )
+
with self.lock:
for i in reversed(range(1, n)):
j = random_interval(&self._bitgen, i)
define_macros=defs + LEGACY_DEFS,
)
config.add_data_files(*depends)
+ config.add_data_files('*.pyi')
return config
/* Random generators for external use */
float random_standard_uniform_f(bitgen_t *bitgen_state) {
- return next_float(bitgen_state);
+ return next_float(bitgen_state);
}
double random_standard_uniform(bitgen_t *bitgen_state) {
* using logfactorial(k) instead.
*/
double random_loggam(double x) {
- double x0, x2, xp, gl, gl0;
+ double x0, x2, lg2pi, gl, gl0;
RAND_INT_TYPE k, n;
static double a[10] = {8.333333333333333e-02, -2.777777777777778e-03,
8.417508417508418e-04, -1.917526917526918e-03,
6.410256410256410e-03, -2.955065359477124e-02,
1.796443723688307e-01, -1.39243221690590e+00};
- x0 = x;
- n = 0;
+
if ((x == 1.0) || (x == 2.0)) {
return 0.0;
- } else if (x <= 7.0) {
+ } else if (x < 7.0) {
n = (RAND_INT_TYPE)(7 - x);
- x0 = x + n;
+ } else {
+ n = 0;
}
- x2 = 1.0 / (x0 * x0);
- xp = 2 * M_PI;
+ x0 = x + n;
+ x2 = (1.0 / x0) * (1.0 / x0);
+ /* log(2 * M_PI) */
+ lg2pi = 1.8378770664093453e+00;
gl0 = a[9];
for (k = 8; k >= 0; k--) {
gl0 *= x2;
gl0 += a[k];
}
- gl = gl0 / x0 + 0.5 * log(xp) + (x0 - 0.5) * log(x0) - x0;
- if (x <= 7.0) {
+ gl = gl0 / x0 + 0.5 * lg2pi + (x0 - 0.5) * log(x0) - x0;
+ if (x < 7.0) {
for (k = 1; k <= n; k++) {
gl -= log(x0 - 1.0);
x0 -= 1.0;
def test_repr(self):
rs = Generator(self.bit_generator(*self.data1['seed']))
assert 'Generator' in repr(rs)
- assert '{:#x}'.format(id(rs)).upper().replace('X', 'x') in repr(rs)
+ assert f'{id(rs):#x}'.upper().replace('X', 'x') in repr(rs)
def test_str(self):
rs = Generator(self.bit_generator(*self.data1['seed']))
assert 'Generator' in str(rs)
assert str(self.bit_generator.__name__) in str(rs)
- assert '{:#x}'.format(id(rs)).upper().replace('X', 'x') not in str(rs)
+ assert f'{id(rs):#x}'.upper().replace('X', 'x') not in str(rs)
def test_pickle(self):
import pickle
# too old or wrong cython, skip the test
cython = None
-
@pytest.mark.skipif(cython is None, reason="requires cython")
@pytest.mark.slow
def test_cython(tmp_path):
{
"seed": 0,
"steps": 10,
- "initial": {"key_md5": "64eaf265d2203179fb5ffb73380cd589", "pos": 9},
- "jumped": {"key_md5": "8cb7b061136efceef5217a9ce2cc9a5a", "pos": 598},
+ "initial": {"key_sha256": "bb1636883c2707b51c5b7fc26c6927af4430f2e0785a8c7bc886337f919f9edf", "pos": 9},
+ "jumped": {"key_sha256": "ff682ac12bb140f2d72fba8d3506cf4e46817a0db27aae1683867629031d8d55", "pos": 598},
},
{
"seed":384908324,
"steps":312,
- "initial": {"key_md5": "e99708a47b82ff51a2c7b0625b81afb5", "pos": 311},
- "jumped": {"key_md5": "2ecdbfc47a895b253e6e19ccb2e74b90", "pos": 276},
+ "initial": {"key_sha256": "16b791a1e04886ccbbb4d448d6ff791267dc458ae599475d08d5cced29d11614", "pos": 311},
+ "jumped": {"key_sha256": "a0110a2cf23b56be0feaed8f787a7fc84bef0cb5623003d75b26bdfa1c18002c", "pos": 276},
},
{
"seed": [839438204, 980239840, 859048019, 821],
"steps": 511,
- "initial": {"key_md5": "9fcd6280df9199785e17e93162ce283c", "pos": 510},
- "jumped": {"key_md5": "433b85229f2ed853cde06cd872818305", "pos": 475},
+ "initial": {"key_sha256": "d306cf01314d51bd37892d874308200951a35265ede54d200f1e065004c3e9ea", "pos": 510},
+ "jumped": {"key_sha256": "0e00ab449f01a5195a83b4aee0dfbc2ce8d46466a640b92e33977d2e42f777f8", "pos": 475},
},
]
assert_array_equal(scalar, array)
def test_repeatability(self, endpoint):
- # We use a md5 hash of generated sequences of 1000 samples
+ # We use a sha256 hash of generated sequences of 1000 samples
# in the range [0, 6) for all but bool, where the range
# is [0, 2). Hashes are for little endian numbers.
- tgt = {'bool': 'b3300e66d2bb59e493d255d47c3a6cbe',
- 'int16': '39624ead49ad67e37545744024d2648b',
- 'int32': '5c4810373f979336c6c0c999996e47a1',
- 'int64': 'ab126c15edff26f55c50d2b7e37391ac',
- 'int8': 'ba71ccaffeeeb9eeb1860f8075020b9c',
- 'uint16': '39624ead49ad67e37545744024d2648b',
- 'uint32': '5c4810373f979336c6c0c999996e47a1',
- 'uint64': 'ab126c15edff26f55c50d2b7e37391ac',
- 'uint8': 'ba71ccaffeeeb9eeb1860f8075020b9c'}
+ tgt = {'bool': '053594a9b82d656f967c54869bc6970aa0358cf94ad469c81478459c6a90eee3',
+ 'int16': '54de9072b6ee9ff7f20b58329556a46a447a8a29d67db51201bf88baa6e4e5d4',
+ 'int32': 'd3a0d5efb04542b25ac712e50d21f39ac30f312a5052e9bbb1ad3baa791ac84b',
+ 'int64': '14e224389ac4580bfbdccb5697d6190b496f91227cf67df60989de3d546389b1',
+ 'int8': '0e203226ff3fbbd1580f15da4621e5f7164d0d8d6b51696dd42d004ece2cbec1',
+ 'uint16': '54de9072b6ee9ff7f20b58329556a46a447a8a29d67db51201bf88baa6e4e5d4',
+ 'uint32': 'd3a0d5efb04542b25ac712e50d21f39ac30f312a5052e9bbb1ad3baa791ac84b',
+ 'uint64': '14e224389ac4580bfbdccb5697d6190b496f91227cf67df60989de3d546389b1',
+ 'uint8': '0e203226ff3fbbd1580f15da4621e5f7164d0d8d6b51696dd42d004ece2cbec1'}
for dt in self.itype[1:]:
random = Generator(MT19937(1234))
val = random.integers(0, 6 - endpoint, size=1000, endpoint=endpoint,
dtype=dt).byteswap()
- res = hashlib.md5(val).hexdigest()
+ res = hashlib.sha256(val).hexdigest()
assert_(tgt[np.dtype(dt).name] == res)
# bools do not depend on endianness
random = Generator(MT19937(1234))
val = random.integers(0, 2 - endpoint, size=1000, endpoint=endpoint,
dtype=bool).view(np.int8)
- res = hashlib.md5(val).hexdigest()
+ res = hashlib.sha256(val).hexdigest()
assert_(tgt[np.dtype(bool).name] == res)
def test_repeatability_broadcasting(self, endpoint):
assert actual.dtype == np.int64
def test_choice_large_sample(self):
- choice_hash = 'd44962a0b1e92f4a3373c23222244e21'
+ choice_hash = '4266599d12bfcfb815213303432341c06b4349f5455890446578877bb322e222'
random = Generator(MT19937(self.seed))
actual = random.choice(10000, 5000, replace=False)
if sys.byteorder != 'little':
actual = actual.byteswap()
- res = hashlib.md5(actual.view(np.int8)).hexdigest()
+ res = hashlib.sha256(actual.view(np.int8)).hexdigest()
assert_(choice_hash == res)
def test_bytes(self):
random.shuffle(actual, axis=-1)
assert_array_equal(actual, desired)
+ def test_shuffle_custom_axis_empty(self):
+ random = Generator(MT19937(self.seed))
+ desired = np.array([]).reshape((0, 6))
+ for axis in (0, 1):
+ actual = np.array([]).reshape((0, 6))
+ random.shuffle(actual, axis=axis)
+ assert_array_equal(actual, desired)
+
def test_shuffle_axis_nonsquare(self):
y1 = np.arange(20).reshape(2, 10)
y2 = y1.copy()
arr = [[1, 2, 3], [4, 5, 6]]
assert_raises(NotImplementedError, random.shuffle, arr, 1)
+ arr = np.array(3)
+ assert_raises(TypeError, random.shuffle, arr)
+ arr = np.ones((3, 2))
+ assert_raises(np.AxisError, random.shuffle, arr, 2)
+
def test_permutation(self):
random = Generator(MT19937(self.seed))
alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
arr_2d = np.atleast_2d([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]).T
actual = random.permutation(arr_2d)
assert_array_equal(actual, np.atleast_2d(desired).T)
-
+
bad_x_str = "abcd"
assert_raises(np.AxisError, random.permutation, bad_x_str)
assert_raises(np.AxisError, random.permutation, arr, 3)
assert_raises(TypeError, random.permutation, arr, slice(1, 2, None))
+ @pytest.mark.parametrize("dtype", [int, object])
+ @pytest.mark.parametrize("axis, expected",
+ [(None, np.array([[3, 7, 0, 9, 10, 11],
+ [8, 4, 2, 5, 1, 6]])),
+ (0, np.array([[6, 1, 2, 9, 10, 11],
+ [0, 7, 8, 3, 4, 5]])),
+ (1, np.array([[ 5, 3, 4, 0, 2, 1],
+ [11, 9, 10, 6, 8, 7]]))])
+ def test_permuted(self, dtype, axis, expected):
+ random = Generator(MT19937(self.seed))
+ x = np.arange(12).reshape(2, 6).astype(dtype)
+ random.permuted(x, axis=axis, out=x)
+ assert_array_equal(x, expected)
+
+ random = Generator(MT19937(self.seed))
+ x = np.arange(12).reshape(2, 6).astype(dtype)
+ y = random.permuted(x, axis=axis)
+ assert y.dtype == dtype
+ assert_array_equal(y, expected)
+
+ def test_permuted_with_strides(self):
+ random = Generator(MT19937(self.seed))
+ x0 = np.arange(22).reshape(2, 11)
+ x1 = x0.copy()
+ x = x0[:, ::3]
+ y = random.permuted(x, axis=1, out=x)
+ expected = np.array([[0, 9, 3, 6],
+ [14, 20, 11, 17]])
+ assert_array_equal(y, expected)
+ x1[:, ::3] = expected
+ # Verify that the original x0 was modified in-place as expected.
+ assert_array_equal(x1, x0)
+
+ def test_permuted_empty(self):
+ y = random.permuted([])
+ assert_array_equal(y, [])
+
+ @pytest.mark.parametrize('outshape', [(2, 3), 5])
+ def test_permuted_out_with_wrong_shape(self, outshape):
+ a = np.array([1, 2, 3])
+ out = np.zeros(outshape, dtype=a.dtype)
+ with pytest.raises(ValueError, match='same shape'):
+ random.permuted(a, out=out)
+
+ def test_permuted_out_with_wrong_type(self):
+ out = np.zeros((3, 5), dtype=np.int32)
+ x = np.ones((3, 5))
+ with pytest.raises(TypeError, match='Cannot cast'):
+ random.permuted(x, axis=1, out=out)
+
def test_beta(self):
random = Generator(MT19937(self.seed))
actual = random.beta(.1, .9, size=(3, 2))
@pytest.mark.parametrize("config", JUMP_TEST_DATA)
def test_jumped(config):
# Each config contains the initial seed, a number of raw steps
- # the md5 hashes of the initial and the final states' keys and
+ # the sha256 hashes of the initial and the final states' keys and
# the position of of the initial and the final state.
# These were produced using the original C implementation.
seed = config["seed"]
key = mt19937.state["state"]["key"]
if sys.byteorder == 'big':
key = key.byteswap()
- md5 = hashlib.md5(key)
+ sha256 = hashlib.sha256(key)
assert mt19937.state["state"]["pos"] == config["initial"]["pos"]
- assert md5.hexdigest() == config["initial"]["key_md5"]
+ assert sha256.hexdigest() == config["initial"]["key_sha256"]
jumped = mt19937.jumped()
key = jumped.state["state"]["key"]
if sys.byteorder == 'big':
key = key.byteswap()
- md5 = hashlib.md5(key)
+ sha256 = hashlib.sha256(key)
assert jumped.state["state"]["pos"] == config["jumped"]["pos"]
- assert md5.hexdigest() == config["jumped"]["key_md5"]
+ assert sha256.hexdigest() == config["jumped"]["key_sha256"]
def test_broadcast_size_error():
# numbers with this large sample
# theoretical large N result is 0.49706795
freq = np.sum(rvsn == 1) / float(N)
- msg = "Frequency was %f, should be > 0.45" % freq
+ msg = f'Frequency was {freq:f}, should be > 0.45'
assert_(freq > 0.45, msg)
# theoretical large N result is 0.19882718
freq = np.sum(rvsn == 2) / float(N)
- msg = "Frequency was %f, should be < 0.23" % freq
+ msg = f'Frequency was {freq:f}, should be < 0.23'
assert_(freq < 0.23, msg)
def test_shuffle_mixed_dimension(self):
def test_repeatability(self):
import hashlib
- # We use a md5 hash of generated sequences of 1000 samples
+ # We use a sha256 hash of generated sequences of 1000 samples
# in the range [0, 6) for all but bool, where the range
# is [0, 2). Hashes are for little endian numbers.
- tgt = {'bool': '7dd3170d7aa461d201a65f8bcf3944b0',
- 'int16': '1b7741b80964bb190c50d541dca1cac1',
- 'int32': '4dc9fcc2b395577ebb51793e58ed1a05',
- 'int64': '17db902806f448331b5a758d7d2ee672',
- 'int8': '27dd30c4e08a797063dffac2490b0be6',
- 'uint16': '1b7741b80964bb190c50d541dca1cac1',
- 'uint32': '4dc9fcc2b395577ebb51793e58ed1a05',
- 'uint64': '17db902806f448331b5a758d7d2ee672',
- 'uint8': '27dd30c4e08a797063dffac2490b0be6'}
+ tgt = {'bool': '509aea74d792fb931784c4b0135392c65aec64beee12b0cc167548a2c3d31e71',
+ 'int16': '7b07f1a920e46f6d0fe02314155a2330bcfd7635e708da50e536c5ebb631a7d4',
+ 'int32': 'e577bfed6c935de944424667e3da285012e741892dcb7051a8f1ce68ab05c92f',
+ 'int64': '0fbead0b06759df2cfb55e43148822d4a1ff953c7eb19a5b08445a63bb64fa9e',
+ 'int8': '001aac3a5acb935a9b186cbe14a1ca064b8bb2dd0b045d48abeacf74d0203404',
+ 'uint16': '7b07f1a920e46f6d0fe02314155a2330bcfd7635e708da50e536c5ebb631a7d4',
+ 'uint32': 'e577bfed6c935de944424667e3da285012e741892dcb7051a8f1ce68ab05c92f',
+ 'uint64': '0fbead0b06759df2cfb55e43148822d4a1ff953c7eb19a5b08445a63bb64fa9e',
+ 'uint8': '001aac3a5acb935a9b186cbe14a1ca064b8bb2dd0b045d48abeacf74d0203404'}
for dt in self.itype[1:]:
np.random.seed(1234)
else:
val = self.rfunc(0, 6, size=1000, dtype=dt).byteswap()
- res = hashlib.md5(val.view(np.int8)).hexdigest()
+ res = hashlib.sha256(val.view(np.int8)).hexdigest()
assert_(tgt[np.dtype(dt).name] == res)
# bools do not depend on endianness
np.random.seed(1234)
val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8)
- res = hashlib.md5(val).hexdigest()
+ res = hashlib.sha256(val).hexdigest()
assert_(tgt[np.dtype(bool).name] == res)
def test_int64_uint64_corner_case(self):
if np.iinfo(int).max < 2**32:
# Windows and some 32-bit platforms, e.g., ARM
- INT_FUNC_HASHES = {'binomial': '670e1c04223ffdbab27e08fbbad7bdba',
- 'logseries': '6bd0183d2f8030c61b0d6e11aaa60caf',
- 'geometric': '6e9df886f3e1e15a643168568d5280c0',
- 'hypergeometric': '7964aa611b046aecd33063b90f4dec06',
- 'multinomial': '68a0b049c16411ed0aa4aff3572431e4',
- 'negative_binomial': 'dc265219eec62b4338d39f849cd36d09',
- 'poisson': '7b4dce8e43552fc82701c2fa8e94dc6e',
- 'zipf': 'fcd2a2095f34578723ac45e43aca48c5',
+ INT_FUNC_HASHES = {'binomial': '2fbead005fc63942decb5326d36a1f32fe2c9d32c904ee61e46866b88447c263',
+ 'logseries': '23ead5dcde35d4cfd4ef2c105e4c3d43304b45dc1b1444b7823b9ee4fa144ebb',
+ 'geometric': '0d764db64f5c3bad48c8c33551c13b4d07a1e7b470f77629bef6c985cac76fcf',
+ 'hypergeometric': '7b59bf2f1691626c5815cdcd9a49e1dd68697251d4521575219e4d2a1b8b2c67',
+ 'multinomial': 'd754fa5b92943a38ec07630de92362dd2e02c43577fc147417dc5b9db94ccdd3',
+ 'negative_binomial': '8eb216f7cb2a63cf55605422845caaff002fddc64a7dc8b2d45acd477a49e824',
+ 'poisson': '70c891d76104013ebd6f6bcf30d403a9074b886ff62e4e6b8eb605bf1a4673b7',
+ 'zipf': '01f074f97517cd5d21747148ac6ca4074dde7fcb7acbaec0a936606fecacd93f',
}
else:
- INT_FUNC_HASHES = {'binomial': 'b5f8dcd74f172836536deb3547257b14',
- 'geometric': '8814571f45c87c59699d62ccd3d6c350',
- 'hypergeometric': 'bc64ae5976eac452115a16dad2dcf642',
- 'logseries': '84be924b37485a27c4a98797bc88a7a4',
- 'multinomial': 'ec3c7f9cf9664044bb0c6fb106934200',
- 'negative_binomial': '210533b2234943591364d0117a552969',
- 'poisson': '0536a8850c79da0c78defd742dccc3e0',
- 'zipf': 'f2841f504dd2525cd67cdcad7561e532',
+ INT_FUNC_HASHES = {'binomial': '8626dd9d052cb608e93d8868de0a7b347258b199493871a1dc56e2a26cacb112',
+ 'geometric': '8edd53d272e49c4fc8fbbe6c7d08d563d62e482921f3131d0a0e068af30f0db9',
+ 'hypergeometric': '83496cc4281c77b786c9b7ad88b74d42e01603a55c60577ebab81c3ba8d45657',
+ 'logseries': '65878a38747c176bc00e930ebafebb69d4e1e16cd3a704e264ea8f5e24f548db',
+ 'multinomial': '7a984ae6dca26fd25374479e118b22f55db0aedccd5a0f2584ceada33db98605',
+ 'negative_binomial': 'd636d968e6a24ae92ab52fe11c46ac45b0897e98714426764e820a7d77602a61',
+ 'poisson': '956552176f77e7c9cb20d0118fc9cf690be488d790ed4b4c4747b965e61b0bb4',
+ 'zipf': 'f84ba7feffda41e606e20b28dfc0f1ea9964a74574513d4a4cbc98433a8bfa45',
}
assert_(vals.min() >= 0)
def test_repeatability(self):
- # We use a md5 hash of generated sequences of 1000 samples
+ # We use a sha256 hash of generated sequences of 1000 samples
# in the range [0, 6) for all but bool, where the range
# is [0, 2). Hashes are for little endian numbers.
- tgt = {'bool': '7dd3170d7aa461d201a65f8bcf3944b0',
- 'int16': '1b7741b80964bb190c50d541dca1cac1',
- 'int32': '4dc9fcc2b395577ebb51793e58ed1a05',
- 'int64': '17db902806f448331b5a758d7d2ee672',
- 'int8': '27dd30c4e08a797063dffac2490b0be6',
- 'uint16': '1b7741b80964bb190c50d541dca1cac1',
- 'uint32': '4dc9fcc2b395577ebb51793e58ed1a05',
- 'uint64': '17db902806f448331b5a758d7d2ee672',
- 'uint8': '27dd30c4e08a797063dffac2490b0be6'}
+ tgt = {'bool': '509aea74d792fb931784c4b0135392c65aec64beee12b0cc167548a2c3d31e71',
+ 'int16': '7b07f1a920e46f6d0fe02314155a2330bcfd7635e708da50e536c5ebb631a7d4',
+ 'int32': 'e577bfed6c935de944424667e3da285012e741892dcb7051a8f1ce68ab05c92f',
+ 'int64': '0fbead0b06759df2cfb55e43148822d4a1ff953c7eb19a5b08445a63bb64fa9e',
+ 'int8': '001aac3a5acb935a9b186cbe14a1ca064b8bb2dd0b045d48abeacf74d0203404',
+ 'uint16': '7b07f1a920e46f6d0fe02314155a2330bcfd7635e708da50e536c5ebb631a7d4',
+ 'uint32': 'e577bfed6c935de944424667e3da285012e741892dcb7051a8f1ce68ab05c92f',
+ 'uint64': '0fbead0b06759df2cfb55e43148822d4a1ff953c7eb19a5b08445a63bb64fa9e',
+ 'uint8': '001aac3a5acb935a9b186cbe14a1ca064b8bb2dd0b045d48abeacf74d0203404'}
for dt in self.itype[1:]:
random.seed(1234)
else:
val = self.rfunc(0, 6, size=1000, dtype=dt).byteswap()
- res = hashlib.md5(val.view(np.int8)).hexdigest()
+ res = hashlib.sha256(val.view(np.int8)).hexdigest()
assert_(tgt[np.dtype(dt).name] == res)
# bools do not depend on endianness
random.seed(1234)
val = self.rfunc(0, 2, size=1000, dtype=bool).view(np.int8)
- res = hashlib.md5(val).hexdigest()
+ res = hashlib.sha256(val).hexdigest()
assert_(tgt[np.dtype(bool).name] == res)
@pytest.mark.skipif(np.iinfo('l').max < 2**32,
a = np.array([42, 1, 2])
p = [None, None, None]
assert_raises(ValueError, random.choice, a, p=p)
-
+
def test_choice_p_non_contiguous(self):
p = np.ones(10) / 5
p[1::2] = 3.0
assert_equal(
sorted(b.data[~b.mask]), sorted(b_orig.data[~b_orig.mask]))
+ def test_shuffle_invalid_objects(self):
+ x = np.array(3)
+ assert_raises(TypeError, random.shuffle, x)
+
def test_permutation(self):
random.seed(self.seed)
alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
# Ensure returned array dtype is correct for platform
def test_integer_dtype(int_func):
random.seed(123456789)
- fname, args, md5 = int_func
+ fname, args, sha256 = int_func
f = getattr(random, fname)
actual = f(*args, size=2)
assert_(actual.dtype == np.dtype('l'))
def test_integer_repeat(int_func):
random.seed(123456789)
- fname, args, md5 = int_func
+ fname, args, sha256 = int_func
f = getattr(random, fname)
val = f(*args, size=1000000)
if sys.byteorder != 'little':
val = val.byteswap()
- res = hashlib.md5(val.view(np.int8)).hexdigest()
- assert_(res == md5)
+ res = hashlib.sha256(val.view(np.int8)).hexdigest()
+ assert_(res == sha256)
def test_broadcast_size_error():
# numbers with this large sample
# theoretical large N result is 0.49706795
freq = np.sum(rvsn == 1) / float(N)
- msg = "Frequency was %f, should be > 0.45" % freq
+ msg = f'Frequency was {freq:f}, should be > 0.45'
assert_(freq > 0.45, msg)
# theoretical large N result is 0.19882718
freq = np.sum(rvsn == 2) / float(N)
- msg = "Frequency was %f, should be < 0.23" % freq
+ msg = f'Frequency was {freq:f}, should be < 0.23'
assert_(freq < 0.23, msg)
def test_shuffle_mixed_dimension(self):
# numbers with this large sample
# theoretical large N result is 0.49706795
freq = np.sum(rvsn == 1) / float(N)
- msg = "Frequency was %f, should be > 0.45" % freq
+ msg = f'Frequency was {freq:f}, should be > 0.45'
assert_(freq > 0.45, msg)
# theoretical large N result is 0.19882718
freq = np.sum(rvsn == 2) / float(N)
- msg = "Frequency was %f, should be < 0.23" % freq
+ msg = f'Frequency was {freq:f}, should be < 0.23'
assert_(freq < 0.23, msg)
def test_shuffle_mixed_dimension(self):
assert_(not comp_state(state, self.rg.bit_generator.state))
else:
bitgen_name = self.rg.bit_generator.__class__.__name__
- pytest.skip('Advance is not supported by {0}'.format(bitgen_name))
+ pytest.skip(f'Advance is not supported by {bitgen_name}')
def test_jump(self):
state = self.rg.bit_generator.state
else:
bitgen_name = self.rg.bit_generator.__class__.__name__
if bitgen_name not in ('SFC64',):
- raise AttributeError('no "jumped" in %s' % bitgen_name)
- pytest.skip('Jump is not supported by {0}'.format(bitgen_name))
+ raise AttributeError(f'no "jumped" in {bitgen_name}')
+ pytest.skip(f'Jump is not supported by {bitgen_name}')
def test_uniform(self):
r = self.rg.uniform(-1.0, 0.0, size=10)
def test_seed_array(self):
if self.seed_vector_bits is None:
bitgen_name = self.bit_generator.__name__
- pytest.skip('Vector seeding is not supported by '
- '{0}'.format(bitgen_name))
+ pytest.skip(f'Vector seeding is not supported by {bitgen_name}')
if self.seed_vector_bits == 32:
dtype = np.uint32
--- /dev/null
+from typing import Any
+
+record: Any
+recarray: Any
+format_parser: Any
config.add_subpackage('polynomial')
config.add_subpackage('random')
config.add_subpackage('testing')
+ config.add_subpackage('typing')
config.add_data_dir('doc')
+ config.add_data_files('py.typed')
+ config.add_data_files('*.pyi')
config.add_subpackage('tests')
config.make_config_py() # installs __config__.py
return config
--- /dev/null
+from typing import Any
+
+assert_equal: Any
+assert_almost_equal: Any
+assert_approx_equal: Any
+assert_array_equal: Any
+assert_array_less: Any
+assert_string_equal: Any
+assert_array_almost_equal: Any
+assert_raises: Any
+build_err_msg: Any
+decorate_methods: Any
+jiffies: Any
+memusage: Any
+print_assert_equal: Any
+raises: Any
+rundocs: Any
+runstring: Any
+verbose: Any
+measure: Any
+assert_: Any
+assert_array_almost_equal_nulp: Any
+assert_raises_regex: Any
+assert_array_max_ulp: Any
+assert_warns: Any
+assert_no_warnings: Any
+assert_allclose: Any
+IgnoreException: Any
+clear_and_catch_warnings: Any
+SkipTest: Any
+KnownFailureException: Any
+temppath: Any
+tempdir: Any
+IS_PYPY: Any
+HAS_REFCOUNT: Any
+suppress_warnings: Any
+assert_array_compare: Any
+_assert_valid_refcount: Any
+_gen_alignment_data: Any
+assert_no_gc_cycles: Any
+break_cycles: Any
+HAS_LAPACK64: Any
+TestCase: Any
+run_module_suite: Any
else:
out = msg
- return "Skipping test: %s: %s" % (func.__name__, out)
+ return f'Skipping test: {func.__name__}: {out}'
# We need to define *two* skippers because Python doesn't allow both
# return with value and yield inside the same function.
# Look for tests in a module's contained objects.
if ismodule(obj) and self._recurse:
for valname, val in obj.__dict__.items():
- valname1 = '%s.%s' % (name, valname)
+ valname1 = f'{name}.{valname}'
if ( (isroutine(val) or isclass(val))
and self._from_module(module, val)):
if ((isfunction(val) or isclass(val) or
ismethod(val) or isinstance(val, property)) and
self._from_module(module, val)):
- valname = '%s.%s' % (name, valname)
+ valname = f'{name}.{valname}'
self._find(tests, val, valname, module, source_lines,
globs, seen)
nose = import_nose()
import numpy
- print("NumPy version %s" % numpy.__version__)
+ print(f'NumPy version {numpy.__version__}')
relaxed_strides = numpy.ones((10, 1), order="C").flags.f_contiguous
print("NumPy relaxed strides checking option:", relaxed_strides)
npdir = os.path.dirname(numpy.__file__)
- print("NumPy is installed in %s" % npdir)
+ print(f'NumPy is installed in {npdir}')
if 'scipy' in self.package_name:
import scipy
- print("SciPy version %s" % scipy.__version__)
+ print(f'SciPy version {scipy.__version__}')
spdir = os.path.dirname(scipy.__file__)
- print("SciPy is installed in %s" % spdir)
+ print(f'SciPy is installed in {spdir}')
pyversion = sys.version.replace('\n', '')
- print("Python version %s" % pyversion)
+ print(f'Python version {pyversion}')
print("nose version %d.%d.%d" % nose.__versioninfo__)
def _get_custom_doctester(self):
argv = self._test_argv(label, verbose, extra_argv)
# our way of doing coverage
if coverage:
- argv += ['--cover-package=%s' % self.package_name, '--with-coverage',
+ argv += [f'--cover-package={self.package_name}', '--with-coverage',
'--cover-tests', '--cover-erase']
if timer:
coverage : bool, optional
If True, report coverage of NumPy code. Default is False.
(This requires the
- `coverage module <https://nedbatchelder.com/code/modules/coveragehtml>`_).
+ `coverage module <https://pypi.org/project/coverage/>`_).
raise_warnings : None, str or sequence of warnings, optional
This specifies which warnings to configure as 'raise' instead
of being shown once during the test execution. Valid strings are:
label, verbose, extra_argv, doctests, coverage, timer)
if doctests:
- print("Running unit tests and doctests for %s" % self.package_name)
+ print(f'Running unit tests and doctests for {self.package_name}')
else:
- print("Running unit tests for %s" % self.package_name)
+ print(f'Running unit tests for {self.package_name}')
self._show_system_info()
"""
- print("Running benchmarks for %s" % self.package_name)
+ print(f'Running benchmarks for {self.package_name}')
self._show_system_info()
argv = self._test_argv(label, verbose, extra_argv)
all_args_with_values = parameterized_argument_value_pairs(func, p)
# Assumes that the function passed is a bound method.
- descs = ["%s=%s" %(n, short_repr(v)) for n, v in all_args_with_values]
+ descs = [f'{n}={short_repr(v)}' for n, v in all_args_with_values]
# The documentation might be a multiline string, so split it
# and just work with the first string, ignoring the period
def gisfinite(x):
- """like isfinite, but always raise an error if type not supported instead of
- returning a TypeError object.
+ """like isfinite, but always raise an error if type not supported instead
+ of returning a TypeError object.
Notes
-----
- isfinite and other ufunc sometimes return a NotImplementedType object instead
- of raising any exception. This function is a wrapper to make sure an
- exception is always raised.
+ isfinite and other ufunc sometimes return a NotImplementedType object
+ instead of raising any exception. This function is a wrapper to make sure
+ an exception is always raised.
This should be removed once this problem is solved at the Ufunc level."""
from numpy.core import isfinite, errstate
# you should copy this function, but keep the counter open, and call
# CollectQueryData() each time you need to know.
# See http://msdn.microsoft.com/library/en-us/dnperfmo/html/perfmonpt2.asp (dead link)
- # My older explanation for this was that the "AddCounter" process forced
- # the CPU to 100%, but the above makes more sense :)
+ # My older explanation for this was that the "AddCounter" process
+ # forced the CPU to 100%, but the above makes more sense :)
import win32pdh
if format is None:
format = win32pdh.PDH_FMT_LONG
- path = win32pdh.MakeCounterPath( (machine, object, instance, None, inum, counter))
+ path = win32pdh.MakeCounterPath( (machine, object, instance, None,
+ inum, counter))
hq = win32pdh.OpenQuery()
try:
hc = win32pdh.AddCounter(hq, path)
win32pdh.PDH_FMT_LONG, None)
elif sys.platform[:5] == 'linux':
- def memusage(_proc_pid_stat='/proc/%s/stat' % (os.getpid())):
+ def memusage(_proc_pid_stat=f'/proc/{os.getpid()}/stat'):
"""
Return virtual memory size in bytes of the running python.
if sys.platform[:5] == 'linux':
- def jiffies(_proc_pid_stat='/proc/%s/stat' % (os.getpid()),
- _load_time=[]):
+ def jiffies(_proc_pid_stat=f'/proc/{os.getpid()}/stat', _load_time=[]):
"""
Return number of jiffies elapsed.
try:
r = r_func(a)
except Exception as exc:
- r = '[repr failed for <{}>: {}]'.format(type(a).__name__, exc)
+ r = f'[repr failed for <{type(a).__name__}>: {exc}]'
if r.count('\n') > 3:
r = '\n'.join(r.splitlines()[:3])
r += '...'
- msg.append(' %s: %s' % (names[i], r))
+ msg.append(f' {names[i]}: {r}')
return '\n'.join(msg)
for k, i in desired.items():
if k not in actual:
raise AssertionError(repr(k))
- assert_equal(actual[k], desired[k], 'key=%r\n%s' % (k, err_msg), verbose)
+ assert_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}',
+ verbose)
return
if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)):
assert_equal(len(actual), len(desired), err_msg, verbose)
for k in range(len(desired)):
- assert_equal(actual[k], desired[k], 'item=%r\n%s' % (k, err_msg), verbose)
+ assert_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}',
+ verbose)
return
from numpy.core import ndarray, isscalar, signbit
from numpy.lib import iscomplexobj, real, imag
raise AssertionError(msg)
-def assert_array_compare(comparison, x, y, err_msg='', verbose=True,
- header='', precision=6, equal_nan=True,
- equal_inf=True):
+def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='',
+ precision=6, equal_nan=True, equal_inf=True):
__tracebackhide__ = True # Hide traceback for py.test
from numpy.core import array, array2string, isnan, inf, bool_, errstate, all, max, object_
at the same locations.
"""
+ __tracebackhide__ = True # Hide traceback for py.test
+
x_id = func(x)
y_id = func(y)
# We include work-arounds here to handle three types of slightly
if not cond:
msg = build_err_msg([x, y],
err_msg
- + '\n(shapes %s, %s mismatch)' % (x.shape,
- y.shape),
+ + f'\n(shapes {x.shape}, {y.shape} mismatch)',
verbose=verbose, header=header,
names=('x', 'y'), precision=precision)
raise AssertionError(msg)
except ValueError:
import traceback
efmt = traceback.format_exc()
- header = 'error during assertion:\n\n%s\n\n%s' % (efmt, header)
+ header = f'error during assertion:\n\n{efmt}\n\n{header}'
msg = build_err_msg([x, y], err_msg, verbose=verbose, header=header,
names=('x', 'y'), precision=precision)
if desired == actual:
return
- diff = list(difflib.Differ().compare(actual.splitlines(True), desired.splitlines(True)))
+ diff = list(difflib.Differ().compare(actual.splitlines(True),
+ desired.splitlines(True)))
diff_list = []
while diff:
d1 = diff.pop(0)
raise AssertionError(repr(d1))
if not diff_list:
return
- msg = 'Differences in strings:\n%s' % (''.join(diff_list)).rstrip()
+ msg = f"Differences in strings:\n{''.join(diff_list).rstrip()}"
if actual != desired:
raise AssertionError(msg)
frame = sys._getframe(1)
locs, globs = frame.f_locals, frame.f_globals
- code = compile(code_str,
- 'Test name: %s ' % label,
- 'exec')
+ code = compile(code_str, f'Test name: {label} ', 'exec')
i = 0
elapsed = jiffies()
while i < times:
equal_nan=equal_nan)
actual, desired = np.asanyarray(actual), np.asanyarray(desired)
- header = 'Not equal to tolerance rtol=%g, atol=%g' % (rtol, atol)
+ header = f'Not equal to tolerance rtol={rtol:g}, atol={atol:g}'
assert_array_compare(compare, actual, desired, err_msg=str(err_msg),
verbose=verbose, header=header, equal_nan=equal_nan)
def integer_repr(x):
- """Return the signed-magnitude interpretation of the binary representation of
- x."""
+ """Return the signed-magnitude interpretation of the binary representation
+ of x."""
import numpy as np
if x.dtype == np.float16:
return _integer_repr(x, np.int16, np.int16(-2**15))
elif x.dtype == np.float64:
return _integer_repr(x, np.int64, np.int64(-2**63))
else:
- raise ValueError("Unsupported dtype %s" % x.dtype)
+ raise ValueError(f'Unsupported dtype {x.dtype}')
@contextlib.contextmanager
l = sup.record(warning_class)
yield
if not len(l) > 0:
- name_str = " when calling %s" % name if name is not None else ""
+ name_str = f' when calling {name}' if name is not None else ''
raise AssertionError("No warning raised" + name_str)
----------
warning_class : class
The class defining the warning that `func` is expected to throw.
- func : callable
- The callable to test.
- \\*args : Arguments
- Arguments passed to `func`.
- \\*\\*kwargs : Kwargs
- Keyword arguments passed to `func`.
+ func : callable, optional
+ Callable to test
+ *args : Arguments
+ Arguments for `func`.
+ **kwargs : Kwargs
+ Keyword arguments for `func`.
Returns
-------
The value returned by `func`.
+ Examples
+ --------
+ >>> import warnings
+ >>> def deprecated_func(num):
+ ... warnings.warn("Please upgrade", DeprecationWarning)
+ ... return num*num
+ >>> with np.testing.assert_warns(DeprecationWarning):
+ ... assert deprecated_func(4) == 16
+ >>> # or passing a func
+ >>> ret = np.testing.assert_warns(DeprecationWarning, deprecated_func, 4)
+ >>> assert ret == 16
"""
if not args:
return _assert_warns_context(warning_class)
warnings.simplefilter('always')
yield
if len(l) > 0:
- name_str = " when calling %s" % name if name is not None else ""
- raise AssertionError("Got warnings%s: %s" % (name_str, l))
+ name_str = f' when calling {name}' if name is not None else ''
+ raise AssertionError(f'Got warnings{name_str}: {l}')
def assert_no_warnings(*args, **kwargs):
break
else:
raise RuntimeError(
- "Unable to fully collect garbage - perhaps a __del__ method is "
- "creating more reference cycles?")
+ "Unable to fully collect garbage - perhaps a __del__ method "
+ "is creating more reference cycles?")
gc.set_debug(gc.DEBUG_SAVEALL)
yield
gc.enable()
if n_objects_in_cycles:
- name_str = " when calling %s" % name if name is not None else ""
+ name_str = f' when calling {name}' if name is not None else ''
raise AssertionError(
"Reference cycles were found{}: {} objects were collected, "
"of which {} are shown below:{}"
if IS_PYPY:
# interpreter runs now, to call deleted objects' __del__ methods
gc.collect()
- # one more, just to make sure
+ # two more, just to make sure
+ gc.collect()
gc.collect()
try:
mem_free = _parse_size(env_value)
except ValueError as exc:
- raise ValueError('Invalid environment variable {}: {!s}'.format(
- env_var, exc))
+ raise ValueError(f'Invalid environment variable {env_var}: {exc}')
- msg = ('{0} GB memory required, but environment variable '
- 'NPY_AVAILABLE_MEM={1} set'.format(
- free_bytes/1e9, env_value))
+ msg = (f'{free_bytes/1e9} GB memory required, but environment variable '
+ f'NPY_AVAILABLE_MEM={env_value} set')
else:
mem_free = _get_mem_available()
"the test.")
mem_free = -1
else:
- msg = '{0} GB memory required, but {1} GB available'.format(
- free_bytes/1e9, mem_free/1e9)
+ msg = f'{free_bytes/1e9} GB memory required, but {mem_free/1e9} GB available'
return msg if mem_free < free_bytes else None
m = size_re.match(size_str.lower())
if not m or m.group(2) not in suffixes:
- raise ValueError("value {!r} not a valid size".format(size_str))
+ raise ValueError(f'value {size_str!r} not a valid size')
return int(float(m.group(1)) * suffixes[m.group(2)])
"""
import numpy as np
+from collections import namedtuple
# Generic object that can be added, but doesn't do anything else
class GenericObject:
for row in ntypes:
print(row, end=' ')
for col in ntypes:
- print(int(np.can_cast(row, col)), end=' ')
+ if np.can_cast(row, col, "equiv"):
+ cast = "#"
+ elif np.can_cast(row, col, "safe"):
+ cast = "="
+ elif np.can_cast(row, col, "same_kind"):
+ cast = "~"
+ elif np.can_cast(row, col, "unsafe"):
+ cast = "."
+ else:
+ cast = " "
+ print(cast, end=' ')
print()
def print_coercion_table(ntypes, inputfirstvalue, inputsecondvalue, firstarray, use_promote_types=False):
print()
+def print_new_cast_table(*, can_cast=True, legacy=False, flags=False):
+ """Prints new casts, the values given are default "can-cast" values, not
+ actual ones.
+ """
+ from numpy.core._multiarray_tests import get_all_cast_information
+
+ cast_table = {
+ 0 : "#", # No cast (classify as equivalent here)
+ 1 : "#", # equivalent casting
+ 2 : "=", # safe casting
+ 3 : "~", # same-kind casting
+ 4 : ".", # unsafe casting
+ }
+ flags_table = {
+ 0 : "▗", 7: "█",
+ 1: "▚", 2: "▐", 4: "▄",
+ 3: "▜", 5: "▙",
+ 6: "▟",
+ }
+
+ cast_info = namedtuple("cast_info", ["can_cast", "legacy", "flags"])
+ no_cast_info = cast_info(" ", " ", " ")
+
+ casts = get_all_cast_information()
+ table = {}
+ dtypes = set()
+ for cast in casts:
+ dtypes.add(cast["from"])
+ dtypes.add(cast["to"])
+
+ if cast["from"] not in table:
+ table[cast["from"]] = {}
+ to_dict = table[cast["from"]]
+
+ can_cast = cast_table[cast["casting"]]
+ legacy = "L" if cast["legacy"] else "."
+ flags = 0
+ if cast["requires_pyapi"]:
+ flags |= 1
+ if cast["supports_unaligned"]:
+ flags |= 2
+ if cast["no_floatingpoint_errors"]:
+ flags |= 4
+
+ flags = flags_table[flags]
+ to_dict[cast["to"]] = cast_info(can_cast=can_cast, legacy=legacy, flags=flags)
+
+ # The np.dtype(x.type) is a bit strange, because dtype classes do
+ # not expose much yet.
+ types = np.typecodes["All"]
+ def sorter(x):
+ # This is a bit weird hack, to get a table as close as possible to
+ # the one printing all typecodes (but expecting user-dtypes).
+ dtype = np.dtype(x.type)
+ try:
+ indx = types.index(dtype.char)
+ except ValueError:
+ indx = np.inf
+ return (indx, dtype.char)
+
+ dtypes = sorted(dtypes, key=sorter)
+
+ def print_table(field="can_cast"):
+ print('X', end=' ')
+ for dt in dtypes:
+ print(np.dtype(dt.type).char, end=' ')
+ print()
+ for from_dt in dtypes:
+ print(np.dtype(from_dt.type).char, end=' ')
+ row = table.get(from_dt, {})
+ for to_dt in dtypes:
+ print(getattr(row.get(to_dt, no_cast_info), field), end=' ')
+ print()
+
+ if can_cast:
+ # Print the actual table:
+ print()
+ print("Casting: # is equivalent, = is safe, ~ is same-kind, and . is unsafe")
+ print()
+ print_table("can_cast")
+
+ if legacy:
+ print()
+ print("L denotes a legacy cast . a non-legacy one.")
+ print()
+ print_table("legacy")
+
+ if flags:
+ print()
+ print(f"{flags_table[0]}: no flags, {flags_table[1]}: PyAPI, "
+ f"{flags_table[2]}: supports unaligned, {flags_table[4]}: no-float-errors")
+ print()
+ print_table("flags")
+
+
if __name__ == '__main__':
print("can cast")
print_cancast_table(np.typecodes['All'])
print()
print("promote_types")
print_coercion_table(np.typecodes['All'], 0, 0, False, True)
+ print("New casting type promotion:")
+ print_new_cast_table(can_cast=True, legacy=True, flags=True)
config.add_subpackage('_private')
config.add_subpackage('tests')
+ config.add_data_files('*.pyi')
return config
if __name__ == '__main__':
if sys.version_info[:2] >= (3, 7):
if py37 is not None:
n_in_context = py37
- elif sys.version_info[:2] >= (3, 4):
+ else:
if py34 is not None:
n_in_context = py34
assert_equal(num_warns, n_in_context)
'show_config': 'numpy.__config__.show',
'who': 'numpy.lib.utils.who',
}
- # These built-in types are re-exported by numpy.
- builtins = {
- 'bool': 'builtins.bool',
- 'complex': 'builtins.complex',
- 'float': 'builtins.float',
- 'int': 'builtins.int',
- 'long': 'builtins.int',
- 'object': 'builtins.object',
- 'str': 'builtins.str',
- 'unicode': 'builtins.str',
- }
- whitelist = dict(undocumented, **builtins)
+ if sys.version_info < (3, 7):
+ # These built-in types are re-exported by numpy.
+ builtins = {
+ 'bool': 'builtins.bool',
+ 'complex': 'builtins.complex',
+ 'float': 'builtins.float',
+ 'int': 'builtins.int',
+ 'long': 'builtins.int',
+ 'object': 'builtins.object',
+ 'str': 'builtins.str',
+ 'unicode': 'builtins.str',
+ }
+ allowlist = dict(undocumented, **builtins)
+ else:
+ # after 3.7, we override dir to not show these members
+ allowlist = undocumented
bad_results = check_dir(np)
# pytest gives better error messages with the builtin assert than with
# assert_equal
- assert bad_results == whitelist
+ assert bad_results == allowlist
@pytest.mark.parametrize('name', ['testing', 'Tester'])
"""Assert that output of dir has only one "testing/tester"
attribute without duplicate"""
assert len(dir(np)) == len(set(dir(np)))
-
+
def test_numpy_linalg():
bad_results = check_dir(np.linalg)
"distutils.log",
"distutils.system_info",
"doc",
- "doc.basics",
- "doc.broadcasting",
- "doc.byteswapping",
"doc.constants",
- "doc.creation",
- "doc.dispatch",
- "doc.glossary",
- "doc.indexing",
- "doc.internals",
- "doc.misc",
- "doc.structured_arrays",
- "doc.subclassing",
"doc.ufuncs",
- "dual",
"f2py",
"fft",
"lib",
"polynomial.polyutils",
"random",
"testing",
+ "typing",
"version",
]]
"core.umath",
"core.umath_tests",
"distutils.ccompiler",
+ 'distutils.ccompiler_opt',
"distutils.command",
"distutils.command.autodist",
"distutils.command.bdist_rpm",
"distutils.fcompiler.nv",
"distutils.fcompiler.sun",
"distutils.fcompiler.vast",
+ "distutils.fcompiler.fujitsu",
"distutils.from_template",
"distutils.intelccompiler",
"distutils.lib2def",
"distutils.numpy_distribution",
"distutils.pathccompiler",
"distutils.unixccompiler",
+ "dual",
"f2py.auxfuncs",
"f2py.capi_maps",
"f2py.cb_rules",
"lib.arraypad",
"lib.arraysetops",
"lib.arrayterator",
- "lib.financial",
"lib.function_base",
"lib.histograms",
"lib.index_tricks",
modnames.append(modname)
if modnames:
- raise AssertionError("Found unexpected modules: {}".format(modnames))
+ raise AssertionError(f'Found unexpected modules: {modnames}')
# Stuff that clearly shouldn't be in the API and is detected by the next test
SKIP_LIST_2 = [
'numpy.math',
'numpy.distutils.log.sys',
- 'numpy.distutils.system_info.copy',
- 'numpy.distutils.system_info.distutils',
- 'numpy.distutils.system_info.log',
- 'numpy.distutils.system_info.os',
- 'numpy.distutils.system_info.platform',
- 'numpy.distutils.system_info.re',
- 'numpy.distutils.system_info.shutil',
- 'numpy.distutils.system_info.subprocess',
- 'numpy.distutils.system_info.sys',
- 'numpy.distutils.system_info.tempfile',
- 'numpy.distutils.system_info.textwrap',
- 'numpy.distutils.system_info.warnings',
'numpy.doc.constants.re',
'numpy.doc.constants.textwrap',
'numpy.lib.emath',
--- /dev/null
+"""
+============================
+Typing (:mod:`numpy.typing`)
+============================
+
+.. warning::
+
+ Some of the types in this module rely on features only present in
+ the standard library in Python 3.8 and greater. If you want to use
+ these types in earlier versions of Python, you should install the
+ typing-extensions_ package.
+
+Large parts of the NumPy API have PEP-484-style type annotations. In
+addition a number of type aliases are available to users, most prominently
+the two below:
+
+- `ArrayLike`: objects that can be converted to arrays
+- `DTypeLike`: objects that can be converted to dtypes
+
+.. _typing-extensions: https://pypi.org/project/typing-extensions/
+
+Differences from the runtime NumPy API
+--------------------------------------
+
+NumPy is very flexible. Trying to describe the full range of
+possibilities statically would result in types that are not very
+helpful. For that reason, the typed NumPy API is often stricter than
+the runtime NumPy API. This section describes some notable
+differences.
+
+ArrayLike
+~~~~~~~~~
+
+The `ArrayLike` type tries to avoid creating object arrays. For
+example,
+
+.. code-block:: python
+
+ >>> np.array(x**2 for x in range(10))
+ array(<generator object <genexpr> at ...>, dtype=object)
+
+is valid NumPy code which will create a 0-dimensional object
+array. Type checkers will complain about the above example when using
+the NumPy types however. If you really intended to do the above, then
+you can either use a ``# type: ignore`` comment:
+
+.. code-block:: python
+
+ >>> np.array(x**2 for x in range(10)) # type: ignore
+
+or explicitly type the array like object as `~typing.Any`:
+
+.. code-block:: python
+
+ >>> from typing import Any
+ >>> array_like: Any = (x**2 for x in range(10))
+ >>> np.array(array_like)
+ array(<generator object <genexpr> at ...>, dtype=object)
+
+ndarray
+~~~~~~~
+
+It's possible to mutate the dtype of an array at runtime. For example,
+the following code is valid:
+
+.. code-block:: python
+
+ >>> x = np.array([1, 2])
+ >>> x.dtype = np.bool_
+
+This sort of mutation is not allowed by the types. Users who want to
+write statically typed code should insted use the `numpy.ndarray.view`
+method to create a view of the array with a different dtype.
+
+DTypeLike
+~~~~~~~~~
+
+The `DTypeLike` type tries to avoid creation of dtype objects using
+dictionary of fields like below:
+
+.. code-block:: python
+
+ >>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)})
+
+Although this is valid Numpy code, the type checker will complain about it,
+since its usage is discouraged.
+Please see : :ref:`Data type objects <arrays.dtypes>`
+
+Number Precision
+~~~~~~~~~~~~~~~~
+
+The precision of `numpy.number` subclasses is treated as a covariant generic
+parameter (see :class:`~NBitBase`), simplifying the annoting of proccesses
+involving precision-based casting.
+
+.. code-block:: python
+
+ >>> from typing import TypeVar
+ >>> import numpy as np
+ >>> import numpy.typing as npt
+
+ >>> T = TypeVar("T", bound=npt.NBitBase)
+ >>> def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
+ ... ...
+
+Consequently, the likes of `~numpy.float16`, `~numpy.float32` and
+`~numpy.float64` are still sub-types of `~numpy.floating`, but, contrary to
+runtime, they're not necessarily considered as sub-classes.
+
+Timedelta64
+~~~~~~~~~~~
+
+The `~numpy.timedelta64` class is not considered a subclass of `~numpy.signedinteger`,
+the former only inheriting from `~numpy.generic` while static type checking.
+
+API
+---
+
+"""
+# NOTE: The API section will be appended with additional entries
+# further down in this file
+
+from typing import TYPE_CHECKING, List
+
+if TYPE_CHECKING:
+ import sys
+ if sys.version_info >= (3, 8):
+ from typing import final
+ else:
+ from typing_extensions import final
+else:
+ def final(f): return f
+
+if not TYPE_CHECKING:
+ __all__ = ["ArrayLike", "DTypeLike", "NBitBase"]
+else:
+ # Ensure that all objects within this module are accessible while
+ # static type checking. This includes private ones, as we need them
+ # for internal use.
+ #
+ # Declare to mypy that `__all__` is a list of strings without assigning
+ # an explicit value
+ __all__: List[str]
+
+
+@final # Dissallow the creation of arbitrary `NBitBase` subclasses
+class NBitBase:
+ """
+ An object representing `numpy.number` precision during static type checking.
+
+ Used exclusively for the purpose static type checking, `NBitBase`
+ represents the base of a hierachieral set of subclasses.
+ Each subsequent subclass is herein used for representing a lower level
+ of precision, *e.g.* ``64Bit > 32Bit > 16Bit``.
+
+ Examples
+ --------
+ Below is a typical usage example: `NBitBase` is herein used for annotating a
+ function that takes a float and integer of arbitrary precision as arguments
+ and returns a new float of whichever precision is largest
+ (*e.g.* ``np.float16 + np.int64 -> np.float64``).
+
+ .. code-block:: python
+
+ >>> from typing import TypeVar, TYPE_CHECKING
+ >>> import numpy as np
+ >>> import numpy.typing as npt
+
+ >>> T = TypeVar("T", bound=npt.NBitBase)
+
+ >>> def add(a: "np.floating[T]", b: "np.integer[T]") -> "np.floating[T]":
+ ... return a + b
+
+ >>> a = np.float16()
+ >>> b = np.int64()
+ >>> out = add(a, b)
+
+ >>> if TYPE_CHECKING:
+ ... reveal_locals()
+ ... # note: Revealed local types are:
+ ... # note: a: numpy.floating[numpy.typing._16Bit*]
+ ... # note: b: numpy.signedinteger[numpy.typing._64Bit*]
+ ... # note: out: numpy.floating[numpy.typing._64Bit*]
+
+ """
+
+ def __init_subclass__(cls) -> None:
+ allowed_names = {
+ "NBitBase", "_256Bit", "_128Bit", "_96Bit", "_80Bit",
+ "_64Bit", "_32Bit", "_16Bit", "_8Bit",
+ }
+ if cls.__name__ not in allowed_names:
+ raise TypeError('cannot inherit from final class "NBitBase"')
+ super().__init_subclass__()
+
+
+# Silence errors about subclassing a `@final`-decorated class
+class _256Bit(NBitBase): ... # type: ignore[misc]
+class _128Bit(_256Bit): ... # type: ignore[misc]
+class _96Bit(_128Bit): ... # type: ignore[misc]
+class _80Bit(_96Bit): ... # type: ignore[misc]
+class _64Bit(_80Bit): ... # type: ignore[misc]
+class _32Bit(_64Bit): ... # type: ignore[misc]
+class _16Bit(_32Bit): ... # type: ignore[misc]
+class _8Bit(_16Bit): ... # type: ignore[misc]
+
+# Clean up the namespace
+del TYPE_CHECKING, final, List
+
+from ._scalars import (
+ _CharLike,
+ _BoolLike,
+ _IntLike,
+ _FloatLike,
+ _ComplexLike,
+ _NumberLike,
+ _ScalarLike,
+ _VoidLike,
+)
+from ._array_like import _SupportsArray, ArrayLike as ArrayLike
+from ._shape import _Shape, _ShapeLike
+from ._dtype_like import _SupportsDType, _VoidDTypeLike, DTypeLike as DTypeLike
+
+if __doc__ is not None:
+ from ._add_docstring import _docstrings
+ __doc__ += _docstrings
+ __doc__ += '\n.. autoclass:: numpy.typing.NBitBase\n'
+ del _docstrings
+
+from numpy._pytesttester import PytestTester
+test = PytestTester(__name__)
+del PytestTester
--- /dev/null
+"""A module for creating docstrings for sphinx ``data`` domains."""
+
+import re
+import textwrap
+
+_docstrings_list = []
+
+
+def add_newdoc(name, value, doc):
+ _docstrings_list.append((name, value, doc))
+
+
+def _parse_docstrings():
+ type_list_ret = []
+ for name, value, doc in _docstrings_list:
+ s = textwrap.dedent(doc).replace("\n", "\n ")
+
+ # Replace sections by rubrics
+ lines = s.split("\n")
+ new_lines = []
+ indent = ""
+ for line in lines:
+ m = re.match(r'^(\s+)[-=]+\s*$', line)
+ if m and new_lines:
+ prev = textwrap.dedent(new_lines.pop())
+ if prev == "Examples":
+ indent = ""
+ new_lines.append(f'{m.group(1)}.. rubric:: {prev}')
+ else:
+ indent = 4 * " "
+ new_lines.append(f'{m.group(1)}.. admonition:: {prev}')
+ new_lines.append("")
+ else:
+ new_lines.append(f"{indent}{line}")
+ s = "\n".join(new_lines)
+
+ # Done.
+ type_list_ret.append(f""".. data:: {name}\n :value: {value}\n {s}""")
+ return "\n".join(type_list_ret)
+
+
+add_newdoc('ArrayLike', 'typing.Union[...]',
+ """
+ A `~typing.Union` representing objects that can be coerced into an `~numpy.ndarray`.
+
+ Among others this includes the likes of:
+
+ * Scalars.
+ * (Nested) sequences.
+ * Objects implementing the `~class.__array__` protocol.
+
+ See Also
+ --------
+ :term:`array_like`:
+ Any scalar or sequence that can be interpreted as an ndarray.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ >>> import numpy as np
+ >>> import numpy.typing as npt
+
+ >>> def as_array(a: npt.ArrayLike) -> np.ndarray:
+ ... return np.array(a)
+
+ """)
+
+add_newdoc('DTypeLike', 'typing.Union[...]',
+ """
+ A `~typing.Union` representing objects that can be coerced into a `~numpy.dtype`.
+
+ Among others this includes the likes of:
+
+ * :class:`type` objects.
+ * Character codes or the names of :class:`type` objects.
+ * Objects with the ``.dtype`` attribute.
+
+ See Also
+ --------
+ :ref:`Specifying and constructing data types <arrays.dtypes.constructing>`
+ A comprehensive overview of all objects that can be coerced into data types.
+
+ Examples
+ --------
+ .. code-block:: python
+
+ >>> import numpy as np
+ >>> import numpy.typing as npt
+
+ >>> def as_dtype(d: npt.DTypeLike) -> np.dtype:
+ ... return np.dtype(d)
+
+ """)
+
+_docstrings = _parse_docstrings()
--- /dev/null
+import sys
+from typing import Any, overload, Sequence, TYPE_CHECKING, Union
+
+from numpy import ndarray
+from ._scalars import _ScalarLike
+from ._dtype_like import DTypeLike
+
+if sys.version_info >= (3, 8):
+ from typing import Protocol
+ HAVE_PROTOCOL = True
+else:
+ try:
+ from typing_extensions import Protocol
+ except ImportError:
+ HAVE_PROTOCOL = False
+ else:
+ HAVE_PROTOCOL = True
+
+if TYPE_CHECKING or HAVE_PROTOCOL:
+ class _SupportsArray(Protocol):
+ @overload
+ def __array__(self, __dtype: DTypeLike = ...) -> ndarray: ...
+ @overload
+ def __array__(self, dtype: DTypeLike = ...) -> ndarray: ...
+else:
+ _SupportsArray = Any
+
+# TODO: support buffer protocols once
+#
+# https://bugs.python.org/issue27501
+#
+# is resolved. See also the mypy issue:
+#
+# https://github.com/python/typing/issues/593
+ArrayLike = Union[
+ _ScalarLike,
+ Sequence[_ScalarLike],
+ Sequence[Sequence[Any]], # TODO: Wait for support for recursive types
+ _SupportsArray,
+]
--- /dev/null
+"""
+A module with various ``typing.Protocol`` subclasses that implement
+the ``__call__`` magic method.
+
+See the `Mypy documentation`_ on protocols for more details.
+
+.. _`Mypy documentation`: https://mypy.readthedocs.io/en/stable/protocols.html#callback-protocols
+
+"""
+
+import sys
+from typing import (
+ Union,
+ TypeVar,
+ overload,
+ Any,
+ Tuple,
+ NoReturn,
+ TYPE_CHECKING,
+)
+
+from numpy import (
+ generic,
+ bool_,
+ timedelta64,
+ number,
+ integer,
+ unsignedinteger,
+ signedinteger,
+ int8,
+ floating,
+ float64,
+ complexfloating,
+ complex128,
+)
+from ._scalars import (
+ _BoolLike,
+ _IntLike,
+ _FloatLike,
+ _ComplexLike,
+ _NumberLike,
+)
+from . import NBitBase
+
+if sys.version_info >= (3, 8):
+ from typing import Protocol
+ HAVE_PROTOCOL = True
+else:
+ try:
+ from typing_extensions import Protocol
+ except ImportError:
+ HAVE_PROTOCOL = False
+ else:
+ HAVE_PROTOCOL = True
+
+if TYPE_CHECKING or HAVE_PROTOCOL:
+ _T = TypeVar("_T")
+ _2Tuple = Tuple[_T, _T]
+
+ _NBit_co = TypeVar("_NBit_co", covariant=True, bound=NBitBase)
+ _NBit = TypeVar("_NBit", bound=NBitBase)
+
+ _IntType = TypeVar("_IntType", bound=integer)
+ _FloatType = TypeVar("_FloatType", bound=floating)
+ _NumberType = TypeVar("_NumberType", bound=number)
+ _NumberType_co = TypeVar("_NumberType_co", covariant=True, bound=number)
+ _GenericType_co = TypeVar("_GenericType_co", covariant=True, bound=generic)
+
+ class _BoolOp(Protocol[_GenericType_co]):
+ @overload
+ def __call__(self, __other: _BoolLike) -> _GenericType_co: ...
+ @overload # platform dependent
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(self, __other: _NumberType) -> _NumberType: ...
+
+ class _BoolBitOp(Protocol[_GenericType_co]):
+ @overload
+ def __call__(self, __other: _BoolLike) -> _GenericType_co: ...
+ @overload # platform dependent
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(self, __other: _IntType) -> _IntType: ...
+
+ class _BoolSub(Protocol):
+ # Note that `__other: bool_` is absent here
+ @overload
+ def __call__(self, __other: bool) -> NoReturn: ...
+ @overload # platform dependent
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(self, __other: _NumberType) -> _NumberType: ...
+
+ class _BoolTrueDiv(Protocol):
+ @overload
+ def __call__(self, __other: Union[float, _IntLike, _BoolLike]) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(self, __other: _NumberType) -> _NumberType: ...
+
+ class _BoolMod(Protocol):
+ @overload
+ def __call__(self, __other: _BoolLike) -> int8: ...
+ @overload # platform dependent
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: _IntType) -> _IntType: ...
+ @overload
+ def __call__(self, __other: _FloatType) -> _FloatType: ...
+
+ class _BoolDivMod(Protocol):
+ @overload
+ def __call__(self, __other: _BoolLike) -> _2Tuple[int8]: ...
+ @overload # platform dependent
+ def __call__(self, __other: int) -> _2Tuple[signedinteger[Any]]: ...
+ @overload
+ def __call__(self, __other: float) -> _2Tuple[float64]: ...
+ @overload
+ def __call__(self, __other: _IntType) -> _2Tuple[_IntType]: ...
+ @overload
+ def __call__(self, __other: _FloatType) -> _2Tuple[_FloatType]: ...
+
+ class _TD64Div(Protocol[_NumberType_co]):
+ @overload
+ def __call__(self, __other: timedelta64) -> _NumberType_co: ...
+ @overload
+ def __call__(self, __other: _FloatLike) -> timedelta64: ...
+
+ class _IntTrueDiv(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> floating[_NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> floating[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(self, __other: integer[_NBit]) -> floating[Union[_NBit_co, _NBit]]: ...
+
+ class _UnsignedIntOp(Protocol[_NBit_co]):
+ # NOTE: `uint64 + signedinteger -> float64`
+ @overload
+ def __call__(self, __other: bool) -> unsignedinteger[_NBit_co]: ...
+ @overload
+ def __call__(
+ self, __other: Union[int, signedinteger[Any]]
+ ) -> Union[signedinteger[Any], float64]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(
+ self, __other: unsignedinteger[_NBit]
+ ) -> unsignedinteger[Union[_NBit_co, _NBit]]: ...
+
+ class _UnsignedIntBitOp(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> unsignedinteger[_NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(self, __other: signedinteger[Any]) -> signedinteger[Any]: ...
+ @overload
+ def __call__(
+ self, __other: unsignedinteger[_NBit]
+ ) -> unsignedinteger[Union[_NBit_co, _NBit]]: ...
+
+ class _UnsignedIntMod(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> unsignedinteger[_NBit_co]: ...
+ @overload
+ def __call__(
+ self, __other: Union[int, signedinteger[Any]]
+ ) -> Union[signedinteger[Any], float64]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(
+ self, __other: unsignedinteger[_NBit]
+ ) -> unsignedinteger[Union[_NBit_co, _NBit]]: ...
+
+ class _UnsignedIntDivMod(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> _2Tuple[signedinteger[_NBit_co]]: ...
+ @overload
+ def __call__(
+ self, __other: Union[int, signedinteger[Any]]
+ ) -> Union[_2Tuple[signedinteger[Any]], _2Tuple[float64]]: ...
+ @overload
+ def __call__(self, __other: float) -> _2Tuple[float64]: ...
+ @overload
+ def __call__(
+ self, __other: unsignedinteger[_NBit]
+ ) -> _2Tuple[unsignedinteger[Union[_NBit_co, _NBit]]]: ...
+
+ class _SignedIntOp(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> signedinteger[_NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(
+ self, __other: signedinteger[_NBit]
+ ) -> signedinteger[Union[_NBit_co, _NBit]]: ...
+
+ class _SignedIntBitOp(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> signedinteger[_NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(
+ self, __other: signedinteger[_NBit]
+ ) -> signedinteger[Union[_NBit_co, _NBit]]: ...
+
+ class _SignedIntMod(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> signedinteger[_NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> signedinteger[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(
+ self, __other: signedinteger[_NBit]
+ ) -> signedinteger[Union[_NBit_co, _NBit]]: ...
+
+ class _SignedIntDivMod(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> _2Tuple[signedinteger[_NBit_co]]: ...
+ @overload
+ def __call__(self, __other: int) -> _2Tuple[signedinteger[Any]]: ...
+ @overload
+ def __call__(self, __other: float) -> _2Tuple[float64]: ...
+ @overload
+ def __call__(
+ self, __other: signedinteger[_NBit]
+ ) -> _2Tuple[signedinteger[Union[_NBit_co, _NBit]]]: ...
+
+ class _FloatOp(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> floating[_NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> floating[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(self, __other: complex) -> complex128: ...
+ @overload
+ def __call__(
+ self, __other: Union[integer[_NBit], floating[_NBit]]
+ ) -> floating[Union[_NBit_co, _NBit]]: ...
+
+ class _FloatMod(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> floating[_NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> floating[Any]: ...
+ @overload
+ def __call__(self, __other: float) -> float64: ...
+ @overload
+ def __call__(
+ self, __other: Union[integer[_NBit], floating[_NBit]]
+ ) -> floating[Union[_NBit_co, _NBit]]: ...
+
+ class _FloatDivMod(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> _2Tuple[floating[_NBit_co]]: ...
+ @overload
+ def __call__(self, __other: int) -> _2Tuple[floating[Any]]: ...
+ @overload
+ def __call__(self, __other: float) -> _2Tuple[float64]: ...
+ @overload
+ def __call__(
+ self, __other: Union[integer[_NBit], floating[_NBit]]
+ ) -> _2Tuple[floating[Union[_NBit_co, _NBit]]]: ...
+
+ class _ComplexOp(Protocol[_NBit_co]):
+ @overload
+ def __call__(self, __other: bool) -> complexfloating[_NBit_co, _NBit_co]: ...
+ @overload
+ def __call__(self, __other: int) -> complexfloating[Any, Any]: ...
+ @overload
+ def __call__(self, __other: Union[float, complex]) -> complex128: ...
+ @overload
+ def __call__(
+ self,
+ __other: Union[
+ integer[_NBit],
+ floating[_NBit],
+ complexfloating[_NBit, _NBit],
+ ]
+ ) -> complexfloating[Union[_NBit_co, _NBit], Union[_NBit_co, _NBit]]: ...
+
+ class _NumberOp(Protocol):
+ def __call__(self, __other: _NumberLike) -> number: ...
+
+else:
+ _BoolOp = Any
+ _BoolBitOp = Any
+ _BoolSub = Any
+ _BoolTrueDiv = Any
+ _BoolMod = Any
+ _BoolDivMod = Any
+ _TD64Div = Any
+ _IntTrueDiv = Any
+ _UnsignedIntOp = Any
+ _UnsignedIntBitOp = Any
+ _UnsignedIntMod = Any
+ _UnsignedIntDivMod = Any
+ _SignedIntOp = Any
+ _SignedIntBitOp = Any
+ _SignedIntMod = Any
+ _SignedIntDivMod = Any
+ _FloatOp = Any
+ _FloatMod = Any
+ _FloatDivMod = Any
+ _ComplexOp = Any
+ _NumberOp = Any
--- /dev/null
+import sys
+from typing import Any, List, Sequence, Tuple, Union, TYPE_CHECKING
+
+from numpy import dtype
+from ._shape import _ShapeLike
+
+if sys.version_info >= (3, 8):
+ from typing import Protocol, TypedDict
+ HAVE_PROTOCOL = True
+else:
+ try:
+ from typing_extensions import Protocol, TypedDict
+ except ImportError:
+ HAVE_PROTOCOL = False
+ else:
+ HAVE_PROTOCOL = True
+
+_DTypeLikeNested = Any # TODO: wait for support for recursive types
+
+if TYPE_CHECKING or HAVE_PROTOCOL:
+ # Mandatory keys
+ class _DTypeDictBase(TypedDict):
+ names: Sequence[str]
+ formats: Sequence[_DTypeLikeNested]
+
+ # Mandatory + optional keys
+ class _DTypeDict(_DTypeDictBase, total=False):
+ offsets: Sequence[int]
+ titles: Sequence[Any] # Only `str` elements are usable as indexing aliases, but all objects are legal
+ itemsize: int
+ aligned: bool
+
+ # A protocol for anything with the dtype attribute
+ class _SupportsDType(Protocol):
+ dtype: _DTypeLikeNested
+
+else:
+ _DTypeDict = Any
+ _SupportsDType = Any
+
+
+# Would create a dtype[np.void]
+_VoidDTypeLike = Union[
+ # (flexible_dtype, itemsize)
+ Tuple[_DTypeLikeNested, int],
+ # (fixed_dtype, shape)
+ Tuple[_DTypeLikeNested, _ShapeLike],
+ # [(field_name, field_dtype, field_shape), ...]
+ #
+ # The type here is quite broad because NumPy accepts quite a wide
+ # range of inputs inside the list; see the tests for some
+ # examples.
+ List[Any],
+ # {'names': ..., 'formats': ..., 'offsets': ..., 'titles': ...,
+ # 'itemsize': ...}
+ _DTypeDict,
+ # (base_dtype, new_dtype)
+ Tuple[_DTypeLikeNested, _DTypeLikeNested],
+]
+
+# Anything that can be coerced into numpy.dtype.
+# Reference: https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
+DTypeLike = Union[
+ dtype,
+ # default data type (float64)
+ None,
+ # array-scalar types and generic types
+ type, # TODO: enumerate these when we add type hints for numpy scalars
+ # anything with a dtype attribute
+ _SupportsDType,
+ # character codes, type strings or comma-separated fields, e.g., 'float64'
+ str,
+ _VoidDTypeLike,
+]
+
+# NOTE: while it is possible to provide the dtype as a dict of
+# dtype-like objects (e.g. `{'field1': ..., 'field2': ..., ...}`),
+# this syntax is officially discourged and
+# therefore not included in the Union defining `DTypeLike`.
+#
+# See https://github.com/numpy/numpy/issues/16891 for more details.
--- /dev/null
+from typing import Union, Tuple, Any
+
+import numpy as np
+
+# NOTE: `_StrLike` and `_BytesLike` are pointless, as `np.str_` and `np.bytes_`
+# are already subclasses of their builtin counterpart
+
+_CharLike = Union[str, bytes]
+
+_BoolLike = Union[bool, np.bool_]
+_IntLike = Union[int, np.integer]
+_FloatLike = Union[_IntLike, float, np.floating]
+_ComplexLike = Union[_FloatLike, complex, np.complexfloating]
+_NumberLike = Union[int, float, complex, np.number, np.bool_]
+
+_ScalarLike = Union[
+ int,
+ float,
+ complex,
+ str,
+ bytes,
+ np.generic,
+]
+
+# `_VoidLike` is technically not a scalar, but it's close enough
+_VoidLike = Union[Tuple[Any, ...], np.void]
--- /dev/null
+from typing import Sequence, Tuple, Union
+
+_Shape = Tuple[int, ...]
+
+# Anything that can be coerced to a shape tuple
+_ShapeLike = Union[int, Sequence[int]]
--- /dev/null
+def configuration(parent_package='', top_path=None):
+ from numpy.distutils.misc_util import Configuration
+ config = Configuration('typing', parent_package, top_path)
+ config.add_subpackage('tests')
+ config.add_data_dir('tests/data')
+ return config
+
+
+if __name__ == '__main__':
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
--- /dev/null
+import numpy as np
+
+b_ = np.bool_()
+dt = np.datetime64(0, "D")
+td = np.timedelta64(0, "D")
+
+b_ - b_ # E: No overload variant
+
+dt + dt # E: Unsupported operand types
+td - dt # E: Unsupported operand types
+td % 1 # E: Unsupported operand types
+td / dt # E: No overload
+td % dt # E: Unsupported operand types
+
+-b_ # E: Unsupported operand type
++b_ # E: Unsupported operand type
--- /dev/null
+import numpy as np
+
+a: np.ndarray
+generator = (i for i in range(10))
+
+np.require(a, requirements=1) # E: No overload variant
+np.require(a, requirements="TEST") # E: incompatible type
+
+np.zeros("test") # E: incompatible type
+np.zeros() # E: Too few arguments
+
+np.ones("test") # E: incompatible type
+np.ones() # E: Too few arguments
+
+np.array(0, float, True) # E: Too many positional
+
+np.linspace(None, 'bob') # E: No overload variant
+np.linspace(0, 2, num=10.0) # E: No overload variant
+np.linspace(0, 2, endpoint='True') # E: No overload variant
+np.linspace(0, 2, retstep=b'False') # E: No overload variant
+np.linspace(0, 2, dtype=0) # E: No overload variant
+np.linspace(0, 2, axis=None) # E: No overload variant
+
+np.logspace(None, 'bob') # E: Argument 1
+np.logspace(0, 2, base=None) # E: Argument "base"
+
+np.geomspace(None, 'bob') # E: Argument 1
+
+np.stack(generator) # E: No overload variant
+np.hstack({1, 2}) # E: incompatible type
+np.vstack(1) # E: incompatible type
--- /dev/null
+import numpy as np
+from numpy.typing import ArrayLike
+
+
+class A:
+ pass
+
+
+x1: ArrayLike = (i for i in range(10)) # E: Incompatible types in assignment
+x2: ArrayLike = A() # E: Incompatible types in assignment
+x3: ArrayLike = {1: "foo", 2: "bar"} # E: Incompatible types in assignment
+
+scalar = np.int64(1)
+scalar.__array__(dtype=np.float64) # E: Unexpected keyword argument
+array = np.array([1])
+array.__array__(dtype=np.float64) # E: Unexpected keyword argument
--- /dev/null
+import numpy as np
+
+i8 = np.int64()
+i4 = np.int32()
+u8 = np.uint64()
+b_ = np.bool_()
+i = int()
+
+f8 = np.float64()
+
+b_ >> f8 # E: No overload variant
+i8 << f8 # E: No overload variant
+i | f8 # E: Unsupported operand types
+i8 ^ f8 # E: No overload variant
+u8 & f8 # E: No overload variant
+~f8 # E: Unsupported operand type
+
+# mypys' error message for `NoReturn` is unfortunately pretty bad
+# TODO: Reenable this once we add support for numerical precision for `number`s
+# a = u8 | 0 # E: Need type annotation
--- /dev/null
+import numpy as np
+
+np.Inf = np.Inf # E: Cannot assign to final
+np.ALLOW_THREADS = np.ALLOW_THREADS # E: Cannot assign to final
+np.little_endian = np.little_endian # E: Cannot assign to final
+np.UFUNC_PYVALS_NAME = np.UFUNC_PYVALS_NAME # E: Cannot assign to final
--- /dev/null
+import numpy as np
+
+class Test:
+ not_dtype = float
+
+
+np.dtype(Test()) # E: No overload variant of "dtype" matches
+
+np.dtype( # E: No overload variant of "dtype" matches
+ {
+ "field1": (float, 1),
+ "field2": (int, 3),
+ }
+)
+
+np.dtype[np.float64](np.int64) # E: Argument 1 to "dtype" has incompatible type
--- /dev/null
+from typing import Any
+
+import numpy as np
+from numpy.typing import _SupportsArray
+
+
+class Index:
+ def __index__(self) -> int:
+ ...
+
+
+a: "np.flatiter[np.ndarray]"
+supports_array: _SupportsArray
+
+a.base = Any # E: Property "base" defined in "flatiter" is read-only
+a.coords = Any # E: Property "coords" defined in "flatiter" is read-only
+a.index = Any # E: Property "index" defined in "flatiter" is read-only
+a.copy(order='C') # E: Unexpected keyword argument
+
+# NOTE: Contrary to `ndarray.__getitem__` its counterpart in `flatiter`
+# does not accept objects with the `__array__` or `__index__` protocols;
+# boolean indexing is just plain broken (gh-17175)
+a[np.bool_()] # E: No overload variant of "__getitem__"
+a[Index()] # E: No overload variant of "__getitem__"
+a[supports_array] # E: No overload variant of "__getitem__"
--- /dev/null
+"""Tests for :mod:`numpy.core.fromnumeric`."""
+
+import numpy as np
+
+A = np.array(True, ndmin=2, dtype=bool)
+A.setflags(write=False)
+
+a = np.bool_(True)
+
+np.take(a, None) # E: No overload variant of "take" matches argument type
+np.take(a, axis=1.0) # E: No overload variant of "take" matches argument type
+np.take(A, out=1) # E: No overload variant of "take" matches argument type
+np.take(A, mode="bob") # E: No overload variant of "take" matches argument type
+
+np.reshape(a, None) # E: Argument 2 to "reshape" has incompatible type
+np.reshape(A, 1, order="bob") # E: Argument "order" to "reshape" has incompatible type
+
+np.choose(a, None) # E: No overload variant of "choose" matches argument type
+np.choose(a, out=1.0) # E: No overload variant of "choose" matches argument type
+np.choose(A, mode="bob") # E: No overload variant of "choose" matches argument type
+
+np.repeat(a, None) # E: Argument 2 to "repeat" has incompatible type
+np.repeat(A, 1, axis=1.0) # E: Argument "axis" to "repeat" has incompatible type
+
+np.swapaxes(A, None, 1) # E: Argument 2 to "swapaxes" has incompatible type
+np.swapaxes(A, 1, [0]) # E: Argument 3 to "swapaxes" has incompatible type
+
+np.transpose(A, axes=1.0) # E: Argument "axes" to "transpose" has incompatible type
+
+np.partition(a, None) # E: Argument 2 to "partition" has incompatible type
+np.partition(
+ a, 0, axis="bob" # E: Argument "axis" to "partition" has incompatible type
+)
+np.partition(
+ A, 0, kind="bob" # E: Argument "kind" to "partition" has incompatible type
+)
+np.partition(
+ A, 0, order=range(5) # E: Argument "order" to "partition" has incompatible type
+)
+
+np.argpartition( # E: No overload variant of "argpartition" matches argument type
+ a, None
+)
+np.argpartition( # E: No overload variant of "argpartition" matches argument type
+ a, 0, axis="bob"
+)
+np.argpartition( # E: No overload variant of "argpartition" matches argument type
+ A, 0, kind="bob"
+)
+np.argpartition(
+ A, 0, order=range(5) # E: Argument "order" to "argpartition" has incompatible type
+)
+
+np.sort(A, axis="bob") # E: Argument "axis" to "sort" has incompatible type
+np.sort(A, kind="bob") # E: Argument "kind" to "sort" has incompatible type
+np.sort(A, order=range(5)) # E: Argument "order" to "sort" has incompatible type
+
+np.argsort(A, axis="bob") # E: Argument "axis" to "argsort" has incompatible type
+np.argsort(A, kind="bob") # E: Argument "kind" to "argsort" has incompatible type
+np.argsort(A, order=range(5)) # E: Argument "order" to "argsort" has incompatible type
+
+np.argmax(A, axis="bob") # E: No overload variant of "argmax" matches argument type
+np.argmax(A, kind="bob") # E: No overload variant of "argmax" matches argument type
+
+np.argmin(A, axis="bob") # E: No overload variant of "argmin" matches argument type
+np.argmin(A, kind="bob") # E: No overload variant of "argmin" matches argument type
+
+np.searchsorted( # E: No overload variant of "searchsorted" matches argument type
+ A[0], 0, side="bob"
+)
+np.searchsorted( # E: No overload variant of "searchsorted" matches argument type
+ A[0], 0, sorter=1.0
+)
+
+np.resize(A, 1.0) # E: Argument 2 to "resize" has incompatible type
+
+np.squeeze(A, 1.0) # E: No overload variant of "squeeze" matches argument type
+
+np.diagonal(A, offset=None) # E: Argument "offset" to "diagonal" has incompatible type
+np.diagonal(A, axis1="bob") # E: Argument "axis1" to "diagonal" has incompatible type
+np.diagonal(A, axis2=[]) # E: Argument "axis2" to "diagonal" has incompatible type
+
+np.trace(A, offset=None) # E: Argument "offset" to "trace" has incompatible type
+np.trace(A, axis1="bob") # E: Argument "axis1" to "trace" has incompatible type
+np.trace(A, axis2=[]) # E: Argument "axis2" to "trace" has incompatible type
+
+np.ravel(a, order="bob") # E: Argument "order" to "ravel" has incompatible type
+
+np.compress(
+ [True], A, axis=1.0 # E: Argument "axis" to "compress" has incompatible type
+)
+
+np.clip(a, 1, 2, out=1) # E: No overload variant of "clip" matches argument type
+np.clip(1, None, None) # E: No overload variant of "clip" matches argument type
+
+np.sum(a, axis=1.0) # E: No overload variant of "sum" matches argument type
+np.sum(a, keepdims=1.0) # E: No overload variant of "sum" matches argument type
+np.sum(a, initial=[1]) # E: No overload variant of "sum" matches argument type
+
+np.all(a, axis=1.0) # E: No overload variant of "all" matches argument type
+np.all(a, keepdims=1.0) # E: No overload variant of "all" matches argument type
+np.all(a, out=1.0) # E: No overload variant of "all" matches argument type
+
+np.any(a, axis=1.0) # E: No overload variant of "any" matches argument type
+np.any(a, keepdims=1.0) # E: No overload variant of "any" matches argument type
+np.any(a, out=1.0) # E: No overload variant of "any" matches argument type
+
+np.cumsum(a, axis=1.0) # E: Argument "axis" to "cumsum" has incompatible type
+np.cumsum(a, dtype=1.0) # E: Argument "dtype" to "cumsum" has incompatible type
+np.cumsum(a, out=1.0) # E: Argument "out" to "cumsum" has incompatible type
+
+np.ptp(a, axis=1.0) # E: No overload variant of "ptp" matches argument type
+np.ptp(a, keepdims=1.0) # E: No overload variant of "ptp" matches argument type
+np.ptp(a, out=1.0) # E: No overload variant of "ptp" matches argument type
+
+np.amax(a, axis=1.0) # E: No overload variant of "amax" matches argument type
+np.amax(a, keepdims=1.0) # E: No overload variant of "amax" matches argument type
+np.amax(a, out=1.0) # E: No overload variant of "amax" matches argument type
+np.amax(a, initial=[1.0]) # E: No overload variant of "amax" matches argument type
+np.amax(a, where=[1.0]) # E: List item 0 has incompatible type
+
+np.amin(a, axis=1.0) # E: No overload variant of "amin" matches argument type
+np.amin(a, keepdims=1.0) # E: No overload variant of "amin" matches argument type
+np.amin(a, out=1.0) # E: No overload variant of "amin" matches argument type
+np.amin(a, initial=[1.0]) # E: No overload variant of "amin" matches argument type
+np.amin(a, where=[1.0]) # E: List item 0 has incompatible type
+
+np.prod(a, axis=1.0) # E: No overload variant of "prod" matches argument type
+np.prod(a, out=False) # E: No overload variant of "prod" matches argument type
+np.prod(a, keepdims=1.0) # E: No overload variant of "prod" matches argument type
+np.prod(a, initial=int) # E: No overload variant of "prod" matches argument type
+np.prod(a, where=1.0) # E: No overload variant of "prod" matches argument type
+
+np.cumprod(a, axis=1.0) # E: Argument "axis" to "cumprod" has incompatible type
+np.cumprod(a, out=False) # E: Argument "out" to "cumprod" has incompatible type
+
+np.size(a, axis=1.0) # E: Argument "axis" to "size" has incompatible type
+
+np.around(a, decimals=1.0) # E: No overload variant of "around" matches argument type
+np.around(a, out=type) # E: No overload variant of "around" matches argument type
+
+np.mean(a, axis=1.0) # E: No overload variant of "mean" matches argument type
+np.mean(a, out=False) # E: No overload variant of "mean" matches argument type
+np.mean(a, keepdims=1.0) # E: No overload variant of "mean" matches argument type
+
+np.std(a, axis=1.0) # E: No overload variant of "std" matches argument type
+np.std(a, out=False) # E: No overload variant of "std" matches argument type
+np.std(a, ddof='test') # E: No overload variant of "std" matches argument type
+np.std(a, keepdims=1.0) # E: No overload variant of "std" matches argument type
+
+np.var(a, axis=1.0) # E: No overload variant of "var" matches argument type
+np.var(a, out=False) # E: No overload variant of "var" matches argument type
+np.var(a, ddof='test') # E: No overload variant of "var" matches argument type
+np.var(a, keepdims=1.0) # E: No overload variant of "var" matches argument type
--- /dev/null
+import numpy as np
+
+np.testing.bob # E: Module has no attribute
+np.bob # E: Module has no attribute
+
+# Stdlib modules in the namespace by accident
+np.warnings # E: Module has no attribute
+np.sys # E: Module has no attribute
+np.os # E: Module has no attribute
+np.math # E: Module has no attribute
--- /dev/null
+import numpy as np
+
+# Ban setting dtype since mutating the type of the array in place
+# makes having ndarray be generic over dtype impossible. Generally
+# users should use `ndarray.view` in this situation anyway. See
+#
+# https://github.com/numpy/numpy-stubs/issues/7
+#
+# for more context.
+float_array = np.array([1.0])
+float_array.dtype = np.bool_ # E: Property "dtype" defined in "ndarray" is read-only
--- /dev/null
+"""
+Tests for miscellaneous (non-magic) ``np.ndarray``/``np.generic`` methods.
+
+More extensive tests are performed for the methods'
+function-based counterpart in `../from_numeric.py`.
+
+"""
+
+import numpy as np
+
+f8: np.float64
+
+f8.argpartition(0) # E: has no attribute
+f8.diagonal() # E: has no attribute
+f8.dot(1) # E: has no attribute
+f8.nonzero() # E: has no attribute
+f8.partition(0) # E: has no attribute
+f8.put(0, 2) # E: has no attribute
+f8.setfield(2, np.float64) # E: has no attribute
+f8.sort() # E: has no attribute
+f8.trace() # E: has no attribute
--- /dev/null
+import numpy as np
+
+# Techincally this works, but probably shouldn't. See
+#
+# https://github.com/numpy/numpy/issues/16366
+#
+np.maximum_sctype(1) # E: incompatible type "int"
+
+np.issubsctype(1, np.int64) # E: incompatible type "int"
+
+np.issubdtype(1, np.int64) # E: incompatible type "int"
+
+np.find_common_type(np.int64, np.int64) # E: incompatible type "Type[signedinteger[Any]]"
--- /dev/null
+import numpy as np
+
+f8: np.float64
+
+# Construction
+
+np.float32(3j) # E: incompatible type
+
+# Technically the following examples are valid NumPy code. But they
+# are not considered a best practice, and people who wish to use the
+# stubs should instead do
+#
+# np.array([1.0, 0.0, 0.0], dtype=np.float32)
+# np.array([], dtype=np.complex64)
+#
+# See e.g. the discussion on the mailing list
+#
+# https://mail.python.org/pipermail/numpy-discussion/2020-April/080566.html
+#
+# and the issue
+#
+# https://github.com/numpy/numpy-stubs/issues/41
+#
+# for more context.
+np.float32([1.0, 0.0, 0.0]) # E: incompatible type
+np.complex64([]) # E: incompatible type
+
+np.complex64(1, 2) # E: Too many arguments
+# TODO: protocols (can't check for non-existent protocols w/ __getattr__)
+
+np.datetime64(0) # E: non-matching overload
+
+class A:
+ def __float__(self):
+ return 1.0
+
+
+np.int8(A()) # E: incompatible type
+np.int16(A()) # E: incompatible type
+np.int32(A()) # E: incompatible type
+np.int64(A()) # E: incompatible type
+np.uint8(A()) # E: incompatible type
+np.uint16(A()) # E: incompatible type
+np.uint32(A()) # E: incompatible type
+np.uint64(A()) # E: incompatible type
+
+np.void("test") # E: incompatible type
+
+np.generic(1) # E: Cannot instantiate abstract class
+np.number(1) # E: Cannot instantiate abstract class
+np.integer(1) # E: Cannot instantiate abstract class
+np.inexact(1) # E: Cannot instantiate abstract class
+np.character("test") # E: Cannot instantiate abstract class
+np.flexible(b"test") # E: Cannot instantiate abstract class
+
+np.float64(value=0.0) # E: Unexpected keyword argument
+np.int64(value=0) # E: Unexpected keyword argument
+np.uint64(value=0) # E: Unexpected keyword argument
+np.complex128(value=0.0j) # E: Unexpected keyword argument
+np.str_(value='bob') # E: No overload variant
+np.bytes_(value=b'test') # E: No overload variant
+np.void(value=b'test') # E: Unexpected keyword argument
+np.bool_(value=True) # E: Unexpected keyword argument
+np.datetime64(value="2019") # E: No overload variant
+np.timedelta64(value=0) # E: Unexpected keyword argument
+
+np.bytes_(b"hello", encoding='utf-8') # E: No overload variant
+np.str_("hello", encoding='utf-8') # E: No overload variant
+
+complex(np.bytes_("1")) # E: No overload variant
+
+f8.item(1) # E: incompatible type
+f8.item((0, 1)) # E: incompatible type
+f8.squeeze(axis=1) # E: incompatible type
+f8.squeeze(axis=(0, 1)) # E: incompatible type
+f8.transpose(1) # E: incompatible type
--- /dev/null
+"""Typing tests for `numpy.core._ufunc_config`."""
+
+import numpy as np
+
+def func1(a: str, b: int, c: float) -> None: ...
+def func2(a: str, *, b: int) -> None: ...
+
+class Write1:
+ def write1(self, a: str) -> None: ...
+
+class Write2:
+ def write(self, a: str, b: str) -> None: ...
+
+class Write3:
+ def write(self, *, a: str) -> None: ...
+
+np.seterrcall(func1) # E: Argument 1 to "seterrcall" has incompatible type
+np.seterrcall(func2) # E: Argument 1 to "seterrcall" has incompatible type
+np.seterrcall(Write1()) # E: Argument 1 to "seterrcall" has incompatible type
+np.seterrcall(Write2()) # E: Argument 1 to "seterrcall" has incompatible type
+np.seterrcall(Write3()) # E: Argument 1 to "seterrcall" has incompatible type
--- /dev/null
+import numpy as np
+
+np.sin.nin + "foo" # E: Unsupported operand types
+np.sin(1, foo="bar") # E: Unexpected keyword argument
+np.sin(1, extobj=["foo", "foo", "foo"]) # E: incompatible type
+
+np.abs(None) # E: incompatible type
--- /dev/null
+import numpy as np
+
+np.AxisError(1.0) # E: Argument 1 to "AxisError" has incompatible type
+np.AxisError(1, ndim=2.0) # E: Argument "ndim" to "AxisError" has incompatible type
+np.AxisError(
+ 2, msg_prefix=404 # E: Argument "msg_prefix" to "AxisError" has incompatible type
+)
--- /dev/null
+[mypy]
+mypy_path = ../../..
+
+[mypy-numpy]
+ignore_errors = True
+
+[mypy-numpy.*]
+ignore_errors = True
--- /dev/null
+import numpy as np
+
+c16 = np.complex128(1)
+f8 = np.float64(1)
+i8 = np.int64(1)
+u8 = np.uint64(1)
+
+c8 = np.complex64(1)
+f4 = np.float32(1)
+i4 = np.int32(1)
+u4 = np.uint32(1)
+
+dt = np.datetime64(1, "D")
+td = np.timedelta64(1, "D")
+
+b_ = np.bool_(1)
+
+b = bool(1)
+c = complex(1)
+f = float(1)
+i = int(1)
+
+AR = np.ones(1, dtype=np.float64)
+AR.setflags(write=False)
+
+# unary ops
+
+-c16
+-c8
+-f8
+-f4
+-i8
+-i4
+-u8
+-u4
+-td
+-AR
+
++c16
++c8
++f8
++f4
++i8
++i4
++u8
++u4
++td
++AR
+
+abs(c16)
+abs(c8)
+abs(f8)
+abs(f4)
+abs(i8)
+abs(i4)
+abs(u8)
+abs(u4)
+abs(td)
+abs(b_)
+abs(AR)
+
+# Time structures
+
+dt + td
+dt + i
+dt + i4
+dt + i8
+dt - dt
+dt - i
+dt - i4
+dt - i8
+
+td + td
+td + i
+td + i4
+td + i8
+td - td
+td - i
+td - i4
+td - i8
+td / f
+td / f4
+td / f8
+td / td
+td // td
+td % td
+
+
+# boolean
+
+b_ / b
+b_ / b_
+b_ / i
+b_ / i8
+b_ / i4
+b_ / u8
+b_ / u4
+b_ / f
+b_ / f8
+b_ / f4
+b_ / c
+b_ / c16
+b_ / c8
+
+b / b_
+b_ / b_
+i / b_
+i8 / b_
+i4 / b_
+u8 / b_
+u4 / b_
+f / b_
+f8 / b_
+f4 / b_
+c / b_
+c16 / b_
+c8 / b_
+
+# Complex
+
+c16 + c16
+c16 + f8
+c16 + i8
+c16 + c8
+c16 + f4
+c16 + i4
+c16 + b_
+c16 + b
+c16 + c
+c16 + f
+c16 + i
+c16 + AR
+
+c16 + c16
+f8 + c16
+i8 + c16
+c8 + c16
+f4 + c16
+i4 + c16
+b_ + c16
+b + c16
+c + c16
+f + c16
+i + c16
+AR + c16
+
+c8 + c16
+c8 + f8
+c8 + i8
+c8 + c8
+c8 + f4
+c8 + i4
+c8 + b_
+c8 + b
+c8 + c
+c8 + f
+c8 + i
+c8 + AR
+
+c16 + c8
+f8 + c8
+i8 + c8
+c8 + c8
+f4 + c8
+i4 + c8
+b_ + c8
+b + c8
+c + c8
+f + c8
+i + c8
+AR + c8
+
+# Float
+
+f8 + f8
+f8 + i8
+f8 + f4
+f8 + i4
+f8 + b_
+f8 + b
+f8 + c
+f8 + f
+f8 + i
+f8 + AR
+
+f8 + f8
+i8 + f8
+f4 + f8
+i4 + f8
+b_ + f8
+b + f8
+c + f8
+f + f8
+i + f8
+AR + f8
+
+f4 + f8
+f4 + i8
+f4 + f4
+f4 + i4
+f4 + b_
+f4 + b
+f4 + c
+f4 + f
+f4 + i
+f4 + AR
+
+f8 + f4
+i8 + f4
+f4 + f4
+i4 + f4
+b_ + f4
+b + f4
+c + f4
+f + f4
+i + f4
+AR + f4
+
+# Int
+
+i8 + i8
+i8 + u8
+i8 + i4
+i8 + u4
+i8 + b_
+i8 + b
+i8 + c
+i8 + f
+i8 + i
+i8 + AR
+
+u8 + u8
+u8 + i4
+u8 + u4
+u8 + b_
+u8 + b
+u8 + c
+u8 + f
+u8 + i
+u8 + AR
+
+i8 + i8
+u8 + i8
+i4 + i8
+u4 + i8
+b_ + i8
+b + i8
+c + i8
+f + i8
+i + i8
+AR + i8
+
+u8 + u8
+i4 + u8
+u4 + u8
+b_ + u8
+b + u8
+c + u8
+f + u8
+i + u8
+AR + u8
+
+i4 + i8
+i4 + i4
+i4 + i
+i4 + b_
+i4 + b
+i4 + AR
+
+u4 + i8
+u4 + i4
+u4 + u8
+u4 + u4
+u4 + i
+u4 + b_
+u4 + b
+u4 + AR
+
+i8 + i4
+i4 + i4
+i + i4
+b_ + i4
+b + i4
+AR + i4
+
+i8 + u4
+i4 + u4
+u8 + u4
+u4 + u4
+b_ + u4
+b + u4
+i + u4
+AR + u4
--- /dev/null
+from typing import List, Any
+import numpy as np
+
+class Index:
+ def __index__(self) -> int:
+ return 0
+
+class SubClass(np.ndarray): ...
+
+i8 = np.int64(1)
+
+A = np.array([1])
+B = A.view(SubClass).copy()
+B_stack = np.array([[1], [1]]).view(SubClass)
+C = [1]
+
+def func(i: int, j: int, **kwargs: Any) -> SubClass:
+ return B
+
+np.array(1, dtype=float)
+np.array(1, copy=False)
+np.array(1, order='F')
+np.array(1, order=None)
+np.array(1, subok=True)
+np.array(1, ndmin=3)
+np.array(1, str, copy=True, order='C', subok=False, ndmin=2)
+
+np.asarray(A)
+np.asarray(B)
+np.asarray(C)
+
+np.asanyarray(A)
+np.asanyarray(B)
+np.asanyarray(B, dtype=int)
+np.asanyarray(C)
+
+np.ascontiguousarray(A)
+np.ascontiguousarray(B)
+np.ascontiguousarray(C)
+
+np.asfortranarray(A)
+np.asfortranarray(B)
+np.asfortranarray(C)
+
+np.require(A)
+np.require(B)
+np.require(B, dtype=int)
+np.require(B, requirements=None)
+np.require(B, requirements="E")
+np.require(B, requirements=["ENSUREARRAY"])
+np.require(B, requirements={"F", "E"})
+np.require(B, requirements=["C", "OWNDATA"])
+np.require(B, requirements="W")
+np.require(B, requirements="A")
+np.require(C)
+
+np.linspace(0, 2)
+np.linspace(0.5, [0, 1, 2])
+np.linspace([0, 1, 2], 3)
+np.linspace(0j, 2)
+np.linspace(0, 2, num=10)
+np.linspace(0, 2, endpoint=True)
+np.linspace(0, 2, retstep=True)
+np.linspace(0j, 2j, retstep=True)
+np.linspace(0, 2, dtype=bool)
+np.linspace([0, 1], [2, 3], axis=Index())
+
+np.logspace(0, 2, base=2)
+np.logspace(0, 2, base=2)
+np.logspace(0, 2, base=[1j, 2j], num=2)
+
+np.geomspace(1, 2)
+
+np.zeros_like(A)
+np.zeros_like(C)
+np.zeros_like(B)
+np.zeros_like(B, dtype=np.int64)
+
+np.ones_like(A)
+np.ones_like(C)
+np.ones_like(B)
+np.ones_like(B, dtype=np.int64)
+
+np.empty_like(A)
+np.empty_like(C)
+np.empty_like(B)
+np.empty_like(B, dtype=np.int64)
+
+np.full_like(A, i8)
+np.full_like(C, i8)
+np.full_like(B, i8)
+np.full_like(B, i8, dtype=np.int64)
+
+np.ones(1)
+np.ones([1, 1, 1])
+
+np.full(1, i8)
+np.full([1, 1, 1], i8)
+
+np.indices([1, 2, 3])
+np.indices([1, 2, 3], sparse=True)
+
+np.fromfunction(func, (3, 5))
+
+np.identity(10)
+
+np.atleast_1d(C)
+np.atleast_1d(A)
+np.atleast_1d(C, C)
+np.atleast_1d(C, A)
+np.atleast_1d(A, A)
+
+np.atleast_2d(C)
+
+np.atleast_3d(C)
+
+np.vstack([C, C])
+np.vstack([C, A])
+np.vstack([A, A])
+
+np.hstack([C, C])
+
+np.stack([C, C])
+np.stack([C, C], axis=0)
+np.stack([C, C], out=B_stack)
+
+np.block([[C, C], [C, C]])
+np.block(A)
--- /dev/null
+from typing import Any, List, Optional
+
+import numpy as np
+from numpy.typing import ArrayLike, DTypeLike, _SupportsArray
+
+x1: ArrayLike = True
+x2: ArrayLike = 5
+x3: ArrayLike = 1.0
+x4: ArrayLike = 1 + 1j
+x5: ArrayLike = np.int8(1)
+x6: ArrayLike = np.float64(1)
+x7: ArrayLike = np.complex128(1)
+x8: ArrayLike = np.array([1, 2, 3])
+x9: ArrayLike = [1, 2, 3]
+x10: ArrayLike = (1, 2, 3)
+x11: ArrayLike = "foo"
+x12: ArrayLike = memoryview(b'foo')
+
+
+class A:
+ def __array__(self, dtype: DTypeLike = None) -> np.ndarray:
+ return np.array([1, 2, 3])
+
+
+x13: ArrayLike = A()
+
+scalar: _SupportsArray = np.int64(1)
+scalar.__array__(np.float64)
+array: _SupportsArray = np.array(1)
+array.__array__(np.float64)
+
+a: _SupportsArray = A()
+a.__array__(np.int64)
+a.__array__(dtype=np.int64)
+
+# Escape hatch for when you mean to make something like an object
+# array.
+object_array_scalar: Any = (i for i in range(10))
+np.array(object_array_scalar)
--- /dev/null
+import numpy as np
+
+i8 = np.int64(1)
+u8 = np.uint64(1)
+
+i4 = np.int32(1)
+u4 = np.uint32(1)
+
+b_ = np.bool_(1)
+
+b = bool(1)
+i = int(1)
+
+AR = np.array([0, 1, 2], dtype=np.int32)
+AR.setflags(write=False)
+
+
+i8 << i8
+i8 >> i8
+i8 | i8
+i8 ^ i8
+i8 & i8
+
+i8 << AR
+i8 >> AR
+i8 | AR
+i8 ^ AR
+i8 & AR
+
+i4 << i4
+i4 >> i4
+i4 | i4
+i4 ^ i4
+i4 & i4
+
+i8 << i4
+i8 >> i4
+i8 | i4
+i8 ^ i4
+i8 & i4
+
+i8 << i
+i8 >> i
+i8 | i
+i8 ^ i
+i8 & i
+
+i8 << b_
+i8 >> b_
+i8 | b_
+i8 ^ b_
+i8 & b_
+
+i8 << b
+i8 >> b
+i8 | b
+i8 ^ b
+i8 & b
+
+u8 << u8
+u8 >> u8
+u8 | u8
+u8 ^ u8
+u8 & u8
+
+u8 << AR
+u8 >> AR
+u8 | AR
+u8 ^ AR
+u8 & AR
+
+u4 << u4
+u4 >> u4
+u4 | u4
+u4 ^ u4
+u4 & u4
+
+u4 << i4
+u4 >> i4
+u4 | i4
+u4 ^ i4
+u4 & i4
+
+u4 << i
+u4 >> i
+u4 | i
+u4 ^ i
+u4 & i
+
+u8 << b_
+u8 >> b_
+u8 | b_
+u8 ^ b_
+u8 & b_
+
+u8 << b
+u8 >> b
+u8 | b
+u8 ^ b
+u8 & b
+
+b_ << b_
+b_ >> b_
+b_ | b_
+b_ ^ b_
+b_ & b_
+
+b_ << AR
+b_ >> AR
+b_ | AR
+b_ ^ AR
+b_ & AR
+
+b_ << b
+b_ >> b
+b_ | b
+b_ ^ b
+b_ & b
+
+b_ << i
+b_ >> i
+b_ | i
+b_ ^ i
+b_ & i
+
+~i8
+~i4
+~u8
+~u4
+~b_
+~AR
--- /dev/null
+import numpy as np
+
+np.dtype(dtype=np.int64)
+np.dtype(int)
+np.dtype("int")
+np.dtype(None)
+
+np.dtype((int, 2))
+np.dtype((int, (1,)))
+
+np.dtype({"names": ["a", "b"], "formats": [int, float]})
+np.dtype({"names": ["a"], "formats": [int], "titles": [object]})
+np.dtype({"names": ["a"], "formats": [int], "titles": [object()]})
+
+np.dtype([("name", np.unicode_, 16), ("grades", np.float64, (2,)), ("age", "int32")])
+
+np.dtype(
+ {
+ "names": ["a", "b"],
+ "formats": [int, float],
+ "itemsize": 9,
+ "aligned": False,
+ "titles": ["x", "y"],
+ "offsets": [0, 1],
+ }
+)
+
+np.dtype((np.float_, float))
+
+
+class Test:
+ dtype = float
+
+
+np.dtype(Test())
--- /dev/null
+import numpy as np
+
+a = np.empty((2, 2)).flat
+
+a.base
+a.copy()
+a.coords
+a.index
+iter(a)
+next(a)
+a[0]
+a[[0, 1, 2]]
+a[...]
+a[:]
--- /dev/null
+"""Tests for :mod:`numpy.core.fromnumeric`."""
+
+import numpy as np
+
+A = np.array(True, ndmin=2, dtype=bool)
+B = np.array(1.0, ndmin=2, dtype=np.float32)
+A.setflags(write=False)
+B.setflags(write=False)
+
+a = np.bool_(True)
+b = np.float32(1.0)
+c = 1.0
+d = np.array(1.0, dtype=np.float32) # writeable
+
+np.take(a, 0)
+np.take(b, 0)
+np.take(c, 0)
+np.take(A, 0)
+np.take(B, 0)
+np.take(A, [0])
+np.take(B, [0])
+
+np.reshape(a, 1)
+np.reshape(b, 1)
+np.reshape(c, 1)
+np.reshape(A, 1)
+np.reshape(B, 1)
+
+np.choose(a, [True, True])
+np.choose(A, [1.0, 1.0])
+
+np.repeat(a, 1)
+np.repeat(b, 1)
+np.repeat(c, 1)
+np.repeat(A, 1)
+np.repeat(B, 1)
+
+np.swapaxes(A, 0, 0)
+np.swapaxes(B, 0, 0)
+
+np.transpose(a)
+np.transpose(b)
+np.transpose(c)
+np.transpose(A)
+np.transpose(B)
+
+np.partition(a, 0, axis=None)
+np.partition(b, 0, axis=None)
+np.partition(c, 0, axis=None)
+np.partition(A, 0)
+np.partition(B, 0)
+
+np.argpartition(a, 0)
+np.argpartition(b, 0)
+np.argpartition(c, 0)
+np.argpartition(A, 0)
+np.argpartition(B, 0)
+
+np.sort(A, 0)
+np.sort(B, 0)
+
+np.argsort(A, 0)
+np.argsort(B, 0)
+
+np.argmax(A)
+np.argmax(B)
+np.argmax(A, axis=0)
+np.argmax(B, axis=0)
+
+np.argmin(A)
+np.argmin(B)
+np.argmin(A, axis=0)
+np.argmin(B, axis=0)
+
+np.searchsorted(A[0], 0)
+np.searchsorted(B[0], 0)
+np.searchsorted(A[0], [0])
+np.searchsorted(B[0], [0])
+
+np.resize(a, (5, 5))
+np.resize(b, (5, 5))
+np.resize(c, (5, 5))
+np.resize(A, (5, 5))
+np.resize(B, (5, 5))
+
+np.squeeze(a)
+np.squeeze(b)
+np.squeeze(c)
+np.squeeze(A)
+np.squeeze(B)
+
+np.diagonal(A)
+np.diagonal(B)
+
+np.trace(A)
+np.trace(B)
+
+np.ravel(a)
+np.ravel(b)
+np.ravel(c)
+np.ravel(A)
+np.ravel(B)
+
+np.nonzero(A)
+np.nonzero(B)
+
+np.shape(a)
+np.shape(b)
+np.shape(c)
+np.shape(A)
+np.shape(B)
+
+np.compress([True], a)
+np.compress([True], b)
+np.compress([True], c)
+np.compress([True], A)
+np.compress([True], B)
+
+np.clip(a, 0, 1.0)
+np.clip(b, -1, 1)
+np.clip(a, 0, None)
+np.clip(b, None, 1)
+np.clip(c, 0, 1)
+np.clip(A, 0, 1)
+np.clip(B, 0, 1)
+np.clip(B, [0, 1], [1, 2])
+
+np.sum(a)
+np.sum(b)
+np.sum(c)
+np.sum(A)
+np.sum(B)
+np.sum(A, axis=0)
+np.sum(B, axis=0)
+
+np.all(a)
+np.all(b)
+np.all(c)
+np.all(A)
+np.all(B)
+np.all(A, axis=0)
+np.all(B, axis=0)
+np.all(A, keepdims=True)
+np.all(B, keepdims=True)
+
+np.any(a)
+np.any(b)
+np.any(c)
+np.any(A)
+np.any(B)
+np.any(A, axis=0)
+np.any(B, axis=0)
+np.any(A, keepdims=True)
+np.any(B, keepdims=True)
+
+np.cumsum(a)
+np.cumsum(b)
+np.cumsum(c)
+np.cumsum(A)
+np.cumsum(B)
+
+np.ptp(b)
+np.ptp(c)
+np.ptp(B)
+np.ptp(B, axis=0)
+np.ptp(B, keepdims=True)
+
+np.amax(a)
+np.amax(b)
+np.amax(c)
+np.amax(A)
+np.amax(B)
+np.amax(A, axis=0)
+np.amax(B, axis=0)
+np.amax(A, keepdims=True)
+np.amax(B, keepdims=True)
+
+np.amin(a)
+np.amin(b)
+np.amin(c)
+np.amin(A)
+np.amin(B)
+np.amin(A, axis=0)
+np.amin(B, axis=0)
+np.amin(A, keepdims=True)
+np.amin(B, keepdims=True)
+
+np.prod(a)
+np.prod(b)
+np.prod(c)
+np.prod(A)
+np.prod(B)
+np.prod(a, dtype=None)
+np.prod(A, dtype=None)
+np.prod(A, axis=0)
+np.prod(B, axis=0)
+np.prod(A, keepdims=True)
+np.prod(B, keepdims=True)
+np.prod(b, out=d)
+np.prod(B, out=d)
+
+np.cumprod(a)
+np.cumprod(b)
+np.cumprod(c)
+np.cumprod(A)
+np.cumprod(B)
+
+np.ndim(a)
+np.ndim(b)
+np.ndim(c)
+np.ndim(A)
+np.ndim(B)
+
+np.size(a)
+np.size(b)
+np.size(c)
+np.size(A)
+np.size(B)
+
+np.around(a)
+np.around(b)
+np.around(c)
+np.around(A)
+np.around(B)
+
+np.mean(a)
+np.mean(b)
+np.mean(c)
+np.mean(A)
+np.mean(B)
+np.mean(A, axis=0)
+np.mean(B, axis=0)
+np.mean(A, keepdims=True)
+np.mean(B, keepdims=True)
+np.mean(b, out=d)
+np.mean(B, out=d)
+
+np.std(a)
+np.std(b)
+np.std(c)
+np.std(A)
+np.std(B)
+np.std(A, axis=0)
+np.std(B, axis=0)
+np.std(A, keepdims=True)
+np.std(B, keepdims=True)
+np.std(b, out=d)
+np.std(B, out=d)
+
+np.var(a)
+np.var(b)
+np.var(c)
+np.var(A)
+np.var(B)
+np.var(A, axis=0)
+np.var(B, axis=0)
+np.var(A, keepdims=True)
+np.var(B, keepdims=True)
+np.var(b, out=d)
+np.var(B, out=d)
--- /dev/null
+from functools import partial
+from typing import Callable, List, Tuple
+
+import pytest # type: ignore
+import numpy as np
+
+AR = np.array(0)
+AR.setflags(write=False)
+
+KACF = frozenset({None, "K", "A", "C", "F"})
+ACF = frozenset({None, "A", "C", "F"})
+CF = frozenset({None, "C", "F"})
+
+order_list: List[Tuple[frozenset, Callable]] = [
+ (KACF, partial(np.ndarray, 1)),
+ (KACF, AR.tobytes),
+ (KACF, partial(AR.astype, int)),
+ (KACF, AR.copy),
+ (ACF, partial(AR.reshape, 1)),
+ (KACF, AR.flatten),
+ (KACF, AR.ravel),
+ (KACF, partial(np.array, 1)),
+ (CF, partial(np.zeros, 1)),
+ (CF, partial(np.ones, 1)),
+ (CF, partial(np.empty, 1)),
+ (CF, partial(np.full, 1, 1)),
+ (KACF, partial(np.zeros_like, AR)),
+ (KACF, partial(np.ones_like, AR)),
+ (KACF, partial(np.empty_like, AR)),
+ (KACF, partial(np.full_like, AR, 1)),
+ (KACF, partial(np.add, 1, 1)), # i.e. np.ufunc.__call__
+ (ACF, partial(np.reshape, AR, 1)),
+ (KACF, partial(np.ravel, AR)),
+ (KACF, partial(np.asarray, 1)),
+ (KACF, partial(np.asanyarray, 1)),
+]
+
+for order_set, func in order_list:
+ for order in order_set:
+ func(order=order)
+
+ invalid_orders = KACF - order_set
+ for order in invalid_orders:
+ with pytest.raises(ValueError):
+ func(order=order)
--- /dev/null
+import numpy as np
+
+f8 = np.float64(1)
+i8 = np.int64(1)
+u8 = np.uint64(1)
+
+f4 = np.float32(1)
+i4 = np.int32(1)
+u4 = np.uint32(1)
+
+td = np.timedelta64(1, "D")
+b_ = np.bool_(1)
+
+b = bool(1)
+f = float(1)
+i = int(1)
+
+AR = np.array([1], dtype=np.bool_)
+AR.setflags(write=False)
+
+AR2 = np.array([1], dtype=np.timedelta64)
+AR2.setflags(write=False)
+
+# Time structures
+
+td % td
+td % AR2
+AR2 % td
+
+divmod(td, td)
+divmod(td, AR2)
+divmod(AR2, td)
+
+# Bool
+
+b_ % b
+b_ % i
+b_ % f
+b_ % b_
+b_ % i8
+b_ % u8
+b_ % f8
+b_ % AR
+
+divmod(b_, b)
+divmod(b_, i)
+divmod(b_, f)
+divmod(b_, b_)
+divmod(b_, i8)
+divmod(b_, u8)
+divmod(b_, f8)
+divmod(b_, AR)
+
+b % b_
+i % b_
+f % b_
+b_ % b_
+i8 % b_
+u8 % b_
+f8 % b_
+AR % b_
+
+divmod(b, b_)
+divmod(i, b_)
+divmod(f, b_)
+divmod(b_, b_)
+divmod(i8, b_)
+divmod(u8, b_)
+divmod(f8, b_)
+divmod(AR, b_)
+
+# int
+
+i8 % b
+i8 % i
+i8 % f
+i8 % i8
+i8 % f8
+i4 % i8
+i4 % f8
+i4 % i4
+i4 % f4
+i8 % AR
+
+divmod(i8, b)
+divmod(i8, i)
+divmod(i8, f)
+divmod(i8, i8)
+divmod(i8, f8)
+divmod(i8, i4)
+divmod(i8, f4)
+divmod(i4, i4)
+divmod(i4, f4)
+divmod(i8, AR)
+
+b % i8
+i % i8
+f % i8
+i8 % i8
+f8 % i8
+i8 % i4
+f8 % i4
+i4 % i4
+f4 % i4
+AR % i8
+
+divmod(b, i8)
+divmod(i, i8)
+divmod(f, i8)
+divmod(i8, i8)
+divmod(f8, i8)
+divmod(i4, i8)
+divmod(f4, i8)
+divmod(i4, i4)
+divmod(f4, i4)
+divmod(AR, i8)
+
+# float
+
+f8 % b
+f8 % i
+f8 % f
+i8 % f4
+f4 % f4
+f8 % AR
+
+divmod(f8, b)
+divmod(f8, i)
+divmod(f8, f)
+divmod(f8, f8)
+divmod(f8, f4)
+divmod(f4, f4)
+divmod(f8, AR)
+
+b % f8
+i % f8
+f % f8
+f8 % f8
+f8 % f8
+f4 % f4
+AR % f8
+
+divmod(b, f8)
+divmod(i, f8)
+divmod(f, f8)
+divmod(f8, f8)
+divmod(f4, f8)
+divmod(f4, f4)
+divmod(AR, f8)
--- /dev/null
+import os
+import tempfile
+
+import numpy as np
+
+nd = np.array([[1, 2], [3, 4]])
+scalar_array = np.array(1)
+
+# item
+scalar_array.item()
+nd.item(1)
+nd.item(0, 1)
+nd.item((0, 1))
+
+# tolist is pretty simple
+
+# itemset
+scalar_array.itemset(3)
+nd.itemset(3, 0)
+nd.itemset((0, 0), 3)
+
+# tobytes
+nd.tobytes()
+nd.tobytes("C")
+nd.tobytes(None)
+
+# tofile
+if os.name != "nt":
+ with tempfile.NamedTemporaryFile(suffix=".txt") as tmp:
+ nd.tofile(tmp.name)
+ nd.tofile(tmp.name, "")
+ nd.tofile(tmp.name, sep="")
+
+ nd.tofile(tmp.name, "", "%s")
+ nd.tofile(tmp.name, format="%s")
+
+ nd.tofile(tmp)
+
+# dump is pretty simple
+# dumps is pretty simple
+
+# astype
+nd.astype("float")
+nd.astype(float)
+
+nd.astype(float, "K")
+nd.astype(float, order="K")
+
+nd.astype(float, "K", "unsafe")
+nd.astype(float, casting="unsafe")
+
+nd.astype(float, "K", "unsafe", True)
+nd.astype(float, subok=True)
+
+nd.astype(float, "K", "unsafe", True, True)
+nd.astype(float, copy=True)
+
+# byteswap
+nd.byteswap()
+nd.byteswap(True)
+
+# copy
+nd.copy()
+nd.copy("C")
+
+# view
+nd.view()
+nd.view(np.int64)
+nd.view(dtype=np.int64)
+nd.view(np.int64, np.matrix)
+nd.view(type=np.matrix)
+
+# getfield
+complex_array = np.array([[1 + 1j, 0], [0, 1 - 1j]], dtype=np.complex128)
+
+complex_array.getfield("float")
+complex_array.getfield(float)
+
+complex_array.getfield("float", 8)
+complex_array.getfield(float, offset=8)
+
+# setflags
+nd.setflags()
+
+nd.setflags(True)
+nd.setflags(write=True)
+
+nd.setflags(True, True)
+nd.setflags(write=True, align=True)
+
+nd.setflags(True, True, False)
+nd.setflags(write=True, align=True, uic=False)
+
+# fill is pretty simple
--- /dev/null
+"""
+Tests for miscellaneous (non-magic) ``np.ndarray``/``np.generic`` methods.
+
+More extensive tests are performed for the methods'
+function-based counterpart in `../from_numeric.py`.
+
+"""
+
+from typing import cast
+import numpy as np
+
+class SubClass(np.ndarray): ...
+
+i4 = np.int32(1)
+A = np.array([[1]], dtype=np.int32)
+B0 = np.empty((), dtype=np.int32).view(SubClass)
+B1 = np.empty((1,), dtype=np.int32).view(SubClass)
+B2 = np.empty((1, 1), dtype=np.int32).view(SubClass)
+C = np.array([0, 1, 2], dtype=np.int32)
+D = np.empty(3).view(SubClass)
+
+i4.all()
+A.all()
+A.all(axis=0)
+A.all(keepdims=True)
+A.all(out=B0)
+
+i4.any()
+A.any()
+A.any(axis=0)
+A.any(keepdims=True)
+A.any(out=B0)
+
+i4.argmax()
+A.argmax()
+A.argmax(axis=0)
+A.argmax(out=B0)
+
+i4.argmin()
+A.argmin()
+A.argmin(axis=0)
+A.argmin(out=B0)
+
+i4.argsort()
+A.argsort()
+
+i4.choose([()])
+_choices = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]], dtype=np.int32)
+C.choose(_choices)
+C.choose(_choices, out=D)
+
+i4.clip(1)
+A.clip(1)
+A.clip(None, 1)
+A.clip(1, out=B2)
+A.clip(None, 1, out=B2)
+
+i4.compress([1])
+A.compress([1])
+A.compress([1], out=B1)
+
+i4.conj()
+A.conj()
+B0.conj()
+
+i4.conjugate()
+A.conjugate()
+B0.conjugate()
+
+i4.cumprod()
+A.cumprod()
+A.cumprod(out=B1)
+
+i4.cumsum()
+A.cumsum()
+A.cumsum(out=B1)
+
+i4.max()
+A.max()
+A.max(axis=0)
+A.max(keepdims=True)
+A.max(out=B0)
+
+i4.mean()
+A.mean()
+A.mean(axis=0)
+A.mean(keepdims=True)
+A.mean(out=B0)
+
+i4.min()
+A.min()
+A.min(axis=0)
+A.min(keepdims=True)
+A.min(out=B0)
+
+i4.newbyteorder()
+A.newbyteorder()
+B0.newbyteorder('|')
+
+i4.prod()
+A.prod()
+A.prod(axis=0)
+A.prod(keepdims=True)
+A.prod(out=B0)
+
+i4.ptp()
+A.ptp()
+A.ptp(axis=0)
+A.ptp(keepdims=True)
+A.astype(int).ptp(out=B0)
+
+i4.round()
+A.round()
+A.round(out=B2)
+
+i4.repeat(1)
+A.repeat(1)
+B0.repeat(1)
+
+i4.std()
+A.std()
+A.std(axis=0)
+A.std(keepdims=True)
+A.std(out=B0.astype(np.float64))
+
+i4.sum()
+A.sum()
+A.sum(axis=0)
+A.sum(keepdims=True)
+A.sum(out=B0)
+
+i4.take(0)
+A.take(0)
+A.take([0])
+A.take(0, out=B0)
+A.take([0], out=B1)
+
+i4.var()
+A.var()
+A.var(axis=0)
+A.var(keepdims=True)
+A.var(out=B0)
+
+A.argpartition([0])
+
+A.diagonal()
+
+A.dot(1)
+A.dot(1, out=B0)
+
+A.nonzero()
+
+C.searchsorted(1)
+
+A.trace()
+A.trace(out=B0)
+
+void = cast(np.void, np.array(1, dtype=[("f", np.float64)]).take(0))
+void.setfield(10, np.float64)
--- /dev/null
+import numpy as np
+
+nd1 = np.array([[1, 2], [3, 4]])
+
+# reshape
+nd1.reshape(4)
+nd1.reshape(2, 2)
+nd1.reshape((2, 2))
+
+nd1.reshape((2, 2), order="C")
+nd1.reshape(4, order="C")
+
+# resize
+nd1.resize()
+nd1.resize(4)
+nd1.resize(2, 2)
+nd1.resize((2, 2))
+
+nd1.resize((2, 2), refcheck=True)
+nd1.resize(4, refcheck=True)
+
+nd2 = np.array([[1, 2], [3, 4]])
+
+# transpose
+nd2.transpose()
+nd2.transpose(1, 0)
+nd2.transpose((1, 0))
+
+# swapaxes
+nd2.swapaxes(0, 1)
+
+# flatten
+nd2.flatten()
+nd2.flatten("C")
+
+# ravel
+nd2.ravel()
+nd2.ravel("C")
+
+# squeeze
+nd2.squeeze()
+
+nd3 = np.array([[1, 2]])
+nd3.squeeze(0)
+
+nd4 = np.array([[[1, 2]]])
+nd4.squeeze((0, 1))
--- /dev/null
+"""
+Tests for :mod:`numpy.core.numeric`.
+
+Does not include tests which fall under ``array_constructors``.
+
+"""
+
+from typing import List
+import numpy as np
+
+class SubClass(np.ndarray):
+ ...
+
+i8 = np.int64(1)
+
+A = np.arange(27).reshape(3, 3, 3)
+B: List[List[List[int]]] = A.tolist()
+C = np.empty((27, 27)).view(SubClass)
+
+np.count_nonzero(i8)
+np.count_nonzero(A)
+np.count_nonzero(B)
+np.count_nonzero(A, keepdims=True)
+np.count_nonzero(A, axis=0)
+
+np.isfortran(i8)
+np.isfortran(A)
+
+np.argwhere(i8)
+np.argwhere(A)
+
+np.flatnonzero(i8)
+np.flatnonzero(A)
+
+np.correlate(B[0][0], A.ravel(), mode="valid")
+np.correlate(A.ravel(), A.ravel(), mode="same")
+
+np.convolve(B[0][0], A.ravel(), mode="valid")
+np.convolve(A.ravel(), A.ravel(), mode="same")
+
+np.outer(i8, A)
+np.outer(B, A)
+np.outer(A, A)
+np.outer(A, A, out=C)
+
+np.tensordot(B, A)
+np.tensordot(A, A)
+np.tensordot(A, A, axes=0)
+np.tensordot(A, A, axes=(0, 1))
+
+np.isscalar(i8)
+np.isscalar(A)
+np.isscalar(B)
+
+np.roll(A, 1)
+np.roll(A, (1, 2))
+np.roll(B, 1)
+
+np.rollaxis(A, 0, 1)
+
+np.moveaxis(A, 0, 1)
+np.moveaxis(A, (0, 1), (1, 2))
+
+np.cross(B, A)
+np.cross(A, A)
+
+np.indices([0, 1, 2])
+np.indices([0, 1, 2], sparse=False)
+np.indices([0, 1, 2], sparse=True)
+
+np.binary_repr(1)
+
+np.base_repr(1)
+
+np.allclose(i8, A)
+np.allclose(B, A)
+np.allclose(A, A)
+
+np.isclose(i8, A)
+np.isclose(B, A)
+np.isclose(A, A)
+
+np.array_equal(i8, A)
+np.array_equal(B, A)
+np.array_equal(A, A)
+
+np.array_equiv(i8, A)
+np.array_equiv(B, A)
+np.array_equiv(A, A)
--- /dev/null
+import numpy as np
+
+np.maximum_sctype("S8")
+np.maximum_sctype(object)
+
+np.issctype(object)
+np.issctype("S8")
+
+np.obj2sctype(list)
+np.obj2sctype(list, default=None)
+np.obj2sctype(list, default=np.string_)
+
+np.issubclass_(np.int32, int)
+np.issubclass_(np.float64, float)
+np.issubclass_(np.float64, (int, float))
+
+np.issubsctype("int64", int)
+np.issubsctype(np.array([1]), np.array([1]))
+
+np.issubdtype("S1", np.string_)
+np.issubdtype(np.float64, np.float32)
+
+np.sctype2char("S1")
+np.sctype2char(list)
+
+np.find_common_type([], [np.int64, np.float32, complex])
+np.find_common_type((), (np.int64, np.float32, complex))
+np.find_common_type([np.int64, np.float32], [])
+np.find_common_type([np.float32], [np.int64, np.float64])
--- /dev/null
+import sys
+import datetime as dt
+
+import pytest
+import numpy as np
+
+
+# Construction
+class D:
+ def __index__(self) -> int:
+ return 0
+
+
+class C:
+ def __complex__(self) -> complex:
+ return 3j
+
+
+class B:
+ def __int__(self) -> int:
+ return 4
+
+
+class A:
+ def __float__(self) -> float:
+ return 4.0
+
+
+np.complex64(3j)
+np.complex64(A())
+np.complex64(C())
+np.complex128(3j)
+np.complex128(C())
+np.complex128(None)
+np.complex64("1.2")
+np.complex128(b"2j")
+
+np.int8(4)
+np.int16(3.4)
+np.int32(4)
+np.int64(-1)
+np.uint8(B())
+np.uint32()
+np.int32("1")
+np.int64(b"2")
+
+np.float16(A())
+np.float32(16)
+np.float64(3.0)
+np.float64(None)
+np.float32("1")
+np.float16(b"2.5")
+
+if sys.version_info >= (3, 8):
+ np.uint64(D())
+ np.float32(D())
+ np.complex64(D())
+
+np.bytes_(b"hello")
+np.bytes_("hello", 'utf-8')
+np.bytes_("hello", encoding='utf-8')
+np.str_("hello")
+np.str_(b"hello", 'utf-8')
+np.str_(b"hello", encoding='utf-8')
+
+# Array-ish semantics
+np.int8().real
+np.int16().imag
+np.int32().data
+np.int64().flags
+
+np.uint8().itemsize * 2
+np.uint16().ndim + 1
+np.uint32().strides
+np.uint64().shape
+
+# Time structures
+np.datetime64()
+np.datetime64(0, "D")
+np.datetime64(0, b"D")
+np.datetime64(0, ('ms', 3))
+np.datetime64("2019")
+np.datetime64(b"2019")
+np.datetime64("2019", "D")
+np.datetime64(np.datetime64())
+np.datetime64(dt.datetime(2000, 5, 3))
+np.datetime64(None)
+np.datetime64(None, "D")
+
+np.timedelta64()
+np.timedelta64(0)
+np.timedelta64(0, "D")
+np.timedelta64(0, ('ms', 3))
+np.timedelta64(0, b"D")
+np.timedelta64("3")
+np.timedelta64(b"5")
+np.timedelta64(np.timedelta64(2))
+np.timedelta64(dt.timedelta(2))
+np.timedelta64(None)
+np.timedelta64(None, "D")
+
+np.void(1)
+np.void(np.int64(1))
+np.void(True)
+np.void(np.bool_(True))
+np.void(b"test")
+np.void(np.bytes_("test"))
+
+# Protocols
+i8 = np.int64()
+u8 = np.uint64()
+f8 = np.float64()
+c16 = np.complex128()
+b_ = np.bool_()
+td = np.timedelta64()
+U = np.str_("1")
+S = np.bytes_("1")
+AR = np.array(1, dtype=np.float64)
+
+int(i8)
+int(u8)
+int(f8)
+int(b_)
+int(td)
+int(U)
+int(S)
+int(AR)
+with pytest.warns(np.ComplexWarning):
+ int(c16)
+
+float(i8)
+float(u8)
+float(f8)
+float(b_)
+float(td)
+float(U)
+float(S)
+float(AR)
+with pytest.warns(np.ComplexWarning):
+ float(c16)
+
+complex(i8)
+complex(u8)
+complex(f8)
+complex(c16)
+complex(b_)
+complex(td)
+complex(U)
+complex(AR)
+
+
+# Misc
+c16.dtype
+c16.real
+c16.imag
+c16.real.real
+c16.real.imag
+c16.ndim
+c16.size
+c16.itemsize
+c16.shape
+c16.strides
+c16.squeeze()
+c16.byteswap()
+c16.transpose()
--- /dev/null
+"""Simple expression that should pass with mypy."""
+import operator
+
+import numpy as np
+from typing import Iterable # noqa: F401
+
+# Basic checks
+array = np.array([1, 2])
+
+
+def ndarray_func(x):
+ # type: (np.ndarray) -> np.ndarray
+ return x
+
+
+ndarray_func(np.array([1, 2]))
+array == 1
+array.dtype == float
+
+# Dtype construction
+np.dtype(float)
+np.dtype(np.float64)
+np.dtype(None)
+np.dtype("float64")
+np.dtype(np.dtype(float))
+np.dtype(("U", 10))
+np.dtype((np.int32, (2, 2)))
+# Define the arguments on the previous line to prevent bidirectional
+# type inference in mypy from broadening the types.
+two_tuples_dtype = [("R", "u1"), ("G", "u1"), ("B", "u1")]
+np.dtype(two_tuples_dtype)
+
+three_tuples_dtype = [("R", "u1", 2)]
+np.dtype(three_tuples_dtype)
+
+mixed_tuples_dtype = [("R", "u1"), ("G", np.unicode_, 1)]
+np.dtype(mixed_tuples_dtype)
+
+shape_tuple_dtype = [("R", "u1", (2, 2))]
+np.dtype(shape_tuple_dtype)
+
+shape_like_dtype = [("R", "u1", (2, 2)), ("G", np.unicode_, 1)]
+np.dtype(shape_like_dtype)
+
+object_dtype = [("field1", object)]
+np.dtype(object_dtype)
+
+np.dtype((np.int32, (np.int8, 4)))
+
+# Dtype comparision
+np.dtype(float) == float
+np.dtype(float) != np.float64
+np.dtype(float) < None
+np.dtype(float) <= "float64"
+np.dtype(float) > np.dtype(float)
+np.dtype(float) >= np.dtype(("U", 10))
+
+# Iteration and indexing
+def iterable_func(x):
+ # type: (Iterable) -> Iterable
+ return x
+
+
+iterable_func(array)
+[element for element in array]
+iter(array)
+zip(array, array)
+array[1]
+array[:]
+array[...]
+array[:] = 0
+
+array_2d = np.ones((3, 3))
+array_2d[:2, :2]
+array_2d[..., 0]
+array_2d[:2, :2] = 0
+
+# Other special methods
+len(array)
+str(array)
+array_scalar = np.array(1)
+int(array_scalar)
+float(array_scalar)
+# currently does not work due to https://github.com/python/typeshed/issues/1904
+# complex(array_scalar)
+bytes(array_scalar)
+operator.index(array_scalar)
+bool(array_scalar)
+
+# comparisons
+array < 1
+array <= 1
+array == 1
+array != 1
+array > 1
+array >= 1
+1 < array
+1 <= array
+1 == array
+1 != array
+1 > array
+1 >= array
+
+# binary arithmetic
+array + 1
+1 + array
+array += 1
+
+array - 1
+1 - array
+array -= 1
+
+array * 1
+1 * array
+array *= 1
+
+nonzero_array = np.array([1, 2])
+array / 1
+1 / nonzero_array
+float_array = np.array([1.0, 2.0])
+float_array /= 1
+
+array // 1
+1 // nonzero_array
+array //= 1
+
+array % 1
+1 % nonzero_array
+array %= 1
+
+divmod(array, 1)
+divmod(1, nonzero_array)
+
+array ** 1
+1 ** array
+array **= 1
+
+array << 1
+1 << array
+array <<= 1
+
+array >> 1
+1 >> array
+array >>= 1
+
+array & 1
+1 & array
+array &= 1
+
+array ^ 1
+1 ^ array
+array ^= 1
+
+array | 1
+1 | array
+array |= 1
+
+# unary arithmetic
+-array
++array
+abs(array)
+~array
+
+# Other methods
+np.array([1, 2]).transpose()
--- /dev/null
+import numpy as np
+
+array = np.array([1, 2])
+
+# The @ operator is not in python 2
+array @ array
--- /dev/null
+"""Typing tests for `numpy.core._ufunc_config`."""
+
+import numpy as np
+
+def func1(a: str, b: int) -> None: ...
+def func2(a: str, b: int, c: float = ...) -> None: ...
+def func3(a: str, b: int) -> int: ...
+
+class Write1:
+ def write(self, a: str) -> None: ...
+
+class Write2:
+ def write(self, a: str, b: int = ...) -> None: ...
+
+class Write3:
+ def write(self, a: str) -> int: ...
+
+
+_err_default = np.geterr()
+_bufsize_default = np.getbufsize()
+_errcall_default = np.geterrcall()
+
+try:
+ np.seterr(all=None)
+ np.seterr(divide="ignore")
+ np.seterr(over="warn")
+ np.seterr(under="call")
+ np.seterr(invalid="raise")
+ np.geterr()
+
+ np.setbufsize(4096)
+ np.getbufsize()
+
+ np.seterrcall(func1)
+ np.seterrcall(func2)
+ np.seterrcall(func3)
+ np.seterrcall(Write1())
+ np.seterrcall(Write2())
+ np.seterrcall(Write3())
+ np.geterrcall()
+
+ with np.errstate(call=func1, all="call"):
+ pass
+ with np.errstate(call=Write1(), divide="log", over="log"):
+ pass
+
+finally:
+ np.seterr(**_err_default)
+ np.setbufsize(_bufsize_default)
+ np.seterrcall(_errcall_default)
--- /dev/null
+import numpy as np
+
+np.sin(1)
+np.sin([1, 2, 3])
+np.sin(1, out=np.empty(1))
+np.matmul(np.ones((2, 2, 2)), np.ones((2, 2, 2)), axes=[(0, 1), (0, 1), (0, 1)])
+np.sin(1, signature="D")
+np.sin(1, extobj=[16, 1, lambda: None])
+# NOTE: `np.generic` subclasses are not guaranteed to support addition;
+# re-enable this we can infer the exact return type of `np.sin(...)`.
+#
+# np.sin(1) + np.sin(1)
+np.sin.types[0]
+np.sin.__name__
+
+np.abs(np.array([1]))
--- /dev/null
+import numpy as np
+
+np.AxisError(1)
+np.AxisError(1, ndim=2)
+np.AxisError(1, ndim=None)
+np.AxisError(1, ndim=2, msg_prefix="error")
+np.AxisError(1, ndim=2, msg_prefix=None)
--- /dev/null
+import numpy as np
+
+c16 = np.complex128()
+f8 = np.float64()
+i8 = np.int64()
+u8 = np.uint64()
+
+c8 = np.complex64()
+f4 = np.float32()
+i4 = np.int32()
+u4 = np.uint32()
+
+dt = np.datetime64(0, "D")
+td = np.timedelta64(0, "D")
+
+b_ = np.bool_()
+
+b = bool()
+c = complex()
+f = float()
+i = int()
+
+AR = np.array([0], dtype=np.float64)
+AR.setflags(write=False)
+
+# unary ops
+
+reveal_type(-c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(-c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(-f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(-f4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(-i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(-i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(-u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(-u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(-td) # E: numpy.timedelta64
+reveal_type(-AR) # E: Any
+
+reveal_type(+c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(+c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(+f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(+f4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(+i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(+i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(+u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(+u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(+td) # E: numpy.timedelta64
+reveal_type(+AR) # E: Any
+
+reveal_type(abs(c16)) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(abs(c8)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(abs(f8)) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(abs(f4)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(abs(i8)) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(abs(i4)) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(abs(u8)) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(abs(u4)) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(abs(td)) # E: numpy.timedelta64
+reveal_type(abs(b_)) # E: numpy.bool_
+reveal_type(abs(AR)) # E: Any
+
+# Time structures
+
+reveal_type(dt + td) # E: numpy.datetime64
+reveal_type(dt + i) # E: numpy.datetime64
+reveal_type(dt + i4) # E: numpy.datetime64
+reveal_type(dt + i8) # E: numpy.datetime64
+reveal_type(dt - dt) # E: numpy.timedelta64
+reveal_type(dt - i) # E: numpy.datetime64
+reveal_type(dt - i4) # E: numpy.datetime64
+reveal_type(dt - i8) # E: numpy.datetime64
+
+reveal_type(td + td) # E: numpy.timedelta64
+reveal_type(td + i) # E: numpy.timedelta64
+reveal_type(td + i4) # E: numpy.timedelta64
+reveal_type(td + i8) # E: numpy.timedelta64
+reveal_type(td - td) # E: numpy.timedelta64
+reveal_type(td - i) # E: numpy.timedelta64
+reveal_type(td - i4) # E: numpy.timedelta64
+reveal_type(td - i8) # E: numpy.timedelta64
+reveal_type(td / f) # E: numpy.timedelta64
+reveal_type(td / f4) # E: numpy.timedelta64
+reveal_type(td / f8) # E: numpy.timedelta64
+reveal_type(td / td) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(td // td) # E: numpy.signedinteger[numpy.typing._64Bit]
+
+# boolean
+
+reveal_type(b_ / b) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / i) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / i8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / i4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / u8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / u4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / f4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(b_ / c) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(b_ / c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(b_ / c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+
+reveal_type(b / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i4 / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(u8 / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(u4 / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 / b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 / b_) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(c / b_) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 / b_) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 / b_) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+
+# Complex
+
+reveal_type(c16 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + f8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + i8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + c8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + f4) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + i4) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + b_) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + b) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + c) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + f) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c16 + i) # E: numpy.complexfloating[Any, Any]
+reveal_type(c16 + AR) # E: Any
+
+reveal_type(c16 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f8 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(i8 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f4 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(i4 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(b_ + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(b + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(i + c16) # E: numpy.complexfloating[Any, Any]
+reveal_type(AR + c16) # E: Any
+
+reveal_type(c8 + c16) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 + f8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 + i8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 + c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(c8 + f4) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(c8 + i4) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(c8 + b_) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(c8 + b) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(c8 + c) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 + f) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 + i) # E: numpy.complexfloating[Any, Any]
+reveal_type(c8 + AR) # E: Any
+
+reveal_type(c16 + c8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f8 + c8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(i8 + c8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(c8 + c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(f4 + c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(i4 + c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(b_ + c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(b + c8) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(c + c8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f + c8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(i + c8) # E: numpy.complexfloating[Any, Any]
+reveal_type(AR + c8) # E: Any
+
+# Float
+
+reveal_type(f8 + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 + i8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 + f4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 + i4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 + b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 + b) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 + c) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f8 + f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 + i) # E: numpy.floating[Any]
+reveal_type(f8 + AR) # E: Any
+
+reveal_type(f8 + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i4 + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(c + f8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i + f8) # E: numpy.floating[Any]
+reveal_type(AR + f8) # E: Any
+
+reveal_type(f4 + f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 + i8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 + f4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(f4 + i4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(f4 + b_) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(f4 + b) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(f4 + c) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f4 + f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 + i) # E: numpy.floating[Any]
+reveal_type(f4 + AR) # E: Any
+
+reveal_type(f8 + f4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 + f4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 + f4) # E: umpy.floating[numpy.typing._32Bit]
+reveal_type(i4 + f4) # E: umpy.floating[numpy.typing._32Bit]
+reveal_type(b_ + f4) # E: umpy.floating[numpy.typing._32Bit]
+reveal_type(b + f4) # E: umpy.floating[numpy.typing._32Bit]
+reveal_type(c + f4) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f + f4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i + f4) # E: numpy.floating[Any]
+reveal_type(AR + f4) # E: Any
+
+# Int
+
+reveal_type(i8 + i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 + u8) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(i8 + i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 + u4) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(i8 + b_) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 + b) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 + c) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(i8 + f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 + i) # E: numpy.signedinteger[Any]
+reveal_type(i8 + AR) # E: Any
+
+reveal_type(u8 + u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 + i4) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(u8 + u4) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 + b_) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 + b) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 + c) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(u8 + f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(u8 + i) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(u8 + AR) # E: Any
+
+reveal_type(i8 + i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(u8 + i8) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(i4 + i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(u4 + i8) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(b_ + i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(b + i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(c + i8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f + i8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i + i8) # E: numpy.signedinteger[Any]
+reveal_type(AR + i8) # E: Any
+
+reveal_type(u8 + u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(i4 + u8) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(u4 + u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(b_ + u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(b + u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(c + u8) # E: numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]
+reveal_type(f + u8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i + u8) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(AR + u8) # E: Any
+
+reveal_type(i4 + i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i4 + i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 + i) # E: numpy.signedinteger[Any]
+reveal_type(i4 + b_) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 + b) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 + AR) # E: Any
+
+reveal_type(u4 + i8) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(u4 + i4) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(u4 + u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u4 + u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(u4 + i) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(u4 + b_) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(u4 + b) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(u4 + AR) # E: Any
+
+reveal_type(i8 + i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i4 + i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i + i4) # E: numpy.signedinteger[Any]
+reveal_type(b_ + i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(b + i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(AR + i4) # E: Any
+
+reveal_type(i8 + u4) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(i4 + u4) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(u8 + u4) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u4 + u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(b_ + u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(b + u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(i + u4) # E: Union[numpy.signedinteger[Any], numpy.floating[numpy.typing._64Bit]]
+reveal_type(AR + u4) # E: Any
--- /dev/null
+from typing import List, Any
+import numpy as np
+
+class SubClass(np.ndarray): ...
+
+i8: np.int64
+
+A: np.ndarray
+B: SubClass
+C: List[int]
+
+def func(i: int, j: int, **kwargs: Any) -> SubClass: ...
+
+reveal_type(np.asarray(A)) # E: ndarray
+reveal_type(np.asarray(B)) # E: ndarray
+reveal_type(np.asarray(C)) # E: ndarray
+
+reveal_type(np.asanyarray(A)) # E: ndarray
+reveal_type(np.asanyarray(B)) # E: SubClass
+reveal_type(np.asanyarray(B, dtype=int)) # E: ndarray
+reveal_type(np.asanyarray(C)) # E: ndarray
+
+reveal_type(np.ascontiguousarray(A)) # E: ndarray
+reveal_type(np.ascontiguousarray(B)) # E: ndarray
+reveal_type(np.ascontiguousarray(C)) # E: ndarray
+
+reveal_type(np.asfortranarray(A)) # E: ndarray
+reveal_type(np.asfortranarray(B)) # E: ndarray
+reveal_type(np.asfortranarray(C)) # E: ndarray
+
+reveal_type(np.require(A)) # E: ndarray
+reveal_type(np.require(B)) # E: SubClass
+reveal_type(np.require(B, requirements=None)) # E: SubClass
+reveal_type(np.require(B, dtype=int)) # E: ndarray
+reveal_type(np.require(B, requirements="E")) # E: ndarray
+reveal_type(np.require(B, requirements=["ENSUREARRAY"])) # E: ndarray
+reveal_type(np.require(B, requirements={"F", "E"})) # E: ndarray
+reveal_type(np.require(B, requirements=["C", "OWNDATA"])) # E: SubClass
+reveal_type(np.require(B, requirements="W")) # E: SubClass
+reveal_type(np.require(B, requirements="A")) # E: SubClass
+reveal_type(np.require(C)) # E: ndarray
+
+reveal_type(np.linspace(0, 10)) # E: numpy.ndarray
+reveal_type(np.linspace(0, 10, retstep=True)) # E: Tuple[numpy.ndarray, numpy.inexact[Any]]
+reveal_type(np.logspace(0, 10)) # E: numpy.ndarray
+reveal_type(np.geomspace(1, 10)) # E: numpy.ndarray
+
+reveal_type(np.zeros_like(A)) # E: numpy.ndarray
+reveal_type(np.zeros_like(C)) # E: numpy.ndarray
+reveal_type(np.zeros_like(B)) # E: SubClass
+reveal_type(np.zeros_like(B, dtype=np.int64)) # E: numpy.ndarray
+
+reveal_type(np.ones_like(A)) # E: numpy.ndarray
+reveal_type(np.ones_like(C)) # E: numpy.ndarray
+reveal_type(np.ones_like(B)) # E: SubClass
+reveal_type(np.ones_like(B, dtype=np.int64)) # E: numpy.ndarray
+
+reveal_type(np.empty_like(A)) # E: numpy.ndarray
+reveal_type(np.empty_like(C)) # E: numpy.ndarray
+reveal_type(np.empty_like(B)) # E: SubClass
+reveal_type(np.empty_like(B, dtype=np.int64)) # E: numpy.ndarray
+
+reveal_type(np.full_like(A, i8)) # E: numpy.ndarray
+reveal_type(np.full_like(C, i8)) # E: numpy.ndarray
+reveal_type(np.full_like(B, i8)) # E: SubClass
+reveal_type(np.full_like(B, i8, dtype=np.int64)) # E: numpy.ndarray
+
+reveal_type(np.ones(1)) # E: numpy.ndarray
+reveal_type(np.ones([1, 1, 1])) # E: numpy.ndarray
+
+reveal_type(np.full(1, i8)) # E: numpy.ndarray
+reveal_type(np.full([1, 1, 1], i8)) # E: numpy.ndarray
+
+reveal_type(np.indices([1, 2, 3])) # E: numpy.ndarray
+reveal_type(np.indices([1, 2, 3], sparse=True)) # E: tuple[numpy.ndarray]
+
+reveal_type(np.fromfunction(func, (3, 5))) # E: SubClass
+
+reveal_type(np.identity(10)) # E: numpy.ndarray
+
+reveal_type(np.atleast_1d(A)) # E: numpy.ndarray
+reveal_type(np.atleast_1d(C)) # E: numpy.ndarray
+reveal_type(np.atleast_1d(A, A)) # E: list[numpy.ndarray]
+reveal_type(np.atleast_1d(A, C)) # E: list[numpy.ndarray]
+reveal_type(np.atleast_1d(C, C)) # E: list[numpy.ndarray]
+
+reveal_type(np.atleast_2d(A)) # E: numpy.ndarray
+
+reveal_type(np.atleast_3d(A)) # E: numpy.ndarray
+
+reveal_type(np.vstack([A, A])) # E: numpy.ndarray
+reveal_type(np.vstack([A, C])) # E: numpy.ndarray
+reveal_type(np.vstack([C, C])) # E: numpy.ndarray
+
+reveal_type(np.hstack([A, A])) # E: numpy.ndarray
+
+reveal_type(np.stack([A, A])) # E: numpy.ndarray
+reveal_type(np.stack([A, A], axis=0)) # E: numpy.ndarray
+reveal_type(np.stack([A, A], out=B)) # E: SubClass
+
+reveal_type(np.block([[A, A], [A, A]])) # E: numpy.ndarray
+reveal_type(np.block(C)) # E: numpy.ndarray
--- /dev/null
+import numpy as np
+
+i8 = np.int64(1)
+u8 = np.uint64(1)
+
+i4 = np.int32(1)
+u4 = np.uint32(1)
+
+b_ = np.bool_(1)
+
+b = bool(1)
+i = int(1)
+
+AR = np.array([0, 1, 2], dtype=np.int32)
+AR.setflags(write=False)
+
+
+reveal_type(i8 << i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 >> i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 | i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 ^ i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 & i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+
+reveal_type(i8 << AR) # E: Any
+reveal_type(i8 >> AR) # E: Any
+reveal_type(i8 | AR) # E: Any
+reveal_type(i8 ^ AR) # E: Any
+reveal_type(i8 & AR) # E: Any
+
+reveal_type(i4 << i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 >> i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 | i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 ^ i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 & i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+
+reveal_type(i8 << i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 >> i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 | i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 ^ i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 & i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+
+reveal_type(i8 << i) # E: numpy.signedinteger[Any]
+reveal_type(i8 >> i) # E: numpy.signedinteger[Any]
+reveal_type(i8 | i) # E: numpy.signedinteger[Any]
+reveal_type(i8 ^ i) # E: numpy.signedinteger[Any]
+reveal_type(i8 & i) # E: numpy.signedinteger[Any]
+
+reveal_type(i8 << b_) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 >> b_) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 | b_) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 ^ b_) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 & b_) # E: numpy.signedinteger[numpy.typing._64Bit]
+
+reveal_type(i8 << b) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 >> b) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 | b) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 ^ b) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 & b) # E: numpy.signedinteger[numpy.typing._64Bit]
+
+reveal_type(u8 << u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 >> u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 | u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 ^ u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 & u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+
+reveal_type(u8 << AR) # E: Any
+reveal_type(u8 >> AR) # E: Any
+reveal_type(u8 | AR) # E: Any
+reveal_type(u8 ^ AR) # E: Any
+reveal_type(u8 & AR) # E: Any
+
+reveal_type(u4 << u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(u4 >> u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(u4 | u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(u4 ^ u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(u4 & u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+
+reveal_type(u4 << i4) # E: numpy.signedinteger[Any]
+reveal_type(u4 >> i4) # E: numpy.signedinteger[Any]
+reveal_type(u4 | i4) # E: numpy.signedinteger[Any]
+reveal_type(u4 ^ i4) # E: numpy.signedinteger[Any]
+reveal_type(u4 & i4) # E: numpy.signedinteger[Any]
+
+reveal_type(u4 << i) # E: numpy.signedinteger[Any]
+reveal_type(u4 >> i) # E: numpy.signedinteger[Any]
+reveal_type(u4 | i) # E: numpy.signedinteger[Any]
+reveal_type(u4 ^ i) # E: numpy.signedinteger[Any]
+reveal_type(u4 & i) # E: numpy.signedinteger[Any]
+
+reveal_type(u8 << b_) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 >> b_) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 | b_) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 ^ b_) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 & b_) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+
+reveal_type(u8 << b) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 >> b) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 | b) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 ^ b) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(u8 & b) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+
+reveal_type(b_ << b_) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(b_ >> b_) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(b_ | b_) # E: numpy.bool_
+reveal_type(b_ ^ b_) # E: numpy.bool_
+reveal_type(b_ & b_) # E: numpy.bool_
+
+reveal_type(b_ << AR) # E: Any
+reveal_type(b_ >> AR) # E: Any
+reveal_type(b_ | AR) # E: Any
+reveal_type(b_ ^ AR) # E: Any
+reveal_type(b_ & AR) # E: Any
+
+reveal_type(b_ << b) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(b_ >> b) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(b_ | b) # E: numpy.bool_
+reveal_type(b_ ^ b) # E: numpy.bool_
+reveal_type(b_ & b) # E: numpy.bool_
+
+reveal_type(b_ << i) # E: numpy.signedinteger[Any]
+reveal_type(b_ >> i) # E: numpy.signedinteger[Any]
+reveal_type(b_ | i) # E: numpy.signedinteger[Any]
+reveal_type(b_ ^ i) # E: numpy.signedinteger[Any]
+reveal_type(b_ & i) # E: numpy.signedinteger[Any]
+
+reveal_type(~i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(~i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(~u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(~u4) # E: numpy.unsignedinteger[numpy.typing._32Bit]
+reveal_type(~b_) # E: numpy.bool_
+reveal_type(~AR) # E: Any
--- /dev/null
+import numpy as np
+
+reveal_type(np.Inf) # E: float
+reveal_type(np.Infinity) # E: float
+reveal_type(np.NAN) # E: float
+reveal_type(np.NINF) # E: float
+reveal_type(np.NZERO) # E: float
+reveal_type(np.NaN) # E: float
+reveal_type(np.PINF) # E: float
+reveal_type(np.PZERO) # E: float
+reveal_type(np.e) # E: float
+reveal_type(np.euler_gamma) # E: float
+reveal_type(np.inf) # E: float
+reveal_type(np.infty) # E: float
+reveal_type(np.nan) # E: float
+reveal_type(np.pi) # E: float
+
+reveal_type(np.ALLOW_THREADS) # E: int
+reveal_type(np.BUFSIZE) # E: int
+reveal_type(np.CLIP) # E: int
+reveal_type(np.ERR_CALL) # E: int
+reveal_type(np.ERR_DEFAULT) # E: int
+reveal_type(np.ERR_IGNORE) # E: int
+reveal_type(np.ERR_LOG) # E: int
+reveal_type(np.ERR_PRINT) # E: int
+reveal_type(np.ERR_RAISE) # E: int
+reveal_type(np.ERR_WARN) # E: int
+reveal_type(np.FLOATING_POINT_SUPPORT) # E: int
+reveal_type(np.FPE_DIVIDEBYZERO) # E: int
+reveal_type(np.FPE_INVALID) # E: int
+reveal_type(np.FPE_OVERFLOW) # E: int
+reveal_type(np.FPE_UNDERFLOW) # E: int
+reveal_type(np.MAXDIMS) # E: int
+reveal_type(np.MAY_SHARE_BOUNDS) # E: int
+reveal_type(np.MAY_SHARE_EXACT) # E: int
+reveal_type(np.RAISE) # E: int
+reveal_type(np.SHIFT_DIVIDEBYZERO) # E: int
+reveal_type(np.SHIFT_INVALID) # E: int
+reveal_type(np.SHIFT_OVERFLOW) # E: int
+reveal_type(np.SHIFT_UNDERFLOW) # E: int
+reveal_type(np.UFUNC_BUFSIZE_DEFAULT) # E: int
+reveal_type(np.WRAP) # E: int
+reveal_type(np.tracemalloc_domain) # E: int
+
+reveal_type(np.little_endian) # E: bool
+reveal_type(np.True_) # E: numpy.bool_
+reveal_type(np.False_) # E: numpy.bool_
+
+reveal_type(np.UFUNC_PYVALS_NAME) # E: str
+
+reveal_type(np.sctypeDict) # E: dict
+reveal_type(np.sctypes) # E: TypedDict
--- /dev/null
+import numpy as np
+
+reveal_type(np.dtype(np.float64)) # E: numpy.dtype[numpy.floating[numpy.typing._64Bit]]
+reveal_type(np.dtype(np.int64)) # E: numpy.dtype[numpy.signedinteger[numpy.typing._64Bit]]
+
+# String aliases
+reveal_type(np.dtype("float64")) # E: numpy.dtype[numpy.floating[numpy.typing._64Bit]]
+reveal_type(np.dtype("float32")) # E: numpy.dtype[numpy.floating[numpy.typing._32Bit]]
+reveal_type(np.dtype("int64")) # E: numpy.dtype[numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(np.dtype("int32")) # E: numpy.dtype[numpy.signedinteger[numpy.typing._32Bit]]
+reveal_type(np.dtype("bool")) # E: numpy.dtype[numpy.bool_]
+reveal_type(np.dtype("bytes")) # E: numpy.dtype[numpy.bytes_]
+reveal_type(np.dtype("str")) # E: numpy.dtype[numpy.str_]
+
+# Python types
+reveal_type(np.dtype(complex)) # E: numpy.dtype[numpy.complexfloating[numpy.typing._64Bit, numpy.typing._64Bit]]
+reveal_type(np.dtype(float)) # E: numpy.dtype[numpy.floating[numpy.typing._64Bit]]
+reveal_type(np.dtype(int)) # E: numpy.dtype
+reveal_type(np.dtype(bool)) # E: numpy.dtype[numpy.bool_]
+reveal_type(np.dtype(str)) # E: numpy.dtype[numpy.str_]
+reveal_type(np.dtype(bytes)) # E: numpy.dtype[numpy.bytes_]
+
+# Special case for None
+reveal_type(np.dtype(None)) # E: numpy.dtype[numpy.floating[numpy.typing._64Bit]]
+
+# Dtypes of dtypes
+reveal_type(np.dtype(np.dtype(np.float64))) # E: numpy.dtype[numpy.floating[numpy.typing._64Bit]]
+
+# Parameterized dtypes
+reveal_type(np.dtype("S8")) # E: numpy.dtype
+
+# Void
+reveal_type(np.dtype(("U", 10))) # E: numpy.dtype[numpy.void]
--- /dev/null
+import numpy as np
+
+a: "np.flatiter[np.ndarray]"
+
+reveal_type(a.base) # E: numpy.ndarray*
+reveal_type(a.copy()) # E: numpy.ndarray*
+reveal_type(a.coords) # E: tuple[builtins.int]
+reveal_type(a.index) # E: int
+reveal_type(iter(a)) # E: Iterator[numpy.generic*]
+reveal_type(next(a)) # E: numpy.generic
+reveal_type(a[0]) # E: numpy.generic
+reveal_type(a[[0, 1, 2]]) # E: numpy.ndarray*
+reveal_type(a[...]) # E: numpy.ndarray*
+reveal_type(a[:]) # E: numpy.ndarray*
--- /dev/null
+"""Tests for :mod:`numpy.core.fromnumeric`."""
+
+import numpy as np
+
+A = np.array(True, ndmin=2, dtype=bool)
+B = np.array(1.0, ndmin=2, dtype=np.float32)
+A.setflags(write=False)
+B.setflags(write=False)
+
+a = np.bool_(True)
+b = np.float32(1.0)
+c = 1.0
+d = np.array(1.0, dtype=np.float32) # writeable
+
+reveal_type(np.take(a, 0)) # E: numpy.bool_
+reveal_type(np.take(b, 0)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(
+ np.take(c, 0) # E: Union[numpy.generic, datetime.datetime, datetime.timedelta]
+)
+reveal_type(
+ np.take(A, 0) # E: Union[numpy.generic, datetime.datetime, datetime.timedelta]
+)
+reveal_type(
+ np.take(B, 0) # E: Union[numpy.generic, datetime.datetime, datetime.timedelta]
+)
+reveal_type(
+ np.take( # E: Union[Union[numpy.generic, datetime.datetime, datetime.timedelta], numpy.ndarray]
+ A, [0]
+ )
+)
+reveal_type(
+ np.take( # E: Union[Union[numpy.generic, datetime.datetime, datetime.timedelta], numpy.ndarray]
+ B, [0]
+ )
+)
+
+reveal_type(np.reshape(a, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(b, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(c, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(A, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(B, 1)) # E: numpy.ndarray
+
+reveal_type(np.choose(a, [True, True])) # E: numpy.bool_
+reveal_type(np.choose(A, [True, True])) # E: numpy.ndarray
+
+reveal_type(np.repeat(a, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(b, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(c, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(A, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(B, 1)) # E: numpy.ndarray
+
+# TODO: Add tests for np.put()
+
+reveal_type(np.swapaxes(A, 0, 0)) # E: numpy.ndarray
+reveal_type(np.swapaxes(B, 0, 0)) # E: numpy.ndarray
+
+reveal_type(np.transpose(a)) # E: numpy.ndarray
+reveal_type(np.transpose(b)) # E: numpy.ndarray
+reveal_type(np.transpose(c)) # E: numpy.ndarray
+reveal_type(np.transpose(A)) # E: numpy.ndarray
+reveal_type(np.transpose(B)) # E: numpy.ndarray
+
+reveal_type(np.partition(a, 0, axis=None)) # E: numpy.ndarray
+reveal_type(np.partition(b, 0, axis=None)) # E: numpy.ndarray
+reveal_type(np.partition(c, 0, axis=None)) # E: numpy.ndarray
+reveal_type(np.partition(A, 0)) # E: numpy.ndarray
+reveal_type(np.partition(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.argpartition(a, 0)) # E: numpy.integer[Any]
+reveal_type(np.argpartition(b, 0)) # E: numpy.integer[Any]
+reveal_type(np.argpartition(c, 0)) # E: numpy.ndarray
+reveal_type(np.argpartition(A, 0)) # E: numpy.ndarray
+reveal_type(np.argpartition(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.sort(A, 0)) # E: numpy.ndarray
+reveal_type(np.sort(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.argsort(A, 0)) # E: numpy.ndarray
+reveal_type(np.argsort(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.argmax(A)) # E: numpy.integer[Any]
+reveal_type(np.argmax(B)) # E: numpy.integer[Any]
+reveal_type(np.argmax(A, axis=0)) # E: Union[numpy.integer[Any], numpy.ndarray]
+reveal_type(np.argmax(B, axis=0)) # E: Union[numpy.integer[Any], numpy.ndarray]
+
+reveal_type(np.argmin(A)) # E: numpy.integer[Any]
+reveal_type(np.argmin(B)) # E: numpy.integer[Any]
+reveal_type(np.argmin(A, axis=0)) # E: Union[numpy.integer[Any], numpy.ndarray]
+reveal_type(np.argmin(B, axis=0)) # E: Union[numpy.integer[Any], numpy.ndarray]
+
+reveal_type(np.searchsorted(A[0], 0)) # E: numpy.integer[Any]
+reveal_type(np.searchsorted(B[0], 0)) # E: numpy.integer[Any]
+reveal_type(np.searchsorted(A[0], [0])) # E: numpy.ndarray
+reveal_type(np.searchsorted(B[0], [0])) # E: numpy.ndarray
+
+reveal_type(np.resize(a, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(b, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(c, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(A, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(B, (5, 5))) # E: numpy.ndarray
+
+reveal_type(np.squeeze(a)) # E: numpy.bool_
+reveal_type(np.squeeze(b)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.squeeze(c)) # E: numpy.ndarray
+reveal_type(np.squeeze(A)) # E: numpy.ndarray
+reveal_type(np.squeeze(B)) # E: numpy.ndarray
+
+reveal_type(np.diagonal(A)) # E: numpy.ndarray
+reveal_type(np.diagonal(B)) # E: numpy.ndarray
+
+reveal_type(np.trace(A)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.trace(B)) # E: Union[numpy.number[Any], numpy.ndarray]
+
+reveal_type(np.ravel(a)) # E: numpy.ndarray
+reveal_type(np.ravel(b)) # E: numpy.ndarray
+reveal_type(np.ravel(c)) # E: numpy.ndarray
+reveal_type(np.ravel(A)) # E: numpy.ndarray
+reveal_type(np.ravel(B)) # E: numpy.ndarray
+
+reveal_type(np.nonzero(a)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(b)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(c)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(A)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(B)) # E: tuple[numpy.ndarray]
+
+reveal_type(np.shape(a)) # E: tuple[builtins.int]
+reveal_type(np.shape(b)) # E: tuple[builtins.int]
+reveal_type(np.shape(c)) # E: tuple[builtins.int]
+reveal_type(np.shape(A)) # E: tuple[builtins.int]
+reveal_type(np.shape(B)) # E: tuple[builtins.int]
+
+reveal_type(np.compress([True], a)) # E: numpy.ndarray
+reveal_type(np.compress([True], b)) # E: numpy.ndarray
+reveal_type(np.compress([True], c)) # E: numpy.ndarray
+reveal_type(np.compress([True], A)) # E: numpy.ndarray
+reveal_type(np.compress([True], B)) # E: numpy.ndarray
+
+reveal_type(np.clip(a, 0, 1.0)) # E: numpy.number[Any]
+reveal_type(np.clip(b, -1, 1)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.clip(c, 0, 1)) # E: numpy.number[Any]
+reveal_type(np.clip(A, 0, 1)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.clip(B, 0, 1)) # E: Union[numpy.number[Any], numpy.ndarray]
+
+reveal_type(np.sum(a)) # E: numpy.number[Any]
+reveal_type(np.sum(b)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.sum(c)) # E: numpy.number[Any]
+reveal_type(np.sum(A)) # E: numpy.number[Any]
+reveal_type(np.sum(B)) # E: numpy.number[Any]
+reveal_type(np.sum(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.sum(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+
+reveal_type(np.all(a)) # E: numpy.bool_
+reveal_type(np.all(b)) # E: numpy.bool_
+reveal_type(np.all(c)) # E: numpy.bool_
+reveal_type(np.all(A)) # E: numpy.bool_
+reveal_type(np.all(B)) # E: numpy.bool_
+reveal_type(np.all(A, axis=0)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.all(B, axis=0)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.all(A, keepdims=True)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.all(B, keepdims=True)) # E: Union[numpy.bool_, numpy.ndarray]
+
+reveal_type(np.any(a)) # E: numpy.bool_
+reveal_type(np.any(b)) # E: numpy.bool_
+reveal_type(np.any(c)) # E: numpy.bool_
+reveal_type(np.any(A)) # E: numpy.bool_
+reveal_type(np.any(B)) # E: numpy.bool_
+reveal_type(np.any(A, axis=0)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.any(B, axis=0)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.any(A, keepdims=True)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.any(B, keepdims=True)) # E: Union[numpy.bool_, numpy.ndarray]
+
+reveal_type(np.cumsum(a)) # E: numpy.ndarray
+reveal_type(np.cumsum(b)) # E: numpy.ndarray
+reveal_type(np.cumsum(c)) # E: numpy.ndarray
+reveal_type(np.cumsum(A)) # E: numpy.ndarray
+reveal_type(np.cumsum(B)) # E: numpy.ndarray
+
+reveal_type(np.ptp(a)) # E: numpy.number[Any]
+reveal_type(np.ptp(b)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.ptp(c)) # E: numpy.number[Any]
+reveal_type(np.ptp(A)) # E: numpy.number[Any]
+reveal_type(np.ptp(B)) # E: numpy.number[Any]
+reveal_type(np.ptp(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.ptp(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.ptp(A, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.ptp(B, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+
+reveal_type(np.amax(a)) # E: numpy.number[Any]
+reveal_type(np.amax(b)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.amax(c)) # E: numpy.number[Any]
+reveal_type(np.amax(A)) # E: numpy.number[Any]
+reveal_type(np.amax(B)) # E: numpy.number[Any]
+reveal_type(np.amax(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.amax(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.amax(A, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.amax(B, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+
+reveal_type(np.amin(a)) # E: numpy.number[Any]
+reveal_type(np.amin(b)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.amin(c)) # E: numpy.number[Any]
+reveal_type(np.amin(A)) # E: numpy.number[Any]
+reveal_type(np.amin(B)) # E: numpy.number[Any]
+reveal_type(np.amin(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.amin(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.amin(A, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.amin(B, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+
+reveal_type(np.prod(a)) # E: numpy.number[Any]
+reveal_type(np.prod(b)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.prod(c)) # E: numpy.number[Any]
+reveal_type(np.prod(A)) # E: numpy.number[Any]
+reveal_type(np.prod(B)) # E: numpy.number[Any]
+reveal_type(np.prod(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.prod(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.prod(A, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.prod(B, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.prod(b, out=d)) # E: numpy.ndarray
+reveal_type(np.prod(B, out=d)) # E: numpy.ndarray
+
+reveal_type(np.cumprod(a)) # E: numpy.ndarray
+reveal_type(np.cumprod(b)) # E: numpy.ndarray
+reveal_type(np.cumprod(c)) # E: numpy.ndarray
+reveal_type(np.cumprod(A)) # E: numpy.ndarray
+reveal_type(np.cumprod(B)) # E: numpy.ndarray
+
+reveal_type(np.ndim(a)) # E: int
+reveal_type(np.ndim(b)) # E: int
+reveal_type(np.ndim(c)) # E: int
+reveal_type(np.ndim(A)) # E: int
+reveal_type(np.ndim(B)) # E: int
+
+reveal_type(np.size(a)) # E: int
+reveal_type(np.size(b)) # E: int
+reveal_type(np.size(c)) # E: int
+reveal_type(np.size(A)) # E: int
+reveal_type(np.size(B)) # E: int
+
+reveal_type(np.around(a)) # E: numpy.number[Any]
+reveal_type(np.around(b)) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.around(c)) # E: numpy.number[Any]
+reveal_type(np.around(A)) # E: numpy.ndarray
+reveal_type(np.around(B)) # E: numpy.ndarray
+
+reveal_type(np.mean(a)) # E: numpy.number[Any]
+reveal_type(np.mean(b)) # E: numpy.number[Any]
+reveal_type(np.mean(c)) # E: numpy.number[Any]
+reveal_type(np.mean(A)) # E: numpy.number[Any]
+reveal_type(np.mean(B)) # E: numpy.number[Any]
+reveal_type(np.mean(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.mean(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.mean(A, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.mean(B, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.mean(b, out=d)) # E: numpy.ndarray
+reveal_type(np.mean(B, out=d)) # E: numpy.ndarray
+
+reveal_type(np.std(a)) # E: numpy.number[Any]
+reveal_type(np.std(b)) # E: numpy.number[Any]
+reveal_type(np.std(c)) # E: numpy.number[Any]
+reveal_type(np.std(A)) # E: numpy.number[Any]
+reveal_type(np.std(B)) # E: numpy.number[Any]
+reveal_type(np.std(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.std(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.std(A, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.std(B, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.std(b, out=d)) # E: numpy.ndarray
+reveal_type(np.std(B, out=d)) # E: numpy.ndarray
+
+reveal_type(np.var(a)) # E: numpy.number[Any]
+reveal_type(np.var(b)) # E: numpy.number[Any]
+reveal_type(np.var(c)) # E: numpy.number[Any]
+reveal_type(np.var(A)) # E: numpy.number[Any]
+reveal_type(np.var(B)) # E: numpy.number[Any]
+reveal_type(np.var(A, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.var(B, axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.var(A, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.var(B, keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(np.var(b, out=d)) # E: numpy.ndarray
+reveal_type(np.var(B, out=d)) # E: numpy.ndarray
--- /dev/null
+import numpy as np
+
+f8 = np.float64()
+i8 = np.int64()
+u8 = np.uint64()
+
+f4 = np.float32()
+i4 = np.int32()
+u4 = np.uint32()
+
+td = np.timedelta64(0, "D")
+b_ = np.bool_()
+
+b = bool()
+f = float()
+i = int()
+
+AR = np.array([1], dtype=np.bool_)
+AR.setflags(write=False)
+
+AR2 = np.array([1], dtype=np.timedelta64)
+AR2.setflags(write=False)
+
+# Time structures
+
+reveal_type(td % td) # E: numpy.timedelta64
+reveal_type(AR2 % td) # E: Any
+reveal_type(td % AR2) # E: Any
+
+reveal_type(divmod(td, td)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.timedelta64]
+reveal_type(divmod(AR2, td)) # E: Tuple[Any, Any]
+reveal_type(divmod(td, AR2)) # E: Tuple[Any, Any]
+
+# Bool
+
+reveal_type(b_ % b) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(b_ % i) # E: numpy.signedinteger[Any]
+reveal_type(b_ % f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ % b_) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(b_ % i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(b_ % u8) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(b_ % f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ % AR) # E: Any
+
+reveal_type(divmod(b_, b)) # E: Tuple[numpy.signedinteger[numpy.typing._8Bit], numpy.signedinteger[numpy.typing._8Bit]]
+reveal_type(divmod(b_, i)) # E: Tuple[numpy.signedinteger[Any], numpy.signedinteger[Any]]
+reveal_type(divmod(b_, f)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(b_, b_)) # E: Tuple[numpy.signedinteger[numpy.typing._8Bit], numpy.signedinteger[numpy.typing._8Bit]]
+reveal_type(divmod(b_, i8)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(b_, u8)) # E: Tuple[numpy.unsignedinteger[numpy.typing._64Bit], numpy.unsignedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(b_, f8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(b_, AR)) # E: Tuple[Any, Any]
+
+reveal_type(b % b_) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(i % b_) # E: numpy.signedinteger[Any]
+reveal_type(f % b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(b_ % b_) # E: numpy.signedinteger[numpy.typing._8Bit]
+reveal_type(i8 % b_) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(u8 % b_) # E: numpy.unsignedinteger[numpy.typing._64Bit]
+reveal_type(f8 % b_) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(AR % b_) # E: Any
+
+reveal_type(divmod(b, b_)) # E: Tuple[numpy.signedinteger[numpy.typing._8Bit], numpy.signedinteger[numpy.typing._8Bit]]
+reveal_type(divmod(i, b_)) # E: Tuple[numpy.signedinteger[Any], numpy.signedinteger[Any]]
+reveal_type(divmod(f, b_)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(b_, b_)) # E: Tuple[numpy.signedinteger[numpy.typing._8Bit], numpy.signedinteger[numpy.typing._8Bit]]
+reveal_type(divmod(i8, b_)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(u8, b_)) # E: Tuple[numpy.unsignedinteger[numpy.typing._64Bit], numpy.unsignedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(f8, b_)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(AR, b_)) # E: Tuple[Any, Any]
+
+# int
+
+reveal_type(i8 % b) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 % i) # E: numpy.signedinteger[Any]
+reveal_type(i8 % f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 % i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i8 % f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i4 % i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i4 % f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i4 % i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(i4 % f4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(i8 % AR) # E: Any
+
+reveal_type(divmod(i8, b)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(i8, i)) # E: Tuple[numpy.signedinteger[Any], numpy.signedinteger[Any]]
+reveal_type(divmod(i8, f)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(i8, i8)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(i8, f8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(i8, i4)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(i8, f4)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(i4, i4)) # E: Tuple[numpy.signedinteger[numpy.typing._32Bit], numpy.signedinteger[numpy.typing._32Bit]]
+reveal_type(divmod(i4, f4)) # E: Tuple[numpy.floating[numpy.typing._32Bit], numpy.floating[numpy.typing._32Bit]]
+reveal_type(divmod(i8, AR)) # E: Tuple[Any, Any]
+
+reveal_type(b % i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(i % i8) # E: numpy.signedinteger[Any]
+reveal_type(f % i8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 % i8) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(f8 % i8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 % i4) # E: numpy.signedinteger[numpy.typing._64Bit]
+reveal_type(f8 % i4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i4 % i4) # E: numpy.signedinteger[numpy.typing._32Bit]
+reveal_type(f4 % i4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(AR % i8) # E: Any
+
+reveal_type(divmod(b, i8)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(i, i8)) # E: Tuple[numpy.signedinteger[Any], numpy.signedinteger[Any]]
+reveal_type(divmod(f, i8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(i8, i8)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(f8, i8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(i4, i8)) # E: Tuple[numpy.signedinteger[numpy.typing._64Bit], numpy.signedinteger[numpy.typing._64Bit]]
+reveal_type(divmod(f4, i8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(i4, i4)) # E: Tuple[numpy.signedinteger[numpy.typing._32Bit], numpy.signedinteger[numpy.typing._32Bit]]
+reveal_type(divmod(f4, i4)) # E: Tuple[numpy.floating[numpy.typing._32Bit], numpy.floating[numpy.typing._32Bit]]
+reveal_type(divmod(AR, i8)) # E: Tuple[Any, Any]
+
+# float
+
+reveal_type(f8 % b) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 % i) # E: numpy.floating[Any]
+reveal_type(f8 % f) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i8 % f4) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 % f4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(f8 % AR) # E: Any
+
+reveal_type(divmod(f8, b)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(f8, i)) # E: Tuple[numpy.floating[Any], numpy.floating[Any]]
+reveal_type(divmod(f8, f)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(f8, f8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(f8, f4)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(f4, f4)) # E: Tuple[numpy.floating[numpy.typing._32Bit], numpy.floating[numpy.typing._32Bit]]
+reveal_type(divmod(f8, AR)) # E: Tuple[Any, Any]
+
+reveal_type(b % f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(i % f8) # E: numpy.floating[Any]
+reveal_type(f % f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 % f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f8 % f8) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(f4 % f4) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(AR % f8) # E: Any
+
+reveal_type(divmod(b, f8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(i, f8)) # E: Tuple[numpy.floating[Any], numpy.floating[Any]]
+reveal_type(divmod(f, f8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(f8, f8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(f4, f8)) # E: Tuple[numpy.floating[numpy.typing._64Bit], numpy.floating[numpy.typing._64Bit]]
+reveal_type(divmod(f4, f4)) # E: Tuple[numpy.floating[numpy.typing._32Bit], numpy.floating[numpy.typing._32Bit]]
+reveal_type(divmod(AR, f8)) # E: Tuple[Any, Any]
--- /dev/null
+import numpy as np
+
+reveal_type(np) # E: ModuleType
+
+reveal_type(np.char) # E: ModuleType
+reveal_type(np.ctypeslib) # E: ModuleType
+reveal_type(np.emath) # E: ModuleType
+reveal_type(np.fft) # E: ModuleType
+reveal_type(np.lib) # E: ModuleType
+reveal_type(np.linalg) # E: ModuleType
+reveal_type(np.ma) # E: ModuleType
+reveal_type(np.matrixlib) # E: ModuleType
+reveal_type(np.polynomial) # E: ModuleType
+reveal_type(np.random) # E: ModuleType
+reveal_type(np.rec) # E: ModuleType
+reveal_type(np.testing) # E: ModuleType
+reveal_type(np.version) # E: ModuleType
+
+# TODO: Remove when annotations have been added to `np.testing.assert_equal`
+reveal_type(np.testing.assert_equal) # E: Any
--- /dev/null
+from typing import TypeVar, Union
+import numpy as np
+import numpy.typing as npt
+
+T = TypeVar("T", bound=npt.NBitBase)
+
+def add(a: np.floating[T], b: np.integer[T]) -> np.floating[T]:
+ return a + b
+
+i8: np.int64
+i4: np.int32
+f8: np.float64
+f4: np.float32
+
+reveal_type(add(f8, i8)) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(add(f4, i8)) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(add(f8, i4)) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(add(f4, i4)) # E: numpy.floating[numpy.typing._32Bit]
--- /dev/null
+import numpy as np
+
+nd = np.array([[1, 2], [3, 4]])
+
+# item
+reveal_type(nd.item()) # E: Any
+reveal_type(nd.item(1)) # E: Any
+reveal_type(nd.item(0, 1)) # E: Any
+reveal_type(nd.item((0, 1))) # E: Any
+
+# tolist
+reveal_type(nd.tolist()) # E: Any
+
+# itemset does not return a value
+# tostring is pretty simple
+# tobytes is pretty simple
+# tofile does not return a value
+# dump does not return a value
+# dumps is pretty simple
+
+# astype
+reveal_type(nd.astype("float")) # E: numpy.ndarray
+reveal_type(nd.astype(float)) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K")) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K", "unsafe")) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K", "unsafe", True)) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K", "unsafe", True, True)) # E: numpy.ndarray
+
+# byteswap
+reveal_type(nd.byteswap()) # E: numpy.ndarray
+reveal_type(nd.byteswap(True)) # E: numpy.ndarray
+
+# copy
+reveal_type(nd.copy()) # E: numpy.ndarray
+reveal_type(nd.copy("C")) # E: numpy.ndarray
+
+# view
+class SubArray(np.ndarray):
+ pass
+
+
+reveal_type(nd.view()) # E: numpy.ndarray
+reveal_type(nd.view(np.int64)) # E: numpy.ndarray
+# replace `Any` with `numpy.matrix` when `matrix` will be added to stubs
+reveal_type(nd.view(np.int64, np.matrix)) # E: Any
+reveal_type(nd.view(np.int64, SubArray)) # E: SubArray
+
+# getfield
+reveal_type(nd.getfield("float")) # E: numpy.ndarray
+reveal_type(nd.getfield(float)) # E: numpy.ndarray
+reveal_type(nd.getfield(float, 8)) # E: numpy.ndarray
+
+# setflags does not return a value
+# fill does not return a value
--- /dev/null
+"""
+Tests for miscellaneous (non-magic) ``np.ndarray``/``np.generic`` methods.
+
+More extensive tests are performed for the methods'
+function-based counterpart in `../from_numeric.py`.
+
+"""
+
+import numpy as np
+
+class SubClass(np.ndarray): ...
+
+f8: np.float64
+A: np.ndarray
+B: SubClass
+
+reveal_type(f8.all()) # E: numpy.bool_
+reveal_type(A.all()) # E: numpy.bool_
+reveal_type(A.all(axis=0)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(A.all(keepdims=True)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(A.all(out=B)) # E: SubClass
+
+reveal_type(f8.any()) # E: numpy.bool_
+reveal_type(A.any()) # E: numpy.bool_
+reveal_type(A.any(axis=0)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(A.any(keepdims=True)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(A.any(out=B)) # E: SubClass
+
+reveal_type(f8.argmax()) # E: numpy.signedinteger[Any]
+reveal_type(A.argmax()) # E: numpy.signedinteger[Any]
+reveal_type(A.argmax(axis=0)) # E: Union[numpy.signedinteger[Any], numpy.ndarray]
+reveal_type(A.argmax(out=B)) # E: SubClass
+
+reveal_type(f8.argmin()) # E: numpy.signedinteger[Any]
+reveal_type(A.argmin()) # E: numpy.signedinteger[Any]
+reveal_type(A.argmin(axis=0)) # E: Union[numpy.signedinteger[Any], numpy.ndarray]
+reveal_type(A.argmin(out=B)) # E: SubClass
+
+reveal_type(f8.argsort()) # E: numpy.ndarray
+reveal_type(A.argsort()) # E: numpy.ndarray
+
+reveal_type(f8.astype(np.int64).choose([()])) # E: numpy.ndarray
+reveal_type(A.choose([0])) # E: numpy.ndarray
+reveal_type(A.choose([0], out=B)) # E: SubClass
+
+reveal_type(f8.clip(1)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.clip(1)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.clip(None, 1)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.clip(1, out=B)) # E: SubClass
+reveal_type(A.clip(None, 1, out=B)) # E: SubClass
+
+reveal_type(f8.compress([0])) # E: numpy.ndarray
+reveal_type(A.compress([0])) # E: numpy.ndarray
+reveal_type(A.compress([0], out=B)) # E: SubClass
+
+reveal_type(f8.conj()) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(A.conj()) # E: numpy.ndarray
+reveal_type(B.conj()) # E: SubClass
+
+reveal_type(f8.conjugate()) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(A.conjugate()) # E: numpy.ndarray
+reveal_type(B.conjugate()) # E: SubClass
+
+reveal_type(f8.cumprod()) # E: numpy.ndarray
+reveal_type(A.cumprod()) # E: numpy.ndarray
+reveal_type(A.cumprod(out=B)) # E: SubClass
+
+reveal_type(f8.cumsum()) # E: numpy.ndarray
+reveal_type(A.cumsum()) # E: numpy.ndarray
+reveal_type(A.cumsum(out=B)) # E: SubClass
+
+reveal_type(f8.max()) # E: numpy.number[Any]
+reveal_type(A.max()) # E: numpy.number[Any]
+reveal_type(A.max(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.max(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.max(out=B)) # E: SubClass
+
+reveal_type(f8.mean()) # E: numpy.number[Any]
+reveal_type(A.mean()) # E: numpy.number[Any]
+reveal_type(A.mean(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.mean(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.mean(out=B)) # E: SubClass
+
+reveal_type(f8.min()) # E: numpy.number[Any]
+reveal_type(A.min()) # E: numpy.number[Any]
+reveal_type(A.min(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.min(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.min(out=B)) # E: SubClass
+
+reveal_type(f8.newbyteorder()) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(A.newbyteorder()) # E: numpy.ndarray
+reveal_type(B.newbyteorder('|')) # E: SubClass
+
+reveal_type(f8.prod()) # E: numpy.number[Any]
+reveal_type(A.prod()) # E: numpy.number[Any]
+reveal_type(A.prod(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.prod(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.prod(out=B)) # E: SubClass
+
+reveal_type(f8.ptp()) # E: numpy.number[Any]
+reveal_type(A.ptp()) # E: numpy.number[Any]
+reveal_type(A.ptp(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.ptp(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.ptp(out=B)) # E: SubClass
+
+reveal_type(f8.round()) # E: numpy.floating[numpy.typing._64Bit]
+reveal_type(A.round()) # E: numpy.ndarray
+reveal_type(A.round(out=B)) # E: SubClass
+
+reveal_type(f8.repeat(1)) # E: numpy.ndarray
+reveal_type(A.repeat(1)) # E: numpy.ndarray
+reveal_type(B.repeat(1)) # E: numpy.ndarray
+
+reveal_type(f8.std()) # E: numpy.number[Any]
+reveal_type(A.std()) # E: numpy.number[Any]
+reveal_type(A.std(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.std(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.std(out=B)) # E: SubClass
+
+reveal_type(f8.sum()) # E: numpy.number[Any]
+reveal_type(A.sum()) # E: numpy.number[Any]
+reveal_type(A.sum(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.sum(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.sum(out=B)) # E: SubClass
+
+reveal_type(f8.take(0)) # E: numpy.generic
+reveal_type(A.take(0)) # E: numpy.generic
+reveal_type(A.take([0])) # E: numpy.ndarray
+reveal_type(A.take(0, out=B)) # E: SubClass
+reveal_type(A.take([0], out=B)) # E: SubClass
+
+reveal_type(f8.var()) # E: numpy.number[Any]
+reveal_type(A.var()) # E: numpy.number[Any]
+reveal_type(A.var(axis=0)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.var(keepdims=True)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.var(out=B)) # E: SubClass
+
+reveal_type(A.argpartition([0])) # E: numpy.ndarray
+
+reveal_type(A.diagonal()) # E: numpy.ndarray
+
+reveal_type(A.dot(1)) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.dot(1, out=B)) # E: SubClass
+
+reveal_type(A.nonzero()) # E: tuple[numpy.ndarray]
+
+reveal_type(A.searchsorted([1])) # E: numpy.ndarray
+
+reveal_type(A.trace()) # E: Union[numpy.number[Any], numpy.ndarray]
+reveal_type(A.trace(out=B)) # E: SubClass
--- /dev/null
+import numpy as np
+
+nd = np.array([[1, 2], [3, 4]])
+
+# reshape
+reveal_type(nd.reshape()) # E: numpy.ndarray
+reveal_type(nd.reshape(4)) # E: numpy.ndarray
+reveal_type(nd.reshape(2, 2)) # E: numpy.ndarray
+reveal_type(nd.reshape((2, 2))) # E: numpy.ndarray
+
+reveal_type(nd.reshape((2, 2), order="C")) # E: numpy.ndarray
+reveal_type(nd.reshape(4, order="C")) # E: numpy.ndarray
+
+# resize does not return a value
+
+# transpose
+reveal_type(nd.transpose()) # E: numpy.ndarray
+reveal_type(nd.transpose(1, 0)) # E: numpy.ndarray
+reveal_type(nd.transpose((1, 0))) # E: numpy.ndarray
+
+# swapaxes
+reveal_type(nd.swapaxes(0, 1)) # E: numpy.ndarray
+
+# flatten
+reveal_type(nd.flatten()) # E: numpy.ndarray
+reveal_type(nd.flatten("C")) # E: numpy.ndarray
+
+# ravel
+reveal_type(nd.ravel()) # E: numpy.ndarray
+reveal_type(nd.ravel("C")) # E: numpy.ndarray
+
+# squeeze
+reveal_type(nd.squeeze()) # E: numpy.ndarray
+reveal_type(nd.squeeze(0)) # E: numpy.ndarray
+reveal_type(nd.squeeze((0, 2))) # E: numpy.ndarray
--- /dev/null
+"""
+Tests for :mod:`numpy.core.numeric`.
+
+Does not include tests which fall under ``array_constructors``.
+
+"""
+
+from typing import List
+import numpy as np
+
+class SubClass(np.ndarray):
+ ...
+
+i8: np.int64
+
+A: np.ndarray
+B: List[int]
+C: SubClass
+
+reveal_type(np.count_nonzero(i8)) # E: int
+reveal_type(np.count_nonzero(A)) # E: int
+reveal_type(np.count_nonzero(B)) # E: int
+reveal_type(np.count_nonzero(A, keepdims=True)) # E: Union[numpy.signedinteger[Any], numpy.ndarray]
+reveal_type(np.count_nonzero(A, axis=0)) # E: Union[numpy.signedinteger[Any], numpy.ndarray]
+
+reveal_type(np.isfortran(i8)) # E: bool
+reveal_type(np.isfortran(A)) # E: bool
+
+reveal_type(np.argwhere(i8)) # E: numpy.ndarray
+reveal_type(np.argwhere(A)) # E: numpy.ndarray
+
+reveal_type(np.flatnonzero(i8)) # E: numpy.ndarray
+reveal_type(np.flatnonzero(A)) # E: numpy.ndarray
+
+reveal_type(np.correlate(B, A, mode="valid")) # E: numpy.ndarray
+reveal_type(np.correlate(A, A, mode="same")) # E: numpy.ndarray
+
+reveal_type(np.convolve(B, A, mode="valid")) # E: numpy.ndarray
+reveal_type(np.convolve(A, A, mode="same")) # E: numpy.ndarray
+
+reveal_type(np.outer(i8, A)) # E: numpy.ndarray
+reveal_type(np.outer(B, A)) # E: numpy.ndarray
+reveal_type(np.outer(A, A)) # E: numpy.ndarray
+reveal_type(np.outer(A, A, out=C)) # E: SubClass
+
+reveal_type(np.tensordot(B, A)) # E: numpy.ndarray
+reveal_type(np.tensordot(A, A)) # E: numpy.ndarray
+reveal_type(np.tensordot(A, A, axes=0)) # E: numpy.ndarray
+reveal_type(np.tensordot(A, A, axes=(0, 1))) # E: numpy.ndarray
+
+reveal_type(np.isscalar(i8)) # E: bool
+reveal_type(np.isscalar(A)) # E: bool
+reveal_type(np.isscalar(B)) # E: bool
+
+reveal_type(np.roll(A, 1)) # E: numpy.ndarray
+reveal_type(np.roll(A, (1, 2))) # E: numpy.ndarray
+reveal_type(np.roll(B, 1)) # E: numpy.ndarray
+
+reveal_type(np.rollaxis(A, 0, 1)) # E: numpy.ndarray
+
+reveal_type(np.moveaxis(A, 0, 1)) # E: numpy.ndarray
+reveal_type(np.moveaxis(A, (0, 1), (1, 2))) # E: numpy.ndarray
+
+reveal_type(np.cross(B, A)) # E: numpy.ndarray
+reveal_type(np.cross(A, A)) # E: numpy.ndarray
+
+reveal_type(np.indices([0, 1, 2])) # E: numpy.ndarray
+reveal_type(np.indices([0, 1, 2], sparse=False)) # E: numpy.ndarray
+reveal_type(np.indices([0, 1, 2], sparse=True)) # E: tuple[numpy.ndarray]
+
+reveal_type(np.binary_repr(1)) # E: str
+
+reveal_type(np.base_repr(1)) # E: str
+
+reveal_type(np.allclose(i8, A)) # E: bool
+reveal_type(np.allclose(B, A)) # E: bool
+reveal_type(np.allclose(A, A)) # E: bool
+
+reveal_type(np.isclose(i8, A)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.isclose(B, A)) # E: Union[numpy.bool_, numpy.ndarray]
+reveal_type(np.isclose(A, A)) # E: Union[numpy.bool_, numpy.ndarray]
+
+reveal_type(np.array_equal(i8, A)) # E: bool
+reveal_type(np.array_equal(B, A)) # E: bool
+reveal_type(np.array_equal(A, A)) # E: bool
+
+reveal_type(np.array_equiv(i8, A)) # E: bool
+reveal_type(np.array_equiv(B, A)) # E: bool
+reveal_type(np.array_equiv(A, A)) # E: bool
--- /dev/null
+import numpy as np
+
+reveal_type(np.issctype(np.generic)) # E: bool
+reveal_type(np.issctype("foo")) # E: bool
+
+reveal_type(np.obj2sctype("S8")) # E: Union[numpy.generic, None]
+reveal_type(np.obj2sctype("S8", default=None)) # E: Union[numpy.generic, None]
+reveal_type(
+ np.obj2sctype("foo", default=int) # E: Union[numpy.generic, Type[builtins.int*]]
+)
+
+reveal_type(np.issubclass_(np.float64, float)) # E: bool
+reveal_type(np.issubclass_(np.float64, (int, float))) # E: bool
+
+reveal_type(np.sctype2char("S8")) # E: str
+reveal_type(np.sctype2char(list)) # E: str
+
+reveal_type(np.find_common_type([np.int64], [np.int64])) # E: numpy.dtype
--- /dev/null
+import numpy as np
+
+x = np.complex64(3 + 2j)
+
+reveal_type(x.real) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(x.imag) # E: numpy.floating[numpy.typing._32Bit]
+
+reveal_type(x.real.real) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(x.real.imag) # E: numpy.floating[numpy.typing._32Bit]
+
+reveal_type(x.itemsize) # E: int
+reveal_type(x.shape) # E: Tuple[]
+reveal_type(x.strides) # E: Tuple[]
+
+reveal_type(x.ndim) # E: Literal[0]
+reveal_type(x.size) # E: Literal[1]
+
+reveal_type(x.squeeze()) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(x.byteswap()) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+reveal_type(x.transpose()) # E: numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]
+
+reveal_type(x.dtype) # E: numpy.dtype[numpy.complexfloating[numpy.typing._32Bit, numpy.typing._32Bit]]
+
+reveal_type(np.complex64().real) # E: numpy.floating[numpy.typing._32Bit]
+reveal_type(np.complex128().imag) # E: numpy.floating[numpy.typing._64Bit]
+
+reveal_type(np.unicode_('foo')) # E: numpy.str_
+reveal_type(np.str0('foo')) # E: numpy.str_
--- /dev/null
+"""Typing tests for `numpy.core._ufunc_config`."""
+
+import numpy as np
+
+def func(a: str, b: int) -> None: ...
+
+class Write:
+ def write(self, value: str) -> None: ...
+
+reveal_type(np.seterr(all=None)) # E: TypedDict('numpy.core._ufunc_config._ErrDict'
+reveal_type(np.seterr(divide="ignore")) # E: TypedDict('numpy.core._ufunc_config._ErrDict'
+reveal_type(np.seterr(over="warn")) # E: TypedDict('numpy.core._ufunc_config._ErrDict'
+reveal_type(np.seterr(under="call")) # E: TypedDict('numpy.core._ufunc_config._ErrDict'
+reveal_type(np.seterr(invalid="raise")) # E: TypedDict('numpy.core._ufunc_config._ErrDict'
+reveal_type(np.geterr()) # E: TypedDict('numpy.core._ufunc_config._ErrDict'
+
+reveal_type(np.setbufsize(4096)) # E: int
+reveal_type(np.getbufsize()) # E: int
+
+reveal_type(np.seterrcall(func)) # E: Union[None, def (builtins.str, builtins.int) -> Any, numpy.core._ufunc_config._SupportsWrite]
+reveal_type(np.seterrcall(Write())) # E: Union[None, def (builtins.str, builtins.int) -> Any, numpy.core._ufunc_config._SupportsWrite]
+reveal_type(np.geterrcall()) # E: Union[None, def (builtins.str, builtins.int) -> Any, numpy.core._ufunc_config._SupportsWrite]
+
+reveal_type(np.errstate(call=func, all="call")) # E: numpy.errstate[def (a: builtins.str, b: builtins.int)]
+reveal_type(np.errstate(call=Write(), divide="log", over="log")) # E: numpy.errstate[ufunc_config.Write]
--- /dev/null
+from typing import Type
+
+import numpy as np
+
+reveal_type(np.ModuleDeprecationWarning()) # E: numpy.ModuleDeprecationWarning
+reveal_type(np.VisibleDeprecationWarning()) # E: numpy.VisibleDeprecationWarning
+reveal_type(np.ComplexWarning()) # E: numpy.ComplexWarning
+reveal_type(np.RankWarning()) # E: numpy.RankWarning
+reveal_type(np.TooHardError()) # E: numpy.TooHardError
+reveal_type(np.AxisError(1)) # E: numpy.AxisError
--- /dev/null
+import os
+from pathlib import Path
+
+import numpy as np
+from numpy.testing import assert_
+
+ROOT = Path(np.__file__).parents[0]
+FILES = [
+ ROOT / "py.typed",
+ ROOT / "__init__.pyi",
+ ROOT / "char.pyi",
+ ROOT / "ctypeslib.pyi",
+ ROOT / "emath.pyi",
+ ROOT / "rec.pyi",
+ ROOT / "core" / "__init__.pyi",
+ ROOT / "distutils" / "__init__.pyi",
+ ROOT / "f2py" / "__init__.pyi",
+ ROOT / "fft" / "__init__.pyi",
+ ROOT / "lib" / "__init__.pyi",
+ ROOT / "linalg" / "__init__.pyi",
+ ROOT / "ma" / "__init__.pyi",
+ ROOT / "matrixlib" / "__init__.pyi",
+ ROOT / "polynomial" / "__init__.pyi",
+ ROOT / "random" / "__init__.pyi",
+ ROOT / "testing" / "__init__.pyi",
+]
+
+
+class TestIsFile:
+ def test_isfile(self):
+ """Test if all ``.pyi`` files are properly installed."""
+ for file in FILES:
+ assert_(os.path.isfile(file))
--- /dev/null
+import importlib.util
+import itertools
+import os
+import re
+from collections import defaultdict
+from typing import Optional
+
+import pytest
+try:
+ from mypy import api
+except ImportError:
+ NO_MYPY = True
+else:
+ NO_MYPY = False
+
+
+DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
+PASS_DIR = os.path.join(DATA_DIR, "pass")
+FAIL_DIR = os.path.join(DATA_DIR, "fail")
+REVEAL_DIR = os.path.join(DATA_DIR, "reveal")
+MYPY_INI = os.path.join(DATA_DIR, "mypy.ini")
+CACHE_DIR = os.path.join(DATA_DIR, ".mypy_cache")
+
+
+def get_test_cases(directory):
+ for root, _, files in os.walk(directory):
+ for fname in files:
+ if os.path.splitext(fname)[-1] == ".py":
+ fullpath = os.path.join(root, fname)
+ # Use relative path for nice py.test name
+ relpath = os.path.relpath(fullpath, start=directory)
+
+ yield pytest.param(
+ fullpath,
+ # Manually specify a name for the test
+ id=relpath,
+ )
+
+
+@pytest.mark.slow
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(PASS_DIR))
+def test_success(path):
+ stdout, stderr, exitcode = api.run([
+ "--config-file",
+ MYPY_INI,
+ "--cache-dir",
+ CACHE_DIR,
+ path,
+ ])
+ assert exitcode == 0, stdout
+ assert re.match(r"Success: no issues found in \d+ source files?", stdout.strip())
+
+
+@pytest.mark.slow
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(FAIL_DIR))
+def test_fail(path):
+ __tracebackhide__ = True
+
+ stdout, stderr, exitcode = api.run([
+ "--config-file",
+ MYPY_INI,
+ "--cache-dir",
+ CACHE_DIR,
+ path,
+ ])
+ assert exitcode != 0
+
+ with open(path) as fin:
+ lines = fin.readlines()
+
+ errors = defaultdict(lambda: "")
+ error_lines = stdout.rstrip("\n").split("\n")
+ assert re.match(
+ r"Found \d+ errors? in \d+ files? \(checked \d+ source files?\)",
+ error_lines[-1].strip(),
+ )
+ for error_line in error_lines[:-1]:
+ error_line = error_line.strip()
+ if not error_line:
+ continue
+
+ match = re.match(
+ r"^.+\.py:(?P<lineno>\d+): (error|note): .+$",
+ error_line,
+ )
+ if match is None:
+ raise ValueError(f"Unexpected error line format: {error_line}")
+ lineno = int(match.group('lineno'))
+ errors[lineno] += error_line
+
+ for i, line in enumerate(lines):
+ lineno = i + 1
+ if line.startswith('#') or (" E:" not in line and lineno not in errors):
+ continue
+
+ target_line = lines[lineno - 1]
+ if "# E:" in target_line:
+ marker = target_line.split("# E:")[-1].strip()
+ expected_error = errors.get(lineno)
+ _test_fail(path, marker, expected_error, lineno)
+ else:
+ pytest.fail(f"Error {repr(errors[lineno])} not found")
+
+
+_FAIL_MSG1 = """Extra error at line {}
+
+Extra error: {!r}
+"""
+
+_FAIL_MSG2 = """Error mismatch at line {}
+
+Expected error: {!r}
+Observed error: {!r}
+"""
+
+
+def _test_fail(path: str, error: str, expected_error: Optional[str], lineno: int) -> None:
+ if expected_error is None:
+ raise AssertionError(_FAIL_MSG1.format(lineno, error))
+ elif error not in expected_error:
+ raise AssertionError(_FAIL_MSG2.format(lineno, expected_error, error))
+
+
+@pytest.mark.slow
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(REVEAL_DIR))
+def test_reveal(path):
+ __tracebackhide__ = True
+
+ stdout, stderr, exitcode = api.run([
+ "--config-file",
+ MYPY_INI,
+ "--cache-dir",
+ CACHE_DIR,
+ path,
+ ])
+
+ with open(path) as fin:
+ lines = fin.read().replace('*', '').split("\n")
+
+ stdout_list = stdout.replace('*', '').split("\n")
+ for error_line in stdout_list:
+ error_line = error_line.strip()
+ if not error_line:
+ continue
+
+ match = re.match(
+ r"^.+\.py:(?P<lineno>\d+): note: .+$",
+ error_line,
+ )
+ if match is None:
+ raise ValueError(f"Unexpected reveal line format: {error_line}")
+ lineno = int(match.group('lineno')) - 1
+ assert "Revealed type is" in error_line
+
+ marker = lines[lineno].split("# E:")[-1].strip()
+ _test_reveal(path, marker, error_line, 1 + lineno)
+
+
+_REVEAL_MSG = """Reveal mismatch at line {}
+
+Expected reveal: {!r}
+Observed reveal: {!r}
+"""
+
+
+def _test_reveal(path: str, reveal: str, expected_reveal: str, lineno: int) -> None:
+ if reveal not in expected_reveal:
+ raise AssertionError(_REVEAL_MSG.format(lineno, expected_reveal, reveal))
+
+
+@pytest.mark.slow
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(PASS_DIR))
+def test_code_runs(path):
+ path_without_extension, _ = os.path.splitext(path)
+ dirname, filename = path.split(os.sep)[-2:]
+ spec = importlib.util.spec_from_file_location(f"{dirname}.{filename}", path)
+ test_module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(test_module)
# THIS FILE IS GENERATED FROM NUMPY SETUP.PY
#
# To compare versions robustly, use `numpy.lib.NumpyVersion`
-short_version = '1.19.5'
-version = '1.19.5'
-full_version = '1.19.5'
-git_revision = '8f4b73a0d04f7bebb06a154b43e5ef5b5980052f'
-release = True
+short_version: str = '1.20.0'
+version: str = '1.20.0'
+full_version: str = '1.20.0'
+git_revision: str = '40a1d54edd06309ea4a092455e9154a8c31c1070'
+release: bool = True
if not release:
version = full_version
name = "Improvements"
showcontent = true
+ [[tool.towncrier.type]]
+ directory = "performance"
+ name = "Performance improvements and changes"
+ showcontent = true
+
[[tool.towncrier.type]]
directory = "change"
name = "Changes"
# Matrix PendingDeprecationWarning.
ignore:the matrix subclass is not
ignore:Importing from numpy.matlib is
+
--- /dev/null
+# These packages are needed for a release in addition to those needed
+# for building, testing, and the creation of documentation.
+
+# download-wheels.py
+urllib3
+beautifulsoup4
+
+# changelog.py
+pygithub
+gitpython
+
+# uploading wheels
+twine
+
+# building and notes
+Paver
+towncrier
import sys
-import os
+import os, glob
# In case we are run from the source directory, we don't want to import the
# project from there:
help="Start IPython shell with PYTHONPATH set")
parser.add_argument("--shell", action="store_true",
help="Start Unix shell with PYTHONPATH set")
+ parser.add_argument("--mypy", action="store_true",
+ help="Run mypy on files with NumPy on the MYPYPATH")
parser.add_argument("--debug", "-g", action="store_true",
help="Debug build")
parser.add_argument("--parallel", "-j", type=int, default=0,
help="Number of parallel jobs during build")
parser.add_argument("--warn-error", action="store_true",
help="Set -Werror to convert all compiler warnings to errors")
+ parser.add_argument("--cpu-baseline", default=None,
+ help="Specify a list of enabled baseline CPU optimizations"),
+ parser.add_argument("--cpu-dispatch", default=None,
+ help="Specify a list of dispatched CPU optimizations"),
+ parser.add_argument("--disable-optimization", action="store_true",
+ help="Disable CPU optimized code(dispatch,simd,fast...)"),
+ parser.add_argument("--simd-test", default=None,
+ help="Specify a list of CPU optimizations to be "
+ "tested against NumPy SIMD interface"),
parser.add_argument("--show-build-log", action="store_true",
help="Show build output rather than using a log file")
parser.add_argument("--bench", action="store_true",
"COMMIT. Note that you need to commit your "
"changes first!"))
parser.add_argument("args", metavar="ARGS", default=[], nargs=REMAINDER,
- help="Arguments to pass to Nose, asv, Python or shell")
+ help="Arguments to pass to pytest, asv, mypy, Python or shell")
args = parser.parse_args(argv)
if args.durations < 0:
import warnings; warnings.filterwarnings("always")
import IPython
import numpy as np
- IPython.embed(user_ns={"np": np})
+ IPython.embed(colors='neutral', user_ns={"np": np})
sys.exit(0)
if args.shell:
subprocess.call([shell] + extra_argv)
sys.exit(0)
+ if args.mypy:
+ try:
+ import mypy.api
+ except ImportError:
+ raise RuntimeError(
+ "Mypy not found. Please install it by running "
+ "pip install -r test_requirements.txt from the repo root"
+ )
+
+ os.environ['MYPYPATH'] = site_dir
+ # By default mypy won't color the output since it isn't being
+ # invoked from a tty.
+ os.environ['MYPY_FORCE_COLOR'] = '1'
+
+ config = os.path.join(
+ site_dir,
+ "numpy",
+ "typing",
+ "tests",
+ "data",
+ "mypy.ini",
+ )
+
+ report, errors, status = mypy.api.run(
+ ['--config-file', config] + args.args
+ )
+ print(report, end='')
+ print(errors, end='', file=sys.stderr)
+ sys.exit(status)
+
if args.coverage:
dst_dir = os.path.join(ROOT_DIR, 'build', 'coverage')
fn = os.path.join(dst_dir, 'coverage_html.js')
out = subprocess.check_output(['git', 'rev-parse', commit_a])
commit_a = out.strip().decode('ascii')
+ # generate config file with the required build options
+ asv_cfpath = [
+ '--config', asv_compare_config(
+ os.path.join(ROOT_DIR, 'benchmarks'), args,
+ # to clear the cache if the user changed build options
+ (commit_a, commit_b)
+ )
+ ]
cmd = ['asv', 'continuous', '-e', '-f', '1.05',
- commit_a, commit_b] + bench_args
+ commit_a, commit_b] + asv_cfpath + bench_args
ret = subprocess.call(cmd, cwd=os.path.join(ROOT_DIR, 'benchmarks'))
sys.exit(ret)
else:
sys.exit(1)
-
def build_project(args):
"""
Build a dev version of the project.
"""
- import distutils.sysconfig
+ import sysconfig
root_ok = [os.path.exists(os.path.join(ROOT_DIR, fn))
for fn in PROJECT_ROOT_FILES]
# Always use ccache, if installed
env['PATH'] = os.pathsep.join(EXTRA_PATH + env.get('PATH', '').split(os.pathsep))
- cvars = distutils.sysconfig.get_config_vars()
+ cvars = sysconfig.get_config_vars()
compiler = env.get('CC') or cvars.get('CC', '')
if 'gcc' in compiler:
# Check that this isn't clang masquerading as gcc.
cmd += ["build_src", "--verbose-cfg"]
if args.warn_error:
cmd += ["--warn-error"]
+ if args.cpu_baseline:
+ cmd += ["--cpu-baseline", args.cpu_baseline]
+ if args.cpu_dispatch:
+ cmd += ["--cpu-dispatch", args.cpu_dispatch]
+ if args.disable_optimization:
+ cmd += ["--disable-optimization"]
+ if args.simd_test is not None:
+ cmd += ["--simd-test", args.simd_test]
# Install; avoid producing eggs so numpy can be imported from dst_dir.
cmd += ['install', '--prefix=' + dst_dir,
'--single-version-externally-managed',
os.makedirs(site_dir)
if not os.path.exists(site_dir_noarch):
os.makedirs(site_dir_noarch)
- env['PYTHONPATH'] = site_dir + ':' + site_dir_noarch
+ env['PYTHONPATH'] = site_dir + os.pathsep + site_dir_noarch
log_filename = os.path.join(ROOT_DIR, 'build.log')
return site_dir, site_dir_noarch
+def asv_compare_config(bench_path, args, h_commits):
+ """
+ Fill the required build options through custom variable
+ 'numpy_build_options' and return the generated config path.
+ """
+ conf_path = os.path.join(bench_path, "asv_compare.conf.json.tpl")
+ nconf_path = os.path.join(bench_path, "_asv_compare.conf.json")
+
+ # add custom build
+ build = []
+ if args.parallel > 1:
+ build += ["-j", str(args.parallel)]
+ if args.cpu_baseline:
+ build += ["--cpu-baseline", args.cpu_baseline]
+ if args.cpu_dispatch:
+ build += ["--cpu-dispatch", args.cpu_dispatch]
+ if args.disable_optimization:
+ build += ["--disable-optimization"]
+
+ is_cached = asv_substitute_config(conf_path, nconf_path,
+ numpy_build_options = ' '.join([f'\\"{v}\\"' for v in build]),
+ )
+ if not is_cached:
+ asv_clear_cache(bench_path, h_commits)
+ return nconf_path
+
+def asv_clear_cache(bench_path, h_commits, env_dir="env"):
+ """
+ Force ASV to clear the cache according to specified commit hashes.
+ """
+ # FIXME: only clear the cache from the current environment dir
+ asv_build_pattern = os.path.join(bench_path, env_dir, "*", "asv-build-cache")
+ for asv_build_cache in glob.glob(asv_build_pattern, recursive=True):
+ for c in h_commits:
+ try: shutil.rmtree(os.path.join(asv_build_cache, c))
+ except OSError: pass
+
+def asv_substitute_config(in_config, out_config, **custom_vars):
+ """
+ A workaround to allow substituting custom tokens within
+ ASV configuration file since there's no official way to add custom
+ variables(e.g. env vars).
+
+ Parameters
+ ----------
+ in_config : str
+ The path of ASV configuration file, e.g. '/path/to/asv.conf.json'
+ out_config : str
+ The path of generated configuration file,
+ e.g. '/path/to/asv_substituted.conf.json'.
+
+ The other keyword arguments represent the custom variables.
+
+ Returns
+ -------
+ True(is cached) if 'out_config' is already generated with
+ the same '**custom_vars' and updated with latest 'in_config',
+ False otherwise.
+
+ Examples
+ --------
+ See asv_compare_config().
+ """
+ assert in_config != out_config
+ assert len(custom_vars) > 0
+
+ def sdbm_hash(*factors):
+ chash = 0
+ for f in factors:
+ for char in str(f):
+ chash = ord(char) + (chash << 6) + (chash << 16) - chash
+ chash &= 0xFFFFFFFF
+ return chash
+
+ vars_hash = sdbm_hash(custom_vars, os.path.getmtime(in_config))
+ try:
+ with open(out_config, "r") as wfd:
+ hash_line = wfd.readline().split('hash:')
+ if len(hash_line) > 1 and int(hash_line[1]) == vars_hash:
+ return True
+ except IOError:
+ pass
+
+ custom_vars = {f'{{{k}}}':v for k, v in custom_vars.items()}
+ with open(in_config, "r") as rfd, open(out_config, "w") as wfd:
+ wfd.write(f"// hash:{vars_hash}\n")
+ wfd.write("// This file is automatically generated by runtests.py\n")
+ for line in rfd:
+ for key, val in custom_vars.items():
+ line = line.replace(key, val)
+ wfd.write(line)
+ return False
#
# GCOV support
import sys
import subprocess
import textwrap
-import sysconfig
import warnings
-
-if sys.version_info[:2] < (3, 6):
- raise RuntimeError("Python version >= 3.6 required.")
+if sys.version_info[:2] < (3, 7):
+ raise RuntimeError("Python version >= 3.7 required.")
import builtins
Development Status :: 5 - Production/Stable
Intended Audience :: Science/Research
Intended Audience :: Developers
-License :: OSI Approved
+License :: OSI Approved :: BSD License
Programming Language :: C
Programming Language :: Python
Programming Language :: Python :: 3
-Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: Implementation :: CPython
Topic :: Software Development
Topic :: Scientific/Engineering
+Typing :: Typed
Operating System :: Microsoft :: Windows
Operating System :: POSIX
Operating System :: Unix
"""
MAJOR = 1
-MINOR = 19
-MICRO = 5
+MINOR = 20
+MICRO = 0
ISRELEASED = True
VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
# The first version not in the `Programming Language :: Python :: ...` classifiers above
if sys.version_info >= (3, 10):
+ fmt = "NumPy {} may not yet support Python {}.{}."
warnings.warn(
- f"NumPy {VERSION} may not yet support Python "
- f"{sys.version_info.major}.{sys.version_info.minor}.",
+ fmt.format(VERSION, *sys.version_info[:2]),
RuntimeWarning,
)
+ del fmt
# Return the git revision as a string
# THIS FILE IS GENERATED FROM NUMPY SETUP.PY
#
# To compare versions robustly, use `numpy.lib.NumpyVersion`
-short_version = '%(version)s'
-version = '%(version)s'
-full_version = '%(full_version)s'
-git_revision = '%(git_revision)s'
-release = %(isrelease)s
+short_version: str = '%(version)s'
+version: str = '%(version)s'
+full_version: str = '%(full_version)s'
+git_revision: str = '%(git_revision)s'
+release: bool = %(isrelease)s
if not release:
version = full_version
raise ValueError('Submodule not clean: {}'.format(line))
-
class concat_license_files():
"""Merge LICENSE.txt and LICENSES_bundled.txt for sdist creation
"""
from numpy.distutils.command.build_clib import build_clib
from numpy.distutils.command.build_ext import build_ext
+ from distutils.version import LooseVersion
+
+ def _needs_gcc_c99_flag(obj):
+ if obj.compiler.compiler_type != 'unix':
+ return False
- def _is_using_gcc(obj):
- is_gcc = False
- if obj.compiler.compiler_type == 'unix':
- cc = sysconfig.get_config_var("CC")
- if not cc:
- cc = ""
- compiler_name = os.path.basename(cc)
- is_gcc = "gcc" in compiler_name
- return is_gcc
+ cc = obj.compiler.compiler[0]
+ if "gcc" not in cc:
+ return False
+
+ # will print something like '4.2.1\n'
+ out = subprocess.run([cc, '-dumpversion'], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, universal_newlines=True)
+ # -std=c99 is default from this version on
+ if LooseVersion(out.stdout) >= LooseVersion('5.0'):
+ return False
+ return True
class new_build_clib(build_clib):
def build_a_library(self, build_info, lib_name, libraries):
- if _is_using_gcc(self):
+ if _needs_gcc_c99_flag(self):
args = build_info.get('extra_compiler_args') or []
args.append('-std=c99')
build_info['extra_compiler_args'] = args
class new_build_ext(build_ext):
def build_extension(self, ext):
- if _is_using_gcc(self):
+ if _needs_gcc_c99_flag(self):
if '-std=c99' not in ext.extra_compile_args:
ext.extra_compile_args.append('-std=c99')
build_ext.build_extension(self, ext)
if not ISRELEASED:
return "https://numpy.org/devdocs"
else:
- # For releaeses, this URL ends up on pypi.
+ # For releases, this URL ends up on pypi.
# By pinning the version, users looking at old PyPI releases can get
# to the associated docs easily.
return "https://numpy.org/doc/{}.{}".format(MAJOR, MINOR)
platforms=["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
test_suite='pytest',
cmdclass=cmdclass,
- python_requires='>=3.6',
+ python_requires='>=3.7',
zip_safe=False,
entry_points={
'console_scripts': f2py_cmds
# library_dirs = C:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2018\windows\mkl\lib\intel64
# libraries = mkl_rt
-# Accelerate
-# ----------
-# Accelerate/vecLib is an OSX framework providing a BLAS and LAPACK implementation.
-#
-# [accelerate]
-# libraries = Accelerate, vecLib
-# #libraries = None
-
# UMFPACK
# -------
# The UMFPACK library is used in scikits.umfpack to factor large sparse matrices.
cython==0.29.21
wheel
setuptools<49.2.0
-hypothesis==5.36.1
+hypothesis==5.41.3
pytest==6.0.2
-pytz==2020.1
+pytz==2020.4
pytest-cov==2.10.1
-pickle5; python_version == '3.7'
-pickle5; python_version == '3.6' and platform_python_implementation != 'PyPy'
+pickle5; python_version == '3.7' and platform_python_implementation != 'PyPy'
# for numpy.random.test.test_extending
cffi
+# For testing types. Notes on the restrictions:
+# - Mypy relies on C API features not present in PyPy
+# - Mypy doesn't currently work on Python 3.9
+mypy==0.790; platform_python_implementation != "PyPy"
+typing_extensions
this_repo = Repo(os.path.join(os.path.dirname(__file__), ".."))
author_msg =\
-u"""
+"""
A total of %d people contributed to this release. People with a "+" by their
names contributed a patch for the first time.
"""
pull_request_msg =\
-u"""
+"""
A total of %d pull requests were merged for this release.
"""
+
def get_authors(revision_range):
pat = u'^.*\\t(.*)$'
lst_release, cur_release = [r.strip() for r in revision_range.split('..')]
-#!/usr/bin/env python
+#!/usr/bin/env python3
+# -*- encoding:utf-8 -*-
"""
-Download NumPy wheels from Anaconda staging area.
+Script to download NumPy wheels from the Anaconda staging area.
+
+Usage::
+
+ $ ./tools/download-wheels.py <version> -w <optional-wheelhouse>
+
+The default wheelhouse is ``release/installers``.
+
+Dependencies
+------------
+
+- beautifulsoup4
+- urllib3
+
+Examples
+--------
+
+While in the repository root::
+
+ $ python tools/download-wheels.py 1.19.0
+ $ python tools/download-wheels.py 1.19.0 -w ~/wheelhouse
"""
-import sys
import os
import re
import shutil
# Edit these for other projects.
STAGING_URL = 'https://anaconda.org/multibuild-wheels-staging/numpy'
-PREFIX = '^.*numpy-'
+PREFIX = 'numpy'
+
def get_wheel_names(version):
""" Get wheel names from Anaconda HTML directory.
"""
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED')
- tmpl = re.compile(PREFIX + version + '.*\.whl$')
- index_url = f"{STAGING_URL}/files"
+ tmpl = re.compile(rf"^.*{PREFIX}-{version}-.*\.whl$")
+ index_url = f"{STAGING_URL}/files"
index_html = http.request('GET', index_url)
soup = BeautifulSoup(index_html.data, 'html.parser')
return soup.findAll(text=tmpl)
"""
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED')
wheel_names = get_wheel_names(version)
- for wheel_name in wheel_names:
+
+ for i, wheel_name in enumerate(wheel_names):
wheel_url = f"{STAGING_URL}/{version}/download/{wheel_name}"
wheel_path = os.path.join(wheelhouse, wheel_name)
with open(wheel_path, 'wb') as f:
with http.request('GET', wheel_url, preload_content=False,) as r:
- print(f"Downloading {wheel_name}")
+ print(f"{i + 1:<4}{wheel_name}")
shutil.copyfileobj(r, f)
+ print(f"\nTotal files downloaded: {len(wheel_names)}")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
"version",
- help="NumPy version to download.")
+ help="NumPy version to download.")
parser.add_argument(
"-w", "--wheelhouse",
default=os.path.join(os.getcwd(), "release", "installers"),
args = parser.parse_args()
wheelhouse = os.path.expanduser(args.wheelhouse)
+ if not os.path.isdir(wheelhouse):
+ raise RuntimeError(
+ f"{wheelhouse} wheelhouse directory is not present."
+ " Perhaps you need to use the '-w' flag to specify one.")
+
download_wheels(args.version, wheelhouse)
--- /dev/null
+#!/usr/bin/env python
+"""Find the functions in a module missing type annotations.
+
+To use it run
+
+./functions_missing_types.py <module>
+
+and it will print out a list of functions in the module that don't
+have types.
+
+"""
+import argparse
+import ast
+import importlib
+import os
+
+NUMPY_ROOT = os.path.dirname(os.path.join(
+ os.path.abspath(__file__), "..",
+))
+
+# Technically "public" functions (they don't start with an underscore)
+# that we don't want to include.
+EXCLUDE_LIST = {
+ "numpy": {
+ # Stdlib modules in the namespace by accident
+ "absolute_import",
+ "division",
+ "print_function",
+ "warnings",
+ "sys",
+ "os",
+ "math",
+ # Accidentally public, deprecated, or shouldn't be used
+ "Tester",
+ "alen",
+ "add_docstring",
+ "add_newdoc",
+ "add_newdoc_ufunc",
+ "core",
+ "compat",
+ "fastCopyAndTranspose",
+ "get_array_wrap",
+ "int_asbuffer",
+ "oldnumeric",
+ "safe_eval",
+ "set_numeric_ops",
+ "test",
+ # Builtins
+ "bool",
+ "complex",
+ "float",
+ "int",
+ "long",
+ "object",
+ "str",
+ "unicode",
+ # More standard names should be preferred
+ "alltrue", # all
+ "sometrue", # any
+ }
+}
+
+
+class FindAttributes(ast.NodeVisitor):
+ """Find top-level attributes/functions/classes in stubs files.
+
+ Do this by walking the stubs ast. See e.g.
+
+ https://greentreesnakes.readthedocs.io/en/latest/index.html
+
+ for more information on working with Python's ast.
+
+ """
+
+ def __init__(self):
+ self.attributes = set()
+
+ def visit_FunctionDef(self, node):
+ if node.name == "__getattr__":
+ # Not really a module member.
+ return
+ self.attributes.add(node.name)
+ # Do not call self.generic_visit; we are only interested in
+ # top-level functions.
+ return
+
+ def visit_ClassDef(self, node):
+ if not node.name.startswith("_"):
+ self.attributes.add(node.name)
+ return
+
+ def visit_AnnAssign(self, node):
+ self.attributes.add(node.target.id)
+
+
+def find_missing(module_name):
+ module_path = os.path.join(
+ NUMPY_ROOT,
+ module_name.replace(".", os.sep),
+ "__init__.pyi",
+ )
+
+ module = importlib.import_module(module_name)
+ module_attributes = {
+ attribute for attribute in dir(module) if not attribute.startswith("_")
+ }
+
+ if os.path.isfile(module_path):
+ with open(module_path) as f:
+ tree = ast.parse(f.read())
+ ast_visitor = FindAttributes()
+ ast_visitor.visit(tree)
+ stubs_attributes = ast_visitor.attributes
+ else:
+ # No stubs for this module yet.
+ stubs_attributes = set()
+
+ exclude_list = EXCLUDE_LIST.get(module_name, set())
+
+ missing = module_attributes - stubs_attributes - exclude_list
+ print("\n".join(sorted(missing)))
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("module")
+ args = parser.parse_args()
+
+ find_missing(args.module)
+
+
+if __name__ == "__main__":
+ main()
from urllib.error import HTTPError
OPENBLAS_V = '0.3.13'
-OPENBLAS_LONG = 'v0.3.13'
+OPENBLAS_LONG = 'v0.3.13-62-gaf2b0d02'
BASE_LOC = 'https://anaconda.org/multibuild-wheels-staging/openblas-libs'
BASEURL = f'{BASE_LOC}/{OPENBLAS_LONG}/download'
ARCHITECTURES = ['', 'windows', 'darwin', 'aarch64', 'x86_64',
runtime_library_dirs = $target/lib
EOF
-echo getting PyPy 3.6-v7.3.1
-wget -q https://downloads.python.org/pypy/pypy3.6-v7.3.1-linux64.tar.bz2 -O pypy.tar.bz2
+echo getting PyPy 3.6-v7.3.2
+wget -q https://downloads.python.org/pypy/pypy3.6-v7.3.2-linux64.tar.bz2 -O pypy.tar.bz2
mkdir -p pypy3
(cd pypy3; tar --strip-components=1 -xf ../pypy.tar.bz2)
pypy3/bin/pypy3 -mensurepip
PUBLIC_SUBMODULES = [
'core',
- 'doc.structured_arrays',
'f2py',
'linalg',
'lib',
'c-info.python-as-glue.rst',
'f2py.getting-started.rst',
'arrays.nditer.cython.rst',
+ # See PR 17222, these should be fixed
+ 'basics.broadcasting.rst',
+ 'basics.byteswapping.rst',
+ 'basics.creation.rst',
+ 'basics.dispatch.rst',
+ 'basics.indexing.rst',
+ 'basics.subclassing.rst',
+ 'basics.types.rst',
+ 'misc.rst',
]
# these names are not required to be present in ALL despite being in
except ValueError:
pass
if not all_dict:
- # Must be a pure documentation module like doc.structured_arrays
+ # Must be a pure documentation module
all_dict.append('__doc__')
# Modules are almost always private; real submodules need a separate
output += "Objects in refguide: %i\n\n" % num_ref
only_all, only_ref, missing = compare(all_dict, others, names, module_name)
- dep_in_ref = set(only_ref).intersection(deprecated)
- only_ref = set(only_ref).difference(deprecated)
+ dep_in_ref = only_ref.intersection(deprecated)
+ only_ref = only_ref.difference(deprecated)
if len(dep_in_ref) > 0:
output += "Deprecated objects in refguide::\n\n"
if (py_obj == NULL ) return "C NULL value";
if (py_obj == Py_None ) return "Python None" ;
if (PyCallable_Check(py_obj)) return "callable" ;
- if (PyString_Check( py_obj)) return "string" ;
- if (PyInt_Check( py_obj)) return "int" ;
+ if (PyBytes_Check( py_obj)) return "string" ;
+ if (PyLong_Check( py_obj)) return "int" ;
if (PyFloat_Check( py_obj)) return "float" ;
if (PyDict_Check( py_obj)) return "dict" ;
if (PyList_Check( py_obj)) return "list" ;
(PyObject* array = NULL)
{
npy_intp dims[1];
- if (!PyInt_Check($input))
+ if (!PyLong_Check($input))
{
const char* typestring = pytype_string($input);
PyErr_Format(PyExc_TypeError,
typestring);
SWIG_fail;
}
- $2 = (DIM_TYPE) PyInt_AsLong($input);
+ $2 = (DIM_TYPE) PyLong_AsSsize_t($input);
+ if ($2 == -1 && PyErr_Occurred()) SWIG_fail;
dims[0] = (npy_intp) $2;
array = PyArray_SimpleNew(1, dims, DATA_TYPECODE);
if (!array) SWIG_fail;
(PyObject* array = NULL)
{
npy_intp dims[1];
- if (!PyInt_Check($input))
+ if (!PyLong_Check($input))
{
const char* typestring = pytype_string($input);
PyErr_Format(PyExc_TypeError,
typestring);
SWIG_fail;
}
- $1 = (DIM_TYPE) PyInt_AsLong($input);
+ $1 = (DIM_TYPE) PyLong_AsSsize_t($input);
+ if ($1 == -1 && PyErr_Occurred()) SWIG_fail;
dims[0] = (npy_intp) $1;
array = PyArray_SimpleNew(1, dims, DATA_TYPECODE);
if (!array) SWIG_fail;
if (!array) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$2), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$2), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$3), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$3), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array || !require_fortran(array)) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$3), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$3), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$4), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$4), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array || !require_fortran(array)) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$4), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$4), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$5), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$5), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array || !require_fortran(array)) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$5), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$5), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$5), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$5), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
if (!array || !require_fortran(array)) SWIG_fail;
%#ifdef SWIGPY_USE_CAPSULE
- PyObject* cap = PyCapsule_New((void*)(*$1), SWIGPY_CAPSULE_NAME, free_cap);
+ PyObject* cap = PyCapsule_New((void*)(*$5), SWIGPY_CAPSULE_NAME, free_cap);
%#else
- PyObject* cap = PyCObject_FromVoidPtr((void*)(*$1), free);
+ PyObject* cap = PyCObject_FromVoidPtr((void*)(*$5), free);
%#endif
%#if NPY_API_VERSION < 0x00000007
SWIGINTERN int
SWIG_AsVal_dec(long)(PyObject * obj, long * val)
{
- if (PyInt_Check(obj)) {
- if (val) *val = PyInt_AsLong(obj);
- return SWIG_OK;
- } else if (PyLong_Check(obj)) {
+ if (PyLong_Check(obj)) {
long v = PyLong_AsLong(obj);
- if (!PyErr_Occurred()) {
+ if (v != -1 || !PyErr_Occurred()) {
if (val) *val = v;
return SWIG_OK;
} else {
%#ifdef SWIG_PYTHON_CAST_MODE
{
int dispatch = 0;
- long v = PyInt_AsLong(obj);
- if (!PyErr_Occurred()) {
+ long v = PyLong_AsLong(obj);
+ if (v != -1 || !PyErr_Occurred()) {
if (val) *val = v;
return SWIG_AddCast(SWIG_OK);
} else {
df -h
ulimit -a
+sudo apt update
+sudo apt install gfortran eatmydata libgfortran5
+
+if [ "$USE_DEBUG" ]
+then
+ sudo apt install python3-dbg python3-dev python3-setuptools
+fi
+
mkdir builds
pushd builds
--- /dev/null
+#!/usr/bin/env python3
+"""
+Run with a repo/build number or list of Travis CI build times to show the optimal build
+order to run faster and make full use of all available parallel build jobs.
+
+Requires the Travis Client CLI
+
+https://github.com/travis-ci/travis.rb#installation
+
+# Example
+
+$ # Check build 22 of hugovk/numpy, and skip the first job (it's a single stage)
+$ travis-sorter.py hugovk/numpy 22 --skip 1
+travis show -r hugovk/numpy 22
+[8, 7, 8, 10, 9, 18, 8, 11, 8, 10, 8, 8, 17, 8, 26]
+[7, 8, 10, 9, 18, 8, 11, 8, 10, 8, 8, 17, 8, 26]
+Before:
+
+ID Duration in mins
+ 1 *******
+ 2 ********
+ 3 **********
+ 4 *********
+ 5 ******************
+ 6 ********
+ 7 ***********
+ 8 ********
+ 9 **********
+10 ********
+11 ********
+12 *****************
+13 ********
+14 **************************
+End: 46
+ ----------------------------------------------
+
+After:
+
+ID Duration in mins
+14 **************************
+ 5 ******************
+12 *****************
+ 7 ***********
+ 3 **********
+ 9 **********
+ 4 *********
+ 2 ********
+ 6 ********
+ 8 ********
+10 ********
+11 ********
+13 ********
+ 1 *******
+End: 34
+ ----------------------------------
+
+# Example
+
+$ python travis-sorter.py 4 4 4 4 4 12 19
+
+Before:
+
+****
+****
+****
+****
+****
+ ************
+ *******************
+12345678901234567890123 = 23 minutes
+
+After:
+
+*******************
+************
+****
+****
+****
+ ****
+ ****
+1234567890123456789 = 19 minutes
+"""
+import argparse
+import re
+import subprocess
+import sys
+
+count = 1
+
+
+def summarise(jobs):
+ end = 0
+ print("ID Duration in mins")
+ for job in jobs:
+ before = " " * job.started
+ active = "*" * job.length
+ print("{:2d} {}{}".format(job.id, before, active))
+ if job.started + job.length > end:
+ end = job.started + job.length
+ # for job in jobs:
+ # print(job)
+ print("End:", end)
+ print(" " + "-" * end)
+
+
+class Job(object):
+ def __init__(self, length):
+ global count
+ self.id = count
+ count += 1
+ self.length = length
+ self.started = -1
+ self.status = "not started"
+ self.ended = False
+
+ def __str__(self):
+ return "{}\tLength: {}\tStarted: {}\tEnded: {}".format(
+ self.id, self.length, self.started, self.ended
+ )
+
+
+def count_status(jobs, status):
+ number = 0
+ for job in jobs:
+ if job.status == status:
+ number += 1
+ return number
+
+
+def simulate(jobs, limit):
+
+ time = 0
+
+ # summarise(jobs)
+
+ while True:
+ # Check if any have ended
+ for job in jobs:
+ if job.status == "active":
+ if time >= job.started + job.length:
+ # print("{}/{} Finished:".format(count_status(jobs, "active"), limit))
+ job.ended = time
+ job.status = "finished"
+ # print(job)
+
+ # Check if any can start
+ for job in jobs:
+ if job.status == "not started":
+ if count_status(jobs, "active") < limit:
+ # print("{}/{} Starting:".format(count_status(jobs, "active"), limit))
+ job.started = time
+ job.status = "active"
+ # print(job)
+
+ time += 1
+
+ # Exit loop?
+ if count_status(jobs, "finished") == len(jobs):
+ break
+
+ summarise(jobs)
+
+
+def do_thing(repo, number):
+ cmd = f"travis show -r {repo} {number or ''}"
+ # cmd = f"travis show --com -r {repo} {number or ''}"
+ print(cmd)
+
+ exitcode = 0
+ # For offline testing
+ output = """Build #4: Upgrade Python syntax with pyupgrade https://github.com/asottile/pyupgrade
+State: passed
+Type: push
+Branch: add-3.7
+Compare URL: https://github.com/hugovk/diff-cover/compare/4ae7cf97c6fa...7eeddb300175
+Duration: 16 min 7 sec
+Started: 2018-10-17 19:03:01
+Finished: 2018-10-17 19:09:53
+
+#4.1 passed: 1 min os: linux, env: TOXENV=py27, python: 2.7
+#4.2 passed: 1 min 43 sec os: linux, env: TOXENV=py34, python: 3.4
+#4.3 passed: 1 min 52 sec os: linux, env: TOXENV=py35, python: 3.5
+#4.4 passed: 1 min 38 sec os: linux, env: TOXENV=py36, python: 3.6
+#4.5 passed: 1 min 47 sec os: linux, env: TOXENV=py37, python: 3.7
+#4.6 passed: 4 min 35 sec os: linux, env: TOXENV=pypy, python: pypy
+#4.7 passed: 3 min 17 sec os: linux, env: TOXENV=pypy3, python: pypy3"""
+
+ # For offline testing
+ output = """Build #9: :arrows_clockwise: [EngCom] Public Pull Requests - 2.3-develop
+State: errored
+Type: push
+Branch: 2.3-develop
+Compare URL: https://github.com/hugovk/magento2/compare/80469a61e061...77af5d65ef4f
+Duration: 4 hrs 12 min 13 sec
+Started: 2018-10-27 17:50:51
+Finished: 2018-10-27 18:54:14
+
+#9.1 passed: 3 min 30 sec os: linux, env: TEST_SUITE=unit, php: 7.1
+#9.2 passed: 3 min 35 sec os: linux, env: TEST_SUITE=unit, php: 7.2
+#9.3 passed: 3 min 41 sec os: linux, env: TEST_SUITE=static, php: 7.2
+#9.4 passed: 8 min 48 sec os: linux, env: TEST_SUITE=js GRUNT_COMMAND=spec, php: 7.2
+#9.5 passed: 3 min 24 sec os: linux, env: TEST_SUITE=js GRUNT_COMMAND=static, php: 7.2
+#9.6 errored: 50 min os: linux, env: TEST_SUITE=integration INTEGRATION_INDEX=1, php: 7.1
+#9.7 passed: 49 min 25 sec os: linux, env: TEST_SUITE=integration INTEGRATION_INDEX=1, php: 7.2
+#9.8 passed: 31 min 54 sec os: linux, env: TEST_SUITE=integration INTEGRATION_INDEX=2, php: 7.1
+#9.9 passed: 31 min 24 sec os: linux, env: TEST_SUITE=integration INTEGRATION_INDEX=2, php: 7.2
+#9.10 passed: 27 min 23 sec os: linux, env: TEST_SUITE=integration INTEGRATION_INDEX=3, php: 7.1
+#9.11 passed: 26 min 9 sec os: linux, env: TEST_SUITE=integration INTEGRATION_INDEX=3, php: 7.2
+#9.12 passed: 13 min os: linux, env: TEST_SUITE=functional, php: 7.2"""
+
+ # Real use
+ exitcode, output = subprocess.getstatusoutput(cmd)
+
+ # print(exitcode)
+ # print(output)
+ if exitcode != 0:
+ print(output)
+ sys.exit(exitcode)
+
+ minutes = []
+ matches = re.findall(r"(pass|fail|error)ed.* (\d+) min (\d+)? ", output)
+ for match in matches:
+ status, m, s = match
+ s = 0 if s == "" else int(s)
+ s += int(m) * 60
+ minutes.append(round(s / 60))
+
+ # print(minutes)
+ return minutes
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="Either give minutes for --jobs (3 5 3 2 5), "
+ "or --repo slug (hugovk/test) and build --number (5)",
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ )
+ parser.add_argument(
+ "input",
+ nargs="+",
+ help="Either: times for each build job (minutes), "
+ "or an org/repo slug and optionally build number",
+ )
+ parser.add_argument(
+ "-l", "--limit", type=int, default=5, help="Concurrent jobs limit"
+ )
+ parser.add_argument(
+ "-s", "--skip", type=int, default=0, help="Skip X jobs at the start"
+ )
+ args = parser.parse_args()
+
+ # If all ints
+ try:
+ for x in args.input:
+ int(x)
+ job_times = args.input
+ except ValueError:
+ try:
+ number = args.input[1]
+ except IndexError:
+ number = None
+ job_times = do_thing(args.input[0], number)
+
+ job_times = job_times[args.skip :]
+ # print(job_times)
+
+ print("Before:")
+ print()
+
+ jobs = []
+ for job_time in job_times:
+ job = Job(job_time)
+ jobs.append(job)
+
+ simulate(jobs, args.limit)
+
+ print()
+ print("After:")
+ print()
+
+ # Sort with longest first
+ jobs.sort(key=lambda job: job.length, reverse=True)
+ # Reset status
+ for job in jobs:
+ job.status = "not started"
+
+ simulate(jobs, args.limit)
# file does not install correctly when Python's optimization level is set
# to strip docstrings (see https://github.com/eliben/pycparser/issues/291).
PYTHONOPTIMIZE="" $PIP install -r test_requirements.txt
+ DURATIONS_FLAG="--durations 10"
if [ -n "$USE_DEBUG" ]; then
export PYTHONPATH=$PWD
- fi
-
- # pytest aborts when running --durations with python3.6-dbg, so only enable
- # it for non-debug tests. That is a cPython bug fixed in later versions of
- # python3.7 but python3.7-dbg is not currently available on travisCI.
- if [ -z "$USE_DEBUG" ]; then
- DURATIONS_FLAG="--durations 10"
+ export MYPYPATH=$PWD
fi
if [ -n "$RUN_COVERAGE" ]; then
export PYTHONWARNINGS="ignore::DeprecationWarning:virtualenv"
$PYTHON -b ../runtests.py -n -v --mode=full $DURATIONS_FLAG $COVERAGE_FLAG
else
- $PYTHON ../runtests.py -n -v $DURATIONS_FLAG
+ $PYTHON ../runtests.py -n -v $DURATIONS_FLAG -- -rs
fi
if [ -n "$RUN_COVERAGE" ]; then
+++ /dev/null
-#!/bin/bash
-#
-set -ex
-
-export CLOUD_CONTAINER_NAME=travis-dev-wheels
-
-if [[ ( ${USE_WHEEL} == 1 ) \
- && ( "${TRAVIS_BRANCH}" == "master" ) \
- && ( "${TRAVIS_PULL_REQUEST}" == "false" ) ]]; then
- pip install wheelhouse_uploader
- python -m wheelhouse_uploader upload --local-folder \
- ${TRAVIS_BUILD_DIR}/dist/ ${CLOUD_CONTAINER_NAME}
-fi
[tox]
envlist =
- py36,py37,py38,
+ py37,py38,py39,
py37-not-relaxed-strides
[testenv]