diff options
111 files changed, 8427 insertions, 703 deletions
diff --git a/.gitignore b/.gitignore index a203abd5b..302968a14 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ GRTAGS GSYMS GTAGS .cache +.mypy_cache/ # Compiled source # ################### diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ea2b414b0..397605765 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -195,16 +195,6 @@ stages: strategy: maxParallel: 6 matrix: - Python36-32bit-fast: - PYTHON_VERSION: '3.6' - PYTHON_ARCH: 'x86' - TEST_MODE: fast - BITS: 32 - Python37-32bit-fast: - PYTHON_VERSION: '3.7' - PYTHON_ARCH: 'x86' - TEST_MODE: fast - BITS: 32 Python38-32bit-fast: PYTHON_VERSION: '3.8' PYTHON_ARCH: 'x86' diff --git a/doc/HOWTO_RELEASE.rst.txt b/doc/HOWTO_RELEASE.rst.txt index 6af8d9ca6..bd15f7f50 100644 --- a/doc/HOWTO_RELEASE.rst.txt +++ b/doc/HOWTO_RELEASE.rst.txt @@ -19,18 +19,11 @@ Source tree 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 @@ -40,16 +33,17 @@ 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. @@ -95,7 +89,6 @@ You will need Cython for building the binaries. Cython compiles the ``.pyx`` 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 ------------ diff --git a/doc/neps/_static/casting_flow.svg b/doc/neps/_static/casting_flow.svg new file mode 100644 index 000000000..8b4b96477 --- /dev/null +++ b/doc/neps/_static/casting_flow.svg @@ -0,0 +1,2212 @@ +<?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> diff --git a/doc/neps/_static/dtype_hierarchy.svg b/doc/neps/_static/dtype_hierarchy.svg new file mode 100644 index 000000000..3bade3d0f --- /dev/null +++ b/doc/neps/_static/dtype_hierarchy.svg @@ -0,0 +1,935 @@ +<?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> diff --git a/doc/neps/nep-0029-deprecation_policy.rst b/doc/neps/nep-0029-deprecation_policy.rst index 9b6022a81..dbead1b9b 100644 --- a/doc/neps/nep-0029-deprecation_policy.rst +++ b/doc/neps/nep-0029-deprecation_policy.rst @@ -1,4 +1,4 @@ -.. _NEP0029: +.. _NEP29: ================================================================================== NEP 29 — Recommend Python and Numpy version support as a community policy standard diff --git a/doc/neps/nep-0042-new-dtypes.rst b/doc/neps/nep-0042-new-dtypes.rst new file mode 100644 index 000000000..1c44c68ea --- /dev/null +++ b/doc/neps/nep-0042-new-dtypes.rst @@ -0,0 +1,1330 @@ +======================================== +NEP 42 — Implementation of New DataTypes +======================================== + +:title: Extensible Datatypes for NumPy +:Author: Sebastian Berg +:Status: Draft +:Type: Standard +:Created: 2019-07-17 + + +.. 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>`. + :ref:`NEP 41 <NEP41>` then provides an overview and generic design + choices for the refactor. NEPs 42 (this document) + and 43 go into the technical details of the internal and external + API changes related to datatypes and universal functions, respectively. + 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. + + +Abstract +-------- + +NEP 40 and 41 detailed the need for the creation of a new datatype system within +NumPy to better serve downstream use-cases and improve the maintainability +and the extensibility of NumPy. +A main issue with the current dtype API is that datatypes are written as +a single Python class with special instances for each of the actual datatypes. +While this certainly has been a practical approach in implementing numerical +datatypes, it does not allow to naturally split up logic. For example, +functions such as ``can_cast`` have explicit logic for each datatype. +Because of this monolithic code structure user-defined datatypes do not have +the same capabilities as NumPy datatypes have. +The current structure also makes understanding and modifying datatypes harder. +The current datatypes are not well encapsulated, so modifications targeting +a single datatype inevitably touch code involving others. +As detailed in NEP 41, the desired general design is to create classes for +each of the NumPy-provided datatypes, meaning that ``np.dtype("float64")`` +returns an instance of a ``Float64`` class which is a subclass of ``np.dtype``. +``np.dtype[float64]`` will also be used to denote this class. +This will allow moving all logic into special methods on the ``np.dtype`` +subclasses. This ``DType`` class would then serve as the central +extension point for adding new dtypes to NumPy. + +This document proposes the new API for the datatypes itself. +A second proposal NEP 43 details proposed changes to the universal +functions. +Note that only the implementation of both NEPs will provide the desired full +functionality. + + +.. note:: + + At this time this NEP is in a preliminary state. Both internal and + external API may be adapted based on user input or implementation needs. + The general design principles and choices, while provisional, should not + be expected to change dramatically. + + +Detailed Description +-------------------- + +NEP 41 layed out the creation of a class hierarchy for datatypes using the +new DType classes to provide all necessary implementations. +This NEP defines the specific choice of API necessary to define new DTypes. +Here, these are suggested as C-API slots; however, conceptually these +translate identically to Python methods. + +Additionally, the NEP proposes to implement the notion of *abstract* DTypes. +Further, we detail – in part – how the proposed methods (C-API slots) +enable all necessary use cases. + +Each section will begin with a short motivation of the issue or what +problem is addressed. This is followed by a description of the proposed +design choice, and then may list alternatives. + + +Nomenclature +"""""""""""" + +As a brief note on nomenclature, it should be noted that ``dtype`` normally +denotes the dtype *instance*, which is the object attached to a numpy array. +On the other hand the ``DType`` class is the subclass of ``np.dtype``. +On the C-level we currently use the name ``descriptor`` or ``descr`` +interchangeably with *dtype instance*. ``descriptor`` or ``descr`` will be +used in proposed C-API names to differentiate dtype instances from DType +classes more clearly. +Note that the notion of dtype class is currently represented mainly as +the ``dtype.num`` and ``dtype.char``. +Please see the `dtype hierarchy figure <hierarchy_figure>`_ for an +illustration of this distinction. + +There are currently classes in NumPy for numeric types e.g. +``np.float64``; however, +these are not DTypes but the corresponding scalar classes +(see also NEP 40 and 41 for discussion on why these are largely unrelated to +the proposed changes). + + +Proposed access to DType class +"""""""""""""""""""""""""""""" + +**Motivation:** + +Currently we often call ``np.dtype`` to create the dtype instance +corresponding to a given scalar type (e.g. ``np.dtype(np.int64)``). +Adding the DType classes may require a way to access the classes conveniently. + +**Description:** + +To avoid duplication, but also to expose the classes conveniently to users +we propose the addition of:: + + np.dtype[np.int64] + +as a class getter. This can work both for user and NumPy DTypes, +although, in many cases a library may choose to provide a more direct +way to access the specific DType class. +This method may initially be limited to concrete DTypes. +The main reason for this choice is to provide a single +clear and future-proof way to find the DType class given the +Python (scalar) class. + +This should not be a common operation, so providing this class getter reduces +the pressure of adding the new DType classes into the namespace. + +*Note: This is currently a possible extension and not yet decided.* + + +Hierarchy of DTypes and Abstract DTypes +""""""""""""""""""""""""""""""""""""""" + +**Motivation:** +The creation of DType classes has already been decided in NEP 41. +Here we discuss the notion of **abstract** DTypes. +There are multiple reasons for this: + +1. It allows the definition of a class hierarchy, in principle allowing checks like + ``isinstance(np.dtype("float64"), np.inexact)``. + **This hierarchy may be a prerequisite to implementing dispatching + for universal functions (NEP 43)** +2. Abstract DTypes can enable code such as + ``arr.astype(Complex)`` to express the desire to cast to a + complex data type of unspecified precision. +3. It anticipates the creation of families of DTypes by users. + For example allowing the creation of an abstract ``Unit`` class with a concrete + ``Float64Unit``. In which case ``Unit(np.float64, "m")`` could be + identical to ``Float64Unit("m")``. + +A very concrete example is the current Pandas ``Categorical`` DType, +which may benefit from abstraction to allow the differentiation of +a categorical of integer values and one of general object values. +The reason for this is that we may want to reject +``common_dtype(CategoricalInt64, String)``, but accept +``common_dtype(CategoricalObject, String)`` to be the ``object`` DType. +The current Pandas ``Categorical`` DType combines both and must remain +representable. The solution is thus to make ``Categorical`` abstract with +the two subclasses ``CategoricalInt64`` and ``CategoricalObject`` +distinguishing the two. + + +**Description:** + +The figure below shows the proposed datatype hierarchy. +It should be noted that abstract DTypes are distinct in two ways: + +1. They do not have instances. Instantiating an abstract DType has to return + a concrete subclass or raise an error (default, and possibly enforced + initially). +2. Unlike concrete DTypes, abstract DTypes can be superclasses, they may also + serve like Python's abstract base classes (ABC). + (It may be possible to simply use/inherit from Python ABCs.) + +These two rules are identical to the type choices made for example in the +`Julia language <https://docs.julialang.org/en/v1/manual/types/#man-abstract-types-1>`_. +It allows for the creation of a datatype hierarchy, but avoids issues with +subclassing concrete DTypes directly. +For example, logic such as ``can_cast`` does not cleanly inherit from a +``Int64`` to a ``Datetime64`` even though the ``Datetime64`` could be seen +as an integer with only a unit attached (and thus implemented as a subclass). + +The main consequence for the DType implementer is that concrete DTypes can +never be subclasses of existing concrete DTypes. +End-users would not notice or need to know about this distinction. +However, subclassing may be a possible mechanism to extend the datatypes +in the future to allow specialized implementations for existing dtypes +such as a GPU float64 subclassing a NumPy float64. + +The combination of (initially) rejecting subclassing of concrete DTypes +while allowing it for abstract ones allows the transparent definition of +a class hierarchy, while avoiding potential issues with subclassing and +especially inheritance. + +As a technical implementation detail: the DType class will require C-side +storage of methods and additional information. +This requires the creation of a ``DTypeMeta`` class. +Each ``DType`` class is thus an instance of ``DTypeMeta`` with a well-defined +and extensible interface. +The end-user will not need to be aware of this. + +.. _hierarchy_figure: +.. figure:: _static/dtype_hierarchy.svg + :figclass: align-center + + +Methods/Slots defined for each DType +"""""""""""""""""""""""""""""""""""" + +NEP 41 detailed that all logic should be defined through special methods +on the DTypes. +This section will list a specific set of such methods (in the form of +Python methods). +The C-side equivalent slot signature will be summarized below after proposing +the general C-API for defining new Datatypes. +Note that while the slots are defined as special Python methods here, this is +for the readers convenience and *not* meant to imply the identical exposure +as a Python API. +This will need to be proposed in a separate, later, NEP. + +Some of the methods may be similar or even reuse existing Python slots. +User-defined DType classes are discouraged from defining or using Python's +special slots without consulting the NumPy developers, in order to allow +defining them later. +For example ``dtype1 & dtype2`` could be a shorthand for +``np.common_dtype(dtype1, dtype2)``, and comparisons should be defined mainly +through casting logic. + + +Additional Information +^^^^^^^^^^^^^^^^^^^^^^ + +In addition to the more detailed methods below, the following general +information is currently provided and will be defined on the class: + +* ``cls.parametric`` (see also `NEP 40 <NEP40>`_): + + * Parametric will be a flag in the (private) C-API. However, the + Python API will instead use a ``ParametricDType`` class from + which to inherit. (This is similar to Python's type flags, which include + flags for some basic subclasses such as subclasses of ``float`` or ``tuple``) + * This flag is mainly to simplify DType creation and casting and + allow for performance tweaks. + * DTypes which are not parametric must define a canonical dtype instance + which should be a singleton. + * Parametric dtypes require some additional methods (below). + +* ``self.canonical`` method (Alternative: new instance attribute) + + * Instead of byteorder, we may want a ``canonical`` flag (reusing the + ISNBO flag – "is native byte order" seems possible here). + This flag signals that the data are stored in the default/canonical way. + In practice this is always an NBO check, but generalization should be possible. + A potential use-case is a complex-conjugated instance of Complex which + stores ``real - imag`` instead of ``real + imag`` and is thus not + the canonical storage. + +* ``ensure_canonical(self) -> dtype`` return a new dtype (or ``self``). + The returned dtype must have the ``canonical`` flag set. + +* ``DType.type`` is the associated scalar type. ``dtype.type`` will be a + class attribute and the current ``dtype.type`` field will be considered + deprecated. This may be relaxed if a use-case arises. + +Additionally, existing methods (and C-side fields) will be provided. +However, the fields ``kind`` and and ``char`` will be set to ``\0`` +(NULL character) on the C-side. +While discouraged, except for NumPy builtin types, ``kind`` both will return +the ``__qualname__`` of the object to ensure uniqueness for all DTypes. +(the replacement for ``kind`` will be to use ``isinstance`` checks). + +Another example of methods that should be moved to the DType class are the +various sorting functions, which shall be implemented by defining a method: + +* ``dtype_get_sort_function(self, sortkind="stable") -> sortfunction`` + +which must return ``NotImplemented`` if the given ``sortkind`` is not known. +Similarly, any function implemented previously which cannot be removed will +be implemented as a special method. +Since these methods can be deprecated and new (renamed) replacements added, +the API is not defined here and it is acceptable if it changes over time. + +For some of the current "methods" defined on the dtype, including sorting, +a long term solution may be to instead create generalized ufuncs to provide +the functionality. + +**Alternatives:** + +Some of these flags could be implemented by inheriting +for example from a ``ParametricDType`` class. However, on the C-side as +an implementation detail it seems simpler to provide a flag. +This does not preclude the possibility of creating a ``ParametricDType`` +to Python to represent the same thing. + +**Example:** + +The ``datetime64`` DType is considered parametric, due to its unit, and +unlike a float64 has no canonical representation. The associated ``type`` +is the ``np.datetime64`` scalar. + + +**Issues and Details:** + +A potential DType such as ``Categorical`` will not be required to have a clear type +associated with it. Instead, the ``type`` may be ``object`` and the +categoircal's values are arbitrary objects. +Unlike with well-defined scalars, this ``type`` cannot +not be used for the dtype discovery necessary for coercion +(compare section `DType Discovery during Array Coercion`_). + + +Coercion to and from Python Objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Motivation:** + +When storing a single value in an array or taking it out of the array, +it is necessary to coerce (convert) it to and from the low-level +representation inside the array. + +**Description:** + +Coercing to and from Python scalars requires two to three methods: + +1. ``__dtype_setitem__(self, item_pointer, value)`` +2. ``__dtype_getitem__(self, item_pointer, base_obj) -> object`` + The ``base_obj`` should be ignored normally, it is provided *only* for + memory management purposes, pointing to an object owning the data. + It exists only to allow support of 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 which + is also used by ``arr.tolist()`` and returns e.g. Python floats 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.) + +These largely correspond to the current definitions. 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. integers, floats, datetime). +In the future a function "``known_scalartype``" may be added to allow a user +dtype to signal which Python scalars it can store directly. + + +**Implementation:** + +The pseudo-code implementation for setting a single item in an array +from an arbitrary Python object ``value`` is (note that some of the +functions are only defined below):: + + 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 +Python ``datetime.datetime`` object (most of the time). + + +**Alternatives:** + +This may be seen as simply a cast to and from the ``object`` dtype. +However, it seems slightly more complicated. This is because +in general a Python object could itself be a zero-dimensional array or +scalar with an associated DType. +Thus, representing it as a normal cast would either require that: + +* The implementor handles all Python classes, even those for which + ``np.array(scalar).astype(UserDType)`` already works because + ``np.array(scalar)`` returns, say, a datetime64 array. +* The cast is actually added between a typed-object to dtype. And even + in this case a generic fallback (for example ``float64`` can use + ``float(scalar)`` to do the cast) is also necessary. + +It is certainly possible to describe the coercion to and from Python objects +using the general casting machinery. However, it seems special enough to +handle specifically. + + +**Further Issues and Discussion:** + +The setitem function currently duplicates some code, such as coercion +from a string. ``datetime64`` allows assignment from string, but the same +conversion also occurs for casts from the string dtype to ``datetime64``. +In the future, we may expose a way to signal whether a conversion is known, +and otherwise a normal cast is made so that the item is effectively set to ``np.array(scalar).astype(requested_dtype)``. + +There is a general issue about the handling of subclasses. We anticipate to not +automatically detect the dtype for ``np.array(float64_subclass)`` to be +float64. The user can still provide ``dtype=np.float64``. However, the above +"assign by casting" using ``np.array(scalar_subclass).astype(requested_dtype)`` +will fail. + +.. note:: + + This means that ``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 will lose precision. + + +DType Discovery during Array Coercion +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An important step in the usage of NumPy arrays is the creation of the array +itself 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 clearly +promoted. +Currently not clearly distinct (but partially existing for strings) is the +use case of:: + + # np.dtype[np.str_] can also be spelled np.str_ or "S" (which works today) + np.array([object(), None], dtype=np.dtype[np.str_]) + +which forces each object to be interpreted as string. This is anticipated +to be useful for example for categorical datatypes:: + + np.array([1, 2, 1, 1, 2], dtype=Categorical) + +to allow the discovery the of all unique values. +(For NumPy ``datetime64`` this is also currently used to allow string input.) + +There are three further issues to consider: + +1. It may be desirable that datatypes can be created which are associated + to normal Python scalars (such as ``datetime.datetime``), which 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 for this is 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 due to the fact that finding the correct shape +of the output array and finding the correct datatype are closely related. + +**Implementation:** + +There are two distinct cases given above: First, when the user has provided no +dtype information, and second when the user provided a DType class – +a notion that is currently represented e.g. by the parametric instance ``"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. +When the DType class is known, the correct dtype instance still needs to be found. +This 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. The reverse lookup will remain hardcoded for the basic Python types initially. + Otherwise the ``type`` attribute will be used, and at least initially may + enforce deriving the scalar from a NumPy-provided scalar base class. + This method may be expanded later (see alternatives). +3. ``__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*, most datatypes + can simply use a default (singleton) dtype instance which is found only + based on the ``type(obj)`` of the Python object. + +The ``type`` which is already associated with any dtype through the +``dtype.type`` attribute maps the DType to the Python type. +This will be cached globally to create a mapping (dictionary) +``known_python_types[type] = DType``. +NumPy currently uses a small hard-coded mapping and conversion of numpy scalars +(inheriting from ``np.generic``) to achieve this. + +.. note:: + + Python integers do not have a clear/concrete NumPy type associated with + them 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 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 functionality provided by + ``np.result_type(python_integer, array)``. + +To allow for a DType to accept specific inputs as known scalars, we will +initially use a method such as ``known_scalar_type`` or ``known_scalar_object`` +which allows discovering an e.g. ``vector`` as a scalar (element) instead of +a sequence (for the command ``np.array(vector, dtype=VectorDType)``). +This will *not* be public API initially, but may be made public at a later +time. + +This will work similar to the following pseudo-code:: + + 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, we have to find out whether an element is actually a sequence. +This means that instead of using the ``object`` dtype directly, we have to +check whether or not it is a sequence. + +The full algorithm (without user provided dtype) 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] + + # Same as 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 above issue 3. is currently (sometimes) supported by NumPy so that +the values of an included array are inspected. +Support in those cases may be kept for compatibility, however, +it will not be exposed to user datatypes. +This means that if e.g. an array with a parametric string dtype is coerced above +(or cast) to an array of a fixed length string dtype (with unknown length), +this will result in an error. +Such a conversion will require passing the correct DType (fixed length of the +string) or providing a utility function to the user. + +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 +the flag to disable registration when in doubt. + +**Alternatives:** + +The above proposes to add a global mapping, however, initially limiting it +to types deriving from a NumPy subclass (and a fixed set of Python types). +This could be relaxed in the future. +Alternatively, we could rely on the scalar belonging to the user dtype to +implement ``scalar.dtype`` or similar. + +Initially, the exact implementation shall be *undefined*, since +scalars will have to derive from a NumPy scalar, they will also have +a ``.dtype`` attribute. A future update can choose to use this instead +of a global mapping. + +An initial alternative suggestion was to use a two-pass approach instead. +The first pass would only find the correct DType class, and the second pass +would then find correct dtype instance (the second pass is often not necessary). +The advantage of this is that the DType class information is vital for universal +functions to decide which loop to execute. +The first pass would provide the full information necessary for value-based +casting currently implemented for scalars, giving even the possibility of +expanding it to e.g. list inputs ``np.add(np.array([8], dtype="uint8"), [4])`` +giving a ``uint8`` result. +This is mainly related to the question to how the common dtype is found above. +It seems unlikely that this is useful, and similar to a global, could be +added later if deemed necessary. + +**Further Issues and Discussion:** + +While it is possible to create e.g. a DType such as Categorical, array, +or vector which can only be used if `dtype=DType` is provided, if this +is necessary these will not roundtrip correctly when converted back +and forth:: + + np.array(np.array(1, dtype=Categorical)[()]) + +requires to pass the original ``dtype=Categorical`` or returns an array +with dtype ``object``. +While a general limitation, the round-tripping shall always be possible if +``dtype=old_dtype`` is provided. + +**Example:** + +The current datetime DType requires a ``__discover_descr_from_pyobject__`` +which returns the correct unit for string inputs. This allows it to support +the current:: + + np.array(["2020-01-02", "2020-01-02 11:24"], dtype="M8") + +By inspecting the date strings. Together with the below common dtype +operation, this allows it to automatically find that the datetime64 unit +should be "minutes". + + +Common DType Operations +^^^^^^^^^^^^^^^^^^^^^^^ + +Numpy currently provides functions like ``np.result_type`` and +``np.promote_types`` for determining common types. +These differ in that ``np.result_type`` can take arrays and scalars as input +and implements value based promotion [1]_. + +To distinguish between the promotion occurring during universal function application, +we will call it "common type" operation here. + +**Motivation:** +Common type operations are vital for array coercion when different +input types are mixed. +They also provide the logic currently used to decide the output dtype of +``np.concatenate()`` and on their own are quite useful. + +Furthermore, common type operations may be used to find the correct dtype +to use for functions with different inputs (including universal functions). +This includes an interesting distinction: + +1. Universal functions use the DType classes for dispatching, they thus + require the common DType class (as a first step). + While this can help with finding the correct loop to execute, the loop + may not need the actual common dtype instance. + (Hypothetical example: + ``float_arr + string_arr -> string``, but the output string length is + not the same as ``np.concatenate(float_arr, string_arr)).dtype``.) +2. Array coercion and concatenation require the common dtype *instance*. + +**Implementation:** +The implementation of the common dtype (instance) determination +has some overlap with casting. +Casting from a specific dtype (Float64) to a String needs to find +the correct string length (a step that is mainly necessary for parametric dtypes). + +We propose the following implementation: + +1. ``__common_dtype__(cls, other : DTypeMeta) -> DTypeMeta`` answers what the common + DType class is given two DType class objects. + It may return ``NotImplemented`` to defer to ``other``. + (For abstract DTypes, subclasses get precedence, concrete types are always + leaves, so always get preference or are tried from left to right). +2. ``__common_instance__(self: SelfT, other : SelfT) -> SelfT`` is used when + two instances of the same DType are given. + For builtin dtypes (that are not parametric), this + currently always returns ``self`` (but ensures native byte order). + This is to preserve metadata. We can thus provide a default implementation + for non-parametric user dtypes. + +These two cases do *not* cover the case where two different dtype instances +need to be promoted. For example `">float64"` and `"S8"`. +The solution is partially "outsourced" to the casting machinery by +splitting the operation up into three steps: + +1. ``Float64.__common_dtype__(type(>float64), type(S8))`` + returns `String` (or defers to ``String.__common_dtype__``). +2. The casting machinery provides the information that `">float64"` casts + to `"S32"` (see below for how casting will be defined). +3. ``String.__common_instance__("S8", "S32")`` returns the final `"S32"`. + +The main reason for this is to avoid the need to implement +identical functionality multiple times. +The design (together with casting) naturally separates the concerns of +different Datatypes. +In the above example, Float64 does not need to know about the cast. +While the casting machinery (``CastingImpl[Float64, String]``) +could include the third step, it is not required to do so and the string +can always be extended (e.g. with new encodings) without extending the +``CastingImpl[Float64, String]``. + +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, dtyp2): + 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.adjust_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 non-parametric DTypes. + +**Note:** + +A currently implemented fallback for the ``__common_dtype__`` operation +is to use the "safe" casting logic. +Since ``int16`` can safely cast to ``int64``, it is clear that +``np.promote_types(int16, int64)`` should be ``int64``. + +However, this cannot define all such operations, and will fail for example for:: + + np.promote_types("int64", "float32") -> np.dtype("float64") + +In this design, it is the responsibility of the DType author to ensure that +in most cases a safe-cast implies that this will be the result of the +``__common_dtype__`` method. + +Note that some 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. + +**Alternatives:** + +The use of casting for common dtype (instance) determination neatly separates +the concerns and allows for a minimal set of duplicate functionality +being implemented. +In cases of mixed DType (classes), it also adds an additional step +to finding the common dtype. +The common dtype (of two instances) could thus be implemented explicitly to avoid +this indirection, potentially only as a fast-path. +The above suggestion assumes that this is, however, not a speed relevant path, +since in most cases, e.g. in array coercion, only a single Python type (and thus +dtype) is involved. +The proposed design hinges in the implementation of casting to be +separated into its own ufunc-like object as described below. + +In principle common DType could be defined only based on "safe casting" rules, +if we order all DTypes and find the first one both can cast to safely. +However, the issue with this approach is that a newly added DType can change +the behaviour of an existing program. For example, a new ``int24`` would be +the first valid common type for ``int16`` and ``uint16``, demoting the currently +defined behaviour of ``int32``. +This API extension could be allowed in the future, while adding it may be +more involved, the current proposal for defining casts is fully opaque in +this regard and thus extensible. + +**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 below casting may need to +decide how to handle the datetime unit. + + +Casting +^^^^^^^ + +Maybe the most complex and interesting operation which is provided +by DTypes is the ability to cast from one dtype to another. +The casting operation is much like a typical function (universal function) on +arrays converting one input to a new output. +There are mainly two distinctions: + +1. Casting always requires an explicit output datatype to be given. +2. The NumPy iterator API requires access to lower-level functions than + is currently necessary for universal functions. + +Casting from one dtype to another can be complex, and generally a casting +function may not implement all details of each input datatype (such as +non-native byte order or unaligned access). +Thus casting naturally is performed in up to three steps: + +1. The input datatype is normalized and prepared for the actual cast. +2. The cast is performed. +3. The cast result, which is in a normalized form, is cast to the requested + form (non-native byte order). + +although often only step 2. is required. + +Further, NumPy provides different casting kinds or safety specifiers: + +* "safe" +* "same_kind" +* "unsafe" + +and in some cases a cast may even be represented as a simple view. + + +**Motivation:** + +Similar to the common dtype/DType operation above, we again have two use cases: + +1. ``arr.astype(np.String)`` (current spelling ``arr.astype("S")``) +2. ``arr.astype(np.dtype("S8"))``. + +Where the first case is also noted in NEP 40 and 41 as a design goal, since +``np.String`` could also be an abstract DType as mentioned above. + +The implementation of casting should also come with as little duplicate +implementation as necessary, i.e. to avoid unnecessary methods on the +DTypes. +Furthermore, it is desirable that casting is implemented similar to universal +functions. + +Analogous to the above, the following also need to be defined: + +1. ``np.can_cast(dtype, DType, "safe")`` (instance to class) +2. ``np.can_cast(dtype, other_dtype, "safe")`` (casting an instance to another instance) + +overloading the meaning of ``dtype`` to mean either class or instance +(on the Python level). +The question of ``np.can_cast(DType, OtherDType, "safe")`` is also a +possibility and may be used internally. +However, it is initially not necessary to expose to Python. + + +**Implementation:** + +During DType creation, DTypes will have the ability to pass a list of +``CastingImpl`` objects, which can define casting to and from the DType. +One of these ``CastingImpl`` objects is special because it should define +the cast within the same DType (from one instance to another). +A DType which does not define this, must have only a single implementation +and not be parametric. + +Each ``CastingImpl`` has a specific DType signature: +``CastingImpl[InputDtype, RequestedDtype]``. +And implements the following methods and attributes: + +* ``adjust_descriptors(self, Tuple[DType] : input) -> casting, Tuple[DType]``. + Here ``casting`` signals the casting safeness (safe, unsafe, or same-kind) + and the output dtype tuple is used for more multi-step casting (see below). +* ``get_transferfunction(...) -> function handling cast`` (signature to be decided). + This function returns a low-level implementation of a strided casting function + ("transfer function"). +* ``cast_kind`` attribute with one of safe, unsafe, or same-kind. Used to + quickly decide casting safety when this is relevant. + +``adjust_descriptors`` provides information about whether or +not a cast is safe and is of importance mainly for parametric DTypes. +``get_transferfunction`` provides NumPy with a function capable of performing +the actual cast. Initially the implementation of ``get_transferfunction`` +will be *private*, and users will only be able to provide contiguous loops +with the signature. + +**Performing the Cast:** + +.. _cast_figure: +.. figure:: _static/casting_flow.svg + :figclass: align-center + +`The above figure <cast_figure>`_ illustrates the multi-step logic necessary to +cast for example an ``int24`` with a value of ``42`` to a string of length 20 +(``"S20"``). +In this example, the implementer only provided the functionality of casting +an ``int24`` to an ``S8`` string (which can hold all 24bit integers). +Due to this limited implementation, the full cast has to do multiple +conversions. The full process is: + +1. Call ``CastingImpl[Int24, String].adjust_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_transferfunction()`` + 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_transferfunction()`` +4. Perform the actual cast using the two transfer functions: + ``int24(42) -> S8("42") -> S20("42")``. + +Note that in this example the ``adjust_descriptors`` function plays a less +central role. It becomes more important for ``np.can_cast``. + +Further, ``adjust_descriptors`` allows the implementation for +``np.array(42, dtype=int24).astype(String)`` to call +``CastingImpl[Int24, String].adjust_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 answer the question of casting safety +``np.can_cast(int24, "S20", casting="safe")``, only the ``adjust_descriptors`` +function is required and called is in the same way as in +`the figure describing a cast <cast_figure>`_. +In this case, the calls to ``adjust_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. + +The casting safety can currently be "equivalent" when a cast is both safe +and can be performed using only a view. +The information that a cast is a simple "view" will instead be handled by +an additional flag. Thus the ``casting`` can have the 6 values in total: +safe, unsafe, same-kind as well as safe+view, unsafe+view, same-kind+view. +Where the current "equivalent" is the same as safe+view. + +(For more information on the ``adjust_descriptor`` signature see the +C-API section below.) + + +**Casting between instances of the same DType:** + +In general one of the casting implementations define by the DType implementor +must be ``CastingImpl[DType, DType]`` (unless there is only a singleton +instance). +To keep the casting to as few steps as possible, this implementation must +be capable any conversions between all instances of this DType. + + +**General Multi-Step Casting** + +In general we could implement certain casts, such as ``int8`` to ``int24`` +even if the user only provides an ``int16 -> int24`` cast. +This proposal currently does not provide this functionality. However, +it could be extended in the future to either find such casts dynamically, +or at least allow ``adjust_descriptors`` to return arbitray ``dtypes``. +If ``CastingImpl[Int8, Int24].adjust_descriptors((int8, int24))`` returns +``(int16, int24)``, the actual casting process could be extended to include +the ``int8 -> int16`` cast. Unlike the above example, which is limited +to at most three steps. + + +**Alternatives:** + +The choice of using only the DType classes in the first step of finding the +correct ``CastingImpl`` means that the default implementation of +``__common_dtype__`` has a reasonable definition of "safe casting" between +DTypes classes (although e.g. the concatenate operation using it may still +fail when attempting to find the actual common instance or cast). + +The split into multiple steps may seem to add complexity +rather than reduce it, however, it consolidates that we have the two distinct +signatures of ``np.can_cast(dtype, DTypeClass)`` and ``np.can_cast(dtype, other_dtype)``. +Further, the above API guarantees the 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, if an encoding was added to the ``String`` +DType, this does not affect the overall cast. +The ``adjust_descriptor`` function can keep returning the default encoding +and the ``CastingImpl[String, String]`` can take care of any necessary encoding +changes. + +The main alternative to the proposed design is to move most of the information +which is here pushed into the ``CastingImpl`` directly into methods +on the DTypes. This, however, will not allow the close similarity between casting +and universal functions. On the up side, it reduces the necessary indirection +as noted below. + +An initial proposal defined two methods ``__can_cast_to__(self, other)`` +to dynamically return ``CastingImpl``. +The advantage of this addition is that it removes the requirement to know all +possible casts at DType creation time (of one of the involved DTypes). +Such API could be added at a later time. It should be noted, however, +that it would be mainly useful for inheritance-like logic, which can be +problematic. As an example two different ``Float64WithUnit`` implementations +both could infer that they can unsafely cast between one another when in fact +some combinations should cast safely or preserve the Unit (both of which the +"base" ``Float64`` would discard). +In the proposed implementation this is not possible, since the two implementations +are not aware of each other. + + +**Notes:** + +The proposed ``CastingImpl`` is designed to be compatible with the +``UFuncImpl`` proposed in NEP 43. +While initially it will be a distinct object or C-struct, the aim is that +``CastingImpl`` can be a subclass or extension of ``UFuncImpl``. +Once this happens, this may naturally allow the use of a ``CastingImpl`` to +pass around a specialized casting function directly. + +In the future, we may consider adding a way to spell out that specific +casts are known to be *not* possible. + +In the above text ``CastingImpl`` is described as a Python object. In practice, +the current plan is to implement it as a C-side structure stored on the ``from`` +datatype. +A Python side API to get an equivalent ``CastingImpl`` object will be created, +but storing it (similar to the current implementation) on the ``from`` datatype +avoids the creation of cyclic reference counts. + +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. + + +**Example:** + +The implementation for casting integers to datetime would currently generally +say that this cast is unsafe (it is always an unsafe cast). +Its ``adjust_descriptors`` functions may look like:: + + def adjust_descriptors(input): + from_dtype, to_dtype = input + + 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 some of these casts, with the possible + exception of the unit-less ``timedelta64`` it may be better to not + define these cast at all. In general we expect that user defined + DTypes will be using other methods such as ``unit.drop_unit(arr)`` + or ``arr * unit.seconds``. + + +C-Side API +^^^^^^^^^^ + +A Python side API shall not be defined here. This is a general side approach. + + +DType creation +"""""""""""""" + +As already mentioned in NEP 41, the interface to define new DTypes in C +is modeled after the limited API in Python: the above-mentioned slots +and some additional necessary information will thus be passed within 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 */ + int is_parametric; /* Is the dtype parametric? */ + int is_abstract; /* Is the dtype abstract? */ + int flags /* flags (to be discussed) */ + /* 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 information will be copied during instantiation. + +**TODO:** The DType author should be able to at define new methods for +their DType, up to defining a full type object and in the future possibly even +extending the ``PyArrayDTypeMeta_Type`` struct. +We have to decide on how (and what) to make available to the user initially. +A proposed initial solution may be to simply allow inheriting from an existing +class. +Further this prevents overriding some slots, such as `==` which may not be +desirable. + + +The proposed method slots are (prepended with ``NPY_dt_``), these are +detailed above and given here for summary: + +* ``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`` + +If not set, most slots are filled with slots which either error or defer automatically. +Non-parametric 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) + +Which will be correct for most dtypes *which do not store metadata*. + +Other slots may be replaced by convenience versions, e.g. sorting methods +can be defined by providing: + +* ``compare(self, char *item_ptr1, char *item_ptr2, int *res) -> {-1, 0}`` + *TODO: We would like an error return, is this reasonable? (similar to old + python compare)* + +which uses generic sorting functionality. In general, we could add a +functions such as: + +* ``get_sort_function(self, NPY_SORTKIND sort_kind) -> {out_sortfunction, NotImplemented, NULL}``. + If the sortkind is not understood it may be allowed to return ``NotImplemented``. + +in the future. However, for example sorting is likely better solved by the +implementation of multiple generalized ufuncs which are called internally. + +**Limitations:** + +Using the above ``PyArrayDTypeMeta_Spec`` struct, the structure itself can +only be extended clumsily (e.g. by adding a version tag to the ``slots`` +to indicate a new, longer version of the struct). +We could also provide the struct using a function, which however will 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: + +* ``cast_kind`` 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 + ``adjust_descriptors`` must use it. +* ``adjust_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 be instances + of the same DType class as the ``CastingImpl`` is defined for. + The ``casting_out`` will be set to ``NPY_SAFE_CASTING``, ``NPY_UNSAFE_CASTING``, + or ``NPY_SAME_KIND_CASTING``. With a new, additional, flag ``NPY_CAST_IS_VIEW`` + which can be set to indicate that no cast is necessary, but a simple view + is sufficient to perform the cast. + The cast should return ``-1`` when a custom error message 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, dtypes[2]) -> int {0, nonzero}`` (must currently succeed) + +This is identical to the proposed API for ufuncs. By default the two dtypes +are passed in as the last argument. On error return (if no error is set) a +generic error will be given. +More optimized loops are in use internally, and will be made available to users +in the future (see notes) +The iterator API does not currently support casting errors: this is +a bug that needs to be fixed. Until it is fixed the loop should always +succeed (return 0). + +Although verbose, the API shall mimic the one for creating a new DType. +The ``PyArrayCastingImpl_Spec`` will include a field for ``dtypes`` and +identical to a ``PyArrayUFuncImpl_Spec``:: + + typedef struct{ + int needs_api; /* whether the cast requires the API */ + PyArray_DTypeMeta *in_dtype; /* input DType class */ + PyArray_DTypeMeta *out_dtype; /* output DType class */ + /* NULL terminated slots defining the methods */ + PyType_Slot *slots; + } PyArrayUFuncImpl_Spec; + +The actual creation function ``PyArrayCastingImpl_FromSpec()`` will additionally +require a ``casting`` parameter to define the default (maximum) casting safety. +The internal representation of ufuncs and casting implementations may differ +initially if it makes implementation simpler, but should be kept opaque to +allow future merging. + +**TODO:** It may be possible to make this more close to the ufuncs or even +use a single FromSpec. This API shall only be finalized after/when NEP 43 +is finalized. + +**Notes:** + +We may initially allow users to define only a single loop. +However, internally NumPy optimizes far more, and this should be made +public incrementally, by either allowing to provide multiple versions, such +as: + +* contiguous inner loop +* strided inner loop +* scalar inner loop + +or more likely through an additional ``get_inner_loop`` function which has +additional information, such as the fixed strides (similar to our internal API). + +The above example does not yet include the definition of setup/teardown +functionality, which may overlap with ``get_inner_loop``. +Since these are similar to the UFunc machinery, this should be defined in +detail in NEP 43 and then incorporated identically into casting. + +Also the ``needs_api`` decision may actually be moved into a setup function, +and removed or mainly provided as a convenience flag. + +The slots/methods used will be prefixed ``NPY_uf_`` for similarity to the ufunc +machinery. + + + +Alternatives +"""""""""""" + +Aside from name changes, and possible signature tweaks, there seem to +be few alternatives to the above structure. +Keeping the creation process close the Python limited API has some advantage. +Convenience functions could still be provided to allow creation with less +code. +The central point in the above design is that the enumerated slots design +is extensible and can be changed without breaking binary compatibility. +A downside is the possible need to pass in e.g. integer flags using a void +pointer inside this structure. + +A downside of this is that compilers cannot warn about function +pointer incompatibilities. There is currently no proposed solution to this. + + +Issues +^^^^^^ + +Any possible design decision will have issues. + +The above split into Python objects has the disadvantage that reference cycles +naturally occur. For example a potential ``CastingImpl`` object needs to +hold on to both ``DTypes``. Further, a scalar type may want to own a +strong reference to the corresponding ``DType`` while the ``DType`` *must* +hold a strong reference to the scalar. +We do not believe that these reference cycles are an issue. The may +require implementation of of cyclic reference counting at some point, but +cyclic reference resolution is very common in Python and dtypes (especially +classes) are only a small number of objects. + +In some cases, the new split will add additional indirections to the code, +since methods on the DType have to be looked up and called. +This should not have serious performance impact and seems necessary to +achieve the desired flexibility. + +From a user-perspective, a more serious downside is that handling certain +functionality in the ``DType`` rather than directly can mean that error +messages need to be raised from places where less context is available. +This may mean that error messages can be less specific. +This will be alleviated by exception chaining. Also decisions such as +returning the casting safety (even when it is impossible to cast) allow +most exceptions to be set at a point where more context is available +and ensures uniform errors messages. + + +Implementation +-------------- + +Internally a few implementation details have to be decided. These will be +fully opaque to the user and can be changed at a later time. + +This includes: + +* How ``CastingImpl`` lookup, and thus the decision whether a cast is possible, + is defined. (This is speed relevant, although mainly during a transition + phase where UFuncs where NEP 43 is not yet implemented). + Thus, it is not very relevant to the NEP. It is only necessary to ensure fast + lookup during the transition phase for the current builtin Numerical types. + +* How the mapping from a python scalar (e.g. ``3.``) to the DType is + implemented. + +The main steps for implementation are outlined in :ref:`NEP 41 <NEP41>`. +This includes the internal restructure for how casting and array-coercion +works. +After this the new public API will be added incrementally. +This includes replacements for certain slots which are occasionally +directly used on the dtype (e.g. ``dtype->f->setitem``). + + +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 NEP 40 and not repeated here for +brevity. + + +References +---------- + +.. [1] 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 of `numpy.result_type`. + + +Copyright +--------- + +This document has been placed in the public domain. diff --git a/doc/neps/nep-0045-c_style_guide.rst b/doc/neps/nep-0045-c_style_guide.rst index 3c21e404f..f579e4f69 100644 --- a/doc/neps/nep-0045-c_style_guide.rst +++ b/doc/neps/nep-0045-c_style_guide.rst @@ -1,3 +1,5 @@ +.. _NEP45: + ================================= NEP 45 — C Style Guide ================================= @@ -71,8 +73,8 @@ C dialect * No compiler warnings with major compilers (gcc, VC++, a few others). -.. Note:: - NumPy still produces compiler warnings that need to be addressed. +.. note:: + NumPy still produces compiler warnings that need to be addressed. Code layout ============ @@ -226,7 +228,8 @@ Naming conventions ``array_real_get``. Single leading underscores should not be used, but some current function names violate that rule due to historical accident. -.. Note:: +.. note:: + Functions whose names begin with a single underscore should be renamed at some point. @@ -244,7 +247,7 @@ C functions, see the files in ``doc/cdoc/``. Related Work ------------ -Based on Van Rossum and Warsaw, `PEP 7 -- Style Guide for C Code <https://www.python.org/dev/peps/pep-0007>`_ +Based on Van Rossum and Warsaw, :pep:`7` Discussion diff --git a/doc/neps/roadmap.rst b/doc/neps/roadmap.rst index 3780499a0..40fcbd325 100644 --- a/doc/neps/roadmap.rst +++ b/doc/neps/roadmap.rst @@ -6,6 +6,7 @@ This is a live snapshot of tasks and features we will be investing resources in. It may be used to encourage and inspire developers and to search for funding. + Interoperability ---------------- @@ -16,11 +17,21 @@ facilitate interoperability with all such packages, and the code that uses them, 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 :ref`NEP18` for details. -- New protocols for overriding other functionality in NumPy may be needed. -- Array duck typing, or handling "duck arrays", needs improvements. See - :ref:`NEP22` 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 ------------- @@ -42,56 +53,59 @@ improve the dtype system. - 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 :ref:`NEP19` and `PR 13163`_. -Indexing --------- +User experience +--------------- -We intend to add new indexing modes for "vectorized indexing" and "outer indexing", -see :ref:`NEP21`. +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: @@ -99,12 +113,17 @@ Other functionality - 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>`__. -.. _implementation: https://gist.github.com/shoyer/1f0a308a06cd96df20879a1ddb8f0006 -.. _`reference implementation`: https://github.com/bashtage/randomgen -.. _`PR 13163`: https://github.com/numpy/numpy/pull/13163 +.. _`mypy`: https://mypy.readthedocs.io +.. _`numpy-stubs`: https://github.com/numpy/numpy-stubs diff --git a/doc/release/upcoming_changes/16056.deprecation.rst b/doc/release/upcoming_changes/16056.deprecation.rst new file mode 100644 index 000000000..788b8c30a --- /dev/null +++ b/doc/release/upcoming_changes/16056.deprecation.rst @@ -0,0 +1,13 @@ +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" diff --git a/doc/release/upcoming_changes/16515.new_feature.rst b/doc/release/upcoming_changes/16515.new_feature.rst new file mode 100644 index 000000000..5b3803429 --- /dev/null +++ b/doc/release/upcoming_changes/16515.new_feature.rst @@ -0,0 +1,8 @@ +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 diff --git a/doc/release/upcoming_changes/16519.improvement.rst b/doc/release/upcoming_changes/16519.improvement.rst new file mode 100644 index 000000000..50c4305e5 --- /dev/null +++ b/doc/release/upcoming_changes/16519.improvement.rst @@ -0,0 +1,4 @@ +Thread-safe f2py callback functions +----------------------------------- + +Callback functions in f2py are now threadsafe. diff --git a/doc/release/upcoming_changes/16554.compatibility.rst b/doc/release/upcoming_changes/16554.compatibility.rst new file mode 100644 index 000000000..a9f3f07e0 --- /dev/null +++ b/doc/release/upcoming_changes/16554.compatibility.rst @@ -0,0 +1,10 @@ +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. diff --git a/doc/release/upcoming_changes/16554.deprecation.rst b/doc/release/upcoming_changes/16554.deprecation.rst new file mode 100644 index 000000000..5602d2d53 --- /dev/null +++ b/doc/release/upcoming_changes/16554.deprecation.rst @@ -0,0 +1,8 @@ +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. diff --git a/doc/release/upcoming_changes/16554.expired.rst b/doc/release/upcoming_changes/16554.expired.rst new file mode 100644 index 000000000..9b5718f8a --- /dev/null +++ b/doc/release/upcoming_changes/16554.expired.rst @@ -0,0 +1,5 @@ +* 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. diff --git a/doc/source/conf.py b/doc/source/conf.py index d6a0f8bf3..65dcae245 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -240,11 +240,12 @@ texinfo_documents = [ # 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), } diff --git a/doc/source/dev/gitwash/git_links.inc b/doc/source/dev/gitwash/git_links.inc index 82e6c75e5..8032dca41 100644 --- a/doc/source/dev/gitwash/git_links.inc +++ b/doc/source/dev/gitwash/git_links.inc @@ -16,7 +16,7 @@ .. _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.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 @@ -42,7 +42,7 @@ .. _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 +.. _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: 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 diff --git a/doc/source/dev/governance/governance.rst b/doc/source/dev/governance/governance.rst index d8719700f..9209f26b7 100644 --- a/doc/source/dev/governance/governance.rst +++ b/doc/source/dev/governance/governance.rst @@ -387,8 +387,7 @@ Acknowledgements ================ 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 ======= diff --git a/doc/source/dev/howto-docs.rst b/doc/source/dev/howto-docs.rst index 0e2e03e0b..17194bd58 100644 --- a/doc/source/dev/howto-docs.rst +++ b/doc/source/dev/howto-docs.rst @@ -4,146 +4,153 @@ 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. diff --git a/doc/source/dev/index.rst b/doc/source/dev/index.rst index 5270bfb77..aeb277a87 100644 --- a/doc/source/dev/index.rst +++ b/doc/source/dev/index.rst @@ -140,8 +140,7 @@ Here's the short summary, complete TOC links are below: 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 @@ -189,7 +188,7 @@ 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 @@ -256,7 +255,7 @@ From the ``doc/`` directory: 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. @@ -291,4 +290,4 @@ The rest of the story 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 diff --git a/doc/source/reference/arrays.classes.rst b/doc/source/reference/arrays.classes.rst index 6c8793342..c5563bddd 100644 --- a/doc/source/reference/arrays.classes.rst +++ b/doc/source/reference/arrays.classes.rst @@ -173,7 +173,7 @@ NumPy provides several hooks that classes can customize: - ``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 diff --git a/doc/source/reference/global_state.rst b/doc/source/reference/global_state.rst index 2a163390e..7bf9310e8 100644 --- a/doc/source/reference/global_state.rst +++ b/doc/source/reference/global_state.rst @@ -81,5 +81,5 @@ This setting should always be enabled. Setting the 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. diff --git a/doc/source/reference/random/new-or-different.rst b/doc/source/reference/random/new-or-different.rst index 03e7775a0..6cab0f729 100644 --- a/doc/source/reference/random/new-or-different.rst +++ b/doc/source/reference/random/new-or-different.rst @@ -15,7 +15,7 @@ What's New or Different 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 @@ -52,7 +52,7 @@ And in more detail: 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 diff --git a/doc/source/reference/ufuncs.rst b/doc/source/reference/ufuncs.rst index 6d58d1a6d..8f506dd8b 100644 --- a/doc/source/reference/ufuncs.rst +++ b/doc/source/reference/ufuncs.rst @@ -109,7 +109,7 @@ The output of the ufunc (and its methods) is not necessarily an :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 diff --git a/doc/source/release/1.19.0-notes.rst b/doc/source/release/1.19.0-notes.rst index ea0ac6193..b40969550 100644 --- a/doc/source/release/1.19.0-notes.rst +++ b/doc/source/release/1.19.0-notes.rst @@ -24,14 +24,14 @@ Calling ``np.array([[1, [1, 2, 3]])`` will issue a ``DeprecationWarning`` as per `NEP 34`_. Users should explicitly use ``dtype=object`` to avoid the warning. -.. _`NEP 34`: https://numpy.org/neps/nep-0034.html +.. _`NEP 34`: https://numpy.org/neps/nep-0034-infer-dtype-is-object.html (`gh-15119 <https://github.com/numpy/numpy/pull/15119>`__) Passing ``shape=0`` to factory functions in ``numpy.rec`` is deprecated ----------------------------------------------------------------------- -``0`` is treated as a special case and is aliased to ``None`` in the functions: +``0`` is treated as a special case and is aliased to ``None`` in the functions: * `numpy.core.records.fromarrays` * `numpy.core.records.fromrecords` @@ -267,6 +267,19 @@ of users. (`gh-16068 <https://github.com/numpy/numpy/pull/16068>`__) +``SeedSequence`` with small seeds no longer conflicts with spawning +------------------------------------------------------------------- +Small seeds (less than ``2**96``) are implicitly 0-padded out to 128 bits, the +size of the internal entropy pool. When spawned, the spawn key was concatenated +before the 0-padding. Since the first spawn key is ``(0,)``, small seeds +before the spawn created the same states as the first spawned ``SeedSequence``. +Now, the seed is explicitly 0-padded out to the internal pool size before +concatenating the spawn key. Spawned ``SeedSequences`` will produce different +results than in the previous release. Unspawned ``SeedSequences`` will still +produce the same results. + +(`gh-16551 <https://github.com/numpy/numpy/pull/16551>`__) + C API changes ============= @@ -284,12 +297,12 @@ functions. (`gh-15251 <https://github.com/numpy/numpy/pull/15251>`__) -Const qualify UFunc inner loops
--------------------------------
-``UFuncGenericFunction`` now expects pointers to const ``dimension`` and
-``strides`` as arguments. This means inner loops may no longer modify
-either ``dimension`` or ``strides``. This change leads to an
-``incompatible-pointer-types`` warning forcing users to either ignore
+Const qualify UFunc inner loops +------------------------------- +``UFuncGenericFunction`` now expects pointers to const ``dimension`` and +``strides`` as arguments. This means inner loops may no longer modify +either ``dimension`` or ``strides``. This change leads to an +``incompatible-pointer-types`` warning forcing users to either ignore the compiler warnings or to const qualify their own loop signatures. (`gh-15355 <https://github.com/numpy/numpy/pull/15355>`__) @@ -316,12 +329,12 @@ now expose this through the buffer interface, meaning ``subok`` option for `numpy.copy` --------------------------------- -A new kwarg, ``subok``, was added to `numpy.copy` to allow users to toggle the +A new kwarg, ``subok``, was added to `numpy.copy` to allow users to toggle the behavior of `numpy.copy` with respect to array subclasses. The default value -is ``False`` which is consistent with the behavior of `numpy.copy` for +is ``False`` which is consistent with the behavior of `numpy.copy` for previous numpy versions. To create a copy that preserves an array subclass with `numpy.copy`, call ``np.copy(arr, subok=True)``. This addition better documents -that the default behavior of `numpy.copy` differs from the +that the default behavior of `numpy.copy` differs from the `numpy.ndarray.copy` method which respects array subclasses by default. (`gh-15685 <https://github.com/numpy/numpy/pull/15685>`__) @@ -345,8 +358,8 @@ as `numpy.sum` or `numpy.mean`. ``equal_nan`` parameter for `numpy.array_equal` ------------------------------------------------ The keyword argument ``equal_nan`` was added to `numpy.array_equal`. -``equal_nan`` is a boolean value that toggles whether or not ``nan`` values -are considered equal in comparison (default is ``False``). This matches API +``equal_nan`` is a boolean value that toggles whether or not ``nan`` values +are considered equal in comparison (default is ``False``). This matches API used in related functions such as `numpy.isclose` and `numpy.allclose`. (`gh-16128 <https://github.com/numpy/numpy/pull/16128>`__) @@ -376,9 +389,9 @@ linear algebra for large arrays. Use AVX512 intrinsic to implement ``np.exp`` when input is ``np.float64`` -------------------------------------------------------------------------- -Use AVX512 intrinsic to implement ``np.exp`` when input is ``np.float64``, +Use AVX512 intrinsic to implement ``np.exp`` when input is ``np.float64``, which can improve the performance of ``np.exp`` with ``np.float64`` input 5-7x -faster than before. The _multiarray_umath.so module has grown about 63 KB on +faster than before. The _multiarray_umath.so module has grown about 63 KB on linux64. (`gh-15648 <https://github.com/numpy/numpy/pull/15648>`__) diff --git a/doc/source/release/1.5.0-notes.rst b/doc/source/release/1.5.0-notes.rst index a2184ab13..2b0c32f3e 100644 --- a/doc/source/release/1.5.0-notes.rst +++ b/doc/source/release/1.5.0-notes.rst @@ -12,11 +12,11 @@ Python 3 compatibility 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. diff --git a/doc/source/user/absolute_beginners.rst b/doc/source/user/absolute_beginners.rst index bd44b70da..5873eb108 100644 --- a/doc/source/user/absolute_beginners.rst +++ b/doc/source/user/absolute_beginners.rst @@ -1531,19 +1531,19 @@ Importing and exporting a CSV ----------------------------- .. 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 diff --git a/doc/source/user/building.rst b/doc/source/user/building.rst index 47a0a03c9..6a880b59e 100644 --- a/doc/source/user/building.rst +++ b/doc/source/user/building.rst @@ -6,6 +6,10 @@ Building from source 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 ------------- @@ -159,6 +163,14 @@ will prefer to use ATLAS, then OpenBLAS and as a last resort MKL. If neither of these exists the build will fail (names are compared lower case). +.. 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/user/quickstart.rst b/doc/source/user/quickstart.rst index 29a4d80ca..b1af81886 100644 --- a/doc/source/user/quickstart.rst +++ b/doc/source/user/quickstart.rst @@ -22,7 +22,7 @@ https://scipy.org/install.html for instructions. **Learner profile** -This tutorial is intended as a quick overview of +This tutorial is intended as a quick overview of algebra and arrays in NumPy and want to understand 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 @@ -1036,6 +1036,8 @@ Basic Linear Algebra Less Basic ========== +.. _broadcasting-rules: + Broadcasting rules ------------------ @@ -1054,7 +1056,7 @@ element is assumed to be the same along that dimension for the "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 ================================== @@ -1390,8 +1392,8 @@ and then use it as:: [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. diff --git a/numpy/__init__.py b/numpy/__init__.py index e6a24f0d1..1c3b11844 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -279,12 +279,11 @@ else: 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 diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi new file mode 100644 index 000000000..f9218391e --- /dev/null +++ b/numpy/__init__.pyi @@ -0,0 +1,1062 @@ +import builtins +import sys +import datetime as dt +from abc import abstractmethod + +from numpy.core._internal import _ctypes +from numpy.typing import ArrayLike, DtypeLike, _Shape, _ShapeLike + +from typing import ( + Any, + ByteString, + Callable, + Container, + Callable, + Dict, + Generic, + IO, + Iterable, + List, + Mapping, + Optional, + overload, + Sequence, + Sized, + SupportsAbs, + SupportsComplex, + SupportsFloat, + SupportsInt, + Text, + Tuple, + Type, + TypeVar, + Union, +) + +if sys.version_info[0] < 3: + class SupportsBytes: ... + +else: + from typing import SupportsBytes + +if sys.version_info >= (3, 8): + from typing import Literal, Protocol +else: + from typing_extensions import Literal, Protocol + +# TODO: remove when the full numpy namespace is defined +def __getattr__(name: str) -> Any: ... + +_NdArraySubClass = TypeVar("_NdArraySubClass", bound=ndarray) + +class dtype: + names: Optional[Tuple[str, ...]] + def __init__( + self, + dtype: DtypeLike, + align: bool = ..., + copy: bool = ..., + ) -> None: ... + 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: str = ...) -> 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: ... + +_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: ... + +_ArraySelf = TypeVar("_ArraySelf", bound=_ArrayOrScalarCommon) + +class _ArrayOrScalarCommon( + SupportsInt, SupportsFloat, SupportsComplex, SupportsBytes, SupportsAbs[Any] +): + @property + def T(self: _ArraySelf) -> _ArraySelf: ... + @property + def base(self) -> Optional[ndarray]: ... + @property + def dtype(self) -> _Dtype: ... + @property + def data(self) -> memoryview: ... + @property + def flags(self) -> _flagsobj: ... + @property + def size(self) -> int: ... + @property + def itemsize(self) -> int: ... + @property + def nbytes(self) -> int: ... + @property + def ndim(self) -> int: ... + @property + def shape(self) -> _Shape: ... + @property + def strides(self) -> _Shape: ... + def __array__(self, __dtype: DtypeLike = ...) -> ndarray: ... + def __int__(self) -> int: ... + def __float__(self) -> float: ... + def __complex__(self) -> complex: ... + if sys.version_info[0] < 3: + def __oct__(self) -> str: ... + def __hex__(self) -> str: ... + def __nonzero__(self) -> bool: ... + def __unicode__(self) -> Text: ... + else: + def __bool__(self) -> bool: ... + def __bytes__(self) -> bytes: ... + def __str__(self) -> str: ... + def __repr__(self) -> str: ... + def __copy__(self: _ArraySelf, order: str = ...) -> _ArraySelf: ... + def __deepcopy__(self: _ArraySelf, memo: 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 __add__(self, other): ... + def __radd__(self, other): ... + def __iadd__(self, other): ... + def __sub__(self, other): ... + def __rsub__(self, other): ... + def __isub__(self, other): ... + def __mul__(self, other): ... + def __rmul__(self, other): ... + def __imul__(self, other): ... + if sys.version_info[0] < 3: + def __div__(self, other): ... + def __rdiv__(self, other): ... + def __idiv__(self, other): ... + def __truediv__(self, other): ... + def __rtruediv__(self, other): ... + def __itruediv__(self, other): ... + def __floordiv__(self, other): ... + def __rfloordiv__(self, other): ... + def __ifloordiv__(self, other): ... + def __mod__(self, other): ... + def __rmod__(self, other): ... + def __imod__(self, other): ... + def __divmod__(self, other): ... + def __rdivmod__(self, other): ... + # NumPy's __pow__ doesn't handle a third argument + def __pow__(self, other): ... + def __rpow__(self, other): ... + def __ipow__(self, other): ... + def __lshift__(self, other): ... + def __rlshift__(self, other): ... + def __ilshift__(self, other): ... + def __rshift__(self, other): ... + def __rrshift__(self, other): ... + def __irshift__(self, other): ... + def __and__(self, other): ... + def __rand__(self, other): ... + def __iand__(self, other): ... + def __xor__(self, other): ... + def __rxor__(self, other): ... + def __ixor__(self, other): ... + def __or__(self, other): ... + def __ror__(self, other): ... + def __ior__(self, other): ... + if sys.version_info[:2] >= (3, 5): + def __matmul__(self, other): ... + def __rmatmul__(self, other): ... + def __neg__(self: _ArraySelf) -> _ArraySelf: ... + def __pos__(self: _ArraySelf) -> _ArraySelf: ... + def __abs__(self: _ArraySelf) -> _ArraySelf: ... + def __invert__(self: _ArraySelf) -> _ArraySelf: ... + # TODO(shoyer): remove when all methods are defined + def __getattr__(self, name) -> Any: ... + +_BufferType = Union[ndarray, bytes, bytearray, memoryview] + +class ndarray(_ArrayOrScalarCommon, Iterable, Sized, Container): + @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: Optional[str] = ..., + ) -> _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 flat(self: _ArraySelf) -> flatiter[_ArraySelf]: ... + @property + def strides(self) -> _Shape: ... + @strides.setter + def strides(self, value: _ShapeLike): ... + # Array conversion + @overload + def item(self, *args: int) -> Any: ... + @overload + def item(self, args: Tuple[int, ...]) -> Any: ... + def tolist(self) -> List[Any]: ... + @overload + def itemset(self, __value: Any) -> None: ... + @overload + def itemset(self, __item: _ShapeLike, __value: Any) -> None: ... + def tobytes(self, order: Optional[str] = ...) -> bytes: ... + def tofile( + self, fid: Union[IO[bytes], str], sep: str = ..., format: str = ... + ) -> None: ... + def dump(self, file: str) -> None: ... + def dumps(self) -> bytes: ... + def astype( + self: _ArraySelf, + dtype: DtypeLike, + order: str = ..., + casting: str = ..., + subok: bool = ..., + copy: bool = ..., + ) -> _ArraySelf: ... + def byteswap(self: _ArraySelf, inplace: bool = ...) -> _ArraySelf: ... + def copy(self: _ArraySelf, order: str = ...) -> _ArraySelf: ... + @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: ... + def getfield( + self: _ArraySelf, dtype: DtypeLike, offset: int = ... + ) -> _ArraySelf: ... + def setflags( + self, write: bool = ..., align: bool = ..., uic: bool = ... + ) -> None: ... + def fill(self, value: Any) -> None: ... + # Shape manipulation + @overload + def reshape( + self: _ArraySelf, shape: Sequence[int], *, order: str = ... + ) -> _ArraySelf: ... + @overload + def reshape(self: _ArraySelf, *shape: int, order: str = ...) -> _ArraySelf: ... + @overload + def resize(self, new_shape: Sequence[int], *, refcheck: bool = ...) -> None: ... + @overload + def resize(self, *new_shape: int, refcheck: bool = ...) -> None: ... + @overload + def transpose(self: _ArraySelf, axes: Sequence[int]) -> _ArraySelf: ... + @overload + def transpose(self: _ArraySelf, *axes: int) -> _ArraySelf: ... + def swapaxes(self: _ArraySelf, axis1: int, axis2: int) -> _ArraySelf: ... + def flatten(self: _ArraySelf, order: str = ...) -> _ArraySelf: ... + def ravel(self: _ArraySelf, order: str = ...) -> _ArraySelf: ... + def squeeze( + self: _ArraySelf, axis: Union[int, Tuple[int, ...]] = ... + ) -> _ArraySelf: ... + # 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 __len__(self) -> int: ... + def __getitem__(self, key) -> Any: ... + def __setitem__(self, key, value): ... + def __iter__(self) -> Any: ... + def __contains__(self, key) -> bool: ... + def __index__(self) -> int: ... + +# 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. + +class generic(_ArrayOrScalarCommon): + @abstractmethod + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + @property + def base(self) -> None: ... + +class _real_generic(generic): # type: ignore + @property + def real(self: _ArraySelf) -> _ArraySelf: ... + @property + def imag(self: _ArraySelf) -> _ArraySelf: ... + +class number(generic): ... # type: ignore + +class bool_(_real_generic): + def __init__(self, __value: object = ...) -> None: ... + +class object_(generic): + def __init__(self, __value: object = ...) -> None: ... + +class datetime64: + @overload + def __init__( + self, __value: Union[datetime64, str, dt.datetime] = ..., __format: str = ... + ) -> None: ... + @overload + def __init__(self, __value: int, __format: str) -> None: ... + def __add__(self, other: Union[timedelta64, int]) -> datetime64: ... + def __sub__(self, other: Union[timedelta64, datetime64, int]) -> timedelta64: ... + +class integer(number, _real_generic): ... # type: ignore +class signedinteger(integer): ... # type: ignore + +class int8(signedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class int16(signedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class int32(signedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class int64(signedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class timedelta64(signedinteger): + def __init__(self, __value: Any = ..., __format: str = ...) -> None: ... + @overload + def __add__(self, other: Union[timedelta64, int]) -> timedelta64: ... + @overload + def __add__(self, other: datetime64) -> datetime64: ... + def __sub__(self, other: Union[timedelta64, int]) -> timedelta64: ... + if sys.version_info[0] < 3: + @overload + def __div__(self, other: timedelta64) -> float: ... + @overload + def __div__(self, other: float) -> timedelta64: ... + @overload + def __truediv__(self, other: timedelta64) -> float: ... + @overload + def __truediv__(self, other: float) -> timedelta64: ... + def __mod__(self, other: timedelta64) -> timedelta64: ... + +class unsignedinteger(integer): ... # type: ignore + +class uint8(unsignedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class uint16(unsignedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class uint32(unsignedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class uint64(unsignedinteger): + def __init__(self, __value: SupportsInt = ...) -> None: ... + +class inexact(number): ... # type: ignore +class floating(inexact, _real_generic): ... # type: ignore + +class float16(floating): + def __init__(self, __value: SupportsFloat = ...) -> None: ... + +class float32(floating): + def __init__(self, __value: SupportsFloat = ...) -> None: ... + +class float64(floating): + def __init__(self, __value: SupportsFloat = ...) -> None: ... + +class complexfloating(inexact): ... # type: ignore + +class complex64(complexfloating): + def __init__( + self, __value: Union[SupportsInt, SupportsFloat, SupportsComplex] = ... + ) -> None: ... + @property + def real(self) -> float32: ... + @property + def imag(self) -> float32: ... + +class complex128(complexfloating): + def __init__( + self, __value: Union[SupportsInt, SupportsFloat, SupportsComplex] = ... + ) -> None: ... + @property + def real(self) -> float64: ... + @property + def imag(self) -> float64: ... + +class flexible(_real_generic): ... # type: ignore + +class void(flexible): + def __init__(self, __value: Union[int, integer, bool_, bytes, bytes_]): ... + +class character(_real_generic): ... # type: ignore + +class bytes_(character): + @overload + def __init__(self, __value: object = ...) -> None: ... + @overload + def __init__( + self, __value: Union[str, str_], encoding: str = ..., errors: str = ... + ) -> None: ... + +class str_(character): + @overload + def __init__(self, __value: object = ...) -> None: ... + @overload + def __init__( + self, __value: Union[bytes, bytes_], encoding: str = ..., errors: str = ... + ) -> None: ... + +# 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 = ..., + subok: bool = ..., + ndmin: int = ..., +) -> ndarray: ... +def zeros( + shape: _ShapeLike, dtype: DtypeLike = ..., order: Optional[str] = ... +) -> ndarray: ... +def ones( + shape: _ShapeLike, dtype: DtypeLike = ..., order: Optional[str] = ... +) -> ndarray: ... +def empty( + shape: _ShapeLike, dtype: DtypeLike = ..., order: Optional[str] = ... +) -> ndarray: ... +def zeros_like( + a: ArrayLike, + dtype: DtypeLike = ..., + order: str = ..., + subok: bool = ..., + shape: Optional[Union[int, Sequence[int]]] = ..., +) -> ndarray: ... +def ones_like( + a: ArrayLike, + dtype: DtypeLike = ..., + order: str = ..., + subok: bool = ..., + shape: Optional[_ShapeLike] = ..., +) -> ndarray: ... +def empty_like( + a: ArrayLike, + dtype: DtypeLike = ..., + order: str = ..., + subok: bool = ..., + shape: Optional[_ShapeLike] = ..., +) -> ndarray: ... +def full( + shape: _ShapeLike, fill_value: Any, dtype: DtypeLike = ..., order: str = ... +) -> ndarray: ... +def full_like( + a: ArrayLike, + fill_value: Any, + dtype: DtypeLike = ..., + order: str = ..., + subok: bool = ..., + shape: Optional[_ShapeLike] = ..., +) -> ndarray: ... +def count_nonzero( + a: ArrayLike, axis: Optional[Union[int, Tuple[int], Tuple[int, int]]] = ... +) -> Union[int, ndarray]: ... +def isfortran(a: ndarray) -> bool: ... +def argwhere(a: ArrayLike) -> ndarray: ... +def flatnonzero(a: ArrayLike) -> ndarray: ... +def correlate(a: ArrayLike, v: ArrayLike, mode: str = ...) -> ndarray: ... +def convolve(a: ArrayLike, v: ArrayLike, mode: str = ...) -> ndarray: ... +def outer(a: ArrayLike, b: ArrayLike, out: ndarray = ...) -> ndarray: ... +def tensordot( + a: ArrayLike, + b: ArrayLike, + axes: Union[ + int, Tuple[int, int], Tuple[Tuple[int, int], ...], Tuple[List[int, int], ...] + ] = ..., +) -> ndarray: ... +def roll( + a: ArrayLike, + shift: Union[int, Tuple[int, ...]], + axis: Optional[Union[int, Tuple[int, ...]]] = ..., +) -> ndarray: ... +def rollaxis(a: ArrayLike, axis: int, start: int = ...) -> ndarray: ... +def moveaxis( + a: ndarray, + source: Union[int, Sequence[int]], + destination: Union[int, Sequence[int]], +) -> ndarray: ... +def cross( + a: ArrayLike, + b: ArrayLike, + axisa: int = ..., + axisb: int = ..., + axisc: int = ..., + axis: Optional[int] = ..., +) -> ndarray: ... +def indices( + dimensions: Sequence[int], dtype: dtype = ..., sparse: bool = ... +) -> Union[ndarray, Tuple[ndarray, ...]]: ... +def fromfunction(function: Callable, shape: Tuple[int, int], **kwargs) -> Any: ... +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 = ...) -> 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: ... + +# +# Constants +# + +Inf: float +Infinity: float +NAN: float +NINF: float +NZERO: float +NaN: float +PINF: float +PZERO: float +e: float +euler_gamma: float +inf: float +infty: float +nan: float +pi: float + +ALLOW_THREADS: int +BUFSIZE: int +CLIP: int +ERR_CALL: int +ERR_DEFAULT: int +ERR_IGNORE: int +ERR_LOG: int +ERR_PRINT: int +ERR_RAISE: int +ERR_WARN: int +FLOATING_POINT_SUPPORT: int +FPE_DIVIDEBYZERO: int +FPE_INVALID: int +FPE_OVERFLOW: int +FPE_UNDERFLOW: int +MAXDIMS: int +MAY_SHARE_BOUNDS: int +MAY_SHARE_EXACT: int +RAISE: int +SHIFT_DIVIDEBYZERO: int +SHIFT_INVALID: int +SHIFT_OVERFLOW: int +SHIFT_UNDERFLOW: int +UFUNC_BUFSIZE_DEFAULT: int +WRAP: int +little_endian: int +tracemalloc_domain: int + +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 = ..., + # TODO: make this precise when we can use Literal. + casting: str = ..., + # TODO: make this precise when we can use Literal. + order: Optional[str] = ..., + 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]] = ..., + ) -> Union[ndarray, generic]: ... + @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 + +# 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: ... + +# Functions from np.core.numerictypes +_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: ... + +# Functions from np.core.fromnumeric +_Mode = Literal["raise", "wrap", "clip"] +_Order = Literal["C", "F", "A"] +_PartitionKind = Literal["introselect"] +_SortKind = Literal["quicksort", "mergesort", "heapsort", "stable"] +_Side = Literal["left", "right"] + +# 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] +) + +# An array-like object consisting of integers +_Int = Union[int, integer] +_Bool = Union[bool, bool_] +_IntOrBool = Union[_Int, _Bool] +_ArrayLikeIntNested = ArrayLike # TODO: wait for support for recursive types +_ArrayLikeBoolNested = ArrayLike # TODO: wait for support for recursive types + +# Integers and booleans can generally be used interchangeably +_ArrayLikeIntOrBool = Union[ + _IntOrBool, + ndarray, + Sequence[_IntOrBool], + Sequence[_ArrayLikeIntNested], + Sequence[_ArrayLikeBoolNested], +] + +# 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: _Mode = ..., +) -> _ScalarGenericDT: ... +@overload +def take( + a: _Scalar, + indices: int, + axis: Optional[int] = ..., + out: Optional[ndarray] = ..., + mode: _Mode = ..., +) -> _ScalarNumpy: ... +@overload +def take( + a: ArrayLike, + indices: int, + axis: Optional[int] = ..., + out: Optional[ndarray] = ..., + mode: _Mode = ..., +) -> _ScalarNumpy: ... +@overload +def take( + a: ArrayLike, + indices: _ArrayLikeIntOrBool, + axis: Optional[int] = ..., + out: Optional[ndarray] = ..., + mode: _Mode = ..., +) -> Union[_ScalarNumpy, ndarray]: ... +def reshape(a: ArrayLike, newshape: _ShapeLike, order: _Order = ...) -> ndarray: ... +@overload +def choose( + a: _ScalarIntOrBool, + choices: ArrayLike, + out: Optional[ndarray] = ..., + mode: _Mode = ..., +) -> _ScalarIntOrBool: ... +@overload +def choose( + a: _IntOrBool, choices: ArrayLike, out: Optional[ndarray] = ..., mode: _Mode = ... +) -> Union[integer, bool_]: ... +@overload +def choose( + a: _ArrayLikeIntOrBool, + choices: ArrayLike, + out: Optional[ndarray] = ..., + mode: _Mode = ..., +) -> ndarray: ... +def repeat( + a: ArrayLike, repeats: _ArrayLikeIntOrBool, axis: Optional[int] = ... +) -> ndarray: ... +def put( + a: ndarray, ind: _ArrayLikeIntOrBool, v: ArrayLike, mode: _Mode = ... +) -> 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: _Side = ..., + sorter: Optional[_ArrayLikeIntOrBool] = ..., # 1D int array +) -> integer: ... +@overload +def searchsorted( + a: ArrayLike, + v: ArrayLike, + side: _Side = ..., + 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: _Order = ...) -> 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: ... diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 20ad39b05..d0ed3d381 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -1525,7 +1525,7 @@ add_newdoc('numpy.core.multiarray', 'c_einsum', 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 @@ -3243,15 +3243,13 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('newbyteorder', 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 @@ -3938,18 +3936,17 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('tobytes', """ 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 ------- @@ -5144,7 +5141,7 @@ add_newdoc('numpy.core', 'ufunc', ('at', add_newdoc('numpy.core.multiarray', 'dtype', """ - dtype(obj, align=False, copy=False) + dtype(dtype, align=False, copy=False) Create a data type object. @@ -5154,7 +5151,7 @@ add_newdoc('numpy.core.multiarray', 'dtype', 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 @@ -5666,15 +5663,11 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('newbyteorder', 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 @@ -6041,9 +6034,9 @@ add_newdoc('numpy.core.numerictypes', 'generic', ('newbyteorder', 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 @@ -6051,9 +6044,7 @@ add_newdoc('numpy.core.numerictypes', 'generic', ('newbyteorder', 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 diff --git a/numpy/core/_dtype.py b/numpy/core/_dtype.py index 76d0b8149..50aeeb5bc 100644 --- a/numpy/core/_dtype.py +++ b/numpy/core/_dtype.py @@ -160,13 +160,13 @@ def _scalar_str(dtype, short): 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 == '|': diff --git a/numpy/core/_internal.pyi b/numpy/core/_internal.pyi new file mode 100644 index 000000000..1b3889e51 --- /dev/null +++ b/numpy/core/_internal.pyi @@ -0,0 +1,18 @@ +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: ... diff --git a/numpy/core/_type_aliases.py b/numpy/core/_type_aliases.py index c26431443..de90fd818 100644 --- a/numpy/core/_type_aliases.py +++ b/numpy/core/_type_aliases.py @@ -11,40 +11,19 @@ and sometimes other mappings too. .. 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 @@ -127,27 +106,24 @@ def _add_aliases(): 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(): @@ -157,20 +133,15 @@ 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) diff --git a/numpy/core/einsumfunc.py b/numpy/core/einsumfunc.py index c46ae173d..f65f4015c 100644 --- a/numpy/core/einsumfunc.py +++ b/numpy/core/einsumfunc.py @@ -1358,11 +1358,18 @@ def einsum(*operands, out=None, optimize=False, **kwargs): 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 @@ -1412,4 +1419,4 @@ def einsum(*operands, out=None, optimize=False, **kwargs): if specified_out: return out else: - return operands[0] + return asanyarray(operands[0], order=output_order) diff --git a/numpy/core/function_base.py b/numpy/core/function_base.py index 9e46f0ea5..f57e95742 100644 --- a/numpy/core/function_base.py +++ b/numpy/core/function_base.py @@ -52,8 +52,10 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, 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 @@ -202,8 +204,10 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, ``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 @@ -297,8 +301,10 @@ def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): 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 @@ -408,8 +414,18 @@ def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): 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) diff --git a/numpy/core/include/numpy/npy_3kcompat.h b/numpy/core/include/numpy/npy_3kcompat.h index 798da6957..7e6b01924 100644 --- a/numpy/core/include/numpy/npy_3kcompat.h +++ b/numpy/core/include/numpy/npy_3kcompat.h @@ -62,9 +62,9 @@ static NPY_INLINE int PyInt_Check(PyObject *op) { #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) #endif diff --git a/numpy/core/numerictypes.py b/numpy/core/numerictypes.py index aac741612..2a015f48f 100644 --- a/numpy/core/numerictypes.py +++ b/numpy/core/numerictypes.py @@ -91,7 +91,7 @@ from numpy.core.multiarray import ( 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', @@ -106,7 +106,6 @@ from ._string_helpers import ( from ._type_aliases import ( sctypeDict, - sctypeNA, allTypes, bitname, sctypes, @@ -512,7 +511,6 @@ typecodes = {'Character':'c', # backwards compatibility --- deprecated name typeDict = sctypeDict -typeNA = sctypeNA # b -> boolean # u -> unsigned integer diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 16bac4272..5351b30bf 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -967,6 +967,7 @@ def configuration(parent_package='',top_path=None): 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() diff --git a/numpy/core/src/common/npy_cpu_features.c.src b/numpy/core/src/common/npy_cpu_features.c.src index bd4743905..d35199760 100644 --- a/numpy/core/src/common/npy_cpu_features.c.src +++ b/numpy/core/src/common/npy_cpu_features.c.src @@ -283,28 +283,7 @@ npy__cpu_init_features_arm8(void) * 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 @@ -339,10 +318,12 @@ npy__cpu_init_features_linux(void) } 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) @@ -367,9 +348,10 @@ npy__cpu_init_features_linux(void) npy__cpu_init_features_arm8(); } else { npy__cpu_have[NPY_CPU_FEATURE_NEON] = (hwcap & NPY__HWCAP_NEON) != 0; - npy__cpu_have[NPY_CPU_FEATURE_NEON_FP16] = (hwcap & (NPY__HWCAP_NEON | NPY__HWCAP_VFPv3 | - NPY__HWCAP_HALF)) != 0; - npy__cpu_have[NPY_CPU_FEATURE_NEON_VFPV4] = (hwcap & (NPY__HWCAP_NEON | NPY__HWCAP_VFPv4)) != 0; + if (npy__cpu_have[NPY_CPU_FEATURE_NEON]) { + npy__cpu_have[NPY_CPU_FEATURE_NEON_FP16] = (hwcap & NPY__HWCAP_HALF) != 0; + npy__cpu_have[NPY_CPU_FEATURE_NEON_VFPV4] = (hwcap & NPY__HWCAP_VFPv4) != 0; + } } return 1; } diff --git a/numpy/core/src/common/npy_cpuinfo_parser.h b/numpy/core/src/common/npy_cpuinfo_parser.h new file mode 100644 index 000000000..4c00c847b --- /dev/null +++ b/numpy/core/src/common/npy_cpuinfo_parser.h @@ -0,0 +1,262 @@ +/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * 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.
+ *
+ * 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.
+ */
+#ifndef __NPY_CPUINFO_PARSER_H__
+#define __NPY_CPUINFO_PARSER_H__
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stddef.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)
+/*
+ * Get the size of a file by reading it until the end. This is needed
+ * because files under /proc do not always return a valid size when
+ * using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed.
+ */
+static int
+get_file_size(const char* pathname)
+{
+ int fd, result = 0;
+ char buffer[256];
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ for (;;) {
+ int ret = read(fd, buffer, sizeof buffer);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ break;
+ }
+ if (ret == 0) {
+ break;
+ }
+ result += ret;
+ }
+ close(fd);
+ return result;
+}
+
+/*
+ * Read the content of /proc/cpuinfo into a user-provided buffer.
+ * Return the length of the data, or -1 on error. Does *not*
+ * zero-terminate the content. Will not read more
+ * than 'buffsize' bytes.
+ */
+static int
+read_file(const char* pathname, char* buffer, size_t buffsize)
+{
+ int fd, count;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+ count = 0;
+ while (count < (int)buffsize) {
+ int ret = read(fd, buffer + count, buffsize - count);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (count == 0) {
+ count = -1;
+ }
+ break;
+ }
+ if (ret == 0) {
+ break;
+ }
+ count += ret;
+ }
+ close(fd);
+ return count;
+}
+
+/*
+ * Extract the content of a the first occurence of a given field in
+ * the content of /proc/cpuinfo and return it as a heap-allocated
+ * string that must be freed by the caller.
+ *
+ * Return NULL if not found
+ */
+static char*
+extract_cpuinfo_field(const char* buffer, int buflen, const char* field)
+{
+ int fieldlen = strlen(field);
+ const char* bufend = buffer + buflen;
+ char* result = NULL;
+ int len;
+ const char *p, *q;
+
+ /* Look for first field occurence, and ensures it starts the line. */
+ p = buffer;
+ for (;;) {
+ p = memmem(p, bufend-p, field, fieldlen);
+ if (p == NULL) {
+ goto EXIT;
+ }
+
+ if (p == buffer || p[-1] == '\n') {
+ break;
+ }
+
+ p += fieldlen;
+ }
+
+ /* Skip to the first column followed by a space */
+ p += fieldlen;
+ p = memchr(p, ':', bufend-p);
+ if (p == NULL || p[1] != ' ') {
+ goto EXIT;
+ }
+
+ /* Find the end of the line */
+ p += 2;
+ q = memchr(p, '\n', bufend-p);
+ if (q == NULL) {
+ q = bufend;
+ }
+
+ /* Copy the line into a heap-allocated buffer */
+ len = q - p;
+ result = malloc(len + 1);
+ if (result == NULL) {
+ goto EXIT;
+ }
+
+ memcpy(result, p, len);
+ result[len] = '\0';
+
+EXIT:
+ return result;
+}
+
+/*
+ * Checks that a space-separated list of items contains one given 'item'.
+ * Returns 1 if found, 0 otherwise.
+ */
+static int
+has_list_item(const char* list, const char* item)
+{
+ const char* p = list;
+ int itemlen = strlen(item);
+
+ if (list == NULL) {
+ return 0;
+ }
+
+ while (*p) {
+ const char* q;
+
+ /* skip spaces */
+ while (*p == ' ' || *p == '\t') {
+ p++;
+ }
+
+ /* find end of current list item */
+ q = p;
+ while (*q && *q != ' ' && *q != '\t') {
+ q++;
+ }
+
+ if (itemlen == q-p && !memcmp(p, item, itemlen)) {
+ return 1;
+ }
+
+ /* skip to next item */
+ p = q;
+ }
+ return 0;
+}
+
+static void setHwcap(char* cpuFeatures, unsigned long* hwcap) {
+ *hwcap |= has_list_item(cpuFeatures, "neon") ? NPY__HWCAP_NEON : 0;
+ *hwcap |= has_list_item(cpuFeatures, "half") ? NPY__HWCAP_HALF : 0;
+ *hwcap |= has_list_item(cpuFeatures, "vfpv3") ? NPY__HWCAP_VFPv3 : 0;
+ *hwcap |= has_list_item(cpuFeatures, "vfpv4") ? NPY__HWCAP_VFPv4 : 0;
+
+ *hwcap |= has_list_item(cpuFeatures, "asimd") ? NPY__HWCAP_ASIMD : 0;
+ *hwcap |= has_list_item(cpuFeatures, "fp") ? NPY__HWCAP_FP : 0;
+ *hwcap |= has_list_item(cpuFeatures, "fphp") ? NPY__HWCAP_FPHP : 0;
+ *hwcap |= has_list_item(cpuFeatures, "asimdhp") ? NPY__HWCAP_ASIMDHP : 0;
+ *hwcap |= has_list_item(cpuFeatures, "asimddp") ? NPY__HWCAP_ASIMDDP : 0;
+ *hwcap |= has_list_item(cpuFeatures, "asimdfhm") ? NPY__HWCAP_ASIMDFHM : 0;
+}
+
+static int
+get_feature_from_proc_cpuinfo(unsigned long *hwcap, unsigned long *hwcap2) {
+ char* cpuinfo = NULL;
+ int cpuinfo_len;
+ cpuinfo_len = get_file_size("/proc/cpuinfo");
+ if (cpuinfo_len < 0) {
+ return 0;
+ }
+ cpuinfo = malloc(cpuinfo_len);
+ if (cpuinfo == NULL) {
+ return 0;
+ }
+ cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, cpuinfo_len);
+ char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features");
+ if(cpuFeatures == NULL) {
+ return 0;
+ }
+ setHwcap(cpuFeatures, hwcap);
+ *hwcap2 |= *hwcap;
+ *hwcap2 |= has_list_item(cpuFeatures, "aes") ? NPY__HWCAP2_AES : 0;
+ *hwcap2 |= has_list_item(cpuFeatures, "pmull") ? NPY__HWCAP2_PMULL : 0;
+ *hwcap2 |= has_list_item(cpuFeatures, "sha1") ? NPY__HWCAP2_SHA1 : 0;
+ *hwcap2 |= has_list_item(cpuFeatures, "sha2") ? NPY__HWCAP2_SHA2 : 0;
+ *hwcap2 |= has_list_item(cpuFeatures, "crc32") ? NPY__HWCAP2_CRC32 : 0;
+ return 1;
+}
+#endif
diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index 0e49b0d63..e41fdc8f1 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -371,8 +371,11 @@ string_converter_helper( 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; @@ -385,8 +388,8 @@ static int byteorder_parser(char const *str, Py_ssize_t length, void *data) 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; } @@ -508,21 +511,36 @@ PyArray_SelectkindConverter(PyObject *obj, NPY_SELECTKIND *selectkind) 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 @@ -581,24 +599,40 @@ PyArray_OrderConverter(PyObject *object, NPY_ORDER *val) 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 diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c index 8d884bc00..4ebd5640d 100644 --- a/numpy/core/src/multiarray/descriptor.c +++ b/numpy/core/src/multiarray/descriptor.c @@ -1678,14 +1678,14 @@ _convert_from_str(PyObject *obj, int align) } /* 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) { diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c index 7aefbfc38..f73cb48d9 100644 --- a/numpy/core/src/multiarray/mapping.c +++ b/numpy/core/src/multiarray/mapping.c @@ -2480,8 +2480,6 @@ PyArray_MapIterCheckIndices(PyArrayMapIterObject *mit) int i; NPY_BEGIN_THREADS_DEF; - intp_type = PyArray_DescrFromType(NPY_INTP); - if (NpyIter_GetIterSize(mit->outer) == 0) { /* * When the outer iteration is empty, the indices broadcast to an @@ -2493,6 +2491,8 @@ PyArray_MapIterCheckIndices(PyArrayMapIterObject *mit) return 0; } + intp_type = PyArray_DescrFromType(NPY_INTP); + NPY_BEGIN_THREADS; for (i=0; i < mit->numiter; i++) { diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src index 48e89915c..e6414e29e 100644 --- a/numpy/core/src/umath/simd.inc.src +++ b/numpy/core/src/umath/simd.inc.src @@ -2698,17 +2698,17 @@ static NPY_GCC_OPT_3 NPY_GCC_TARGET_@ISA@ void /* process elements using glibc for large elements */ if (my_trig_op == npy_compute_cos) { - for (int ii = 0; iglibc_mask != 0; ii++) { + for (int ii = 0, jj = 0; iglibc_mask != 0; ii++, jj += stride) { if (iglibc_mask & 0x01) { - op[ii] = npy_cosf(ip[ii]); + op[ii] = npy_cosf(ip[jj]); } iglibc_mask = iglibc_mask >> 1; } } else { - for (int ii = 0; iglibc_mask != 0; ii++) { + for (int ii = 0, jj = 0; iglibc_mask != 0; ii++, jj += stride) { if (iglibc_mask & 0x01) { - op[ii] = npy_sinf(ip[ii]); + op[ii] = npy_sinf(ip[jj]); } iglibc_mask = iglibc_mask >> 1; } diff --git a/numpy/core/tests/test_conversion_utils.py b/numpy/core/tests/test_conversion_utils.py index e96113d09..d8849ee29 100644 --- a/numpy/core/tests/test_conversion_utils.py +++ b/numpy/core/tests/test_conversion_utils.py @@ -7,19 +7,31 @@ import pytest 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: @@ -33,13 +45,13 @@ class StringConverterTestCase: 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()) @@ -69,6 +81,8 @@ class StringConverterTestCase: 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') @@ -85,10 +99,12 @@ class TestByteorderConverter(StringConverterTestCase): 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') @@ -113,6 +129,8 @@ class TestSearchsideConverter(StringConverterTestCase): 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') diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index 523638a35..9dcf4a9c9 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -313,19 +313,14 @@ class TestBinaryReprInsufficientWidthParameterForRepresentation(_DeprecationTest 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,)) @@ -438,14 +433,6 @@ class TestGeneratorSum(_DeprecationTestCase): 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): @@ -645,3 +632,13 @@ class TestIncorrectAdvancedIndexWithEmptyResult(_DeprecationTestCase): 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')) diff --git a/numpy/core/tests/test_dtype.py b/numpy/core/tests/test_dtype.py index 73aa01de6..2e2b0dbe2 100644 --- a/numpy/core/tests/test_dtype.py +++ b/numpy/core/tests/test_dtype.py @@ -86,6 +86,15 @@ class TestBuiltin: 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', @@ -1047,6 +1056,11 @@ def test_invalid_dtype_string(): 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: @@ -1324,4 +1338,3 @@ class TestFromCTypes: pair_type = np.dtype('{},{}'.format(*pair)) expected = np.dtype([('f0', pair[0]), ('f1', pair[1])]) assert_equal(pair_type, expected) - diff --git a/numpy/core/tests/test_einsum.py b/numpy/core/tests/test_einsum.py index da84735a0..c697d0c2d 100644 --- a/numpy/core/tests/test_einsum.py +++ b/numpy/core/tests/test_einsum.py @@ -94,6 +94,10 @@ class TestEinsum: 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]: @@ -876,6 +880,41 @@ class TestEinsum: 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): diff --git a/numpy/core/tests/test_function_base.py b/numpy/core/tests/test_function_base.py index 2197ef0cd..62a9772c8 100644 --- a/numpy/core/tests/test_function_base.py +++ b/numpy/core/tests/test_function_base.py @@ -1,6 +1,6 @@ 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, @@ -113,6 +113,40 @@ class TestGeomspace: 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) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 1a8268eb8..e116077f9 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -2153,10 +2153,10 @@ class TestMethods: # 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) @@ -2165,10 +2165,10 @@ class TestMethods: 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') @@ -2181,21 +2181,21 @@ class TestMethods: # 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 @@ -2204,21 +2204,21 @@ class TestMethods: 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 @@ -2233,16 +2233,16 @@ class TestMethods: 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): @@ -2297,9 +2297,9 @@ class TestMethods: 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) @@ -2310,15 +2310,15 @@ class TestMethods: 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 @@ -2339,16 +2339,16 @@ class TestMethods: # 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 @@ -2358,9 +2358,9 @@ class TestMethods: 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): @@ -2370,10 +2370,10 @@ class TestMethods: 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 diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 96a6d810f..cf18a5d93 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -42,13 +42,6 @@ class TestRegression: 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 diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 91acd6ac3..f836af168 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -890,15 +890,17 @@ class TestAVXFloat32Transcendental: sizes = np.arange(2,100) for ii in sizes: x_f32 = np.float32(np.random.uniform(low=0.01,high=88.1,size=ii)) + x_f32_large = x_f32.copy() + x_f32_large[3:-1:4] = 120000.0 exp_true = np.exp(x_f32) log_true = np.log(x_f32) - sin_true = np.sin(x_f32) - cos_true = np.cos(x_f32) + sin_true = np.sin(x_f32_large) + cos_true = np.cos(x_f32_large) for jj in strides: assert_array_almost_equal_nulp(np.exp(x_f32[::jj]), exp_true[::jj], nulp=2) assert_array_almost_equal_nulp(np.log(x_f32[::jj]), log_true[::jj], nulp=2) - assert_array_almost_equal_nulp(np.sin(x_f32[::jj]), sin_true[::jj], nulp=2) - assert_array_almost_equal_nulp(np.cos(x_f32[::jj]), cos_true[::jj], nulp=2) + assert_array_almost_equal_nulp(np.sin(x_f32_large[::jj]), sin_true[::jj], nulp=2) + assert_array_almost_equal_nulp(np.cos(x_f32_large[::jj]), cos_true[::jj], nulp=2) class TestLogAddExp(_FilterInvalids): def test_logaddexp_values(self): diff --git a/numpy/core/tests/test_umath_accuracy.py b/numpy/core/tests/test_umath_accuracy.py index e3c2eb025..33080edbb 100644 --- a/numpy/core/tests/test_umath_accuracy.py +++ b/numpy/core/tests/test_umath_accuracy.py @@ -57,9 +57,3 @@ class TestAccuracy: outval = outval[perm] maxulperr = data_subset['ulperr'].max() assert_array_max_ulp(npfunc(inval), outval, maxulperr) - - def test_ignore_nan_ulperror(self): - # Ignore ULP differences between various NAN's - nan1_f32 = np.array(str_to_float('0xffffffff'), dtype=np.float32) - nan2_f32 = np.array(str_to_float('0x7fddbfbf'), dtype=np.float32) - assert_array_max_ulp(nan1_f32, nan2_f32, 0) diff --git a/numpy/doc/dispatch.py b/numpy/doc/dispatch.py index ba76a43ae..af70ed836 100644 --- a/numpy/doc/dispatch.py +++ b/numpy/doc/dispatch.py @@ -267,5 +267,5 @@ 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>`_. +See also :doc:`NEP 18<neps:nep-0018-array-function-protocol>`. """ diff --git a/numpy/f2py/cb_rules.py b/numpy/f2py/cb_rules.py index 87887c152..3068dc897 100644 --- a/numpy/f2py/cb_rules.py +++ b/numpy/f2py/cb_rules.py @@ -33,119 +33,154 @@ cb_routine_rules = { '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': """\ @@ -188,26 +223,26 @@ cb_rout_rules = [ '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'], @@ -232,32 +267,32 @@ return_value """, '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'}, @@ -314,61 +349,61 @@ cb_arg_rules = [ '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), @@ -376,52 +411,52 @@ cb_arg_rules = [ }, # 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) diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py index f1ac214d4..ccbc9b0fb 100644 --- a/numpy/f2py/cfuncs.py +++ b/numpy/f2py/cfuncs.py @@ -543,6 +543,21 @@ cppmacros['OLDPYNUM'] = """\ #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'] = """\ diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py index ecfc71ae3..7b25b545a 100755 --- a/numpy/f2py/rules.py +++ b/numpy/f2py/rules.py @@ -266,18 +266,18 @@ static PyObject *#apiname#(const PyObject *capi_self, 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 @@ -290,27 +290,27 @@ if (PyErr_Occurred()) 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# """, @@ -749,36 +749,35 @@ arg_rules = [ '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\"); @@ -796,35 +795,29 @@ if (#varname#_capi==Py_None) { } } } - 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':'' diff --git a/numpy/f2py/src/fortranobject.c b/numpy/f2py/src/fortranobject.c index b3a04bcf0..aa46c57d0 100644 --- a/numpy/f2py/src/fortranobject.c +++ b/numpy/f2py/src/fortranobject.c @@ -30,6 +30,68 @@ F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj) 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 *); diff --git a/numpy/f2py/src/fortranobject.h b/numpy/f2py/src/fortranobject.h index 5c382ab7b..d4cc10243 100644 --- a/numpy/f2py/src/fortranobject.h +++ b/numpy/f2py/src/fortranobject.h @@ -86,6 +86,9 @@ PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)); 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 diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py index 4e29ab9fc..81650a819 100644 --- a/numpy/f2py/tests/test_callback.py +++ b/numpy/f2py/tests/test_callback.py @@ -2,6 +2,10 @@ import math 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 @@ -161,3 +165,49 @@ cf2py intent(out) a 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"] diff --git a/numpy/lib/format.py b/numpy/lib/format.py index 2afa4ac10..cb2d511af 100644 --- a/numpy/lib/format.py +++ b/numpy/lib/format.py @@ -156,8 +156,8 @@ names. 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. """ diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 4ebca6360..cf6f4891c 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -1971,8 +1971,7 @@ class vectorize: 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 -------- @@ -3120,7 +3119,7 @@ def i0(x): .. [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 -------- diff --git a/numpy/lib/mixins.py b/numpy/lib/mixins.py index 50157069c..c81239f6b 100644 --- a/numpy/lib/mixins.py +++ b/numpy/lib/mixins.py @@ -68,7 +68,7 @@ class NDArrayOperatorsMixin: 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 diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 8d612b8ed..b5371f51a 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -21,6 +21,7 @@ Released for unlimited redistribution. """ # pylint: disable-msg=E1002 import builtins +import inspect import operator import warnings import textwrap @@ -122,15 +123,8 @@ def doc_note(initialdoc, note): 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:]) diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py index f86ebf551..8ede29da1 100644 --- a/numpy/ma/extras.py +++ b/numpy/ma/extras.py @@ -244,11 +244,6 @@ class _fromnxfunction: 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 @@ -258,9 +253,9 @@ class _fromnxfunction: 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): diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 6f34144bb..76a92f5ca 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -34,8 +34,8 @@ from numpy.ma.core import ( 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, @@ -5283,3 +5283,33 @@ def test_mask_shape_assignment_does_not_break_masked(): 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) diff --git a/numpy/polynomial/_polybase.py b/numpy/polynomial/_polybase.py index 30887b670..b5341ba37 100644 --- a/numpy/polynomial/_polybase.py +++ b/numpy/polynomial/_polybase.py @@ -919,10 +919,8 @@ class ABCPolyBase(abc.ABC): ---------- 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 diff --git a/numpy/polynomial/chebyshev.py b/numpy/polynomial/chebyshev.py index 4ddb0c688..431617414 100644 --- a/numpy/polynomial/chebyshev.py +++ b/numpy/polynomial/chebyshev.py @@ -104,7 +104,7 @@ References ---------- .. [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 diff --git a/numpy/py.typed b/numpy/py.typed new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/numpy/py.typed diff --git a/numpy/random/_common.pyx b/numpy/random/_common.pyx index ef1afac7c..6d77aed03 100644 --- a/numpy/random/_common.pyx +++ b/numpy/random/_common.pyx @@ -218,6 +218,20 @@ cdef np.ndarray int_to_array(object value, object name, object bits, object uint return out +cdef validate_output_shape(iter_shape, np.ndarray output): + cdef np.npy_intp *shape + cdef ndim, i + cdef bint error + dims = np.PyArray_DIMS(output) + ndim = np.PyArray_NDIM(output) + output_shape = tuple((dims[i] for i in range(ndim))) + if iter_shape != output_shape: + raise ValueError( + f"Output size {output_shape} is not compatible with broadcast " + f"dimensions of inputs {iter_shape}." + ) + + cdef check_output(object out, object dtype, object size): if out is None: return @@ -404,6 +418,7 @@ cdef object cont_broadcast_1(void *func, void *state, object size, object lock, randoms_data = <double *>np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew2(randoms, a_arr) + validate_output_shape(it.shape, randoms) with lock, nogil: for i in range(n): @@ -441,6 +456,8 @@ cdef object cont_broadcast_2(void *func, void *state, object size, object lock, n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) + validate_output_shape(it.shape, randoms) + with lock, nogil: for i in range(n): a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0] @@ -482,6 +499,8 @@ cdef object cont_broadcast_3(void *func, void *state, object size, object lock, n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew4(randoms, a_arr, b_arr, c_arr) + validate_output_shape(it.shape, randoms) + with lock, nogil: for i in range(n): a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0] @@ -611,6 +630,8 @@ cdef object discrete_broadcast_d(void *func, void *state, object size, object lo n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew2(randoms, a_arr) + validate_output_shape(it.shape, randoms) + with lock, nogil: for i in range(n): a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0] @@ -645,6 +666,8 @@ cdef object discrete_broadcast_dd(void *func, void *state, object size, object l n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) + validate_output_shape(it.shape, randoms) + with lock, nogil: for i in range(n): a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0] @@ -680,6 +703,8 @@ cdef object discrete_broadcast_di(void *func, void *state, object size, object l n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew3(randoms, a_arr, b_arr) + validate_output_shape(it.shape, randoms) + with lock, nogil: for i in range(n): a_val = (<double*>np.PyArray_MultiIter_DATA(it, 1))[0] @@ -719,6 +744,8 @@ cdef object discrete_broadcast_iii(void *func, void *state, object size, object n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew4(randoms, a_arr, b_arr, c_arr) + validate_output_shape(it.shape, randoms) + with lock, nogil: for i in range(n): a_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 1))[0] @@ -750,6 +777,8 @@ cdef object discrete_broadcast_i(void *func, void *state, object size, object lo n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew2(randoms, a_arr) + validate_output_shape(it.shape, randoms) + with lock, nogil: for i in range(n): a_val = (<int64_t*>np.PyArray_MultiIter_DATA(it, 1))[0] @@ -923,6 +952,7 @@ cdef object cont_broadcast_1_f(void *func, bitgen_t *state, object size, object randoms_data = <float *>np.PyArray_DATA(randoms) n = np.PyArray_SIZE(randoms) it = np.PyArray_MultiIterNew2(randoms, a_arr) + validate_output_shape(it.shape, randoms) with lock, nogil: for i in range(n): diff --git a/numpy/random/_generator.pyx b/numpy/random/_generator.pyx index 2e54dce5f..0936ea2e8 100644 --- a/numpy/random/_generator.pyx +++ b/numpy/random/_generator.pyx @@ -2779,7 +2779,7 @@ cdef class Generator: generate zero positive results. >>> sum(rng.binomial(9, 0.1, 20000) == 0)/20000. - # answer = 0.38885, or 38%. + # answer = 0.38885, or 39%. """ @@ -3345,7 +3345,8 @@ cdef class Generator: 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. diff --git a/numpy/random/bit_generator.pyx b/numpy/random/bit_generator.pyx index f145ec13d..3c52a9933 100644 --- a/numpy/random/bit_generator.pyx +++ b/numpy/random/bit_generator.pyx @@ -382,13 +382,22 @@ cdef class SeedSequence(): ------- entropy_array : 1D uint32 array """ - # Convert run-entropy, program-entropy, and the spawn key into uint32 + # Convert run-entropy and the spawn key into uint32 # arrays and concatenate them. # We MUST have at least some run-entropy. The others are optional. assert self.entropy is not None run_entropy = _coerce_to_uint32_array(self.entropy) spawn_entropy = _coerce_to_uint32_array(self.spawn_key) + if len(spawn_entropy) > 0 and len(run_entropy) < self.pool_size: + # Explicitly fill out the entropy with 0s to the pool size to avoid + # conflict with spawn keys. We changed this in 1.19.0 to fix + # gh-16539. In order to preserve stream-compatibility with + # unspawned SeedSequences with small entropy inputs, we only do + # this when a spawn_key is specified. + diff = self.pool_size - len(run_entropy) + run_entropy = np.concatenate( + [run_entropy, np.zeros(diff, dtype=np.uint32)]) entropy_array = np.concatenate([run_entropy, spawn_entropy]) return entropy_array diff --git a/numpy/random/tests/test_generator_mt19937.py b/numpy/random/tests/test_generator_mt19937.py index f72b748ba..332b63198 100644 --- a/numpy/random/tests/test_generator_mt19937.py +++ b/numpy/random/tests/test_generator_mt19937.py @@ -2397,3 +2397,44 @@ def test_jumped(config): md5 = hashlib.md5(key) assert jumped.state["state"]["pos"] == config["jumped"]["pos"] assert md5.hexdigest() == config["jumped"]["key_md5"] + + +def test_broadcast_size_error(): + mu = np.ones(3) + sigma = np.ones((4, 3)) + size = (10, 4, 2) + assert random.normal(mu, sigma, size=(5, 4, 3)).shape == (5, 4, 3) + with pytest.raises(ValueError): + random.normal(mu, sigma, size=size) + with pytest.raises(ValueError): + random.normal(mu, sigma, size=(1, 3)) + with pytest.raises(ValueError): + random.normal(mu, sigma, size=(4, 1, 1)) + # 1 arg + shape = np.ones((4, 3)) + with pytest.raises(ValueError): + random.standard_gamma(shape, size=size) + with pytest.raises(ValueError): + random.standard_gamma(shape, size=(3,)) + with pytest.raises(ValueError): + random.standard_gamma(shape, size=3) + # Check out + out = np.empty(size) + with pytest.raises(ValueError): + random.standard_gamma(shape, out=out) + + # 3 arg + a = random.chisquare(5, size=3) + b = random.chisquare(5, size=(4, 3)) + c = random.chisquare(5, size=(5, 4, 3)) + assert random.noncentral_f(a, b, c).shape == (5, 4, 3) + with pytest.raises(ValueError, match=r"Output size \(6, 5, 1, 1\) is"): + random.noncentral_f(a, b, c, size=(6, 5, 1, 1)) + + +def test_broadcast_size_scalar(): + mu = np.ones(3) + sigma = np.ones(3) + random.normal(mu, sigma, size=3) + with pytest.raises(ValueError): + random.normal(mu, sigma, size=2) diff --git a/numpy/random/tests/test_seed_sequence.py b/numpy/random/tests/test_seed_sequence.py index fe23680ed..f08cf80fa 100644 --- a/numpy/random/tests/test_seed_sequence.py +++ b/numpy/random/tests/test_seed_sequence.py @@ -1,5 +1,5 @@ import numpy as np -from numpy.testing import assert_array_equal +from numpy.testing import assert_array_equal, assert_array_compare from numpy.random import SeedSequence @@ -52,3 +52,29 @@ def test_reference_data(): assert_array_equal(state, expected) state64 = ss.generate_state(len(expected64), dtype=np.uint64) assert_array_equal(state64, expected64) + + +def test_zero_padding(): + """ Ensure that the implicit zero-padding does not cause problems. + """ + # Ensure that large integers are inserted in little-endian fashion to avoid + # trailing 0s. + ss0 = SeedSequence(42) + ss1 = SeedSequence(42 << 32) + assert_array_compare( + np.not_equal, + ss0.generate_state(4), + ss1.generate_state(4)) + + # Ensure backwards compatibility with the original 0.17 release for small + # integers and no spawn key. + expected42 = np.array([3444837047, 2669555309, 2046530742, 3581440988], + dtype=np.uint32) + assert_array_equal(SeedSequence(42).generate_state(4), expected42) + + # Regression test for gh-16539 to ensure that the implicit 0s don't + # conflict with spawn keys. + assert_array_compare( + np.not_equal, + SeedSequence(42, spawn_key=(0,)).generate_state(4), + expected42) diff --git a/numpy/setup.py b/numpy/setup.py index 52db6a68b..c6498d101 100644 --- a/numpy/setup.py +++ b/numpy/setup.py @@ -18,6 +18,8 @@ def configuration(parent_package='',top_path=None): config.add_subpackage('random') config.add_subpackage('testing') 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 diff --git a/numpy/testing/_private/nosetester.py b/numpy/testing/_private/nosetester.py index bd6d002aa..57691a448 100644 --- a/numpy/testing/_private/nosetester.py +++ b/numpy/testing/_private/nosetester.py @@ -352,7 +352,7 @@ class NoseTester: 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: diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py index b899e94f4..6a6cc664a 100644 --- a/numpy/testing/tests/test_utils.py +++ b/numpy/testing/tests/test_utils.py @@ -941,6 +941,17 @@ class TestArrayAlmostEqualNulp: assert_raises(AssertionError, assert_array_almost_equal_nulp, x, y, nulp) + def test_float64_ignore_nan(self): + # Ignore ULP differences between various NAN's + # Note that MIPS may reverse quiet and signaling nans + # so we use the builtin version as a base. + offset = np.uint64(0xffffffff) + nan1_i64 = np.array(np.nan, dtype=np.float64).view(np.uint64) + nan2_i64 = nan1_i64 ^ offset # nan payload on MIPS is all ones. + nan1_f64 = nan1_i64.view(np.float64) + nan2_f64 = nan2_i64.view(np.float64) + assert_array_max_ulp(nan1_f64, nan2_f64, 0) + def test_float32_pass(self): nulp = 5 x = np.linspace(-20, 20, 50, dtype=np.float32) @@ -971,6 +982,17 @@ class TestArrayAlmostEqualNulp: assert_raises(AssertionError, assert_array_almost_equal_nulp, x, y, nulp) + def test_float32_ignore_nan(self): + # Ignore ULP differences between various NAN's + # Note that MIPS may reverse quiet and signaling nans + # so we use the builtin version as a base. + offset = np.uint32(0xffff) + nan1_i32 = np.array(np.nan, dtype=np.float32).view(np.uint32) + nan2_i32 = nan1_i32 ^ offset # nan payload on MIPS is all ones. + nan1_f32 = nan1_i32.view(np.float32) + nan2_f32 = nan2_i32.view(np.float32) + assert_array_max_ulp(nan1_f32, nan2_f32, 0) + def test_float16_pass(self): nulp = 5 x = np.linspace(-4, 4, 10, dtype=np.float16) @@ -1001,6 +1023,17 @@ class TestArrayAlmostEqualNulp: assert_raises(AssertionError, assert_array_almost_equal_nulp, x, y, nulp) + def test_float16_ignore_nan(self): + # Ignore ULP differences between various NAN's + # Note that MIPS may reverse quiet and signaling nans + # so we use the builtin version as a base. + offset = np.uint16(0xff) + nan1_i16 = np.array(np.nan, dtype=np.float16).view(np.uint16) + nan2_i16 = nan1_i16 ^ offset # nan payload on MIPS is all ones. + nan1_f16 = nan1_i16.view(np.float16) + nan2_f16 = nan2_i16.view(np.float16) + assert_array_max_ulp(nan1_f16, nan2_f16, 0) + def test_complex128_pass(self): nulp = 5 x = np.linspace(-20, 20, 50, dtype=np.float64) diff --git a/numpy/tests/setup.py b/numpy/tests/setup.py new file mode 100644 index 000000000..f034cdf95 --- /dev/null +++ b/numpy/tests/setup.py @@ -0,0 +1,10 @@ +def configuration(parent_package='', top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('tests', parent_package, top_path) + config.add_data_dir('typing') + return config + + +if __name__ == '__main__': + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/tests/test_typing.py b/numpy/tests/test_typing.py new file mode 100644 index 000000000..04ea3c64d --- /dev/null +++ b/numpy/tests/test_typing.py @@ -0,0 +1,142 @@ +import importlib.util +import itertools +import os +import re +from collections import defaultdict + +import pytest +try: + from mypy import api +except ImportError: + NO_MYPY = True +else: + NO_MYPY = False + +TESTS_DIR = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "typing", +) +PASS_DIR = os.path.join(TESTS_DIR, "pass") +FAIL_DIR = os.path.join(TESTS_DIR, "fail") +REVEAL_DIR = os.path.join(TESTS_DIR, "reveal") +MYPY_INI = os.path.join(TESTS_DIR, "mypy.ini") +CACHE_DIR = os.path.join(TESTS_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.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.skipif(NO_MYPY, reason="Mypy is not installed") +@pytest.mark.parametrize("path", get_test_cases(FAIL_DIR)) +def test_fail(path): + 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 " 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() + assert lineno in errors, f'Extra error "{marker}"' + assert marker in errors[lineno] + else: + pytest.fail(f"Error {repr(errors[lineno])} not found") + + +@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed") +@pytest.mark.parametrize("path", get_test_cases(REVEAL_DIR)) +def test_reveal(path): + stdout, stderr, exitcode = api.run([ + "--config-file", + MYPY_INI, + "--cache-dir", + CACHE_DIR, + path, + ]) + + with open(path) as fin: + lines = fin.readlines() + + for error_line in stdout.split("\n"): + 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')) + assert "Revealed type is" in error_line + marker = lines[lineno - 1].split("# E:")[-1].strip() + assert marker in error_line + + +@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) diff --git a/numpy/tests/typing/fail/array_like.py b/numpy/tests/typing/fail/array_like.py new file mode 100644 index 000000000..a5ef5795f --- /dev/null +++ b/numpy/tests/typing/fail/array_like.py @@ -0,0 +1,22 @@ +from typing import Any, TYPE_CHECKING + +import numpy as np + +if TYPE_CHECKING: + from numpy.typing import ArrayLike +else: + ArrayLike = Any + + +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 diff --git a/numpy/tests/typing/fail/fromnumeric.py b/numpy/tests/typing/fail/fromnumeric.py new file mode 100644 index 000000000..7455ce722 --- /dev/null +++ b/numpy/tests/typing/fail/fromnumeric.py @@ -0,0 +1,91 @@ +"""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 +) diff --git a/numpy/tests/typing/fail/ndarray.py b/numpy/tests/typing/fail/ndarray.py new file mode 100644 index 000000000..5a5130d40 --- /dev/null +++ b/numpy/tests/typing/fail/ndarray.py @@ -0,0 +1,11 @@ +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 diff --git a/numpy/tests/typing/fail/numerictypes.py b/numpy/tests/typing/fail/numerictypes.py new file mode 100644 index 000000000..dd03eacc1 --- /dev/null +++ b/numpy/tests/typing/fail/numerictypes.py @@ -0,0 +1,13 @@ +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[int64]" diff --git a/numpy/tests/typing/fail/scalars.py b/numpy/tests/typing/fail/scalars.py new file mode 100644 index 000000000..5d7221895 --- /dev/null +++ b/numpy/tests/typing/fail/scalars.py @@ -0,0 +1,81 @@ +import numpy as np + +# 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 + +dt_64 = np.datetime64(0, "D") +td_64 = np.timedelta64(1, "h") + +dt_64 + dt_64 # E: Unsupported operand types + +td_64 - dt_64 # E: Unsupported operand types +td_64 / dt_64 # E: No overload +td_64 % 1 # E: Unsupported operand types +td_64 % dt_64 # E: Unsupported operand types + + +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.signedinteger(1) # E: Cannot instantiate abstract class +np.unsignedinteger(1) # E: Cannot instantiate abstract class +np.inexact(1) # E: Cannot instantiate abstract class +np.floating(1) # E: Cannot instantiate abstract class +np.complexfloating(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 diff --git a/numpy/tests/typing/fail/simple.py b/numpy/tests/typing/fail/simple.py new file mode 100644 index 000000000..b5e9d1b13 --- /dev/null +++ b/numpy/tests/typing/fail/simple.py @@ -0,0 +1,10 @@ +"""Simple expression that should fail with mypy.""" + +import numpy as np + +# Array creation routines checks +np.zeros("test") # E: incompatible type +np.zeros() # E: Too few arguments + +np.ones("test") # E: incompatible type +np.ones() # E: Too few arguments diff --git a/numpy/tests/typing/fail/ufuncs.py b/numpy/tests/typing/fail/ufuncs.py new file mode 100644 index 000000000..b178a4ea4 --- /dev/null +++ b/numpy/tests/typing/fail/ufuncs.py @@ -0,0 +1,5 @@ +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 diff --git a/numpy/tests/typing/fail/warnings_and_errors.py b/numpy/tests/typing/fail/warnings_and_errors.py new file mode 100644 index 000000000..7390cc45f --- /dev/null +++ b/numpy/tests/typing/fail/warnings_and_errors.py @@ -0,0 +1,7 @@ +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 +) diff --git a/numpy/tests/typing/mypy.ini b/numpy/tests/typing/mypy.ini new file mode 100644 index 000000000..91d93588a --- /dev/null +++ b/numpy/tests/typing/mypy.ini @@ -0,0 +1,8 @@ +[mypy] +mypy_path = ../../.. + +[mypy-numpy] +ignore_errors = True + +[mypy-numpy.*] +ignore_errors = True diff --git a/numpy/tests/typing/pass/array_like.py b/numpy/tests/typing/pass/array_like.py new file mode 100644 index 000000000..098149c4b --- /dev/null +++ b/numpy/tests/typing/pass/array_like.py @@ -0,0 +1,44 @@ +from typing import Any, List, Optional, TYPE_CHECKING + +import numpy as np + +if TYPE_CHECKING: + from numpy.typing import ArrayLike, DtypeLike, _SupportsArray +else: + ArrayLike = Any + DtypeLike = Any + _SupportsArray = Any + +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" + + +class A: + def __array__(self, dtype: DtypeLike = None) -> np.ndarray: + return np.array([1, 2, 3]) + + +x12: 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) diff --git a/numpy/tests/typing/pass/dtype.py b/numpy/tests/typing/pass/dtype.py new file mode 100644 index 000000000..f954fdd44 --- /dev/null +++ b/numpy/tests/typing/pass/dtype.py @@ -0,0 +1,3 @@ +import numpy as np + +np.dtype(dtype=np.int64) diff --git a/numpy/tests/typing/pass/fromnumeric.py b/numpy/tests/typing/pass/fromnumeric.py new file mode 100644 index 000000000..0ce8ef970 --- /dev/null +++ b/numpy/tests/typing/pass/fromnumeric.py @@ -0,0 +1,116 @@ +"""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 + +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) diff --git a/numpy/tests/typing/pass/ndarray_conversion.py b/numpy/tests/typing/pass/ndarray_conversion.py new file mode 100644 index 000000000..303cf53e4 --- /dev/null +++ b/numpy/tests/typing/pass/ndarray_conversion.py @@ -0,0 +1,94 @@ +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 diff --git a/numpy/tests/typing/pass/ndarray_shape_manipulation.py b/numpy/tests/typing/pass/ndarray_shape_manipulation.py new file mode 100644 index 000000000..0ca3dff39 --- /dev/null +++ b/numpy/tests/typing/pass/ndarray_shape_manipulation.py @@ -0,0 +1,47 @@ +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)) diff --git a/numpy/tests/typing/pass/numerictypes.py b/numpy/tests/typing/pass/numerictypes.py new file mode 100644 index 000000000..4f205cabc --- /dev/null +++ b/numpy/tests/typing/pass/numerictypes.py @@ -0,0 +1,29 @@ +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]) diff --git a/numpy/tests/typing/pass/scalars.py b/numpy/tests/typing/pass/scalars.py new file mode 100644 index 000000000..7de182626 --- /dev/null +++ b/numpy/tests/typing/pass/scalars.py @@ -0,0 +1,92 @@ +import numpy as np + + +# Construction +class C: + def __complex__(self): + return 3j + + +class B: + def __int__(self): + return 4 + + +class A: + def __float__(self): + return 4.0 + + +np.complex64(3j) +np.complex64(C()) +np.complex128(3j) +np.complex128(C()) + +np.int8(4) +np.int16(3.4) +np.int32(4) +np.int64(-1) +np.uint8(B()) +np.uint32() + +np.float16(A()) +np.float32(16) +np.float64(3.0) + +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') + +# Protocols +float(np.int8(4)) +int(np.int16(5)) +np.int8(np.float32(6)) + +# TODO(alan): test after https://github.com/python/typeshed/pull/2004 +# complex(np.int32(8)) + +abs(np.int8(4)) + +# 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("2019") +np.datetime64("2019", "D") + +np.timedelta64() +np.timedelta64(0) +np.timedelta64(0, "D") + +dt_64 = np.datetime64(0, "D") +td_64 = np.timedelta64(1, "h") + +dt_64 + td_64 +dt_64 - dt_64 +dt_64 - td_64 + +td_64 + td_64 +td_64 - td_64 +td_64 / 1.0 +td_64 / td_64 +td_64 % td_64 + +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")) diff --git a/numpy/tests/typing/pass/simple.py b/numpy/tests/typing/pass/simple.py new file mode 100644 index 000000000..e0157ab81 --- /dev/null +++ b/numpy/tests/typing/pass/simple.py @@ -0,0 +1,176 @@ +"""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 + +# Array creation routines checks +ndarray_func(np.zeros([1, 2])) +ndarray_func(np.ones([1, 2])) +ndarray_func(np.empty([1, 2])) + +ndarray_func(np.zeros_like(array)) +ndarray_func(np.ones_like(array)) +ndarray_func(np.empty_like(array)) + +# 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({"col1": ("U10", 0), "col2": ("float32", 10)}) +np.dtype((np.int32, {"real": (np.int16, 0), "imag": (np.int16, 2)})) +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() diff --git a/numpy/tests/typing/pass/simple_py3.py b/numpy/tests/typing/pass/simple_py3.py new file mode 100644 index 000000000..c05a1ce61 --- /dev/null +++ b/numpy/tests/typing/pass/simple_py3.py @@ -0,0 +1,6 @@ +import numpy as np + +array = np.array([1, 2]) + +# The @ operator is not in python 2 +array @ array diff --git a/numpy/tests/typing/pass/ufuncs.py b/numpy/tests/typing/pass/ufuncs.py new file mode 100644 index 000000000..c81ac48d1 --- /dev/null +++ b/numpy/tests/typing/pass/ufuncs.py @@ -0,0 +1,11 @@ +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]) +np.sin(1) + np.sin(1) +np.sin.types[0] +np.sin.__name__ diff --git a/numpy/tests/typing/pass/warnings_and_errors.py b/numpy/tests/typing/pass/warnings_and_errors.py new file mode 100644 index 000000000..5b6ec2626 --- /dev/null +++ b/numpy/tests/typing/pass/warnings_and_errors.py @@ -0,0 +1,7 @@ +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) diff --git a/numpy/tests/typing/reveal/constants.py b/numpy/tests/typing/reveal/constants.py new file mode 100644 index 000000000..8e00810bd --- /dev/null +++ b/numpy/tests/typing/reveal/constants.py @@ -0,0 +1,44 @@ +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.little_endian) # E: int +reveal_type(np.tracemalloc_domain) # E: int diff --git a/numpy/tests/typing/reveal/fromnumeric.py b/numpy/tests/typing/reveal/fromnumeric.py new file mode 100644 index 000000000..7d79d5fa9 --- /dev/null +++ b/numpy/tests/typing/reveal/fromnumeric.py @@ -0,0 +1,135 @@ +"""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 + +reveal_type(np.take(a, 0)) # E: numpy.bool_ +reveal_type(np.take(b, 0)) # E: numpy.float32 +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 +reveal_type(np.argpartition(b, 0)) # E: numpy.integer +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 +reveal_type(np.argmax(B)) # E: numpy.integer +reveal_type(np.argmax(A, axis=0)) # E: Union[numpy.integer, numpy.ndarray] +reveal_type(np.argmax(B, axis=0)) # E: Union[numpy.integer, numpy.ndarray] + +reveal_type(np.argmin(A)) # E: numpy.integer +reveal_type(np.argmin(B)) # E: numpy.integer +reveal_type(np.argmin(A, axis=0)) # E: Union[numpy.integer, numpy.ndarray] +reveal_type(np.argmin(B, axis=0)) # E: Union[numpy.integer, numpy.ndarray] + +reveal_type(np.searchsorted(A[0], 0)) # E: numpy.integer +reveal_type(np.searchsorted(B[0], 0)) # E: numpy.integer +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.float32 +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, numpy.ndarray] +reveal_type(np.trace(B)) # E: Union[numpy.number, 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 diff --git a/numpy/tests/typing/reveal/ndarray_conversion.py b/numpy/tests/typing/reveal/ndarray_conversion.py new file mode 100644 index 000000000..411adcf63 --- /dev/null +++ b/numpy/tests/typing/reveal/ndarray_conversion.py @@ -0,0 +1,54 @@ +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: builtins.list[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 diff --git a/numpy/tests/typing/reveal/ndarray_shape_manipulation.py b/numpy/tests/typing/reveal/ndarray_shape_manipulation.py new file mode 100644 index 000000000..a44e1cfa1 --- /dev/null +++ b/numpy/tests/typing/reveal/ndarray_shape_manipulation.py @@ -0,0 +1,35 @@ +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 diff --git a/numpy/tests/typing/reveal/numerictypes.py b/numpy/tests/typing/reveal/numerictypes.py new file mode 100644 index 000000000..e026158cd --- /dev/null +++ b/numpy/tests/typing/reveal/numerictypes.py @@ -0,0 +1,18 @@ +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 diff --git a/numpy/tests/typing/reveal/scalars.py b/numpy/tests/typing/reveal/scalars.py new file mode 100644 index 000000000..8a9555fc3 --- /dev/null +++ b/numpy/tests/typing/reveal/scalars.py @@ -0,0 +1,30 @@ +import numpy as np + +x = np.complex64(3 + 2j) + +reveal_type(x.real) # E: numpy.float32 +reveal_type(x.imag) # E: numpy.float32 + +reveal_type(x.real.real) # E: numpy.float32 +reveal_type(x.real.imag) # E: numpy.float32 + +reveal_type(x.itemsize) # E: int +reveal_type(x.shape) # E: tuple[builtins.int] +reveal_type(x.strides) # E: tuple[builtins.int] + +# Time structures +dt = np.datetime64(0, "D") +td = np.timedelta64(0, "D") + +reveal_type(dt + td) # E: numpy.datetime64 +reveal_type(dt + 1) # E: numpy.datetime64 +reveal_type(dt - dt) # E: numpy.timedelta64 +reveal_type(dt - 1) # E: numpy.timedelta64 + +reveal_type(td + td) # E: numpy.timedelta64 +reveal_type(td + 1) # E: numpy.timedelta64 +reveal_type(td - td) # E: numpy.timedelta64 +reveal_type(td - 1) # E: numpy.timedelta64 +reveal_type(td / 1.0) # E: numpy.timedelta64 +reveal_type(td / td) # E: float +reveal_type(td % td) # E: numpy.timedelta64 diff --git a/numpy/tests/typing/reveal/warnings_and_errors.py b/numpy/tests/typing/reveal/warnings_and_errors.py new file mode 100644 index 000000000..c428deb7a --- /dev/null +++ b/numpy/tests/typing/reveal/warnings_and_errors.py @@ -0,0 +1,10 @@ +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 diff --git a/numpy/typing.pyi b/numpy/typing.pyi new file mode 100644 index 000000000..f5705192a --- /dev/null +++ b/numpy/typing.pyi @@ -0,0 +1,64 @@ +import sys +from typing import Any, Dict, List, overload, Sequence, Text, Tuple, Union + +from numpy import dtype, ndarray + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from typing_extensions import Protocol + +_Shape = Tuple[int, ...] + +# Anything that can be coerced to a shape tuple +_ShapeLike = Union[int, Sequence[int]] + +_DtypeLikeNested = Any # TODO: wait for support for recursive types + +# 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 + # TODO: add a protocol for anything with a dtype attribute + # character codes, type strings or comma-separated fields, e.g., 'float64' + str, + # (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': ...} + # TODO: use TypedDict when/if it's officially supported + Dict[ + str, + Union[ + Sequence[str], # names + Sequence[_DtypeLikeNested], # formats + Sequence[int], # offsets + Sequence[Union[bytes, Text, None]], # titles + int, # itemsize + ], + ], + # {'field1': ..., 'field2': ..., ...} + Dict[str, Tuple[_DtypeLikeNested, int]], + # (base_dtype, new_dtype) + Tuple[_DtypeLikeNested, _DtypeLikeNested], +] + +class _SupportsArray(Protocol): + @overload + def __array__(self, __dtype: DtypeLike = ...) -> ndarray: ... + @overload + def __array__(self, dtype: DtypeLike = ...) -> ndarray: ... + +ArrayLike = Union[bool, int, float, complex, _SupportsArray, Sequence] diff --git a/site.cfg.example b/site.cfg.example index 3eba3bbd7..c809303a2 100644 --- a/site.cfg.example +++ b/site.cfg.example @@ -242,14 +242,6 @@ # 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. diff --git a/test_requirements.txt b/test_requirements.txt index 026bbe414..a555b8295 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,9 +1,15 @@ cython==0.29.19 hypothesis==5.16.0 -pytest==5.4.2 +pytest==5.4.3 pytz==2020.1 pytest-cov==2.9.0 pickle5; python_version == '3.7' pickle5; python_version == '3.6' 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 +# - Python 3.6 doesn't work because it doesn't understand py.typed +mypy==0.770; platform_python_implementation != "PyPy" and python_version > "3.6" and python_version < "3.9" +typing_extensions |