sync 2026-10-29 07:40 GMT (part 3)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- v12x/pylib/numpy/_array_api_info.py +349 -0
- v12x/pylib/numpy/_configtool.py +39 -0
- v12x/pylib/numpy/_core/__init__.py +203 -0
- v12x/pylib/numpy/_core/_add_newdocs.py +0 -0
- v12x/pylib/numpy/_core/_add_newdocs_scalars.py +381 -0
- v12x/pylib/numpy/_core/_asarray.py +130 -0
- v12x/pylib/numpy/_core/_dtype.py +366 -0
- v12x/pylib/numpy/_core/_dtype_ctypes.py +120 -0
- v12x/pylib/numpy/_core/_exceptions.py +162 -0
- v12x/pylib/numpy/_core/_internal.py +964 -0
- v12x/pylib/numpy/_core/_methods.py +252 -0
- v12x/pylib/numpy/_core/_string_helpers.py +100 -0
- v12x/pylib/numpy/_core/_type_aliases.py +130 -0
- v12x/pylib/numpy/_core/_ufunc_config.py +515 -0
- v12x/pylib/numpy/_core/arrayprint.py +1788 -0
- v12x/pylib/numpy/_core/cversions.py +13 -0
- v12x/pylib/numpy/_core/defchararray.py +1429 -0
- v12x/pylib/numpy/_core/einsumfunc.py +1647 -0
- v12x/pylib/numpy/_core/fromnumeric.py +0 -0
- v12x/pylib/numpy/_core/function_base.py +547 -0
- v12x/pylib/numpy/_core/getlimits.py +449 -0
- v12x/pylib/numpy/_core/memmap.py +362 -0
- v12x/pylib/numpy/_core/multiarray.py +1743 -0
- v12x/pylib/numpy/_core/numeric.py +2707 -0
- v12x/pylib/numpy/_core/numerictypes.py +576 -0
- v12x/pylib/numpy/_core/overrides.py +188 -0
- v12x/pylib/numpy/_core/printoptions.py +32 -0
- v12x/pylib/numpy/_core/records.py +1101 -0
- v12x/pylib/numpy/_core/shape_base.py +996 -0
- v12x/pylib/numpy/_core/strings.py +1813 -0
- v12x/pylib/numpy/_core/tests/_locales.py +72 -0
- v12x/pylib/numpy/_core/tests/_natype.py +144 -0
- v12x/pylib/numpy/_core/tests/examples/cython/setup.py +39 -0
- v12x/pylib/numpy/_core/tests/examples/limited_api/setup.py +24 -0
- v12x/pylib/numpy/_core/tests/test__exceptions.py +90 -0
- v12x/pylib/numpy/_core/tests/test_abc.py +54 -0
- v12x/pylib/numpy/_core/tests/test_api.py +668 -0
- v12x/pylib/numpy/_core/tests/test_argparse.py +90 -0
- v12x/pylib/numpy/_core/tests/test_array_api_info.py +113 -0
- v12x/pylib/numpy/_core/tests/test_array_coercion.py +943 -0
- v12x/pylib/numpy/_core/tests/test_array_interface.py +222 -0
- v12x/pylib/numpy/_core/tests/test_arraymethod.py +85 -0
- v12x/pylib/numpy/_core/tests/test_arrayobject.py +198 -0
- v12x/pylib/numpy/_core/tests/test_arrayprint.py +1363 -0
- v12x/pylib/numpy/_core/tests/test_casting_floatingpoint_errors.py +154 -0
- v12x/pylib/numpy/_core/tests/test_casting_unittests.py +970 -0
- v12x/pylib/numpy/_core/tests/test_conversion_utils.py +209 -0
- v12x/pylib/numpy/_core/tests/test_cpu_dispatcher.py +48 -0
- v12x/pylib/numpy/_core/tests/test_cpu_features.py +533 -0
- v12x/pylib/numpy/_core/tests/test_custom_dtypes.py +511 -0
v12x/pylib/numpy/_array_api_info.py
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Array API Inspection namespace
|
| 3 |
+
|
| 4 |
+
This is the namespace for inspection functions as defined by the array API
|
| 5 |
+
standard. See
|
| 6 |
+
https://data-apis.org/array-api/latest/API_specification/inspection.html for
|
| 7 |
+
more details.
|
| 8 |
+
|
| 9 |
+
"""
|
| 10 |
+
from numpy._core import (
|
| 11 |
+
bool,
|
| 12 |
+
complex64,
|
| 13 |
+
complex128,
|
| 14 |
+
dtype,
|
| 15 |
+
float32,
|
| 16 |
+
float64,
|
| 17 |
+
int8,
|
| 18 |
+
int16,
|
| 19 |
+
int32,
|
| 20 |
+
int64,
|
| 21 |
+
intp,
|
| 22 |
+
uint8,
|
| 23 |
+
uint16,
|
| 24 |
+
uint32,
|
| 25 |
+
uint64,
|
| 26 |
+
)
|
| 27 |
+
from numpy._utils import set_module
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
@set_module('numpy')
|
| 31 |
+
class __array_namespace_info__:
|
| 32 |
+
"""
|
| 33 |
+
Get the array API inspection namespace for NumPy.
|
| 34 |
+
|
| 35 |
+
The array API inspection namespace defines the following functions:
|
| 36 |
+
|
| 37 |
+
- capabilities()
|
| 38 |
+
- default_device()
|
| 39 |
+
- default_dtypes()
|
| 40 |
+
- dtypes()
|
| 41 |
+
- devices()
|
| 42 |
+
|
| 43 |
+
See
|
| 44 |
+
https://data-apis.org/array-api/latest/API_specification/inspection.html
|
| 45 |
+
for more details.
|
| 46 |
+
|
| 47 |
+
Returns
|
| 48 |
+
-------
|
| 49 |
+
info : ModuleType
|
| 50 |
+
The array API inspection namespace for NumPy.
|
| 51 |
+
|
| 52 |
+
Examples
|
| 53 |
+
--------
|
| 54 |
+
>>> info = np.__array_namespace_info__()
|
| 55 |
+
>>> info.default_dtypes()
|
| 56 |
+
{'real floating': numpy.float64,
|
| 57 |
+
'complex floating': numpy.complex128,
|
| 58 |
+
'integral': numpy.int64,
|
| 59 |
+
'indexing': numpy.int64}
|
| 60 |
+
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
def capabilities(self):
|
| 64 |
+
"""
|
| 65 |
+
Return a dictionary of array API library capabilities.
|
| 66 |
+
|
| 67 |
+
The resulting dictionary has the following keys:
|
| 68 |
+
|
| 69 |
+
- **"boolean indexing"**: boolean indicating whether an array library
|
| 70 |
+
supports boolean indexing. Always ``True`` for NumPy.
|
| 71 |
+
|
| 72 |
+
- **"data-dependent shapes"**: boolean indicating whether an array
|
| 73 |
+
library supports data-dependent output shapes. Always ``True`` for
|
| 74 |
+
NumPy.
|
| 75 |
+
|
| 76 |
+
- **"max dimensions"**: integer indicating maximum number of supported
|
| 77 |
+
dimensions. Always ``64`` for NumPy.
|
| 78 |
+
|
| 79 |
+
See
|
| 80 |
+
https://data-apis.org/array-api/latest/API_specification/generated/array_api.info.capabilities.html
|
| 81 |
+
for more details.
|
| 82 |
+
|
| 83 |
+
See Also
|
| 84 |
+
--------
|
| 85 |
+
__array_namespace_info__.default_device,
|
| 86 |
+
__array_namespace_info__.default_dtypes,
|
| 87 |
+
__array_namespace_info__.dtypes,
|
| 88 |
+
__array_namespace_info__.devices
|
| 89 |
+
|
| 90 |
+
Returns
|
| 91 |
+
-------
|
| 92 |
+
capabilities : dict
|
| 93 |
+
A dictionary of array API library capabilities.
|
| 94 |
+
|
| 95 |
+
Examples
|
| 96 |
+
--------
|
| 97 |
+
>>> info = np.__array_namespace_info__()
|
| 98 |
+
>>> info.capabilities()
|
| 99 |
+
{'boolean indexing': True,
|
| 100 |
+
'data-dependent shapes': True,
|
| 101 |
+
'max dimensions': 64}
|
| 102 |
+
|
| 103 |
+
"""
|
| 104 |
+
return {
|
| 105 |
+
"boolean indexing": True,
|
| 106 |
+
"data-dependent shapes": True,
|
| 107 |
+
"max dimensions": 64,
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
def default_device(self):
|
| 111 |
+
"""
|
| 112 |
+
The default device used for new NumPy arrays.
|
| 113 |
+
|
| 114 |
+
For NumPy, this always returns ``'cpu'``.
|
| 115 |
+
|
| 116 |
+
See Also
|
| 117 |
+
--------
|
| 118 |
+
__array_namespace_info__.capabilities,
|
| 119 |
+
__array_namespace_info__.default_dtypes,
|
| 120 |
+
__array_namespace_info__.dtypes,
|
| 121 |
+
__array_namespace_info__.devices
|
| 122 |
+
|
| 123 |
+
Returns
|
| 124 |
+
-------
|
| 125 |
+
device : str
|
| 126 |
+
The default device used for new NumPy arrays.
|
| 127 |
+
|
| 128 |
+
Examples
|
| 129 |
+
--------
|
| 130 |
+
>>> info = np.__array_namespace_info__()
|
| 131 |
+
>>> info.default_device()
|
| 132 |
+
'cpu'
|
| 133 |
+
|
| 134 |
+
"""
|
| 135 |
+
return "cpu"
|
| 136 |
+
|
| 137 |
+
def default_dtypes(self, *, device=None):
|
| 138 |
+
"""
|
| 139 |
+
The default data types used for new NumPy arrays.
|
| 140 |
+
|
| 141 |
+
For NumPy, this always returns the following dictionary:
|
| 142 |
+
|
| 143 |
+
- **"real floating"**: ``numpy.float64``
|
| 144 |
+
- **"complex floating"**: ``numpy.complex128``
|
| 145 |
+
- **"integral"**: ``numpy.intp``
|
| 146 |
+
- **"indexing"**: ``numpy.intp``
|
| 147 |
+
|
| 148 |
+
Parameters
|
| 149 |
+
----------
|
| 150 |
+
device : str, optional
|
| 151 |
+
The device to get the default data types for. For NumPy, only
|
| 152 |
+
``'cpu'`` is allowed.
|
| 153 |
+
|
| 154 |
+
Returns
|
| 155 |
+
-------
|
| 156 |
+
dtypes : dict
|
| 157 |
+
A dictionary describing the default data types used for new NumPy
|
| 158 |
+
arrays.
|
| 159 |
+
|
| 160 |
+
See Also
|
| 161 |
+
--------
|
| 162 |
+
__array_namespace_info__.capabilities,
|
| 163 |
+
__array_namespace_info__.default_device,
|
| 164 |
+
__array_namespace_info__.dtypes,
|
| 165 |
+
__array_namespace_info__.devices
|
| 166 |
+
|
| 167 |
+
Examples
|
| 168 |
+
--------
|
| 169 |
+
>>> info = np.__array_namespace_info__()
|
| 170 |
+
>>> info.default_dtypes()
|
| 171 |
+
{'real floating': numpy.float64,
|
| 172 |
+
'complex floating': numpy.complex128,
|
| 173 |
+
'integral': numpy.int64,
|
| 174 |
+
'indexing': numpy.int64}
|
| 175 |
+
|
| 176 |
+
"""
|
| 177 |
+
if device not in ["cpu", None]:
|
| 178 |
+
raise ValueError(
|
| 179 |
+
'Device not understood. Only "cpu" is allowed, but received:'
|
| 180 |
+
f' {device}'
|
| 181 |
+
)
|
| 182 |
+
return {
|
| 183 |
+
"real floating": dtype(float64),
|
| 184 |
+
"complex floating": dtype(complex128),
|
| 185 |
+
"integral": dtype(intp),
|
| 186 |
+
"indexing": dtype(intp),
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
def dtypes(self, *, device=None, kind=None):
|
| 190 |
+
"""
|
| 191 |
+
The array API data types supported by NumPy.
|
| 192 |
+
|
| 193 |
+
Note that this function only returns data types that are defined by
|
| 194 |
+
the array API.
|
| 195 |
+
|
| 196 |
+
Parameters
|
| 197 |
+
----------
|
| 198 |
+
device : str, optional
|
| 199 |
+
The device to get the data types for. For NumPy, only ``'cpu'`` is
|
| 200 |
+
allowed.
|
| 201 |
+
kind : str or tuple of str, optional
|
| 202 |
+
The kind of data types to return. If ``None``, all data types are
|
| 203 |
+
returned. If a string, only data types of that kind are returned.
|
| 204 |
+
If a tuple, a dictionary containing the union of the given kinds
|
| 205 |
+
is returned. The following kinds are supported:
|
| 206 |
+
|
| 207 |
+
- ``'bool'``: boolean data types (i.e., ``bool``).
|
| 208 |
+
- ``'signed integer'``: signed integer data types (i.e., ``int8``,
|
| 209 |
+
``int16``, ``int32``, ``int64``).
|
| 210 |
+
- ``'unsigned integer'``: unsigned integer data types (i.e.,
|
| 211 |
+
``uint8``, ``uint16``, ``uint32``, ``uint64``).
|
| 212 |
+
- ``'integral'``: integer data types. Shorthand for ``('signed
|
| 213 |
+
integer', 'unsigned integer')``.
|
| 214 |
+
- ``'real floating'``: real-valued floating-point data types
|
| 215 |
+
(i.e., ``float32``, ``float64``).
|
| 216 |
+
- ``'complex floating'``: complex floating-point data types (i.e.,
|
| 217 |
+
``complex64``, ``complex128``).
|
| 218 |
+
- ``'numeric'``: numeric data types. Shorthand for ``('integral',
|
| 219 |
+
'real floating', 'complex floating')``.
|
| 220 |
+
|
| 221 |
+
Returns
|
| 222 |
+
-------
|
| 223 |
+
dtypes : dict
|
| 224 |
+
A dictionary mapping the names of data types to the corresponding
|
| 225 |
+
NumPy data types.
|
| 226 |
+
|
| 227 |
+
See Also
|
| 228 |
+
--------
|
| 229 |
+
__array_namespace_info__.capabilities,
|
| 230 |
+
__array_namespace_info__.default_device,
|
| 231 |
+
__array_namespace_info__.default_dtypes,
|
| 232 |
+
__array_namespace_info__.devices
|
| 233 |
+
|
| 234 |
+
Examples
|
| 235 |
+
--------
|
| 236 |
+
>>> info = np.__array_namespace_info__()
|
| 237 |
+
>>> info.dtypes(kind='signed integer')
|
| 238 |
+
{'int8': numpy.int8,
|
| 239 |
+
'int16': numpy.int16,
|
| 240 |
+
'int32': numpy.int32,
|
| 241 |
+
'int64': numpy.int64}
|
| 242 |
+
|
| 243 |
+
"""
|
| 244 |
+
if device not in ["cpu", None]:
|
| 245 |
+
raise ValueError(
|
| 246 |
+
'Device not understood. Only "cpu" is allowed, but received:'
|
| 247 |
+
f' {device}'
|
| 248 |
+
)
|
| 249 |
+
if kind is None:
|
| 250 |
+
return {
|
| 251 |
+
"bool": dtype(bool),
|
| 252 |
+
"int8": dtype(int8),
|
| 253 |
+
"int16": dtype(int16),
|
| 254 |
+
"int32": dtype(int32),
|
| 255 |
+
"int64": dtype(int64),
|
| 256 |
+
"uint8": dtype(uint8),
|
| 257 |
+
"uint16": dtype(uint16),
|
| 258 |
+
"uint32": dtype(uint32),
|
| 259 |
+
"uint64": dtype(uint64),
|
| 260 |
+
"float32": dtype(float32),
|
| 261 |
+
"float64": dtype(float64),
|
| 262 |
+
"complex64": dtype(complex64),
|
| 263 |
+
"complex128": dtype(complex128),
|
| 264 |
+
}
|
| 265 |
+
if kind == "bool":
|
| 266 |
+
return {"bool": bool}
|
| 267 |
+
if kind == "signed integer":
|
| 268 |
+
return {
|
| 269 |
+
"int8": dtype(int8),
|
| 270 |
+
"int16": dtype(int16),
|
| 271 |
+
"int32": dtype(int32),
|
| 272 |
+
"int64": dtype(int64),
|
| 273 |
+
}
|
| 274 |
+
if kind == "unsigned integer":
|
| 275 |
+
return {
|
| 276 |
+
"uint8": dtype(uint8),
|
| 277 |
+
"uint16": dtype(uint16),
|
| 278 |
+
"uint32": dtype(uint32),
|
| 279 |
+
"uint64": dtype(uint64),
|
| 280 |
+
}
|
| 281 |
+
if kind == "integral":
|
| 282 |
+
return {
|
| 283 |
+
"int8": dtype(int8),
|
| 284 |
+
"int16": dtype(int16),
|
| 285 |
+
"int32": dtype(int32),
|
| 286 |
+
"int64": dtype(int64),
|
| 287 |
+
"uint8": dtype(uint8),
|
| 288 |
+
"uint16": dtype(uint16),
|
| 289 |
+
"uint32": dtype(uint32),
|
| 290 |
+
"uint64": dtype(uint64),
|
| 291 |
+
}
|
| 292 |
+
if kind == "real floating":
|
| 293 |
+
return {
|
| 294 |
+
"float32": dtype(float32),
|
| 295 |
+
"float64": dtype(float64),
|
| 296 |
+
}
|
| 297 |
+
if kind == "complex floating":
|
| 298 |
+
return {
|
| 299 |
+
"complex64": dtype(complex64),
|
| 300 |
+
"complex128": dtype(complex128),
|
| 301 |
+
}
|
| 302 |
+
if kind == "numeric":
|
| 303 |
+
return {
|
| 304 |
+
"int8": dtype(int8),
|
| 305 |
+
"int16": dtype(int16),
|
| 306 |
+
"int32": dtype(int32),
|
| 307 |
+
"int64": dtype(int64),
|
| 308 |
+
"uint8": dtype(uint8),
|
| 309 |
+
"uint16": dtype(uint16),
|
| 310 |
+
"uint32": dtype(uint32),
|
| 311 |
+
"uint64": dtype(uint64),
|
| 312 |
+
"float32": dtype(float32),
|
| 313 |
+
"float64": dtype(float64),
|
| 314 |
+
"complex64": dtype(complex64),
|
| 315 |
+
"complex128": dtype(complex128),
|
| 316 |
+
}
|
| 317 |
+
if isinstance(kind, tuple):
|
| 318 |
+
res = {}
|
| 319 |
+
for k in kind:
|
| 320 |
+
res.update(self.dtypes(kind=k))
|
| 321 |
+
return res
|
| 322 |
+
raise ValueError(f"unsupported kind: {kind!r}")
|
| 323 |
+
|
| 324 |
+
def devices(self):
|
| 325 |
+
"""
|
| 326 |
+
The devices supported by NumPy.
|
| 327 |
+
|
| 328 |
+
For NumPy, this always returns ``('cpu',)``.
|
| 329 |
+
|
| 330 |
+
Returns
|
| 331 |
+
-------
|
| 332 |
+
devices : list of str
|
| 333 |
+
The devices supported by NumPy.
|
| 334 |
+
|
| 335 |
+
See Also
|
| 336 |
+
--------
|
| 337 |
+
__array_namespace_info__.capabilities,
|
| 338 |
+
__array_namespace_info__.default_device,
|
| 339 |
+
__array_namespace_info__.default_dtypes,
|
| 340 |
+
__array_namespace_info__.dtypes
|
| 341 |
+
|
| 342 |
+
Examples
|
| 343 |
+
--------
|
| 344 |
+
>>> info = np.__array_namespace_info__()
|
| 345 |
+
>>> info.devices()
|
| 346 |
+
('cpu',)
|
| 347 |
+
|
| 348 |
+
"""
|
| 349 |
+
return ("cpu",)
|
v12x/pylib/numpy/_configtool.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import sys
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
from .lib._utils_impl import get_include
|
| 6 |
+
from .version import __version__
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def main() -> None:
|
| 10 |
+
parser = argparse.ArgumentParser()
|
| 11 |
+
parser.add_argument(
|
| 12 |
+
"--version",
|
| 13 |
+
action="version",
|
| 14 |
+
version=__version__,
|
| 15 |
+
help="Print the version and exit.",
|
| 16 |
+
)
|
| 17 |
+
parser.add_argument(
|
| 18 |
+
"--cflags",
|
| 19 |
+
action="store_true",
|
| 20 |
+
help="Compile flag needed when using the NumPy headers.",
|
| 21 |
+
)
|
| 22 |
+
parser.add_argument(
|
| 23 |
+
"--pkgconfigdir",
|
| 24 |
+
action="store_true",
|
| 25 |
+
help=("Print the pkgconfig directory in which `numpy.pc` is stored "
|
| 26 |
+
"(useful for setting $PKG_CONFIG_PATH)."),
|
| 27 |
+
)
|
| 28 |
+
args = parser.parse_args()
|
| 29 |
+
if not sys.argv[1:]:
|
| 30 |
+
parser.print_help()
|
| 31 |
+
if args.cflags:
|
| 32 |
+
print("-I" + get_include())
|
| 33 |
+
if args.pkgconfigdir:
|
| 34 |
+
_path = Path(get_include()) / '..' / 'lib' / 'pkgconfig'
|
| 35 |
+
print(_path.resolve())
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
if __name__ == "__main__":
|
| 39 |
+
main()
|
v12x/pylib/numpy/_core/__init__.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Contains the core of NumPy: ndarray, ufuncs, dtypes, etc.
|
| 3 |
+
|
| 4 |
+
Please note that this module is private. All functions and objects
|
| 5 |
+
are available in the main ``numpy`` namespace - use that instead.
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import os
|
| 10 |
+
|
| 11 |
+
from numpy.version import version as __version__
|
| 12 |
+
|
| 13 |
+
# disables OpenBLAS affinity setting of the main thread that limits
|
| 14 |
+
# python threads or processes to one core
|
| 15 |
+
env_added = []
|
| 16 |
+
for envkey in ['OPENBLAS_MAIN_FREE']:
|
| 17 |
+
if envkey not in os.environ:
|
| 18 |
+
# Note: using `putenv` (and `unsetenv` further down) instead of updating
|
| 19 |
+
# `os.environ` on purpose to avoid a race condition, see gh-30627.
|
| 20 |
+
os.putenv(envkey, '1')
|
| 21 |
+
env_added.append(envkey)
|
| 22 |
+
|
| 23 |
+
try:
|
| 24 |
+
from . import multiarray
|
| 25 |
+
except ImportError as exc:
|
| 26 |
+
import sys
|
| 27 |
+
|
| 28 |
+
# Bypass for the module re-initialization opt-out
|
| 29 |
+
if exc.msg == "cannot load module more than once per process":
|
| 30 |
+
raise
|
| 31 |
+
|
| 32 |
+
# Basically always, the problem should be that the C module is wrong/missing...
|
| 33 |
+
if (
|
| 34 |
+
isinstance(exc, ModuleNotFoundError)
|
| 35 |
+
and exc.name == "numpy._core._multiarray_umath"
|
| 36 |
+
):
|
| 37 |
+
import sys
|
| 38 |
+
candidates = []
|
| 39 |
+
for path in __path__:
|
| 40 |
+
candidates.extend(
|
| 41 |
+
f for f in os.listdir(path) if f.startswith("_multiarray_umath"))
|
| 42 |
+
if len(candidates) == 0:
|
| 43 |
+
bad_c_module_info = (
|
| 44 |
+
"We found no compiled module, did NumPy build successfully?\n")
|
| 45 |
+
else:
|
| 46 |
+
candidate_str = '\n * '.join(candidates)
|
| 47 |
+
# cache_tag is documented to be possibly None, so just use name if it is
|
| 48 |
+
# this guesses at cache_tag being the same as the extension module scheme
|
| 49 |
+
tag = sys.implementation.cache_tag or sys.implementation.name
|
| 50 |
+
bad_c_module_info = (
|
| 51 |
+
f"The following compiled module files exist, but seem incompatible\n"
|
| 52 |
+
f"with with either python '{tag}' or the "
|
| 53 |
+
f"platform '{sys.platform}':\n\n * {candidate_str}\n"
|
| 54 |
+
)
|
| 55 |
+
else:
|
| 56 |
+
bad_c_module_info = ""
|
| 57 |
+
|
| 58 |
+
major, minor, *_ = sys.version_info
|
| 59 |
+
msg = f"""
|
| 60 |
+
|
| 61 |
+
IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!
|
| 62 |
+
|
| 63 |
+
Importing the numpy C-extensions failed. This error can happen for
|
| 64 |
+
many reasons, often due to issues with your setup or how NumPy was
|
| 65 |
+
installed.
|
| 66 |
+
{bad_c_module_info}
|
| 67 |
+
We have compiled some common reasons and troubleshooting tips at:
|
| 68 |
+
|
| 69 |
+
https://numpy.org/devdocs/user/troubleshooting-importerror.html
|
| 70 |
+
|
| 71 |
+
Please note and check the following:
|
| 72 |
+
|
| 73 |
+
* The Python version is: Python {major}.{minor} from "{sys.executable}"
|
| 74 |
+
* The NumPy version is: "{__version__}"
|
| 75 |
+
|
| 76 |
+
and make sure that they are the versions you expect.
|
| 77 |
+
|
| 78 |
+
Please carefully study the information and documentation linked above.
|
| 79 |
+
This is unlikely to be a NumPy issue but will be caused by a bad install
|
| 80 |
+
or environment on your machine.
|
| 81 |
+
|
| 82 |
+
Original error was: {exc}
|
| 83 |
+
"""
|
| 84 |
+
|
| 85 |
+
raise ImportError(msg) from exc
|
| 86 |
+
finally:
|
| 87 |
+
for envkey in env_added:
|
| 88 |
+
os.unsetenv(envkey)
|
| 89 |
+
del envkey
|
| 90 |
+
del env_added
|
| 91 |
+
del os
|
| 92 |
+
|
| 93 |
+
from . import umath
|
| 94 |
+
|
| 95 |
+
# Check that multiarray,umath are pure python modules wrapping
|
| 96 |
+
# _multiarray_umath and not either of the old c-extension modules
|
| 97 |
+
if not (hasattr(multiarray, '_multiarray_umath') and
|
| 98 |
+
hasattr(umath, '_multiarray_umath')):
|
| 99 |
+
import sys
|
| 100 |
+
path = sys.modules['numpy'].__path__
|
| 101 |
+
msg = ("Something is wrong with the numpy installation. "
|
| 102 |
+
"While importing we detected an older version of "
|
| 103 |
+
"numpy in {}. One method of fixing this is to repeatedly uninstall "
|
| 104 |
+
"numpy until none is found, then reinstall this version.")
|
| 105 |
+
raise ImportError(msg.format(path))
|
| 106 |
+
|
| 107 |
+
from . import numerictypes as nt
|
| 108 |
+
from .numerictypes import sctypeDict, sctypes
|
| 109 |
+
|
| 110 |
+
multiarray.set_typeDict(nt.sctypeDict)
|
| 111 |
+
from . import einsumfunc, fromnumeric, function_base, getlimits, numeric, shape_base
|
| 112 |
+
from .einsumfunc import *
|
| 113 |
+
from .fromnumeric import *
|
| 114 |
+
from .function_base import *
|
| 115 |
+
from .getlimits import *
|
| 116 |
+
|
| 117 |
+
# Note: module name memmap is overwritten by a class with same name
|
| 118 |
+
from .memmap import *
|
| 119 |
+
from .numeric import *
|
| 120 |
+
from .records import recarray, record
|
| 121 |
+
from .shape_base import *
|
| 122 |
+
|
| 123 |
+
del nt
|
| 124 |
+
|
| 125 |
+
# do this after everything else, to minimize the chance of this misleadingly
|
| 126 |
+
# appearing in an import-time traceback
|
| 127 |
+
# add these for module-freeze analysis (like PyInstaller)
|
| 128 |
+
from . import (
|
| 129 |
+
_add_newdocs,
|
| 130 |
+
_add_newdocs_scalars,
|
| 131 |
+
_dtype,
|
| 132 |
+
_dtype_ctypes,
|
| 133 |
+
_internal,
|
| 134 |
+
_methods,
|
| 135 |
+
)
|
| 136 |
+
from .numeric import absolute as abs
|
| 137 |
+
|
| 138 |
+
acos = numeric.arccos
|
| 139 |
+
acosh = numeric.arccosh
|
| 140 |
+
asin = numeric.arcsin
|
| 141 |
+
asinh = numeric.arcsinh
|
| 142 |
+
atan = numeric.arctan
|
| 143 |
+
atanh = numeric.arctanh
|
| 144 |
+
atan2 = numeric.arctan2
|
| 145 |
+
concat = numeric.concatenate
|
| 146 |
+
bitwise_left_shift = numeric.left_shift
|
| 147 |
+
bitwise_invert = numeric.invert
|
| 148 |
+
bitwise_right_shift = numeric.right_shift
|
| 149 |
+
permute_dims = numeric.transpose
|
| 150 |
+
pow = numeric.power
|
| 151 |
+
|
| 152 |
+
__all__ = [
|
| 153 |
+
"abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2",
|
| 154 |
+
"bitwise_invert", "bitwise_left_shift", "bitwise_right_shift", "concat",
|
| 155 |
+
"pow", "permute_dims", "memmap", "sctypeDict", "record", "recarray"
|
| 156 |
+
]
|
| 157 |
+
__all__ += numeric.__all__
|
| 158 |
+
__all__ += function_base.__all__
|
| 159 |
+
__all__ += getlimits.__all__
|
| 160 |
+
__all__ += shape_base.__all__
|
| 161 |
+
__all__ += einsumfunc.__all__
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def _ufunc_reduce(func):
|
| 165 |
+
# Report the `__name__`. pickle will try to find the module. Note that
|
| 166 |
+
# pickle supports for this `__name__` to be a `__qualname__`. It may
|
| 167 |
+
# make sense to add a `__qualname__` to ufuncs, to allow this more
|
| 168 |
+
# explicitly (Numba has ufuncs as attributes).
|
| 169 |
+
# See also: https://github.com/dask/distributed/issues/3450
|
| 170 |
+
return func.__name__
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def _DType_reconstruct(scalar_type):
|
| 174 |
+
# This is a work-around to pickle type(np.dtype(np.float64)), etc.
|
| 175 |
+
# and it should eventually be replaced with a better solution, e.g. when
|
| 176 |
+
# DTypes become HeapTypes.
|
| 177 |
+
return type(dtype(scalar_type))
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def _DType_reduce(DType):
|
| 181 |
+
# As types/classes, most DTypes can simply be pickled by their name:
|
| 182 |
+
if not DType._legacy or DType.__module__ == "numpy.dtypes":
|
| 183 |
+
return DType.__name__
|
| 184 |
+
|
| 185 |
+
# However, user defined legacy dtypes (like rational) do not end up in
|
| 186 |
+
# `numpy.dtypes` as module and do not have a public class at all.
|
| 187 |
+
# For these, we pickle them by reconstructing them from the scalar type:
|
| 188 |
+
scalar_type = DType.type
|
| 189 |
+
return _DType_reconstruct, (scalar_type,)
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
import copyreg
|
| 193 |
+
|
| 194 |
+
copyreg.pickle(ufunc, _ufunc_reduce)
|
| 195 |
+
copyreg.pickle(type(dtype), _DType_reduce, _DType_reconstruct)
|
| 196 |
+
|
| 197 |
+
# Unclutter namespace (must keep _*_reconstruct for unpickling)
|
| 198 |
+
del copyreg, _ufunc_reduce, _DType_reduce
|
| 199 |
+
|
| 200 |
+
from numpy._pytesttester import PytestTester
|
| 201 |
+
|
| 202 |
+
test = PytestTester(__name__)
|
| 203 |
+
del PytestTester
|
v12x/pylib/numpy/_core/_add_newdocs.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
v12x/pylib/numpy/_core/_add_newdocs_scalars.py
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This file is separate from ``_add_newdocs.py`` so that it can be mocked out by
|
| 3 |
+
our sphinx ``conf.py`` during doc builds, where we want to avoid showing
|
| 4 |
+
platform-dependent information.
|
| 5 |
+
"""
|
| 6 |
+
import os
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
from numpy._core import dtype, numerictypes as _numerictypes
|
| 10 |
+
from numpy._core.function_base import add_newdoc
|
| 11 |
+
|
| 12 |
+
##############################################################################
|
| 13 |
+
#
|
| 14 |
+
# Documentation for concrete scalar classes
|
| 15 |
+
#
|
| 16 |
+
##############################################################################
|
| 17 |
+
|
| 18 |
+
def numeric_type_aliases(aliases):
|
| 19 |
+
def type_aliases_gen():
|
| 20 |
+
for alias, doc in aliases:
|
| 21 |
+
try:
|
| 22 |
+
alias_type = getattr(_numerictypes, alias)
|
| 23 |
+
except AttributeError:
|
| 24 |
+
# The set of aliases that actually exist varies between platforms
|
| 25 |
+
pass
|
| 26 |
+
else:
|
| 27 |
+
yield (alias_type, alias, doc)
|
| 28 |
+
return list(type_aliases_gen())
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
possible_aliases = numeric_type_aliases([
|
| 32 |
+
('int8', '8-bit signed integer (``-128`` to ``127``)'),
|
| 33 |
+
('int16', '16-bit signed integer (``-32_768`` to ``32_767``)'),
|
| 34 |
+
('int32', '32-bit signed integer (``-2_147_483_648`` to ``2_147_483_647``)'),
|
| 35 |
+
('int64', '64-bit signed integer (``-9_223_372_036_854_775_808`` to ``9_223_372_036_854_775_807``)'),
|
| 36 |
+
('intp', 'Signed integer large enough to fit pointer, compatible with C ``intptr_t``'),
|
| 37 |
+
('uint8', '8-bit unsigned integer (``0`` to ``255``)'),
|
| 38 |
+
('uint16', '16-bit unsigned integer (``0`` to ``65_535``)'),
|
| 39 |
+
('uint32', '32-bit unsigned integer (``0`` to ``4_294_967_295``)'),
|
| 40 |
+
('uint64', '64-bit unsigned integer (``0`` to ``18_446_744_073_709_551_615``)'),
|
| 41 |
+
('uintp', 'Unsigned integer large enough to fit pointer, compatible with C ``uintptr_t``'),
|
| 42 |
+
('float16', '16-bit-precision floating-point number type: sign bit, 5 bits exponent, 10 bits mantissa'),
|
| 43 |
+
('float32', '32-bit-precision floating-point number type: sign bit, 8 bits exponent, 23 bits mantissa'),
|
| 44 |
+
('float64', '64-bit precision floating-point number type: sign bit, 11 bits exponent, 52 bits mantissa'),
|
| 45 |
+
('float96', '96-bit extended-precision floating-point number type'),
|
| 46 |
+
('float128', '128-bit extended-precision floating-point number type'),
|
| 47 |
+
('complex64', 'Complex number type composed of 2 32-bit-precision floating-point numbers'),
|
| 48 |
+
('complex128', 'Complex number type composed of 2 64-bit-precision floating-point numbers'),
|
| 49 |
+
('complex192', 'Complex number type composed of 2 96-bit extended-precision floating-point numbers'),
|
| 50 |
+
('complex256', 'Complex number type composed of 2 128-bit extended-precision floating-point numbers'),
|
| 51 |
+
])
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def _get_platform_and_machine():
|
| 55 |
+
try:
|
| 56 |
+
system, _, _, _, machine = os.uname()
|
| 57 |
+
except AttributeError:
|
| 58 |
+
system = sys.platform
|
| 59 |
+
if system == 'win32':
|
| 60 |
+
machine = os.environ.get('PROCESSOR_ARCHITEW6432', '') \
|
| 61 |
+
or os.environ.get('PROCESSOR_ARCHITECTURE', '')
|
| 62 |
+
else:
|
| 63 |
+
machine = 'unknown'
|
| 64 |
+
return system, machine
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
_system, _machine = _get_platform_and_machine()
|
| 68 |
+
_doc_alias_string = f":Alias on this platform ({_system} {_machine}):"
|
| 69 |
+
|
| 70 |
+
# docstring prefix that cpython uses to populate `__text_signature__`
|
| 71 |
+
_ARGUMENT_CLINIC_TEMPLATE = """{name}{signature}
|
| 72 |
+
--
|
| 73 |
+
|
| 74 |
+
{docstring}"""
|
| 75 |
+
|
| 76 |
+
def add_newdoc_for_scalar_type(name: str, text_signature: str, doc: str) -> None:
|
| 77 |
+
# note: `:field: value` is rST syntax which renders as field lists.
|
| 78 |
+
cls = getattr(_numerictypes, name)
|
| 79 |
+
module = cls.__module__
|
| 80 |
+
|
| 81 |
+
lines_extra = [
|
| 82 |
+
"", # blank line after main doc
|
| 83 |
+
f":Character code: ``{dtype(cls).char!r}``",
|
| 84 |
+
]
|
| 85 |
+
|
| 86 |
+
if name != cls.__name__:
|
| 87 |
+
lines_extra.append(f":Canonical name: `{module}.{name}`")
|
| 88 |
+
|
| 89 |
+
lines_extra.extend(
|
| 90 |
+
f"{_doc_alias_string} `{module}.{alias}`: {doc}."
|
| 91 |
+
for alias_type, alias, doc in possible_aliases
|
| 92 |
+
if alias_type is cls
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
docstring = _ARGUMENT_CLINIC_TEMPLATE.format(
|
| 96 |
+
name=cls.__name__, # must match the class name
|
| 97 |
+
signature=text_signature,
|
| 98 |
+
docstring="\n".join([doc.strip(), *lines_extra]),
|
| 99 |
+
)
|
| 100 |
+
add_newdoc('numpy._core.numerictypes', name, docstring)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
for bool_name in ('bool', 'bool_'):
|
| 104 |
+
add_newdoc_for_scalar_type(bool_name, '(value=False, /)', """
|
| 105 |
+
Boolean type (True or False), stored as a byte.
|
| 106 |
+
|
| 107 |
+
.. warning::
|
| 108 |
+
|
| 109 |
+
The :class:`bool` type is not a subclass of the :class:`int_` type
|
| 110 |
+
(the :class:`bool` is not even a number type). This is different
|
| 111 |
+
than Python's default implementation of :class:`bool` as a
|
| 112 |
+
sub-class of :class:`int`.
|
| 113 |
+
""")
|
| 114 |
+
|
| 115 |
+
add_newdoc_for_scalar_type('byte', '(value=0, /)', """
|
| 116 |
+
Signed integer type, compatible with C ``char``.
|
| 117 |
+
""")
|
| 118 |
+
|
| 119 |
+
add_newdoc_for_scalar_type('short', '(value=0, /)', """
|
| 120 |
+
Signed integer type, compatible with C ``short``.
|
| 121 |
+
""")
|
| 122 |
+
|
| 123 |
+
add_newdoc_for_scalar_type('intc', '(value=0, /)', """
|
| 124 |
+
Signed integer type, compatible with C ``int``.
|
| 125 |
+
""")
|
| 126 |
+
|
| 127 |
+
add_newdoc_for_scalar_type('long', '(value=0, /)', """
|
| 128 |
+
Signed integer type, compatible with C ``long``.
|
| 129 |
+
""")
|
| 130 |
+
|
| 131 |
+
# TODO: These docs probably need an if to highlight the default rather than
|
| 132 |
+
# the C-types (and be correct).
|
| 133 |
+
add_newdoc_for_scalar_type('int_', '(value=0, /)', """
|
| 134 |
+
Default signed integer type, 64bit on 64bit systems and 32bit on 32bit systems.
|
| 135 |
+
""")
|
| 136 |
+
|
| 137 |
+
add_newdoc_for_scalar_type('longlong', '(value=0, /)', """
|
| 138 |
+
Signed integer type, compatible with C ``long long``.
|
| 139 |
+
""")
|
| 140 |
+
|
| 141 |
+
add_newdoc_for_scalar_type('ubyte', '(value=0, /)', """
|
| 142 |
+
Unsigned integer type, compatible with C ``unsigned char``.
|
| 143 |
+
""")
|
| 144 |
+
|
| 145 |
+
add_newdoc_for_scalar_type('ushort', '(value=0, /)', """
|
| 146 |
+
Unsigned integer type, compatible with C ``unsigned short``.
|
| 147 |
+
""")
|
| 148 |
+
|
| 149 |
+
add_newdoc_for_scalar_type('uintc', '(value=0, /)', """
|
| 150 |
+
Unsigned integer type, compatible with C ``unsigned int``.
|
| 151 |
+
""")
|
| 152 |
+
|
| 153 |
+
add_newdoc_for_scalar_type('uint', '(value=0, /)', """
|
| 154 |
+
Unsigned signed integer type, 64bit on 64bit systems and 32bit on 32bit systems.
|
| 155 |
+
""")
|
| 156 |
+
|
| 157 |
+
add_newdoc_for_scalar_type('ulong', '(value=0, /)', """
|
| 158 |
+
Unsigned integer type, compatible with C ``unsigned long``.
|
| 159 |
+
""")
|
| 160 |
+
|
| 161 |
+
add_newdoc_for_scalar_type('ulonglong', '(value=0, /)', """
|
| 162 |
+
Unsigned integer type, compatible with C ``unsigned long long``.
|
| 163 |
+
""")
|
| 164 |
+
|
| 165 |
+
add_newdoc_for_scalar_type('half', '(value=0, /)', """
|
| 166 |
+
Half-precision floating-point number type.
|
| 167 |
+
""")
|
| 168 |
+
|
| 169 |
+
add_newdoc_for_scalar_type('single', '(value=0, /)', """
|
| 170 |
+
Single-precision floating-point number type, compatible with C ``float``.
|
| 171 |
+
""")
|
| 172 |
+
|
| 173 |
+
add_newdoc_for_scalar_type('double', '(value=0, /)', """
|
| 174 |
+
Double-precision floating-point number type, compatible with Python :class:`float` and C ``double``.
|
| 175 |
+
""")
|
| 176 |
+
|
| 177 |
+
add_newdoc_for_scalar_type('longdouble', '(value=0, /)', """
|
| 178 |
+
Extended-precision floating-point number type, compatible with C ``long double``
|
| 179 |
+
but not necessarily with IEEE 754 quadruple-precision.
|
| 180 |
+
""")
|
| 181 |
+
|
| 182 |
+
add_newdoc_for_scalar_type('csingle', '(real=0, imag=0, /)', """
|
| 183 |
+
Complex number type composed of two single-precision floating-point numbers.
|
| 184 |
+
""")
|
| 185 |
+
|
| 186 |
+
add_newdoc_for_scalar_type('cdouble', '(real=0, imag=0, /)', """
|
| 187 |
+
Complex number type composed of two double-precision floating-point numbers,
|
| 188 |
+
compatible with Python :class:`complex`.
|
| 189 |
+
""")
|
| 190 |
+
|
| 191 |
+
add_newdoc_for_scalar_type('clongdouble', '(real=0, imag=0, /)', """
|
| 192 |
+
Complex number type composed of two extended-precision floating-point numbers.
|
| 193 |
+
""")
|
| 194 |
+
|
| 195 |
+
add_newdoc_for_scalar_type('object_', '(value=None, /)', """
|
| 196 |
+
Any Python object.
|
| 197 |
+
""")
|
| 198 |
+
|
| 199 |
+
add_newdoc_for_scalar_type('str_', '(value="", /, *args, **kwargs)', r"""
|
| 200 |
+
A unicode string.
|
| 201 |
+
|
| 202 |
+
This type strips trailing null codepoints.
|
| 203 |
+
|
| 204 |
+
>>> s = np.str_("abc\x00")
|
| 205 |
+
>>> s
|
| 206 |
+
'abc'
|
| 207 |
+
|
| 208 |
+
Unlike the builtin :class:`str`, this supports the
|
| 209 |
+
:ref:`python:bufferobjects`, exposing its contents as UCS4:
|
| 210 |
+
|
| 211 |
+
>>> m = memoryview(np.str_("abc"))
|
| 212 |
+
>>> m.format
|
| 213 |
+
'3w'
|
| 214 |
+
>>> m.tobytes()
|
| 215 |
+
b'a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00'
|
| 216 |
+
""")
|
| 217 |
+
|
| 218 |
+
add_newdoc_for_scalar_type('bytes_', '(value="", /, *args, **kwargs)', r"""
|
| 219 |
+
A byte string.
|
| 220 |
+
|
| 221 |
+
When used in arrays, this type strips trailing null bytes.
|
| 222 |
+
""")
|
| 223 |
+
|
| 224 |
+
add_newdoc_for_scalar_type('void', '(length_or_data, /, dtype=None)', r"""
|
| 225 |
+
np.void(length_or_data, /, dtype=None)
|
| 226 |
+
|
| 227 |
+
Create a new structured or unstructured void scalar.
|
| 228 |
+
|
| 229 |
+
Parameters
|
| 230 |
+
----------
|
| 231 |
+
length_or_data : int, array-like, bytes-like, object
|
| 232 |
+
One of multiple meanings (see notes). The length or
|
| 233 |
+
bytes data of an unstructured void. Or alternatively,
|
| 234 |
+
the data to be stored in the new scalar when `dtype`
|
| 235 |
+
is provided.
|
| 236 |
+
This can be an array-like, in which case an array may
|
| 237 |
+
be returned.
|
| 238 |
+
dtype : dtype, optional
|
| 239 |
+
If provided the dtype of the new scalar. This dtype must
|
| 240 |
+
be "void" dtype (i.e. a structured or unstructured void,
|
| 241 |
+
see also :ref:`defining-structured-types`).
|
| 242 |
+
|
| 243 |
+
.. versionadded:: 1.24
|
| 244 |
+
|
| 245 |
+
Notes
|
| 246 |
+
-----
|
| 247 |
+
For historical reasons and because void scalars can represent both
|
| 248 |
+
arbitrary byte data and structured dtypes, the void constructor
|
| 249 |
+
has three calling conventions:
|
| 250 |
+
|
| 251 |
+
1. ``np.void(5)`` creates a ``dtype="V5"`` scalar filled with five
|
| 252 |
+
``\0`` bytes. The 5 can be a Python or NumPy integer.
|
| 253 |
+
2. ``np.void(b"bytes-like")`` creates a void scalar from the byte string.
|
| 254 |
+
The dtype itemsize will match the byte string length, here ``"V10"``.
|
| 255 |
+
3. When a ``dtype=`` is passed the call is roughly the same as an
|
| 256 |
+
array creation. However, a void scalar rather than array is returned.
|
| 257 |
+
|
| 258 |
+
Please see the examples which show all three different conventions.
|
| 259 |
+
|
| 260 |
+
Examples
|
| 261 |
+
--------
|
| 262 |
+
>>> np.void(5)
|
| 263 |
+
np.void(b'\x00\x00\x00\x00\x00')
|
| 264 |
+
>>> np.void(b'abcd')
|
| 265 |
+
np.void(b'\x61\x62\x63\x64')
|
| 266 |
+
>>> np.void((3.2, b'eggs'), dtype="d,S5")
|
| 267 |
+
np.void((3.2, b'eggs'), dtype=[('f0', '<f8'), ('f1', 'S5')])
|
| 268 |
+
>>> np.void(3, dtype=[('x', np.int8), ('y', np.int8)])
|
| 269 |
+
np.void((3, 3), dtype=[('x', 'i1'), ('y', 'i1')])
|
| 270 |
+
""")
|
| 271 |
+
|
| 272 |
+
add_newdoc_for_scalar_type('datetime64', '(value=None, /, *args)', """
|
| 273 |
+
If created from a 64-bit integer, it represents an offset from ``1970-01-01T00:00:00``.
|
| 274 |
+
If created from string, the string can be in ISO 8601 date or datetime format.
|
| 275 |
+
|
| 276 |
+
When parsing a string to create a datetime object, if the string contains
|
| 277 |
+
a trailing timezone (A 'Z' or a timezone offset), the timezone will be
|
| 278 |
+
dropped and a User Warning is given.
|
| 279 |
+
|
| 280 |
+
Datetime64 objects should be considered to be UTC and therefore have an
|
| 281 |
+
offset of +0000.
|
| 282 |
+
|
| 283 |
+
>>> np.datetime64(10, 'Y')
|
| 284 |
+
np.datetime64('1980')
|
| 285 |
+
>>> np.datetime64('1980', 'Y')
|
| 286 |
+
np.datetime64('1980')
|
| 287 |
+
>>> np.datetime64(10, 'D')
|
| 288 |
+
np.datetime64('1970-01-11')
|
| 289 |
+
|
| 290 |
+
See :ref:`arrays.datetime` for more information.
|
| 291 |
+
""")
|
| 292 |
+
|
| 293 |
+
add_newdoc_for_scalar_type('timedelta64', '(value=0, /, *args)', """
|
| 294 |
+
A timedelta stored as a 64-bit integer.
|
| 295 |
+
|
| 296 |
+
See :ref:`arrays.datetime` for more information.
|
| 297 |
+
""")
|
| 298 |
+
|
| 299 |
+
add_newdoc('numpy._core.numerictypes', "integer", ('is_integer',
|
| 300 |
+
"""
|
| 301 |
+
is_integer($self, /)
|
| 302 |
+
--
|
| 303 |
+
|
| 304 |
+
integer.is_integer() -> bool
|
| 305 |
+
|
| 306 |
+
Return ``True`` if the number is finite with integral value.
|
| 307 |
+
|
| 308 |
+
.. versionadded:: 1.22
|
| 309 |
+
|
| 310 |
+
Examples
|
| 311 |
+
--------
|
| 312 |
+
>>> import numpy as np
|
| 313 |
+
>>> np.int64(-2).is_integer()
|
| 314 |
+
True
|
| 315 |
+
>>> np.uint32(5).is_integer()
|
| 316 |
+
True
|
| 317 |
+
"""))
|
| 318 |
+
|
| 319 |
+
# TODO: work out how to put this on the base class, np.floating
|
| 320 |
+
for float_name in ('half', 'single', 'double', 'longdouble'):
|
| 321 |
+
add_newdoc('numpy._core.numerictypes', float_name, ('as_integer_ratio',
|
| 322 |
+
f"""
|
| 323 |
+
as_integer_ratio($self, /)
|
| 324 |
+
--
|
| 325 |
+
|
| 326 |
+
{float_name}.as_integer_ratio() -> (int, int)
|
| 327 |
+
|
| 328 |
+
Return a pair of integers, whose ratio is exactly equal to the original
|
| 329 |
+
floating point number, and with a positive denominator.
|
| 330 |
+
Raise `OverflowError` on infinities and a `ValueError` on NaNs.
|
| 331 |
+
|
| 332 |
+
>>> np.{float_name}(10.0).as_integer_ratio()
|
| 333 |
+
(10, 1)
|
| 334 |
+
>>> np.{float_name}(0.0).as_integer_ratio()
|
| 335 |
+
(0, 1)
|
| 336 |
+
>>> np.{float_name}(-.25).as_integer_ratio()
|
| 337 |
+
(-1, 4)
|
| 338 |
+
"""))
|
| 339 |
+
|
| 340 |
+
add_newdoc('numpy._core.numerictypes', float_name, ('is_integer',
|
| 341 |
+
f"""
|
| 342 |
+
is_integer($self, /)
|
| 343 |
+
--
|
| 344 |
+
|
| 345 |
+
{float_name}.is_integer() -> bool
|
| 346 |
+
|
| 347 |
+
Return ``True`` if the floating point number is finite with integral
|
| 348 |
+
value, and ``False`` otherwise.
|
| 349 |
+
|
| 350 |
+
.. versionadded:: 1.22
|
| 351 |
+
|
| 352 |
+
Examples
|
| 353 |
+
--------
|
| 354 |
+
>>> np.{float_name}(-2.0).is_integer()
|
| 355 |
+
True
|
| 356 |
+
>>> np.{float_name}(3.2).is_integer()
|
| 357 |
+
False
|
| 358 |
+
"""))
|
| 359 |
+
|
| 360 |
+
for int_name in ('int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32',
|
| 361 |
+
'int64', 'uint64', 'int64', 'uint64', 'int64', 'uint64',
|
| 362 |
+
'longlong', 'ulonglong'):
|
| 363 |
+
# Add negative examples for signed cases by checking typecode
|
| 364 |
+
add_newdoc('numpy._core.numerictypes', int_name, ('bit_count',
|
| 365 |
+
f"""
|
| 366 |
+
bit_count($self, /)
|
| 367 |
+
--
|
| 368 |
+
|
| 369 |
+
{int_name}.bit_count() -> int
|
| 370 |
+
|
| 371 |
+
Computes the number of 1-bits in the absolute value of the input.
|
| 372 |
+
Analogous to the builtin `int.bit_count` or ``popcount`` in C++.
|
| 373 |
+
|
| 374 |
+
Examples
|
| 375 |
+
--------
|
| 376 |
+
>>> np.{int_name}(127).bit_count()
|
| 377 |
+
7""" +
|
| 378 |
+
(f"""
|
| 379 |
+
>>> np.{int_name}(-127).bit_count()
|
| 380 |
+
7
|
| 381 |
+
""" if dtype(int_name).char.islower() else "")))
|
v12x/pylib/numpy/_core/_asarray.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Functions in the ``as*array`` family that promote array-likes into arrays.
|
| 3 |
+
|
| 4 |
+
`require` fits this category despite its name not matching this pattern.
|
| 5 |
+
"""
|
| 6 |
+
from .multiarray import array, asanyarray
|
| 7 |
+
from .overrides import array_function_dispatch, finalize_array_function_like, set_module
|
| 8 |
+
|
| 9 |
+
__all__ = ["require"]
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
POSSIBLE_FLAGS = {
|
| 13 |
+
'C': 'C', 'C_CONTIGUOUS': 'C', 'CONTIGUOUS': 'C',
|
| 14 |
+
'F': 'F', 'F_CONTIGUOUS': 'F', 'FORTRAN': 'F',
|
| 15 |
+
'A': 'A', 'ALIGNED': 'A',
|
| 16 |
+
'W': 'W', 'WRITEABLE': 'W',
|
| 17 |
+
'O': 'O', 'OWNDATA': 'O',
|
| 18 |
+
'E': 'E', 'ENSUREARRAY': 'E'
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@finalize_array_function_like
|
| 23 |
+
@set_module('numpy')
|
| 24 |
+
def require(a, dtype=None, requirements=None, *, like=None):
|
| 25 |
+
"""
|
| 26 |
+
Return an ndarray of the provided type that satisfies requirements.
|
| 27 |
+
|
| 28 |
+
This function is useful to be sure that an array with the correct flags
|
| 29 |
+
is returned for passing to compiled code (perhaps through ctypes).
|
| 30 |
+
|
| 31 |
+
Parameters
|
| 32 |
+
----------
|
| 33 |
+
a : array_like
|
| 34 |
+
The object to be converted to a type-and-requirement-satisfying array.
|
| 35 |
+
dtype : data-type
|
| 36 |
+
The required data-type. If None preserve the current dtype. If your
|
| 37 |
+
application requires the data to be in native byteorder, include
|
| 38 |
+
a byteorder specification as a part of the dtype specification.
|
| 39 |
+
requirements : str or sequence of str
|
| 40 |
+
The requirements list can be any of the following
|
| 41 |
+
|
| 42 |
+
* 'F_CONTIGUOUS' ('F') - ensure a Fortran-contiguous array
|
| 43 |
+
* 'C_CONTIGUOUS' ('C') - ensure a C-contiguous array
|
| 44 |
+
* 'ALIGNED' ('A') - ensure a data-type aligned array
|
| 45 |
+
* 'WRITEABLE' ('W') - ensure a writable array
|
| 46 |
+
* 'OWNDATA' ('O') - ensure an array that owns its own data
|
| 47 |
+
* 'ENSUREARRAY', ('E') - ensure a base array, instead of a subclass
|
| 48 |
+
${ARRAY_FUNCTION_LIKE}
|
| 49 |
+
|
| 50 |
+
.. versionadded:: 1.20.0
|
| 51 |
+
|
| 52 |
+
Returns
|
| 53 |
+
-------
|
| 54 |
+
out : ndarray
|
| 55 |
+
Array with specified requirements and type if given.
|
| 56 |
+
|
| 57 |
+
See Also
|
| 58 |
+
--------
|
| 59 |
+
asarray : Convert input to an ndarray.
|
| 60 |
+
asanyarray : Convert to an ndarray, but pass through ndarray subclasses.
|
| 61 |
+
ascontiguousarray : Convert input to a contiguous array.
|
| 62 |
+
asfortranarray : Convert input to an ndarray with column-major
|
| 63 |
+
memory order.
|
| 64 |
+
ndarray.flags : Information about the memory layout of the array.
|
| 65 |
+
|
| 66 |
+
Notes
|
| 67 |
+
-----
|
| 68 |
+
The returned array will be guaranteed to have the listed requirements
|
| 69 |
+
by making a copy if needed.
|
| 70 |
+
|
| 71 |
+
Examples
|
| 72 |
+
--------
|
| 73 |
+
>>> import numpy as np
|
| 74 |
+
>>> x = np.arange(6).reshape(2,3)
|
| 75 |
+
>>> x.flags
|
| 76 |
+
C_CONTIGUOUS : True
|
| 77 |
+
F_CONTIGUOUS : False
|
| 78 |
+
OWNDATA : False
|
| 79 |
+
WRITEABLE : True
|
| 80 |
+
ALIGNED : True
|
| 81 |
+
WRITEBACKIFCOPY : False
|
| 82 |
+
|
| 83 |
+
>>> y = np.require(x, dtype=np.float32, requirements=['A', 'O', 'W', 'F'])
|
| 84 |
+
>>> y.flags
|
| 85 |
+
C_CONTIGUOUS : False
|
| 86 |
+
F_CONTIGUOUS : True
|
| 87 |
+
OWNDATA : True
|
| 88 |
+
WRITEABLE : True
|
| 89 |
+
ALIGNED : True
|
| 90 |
+
WRITEBACKIFCOPY : False
|
| 91 |
+
|
| 92 |
+
"""
|
| 93 |
+
if like is not None:
|
| 94 |
+
return _require_with_like(
|
| 95 |
+
like,
|
| 96 |
+
a,
|
| 97 |
+
dtype=dtype,
|
| 98 |
+
requirements=requirements,
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
if not requirements:
|
| 102 |
+
return asanyarray(a, dtype=dtype)
|
| 103 |
+
|
| 104 |
+
requirements = {POSSIBLE_FLAGS[x.upper()] for x in requirements}
|
| 105 |
+
|
| 106 |
+
if 'E' in requirements:
|
| 107 |
+
requirements.remove('E')
|
| 108 |
+
subok = False
|
| 109 |
+
else:
|
| 110 |
+
subok = True
|
| 111 |
+
|
| 112 |
+
order = 'A'
|
| 113 |
+
if requirements >= {'C', 'F'}:
|
| 114 |
+
raise ValueError('Cannot specify both "C" and "F" order')
|
| 115 |
+
elif 'F' in requirements:
|
| 116 |
+
order = 'F'
|
| 117 |
+
requirements.remove('F')
|
| 118 |
+
elif 'C' in requirements:
|
| 119 |
+
order = 'C'
|
| 120 |
+
requirements.remove('C')
|
| 121 |
+
|
| 122 |
+
arr = array(a, dtype=dtype, order=order, copy=None, subok=subok)
|
| 123 |
+
|
| 124 |
+
for prop in requirements:
|
| 125 |
+
if not arr.flags[prop]:
|
| 126 |
+
return arr.copy(order)
|
| 127 |
+
return arr
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
_require_with_like = array_function_dispatch()(require)
|
v12x/pylib/numpy/_core/_dtype.py
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
A place for code to be called from the implementation of np.dtype
|
| 3 |
+
|
| 4 |
+
String handling is much easier to do correctly in python.
|
| 5 |
+
"""
|
| 6 |
+
import numpy as np
|
| 7 |
+
|
| 8 |
+
_kind_to_stem = {
|
| 9 |
+
'u': 'uint',
|
| 10 |
+
'i': 'int',
|
| 11 |
+
'c': 'complex',
|
| 12 |
+
'f': 'float',
|
| 13 |
+
'b': 'bool',
|
| 14 |
+
'V': 'void',
|
| 15 |
+
'O': 'object',
|
| 16 |
+
'M': 'datetime',
|
| 17 |
+
'm': 'timedelta',
|
| 18 |
+
'S': 'bytes',
|
| 19 |
+
'U': 'str',
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _kind_name(dtype):
|
| 24 |
+
try:
|
| 25 |
+
return _kind_to_stem[dtype.kind]
|
| 26 |
+
except KeyError as e:
|
| 27 |
+
raise RuntimeError(
|
| 28 |
+
f"internal dtype error, unknown kind {dtype.kind!r}"
|
| 29 |
+
) from None
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def __str__(dtype):
|
| 33 |
+
if dtype.fields is not None:
|
| 34 |
+
return _struct_str(dtype, include_align=True)
|
| 35 |
+
elif dtype.subdtype:
|
| 36 |
+
return _subarray_str(dtype)
|
| 37 |
+
elif issubclass(dtype.type, np.flexible) or not dtype.isnative:
|
| 38 |
+
return dtype.str
|
| 39 |
+
else:
|
| 40 |
+
return dtype.name
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def __repr__(dtype):
|
| 44 |
+
arg_str = _construction_repr(dtype, include_align=False)
|
| 45 |
+
if dtype.isalignedstruct:
|
| 46 |
+
arg_str = arg_str + ", align=True"
|
| 47 |
+
return f"dtype({arg_str})"
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def _unpack_field(dtype, offset, title=None):
|
| 51 |
+
"""
|
| 52 |
+
Helper function to normalize the items in dtype.fields.
|
| 53 |
+
|
| 54 |
+
Call as:
|
| 55 |
+
|
| 56 |
+
dtype, offset, title = _unpack_field(*dtype.fields[name])
|
| 57 |
+
"""
|
| 58 |
+
return dtype, offset, title
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def _isunsized(dtype):
|
| 62 |
+
# PyDataType_ISUNSIZED
|
| 63 |
+
return dtype.itemsize == 0
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def _construction_repr(dtype, include_align=False, short=False):
|
| 67 |
+
"""
|
| 68 |
+
Creates a string repr of the dtype, excluding the 'dtype()' part
|
| 69 |
+
surrounding the object. This object may be a string, a list, or
|
| 70 |
+
a dict depending on the nature of the dtype. This
|
| 71 |
+
is the object passed as the first parameter to the dtype
|
| 72 |
+
constructor, and if no additional constructor parameters are
|
| 73 |
+
given, will reproduce the exact memory layout.
|
| 74 |
+
|
| 75 |
+
Parameters
|
| 76 |
+
----------
|
| 77 |
+
short : bool
|
| 78 |
+
If true, this creates a shorter repr using 'kind' and 'itemsize',
|
| 79 |
+
instead of the longer type name.
|
| 80 |
+
|
| 81 |
+
include_align : bool
|
| 82 |
+
If true, this includes the 'align=True' parameter
|
| 83 |
+
inside the struct dtype construction dict when needed. Use this flag
|
| 84 |
+
if you want a proper repr string without the 'dtype()' part around it.
|
| 85 |
+
|
| 86 |
+
If false, this does not preserve the
|
| 87 |
+
'align=True' parameter or sticky NPY_ALIGNED_STRUCT flag for
|
| 88 |
+
struct arrays like the regular repr does, because the 'align'
|
| 89 |
+
flag is not part of first dtype constructor parameter. This
|
| 90 |
+
mode is intended for a full 'repr', where the 'align=True' is
|
| 91 |
+
provided as the second parameter.
|
| 92 |
+
"""
|
| 93 |
+
if dtype.fields is not None:
|
| 94 |
+
return _struct_str(dtype, include_align=include_align)
|
| 95 |
+
elif dtype.subdtype:
|
| 96 |
+
return _subarray_str(dtype)
|
| 97 |
+
else:
|
| 98 |
+
return _scalar_str(dtype, short=short)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def _scalar_str(dtype, short):
|
| 102 |
+
byteorder = _byte_order_str(dtype)
|
| 103 |
+
|
| 104 |
+
if dtype.type == np.bool:
|
| 105 |
+
if short:
|
| 106 |
+
return "'?'"
|
| 107 |
+
else:
|
| 108 |
+
return "'bool'"
|
| 109 |
+
|
| 110 |
+
elif dtype.type == np.object_:
|
| 111 |
+
# The object reference may be different sizes on different
|
| 112 |
+
# platforms, so it should never include the itemsize here.
|
| 113 |
+
return "'O'"
|
| 114 |
+
|
| 115 |
+
elif dtype.type == np.bytes_:
|
| 116 |
+
if _isunsized(dtype):
|
| 117 |
+
return "'S'"
|
| 118 |
+
else:
|
| 119 |
+
return f"'S{dtype.itemsize}'"
|
| 120 |
+
|
| 121 |
+
elif dtype.type == np.str_:
|
| 122 |
+
if _isunsized(dtype):
|
| 123 |
+
return f"'{byteorder}U'"
|
| 124 |
+
else:
|
| 125 |
+
return f"'{byteorder}U{dtype.itemsize // 4}'"
|
| 126 |
+
|
| 127 |
+
elif dtype.type is str:
|
| 128 |
+
return "'T'"
|
| 129 |
+
|
| 130 |
+
elif not type(dtype)._legacy:
|
| 131 |
+
return f"'{byteorder}{type(dtype).__name__}{dtype.itemsize * 8}'"
|
| 132 |
+
|
| 133 |
+
# unlike the other types, subclasses of void are preserved - but
|
| 134 |
+
# historically the repr does not actually reveal the subclass
|
| 135 |
+
elif issubclass(dtype.type, np.void):
|
| 136 |
+
if _isunsized(dtype):
|
| 137 |
+
return "'V'"
|
| 138 |
+
else:
|
| 139 |
+
return f"'V{dtype.itemsize}'"
|
| 140 |
+
|
| 141 |
+
elif dtype.type == np.datetime64:
|
| 142 |
+
return f"'{byteorder}M8{_datetime_metadata_str(dtype)}'"
|
| 143 |
+
|
| 144 |
+
elif dtype.type == np.timedelta64:
|
| 145 |
+
return f"'{byteorder}m8{_datetime_metadata_str(dtype)}'"
|
| 146 |
+
|
| 147 |
+
elif dtype.isbuiltin == 2:
|
| 148 |
+
return dtype.type.__name__
|
| 149 |
+
|
| 150 |
+
elif np.issubdtype(dtype, np.number):
|
| 151 |
+
# Short repr with endianness, like '<f8'
|
| 152 |
+
if short or dtype.byteorder not in ('=', '|'):
|
| 153 |
+
return f"'{byteorder}{dtype.kind}{dtype.itemsize}'"
|
| 154 |
+
|
| 155 |
+
# Longer repr, like 'float64'
|
| 156 |
+
else:
|
| 157 |
+
return f"'{_kind_name(dtype)}{8 * dtype.itemsize}'"
|
| 158 |
+
|
| 159 |
+
else:
|
| 160 |
+
raise RuntimeError(
|
| 161 |
+
"Internal error: NumPy dtype unrecognized type number")
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def _byte_order_str(dtype):
|
| 165 |
+
""" Normalize byteorder to '<' or '>' """
|
| 166 |
+
# hack to obtain the native and swapped byte order characters
|
| 167 |
+
swapped = np.dtype(int).newbyteorder('S')
|
| 168 |
+
native = swapped.newbyteorder('S')
|
| 169 |
+
|
| 170 |
+
byteorder = dtype.byteorder
|
| 171 |
+
if byteorder == '=':
|
| 172 |
+
return native.byteorder
|
| 173 |
+
if byteorder == 'S':
|
| 174 |
+
# TODO: this path can never be reached
|
| 175 |
+
return swapped.byteorder
|
| 176 |
+
elif byteorder == '|':
|
| 177 |
+
return ''
|
| 178 |
+
else:
|
| 179 |
+
return byteorder
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
def _datetime_metadata_str(dtype):
|
| 183 |
+
# TODO: this duplicates the C metastr_to_unicode functionality
|
| 184 |
+
unit, count = np.datetime_data(dtype)
|
| 185 |
+
if unit == 'generic':
|
| 186 |
+
return ''
|
| 187 |
+
elif count == 1:
|
| 188 |
+
return f'[{unit}]'
|
| 189 |
+
else:
|
| 190 |
+
return f'[{count}{unit}]'
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def _struct_dict_str(dtype, includealignedflag):
|
| 194 |
+
# unpack the fields dictionary into ls
|
| 195 |
+
names = dtype.names
|
| 196 |
+
fld_dtypes = []
|
| 197 |
+
offsets = []
|
| 198 |
+
titles = []
|
| 199 |
+
for name in names:
|
| 200 |
+
fld_dtype, offset, title = _unpack_field(*dtype.fields[name])
|
| 201 |
+
fld_dtypes.append(fld_dtype)
|
| 202 |
+
offsets.append(offset)
|
| 203 |
+
titles.append(title)
|
| 204 |
+
|
| 205 |
+
# Build up a string to make the dictionary
|
| 206 |
+
|
| 207 |
+
if np._core.arrayprint._get_legacy_print_mode() <= 121:
|
| 208 |
+
colon = ":"
|
| 209 |
+
fieldsep = ","
|
| 210 |
+
else:
|
| 211 |
+
colon = ": "
|
| 212 |
+
fieldsep = ", "
|
| 213 |
+
|
| 214 |
+
# First, the names
|
| 215 |
+
ret = f"{{'names'{colon}["
|
| 216 |
+
ret += fieldsep.join(repr(name) for name in names)
|
| 217 |
+
|
| 218 |
+
# Second, the formats
|
| 219 |
+
ret += f"], 'formats'{colon}["
|
| 220 |
+
ret += fieldsep.join(
|
| 221 |
+
_construction_repr(fld_dtype, short=True) for fld_dtype in fld_dtypes)
|
| 222 |
+
|
| 223 |
+
# Third, the offsets
|
| 224 |
+
ret += f"], 'offsets'{colon}["
|
| 225 |
+
ret += fieldsep.join(f"{offset}" for offset in offsets)
|
| 226 |
+
|
| 227 |
+
# Fourth, the titles
|
| 228 |
+
if any(title is not None for title in titles):
|
| 229 |
+
ret += f"], 'titles'{colon}["
|
| 230 |
+
ret += fieldsep.join(repr(title) for title in titles)
|
| 231 |
+
|
| 232 |
+
# Fifth, the itemsize
|
| 233 |
+
ret += f"], 'itemsize'{colon}{dtype.itemsize}"
|
| 234 |
+
|
| 235 |
+
if (includealignedflag and dtype.isalignedstruct):
|
| 236 |
+
# Finally, the aligned flag
|
| 237 |
+
ret += f", 'aligned'{colon}True}}"
|
| 238 |
+
else:
|
| 239 |
+
ret += "}"
|
| 240 |
+
|
| 241 |
+
return ret
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def _aligned_offset(offset, alignment):
|
| 245 |
+
# round up offset:
|
| 246 |
+
return - (-offset // alignment) * alignment
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def _is_packed(dtype):
|
| 250 |
+
"""
|
| 251 |
+
Checks whether the structured data type in 'dtype'
|
| 252 |
+
has a simple layout, where all the fields are in order,
|
| 253 |
+
and follow each other with no alignment padding.
|
| 254 |
+
|
| 255 |
+
When this returns true, the dtype can be reconstructed
|
| 256 |
+
from a list of the field names and dtypes with no additional
|
| 257 |
+
dtype parameters.
|
| 258 |
+
|
| 259 |
+
Duplicates the C `is_dtype_struct_simple_unaligned_layout` function.
|
| 260 |
+
"""
|
| 261 |
+
align = dtype.isalignedstruct
|
| 262 |
+
max_alignment = 1
|
| 263 |
+
total_offset = 0
|
| 264 |
+
for name in dtype.names:
|
| 265 |
+
fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name])
|
| 266 |
+
|
| 267 |
+
if align:
|
| 268 |
+
total_offset = _aligned_offset(total_offset, fld_dtype.alignment)
|
| 269 |
+
max_alignment = max(max_alignment, fld_dtype.alignment)
|
| 270 |
+
|
| 271 |
+
if fld_offset != total_offset:
|
| 272 |
+
return False
|
| 273 |
+
total_offset += fld_dtype.itemsize
|
| 274 |
+
|
| 275 |
+
if align:
|
| 276 |
+
total_offset = _aligned_offset(total_offset, max_alignment)
|
| 277 |
+
|
| 278 |
+
return total_offset == dtype.itemsize
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def _struct_list_str(dtype):
|
| 282 |
+
items = []
|
| 283 |
+
for name in dtype.names:
|
| 284 |
+
fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name])
|
| 285 |
+
|
| 286 |
+
item = "("
|
| 287 |
+
if title is not None:
|
| 288 |
+
item += f"({title!r}, {name!r}), "
|
| 289 |
+
else:
|
| 290 |
+
item += f"{name!r}, "
|
| 291 |
+
# Special case subarray handling here
|
| 292 |
+
if fld_dtype.subdtype is not None:
|
| 293 |
+
base, shape = fld_dtype.subdtype
|
| 294 |
+
item += f"{_construction_repr(base, short=True)}, {shape}"
|
| 295 |
+
else:
|
| 296 |
+
item += _construction_repr(fld_dtype, short=True)
|
| 297 |
+
|
| 298 |
+
item += ")"
|
| 299 |
+
items.append(item)
|
| 300 |
+
|
| 301 |
+
return "[" + ", ".join(items) + "]"
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
def _struct_str(dtype, include_align):
|
| 305 |
+
# The list str representation can't include the 'align=' flag,
|
| 306 |
+
# so if it is requested and the struct has the aligned flag set,
|
| 307 |
+
# we must use the dict str instead.
|
| 308 |
+
if not (include_align and dtype.isalignedstruct) and _is_packed(dtype):
|
| 309 |
+
sub = _struct_list_str(dtype)
|
| 310 |
+
|
| 311 |
+
else:
|
| 312 |
+
sub = _struct_dict_str(dtype, include_align)
|
| 313 |
+
|
| 314 |
+
# If the data type isn't the default, void, show it
|
| 315 |
+
if dtype.type != np.void:
|
| 316 |
+
return f"({dtype.type.__module__}.{dtype.type.__name__}, {sub})"
|
| 317 |
+
else:
|
| 318 |
+
return sub
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
def _subarray_str(dtype):
|
| 322 |
+
base, shape = dtype.subdtype
|
| 323 |
+
return f"({_construction_repr(base, short=True)}, {shape})"
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
def _name_includes_bit_suffix(dtype):
|
| 327 |
+
if dtype.type == np.object_:
|
| 328 |
+
# pointer size varies by system, best to omit it
|
| 329 |
+
return False
|
| 330 |
+
elif dtype.type == np.bool:
|
| 331 |
+
# implied
|
| 332 |
+
return False
|
| 333 |
+
elif dtype.type is None:
|
| 334 |
+
return True
|
| 335 |
+
elif np.issubdtype(dtype, np.flexible) and _isunsized(dtype):
|
| 336 |
+
# unspecified
|
| 337 |
+
return False
|
| 338 |
+
else:
|
| 339 |
+
return True
|
| 340 |
+
|
| 341 |
+
|
| 342 |
+
def _name_get(dtype):
|
| 343 |
+
# provides dtype.name.__get__, documented as returning a "bit name"
|
| 344 |
+
|
| 345 |
+
if dtype.isbuiltin == 2:
|
| 346 |
+
# user dtypes don't promise to do anything special
|
| 347 |
+
return dtype.type.__name__
|
| 348 |
+
|
| 349 |
+
if not type(dtype)._legacy:
|
| 350 |
+
name = type(dtype).__name__
|
| 351 |
+
|
| 352 |
+
elif issubclass(dtype.type, np.void):
|
| 353 |
+
# historically, void subclasses preserve their name, eg `record64`
|
| 354 |
+
name = dtype.type.__name__
|
| 355 |
+
else:
|
| 356 |
+
name = _kind_name(dtype)
|
| 357 |
+
|
| 358 |
+
# append bit counts
|
| 359 |
+
if _name_includes_bit_suffix(dtype):
|
| 360 |
+
name += f"{dtype.itemsize * 8}"
|
| 361 |
+
|
| 362 |
+
# append metadata to datetimes
|
| 363 |
+
if dtype.type in (np.datetime64, np.timedelta64):
|
| 364 |
+
name += _datetime_metadata_str(dtype)
|
| 365 |
+
|
| 366 |
+
return name
|
v12x/pylib/numpy/_core/_dtype_ctypes.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Conversion from ctypes to dtype.
|
| 3 |
+
|
| 4 |
+
In an ideal world, we could achieve this through the PEP3118 buffer protocol,
|
| 5 |
+
something like::
|
| 6 |
+
|
| 7 |
+
def dtype_from_ctypes_type(t):
|
| 8 |
+
# needed to ensure that the shape of `t` is within memoryview.format
|
| 9 |
+
class DummyStruct(ctypes.Structure):
|
| 10 |
+
_fields_ = [('a', t)]
|
| 11 |
+
|
| 12 |
+
# empty to avoid memory allocation
|
| 13 |
+
ctype_0 = (DummyStruct * 0)()
|
| 14 |
+
mv = memoryview(ctype_0)
|
| 15 |
+
|
| 16 |
+
# convert the struct, and slice back out the field
|
| 17 |
+
return _dtype_from_pep3118(mv.format)['a']
|
| 18 |
+
|
| 19 |
+
Unfortunately, this fails because:
|
| 20 |
+
|
| 21 |
+
* ctypes cannot handle length-0 arrays with PEP3118 (bpo-32782)
|
| 22 |
+
* PEP3118 cannot represent unions, but both numpy and ctypes can
|
| 23 |
+
* ctypes cannot handle big-endian structs with PEP3118 (bpo-32780)
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
# We delay-import ctypes for distributions that do not include it.
|
| 27 |
+
# While this module is not used unless the user passes in ctypes
|
| 28 |
+
# members, it is eagerly imported from numpy/_core/__init__.py.
|
| 29 |
+
import numpy as np
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def _from_ctypes_array(t):
|
| 33 |
+
return np.dtype((dtype_from_ctypes_type(t._type_), (t._length_,)))
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def _from_ctypes_structure(t):
|
| 37 |
+
for item in t._fields_:
|
| 38 |
+
if len(item) > 2:
|
| 39 |
+
raise TypeError(
|
| 40 |
+
"ctypes bitfields have no dtype equivalent")
|
| 41 |
+
|
| 42 |
+
if hasattr(t, "_pack_"):
|
| 43 |
+
import ctypes
|
| 44 |
+
formats = []
|
| 45 |
+
offsets = []
|
| 46 |
+
names = []
|
| 47 |
+
current_offset = 0
|
| 48 |
+
for fname, ftyp in t._fields_:
|
| 49 |
+
names.append(fname)
|
| 50 |
+
formats.append(dtype_from_ctypes_type(ftyp))
|
| 51 |
+
# Each type has a default offset, this is platform dependent
|
| 52 |
+
# for some types.
|
| 53 |
+
effective_pack = min(t._pack_, ctypes.alignment(ftyp))
|
| 54 |
+
current_offset = (
|
| 55 |
+
(current_offset + effective_pack - 1) // effective_pack
|
| 56 |
+
) * effective_pack
|
| 57 |
+
offsets.append(current_offset)
|
| 58 |
+
current_offset += ctypes.sizeof(ftyp)
|
| 59 |
+
|
| 60 |
+
return np.dtype({
|
| 61 |
+
"formats": formats,
|
| 62 |
+
"offsets": offsets,
|
| 63 |
+
"names": names,
|
| 64 |
+
"itemsize": ctypes.sizeof(t)})
|
| 65 |
+
else:
|
| 66 |
+
fields = []
|
| 67 |
+
for fname, ftyp in t._fields_:
|
| 68 |
+
fields.append((fname, dtype_from_ctypes_type(ftyp)))
|
| 69 |
+
|
| 70 |
+
# by default, ctypes structs are aligned
|
| 71 |
+
return np.dtype(fields, align=True)
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def _from_ctypes_scalar(t):
|
| 75 |
+
"""
|
| 76 |
+
Return the dtype type with endianness included if it's the case
|
| 77 |
+
"""
|
| 78 |
+
if getattr(t, '__ctype_be__', None) is t:
|
| 79 |
+
return np.dtype('>' + t._type_)
|
| 80 |
+
elif getattr(t, '__ctype_le__', None) is t:
|
| 81 |
+
return np.dtype('<' + t._type_)
|
| 82 |
+
else:
|
| 83 |
+
return np.dtype(t._type_)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def _from_ctypes_union(t):
|
| 87 |
+
import ctypes
|
| 88 |
+
formats = []
|
| 89 |
+
offsets = []
|
| 90 |
+
names = []
|
| 91 |
+
for fname, ftyp in t._fields_:
|
| 92 |
+
names.append(fname)
|
| 93 |
+
formats.append(dtype_from_ctypes_type(ftyp))
|
| 94 |
+
offsets.append(0) # Union fields are offset to 0
|
| 95 |
+
|
| 96 |
+
return np.dtype({
|
| 97 |
+
"formats": formats,
|
| 98 |
+
"offsets": offsets,
|
| 99 |
+
"names": names,
|
| 100 |
+
"itemsize": ctypes.sizeof(t)})
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def dtype_from_ctypes_type(t):
|
| 104 |
+
"""
|
| 105 |
+
Construct a dtype object from a ctypes type
|
| 106 |
+
"""
|
| 107 |
+
import _ctypes
|
| 108 |
+
if issubclass(t, _ctypes.Array):
|
| 109 |
+
return _from_ctypes_array(t)
|
| 110 |
+
elif issubclass(t, _ctypes._Pointer):
|
| 111 |
+
raise TypeError("ctypes pointers have no dtype equivalent")
|
| 112 |
+
elif issubclass(t, _ctypes.Structure):
|
| 113 |
+
return _from_ctypes_structure(t)
|
| 114 |
+
elif issubclass(t, _ctypes.Union):
|
| 115 |
+
return _from_ctypes_union(t)
|
| 116 |
+
elif isinstance(getattr(t, '_type_', None), str):
|
| 117 |
+
return _from_ctypes_scalar(t)
|
| 118 |
+
else:
|
| 119 |
+
raise NotImplementedError(
|
| 120 |
+
f"Unknown ctypes type {t.__name__}")
|
v12x/pylib/numpy/_core/_exceptions.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Various richly-typed exceptions, that also help us deal with string formatting
|
| 3 |
+
in python where it's easier.
|
| 4 |
+
|
| 5 |
+
By putting the formatting in `__str__`, we also avoid paying the cost for
|
| 6 |
+
users who silence the exceptions.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
def _unpack_tuple(tup):
|
| 10 |
+
if len(tup) == 1:
|
| 11 |
+
return tup[0]
|
| 12 |
+
else:
|
| 13 |
+
return tup
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def _display_as_base(cls):
|
| 17 |
+
"""
|
| 18 |
+
A decorator that makes an exception class look like its base.
|
| 19 |
+
|
| 20 |
+
We use this to hide subclasses that are implementation details - the user
|
| 21 |
+
should catch the base type, which is what the traceback will show them.
|
| 22 |
+
|
| 23 |
+
Classes decorated with this decorator are subject to removal without a
|
| 24 |
+
deprecation warning.
|
| 25 |
+
"""
|
| 26 |
+
assert issubclass(cls, Exception)
|
| 27 |
+
cls.__name__ = cls.__base__.__name__
|
| 28 |
+
return cls
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class UFuncTypeError(TypeError):
|
| 32 |
+
""" Base class for all ufunc exceptions """
|
| 33 |
+
def __init__(self, ufunc):
|
| 34 |
+
self.ufunc = ufunc
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@_display_as_base
|
| 38 |
+
class _UFuncNoLoopError(UFuncTypeError):
|
| 39 |
+
""" Thrown when a ufunc loop cannot be found """
|
| 40 |
+
def __init__(self, ufunc, dtypes):
|
| 41 |
+
super().__init__(ufunc)
|
| 42 |
+
self.dtypes = tuple(dtypes)
|
| 43 |
+
|
| 44 |
+
def __str__(self):
|
| 45 |
+
return (
|
| 46 |
+
f"ufunc {self.ufunc.__name__!r} did not contain a loop with signature "
|
| 47 |
+
f"matching types {_unpack_tuple(self.dtypes[:self.ufunc.nin])!r} "
|
| 48 |
+
f"-> {_unpack_tuple(self.dtypes[self.ufunc.nin:])!r}"
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
@_display_as_base
|
| 53 |
+
class _UFuncBinaryResolutionError(_UFuncNoLoopError):
|
| 54 |
+
""" Thrown when a binary resolution fails """
|
| 55 |
+
def __init__(self, ufunc, dtypes):
|
| 56 |
+
super().__init__(ufunc, dtypes)
|
| 57 |
+
assert len(self.dtypes) == 2
|
| 58 |
+
|
| 59 |
+
def __str__(self):
|
| 60 |
+
return (
|
| 61 |
+
"ufunc {!r} cannot use operands with types {!r} and {!r}"
|
| 62 |
+
).format(
|
| 63 |
+
self.ufunc.__name__, *self.dtypes
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
@_display_as_base
|
| 68 |
+
class _UFuncCastingError(UFuncTypeError):
|
| 69 |
+
def __init__(self, ufunc, casting, from_, to):
|
| 70 |
+
super().__init__(ufunc)
|
| 71 |
+
self.casting = casting
|
| 72 |
+
self.from_ = from_
|
| 73 |
+
self.to = to
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
@_display_as_base
|
| 77 |
+
class _UFuncInputCastingError(_UFuncCastingError):
|
| 78 |
+
""" Thrown when a ufunc input cannot be casted """
|
| 79 |
+
def __init__(self, ufunc, casting, from_, to, i):
|
| 80 |
+
super().__init__(ufunc, casting, from_, to)
|
| 81 |
+
self.in_i = i
|
| 82 |
+
|
| 83 |
+
def __str__(self):
|
| 84 |
+
# only show the number if more than one input exists
|
| 85 |
+
i_str = f"{self.in_i} " if self.ufunc.nin != 1 else ""
|
| 86 |
+
return (
|
| 87 |
+
f"Cannot cast ufunc {self.ufunc.__name__!r} input {i_str}from "
|
| 88 |
+
f"{self.from_!r} to {self.to!r} with casting rule {self.casting!r}"
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
@_display_as_base
|
| 93 |
+
class _UFuncOutputCastingError(_UFuncCastingError):
|
| 94 |
+
""" Thrown when a ufunc output cannot be casted """
|
| 95 |
+
def __init__(self, ufunc, casting, from_, to, i):
|
| 96 |
+
super().__init__(ufunc, casting, from_, to)
|
| 97 |
+
self.out_i = i
|
| 98 |
+
|
| 99 |
+
def __str__(self):
|
| 100 |
+
# only show the number if more than one output exists
|
| 101 |
+
i_str = f"{self.out_i} " if self.ufunc.nout != 1 else ""
|
| 102 |
+
return (
|
| 103 |
+
f"Cannot cast ufunc {self.ufunc.__name__!r} output {i_str}from "
|
| 104 |
+
f"{self.from_!r} to {self.to!r} with casting rule {self.casting!r}"
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
@_display_as_base
|
| 109 |
+
class _ArrayMemoryError(MemoryError):
|
| 110 |
+
""" Thrown when an array cannot be allocated"""
|
| 111 |
+
def __init__(self, shape, dtype):
|
| 112 |
+
self.shape = shape
|
| 113 |
+
self.dtype = dtype
|
| 114 |
+
|
| 115 |
+
@property
|
| 116 |
+
def _total_size(self):
|
| 117 |
+
num_bytes = self.dtype.itemsize
|
| 118 |
+
for dim in self.shape:
|
| 119 |
+
num_bytes *= dim
|
| 120 |
+
return num_bytes
|
| 121 |
+
|
| 122 |
+
@staticmethod
|
| 123 |
+
def _size_to_string(num_bytes):
|
| 124 |
+
""" Convert a number of bytes into a binary size string """
|
| 125 |
+
|
| 126 |
+
# https://en.wikipedia.org/wiki/Binary_prefix
|
| 127 |
+
LOG2_STEP = 10
|
| 128 |
+
STEP = 1024
|
| 129 |
+
units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
|
| 130 |
+
|
| 131 |
+
unit_i = max(num_bytes.bit_length() - 1, 1) // LOG2_STEP
|
| 132 |
+
unit_val = 1 << (unit_i * LOG2_STEP)
|
| 133 |
+
n_units = num_bytes / unit_val
|
| 134 |
+
del unit_val
|
| 135 |
+
|
| 136 |
+
# ensure we pick a unit that is correct after rounding
|
| 137 |
+
if round(n_units) == STEP:
|
| 138 |
+
unit_i += 1
|
| 139 |
+
n_units /= STEP
|
| 140 |
+
|
| 141 |
+
# deal with sizes so large that we don't have units for them
|
| 142 |
+
if unit_i >= len(units):
|
| 143 |
+
new_unit_i = len(units) - 1
|
| 144 |
+
n_units *= 1 << ((unit_i - new_unit_i) * LOG2_STEP)
|
| 145 |
+
unit_i = new_unit_i
|
| 146 |
+
|
| 147 |
+
unit_name = units[unit_i]
|
| 148 |
+
# format with a sensible number of digits
|
| 149 |
+
if unit_i == 0:
|
| 150 |
+
# no decimal point on bytes
|
| 151 |
+
return f'{n_units:.0f} {unit_name}'
|
| 152 |
+
elif round(n_units) < 1000:
|
| 153 |
+
# 3 significant figures, if none are dropped to the left of the .
|
| 154 |
+
return f'{n_units:#.3g} {unit_name}'
|
| 155 |
+
else:
|
| 156 |
+
# just give all the digits otherwise
|
| 157 |
+
return f'{n_units:#.0f} {unit_name}'
|
| 158 |
+
|
| 159 |
+
def __str__(self):
|
| 160 |
+
size_str = self._size_to_string(self._total_size)
|
| 161 |
+
return (f"Unable to allocate {size_str} for an array with shape "
|
| 162 |
+
f"{self.shape} and data type {self.dtype}")
|
v12x/pylib/numpy/_core/_internal.py
ADDED
|
@@ -0,0 +1,964 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
A place for internal code
|
| 3 |
+
|
| 4 |
+
Some things are more easily handled Python.
|
| 5 |
+
|
| 6 |
+
"""
|
| 7 |
+
import ast
|
| 8 |
+
import math
|
| 9 |
+
import re
|
| 10 |
+
import sys
|
| 11 |
+
import warnings
|
| 12 |
+
|
| 13 |
+
from numpy import _NoValue
|
| 14 |
+
from numpy.exceptions import DTypePromotionError
|
| 15 |
+
|
| 16 |
+
from ._multiarray_umath import _is_view_safe_cast
|
| 17 |
+
from .multiarray import StringDType, array, dtype, promote_types
|
| 18 |
+
|
| 19 |
+
try:
|
| 20 |
+
import ctypes
|
| 21 |
+
except ImportError:
|
| 22 |
+
ctypes = None
|
| 23 |
+
|
| 24 |
+
if sys.byteorder == 'little':
|
| 25 |
+
_nbo = '<'
|
| 26 |
+
else:
|
| 27 |
+
_nbo = '>'
|
| 28 |
+
|
| 29 |
+
def _makenames_list(adict, align):
|
| 30 |
+
allfields = []
|
| 31 |
+
|
| 32 |
+
for fname, obj in adict.items():
|
| 33 |
+
n = len(obj)
|
| 34 |
+
if not isinstance(obj, tuple) or n not in (2, 3):
|
| 35 |
+
raise ValueError("entry not a 2- or 3- tuple")
|
| 36 |
+
if n > 2 and obj[2] == fname:
|
| 37 |
+
continue
|
| 38 |
+
num = int(obj[1])
|
| 39 |
+
if num < 0:
|
| 40 |
+
raise ValueError("invalid offset.")
|
| 41 |
+
format = dtype(obj[0], align=align)
|
| 42 |
+
if n > 2:
|
| 43 |
+
title = obj[2]
|
| 44 |
+
else:
|
| 45 |
+
title = None
|
| 46 |
+
allfields.append((fname, format, num, title))
|
| 47 |
+
# sort by offsets
|
| 48 |
+
allfields.sort(key=lambda x: x[2])
|
| 49 |
+
names = [x[0] for x in allfields]
|
| 50 |
+
formats = [x[1] for x in allfields]
|
| 51 |
+
offsets = [x[2] for x in allfields]
|
| 52 |
+
titles = [x[3] for x in allfields]
|
| 53 |
+
|
| 54 |
+
return names, formats, offsets, titles
|
| 55 |
+
|
| 56 |
+
# Called in PyArray_DescrConverter function when
|
| 57 |
+
# a dictionary without "names" and "formats"
|
| 58 |
+
# fields is used as a data-type descriptor.
|
| 59 |
+
def _usefields(adict, align):
|
| 60 |
+
try:
|
| 61 |
+
names = adict[-1]
|
| 62 |
+
except KeyError:
|
| 63 |
+
names = None
|
| 64 |
+
if names is None:
|
| 65 |
+
names, formats, offsets, titles = _makenames_list(adict, align)
|
| 66 |
+
else:
|
| 67 |
+
formats = []
|
| 68 |
+
offsets = []
|
| 69 |
+
titles = []
|
| 70 |
+
for name in names:
|
| 71 |
+
res = adict[name]
|
| 72 |
+
formats.append(res[0])
|
| 73 |
+
offsets.append(res[1])
|
| 74 |
+
if len(res) > 2:
|
| 75 |
+
titles.append(res[2])
|
| 76 |
+
else:
|
| 77 |
+
titles.append(None)
|
| 78 |
+
|
| 79 |
+
return dtype({"names": names,
|
| 80 |
+
"formats": formats,
|
| 81 |
+
"offsets": offsets,
|
| 82 |
+
"titles": titles}, align)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
# construct an array_protocol descriptor list
|
| 86 |
+
# from the fields attribute of a descriptor
|
| 87 |
+
# This calls itself recursively but should eventually hit
|
| 88 |
+
# a descriptor that has no fields and then return
|
| 89 |
+
# a simple typestring
|
| 90 |
+
|
| 91 |
+
def _array_descr(descriptor):
|
| 92 |
+
fields = descriptor.fields
|
| 93 |
+
if fields is None:
|
| 94 |
+
subdtype = descriptor.subdtype
|
| 95 |
+
if subdtype is None:
|
| 96 |
+
if descriptor.metadata is None:
|
| 97 |
+
return descriptor.str
|
| 98 |
+
else:
|
| 99 |
+
new = descriptor.metadata.copy()
|
| 100 |
+
if new:
|
| 101 |
+
return (descriptor.str, new)
|
| 102 |
+
else:
|
| 103 |
+
return descriptor.str
|
| 104 |
+
else:
|
| 105 |
+
return (_array_descr(subdtype[0]), subdtype[1])
|
| 106 |
+
|
| 107 |
+
names = descriptor.names
|
| 108 |
+
ordered_fields = [fields[x] + (x,) for x in names]
|
| 109 |
+
result = []
|
| 110 |
+
offset = 0
|
| 111 |
+
for field in ordered_fields:
|
| 112 |
+
if field[1] > offset:
|
| 113 |
+
num = field[1] - offset
|
| 114 |
+
result.append(('', f'|V{num}'))
|
| 115 |
+
offset += num
|
| 116 |
+
elif field[1] < offset:
|
| 117 |
+
raise ValueError(
|
| 118 |
+
"dtype.descr is not defined for types with overlapping or "
|
| 119 |
+
"out-of-order fields")
|
| 120 |
+
if len(field) > 3:
|
| 121 |
+
name = (field[2], field[3])
|
| 122 |
+
else:
|
| 123 |
+
name = field[2]
|
| 124 |
+
if field[0].subdtype:
|
| 125 |
+
tup = (name, _array_descr(field[0].subdtype[0]),
|
| 126 |
+
field[0].subdtype[1])
|
| 127 |
+
else:
|
| 128 |
+
tup = (name, _array_descr(field[0]))
|
| 129 |
+
offset += field[0].itemsize
|
| 130 |
+
result.append(tup)
|
| 131 |
+
|
| 132 |
+
if descriptor.itemsize > offset:
|
| 133 |
+
num = descriptor.itemsize - offset
|
| 134 |
+
result.append(('', f'|V{num}'))
|
| 135 |
+
|
| 136 |
+
return result
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
# format_re was originally from numarray by J. Todd Miller
|
| 140 |
+
|
| 141 |
+
format_re = re.compile(r'(?P<order1>[<>|=]?)'
|
| 142 |
+
r'(?P<repeats> *[(]?[ ,0-9]*[)]? *)'
|
| 143 |
+
r'(?P<order2>[<>|=]?)'
|
| 144 |
+
r'(?P<dtype>[A-Za-z0-9.?]*(?:\[[a-zA-Z0-9,.]+\])?)')
|
| 145 |
+
sep_re = re.compile(r'\s*,\s*')
|
| 146 |
+
space_re = re.compile(r'\s+$')
|
| 147 |
+
|
| 148 |
+
# astr is a string (perhaps comma separated)
|
| 149 |
+
|
| 150 |
+
_convorder = {'=': _nbo}
|
| 151 |
+
|
| 152 |
+
def _commastring(astr):
|
| 153 |
+
startindex = 0
|
| 154 |
+
result = []
|
| 155 |
+
islist = False
|
| 156 |
+
while startindex < len(astr):
|
| 157 |
+
mo = format_re.match(astr, pos=startindex)
|
| 158 |
+
try:
|
| 159 |
+
(order1, repeats, order2, dtype) = mo.groups()
|
| 160 |
+
except (TypeError, AttributeError):
|
| 161 |
+
raise ValueError(
|
| 162 |
+
f'format number {len(result) + 1} of "{astr}" is not recognized'
|
| 163 |
+
) from None
|
| 164 |
+
startindex = mo.end()
|
| 165 |
+
# Separator or ending padding
|
| 166 |
+
if startindex < len(astr):
|
| 167 |
+
if space_re.match(astr, pos=startindex):
|
| 168 |
+
startindex = len(astr)
|
| 169 |
+
else:
|
| 170 |
+
mo = sep_re.match(astr, pos=startindex)
|
| 171 |
+
if not mo:
|
| 172 |
+
raise ValueError(
|
| 173 |
+
f'format number {len(result) + 1} of "{astr}" '
|
| 174 |
+
'is not recognized')
|
| 175 |
+
startindex = mo.end()
|
| 176 |
+
islist = True
|
| 177 |
+
|
| 178 |
+
if order2 == '':
|
| 179 |
+
order = order1
|
| 180 |
+
elif order1 == '':
|
| 181 |
+
order = order2
|
| 182 |
+
else:
|
| 183 |
+
order1 = _convorder.get(order1, order1)
|
| 184 |
+
order2 = _convorder.get(order2, order2)
|
| 185 |
+
if (order1 != order2):
|
| 186 |
+
raise ValueError(
|
| 187 |
+
f'inconsistent byte-order specification {order1} and {order2}')
|
| 188 |
+
order = order1
|
| 189 |
+
|
| 190 |
+
if order in ('|', '=', _nbo):
|
| 191 |
+
order = ''
|
| 192 |
+
dtype = order + dtype
|
| 193 |
+
if repeats == '':
|
| 194 |
+
newitem = dtype
|
| 195 |
+
else:
|
| 196 |
+
if (repeats[0] == "(" and repeats[-1] == ")"
|
| 197 |
+
and repeats[1:-1].strip() != ""
|
| 198 |
+
and "," not in repeats):
|
| 199 |
+
warnings.warn(
|
| 200 |
+
'Passing in a parenthesized single number for repeats '
|
| 201 |
+
'is deprecated; pass either a single number or indicate '
|
| 202 |
+
'a tuple with a comma, like "(2,)".', DeprecationWarning,
|
| 203 |
+
stacklevel=2)
|
| 204 |
+
newitem = (dtype, ast.literal_eval(repeats))
|
| 205 |
+
|
| 206 |
+
result.append(newitem)
|
| 207 |
+
|
| 208 |
+
return result if islist else result[0]
|
| 209 |
+
|
| 210 |
+
class dummy_ctype:
|
| 211 |
+
|
| 212 |
+
def __init__(self, cls):
|
| 213 |
+
self._cls = cls
|
| 214 |
+
|
| 215 |
+
def __mul__(self, other):
|
| 216 |
+
return self
|
| 217 |
+
|
| 218 |
+
def __call__(self, *other):
|
| 219 |
+
return self._cls(other)
|
| 220 |
+
|
| 221 |
+
def __eq__(self, other):
|
| 222 |
+
return self._cls == other._cls
|
| 223 |
+
|
| 224 |
+
def __ne__(self, other):
|
| 225 |
+
return self._cls != other._cls
|
| 226 |
+
|
| 227 |
+
def _getintp_ctype():
|
| 228 |
+
val = _getintp_ctype.cache
|
| 229 |
+
if val is not None:
|
| 230 |
+
return val
|
| 231 |
+
if ctypes is None:
|
| 232 |
+
import numpy as np
|
| 233 |
+
val = dummy_ctype(np.intp)
|
| 234 |
+
else:
|
| 235 |
+
char = dtype('n').char
|
| 236 |
+
if char == 'i':
|
| 237 |
+
val = ctypes.c_int
|
| 238 |
+
elif char == 'l':
|
| 239 |
+
val = ctypes.c_long
|
| 240 |
+
elif char == 'q':
|
| 241 |
+
val = ctypes.c_longlong
|
| 242 |
+
else:
|
| 243 |
+
val = ctypes.c_long
|
| 244 |
+
_getintp_ctype.cache = val
|
| 245 |
+
return val
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
_getintp_ctype.cache = None
|
| 249 |
+
|
| 250 |
+
# Used for .ctypes attribute of ndarray
|
| 251 |
+
|
| 252 |
+
class _missing_ctypes:
|
| 253 |
+
def cast(self, num, obj):
|
| 254 |
+
return num.value
|
| 255 |
+
|
| 256 |
+
class c_void_p:
|
| 257 |
+
def __init__(self, ptr):
|
| 258 |
+
self.value = ptr
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
class _ctypes:
|
| 262 |
+
def __init__(self, array, ptr=None):
|
| 263 |
+
self._arr = array
|
| 264 |
+
|
| 265 |
+
if ctypes:
|
| 266 |
+
self._ctypes = ctypes
|
| 267 |
+
self._data = self._ctypes.c_void_p(ptr)
|
| 268 |
+
else:
|
| 269 |
+
# fake a pointer-like object that holds onto the reference
|
| 270 |
+
self._ctypes = _missing_ctypes()
|
| 271 |
+
self._data = self._ctypes.c_void_p(ptr)
|
| 272 |
+
self._data._objects = array
|
| 273 |
+
|
| 274 |
+
if self._arr.ndim == 0:
|
| 275 |
+
self._zerod = True
|
| 276 |
+
else:
|
| 277 |
+
self._zerod = False
|
| 278 |
+
|
| 279 |
+
def data_as(self, obj):
|
| 280 |
+
"""
|
| 281 |
+
Return the data pointer cast to a particular c-types object.
|
| 282 |
+
For example, calling ``self._as_parameter_`` is equivalent to
|
| 283 |
+
``self.data_as(ctypes.c_void_p)``. Perhaps you want to use
|
| 284 |
+
the data as a pointer to a ctypes array of floating-point data:
|
| 285 |
+
``self.data_as(ctypes.POINTER(ctypes.c_double))``.
|
| 286 |
+
|
| 287 |
+
The returned pointer will keep a reference to the array.
|
| 288 |
+
"""
|
| 289 |
+
# _ctypes.cast function causes a circular reference of self._data in
|
| 290 |
+
# self._data._objects. Attributes of self._data cannot be released
|
| 291 |
+
# until gc.collect is called. Make a copy of the pointer first then
|
| 292 |
+
# let it hold the array reference. This is a workaround to circumvent
|
| 293 |
+
# the CPython bug https://bugs.python.org/issue12836.
|
| 294 |
+
ptr = self._ctypes.cast(self._data, obj)
|
| 295 |
+
ptr._arr = self._arr
|
| 296 |
+
return ptr
|
| 297 |
+
|
| 298 |
+
def shape_as(self, obj):
|
| 299 |
+
"""
|
| 300 |
+
Return the shape tuple as an array of some other c-types
|
| 301 |
+
type. For example: ``self.shape_as(ctypes.c_short)``.
|
| 302 |
+
"""
|
| 303 |
+
if self._zerod:
|
| 304 |
+
return None
|
| 305 |
+
return (obj * self._arr.ndim)(*self._arr.shape)
|
| 306 |
+
|
| 307 |
+
def strides_as(self, obj):
|
| 308 |
+
"""
|
| 309 |
+
Return the strides tuple as an array of some other
|
| 310 |
+
c-types type. For example: ``self.strides_as(ctypes.c_longlong)``.
|
| 311 |
+
"""
|
| 312 |
+
if self._zerod:
|
| 313 |
+
return None
|
| 314 |
+
return (obj * self._arr.ndim)(*self._arr.strides)
|
| 315 |
+
|
| 316 |
+
@property
|
| 317 |
+
def data(self):
|
| 318 |
+
"""
|
| 319 |
+
A pointer to the memory area of the array as a Python integer.
|
| 320 |
+
This memory area may contain data that is not aligned, or not in
|
| 321 |
+
correct byte-order. The memory area may not even be writeable.
|
| 322 |
+
The array flags and data-type of this array should be respected
|
| 323 |
+
when passing this attribute to arbitrary C-code to avoid trouble
|
| 324 |
+
that can include Python crashing. User Beware! The value of this
|
| 325 |
+
attribute is exactly the same as:
|
| 326 |
+
``self._array_interface_['data'][0]``.
|
| 327 |
+
|
| 328 |
+
Note that unlike ``data_as``, a reference won't be kept to the array:
|
| 329 |
+
code like ``ctypes.c_void_p((a + b).ctypes.data)`` will result in a
|
| 330 |
+
pointer to a deallocated array, and should be spelt
|
| 331 |
+
``(a + b).ctypes.data_as(ctypes.c_void_p)``
|
| 332 |
+
"""
|
| 333 |
+
return self._data.value
|
| 334 |
+
|
| 335 |
+
@property
|
| 336 |
+
def shape(self):
|
| 337 |
+
"""
|
| 338 |
+
(c_intp*self.ndim): A ctypes array of length self.ndim where
|
| 339 |
+
the basetype is the C-integer corresponding to ``dtype('p')`` on this
|
| 340 |
+
platform (see `~numpy.ctypeslib.c_intp`). This base-type could be
|
| 341 |
+
`ctypes.c_int`, `ctypes.c_long`, or `ctypes.c_longlong` depending on
|
| 342 |
+
the platform. The ctypes array contains the shape of
|
| 343 |
+
the underlying array.
|
| 344 |
+
"""
|
| 345 |
+
return self.shape_as(_getintp_ctype())
|
| 346 |
+
|
| 347 |
+
@property
|
| 348 |
+
def strides(self):
|
| 349 |
+
"""
|
| 350 |
+
(c_intp*self.ndim): A ctypes array of length self.ndim where
|
| 351 |
+
the basetype is the same as for the shape attribute. This ctypes
|
| 352 |
+
array contains the strides information from the underlying array.
|
| 353 |
+
This strides information is important for showing how many bytes
|
| 354 |
+
must be jumped to get to the next element in the array.
|
| 355 |
+
"""
|
| 356 |
+
return self.strides_as(_getintp_ctype())
|
| 357 |
+
|
| 358 |
+
@property
|
| 359 |
+
def _as_parameter_(self):
|
| 360 |
+
"""
|
| 361 |
+
Overrides the ctypes semi-magic method
|
| 362 |
+
|
| 363 |
+
Enables `c_func(some_array.ctypes)`
|
| 364 |
+
"""
|
| 365 |
+
return self.data_as(ctypes.c_void_p)
|
| 366 |
+
|
| 367 |
+
|
| 368 |
+
def _newnames(datatype, order):
|
| 369 |
+
"""
|
| 370 |
+
Given a datatype and an order object, return a new names tuple, with the
|
| 371 |
+
order indicated
|
| 372 |
+
"""
|
| 373 |
+
oldnames = datatype.names
|
| 374 |
+
nameslist = list(oldnames)
|
| 375 |
+
if isinstance(order, str):
|
| 376 |
+
order = [order]
|
| 377 |
+
seen = set()
|
| 378 |
+
if isinstance(order, (list, tuple)):
|
| 379 |
+
for name in order:
|
| 380 |
+
try:
|
| 381 |
+
nameslist.remove(name)
|
| 382 |
+
except ValueError:
|
| 383 |
+
if name in seen:
|
| 384 |
+
raise ValueError(f"duplicate field name: {name}") from None
|
| 385 |
+
else:
|
| 386 |
+
raise ValueError(f"unknown field name: {name}") from None
|
| 387 |
+
seen.add(name)
|
| 388 |
+
return tuple(list(order) + nameslist)
|
| 389 |
+
raise ValueError(f"unsupported order value: {order}")
|
| 390 |
+
|
| 391 |
+
def _copy_fields(ary):
|
| 392 |
+
"""Return copy of structured array with padding between fields removed.
|
| 393 |
+
|
| 394 |
+
Parameters
|
| 395 |
+
----------
|
| 396 |
+
ary : ndarray
|
| 397 |
+
Structured array from which to remove padding bytes
|
| 398 |
+
|
| 399 |
+
Returns
|
| 400 |
+
-------
|
| 401 |
+
ary_copy : ndarray
|
| 402 |
+
Copy of ary with padding bytes removed
|
| 403 |
+
"""
|
| 404 |
+
dt = ary.dtype
|
| 405 |
+
copy_dtype = {'names': dt.names,
|
| 406 |
+
'formats': [dt.fields[name][0] for name in dt.names]}
|
| 407 |
+
return array(ary, dtype=copy_dtype, copy=True)
|
| 408 |
+
|
| 409 |
+
def _promote_fields(dt1, dt2):
|
| 410 |
+
""" Perform type promotion for two structured dtypes.
|
| 411 |
+
|
| 412 |
+
Parameters
|
| 413 |
+
----------
|
| 414 |
+
dt1 : structured dtype
|
| 415 |
+
First dtype.
|
| 416 |
+
dt2 : structured dtype
|
| 417 |
+
Second dtype.
|
| 418 |
+
|
| 419 |
+
Returns
|
| 420 |
+
-------
|
| 421 |
+
out : dtype
|
| 422 |
+
The promoted dtype
|
| 423 |
+
|
| 424 |
+
Notes
|
| 425 |
+
-----
|
| 426 |
+
If one of the inputs is aligned, the result will be. The titles of
|
| 427 |
+
both descriptors must match (point to the same field).
|
| 428 |
+
"""
|
| 429 |
+
# Both must be structured and have the same names in the same order
|
| 430 |
+
if (dt1.names is None or dt2.names is None) or dt1.names != dt2.names:
|
| 431 |
+
raise DTypePromotionError(
|
| 432 |
+
f"field names `{dt1.names}` and `{dt2.names}` mismatch.")
|
| 433 |
+
|
| 434 |
+
# if both are identical, we can (maybe!) just return the same dtype.
|
| 435 |
+
identical = dt1 is dt2
|
| 436 |
+
new_fields = []
|
| 437 |
+
for name in dt1.names:
|
| 438 |
+
field1 = dt1.fields[name]
|
| 439 |
+
field2 = dt2.fields[name]
|
| 440 |
+
new_descr = promote_types(field1[0], field2[0])
|
| 441 |
+
identical = identical and new_descr is field1[0]
|
| 442 |
+
|
| 443 |
+
# Check that the titles match (if given):
|
| 444 |
+
if field1[2:] != field2[2:]:
|
| 445 |
+
raise DTypePromotionError(
|
| 446 |
+
f"field titles of field '{name}' mismatch")
|
| 447 |
+
if len(field1) == 2:
|
| 448 |
+
new_fields.append((name, new_descr))
|
| 449 |
+
else:
|
| 450 |
+
new_fields.append(((field1[2], name), new_descr))
|
| 451 |
+
|
| 452 |
+
res = dtype(new_fields, align=dt1.isalignedstruct or dt2.isalignedstruct)
|
| 453 |
+
|
| 454 |
+
# Might as well preserve identity (and metadata) if the dtype is identical
|
| 455 |
+
# and the itemsize, offsets are also unmodified. This could probably be
|
| 456 |
+
# sped up, but also probably just be removed entirely.
|
| 457 |
+
if identical and res.itemsize == dt1.itemsize:
|
| 458 |
+
for name in dt1.names:
|
| 459 |
+
if dt1.fields[name][1] != res.fields[name][1]:
|
| 460 |
+
return res # the dtype changed.
|
| 461 |
+
return dt1
|
| 462 |
+
|
| 463 |
+
return res
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def _getfield_is_safe(oldtype, newtype, offset):
|
| 467 |
+
""" Checks safety of getfield for object arrays.
|
| 468 |
+
|
| 469 |
+
As in _view_is_safe, we need to check that memory containing objects is not
|
| 470 |
+
reinterpreted as a non-object datatype and vice versa.
|
| 471 |
+
|
| 472 |
+
Parameters
|
| 473 |
+
----------
|
| 474 |
+
oldtype : data-type
|
| 475 |
+
Data type of the original ndarray.
|
| 476 |
+
newtype : data-type
|
| 477 |
+
Data type of the field being accessed by ndarray.getfield
|
| 478 |
+
offset : int
|
| 479 |
+
Offset of the field being accessed by ndarray.getfield
|
| 480 |
+
|
| 481 |
+
Raises
|
| 482 |
+
------
|
| 483 |
+
TypeError
|
| 484 |
+
If the field access is invalid
|
| 485 |
+
|
| 486 |
+
"""
|
| 487 |
+
if newtype.hasobject or oldtype.hasobject:
|
| 488 |
+
if offset == 0 and _is_view_safe_cast(oldtype, newtype):
|
| 489 |
+
return
|
| 490 |
+
if oldtype.names is not None:
|
| 491 |
+
for name in oldtype.names:
|
| 492 |
+
if (oldtype.fields[name][1] == offset and
|
| 493 |
+
oldtype.fields[name][0] == newtype):
|
| 494 |
+
return
|
| 495 |
+
raise TypeError("Cannot get/set field of an object array")
|
| 496 |
+
return
|
| 497 |
+
|
| 498 |
+
def _view_is_safe(oldtype, newtype):
|
| 499 |
+
""" Checks safety of a view involving object arrays, for example when
|
| 500 |
+
doing::
|
| 501 |
+
|
| 502 |
+
np.zeros(10, dtype=oldtype).view(newtype)
|
| 503 |
+
|
| 504 |
+
Parameters
|
| 505 |
+
----------
|
| 506 |
+
oldtype : data-type
|
| 507 |
+
Data type of original ndarray
|
| 508 |
+
newtype : data-type
|
| 509 |
+
Data type of the view
|
| 510 |
+
|
| 511 |
+
Raises
|
| 512 |
+
------
|
| 513 |
+
TypeError
|
| 514 |
+
If the new type is incompatible with the old type.
|
| 515 |
+
|
| 516 |
+
"""
|
| 517 |
+
|
| 518 |
+
# more precise than ``oldtype == newtype``: e.g. dtype((np.record, 'i4,i4'))
|
| 519 |
+
# views safely as dtype((np.void, 'i4,i4')), while two equal StringDType
|
| 520 |
+
# instances with separate allocators do not
|
| 521 |
+
if _is_view_safe_cast(oldtype, newtype):
|
| 522 |
+
return
|
| 523 |
+
|
| 524 |
+
if newtype.hasobject or oldtype.hasobject:
|
| 525 |
+
raise TypeError("Cannot change data-type for array of references.")
|
| 526 |
+
return
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
# Given a string containing a PEP 3118 format specifier,
|
| 530 |
+
# construct a NumPy dtype
|
| 531 |
+
|
| 532 |
+
_pep3118_native_map = {
|
| 533 |
+
'?': '?',
|
| 534 |
+
'c': 'S1',
|
| 535 |
+
'b': 'b',
|
| 536 |
+
'B': 'B',
|
| 537 |
+
'h': 'h',
|
| 538 |
+
'H': 'H',
|
| 539 |
+
'i': 'i',
|
| 540 |
+
'I': 'I',
|
| 541 |
+
'l': 'l',
|
| 542 |
+
'L': 'L',
|
| 543 |
+
'q': 'q',
|
| 544 |
+
'Q': 'Q',
|
| 545 |
+
'e': 'e',
|
| 546 |
+
'f': 'f',
|
| 547 |
+
'd': 'd',
|
| 548 |
+
'g': 'g',
|
| 549 |
+
'Zf': 'F',
|
| 550 |
+
'Zd': 'D',
|
| 551 |
+
'Zg': 'G',
|
| 552 |
+
's': 'S',
|
| 553 |
+
'w': 'U',
|
| 554 |
+
'O': 'O',
|
| 555 |
+
'x': 'V', # padding
|
| 556 |
+
}
|
| 557 |
+
_pep3118_native_typechars = ''.join(_pep3118_native_map.keys())
|
| 558 |
+
|
| 559 |
+
_pep3118_standard_map = {
|
| 560 |
+
'?': '?',
|
| 561 |
+
'c': 'S1',
|
| 562 |
+
'b': 'b',
|
| 563 |
+
'B': 'B',
|
| 564 |
+
'h': 'i2',
|
| 565 |
+
'H': 'u2',
|
| 566 |
+
'i': 'i4',
|
| 567 |
+
'I': 'u4',
|
| 568 |
+
'l': 'i4',
|
| 569 |
+
'L': 'u4',
|
| 570 |
+
'q': 'i8',
|
| 571 |
+
'Q': 'u8',
|
| 572 |
+
'e': 'f2',
|
| 573 |
+
'f': 'f',
|
| 574 |
+
'd': 'd',
|
| 575 |
+
'Zf': 'F',
|
| 576 |
+
'Zd': 'D',
|
| 577 |
+
's': 'S',
|
| 578 |
+
'w': 'U',
|
| 579 |
+
'O': 'O',
|
| 580 |
+
'x': 'V', # padding
|
| 581 |
+
}
|
| 582 |
+
_pep3118_standard_typechars = ''.join(_pep3118_standard_map.keys())
|
| 583 |
+
|
| 584 |
+
_pep3118_unsupported_map = {
|
| 585 |
+
'u': 'UCS-2 strings',
|
| 586 |
+
'&': 'pointers',
|
| 587 |
+
't': 'bitfields',
|
| 588 |
+
'X': 'function pointers',
|
| 589 |
+
}
|
| 590 |
+
|
| 591 |
+
class _Stream:
|
| 592 |
+
def __init__(self, s):
|
| 593 |
+
self.s = s
|
| 594 |
+
self.byteorder = '@'
|
| 595 |
+
|
| 596 |
+
def advance(self, n):
|
| 597 |
+
res = self.s[:n]
|
| 598 |
+
self.s = self.s[n:]
|
| 599 |
+
return res
|
| 600 |
+
|
| 601 |
+
def consume(self, c):
|
| 602 |
+
if self.s[:len(c)] == c:
|
| 603 |
+
self.advance(len(c))
|
| 604 |
+
return True
|
| 605 |
+
return False
|
| 606 |
+
|
| 607 |
+
def consume_until(self, c):
|
| 608 |
+
if callable(c):
|
| 609 |
+
i = 0
|
| 610 |
+
while i < len(self.s) and not c(self.s[i]):
|
| 611 |
+
i = i + 1
|
| 612 |
+
return self.advance(i)
|
| 613 |
+
else:
|
| 614 |
+
i = self.s.index(c)
|
| 615 |
+
res = self.advance(i)
|
| 616 |
+
self.advance(len(c))
|
| 617 |
+
return res
|
| 618 |
+
|
| 619 |
+
@property
|
| 620 |
+
def next(self):
|
| 621 |
+
return self.s[0]
|
| 622 |
+
|
| 623 |
+
def __bool__(self):
|
| 624 |
+
return bool(self.s)
|
| 625 |
+
|
| 626 |
+
|
| 627 |
+
def _dtype_from_pep3118(spec):
|
| 628 |
+
stream = _Stream(spec)
|
| 629 |
+
dtype, align = __dtype_from_pep3118(stream, is_subdtype=False)
|
| 630 |
+
return dtype
|
| 631 |
+
|
| 632 |
+
def __dtype_from_pep3118(stream, is_subdtype):
|
| 633 |
+
field_spec = {
|
| 634 |
+
'names': [],
|
| 635 |
+
'formats': [],
|
| 636 |
+
'offsets': [],
|
| 637 |
+
'itemsize': 0
|
| 638 |
+
}
|
| 639 |
+
offset = 0
|
| 640 |
+
common_alignment = 1
|
| 641 |
+
is_padding = False
|
| 642 |
+
|
| 643 |
+
# Parse spec
|
| 644 |
+
while stream:
|
| 645 |
+
value = None
|
| 646 |
+
|
| 647 |
+
# End of structure, bail out to upper level
|
| 648 |
+
if stream.consume('}'):
|
| 649 |
+
break
|
| 650 |
+
|
| 651 |
+
# Sub-arrays (1)
|
| 652 |
+
shape = None
|
| 653 |
+
if stream.consume('('):
|
| 654 |
+
shape = stream.consume_until(')')
|
| 655 |
+
shape = tuple(map(int, shape.split(',')))
|
| 656 |
+
|
| 657 |
+
# Byte order
|
| 658 |
+
if stream.next in ('@', '=', '<', '>', '^', '!'):
|
| 659 |
+
byteorder = stream.advance(1)
|
| 660 |
+
if byteorder == '!':
|
| 661 |
+
byteorder = '>'
|
| 662 |
+
stream.byteorder = byteorder
|
| 663 |
+
|
| 664 |
+
# Byte order characters also control native vs. standard type sizes
|
| 665 |
+
if stream.byteorder in ('@', '^'):
|
| 666 |
+
type_map = _pep3118_native_map
|
| 667 |
+
type_map_chars = _pep3118_native_typechars
|
| 668 |
+
else:
|
| 669 |
+
type_map = _pep3118_standard_map
|
| 670 |
+
type_map_chars = _pep3118_standard_typechars
|
| 671 |
+
|
| 672 |
+
# Item sizes
|
| 673 |
+
itemsize_str = stream.consume_until(lambda c: not c.isdigit())
|
| 674 |
+
if itemsize_str:
|
| 675 |
+
itemsize = int(itemsize_str)
|
| 676 |
+
else:
|
| 677 |
+
itemsize = 1
|
| 678 |
+
|
| 679 |
+
# Data types
|
| 680 |
+
is_padding = False
|
| 681 |
+
|
| 682 |
+
if stream.consume('T{'):
|
| 683 |
+
value, align = __dtype_from_pep3118(
|
| 684 |
+
stream, is_subdtype=True)
|
| 685 |
+
elif stream.next in type_map_chars:
|
| 686 |
+
if stream.next == 'Z':
|
| 687 |
+
typechar = stream.advance(2)
|
| 688 |
+
else:
|
| 689 |
+
typechar = stream.advance(1)
|
| 690 |
+
|
| 691 |
+
is_padding = (typechar == 'x')
|
| 692 |
+
dtypechar = type_map[typechar]
|
| 693 |
+
if dtypechar in 'USV':
|
| 694 |
+
dtypechar += f'{itemsize}'
|
| 695 |
+
itemsize = 1
|
| 696 |
+
numpy_byteorder = {'@': '=', '^': '='}.get(
|
| 697 |
+
stream.byteorder, stream.byteorder)
|
| 698 |
+
value = dtype(numpy_byteorder + dtypechar)
|
| 699 |
+
align = value.alignment
|
| 700 |
+
elif stream.next in _pep3118_unsupported_map:
|
| 701 |
+
desc = _pep3118_unsupported_map[stream.next]
|
| 702 |
+
raise NotImplementedError(
|
| 703 |
+
f"Unrepresentable PEP 3118 data type {stream.next!r} ({desc})")
|
| 704 |
+
else:
|
| 705 |
+
raise ValueError(
|
| 706 |
+
f"Unknown PEP 3118 data type specifier {stream.s!r}"
|
| 707 |
+
)
|
| 708 |
+
|
| 709 |
+
#
|
| 710 |
+
# Native alignment may require padding
|
| 711 |
+
#
|
| 712 |
+
# Here we assume that the presence of a '@' character implicitly
|
| 713 |
+
# implies that the start of the array is *already* aligned.
|
| 714 |
+
#
|
| 715 |
+
extra_offset = 0
|
| 716 |
+
if stream.byteorder == '@':
|
| 717 |
+
start_padding = (-offset) % align
|
| 718 |
+
intra_padding = (-value.itemsize) % align
|
| 719 |
+
|
| 720 |
+
offset += start_padding
|
| 721 |
+
|
| 722 |
+
if intra_padding != 0:
|
| 723 |
+
if itemsize > 1 or (shape is not None and _prod(shape) > 1):
|
| 724 |
+
# Inject internal padding to the end of the sub-item
|
| 725 |
+
value = _add_trailing_padding(value, intra_padding)
|
| 726 |
+
else:
|
| 727 |
+
# We can postpone the injection of internal padding,
|
| 728 |
+
# as the item appears at most once
|
| 729 |
+
extra_offset += intra_padding
|
| 730 |
+
|
| 731 |
+
# Update common alignment
|
| 732 |
+
common_alignment = _lcm(align, common_alignment)
|
| 733 |
+
|
| 734 |
+
# Convert itemsize to sub-array
|
| 735 |
+
if itemsize != 1:
|
| 736 |
+
value = dtype((value, (itemsize,)))
|
| 737 |
+
|
| 738 |
+
# Sub-arrays (2)
|
| 739 |
+
if shape is not None:
|
| 740 |
+
value = dtype((value, shape))
|
| 741 |
+
|
| 742 |
+
# Field name
|
| 743 |
+
if stream.consume(':'):
|
| 744 |
+
name = stream.consume_until(':')
|
| 745 |
+
else:
|
| 746 |
+
name = None
|
| 747 |
+
|
| 748 |
+
if not (is_padding and name is None):
|
| 749 |
+
if name is not None and name in field_spec['names']:
|
| 750 |
+
raise RuntimeError(
|
| 751 |
+
f"Duplicate field name '{name}' in PEP3118 format"
|
| 752 |
+
)
|
| 753 |
+
field_spec['names'].append(name)
|
| 754 |
+
field_spec['formats'].append(value)
|
| 755 |
+
field_spec['offsets'].append(offset)
|
| 756 |
+
|
| 757 |
+
offset += value.itemsize
|
| 758 |
+
offset += extra_offset
|
| 759 |
+
|
| 760 |
+
field_spec['itemsize'] = offset
|
| 761 |
+
|
| 762 |
+
# extra final padding for aligned types
|
| 763 |
+
if stream.byteorder == '@':
|
| 764 |
+
field_spec['itemsize'] += (-offset) % common_alignment
|
| 765 |
+
|
| 766 |
+
# Check if this was a simple 1-item type, and unwrap it
|
| 767 |
+
if (field_spec['names'] == [None]
|
| 768 |
+
and field_spec['offsets'][0] == 0
|
| 769 |
+
and field_spec['itemsize'] == field_spec['formats'][0].itemsize
|
| 770 |
+
and not is_subdtype):
|
| 771 |
+
ret = field_spec['formats'][0]
|
| 772 |
+
else:
|
| 773 |
+
_fix_names(field_spec)
|
| 774 |
+
ret = dtype(field_spec)
|
| 775 |
+
|
| 776 |
+
# Finished
|
| 777 |
+
return ret, common_alignment
|
| 778 |
+
|
| 779 |
+
def _fix_names(field_spec):
|
| 780 |
+
""" Replace names which are None with the next unused f%d name """
|
| 781 |
+
names = field_spec['names']
|
| 782 |
+
for i, name in enumerate(names):
|
| 783 |
+
if name is not None:
|
| 784 |
+
continue
|
| 785 |
+
|
| 786 |
+
j = 0
|
| 787 |
+
while True:
|
| 788 |
+
name = f'f{j}'
|
| 789 |
+
if name not in names:
|
| 790 |
+
break
|
| 791 |
+
j = j + 1
|
| 792 |
+
names[i] = name
|
| 793 |
+
|
| 794 |
+
def _add_trailing_padding(value, padding):
|
| 795 |
+
"""Inject the specified number of padding bytes at the end of a dtype"""
|
| 796 |
+
if value.fields is None:
|
| 797 |
+
field_spec = {
|
| 798 |
+
'names': ['f0'],
|
| 799 |
+
'formats': [value],
|
| 800 |
+
'offsets': [0],
|
| 801 |
+
'itemsize': value.itemsize
|
| 802 |
+
}
|
| 803 |
+
else:
|
| 804 |
+
fields = value.fields
|
| 805 |
+
names = value.names
|
| 806 |
+
field_spec = {
|
| 807 |
+
'names': names,
|
| 808 |
+
'formats': [fields[name][0] for name in names],
|
| 809 |
+
'offsets': [fields[name][1] for name in names],
|
| 810 |
+
'itemsize': value.itemsize
|
| 811 |
+
}
|
| 812 |
+
|
| 813 |
+
field_spec['itemsize'] += padding
|
| 814 |
+
return dtype(field_spec)
|
| 815 |
+
|
| 816 |
+
def _prod(a):
|
| 817 |
+
p = 1
|
| 818 |
+
for x in a:
|
| 819 |
+
p *= x
|
| 820 |
+
return p
|
| 821 |
+
|
| 822 |
+
def _gcd(a, b):
|
| 823 |
+
"""Calculate the greatest common divisor of a and b"""
|
| 824 |
+
if not (math.isfinite(a) and math.isfinite(b)):
|
| 825 |
+
raise ValueError('Can only find greatest common divisor of '
|
| 826 |
+
f'finite arguments, found "{a}" and "{b}"')
|
| 827 |
+
while b:
|
| 828 |
+
a, b = b, a % b
|
| 829 |
+
return a
|
| 830 |
+
|
| 831 |
+
def _lcm(a, b):
|
| 832 |
+
return a // _gcd(a, b) * b
|
| 833 |
+
|
| 834 |
+
def array_ufunc_errmsg_formatter(dummy, ufunc, method, *inputs, **kwargs):
|
| 835 |
+
""" Format the error message for when __array_ufunc__ gives up. """
|
| 836 |
+
args_string = ', '.join([f'{arg!r}' for arg in inputs] +
|
| 837 |
+
[f'{k}={v!r}'
|
| 838 |
+
for k, v in kwargs.items()])
|
| 839 |
+
args = inputs + kwargs.get('out', ())
|
| 840 |
+
types_string = ', '.join(repr(type(arg).__name__) for arg in args)
|
| 841 |
+
return ('operand type(s) all returned NotImplemented from '
|
| 842 |
+
f'__array_ufunc__({ufunc!r}, {method!r}, {args_string}): {types_string}'
|
| 843 |
+
)
|
| 844 |
+
|
| 845 |
+
|
| 846 |
+
def array_function_errmsg_formatter(public_api, types):
|
| 847 |
+
""" Format the error message for when __array_ufunc__ gives up. """
|
| 848 |
+
func_name = f'{public_api.__module__}.{public_api.__name__}'
|
| 849 |
+
return (f"no implementation found for '{func_name}' on types that implement "
|
| 850 |
+
f'__array_function__: {list(types)}')
|
| 851 |
+
|
| 852 |
+
|
| 853 |
+
def _ufunc_doc_signature_formatter(ufunc):
|
| 854 |
+
"""
|
| 855 |
+
Builds a signature string which resembles PEP 457
|
| 856 |
+
|
| 857 |
+
This is used to construct the first line of the docstring
|
| 858 |
+
|
| 859 |
+
Keep in sync with `_ufunc_inspect_signature_builder`.
|
| 860 |
+
"""
|
| 861 |
+
|
| 862 |
+
# input arguments are simple
|
| 863 |
+
if ufunc.nin == 1:
|
| 864 |
+
in_args = 'x'
|
| 865 |
+
else:
|
| 866 |
+
in_args = ', '.join(f'x{i + 1}' for i in range(ufunc.nin))
|
| 867 |
+
|
| 868 |
+
# output arguments are both keyword or positional
|
| 869 |
+
if ufunc.nout == 0:
|
| 870 |
+
out_args = ', /, out=()'
|
| 871 |
+
elif ufunc.nout == 1:
|
| 872 |
+
out_args = ', /, out=None'
|
| 873 |
+
else:
|
| 874 |
+
out_args = '[, {positional}], / [, out={default}]'.format(
|
| 875 |
+
positional=', '.join(
|
| 876 |
+
f'out{i + 1}' for i in range(ufunc.nout)),
|
| 877 |
+
default=repr((None,) * ufunc.nout)
|
| 878 |
+
)
|
| 879 |
+
|
| 880 |
+
# keyword only args depend on whether this is a gufunc
|
| 881 |
+
kwargs = (
|
| 882 |
+
", casting='same_kind'"
|
| 883 |
+
", order='K'"
|
| 884 |
+
", dtype=None"
|
| 885 |
+
", subok=True"
|
| 886 |
+
)
|
| 887 |
+
|
| 888 |
+
# NOTE: gufuncs may or may not support the `axis` parameter
|
| 889 |
+
if ufunc.signature is None:
|
| 890 |
+
kwargs = f", where=True{kwargs}[, signature]"
|
| 891 |
+
else:
|
| 892 |
+
kwargs += "[, signature, axes, axis]"
|
| 893 |
+
|
| 894 |
+
# join all the parts together
|
| 895 |
+
return f'{ufunc.__name__}({in_args}{out_args}, *{kwargs})'
|
| 896 |
+
|
| 897 |
+
|
| 898 |
+
def _ufunc_inspect_signature_builder(ufunc):
|
| 899 |
+
"""
|
| 900 |
+
Builds a ``__signature__`` string.
|
| 901 |
+
|
| 902 |
+
Should be kept in sync with `_ufunc_doc_signature_formatter`.
|
| 903 |
+
"""
|
| 904 |
+
|
| 905 |
+
from inspect import Parameter, Signature
|
| 906 |
+
|
| 907 |
+
params = []
|
| 908 |
+
|
| 909 |
+
# positional-only input parameters
|
| 910 |
+
if ufunc.nin == 1:
|
| 911 |
+
params.append(Parameter("x", Parameter.POSITIONAL_ONLY))
|
| 912 |
+
else:
|
| 913 |
+
params.extend(
|
| 914 |
+
Parameter(f"x{i}", Parameter.POSITIONAL_ONLY)
|
| 915 |
+
for i in range(1, ufunc.nin + 1)
|
| 916 |
+
)
|
| 917 |
+
|
| 918 |
+
# for the sake of simplicity, we only consider a single output parameter
|
| 919 |
+
if ufunc.nout == 1:
|
| 920 |
+
out_default = None
|
| 921 |
+
else:
|
| 922 |
+
out_default = (None,) * ufunc.nout
|
| 923 |
+
params.append(
|
| 924 |
+
Parameter("out", Parameter.POSITIONAL_OR_KEYWORD, default=out_default),
|
| 925 |
+
)
|
| 926 |
+
|
| 927 |
+
if ufunc.signature is None:
|
| 928 |
+
params.append(Parameter("where", Parameter.KEYWORD_ONLY, default=True))
|
| 929 |
+
else:
|
| 930 |
+
# NOTE: not all gufuncs support the `axis` parameters
|
| 931 |
+
params.append(Parameter("axes", Parameter.KEYWORD_ONLY, default=_NoValue))
|
| 932 |
+
params.append(Parameter("axis", Parameter.KEYWORD_ONLY, default=_NoValue))
|
| 933 |
+
params.append(Parameter("keepdims", Parameter.KEYWORD_ONLY, default=False))
|
| 934 |
+
|
| 935 |
+
params.extend((
|
| 936 |
+
Parameter("casting", Parameter.KEYWORD_ONLY, default='same_kind'),
|
| 937 |
+
Parameter("order", Parameter.KEYWORD_ONLY, default='K'),
|
| 938 |
+
Parameter("dtype", Parameter.KEYWORD_ONLY, default=None),
|
| 939 |
+
Parameter("subok", Parameter.KEYWORD_ONLY, default=True),
|
| 940 |
+
Parameter("signature", Parameter.KEYWORD_ONLY, default=None),
|
| 941 |
+
))
|
| 942 |
+
|
| 943 |
+
return Signature(params)
|
| 944 |
+
|
| 945 |
+
|
| 946 |
+
def npy_ctypes_check(cls):
|
| 947 |
+
# determine if a class comes from ctypes, in order to work around
|
| 948 |
+
# a bug in the buffer protocol for those objects, bpo-10746
|
| 949 |
+
try:
|
| 950 |
+
# ctypes class are new-style, so have an __mro__. This probably fails
|
| 951 |
+
# for ctypes classes with multiple inheritance.
|
| 952 |
+
# # (..., _ctypes._CData, object)
|
| 953 |
+
ctype_base = cls.__mro__[-2]
|
| 954 |
+
# right now, they're part of the _ctypes module
|
| 955 |
+
return '_ctypes' in ctype_base.__module__
|
| 956 |
+
except Exception:
|
| 957 |
+
return False
|
| 958 |
+
|
| 959 |
+
# used to handle the _NoValue default argument for na_object
|
| 960 |
+
# in the C implementation of the __reduce__ method for stringdtype
|
| 961 |
+
def _convert_to_stringdtype_kwargs(coerce, na_object=_NoValue):
|
| 962 |
+
if na_object is _NoValue:
|
| 963 |
+
return StringDType(coerce=coerce)
|
| 964 |
+
return StringDType(coerce=coerce, na_object=na_object)
|
v12x/pylib/numpy/_core/_methods.py
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Array methods which are called by both the C-code for the method
|
| 3 |
+
and the Python code for the NumPy-namespace function
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
import os
|
| 7 |
+
import pickle
|
| 8 |
+
import warnings
|
| 9 |
+
from contextlib import nullcontext
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
from numpy._core import multiarray as mu, numerictypes as nt, umath as um
|
| 13 |
+
from numpy._core.multiarray import asanyarray
|
| 14 |
+
from numpy._globals import _NoValue
|
| 15 |
+
|
| 16 |
+
# save those O(100) nanoseconds!
|
| 17 |
+
bool_dt = mu.dtype("bool")
|
| 18 |
+
umr_maximum = um.maximum.reduce
|
| 19 |
+
umr_minimum = um.minimum.reduce
|
| 20 |
+
umr_sum = um.add.reduce
|
| 21 |
+
umr_prod = um.multiply.reduce
|
| 22 |
+
umr_bitwise_count = um.bitwise_count
|
| 23 |
+
umr_any = um.logical_or.reduce
|
| 24 |
+
umr_all = um.logical_and.reduce
|
| 25 |
+
|
| 26 |
+
# Complex types to -> (2,)float view for fast-path computation in _var()
|
| 27 |
+
_complex_to_float = {
|
| 28 |
+
nt.dtype(nt.csingle): nt.dtype(nt.single),
|
| 29 |
+
nt.dtype(nt.cdouble): nt.dtype(nt.double),
|
| 30 |
+
}
|
| 31 |
+
# Special case for windows: ensure double takes precedence
|
| 32 |
+
if nt.dtype(nt.longdouble) != nt.dtype(nt.double):
|
| 33 |
+
_complex_to_float.update({
|
| 34 |
+
nt.dtype(nt.clongdouble): nt.dtype(nt.longdouble),
|
| 35 |
+
})
|
| 36 |
+
|
| 37 |
+
# avoid keyword arguments to speed up parsing, saves about 15%-20% for very
|
| 38 |
+
# small reductions
|
| 39 |
+
def _amax(a, axis=None, out=None, keepdims=False,
|
| 40 |
+
initial=_NoValue, where=True):
|
| 41 |
+
return umr_maximum(a, axis, None, out, keepdims, initial, where)
|
| 42 |
+
|
| 43 |
+
def _amin(a, axis=None, out=None, keepdims=False,
|
| 44 |
+
initial=_NoValue, where=True):
|
| 45 |
+
return umr_minimum(a, axis, None, out, keepdims, initial, where)
|
| 46 |
+
|
| 47 |
+
def _sum(a, axis=None, dtype=None, out=None, keepdims=False,
|
| 48 |
+
initial=_NoValue, where=True):
|
| 49 |
+
return umr_sum(a, axis, dtype, out, keepdims, initial, where)
|
| 50 |
+
|
| 51 |
+
def _prod(a, axis=None, dtype=None, out=None, keepdims=False,
|
| 52 |
+
initial=_NoValue, where=True):
|
| 53 |
+
return umr_prod(a, axis, dtype, out, keepdims, initial, where)
|
| 54 |
+
|
| 55 |
+
def _any(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
|
| 56 |
+
# By default, return a boolean for any and all
|
| 57 |
+
if dtype is None:
|
| 58 |
+
dtype = bool_dt
|
| 59 |
+
# Parsing keyword arguments is currently fairly slow, so avoid it for now
|
| 60 |
+
if where is True:
|
| 61 |
+
return umr_any(a, axis, dtype, out, keepdims)
|
| 62 |
+
return umr_any(a, axis, dtype, out, keepdims, where=where)
|
| 63 |
+
|
| 64 |
+
def _all(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
|
| 65 |
+
# By default, return a boolean for any and all
|
| 66 |
+
if dtype is None:
|
| 67 |
+
dtype = bool_dt
|
| 68 |
+
# Parsing keyword arguments is currently fairly slow, so avoid it for now
|
| 69 |
+
if where is True:
|
| 70 |
+
return umr_all(a, axis, dtype, out, keepdims)
|
| 71 |
+
return umr_all(a, axis, dtype, out, keepdims, where=where)
|
| 72 |
+
|
| 73 |
+
def _count_reduce_items(arr, axis, keepdims=False, where=True):
|
| 74 |
+
# fast-path for the default case
|
| 75 |
+
if where is True:
|
| 76 |
+
# no boolean mask given, calculate items according to axis
|
| 77 |
+
if axis is None:
|
| 78 |
+
axis = tuple(range(arr.ndim))
|
| 79 |
+
elif not isinstance(axis, tuple):
|
| 80 |
+
axis = (axis,)
|
| 81 |
+
items = 1
|
| 82 |
+
for ax in axis:
|
| 83 |
+
items *= arr.shape[mu.normalize_axis_index(ax, arr.ndim)]
|
| 84 |
+
items = nt.intp(items)
|
| 85 |
+
else:
|
| 86 |
+
# TODO: Optimize case when `where` is broadcast along a non-reduction
|
| 87 |
+
# axis and full sum is more excessive than needed.
|
| 88 |
+
|
| 89 |
+
# guarded to protect circular imports
|
| 90 |
+
from numpy.lib._stride_tricks_impl import broadcast_to
|
| 91 |
+
# count True values in (potentially broadcasted) boolean mask
|
| 92 |
+
items = umr_sum(broadcast_to(where, arr.shape), axis, nt.intp, None,
|
| 93 |
+
keepdims)
|
| 94 |
+
return items
|
| 95 |
+
|
| 96 |
+
def _clip(a, min=None, max=None, out=None, **kwargs):
|
| 97 |
+
if a.dtype.kind in "iu":
|
| 98 |
+
# If min/max is a Python integer, deal with out-of-bound values here.
|
| 99 |
+
# (This enforces NEP 50 rules as no value based promotion is done.)
|
| 100 |
+
if type(min) is int and min <= np.iinfo(a.dtype).min:
|
| 101 |
+
min = None
|
| 102 |
+
if type(max) is int and max >= np.iinfo(a.dtype).max:
|
| 103 |
+
max = None
|
| 104 |
+
|
| 105 |
+
if min is None and max is None:
|
| 106 |
+
# return identity
|
| 107 |
+
return um.positive(a, out=out, **kwargs)
|
| 108 |
+
elif min is None:
|
| 109 |
+
return um.minimum(a, max, out=out, **kwargs)
|
| 110 |
+
elif max is None:
|
| 111 |
+
return um.maximum(a, min, out=out, **kwargs)
|
| 112 |
+
else:
|
| 113 |
+
return um.clip(a, min, max, out=out, **kwargs)
|
| 114 |
+
|
| 115 |
+
def _mean(a, axis=None, dtype=None, out=None, keepdims=False, *, where=True):
|
| 116 |
+
arr = asanyarray(a)
|
| 117 |
+
|
| 118 |
+
is_float16_result = False
|
| 119 |
+
|
| 120 |
+
rcount = _count_reduce_items(arr, axis, keepdims=keepdims, where=where)
|
| 121 |
+
if rcount == 0 if where is True else umr_any(rcount == 0, axis=None):
|
| 122 |
+
warnings.warn("Mean of empty slice", RuntimeWarning, stacklevel=2)
|
| 123 |
+
|
| 124 |
+
# Cast bool, unsigned int, and int to float64 by default
|
| 125 |
+
if dtype is None:
|
| 126 |
+
if issubclass(arr.dtype.type, (nt.integer, nt.bool)):
|
| 127 |
+
dtype = mu.dtype('f8')
|
| 128 |
+
elif issubclass(arr.dtype.type, nt.float16):
|
| 129 |
+
dtype = mu.dtype('f4')
|
| 130 |
+
is_float16_result = True
|
| 131 |
+
|
| 132 |
+
ret = umr_sum(arr, axis, dtype, out, keepdims, where=where)
|
| 133 |
+
if isinstance(ret, mu.ndarray):
|
| 134 |
+
ret = um.true_divide(
|
| 135 |
+
ret, rcount, out=ret, casting='unsafe', subok=False)
|
| 136 |
+
if is_float16_result and out is None:
|
| 137 |
+
ret = arr.dtype.type(ret)
|
| 138 |
+
elif hasattr(ret, 'dtype'):
|
| 139 |
+
if is_float16_result:
|
| 140 |
+
ret = arr.dtype.type(ret / rcount)
|
| 141 |
+
else:
|
| 142 |
+
ret = ret.dtype.type(ret / rcount)
|
| 143 |
+
else:
|
| 144 |
+
ret = ret / rcount
|
| 145 |
+
|
| 146 |
+
return ret
|
| 147 |
+
|
| 148 |
+
def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *,
|
| 149 |
+
where=True, mean=None):
|
| 150 |
+
arr = asanyarray(a)
|
| 151 |
+
|
| 152 |
+
rcount = _count_reduce_items(arr, axis, keepdims=keepdims, where=where)
|
| 153 |
+
# Make this warning show up on top.
|
| 154 |
+
if ddof >= rcount if where is True else umr_any(ddof >= rcount, axis=None):
|
| 155 |
+
warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning,
|
| 156 |
+
stacklevel=2)
|
| 157 |
+
|
| 158 |
+
# Cast bool, unsigned int, and int to float64 by default
|
| 159 |
+
if dtype is None and issubclass(arr.dtype.type, (nt.integer, nt.bool)):
|
| 160 |
+
dtype = mu.dtype('f8')
|
| 161 |
+
|
| 162 |
+
if mean is not None:
|
| 163 |
+
arrmean = mean
|
| 164 |
+
else:
|
| 165 |
+
# Compute the mean.
|
| 166 |
+
# Note that if dtype is not of inexact type then arraymean will
|
| 167 |
+
# not be either.
|
| 168 |
+
arrmean = umr_sum(arr, axis, dtype, keepdims=True, where=where)
|
| 169 |
+
# The shape of rcount has to match arrmean to not change the shape of
|
| 170 |
+
# out in broadcasting. Otherwise, it cannot be stored back to arrmean.
|
| 171 |
+
if rcount.ndim == 0:
|
| 172 |
+
# fast-path for default case when where is True
|
| 173 |
+
div = rcount
|
| 174 |
+
else:
|
| 175 |
+
# matching rcount to arrmean when where is specified as array
|
| 176 |
+
div = rcount.reshape(arrmean.shape)
|
| 177 |
+
if isinstance(arrmean, mu.ndarray):
|
| 178 |
+
arrmean = um.true_divide(arrmean, div, out=arrmean,
|
| 179 |
+
casting='unsafe', subok=False)
|
| 180 |
+
elif hasattr(arrmean, "dtype"):
|
| 181 |
+
arrmean = arrmean.dtype.type(arrmean / rcount)
|
| 182 |
+
else:
|
| 183 |
+
arrmean = arrmean / rcount
|
| 184 |
+
|
| 185 |
+
# Compute sum of squared deviations from mean
|
| 186 |
+
# Note that x may not be inexact and that we need it to be an array,
|
| 187 |
+
# not a scalar.
|
| 188 |
+
x = um.subtract(arr, arrmean, out=...)
|
| 189 |
+
if issubclass(arr.dtype.type, (nt.floating, nt.integer)):
|
| 190 |
+
x = um.square(x, out=x)
|
| 191 |
+
# Fast-paths for built-in complex types
|
| 192 |
+
elif (_float_dtype := _complex_to_float.get(x.dtype)) is not None:
|
| 193 |
+
xv = x.view(dtype=(_float_dtype, (2,)))
|
| 194 |
+
um.square(xv, out=xv)
|
| 195 |
+
x = um.add(xv[..., 0], xv[..., 1], out=x.real)
|
| 196 |
+
# Most general case; includes handling object arrays containing imaginary
|
| 197 |
+
# numbers and complex types with non-native byteorder
|
| 198 |
+
else:
|
| 199 |
+
x = um.multiply(x, um.conjugate(x), out=x).real
|
| 200 |
+
|
| 201 |
+
ret = umr_sum(x, axis, dtype, out, keepdims=keepdims, where=where)
|
| 202 |
+
|
| 203 |
+
# Compute degrees of freedom and make sure it is not negative.
|
| 204 |
+
rcount = um.maximum(rcount - ddof, 0)
|
| 205 |
+
|
| 206 |
+
# divide by degrees of freedom
|
| 207 |
+
if isinstance(ret, mu.ndarray):
|
| 208 |
+
ret = um.true_divide(
|
| 209 |
+
ret, rcount, out=ret, casting='unsafe', subok=False)
|
| 210 |
+
elif hasattr(ret, 'dtype'):
|
| 211 |
+
ret = ret.dtype.type(ret / rcount)
|
| 212 |
+
else:
|
| 213 |
+
ret = ret / rcount
|
| 214 |
+
|
| 215 |
+
return ret
|
| 216 |
+
|
| 217 |
+
def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *,
|
| 218 |
+
where=True, mean=None):
|
| 219 |
+
ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
|
| 220 |
+
keepdims=keepdims, where=where, mean=mean)
|
| 221 |
+
|
| 222 |
+
if isinstance(ret, mu.ndarray):
|
| 223 |
+
ret = um.sqrt(ret, out=ret)
|
| 224 |
+
elif hasattr(ret, 'dtype'):
|
| 225 |
+
ret = ret.dtype.type(um.sqrt(ret))
|
| 226 |
+
else:
|
| 227 |
+
ret = um.sqrt(ret)
|
| 228 |
+
|
| 229 |
+
return ret
|
| 230 |
+
|
| 231 |
+
def _ptp(a, axis=None, out=None, keepdims=False):
|
| 232 |
+
return um.subtract(
|
| 233 |
+
umr_maximum(a, axis, None, out, keepdims),
|
| 234 |
+
umr_minimum(a, axis, None, None, keepdims),
|
| 235 |
+
out
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
def _dump(self, file, protocol=2):
|
| 239 |
+
if hasattr(file, 'write'):
|
| 240 |
+
ctx = nullcontext(file)
|
| 241 |
+
else:
|
| 242 |
+
ctx = open(os.fspath(file), "wb")
|
| 243 |
+
with ctx as f:
|
| 244 |
+
pickle.dump(self, f, protocol=protocol)
|
| 245 |
+
|
| 246 |
+
def _dumps(self, protocol=2):
|
| 247 |
+
return pickle.dumps(self, protocol=protocol)
|
| 248 |
+
|
| 249 |
+
def _bitwise_count(a, out=None, *, where=True, casting='same_kind',
|
| 250 |
+
order='K', dtype=None, subok=True):
|
| 251 |
+
return umr_bitwise_count(a, out, where=where, casting=casting,
|
| 252 |
+
order=order, dtype=dtype, subok=subok)
|
v12x/pylib/numpy/_core/_string_helpers.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
String-handling utilities to avoid locale-dependence.
|
| 3 |
+
|
| 4 |
+
Used primarily to generate type name aliases.
|
| 5 |
+
"""
|
| 6 |
+
# "import string" is costly to import!
|
| 7 |
+
# Construct the translation tables directly
|
| 8 |
+
# "A" = chr(65), "a" = chr(97)
|
| 9 |
+
_all_chars = tuple(map(chr, range(256)))
|
| 10 |
+
_ascii_upper = _all_chars[65:65 + 26]
|
| 11 |
+
_ascii_lower = _all_chars[97:97 + 26]
|
| 12 |
+
LOWER_TABLE = _all_chars[:65] + _ascii_lower + _all_chars[65 + 26:]
|
| 13 |
+
UPPER_TABLE = _all_chars[:97] + _ascii_upper + _all_chars[97 + 26:]
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def english_lower(s):
|
| 17 |
+
""" Apply English case rules to convert ASCII strings to all lower case.
|
| 18 |
+
|
| 19 |
+
This is an internal utility function to replace calls to str.lower() such
|
| 20 |
+
that we can avoid changing behavior with changing locales. In particular,
|
| 21 |
+
Turkish has distinct dotted and dotless variants of the Latin letter "I" in
|
| 22 |
+
both lowercase and uppercase. Thus, "I".lower() != "i" in a "tr" locale.
|
| 23 |
+
|
| 24 |
+
Parameters
|
| 25 |
+
----------
|
| 26 |
+
s : str
|
| 27 |
+
|
| 28 |
+
Returns
|
| 29 |
+
-------
|
| 30 |
+
lowered : str
|
| 31 |
+
|
| 32 |
+
Examples
|
| 33 |
+
--------
|
| 34 |
+
>>> from numpy._core.numerictypes import english_lower
|
| 35 |
+
>>> english_lower('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_')
|
| 36 |
+
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789_'
|
| 37 |
+
>>> english_lower('')
|
| 38 |
+
''
|
| 39 |
+
"""
|
| 40 |
+
lowered = s.translate(LOWER_TABLE)
|
| 41 |
+
return lowered
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def english_upper(s):
|
| 45 |
+
""" Apply English case rules to convert ASCII strings to all upper case.
|
| 46 |
+
|
| 47 |
+
This is an internal utility function to replace calls to str.upper() such
|
| 48 |
+
that we can avoid changing behavior with changing locales. In particular,
|
| 49 |
+
Turkish has distinct dotted and dotless variants of the Latin letter "I" in
|
| 50 |
+
both lowercase and uppercase. Thus, "i".upper() != "I" in a "tr" locale.
|
| 51 |
+
|
| 52 |
+
Parameters
|
| 53 |
+
----------
|
| 54 |
+
s : str
|
| 55 |
+
|
| 56 |
+
Returns
|
| 57 |
+
-------
|
| 58 |
+
uppered : str
|
| 59 |
+
|
| 60 |
+
Examples
|
| 61 |
+
--------
|
| 62 |
+
>>> from numpy._core.numerictypes import english_upper
|
| 63 |
+
>>> english_upper('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_')
|
| 64 |
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
|
| 65 |
+
>>> english_upper('')
|
| 66 |
+
''
|
| 67 |
+
"""
|
| 68 |
+
uppered = s.translate(UPPER_TABLE)
|
| 69 |
+
return uppered
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def english_capitalize(s):
|
| 73 |
+
""" Apply English case rules to convert the first character of an ASCII
|
| 74 |
+
string to upper case.
|
| 75 |
+
|
| 76 |
+
This is an internal utility function to replace calls to str.capitalize()
|
| 77 |
+
such that we can avoid changing behavior with changing locales.
|
| 78 |
+
|
| 79 |
+
Parameters
|
| 80 |
+
----------
|
| 81 |
+
s : str
|
| 82 |
+
|
| 83 |
+
Returns
|
| 84 |
+
-------
|
| 85 |
+
capitalized : str
|
| 86 |
+
|
| 87 |
+
Examples
|
| 88 |
+
--------
|
| 89 |
+
>>> from numpy._core.numerictypes import english_capitalize
|
| 90 |
+
>>> english_capitalize('int8')
|
| 91 |
+
'Int8'
|
| 92 |
+
>>> english_capitalize('Int8')
|
| 93 |
+
'Int8'
|
| 94 |
+
>>> english_capitalize('')
|
| 95 |
+
''
|
| 96 |
+
"""
|
| 97 |
+
if s:
|
| 98 |
+
return english_upper(s[0]) + s[1:]
|
| 99 |
+
else:
|
| 100 |
+
return s
|
v12x/pylib/numpy/_core/_type_aliases.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Due to compatibility, numpy has a very large number of different naming
|
| 3 |
+
conventions for the scalar types (those subclassing from `numpy.generic`).
|
| 4 |
+
This file produces a convoluted set of dictionaries mapping names to types,
|
| 5 |
+
and sometimes other mappings too.
|
| 6 |
+
|
| 7 |
+
.. data:: allTypes
|
| 8 |
+
A dictionary of names to types that will be exposed as attributes through
|
| 9 |
+
``np._core.numerictypes.*``
|
| 10 |
+
|
| 11 |
+
.. data:: sctypeDict
|
| 12 |
+
Similar to `allTypes`, but maps a broader set of aliases to their types.
|
| 13 |
+
|
| 14 |
+
.. data:: sctypes
|
| 15 |
+
A dictionary keyed by a "type group" string, providing a list of types
|
| 16 |
+
under that group.
|
| 17 |
+
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import numpy._core.multiarray as ma
|
| 21 |
+
from numpy._core.multiarray import dtype, typeinfo
|
| 22 |
+
|
| 23 |
+
######################################
|
| 24 |
+
# Building `sctypeDict` and `allTypes`
|
| 25 |
+
######################################
|
| 26 |
+
|
| 27 |
+
sctypeDict = {}
|
| 28 |
+
allTypes = {}
|
| 29 |
+
c_names_dict = {}
|
| 30 |
+
|
| 31 |
+
_abstract_type_names = {
|
| 32 |
+
"generic", "integer", "inexact", "floating", "number",
|
| 33 |
+
"flexible", "character", "complexfloating", "unsignedinteger",
|
| 34 |
+
"signedinteger"
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
for _abstract_type_name in _abstract_type_names:
|
| 38 |
+
allTypes[_abstract_type_name] = getattr(ma, _abstract_type_name)
|
| 39 |
+
del _abstract_type_name
|
| 40 |
+
|
| 41 |
+
for k, v in typeinfo.items():
|
| 42 |
+
if k.startswith("NPY_") and v not in c_names_dict:
|
| 43 |
+
c_names_dict[k[4:]] = v
|
| 44 |
+
else:
|
| 45 |
+
concrete_type = v.type
|
| 46 |
+
allTypes[k] = concrete_type
|
| 47 |
+
sctypeDict[k] = concrete_type
|
| 48 |
+
del concrete_type
|
| 49 |
+
del k, v
|
| 50 |
+
|
| 51 |
+
_aliases = {
|
| 52 |
+
"double": "float64",
|
| 53 |
+
"cdouble": "complex128",
|
| 54 |
+
"single": "float32",
|
| 55 |
+
"csingle": "complex64",
|
| 56 |
+
"half": "float16",
|
| 57 |
+
"bool_": "bool",
|
| 58 |
+
# Default integer:
|
| 59 |
+
"int_": "intp",
|
| 60 |
+
"uint": "uintp",
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
for k, v in _aliases.items():
|
| 64 |
+
sctypeDict[k] = allTypes[v]
|
| 65 |
+
allTypes[k] = allTypes[v]
|
| 66 |
+
del k, v
|
| 67 |
+
|
| 68 |
+
# extra aliases are added only to `sctypeDict`
|
| 69 |
+
# to support dtype name access, such as`np.dtype("float")`
|
| 70 |
+
_extra_aliases = {
|
| 71 |
+
"float": "float64",
|
| 72 |
+
"complex": "complex128",
|
| 73 |
+
"object": "object_",
|
| 74 |
+
"bytes": "bytes_",
|
| 75 |
+
"int": "int_",
|
| 76 |
+
"str": "str_",
|
| 77 |
+
"unicode": "str_",
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
for k, v in _extra_aliases.items():
|
| 81 |
+
sctypeDict[k] = allTypes[v]
|
| 82 |
+
del k, v
|
| 83 |
+
|
| 84 |
+
# include extended precision sized aliases
|
| 85 |
+
for is_complex, full_name in [(False, "longdouble"), (True, "clongdouble")]:
|
| 86 |
+
longdouble_type = allTypes[full_name]
|
| 87 |
+
|
| 88 |
+
bits = dtype(longdouble_type).itemsize * 8
|
| 89 |
+
base_name = "complex" if is_complex else "float"
|
| 90 |
+
extended_prec_name = f"{base_name}{bits}"
|
| 91 |
+
if extended_prec_name not in allTypes:
|
| 92 |
+
sctypeDict[extended_prec_name] = longdouble_type
|
| 93 |
+
allTypes[extended_prec_name] = longdouble_type
|
| 94 |
+
|
| 95 |
+
del is_complex, full_name, longdouble_type, bits, base_name, extended_prec_name
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
####################
|
| 99 |
+
# Building `sctypes`
|
| 100 |
+
####################
|
| 101 |
+
|
| 102 |
+
sctypes = {"int": set(), "uint": set(), "float": set(),
|
| 103 |
+
"complex": set(), "others": set()}
|
| 104 |
+
|
| 105 |
+
for type_info in typeinfo.values():
|
| 106 |
+
if type_info.kind in ["M", "m"]: # exclude timedelta and datetime
|
| 107 |
+
continue
|
| 108 |
+
|
| 109 |
+
concrete_type = type_info.type
|
| 110 |
+
|
| 111 |
+
# find proper group for each concrete type
|
| 112 |
+
for type_group, abstract_type in [
|
| 113 |
+
("int", ma.signedinteger), ("uint", ma.unsignedinteger),
|
| 114 |
+
("float", ma.floating), ("complex", ma.complexfloating),
|
| 115 |
+
("others", ma.generic)
|
| 116 |
+
]:
|
| 117 |
+
if issubclass(concrete_type, abstract_type):
|
| 118 |
+
sctypes[type_group].add(concrete_type)
|
| 119 |
+
del type_group, abstract_type
|
| 120 |
+
break
|
| 121 |
+
|
| 122 |
+
del type_info, concrete_type
|
| 123 |
+
|
| 124 |
+
# sort sctype groups by bitsize, then by name (sort needs to be deterministic)
|
| 125 |
+
for sctype_key in sctypes.keys():
|
| 126 |
+
sctype_list = list(sctypes[sctype_key])
|
| 127 |
+
sctype_list.sort(key=lambda x: (dtype(x).itemsize, x.__name__))
|
| 128 |
+
sctypes[sctype_key] = sctype_list
|
| 129 |
+
|
| 130 |
+
del sctype_key, sctype_list
|
v12x/pylib/numpy/_core/_ufunc_config.py
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Functions for changing global ufunc configuration
|
| 3 |
+
|
| 4 |
+
This provides helpers which wrap `_get_extobj_dict` and `_make_extobj`, and
|
| 5 |
+
`_extobj_contextvar` from umath.
|
| 6 |
+
"""
|
| 7 |
+
import functools
|
| 8 |
+
|
| 9 |
+
from numpy._utils import set_module
|
| 10 |
+
|
| 11 |
+
from .umath import _extobj_contextvar, _get_extobj_dict, _make_extobj
|
| 12 |
+
|
| 13 |
+
__all__ = [
|
| 14 |
+
"seterr", "geterr", "setbufsize", "getbufsize", "seterrcall", "geterrcall",
|
| 15 |
+
"errstate"
|
| 16 |
+
]
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
@set_module('numpy')
|
| 20 |
+
def seterr(all=None, divide=None, over=None, under=None, invalid=None):
|
| 21 |
+
"""
|
| 22 |
+
Set how floating-point errors are handled.
|
| 23 |
+
|
| 24 |
+
Note that operations on integer scalar types (such as `int16`) are
|
| 25 |
+
handled like floating point, and are affected by these settings.
|
| 26 |
+
|
| 27 |
+
Parameters
|
| 28 |
+
----------
|
| 29 |
+
all : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
|
| 30 |
+
Set treatment for all types of floating-point errors at once:
|
| 31 |
+
|
| 32 |
+
- ignore: Take no action when the exception occurs.
|
| 33 |
+
- warn: Print a :exc:`RuntimeWarning` (via the Python `warnings`
|
| 34 |
+
module).
|
| 35 |
+
- raise: Raise a :exc:`FloatingPointError`.
|
| 36 |
+
- call: Call a function specified using the `seterrcall` function.
|
| 37 |
+
- print: Print a warning directly to ``stdout``.
|
| 38 |
+
- log: Record error in a Log object specified by `seterrcall`.
|
| 39 |
+
|
| 40 |
+
The default is not to change the current behavior.
|
| 41 |
+
divide : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
|
| 42 |
+
Treatment for division by zero.
|
| 43 |
+
over : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
|
| 44 |
+
Treatment for floating-point overflow.
|
| 45 |
+
under : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
|
| 46 |
+
Treatment for floating-point underflow.
|
| 47 |
+
invalid : {'ignore', 'warn', 'raise', 'call', 'print', 'log'}, optional
|
| 48 |
+
Treatment for invalid floating-point operation.
|
| 49 |
+
|
| 50 |
+
Returns
|
| 51 |
+
-------
|
| 52 |
+
old_settings : dict
|
| 53 |
+
Dictionary containing the old settings.
|
| 54 |
+
|
| 55 |
+
See also
|
| 56 |
+
--------
|
| 57 |
+
seterrcall : Set a callback function for the 'call' mode.
|
| 58 |
+
geterr, geterrcall, errstate
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
Notes
|
| 62 |
+
-----
|
| 63 |
+
The floating-point exceptions are defined in the IEEE 754 standard [1]_:
|
| 64 |
+
|
| 65 |
+
- Division by zero: infinite result obtained from finite numbers.
|
| 66 |
+
- Overflow: result too large to be expressed.
|
| 67 |
+
- Underflow: result so close to zero that some precision
|
| 68 |
+
was lost.
|
| 69 |
+
- Invalid operation: result is not an expressible number, typically
|
| 70 |
+
indicates that a NaN was produced.
|
| 71 |
+
|
| 72 |
+
**Concurrency note:** see :ref:`fp_error_handling`
|
| 73 |
+
|
| 74 |
+
.. [1] https://en.wikipedia.org/wiki/IEEE_754
|
| 75 |
+
|
| 76 |
+
Examples
|
| 77 |
+
--------
|
| 78 |
+
>>> import numpy as np
|
| 79 |
+
>>> orig_settings = np.seterr(all='ignore') # seterr to known value
|
| 80 |
+
>>> np.int16(32000) * np.int16(3)
|
| 81 |
+
np.int16(30464)
|
| 82 |
+
>>> np.seterr(over='raise')
|
| 83 |
+
{'divide': 'ignore', 'over': 'ignore', 'under': 'ignore', 'invalid': 'ignore'}
|
| 84 |
+
>>> old_settings = np.seterr(all='warn', over='raise')
|
| 85 |
+
>>> np.int16(32000) * np.int16(3)
|
| 86 |
+
Traceback (most recent call last):
|
| 87 |
+
File "<stdin>", line 1, in <module>
|
| 88 |
+
FloatingPointError: overflow encountered in scalar multiply
|
| 89 |
+
|
| 90 |
+
>>> old_settings = np.seterr(all='print')
|
| 91 |
+
>>> np.geterr()
|
| 92 |
+
{'divide': 'print', 'over': 'print', 'under': 'print', 'invalid': 'print'}
|
| 93 |
+
>>> np.int16(32000) * np.int16(3)
|
| 94 |
+
np.int16(30464)
|
| 95 |
+
>>> np.seterr(**orig_settings) # restore original
|
| 96 |
+
{'divide': 'print', 'over': 'print', 'under': 'print', 'invalid': 'print'}
|
| 97 |
+
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
old = _get_extobj_dict()
|
| 101 |
+
# The errstate doesn't include call and bufsize, so pop them:
|
| 102 |
+
old.pop("call", None)
|
| 103 |
+
old.pop("bufsize", None)
|
| 104 |
+
|
| 105 |
+
extobj = _make_extobj(
|
| 106 |
+
all=all, divide=divide, over=over, under=under, invalid=invalid)
|
| 107 |
+
_extobj_contextvar.set(extobj)
|
| 108 |
+
return old
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
@set_module('numpy')
|
| 112 |
+
def geterr():
|
| 113 |
+
"""
|
| 114 |
+
Get the current way of handling floating-point errors.
|
| 115 |
+
|
| 116 |
+
Returns
|
| 117 |
+
-------
|
| 118 |
+
res : dict
|
| 119 |
+
A dictionary with keys "divide", "over", "under", and "invalid",
|
| 120 |
+
whose values are from the strings "ignore", "print", "log", "warn",
|
| 121 |
+
"raise", and "call". The keys represent possible floating-point
|
| 122 |
+
exceptions, and the values define how these exceptions are handled.
|
| 123 |
+
|
| 124 |
+
See Also
|
| 125 |
+
--------
|
| 126 |
+
geterrcall, seterr, seterrcall
|
| 127 |
+
|
| 128 |
+
Notes
|
| 129 |
+
-----
|
| 130 |
+
For complete documentation of the types of floating-point exceptions and
|
| 131 |
+
treatment options, see `seterr`.
|
| 132 |
+
|
| 133 |
+
**Concurrency note:** see :doc:`/reference/routines.err`
|
| 134 |
+
|
| 135 |
+
Examples
|
| 136 |
+
--------
|
| 137 |
+
>>> import numpy as np
|
| 138 |
+
>>> np.geterr()
|
| 139 |
+
{'divide': 'warn', 'over': 'warn', 'under': 'ignore', 'invalid': 'warn'}
|
| 140 |
+
>>> np.arange(3.) / np.arange(3.) # doctest: +SKIP
|
| 141 |
+
array([nan, 1., 1.])
|
| 142 |
+
RuntimeWarning: invalid value encountered in divide
|
| 143 |
+
|
| 144 |
+
>>> oldsettings = np.seterr(all='warn', invalid='raise')
|
| 145 |
+
>>> np.geterr()
|
| 146 |
+
{'divide': 'warn', 'over': 'warn', 'under': 'warn', 'invalid': 'raise'}
|
| 147 |
+
>>> np.arange(3.) / np.arange(3.)
|
| 148 |
+
Traceback (most recent call last):
|
| 149 |
+
...
|
| 150 |
+
FloatingPointError: invalid value encountered in divide
|
| 151 |
+
>>> oldsettings = np.seterr(**oldsettings) # restore original
|
| 152 |
+
|
| 153 |
+
"""
|
| 154 |
+
res = _get_extobj_dict()
|
| 155 |
+
# The "geterr" doesn't include call and bufsize,:
|
| 156 |
+
res.pop("call", None)
|
| 157 |
+
res.pop("bufsize", None)
|
| 158 |
+
return res
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
@set_module('numpy')
|
| 162 |
+
def setbufsize(size):
|
| 163 |
+
"""
|
| 164 |
+
Set the size of the buffer used in ufuncs.
|
| 165 |
+
|
| 166 |
+
.. versionchanged:: 2.0
|
| 167 |
+
The scope of setting the buffer is tied to the `numpy.errstate`
|
| 168 |
+
context. Exiting a ``with errstate():`` will also restore the bufsize.
|
| 169 |
+
|
| 170 |
+
Parameters
|
| 171 |
+
----------
|
| 172 |
+
size : int
|
| 173 |
+
Size of buffer.
|
| 174 |
+
|
| 175 |
+
Returns
|
| 176 |
+
-------
|
| 177 |
+
bufsize : int
|
| 178 |
+
Previous size of ufunc buffer in bytes.
|
| 179 |
+
|
| 180 |
+
Notes
|
| 181 |
+
-----
|
| 182 |
+
**Concurrency note:** see :doc:`/reference/routines.err`
|
| 183 |
+
|
| 184 |
+
Examples
|
| 185 |
+
--------
|
| 186 |
+
When exiting a `numpy.errstate` context manager the bufsize is restored:
|
| 187 |
+
|
| 188 |
+
>>> import numpy as np
|
| 189 |
+
>>> with np.errstate():
|
| 190 |
+
... np.setbufsize(4096)
|
| 191 |
+
... print(np.getbufsize())
|
| 192 |
+
...
|
| 193 |
+
8192
|
| 194 |
+
4096
|
| 195 |
+
>>> np.getbufsize()
|
| 196 |
+
8192
|
| 197 |
+
|
| 198 |
+
"""
|
| 199 |
+
if size < 0:
|
| 200 |
+
raise ValueError("buffer size must be non-negative")
|
| 201 |
+
old = _get_extobj_dict()["bufsize"]
|
| 202 |
+
extobj = _make_extobj(bufsize=size)
|
| 203 |
+
_extobj_contextvar.set(extobj)
|
| 204 |
+
return old
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
@set_module('numpy')
|
| 208 |
+
def getbufsize():
|
| 209 |
+
"""
|
| 210 |
+
Return the size of the buffer used in ufuncs.
|
| 211 |
+
|
| 212 |
+
Returns
|
| 213 |
+
-------
|
| 214 |
+
getbufsize : int
|
| 215 |
+
Size of ufunc buffer in bytes.
|
| 216 |
+
|
| 217 |
+
Notes
|
| 218 |
+
-----
|
| 219 |
+
|
| 220 |
+
**Concurrency note:** see :doc:`/reference/routines.err`
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
Examples
|
| 224 |
+
--------
|
| 225 |
+
>>> import numpy as np
|
| 226 |
+
>>> np.getbufsize()
|
| 227 |
+
8192
|
| 228 |
+
|
| 229 |
+
"""
|
| 230 |
+
return _get_extobj_dict()["bufsize"]
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
@set_module('numpy')
|
| 234 |
+
def seterrcall(func):
|
| 235 |
+
"""
|
| 236 |
+
Set the floating-point error callback function or log object.
|
| 237 |
+
|
| 238 |
+
There are two ways to capture floating-point error messages. The first
|
| 239 |
+
is to set the error-handler to 'call', using `seterr`. Then, set
|
| 240 |
+
the function to call using this function.
|
| 241 |
+
|
| 242 |
+
The second is to set the error-handler to 'log', using `seterr`.
|
| 243 |
+
Floating-point errors then trigger a call to the 'write' method of
|
| 244 |
+
the provided object.
|
| 245 |
+
|
| 246 |
+
Parameters
|
| 247 |
+
----------
|
| 248 |
+
func : callable f(err, flag) or object with write method
|
| 249 |
+
Function to call upon floating-point errors ('call'-mode) or
|
| 250 |
+
object whose 'write' method is used to log such message ('log'-mode).
|
| 251 |
+
|
| 252 |
+
The call function takes two arguments. The first is a string describing
|
| 253 |
+
the type of error (such as "divide by zero", "overflow", "underflow",
|
| 254 |
+
or "invalid value"), and the second is the status flag. The flag is a
|
| 255 |
+
byte, whose four least-significant bits indicate the type of error, one
|
| 256 |
+
of "divide", "over", "under", "invalid"::
|
| 257 |
+
|
| 258 |
+
[0 0 0 0 divide over under invalid]
|
| 259 |
+
|
| 260 |
+
In other words, ``flags = divide + 2*over + 4*under + 8*invalid``.
|
| 261 |
+
|
| 262 |
+
If an object is provided, its write method should take one argument,
|
| 263 |
+
a string.
|
| 264 |
+
|
| 265 |
+
Returns
|
| 266 |
+
-------
|
| 267 |
+
h : callable, log instance or None
|
| 268 |
+
The old error handler.
|
| 269 |
+
|
| 270 |
+
See Also
|
| 271 |
+
--------
|
| 272 |
+
seterr, geterr, geterrcall
|
| 273 |
+
|
| 274 |
+
Notes
|
| 275 |
+
-----
|
| 276 |
+
|
| 277 |
+
**Concurrency note:** see :doc:`/reference/routines.err`
|
| 278 |
+
|
| 279 |
+
Examples
|
| 280 |
+
--------
|
| 281 |
+
Callback upon error:
|
| 282 |
+
|
| 283 |
+
>>> def err_handler(type, flag):
|
| 284 |
+
... print("Floating point error (%s), with flag %s" % (type, flag))
|
| 285 |
+
...
|
| 286 |
+
|
| 287 |
+
>>> import numpy as np
|
| 288 |
+
|
| 289 |
+
>>> orig_handler = np.seterrcall(err_handler)
|
| 290 |
+
>>> orig_err = np.seterr(all='call')
|
| 291 |
+
|
| 292 |
+
>>> np.array([1, 2, 3]) / 0.0
|
| 293 |
+
Floating point error (divide by zero), with flag 1
|
| 294 |
+
array([inf, inf, inf])
|
| 295 |
+
|
| 296 |
+
>>> np.seterrcall(orig_handler)
|
| 297 |
+
<function err_handler at 0x...>
|
| 298 |
+
>>> np.seterr(**orig_err)
|
| 299 |
+
{'divide': 'call', 'over': 'call', 'under': 'call', 'invalid': 'call'}
|
| 300 |
+
|
| 301 |
+
Log error message:
|
| 302 |
+
|
| 303 |
+
>>> class Log:
|
| 304 |
+
... def write(self, msg):
|
| 305 |
+
... print("LOG: %s" % msg)
|
| 306 |
+
...
|
| 307 |
+
|
| 308 |
+
>>> log = Log()
|
| 309 |
+
>>> saved_handler = np.seterrcall(log)
|
| 310 |
+
>>> save_err = np.seterr(all='log')
|
| 311 |
+
|
| 312 |
+
>>> np.array([1, 2, 3]) / 0.0
|
| 313 |
+
LOG: Warning: divide by zero encountered in divide
|
| 314 |
+
array([inf, inf, inf])
|
| 315 |
+
|
| 316 |
+
>>> np.seterrcall(orig_handler)
|
| 317 |
+
<numpy.Log object at 0x...>
|
| 318 |
+
>>> np.seterr(**orig_err)
|
| 319 |
+
{'divide': 'log', 'over': 'log', 'under': 'log', 'invalid': 'log'}
|
| 320 |
+
|
| 321 |
+
"""
|
| 322 |
+
old = _get_extobj_dict()["call"]
|
| 323 |
+
extobj = _make_extobj(call=func)
|
| 324 |
+
_extobj_contextvar.set(extobj)
|
| 325 |
+
return old
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
@set_module('numpy')
|
| 329 |
+
def geterrcall():
|
| 330 |
+
"""
|
| 331 |
+
Return the current callback function used on floating-point errors.
|
| 332 |
+
|
| 333 |
+
When the error handling for a floating-point error (one of "divide",
|
| 334 |
+
"over", "under", or "invalid") is set to 'call' or 'log', the function
|
| 335 |
+
that is called or the log instance that is written to is returned by
|
| 336 |
+
`geterrcall`. This function or log instance has been set with
|
| 337 |
+
`seterrcall`.
|
| 338 |
+
|
| 339 |
+
Returns
|
| 340 |
+
-------
|
| 341 |
+
errobj : callable, log instance or None
|
| 342 |
+
The current error handler. If no handler was set through `seterrcall`,
|
| 343 |
+
``None`` is returned.
|
| 344 |
+
|
| 345 |
+
See Also
|
| 346 |
+
--------
|
| 347 |
+
seterrcall, seterr, geterr
|
| 348 |
+
|
| 349 |
+
Notes
|
| 350 |
+
-----
|
| 351 |
+
For complete documentation of the types of floating-point exceptions and
|
| 352 |
+
treatment options, see `seterr`.
|
| 353 |
+
|
| 354 |
+
**Concurrency note:** see :ref:`fp_error_handling`
|
| 355 |
+
|
| 356 |
+
Examples
|
| 357 |
+
--------
|
| 358 |
+
>>> import numpy as np
|
| 359 |
+
>>> np.geterrcall() # we did not yet set a handler, returns None
|
| 360 |
+
|
| 361 |
+
>>> orig_settings = np.seterr(all='call')
|
| 362 |
+
>>> def err_handler(type, flag):
|
| 363 |
+
... print("Floating point error (%s), with flag %s" % (type, flag))
|
| 364 |
+
>>> old_handler = np.seterrcall(err_handler)
|
| 365 |
+
>>> np.array([1, 2, 3]) / 0.0
|
| 366 |
+
Floating point error (divide by zero), with flag 1
|
| 367 |
+
array([inf, inf, inf])
|
| 368 |
+
|
| 369 |
+
>>> cur_handler = np.geterrcall()
|
| 370 |
+
>>> cur_handler is err_handler
|
| 371 |
+
True
|
| 372 |
+
>>> old_settings = np.seterr(**orig_settings) # restore original
|
| 373 |
+
>>> old_handler = np.seterrcall(None) # restore original
|
| 374 |
+
|
| 375 |
+
"""
|
| 376 |
+
return _get_extobj_dict()["call"]
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
class _unspecified:
|
| 380 |
+
pass
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
_Unspecified = _unspecified()
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
@set_module('numpy')
|
| 387 |
+
class errstate:
|
| 388 |
+
"""
|
| 389 |
+
errstate(**kwargs)
|
| 390 |
+
|
| 391 |
+
Context manager for floating-point error handling.
|
| 392 |
+
|
| 393 |
+
Using an instance of `errstate` as a context manager allows statements in
|
| 394 |
+
that context to execute with a known error handling behavior. Upon entering
|
| 395 |
+
the context the error handling is set with `seterr` and `seterrcall`, and
|
| 396 |
+
upon exiting it is reset to what it was before.
|
| 397 |
+
|
| 398 |
+
.. versionchanged:: 1.17.0
|
| 399 |
+
`errstate` is also usable as a function decorator, saving
|
| 400 |
+
a level of indentation if an entire function is wrapped.
|
| 401 |
+
|
| 402 |
+
.. versionchanged:: 2.0
|
| 403 |
+
`errstate` is now fully thread and asyncio safe, but may not be
|
| 404 |
+
entered more than once.
|
| 405 |
+
It is not safe to decorate async functions using ``errstate``.
|
| 406 |
+
|
| 407 |
+
Parameters
|
| 408 |
+
----------
|
| 409 |
+
kwargs : {divide, over, under, invalid}
|
| 410 |
+
Keyword arguments. The valid keywords are the possible floating-point
|
| 411 |
+
exceptions. Each keyword should have a string value that defines the
|
| 412 |
+
treatment for the particular error. Possible values are
|
| 413 |
+
{'ignore', 'warn', 'raise', 'call', 'print', 'log'}.
|
| 414 |
+
|
| 415 |
+
See Also
|
| 416 |
+
--------
|
| 417 |
+
seterr, geterr, seterrcall, geterrcall
|
| 418 |
+
|
| 419 |
+
Notes
|
| 420 |
+
-----
|
| 421 |
+
For complete documentation of the types of floating-point exceptions and
|
| 422 |
+
treatment options, see `seterr`.
|
| 423 |
+
|
| 424 |
+
**Concurrency note:** see :ref:`fp_error_handling`
|
| 425 |
+
|
| 426 |
+
Examples
|
| 427 |
+
--------
|
| 428 |
+
>>> import numpy as np
|
| 429 |
+
>>> olderr = np.seterr(all='ignore') # Set error handling to known state.
|
| 430 |
+
|
| 431 |
+
>>> np.arange(3) / 0.
|
| 432 |
+
array([nan, inf, inf])
|
| 433 |
+
>>> with np.errstate(divide='ignore'):
|
| 434 |
+
... np.arange(3) / 0.
|
| 435 |
+
array([nan, inf, inf])
|
| 436 |
+
|
| 437 |
+
>>> np.sqrt(-1)
|
| 438 |
+
np.float64(nan)
|
| 439 |
+
>>> with np.errstate(invalid='raise'):
|
| 440 |
+
... np.sqrt(-1)
|
| 441 |
+
Traceback (most recent call last):
|
| 442 |
+
File "<stdin>", line 2, in <module>
|
| 443 |
+
FloatingPointError: invalid value encountered in sqrt
|
| 444 |
+
|
| 445 |
+
Outside the context the error handling behavior has not changed:
|
| 446 |
+
|
| 447 |
+
>>> np.geterr()
|
| 448 |
+
{'divide': 'ignore', 'over': 'ignore', 'under': 'ignore', 'invalid': 'ignore'}
|
| 449 |
+
>>> olderr = np.seterr(**olderr) # restore original state
|
| 450 |
+
|
| 451 |
+
"""
|
| 452 |
+
__slots__ = (
|
| 453 |
+
"_all",
|
| 454 |
+
"_call",
|
| 455 |
+
"_divide",
|
| 456 |
+
"_invalid",
|
| 457 |
+
"_over",
|
| 458 |
+
"_token",
|
| 459 |
+
"_under",
|
| 460 |
+
)
|
| 461 |
+
|
| 462 |
+
def __init__(self, *, call=_Unspecified,
|
| 463 |
+
all=None, divide=None, over=None, under=None, invalid=None):
|
| 464 |
+
self._token = None
|
| 465 |
+
self._call = call
|
| 466 |
+
self._all = all
|
| 467 |
+
self._divide = divide
|
| 468 |
+
self._over = over
|
| 469 |
+
self._under = under
|
| 470 |
+
self._invalid = invalid
|
| 471 |
+
|
| 472 |
+
def __enter__(self):
|
| 473 |
+
# Note that __call__ duplicates much of this logic
|
| 474 |
+
if self._token is not None:
|
| 475 |
+
raise TypeError("Cannot enter `np.errstate` twice.")
|
| 476 |
+
if self._call is _Unspecified:
|
| 477 |
+
extobj = _make_extobj(
|
| 478 |
+
all=self._all, divide=self._divide, over=self._over,
|
| 479 |
+
under=self._under, invalid=self._invalid)
|
| 480 |
+
else:
|
| 481 |
+
extobj = _make_extobj(
|
| 482 |
+
call=self._call,
|
| 483 |
+
all=self._all, divide=self._divide, over=self._over,
|
| 484 |
+
under=self._under, invalid=self._invalid)
|
| 485 |
+
|
| 486 |
+
self._token = _extobj_contextvar.set(extobj)
|
| 487 |
+
|
| 488 |
+
def __exit__(self, *exc_info):
|
| 489 |
+
_extobj_contextvar.reset(self._token)
|
| 490 |
+
|
| 491 |
+
def __call__(self, func):
|
| 492 |
+
# We need to customize `__call__` compared to `ContextDecorator`
|
| 493 |
+
# because we must store the token per-thread so cannot store it on
|
| 494 |
+
# the instance (we could create a new instance for this).
|
| 495 |
+
# This duplicates the code from `__enter__`.
|
| 496 |
+
@functools.wraps(func)
|
| 497 |
+
def inner(*args, **kwargs):
|
| 498 |
+
if self._call is _Unspecified:
|
| 499 |
+
extobj = _make_extobj(
|
| 500 |
+
all=self._all, divide=self._divide, over=self._over,
|
| 501 |
+
under=self._under, invalid=self._invalid)
|
| 502 |
+
else:
|
| 503 |
+
extobj = _make_extobj(
|
| 504 |
+
call=self._call,
|
| 505 |
+
all=self._all, divide=self._divide, over=self._over,
|
| 506 |
+
under=self._under, invalid=self._invalid)
|
| 507 |
+
|
| 508 |
+
_token = _extobj_contextvar.set(extobj)
|
| 509 |
+
try:
|
| 510 |
+
# Call the original, decorated, function:
|
| 511 |
+
return func(*args, **kwargs)
|
| 512 |
+
finally:
|
| 513 |
+
_extobj_contextvar.reset(_token)
|
| 514 |
+
|
| 515 |
+
return inner
|
v12x/pylib/numpy/_core/arrayprint.py
ADDED
|
@@ -0,0 +1,1788 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Array printing function
|
| 2 |
+
|
| 3 |
+
$Id: arrayprint.py,v 1.9 2005/09/13 13:58:44 teoliphant Exp $
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
__all__ = ["array2string", "array_str", "array_repr",
|
| 7 |
+
"set_printoptions", "get_printoptions", "printoptions",
|
| 8 |
+
"format_float_positional", "format_float_scientific"]
|
| 9 |
+
__docformat__ = 'restructuredtext'
|
| 10 |
+
|
| 11 |
+
#
|
| 12 |
+
# Written by Konrad Hinsen <hinsenk@ere.umontreal.ca>
|
| 13 |
+
# last revision: 1996-3-13
|
| 14 |
+
# modified by Jim Hugunin 1997-3-3 for repr's and str's (and other details)
|
| 15 |
+
# and by Perry Greenfield 2000-4-1 for numarray
|
| 16 |
+
# and by Travis Oliphant 2005-8-22 for numpy
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
# Note: Both scalartypes.c.src and arrayprint.py implement strs for numpy
|
| 20 |
+
# scalars but for different purposes. scalartypes.c.src has str/reprs for when
|
| 21 |
+
# the scalar is printed on its own, while arrayprint.py has strs for when
|
| 22 |
+
# scalars are printed inside an ndarray. Only the latter strs are currently
|
| 23 |
+
# user-customizable.
|
| 24 |
+
|
| 25 |
+
import functools
|
| 26 |
+
import numbers
|
| 27 |
+
import sys
|
| 28 |
+
|
| 29 |
+
try:
|
| 30 |
+
from _thread import get_ident
|
| 31 |
+
except ImportError:
|
| 32 |
+
from _dummy_thread import get_ident
|
| 33 |
+
|
| 34 |
+
import contextlib
|
| 35 |
+
import operator
|
| 36 |
+
import warnings
|
| 37 |
+
|
| 38 |
+
import numpy as np
|
| 39 |
+
|
| 40 |
+
from . import numerictypes as _nt
|
| 41 |
+
from .fromnumeric import any
|
| 42 |
+
from .multiarray import (
|
| 43 |
+
array,
|
| 44 |
+
datetime_as_string,
|
| 45 |
+
datetime_data,
|
| 46 |
+
dragon4_positional,
|
| 47 |
+
dragon4_scientific,
|
| 48 |
+
ndarray,
|
| 49 |
+
)
|
| 50 |
+
from .numeric import asarray, concatenate, errstate
|
| 51 |
+
from .numerictypes import complex128, flexible, float64, int_
|
| 52 |
+
from .overrides import array_function_dispatch, set_module
|
| 53 |
+
from .printoptions import format_options
|
| 54 |
+
from .umath import absolute, isfinite, isinf, isnat
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def _make_options_dict(precision=None, threshold=None, edgeitems=None,
|
| 58 |
+
linewidth=None, suppress=None, nanstr=None, infstr=None,
|
| 59 |
+
sign=None, formatter=None, floatmode=None, legacy=None,
|
| 60 |
+
override_repr=None):
|
| 61 |
+
"""
|
| 62 |
+
Make a dictionary out of the non-None arguments, plus conversion of
|
| 63 |
+
*legacy* and sanity checks.
|
| 64 |
+
"""
|
| 65 |
+
|
| 66 |
+
options = {k: v for k, v in list(locals().items()) if v is not None}
|
| 67 |
+
|
| 68 |
+
if suppress is not None:
|
| 69 |
+
options['suppress'] = bool(suppress)
|
| 70 |
+
|
| 71 |
+
modes = ['fixed', 'unique', 'maxprec', 'maxprec_equal']
|
| 72 |
+
if floatmode not in modes + [None]:
|
| 73 |
+
raise ValueError("floatmode option must be one of " +
|
| 74 |
+
", ".join(f'"{m}"' for m in modes))
|
| 75 |
+
|
| 76 |
+
if sign not in [None, '-', '+', ' ']:
|
| 77 |
+
raise ValueError("sign option must be one of ' ', '+', or '-'")
|
| 78 |
+
|
| 79 |
+
if legacy is False:
|
| 80 |
+
options['legacy'] = sys.maxsize
|
| 81 |
+
elif legacy == False:
|
| 82 |
+
warnings.warn(
|
| 83 |
+
f"Passing `legacy={legacy!r}` is deprecated.",
|
| 84 |
+
FutureWarning, stacklevel=3
|
| 85 |
+
)
|
| 86 |
+
options['legacy'] = sys.maxsize
|
| 87 |
+
elif legacy == '1.13':
|
| 88 |
+
options['legacy'] = 113
|
| 89 |
+
elif legacy == '1.21':
|
| 90 |
+
options['legacy'] = 121
|
| 91 |
+
elif legacy == '1.25':
|
| 92 |
+
options['legacy'] = 125
|
| 93 |
+
elif legacy == '2.1':
|
| 94 |
+
options['legacy'] = 201
|
| 95 |
+
elif legacy == '2.2':
|
| 96 |
+
options['legacy'] = 202
|
| 97 |
+
elif legacy is None:
|
| 98 |
+
pass # OK, do nothing.
|
| 99 |
+
else:
|
| 100 |
+
warnings.warn(
|
| 101 |
+
"legacy printing option can currently only be '1.13', '1.21', "
|
| 102 |
+
"'1.25', '2.1', '2.2' or `False`", stacklevel=3)
|
| 103 |
+
|
| 104 |
+
if threshold is not None:
|
| 105 |
+
# forbid the bad threshold arg suggested by stack overflow, gh-12351
|
| 106 |
+
if not isinstance(threshold, numbers.Number):
|
| 107 |
+
raise TypeError("threshold must be numeric")
|
| 108 |
+
if np.isnan(threshold):
|
| 109 |
+
raise ValueError("threshold must be non-NAN, try "
|
| 110 |
+
"sys.maxsize for untruncated representation")
|
| 111 |
+
|
| 112 |
+
if precision is not None:
|
| 113 |
+
# forbid the bad precision arg as suggested by issue #18254
|
| 114 |
+
try:
|
| 115 |
+
options['precision'] = operator.index(precision)
|
| 116 |
+
except TypeError as e:
|
| 117 |
+
raise TypeError('precision must be an integer') from e
|
| 118 |
+
|
| 119 |
+
return options
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
@set_module('numpy')
|
| 123 |
+
def set_printoptions(precision=None, threshold=None, edgeitems=None,
|
| 124 |
+
linewidth=None, suppress=None, nanstr=None,
|
| 125 |
+
infstr=None, formatter=None, sign=None, floatmode=None,
|
| 126 |
+
*, legacy=None, override_repr=None):
|
| 127 |
+
"""
|
| 128 |
+
Set printing options.
|
| 129 |
+
|
| 130 |
+
These options determine the way floating point numbers, arrays and
|
| 131 |
+
other NumPy objects are displayed.
|
| 132 |
+
|
| 133 |
+
Parameters
|
| 134 |
+
----------
|
| 135 |
+
precision : int or None, optional
|
| 136 |
+
Number of digits of precision for floating point output (default 8).
|
| 137 |
+
May be None if `floatmode` is not `fixed`, to print as many digits as
|
| 138 |
+
necessary to uniquely specify the value.
|
| 139 |
+
threshold : int, optional
|
| 140 |
+
Total number of array elements which trigger summarization
|
| 141 |
+
rather than full repr (default 1000).
|
| 142 |
+
To always use the full repr without summarization, pass `sys.maxsize`.
|
| 143 |
+
edgeitems : int, optional
|
| 144 |
+
Number of array items in summary at beginning and end of
|
| 145 |
+
each dimension (default 3).
|
| 146 |
+
linewidth : int, optional
|
| 147 |
+
The number of characters per line for the purpose of inserting
|
| 148 |
+
line breaks (default 75).
|
| 149 |
+
suppress : bool, optional
|
| 150 |
+
If True, always print floating point numbers using fixed point
|
| 151 |
+
notation, in which case numbers equal to zero in the current precision
|
| 152 |
+
will print as zero. If False, then scientific notation is used when
|
| 153 |
+
absolute value of the smallest number is < 1e-4 or the ratio of the
|
| 154 |
+
maximum absolute value to the minimum is > 1e3. The default is False.
|
| 155 |
+
nanstr : str, optional
|
| 156 |
+
String representation of floating point not-a-number (default nan).
|
| 157 |
+
infstr : str, optional
|
| 158 |
+
String representation of floating point infinity (default inf).
|
| 159 |
+
sign : string, either '-', '+', or ' ', optional
|
| 160 |
+
Controls printing of the sign of floating-point types. If '+', always
|
| 161 |
+
print the sign of positive values. If ' ', always prints a space
|
| 162 |
+
(whitespace character) in the sign position of positive values. If
|
| 163 |
+
'-', omit the sign character of positive values. (default '-')
|
| 164 |
+
|
| 165 |
+
.. versionchanged:: 2.0
|
| 166 |
+
The sign parameter can now be an integer type, previously
|
| 167 |
+
types were floating-point types.
|
| 168 |
+
|
| 169 |
+
formatter : dict of callables, optional
|
| 170 |
+
If not None, the keys should indicate the type(s) that the respective
|
| 171 |
+
formatting function applies to. Callables should return a string.
|
| 172 |
+
Types that are not specified (by their corresponding keys) are handled
|
| 173 |
+
by the default formatters. Individual types for which a formatter
|
| 174 |
+
can be set are:
|
| 175 |
+
|
| 176 |
+
- 'bool'
|
| 177 |
+
- 'int'
|
| 178 |
+
- 'timedelta' : a `numpy.timedelta64`
|
| 179 |
+
- 'datetime' : a `numpy.datetime64`
|
| 180 |
+
- 'float'
|
| 181 |
+
- 'longfloat' : 128-bit floats
|
| 182 |
+
- 'complexfloat'
|
| 183 |
+
- 'longcomplexfloat' : composed of two 128-bit floats
|
| 184 |
+
- 'numpystr' : types `numpy.bytes_` and `numpy.str_`
|
| 185 |
+
- 'object' : `np.object_` arrays
|
| 186 |
+
|
| 187 |
+
Other keys that can be used to set a group of types at once are:
|
| 188 |
+
|
| 189 |
+
- 'all' : sets all types
|
| 190 |
+
- 'int_kind' : sets 'int'
|
| 191 |
+
- 'float_kind' : sets 'float' and 'longfloat'
|
| 192 |
+
- 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
|
| 193 |
+
- 'str_kind' : sets 'numpystr'
|
| 194 |
+
floatmode : str, optional
|
| 195 |
+
Controls the interpretation of the `precision` option for
|
| 196 |
+
floating-point types. Can take the following values
|
| 197 |
+
(default maxprec_equal):
|
| 198 |
+
|
| 199 |
+
* 'fixed': Always print exactly `precision` fractional digits,
|
| 200 |
+
even if this would print more or fewer digits than
|
| 201 |
+
necessary to specify the value uniquely.
|
| 202 |
+
* 'unique': Print the minimum number of fractional digits necessary
|
| 203 |
+
to represent each value uniquely. Different elements may
|
| 204 |
+
have a different number of digits. The value of the
|
| 205 |
+
`precision` option is ignored.
|
| 206 |
+
* 'maxprec': Print at most `precision` fractional digits, but if
|
| 207 |
+
an element can be uniquely represented with fewer digits
|
| 208 |
+
only print it with that many.
|
| 209 |
+
* 'maxprec_equal': Print at most `precision` fractional digits,
|
| 210 |
+
but if every element in the array can be uniquely
|
| 211 |
+
represented with an equal number of fewer digits, use that
|
| 212 |
+
many digits for all elements.
|
| 213 |
+
legacy : string or `False`, optional
|
| 214 |
+
If set to the string ``'1.13'`` enables 1.13 legacy printing mode. This
|
| 215 |
+
approximates numpy 1.13 print output by including a space in the sign
|
| 216 |
+
position of floats and different behavior for 0d arrays. This also
|
| 217 |
+
enables 1.21 legacy printing mode (described below).
|
| 218 |
+
|
| 219 |
+
If set to the string ``'1.21'`` enables 1.21 legacy printing mode. This
|
| 220 |
+
approximates numpy 1.21 print output of complex structured dtypes
|
| 221 |
+
by not inserting spaces after commas that separate fields and after
|
| 222 |
+
colons.
|
| 223 |
+
|
| 224 |
+
If set to ``'1.25'`` approximates printing of 1.25 which mainly means
|
| 225 |
+
that numeric scalars are printed without their type information, e.g.
|
| 226 |
+
as ``3.0`` rather than ``np.float64(3.0)``.
|
| 227 |
+
|
| 228 |
+
If set to ``'2.1'``, shape information is not given when arrays are
|
| 229 |
+
summarized (i.e., multiple elements replaced with ``...``).
|
| 230 |
+
|
| 231 |
+
If set to ``'2.2'``, the transition to use scientific notation for
|
| 232 |
+
printing ``np.float16`` and ``np.float32`` types may happen later or
|
| 233 |
+
not at all for larger values.
|
| 234 |
+
|
| 235 |
+
If set to `False`, disables legacy mode.
|
| 236 |
+
|
| 237 |
+
Unrecognized strings will be ignored with a warning for forward
|
| 238 |
+
compatibility.
|
| 239 |
+
|
| 240 |
+
.. versionchanged:: 1.22.0
|
| 241 |
+
.. versionchanged:: 2.2
|
| 242 |
+
|
| 243 |
+
override_repr: callable, optional
|
| 244 |
+
If set a passed function will be used for generating arrays' repr.
|
| 245 |
+
Other options will be ignored.
|
| 246 |
+
|
| 247 |
+
See Also
|
| 248 |
+
--------
|
| 249 |
+
get_printoptions, printoptions, array2string
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
Notes
|
| 253 |
+
-----
|
| 254 |
+
|
| 255 |
+
* ``formatter`` is always reset with a call to `set_printoptions`.
|
| 256 |
+
* Use `printoptions` as a context manager to set the values temporarily.
|
| 257 |
+
* These print options apply only to NumPy ndarrays, not to scalars.
|
| 258 |
+
|
| 259 |
+
**Concurrency note:** see :ref:`text_formatting_options`
|
| 260 |
+
|
| 261 |
+
Examples
|
| 262 |
+
--------
|
| 263 |
+
Floating point precision can be set:
|
| 264 |
+
|
| 265 |
+
>>> import numpy as np
|
| 266 |
+
>>> np.set_printoptions(precision=4)
|
| 267 |
+
>>> np.array([1.123456789])
|
| 268 |
+
[1.1235]
|
| 269 |
+
|
| 270 |
+
Long arrays can be summarised:
|
| 271 |
+
|
| 272 |
+
>>> np.set_printoptions(threshold=5)
|
| 273 |
+
>>> np.arange(10)
|
| 274 |
+
array([0, 1, 2, ..., 7, 8, 9], shape=(10,))
|
| 275 |
+
|
| 276 |
+
Small results can be suppressed:
|
| 277 |
+
|
| 278 |
+
>>> eps = np.finfo(float).eps
|
| 279 |
+
>>> x = np.arange(4.)
|
| 280 |
+
>>> x**2 - (x + eps)**2
|
| 281 |
+
array([-4.9304e-32, -4.4409e-16, 0.0000e+00, 0.0000e+00])
|
| 282 |
+
>>> np.set_printoptions(suppress=True)
|
| 283 |
+
>>> x**2 - (x + eps)**2
|
| 284 |
+
array([-0., -0., 0., 0.])
|
| 285 |
+
|
| 286 |
+
A custom formatter can be used to display array elements as desired:
|
| 287 |
+
|
| 288 |
+
>>> np.set_printoptions(formatter={'all':lambda x: 'int: '+str(-x)})
|
| 289 |
+
>>> x = np.arange(3)
|
| 290 |
+
>>> x
|
| 291 |
+
array([int: 0, int: -1, int: -2])
|
| 292 |
+
>>> np.set_printoptions() # formatter gets reset
|
| 293 |
+
>>> x
|
| 294 |
+
array([0, 1, 2])
|
| 295 |
+
|
| 296 |
+
To put back the default options, you can use:
|
| 297 |
+
|
| 298 |
+
>>> np.set_printoptions(edgeitems=3, infstr='inf',
|
| 299 |
+
... linewidth=75, nanstr='nan', precision=8,
|
| 300 |
+
... suppress=False, threshold=1000, formatter=None)
|
| 301 |
+
|
| 302 |
+
Also to temporarily override options, use `printoptions`
|
| 303 |
+
as a context manager:
|
| 304 |
+
|
| 305 |
+
>>> with np.printoptions(precision=2, suppress=True, threshold=5):
|
| 306 |
+
... np.linspace(0, 10, 10)
|
| 307 |
+
array([ 0. , 1.11, 2.22, ..., 7.78, 8.89, 10. ], shape=(10,))
|
| 308 |
+
|
| 309 |
+
"""
|
| 310 |
+
_set_printoptions(precision, threshold, edgeitems, linewidth, suppress,
|
| 311 |
+
nanstr, infstr, formatter, sign, floatmode,
|
| 312 |
+
legacy=legacy, override_repr=override_repr)
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
def _set_printoptions(precision=None, threshold=None, edgeitems=None,
|
| 316 |
+
linewidth=None, suppress=None, nanstr=None,
|
| 317 |
+
infstr=None, formatter=None, sign=None, floatmode=None,
|
| 318 |
+
*, legacy=None, override_repr=None):
|
| 319 |
+
new_opt = _make_options_dict(precision, threshold, edgeitems, linewidth,
|
| 320 |
+
suppress, nanstr, infstr, sign, formatter,
|
| 321 |
+
floatmode, legacy)
|
| 322 |
+
# formatter and override_repr are always reset
|
| 323 |
+
new_opt['formatter'] = formatter
|
| 324 |
+
new_opt['override_repr'] = override_repr
|
| 325 |
+
|
| 326 |
+
updated_opt = format_options.get() | new_opt
|
| 327 |
+
updated_opt.update(new_opt)
|
| 328 |
+
|
| 329 |
+
if updated_opt['legacy'] == 113:
|
| 330 |
+
updated_opt['sign'] = '-'
|
| 331 |
+
|
| 332 |
+
return format_options.set(updated_opt)
|
| 333 |
+
|
| 334 |
+
|
| 335 |
+
@set_module('numpy')
|
| 336 |
+
def get_printoptions():
|
| 337 |
+
"""
|
| 338 |
+
Return the current print options.
|
| 339 |
+
|
| 340 |
+
Returns
|
| 341 |
+
-------
|
| 342 |
+
print_opts : dict
|
| 343 |
+
Dictionary of current print options with keys
|
| 344 |
+
|
| 345 |
+
- precision : int
|
| 346 |
+
- threshold : int
|
| 347 |
+
- edgeitems : int
|
| 348 |
+
- linewidth : int
|
| 349 |
+
- suppress : bool
|
| 350 |
+
- nanstr : str
|
| 351 |
+
- infstr : str
|
| 352 |
+
- sign : str
|
| 353 |
+
- formatter : dict of callables
|
| 354 |
+
- floatmode : str
|
| 355 |
+
- legacy : str or False
|
| 356 |
+
|
| 357 |
+
For a full description of these options, see `set_printoptions`.
|
| 358 |
+
|
| 359 |
+
Notes
|
| 360 |
+
-----
|
| 361 |
+
These print options apply only to NumPy ndarrays, not to scalars.
|
| 362 |
+
|
| 363 |
+
**Concurrency note:** see :ref:`text_formatting_options`
|
| 364 |
+
|
| 365 |
+
See Also
|
| 366 |
+
--------
|
| 367 |
+
set_printoptions, printoptions
|
| 368 |
+
|
| 369 |
+
Examples
|
| 370 |
+
--------
|
| 371 |
+
>>> import numpy as np
|
| 372 |
+
|
| 373 |
+
>>> np.get_printoptions()
|
| 374 |
+
{'edgeitems': 3, 'threshold': 1000, ..., 'override_repr': None}
|
| 375 |
+
|
| 376 |
+
>>> np.get_printoptions()['linewidth']
|
| 377 |
+
75
|
| 378 |
+
>>> np.set_printoptions(linewidth=100)
|
| 379 |
+
>>> np.get_printoptions()['linewidth']
|
| 380 |
+
100
|
| 381 |
+
|
| 382 |
+
"""
|
| 383 |
+
opts = format_options.get().copy()
|
| 384 |
+
opts['legacy'] = {
|
| 385 |
+
113: '1.13', 121: '1.21', 125: '1.25', 201: '2.1',
|
| 386 |
+
202: '2.2', sys.maxsize: False,
|
| 387 |
+
}[opts['legacy']]
|
| 388 |
+
return opts
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
def _get_legacy_print_mode():
|
| 392 |
+
"""Return the legacy print mode as an int."""
|
| 393 |
+
return format_options.get()['legacy']
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
@set_module('numpy')
|
| 397 |
+
@contextlib.contextmanager
|
| 398 |
+
def printoptions(*args, **kwargs):
|
| 399 |
+
"""Context manager for setting print options.
|
| 400 |
+
|
| 401 |
+
Set print options for the scope of the `with` block, and restore the old
|
| 402 |
+
options at the end. See `set_printoptions` for the full description of
|
| 403 |
+
available options.
|
| 404 |
+
|
| 405 |
+
Examples
|
| 406 |
+
--------
|
| 407 |
+
>>> import numpy as np
|
| 408 |
+
|
| 409 |
+
>>> from numpy.testing import assert_equal
|
| 410 |
+
>>> with np.printoptions(precision=2):
|
| 411 |
+
... np.array([2.0]) / 3
|
| 412 |
+
array([0.67])
|
| 413 |
+
|
| 414 |
+
The `as`-clause of the `with`-statement gives the current print options:
|
| 415 |
+
|
| 416 |
+
>>> with np.printoptions(precision=2) as opts:
|
| 417 |
+
... assert_equal(opts, np.get_printoptions())
|
| 418 |
+
|
| 419 |
+
See Also
|
| 420 |
+
--------
|
| 421 |
+
set_printoptions, get_printoptions
|
| 422 |
+
|
| 423 |
+
Notes
|
| 424 |
+
-----
|
| 425 |
+
These print options apply only to NumPy ndarrays, not to scalars.
|
| 426 |
+
|
| 427 |
+
**Concurrency note:** see :ref:`text_formatting_options`
|
| 428 |
+
|
| 429 |
+
"""
|
| 430 |
+
token = _set_printoptions(*args, **kwargs)
|
| 431 |
+
|
| 432 |
+
try:
|
| 433 |
+
yield get_printoptions()
|
| 434 |
+
finally:
|
| 435 |
+
format_options.reset(token)
|
| 436 |
+
|
| 437 |
+
|
| 438 |
+
def _leading_trailing(a, edgeitems, index=()):
|
| 439 |
+
"""
|
| 440 |
+
Keep only the N-D corners (leading and trailing edges) of an array.
|
| 441 |
+
|
| 442 |
+
Should be passed a base-class ndarray, since it makes no guarantees about
|
| 443 |
+
preserving subclasses.
|
| 444 |
+
"""
|
| 445 |
+
axis = len(index)
|
| 446 |
+
if axis == a.ndim:
|
| 447 |
+
return a[index]
|
| 448 |
+
|
| 449 |
+
if a.shape[axis] > 2 * edgeitems:
|
| 450 |
+
return concatenate((
|
| 451 |
+
_leading_trailing(a, edgeitems, index + np.index_exp[:edgeitems]),
|
| 452 |
+
_leading_trailing(a, edgeitems, index + np.index_exp[-edgeitems:])
|
| 453 |
+
), axis=axis)
|
| 454 |
+
else:
|
| 455 |
+
return _leading_trailing(a, edgeitems, index + np.index_exp[:])
|
| 456 |
+
|
| 457 |
+
|
| 458 |
+
def _object_format(o):
|
| 459 |
+
""" Object arrays containing lists should be printed unambiguously """
|
| 460 |
+
if type(o) is list:
|
| 461 |
+
fmt = 'list({!r})'
|
| 462 |
+
else:
|
| 463 |
+
fmt = '{!r}'
|
| 464 |
+
return fmt.format(o)
|
| 465 |
+
|
| 466 |
+
def repr_format(x):
|
| 467 |
+
if isinstance(x, (np.str_, np.bytes_)):
|
| 468 |
+
return repr(x.item())
|
| 469 |
+
return repr(x)
|
| 470 |
+
|
| 471 |
+
def str_format(x):
|
| 472 |
+
if isinstance(x, (np.str_, np.bytes_)):
|
| 473 |
+
return str(x.item())
|
| 474 |
+
return str(x)
|
| 475 |
+
|
| 476 |
+
def _get_formatdict(data, *, precision, floatmode, suppress, sign, legacy,
|
| 477 |
+
formatter, **kwargs):
|
| 478 |
+
# note: extra arguments in kwargs are ignored
|
| 479 |
+
|
| 480 |
+
# wrapped in lambdas to avoid taking a code path
|
| 481 |
+
# with the wrong type of data
|
| 482 |
+
formatdict = {
|
| 483 |
+
'bool': lambda: BoolFormat(data),
|
| 484 |
+
'int': lambda: IntegerFormat(data, sign),
|
| 485 |
+
'float': lambda: FloatingFormat(
|
| 486 |
+
data, precision, floatmode, suppress, sign, legacy=legacy),
|
| 487 |
+
'longfloat': lambda: FloatingFormat(
|
| 488 |
+
data, precision, floatmode, suppress, sign, legacy=legacy),
|
| 489 |
+
'complexfloat': lambda: ComplexFloatingFormat(
|
| 490 |
+
data, precision, floatmode, suppress, sign, legacy=legacy),
|
| 491 |
+
'longcomplexfloat': lambda: ComplexFloatingFormat(
|
| 492 |
+
data, precision, floatmode, suppress, sign, legacy=legacy),
|
| 493 |
+
'datetime': lambda: DatetimeFormat(data, legacy=legacy),
|
| 494 |
+
'timedelta': lambda: TimedeltaFormat(data),
|
| 495 |
+
'object': lambda: _object_format,
|
| 496 |
+
'void': lambda: str_format,
|
| 497 |
+
'numpystr': lambda: repr_format}
|
| 498 |
+
|
| 499 |
+
# we need to wrap values in `formatter` in a lambda, so that the interface
|
| 500 |
+
# is the same as the above values.
|
| 501 |
+
def indirect(x):
|
| 502 |
+
return lambda: x
|
| 503 |
+
|
| 504 |
+
if formatter is not None:
|
| 505 |
+
fkeys = [k for k in formatter.keys() if formatter[k] is not None]
|
| 506 |
+
if 'all' in fkeys:
|
| 507 |
+
for key in formatdict.keys():
|
| 508 |
+
formatdict[key] = indirect(formatter['all'])
|
| 509 |
+
if 'int_kind' in fkeys:
|
| 510 |
+
for key in ['int']:
|
| 511 |
+
formatdict[key] = indirect(formatter['int_kind'])
|
| 512 |
+
if 'float_kind' in fkeys:
|
| 513 |
+
for key in ['float', 'longfloat']:
|
| 514 |
+
formatdict[key] = indirect(formatter['float_kind'])
|
| 515 |
+
if 'complex_kind' in fkeys:
|
| 516 |
+
for key in ['complexfloat', 'longcomplexfloat']:
|
| 517 |
+
formatdict[key] = indirect(formatter['complex_kind'])
|
| 518 |
+
if 'str_kind' in fkeys:
|
| 519 |
+
formatdict['numpystr'] = indirect(formatter['str_kind'])
|
| 520 |
+
for key in formatdict.keys():
|
| 521 |
+
if key in fkeys:
|
| 522 |
+
formatdict[key] = indirect(formatter[key])
|
| 523 |
+
|
| 524 |
+
return formatdict
|
| 525 |
+
|
| 526 |
+
def _get_format_function(data, **options):
|
| 527 |
+
"""
|
| 528 |
+
find the right formatting function for the dtype_
|
| 529 |
+
"""
|
| 530 |
+
dtype_ = data.dtype
|
| 531 |
+
dtypeobj = dtype_.type
|
| 532 |
+
formatdict = _get_formatdict(data, **options)
|
| 533 |
+
|
| 534 |
+
if dtypeobj is None:
|
| 535 |
+
return formatdict["numpystr"]()
|
| 536 |
+
elif (getattr(dtypeobj, "__module__", None) != "numpy"
|
| 537 |
+
and not issubclass(dtypeobj, str)):
|
| 538 |
+
# Use `str()` as a default format for non-NumPy dtypes. This should be
|
| 539 |
+
# improved. We use `str` assuming that `repr` is likely to duplicate
|
| 540 |
+
# information that is contained in the dtype.
|
| 541 |
+
# (Do this early, because e.g. quaddtype subclasses floating.)
|
| 542 |
+
return formatdict['void']()
|
| 543 |
+
elif issubclass(dtypeobj, _nt.bool):
|
| 544 |
+
return formatdict['bool']()
|
| 545 |
+
elif issubclass(dtypeobj, _nt.integer):
|
| 546 |
+
if issubclass(dtypeobj, _nt.timedelta64):
|
| 547 |
+
return formatdict['timedelta']()
|
| 548 |
+
else:
|
| 549 |
+
return formatdict['int']()
|
| 550 |
+
elif issubclass(dtypeobj, _nt.floating):
|
| 551 |
+
if issubclass(dtypeobj, _nt.longdouble):
|
| 552 |
+
return formatdict['longfloat']()
|
| 553 |
+
else:
|
| 554 |
+
return formatdict['float']()
|
| 555 |
+
elif issubclass(dtypeobj, _nt.complexfloating):
|
| 556 |
+
if issubclass(dtypeobj, _nt.clongdouble):
|
| 557 |
+
return formatdict['longcomplexfloat']()
|
| 558 |
+
else:
|
| 559 |
+
return formatdict['complexfloat']()
|
| 560 |
+
elif issubclass(dtypeobj, (_nt.str_, _nt.bytes_)):
|
| 561 |
+
return formatdict['numpystr']()
|
| 562 |
+
elif issubclass(dtypeobj, _nt.datetime64):
|
| 563 |
+
return formatdict['datetime']()
|
| 564 |
+
elif issubclass(dtypeobj, _nt.object_):
|
| 565 |
+
return formatdict['object']()
|
| 566 |
+
elif issubclass(dtypeobj, _nt.void):
|
| 567 |
+
if dtype_.names is not None:
|
| 568 |
+
return StructuredVoidFormat.from_data(data, **options)
|
| 569 |
+
else:
|
| 570 |
+
return formatdict['void']()
|
| 571 |
+
else:
|
| 572 |
+
return formatdict['numpystr']()
|
| 573 |
+
|
| 574 |
+
|
| 575 |
+
def _recursive_guard(fillvalue='...'):
|
| 576 |
+
"""
|
| 577 |
+
Like the python 3.2 reprlib.recursive_repr, but forwards *args and **kwargs
|
| 578 |
+
|
| 579 |
+
Decorates a function such that if it calls itself with the same first
|
| 580 |
+
argument, it returns `fillvalue` instead of recursing.
|
| 581 |
+
|
| 582 |
+
Largely copied from reprlib.recursive_repr
|
| 583 |
+
"""
|
| 584 |
+
|
| 585 |
+
def decorating_function(f):
|
| 586 |
+
repr_running = set()
|
| 587 |
+
|
| 588 |
+
@functools.wraps(f)
|
| 589 |
+
def wrapper(self, *args, **kwargs):
|
| 590 |
+
key = id(self), get_ident()
|
| 591 |
+
if key in repr_running:
|
| 592 |
+
return fillvalue
|
| 593 |
+
repr_running.add(key)
|
| 594 |
+
try:
|
| 595 |
+
return f(self, *args, **kwargs)
|
| 596 |
+
finally:
|
| 597 |
+
repr_running.discard(key)
|
| 598 |
+
|
| 599 |
+
return wrapper
|
| 600 |
+
|
| 601 |
+
return decorating_function
|
| 602 |
+
|
| 603 |
+
|
| 604 |
+
# gracefully handle recursive calls, when object arrays contain themselves
|
| 605 |
+
@_recursive_guard()
|
| 606 |
+
def _array2string(a, options, separator=' ', prefix=""):
|
| 607 |
+
# The formatter __init__s in _get_format_function cannot deal with
|
| 608 |
+
# subclasses yet, and we also need to avoid recursion issues in
|
| 609 |
+
# _formatArray with subclasses which return 0d arrays in place of scalars
|
| 610 |
+
data = asarray(a)
|
| 611 |
+
if a.shape == ():
|
| 612 |
+
a = data
|
| 613 |
+
|
| 614 |
+
if a.size > options['threshold']:
|
| 615 |
+
summary_insert = "..."
|
| 616 |
+
data = _leading_trailing(data, options['edgeitems'])
|
| 617 |
+
else:
|
| 618 |
+
summary_insert = ""
|
| 619 |
+
|
| 620 |
+
# find the right formatting function for the array
|
| 621 |
+
format_function = _get_format_function(data, **options)
|
| 622 |
+
|
| 623 |
+
# skip over "["
|
| 624 |
+
next_line_prefix = " "
|
| 625 |
+
# skip over array(
|
| 626 |
+
next_line_prefix += " " * len(prefix)
|
| 627 |
+
|
| 628 |
+
lst = _formatArray(a, format_function, options['linewidth'],
|
| 629 |
+
next_line_prefix, separator, options['edgeitems'],
|
| 630 |
+
summary_insert, options['legacy'])
|
| 631 |
+
return lst
|
| 632 |
+
|
| 633 |
+
|
| 634 |
+
def _array2string_dispatcher(
|
| 635 |
+
a, max_line_width=None, precision=None,
|
| 636 |
+
suppress_small=None, separator=None, prefix=None,
|
| 637 |
+
*, formatter=None, threshold=None,
|
| 638 |
+
edgeitems=None, sign=None, floatmode=None, suffix=None,
|
| 639 |
+
legacy=None):
|
| 640 |
+
return (a,)
|
| 641 |
+
|
| 642 |
+
|
| 643 |
+
@array_function_dispatch(_array2string_dispatcher, module='numpy')
|
| 644 |
+
def array2string(a, max_line_width=None, precision=None,
|
| 645 |
+
suppress_small=None, separator=' ', prefix="",
|
| 646 |
+
*, formatter=None, threshold=None,
|
| 647 |
+
edgeitems=None, sign=None, floatmode=None, suffix="",
|
| 648 |
+
legacy=None):
|
| 649 |
+
"""
|
| 650 |
+
Return a string representation of an array.
|
| 651 |
+
|
| 652 |
+
Parameters
|
| 653 |
+
----------
|
| 654 |
+
a : ndarray
|
| 655 |
+
Input array.
|
| 656 |
+
max_line_width : int, optional
|
| 657 |
+
Inserts newlines if text is longer than `max_line_width`.
|
| 658 |
+
Defaults to ``numpy.get_printoptions()['linewidth']``.
|
| 659 |
+
precision : int or None, optional
|
| 660 |
+
Floating point precision.
|
| 661 |
+
Defaults to ``numpy.get_printoptions()['precision']``.
|
| 662 |
+
suppress_small : bool, optional
|
| 663 |
+
Represent numbers "very close" to zero as zero; default is False.
|
| 664 |
+
Very close is defined by precision: if the precision is 8, e.g.,
|
| 665 |
+
numbers smaller (in absolute value) than 5e-9 are represented as
|
| 666 |
+
zero.
|
| 667 |
+
Defaults to ``numpy.get_printoptions()['suppress']``.
|
| 668 |
+
separator : str, optional
|
| 669 |
+
Inserted between elements.
|
| 670 |
+
prefix : str, optional
|
| 671 |
+
suffix : str, optional
|
| 672 |
+
The length of the prefix and suffix strings are used to respectively
|
| 673 |
+
align and wrap the output. An array is typically printed as::
|
| 674 |
+
|
| 675 |
+
prefix + array2string(a) + suffix
|
| 676 |
+
|
| 677 |
+
The output is left-padded by the length of the prefix string, and
|
| 678 |
+
wrapping is forced at the column ``max_line_width - len(suffix)``.
|
| 679 |
+
It should be noted that the content of prefix and suffix strings are
|
| 680 |
+
not included in the output.
|
| 681 |
+
formatter : dict of callables, optional
|
| 682 |
+
If not None, the keys should indicate the type(s) that the respective
|
| 683 |
+
formatting function applies to. Callables should return a string.
|
| 684 |
+
Types that are not specified (by their corresponding keys) are handled
|
| 685 |
+
by the default formatters. Individual types for which a formatter
|
| 686 |
+
can be set are:
|
| 687 |
+
|
| 688 |
+
- 'bool'
|
| 689 |
+
- 'int'
|
| 690 |
+
- 'timedelta' : a `numpy.timedelta64`
|
| 691 |
+
- 'datetime' : a `numpy.datetime64`
|
| 692 |
+
- 'float'
|
| 693 |
+
- 'longfloat' : 128-bit floats
|
| 694 |
+
- 'complexfloat'
|
| 695 |
+
- 'longcomplexfloat' : composed of two 128-bit floats
|
| 696 |
+
- 'void' : type `numpy.void`
|
| 697 |
+
- 'numpystr' : types `numpy.bytes_` and `numpy.str_`
|
| 698 |
+
|
| 699 |
+
Other keys that can be used to set a group of types at once are:
|
| 700 |
+
|
| 701 |
+
- 'all' : sets all types
|
| 702 |
+
- 'int_kind' : sets 'int'
|
| 703 |
+
- 'float_kind' : sets 'float' and 'longfloat'
|
| 704 |
+
- 'complex_kind' : sets 'complexfloat' and 'longcomplexfloat'
|
| 705 |
+
- 'str_kind' : sets 'numpystr'
|
| 706 |
+
threshold : int, optional
|
| 707 |
+
Total number of array elements which trigger summarization
|
| 708 |
+
rather than full repr.
|
| 709 |
+
Defaults to ``numpy.get_printoptions()['threshold']``.
|
| 710 |
+
edgeitems : int, optional
|
| 711 |
+
Number of array items in summary at beginning and end of
|
| 712 |
+
each dimension.
|
| 713 |
+
Defaults to ``numpy.get_printoptions()['edgeitems']``.
|
| 714 |
+
sign : string, either '-', '+', or ' ', optional
|
| 715 |
+
Controls printing of the sign of floating-point types. If '+', always
|
| 716 |
+
print the sign of positive values. If ' ', always prints a space
|
| 717 |
+
(whitespace character) in the sign position of positive values. If
|
| 718 |
+
'-', omit the sign character of positive values.
|
| 719 |
+
Defaults to ``numpy.get_printoptions()['sign']``.
|
| 720 |
+
|
| 721 |
+
.. versionchanged:: 2.0
|
| 722 |
+
The sign parameter can now be an integer type, previously
|
| 723 |
+
types were floating-point types.
|
| 724 |
+
|
| 725 |
+
floatmode : str, optional
|
| 726 |
+
Controls the interpretation of the `precision` option for
|
| 727 |
+
floating-point types.
|
| 728 |
+
Defaults to ``numpy.get_printoptions()['floatmode']``.
|
| 729 |
+
Can take the following values:
|
| 730 |
+
|
| 731 |
+
- 'fixed': Always print exactly `precision` fractional digits,
|
| 732 |
+
even if this would print more or fewer digits than
|
| 733 |
+
necessary to specify the value uniquely.
|
| 734 |
+
- 'unique': Print the minimum number of fractional digits necessary
|
| 735 |
+
to represent each value uniquely. Different elements may
|
| 736 |
+
have a different number of digits. The value of the
|
| 737 |
+
`precision` option is ignored.
|
| 738 |
+
- 'maxprec': Print at most `precision` fractional digits, but if
|
| 739 |
+
an element can be uniquely represented with fewer digits
|
| 740 |
+
only print it with that many.
|
| 741 |
+
- 'maxprec_equal': Print at most `precision` fractional digits,
|
| 742 |
+
but if every element in the array can be uniquely
|
| 743 |
+
represented with an equal number of fewer digits, use that
|
| 744 |
+
many digits for all elements.
|
| 745 |
+
legacy : string or `False`, optional
|
| 746 |
+
If set to the string ``'1.13'`` enables 1.13 legacy printing mode. This
|
| 747 |
+
approximates numpy 1.13 print output by including a space in the sign
|
| 748 |
+
position of floats and different behavior for 0d arrays. If set to
|
| 749 |
+
`False`, disables legacy mode. Unrecognized strings will be ignored
|
| 750 |
+
with a warning for forward compatibility.
|
| 751 |
+
|
| 752 |
+
Returns
|
| 753 |
+
-------
|
| 754 |
+
array_str : str
|
| 755 |
+
String representation of the array.
|
| 756 |
+
|
| 757 |
+
Raises
|
| 758 |
+
------
|
| 759 |
+
TypeError
|
| 760 |
+
if a callable in `formatter` does not return a string.
|
| 761 |
+
|
| 762 |
+
See Also
|
| 763 |
+
--------
|
| 764 |
+
array_str, array_repr, set_printoptions, get_printoptions
|
| 765 |
+
|
| 766 |
+
Notes
|
| 767 |
+
-----
|
| 768 |
+
If a formatter is specified for a certain type, the `precision` keyword is
|
| 769 |
+
ignored for that type.
|
| 770 |
+
|
| 771 |
+
This is a very flexible function; `array_repr` and `array_str` are using
|
| 772 |
+
`array2string` internally so keywords with the same name should work
|
| 773 |
+
identically in all three functions.
|
| 774 |
+
|
| 775 |
+
Examples
|
| 776 |
+
--------
|
| 777 |
+
>>> import numpy as np
|
| 778 |
+
>>> x = np.array([1e-16,1,2,3])
|
| 779 |
+
>>> np.array2string(x, precision=2, separator=',',
|
| 780 |
+
... suppress_small=True)
|
| 781 |
+
'[0.,1.,2.,3.]'
|
| 782 |
+
|
| 783 |
+
>>> x = np.arange(3.)
|
| 784 |
+
>>> np.array2string(x, formatter={'float_kind':lambda x: "%.2f" % x})
|
| 785 |
+
'[0.00 1.00 2.00]'
|
| 786 |
+
|
| 787 |
+
>>> x = np.arange(3)
|
| 788 |
+
>>> np.array2string(x, formatter={'int':lambda x: hex(x)})
|
| 789 |
+
'[0x0 0x1 0x2]'
|
| 790 |
+
|
| 791 |
+
"""
|
| 792 |
+
|
| 793 |
+
overrides = _make_options_dict(precision, threshold, edgeitems,
|
| 794 |
+
max_line_width, suppress_small, None, None,
|
| 795 |
+
sign, formatter, floatmode, legacy)
|
| 796 |
+
options = format_options.get().copy()
|
| 797 |
+
options.update(overrides)
|
| 798 |
+
|
| 799 |
+
if options['legacy'] <= 113:
|
| 800 |
+
if a.shape == () and a.dtype.names is None:
|
| 801 |
+
return repr(a.item())
|
| 802 |
+
|
| 803 |
+
if options['legacy'] > 113:
|
| 804 |
+
options['linewidth'] -= len(suffix)
|
| 805 |
+
|
| 806 |
+
# treat as a null array if any of shape elements == 0
|
| 807 |
+
if a.size == 0:
|
| 808 |
+
return "[]"
|
| 809 |
+
|
| 810 |
+
return _array2string(a, options, separator, prefix)
|
| 811 |
+
|
| 812 |
+
|
| 813 |
+
def _extendLine(s, line, word, line_width, next_line_prefix, legacy):
|
| 814 |
+
needs_wrap = len(line) + len(word) > line_width
|
| 815 |
+
if legacy > 113:
|
| 816 |
+
# don't wrap lines if it won't help
|
| 817 |
+
if len(line) <= len(next_line_prefix):
|
| 818 |
+
needs_wrap = False
|
| 819 |
+
|
| 820 |
+
if needs_wrap:
|
| 821 |
+
s += line.rstrip() + "\n"
|
| 822 |
+
line = next_line_prefix
|
| 823 |
+
line += word
|
| 824 |
+
return s, line
|
| 825 |
+
|
| 826 |
+
|
| 827 |
+
def _extendLine_pretty(s, line, word, line_width, next_line_prefix, legacy):
|
| 828 |
+
"""
|
| 829 |
+
Extends line with nicely formatted (possibly multi-line) string ``word``.
|
| 830 |
+
"""
|
| 831 |
+
words = word.splitlines()
|
| 832 |
+
if len(words) == 1 or legacy <= 113:
|
| 833 |
+
return _extendLine(s, line, word, line_width, next_line_prefix, legacy)
|
| 834 |
+
|
| 835 |
+
max_word_length = max(len(word) for word in words)
|
| 836 |
+
if (len(line) + max_word_length > line_width and
|
| 837 |
+
len(line) > len(next_line_prefix)):
|
| 838 |
+
s += line.rstrip() + '\n'
|
| 839 |
+
line = next_line_prefix + words[0]
|
| 840 |
+
indent = next_line_prefix
|
| 841 |
+
else:
|
| 842 |
+
indent = len(line) * ' '
|
| 843 |
+
line += words[0]
|
| 844 |
+
|
| 845 |
+
for word in words[1::]:
|
| 846 |
+
s += line.rstrip() + '\n'
|
| 847 |
+
line = indent + word
|
| 848 |
+
|
| 849 |
+
suffix_length = max_word_length - len(words[-1])
|
| 850 |
+
line += suffix_length * ' '
|
| 851 |
+
|
| 852 |
+
return s, line
|
| 853 |
+
|
| 854 |
+
def _formatArray(a, format_function, line_width, next_line_prefix,
|
| 855 |
+
separator, edge_items, summary_insert, legacy):
|
| 856 |
+
"""formatArray is designed for two modes of operation:
|
| 857 |
+
|
| 858 |
+
1. Full output
|
| 859 |
+
|
| 860 |
+
2. Summarized output
|
| 861 |
+
|
| 862 |
+
"""
|
| 863 |
+
def recurser(index, hanging_indent, curr_width):
|
| 864 |
+
"""
|
| 865 |
+
By using this local function, we don't need to recurse with all the
|
| 866 |
+
arguments. Since this function is not created recursively, the cost is
|
| 867 |
+
not significant
|
| 868 |
+
"""
|
| 869 |
+
axis = len(index)
|
| 870 |
+
axes_left = a.ndim - axis
|
| 871 |
+
|
| 872 |
+
if axes_left == 0:
|
| 873 |
+
return format_function(a[index])
|
| 874 |
+
|
| 875 |
+
# when recursing, add a space to align with the [ added, and reduce the
|
| 876 |
+
# length of the line by 1
|
| 877 |
+
next_hanging_indent = hanging_indent + ' '
|
| 878 |
+
if legacy <= 113:
|
| 879 |
+
next_width = curr_width
|
| 880 |
+
else:
|
| 881 |
+
next_width = curr_width - len(']')
|
| 882 |
+
|
| 883 |
+
a_len = a.shape[axis]
|
| 884 |
+
show_summary = summary_insert and 2 * edge_items < a_len
|
| 885 |
+
if show_summary:
|
| 886 |
+
leading_items = edge_items
|
| 887 |
+
trailing_items = edge_items
|
| 888 |
+
else:
|
| 889 |
+
leading_items = 0
|
| 890 |
+
trailing_items = a_len
|
| 891 |
+
|
| 892 |
+
# stringify the array with the hanging indent on the first line too
|
| 893 |
+
s = ''
|
| 894 |
+
|
| 895 |
+
# last axis (rows) - wrap elements if they would not fit on one line
|
| 896 |
+
if axes_left == 1:
|
| 897 |
+
# the length up until the beginning of the separator / bracket
|
| 898 |
+
if legacy <= 113:
|
| 899 |
+
elem_width = curr_width - len(separator.rstrip())
|
| 900 |
+
else:
|
| 901 |
+
elem_width = curr_width - max(
|
| 902 |
+
len(separator.rstrip()), len(']')
|
| 903 |
+
)
|
| 904 |
+
|
| 905 |
+
line = hanging_indent
|
| 906 |
+
for i in range(leading_items):
|
| 907 |
+
word = recurser(index + (i,), next_hanging_indent, next_width)
|
| 908 |
+
s, line = _extendLine_pretty(
|
| 909 |
+
s, line, word, elem_width, hanging_indent, legacy)
|
| 910 |
+
line += separator
|
| 911 |
+
|
| 912 |
+
if show_summary:
|
| 913 |
+
s, line = _extendLine(
|
| 914 |
+
s, line, summary_insert, elem_width, hanging_indent, legacy
|
| 915 |
+
)
|
| 916 |
+
if legacy <= 113:
|
| 917 |
+
line += ", "
|
| 918 |
+
else:
|
| 919 |
+
line += separator
|
| 920 |
+
|
| 921 |
+
for i in range(trailing_items, 1, -1):
|
| 922 |
+
word = recurser(index + (-i,), next_hanging_indent, next_width)
|
| 923 |
+
s, line = _extendLine_pretty(
|
| 924 |
+
s, line, word, elem_width, hanging_indent, legacy)
|
| 925 |
+
line += separator
|
| 926 |
+
|
| 927 |
+
if legacy <= 113:
|
| 928 |
+
# width of the separator is not considered on 1.13
|
| 929 |
+
elem_width = curr_width
|
| 930 |
+
word = recurser(index + (-1,), next_hanging_indent, next_width)
|
| 931 |
+
s, line = _extendLine_pretty(
|
| 932 |
+
s, line, word, elem_width, hanging_indent, legacy)
|
| 933 |
+
|
| 934 |
+
s += line
|
| 935 |
+
|
| 936 |
+
# other axes - insert newlines between rows
|
| 937 |
+
else:
|
| 938 |
+
s = ''
|
| 939 |
+
line_sep = separator.rstrip() + '\n' * (axes_left - 1)
|
| 940 |
+
|
| 941 |
+
for i in range(leading_items):
|
| 942 |
+
nested = recurser(
|
| 943 |
+
index + (i,), next_hanging_indent, next_width
|
| 944 |
+
)
|
| 945 |
+
s += hanging_indent + nested + line_sep
|
| 946 |
+
|
| 947 |
+
if show_summary:
|
| 948 |
+
if legacy <= 113:
|
| 949 |
+
# trailing space, fixed nbr of newlines,
|
| 950 |
+
# and fixed separator
|
| 951 |
+
s += hanging_indent + summary_insert + ", \n"
|
| 952 |
+
else:
|
| 953 |
+
s += hanging_indent + summary_insert + line_sep
|
| 954 |
+
|
| 955 |
+
for i in range(trailing_items, 1, -1):
|
| 956 |
+
nested = recurser(index + (-i,), next_hanging_indent,
|
| 957 |
+
next_width)
|
| 958 |
+
s += hanging_indent + nested + line_sep
|
| 959 |
+
|
| 960 |
+
nested = recurser(index + (-1,), next_hanging_indent, next_width)
|
| 961 |
+
s += hanging_indent + nested
|
| 962 |
+
|
| 963 |
+
# remove the hanging indent, and wrap in []
|
| 964 |
+
s = '[' + s[len(hanging_indent):] + ']'
|
| 965 |
+
return s
|
| 966 |
+
|
| 967 |
+
try:
|
| 968 |
+
# invoke the recursive part with an initial index and prefix
|
| 969 |
+
return recurser(index=(),
|
| 970 |
+
hanging_indent=next_line_prefix,
|
| 971 |
+
curr_width=line_width)
|
| 972 |
+
finally:
|
| 973 |
+
# recursive closures have a cyclic reference to themselves, which
|
| 974 |
+
# requires gc to collect (gh-10620). To avoid this problem, for
|
| 975 |
+
# performance, we break the cycle:
|
| 976 |
+
recurser = None
|
| 977 |
+
|
| 978 |
+
def _none_or_positive_arg(x, name):
|
| 979 |
+
if x is None:
|
| 980 |
+
return -1
|
| 981 |
+
if x < 0:
|
| 982 |
+
raise ValueError(f"{name} must be >= 0")
|
| 983 |
+
return x
|
| 984 |
+
|
| 985 |
+
class FloatingFormat:
|
| 986 |
+
""" Formatter for subtypes of np.floating """
|
| 987 |
+
def __init__(self, data, precision, floatmode, suppress_small, sign=False,
|
| 988 |
+
*, legacy=None):
|
| 989 |
+
# for backcompatibility, accept bools
|
| 990 |
+
if isinstance(sign, bool):
|
| 991 |
+
sign = '+' if sign else '-'
|
| 992 |
+
|
| 993 |
+
self._legacy = legacy
|
| 994 |
+
if self._legacy <= 113:
|
| 995 |
+
# when not 0d, legacy does not support '-'
|
| 996 |
+
if data.shape != () and sign == '-':
|
| 997 |
+
sign = ' '
|
| 998 |
+
|
| 999 |
+
self.floatmode = floatmode
|
| 1000 |
+
if floatmode == 'unique':
|
| 1001 |
+
self.precision = None
|
| 1002 |
+
else:
|
| 1003 |
+
self.precision = precision
|
| 1004 |
+
|
| 1005 |
+
self.precision = _none_or_positive_arg(self.precision, 'precision')
|
| 1006 |
+
|
| 1007 |
+
self.suppress_small = suppress_small
|
| 1008 |
+
self.sign = sign
|
| 1009 |
+
self.exp_format = False
|
| 1010 |
+
self.large_exponent = False
|
| 1011 |
+
self.fillFormat(data)
|
| 1012 |
+
|
| 1013 |
+
def fillFormat(self, data):
|
| 1014 |
+
# only the finite values are used to compute the number of digits
|
| 1015 |
+
finite_vals = data[isfinite(data)]
|
| 1016 |
+
|
| 1017 |
+
# choose exponential mode based on the non-zero finite values:
|
| 1018 |
+
abs_non_zero = absolute(finite_vals[finite_vals != 0])
|
| 1019 |
+
if len(abs_non_zero) != 0:
|
| 1020 |
+
max_val = np.max(abs_non_zero)
|
| 1021 |
+
min_val = np.min(abs_non_zero)
|
| 1022 |
+
if self._legacy <= 202:
|
| 1023 |
+
exp_cutoff_max = 1.e8
|
| 1024 |
+
else:
|
| 1025 |
+
# consider data type while deciding the max cutoff for exp format
|
| 1026 |
+
exp_cutoff_max = 10.**min(8, np.finfo(data.dtype).precision)
|
| 1027 |
+
with errstate(over='ignore'): # division can overflow
|
| 1028 |
+
if max_val >= exp_cutoff_max or (not self.suppress_small and
|
| 1029 |
+
(min_val < 0.0001 or max_val / min_val > 1000.)):
|
| 1030 |
+
self.exp_format = True
|
| 1031 |
+
|
| 1032 |
+
# do a first pass of printing all the numbers, to determine sizes
|
| 1033 |
+
if len(finite_vals) == 0:
|
| 1034 |
+
self.pad_left = 0
|
| 1035 |
+
self.pad_right = 0
|
| 1036 |
+
self.trim = '.'
|
| 1037 |
+
self.exp_size = -1
|
| 1038 |
+
self.unique = True
|
| 1039 |
+
self.min_digits = None
|
| 1040 |
+
elif self.exp_format:
|
| 1041 |
+
trim, unique = '.', True
|
| 1042 |
+
if self.floatmode == 'fixed' or self._legacy <= 113:
|
| 1043 |
+
trim, unique = 'k', False
|
| 1044 |
+
strs = (dragon4_scientific(x, precision=self.precision,
|
| 1045 |
+
unique=unique, trim=trim, sign=self.sign == '+')
|
| 1046 |
+
for x in finite_vals)
|
| 1047 |
+
frac_strs, _, exp_strs = zip(*(s.partition('e') for s in strs))
|
| 1048 |
+
int_part, frac_part = zip(*(s.split('.') for s in frac_strs))
|
| 1049 |
+
self.exp_size = max(len(s) for s in exp_strs) - 1
|
| 1050 |
+
|
| 1051 |
+
self.trim = 'k'
|
| 1052 |
+
self.precision = max(len(s) for s in frac_part)
|
| 1053 |
+
self.min_digits = self.precision
|
| 1054 |
+
self.unique = unique
|
| 1055 |
+
|
| 1056 |
+
# for back-compat with np 1.13, use 2 spaces & sign and full prec
|
| 1057 |
+
if self._legacy <= 113:
|
| 1058 |
+
self.pad_left = 3
|
| 1059 |
+
else:
|
| 1060 |
+
# this should be only 1 or 2. Can be calculated from sign.
|
| 1061 |
+
self.pad_left = max(len(s) for s in int_part)
|
| 1062 |
+
# pad_right is only needed for nan length calculation
|
| 1063 |
+
self.pad_right = self.exp_size + 2 + self.precision
|
| 1064 |
+
else:
|
| 1065 |
+
trim, unique = '.', True
|
| 1066 |
+
if self.floatmode == 'fixed':
|
| 1067 |
+
trim, unique = 'k', False
|
| 1068 |
+
strs = (dragon4_positional(x, precision=self.precision,
|
| 1069 |
+
fractional=True,
|
| 1070 |
+
unique=unique, trim=trim,
|
| 1071 |
+
sign=self.sign == '+')
|
| 1072 |
+
for x in finite_vals)
|
| 1073 |
+
int_part, frac_part = zip(*(s.split('.') for s in strs))
|
| 1074 |
+
if self._legacy <= 113:
|
| 1075 |
+
self.pad_left = 1 + max(len(s.lstrip('-+')) for s in int_part)
|
| 1076 |
+
else:
|
| 1077 |
+
self.pad_left = max(len(s) for s in int_part)
|
| 1078 |
+
self.pad_right = max(len(s) for s in frac_part)
|
| 1079 |
+
self.exp_size = -1
|
| 1080 |
+
self.unique = unique
|
| 1081 |
+
|
| 1082 |
+
if self.floatmode in ['fixed', 'maxprec_equal']:
|
| 1083 |
+
self.precision = self.min_digits = self.pad_right
|
| 1084 |
+
self.trim = 'k'
|
| 1085 |
+
else:
|
| 1086 |
+
self.trim = '.'
|
| 1087 |
+
self.min_digits = 0
|
| 1088 |
+
|
| 1089 |
+
if self._legacy > 113:
|
| 1090 |
+
# account for sign = ' ' by adding one to pad_left
|
| 1091 |
+
if self.sign == ' ' and not any(np.signbit(finite_vals)):
|
| 1092 |
+
self.pad_left += 1
|
| 1093 |
+
|
| 1094 |
+
# if there are non-finite values, may need to increase pad_left
|
| 1095 |
+
if data.size != finite_vals.size:
|
| 1096 |
+
neginf = self.sign != '-' or any(data[isinf(data)] < 0)
|
| 1097 |
+
offset = self.pad_right + 1 # +1 for decimal pt
|
| 1098 |
+
current_options = format_options.get()
|
| 1099 |
+
self.pad_left = max(
|
| 1100 |
+
self.pad_left, len(current_options['nanstr']) - offset,
|
| 1101 |
+
len(current_options['infstr']) + neginf - offset
|
| 1102 |
+
)
|
| 1103 |
+
|
| 1104 |
+
def __call__(self, x):
|
| 1105 |
+
if not np.isfinite(x):
|
| 1106 |
+
with errstate(invalid='ignore'):
|
| 1107 |
+
current_options = format_options.get()
|
| 1108 |
+
if np.isnan(x):
|
| 1109 |
+
sign = '+' if self.sign == '+' else ''
|
| 1110 |
+
ret = sign + current_options['nanstr']
|
| 1111 |
+
else: # isinf
|
| 1112 |
+
sign = '-' if x < 0 else '+' if self.sign == '+' else ''
|
| 1113 |
+
ret = sign + current_options['infstr']
|
| 1114 |
+
return ' ' * (
|
| 1115 |
+
self.pad_left + self.pad_right + 1 - len(ret)
|
| 1116 |
+
) + ret
|
| 1117 |
+
|
| 1118 |
+
if self.exp_format:
|
| 1119 |
+
return dragon4_scientific(x,
|
| 1120 |
+
precision=self.precision,
|
| 1121 |
+
min_digits=self.min_digits,
|
| 1122 |
+
unique=self.unique,
|
| 1123 |
+
trim=self.trim,
|
| 1124 |
+
sign=self.sign == '+',
|
| 1125 |
+
pad_left=self.pad_left,
|
| 1126 |
+
exp_digits=self.exp_size)
|
| 1127 |
+
else:
|
| 1128 |
+
return dragon4_positional(x,
|
| 1129 |
+
precision=self.precision,
|
| 1130 |
+
min_digits=self.min_digits,
|
| 1131 |
+
unique=self.unique,
|
| 1132 |
+
fractional=True,
|
| 1133 |
+
trim=self.trim,
|
| 1134 |
+
sign=self.sign == '+',
|
| 1135 |
+
pad_left=self.pad_left,
|
| 1136 |
+
pad_right=self.pad_right)
|
| 1137 |
+
|
| 1138 |
+
|
| 1139 |
+
@set_module('numpy')
|
| 1140 |
+
def format_float_scientific(x, precision=None, unique=True, trim='k',
|
| 1141 |
+
sign=False, pad_left=None, exp_digits=None,
|
| 1142 |
+
min_digits=None):
|
| 1143 |
+
"""
|
| 1144 |
+
Format a floating-point scalar as a decimal string in scientific notation.
|
| 1145 |
+
|
| 1146 |
+
Provides control over rounding, trimming and padding. Uses and assumes
|
| 1147 |
+
IEEE unbiased rounding. Uses the "Dragon4" algorithm.
|
| 1148 |
+
|
| 1149 |
+
Parameters
|
| 1150 |
+
----------
|
| 1151 |
+
x : python float or numpy floating scalar
|
| 1152 |
+
Value to format.
|
| 1153 |
+
precision : non-negative integer or None, optional
|
| 1154 |
+
Maximum number of digits to print. May be None if `unique` is
|
| 1155 |
+
`True`, but must be an integer if unique is `False`.
|
| 1156 |
+
unique : boolean, optional
|
| 1157 |
+
If `True`, use a digit-generation strategy which gives the shortest
|
| 1158 |
+
representation which uniquely identifies the floating-point number from
|
| 1159 |
+
other values of the same type, by judicious rounding. If `precision`
|
| 1160 |
+
is given fewer digits than necessary can be printed. If `min_digits`
|
| 1161 |
+
is given more can be printed, in which cases the last digit is rounded
|
| 1162 |
+
with unbiased rounding.
|
| 1163 |
+
If `False`, digits are generated as if printing an infinite-precision
|
| 1164 |
+
value and stopping after `precision` digits, rounding the remaining
|
| 1165 |
+
value with unbiased rounding
|
| 1166 |
+
trim : one of 'k', '.', '0', '-', optional
|
| 1167 |
+
Controls post-processing trimming of trailing digits, as follows:
|
| 1168 |
+
|
| 1169 |
+
* 'k' : keep trailing zeros, keep decimal point (no trimming)
|
| 1170 |
+
* '.' : trim all trailing zeros, leave decimal point
|
| 1171 |
+
* '0' : trim all but the zero before the decimal point. Insert the
|
| 1172 |
+
zero if it is missing.
|
| 1173 |
+
* '-' : trim trailing zeros and any trailing decimal point
|
| 1174 |
+
sign : boolean, optional
|
| 1175 |
+
Whether to show the sign for positive values.
|
| 1176 |
+
pad_left : non-negative integer, optional
|
| 1177 |
+
Pad the left side of the string with whitespace until at least that
|
| 1178 |
+
many characters are to the left of the decimal point.
|
| 1179 |
+
exp_digits : non-negative integer, optional
|
| 1180 |
+
Pad the exponent with zeros until it contains at least this
|
| 1181 |
+
many digits. If omitted, the exponent will be at least 2 digits.
|
| 1182 |
+
min_digits : non-negative integer or None, optional
|
| 1183 |
+
Minimum number of digits to print. This only has an effect for
|
| 1184 |
+
`unique=True`. In that case more digits than necessary to uniquely
|
| 1185 |
+
identify the value may be printed and rounded unbiased.
|
| 1186 |
+
|
| 1187 |
+
.. versionadded:: 1.21.0
|
| 1188 |
+
|
| 1189 |
+
Returns
|
| 1190 |
+
-------
|
| 1191 |
+
rep : string
|
| 1192 |
+
The string representation of the floating point value
|
| 1193 |
+
|
| 1194 |
+
See Also
|
| 1195 |
+
--------
|
| 1196 |
+
format_float_positional
|
| 1197 |
+
|
| 1198 |
+
Examples
|
| 1199 |
+
--------
|
| 1200 |
+
>>> import numpy as np
|
| 1201 |
+
>>> np.format_float_scientific(np.float32(np.pi))
|
| 1202 |
+
'3.1415927e+00'
|
| 1203 |
+
>>> s = np.float32(1.23e24)
|
| 1204 |
+
>>> np.format_float_scientific(s, unique=False, precision=15)
|
| 1205 |
+
'1.230000071797338e+24'
|
| 1206 |
+
>>> np.format_float_scientific(s, exp_digits=4)
|
| 1207 |
+
'1.23e+0024'
|
| 1208 |
+
"""
|
| 1209 |
+
precision = _none_or_positive_arg(precision, 'precision')
|
| 1210 |
+
pad_left = _none_or_positive_arg(pad_left, 'pad_left')
|
| 1211 |
+
exp_digits = _none_or_positive_arg(exp_digits, 'exp_digits')
|
| 1212 |
+
min_digits = _none_or_positive_arg(min_digits, 'min_digits')
|
| 1213 |
+
if min_digits > 0 and precision > 0 and min_digits > precision:
|
| 1214 |
+
raise ValueError("min_digits must be less than or equal to precision")
|
| 1215 |
+
return dragon4_scientific(x, precision=precision, unique=unique,
|
| 1216 |
+
trim=trim, sign=sign, pad_left=pad_left,
|
| 1217 |
+
exp_digits=exp_digits, min_digits=min_digits)
|
| 1218 |
+
|
| 1219 |
+
|
| 1220 |
+
@set_module('numpy')
|
| 1221 |
+
def format_float_positional(x, precision=None, unique=True,
|
| 1222 |
+
fractional=True, trim='k', sign=False,
|
| 1223 |
+
pad_left=None, pad_right=None, min_digits=None):
|
| 1224 |
+
"""
|
| 1225 |
+
Format a floating-point scalar as a decimal string in positional notation.
|
| 1226 |
+
|
| 1227 |
+
Provides control over rounding, trimming and padding. Uses and assumes
|
| 1228 |
+
IEEE unbiased rounding. Uses the "Dragon4" algorithm.
|
| 1229 |
+
|
| 1230 |
+
Parameters
|
| 1231 |
+
----------
|
| 1232 |
+
x : python float or numpy floating scalar
|
| 1233 |
+
Value to format.
|
| 1234 |
+
precision : non-negative integer or None, optional
|
| 1235 |
+
Maximum number of digits to print. May be None if `unique` is
|
| 1236 |
+
`True`, but must be an integer if unique is `False`.
|
| 1237 |
+
unique : boolean, optional
|
| 1238 |
+
If `True`, use a digit-generation strategy which gives the shortest
|
| 1239 |
+
representation which uniquely identifies the floating-point number from
|
| 1240 |
+
other values of the same type, by judicious rounding. If `precision`
|
| 1241 |
+
is given fewer digits than necessary can be printed, or if `min_digits`
|
| 1242 |
+
is given more can be printed, in which cases the last digit is rounded
|
| 1243 |
+
with unbiased rounding.
|
| 1244 |
+
If `False`, digits are generated as if printing an infinite-precision
|
| 1245 |
+
value and stopping after `precision` digits, rounding the remaining
|
| 1246 |
+
value with unbiased rounding
|
| 1247 |
+
fractional : boolean, optional
|
| 1248 |
+
If `True`, the cutoffs of `precision` and `min_digits` refer to the
|
| 1249 |
+
total number of digits after the decimal point, including leading
|
| 1250 |
+
zeros.
|
| 1251 |
+
If `False`, `precision` and `min_digits` refer to the total number of
|
| 1252 |
+
significant digits, before or after the decimal point, ignoring leading
|
| 1253 |
+
zeros.
|
| 1254 |
+
trim : one of 'k', '.', '0', '-', optional
|
| 1255 |
+
Controls post-processing trimming of trailing digits, as follows:
|
| 1256 |
+
|
| 1257 |
+
* 'k' : keep trailing zeros, keep decimal point (no trimming)
|
| 1258 |
+
* '.' : trim all trailing zeros, leave decimal point
|
| 1259 |
+
* '0' : trim all but the zero before the decimal point. Insert the
|
| 1260 |
+
zero if it is missing.
|
| 1261 |
+
* '-' : trim trailing zeros and any trailing decimal point
|
| 1262 |
+
sign : boolean, optional
|
| 1263 |
+
Whether to show the sign for positive values.
|
| 1264 |
+
pad_left : non-negative integer, optional
|
| 1265 |
+
Pad the left side of the string with whitespace until at least that
|
| 1266 |
+
many characters are to the left of the decimal point.
|
| 1267 |
+
pad_right : non-negative integer, optional
|
| 1268 |
+
Pad the right side of the string with whitespace until at least that
|
| 1269 |
+
many characters are to the right of the decimal point.
|
| 1270 |
+
min_digits : non-negative integer or None, optional
|
| 1271 |
+
Minimum number of digits to print. Only has an effect if `unique=True`
|
| 1272 |
+
in which case additional digits past those necessary to uniquely
|
| 1273 |
+
identify the value may be printed, rounding the last additional digit.
|
| 1274 |
+
|
| 1275 |
+
.. versionadded:: 1.21.0
|
| 1276 |
+
|
| 1277 |
+
Returns
|
| 1278 |
+
-------
|
| 1279 |
+
rep : string
|
| 1280 |
+
The string representation of the floating point value
|
| 1281 |
+
|
| 1282 |
+
See Also
|
| 1283 |
+
--------
|
| 1284 |
+
format_float_scientific
|
| 1285 |
+
|
| 1286 |
+
Examples
|
| 1287 |
+
--------
|
| 1288 |
+
>>> import numpy as np
|
| 1289 |
+
>>> np.format_float_positional(np.float32(np.pi))
|
| 1290 |
+
'3.1415927'
|
| 1291 |
+
>>> np.format_float_positional(np.float16(np.pi))
|
| 1292 |
+
'3.14'
|
| 1293 |
+
>>> np.format_float_positional(np.float16(0.3))
|
| 1294 |
+
'0.3'
|
| 1295 |
+
>>> np.format_float_positional(np.float16(0.3), unique=False, precision=10)
|
| 1296 |
+
'0.3000488281'
|
| 1297 |
+
"""
|
| 1298 |
+
precision = _none_or_positive_arg(precision, 'precision')
|
| 1299 |
+
pad_left = _none_or_positive_arg(pad_left, 'pad_left')
|
| 1300 |
+
pad_right = _none_or_positive_arg(pad_right, 'pad_right')
|
| 1301 |
+
min_digits = _none_or_positive_arg(min_digits, 'min_digits')
|
| 1302 |
+
if not fractional and precision == 0:
|
| 1303 |
+
raise ValueError("precision must be greater than 0 if "
|
| 1304 |
+
"fractional=False")
|
| 1305 |
+
if min_digits > 0 and precision > 0 and min_digits > precision:
|
| 1306 |
+
raise ValueError("min_digits must be less than or equal to precision")
|
| 1307 |
+
return dragon4_positional(x, precision=precision, unique=unique,
|
| 1308 |
+
fractional=fractional, trim=trim,
|
| 1309 |
+
sign=sign, pad_left=pad_left,
|
| 1310 |
+
pad_right=pad_right, min_digits=min_digits)
|
| 1311 |
+
|
| 1312 |
+
class IntegerFormat:
|
| 1313 |
+
def __init__(self, data, sign='-'):
|
| 1314 |
+
if data.size > 0:
|
| 1315 |
+
data_max = np.max(data)
|
| 1316 |
+
data_min = np.min(data)
|
| 1317 |
+
data_max_str_len = len(str(data_max))
|
| 1318 |
+
if sign == ' ' and data_min < 0:
|
| 1319 |
+
sign = '-'
|
| 1320 |
+
if data_max >= 0 and sign in "+ ":
|
| 1321 |
+
data_max_str_len += 1
|
| 1322 |
+
max_str_len = max(data_max_str_len,
|
| 1323 |
+
len(str(data_min)))
|
| 1324 |
+
else:
|
| 1325 |
+
max_str_len = 0
|
| 1326 |
+
self.format = f'{{:{sign}{max_str_len}d}}'
|
| 1327 |
+
|
| 1328 |
+
def __call__(self, x):
|
| 1329 |
+
return self.format.format(x)
|
| 1330 |
+
|
| 1331 |
+
class BoolFormat:
|
| 1332 |
+
def __init__(self, data, **kwargs):
|
| 1333 |
+
# add an extra space so " True" and "False" have the same length and
|
| 1334 |
+
# array elements align nicely when printed, except in 0d arrays
|
| 1335 |
+
self.truestr = ' True' if data.shape != () else 'True'
|
| 1336 |
+
|
| 1337 |
+
def __call__(self, x):
|
| 1338 |
+
return self.truestr if x else "False"
|
| 1339 |
+
|
| 1340 |
+
|
| 1341 |
+
class ComplexFloatingFormat:
|
| 1342 |
+
""" Formatter for subtypes of np.complexfloating """
|
| 1343 |
+
def __init__(self, x, precision, floatmode, suppress_small,
|
| 1344 |
+
sign=False, *, legacy=None):
|
| 1345 |
+
# for backcompatibility, accept bools
|
| 1346 |
+
if isinstance(sign, bool):
|
| 1347 |
+
sign = '+' if sign else '-'
|
| 1348 |
+
|
| 1349 |
+
floatmode_real = floatmode_imag = floatmode
|
| 1350 |
+
if legacy <= 113:
|
| 1351 |
+
floatmode_real = 'maxprec_equal'
|
| 1352 |
+
floatmode_imag = 'maxprec'
|
| 1353 |
+
|
| 1354 |
+
self.real_format = FloatingFormat(
|
| 1355 |
+
x.real, precision, floatmode_real, suppress_small,
|
| 1356 |
+
sign=sign, legacy=legacy
|
| 1357 |
+
)
|
| 1358 |
+
self.imag_format = FloatingFormat(
|
| 1359 |
+
x.imag, precision, floatmode_imag, suppress_small,
|
| 1360 |
+
sign='+', legacy=legacy
|
| 1361 |
+
)
|
| 1362 |
+
|
| 1363 |
+
def __call__(self, x):
|
| 1364 |
+
r = self.real_format(x.real)
|
| 1365 |
+
i = self.imag_format(x.imag)
|
| 1366 |
+
|
| 1367 |
+
# add the 'j' before the terminal whitespace in i
|
| 1368 |
+
sp = len(i.rstrip())
|
| 1369 |
+
i = i[:sp] + 'j' + i[sp:]
|
| 1370 |
+
|
| 1371 |
+
return r + i
|
| 1372 |
+
|
| 1373 |
+
|
| 1374 |
+
class _TimelikeFormat:
|
| 1375 |
+
def __init__(self, data):
|
| 1376 |
+
non_nat = data[~isnat(data)]
|
| 1377 |
+
if len(non_nat) > 0:
|
| 1378 |
+
# Max str length of non-NaT elements
|
| 1379 |
+
max_str_len = max(len(self._format_non_nat(np.max(non_nat))),
|
| 1380 |
+
len(self._format_non_nat(np.min(non_nat))))
|
| 1381 |
+
else:
|
| 1382 |
+
max_str_len = 0
|
| 1383 |
+
if len(non_nat) < data.size:
|
| 1384 |
+
# data contains a NaT
|
| 1385 |
+
max_str_len = max(max_str_len, 5)
|
| 1386 |
+
self._format = f'%{max_str_len}s'
|
| 1387 |
+
self._nat = "'NaT'".rjust(max_str_len)
|
| 1388 |
+
|
| 1389 |
+
def _format_non_nat(self, x):
|
| 1390 |
+
# override in subclass
|
| 1391 |
+
raise NotImplementedError
|
| 1392 |
+
|
| 1393 |
+
def __call__(self, x):
|
| 1394 |
+
if isnat(x):
|
| 1395 |
+
return self._nat
|
| 1396 |
+
else:
|
| 1397 |
+
return self._format % self._format_non_nat(x)
|
| 1398 |
+
|
| 1399 |
+
|
| 1400 |
+
class DatetimeFormat(_TimelikeFormat):
|
| 1401 |
+
def __init__(self, x, unit=None, timezone=None, casting='same_kind',
|
| 1402 |
+
legacy=False):
|
| 1403 |
+
# Get the unit from the dtype
|
| 1404 |
+
if unit is None:
|
| 1405 |
+
if x.dtype.kind == 'M':
|
| 1406 |
+
unit = datetime_data(x.dtype)[0]
|
| 1407 |
+
else:
|
| 1408 |
+
unit = 's'
|
| 1409 |
+
|
| 1410 |
+
if timezone is None:
|
| 1411 |
+
timezone = 'naive'
|
| 1412 |
+
self.timezone = timezone
|
| 1413 |
+
self.unit = unit
|
| 1414 |
+
self.casting = casting
|
| 1415 |
+
self.legacy = legacy
|
| 1416 |
+
|
| 1417 |
+
# must be called after the above are configured
|
| 1418 |
+
super().__init__(x)
|
| 1419 |
+
|
| 1420 |
+
def __call__(self, x):
|
| 1421 |
+
if self.legacy <= 113:
|
| 1422 |
+
return self._format_non_nat(x)
|
| 1423 |
+
return super().__call__(x)
|
| 1424 |
+
|
| 1425 |
+
def _format_non_nat(self, x):
|
| 1426 |
+
datetime_str = datetime_as_string(x,
|
| 1427 |
+
unit=self.unit,
|
| 1428 |
+
timezone=self.timezone,
|
| 1429 |
+
casting=self.casting)
|
| 1430 |
+
return f"'{datetime_str}'"
|
| 1431 |
+
|
| 1432 |
+
|
| 1433 |
+
class TimedeltaFormat(_TimelikeFormat):
|
| 1434 |
+
def _format_non_nat(self, x):
|
| 1435 |
+
return str(x.astype('i8'))
|
| 1436 |
+
|
| 1437 |
+
|
| 1438 |
+
class SubArrayFormat:
|
| 1439 |
+
def __init__(self, format_function, **options):
|
| 1440 |
+
self.format_function = format_function
|
| 1441 |
+
self.threshold = options['threshold']
|
| 1442 |
+
self.edge_items = options['edgeitems']
|
| 1443 |
+
|
| 1444 |
+
def __call__(self, a):
|
| 1445 |
+
self.summary_insert = "..." if a.size > self.threshold else ""
|
| 1446 |
+
return self.format_array(a)
|
| 1447 |
+
|
| 1448 |
+
def format_array(self, a):
|
| 1449 |
+
if np.ndim(a) == 0:
|
| 1450 |
+
return self.format_function(a)
|
| 1451 |
+
|
| 1452 |
+
if self.summary_insert and a.shape[0] > 2 * self.edge_items:
|
| 1453 |
+
formatted = (
|
| 1454 |
+
[self.format_array(a_) for a_ in a[:self.edge_items]]
|
| 1455 |
+
+ [self.summary_insert]
|
| 1456 |
+
+ [self.format_array(a_) for a_ in a[-self.edge_items:]]
|
| 1457 |
+
)
|
| 1458 |
+
else:
|
| 1459 |
+
formatted = [self.format_array(a_) for a_ in a]
|
| 1460 |
+
|
| 1461 |
+
return "[" + ", ".join(formatted) + "]"
|
| 1462 |
+
|
| 1463 |
+
|
| 1464 |
+
class StructuredVoidFormat:
|
| 1465 |
+
"""
|
| 1466 |
+
Formatter for structured np.void objects.
|
| 1467 |
+
|
| 1468 |
+
This does not work on structured alias types like
|
| 1469 |
+
np.dtype(('i4', 'i2,i2')), as alias scalars lose their field information,
|
| 1470 |
+
and the implementation relies upon np.void.__getitem__.
|
| 1471 |
+
"""
|
| 1472 |
+
def __init__(self, format_functions):
|
| 1473 |
+
self.format_functions = format_functions
|
| 1474 |
+
|
| 1475 |
+
@classmethod
|
| 1476 |
+
def from_data(cls, data, **options):
|
| 1477 |
+
"""
|
| 1478 |
+
This is a second way to initialize StructuredVoidFormat,
|
| 1479 |
+
using the raw data as input. Added to avoid changing
|
| 1480 |
+
the signature of __init__.
|
| 1481 |
+
"""
|
| 1482 |
+
format_functions = []
|
| 1483 |
+
for field_name in data.dtype.names:
|
| 1484 |
+
format_function = _get_format_function(data[field_name], **options)
|
| 1485 |
+
if data.dtype[field_name].shape != ():
|
| 1486 |
+
format_function = SubArrayFormat(format_function, **options)
|
| 1487 |
+
format_functions.append(format_function)
|
| 1488 |
+
return cls(format_functions)
|
| 1489 |
+
|
| 1490 |
+
def __call__(self, x):
|
| 1491 |
+
str_fields = [
|
| 1492 |
+
format_function(field)
|
| 1493 |
+
for field, format_function in zip(x, self.format_functions)
|
| 1494 |
+
]
|
| 1495 |
+
if len(str_fields) == 1:
|
| 1496 |
+
return f"({str_fields[0]},)"
|
| 1497 |
+
else:
|
| 1498 |
+
return f"({', '.join(str_fields)})"
|
| 1499 |
+
|
| 1500 |
+
|
| 1501 |
+
def _void_scalar_to_string(x, is_repr=True):
|
| 1502 |
+
"""
|
| 1503 |
+
Implements the repr for structured-void scalars. It is called from the
|
| 1504 |
+
scalartypes.c.src code, and is placed here because it uses the elementwise
|
| 1505 |
+
formatters defined above.
|
| 1506 |
+
"""
|
| 1507 |
+
options = format_options.get().copy()
|
| 1508 |
+
|
| 1509 |
+
if options["legacy"] <= 125:
|
| 1510 |
+
return StructuredVoidFormat.from_data(array(x), **options)(x)
|
| 1511 |
+
|
| 1512 |
+
if options.get('formatter') is None:
|
| 1513 |
+
options['formatter'] = {}
|
| 1514 |
+
options['formatter'].setdefault('float_kind', str)
|
| 1515 |
+
val_repr = StructuredVoidFormat.from_data(array(x), **options)(x)
|
| 1516 |
+
if not is_repr:
|
| 1517 |
+
return val_repr
|
| 1518 |
+
cls = type(x)
|
| 1519 |
+
cls_fqn = cls.__module__.replace("numpy", "np") + "." + cls.__name__
|
| 1520 |
+
void_dtype = np.dtype((np.void, x.dtype))
|
| 1521 |
+
return f"{cls_fqn}({val_repr}, dtype={void_dtype!s})"
|
| 1522 |
+
|
| 1523 |
+
|
| 1524 |
+
_typelessdata = [int_, float64, complex128, _nt.bool]
|
| 1525 |
+
|
| 1526 |
+
|
| 1527 |
+
def dtype_is_implied(dtype):
|
| 1528 |
+
"""
|
| 1529 |
+
Determine if the given dtype is implied by the representation
|
| 1530 |
+
of its values.
|
| 1531 |
+
|
| 1532 |
+
Parameters
|
| 1533 |
+
----------
|
| 1534 |
+
dtype : dtype
|
| 1535 |
+
Data type
|
| 1536 |
+
|
| 1537 |
+
Returns
|
| 1538 |
+
-------
|
| 1539 |
+
implied : bool
|
| 1540 |
+
True if the dtype is implied by the representation of its values.
|
| 1541 |
+
|
| 1542 |
+
Examples
|
| 1543 |
+
--------
|
| 1544 |
+
>>> import numpy as np
|
| 1545 |
+
>>> np._core.arrayprint.dtype_is_implied(int)
|
| 1546 |
+
True
|
| 1547 |
+
>>> np.array([1, 2, 3], int)
|
| 1548 |
+
array([1, 2, 3])
|
| 1549 |
+
>>> np._core.arrayprint.dtype_is_implied(np.int8)
|
| 1550 |
+
False
|
| 1551 |
+
>>> np.array([1, 2, 3], np.int8)
|
| 1552 |
+
array([1, 2, 3], dtype=int8)
|
| 1553 |
+
"""
|
| 1554 |
+
dtype = np.dtype(dtype)
|
| 1555 |
+
if format_options.get()['legacy'] <= 113 and dtype.type == np.bool:
|
| 1556 |
+
return False
|
| 1557 |
+
|
| 1558 |
+
# not just void types can be structured, and names are not part of the repr
|
| 1559 |
+
if dtype.names is not None:
|
| 1560 |
+
return False
|
| 1561 |
+
|
| 1562 |
+
# should care about endianness *unless size is 1* (e.g., int8, bool)
|
| 1563 |
+
if not dtype.isnative:
|
| 1564 |
+
return False
|
| 1565 |
+
|
| 1566 |
+
return dtype.type in _typelessdata
|
| 1567 |
+
|
| 1568 |
+
|
| 1569 |
+
def dtype_short_repr(dtype):
|
| 1570 |
+
"""
|
| 1571 |
+
Convert a dtype to a short form which evaluates to the same dtype.
|
| 1572 |
+
|
| 1573 |
+
The intent is roughly that the following holds
|
| 1574 |
+
|
| 1575 |
+
>>> from numpy import *
|
| 1576 |
+
>>> dt = np.int64([1, 2]).dtype
|
| 1577 |
+
>>> assert eval(dtype_short_repr(dt)) == dt
|
| 1578 |
+
"""
|
| 1579 |
+
if not type(dtype)._legacy:
|
| 1580 |
+
# TODO: Custom repr for user DTypes, logic should likely move.
|
| 1581 |
+
return repr(dtype)
|
| 1582 |
+
if dtype.names is not None:
|
| 1583 |
+
# structured dtypes give a list or tuple repr
|
| 1584 |
+
return str(dtype)
|
| 1585 |
+
elif issubclass(dtype.type, flexible):
|
| 1586 |
+
# handle these separately so they don't give garbage like str256
|
| 1587 |
+
return f"'{str(dtype)}'"
|
| 1588 |
+
|
| 1589 |
+
typename = dtype.name
|
| 1590 |
+
if not dtype.isnative:
|
| 1591 |
+
# deal with cases like dtype('<u2') that are identical to an
|
| 1592 |
+
# established dtype (in this case uint16)
|
| 1593 |
+
# except that they have a different endianness.
|
| 1594 |
+
return f"'{str(dtype)}'"
|
| 1595 |
+
# quote typenames which can't be represented as python variable names
|
| 1596 |
+
if typename and not (typename[0].isalpha() and typename.isalnum()):
|
| 1597 |
+
typename = repr(typename)
|
| 1598 |
+
return typename
|
| 1599 |
+
|
| 1600 |
+
|
| 1601 |
+
def _array_repr_implementation(
|
| 1602 |
+
arr, max_line_width=None, precision=None, suppress_small=None,
|
| 1603 |
+
array2string=array2string):
|
| 1604 |
+
"""Internal version of array_repr() that allows overriding array2string."""
|
| 1605 |
+
current_options = format_options.get()
|
| 1606 |
+
override_repr = current_options["override_repr"]
|
| 1607 |
+
if override_repr is not None:
|
| 1608 |
+
return override_repr(arr)
|
| 1609 |
+
|
| 1610 |
+
if max_line_width is None:
|
| 1611 |
+
max_line_width = current_options['linewidth']
|
| 1612 |
+
|
| 1613 |
+
if type(arr) is not ndarray:
|
| 1614 |
+
class_name = type(arr).__name__
|
| 1615 |
+
else:
|
| 1616 |
+
class_name = "array"
|
| 1617 |
+
|
| 1618 |
+
prefix = class_name + "("
|
| 1619 |
+
if (current_options['legacy'] <= 113 and
|
| 1620 |
+
arr.shape == () and not arr.dtype.names):
|
| 1621 |
+
lst = repr(arr.item())
|
| 1622 |
+
else:
|
| 1623 |
+
lst = array2string(arr, max_line_width, precision, suppress_small,
|
| 1624 |
+
', ', prefix, suffix=")")
|
| 1625 |
+
|
| 1626 |
+
# Add dtype and shape information if these cannot be inferred from
|
| 1627 |
+
# the array string.
|
| 1628 |
+
extras = []
|
| 1629 |
+
if ((arr.size == 0 and arr.shape != (0,))
|
| 1630 |
+
or (current_options['legacy'] > 210
|
| 1631 |
+
and arr.size > current_options['threshold'])):
|
| 1632 |
+
extras.append(f"shape={arr.shape}")
|
| 1633 |
+
if not dtype_is_implied(arr.dtype) or arr.size == 0:
|
| 1634 |
+
extras.append(f"dtype={dtype_short_repr(arr.dtype)}")
|
| 1635 |
+
|
| 1636 |
+
if not extras:
|
| 1637 |
+
return prefix + lst + ")"
|
| 1638 |
+
|
| 1639 |
+
arr_str = prefix + lst + ","
|
| 1640 |
+
extra_str = ", ".join(extras) + ")"
|
| 1641 |
+
# compute whether we should put extras on a new line: Do so if adding the
|
| 1642 |
+
# extras would extend the last line past max_line_width.
|
| 1643 |
+
# Note: This line gives the correct result even when rfind returns -1.
|
| 1644 |
+
last_line_len = len(arr_str) - (arr_str.rfind('\n') + 1)
|
| 1645 |
+
spacer = " "
|
| 1646 |
+
if current_options['legacy'] <= 113:
|
| 1647 |
+
if issubclass(arr.dtype.type, flexible):
|
| 1648 |
+
spacer = '\n' + ' ' * len(prefix)
|
| 1649 |
+
elif last_line_len + len(extra_str) + 1 > max_line_width:
|
| 1650 |
+
spacer = '\n' + ' ' * len(prefix)
|
| 1651 |
+
|
| 1652 |
+
return arr_str + spacer + extra_str
|
| 1653 |
+
|
| 1654 |
+
|
| 1655 |
+
def _array_repr_dispatcher(
|
| 1656 |
+
arr, max_line_width=None, precision=None, suppress_small=None):
|
| 1657 |
+
return (arr,)
|
| 1658 |
+
|
| 1659 |
+
|
| 1660 |
+
@array_function_dispatch(_array_repr_dispatcher, module='numpy')
|
| 1661 |
+
def array_repr(arr, max_line_width=None, precision=None, suppress_small=None):
|
| 1662 |
+
"""
|
| 1663 |
+
Return the string representation of an array.
|
| 1664 |
+
|
| 1665 |
+
Parameters
|
| 1666 |
+
----------
|
| 1667 |
+
arr : ndarray
|
| 1668 |
+
Input array.
|
| 1669 |
+
max_line_width : int, optional
|
| 1670 |
+
Inserts newlines if text is longer than `max_line_width`.
|
| 1671 |
+
Defaults to ``numpy.get_printoptions()['linewidth']``.
|
| 1672 |
+
precision : int, optional
|
| 1673 |
+
Floating point precision.
|
| 1674 |
+
Defaults to ``numpy.get_printoptions()['precision']``.
|
| 1675 |
+
suppress_small : bool, optional
|
| 1676 |
+
Represent numbers "very close" to zero as zero; default is False.
|
| 1677 |
+
Very close is defined by precision: if the precision is 8, e.g.,
|
| 1678 |
+
numbers smaller (in absolute value) than 5e-9 are represented as
|
| 1679 |
+
zero.
|
| 1680 |
+
Defaults to ``numpy.get_printoptions()['suppress']``.
|
| 1681 |
+
|
| 1682 |
+
Returns
|
| 1683 |
+
-------
|
| 1684 |
+
string : str
|
| 1685 |
+
The string representation of an array.
|
| 1686 |
+
|
| 1687 |
+
See Also
|
| 1688 |
+
--------
|
| 1689 |
+
array_str, array2string, set_printoptions
|
| 1690 |
+
|
| 1691 |
+
Examples
|
| 1692 |
+
--------
|
| 1693 |
+
>>> import numpy as np
|
| 1694 |
+
>>> np.array_repr(np.array([1,2]))
|
| 1695 |
+
'array([1, 2])'
|
| 1696 |
+
>>> np.array_repr(np.ma.array([0.]))
|
| 1697 |
+
'MaskedArray([0.])'
|
| 1698 |
+
>>> np.array_repr(np.array([], np.int32))
|
| 1699 |
+
'array([], dtype=int32)'
|
| 1700 |
+
|
| 1701 |
+
>>> x = np.array([1e-6, 4e-7, 2, 3])
|
| 1702 |
+
>>> np.array_repr(x, precision=6, suppress_small=True)
|
| 1703 |
+
'array([0.000001, 0. , 2. , 3. ])'
|
| 1704 |
+
|
| 1705 |
+
"""
|
| 1706 |
+
return _array_repr_implementation(
|
| 1707 |
+
arr, max_line_width, precision, suppress_small)
|
| 1708 |
+
|
| 1709 |
+
|
| 1710 |
+
@_recursive_guard()
|
| 1711 |
+
def _guarded_repr_or_str(v):
|
| 1712 |
+
if isinstance(v, bytes):
|
| 1713 |
+
return repr(v)
|
| 1714 |
+
return str(v)
|
| 1715 |
+
|
| 1716 |
+
|
| 1717 |
+
def _array_str_implementation(
|
| 1718 |
+
a, max_line_width=None, precision=None, suppress_small=None,
|
| 1719 |
+
array2string=array2string):
|
| 1720 |
+
"""Internal version of array_str() that allows overriding array2string."""
|
| 1721 |
+
if (format_options.get()['legacy'] <= 113 and
|
| 1722 |
+
a.shape == () and not a.dtype.names):
|
| 1723 |
+
return str(a.item())
|
| 1724 |
+
|
| 1725 |
+
# the str of 0d arrays is a special case: It should appear like a scalar,
|
| 1726 |
+
# so floats are not truncated by `precision`, and strings are not wrapped
|
| 1727 |
+
# in quotes. So we return the str of the scalar value.
|
| 1728 |
+
if a.shape == ():
|
| 1729 |
+
# obtain a scalar and call str on it, avoiding problems for subclasses
|
| 1730 |
+
# for which indexing with () returns a 0d instead of a scalar by using
|
| 1731 |
+
# ndarray's getindex. Also guard against recursive 0d object arrays.
|
| 1732 |
+
return _guarded_repr_or_str(np.ndarray.__getitem__(a, ()))
|
| 1733 |
+
|
| 1734 |
+
return array2string(a, max_line_width, precision, suppress_small, ' ', "")
|
| 1735 |
+
|
| 1736 |
+
|
| 1737 |
+
def _array_str_dispatcher(
|
| 1738 |
+
a, max_line_width=None, precision=None, suppress_small=None):
|
| 1739 |
+
return (a,)
|
| 1740 |
+
|
| 1741 |
+
|
| 1742 |
+
@array_function_dispatch(_array_str_dispatcher, module='numpy')
|
| 1743 |
+
def array_str(a, max_line_width=None, precision=None, suppress_small=None):
|
| 1744 |
+
"""
|
| 1745 |
+
Return a string representation of the data in an array.
|
| 1746 |
+
|
| 1747 |
+
The data in the array is returned as a single string. This function is
|
| 1748 |
+
similar to `array_repr`, the difference being that `array_repr` also
|
| 1749 |
+
returns information on the kind of array and its data type.
|
| 1750 |
+
|
| 1751 |
+
Parameters
|
| 1752 |
+
----------
|
| 1753 |
+
a : ndarray
|
| 1754 |
+
Input array.
|
| 1755 |
+
max_line_width : int, optional
|
| 1756 |
+
Inserts newlines if text is longer than `max_line_width`.
|
| 1757 |
+
Defaults to ``numpy.get_printoptions()['linewidth']``.
|
| 1758 |
+
precision : int, optional
|
| 1759 |
+
Floating point precision.
|
| 1760 |
+
Defaults to ``numpy.get_printoptions()['precision']``.
|
| 1761 |
+
suppress_small : bool, optional
|
| 1762 |
+
Represent numbers "very close" to zero as zero; default is False.
|
| 1763 |
+
Very close is defined by precision: if the precision is 8, e.g.,
|
| 1764 |
+
numbers smaller (in absolute value) than 5e-9 are represented as
|
| 1765 |
+
zero.
|
| 1766 |
+
Defaults to ``numpy.get_printoptions()['suppress']``.
|
| 1767 |
+
|
| 1768 |
+
See Also
|
| 1769 |
+
--------
|
| 1770 |
+
array2string, array_repr, set_printoptions
|
| 1771 |
+
|
| 1772 |
+
Examples
|
| 1773 |
+
--------
|
| 1774 |
+
>>> import numpy as np
|
| 1775 |
+
>>> np.array_str(np.arange(3))
|
| 1776 |
+
'[0 1 2]'
|
| 1777 |
+
|
| 1778 |
+
"""
|
| 1779 |
+
return _array_str_implementation(
|
| 1780 |
+
a, max_line_width, precision, suppress_small)
|
| 1781 |
+
|
| 1782 |
+
|
| 1783 |
+
# needed if __array_function__ is disabled
|
| 1784 |
+
_array2string_impl = getattr(array2string, '__wrapped__', array2string)
|
| 1785 |
+
_default_array_str = functools.partial(_array_str_implementation,
|
| 1786 |
+
array2string=_array2string_impl)
|
| 1787 |
+
_default_array_repr = functools.partial(_array_repr_implementation,
|
| 1788 |
+
array2string=_array2string_impl)
|
v12x/pylib/numpy/_core/cversions.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Simple script to compute the api hash of the current API.
|
| 2 |
+
|
| 3 |
+
The API has is defined by numpy_api_order and ufunc_api_order.
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
from os.path import dirname
|
| 7 |
+
|
| 8 |
+
from code_generators.genapi import fullapi_hash
|
| 9 |
+
from code_generators.numpy_api import full_api
|
| 10 |
+
|
| 11 |
+
if __name__ == '__main__':
|
| 12 |
+
curdir = dirname(__file__)
|
| 13 |
+
print(fullapi_hash(full_api))
|
v12x/pylib/numpy/_core/defchararray.py
ADDED
|
@@ -0,0 +1,1429 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module contains a set of functions for vectorized string
|
| 3 |
+
operations and methods.
|
| 4 |
+
|
| 5 |
+
.. note::
|
| 6 |
+
The `chararray` class exists for backwards compatibility with
|
| 7 |
+
Numarray, it is not recommended for new development. Starting from numpy
|
| 8 |
+
1.4, if one needs arrays of strings, it is recommended to use arrays of
|
| 9 |
+
`dtype` `object_`, `bytes_` or `str_`, and use the free functions
|
| 10 |
+
in the `numpy.char` module for fast vectorized string operations.
|
| 11 |
+
|
| 12 |
+
Some methods will only be available if the corresponding string method is
|
| 13 |
+
available in your version of Python.
|
| 14 |
+
|
| 15 |
+
The preferred alias for `defchararray` is `numpy.char`.
|
| 16 |
+
|
| 17 |
+
"""
|
| 18 |
+
import functools
|
| 19 |
+
|
| 20 |
+
import numpy as np
|
| 21 |
+
from numpy._core import overrides
|
| 22 |
+
from numpy._core.multiarray import compare_chararrays
|
| 23 |
+
from numpy._core.strings import (
|
| 24 |
+
_join as join,
|
| 25 |
+
_rsplit as rsplit,
|
| 26 |
+
_split as split,
|
| 27 |
+
_splitlines as splitlines,
|
| 28 |
+
)
|
| 29 |
+
from numpy._utils import set_module
|
| 30 |
+
from numpy.strings import *
|
| 31 |
+
from numpy.strings import (
|
| 32 |
+
multiply as strings_multiply,
|
| 33 |
+
partition as strings_partition,
|
| 34 |
+
rpartition as strings_rpartition,
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
from .numeric import array as narray, asarray as asnarray, ndarray
|
| 38 |
+
from .numerictypes import bytes_, character, str_
|
| 39 |
+
|
| 40 |
+
__all__ = [
|
| 41 |
+
'equal', 'not_equal', 'greater_equal', 'less_equal',
|
| 42 |
+
'greater', 'less', 'str_len', 'add', 'multiply', 'mod', 'capitalize',
|
| 43 |
+
'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs',
|
| 44 |
+
'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace',
|
| 45 |
+
'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition',
|
| 46 |
+
'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit',
|
| 47 |
+
'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase',
|
| 48 |
+
'title', 'translate', 'upper', 'zfill', 'isnumeric', 'isdecimal',
|
| 49 |
+
'array', 'asarray', 'compare_chararrays', 'chararray'
|
| 50 |
+
]
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
array_function_dispatch = functools.partial(
|
| 54 |
+
overrides.array_function_dispatch, module='numpy.char')
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def _binary_op_dispatcher(x1, x2):
|
| 58 |
+
return (x1, x2)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
@array_function_dispatch(_binary_op_dispatcher)
|
| 62 |
+
def equal(x1, x2):
|
| 63 |
+
"""
|
| 64 |
+
Return (x1 == x2) element-wise.
|
| 65 |
+
|
| 66 |
+
Unlike `numpy.equal`, this comparison is performed by first
|
| 67 |
+
stripping whitespace characters from the end of the string. This
|
| 68 |
+
behavior is provided for backward-compatibility with numarray.
|
| 69 |
+
|
| 70 |
+
Parameters
|
| 71 |
+
----------
|
| 72 |
+
x1, x2 : array_like of str or unicode
|
| 73 |
+
Input arrays of the same shape.
|
| 74 |
+
|
| 75 |
+
Returns
|
| 76 |
+
-------
|
| 77 |
+
out : ndarray
|
| 78 |
+
Output array of bools.
|
| 79 |
+
|
| 80 |
+
Examples
|
| 81 |
+
--------
|
| 82 |
+
>>> import numpy as np
|
| 83 |
+
>>> y = "aa "
|
| 84 |
+
>>> x = "aa"
|
| 85 |
+
>>> np.char.equal(x, y)
|
| 86 |
+
array(True)
|
| 87 |
+
|
| 88 |
+
See Also
|
| 89 |
+
--------
|
| 90 |
+
not_equal, greater_equal, less_equal, greater, less
|
| 91 |
+
"""
|
| 92 |
+
return compare_chararrays(x1, x2, '==', True)
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
@array_function_dispatch(_binary_op_dispatcher)
|
| 96 |
+
def not_equal(x1, x2):
|
| 97 |
+
"""
|
| 98 |
+
Return (x1 != x2) element-wise.
|
| 99 |
+
|
| 100 |
+
Unlike `numpy.not_equal`, this comparison is performed by first
|
| 101 |
+
stripping whitespace characters from the end of the string. This
|
| 102 |
+
behavior is provided for backward-compatibility with numarray.
|
| 103 |
+
|
| 104 |
+
Parameters
|
| 105 |
+
----------
|
| 106 |
+
x1, x2 : array_like of str or unicode
|
| 107 |
+
Input arrays of the same shape.
|
| 108 |
+
|
| 109 |
+
Returns
|
| 110 |
+
-------
|
| 111 |
+
out : ndarray
|
| 112 |
+
Output array of bools.
|
| 113 |
+
|
| 114 |
+
See Also
|
| 115 |
+
--------
|
| 116 |
+
equal, greater_equal, less_equal, greater, less
|
| 117 |
+
|
| 118 |
+
Examples
|
| 119 |
+
--------
|
| 120 |
+
>>> import numpy as np
|
| 121 |
+
>>> x1 = np.array(['a', 'b', 'c'])
|
| 122 |
+
>>> np.char.not_equal(x1, 'b')
|
| 123 |
+
array([ True, False, True])
|
| 124 |
+
|
| 125 |
+
"""
|
| 126 |
+
return compare_chararrays(x1, x2, '!=', True)
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
@array_function_dispatch(_binary_op_dispatcher)
|
| 130 |
+
def greater_equal(x1, x2):
|
| 131 |
+
"""
|
| 132 |
+
Return (x1 >= x2) element-wise.
|
| 133 |
+
|
| 134 |
+
Unlike `numpy.greater_equal`, this comparison is performed by
|
| 135 |
+
first stripping whitespace characters from the end of the string.
|
| 136 |
+
This behavior is provided for backward-compatibility with
|
| 137 |
+
numarray.
|
| 138 |
+
|
| 139 |
+
Parameters
|
| 140 |
+
----------
|
| 141 |
+
x1, x2 : array_like of str or unicode
|
| 142 |
+
Input arrays of the same shape.
|
| 143 |
+
|
| 144 |
+
Returns
|
| 145 |
+
-------
|
| 146 |
+
out : ndarray
|
| 147 |
+
Output array of bools.
|
| 148 |
+
|
| 149 |
+
See Also
|
| 150 |
+
--------
|
| 151 |
+
equal, not_equal, less_equal, greater, less
|
| 152 |
+
|
| 153 |
+
Examples
|
| 154 |
+
--------
|
| 155 |
+
>>> import numpy as np
|
| 156 |
+
>>> x1 = np.array(['a', 'b', 'c'])
|
| 157 |
+
>>> np.char.greater_equal(x1, 'b')
|
| 158 |
+
array([False, True, True])
|
| 159 |
+
|
| 160 |
+
"""
|
| 161 |
+
return compare_chararrays(x1, x2, '>=', True)
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
@array_function_dispatch(_binary_op_dispatcher)
|
| 165 |
+
def less_equal(x1, x2):
|
| 166 |
+
"""
|
| 167 |
+
Return (x1 <= x2) element-wise.
|
| 168 |
+
|
| 169 |
+
Unlike `numpy.less_equal`, this comparison is performed by first
|
| 170 |
+
stripping whitespace characters from the end of the string. This
|
| 171 |
+
behavior is provided for backward-compatibility with numarray.
|
| 172 |
+
|
| 173 |
+
Parameters
|
| 174 |
+
----------
|
| 175 |
+
x1, x2 : array_like of str or unicode
|
| 176 |
+
Input arrays of the same shape.
|
| 177 |
+
|
| 178 |
+
Returns
|
| 179 |
+
-------
|
| 180 |
+
out : ndarray
|
| 181 |
+
Output array of bools.
|
| 182 |
+
|
| 183 |
+
See Also
|
| 184 |
+
--------
|
| 185 |
+
equal, not_equal, greater_equal, greater, less
|
| 186 |
+
|
| 187 |
+
Examples
|
| 188 |
+
--------
|
| 189 |
+
>>> import numpy as np
|
| 190 |
+
>>> x1 = np.array(['a', 'b', 'c'])
|
| 191 |
+
>>> np.char.less_equal(x1, 'b')
|
| 192 |
+
array([ True, True, False])
|
| 193 |
+
|
| 194 |
+
"""
|
| 195 |
+
return compare_chararrays(x1, x2, '<=', True)
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
@array_function_dispatch(_binary_op_dispatcher)
|
| 199 |
+
def greater(x1, x2):
|
| 200 |
+
"""
|
| 201 |
+
Return (x1 > x2) element-wise.
|
| 202 |
+
|
| 203 |
+
Unlike `numpy.greater`, this comparison is performed by first
|
| 204 |
+
stripping whitespace characters from the end of the string. This
|
| 205 |
+
behavior is provided for backward-compatibility with numarray.
|
| 206 |
+
|
| 207 |
+
Parameters
|
| 208 |
+
----------
|
| 209 |
+
x1, x2 : array_like of str or unicode
|
| 210 |
+
Input arrays of the same shape.
|
| 211 |
+
|
| 212 |
+
Returns
|
| 213 |
+
-------
|
| 214 |
+
out : ndarray
|
| 215 |
+
Output array of bools.
|
| 216 |
+
|
| 217 |
+
See Also
|
| 218 |
+
--------
|
| 219 |
+
equal, not_equal, greater_equal, less_equal, less
|
| 220 |
+
|
| 221 |
+
Examples
|
| 222 |
+
--------
|
| 223 |
+
>>> import numpy as np
|
| 224 |
+
>>> x1 = np.array(['a', 'b', 'c'])
|
| 225 |
+
>>> np.char.greater(x1, 'b')
|
| 226 |
+
array([False, False, True])
|
| 227 |
+
|
| 228 |
+
"""
|
| 229 |
+
return compare_chararrays(x1, x2, '>', True)
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
@array_function_dispatch(_binary_op_dispatcher)
|
| 233 |
+
def less(x1, x2):
|
| 234 |
+
"""
|
| 235 |
+
Return (x1 < x2) element-wise.
|
| 236 |
+
|
| 237 |
+
Unlike `numpy.greater`, this comparison is performed by first
|
| 238 |
+
stripping whitespace characters from the end of the string. This
|
| 239 |
+
behavior is provided for backward-compatibility with numarray.
|
| 240 |
+
|
| 241 |
+
Parameters
|
| 242 |
+
----------
|
| 243 |
+
x1, x2 : array_like of str or unicode
|
| 244 |
+
Input arrays of the same shape.
|
| 245 |
+
|
| 246 |
+
Returns
|
| 247 |
+
-------
|
| 248 |
+
out : ndarray
|
| 249 |
+
Output array of bools.
|
| 250 |
+
|
| 251 |
+
See Also
|
| 252 |
+
--------
|
| 253 |
+
equal, not_equal, greater_equal, less_equal, greater
|
| 254 |
+
|
| 255 |
+
Examples
|
| 256 |
+
--------
|
| 257 |
+
>>> import numpy as np
|
| 258 |
+
>>> x1 = np.array(['a', 'b', 'c'])
|
| 259 |
+
>>> np.char.less(x1, 'b')
|
| 260 |
+
array([True, False, False])
|
| 261 |
+
|
| 262 |
+
"""
|
| 263 |
+
return compare_chararrays(x1, x2, '<', True)
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
@set_module("numpy.char")
|
| 267 |
+
def multiply(a, i):
|
| 268 |
+
"""
|
| 269 |
+
Return (a * i), that is string multiple concatenation,
|
| 270 |
+
element-wise.
|
| 271 |
+
|
| 272 |
+
Values in ``i`` of less than 0 are treated as 0 (which yields an
|
| 273 |
+
empty string).
|
| 274 |
+
|
| 275 |
+
Parameters
|
| 276 |
+
----------
|
| 277 |
+
a : array_like, with ``bytes_`` or ``str_`` dtype
|
| 278 |
+
|
| 279 |
+
i : array_like, with any integer dtype
|
| 280 |
+
|
| 281 |
+
Returns
|
| 282 |
+
-------
|
| 283 |
+
out : ndarray
|
| 284 |
+
Output array of str or unicode, depending on input types
|
| 285 |
+
|
| 286 |
+
Notes
|
| 287 |
+
-----
|
| 288 |
+
This is a thin wrapper around np.strings.multiply that raises
|
| 289 |
+
`ValueError` when ``i`` is not an integer. It only
|
| 290 |
+
exists for backwards-compatibility.
|
| 291 |
+
|
| 292 |
+
Examples
|
| 293 |
+
--------
|
| 294 |
+
>>> import numpy as np
|
| 295 |
+
>>> a = np.array(["a", "b", "c"])
|
| 296 |
+
>>> np.strings.multiply(a, 3)
|
| 297 |
+
array(['aaa', 'bbb', 'ccc'], dtype='<U3')
|
| 298 |
+
>>> i = np.array([1, 2, 3])
|
| 299 |
+
>>> np.strings.multiply(a, i)
|
| 300 |
+
array(['a', 'bb', 'ccc'], dtype='<U3')
|
| 301 |
+
>>> np.strings.multiply(np.array(['a']), i)
|
| 302 |
+
array(['a', 'aa', 'aaa'], dtype='<U3')
|
| 303 |
+
>>> a = np.array(['a', 'b', 'c', 'd', 'e', 'f']).reshape((2, 3))
|
| 304 |
+
>>> np.strings.multiply(a, 3)
|
| 305 |
+
array([['aaa', 'bbb', 'ccc'],
|
| 306 |
+
['ddd', 'eee', 'fff']], dtype='<U3')
|
| 307 |
+
>>> np.strings.multiply(a, i)
|
| 308 |
+
array([['a', 'bb', 'ccc'],
|
| 309 |
+
['d', 'ee', 'fff']], dtype='<U3')
|
| 310 |
+
|
| 311 |
+
"""
|
| 312 |
+
try:
|
| 313 |
+
return strings_multiply(a, i)
|
| 314 |
+
except TypeError:
|
| 315 |
+
raise ValueError("Can only multiply by integers")
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
@set_module("numpy.char")
|
| 319 |
+
def partition(a, sep):
|
| 320 |
+
"""
|
| 321 |
+
Partition each element in `a` around `sep`.
|
| 322 |
+
|
| 323 |
+
Calls :meth:`str.partition` element-wise.
|
| 324 |
+
|
| 325 |
+
For each element in `a`, split the element as the first
|
| 326 |
+
occurrence of `sep`, and return 3 strings containing the part
|
| 327 |
+
before the separator, the separator itself, and the part after
|
| 328 |
+
the separator. If the separator is not found, return 3 strings
|
| 329 |
+
containing the string itself, followed by two empty strings.
|
| 330 |
+
|
| 331 |
+
Parameters
|
| 332 |
+
----------
|
| 333 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 334 |
+
Input array
|
| 335 |
+
sep : {str, unicode}
|
| 336 |
+
Separator to split each string element in `a`.
|
| 337 |
+
|
| 338 |
+
Returns
|
| 339 |
+
-------
|
| 340 |
+
out : ndarray
|
| 341 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 342 |
+
depending on input types. The output array will have an extra
|
| 343 |
+
dimension with 3 elements per input element.
|
| 344 |
+
|
| 345 |
+
Examples
|
| 346 |
+
--------
|
| 347 |
+
>>> import numpy as np
|
| 348 |
+
>>> x = np.array(["Numpy is nice!"])
|
| 349 |
+
>>> np.char.partition(x, " ")
|
| 350 |
+
array([['Numpy', ' ', 'is nice!']], dtype='<U8')
|
| 351 |
+
|
| 352 |
+
See Also
|
| 353 |
+
--------
|
| 354 |
+
str.partition
|
| 355 |
+
|
| 356 |
+
"""
|
| 357 |
+
return np.stack(strings_partition(a, sep), axis=-1)
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
@set_module("numpy.char")
|
| 361 |
+
def rpartition(a, sep):
|
| 362 |
+
"""
|
| 363 |
+
Partition (split) each element around the right-most separator.
|
| 364 |
+
|
| 365 |
+
Calls :meth:`str.rpartition` element-wise.
|
| 366 |
+
|
| 367 |
+
For each element in `a`, split the element as the last
|
| 368 |
+
occurrence of `sep`, and return 3 strings containing the part
|
| 369 |
+
before the separator, the separator itself, and the part after
|
| 370 |
+
the separator. If the separator is not found, return 3 strings
|
| 371 |
+
containing the string itself, followed by two empty strings.
|
| 372 |
+
|
| 373 |
+
Parameters
|
| 374 |
+
----------
|
| 375 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 376 |
+
Input array
|
| 377 |
+
sep : str or unicode
|
| 378 |
+
Right-most separator to split each element in array.
|
| 379 |
+
|
| 380 |
+
Returns
|
| 381 |
+
-------
|
| 382 |
+
out : ndarray
|
| 383 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 384 |
+
depending on input types. The output array will have an extra
|
| 385 |
+
dimension with 3 elements per input element.
|
| 386 |
+
|
| 387 |
+
See Also
|
| 388 |
+
--------
|
| 389 |
+
str.rpartition
|
| 390 |
+
|
| 391 |
+
Examples
|
| 392 |
+
--------
|
| 393 |
+
>>> import numpy as np
|
| 394 |
+
>>> a = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 395 |
+
>>> np.char.rpartition(a, 'A')
|
| 396 |
+
array([['aAaAa', 'A', ''],
|
| 397 |
+
[' a', 'A', ' '],
|
| 398 |
+
['abB', 'A', 'Bba']], dtype='<U5')
|
| 399 |
+
|
| 400 |
+
"""
|
| 401 |
+
return np.stack(strings_rpartition(a, sep), axis=-1)
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
@set_module("numpy.char")
|
| 405 |
+
class chararray(ndarray):
|
| 406 |
+
"""
|
| 407 |
+
chararray(shape, itemsize=1, unicode=False, buffer=None, offset=0,
|
| 408 |
+
strides=None, order=None)
|
| 409 |
+
|
| 410 |
+
Provides a convenient view on arrays of string and unicode values.
|
| 411 |
+
|
| 412 |
+
.. deprecated:: 2.5
|
| 413 |
+
``chararray`` is deprecated. Use an ``ndarray`` with a string or
|
| 414 |
+
bytes dtype instead.
|
| 415 |
+
|
| 416 |
+
.. note::
|
| 417 |
+
The `chararray` class exists for backwards compatibility with
|
| 418 |
+
Numarray, it is not recommended for new development. Starting from numpy
|
| 419 |
+
1.4, if one needs arrays of strings, it is recommended to use arrays of
|
| 420 |
+
`dtype` `~numpy.object_`, `~numpy.bytes_` or `~numpy.str_`, and use
|
| 421 |
+
the free functions in the `numpy.char` module for fast vectorized
|
| 422 |
+
string operations.
|
| 423 |
+
|
| 424 |
+
Versus a NumPy array of dtype `~numpy.bytes_` or `~numpy.str_`, this
|
| 425 |
+
class adds the following functionality:
|
| 426 |
+
|
| 427 |
+
1) values automatically have whitespace removed from the end
|
| 428 |
+
when indexed
|
| 429 |
+
|
| 430 |
+
2) comparison operators automatically remove whitespace from the
|
| 431 |
+
end when comparing values
|
| 432 |
+
|
| 433 |
+
3) vectorized string operations are provided as methods
|
| 434 |
+
(e.g. `.endswith`) and infix operators (e.g. ``"+", "*", "%"``)
|
| 435 |
+
|
| 436 |
+
chararrays should be created using `numpy.char.array` or
|
| 437 |
+
`numpy.char.asarray`, rather than this constructor directly.
|
| 438 |
+
|
| 439 |
+
This constructor creates the array, using `buffer` (with `offset`
|
| 440 |
+
and `strides`) if it is not ``None``. If `buffer` is ``None``, then
|
| 441 |
+
constructs a new array with `strides` in "C order", unless both
|
| 442 |
+
``len(shape) >= 2`` and ``order='F'``, in which case `strides`
|
| 443 |
+
is in "Fortran order".
|
| 444 |
+
|
| 445 |
+
Methods
|
| 446 |
+
-------
|
| 447 |
+
astype
|
| 448 |
+
argsort
|
| 449 |
+
copy
|
| 450 |
+
count
|
| 451 |
+
decode
|
| 452 |
+
dump
|
| 453 |
+
dumps
|
| 454 |
+
encode
|
| 455 |
+
endswith
|
| 456 |
+
expandtabs
|
| 457 |
+
fill
|
| 458 |
+
find
|
| 459 |
+
flatten
|
| 460 |
+
getfield
|
| 461 |
+
index
|
| 462 |
+
isalnum
|
| 463 |
+
isalpha
|
| 464 |
+
isdecimal
|
| 465 |
+
isdigit
|
| 466 |
+
islower
|
| 467 |
+
isnumeric
|
| 468 |
+
isspace
|
| 469 |
+
istitle
|
| 470 |
+
isupper
|
| 471 |
+
item
|
| 472 |
+
join
|
| 473 |
+
ljust
|
| 474 |
+
lower
|
| 475 |
+
lstrip
|
| 476 |
+
nonzero
|
| 477 |
+
put
|
| 478 |
+
ravel
|
| 479 |
+
repeat
|
| 480 |
+
replace
|
| 481 |
+
reshape
|
| 482 |
+
resize
|
| 483 |
+
rfind
|
| 484 |
+
rindex
|
| 485 |
+
rjust
|
| 486 |
+
rsplit
|
| 487 |
+
rstrip
|
| 488 |
+
searchsorted
|
| 489 |
+
setfield
|
| 490 |
+
setflags
|
| 491 |
+
sort
|
| 492 |
+
split
|
| 493 |
+
splitlines
|
| 494 |
+
squeeze
|
| 495 |
+
startswith
|
| 496 |
+
strip
|
| 497 |
+
swapaxes
|
| 498 |
+
swapcase
|
| 499 |
+
take
|
| 500 |
+
title
|
| 501 |
+
tofile
|
| 502 |
+
tolist
|
| 503 |
+
translate
|
| 504 |
+
transpose
|
| 505 |
+
upper
|
| 506 |
+
view
|
| 507 |
+
zfill
|
| 508 |
+
|
| 509 |
+
Parameters
|
| 510 |
+
----------
|
| 511 |
+
shape : tuple
|
| 512 |
+
Shape of the array.
|
| 513 |
+
itemsize : int, optional
|
| 514 |
+
Length of each array element, in number of characters. Default is 1.
|
| 515 |
+
unicode : bool, optional
|
| 516 |
+
Are the array elements of type unicode (True) or string (False).
|
| 517 |
+
Default is False.
|
| 518 |
+
buffer : object exposing the buffer interface or str, optional
|
| 519 |
+
Memory address of the start of the array data. Default is None,
|
| 520 |
+
in which case a new array is created.
|
| 521 |
+
offset : int, optional
|
| 522 |
+
Fixed stride displacement from the beginning of an axis?
|
| 523 |
+
Default is 0. Needs to be >=0.
|
| 524 |
+
strides : array_like of ints, optional
|
| 525 |
+
Strides for the array (see `~numpy.ndarray.strides` for
|
| 526 |
+
full description). Default is None.
|
| 527 |
+
order : {'C', 'F'}, optional
|
| 528 |
+
The order in which the array data is stored in memory: 'C' ->
|
| 529 |
+
"row major" order (the default), 'F' -> "column major"
|
| 530 |
+
(Fortran) order.
|
| 531 |
+
|
| 532 |
+
Examples
|
| 533 |
+
--------
|
| 534 |
+
>>> import numpy as np
|
| 535 |
+
>>> charar = np.char.chararray((3, 3))
|
| 536 |
+
>>> charar[:] = 'a'
|
| 537 |
+
>>> charar
|
| 538 |
+
chararray([[b'a', b'a', b'a'],
|
| 539 |
+
[b'a', b'a', b'a'],
|
| 540 |
+
[b'a', b'a', b'a']], dtype='|S1')
|
| 541 |
+
|
| 542 |
+
>>> charar = np.char.chararray(charar.shape, itemsize=5)
|
| 543 |
+
>>> charar[:] = 'abc'
|
| 544 |
+
>>> charar
|
| 545 |
+
chararray([[b'abc', b'abc', b'abc'],
|
| 546 |
+
[b'abc', b'abc', b'abc'],
|
| 547 |
+
[b'abc', b'abc', b'abc']], dtype='|S5')
|
| 548 |
+
|
| 549 |
+
"""
|
| 550 |
+
def __new__(cls, shape, itemsize=1, unicode=False, buffer=None,
|
| 551 |
+
offset=0, strides=None, order='C'):
|
| 552 |
+
if unicode:
|
| 553 |
+
dtype = str_
|
| 554 |
+
else:
|
| 555 |
+
dtype = bytes_
|
| 556 |
+
|
| 557 |
+
# force itemsize to be a Python int, since using NumPy integer
|
| 558 |
+
# types results in itemsize.itemsize being used as the size of
|
| 559 |
+
# strings in the new array.
|
| 560 |
+
itemsize = int(itemsize)
|
| 561 |
+
|
| 562 |
+
if isinstance(buffer, str):
|
| 563 |
+
# unicode objects do not have the buffer interface
|
| 564 |
+
filler = buffer
|
| 565 |
+
buffer = None
|
| 566 |
+
else:
|
| 567 |
+
filler = None
|
| 568 |
+
|
| 569 |
+
if buffer is None:
|
| 570 |
+
self = ndarray.__new__(cls, shape, (dtype, itemsize),
|
| 571 |
+
order=order)
|
| 572 |
+
else:
|
| 573 |
+
self = ndarray.__new__(cls, shape, (dtype, itemsize),
|
| 574 |
+
buffer=buffer,
|
| 575 |
+
offset=offset, strides=strides,
|
| 576 |
+
order=order)
|
| 577 |
+
if filler is not None:
|
| 578 |
+
self[...] = filler
|
| 579 |
+
|
| 580 |
+
return self
|
| 581 |
+
|
| 582 |
+
def __array_wrap__(self, arr, context=None, return_scalar=False):
|
| 583 |
+
# When calling a ufunc (and some other functions), we return a
|
| 584 |
+
# chararray if the ufunc output is a string-like array,
|
| 585 |
+
# or an ndarray otherwise
|
| 586 |
+
if arr.dtype.char in "SUbc":
|
| 587 |
+
return arr.view(type(self))
|
| 588 |
+
return arr
|
| 589 |
+
|
| 590 |
+
def __array_finalize__(self, obj):
|
| 591 |
+
# The b is a special case because it is used for reconstructing.
|
| 592 |
+
if self.dtype.char not in 'VSUbc':
|
| 593 |
+
raise ValueError("Can only create a chararray from string data.")
|
| 594 |
+
|
| 595 |
+
def __getitem__(self, obj):
|
| 596 |
+
val = ndarray.__getitem__(self, obj)
|
| 597 |
+
if isinstance(val, character):
|
| 598 |
+
return val.rstrip()
|
| 599 |
+
return val
|
| 600 |
+
|
| 601 |
+
# IMPLEMENTATION NOTE: Most of the methods of this class are
|
| 602 |
+
# direct delegations to the free functions in this module.
|
| 603 |
+
# However, those that return an array of strings should instead
|
| 604 |
+
# return a chararray, so some extra wrapping is required.
|
| 605 |
+
|
| 606 |
+
def __eq__(self, other):
|
| 607 |
+
"""
|
| 608 |
+
Return (self == other) element-wise.
|
| 609 |
+
|
| 610 |
+
See Also
|
| 611 |
+
--------
|
| 612 |
+
equal
|
| 613 |
+
"""
|
| 614 |
+
return equal(self, other)
|
| 615 |
+
|
| 616 |
+
def __ne__(self, other):
|
| 617 |
+
"""
|
| 618 |
+
Return (self != other) element-wise.
|
| 619 |
+
|
| 620 |
+
See Also
|
| 621 |
+
--------
|
| 622 |
+
not_equal
|
| 623 |
+
"""
|
| 624 |
+
return not_equal(self, other)
|
| 625 |
+
|
| 626 |
+
def __ge__(self, other):
|
| 627 |
+
"""
|
| 628 |
+
Return (self >= other) element-wise.
|
| 629 |
+
|
| 630 |
+
See Also
|
| 631 |
+
--------
|
| 632 |
+
greater_equal
|
| 633 |
+
"""
|
| 634 |
+
return greater_equal(self, other)
|
| 635 |
+
|
| 636 |
+
def __le__(self, other):
|
| 637 |
+
"""
|
| 638 |
+
Return (self <= other) element-wise.
|
| 639 |
+
|
| 640 |
+
See Also
|
| 641 |
+
--------
|
| 642 |
+
less_equal
|
| 643 |
+
"""
|
| 644 |
+
return less_equal(self, other)
|
| 645 |
+
|
| 646 |
+
def __gt__(self, other):
|
| 647 |
+
"""
|
| 648 |
+
Return (self > other) element-wise.
|
| 649 |
+
|
| 650 |
+
See Also
|
| 651 |
+
--------
|
| 652 |
+
greater
|
| 653 |
+
"""
|
| 654 |
+
return greater(self, other)
|
| 655 |
+
|
| 656 |
+
def __lt__(self, other):
|
| 657 |
+
"""
|
| 658 |
+
Return (self < other) element-wise.
|
| 659 |
+
|
| 660 |
+
See Also
|
| 661 |
+
--------
|
| 662 |
+
less
|
| 663 |
+
"""
|
| 664 |
+
return less(self, other)
|
| 665 |
+
|
| 666 |
+
def __add__(self, other):
|
| 667 |
+
"""
|
| 668 |
+
Return (self + other), that is string concatenation,
|
| 669 |
+
element-wise for a pair of array_likes of str or unicode.
|
| 670 |
+
|
| 671 |
+
See Also
|
| 672 |
+
--------
|
| 673 |
+
add
|
| 674 |
+
"""
|
| 675 |
+
return add(self, other)
|
| 676 |
+
|
| 677 |
+
def __radd__(self, other):
|
| 678 |
+
"""
|
| 679 |
+
Return (other + self), that is string concatenation,
|
| 680 |
+
element-wise for a pair of array_likes of `bytes_` or `str_`.
|
| 681 |
+
|
| 682 |
+
See Also
|
| 683 |
+
--------
|
| 684 |
+
add
|
| 685 |
+
"""
|
| 686 |
+
return add(other, self)
|
| 687 |
+
|
| 688 |
+
def __mul__(self, i):
|
| 689 |
+
"""
|
| 690 |
+
Return (self * i), that is string multiple concatenation,
|
| 691 |
+
element-wise.
|
| 692 |
+
|
| 693 |
+
See Also
|
| 694 |
+
--------
|
| 695 |
+
multiply
|
| 696 |
+
"""
|
| 697 |
+
return asarray(multiply(self, i))
|
| 698 |
+
|
| 699 |
+
def __rmul__(self, i):
|
| 700 |
+
"""
|
| 701 |
+
Return (self * i), that is string multiple concatenation,
|
| 702 |
+
element-wise.
|
| 703 |
+
|
| 704 |
+
See Also
|
| 705 |
+
--------
|
| 706 |
+
multiply
|
| 707 |
+
"""
|
| 708 |
+
return asarray(multiply(self, i))
|
| 709 |
+
|
| 710 |
+
def __mod__(self, i):
|
| 711 |
+
"""
|
| 712 |
+
Return (self % i), that is pre-Python 2.6 string formatting
|
| 713 |
+
(interpolation), element-wise for a pair of array_likes of `bytes_`
|
| 714 |
+
or `str_`.
|
| 715 |
+
|
| 716 |
+
See Also
|
| 717 |
+
--------
|
| 718 |
+
mod
|
| 719 |
+
"""
|
| 720 |
+
return asarray(mod(self, i))
|
| 721 |
+
|
| 722 |
+
def __rmod__(self, other):
|
| 723 |
+
return NotImplemented
|
| 724 |
+
|
| 725 |
+
def argsort(self, axis=-1, kind=None, order=None, *, stable=None, descending=None):
|
| 726 |
+
"""
|
| 727 |
+
Return the indices that sort the array lexicographically.
|
| 728 |
+
|
| 729 |
+
For full documentation see `numpy.argsort`, for which this method is
|
| 730 |
+
in fact merely a "thin wrapper."
|
| 731 |
+
|
| 732 |
+
Examples
|
| 733 |
+
--------
|
| 734 |
+
>>> c = np.array(['a1b c', '1b ca', 'b ca1', 'Ca1b'], 'S5')
|
| 735 |
+
>>> c = c.view(np.char.chararray); c
|
| 736 |
+
chararray(['a1b c', '1b ca', 'b ca1', 'Ca1b'],
|
| 737 |
+
dtype='|S5')
|
| 738 |
+
>>> c[c.argsort()]
|
| 739 |
+
chararray(['1b ca', 'Ca1b', 'a1b c', 'b ca1'],
|
| 740 |
+
dtype='|S5')
|
| 741 |
+
|
| 742 |
+
"""
|
| 743 |
+
return self.__array__().argsort(
|
| 744 |
+
axis, kind, order, stable=stable, descending=descending
|
| 745 |
+
)
|
| 746 |
+
|
| 747 |
+
argsort.__doc__ = ndarray.argsort.__doc__
|
| 748 |
+
|
| 749 |
+
def capitalize(self):
|
| 750 |
+
"""
|
| 751 |
+
Return a copy of `self` with only the first character of each element
|
| 752 |
+
capitalized.
|
| 753 |
+
|
| 754 |
+
See Also
|
| 755 |
+
--------
|
| 756 |
+
char.capitalize
|
| 757 |
+
|
| 758 |
+
"""
|
| 759 |
+
return asarray(capitalize(self))
|
| 760 |
+
|
| 761 |
+
def center(self, width, fillchar=' '):
|
| 762 |
+
"""
|
| 763 |
+
Return a copy of `self` with its elements centered in a
|
| 764 |
+
string of length `width`.
|
| 765 |
+
|
| 766 |
+
See Also
|
| 767 |
+
--------
|
| 768 |
+
center
|
| 769 |
+
"""
|
| 770 |
+
return asarray(center(self, width, fillchar))
|
| 771 |
+
|
| 772 |
+
def count(self, sub, start=0, end=None):
|
| 773 |
+
"""
|
| 774 |
+
Returns an array with the number of non-overlapping occurrences of
|
| 775 |
+
substring `sub` in the range [`start`, `end`].
|
| 776 |
+
|
| 777 |
+
See Also
|
| 778 |
+
--------
|
| 779 |
+
char.count
|
| 780 |
+
|
| 781 |
+
"""
|
| 782 |
+
return count(self, sub, start, end)
|
| 783 |
+
|
| 784 |
+
def decode(self, encoding=None, errors=None):
|
| 785 |
+
"""
|
| 786 |
+
Calls ``bytes.decode`` element-wise.
|
| 787 |
+
|
| 788 |
+
See Also
|
| 789 |
+
--------
|
| 790 |
+
char.decode
|
| 791 |
+
|
| 792 |
+
"""
|
| 793 |
+
return decode(self, encoding, errors)
|
| 794 |
+
|
| 795 |
+
def encode(self, encoding=None, errors=None):
|
| 796 |
+
"""
|
| 797 |
+
Calls :meth:`str.encode` element-wise.
|
| 798 |
+
|
| 799 |
+
See Also
|
| 800 |
+
--------
|
| 801 |
+
char.encode
|
| 802 |
+
|
| 803 |
+
"""
|
| 804 |
+
return encode(self, encoding, errors)
|
| 805 |
+
|
| 806 |
+
def endswith(self, suffix, start=0, end=None):
|
| 807 |
+
"""
|
| 808 |
+
Returns a boolean array which is `True` where the string element
|
| 809 |
+
in `self` ends with `suffix`, otherwise `False`.
|
| 810 |
+
|
| 811 |
+
See Also
|
| 812 |
+
--------
|
| 813 |
+
char.endswith
|
| 814 |
+
|
| 815 |
+
"""
|
| 816 |
+
return endswith(self, suffix, start, end)
|
| 817 |
+
|
| 818 |
+
def expandtabs(self, tabsize=8):
|
| 819 |
+
"""
|
| 820 |
+
Return a copy of each string element where all tab characters are
|
| 821 |
+
replaced by one or more spaces.
|
| 822 |
+
|
| 823 |
+
See Also
|
| 824 |
+
--------
|
| 825 |
+
char.expandtabs
|
| 826 |
+
|
| 827 |
+
"""
|
| 828 |
+
return asarray(expandtabs(self, tabsize))
|
| 829 |
+
|
| 830 |
+
def find(self, sub, start=0, end=None):
|
| 831 |
+
"""
|
| 832 |
+
For each element, return the lowest index in the string where
|
| 833 |
+
substring `sub` is found.
|
| 834 |
+
|
| 835 |
+
See Also
|
| 836 |
+
--------
|
| 837 |
+
char.find
|
| 838 |
+
|
| 839 |
+
"""
|
| 840 |
+
return find(self, sub, start, end)
|
| 841 |
+
|
| 842 |
+
def index(self, sub, start=0, end=None):
|
| 843 |
+
"""
|
| 844 |
+
Like `find`, but raises :exc:`ValueError` when the substring is not
|
| 845 |
+
found.
|
| 846 |
+
|
| 847 |
+
See Also
|
| 848 |
+
--------
|
| 849 |
+
char.index
|
| 850 |
+
|
| 851 |
+
"""
|
| 852 |
+
return index(self, sub, start, end)
|
| 853 |
+
|
| 854 |
+
def isalnum(self):
|
| 855 |
+
"""
|
| 856 |
+
Returns true for each element if all characters in the string
|
| 857 |
+
are alphanumeric and there is at least one character, false
|
| 858 |
+
otherwise.
|
| 859 |
+
|
| 860 |
+
See Also
|
| 861 |
+
--------
|
| 862 |
+
char.isalnum
|
| 863 |
+
|
| 864 |
+
"""
|
| 865 |
+
return isalnum(self)
|
| 866 |
+
|
| 867 |
+
def isalpha(self):
|
| 868 |
+
"""
|
| 869 |
+
Returns true for each element if all characters in the string
|
| 870 |
+
are alphabetic and there is at least one character, false
|
| 871 |
+
otherwise.
|
| 872 |
+
|
| 873 |
+
See Also
|
| 874 |
+
--------
|
| 875 |
+
char.isalpha
|
| 876 |
+
|
| 877 |
+
"""
|
| 878 |
+
return isalpha(self)
|
| 879 |
+
|
| 880 |
+
def isdigit(self):
|
| 881 |
+
"""
|
| 882 |
+
Returns true for each element if all characters in the string are
|
| 883 |
+
digits and there is at least one character, false otherwise.
|
| 884 |
+
|
| 885 |
+
See Also
|
| 886 |
+
--------
|
| 887 |
+
char.isdigit
|
| 888 |
+
|
| 889 |
+
"""
|
| 890 |
+
return isdigit(self)
|
| 891 |
+
|
| 892 |
+
def islower(self):
|
| 893 |
+
"""
|
| 894 |
+
Returns true for each element if all cased characters in the
|
| 895 |
+
string are lowercase and there is at least one cased character,
|
| 896 |
+
false otherwise.
|
| 897 |
+
|
| 898 |
+
See Also
|
| 899 |
+
--------
|
| 900 |
+
char.islower
|
| 901 |
+
|
| 902 |
+
"""
|
| 903 |
+
return islower(self)
|
| 904 |
+
|
| 905 |
+
def isspace(self):
|
| 906 |
+
"""
|
| 907 |
+
Returns true for each element if there are only whitespace
|
| 908 |
+
characters in the string and there is at least one character,
|
| 909 |
+
false otherwise.
|
| 910 |
+
|
| 911 |
+
See Also
|
| 912 |
+
--------
|
| 913 |
+
char.isspace
|
| 914 |
+
|
| 915 |
+
"""
|
| 916 |
+
return isspace(self)
|
| 917 |
+
|
| 918 |
+
def istitle(self):
|
| 919 |
+
"""
|
| 920 |
+
Returns true for each element if the element is a titlecased
|
| 921 |
+
string and there is at least one character, false otherwise.
|
| 922 |
+
|
| 923 |
+
See Also
|
| 924 |
+
--------
|
| 925 |
+
char.istitle
|
| 926 |
+
|
| 927 |
+
"""
|
| 928 |
+
return istitle(self)
|
| 929 |
+
|
| 930 |
+
def isupper(self):
|
| 931 |
+
"""
|
| 932 |
+
Returns true for each element if all cased characters in the
|
| 933 |
+
string are uppercase and there is at least one character, false
|
| 934 |
+
otherwise.
|
| 935 |
+
|
| 936 |
+
See Also
|
| 937 |
+
--------
|
| 938 |
+
char.isupper
|
| 939 |
+
|
| 940 |
+
"""
|
| 941 |
+
return isupper(self)
|
| 942 |
+
|
| 943 |
+
def join(self, seq):
|
| 944 |
+
"""
|
| 945 |
+
Return a string which is the concatenation of the strings in the
|
| 946 |
+
sequence `seq`.
|
| 947 |
+
|
| 948 |
+
See Also
|
| 949 |
+
--------
|
| 950 |
+
char.join
|
| 951 |
+
|
| 952 |
+
"""
|
| 953 |
+
return join(self, seq)
|
| 954 |
+
|
| 955 |
+
def ljust(self, width, fillchar=' '):
|
| 956 |
+
"""
|
| 957 |
+
Return an array with the elements of `self` left-justified in a
|
| 958 |
+
string of length `width`.
|
| 959 |
+
|
| 960 |
+
See Also
|
| 961 |
+
--------
|
| 962 |
+
char.ljust
|
| 963 |
+
|
| 964 |
+
"""
|
| 965 |
+
return asarray(ljust(self, width, fillchar))
|
| 966 |
+
|
| 967 |
+
def lower(self):
|
| 968 |
+
"""
|
| 969 |
+
Return an array with the elements of `self` converted to
|
| 970 |
+
lowercase.
|
| 971 |
+
|
| 972 |
+
See Also
|
| 973 |
+
--------
|
| 974 |
+
char.lower
|
| 975 |
+
|
| 976 |
+
"""
|
| 977 |
+
return asarray(lower(self))
|
| 978 |
+
|
| 979 |
+
def lstrip(self, chars=None):
|
| 980 |
+
"""
|
| 981 |
+
For each element in `self`, return a copy with the leading characters
|
| 982 |
+
removed.
|
| 983 |
+
|
| 984 |
+
See Also
|
| 985 |
+
--------
|
| 986 |
+
char.lstrip
|
| 987 |
+
|
| 988 |
+
"""
|
| 989 |
+
return lstrip(self, chars)
|
| 990 |
+
|
| 991 |
+
def partition(self, sep):
|
| 992 |
+
"""
|
| 993 |
+
Partition each element in `self` around `sep`.
|
| 994 |
+
|
| 995 |
+
See Also
|
| 996 |
+
--------
|
| 997 |
+
partition
|
| 998 |
+
"""
|
| 999 |
+
return asarray(partition(self, sep))
|
| 1000 |
+
|
| 1001 |
+
def replace(self, old, new, count=None):
|
| 1002 |
+
"""
|
| 1003 |
+
For each element in `self`, return a copy of the string with all
|
| 1004 |
+
occurrences of substring `old` replaced by `new`.
|
| 1005 |
+
|
| 1006 |
+
See Also
|
| 1007 |
+
--------
|
| 1008 |
+
char.replace
|
| 1009 |
+
|
| 1010 |
+
"""
|
| 1011 |
+
return replace(self, old, new, count if count is not None else -1)
|
| 1012 |
+
|
| 1013 |
+
def rfind(self, sub, start=0, end=None):
|
| 1014 |
+
"""
|
| 1015 |
+
For each element in `self`, return the highest index in the string
|
| 1016 |
+
where substring `sub` is found, such that `sub` is contained
|
| 1017 |
+
within [`start`, `end`].
|
| 1018 |
+
|
| 1019 |
+
See Also
|
| 1020 |
+
--------
|
| 1021 |
+
char.rfind
|
| 1022 |
+
|
| 1023 |
+
"""
|
| 1024 |
+
return rfind(self, sub, start, end)
|
| 1025 |
+
|
| 1026 |
+
def rindex(self, sub, start=0, end=None):
|
| 1027 |
+
"""
|
| 1028 |
+
Like `rfind`, but raises :exc:`ValueError` when the substring `sub` is
|
| 1029 |
+
not found.
|
| 1030 |
+
|
| 1031 |
+
See Also
|
| 1032 |
+
--------
|
| 1033 |
+
char.rindex
|
| 1034 |
+
|
| 1035 |
+
"""
|
| 1036 |
+
return rindex(self, sub, start, end)
|
| 1037 |
+
|
| 1038 |
+
def rjust(self, width, fillchar=' '):
|
| 1039 |
+
"""
|
| 1040 |
+
Return an array with the elements of `self`
|
| 1041 |
+
right-justified in a string of length `width`.
|
| 1042 |
+
|
| 1043 |
+
See Also
|
| 1044 |
+
--------
|
| 1045 |
+
char.rjust
|
| 1046 |
+
|
| 1047 |
+
"""
|
| 1048 |
+
return asarray(rjust(self, width, fillchar))
|
| 1049 |
+
|
| 1050 |
+
def rpartition(self, sep):
|
| 1051 |
+
"""
|
| 1052 |
+
Partition each element in `self` around `sep`.
|
| 1053 |
+
|
| 1054 |
+
See Also
|
| 1055 |
+
--------
|
| 1056 |
+
rpartition
|
| 1057 |
+
"""
|
| 1058 |
+
return asarray(rpartition(self, sep))
|
| 1059 |
+
|
| 1060 |
+
def rsplit(self, sep=None, maxsplit=None):
|
| 1061 |
+
"""
|
| 1062 |
+
For each element in `self`, return a list of the words in
|
| 1063 |
+
the string, using `sep` as the delimiter string.
|
| 1064 |
+
|
| 1065 |
+
See Also
|
| 1066 |
+
--------
|
| 1067 |
+
char.rsplit
|
| 1068 |
+
|
| 1069 |
+
"""
|
| 1070 |
+
return rsplit(self, sep, maxsplit)
|
| 1071 |
+
|
| 1072 |
+
def rstrip(self, chars=None):
|
| 1073 |
+
"""
|
| 1074 |
+
For each element in `self`, return a copy with the trailing
|
| 1075 |
+
characters removed.
|
| 1076 |
+
|
| 1077 |
+
See Also
|
| 1078 |
+
--------
|
| 1079 |
+
char.rstrip
|
| 1080 |
+
|
| 1081 |
+
"""
|
| 1082 |
+
return rstrip(self, chars)
|
| 1083 |
+
|
| 1084 |
+
def split(self, sep=None, maxsplit=None):
|
| 1085 |
+
"""
|
| 1086 |
+
For each element in `self`, return a list of the words in the
|
| 1087 |
+
string, using `sep` as the delimiter string.
|
| 1088 |
+
|
| 1089 |
+
See Also
|
| 1090 |
+
--------
|
| 1091 |
+
char.split
|
| 1092 |
+
|
| 1093 |
+
"""
|
| 1094 |
+
return split(self, sep, maxsplit)
|
| 1095 |
+
|
| 1096 |
+
def splitlines(self, keepends=None):
|
| 1097 |
+
"""
|
| 1098 |
+
For each element in `self`, return a list of the lines in the
|
| 1099 |
+
element, breaking at line boundaries.
|
| 1100 |
+
|
| 1101 |
+
See Also
|
| 1102 |
+
--------
|
| 1103 |
+
char.splitlines
|
| 1104 |
+
|
| 1105 |
+
"""
|
| 1106 |
+
return splitlines(self, keepends)
|
| 1107 |
+
|
| 1108 |
+
def startswith(self, prefix, start=0, end=None):
|
| 1109 |
+
"""
|
| 1110 |
+
Returns a boolean array which is `True` where the string element
|
| 1111 |
+
in `self` starts with `prefix`, otherwise `False`.
|
| 1112 |
+
|
| 1113 |
+
See Also
|
| 1114 |
+
--------
|
| 1115 |
+
char.startswith
|
| 1116 |
+
|
| 1117 |
+
"""
|
| 1118 |
+
return startswith(self, prefix, start, end)
|
| 1119 |
+
|
| 1120 |
+
def strip(self, chars=None):
|
| 1121 |
+
"""
|
| 1122 |
+
For each element in `self`, return a copy with the leading and
|
| 1123 |
+
trailing characters removed.
|
| 1124 |
+
|
| 1125 |
+
See Also
|
| 1126 |
+
--------
|
| 1127 |
+
char.strip
|
| 1128 |
+
|
| 1129 |
+
"""
|
| 1130 |
+
return strip(self, chars)
|
| 1131 |
+
|
| 1132 |
+
def swapcase(self):
|
| 1133 |
+
"""
|
| 1134 |
+
For each element in `self`, return a copy of the string with
|
| 1135 |
+
uppercase characters converted to lowercase and vice versa.
|
| 1136 |
+
|
| 1137 |
+
See Also
|
| 1138 |
+
--------
|
| 1139 |
+
char.swapcase
|
| 1140 |
+
|
| 1141 |
+
"""
|
| 1142 |
+
return asarray(swapcase(self))
|
| 1143 |
+
|
| 1144 |
+
def title(self):
|
| 1145 |
+
"""
|
| 1146 |
+
For each element in `self`, return a titlecased version of the
|
| 1147 |
+
string: words start with uppercase characters, all remaining cased
|
| 1148 |
+
characters are lowercase.
|
| 1149 |
+
|
| 1150 |
+
See Also
|
| 1151 |
+
--------
|
| 1152 |
+
char.title
|
| 1153 |
+
|
| 1154 |
+
"""
|
| 1155 |
+
return asarray(title(self))
|
| 1156 |
+
|
| 1157 |
+
def translate(self, table, deletechars=None):
|
| 1158 |
+
"""
|
| 1159 |
+
For each element in `self`, return a copy of the string where
|
| 1160 |
+
all characters occurring in the optional argument
|
| 1161 |
+
`deletechars` are removed, and the remaining characters have
|
| 1162 |
+
been mapped through the given translation table.
|
| 1163 |
+
|
| 1164 |
+
See Also
|
| 1165 |
+
--------
|
| 1166 |
+
char.translate
|
| 1167 |
+
|
| 1168 |
+
"""
|
| 1169 |
+
return asarray(translate(self, table, deletechars))
|
| 1170 |
+
|
| 1171 |
+
def upper(self):
|
| 1172 |
+
"""
|
| 1173 |
+
Return an array with the elements of `self` converted to
|
| 1174 |
+
uppercase.
|
| 1175 |
+
|
| 1176 |
+
See Also
|
| 1177 |
+
--------
|
| 1178 |
+
char.upper
|
| 1179 |
+
|
| 1180 |
+
"""
|
| 1181 |
+
return asarray(upper(self))
|
| 1182 |
+
|
| 1183 |
+
def zfill(self, width):
|
| 1184 |
+
"""
|
| 1185 |
+
Return the numeric string left-filled with zeros in a string of
|
| 1186 |
+
length `width`.
|
| 1187 |
+
|
| 1188 |
+
See Also
|
| 1189 |
+
--------
|
| 1190 |
+
char.zfill
|
| 1191 |
+
|
| 1192 |
+
"""
|
| 1193 |
+
return asarray(zfill(self, width))
|
| 1194 |
+
|
| 1195 |
+
def isnumeric(self):
|
| 1196 |
+
"""
|
| 1197 |
+
For each element in `self`, return True if there are only
|
| 1198 |
+
numeric characters in the element.
|
| 1199 |
+
|
| 1200 |
+
See Also
|
| 1201 |
+
--------
|
| 1202 |
+
char.isnumeric
|
| 1203 |
+
|
| 1204 |
+
"""
|
| 1205 |
+
return isnumeric(self)
|
| 1206 |
+
|
| 1207 |
+
def isdecimal(self):
|
| 1208 |
+
"""
|
| 1209 |
+
For each element in `self`, return True if there are only
|
| 1210 |
+
decimal characters in the element.
|
| 1211 |
+
|
| 1212 |
+
See Also
|
| 1213 |
+
--------
|
| 1214 |
+
char.isdecimal
|
| 1215 |
+
|
| 1216 |
+
"""
|
| 1217 |
+
return isdecimal(self)
|
| 1218 |
+
|
| 1219 |
+
|
| 1220 |
+
@set_module("numpy.char")
|
| 1221 |
+
def array(obj, itemsize=None, copy=True, unicode=None, order=None):
|
| 1222 |
+
"""
|
| 1223 |
+
Create a `~numpy.char.chararray`.
|
| 1224 |
+
|
| 1225 |
+
.. deprecated:: 2.5
|
| 1226 |
+
``chararray`` is deprecated. Use an ``ndarray`` with a string or
|
| 1227 |
+
bytes dtype instead.
|
| 1228 |
+
|
| 1229 |
+
.. note::
|
| 1230 |
+
This class is provided for numarray backward-compatibility.
|
| 1231 |
+
New code (not concerned with numarray compatibility) should use
|
| 1232 |
+
arrays of type `bytes_` or `str_` and use the free functions
|
| 1233 |
+
in :mod:`numpy.char` for fast vectorized string operations instead.
|
| 1234 |
+
|
| 1235 |
+
Versus a NumPy array of dtype `bytes_` or `str_`, this
|
| 1236 |
+
class adds the following functionality:
|
| 1237 |
+
|
| 1238 |
+
1) values automatically have whitespace removed from the end
|
| 1239 |
+
when indexed
|
| 1240 |
+
|
| 1241 |
+
2) comparison operators automatically remove whitespace from the
|
| 1242 |
+
end when comparing values
|
| 1243 |
+
|
| 1244 |
+
3) vectorized string operations are provided as methods
|
| 1245 |
+
(e.g. `chararray.endswith <numpy.char.chararray.endswith>`)
|
| 1246 |
+
and infix operators (e.g. ``+, *, %``)
|
| 1247 |
+
|
| 1248 |
+
Parameters
|
| 1249 |
+
----------
|
| 1250 |
+
obj : array of str or unicode-like
|
| 1251 |
+
|
| 1252 |
+
itemsize : int, optional
|
| 1253 |
+
`itemsize` is the number of characters per scalar in the
|
| 1254 |
+
resulting array. If `itemsize` is None, and `obj` is an
|
| 1255 |
+
object array or a Python list, the `itemsize` will be
|
| 1256 |
+
automatically determined. If `itemsize` is provided and `obj`
|
| 1257 |
+
is of type str or unicode, then the `obj` string will be
|
| 1258 |
+
chunked into `itemsize` pieces.
|
| 1259 |
+
|
| 1260 |
+
copy : bool, optional
|
| 1261 |
+
If true (default), then the object is copied. Otherwise, a copy
|
| 1262 |
+
will only be made if ``__array__`` returns a copy, if obj is a
|
| 1263 |
+
nested sequence, or if a copy is needed to satisfy any of the other
|
| 1264 |
+
requirements (`itemsize`, unicode, `order`, etc.).
|
| 1265 |
+
|
| 1266 |
+
unicode : bool, optional
|
| 1267 |
+
When true, the resulting `~numpy.char.chararray` can contain Unicode
|
| 1268 |
+
characters, when false only 8-bit characters. If unicode is
|
| 1269 |
+
None and `obj` is one of the following:
|
| 1270 |
+
|
| 1271 |
+
- a `~numpy.char.chararray`,
|
| 1272 |
+
- an ndarray of type :class:`str_` or :class:`bytes_`
|
| 1273 |
+
- a Python :class:`str` or :class:`bytes` object,
|
| 1274 |
+
|
| 1275 |
+
then the unicode setting of the output array will be
|
| 1276 |
+
automatically determined.
|
| 1277 |
+
|
| 1278 |
+
order : {'C', 'F', 'A'}, optional
|
| 1279 |
+
Specify the order of the array. If order is 'C' (default), then the
|
| 1280 |
+
array will be in C-contiguous order (last-index varies the
|
| 1281 |
+
fastest). If order is 'F', then the returned array
|
| 1282 |
+
will be in Fortran-contiguous order (first-index varies the
|
| 1283 |
+
fastest). If order is 'A', then the returned array may
|
| 1284 |
+
be in any order (either C-, Fortran-contiguous, or even
|
| 1285 |
+
discontiguous).
|
| 1286 |
+
|
| 1287 |
+
Examples
|
| 1288 |
+
--------
|
| 1289 |
+
|
| 1290 |
+
>>> import numpy as np
|
| 1291 |
+
>>> char_array = np.char.array(['hello', 'world', 'numpy','array'])
|
| 1292 |
+
>>> char_array
|
| 1293 |
+
chararray(['hello', 'world', 'numpy', 'array'], dtype='<U5')
|
| 1294 |
+
|
| 1295 |
+
"""
|
| 1296 |
+
if isinstance(obj, (bytes, str)):
|
| 1297 |
+
if unicode is None:
|
| 1298 |
+
if isinstance(obj, str):
|
| 1299 |
+
unicode = True
|
| 1300 |
+
else:
|
| 1301 |
+
unicode = False
|
| 1302 |
+
|
| 1303 |
+
if itemsize is None:
|
| 1304 |
+
itemsize = len(obj)
|
| 1305 |
+
shape = len(obj) // itemsize
|
| 1306 |
+
|
| 1307 |
+
return chararray(shape, itemsize=itemsize, unicode=unicode,
|
| 1308 |
+
buffer=obj, order=order)
|
| 1309 |
+
|
| 1310 |
+
if isinstance(obj, (list, tuple)):
|
| 1311 |
+
obj = asnarray(obj)
|
| 1312 |
+
|
| 1313 |
+
if isinstance(obj, ndarray) and issubclass(obj.dtype.type, character):
|
| 1314 |
+
# If we just have a vanilla chararray, create a chararray
|
| 1315 |
+
# view around it.
|
| 1316 |
+
if not isinstance(obj, chararray):
|
| 1317 |
+
obj = obj.view(chararray)
|
| 1318 |
+
|
| 1319 |
+
if itemsize is None:
|
| 1320 |
+
itemsize = obj.itemsize
|
| 1321 |
+
# itemsize is in 8-bit chars, so for Unicode, we need
|
| 1322 |
+
# to divide by the size of a single Unicode character,
|
| 1323 |
+
# which for NumPy is always 4
|
| 1324 |
+
if issubclass(obj.dtype.type, str_):
|
| 1325 |
+
itemsize //= 4
|
| 1326 |
+
|
| 1327 |
+
if unicode is None:
|
| 1328 |
+
if issubclass(obj.dtype.type, str_):
|
| 1329 |
+
unicode = True
|
| 1330 |
+
else:
|
| 1331 |
+
unicode = False
|
| 1332 |
+
|
| 1333 |
+
if unicode:
|
| 1334 |
+
dtype = str_
|
| 1335 |
+
else:
|
| 1336 |
+
dtype = bytes_
|
| 1337 |
+
|
| 1338 |
+
if order is not None:
|
| 1339 |
+
obj = asnarray(obj, order=order)
|
| 1340 |
+
if (copy or
|
| 1341 |
+
(itemsize != obj.itemsize) or
|
| 1342 |
+
(not unicode and isinstance(obj, str_)) or
|
| 1343 |
+
(unicode and isinstance(obj, bytes_))):
|
| 1344 |
+
obj = obj.astype((dtype, int(itemsize)))
|
| 1345 |
+
return obj
|
| 1346 |
+
|
| 1347 |
+
if isinstance(obj, ndarray) and issubclass(obj.dtype.type, object):
|
| 1348 |
+
if itemsize is None:
|
| 1349 |
+
# Since no itemsize was specified, convert the input array to
|
| 1350 |
+
# a list so the ndarray constructor will automatically
|
| 1351 |
+
# determine the itemsize for us.
|
| 1352 |
+
obj = obj.tolist()
|
| 1353 |
+
# Fall through to the default case
|
| 1354 |
+
|
| 1355 |
+
if unicode:
|
| 1356 |
+
dtype = str_
|
| 1357 |
+
else:
|
| 1358 |
+
dtype = bytes_
|
| 1359 |
+
|
| 1360 |
+
if itemsize is None:
|
| 1361 |
+
val = narray(obj, dtype=dtype, order=order, subok=True)
|
| 1362 |
+
else:
|
| 1363 |
+
val = narray(obj, dtype=(dtype, itemsize), order=order, subok=True)
|
| 1364 |
+
return val.view(chararray)
|
| 1365 |
+
|
| 1366 |
+
|
| 1367 |
+
@set_module("numpy.char")
|
| 1368 |
+
def asarray(obj, itemsize=None, unicode=None, order=None):
|
| 1369 |
+
"""
|
| 1370 |
+
Convert the input to a `~numpy.char.chararray`, copying the data only if
|
| 1371 |
+
necessary.
|
| 1372 |
+
|
| 1373 |
+
.. deprecated:: 2.5
|
| 1374 |
+
``chararray`` is deprecated. Use an ``ndarray`` with a string or
|
| 1375 |
+
bytes dtype instead.
|
| 1376 |
+
|
| 1377 |
+
Versus a NumPy array of dtype `bytes_` or `str_`, this
|
| 1378 |
+
class adds the following functionality:
|
| 1379 |
+
|
| 1380 |
+
1) values automatically have whitespace removed from the end
|
| 1381 |
+
when indexed
|
| 1382 |
+
|
| 1383 |
+
2) comparison operators automatically remove whitespace from the
|
| 1384 |
+
end when comparing values
|
| 1385 |
+
|
| 1386 |
+
3) vectorized string operations are provided as methods
|
| 1387 |
+
(e.g. `chararray.endswith <numpy.char.chararray.endswith>`)
|
| 1388 |
+
and infix operators (e.g. ``+``, ``*``, ``%``)
|
| 1389 |
+
|
| 1390 |
+
Parameters
|
| 1391 |
+
----------
|
| 1392 |
+
obj : array of str or unicode-like
|
| 1393 |
+
|
| 1394 |
+
itemsize : int, optional
|
| 1395 |
+
`itemsize` is the number of characters per scalar in the
|
| 1396 |
+
resulting array. If `itemsize` is None, and `obj` is an
|
| 1397 |
+
object array or a Python list, the `itemsize` will be
|
| 1398 |
+
automatically determined. If `itemsize` is provided and `obj`
|
| 1399 |
+
is of type str or unicode, then the `obj` string will be
|
| 1400 |
+
chunked into `itemsize` pieces.
|
| 1401 |
+
|
| 1402 |
+
unicode : bool, optional
|
| 1403 |
+
When true, the resulting `~numpy.char.chararray` can contain Unicode
|
| 1404 |
+
characters, when false only 8-bit characters. If unicode is
|
| 1405 |
+
None and `obj` is one of the following:
|
| 1406 |
+
|
| 1407 |
+
- a `~numpy.char.chararray`,
|
| 1408 |
+
- an ndarray of type `str_` or `unicode_`
|
| 1409 |
+
- a Python str or unicode object,
|
| 1410 |
+
|
| 1411 |
+
then the unicode setting of the output array will be
|
| 1412 |
+
automatically determined.
|
| 1413 |
+
|
| 1414 |
+
order : {'C', 'F'}, optional
|
| 1415 |
+
Specify the order of the array. If order is 'C' (default), then the
|
| 1416 |
+
array will be in C-contiguous order (last-index varies the
|
| 1417 |
+
fastest). If order is 'F', then the returned array
|
| 1418 |
+
will be in Fortran-contiguous order (first-index varies the
|
| 1419 |
+
fastest).
|
| 1420 |
+
|
| 1421 |
+
Examples
|
| 1422 |
+
--------
|
| 1423 |
+
>>> import numpy as np
|
| 1424 |
+
>>> np.char.asarray(['hello', 'world'])
|
| 1425 |
+
chararray(['hello', 'world'], dtype='<U5')
|
| 1426 |
+
|
| 1427 |
+
"""
|
| 1428 |
+
return array(obj, itemsize, copy=False,
|
| 1429 |
+
unicode=unicode, order=order)
|
v12x/pylib/numpy/_core/einsumfunc.py
ADDED
|
@@ -0,0 +1,1647 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Implementation of optimized einsum.
|
| 3 |
+
|
| 4 |
+
"""
|
| 5 |
+
import functools
|
| 6 |
+
import itertools
|
| 7 |
+
import operator
|
| 8 |
+
|
| 9 |
+
from numpy._core.multiarray import c_einsum, matmul
|
| 10 |
+
from numpy._core.numeric import asanyarray, reshape
|
| 11 |
+
from numpy._core.overrides import array_function_dispatch
|
| 12 |
+
from numpy._core.umath import multiply
|
| 13 |
+
|
| 14 |
+
__all__ = ['einsum', 'einsum_path']
|
| 15 |
+
|
| 16 |
+
# importing string for string.ascii_letters would be too slow
|
| 17 |
+
# the first import before caching has been measured to take 800 µs (#23777)
|
| 18 |
+
# imports begin with uppercase to mimic ASCII values to avoid sorting issues
|
| 19 |
+
einsum_symbols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
| 20 |
+
einsum_symbols_set = set(einsum_symbols)
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _flop_count(idx_contraction, inner, num_terms, size_dictionary):
|
| 24 |
+
"""
|
| 25 |
+
Computes the number of FLOPS in the contraction.
|
| 26 |
+
|
| 27 |
+
Parameters
|
| 28 |
+
----------
|
| 29 |
+
idx_contraction : iterable
|
| 30 |
+
The indices involved in the contraction
|
| 31 |
+
inner : bool
|
| 32 |
+
Does this contraction require an inner product?
|
| 33 |
+
num_terms : int
|
| 34 |
+
The number of terms in a contraction
|
| 35 |
+
size_dictionary : dict
|
| 36 |
+
The size of each of the indices in idx_contraction
|
| 37 |
+
|
| 38 |
+
Returns
|
| 39 |
+
-------
|
| 40 |
+
flop_count : int
|
| 41 |
+
The total number of FLOPS required for the contraction.
|
| 42 |
+
|
| 43 |
+
Examples
|
| 44 |
+
--------
|
| 45 |
+
|
| 46 |
+
>>> _flop_count('abc', False, 1, {'a': 2, 'b':3, 'c':5})
|
| 47 |
+
30
|
| 48 |
+
|
| 49 |
+
>>> _flop_count('abc', True, 2, {'a': 2, 'b':3, 'c':5})
|
| 50 |
+
60
|
| 51 |
+
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
overall_size = _compute_size_by_dict(idx_contraction, size_dictionary)
|
| 55 |
+
op_factor = max(1, num_terms - 1)
|
| 56 |
+
if inner:
|
| 57 |
+
op_factor += 1
|
| 58 |
+
|
| 59 |
+
return overall_size * op_factor
|
| 60 |
+
|
| 61 |
+
def _compute_size_by_dict(indices, idx_dict):
|
| 62 |
+
"""
|
| 63 |
+
Computes the product of the elements in indices based on the dictionary
|
| 64 |
+
idx_dict.
|
| 65 |
+
|
| 66 |
+
Parameters
|
| 67 |
+
----------
|
| 68 |
+
indices : iterable
|
| 69 |
+
Indices to base the product on.
|
| 70 |
+
idx_dict : dictionary
|
| 71 |
+
Dictionary of index sizes
|
| 72 |
+
|
| 73 |
+
Returns
|
| 74 |
+
-------
|
| 75 |
+
ret : int
|
| 76 |
+
The resulting product.
|
| 77 |
+
|
| 78 |
+
Examples
|
| 79 |
+
--------
|
| 80 |
+
>>> _compute_size_by_dict('abbc', {'a': 2, 'b':3, 'c':5})
|
| 81 |
+
90
|
| 82 |
+
|
| 83 |
+
"""
|
| 84 |
+
ret = 1
|
| 85 |
+
for i in indices:
|
| 86 |
+
ret *= idx_dict[i]
|
| 87 |
+
return ret
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def _find_contraction(positions, input_sets, output_set):
|
| 91 |
+
"""
|
| 92 |
+
Finds the contraction for a given set of input and output sets.
|
| 93 |
+
|
| 94 |
+
Parameters
|
| 95 |
+
----------
|
| 96 |
+
positions : iterable
|
| 97 |
+
Integer positions of terms used in the contraction.
|
| 98 |
+
input_sets : list
|
| 99 |
+
List of sets that represent the lhs side of the einsum subscript
|
| 100 |
+
output_set : set
|
| 101 |
+
Set that represents the rhs side of the overall einsum subscript
|
| 102 |
+
|
| 103 |
+
Returns
|
| 104 |
+
-------
|
| 105 |
+
new_result : set
|
| 106 |
+
The indices of the resulting contraction
|
| 107 |
+
remaining : list
|
| 108 |
+
List of sets that have not been contracted, the new set is appended to
|
| 109 |
+
the end of this list
|
| 110 |
+
idx_removed : set
|
| 111 |
+
Indices removed from the entire contraction
|
| 112 |
+
idx_contraction : set
|
| 113 |
+
The indices used in the current contraction
|
| 114 |
+
|
| 115 |
+
Examples
|
| 116 |
+
--------
|
| 117 |
+
|
| 118 |
+
# A simple dot product test case
|
| 119 |
+
>>> pos = (0, 1)
|
| 120 |
+
>>> isets = [set('ab'), set('bc')]
|
| 121 |
+
>>> oset = set('ac')
|
| 122 |
+
>>> _find_contraction(pos, isets, oset)
|
| 123 |
+
({'a', 'c'}, [{'a', 'c'}], {'b'}, {'a', 'b', 'c'})
|
| 124 |
+
|
| 125 |
+
# A more complex case with additional terms in the contraction
|
| 126 |
+
>>> pos = (0, 2)
|
| 127 |
+
>>> isets = [set('abd'), set('ac'), set('bdc')]
|
| 128 |
+
>>> oset = set('ac')
|
| 129 |
+
>>> _find_contraction(pos, isets, oset)
|
| 130 |
+
({'a', 'c'}, [{'a', 'c'}, {'a', 'c'}], {'b', 'd'}, {'a', 'b', 'c', 'd'})
|
| 131 |
+
"""
|
| 132 |
+
|
| 133 |
+
idx_contract = set()
|
| 134 |
+
idx_remain = output_set.copy()
|
| 135 |
+
remaining = []
|
| 136 |
+
for ind, value in enumerate(input_sets):
|
| 137 |
+
if ind in positions:
|
| 138 |
+
idx_contract |= value
|
| 139 |
+
else:
|
| 140 |
+
remaining.append(value)
|
| 141 |
+
idx_remain |= value
|
| 142 |
+
|
| 143 |
+
new_result = idx_remain & idx_contract
|
| 144 |
+
idx_removed = (idx_contract - new_result)
|
| 145 |
+
remaining.append(new_result)
|
| 146 |
+
|
| 147 |
+
return (new_result, remaining, idx_removed, idx_contract)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def _optimal_path(input_sets, output_set, idx_dict, memory_limit):
|
| 151 |
+
"""
|
| 152 |
+
Computes all possible pair contractions, sieves the results based
|
| 153 |
+
on ``memory_limit`` and returns the lowest cost path. This algorithm
|
| 154 |
+
scales factorial with respect to the elements in the list ``input_sets``.
|
| 155 |
+
|
| 156 |
+
Parameters
|
| 157 |
+
----------
|
| 158 |
+
input_sets : list
|
| 159 |
+
List of sets that represent the lhs side of the einsum subscript
|
| 160 |
+
output_set : set
|
| 161 |
+
Set that represents the rhs side of the overall einsum subscript
|
| 162 |
+
idx_dict : dictionary
|
| 163 |
+
Dictionary of index sizes
|
| 164 |
+
memory_limit : int
|
| 165 |
+
The maximum number of elements in a temporary array
|
| 166 |
+
|
| 167 |
+
Returns
|
| 168 |
+
-------
|
| 169 |
+
path : list
|
| 170 |
+
The optimal contraction order within the memory limit constraint.
|
| 171 |
+
|
| 172 |
+
Examples
|
| 173 |
+
--------
|
| 174 |
+
>>> isets = [set('abd'), set('ac'), set('bdc')]
|
| 175 |
+
>>> oset = set()
|
| 176 |
+
>>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4}
|
| 177 |
+
>>> _optimal_path(isets, oset, idx_sizes, 5000)
|
| 178 |
+
[(0, 2), (0, 1)]
|
| 179 |
+
"""
|
| 180 |
+
|
| 181 |
+
full_results = [(0, [], input_sets)]
|
| 182 |
+
for iteration in range(len(input_sets) - 1):
|
| 183 |
+
iter_results = []
|
| 184 |
+
|
| 185 |
+
# Compute all unique pairs
|
| 186 |
+
for curr in full_results:
|
| 187 |
+
cost, positions, remaining = curr
|
| 188 |
+
for con in itertools.combinations(
|
| 189 |
+
range(len(input_sets) - iteration), 2
|
| 190 |
+
):
|
| 191 |
+
|
| 192 |
+
# Find the contraction
|
| 193 |
+
cont = _find_contraction(con, remaining, output_set)
|
| 194 |
+
new_result, new_input_sets, idx_removed, idx_contract = cont
|
| 195 |
+
|
| 196 |
+
# Sieve the results based on memory_limit
|
| 197 |
+
new_size = _compute_size_by_dict(new_result, idx_dict)
|
| 198 |
+
if new_size > memory_limit:
|
| 199 |
+
continue
|
| 200 |
+
|
| 201 |
+
# Build (total_cost, positions, indices_remaining)
|
| 202 |
+
total_cost = cost + _flop_count(
|
| 203 |
+
idx_contract, idx_removed, len(con), idx_dict
|
| 204 |
+
)
|
| 205 |
+
new_pos = positions + [con]
|
| 206 |
+
iter_results.append((total_cost, new_pos, new_input_sets))
|
| 207 |
+
|
| 208 |
+
# Update combinatorial list, if we did not find anything return best
|
| 209 |
+
# path + remaining contractions
|
| 210 |
+
if iter_results:
|
| 211 |
+
full_results = iter_results
|
| 212 |
+
else:
|
| 213 |
+
path = min(full_results, key=lambda x: x[0])[1]
|
| 214 |
+
path += [tuple(range(len(input_sets) - iteration))]
|
| 215 |
+
return path
|
| 216 |
+
|
| 217 |
+
# If we have not found anything return single einsum contraction
|
| 218 |
+
if len(full_results) == 0:
|
| 219 |
+
return [tuple(range(len(input_sets)))]
|
| 220 |
+
|
| 221 |
+
path = min(full_results, key=lambda x: x[0])[1]
|
| 222 |
+
return path
|
| 223 |
+
|
| 224 |
+
def _parse_possible_contraction(
|
| 225 |
+
positions, input_sets, output_set, idx_dict,
|
| 226 |
+
memory_limit, path_cost, naive_cost
|
| 227 |
+
):
|
| 228 |
+
"""Compute the cost (removed size + flops) and resultant indices for
|
| 229 |
+
performing the contraction specified by ``positions``.
|
| 230 |
+
|
| 231 |
+
Parameters
|
| 232 |
+
----------
|
| 233 |
+
positions : tuple of int
|
| 234 |
+
The locations of the proposed tensors to contract.
|
| 235 |
+
input_sets : list of sets
|
| 236 |
+
The indices found on each tensors.
|
| 237 |
+
output_set : set
|
| 238 |
+
The output indices of the expression.
|
| 239 |
+
idx_dict : dict
|
| 240 |
+
Mapping of each index to its size.
|
| 241 |
+
memory_limit : int
|
| 242 |
+
The total allowed size for an intermediary tensor.
|
| 243 |
+
path_cost : int
|
| 244 |
+
The contraction cost so far.
|
| 245 |
+
naive_cost : int
|
| 246 |
+
The cost of the unoptimized expression.
|
| 247 |
+
|
| 248 |
+
Returns
|
| 249 |
+
-------
|
| 250 |
+
cost : (int, int)
|
| 251 |
+
A tuple containing the size of any indices removed, and the flop cost.
|
| 252 |
+
positions : tuple of int
|
| 253 |
+
The locations of the proposed tensors to contract.
|
| 254 |
+
new_input_sets : list of sets
|
| 255 |
+
The resulting new list of indices if this proposed contraction
|
| 256 |
+
is performed.
|
| 257 |
+
|
| 258 |
+
"""
|
| 259 |
+
|
| 260 |
+
# Find the contraction
|
| 261 |
+
contract = _find_contraction(positions, input_sets, output_set)
|
| 262 |
+
idx_result, new_input_sets, idx_removed, idx_contract = contract
|
| 263 |
+
|
| 264 |
+
# Sieve the results based on memory_limit
|
| 265 |
+
new_size = _compute_size_by_dict(idx_result, idx_dict)
|
| 266 |
+
if new_size > memory_limit:
|
| 267 |
+
return None
|
| 268 |
+
|
| 269 |
+
# Build sort tuple
|
| 270 |
+
old_sizes = (
|
| 271 |
+
_compute_size_by_dict(input_sets[p], idx_dict) for p in positions
|
| 272 |
+
)
|
| 273 |
+
removed_size = sum(old_sizes) - new_size
|
| 274 |
+
|
| 275 |
+
# NB: removed_size used to be just the size of any removed indices i.e.:
|
| 276 |
+
# helpers.compute_size_by_dict(idx_removed, idx_dict)
|
| 277 |
+
cost = _flop_count(idx_contract, idx_removed, len(positions), idx_dict)
|
| 278 |
+
sort = (-removed_size, cost)
|
| 279 |
+
|
| 280 |
+
# Sieve based on total cost as well
|
| 281 |
+
if (path_cost + cost) > naive_cost:
|
| 282 |
+
return None
|
| 283 |
+
|
| 284 |
+
# Add contraction to possible choices
|
| 285 |
+
return [sort, positions, new_input_sets]
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
def _update_other_results(results, best):
|
| 289 |
+
"""Update the positions and provisional input_sets of ``results``
|
| 290 |
+
based on performing the contraction result ``best``. Remove any
|
| 291 |
+
involving the tensors contracted.
|
| 292 |
+
|
| 293 |
+
Parameters
|
| 294 |
+
----------
|
| 295 |
+
results : list
|
| 296 |
+
List of contraction results produced by
|
| 297 |
+
``_parse_possible_contraction``.
|
| 298 |
+
best : list
|
| 299 |
+
The best contraction of ``results`` i.e. the one that
|
| 300 |
+
will be performed.
|
| 301 |
+
|
| 302 |
+
Returns
|
| 303 |
+
-------
|
| 304 |
+
mod_results : list
|
| 305 |
+
The list of modified results, updated with outcome of
|
| 306 |
+
``best`` contraction.
|
| 307 |
+
"""
|
| 308 |
+
|
| 309 |
+
best_con = best[1]
|
| 310 |
+
bx, by = best_con
|
| 311 |
+
mod_results = []
|
| 312 |
+
|
| 313 |
+
for cost, (x, y), con_sets in results:
|
| 314 |
+
|
| 315 |
+
# Ignore results involving tensors just contracted
|
| 316 |
+
if x in best_con or y in best_con:
|
| 317 |
+
continue
|
| 318 |
+
|
| 319 |
+
# Update the input_sets
|
| 320 |
+
del con_sets[by - int(by > x) - int(by > y)]
|
| 321 |
+
del con_sets[bx - int(bx > x) - int(bx > y)]
|
| 322 |
+
con_sets.insert(-1, best[2][-1])
|
| 323 |
+
|
| 324 |
+
# Update the position indices
|
| 325 |
+
mod_con = x - int(x > bx) - int(x > by), y - int(y > bx) - int(y > by)
|
| 326 |
+
mod_results.append((cost, mod_con, con_sets))
|
| 327 |
+
|
| 328 |
+
return mod_results
|
| 329 |
+
|
| 330 |
+
def _greedy_path(input_sets, output_set, idx_dict, memory_limit):
|
| 331 |
+
"""
|
| 332 |
+
Finds the path by contracting the best pair until the input list is
|
| 333 |
+
exhausted. The best pair is found by minimizing the tuple
|
| 334 |
+
``(-prod(indices_removed), cost)``. What this amounts to is prioritizing
|
| 335 |
+
matrix multiplication or inner product operations, then Hadamard like
|
| 336 |
+
operations, and finally outer operations. Outer products are limited by
|
| 337 |
+
``memory_limit``. This algorithm scales cubically with respect to the
|
| 338 |
+
number of elements in the list ``input_sets``.
|
| 339 |
+
|
| 340 |
+
Parameters
|
| 341 |
+
----------
|
| 342 |
+
input_sets : list
|
| 343 |
+
List of sets that represent the lhs side of the einsum subscript
|
| 344 |
+
output_set : set
|
| 345 |
+
Set that represents the rhs side of the overall einsum subscript
|
| 346 |
+
idx_dict : dictionary
|
| 347 |
+
Dictionary of index sizes
|
| 348 |
+
memory_limit : int
|
| 349 |
+
The maximum number of elements in a temporary array
|
| 350 |
+
|
| 351 |
+
Returns
|
| 352 |
+
-------
|
| 353 |
+
path : list
|
| 354 |
+
The greedy contraction order within the memory limit constraint.
|
| 355 |
+
|
| 356 |
+
Examples
|
| 357 |
+
--------
|
| 358 |
+
>>> isets = [set('abd'), set('ac'), set('bdc')]
|
| 359 |
+
>>> oset = set()
|
| 360 |
+
>>> idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4}
|
| 361 |
+
>>> _greedy_path(isets, oset, idx_sizes, 5000)
|
| 362 |
+
[(0, 2), (0, 1)]
|
| 363 |
+
"""
|
| 364 |
+
|
| 365 |
+
# Handle trivial cases that leaked through
|
| 366 |
+
if len(input_sets) == 1:
|
| 367 |
+
return [(0,)]
|
| 368 |
+
elif len(input_sets) == 2:
|
| 369 |
+
return [(0, 1)]
|
| 370 |
+
|
| 371 |
+
# Build up a naive cost
|
| 372 |
+
contract = _find_contraction(
|
| 373 |
+
range(len(input_sets)), input_sets, output_set
|
| 374 |
+
)
|
| 375 |
+
idx_result, new_input_sets, idx_removed, idx_contract = contract
|
| 376 |
+
naive_cost = _flop_count(
|
| 377 |
+
idx_contract, idx_removed, len(input_sets), idx_dict
|
| 378 |
+
)
|
| 379 |
+
|
| 380 |
+
# Initially iterate over all pairs
|
| 381 |
+
comb_iter = itertools.combinations(range(len(input_sets)), 2)
|
| 382 |
+
known_contractions = []
|
| 383 |
+
|
| 384 |
+
path_cost = 0
|
| 385 |
+
path = []
|
| 386 |
+
|
| 387 |
+
for iteration in range(len(input_sets) - 1):
|
| 388 |
+
|
| 389 |
+
# Iterate over all pairs on the first step, only previously
|
| 390 |
+
# found pairs on subsequent steps
|
| 391 |
+
for positions in comb_iter:
|
| 392 |
+
|
| 393 |
+
# Always initially ignore outer products
|
| 394 |
+
if input_sets[positions[0]].isdisjoint(input_sets[positions[1]]):
|
| 395 |
+
continue
|
| 396 |
+
|
| 397 |
+
result = _parse_possible_contraction(
|
| 398 |
+
positions, input_sets, output_set, idx_dict,
|
| 399 |
+
memory_limit, path_cost, naive_cost
|
| 400 |
+
)
|
| 401 |
+
if result is not None:
|
| 402 |
+
known_contractions.append(result)
|
| 403 |
+
|
| 404 |
+
# If we do not have an inner contraction, rescan pairs
|
| 405 |
+
# including outer products
|
| 406 |
+
if len(known_contractions) == 0:
|
| 407 |
+
|
| 408 |
+
# Then check the outer products
|
| 409 |
+
for positions in itertools.combinations(
|
| 410 |
+
range(len(input_sets)), 2
|
| 411 |
+
):
|
| 412 |
+
result = _parse_possible_contraction(
|
| 413 |
+
positions, input_sets, output_set, idx_dict,
|
| 414 |
+
memory_limit, path_cost, naive_cost
|
| 415 |
+
)
|
| 416 |
+
if result is not None:
|
| 417 |
+
known_contractions.append(result)
|
| 418 |
+
|
| 419 |
+
# If we still did not find any remaining contractions,
|
| 420 |
+
# default back to einsum like behavior
|
| 421 |
+
if len(known_contractions) == 0:
|
| 422 |
+
path.append(tuple(range(len(input_sets))))
|
| 423 |
+
break
|
| 424 |
+
|
| 425 |
+
# Sort based on first index
|
| 426 |
+
best = min(known_contractions, key=lambda x: x[0])
|
| 427 |
+
|
| 428 |
+
# Now propagate as many unused contractions as possible
|
| 429 |
+
# to the next iteration
|
| 430 |
+
known_contractions = _update_other_results(known_contractions, best)
|
| 431 |
+
|
| 432 |
+
# Next iteration only compute contractions with the new tensor
|
| 433 |
+
# All other contractions have been accounted for
|
| 434 |
+
input_sets = best[2]
|
| 435 |
+
new_tensor_pos = len(input_sets) - 1
|
| 436 |
+
comb_iter = ((i, new_tensor_pos) for i in range(new_tensor_pos))
|
| 437 |
+
|
| 438 |
+
# Update path and total cost
|
| 439 |
+
path.append(best[1])
|
| 440 |
+
path_cost += best[0][1]
|
| 441 |
+
|
| 442 |
+
return path
|
| 443 |
+
|
| 444 |
+
|
| 445 |
+
def _parse_einsum_input(operands):
|
| 446 |
+
"""
|
| 447 |
+
A reproduction of einsum c side einsum parsing in python.
|
| 448 |
+
|
| 449 |
+
Returns
|
| 450 |
+
-------
|
| 451 |
+
input_strings : str
|
| 452 |
+
Parsed input strings
|
| 453 |
+
output_string : str
|
| 454 |
+
Parsed output string
|
| 455 |
+
operands : list of array_like
|
| 456 |
+
The operands to use in the numpy contraction
|
| 457 |
+
|
| 458 |
+
Examples
|
| 459 |
+
--------
|
| 460 |
+
The operand list is simplified to reduce printing:
|
| 461 |
+
|
| 462 |
+
>>> np.random.seed(123)
|
| 463 |
+
>>> a = np.random.rand(4, 4)
|
| 464 |
+
>>> b = np.random.rand(4, 4, 4)
|
| 465 |
+
>>> _parse_einsum_input(('...a,...a->...', a, b))
|
| 466 |
+
('za,xza', 'xz', [a, b]) # may vary
|
| 467 |
+
|
| 468 |
+
>>> _parse_einsum_input((a, [Ellipsis, 0], b, [Ellipsis, 0]))
|
| 469 |
+
('za,xza', 'xz', [a, b]) # may vary
|
| 470 |
+
"""
|
| 471 |
+
|
| 472 |
+
if len(operands) == 0:
|
| 473 |
+
raise ValueError("No input operands")
|
| 474 |
+
|
| 475 |
+
if isinstance(operands[0], str):
|
| 476 |
+
subscripts = operands[0].replace(" ", "")
|
| 477 |
+
operands = [asanyarray(v) for v in operands[1:]]
|
| 478 |
+
|
| 479 |
+
# Ensure all characters are valid
|
| 480 |
+
for s in subscripts:
|
| 481 |
+
if s in '.,->':
|
| 482 |
+
continue
|
| 483 |
+
if s not in einsum_symbols:
|
| 484 |
+
raise ValueError(f"Character {s} is not a valid symbol.")
|
| 485 |
+
|
| 486 |
+
else:
|
| 487 |
+
tmp_operands = list(operands)
|
| 488 |
+
operand_list = []
|
| 489 |
+
subscript_list = []
|
| 490 |
+
for p in range(len(operands) // 2):
|
| 491 |
+
operand_list.append(tmp_operands.pop(0))
|
| 492 |
+
subscript_list.append(tmp_operands.pop(0))
|
| 493 |
+
|
| 494 |
+
output_list = tmp_operands[-1] if len(tmp_operands) else None
|
| 495 |
+
operands = [asanyarray(v) for v in operand_list]
|
| 496 |
+
subscripts = ""
|
| 497 |
+
last = len(subscript_list) - 1
|
| 498 |
+
for num, sub in enumerate(subscript_list):
|
| 499 |
+
for s in sub:
|
| 500 |
+
if s is Ellipsis:
|
| 501 |
+
subscripts += "..."
|
| 502 |
+
else:
|
| 503 |
+
try:
|
| 504 |
+
s = operator.index(s)
|
| 505 |
+
except TypeError as e:
|
| 506 |
+
raise TypeError(
|
| 507 |
+
"For this input type lists must contain "
|
| 508 |
+
"either int or Ellipsis"
|
| 509 |
+
) from e
|
| 510 |
+
subscripts += einsum_symbols[s]
|
| 511 |
+
if num != last:
|
| 512 |
+
subscripts += ","
|
| 513 |
+
|
| 514 |
+
if output_list is not None:
|
| 515 |
+
subscripts += "->"
|
| 516 |
+
for s in output_list:
|
| 517 |
+
if s is Ellipsis:
|
| 518 |
+
subscripts += "..."
|
| 519 |
+
else:
|
| 520 |
+
try:
|
| 521 |
+
s = operator.index(s)
|
| 522 |
+
except TypeError as e:
|
| 523 |
+
raise TypeError(
|
| 524 |
+
"For this input type lists must contain "
|
| 525 |
+
"either int or Ellipsis"
|
| 526 |
+
) from e
|
| 527 |
+
subscripts += einsum_symbols[s]
|
| 528 |
+
# Check for proper "->"
|
| 529 |
+
if ("-" in subscripts) or (">" in subscripts):
|
| 530 |
+
invalid = (subscripts.count("-") > 1) or (subscripts.count(">") > 1)
|
| 531 |
+
if invalid or (subscripts.count("->") != 1):
|
| 532 |
+
raise ValueError("Subscripts can only contain one '->'.")
|
| 533 |
+
|
| 534 |
+
# Parse ellipses
|
| 535 |
+
if "." in subscripts:
|
| 536 |
+
used = subscripts.replace(".", "").replace(",", "").replace("->", "")
|
| 537 |
+
unused = list(einsum_symbols_set - set(used))
|
| 538 |
+
ellipse_inds = "".join(unused)
|
| 539 |
+
longest = 0
|
| 540 |
+
|
| 541 |
+
if "->" in subscripts:
|
| 542 |
+
input_tmp, output_sub = subscripts.split("->")
|
| 543 |
+
split_subscripts = input_tmp.split(",")
|
| 544 |
+
out_sub = True
|
| 545 |
+
else:
|
| 546 |
+
split_subscripts = subscripts.split(',')
|
| 547 |
+
out_sub = False
|
| 548 |
+
|
| 549 |
+
for num, sub in enumerate(split_subscripts):
|
| 550 |
+
if "." in sub:
|
| 551 |
+
if (sub.count(".") != 3) or (sub.count("...") != 1):
|
| 552 |
+
raise ValueError("Invalid Ellipses.")
|
| 553 |
+
|
| 554 |
+
# Take into account numerical values
|
| 555 |
+
if operands[num].shape == ():
|
| 556 |
+
ellipse_count = 0
|
| 557 |
+
else:
|
| 558 |
+
ellipse_count = max(operands[num].ndim, 1)
|
| 559 |
+
ellipse_count -= (len(sub) - 3)
|
| 560 |
+
|
| 561 |
+
if ellipse_count > longest:
|
| 562 |
+
longest = ellipse_count
|
| 563 |
+
|
| 564 |
+
if ellipse_count < 0:
|
| 565 |
+
raise ValueError("Ellipses lengths do not match.")
|
| 566 |
+
elif ellipse_count == 0:
|
| 567 |
+
split_subscripts[num] = sub.replace('...', '')
|
| 568 |
+
else:
|
| 569 |
+
rep_inds = ellipse_inds[-ellipse_count:]
|
| 570 |
+
split_subscripts[num] = sub.replace('...', rep_inds)
|
| 571 |
+
|
| 572 |
+
subscripts = ",".join(split_subscripts)
|
| 573 |
+
if longest == 0:
|
| 574 |
+
out_ellipse = ""
|
| 575 |
+
else:
|
| 576 |
+
out_ellipse = ellipse_inds[-longest:]
|
| 577 |
+
|
| 578 |
+
if out_sub:
|
| 579 |
+
subscripts += "->" + output_sub.replace("...", out_ellipse)
|
| 580 |
+
else:
|
| 581 |
+
# Special care for outputless ellipses
|
| 582 |
+
output_subscript = ""
|
| 583 |
+
tmp_subscripts = subscripts.replace(",", "")
|
| 584 |
+
for s in sorted(set(tmp_subscripts)):
|
| 585 |
+
if s not in (einsum_symbols):
|
| 586 |
+
raise ValueError(f"Character {s} is not a valid symbol.")
|
| 587 |
+
if tmp_subscripts.count(s) == 1:
|
| 588 |
+
output_subscript += s
|
| 589 |
+
normal_inds = ''.join(sorted(set(output_subscript) -
|
| 590 |
+
set(out_ellipse)))
|
| 591 |
+
|
| 592 |
+
subscripts += "->" + out_ellipse + normal_inds
|
| 593 |
+
|
| 594 |
+
# Build output string if does not exist
|
| 595 |
+
if "->" in subscripts:
|
| 596 |
+
input_subscripts, output_subscript = subscripts.split("->")
|
| 597 |
+
else:
|
| 598 |
+
input_subscripts = subscripts
|
| 599 |
+
# Build output subscripts
|
| 600 |
+
tmp_subscripts = subscripts.replace(",", "")
|
| 601 |
+
output_subscript = ""
|
| 602 |
+
for s in sorted(set(tmp_subscripts)):
|
| 603 |
+
if s not in einsum_symbols:
|
| 604 |
+
raise ValueError(f"Character {s} is not a valid symbol.")
|
| 605 |
+
if tmp_subscripts.count(s) == 1:
|
| 606 |
+
output_subscript += s
|
| 607 |
+
|
| 608 |
+
# Make sure output subscripts are in the input
|
| 609 |
+
for char in output_subscript:
|
| 610 |
+
if output_subscript.count(char) != 1:
|
| 611 |
+
raise ValueError(f"Output character {char} appeared more than once in "
|
| 612 |
+
"the output.")
|
| 613 |
+
if char not in input_subscripts:
|
| 614 |
+
raise ValueError(f"Output character {char} did not appear in the input")
|
| 615 |
+
|
| 616 |
+
# Make sure number operands is equivalent to the number of terms
|
| 617 |
+
if len(input_subscripts.split(',')) != len(operands):
|
| 618 |
+
raise ValueError("Number of einsum subscripts must be equal to the "
|
| 619 |
+
"number of operands.")
|
| 620 |
+
|
| 621 |
+
return (input_subscripts, output_subscript, operands)
|
| 622 |
+
|
| 623 |
+
|
| 624 |
+
def _einsum_path_dispatcher(*operands, optimize=None, einsum_call=None):
|
| 625 |
+
# NOTE: technically, we should only dispatch on array-like arguments, not
|
| 626 |
+
# subscripts (given as strings). But separating operands into
|
| 627 |
+
# arrays/subscripts is a little tricky/slow (given einsum's two supported
|
| 628 |
+
# signatures), so as a practical shortcut we dispatch on everything.
|
| 629 |
+
# Strings will be ignored for dispatching since they don't define
|
| 630 |
+
# __array_function__.
|
| 631 |
+
return operands
|
| 632 |
+
|
| 633 |
+
|
| 634 |
+
@array_function_dispatch(_einsum_path_dispatcher, module='numpy')
|
| 635 |
+
def einsum_path(*operands, optimize='greedy', einsum_call=False):
|
| 636 |
+
"""
|
| 637 |
+
einsum_path(subscripts, *operands, optimize='greedy')
|
| 638 |
+
|
| 639 |
+
Evaluates the lowest cost contraction order for an einsum expression by
|
| 640 |
+
considering the creation of intermediate arrays.
|
| 641 |
+
|
| 642 |
+
Parameters
|
| 643 |
+
----------
|
| 644 |
+
subscripts : str
|
| 645 |
+
Specifies the subscripts for summation.
|
| 646 |
+
*operands : list of array_like
|
| 647 |
+
These are the arrays for the operation.
|
| 648 |
+
optimize : {bool, list, tuple, 'greedy', 'optimal'}
|
| 649 |
+
Choose the type of path. If a tuple is provided, the second argument is
|
| 650 |
+
assumed to be the maximum intermediate size created. If only a single
|
| 651 |
+
argument is provided the largest input or output array size is used
|
| 652 |
+
as a maximum intermediate size.
|
| 653 |
+
|
| 654 |
+
* if a list is given that starts with ``einsum_path``, uses this as the
|
| 655 |
+
contraction path
|
| 656 |
+
* if False no optimization is taken
|
| 657 |
+
* if True defaults to the 'greedy' algorithm
|
| 658 |
+
* 'optimal' An algorithm that combinatorially explores all possible
|
| 659 |
+
ways of contracting the listed tensors and chooses the least costly
|
| 660 |
+
path. Scales exponentially with the number of terms in the
|
| 661 |
+
contraction.
|
| 662 |
+
* 'greedy' An algorithm that chooses the best pair contraction
|
| 663 |
+
at each step. Effectively, this algorithm searches the largest inner,
|
| 664 |
+
Hadamard, and then outer products at each step. Scales cubically with
|
| 665 |
+
the number of terms in the contraction. Equivalent to the 'optimal'
|
| 666 |
+
path for most contractions.
|
| 667 |
+
|
| 668 |
+
Default is 'greedy'.
|
| 669 |
+
|
| 670 |
+
Returns
|
| 671 |
+
-------
|
| 672 |
+
path : list of tuples
|
| 673 |
+
A list representation of the einsum path.
|
| 674 |
+
string_repr : str
|
| 675 |
+
A printable representation of the einsum path.
|
| 676 |
+
|
| 677 |
+
Notes
|
| 678 |
+
-----
|
| 679 |
+
The resulting path indicates which terms of the input contraction should be
|
| 680 |
+
contracted first, the result of this contraction is then appended to the
|
| 681 |
+
end of the contraction list. This list can then be iterated over until all
|
| 682 |
+
intermediate contractions are complete.
|
| 683 |
+
|
| 684 |
+
See Also
|
| 685 |
+
--------
|
| 686 |
+
einsum, linalg.multi_dot
|
| 687 |
+
|
| 688 |
+
Examples
|
| 689 |
+
--------
|
| 690 |
+
|
| 691 |
+
We can begin with a chain dot example. In this case, it is optimal to
|
| 692 |
+
contract the ``b`` and ``c`` tensors first as represented by the first
|
| 693 |
+
element of the path ``(1, 2)``. The resulting tensor is added to the end
|
| 694 |
+
of the contraction and the remaining contraction ``(0, 1)`` is then
|
| 695 |
+
completed.
|
| 696 |
+
|
| 697 |
+
>>> np.random.seed(123)
|
| 698 |
+
>>> a = np.random.rand(2, 2)
|
| 699 |
+
>>> b = np.random.rand(2, 5)
|
| 700 |
+
>>> c = np.random.rand(5, 2)
|
| 701 |
+
>>> path_info = np.einsum_path('ij,jk,kl->il', a, b, c, optimize='greedy')
|
| 702 |
+
>>> print(path_info[0])
|
| 703 |
+
['einsum_path', (1, 2), (0, 1)]
|
| 704 |
+
>>> print(path_info[1])
|
| 705 |
+
Complete contraction: ij,jk,kl->il # may vary
|
| 706 |
+
Naive scaling: 4
|
| 707 |
+
Optimized scaling: 3
|
| 708 |
+
Naive FLOP count: 1.600e+02
|
| 709 |
+
Optimized FLOP count: 5.600e+01
|
| 710 |
+
Theoretical speedup: 2.857
|
| 711 |
+
Largest intermediate: 4.000e+00 elements
|
| 712 |
+
-------------------------------------------------------------------------
|
| 713 |
+
scaling current remaining
|
| 714 |
+
-------------------------------------------------------------------------
|
| 715 |
+
3 kl,jk->jl ij,jl->il
|
| 716 |
+
3 jl,ij->il il->il
|
| 717 |
+
|
| 718 |
+
|
| 719 |
+
A more complex index transformation example.
|
| 720 |
+
|
| 721 |
+
>>> I = np.random.rand(10, 10, 10, 10)
|
| 722 |
+
>>> C = np.random.rand(10, 10)
|
| 723 |
+
>>> path_info = np.einsum_path('ea,fb,abcd,gc,hd->efgh', C, C, I, C, C,
|
| 724 |
+
... optimize='greedy')
|
| 725 |
+
|
| 726 |
+
>>> print(path_info[0])
|
| 727 |
+
['einsum_path', (0, 2), (0, 3), (0, 2), (0, 1)]
|
| 728 |
+
>>> print(path_info[1])
|
| 729 |
+
Complete contraction: ea,fb,abcd,gc,hd->efgh # may vary
|
| 730 |
+
Naive scaling: 8
|
| 731 |
+
Optimized scaling: 5
|
| 732 |
+
Naive FLOP count: 8.000e+08
|
| 733 |
+
Optimized FLOP count: 8.000e+05
|
| 734 |
+
Theoretical speedup: 1000.000
|
| 735 |
+
Largest intermediate: 1.000e+04 elements
|
| 736 |
+
--------------------------------------------------------------------------
|
| 737 |
+
scaling current remaining
|
| 738 |
+
--------------------------------------------------------------------------
|
| 739 |
+
5 abcd,ea->bcde fb,gc,hd,bcde->efgh
|
| 740 |
+
5 bcde,fb->cdef gc,hd,cdef->efgh
|
| 741 |
+
5 cdef,gc->defg hd,defg->efgh
|
| 742 |
+
5 defg,hd->efgh efgh->efgh
|
| 743 |
+
"""
|
| 744 |
+
|
| 745 |
+
# Figure out what the path really is
|
| 746 |
+
path_type = optimize
|
| 747 |
+
if path_type is True:
|
| 748 |
+
path_type = 'greedy'
|
| 749 |
+
if path_type is None:
|
| 750 |
+
path_type = False
|
| 751 |
+
|
| 752 |
+
explicit_einsum_path = False
|
| 753 |
+
memory_limit = None
|
| 754 |
+
|
| 755 |
+
# No optimization or a named path algorithm
|
| 756 |
+
if (path_type is False) or isinstance(path_type, str):
|
| 757 |
+
pass
|
| 758 |
+
|
| 759 |
+
# Given an explicit path
|
| 760 |
+
elif len(path_type) and (path_type[0] == 'einsum_path'):
|
| 761 |
+
explicit_einsum_path = True
|
| 762 |
+
|
| 763 |
+
# Path tuple with memory limit
|
| 764 |
+
elif ((len(path_type) == 2) and isinstance(path_type[0], str) and
|
| 765 |
+
isinstance(path_type[1], (int, float))):
|
| 766 |
+
memory_limit = int(path_type[1])
|
| 767 |
+
path_type = path_type[0]
|
| 768 |
+
|
| 769 |
+
else:
|
| 770 |
+
raise TypeError(f"Did not understand the path: {str(path_type)}")
|
| 771 |
+
|
| 772 |
+
# Hidden option, only einsum should call this
|
| 773 |
+
einsum_call_arg = einsum_call
|
| 774 |
+
|
| 775 |
+
# Python side parsing
|
| 776 |
+
input_subscripts, output_subscript, operands = (
|
| 777 |
+
_parse_einsum_input(operands)
|
| 778 |
+
)
|
| 779 |
+
|
| 780 |
+
# Build a few useful list and sets
|
| 781 |
+
input_list = input_subscripts.split(',')
|
| 782 |
+
num_inputs = len(input_list)
|
| 783 |
+
input_sets = [set(x) for x in input_list]
|
| 784 |
+
output_set = set(output_subscript)
|
| 785 |
+
indices = set(input_subscripts.replace(',', ''))
|
| 786 |
+
num_indices = len(indices)
|
| 787 |
+
|
| 788 |
+
# Get length of each unique dimension and ensure all dimensions are correct
|
| 789 |
+
dimension_dict = {}
|
| 790 |
+
for tnum, term in enumerate(input_list):
|
| 791 |
+
sh = operands[tnum].shape
|
| 792 |
+
if len(sh) != len(term):
|
| 793 |
+
raise ValueError(f"Einstein sum subscript {input_subscripts[tnum]} "
|
| 794 |
+
"does not contain the "
|
| 795 |
+
f"correct number of indices for operand {tnum}.")
|
| 796 |
+
for cnum, char in enumerate(term):
|
| 797 |
+
dim = sh[cnum]
|
| 798 |
+
|
| 799 |
+
if char in dimension_dict.keys():
|
| 800 |
+
# For broadcasting cases we always want the largest dim size
|
| 801 |
+
if dimension_dict[char] == 1:
|
| 802 |
+
dimension_dict[char] = dim
|
| 803 |
+
elif dim not in (1, dimension_dict[char]):
|
| 804 |
+
raise ValueError(f"Size of label {char!r} for "
|
| 805 |
+
f"operand {tnum} ({dimension_dict[char]}) "
|
| 806 |
+
f"does not match previous terms ({dim}).")
|
| 807 |
+
else:
|
| 808 |
+
dimension_dict[char] = dim
|
| 809 |
+
|
| 810 |
+
# Compute size of each input array plus the output array
|
| 811 |
+
size_list = [_compute_size_by_dict(term, dimension_dict)
|
| 812 |
+
for term in input_list + [output_subscript]]
|
| 813 |
+
max_size = max(size_list)
|
| 814 |
+
|
| 815 |
+
if memory_limit is None:
|
| 816 |
+
memory_arg = max_size
|
| 817 |
+
else:
|
| 818 |
+
memory_arg = memory_limit
|
| 819 |
+
|
| 820 |
+
# Compute the path
|
| 821 |
+
if explicit_einsum_path:
|
| 822 |
+
path = path_type[1:]
|
| 823 |
+
elif (
|
| 824 |
+
(path_type is False)
|
| 825 |
+
or (num_inputs in [1, 2])
|
| 826 |
+
or (indices == output_set)
|
| 827 |
+
):
|
| 828 |
+
# Nothing to be optimized, leave it to einsum
|
| 829 |
+
path = [tuple(range(num_inputs))]
|
| 830 |
+
elif path_type == "greedy":
|
| 831 |
+
path = _greedy_path(
|
| 832 |
+
input_sets, output_set, dimension_dict, memory_arg
|
| 833 |
+
)
|
| 834 |
+
elif path_type == "optimal":
|
| 835 |
+
path = _optimal_path(
|
| 836 |
+
input_sets, output_set, dimension_dict, memory_arg
|
| 837 |
+
)
|
| 838 |
+
else:
|
| 839 |
+
raise KeyError("Path name %s not found", path_type)
|
| 840 |
+
|
| 841 |
+
cost_list, scale_list, size_list, contraction_list = [], [], [], []
|
| 842 |
+
|
| 843 |
+
# Build contraction tuple (positions, gemm, einsum_str, remaining)
|
| 844 |
+
for cnum, contract_inds in enumerate(path):
|
| 845 |
+
# Make sure we remove inds from right to left
|
| 846 |
+
contract_inds = tuple(sorted(contract_inds, reverse=True))
|
| 847 |
+
|
| 848 |
+
contract = _find_contraction(contract_inds, input_sets, output_set)
|
| 849 |
+
out_inds, input_sets, idx_removed, idx_contract = contract
|
| 850 |
+
|
| 851 |
+
if not einsum_call_arg:
|
| 852 |
+
# these are only needed for printing info
|
| 853 |
+
cost = _flop_count(
|
| 854 |
+
idx_contract, idx_removed, len(contract_inds), dimension_dict
|
| 855 |
+
)
|
| 856 |
+
cost_list.append(cost)
|
| 857 |
+
scale_list.append(len(idx_contract))
|
| 858 |
+
size_list.append(_compute_size_by_dict(out_inds, dimension_dict))
|
| 859 |
+
|
| 860 |
+
tmp_inputs = []
|
| 861 |
+
for x in contract_inds:
|
| 862 |
+
tmp_inputs.append(input_list.pop(x))
|
| 863 |
+
|
| 864 |
+
# Last contraction
|
| 865 |
+
if (cnum - len(path)) == -1:
|
| 866 |
+
idx_result = output_subscript
|
| 867 |
+
else:
|
| 868 |
+
sort_result = [(dimension_dict[ind], ind) for ind in out_inds]
|
| 869 |
+
idx_result = "".join([x[1] for x in sorted(sort_result)])
|
| 870 |
+
|
| 871 |
+
input_list.append(idx_result)
|
| 872 |
+
einsum_str = ",".join(tmp_inputs) + "->" + idx_result
|
| 873 |
+
|
| 874 |
+
contraction = (contract_inds, einsum_str, input_list[:])
|
| 875 |
+
contraction_list.append(contraction)
|
| 876 |
+
|
| 877 |
+
if len(input_list) != 1:
|
| 878 |
+
# Explicit "einsum_path" is usually trusted, but we detect this kind of
|
| 879 |
+
# mistake in order to prevent from returning an intermediate value.
|
| 880 |
+
raise RuntimeError(
|
| 881 |
+
f"Invalid einsum_path is specified: {len(input_list) - 1} more "
|
| 882 |
+
"operands has to be contracted.")
|
| 883 |
+
|
| 884 |
+
if einsum_call_arg:
|
| 885 |
+
return (operands, contraction_list)
|
| 886 |
+
|
| 887 |
+
# Return the path along with a nice string representation
|
| 888 |
+
overall_contraction = input_subscripts + "->" + output_subscript
|
| 889 |
+
|
| 890 |
+
# Compute naive cost
|
| 891 |
+
# This isn't quite right, need to look into exactly how einsum does this
|
| 892 |
+
inner_product = (
|
| 893 |
+
sum(len(set(x)) for x in input_subscripts.split(',')) - num_indices
|
| 894 |
+
) > 0
|
| 895 |
+
naive_cost = _flop_count(
|
| 896 |
+
indices, inner_product, num_inputs, dimension_dict
|
| 897 |
+
)
|
| 898 |
+
|
| 899 |
+
opt_cost = sum(cost_list) + 1
|
| 900 |
+
speedup = naive_cost / opt_cost
|
| 901 |
+
max_i = max(size_list)
|
| 902 |
+
|
| 903 |
+
path_print = f" Complete contraction: {overall_contraction}\n"
|
| 904 |
+
path_print += f" Naive scaling: {num_indices}\n"
|
| 905 |
+
path_print += f" Optimized scaling: {max(scale_list)}\n"
|
| 906 |
+
path_print += f" Naive FLOP count: {naive_cost:.3e}\n"
|
| 907 |
+
path_print += f" Optimized FLOP count: {opt_cost:.3e}\n"
|
| 908 |
+
path_print += f" Theoretical speedup: {speedup:3.3f}\n"
|
| 909 |
+
path_print += f" Largest intermediate: {max_i:.3e} elements\n"
|
| 910 |
+
path_print += "-" * 74 + "\n"
|
| 911 |
+
path_print += f"{'scaling':>6} {'current':>24} {'remaining':>40}\n"
|
| 912 |
+
path_print += "-" * 74
|
| 913 |
+
|
| 914 |
+
for n, contraction in enumerate(contraction_list):
|
| 915 |
+
_, einsum_str, remaining = contraction
|
| 916 |
+
remaining_str = ",".join(remaining) + "->" + output_subscript
|
| 917 |
+
path_print += f"\n{scale_list[n]:4d} {einsum_str:>24} {remaining_str:>40}"
|
| 918 |
+
|
| 919 |
+
path = ['einsum_path'] + path
|
| 920 |
+
return (path, path_print)
|
| 921 |
+
|
| 922 |
+
|
| 923 |
+
def _parse_eq_to_pure_multiplication(a_term, shape_a, b_term, shape_b, out):
|
| 924 |
+
"""If there are no contracted indices, then we can directly transpose and
|
| 925 |
+
insert singleton dimensions into ``a`` and ``b`` such that (broadcast)
|
| 926 |
+
elementwise multiplication performs the einsum.
|
| 927 |
+
|
| 928 |
+
No need to cache this as it is within the cached
|
| 929 |
+
``_parse_eq_to_batch_matmul``.
|
| 930 |
+
|
| 931 |
+
"""
|
| 932 |
+
desired_a = ""
|
| 933 |
+
desired_b = ""
|
| 934 |
+
new_shape_a = []
|
| 935 |
+
new_shape_b = []
|
| 936 |
+
for ix in out:
|
| 937 |
+
if ix in a_term:
|
| 938 |
+
desired_a += ix
|
| 939 |
+
new_shape_a.append(shape_a[a_term.index(ix)])
|
| 940 |
+
else:
|
| 941 |
+
new_shape_a.append(1)
|
| 942 |
+
if ix in b_term:
|
| 943 |
+
desired_b += ix
|
| 944 |
+
new_shape_b.append(shape_b[b_term.index(ix)])
|
| 945 |
+
else:
|
| 946 |
+
new_shape_b.append(1)
|
| 947 |
+
|
| 948 |
+
if desired_a != a_term:
|
| 949 |
+
eq_a = f"{a_term}->{desired_a}"
|
| 950 |
+
else:
|
| 951 |
+
eq_a = None
|
| 952 |
+
if desired_b != b_term:
|
| 953 |
+
eq_b = f"{b_term}->{desired_b}"
|
| 954 |
+
else:
|
| 955 |
+
eq_b = None
|
| 956 |
+
|
| 957 |
+
return (
|
| 958 |
+
eq_a,
|
| 959 |
+
eq_b,
|
| 960 |
+
new_shape_a,
|
| 961 |
+
new_shape_b,
|
| 962 |
+
None, # new_shape_ab, not needed since not fusing
|
| 963 |
+
None, # perm_ab, not needed as we transpose a and b first
|
| 964 |
+
True, # pure_multiplication=True
|
| 965 |
+
)
|
| 966 |
+
|
| 967 |
+
|
| 968 |
+
@functools.lru_cache(2**12)
|
| 969 |
+
def _parse_eq_to_batch_matmul(eq, shape_a, shape_b):
|
| 970 |
+
"""Cached parsing of a two term einsum equation into the necessary
|
| 971 |
+
sequence of arguments for contraction via batched matrix multiplication.
|
| 972 |
+
The steps we need to specify are:
|
| 973 |
+
|
| 974 |
+
1. Remove repeated and trivial indices from the left and right terms,
|
| 975 |
+
and transpose them, done as a single einsum.
|
| 976 |
+
2. Fuse the remaining indices so we have two 3D tensors.
|
| 977 |
+
3. Perform the batched matrix multiplication.
|
| 978 |
+
4. Unfuse the output to get the desired final index order.
|
| 979 |
+
|
| 980 |
+
"""
|
| 981 |
+
lhs, out = eq.split("->")
|
| 982 |
+
a_term, b_term = lhs.split(",")
|
| 983 |
+
|
| 984 |
+
if len(a_term) != len(shape_a):
|
| 985 |
+
raise ValueError(f"Term '{a_term}' does not match shape {shape_a}.")
|
| 986 |
+
if len(b_term) != len(shape_b):
|
| 987 |
+
raise ValueError(f"Term '{b_term}' does not match shape {shape_b}.")
|
| 988 |
+
|
| 989 |
+
sizes = {}
|
| 990 |
+
singletons = set()
|
| 991 |
+
|
| 992 |
+
# parse left term to unique indices with size > 1
|
| 993 |
+
left = {}
|
| 994 |
+
for ix, d in zip(a_term, shape_a):
|
| 995 |
+
if d == 1:
|
| 996 |
+
# everything (including broadcasting) works nicely if simply ignore
|
| 997 |
+
# such dimensions, but we do need to track if they appear in output
|
| 998 |
+
# and thus should be reintroduced later
|
| 999 |
+
singletons.add(ix)
|
| 1000 |
+
continue
|
| 1001 |
+
if sizes.setdefault(ix, d) != d:
|
| 1002 |
+
# set and check size
|
| 1003 |
+
raise ValueError(
|
| 1004 |
+
f"Index {ix} has mismatched sizes {sizes[ix]} and {d}."
|
| 1005 |
+
)
|
| 1006 |
+
left[ix] = True
|
| 1007 |
+
|
| 1008 |
+
# parse right term to unique indices with size > 1
|
| 1009 |
+
right = {}
|
| 1010 |
+
for ix, d in zip(b_term, shape_b):
|
| 1011 |
+
# broadcast indices (size 1 on one input and size != 1
|
| 1012 |
+
# on the other) should not be treated as singletons
|
| 1013 |
+
if d == 1:
|
| 1014 |
+
if ix not in left:
|
| 1015 |
+
singletons.add(ix)
|
| 1016 |
+
continue
|
| 1017 |
+
singletons.discard(ix)
|
| 1018 |
+
|
| 1019 |
+
if sizes.setdefault(ix, d) != d:
|
| 1020 |
+
# set and check size
|
| 1021 |
+
raise ValueError(
|
| 1022 |
+
f"Index {ix} has mismatched sizes {sizes[ix]} and {d}."
|
| 1023 |
+
)
|
| 1024 |
+
right[ix] = True
|
| 1025 |
+
|
| 1026 |
+
# now we classify the unique size > 1 indices only
|
| 1027 |
+
bat_inds = [] # appears on A, B, O
|
| 1028 |
+
con_inds = [] # appears on A, B, .
|
| 1029 |
+
a_keep = [] # appears on A, ., O
|
| 1030 |
+
b_keep = [] # appears on ., B, O
|
| 1031 |
+
# other indices (appearing on A or B only) will
|
| 1032 |
+
# be summed or traced out prior to the matmul
|
| 1033 |
+
for ix in left:
|
| 1034 |
+
if right.pop(ix, False):
|
| 1035 |
+
if ix in out:
|
| 1036 |
+
bat_inds.append(ix)
|
| 1037 |
+
else:
|
| 1038 |
+
con_inds.append(ix)
|
| 1039 |
+
elif ix in out:
|
| 1040 |
+
a_keep.append(ix)
|
| 1041 |
+
# now only indices unique to right remain
|
| 1042 |
+
for ix in right:
|
| 1043 |
+
if ix in out:
|
| 1044 |
+
b_keep.append(ix)
|
| 1045 |
+
|
| 1046 |
+
if not con_inds:
|
| 1047 |
+
# contraction is pure multiplication, prepare inputs differently
|
| 1048 |
+
return _parse_eq_to_pure_multiplication(
|
| 1049 |
+
a_term, shape_a, b_term, shape_b, out
|
| 1050 |
+
)
|
| 1051 |
+
|
| 1052 |
+
# only need the size one indices that appear in the output
|
| 1053 |
+
singletons = [ix for ix in out if ix in singletons]
|
| 1054 |
+
|
| 1055 |
+
# take diagonal, remove any trivial axes and transpose left
|
| 1056 |
+
desired_a = "".join((*bat_inds, *a_keep, *con_inds))
|
| 1057 |
+
if a_term != desired_a:
|
| 1058 |
+
eq_a = f"{a_term}->{desired_a}"
|
| 1059 |
+
else:
|
| 1060 |
+
eq_a = None
|
| 1061 |
+
|
| 1062 |
+
# take diagonal, remove any trivial axes and transpose right
|
| 1063 |
+
desired_b = "".join((*bat_inds, *con_inds, *b_keep))
|
| 1064 |
+
if b_term != desired_b:
|
| 1065 |
+
eq_b = f"{b_term}->{desired_b}"
|
| 1066 |
+
else:
|
| 1067 |
+
eq_b = None
|
| 1068 |
+
|
| 1069 |
+
# then we want to reshape
|
| 1070 |
+
if bat_inds:
|
| 1071 |
+
lgroups = (bat_inds, a_keep, con_inds)
|
| 1072 |
+
rgroups = (bat_inds, con_inds, b_keep)
|
| 1073 |
+
ogroups = (bat_inds, a_keep, b_keep)
|
| 1074 |
+
else:
|
| 1075 |
+
# avoid size 1 batch dimension if no batch indices
|
| 1076 |
+
lgroups = (a_keep, con_inds)
|
| 1077 |
+
rgroups = (con_inds, b_keep)
|
| 1078 |
+
ogroups = (a_keep, b_keep)
|
| 1079 |
+
|
| 1080 |
+
if any(len(group) != 1 for group in lgroups):
|
| 1081 |
+
# need to fuse 'kept' and contracted indices
|
| 1082 |
+
# (though could allow batch indices to be broadcast)
|
| 1083 |
+
new_shape_a = tuple(
|
| 1084 |
+
functools.reduce(operator.mul, (sizes[ix] for ix in ix_group), 1)
|
| 1085 |
+
for ix_group in lgroups
|
| 1086 |
+
)
|
| 1087 |
+
else:
|
| 1088 |
+
new_shape_a = None
|
| 1089 |
+
|
| 1090 |
+
if any(len(group) != 1 for group in rgroups):
|
| 1091 |
+
# need to fuse 'kept' and contracted indices
|
| 1092 |
+
# (though could allow batch indices to be broadcast)
|
| 1093 |
+
new_shape_b = tuple(
|
| 1094 |
+
functools.reduce(operator.mul, (sizes[ix] for ix in ix_group), 1)
|
| 1095 |
+
for ix_group in rgroups
|
| 1096 |
+
)
|
| 1097 |
+
else:
|
| 1098 |
+
new_shape_b = None
|
| 1099 |
+
|
| 1100 |
+
if any(len(group) != 1 for group in ogroups) or singletons:
|
| 1101 |
+
new_shape_ab = (1,) * len(singletons) + tuple(
|
| 1102 |
+
sizes[ix] for ix_group in ogroups for ix in ix_group
|
| 1103 |
+
)
|
| 1104 |
+
else:
|
| 1105 |
+
new_shape_ab = None
|
| 1106 |
+
|
| 1107 |
+
# then we might need to permute the matmul produced output:
|
| 1108 |
+
out_produced = "".join((*singletons, *bat_inds, *a_keep, *b_keep))
|
| 1109 |
+
if out_produced != out:
|
| 1110 |
+
perm_ab = tuple(out_produced.index(ix) for ix in out)
|
| 1111 |
+
else:
|
| 1112 |
+
perm_ab = None
|
| 1113 |
+
|
| 1114 |
+
return (
|
| 1115 |
+
eq_a,
|
| 1116 |
+
eq_b,
|
| 1117 |
+
new_shape_a,
|
| 1118 |
+
new_shape_b,
|
| 1119 |
+
new_shape_ab,
|
| 1120 |
+
perm_ab,
|
| 1121 |
+
False, # pure_multiplication=False
|
| 1122 |
+
)
|
| 1123 |
+
|
| 1124 |
+
|
| 1125 |
+
@functools.lru_cache(maxsize=64)
|
| 1126 |
+
def _parse_output_order(order, a_is_fcontig, b_is_fcontig):
|
| 1127 |
+
order = order.upper()
|
| 1128 |
+
if order == "K":
|
| 1129 |
+
return None
|
| 1130 |
+
elif order in "CF":
|
| 1131 |
+
return order
|
| 1132 |
+
elif order == "A":
|
| 1133 |
+
if a_is_fcontig and b_is_fcontig:
|
| 1134 |
+
return "F"
|
| 1135 |
+
else:
|
| 1136 |
+
return "C"
|
| 1137 |
+
else:
|
| 1138 |
+
raise ValueError(
|
| 1139 |
+
"ValueError: order must be one of "
|
| 1140 |
+
f"'C', 'F', 'A', or 'K' (got '{order}')"
|
| 1141 |
+
)
|
| 1142 |
+
|
| 1143 |
+
|
| 1144 |
+
def bmm_einsum(eq, a, b, out=None, **kwargs):
|
| 1145 |
+
"""Perform arbitrary pairwise einsums using only ``matmul``, or
|
| 1146 |
+
``multiply`` if no contracted indices are involved (plus maybe single term
|
| 1147 |
+
``einsum`` to prepare the terms individually). The logic for each is cached
|
| 1148 |
+
based on the equation and array shape, and each step is only performed if
|
| 1149 |
+
necessary.
|
| 1150 |
+
|
| 1151 |
+
Parameters
|
| 1152 |
+
----------
|
| 1153 |
+
eq : str
|
| 1154 |
+
The einsum equation.
|
| 1155 |
+
a : array_like
|
| 1156 |
+
The first array to contract.
|
| 1157 |
+
b : array_like
|
| 1158 |
+
The second array to contract.
|
| 1159 |
+
|
| 1160 |
+
Returns
|
| 1161 |
+
-------
|
| 1162 |
+
array_like
|
| 1163 |
+
|
| 1164 |
+
Notes
|
| 1165 |
+
-----
|
| 1166 |
+
A fuller description of this algorithm, and original source for this
|
| 1167 |
+
implementation, can be found at https://github.com/jcmgray/einsum_bmm.
|
| 1168 |
+
"""
|
| 1169 |
+
(
|
| 1170 |
+
eq_a,
|
| 1171 |
+
eq_b,
|
| 1172 |
+
new_shape_a,
|
| 1173 |
+
new_shape_b,
|
| 1174 |
+
new_shape_ab,
|
| 1175 |
+
perm_ab,
|
| 1176 |
+
pure_multiplication,
|
| 1177 |
+
) = _parse_eq_to_batch_matmul(eq, a.shape, b.shape)
|
| 1178 |
+
|
| 1179 |
+
# n.b. one could special case various cases to call c_einsum directly here
|
| 1180 |
+
|
| 1181 |
+
# need to handle `order` a little manually, since we do transpose
|
| 1182 |
+
# operations before and potentially after the ufunc calls
|
| 1183 |
+
output_order = _parse_output_order(
|
| 1184 |
+
kwargs.pop("order", "K"), a.flags.f_contiguous, b.flags.f_contiguous
|
| 1185 |
+
)
|
| 1186 |
+
|
| 1187 |
+
# prepare left
|
| 1188 |
+
if eq_a is not None:
|
| 1189 |
+
# diagonals, sums, and transpose
|
| 1190 |
+
a = c_einsum(eq_a, a)
|
| 1191 |
+
if new_shape_a is not None:
|
| 1192 |
+
a = reshape(a, new_shape_a)
|
| 1193 |
+
|
| 1194 |
+
# prepare right
|
| 1195 |
+
if eq_b is not None:
|
| 1196 |
+
# diagonals, sums, and transpose
|
| 1197 |
+
b = c_einsum(eq_b, b)
|
| 1198 |
+
if new_shape_b is not None:
|
| 1199 |
+
b = reshape(b, new_shape_b)
|
| 1200 |
+
|
| 1201 |
+
if pure_multiplication:
|
| 1202 |
+
# no contracted indices
|
| 1203 |
+
if output_order is not None:
|
| 1204 |
+
kwargs["order"] = output_order
|
| 1205 |
+
|
| 1206 |
+
# do the 'contraction' via multiplication!
|
| 1207 |
+
return multiply(a, b, out=out, **kwargs)
|
| 1208 |
+
|
| 1209 |
+
# can only supply out here if no other reshaping / transposing
|
| 1210 |
+
matmul_out_compatible = (new_shape_ab is None) and (perm_ab is None)
|
| 1211 |
+
if matmul_out_compatible:
|
| 1212 |
+
kwargs["out"] = out
|
| 1213 |
+
|
| 1214 |
+
# do the contraction!
|
| 1215 |
+
ab = matmul(a, b, **kwargs)
|
| 1216 |
+
|
| 1217 |
+
# prepare the output
|
| 1218 |
+
if new_shape_ab is not None:
|
| 1219 |
+
ab = reshape(ab, new_shape_ab)
|
| 1220 |
+
if perm_ab is not None:
|
| 1221 |
+
ab = ab.transpose(perm_ab)
|
| 1222 |
+
|
| 1223 |
+
if (out is not None) and (not matmul_out_compatible):
|
| 1224 |
+
# handle case where out is specified, but we also needed
|
| 1225 |
+
# to reshape / transpose ``ab`` after the matmul
|
| 1226 |
+
out[...] = ab
|
| 1227 |
+
ab = out
|
| 1228 |
+
elif output_order is not None:
|
| 1229 |
+
ab = asanyarray(ab, order=output_order)
|
| 1230 |
+
|
| 1231 |
+
return ab
|
| 1232 |
+
|
| 1233 |
+
|
| 1234 |
+
def _einsum_dispatcher(*operands, out=None, optimize=None, **kwargs):
|
| 1235 |
+
# Arguably we dispatch on more arguments than we really should; see note in
|
| 1236 |
+
# _einsum_path_dispatcher for why.
|
| 1237 |
+
yield from operands
|
| 1238 |
+
yield out
|
| 1239 |
+
|
| 1240 |
+
|
| 1241 |
+
# Rewrite einsum to handle different cases
|
| 1242 |
+
@array_function_dispatch(_einsum_dispatcher, module='numpy')
|
| 1243 |
+
def einsum(*operands, out=None, optimize=False, **kwargs):
|
| 1244 |
+
"""
|
| 1245 |
+
einsum(subscripts, *operands, out=None, dtype=None, order='K',
|
| 1246 |
+
casting='safe', optimize=False)
|
| 1247 |
+
|
| 1248 |
+
Evaluates the Einstein summation convention on the operands.
|
| 1249 |
+
|
| 1250 |
+
Using the Einstein summation convention, many common multi-dimensional,
|
| 1251 |
+
linear algebraic array operations can be represented in a simple fashion.
|
| 1252 |
+
In *implicit* mode `einsum` computes these values.
|
| 1253 |
+
|
| 1254 |
+
In *explicit* mode, `einsum` provides further flexibility to compute
|
| 1255 |
+
other array operations that might not be considered classical Einstein
|
| 1256 |
+
summation operations, by disabling, or forcing summation over specified
|
| 1257 |
+
subscript labels.
|
| 1258 |
+
|
| 1259 |
+
See the notes and examples for clarification.
|
| 1260 |
+
|
| 1261 |
+
Parameters
|
| 1262 |
+
----------
|
| 1263 |
+
subscripts : str
|
| 1264 |
+
Specifies the subscripts for summation as comma separated list of
|
| 1265 |
+
subscript labels. An implicit (classical Einstein summation)
|
| 1266 |
+
calculation is performed unless the explicit indicator '->' is
|
| 1267 |
+
included as well as subscript labels of the precise output form.
|
| 1268 |
+
operands : list of array_like
|
| 1269 |
+
These are the arrays for the operation.
|
| 1270 |
+
out : ndarray, optional
|
| 1271 |
+
If provided, the calculation is done into this array.
|
| 1272 |
+
dtype : {data-type, None}, optional
|
| 1273 |
+
If provided, forces the calculation to use the data type specified.
|
| 1274 |
+
Note that you may have to also give a more liberal `casting`
|
| 1275 |
+
parameter to allow the conversions. Default is None.
|
| 1276 |
+
order : {'C', 'F', 'A', 'K'}, optional
|
| 1277 |
+
Controls the memory layout of the output. 'C' means it should
|
| 1278 |
+
be C contiguous. 'F' means it should be Fortran contiguous,
|
| 1279 |
+
'A' means it should be 'F' if the inputs are all 'F', 'C' otherwise.
|
| 1280 |
+
'K' means it should be as close to the layout as the inputs as
|
| 1281 |
+
is possible, including arbitrarily permuted axes.
|
| 1282 |
+
Default is 'K'.
|
| 1283 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
|
| 1284 |
+
Controls what kind of data casting may occur. Setting this to
|
| 1285 |
+
'unsafe' is not recommended, as it can adversely affect accumulations.
|
| 1286 |
+
|
| 1287 |
+
* 'no' means the data types should not be cast at all.
|
| 1288 |
+
* 'equiv' means only byte-order changes are allowed.
|
| 1289 |
+
* 'safe' means only casts which can preserve values are allowed.
|
| 1290 |
+
* 'same_kind' means only safe casts or casts within a kind,
|
| 1291 |
+
like float64 to float32, are allowed.
|
| 1292 |
+
* 'unsafe' means any data conversions may be done.
|
| 1293 |
+
|
| 1294 |
+
Default is 'safe'.
|
| 1295 |
+
optimize : {False, True, 'greedy', 'optimal'}, optional
|
| 1296 |
+
Controls if intermediate optimization should occur. No optimization
|
| 1297 |
+
will occur if False and True will default to the 'greedy' algorithm.
|
| 1298 |
+
Also accepts an explicit contraction list from the ``np.einsum_path``
|
| 1299 |
+
function. See ``np.einsum_path`` for more details. Defaults to False.
|
| 1300 |
+
|
| 1301 |
+
Returns
|
| 1302 |
+
-------
|
| 1303 |
+
output : ndarray
|
| 1304 |
+
The calculation based on the Einstein summation convention.
|
| 1305 |
+
|
| 1306 |
+
See Also
|
| 1307 |
+
--------
|
| 1308 |
+
einsum_path, dot, inner, outer, tensordot, linalg.multi_dot
|
| 1309 |
+
einsum:
|
| 1310 |
+
Similar verbose interface is provided by the
|
| 1311 |
+
`einops <https://github.com/arogozhnikov/einops>`_ package to cover
|
| 1312 |
+
additional operations: transpose, reshape/flatten, repeat/tile,
|
| 1313 |
+
squeeze/unsqueeze and reductions.
|
| 1314 |
+
The `opt_einsum <https://optimized-einsum.readthedocs.io/en/stable/>`_
|
| 1315 |
+
optimizes contraction order for einsum-like expressions
|
| 1316 |
+
in backend-agnostic manner.
|
| 1317 |
+
|
| 1318 |
+
Notes
|
| 1319 |
+
-----
|
| 1320 |
+
The Einstein summation convention can be used to compute
|
| 1321 |
+
many multi-dimensional, linear algebraic array operations. `einsum`
|
| 1322 |
+
provides a succinct way of representing these.
|
| 1323 |
+
|
| 1324 |
+
A non-exhaustive list of these operations,
|
| 1325 |
+
which can be computed by `einsum`, is shown below along with examples:
|
| 1326 |
+
|
| 1327 |
+
* Trace of an array, :py:func:`numpy.trace`.
|
| 1328 |
+
* Return a diagonal, :py:func:`numpy.diag`.
|
| 1329 |
+
* Array axis summations, :py:func:`numpy.sum`.
|
| 1330 |
+
* Transpositions and permutations, :py:func:`numpy.transpose`.
|
| 1331 |
+
* Matrix multiplication and dot product, :py:func:`numpy.matmul`
|
| 1332 |
+
:py:func:`numpy.dot`.
|
| 1333 |
+
* Vector inner and outer products, :py:func:`numpy.inner`
|
| 1334 |
+
:py:func:`numpy.outer`.
|
| 1335 |
+
* Broadcasting, element-wise and scalar multiplication,
|
| 1336 |
+
:py:func:`numpy.multiply`.
|
| 1337 |
+
* Tensor contractions, :py:func:`numpy.tensordot`.
|
| 1338 |
+
* Chained array operations, in efficient calculation order,
|
| 1339 |
+
:py:func:`numpy.einsum_path`.
|
| 1340 |
+
|
| 1341 |
+
The subscripts string is a comma-separated list of subscript labels,
|
| 1342 |
+
where each label refers to a dimension of the corresponding operand.
|
| 1343 |
+
Whenever a label is repeated it is summed, so ``np.einsum('i,i', a, b)``
|
| 1344 |
+
is equivalent to :py:func:`np.inner(a,b) <numpy.inner>`. If a label
|
| 1345 |
+
appears only once, it is not summed, so ``np.einsum('i', a)``
|
| 1346 |
+
produces a view of ``a`` with no changes. A further example
|
| 1347 |
+
``np.einsum('ij,jk', a, b)`` describes traditional matrix multiplication
|
| 1348 |
+
and is equivalent to :py:func:`np.matmul(a,b) <numpy.matmul>`.
|
| 1349 |
+
Repeated subscript labels in one operand take the diagonal.
|
| 1350 |
+
For example, ``np.einsum('ii', a)`` is equivalent to
|
| 1351 |
+
:py:func:`np.trace(a) <numpy.trace>`.
|
| 1352 |
+
|
| 1353 |
+
In *implicit mode*, the chosen subscripts are important
|
| 1354 |
+
since the axes of the output are reordered alphabetically. This
|
| 1355 |
+
means that ``np.einsum('ij', a)`` doesn't affect a 2D array, while
|
| 1356 |
+
``np.einsum('ji', a)`` takes its transpose. Additionally,
|
| 1357 |
+
``np.einsum('ij,jk', a, b)`` returns a matrix multiplication, while,
|
| 1358 |
+
``np.einsum('ij,jh', a, b)`` returns the transpose of the
|
| 1359 |
+
multiplication since subscript 'h' precedes subscript 'i'.
|
| 1360 |
+
|
| 1361 |
+
In *explicit mode* the output can be directly controlled by
|
| 1362 |
+
specifying output subscript labels. This requires the
|
| 1363 |
+
identifier '->' as well as the list of output subscript labels.
|
| 1364 |
+
This feature increases the flexibility of the function since
|
| 1365 |
+
summing can be disabled or forced when required. The call
|
| 1366 |
+
``np.einsum('i->', a)`` is like :py:func:`np.sum(a) <numpy.sum>`
|
| 1367 |
+
if ``a`` is a 1-D array, and ``np.einsum('ii->i', a)``
|
| 1368 |
+
is like :py:func:`np.diag(a) <numpy.diag>` if ``a`` is a square 2-D array.
|
| 1369 |
+
The difference is that `einsum` does not allow broadcasting by default.
|
| 1370 |
+
Additionally ``np.einsum('ij,jh->ih', a, b)`` directly specifies the
|
| 1371 |
+
order of the output subscript labels and therefore returns matrix
|
| 1372 |
+
multiplication, unlike the example above in implicit mode.
|
| 1373 |
+
|
| 1374 |
+
To enable and control broadcasting, use an ellipsis. Default
|
| 1375 |
+
NumPy-style broadcasting is done by adding an ellipsis
|
| 1376 |
+
to the left of each term, like ``np.einsum('...ii->...i', a)``.
|
| 1377 |
+
``np.einsum('...i->...', a)`` is like
|
| 1378 |
+
:py:func:`np.sum(a, axis=-1) <numpy.sum>` for array ``a`` of any shape.
|
| 1379 |
+
To take the trace along the first and last axes,
|
| 1380 |
+
you can do ``np.einsum('i...i', a)``, or to do a matrix-matrix
|
| 1381 |
+
product with the left-most indices instead of rightmost, one can do
|
| 1382 |
+
``np.einsum('ij...,jk...->ik...', a, b)``.
|
| 1383 |
+
|
| 1384 |
+
When there is only one operand, no axes are summed, and no output
|
| 1385 |
+
parameter is provided, a view into the operand is returned instead
|
| 1386 |
+
of a new array. Thus, taking the diagonal as ``np.einsum('ii->i', a)``
|
| 1387 |
+
produces a view (changed in version 1.10.0).
|
| 1388 |
+
|
| 1389 |
+
`einsum` also provides an alternative way to provide the subscripts and
|
| 1390 |
+
operands as ``einsum(op0, sublist0, op1, sublist1, ..., [sublistout])``.
|
| 1391 |
+
If the output shape is not provided in this format `einsum` will be
|
| 1392 |
+
calculated in implicit mode, otherwise it will be performed explicitly.
|
| 1393 |
+
The examples below have corresponding `einsum` calls with the two
|
| 1394 |
+
parameter methods.
|
| 1395 |
+
|
| 1396 |
+
Views returned from einsum are now writeable whenever the input array
|
| 1397 |
+
is writeable. For example, ``np.einsum('ijk...->kji...', a)`` will now
|
| 1398 |
+
have the same effect as :py:func:`np.swapaxes(a, 0, 2) <numpy.swapaxes>`
|
| 1399 |
+
and ``np.einsum('ii->i', a)`` will return a writeable view of the diagonal
|
| 1400 |
+
of a 2D array.
|
| 1401 |
+
|
| 1402 |
+
Added the ``optimize`` argument which will optimize the contraction order
|
| 1403 |
+
of an einsum expression. For a contraction with three or more operands
|
| 1404 |
+
this can greatly increase the computational efficiency at the cost of
|
| 1405 |
+
a larger memory footprint during computation.
|
| 1406 |
+
|
| 1407 |
+
Typically a 'greedy' algorithm is applied which empirical tests have shown
|
| 1408 |
+
returns the optimal path in the majority of cases. In some cases 'optimal'
|
| 1409 |
+
will return the superlative path through a more expensive, exhaustive
|
| 1410 |
+
search. For iterative calculations it may be advisable to calculate
|
| 1411 |
+
the optimal path once and reuse that path by supplying it as an argument.
|
| 1412 |
+
An example is given below.
|
| 1413 |
+
|
| 1414 |
+
See :py:func:`numpy.einsum_path` for more details.
|
| 1415 |
+
|
| 1416 |
+
Examples
|
| 1417 |
+
--------
|
| 1418 |
+
>>> a = np.arange(25).reshape(5,5)
|
| 1419 |
+
>>> b = np.arange(5)
|
| 1420 |
+
>>> c = np.arange(6).reshape(2,3)
|
| 1421 |
+
|
| 1422 |
+
Trace of a matrix:
|
| 1423 |
+
|
| 1424 |
+
>>> np.einsum('ii', a)
|
| 1425 |
+
60
|
| 1426 |
+
>>> np.einsum(a, [0,0])
|
| 1427 |
+
60
|
| 1428 |
+
>>> np.trace(a)
|
| 1429 |
+
60
|
| 1430 |
+
|
| 1431 |
+
Extract the diagonal (requires explicit form):
|
| 1432 |
+
|
| 1433 |
+
>>> np.einsum('ii->i', a)
|
| 1434 |
+
array([ 0, 6, 12, 18, 24])
|
| 1435 |
+
>>> np.einsum(a, [0,0], [0])
|
| 1436 |
+
array([ 0, 6, 12, 18, 24])
|
| 1437 |
+
>>> np.diag(a)
|
| 1438 |
+
array([ 0, 6, 12, 18, 24])
|
| 1439 |
+
|
| 1440 |
+
Sum over an axis (requires explicit form):
|
| 1441 |
+
|
| 1442 |
+
>>> np.einsum('ij->i', a)
|
| 1443 |
+
array([ 10, 35, 60, 85, 110])
|
| 1444 |
+
>>> np.einsum(a, [0,1], [0])
|
| 1445 |
+
array([ 10, 35, 60, 85, 110])
|
| 1446 |
+
>>> np.sum(a, axis=1)
|
| 1447 |
+
array([ 10, 35, 60, 85, 110])
|
| 1448 |
+
|
| 1449 |
+
For higher dimensional arrays summing a single axis can be done
|
| 1450 |
+
with ellipsis:
|
| 1451 |
+
|
| 1452 |
+
>>> np.einsum('...j->...', a)
|
| 1453 |
+
array([ 10, 35, 60, 85, 110])
|
| 1454 |
+
>>> np.einsum(a, [Ellipsis,1], [Ellipsis])
|
| 1455 |
+
array([ 10, 35, 60, 85, 110])
|
| 1456 |
+
|
| 1457 |
+
Compute a matrix transpose, or reorder any number of axes:
|
| 1458 |
+
|
| 1459 |
+
>>> np.einsum('ji', c)
|
| 1460 |
+
array([[0, 3],
|
| 1461 |
+
[1, 4],
|
| 1462 |
+
[2, 5]])
|
| 1463 |
+
>>> np.einsum('ij->ji', c)
|
| 1464 |
+
array([[0, 3],
|
| 1465 |
+
[1, 4],
|
| 1466 |
+
[2, 5]])
|
| 1467 |
+
>>> np.einsum(c, [1,0])
|
| 1468 |
+
array([[0, 3],
|
| 1469 |
+
[1, 4],
|
| 1470 |
+
[2, 5]])
|
| 1471 |
+
>>> np.transpose(c)
|
| 1472 |
+
array([[0, 3],
|
| 1473 |
+
[1, 4],
|
| 1474 |
+
[2, 5]])
|
| 1475 |
+
|
| 1476 |
+
Vector inner products:
|
| 1477 |
+
|
| 1478 |
+
>>> np.einsum('i,i', b, b)
|
| 1479 |
+
30
|
| 1480 |
+
>>> np.einsum(b, [0], b, [0])
|
| 1481 |
+
30
|
| 1482 |
+
>>> np.inner(b,b)
|
| 1483 |
+
30
|
| 1484 |
+
|
| 1485 |
+
Matrix vector multiplication:
|
| 1486 |
+
|
| 1487 |
+
>>> np.einsum('ij,j', a, b)
|
| 1488 |
+
array([ 30, 80, 130, 180, 230])
|
| 1489 |
+
>>> np.einsum(a, [0,1], b, [1])
|
| 1490 |
+
array([ 30, 80, 130, 180, 230])
|
| 1491 |
+
>>> np.dot(a, b)
|
| 1492 |
+
array([ 30, 80, 130, 180, 230])
|
| 1493 |
+
>>> np.einsum('...j,j', a, b)
|
| 1494 |
+
array([ 30, 80, 130, 180, 230])
|
| 1495 |
+
|
| 1496 |
+
Broadcasting and scalar multiplication:
|
| 1497 |
+
|
| 1498 |
+
>>> np.einsum('..., ...', 3, c)
|
| 1499 |
+
array([[ 0, 3, 6],
|
| 1500 |
+
[ 9, 12, 15]])
|
| 1501 |
+
>>> np.einsum(',ij', 3, c)
|
| 1502 |
+
array([[ 0, 3, 6],
|
| 1503 |
+
[ 9, 12, 15]])
|
| 1504 |
+
>>> np.einsum(3, [Ellipsis], c, [Ellipsis])
|
| 1505 |
+
array([[ 0, 3, 6],
|
| 1506 |
+
[ 9, 12, 15]])
|
| 1507 |
+
>>> np.multiply(3, c)
|
| 1508 |
+
array([[ 0, 3, 6],
|
| 1509 |
+
[ 9, 12, 15]])
|
| 1510 |
+
|
| 1511 |
+
Vector outer product:
|
| 1512 |
+
|
| 1513 |
+
>>> np.einsum('i,j', np.arange(2)+1, b)
|
| 1514 |
+
array([[0, 1, 2, 3, 4],
|
| 1515 |
+
[0, 2, 4, 6, 8]])
|
| 1516 |
+
>>> np.einsum(np.arange(2)+1, [0], b, [1])
|
| 1517 |
+
array([[0, 1, 2, 3, 4],
|
| 1518 |
+
[0, 2, 4, 6, 8]])
|
| 1519 |
+
>>> np.outer(np.arange(2)+1, b)
|
| 1520 |
+
array([[0, 1, 2, 3, 4],
|
| 1521 |
+
[0, 2, 4, 6, 8]])
|
| 1522 |
+
|
| 1523 |
+
Tensor contraction:
|
| 1524 |
+
|
| 1525 |
+
>>> a = np.arange(60.).reshape(3,4,5)
|
| 1526 |
+
>>> b = np.arange(24.).reshape(4,3,2)
|
| 1527 |
+
>>> np.einsum('ijk,jil->kl', a, b)
|
| 1528 |
+
array([[4400., 4730.],
|
| 1529 |
+
[4532., 4874.],
|
| 1530 |
+
[4664., 5018.],
|
| 1531 |
+
[4796., 5162.],
|
| 1532 |
+
[4928., 5306.]])
|
| 1533 |
+
>>> np.einsum(a, [0,1,2], b, [1,0,3], [2,3])
|
| 1534 |
+
array([[4400., 4730.],
|
| 1535 |
+
[4532., 4874.],
|
| 1536 |
+
[4664., 5018.],
|
| 1537 |
+
[4796., 5162.],
|
| 1538 |
+
[4928., 5306.]])
|
| 1539 |
+
>>> np.tensordot(a,b, axes=([1,0],[0,1]))
|
| 1540 |
+
array([[4400., 4730.],
|
| 1541 |
+
[4532., 4874.],
|
| 1542 |
+
[4664., 5018.],
|
| 1543 |
+
[4796., 5162.],
|
| 1544 |
+
[4928., 5306.]])
|
| 1545 |
+
|
| 1546 |
+
Writeable returned arrays (since version 1.10.0):
|
| 1547 |
+
|
| 1548 |
+
>>> a = np.zeros((3, 3))
|
| 1549 |
+
>>> np.einsum('ii->i', a)[:] = 1
|
| 1550 |
+
>>> a
|
| 1551 |
+
array([[1., 0., 0.],
|
| 1552 |
+
[0., 1., 0.],
|
| 1553 |
+
[0., 0., 1.]])
|
| 1554 |
+
|
| 1555 |
+
Example of ellipsis use:
|
| 1556 |
+
|
| 1557 |
+
>>> a = np.arange(6).reshape((3,2))
|
| 1558 |
+
>>> b = np.arange(12).reshape((4,3))
|
| 1559 |
+
>>> np.einsum('ki,jk->ij', a, b)
|
| 1560 |
+
array([[10, 28, 46, 64],
|
| 1561 |
+
[13, 40, 67, 94]])
|
| 1562 |
+
>>> np.einsum('ki,...k->i...', a, b)
|
| 1563 |
+
array([[10, 28, 46, 64],
|
| 1564 |
+
[13, 40, 67, 94]])
|
| 1565 |
+
>>> np.einsum('k...,jk', a, b)
|
| 1566 |
+
array([[10, 28, 46, 64],
|
| 1567 |
+
[13, 40, 67, 94]])
|
| 1568 |
+
|
| 1569 |
+
Chained array operations. For more complicated contractions, speed ups
|
| 1570 |
+
might be achieved by repeatedly computing a 'greedy' path or pre-computing
|
| 1571 |
+
the 'optimal' path and repeatedly applying it, using an `einsum_path`
|
| 1572 |
+
insertion (since version 1.12.0). Performance improvements can be
|
| 1573 |
+
particularly significant with larger arrays:
|
| 1574 |
+
|
| 1575 |
+
>>> a = np.ones(64).reshape(2,4,8)
|
| 1576 |
+
|
| 1577 |
+
Basic `einsum`: ~1520ms (benchmarked on 3.1GHz Intel i5.)
|
| 1578 |
+
|
| 1579 |
+
>>> for iteration in range(500):
|
| 1580 |
+
... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a)
|
| 1581 |
+
|
| 1582 |
+
Sub-optimal `einsum` (due to repeated path calculation time): ~330ms
|
| 1583 |
+
|
| 1584 |
+
>>> for iteration in range(500):
|
| 1585 |
+
... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a,
|
| 1586 |
+
... optimize='optimal')
|
| 1587 |
+
|
| 1588 |
+
Greedy `einsum` (faster optimal path approximation): ~160ms
|
| 1589 |
+
|
| 1590 |
+
>>> for iteration in range(500):
|
| 1591 |
+
... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize='greedy')
|
| 1592 |
+
|
| 1593 |
+
Optimal `einsum` (best usage pattern in some use cases): ~110ms
|
| 1594 |
+
|
| 1595 |
+
>>> path = np.einsum_path('ijk,ilm,njm,nlk,abc->',a,a,a,a,a,
|
| 1596 |
+
... optimize='optimal')[0]
|
| 1597 |
+
>>> for iteration in range(500):
|
| 1598 |
+
... _ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize=path)
|
| 1599 |
+
|
| 1600 |
+
"""
|
| 1601 |
+
# Special handling if out is specified
|
| 1602 |
+
specified_out = out is not None
|
| 1603 |
+
|
| 1604 |
+
# If no optimization, run pure einsum
|
| 1605 |
+
if optimize is False:
|
| 1606 |
+
if specified_out:
|
| 1607 |
+
kwargs['out'] = out
|
| 1608 |
+
return c_einsum(*operands, **kwargs)
|
| 1609 |
+
|
| 1610 |
+
# Check the kwargs to avoid a more cryptic error later, without having to
|
| 1611 |
+
# repeat default values here
|
| 1612 |
+
valid_einsum_kwargs = ['dtype', 'order', 'casting']
|
| 1613 |
+
unknown_kwargs = [k for k in kwargs if k not in valid_einsum_kwargs]
|
| 1614 |
+
if len(unknown_kwargs):
|
| 1615 |
+
raise TypeError(f"Did not understand the following kwargs: {unknown_kwargs}")
|
| 1616 |
+
|
| 1617 |
+
# Build the contraction list and operand
|
| 1618 |
+
operands, contraction_list = einsum_path(*operands, optimize=optimize,
|
| 1619 |
+
einsum_call=True)
|
| 1620 |
+
|
| 1621 |
+
# Start contraction loop
|
| 1622 |
+
for num, contraction in enumerate(contraction_list):
|
| 1623 |
+
inds, einsum_str, _ = contraction
|
| 1624 |
+
tmp_operands = [operands.pop(x) for x in inds]
|
| 1625 |
+
|
| 1626 |
+
# Do we need to deal with the output?
|
| 1627 |
+
handle_out = specified_out and ((num + 1) == len(contraction_list))
|
| 1628 |
+
|
| 1629 |
+
# If out was specified
|
| 1630 |
+
if handle_out:
|
| 1631 |
+
kwargs["out"] = out
|
| 1632 |
+
|
| 1633 |
+
if len(tmp_operands) == 2:
|
| 1634 |
+
# Call (batched) matrix multiplication if possible
|
| 1635 |
+
new_view = bmm_einsum(einsum_str, *tmp_operands, **kwargs)
|
| 1636 |
+
else:
|
| 1637 |
+
# Call einsum
|
| 1638 |
+
new_view = c_einsum(einsum_str, *tmp_operands, **kwargs)
|
| 1639 |
+
|
| 1640 |
+
# Append new items and dereference what we can
|
| 1641 |
+
operands.append(new_view)
|
| 1642 |
+
del tmp_operands, new_view
|
| 1643 |
+
|
| 1644 |
+
if specified_out:
|
| 1645 |
+
return out
|
| 1646 |
+
else:
|
| 1647 |
+
return operands[0]
|
v12x/pylib/numpy/_core/fromnumeric.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
v12x/pylib/numpy/_core/function_base.py
ADDED
|
@@ -0,0 +1,547 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import functools
|
| 2 |
+
import inspect
|
| 3 |
+
import operator
|
| 4 |
+
import types
|
| 5 |
+
import warnings
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
from numpy._core import overrides
|
| 9 |
+
from numpy._core._multiarray_umath import _array_converter
|
| 10 |
+
from numpy._core.multiarray import add_docstring
|
| 11 |
+
|
| 12 |
+
from . import numeric as _nx
|
| 13 |
+
from .numeric import asanyarray, nan, ndim, result_type
|
| 14 |
+
|
| 15 |
+
__all__ = ['logspace', 'linspace', 'geomspace']
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
array_function_dispatch = functools.partial(
|
| 19 |
+
overrides.array_function_dispatch, module='numpy')
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _linspace_dispatcher(start, stop, num=None, endpoint=None, retstep=None,
|
| 23 |
+
dtype=None, axis=None, *, device=None):
|
| 24 |
+
return (start, stop)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
@array_function_dispatch(_linspace_dispatcher)
|
| 28 |
+
def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None,
|
| 29 |
+
axis=0, *, device=None):
|
| 30 |
+
"""
|
| 31 |
+
Return evenly spaced numbers over a specified interval.
|
| 32 |
+
|
| 33 |
+
Returns `num` evenly spaced samples, calculated over the
|
| 34 |
+
interval [`start`, `stop`].
|
| 35 |
+
|
| 36 |
+
The endpoint of the interval can optionally be excluded.
|
| 37 |
+
|
| 38 |
+
.. versionchanged:: 1.20.0
|
| 39 |
+
Values are rounded towards ``-inf`` instead of ``0`` when an
|
| 40 |
+
integer ``dtype`` is specified. The old behavior can
|
| 41 |
+
still be obtained with ``np.linspace(start, stop, num).astype(np.int_)``
|
| 42 |
+
|
| 43 |
+
Parameters
|
| 44 |
+
----------
|
| 45 |
+
start : array_like
|
| 46 |
+
The starting value of the sequence.
|
| 47 |
+
stop : array_like
|
| 48 |
+
The end value of the sequence, unless `endpoint` is set to False.
|
| 49 |
+
In that case, the sequence consists of all but the last of ``num + 1``
|
| 50 |
+
evenly spaced samples, so that `stop` is excluded. Note that the step
|
| 51 |
+
size changes when `endpoint` is False.
|
| 52 |
+
num : int, optional
|
| 53 |
+
Number of samples to generate. Default is 50. Must be non-negative.
|
| 54 |
+
endpoint : bool, optional
|
| 55 |
+
If True, `stop` is the last sample. Otherwise, it is not included.
|
| 56 |
+
Default is True.
|
| 57 |
+
retstep : bool, optional
|
| 58 |
+
If True, return (`samples`, `step`), where `step` is the spacing
|
| 59 |
+
between samples.
|
| 60 |
+
dtype : dtype, optional
|
| 61 |
+
The type of the output array. If `dtype` is not given, the data type
|
| 62 |
+
is inferred from `start` and `stop`. The inferred dtype will never be
|
| 63 |
+
an integer; `float` is chosen even if the arguments would produce an
|
| 64 |
+
array of integers.
|
| 65 |
+
axis : int, optional
|
| 66 |
+
The axis in the result to store the samples. Relevant only if start
|
| 67 |
+
or stop are array-like. By default (0), the samples will be along a
|
| 68 |
+
new axis inserted at the beginning. Use -1 to get an axis at the end.
|
| 69 |
+
device : str, optional
|
| 70 |
+
The device on which to place the created array. Default: None.
|
| 71 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 72 |
+
|
| 73 |
+
.. versionadded:: 2.0.0
|
| 74 |
+
|
| 75 |
+
Returns
|
| 76 |
+
-------
|
| 77 |
+
samples : ndarray
|
| 78 |
+
There are `num` equally spaced samples in the closed interval
|
| 79 |
+
``[start, stop]`` or the half-open interval ``[start, stop)``
|
| 80 |
+
(depending on whether `endpoint` is True or False).
|
| 81 |
+
step : float, optional
|
| 82 |
+
Only returned if `retstep` is True
|
| 83 |
+
|
| 84 |
+
Size of spacing between samples.
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
See Also
|
| 88 |
+
--------
|
| 89 |
+
arange : Similar to `linspace`, but uses a step size (instead of the
|
| 90 |
+
number of samples).
|
| 91 |
+
geomspace : Similar to `linspace`, but with numbers spaced evenly on a log
|
| 92 |
+
scale (a geometric progression).
|
| 93 |
+
logspace : Similar to `geomspace`, but with the end points specified as
|
| 94 |
+
logarithms.
|
| 95 |
+
:ref:`how-to-partition`
|
| 96 |
+
|
| 97 |
+
Examples
|
| 98 |
+
--------
|
| 99 |
+
>>> import numpy as np
|
| 100 |
+
>>> np.linspace(2.0, 3.0, num=5)
|
| 101 |
+
array([2. , 2.25, 2.5 , 2.75, 3. ])
|
| 102 |
+
>>> np.linspace(2.0, 3.0, num=5, endpoint=False)
|
| 103 |
+
array([2. , 2.2, 2.4, 2.6, 2.8])
|
| 104 |
+
>>> np.linspace(2.0, 3.0, num=5, retstep=True)
|
| 105 |
+
(array([2. , 2.25, 2.5 , 2.75, 3. ]), 0.25)
|
| 106 |
+
|
| 107 |
+
Graphical illustration:
|
| 108 |
+
|
| 109 |
+
>>> import matplotlib.pyplot as plt
|
| 110 |
+
>>> N = 8
|
| 111 |
+
>>> y = np.zeros(N)
|
| 112 |
+
>>> x1 = np.linspace(0, 10, N, endpoint=True)
|
| 113 |
+
>>> x2 = np.linspace(0, 10, N, endpoint=False)
|
| 114 |
+
>>> plt.plot(x1, y, 'o')
|
| 115 |
+
[<matplotlib.lines.Line2D object at 0x...>]
|
| 116 |
+
>>> plt.plot(x2, y + 0.5, 'o')
|
| 117 |
+
[<matplotlib.lines.Line2D object at 0x...>]
|
| 118 |
+
>>> plt.ylim([-0.5, 1])
|
| 119 |
+
(-0.5, 1)
|
| 120 |
+
>>> plt.show()
|
| 121 |
+
|
| 122 |
+
"""
|
| 123 |
+
num = operator.index(num)
|
| 124 |
+
if num < 0:
|
| 125 |
+
raise ValueError(
|
| 126 |
+
f"Number of samples, {num}, must be non-negative."
|
| 127 |
+
)
|
| 128 |
+
div = (num - 1) if endpoint else num
|
| 129 |
+
|
| 130 |
+
conv = _array_converter(start, stop)
|
| 131 |
+
start, stop = conv.as_arrays()
|
| 132 |
+
dt = conv.result_type(ensure_inexact=True)
|
| 133 |
+
|
| 134 |
+
if dtype is None:
|
| 135 |
+
dtype = dt
|
| 136 |
+
integer_dtype = False
|
| 137 |
+
else:
|
| 138 |
+
integer_dtype = _nx.issubdtype(dtype, _nx.integer)
|
| 139 |
+
|
| 140 |
+
# Use `dtype=type(dt)` to enforce a floating point evaluation:
|
| 141 |
+
delta = np.subtract(stop, start, dtype=type(dt))
|
| 142 |
+
y = _nx.arange(
|
| 143 |
+
0, num, dtype=dt, device=device
|
| 144 |
+
).reshape((-1,) + (1,) * ndim(delta))
|
| 145 |
+
|
| 146 |
+
# In-place multiplication y *= delta/div is faster, but prevents
|
| 147 |
+
# the multiplicant from overriding what class is produced, and thus
|
| 148 |
+
# prevents, e.g. use of Quantities, see gh-7142. Hence, we multiply
|
| 149 |
+
# in place only for standard scalar types.
|
| 150 |
+
if div > 0:
|
| 151 |
+
_mult_inplace = _nx.isscalar(delta)
|
| 152 |
+
step = delta / div
|
| 153 |
+
any_step_zero = (
|
| 154 |
+
step == 0 if _mult_inplace else _nx.asanyarray(step == 0).any())
|
| 155 |
+
if any_step_zero:
|
| 156 |
+
# Special handling for denormal numbers, gh-5437
|
| 157 |
+
y /= div
|
| 158 |
+
if _mult_inplace:
|
| 159 |
+
y *= delta
|
| 160 |
+
else:
|
| 161 |
+
y = y * delta
|
| 162 |
+
elif _mult_inplace:
|
| 163 |
+
y *= step
|
| 164 |
+
else:
|
| 165 |
+
y = y * step
|
| 166 |
+
else:
|
| 167 |
+
# sequences with 0 items or 1 item with endpoint=True (i.e. div <= 0)
|
| 168 |
+
# have an undefined step
|
| 169 |
+
step = nan
|
| 170 |
+
# Multiply with delta to allow possible override of output class.
|
| 171 |
+
y = y * delta
|
| 172 |
+
|
| 173 |
+
y += start
|
| 174 |
+
|
| 175 |
+
if endpoint and num > 1:
|
| 176 |
+
y[-1, ...] = stop
|
| 177 |
+
|
| 178 |
+
if axis != 0:
|
| 179 |
+
y = _nx.moveaxis(y, 0, axis)
|
| 180 |
+
|
| 181 |
+
if integer_dtype:
|
| 182 |
+
_nx.floor(y, out=y)
|
| 183 |
+
|
| 184 |
+
y = conv.wrap(y.astype(dtype, copy=False))
|
| 185 |
+
if retstep:
|
| 186 |
+
return y, step
|
| 187 |
+
else:
|
| 188 |
+
return y
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
def _logspace_dispatcher(start, stop, num=None, endpoint=None, base=None,
|
| 192 |
+
dtype=None, axis=None):
|
| 193 |
+
return (start, stop, base)
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
@array_function_dispatch(_logspace_dispatcher)
|
| 197 |
+
def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None,
|
| 198 |
+
axis=0):
|
| 199 |
+
"""
|
| 200 |
+
Return numbers spaced evenly on a log scale.
|
| 201 |
+
|
| 202 |
+
In linear space, the sequence starts at ``base ** start``
|
| 203 |
+
(`base` to the power of `start`) and ends with ``base ** stop``
|
| 204 |
+
(see `endpoint` below).
|
| 205 |
+
|
| 206 |
+
.. versionchanged:: 1.25.0
|
| 207 |
+
Non-scalar 'base` is now supported
|
| 208 |
+
|
| 209 |
+
Parameters
|
| 210 |
+
----------
|
| 211 |
+
start : array_like
|
| 212 |
+
``base ** start`` is the starting value of the sequence.
|
| 213 |
+
stop : array_like
|
| 214 |
+
``base ** stop`` is the final value of the sequence, unless `endpoint`
|
| 215 |
+
is False. In that case, ``num + 1`` values are spaced over the
|
| 216 |
+
interval in log-space, of which all but the last (a sequence of
|
| 217 |
+
length `num`) are returned.
|
| 218 |
+
num : integer, optional
|
| 219 |
+
Number of samples to generate. Default is 50.
|
| 220 |
+
endpoint : boolean, optional
|
| 221 |
+
If true, `stop` is the last sample. Otherwise, it is not included.
|
| 222 |
+
Default is True.
|
| 223 |
+
base : array_like, optional
|
| 224 |
+
The base of the log space. The step size between the elements in
|
| 225 |
+
``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform.
|
| 226 |
+
Default is 10.0.
|
| 227 |
+
dtype : dtype
|
| 228 |
+
The type of the output array. If `dtype` is not given, the data type
|
| 229 |
+
is inferred from `start` and `stop`. The inferred type will never be
|
| 230 |
+
an integer; `float` is chosen even if the arguments would produce an
|
| 231 |
+
array of integers.
|
| 232 |
+
axis : int, optional
|
| 233 |
+
The axis in the result to store the samples. Relevant only if start,
|
| 234 |
+
stop, or base are array-like. By default (0), the samples will be
|
| 235 |
+
along a new axis inserted at the beginning. Use -1 to get an axis at
|
| 236 |
+
the end.
|
| 237 |
+
|
| 238 |
+
Returns
|
| 239 |
+
-------
|
| 240 |
+
samples : ndarray
|
| 241 |
+
`num` samples, equally spaced on a log scale.
|
| 242 |
+
|
| 243 |
+
See Also
|
| 244 |
+
--------
|
| 245 |
+
arange : Similar to linspace, with the step size specified instead of the
|
| 246 |
+
number of samples. Note that, when used with a float endpoint, the
|
| 247 |
+
endpoint may or may not be included.
|
| 248 |
+
linspace : Similar to logspace, but with the samples uniformly distributed
|
| 249 |
+
in linear space, instead of log space.
|
| 250 |
+
geomspace : Similar to logspace, but with endpoints specified directly.
|
| 251 |
+
:ref:`how-to-partition`
|
| 252 |
+
|
| 253 |
+
Notes
|
| 254 |
+
-----
|
| 255 |
+
If base is a scalar, logspace is equivalent to the code
|
| 256 |
+
|
| 257 |
+
>>> y = np.linspace(start, stop, num=num, endpoint=endpoint)
|
| 258 |
+
... # doctest: +SKIP
|
| 259 |
+
>>> power(base, y).astype(dtype)
|
| 260 |
+
... # doctest: +SKIP
|
| 261 |
+
|
| 262 |
+
Examples
|
| 263 |
+
--------
|
| 264 |
+
>>> import numpy as np
|
| 265 |
+
>>> np.logspace(2.0, 3.0, num=4)
|
| 266 |
+
array([ 100. , 215.443469 , 464.15888336, 1000. ])
|
| 267 |
+
>>> np.logspace(2.0, 3.0, num=4, endpoint=False)
|
| 268 |
+
array([100. , 177.827941 , 316.22776602, 562.34132519])
|
| 269 |
+
>>> np.logspace(2.0, 3.0, num=4, base=2.0)
|
| 270 |
+
array([4. , 5.0396842 , 6.34960421, 8. ])
|
| 271 |
+
>>> np.logspace(2.0, 3.0, num=4, base=[2.0, 3.0], axis=-1)
|
| 272 |
+
array([[ 4. , 5.0396842 , 6.34960421, 8. ],
|
| 273 |
+
[ 9. , 12.98024613, 18.72075441, 27. ]])
|
| 274 |
+
|
| 275 |
+
Graphical illustration:
|
| 276 |
+
|
| 277 |
+
>>> import matplotlib.pyplot as plt
|
| 278 |
+
>>> N = 10
|
| 279 |
+
>>> x1 = np.logspace(0.1, 1, N, endpoint=True)
|
| 280 |
+
>>> x2 = np.logspace(0.1, 1, N, endpoint=False)
|
| 281 |
+
>>> y = np.zeros(N)
|
| 282 |
+
>>> plt.plot(x1, y, 'o')
|
| 283 |
+
[<matplotlib.lines.Line2D object at 0x...>]
|
| 284 |
+
>>> plt.plot(x2, y + 0.5, 'o')
|
| 285 |
+
[<matplotlib.lines.Line2D object at 0x...>]
|
| 286 |
+
>>> plt.ylim([-0.5, 1])
|
| 287 |
+
(-0.5, 1)
|
| 288 |
+
>>> plt.show()
|
| 289 |
+
|
| 290 |
+
"""
|
| 291 |
+
if not isinstance(base, (float, int)) and np.ndim(base):
|
| 292 |
+
# If base is non-scalar, broadcast it with the others, since it
|
| 293 |
+
# may influence how axis is interpreted.
|
| 294 |
+
ndmax = np.broadcast(start, stop, base).ndim
|
| 295 |
+
start, stop, base = (
|
| 296 |
+
np.array(a, copy=None, subok=True, ndmin=ndmax)
|
| 297 |
+
for a in (start, stop, base)
|
| 298 |
+
)
|
| 299 |
+
base = np.expand_dims(base, axis=axis)
|
| 300 |
+
y = linspace(start, stop, num=num, endpoint=endpoint, axis=axis)
|
| 301 |
+
if dtype is None:
|
| 302 |
+
return _nx.power(base, y)
|
| 303 |
+
return _nx.power(base, y).astype(dtype, copy=False)
|
| 304 |
+
|
| 305 |
+
|
| 306 |
+
def _geomspace_dispatcher(start, stop, num=None, endpoint=None, dtype=None,
|
| 307 |
+
axis=None):
|
| 308 |
+
return (start, stop)
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
@array_function_dispatch(_geomspace_dispatcher)
|
| 312 |
+
def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0):
|
| 313 |
+
"""
|
| 314 |
+
Return numbers spaced evenly on a log scale (a geometric progression).
|
| 315 |
+
|
| 316 |
+
This is similar to `logspace`, but with endpoints specified directly.
|
| 317 |
+
Each output sample is a constant multiple of the previous.
|
| 318 |
+
|
| 319 |
+
Parameters
|
| 320 |
+
----------
|
| 321 |
+
start : array_like
|
| 322 |
+
The starting value of the sequence.
|
| 323 |
+
stop : array_like
|
| 324 |
+
The final value of the sequence, unless `endpoint` is False.
|
| 325 |
+
In that case, ``num + 1`` values are spaced over the
|
| 326 |
+
interval in log-space, of which all but the last (a sequence of
|
| 327 |
+
length `num`) are returned.
|
| 328 |
+
num : integer, optional
|
| 329 |
+
Number of samples to generate. Default is 50.
|
| 330 |
+
endpoint : boolean, optional
|
| 331 |
+
If true, `stop` is the last sample. Otherwise, it is not included.
|
| 332 |
+
Default is True.
|
| 333 |
+
dtype : dtype
|
| 334 |
+
The type of the output array. If `dtype` is not given, the data type
|
| 335 |
+
is inferred from `start` and `stop`. The inferred dtype will never be
|
| 336 |
+
an integer; `float` is chosen even if the arguments would produce an
|
| 337 |
+
array of integers.
|
| 338 |
+
axis : int, optional
|
| 339 |
+
The axis in the result to store the samples. Relevant only if start
|
| 340 |
+
or stop are array-like. By default (0), the samples will be along a
|
| 341 |
+
new axis inserted at the beginning. Use -1 to get an axis at the end.
|
| 342 |
+
|
| 343 |
+
Returns
|
| 344 |
+
-------
|
| 345 |
+
samples : ndarray
|
| 346 |
+
`num` samples, equally spaced on a log scale.
|
| 347 |
+
|
| 348 |
+
See Also
|
| 349 |
+
--------
|
| 350 |
+
logspace : Similar to geomspace, but with endpoints specified using log
|
| 351 |
+
and base.
|
| 352 |
+
linspace : Similar to geomspace, but with arithmetic instead of geometric
|
| 353 |
+
progression.
|
| 354 |
+
arange : Similar to linspace, with the step size specified instead of the
|
| 355 |
+
number of samples.
|
| 356 |
+
:ref:`how-to-partition`
|
| 357 |
+
|
| 358 |
+
Notes
|
| 359 |
+
-----
|
| 360 |
+
If the inputs or dtype are complex, the output will follow a logarithmic
|
| 361 |
+
spiral in the complex plane. (There are an infinite number of spirals
|
| 362 |
+
passing through two points; the output will follow the shortest such path.)
|
| 363 |
+
|
| 364 |
+
Examples
|
| 365 |
+
--------
|
| 366 |
+
>>> import numpy as np
|
| 367 |
+
>>> np.geomspace(1, 1000, num=4)
|
| 368 |
+
array([ 1., 10., 100., 1000.])
|
| 369 |
+
>>> np.geomspace(1, 1000, num=3, endpoint=False)
|
| 370 |
+
array([ 1., 10., 100.])
|
| 371 |
+
>>> np.geomspace(1, 1000, num=4, endpoint=False)
|
| 372 |
+
array([ 1. , 5.62341325, 31.6227766 , 177.827941 ])
|
| 373 |
+
>>> np.geomspace(1, 256, num=9)
|
| 374 |
+
array([ 1., 2., 4., 8., 16., 32., 64., 128., 256.])
|
| 375 |
+
|
| 376 |
+
Note that the above may not produce exact integers:
|
| 377 |
+
|
| 378 |
+
>>> np.geomspace(1, 256, num=9, dtype=np.int_)
|
| 379 |
+
array([ 1, 2, 4, 7, 16, 32, 63, 127, 256])
|
| 380 |
+
>>> np.around(np.geomspace(1, 256, num=9)).astype(np.int_)
|
| 381 |
+
array([ 1, 2, 4, 8, 16, 32, 64, 128, 256])
|
| 382 |
+
|
| 383 |
+
Negative, decreasing, and complex inputs are allowed:
|
| 384 |
+
|
| 385 |
+
>>> np.geomspace(1000, 1, num=4)
|
| 386 |
+
array([1000., 100., 10., 1.])
|
| 387 |
+
>>> np.geomspace(-1000, -1, num=4)
|
| 388 |
+
array([-1000., -100., -10., -1.])
|
| 389 |
+
>>> np.geomspace(1j, 1000j, num=4) # Straight line
|
| 390 |
+
array([0. +1.j, 0. +10.j, 0. +100.j, 0.+1000.j])
|
| 391 |
+
>>> np.geomspace(-1+0j, 1+0j, num=5) # Circle
|
| 392 |
+
array([-1.00000000e+00+1.22464680e-16j, -7.07106781e-01+7.07106781e-01j,
|
| 393 |
+
6.12323400e-17+1.00000000e+00j, 7.07106781e-01+7.07106781e-01j,
|
| 394 |
+
1.00000000e+00+0.00000000e+00j])
|
| 395 |
+
|
| 396 |
+
Graphical illustration of `endpoint` parameter:
|
| 397 |
+
|
| 398 |
+
>>> import matplotlib.pyplot as plt
|
| 399 |
+
>>> N = 10
|
| 400 |
+
>>> y = np.zeros(N)
|
| 401 |
+
>>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=True), y + 1, 'o')
|
| 402 |
+
[<matplotlib.lines.Line2D object at 0x...>]
|
| 403 |
+
>>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=False), y + 2, 'o')
|
| 404 |
+
[<matplotlib.lines.Line2D object at 0x...>]
|
| 405 |
+
>>> plt.axis([0.5, 2000, 0, 3])
|
| 406 |
+
[0.5, 2000, 0, 3]
|
| 407 |
+
>>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both')
|
| 408 |
+
>>> plt.show()
|
| 409 |
+
|
| 410 |
+
"""
|
| 411 |
+
start = asanyarray(start)
|
| 412 |
+
stop = asanyarray(stop)
|
| 413 |
+
if _nx.any(start == 0) or _nx.any(stop == 0):
|
| 414 |
+
raise ValueError('Geometric sequence cannot include zero')
|
| 415 |
+
|
| 416 |
+
dt = result_type(start, stop, float(num), _nx.zeros((), dtype))
|
| 417 |
+
if dtype is None:
|
| 418 |
+
dtype = dt
|
| 419 |
+
else:
|
| 420 |
+
# complex to dtype('complex128'), for instance
|
| 421 |
+
dtype = _nx.dtype(dtype)
|
| 422 |
+
|
| 423 |
+
# Promote both arguments to the same dtype in case, for instance, one is
|
| 424 |
+
# complex and another is negative and log would produce NaN otherwise.
|
| 425 |
+
# Copy since we may change things in-place further down.
|
| 426 |
+
start = start.astype(dt, copy=True)
|
| 427 |
+
stop = stop.astype(dt, copy=True)
|
| 428 |
+
|
| 429 |
+
# Allow negative real values and ensure a consistent result for complex
|
| 430 |
+
# (including avoiding negligible real or imaginary parts in output) by
|
| 431 |
+
# rotating start to positive real, calculating, then undoing rotation.
|
| 432 |
+
out_sign = _nx.sign(start)
|
| 433 |
+
start /= out_sign
|
| 434 |
+
stop = stop / out_sign
|
| 435 |
+
|
| 436 |
+
log_start = _nx.log10(start)
|
| 437 |
+
log_stop = _nx.log10(stop)
|
| 438 |
+
result = logspace(log_start, log_stop, num=num,
|
| 439 |
+
endpoint=endpoint, base=10.0, dtype=dt)
|
| 440 |
+
|
| 441 |
+
# Make sure the endpoints match the start and stop arguments. This is
|
| 442 |
+
# necessary because np.exp(np.log(x)) is not necessarily equal to x.
|
| 443 |
+
if num > 0:
|
| 444 |
+
result[0] = start
|
| 445 |
+
if num > 1 and endpoint:
|
| 446 |
+
result[-1] = stop
|
| 447 |
+
|
| 448 |
+
result *= out_sign
|
| 449 |
+
|
| 450 |
+
if axis != 0:
|
| 451 |
+
result = _nx.moveaxis(result, 0, axis)
|
| 452 |
+
|
| 453 |
+
return result.astype(dtype, copy=False)
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
def _needs_add_docstring(obj):
|
| 457 |
+
"""
|
| 458 |
+
Returns true if the only way to set the docstring of `obj` from python is
|
| 459 |
+
via add_docstring.
|
| 460 |
+
|
| 461 |
+
This function errs on the side of being overly conservative.
|
| 462 |
+
"""
|
| 463 |
+
Py_TPFLAGS_HEAPTYPE = 1 << 9
|
| 464 |
+
|
| 465 |
+
if isinstance(obj, (types.FunctionType, types.MethodType, property)):
|
| 466 |
+
return False
|
| 467 |
+
|
| 468 |
+
if isinstance(obj, type) and obj.__flags__ & Py_TPFLAGS_HEAPTYPE:
|
| 469 |
+
return False
|
| 470 |
+
|
| 471 |
+
return True
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def _add_docstring(obj, doc, warn_on_python):
|
| 475 |
+
if warn_on_python and not _needs_add_docstring(obj):
|
| 476 |
+
warnings.warn(
|
| 477 |
+
f"add_newdoc was used on a pure-python object {obj}. "
|
| 478 |
+
"Prefer to attach it directly to the source.",
|
| 479 |
+
UserWarning,
|
| 480 |
+
stacklevel=3)
|
| 481 |
+
|
| 482 |
+
doc = inspect.cleandoc(doc)
|
| 483 |
+
|
| 484 |
+
try:
|
| 485 |
+
add_docstring(obj, doc)
|
| 486 |
+
except Exception:
|
| 487 |
+
pass
|
| 488 |
+
|
| 489 |
+
|
| 490 |
+
def add_newdoc(place, obj, doc, warn_on_python=True):
|
| 491 |
+
"""
|
| 492 |
+
Add documentation to an existing object, typically one defined in C
|
| 493 |
+
|
| 494 |
+
The purpose is to allow easier editing of the docstrings without requiring
|
| 495 |
+
a re-compile. This exists primarily for internal use within numpy itself.
|
| 496 |
+
|
| 497 |
+
Parameters
|
| 498 |
+
----------
|
| 499 |
+
place : str
|
| 500 |
+
The absolute name of the module to import from
|
| 501 |
+
obj : str | None
|
| 502 |
+
The name of the object to add documentation to, typically a class or
|
| 503 |
+
function name.
|
| 504 |
+
doc : str | tuple[str, str] | list[tuple[str, str]]
|
| 505 |
+
If a string, the documentation to apply to `obj`
|
| 506 |
+
|
| 507 |
+
If a tuple, then the first element is interpreted as an attribute
|
| 508 |
+
of `obj` and the second as the docstring to apply -
|
| 509 |
+
``(method, docstring)``
|
| 510 |
+
|
| 511 |
+
If a list, then each element of the list should be a tuple of length
|
| 512 |
+
two - ``[(method1, docstring1), (method2, docstring2), ...]``
|
| 513 |
+
warn_on_python : bool
|
| 514 |
+
If True, the default, emit `UserWarning` if this is used to attach
|
| 515 |
+
documentation to a pure-python object.
|
| 516 |
+
|
| 517 |
+
Notes
|
| 518 |
+
-----
|
| 519 |
+
This routine never raises an error if the docstring can't be written, but
|
| 520 |
+
will raise an error if the object being documented does not exist.
|
| 521 |
+
|
| 522 |
+
This routine cannot modify read-only docstrings, as appear
|
| 523 |
+
in new-style classes or built-in functions. Because this
|
| 524 |
+
routine never raises an error the caller must check manually
|
| 525 |
+
that the docstrings were changed.
|
| 526 |
+
|
| 527 |
+
Since this function grabs the ``char *`` from a c-level str object and puts
|
| 528 |
+
it into the ``tp_doc`` slot of the type of `obj`, it violates a number of
|
| 529 |
+
C-API best-practices, by:
|
| 530 |
+
|
| 531 |
+
- modifying a `PyTypeObject` after calling `PyType_Ready`
|
| 532 |
+
- calling `Py_INCREF` on the str and losing the reference, so the str
|
| 533 |
+
will never be released
|
| 534 |
+
|
| 535 |
+
If possible it should be avoided.
|
| 536 |
+
"""
|
| 537 |
+
new = getattr(__import__(place, globals(), {}, [obj]), obj)
|
| 538 |
+
if isinstance(doc, str):
|
| 539 |
+
if "${ARRAY_FUNCTION_LIKE}" in doc:
|
| 540 |
+
doc = overrides.get_array_function_like_doc(new, doc)
|
| 541 |
+
_add_docstring(new, doc, warn_on_python)
|
| 542 |
+
elif isinstance(doc, tuple):
|
| 543 |
+
attr, docstring = doc
|
| 544 |
+
_add_docstring(getattr(new, attr), docstring, warn_on_python)
|
| 545 |
+
elif isinstance(doc, list):
|
| 546 |
+
for attr, docstring in doc:
|
| 547 |
+
_add_docstring(getattr(new, attr), docstring, warn_on_python)
|
v12x/pylib/numpy/_core/getlimits.py
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Machine limits for Float32 and Float64 and (long double) if available...
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
__all__ = ['finfo', 'iinfo']
|
| 5 |
+
|
| 6 |
+
import math
|
| 7 |
+
import types
|
| 8 |
+
from functools import cached_property
|
| 9 |
+
|
| 10 |
+
from numpy._utils import set_module
|
| 11 |
+
|
| 12 |
+
from . import numeric, numerictypes as ntypes
|
| 13 |
+
from ._multiarray_umath import _finfo_get_realdtype, _populate_finfo_constants
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def _fr0(a):
|
| 17 |
+
"""fix rank-0 --> rank-1"""
|
| 18 |
+
if a.ndim == 0:
|
| 19 |
+
a = a.reshape((1,))
|
| 20 |
+
return a
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _fr1(a):
|
| 24 |
+
"""fix rank > 0 --> rank-0"""
|
| 25 |
+
if a.size == 1:
|
| 26 |
+
a = a.reshape(())
|
| 27 |
+
return a
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
# Parameters for creating MachAr / MachAr-like objects
|
| 31 |
+
_title_fmt = 'numpy {} precision floating point number'
|
| 32 |
+
_MACHAR_PARAMS = {
|
| 33 |
+
ntypes.double: {
|
| 34 |
+
'itype': ntypes.int64,
|
| 35 |
+
'fmt': '%24.16e',
|
| 36 |
+
'title': _title_fmt.format('double')},
|
| 37 |
+
ntypes.single: {
|
| 38 |
+
'itype': ntypes.int32,
|
| 39 |
+
'fmt': '%15.7e',
|
| 40 |
+
'title': _title_fmt.format('single')},
|
| 41 |
+
ntypes.longdouble: {
|
| 42 |
+
'itype': ntypes.longlong,
|
| 43 |
+
'fmt': '%s',
|
| 44 |
+
'title': _title_fmt.format('long double')},
|
| 45 |
+
ntypes.half: {
|
| 46 |
+
'itype': ntypes.int16,
|
| 47 |
+
'fmt': '%12.5e',
|
| 48 |
+
'title': _title_fmt.format('half')}}
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
@set_module('numpy')
|
| 52 |
+
class finfo:
|
| 53 |
+
"""
|
| 54 |
+
finfo(dtype)
|
| 55 |
+
|
| 56 |
+
Machine limits for floating point types.
|
| 57 |
+
|
| 58 |
+
Attributes
|
| 59 |
+
----------
|
| 60 |
+
bits : int
|
| 61 |
+
The number of bits occupied by the type.
|
| 62 |
+
dtype : dtype
|
| 63 |
+
Returns the dtype for which `finfo` returns information. For complex
|
| 64 |
+
input, the returned dtype is the associated ``float*`` dtype for its
|
| 65 |
+
real and complex components.
|
| 66 |
+
eps : float
|
| 67 |
+
The difference between 1.0 and the next smallest representable float
|
| 68 |
+
larger than 1.0. For example, for 64-bit binary floats in the IEEE-754
|
| 69 |
+
standard, ``eps = 2**-52``, approximately 2.22e-16.
|
| 70 |
+
epsneg : float
|
| 71 |
+
The difference between 1.0 and the next smallest representable float
|
| 72 |
+
less than 1.0. For example, for 64-bit binary floats in the IEEE-754
|
| 73 |
+
standard, ``epsneg = 2**-53``, approximately 1.11e-16.
|
| 74 |
+
iexp : int
|
| 75 |
+
The number of bits in the exponent portion of the floating point
|
| 76 |
+
representation.
|
| 77 |
+
machep : int
|
| 78 |
+
The exponent that yields `eps`.
|
| 79 |
+
max : floating point number of the appropriate type
|
| 80 |
+
The largest representable number.
|
| 81 |
+
maxexp : int
|
| 82 |
+
The smallest positive power of the base (2) that causes overflow.
|
| 83 |
+
Corresponds to the C standard MAX_EXP.
|
| 84 |
+
min : floating point number of the appropriate type
|
| 85 |
+
The smallest representable number, typically ``-max``.
|
| 86 |
+
minexp : int
|
| 87 |
+
The most negative power of the base (2) consistent with there
|
| 88 |
+
being no leading 0's in the mantissa. Corresponds to the C
|
| 89 |
+
standard MIN_EXP - 1.
|
| 90 |
+
negep : int
|
| 91 |
+
The exponent that yields `epsneg`.
|
| 92 |
+
nexp : int
|
| 93 |
+
The number of bits in the exponent including its sign and bias.
|
| 94 |
+
nmant : int
|
| 95 |
+
The number of explicit bits in the mantissa (excluding the implicit
|
| 96 |
+
leading bit for normalized numbers).
|
| 97 |
+
precision : int
|
| 98 |
+
The approximate number of decimal digits to which this kind of
|
| 99 |
+
float is precise.
|
| 100 |
+
resolution : floating point number of the appropriate type
|
| 101 |
+
The approximate decimal resolution of this type, i.e.,
|
| 102 |
+
``10**-precision``.
|
| 103 |
+
tiny : float
|
| 104 |
+
An alias for `smallest_normal`, kept for backwards compatibility.
|
| 105 |
+
smallest_normal : float
|
| 106 |
+
The smallest positive floating point number with 1 as leading bit in
|
| 107 |
+
the mantissa following IEEE-754 (see Notes).
|
| 108 |
+
smallest_subnormal : float
|
| 109 |
+
The smallest positive floating point number with 0 as leading bit in
|
| 110 |
+
the mantissa following IEEE-754.
|
| 111 |
+
|
| 112 |
+
Parameters
|
| 113 |
+
----------
|
| 114 |
+
dtype : float, dtype, or instance
|
| 115 |
+
Kind of floating point or complex floating point
|
| 116 |
+
data-type about which to get information.
|
| 117 |
+
|
| 118 |
+
See Also
|
| 119 |
+
--------
|
| 120 |
+
iinfo : The equivalent for integer data types.
|
| 121 |
+
spacing : The distance between a value and the nearest adjacent number
|
| 122 |
+
nextafter : The next floating point value after x1 towards x2
|
| 123 |
+
|
| 124 |
+
Notes
|
| 125 |
+
-----
|
| 126 |
+
For developers of NumPy: do not instantiate this at the module level.
|
| 127 |
+
The initial calculation of these parameters is expensive and negatively
|
| 128 |
+
impacts import times. These objects are cached, so calling ``finfo()``
|
| 129 |
+
repeatedly inside your functions is not a problem.
|
| 130 |
+
|
| 131 |
+
Note that ``smallest_normal`` is not actually the smallest positive
|
| 132 |
+
representable value in a NumPy floating point type. As in the IEEE-754
|
| 133 |
+
standard [1]_, NumPy floating point types make use of subnormal numbers to
|
| 134 |
+
fill the gap between 0 and ``smallest_normal``. However, subnormal numbers
|
| 135 |
+
may have significantly reduced precision [2]_.
|
| 136 |
+
|
| 137 |
+
For ``longdouble``, the representation varies across platforms. On most
|
| 138 |
+
platforms it is IEEE 754 binary128 (quad precision) or binary64-extended
|
| 139 |
+
(80-bit extended precision). On PowerPC systems, it may use the IBM
|
| 140 |
+
double-double format (a pair of float64 values), which has special
|
| 141 |
+
characteristics for precision and range.
|
| 142 |
+
|
| 143 |
+
This function can also be used for complex data types as well. If used,
|
| 144 |
+
the output will be the same as the corresponding real float type
|
| 145 |
+
(e.g. numpy.finfo(numpy.csingle) is the same as numpy.finfo(numpy.single)).
|
| 146 |
+
However, the output is true for the real and imaginary components.
|
| 147 |
+
|
| 148 |
+
References
|
| 149 |
+
----------
|
| 150 |
+
.. [1] IEEE Standard for Floating-Point Arithmetic, IEEE Std 754-2008,
|
| 151 |
+
pp.1-70, 2008, https://doi.org/10.1109/IEEESTD.2008.4610935
|
| 152 |
+
.. [2] Wikipedia, "Denormal Numbers",
|
| 153 |
+
https://en.wikipedia.org/wiki/Denormal_number
|
| 154 |
+
|
| 155 |
+
Examples
|
| 156 |
+
--------
|
| 157 |
+
>>> import numpy as np
|
| 158 |
+
>>> np.finfo(np.float64).dtype
|
| 159 |
+
dtype('float64')
|
| 160 |
+
>>> np.finfo(np.complex64).dtype
|
| 161 |
+
dtype('float32')
|
| 162 |
+
|
| 163 |
+
"""
|
| 164 |
+
|
| 165 |
+
_finfo_cache = {} # noqa: RUF012
|
| 166 |
+
|
| 167 |
+
__class_getitem__ = classmethod(types.GenericAlias)
|
| 168 |
+
|
| 169 |
+
def __new__(cls, dtype):
|
| 170 |
+
if dtype is None:
|
| 171 |
+
raise TypeError("dtype must not be None")
|
| 172 |
+
|
| 173 |
+
try:
|
| 174 |
+
obj = cls._finfo_cache.get(dtype) # most common path
|
| 175 |
+
if obj is not None:
|
| 176 |
+
return obj
|
| 177 |
+
except TypeError:
|
| 178 |
+
pass
|
| 179 |
+
|
| 180 |
+
try:
|
| 181 |
+
dtype = numeric.dtype(dtype)
|
| 182 |
+
except TypeError:
|
| 183 |
+
# In case a float instance was given
|
| 184 |
+
dtype = numeric.dtype(type(dtype))
|
| 185 |
+
|
| 186 |
+
obj = cls._finfo_cache.get(dtype)
|
| 187 |
+
if obj is not None:
|
| 188 |
+
return obj
|
| 189 |
+
dtypes = [dtype]
|
| 190 |
+
# Call result_type to normalize to e.g. native byte-order:
|
| 191 |
+
newdtype = numeric.result_type(dtype)
|
| 192 |
+
if newdtype is not dtype:
|
| 193 |
+
dtypes.append(newdtype)
|
| 194 |
+
dtype = newdtype
|
| 195 |
+
|
| 196 |
+
obj = cls._finfo_cache.get(dtype)
|
| 197 |
+
if obj is not None:
|
| 198 |
+
return obj
|
| 199 |
+
|
| 200 |
+
sctype = newdtype.type
|
| 201 |
+
if sctype is not None and not issubclass(sctype, numeric.floating):
|
| 202 |
+
newdtype = _finfo_get_realdtype(dtype)
|
| 203 |
+
if newdtype is not dtype:
|
| 204 |
+
# dtype changed, for example from complex128 to float64
|
| 205 |
+
dtypes.append(newdtype)
|
| 206 |
+
dtype = newdtype
|
| 207 |
+
|
| 208 |
+
obj = cls._finfo_cache.get(dtype, None)
|
| 209 |
+
if obj is not None:
|
| 210 |
+
# the original dtype was not in the cache, but the new
|
| 211 |
+
# dtype is in the cache. we add the original dtypes to
|
| 212 |
+
# the cache and return the result
|
| 213 |
+
for dt in dtypes:
|
| 214 |
+
cls._finfo_cache[dt] = obj
|
| 215 |
+
return obj
|
| 216 |
+
obj = object.__new__(cls)._init(dtype)
|
| 217 |
+
for dt in dtypes:
|
| 218 |
+
cls._finfo_cache[dt] = obj
|
| 219 |
+
return obj
|
| 220 |
+
|
| 221 |
+
def _init(self, dtype):
|
| 222 |
+
self.dtype = numeric.dtype(dtype)
|
| 223 |
+
self.bits = self.dtype.itemsize * 8
|
| 224 |
+
self._fmt = None
|
| 225 |
+
self._repr = None
|
| 226 |
+
_populate_finfo_constants(self, self.dtype)
|
| 227 |
+
return self
|
| 228 |
+
|
| 229 |
+
@cached_property
|
| 230 |
+
def epsneg(self):
|
| 231 |
+
# Assume typical floating point logic. Could also use nextafter.
|
| 232 |
+
return self.eps / self._radix
|
| 233 |
+
|
| 234 |
+
@cached_property
|
| 235 |
+
def resolution(self):
|
| 236 |
+
return self.dtype.type(10)**-self.precision
|
| 237 |
+
|
| 238 |
+
@cached_property
|
| 239 |
+
def machep(self):
|
| 240 |
+
return int(math.log2(self.eps))
|
| 241 |
+
|
| 242 |
+
@cached_property
|
| 243 |
+
def negep(self):
|
| 244 |
+
return int(math.log2(self.epsneg))
|
| 245 |
+
|
| 246 |
+
@cached_property
|
| 247 |
+
def nexp(self):
|
| 248 |
+
# considering all ones (inf/nan) and all zeros (subnormal/zero)
|
| 249 |
+
return math.ceil(math.log2(self.maxexp - self.minexp + 2))
|
| 250 |
+
|
| 251 |
+
@cached_property
|
| 252 |
+
def iexp(self):
|
| 253 |
+
# Calculate exponent bits from it's range:
|
| 254 |
+
return math.ceil(math.log2(self.maxexp - self.minexp))
|
| 255 |
+
|
| 256 |
+
def __str__(self):
|
| 257 |
+
if (fmt := getattr(self, "_fmt", None)) is not None:
|
| 258 |
+
return fmt
|
| 259 |
+
|
| 260 |
+
def get_str(name, pad=None):
|
| 261 |
+
if (val := getattr(self, name, None)) is None:
|
| 262 |
+
return "<undefined>"
|
| 263 |
+
if pad is not None:
|
| 264 |
+
s = str(val).ljust(pad)
|
| 265 |
+
return str(val)
|
| 266 |
+
|
| 267 |
+
precision = get_str("precision", 3)
|
| 268 |
+
machep = get_str("machep", 6)
|
| 269 |
+
negep = get_str("negep", 6)
|
| 270 |
+
minexp = get_str("minexp", 6)
|
| 271 |
+
maxexp = get_str("maxexp", 6)
|
| 272 |
+
resolution = get_str("resolution")
|
| 273 |
+
eps = get_str("eps")
|
| 274 |
+
epsneg = get_str("epsneg")
|
| 275 |
+
tiny = get_str("tiny")
|
| 276 |
+
smallest_normal = get_str("smallest_normal")
|
| 277 |
+
smallest_subnormal = get_str("smallest_subnormal")
|
| 278 |
+
nexp = get_str("nexp", 6)
|
| 279 |
+
max_ = get_str("max")
|
| 280 |
+
if hasattr(self, "min") and hasattr(self, "max") and -self.min == self.max:
|
| 281 |
+
min_ = "-max"
|
| 282 |
+
else:
|
| 283 |
+
min_ = get_str("min")
|
| 284 |
+
|
| 285 |
+
fmt = (
|
| 286 |
+
f'Machine parameters for {self.dtype}\n'
|
| 287 |
+
f'---------------------------------------------------------------\n'
|
| 288 |
+
f'precision = {precision} resolution = {resolution}\n'
|
| 289 |
+
f'machep = {machep} eps = {eps}\n'
|
| 290 |
+
f'negep = {negep} epsneg = {epsneg}\n'
|
| 291 |
+
f'minexp = {minexp} tiny = {tiny}\n'
|
| 292 |
+
f'maxexp = {maxexp} max = {max_}\n'
|
| 293 |
+
f'nexp = {nexp} min = {min_}\n'
|
| 294 |
+
f'smallest_normal = {smallest_normal} '
|
| 295 |
+
f'smallest_subnormal = {smallest_subnormal}\n'
|
| 296 |
+
f'---------------------------------------------------------------\n'
|
| 297 |
+
)
|
| 298 |
+
self._fmt = fmt
|
| 299 |
+
return fmt
|
| 300 |
+
|
| 301 |
+
def __repr__(self):
|
| 302 |
+
if (repr_str := getattr(self, "_repr", None)) is not None:
|
| 303 |
+
return repr_str
|
| 304 |
+
|
| 305 |
+
c = self.__class__.__name__
|
| 306 |
+
|
| 307 |
+
# Use precision+1 digits in exponential notation
|
| 308 |
+
fmt_str = _MACHAR_PARAMS.get(self.dtype.type, {}).get('fmt', '%s')
|
| 309 |
+
if fmt_str != '%s' and hasattr(self, 'max') and hasattr(self, 'min'):
|
| 310 |
+
max_str = (fmt_str % self.max).strip()
|
| 311 |
+
min_str = (fmt_str % self.min).strip()
|
| 312 |
+
else:
|
| 313 |
+
max_str = str(self.max)
|
| 314 |
+
min_str = str(self.min)
|
| 315 |
+
|
| 316 |
+
resolution_str = str(self.resolution)
|
| 317 |
+
|
| 318 |
+
repr_str = (f"{c}(resolution={resolution_str}, min={min_str},"
|
| 319 |
+
f" max={max_str}, dtype={self.dtype})")
|
| 320 |
+
self._repr = repr_str
|
| 321 |
+
return repr_str
|
| 322 |
+
|
| 323 |
+
@cached_property
|
| 324 |
+
def tiny(self):
|
| 325 |
+
"""Return the value for tiny, alias of smallest_normal.
|
| 326 |
+
|
| 327 |
+
Returns
|
| 328 |
+
-------
|
| 329 |
+
tiny : float
|
| 330 |
+
Value for the smallest normal, alias of smallest_normal.
|
| 331 |
+
|
| 332 |
+
Warns
|
| 333 |
+
-----
|
| 334 |
+
UserWarning
|
| 335 |
+
If the calculated value for the smallest normal is requested for
|
| 336 |
+
double-double.
|
| 337 |
+
"""
|
| 338 |
+
return self.smallest_normal
|
| 339 |
+
|
| 340 |
+
|
| 341 |
+
@set_module('numpy')
|
| 342 |
+
class iinfo:
|
| 343 |
+
"""
|
| 344 |
+
iinfo(type)
|
| 345 |
+
|
| 346 |
+
Machine limits for integer types.
|
| 347 |
+
|
| 348 |
+
Attributes
|
| 349 |
+
----------
|
| 350 |
+
bits : int
|
| 351 |
+
The number of bits occupied by the type.
|
| 352 |
+
dtype : dtype
|
| 353 |
+
Returns the dtype for which `iinfo` returns information.
|
| 354 |
+
min : int
|
| 355 |
+
The smallest integer expressible by the type.
|
| 356 |
+
max : int
|
| 357 |
+
The largest integer expressible by the type.
|
| 358 |
+
|
| 359 |
+
Parameters
|
| 360 |
+
----------
|
| 361 |
+
int_type : integer type, dtype, or instance
|
| 362 |
+
The kind of integer data type to get information about.
|
| 363 |
+
|
| 364 |
+
See Also
|
| 365 |
+
--------
|
| 366 |
+
finfo : The equivalent for floating point data types.
|
| 367 |
+
|
| 368 |
+
Examples
|
| 369 |
+
--------
|
| 370 |
+
With types:
|
| 371 |
+
|
| 372 |
+
>>> import numpy as np
|
| 373 |
+
>>> ii16 = np.iinfo(np.int16)
|
| 374 |
+
>>> ii16.min
|
| 375 |
+
-32768
|
| 376 |
+
>>> ii16.max
|
| 377 |
+
32767
|
| 378 |
+
>>> ii32 = np.iinfo(np.int32)
|
| 379 |
+
>>> ii32.min
|
| 380 |
+
-2147483648
|
| 381 |
+
>>> ii32.max
|
| 382 |
+
2147483647
|
| 383 |
+
|
| 384 |
+
With instances:
|
| 385 |
+
|
| 386 |
+
>>> ii32 = np.iinfo(np.int32(10))
|
| 387 |
+
>>> ii32.min
|
| 388 |
+
-2147483648
|
| 389 |
+
>>> ii32.max
|
| 390 |
+
2147483647
|
| 391 |
+
|
| 392 |
+
"""
|
| 393 |
+
|
| 394 |
+
_min_vals = {} # noqa: RUF012
|
| 395 |
+
_max_vals = {} # noqa: RUF012
|
| 396 |
+
|
| 397 |
+
__class_getitem__ = classmethod(types.GenericAlias)
|
| 398 |
+
|
| 399 |
+
def __init__(self, int_type):
|
| 400 |
+
try:
|
| 401 |
+
self.dtype = numeric.dtype(int_type)
|
| 402 |
+
except TypeError:
|
| 403 |
+
self.dtype = numeric.dtype(type(int_type))
|
| 404 |
+
self.kind = self.dtype.kind
|
| 405 |
+
self.bits = self.dtype.itemsize * 8
|
| 406 |
+
self.key = f"{self.kind}{self.bits}"
|
| 407 |
+
if self.kind not in 'iu':
|
| 408 |
+
raise ValueError(f"Invalid integer data type {self.kind!r}.")
|
| 409 |
+
|
| 410 |
+
@property
|
| 411 |
+
def min(self):
|
| 412 |
+
"""Minimum value of given dtype."""
|
| 413 |
+
if self.kind == 'u':
|
| 414 |
+
return 0
|
| 415 |
+
else:
|
| 416 |
+
try:
|
| 417 |
+
val = iinfo._min_vals[self.key]
|
| 418 |
+
except KeyError:
|
| 419 |
+
val = int(-(1 << (self.bits - 1)))
|
| 420 |
+
iinfo._min_vals[self.key] = val
|
| 421 |
+
return val
|
| 422 |
+
|
| 423 |
+
@property
|
| 424 |
+
def max(self):
|
| 425 |
+
"""Maximum value of given dtype."""
|
| 426 |
+
try:
|
| 427 |
+
val = iinfo._max_vals[self.key]
|
| 428 |
+
except KeyError:
|
| 429 |
+
if self.kind == 'u':
|
| 430 |
+
val = int((1 << self.bits) - 1)
|
| 431 |
+
else:
|
| 432 |
+
val = int((1 << (self.bits - 1)) - 1)
|
| 433 |
+
iinfo._max_vals[self.key] = val
|
| 434 |
+
return val
|
| 435 |
+
|
| 436 |
+
def __str__(self):
|
| 437 |
+
"""String representation."""
|
| 438 |
+
fmt = (
|
| 439 |
+
'Machine parameters for %(dtype)s\n'
|
| 440 |
+
'---------------------------------------------------------------\n'
|
| 441 |
+
'min = %(min)s\n'
|
| 442 |
+
'max = %(max)s\n'
|
| 443 |
+
'---------------------------------------------------------------\n'
|
| 444 |
+
)
|
| 445 |
+
return fmt % {'dtype': self.dtype, 'min': self.min, 'max': self.max}
|
| 446 |
+
|
| 447 |
+
def __repr__(self):
|
| 448 |
+
name = self.__class__.__name__
|
| 449 |
+
return f'{name}(min={self.min}, max={self.max}, dtype={self.dtype})'
|
v12x/pylib/numpy/_core/memmap.py
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import operator
|
| 2 |
+
from contextlib import nullcontext
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
from numpy._utils import set_module
|
| 6 |
+
|
| 7 |
+
from .numeric import dtype, ndarray, uint8
|
| 8 |
+
|
| 9 |
+
__all__ = ['memmap']
|
| 10 |
+
|
| 11 |
+
dtypedescr = dtype
|
| 12 |
+
valid_filemodes = ["r", "c", "r+", "w+"]
|
| 13 |
+
writeable_filemodes = ["r+", "w+"]
|
| 14 |
+
|
| 15 |
+
mode_equivalents = {
|
| 16 |
+
"readonly": "r",
|
| 17 |
+
"copyonwrite": "c",
|
| 18 |
+
"readwrite": "r+",
|
| 19 |
+
"write": "w+"
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@set_module('numpy')
|
| 24 |
+
class memmap(ndarray):
|
| 25 |
+
"""Create a memory-map to an array stored in a *binary* file on disk.
|
| 26 |
+
|
| 27 |
+
Memory-mapped files are used for accessing small segments of large files
|
| 28 |
+
on disk, without reading the entire file into memory. NumPy's
|
| 29 |
+
memmap's are array-like objects. This differs from Python's ``mmap``
|
| 30 |
+
module, which uses file-like objects.
|
| 31 |
+
|
| 32 |
+
This subclass of ndarray has some unpleasant interactions with
|
| 33 |
+
some operations, because it doesn't quite fit properly as a subclass.
|
| 34 |
+
An alternative to using this subclass is to create the ``mmap``
|
| 35 |
+
object yourself, then create an ndarray with ndarray.__new__ directly,
|
| 36 |
+
passing the object created in its 'buffer=' parameter.
|
| 37 |
+
|
| 38 |
+
This class may at some point be turned into a factory function
|
| 39 |
+
which returns a view into an mmap buffer.
|
| 40 |
+
|
| 41 |
+
Flush the memmap instance to write the changes to the file. Currently there
|
| 42 |
+
is no API to close the underlying ``mmap``. It is tricky to ensure the
|
| 43 |
+
resource is actually closed, since it may be shared between different
|
| 44 |
+
memmap instances.
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
Parameters
|
| 48 |
+
----------
|
| 49 |
+
filename : str, file-like object, or pathlib.Path instance
|
| 50 |
+
The file name or file object to be used as the array data buffer.
|
| 51 |
+
dtype : data-type, optional
|
| 52 |
+
The data-type used to interpret the file contents.
|
| 53 |
+
Default is `uint8`.
|
| 54 |
+
mode : {'r+', 'r', 'w+', 'c'}, optional
|
| 55 |
+
The file is opened in this mode:
|
| 56 |
+
|
| 57 |
+
+------+-------------------------------------------------------------+
|
| 58 |
+
| 'r' | Open existing file for reading only. |
|
| 59 |
+
+------+-------------------------------------------------------------+
|
| 60 |
+
| 'r+' | Open existing file for reading and writing. |
|
| 61 |
+
+------+-------------------------------------------------------------+
|
| 62 |
+
| 'w+' | Create or overwrite existing file for reading and writing. |
|
| 63 |
+
| | If ``mode == 'w+'`` then `shape` must also be specified. |
|
| 64 |
+
+------+-------------------------------------------------------------+
|
| 65 |
+
| 'c' | Copy-on-write: assignments affect data in memory, but |
|
| 66 |
+
| | changes are not saved to disk. The file on disk is |
|
| 67 |
+
| | read-only. |
|
| 68 |
+
+------+-------------------------------------------------------------+
|
| 69 |
+
|
| 70 |
+
Default is 'r+'.
|
| 71 |
+
offset : int, optional
|
| 72 |
+
In the file, array data starts at this offset. Since `offset` is
|
| 73 |
+
measured in bytes, it should normally be a multiple of the byte-size
|
| 74 |
+
of `dtype`. When ``mode != 'r'``, even positive offsets beyond end of
|
| 75 |
+
file are valid; The file will be extended to accommodate the
|
| 76 |
+
additional data. By default, ``memmap`` will start at the beginning of
|
| 77 |
+
the file, even if ``filename`` is a file pointer ``fp`` and
|
| 78 |
+
``fp.tell() != 0``.
|
| 79 |
+
shape : int or sequence of ints, optional
|
| 80 |
+
The desired shape of the array. If ``mode == 'r'`` and the number
|
| 81 |
+
of remaining bytes after `offset` is not a multiple of the byte-size
|
| 82 |
+
of `dtype`, you must specify `shape`. By default, the returned array
|
| 83 |
+
will be 1-D with the number of elements determined by file size
|
| 84 |
+
and data-type.
|
| 85 |
+
|
| 86 |
+
.. versionchanged:: 2.0
|
| 87 |
+
The shape parameter can now be any integer sequence type, previously
|
| 88 |
+
types were limited to tuple and int.
|
| 89 |
+
|
| 90 |
+
order : {'C', 'F'}, optional
|
| 91 |
+
Specify the order of the ndarray memory layout:
|
| 92 |
+
:term:`row-major`, C-style or :term:`column-major`,
|
| 93 |
+
Fortran-style. This only has an effect if the shape is
|
| 94 |
+
greater than 1-D. The default order is 'C'.
|
| 95 |
+
|
| 96 |
+
Attributes
|
| 97 |
+
----------
|
| 98 |
+
filename : str or pathlib.Path instance
|
| 99 |
+
Path to the mapped file.
|
| 100 |
+
offset : int
|
| 101 |
+
Offset position in the file.
|
| 102 |
+
mode : str
|
| 103 |
+
File mode.
|
| 104 |
+
|
| 105 |
+
Methods
|
| 106 |
+
-------
|
| 107 |
+
flush
|
| 108 |
+
Flush any changes in memory to file on disk.
|
| 109 |
+
When you delete a memmap object, flush is called first to write
|
| 110 |
+
changes to disk.
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
See also
|
| 114 |
+
--------
|
| 115 |
+
lib.format.open_memmap : Create or load a memory-mapped ``.npy`` file.
|
| 116 |
+
|
| 117 |
+
Notes
|
| 118 |
+
-----
|
| 119 |
+
The memmap object can be used anywhere an ndarray is accepted.
|
| 120 |
+
Given a memmap ``fp``, ``isinstance(fp, numpy.ndarray)`` returns
|
| 121 |
+
``True``.
|
| 122 |
+
|
| 123 |
+
Memory-mapped files cannot be larger than 2GB on 32-bit systems.
|
| 124 |
+
|
| 125 |
+
When a memmap causes a file to be created or extended beyond its
|
| 126 |
+
current size in the filesystem, the contents of the new part are
|
| 127 |
+
unspecified. On systems with POSIX filesystem semantics, the extended
|
| 128 |
+
part will be filled with zero bytes.
|
| 129 |
+
|
| 130 |
+
Examples
|
| 131 |
+
--------
|
| 132 |
+
>>> import numpy as np
|
| 133 |
+
>>> data = np.arange(12, dtype=np.float32).reshape((3, 4))
|
| 134 |
+
|
| 135 |
+
This example uses a temporary file so that doctest doesn't write
|
| 136 |
+
files to your directory. You would use a 'normal' filename.
|
| 137 |
+
|
| 138 |
+
>>> from tempfile import mkdtemp
|
| 139 |
+
>>> import os.path as path
|
| 140 |
+
>>> filename = path.join(mkdtemp(), 'newfile.dat')
|
| 141 |
+
|
| 142 |
+
Create a memmap with dtype and shape that matches our data:
|
| 143 |
+
|
| 144 |
+
>>> fp = np.memmap(filename, dtype=np.float32, mode='w+', shape=(3,4))
|
| 145 |
+
>>> fp
|
| 146 |
+
memmap([[0., 0., 0., 0.],
|
| 147 |
+
[0., 0., 0., 0.],
|
| 148 |
+
[0., 0., 0., 0.]], dtype=float32)
|
| 149 |
+
|
| 150 |
+
Write data to memmap array:
|
| 151 |
+
|
| 152 |
+
>>> fp[:] = data[:]
|
| 153 |
+
>>> fp
|
| 154 |
+
memmap([[ 0., 1., 2., 3.],
|
| 155 |
+
[ 4., 5., 6., 7.],
|
| 156 |
+
[ 8., 9., 10., 11.]], dtype=float32)
|
| 157 |
+
|
| 158 |
+
>>> fp.filename == path.abspath(filename)
|
| 159 |
+
True
|
| 160 |
+
|
| 161 |
+
Flushes memory changes to disk in order to read them back
|
| 162 |
+
|
| 163 |
+
>>> fp.flush()
|
| 164 |
+
|
| 165 |
+
Load the memmap and verify data was stored:
|
| 166 |
+
|
| 167 |
+
>>> newfp = np.memmap(filename, dtype=np.float32, mode='r', shape=(3,4))
|
| 168 |
+
>>> newfp
|
| 169 |
+
memmap([[ 0., 1., 2., 3.],
|
| 170 |
+
[ 4., 5., 6., 7.],
|
| 171 |
+
[ 8., 9., 10., 11.]], dtype=float32)
|
| 172 |
+
|
| 173 |
+
Read-only memmap:
|
| 174 |
+
|
| 175 |
+
>>> fpr = np.memmap(filename, dtype=np.float32, mode='r', shape=(3,4))
|
| 176 |
+
>>> fpr.flags.writeable
|
| 177 |
+
False
|
| 178 |
+
|
| 179 |
+
Copy-on-write memmap:
|
| 180 |
+
|
| 181 |
+
>>> fpc = np.memmap(filename, dtype=np.float32, mode='c', shape=(3,4))
|
| 182 |
+
>>> fpc.flags.writeable
|
| 183 |
+
True
|
| 184 |
+
|
| 185 |
+
It's possible to assign to copy-on-write array, but values are only
|
| 186 |
+
written into the memory copy of the array, and not written to disk:
|
| 187 |
+
|
| 188 |
+
>>> fpc
|
| 189 |
+
memmap([[ 0., 1., 2., 3.],
|
| 190 |
+
[ 4., 5., 6., 7.],
|
| 191 |
+
[ 8., 9., 10., 11.]], dtype=float32)
|
| 192 |
+
>>> fpc[0,:] = 0
|
| 193 |
+
>>> fpc
|
| 194 |
+
memmap([[ 0., 0., 0., 0.],
|
| 195 |
+
[ 4., 5., 6., 7.],
|
| 196 |
+
[ 8., 9., 10., 11.]], dtype=float32)
|
| 197 |
+
|
| 198 |
+
File on disk is unchanged:
|
| 199 |
+
|
| 200 |
+
>>> fpr
|
| 201 |
+
memmap([[ 0., 1., 2., 3.],
|
| 202 |
+
[ 4., 5., 6., 7.],
|
| 203 |
+
[ 8., 9., 10., 11.]], dtype=float32)
|
| 204 |
+
|
| 205 |
+
Offset into a memmap:
|
| 206 |
+
|
| 207 |
+
>>> fpo = np.memmap(filename, dtype=np.float32, mode='r', offset=16)
|
| 208 |
+
>>> fpo
|
| 209 |
+
memmap([ 4., 5., 6., 7., 8., 9., 10., 11.], dtype=float32)
|
| 210 |
+
|
| 211 |
+
"""
|
| 212 |
+
|
| 213 |
+
__array_priority__ = -100.0
|
| 214 |
+
|
| 215 |
+
def __new__(cls, filename, dtype=uint8, mode='r+', offset=0,
|
| 216 |
+
shape=None, order='C'):
|
| 217 |
+
# Import here to minimize 'import numpy' overhead
|
| 218 |
+
import mmap
|
| 219 |
+
import os.path
|
| 220 |
+
try:
|
| 221 |
+
mode = mode_equivalents[mode]
|
| 222 |
+
except KeyError as e:
|
| 223 |
+
if mode not in valid_filemodes:
|
| 224 |
+
all_modes = valid_filemodes + list(mode_equivalents.keys())
|
| 225 |
+
raise ValueError(
|
| 226 |
+
f"mode must be one of {all_modes!r} (got {mode!r})"
|
| 227 |
+
) from None
|
| 228 |
+
|
| 229 |
+
if mode == 'w+' and shape is None:
|
| 230 |
+
raise ValueError("shape must be given if mode == 'w+'")
|
| 231 |
+
|
| 232 |
+
if hasattr(filename, 'read'):
|
| 233 |
+
f_ctx = nullcontext(filename)
|
| 234 |
+
else:
|
| 235 |
+
f_ctx = open(
|
| 236 |
+
os.fspath(filename),
|
| 237 |
+
('r' if mode == 'c' else mode) + 'b'
|
| 238 |
+
)
|
| 239 |
+
|
| 240 |
+
with f_ctx as fid:
|
| 241 |
+
fid.seek(0, 2)
|
| 242 |
+
flen = fid.tell()
|
| 243 |
+
descr = dtypedescr(dtype)
|
| 244 |
+
_dbytes = descr.itemsize
|
| 245 |
+
|
| 246 |
+
if shape is None:
|
| 247 |
+
bytes = flen - offset
|
| 248 |
+
if bytes % _dbytes:
|
| 249 |
+
raise ValueError("Size of available data is not a "
|
| 250 |
+
"multiple of the data-type size.")
|
| 251 |
+
size = bytes // _dbytes
|
| 252 |
+
shape = (size,)
|
| 253 |
+
else:
|
| 254 |
+
if not isinstance(shape, (tuple, list)):
|
| 255 |
+
try:
|
| 256 |
+
shape = [operator.index(shape)]
|
| 257 |
+
except TypeError:
|
| 258 |
+
pass
|
| 259 |
+
shape = tuple(shape)
|
| 260 |
+
size = np.intp(1) # avoid overflows
|
| 261 |
+
for k in shape:
|
| 262 |
+
size *= k
|
| 263 |
+
|
| 264 |
+
bytes = int(offset + size * _dbytes)
|
| 265 |
+
|
| 266 |
+
if mode in ('w+', 'r+'):
|
| 267 |
+
# gh-27723
|
| 268 |
+
# if bytes == 0, we write out 1 byte to allow empty memmap.
|
| 269 |
+
bytes = max(bytes, 1)
|
| 270 |
+
if flen < bytes:
|
| 271 |
+
fid.seek(bytes - 1, 0)
|
| 272 |
+
fid.write(b'\0')
|
| 273 |
+
fid.flush()
|
| 274 |
+
|
| 275 |
+
if mode == 'c':
|
| 276 |
+
acc = mmap.ACCESS_COPY
|
| 277 |
+
elif mode == 'r':
|
| 278 |
+
acc = mmap.ACCESS_READ
|
| 279 |
+
else:
|
| 280 |
+
acc = mmap.ACCESS_WRITE
|
| 281 |
+
|
| 282 |
+
start = offset - offset % mmap.ALLOCATIONGRANULARITY
|
| 283 |
+
bytes -= start
|
| 284 |
+
# bytes == 0 is problematic as in mmap length=0 maps the full file.
|
| 285 |
+
# See PR gh-27723 for a more detailed explanation.
|
| 286 |
+
if bytes == 0 and start > 0:
|
| 287 |
+
bytes += mmap.ALLOCATIONGRANULARITY
|
| 288 |
+
start -= mmap.ALLOCATIONGRANULARITY
|
| 289 |
+
array_offset = offset - start
|
| 290 |
+
mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
|
| 291 |
+
|
| 292 |
+
self = ndarray.__new__(cls, shape, dtype=descr, buffer=mm,
|
| 293 |
+
offset=array_offset, order=order)
|
| 294 |
+
self._mmap = mm
|
| 295 |
+
self.offset = offset
|
| 296 |
+
self.mode = mode
|
| 297 |
+
|
| 298 |
+
if isinstance(filename, os.PathLike):
|
| 299 |
+
# special case - if we were constructed with a pathlib.path,
|
| 300 |
+
# then filename is a path object, not a string
|
| 301 |
+
self.filename = filename.resolve()
|
| 302 |
+
elif hasattr(fid, "name") and isinstance(fid.name, str):
|
| 303 |
+
# py3 returns int for TemporaryFile().name
|
| 304 |
+
self.filename = os.path.abspath(fid.name)
|
| 305 |
+
# same as memmap copies (e.g. memmap + 1)
|
| 306 |
+
else:
|
| 307 |
+
self.filename = None
|
| 308 |
+
|
| 309 |
+
return self
|
| 310 |
+
|
| 311 |
+
def __array_finalize__(self, obj):
|
| 312 |
+
if hasattr(obj, '_mmap') and np.may_share_memory(self, obj):
|
| 313 |
+
self._mmap = obj._mmap
|
| 314 |
+
self.filename = obj.filename
|
| 315 |
+
self.offset = obj.offset
|
| 316 |
+
self.mode = obj.mode
|
| 317 |
+
else:
|
| 318 |
+
self._mmap = None
|
| 319 |
+
self.filename = None
|
| 320 |
+
self.offset = None
|
| 321 |
+
self.mode = None
|
| 322 |
+
|
| 323 |
+
def flush(self):
|
| 324 |
+
"""
|
| 325 |
+
Write any changes in the array to the file on disk.
|
| 326 |
+
|
| 327 |
+
For further information, see `memmap`.
|
| 328 |
+
|
| 329 |
+
Parameters
|
| 330 |
+
----------
|
| 331 |
+
None
|
| 332 |
+
|
| 333 |
+
See Also
|
| 334 |
+
--------
|
| 335 |
+
memmap
|
| 336 |
+
|
| 337 |
+
"""
|
| 338 |
+
if self.base is not None and hasattr(self.base, 'flush'):
|
| 339 |
+
self.base.flush()
|
| 340 |
+
|
| 341 |
+
def __array_wrap__(self, arr, context=None, return_scalar=False):
|
| 342 |
+
arr = super().__array_wrap__(arr, context)
|
| 343 |
+
|
| 344 |
+
# Return a memmap if a memmap was given as the output of the
|
| 345 |
+
# ufunc. Leave the arr class unchanged if self is not a memmap
|
| 346 |
+
# to keep original memmap subclasses behavior
|
| 347 |
+
if self is arr or type(self) is not memmap:
|
| 348 |
+
return arr
|
| 349 |
+
|
| 350 |
+
# Return scalar instead of 0d memmap, e.g. for np.sum with
|
| 351 |
+
# axis=None (note that subclasses will not reach here)
|
| 352 |
+
if return_scalar:
|
| 353 |
+
return arr[()]
|
| 354 |
+
|
| 355 |
+
# Return ndarray otherwise
|
| 356 |
+
return arr.view(np.ndarray)
|
| 357 |
+
|
| 358 |
+
def __getitem__(self, index):
|
| 359 |
+
res = super().__getitem__(index)
|
| 360 |
+
if type(res) is memmap and res._mmap is None:
|
| 361 |
+
return res.view(type=ndarray)
|
| 362 |
+
return res
|
v12x/pylib/numpy/_core/multiarray.py
ADDED
|
@@ -0,0 +1,1743 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Create the numpy._core.multiarray namespace for backward compatibility.
|
| 3 |
+
In v1.16 the multiarray and umath c-extension modules were merged into
|
| 4 |
+
a single _multiarray_umath extension module. So we replicate the old
|
| 5 |
+
namespace by importing from the extension module.
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import functools
|
| 10 |
+
|
| 11 |
+
from . import _multiarray_umath, overrides
|
| 12 |
+
from ._multiarray_umath import *
|
| 13 |
+
|
| 14 |
+
# These imports are needed for backward compatibility,
|
| 15 |
+
# do not change them. issue gh-15518
|
| 16 |
+
# _get_ndarray_c_version is semi-public, on purpose not added to __all__
|
| 17 |
+
from ._multiarray_umath import ( # noqa: F401
|
| 18 |
+
_ARRAY_API,
|
| 19 |
+
_flagdict,
|
| 20 |
+
_get_madvise_hugepage,
|
| 21 |
+
_get_ndarray_c_version,
|
| 22 |
+
_monotonicity,
|
| 23 |
+
_place,
|
| 24 |
+
_reconstruct,
|
| 25 |
+
_set_madvise_hugepage,
|
| 26 |
+
_vec_string,
|
| 27 |
+
from_dlpack,
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
__all__ = [
|
| 31 |
+
'_ARRAY_API', 'ALLOW_THREADS', 'BUFSIZE', 'CLIP', 'DATETIMEUNITS',
|
| 32 |
+
'ITEM_HASOBJECT', 'ITEM_IS_POINTER', 'LIST_PICKLE', 'MAXDIMS',
|
| 33 |
+
'MAY_SHARE_BOUNDS', 'MAY_SHARE_EXACT', 'NEEDS_INIT', 'NEEDS_PYAPI',
|
| 34 |
+
'RAISE', 'USE_GETITEM', 'USE_SETITEM', 'WRAP',
|
| 35 |
+
'_flagdict', 'from_dlpack', '_place', '_reconstruct', '_vec_string',
|
| 36 |
+
'_monotonicity', 'add_docstring', 'arange', 'array', 'asarray',
|
| 37 |
+
'asanyarray', 'ascontiguousarray', 'asfortranarray', 'bincount',
|
| 38 |
+
'broadcast', 'busday_count', 'busday_offset', 'busdaycalendar', 'can_cast',
|
| 39 |
+
'compare_chararrays', 'concatenate', 'copyto', 'correlate', 'correlate2',
|
| 40 |
+
'count_nonzero', 'c_einsum', 'datetime_as_string', 'datetime_data',
|
| 41 |
+
'dot', 'dragon4_positional', 'dragon4_scientific', 'dtype',
|
| 42 |
+
'empty', 'empty_like', 'error', 'flagsobj', 'flatiter', 'format_longfloat',
|
| 43 |
+
'frombuffer', 'fromfile', 'fromiter', 'fromstring',
|
| 44 |
+
'get_handler_name', 'get_handler_version', 'inner', 'interp',
|
| 45 |
+
'interp_complex', 'is_busday', 'lexsort', 'matmul', 'vecdot',
|
| 46 |
+
'may_share_memory', 'min_scalar_type', 'ndarray', 'nditer', 'nested_iters',
|
| 47 |
+
'normalize_axis_index', 'packbits', 'promote_types', 'putmask',
|
| 48 |
+
'ravel_multi_index', 'result_type', 'scalar', 'set_datetimeparse_function',
|
| 49 |
+
'set_typeDict', 'shares_memory', 'typeinfo',
|
| 50 |
+
'unpackbits', 'unravel_index', 'vdot', 'where', 'zeros']
|
| 51 |
+
|
| 52 |
+
# For backward compatibility, make sure pickle imports
|
| 53 |
+
# these functions from here
|
| 54 |
+
_reconstruct.__module__ = 'numpy._core.multiarray'
|
| 55 |
+
scalar.__module__ = 'numpy._core.multiarray'
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
from_dlpack.__module__ = 'numpy'
|
| 59 |
+
arange.__module__ = 'numpy'
|
| 60 |
+
array.__module__ = 'numpy'
|
| 61 |
+
asarray.__module__ = 'numpy'
|
| 62 |
+
asanyarray.__module__ = 'numpy'
|
| 63 |
+
ascontiguousarray.__module__ = 'numpy'
|
| 64 |
+
asfortranarray.__module__ = 'numpy'
|
| 65 |
+
datetime_data.__module__ = 'numpy'
|
| 66 |
+
empty.__module__ = 'numpy'
|
| 67 |
+
frombuffer.__module__ = 'numpy'
|
| 68 |
+
fromfile.__module__ = 'numpy'
|
| 69 |
+
fromiter.__module__ = 'numpy'
|
| 70 |
+
frompyfunc.__module__ = 'numpy'
|
| 71 |
+
fromstring.__module__ = 'numpy'
|
| 72 |
+
may_share_memory.__module__ = 'numpy'
|
| 73 |
+
nested_iters.__module__ = 'numpy'
|
| 74 |
+
promote_types.__module__ = 'numpy'
|
| 75 |
+
zeros.__module__ = 'numpy'
|
| 76 |
+
normalize_axis_index.__module__ = 'numpy.lib.array_utils'
|
| 77 |
+
add_docstring.__module__ = 'numpy.lib'
|
| 78 |
+
compare_chararrays.__module__ = 'numpy.char'
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def _override___module__():
|
| 82 |
+
namespace_names = globals()
|
| 83 |
+
for ufunc_name in [
|
| 84 |
+
'absolute', 'arccos', 'arccosh', 'add', 'arcsin', 'arcsinh', 'arctan',
|
| 85 |
+
'arctan2', 'arctanh', 'bitwise_and', 'bitwise_count', 'invert',
|
| 86 |
+
'left_shift', 'bitwise_or', 'right_shift', 'bitwise_xor', 'cbrt',
|
| 87 |
+
'ceil', 'conjugate', 'copysign', 'cos', 'cosh', 'deg2rad', 'degrees',
|
| 88 |
+
'divide', 'divmod', 'equal', 'exp', 'exp2', 'expm1', 'fabs',
|
| 89 |
+
'float_power', 'floor', 'floor_divide', 'fmax', 'fmin', 'fmod',
|
| 90 |
+
'frexp', 'gcd', 'greater', 'greater_equal', 'heaviside', 'hypot',
|
| 91 |
+
'isfinite', 'isinf', 'isnan', 'isnat', 'lcm', 'ldexp', 'less',
|
| 92 |
+
'less_equal', 'log', 'log10', 'log1p', 'log2', 'logaddexp',
|
| 93 |
+
'logaddexp2', 'logical_and', 'logical_not', 'logical_or',
|
| 94 |
+
'logical_xor', 'matmul', 'matvec', 'maximum', 'minimum', 'remainder',
|
| 95 |
+
'modf', 'multiply', 'negative', 'nextafter', 'not_equal', 'positive',
|
| 96 |
+
'power', 'rad2deg', 'radians', 'reciprocal', 'rint', 'sign', 'signbit',
|
| 97 |
+
'sin', 'sinh', 'spacing', 'sqrt', 'square', 'subtract', 'tan', 'tanh',
|
| 98 |
+
'trunc', 'vecdot', 'vecmat',
|
| 99 |
+
]:
|
| 100 |
+
ufunc = namespace_names[ufunc_name]
|
| 101 |
+
ufunc.__module__ = "numpy"
|
| 102 |
+
ufunc.__qualname__ = ufunc_name
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
_override___module__()
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# We can't verify dispatcher signatures because NumPy's C functions don't
|
| 109 |
+
# support introspection.
|
| 110 |
+
array_function_from_c_func_and_dispatcher = functools.partial(
|
| 111 |
+
overrides.array_function_from_dispatcher,
|
| 112 |
+
module='numpy', docs_from_dispatcher=True, verify=False)
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.empty_like)
|
| 116 |
+
def empty_like(
|
| 117 |
+
prototype, dtype=None, order="K", subok=True, shape=None, *, device=None
|
| 118 |
+
):
|
| 119 |
+
"""
|
| 120 |
+
empty_like(
|
| 121 |
+
prototype,
|
| 122 |
+
/,
|
| 123 |
+
dtype=None,
|
| 124 |
+
order='K',
|
| 125 |
+
subok=True,
|
| 126 |
+
shape=None,
|
| 127 |
+
*,
|
| 128 |
+
device=None,
|
| 129 |
+
)
|
| 130 |
+
--
|
| 131 |
+
|
| 132 |
+
Return a new array with the same shape and type as a given array.
|
| 133 |
+
|
| 134 |
+
Parameters
|
| 135 |
+
----------
|
| 136 |
+
prototype : array_like
|
| 137 |
+
The shape and data-type of `prototype` define these same attributes
|
| 138 |
+
of the returned array.
|
| 139 |
+
dtype : data-type, optional
|
| 140 |
+
Overrides the data type of the result.
|
| 141 |
+
order : {'C', 'F', 'A', or 'K'}, optional
|
| 142 |
+
Overrides the memory layout of the result. 'C' means C-order,
|
| 143 |
+
'F' means F-order, 'A' means 'F' if `prototype` is Fortran
|
| 144 |
+
contiguous, 'C' otherwise. 'K' means match the layout of `prototype`
|
| 145 |
+
as closely as possible.
|
| 146 |
+
subok : bool, optional.
|
| 147 |
+
If True, then the newly created array will use the sub-class
|
| 148 |
+
type of `prototype`, otherwise it will be a base-class array. Defaults
|
| 149 |
+
to True.
|
| 150 |
+
shape : int or sequence of ints, optional.
|
| 151 |
+
Overrides the shape of the result. If order='K' and the number of
|
| 152 |
+
dimensions is unchanged, will try to keep order, otherwise,
|
| 153 |
+
order='C' is implied.
|
| 154 |
+
device : str, optional
|
| 155 |
+
The device on which to place the created array. Default: None.
|
| 156 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 157 |
+
|
| 158 |
+
.. versionadded:: 2.0.0
|
| 159 |
+
|
| 160 |
+
Returns
|
| 161 |
+
-------
|
| 162 |
+
out : ndarray
|
| 163 |
+
Array of uninitialized (arbitrary) data with the same
|
| 164 |
+
shape and type as `prototype`.
|
| 165 |
+
|
| 166 |
+
See Also
|
| 167 |
+
--------
|
| 168 |
+
ones_like : Return an array of ones with shape and type of input.
|
| 169 |
+
zeros_like : Return an array of zeros with shape and type of input.
|
| 170 |
+
full_like : Return a new array with shape of input filled with value.
|
| 171 |
+
empty : Return a new uninitialized array.
|
| 172 |
+
|
| 173 |
+
Notes
|
| 174 |
+
-----
|
| 175 |
+
Unlike other array creation functions (e.g. `zeros_like`, `ones_like`,
|
| 176 |
+
`full_like`), `empty_like` does not initialize the values of the array,
|
| 177 |
+
and may therefore be marginally faster. However, the values stored in the
|
| 178 |
+
newly allocated array are arbitrary. For reproducible behavior, be sure
|
| 179 |
+
to set each element of the array before reading.
|
| 180 |
+
|
| 181 |
+
Examples
|
| 182 |
+
--------
|
| 183 |
+
>>> import numpy as np
|
| 184 |
+
>>> a = ([1,2,3], [4,5,6]) # a is array-like
|
| 185 |
+
>>> np.empty_like(a)
|
| 186 |
+
array([[-1073741821, -1073741821, 3], # uninitialized
|
| 187 |
+
[ 0, 0, -1073741821]])
|
| 188 |
+
>>> a = np.array([[1., 2., 3.],[4.,5.,6.]])
|
| 189 |
+
>>> np.empty_like(a)
|
| 190 |
+
array([[ -2.00000715e+000, 1.48219694e-323, -2.00000572e+000], # uninitialized
|
| 191 |
+
[ 4.38791518e-305, -2.00000715e+000, 4.17269252e-309]])
|
| 192 |
+
|
| 193 |
+
"""
|
| 194 |
+
return (prototype,)
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.concatenate)
|
| 198 |
+
def concatenate(arrays, axis=0, out=None, *, dtype=None, casting="same_kind"):
|
| 199 |
+
"""
|
| 200 |
+
concatenate(
|
| 201 |
+
arrays,
|
| 202 |
+
/,
|
| 203 |
+
axis=0,
|
| 204 |
+
out=None,
|
| 205 |
+
*,
|
| 206 |
+
dtype=None,
|
| 207 |
+
casting="same_kind",
|
| 208 |
+
)
|
| 209 |
+
--
|
| 210 |
+
|
| 211 |
+
Join a sequence of arrays along an existing axis.
|
| 212 |
+
|
| 213 |
+
.. versionadded:: 2.0
|
| 214 |
+
``numpy.concat`` added as a shorthand for ``numpy.concatenate``.
|
| 215 |
+
|
| 216 |
+
Parameters
|
| 217 |
+
----------
|
| 218 |
+
a1, a2, ... : sequence of array_like
|
| 219 |
+
The arrays must have the same shape, except in the dimension
|
| 220 |
+
corresponding to `axis` (the first, by default).
|
| 221 |
+
axis : int, optional
|
| 222 |
+
The axis along which the arrays will be joined. If axis is None,
|
| 223 |
+
arrays are flattened before use. Default is 0.
|
| 224 |
+
out : ndarray, optional
|
| 225 |
+
If provided, the destination to place the result. The shape must be
|
| 226 |
+
correct, matching that of what concatenate would have returned if no
|
| 227 |
+
out argument were specified.
|
| 228 |
+
dtype : str or dtype
|
| 229 |
+
If provided, the destination array will have this dtype. Cannot be
|
| 230 |
+
provided together with `out`.
|
| 231 |
+
|
| 232 |
+
.. versionadded:: 1.20.0
|
| 233 |
+
|
| 234 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
|
| 235 |
+
Controls what kind of data casting may occur. Defaults to 'same_kind'.
|
| 236 |
+
For a description of the options, please see :term:`casting`.
|
| 237 |
+
|
| 238 |
+
.. versionadded:: 1.20.0
|
| 239 |
+
|
| 240 |
+
Returns
|
| 241 |
+
-------
|
| 242 |
+
res : ndarray
|
| 243 |
+
The concatenated array.
|
| 244 |
+
|
| 245 |
+
See Also
|
| 246 |
+
--------
|
| 247 |
+
ma.concatenate : Concatenate function that preserves input masks.
|
| 248 |
+
array_split : Split an array into multiple sub-arrays of equal or
|
| 249 |
+
near-equal size.
|
| 250 |
+
split : Split array into a list of multiple sub-arrays of equal size.
|
| 251 |
+
hsplit : Split array into multiple sub-arrays horizontally (column wise).
|
| 252 |
+
vsplit : Split array into multiple sub-arrays vertically (row wise).
|
| 253 |
+
dsplit : Split array into multiple sub-arrays along the 3rd axis (depth).
|
| 254 |
+
stack : Stack a sequence of arrays along a new axis.
|
| 255 |
+
block : Assemble arrays from blocks.
|
| 256 |
+
hstack : Stack arrays in sequence horizontally (column wise).
|
| 257 |
+
vstack : Stack arrays in sequence vertically (row wise).
|
| 258 |
+
dstack : Stack arrays in sequence depth wise (along third dimension).
|
| 259 |
+
column_stack : Stack 1-D arrays as columns into a 2-D array.
|
| 260 |
+
|
| 261 |
+
Notes
|
| 262 |
+
-----
|
| 263 |
+
When one or more of the arrays to be concatenated is a MaskedArray,
|
| 264 |
+
this function will return a MaskedArray object instead of an ndarray,
|
| 265 |
+
but the input masks are *not* preserved. In cases where a MaskedArray
|
| 266 |
+
is expected as input, use the ma.concatenate function from the masked
|
| 267 |
+
array module instead.
|
| 268 |
+
|
| 269 |
+
Examples
|
| 270 |
+
--------
|
| 271 |
+
>>> import numpy as np
|
| 272 |
+
>>> a = np.array([[1, 2], [3, 4]])
|
| 273 |
+
>>> b = np.array([[5, 6]])
|
| 274 |
+
>>> np.concatenate((a, b), axis=0)
|
| 275 |
+
array([[1, 2],
|
| 276 |
+
[3, 4],
|
| 277 |
+
[5, 6]])
|
| 278 |
+
>>> np.concatenate((a, b.T), axis=1)
|
| 279 |
+
array([[1, 2, 5],
|
| 280 |
+
[3, 4, 6]])
|
| 281 |
+
>>> np.concatenate((a, b), axis=None)
|
| 282 |
+
array([1, 2, 3, 4, 5, 6])
|
| 283 |
+
|
| 284 |
+
This function will not preserve masking of MaskedArray inputs.
|
| 285 |
+
|
| 286 |
+
>>> a = np.ma.arange(3)
|
| 287 |
+
>>> a[1] = np.ma.masked
|
| 288 |
+
>>> b = np.arange(2, 5)
|
| 289 |
+
>>> a
|
| 290 |
+
masked_array(data=[0, --, 2],
|
| 291 |
+
mask=[False, True, False],
|
| 292 |
+
fill_value=999999)
|
| 293 |
+
>>> b
|
| 294 |
+
array([2, 3, 4])
|
| 295 |
+
>>> np.concatenate([a, b])
|
| 296 |
+
masked_array(data=[0, 1, 2, 2, 3, 4],
|
| 297 |
+
mask=False,
|
| 298 |
+
fill_value=999999)
|
| 299 |
+
>>> np.ma.concatenate([a, b])
|
| 300 |
+
masked_array(data=[0, --, 2, 2, 3, 4],
|
| 301 |
+
mask=[False, True, False, False, False, False],
|
| 302 |
+
fill_value=999999)
|
| 303 |
+
|
| 304 |
+
"""
|
| 305 |
+
if out is not None:
|
| 306 |
+
# optimize for the typical case where only arrays is provided
|
| 307 |
+
arrays = list(arrays)
|
| 308 |
+
arrays.append(out)
|
| 309 |
+
return arrays
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.inner)
|
| 313 |
+
def inner(a, b, /):
|
| 314 |
+
"""
|
| 315 |
+
inner(a, b, /)
|
| 316 |
+
|
| 317 |
+
Inner product of two arrays.
|
| 318 |
+
|
| 319 |
+
Ordinary inner product of vectors for 1-D arrays (without complex
|
| 320 |
+
conjugation), in higher dimensions a sum product over the last axes.
|
| 321 |
+
|
| 322 |
+
Parameters
|
| 323 |
+
----------
|
| 324 |
+
a, b : array_like
|
| 325 |
+
If `a` and `b` are nonscalar, their last dimensions must match.
|
| 326 |
+
|
| 327 |
+
Returns
|
| 328 |
+
-------
|
| 329 |
+
out : ndarray
|
| 330 |
+
If `a` and `b` are both
|
| 331 |
+
scalars or both 1-D arrays then a scalar is returned; otherwise
|
| 332 |
+
an array is returned.
|
| 333 |
+
``out.shape = (*a.shape[:-1], *b.shape[:-1])``
|
| 334 |
+
|
| 335 |
+
Raises
|
| 336 |
+
------
|
| 337 |
+
ValueError
|
| 338 |
+
If both `a` and `b` are nonscalar and their last dimensions have
|
| 339 |
+
different sizes.
|
| 340 |
+
|
| 341 |
+
See Also
|
| 342 |
+
--------
|
| 343 |
+
tensordot : Sum products over arbitrary axes.
|
| 344 |
+
dot : Generalised matrix product, using second last dimension of `b`.
|
| 345 |
+
vecdot : Vector dot product of two arrays.
|
| 346 |
+
einsum : Einstein summation convention.
|
| 347 |
+
|
| 348 |
+
Notes
|
| 349 |
+
-----
|
| 350 |
+
For vectors (1-D arrays) it computes the ordinary inner-product::
|
| 351 |
+
|
| 352 |
+
np.inner(a, b) = sum(a[:]*b[:])
|
| 353 |
+
|
| 354 |
+
More generally, if ``ndim(a) = r > 0`` and ``ndim(b) = s > 0``::
|
| 355 |
+
|
| 356 |
+
np.inner(a, b) = np.tensordot(a, b, axes=(-1,-1))
|
| 357 |
+
|
| 358 |
+
or explicitly::
|
| 359 |
+
|
| 360 |
+
np.inner(a, b)[i0,...,ir-2,j0,...,js-2]
|
| 361 |
+
= sum(a[i0,...,ir-2,:]*b[j0,...,js-2,:])
|
| 362 |
+
|
| 363 |
+
In addition `a` or `b` may be scalars, in which case::
|
| 364 |
+
|
| 365 |
+
np.inner(a,b) = a*b
|
| 366 |
+
|
| 367 |
+
Examples
|
| 368 |
+
--------
|
| 369 |
+
Ordinary inner product for vectors:
|
| 370 |
+
|
| 371 |
+
>>> import numpy as np
|
| 372 |
+
>>> a = np.array([1,2,3])
|
| 373 |
+
>>> b = np.array([0,1,0])
|
| 374 |
+
>>> np.inner(a, b)
|
| 375 |
+
2
|
| 376 |
+
|
| 377 |
+
Some multidimensional examples:
|
| 378 |
+
|
| 379 |
+
>>> a = np.arange(24).reshape((2,3,4))
|
| 380 |
+
>>> b = np.arange(4)
|
| 381 |
+
>>> c = np.inner(a, b)
|
| 382 |
+
>>> c.shape
|
| 383 |
+
(2, 3)
|
| 384 |
+
>>> c
|
| 385 |
+
array([[ 14, 38, 62],
|
| 386 |
+
[ 86, 110, 134]])
|
| 387 |
+
|
| 388 |
+
>>> a = np.arange(2).reshape((1,1,2))
|
| 389 |
+
>>> b = np.arange(6).reshape((3,2))
|
| 390 |
+
>>> c = np.inner(a, b)
|
| 391 |
+
>>> c.shape
|
| 392 |
+
(1, 1, 3)
|
| 393 |
+
>>> c
|
| 394 |
+
array([[[1, 3, 5]]])
|
| 395 |
+
|
| 396 |
+
An example where `b` is a scalar:
|
| 397 |
+
|
| 398 |
+
>>> np.inner(np.eye(2), 7)
|
| 399 |
+
array([[7., 0.],
|
| 400 |
+
[0., 7.]])
|
| 401 |
+
|
| 402 |
+
"""
|
| 403 |
+
return (a, b)
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.where)
|
| 407 |
+
def where(condition, x=None, y=None, /):
|
| 408 |
+
"""
|
| 409 |
+
where(condition, [x, y], /)
|
| 410 |
+
|
| 411 |
+
Return elements chosen from `x` or `y` depending on `condition`.
|
| 412 |
+
|
| 413 |
+
.. note::
|
| 414 |
+
When only `condition` is provided, this function is a shorthand for
|
| 415 |
+
``np.asarray(condition).nonzero()``. Using `nonzero` directly should be
|
| 416 |
+
preferred, as it behaves correctly for subclasses. The rest of this
|
| 417 |
+
documentation covers only the case where all three arguments are
|
| 418 |
+
provided.
|
| 419 |
+
|
| 420 |
+
Parameters
|
| 421 |
+
----------
|
| 422 |
+
condition : array_like, bool
|
| 423 |
+
Where True, yield `x`, otherwise yield `y`.
|
| 424 |
+
x, y : array_like
|
| 425 |
+
Values from which to choose. `x`, `y` and `condition` need to be
|
| 426 |
+
broadcastable to some shape.
|
| 427 |
+
|
| 428 |
+
Returns
|
| 429 |
+
-------
|
| 430 |
+
out : ndarray
|
| 431 |
+
An array with elements from `x` where `condition` is True, and elements
|
| 432 |
+
from `y` elsewhere.
|
| 433 |
+
|
| 434 |
+
See Also
|
| 435 |
+
--------
|
| 436 |
+
choose
|
| 437 |
+
nonzero : The function that is called when x and y are omitted
|
| 438 |
+
|
| 439 |
+
Notes
|
| 440 |
+
-----
|
| 441 |
+
If all the arrays are 1-D, `where` is equivalent to::
|
| 442 |
+
|
| 443 |
+
[xv if c else yv
|
| 444 |
+
for c, xv, yv in zip(condition, x, y)]
|
| 445 |
+
|
| 446 |
+
Examples
|
| 447 |
+
--------
|
| 448 |
+
>>> import numpy as np
|
| 449 |
+
>>> a = np.arange(10)
|
| 450 |
+
>>> a
|
| 451 |
+
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
| 452 |
+
>>> np.where(a < 5, a, 10*a)
|
| 453 |
+
array([ 0, 1, 2, 3, 4, 50, 60, 70, 80, 90])
|
| 454 |
+
|
| 455 |
+
This can be used on multidimensional arrays too:
|
| 456 |
+
|
| 457 |
+
>>> np.where([[True, False], [True, True]],
|
| 458 |
+
... [[1, 2], [3, 4]],
|
| 459 |
+
... [[9, 8], [7, 6]])
|
| 460 |
+
array([[1, 8],
|
| 461 |
+
[3, 4]])
|
| 462 |
+
|
| 463 |
+
The shapes of x, y, and the condition are broadcast together:
|
| 464 |
+
|
| 465 |
+
>>> x, y = np.ogrid[:3, :4]
|
| 466 |
+
>>> np.where(x < y, x, 10 + y) # both x and 10+y are broadcast
|
| 467 |
+
array([[10, 0, 0, 0],
|
| 468 |
+
[10, 11, 1, 1],
|
| 469 |
+
[10, 11, 12, 2]])
|
| 470 |
+
|
| 471 |
+
>>> a = np.array([[0, 1, 2],
|
| 472 |
+
... [0, 2, 4],
|
| 473 |
+
... [0, 3, 6]])
|
| 474 |
+
>>> np.where(a < 4, a, -1) # -1 is broadcast
|
| 475 |
+
array([[ 0, 1, 2],
|
| 476 |
+
[ 0, 2, -1],
|
| 477 |
+
[ 0, 3, -1]])
|
| 478 |
+
"""
|
| 479 |
+
return (condition, x, y)
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.lexsort)
|
| 483 |
+
def lexsort(keys, axis=-1):
|
| 484 |
+
"""
|
| 485 |
+
lexsort(keys, axis=-1)
|
| 486 |
+
|
| 487 |
+
Perform an indirect stable sort using a sequence of keys.
|
| 488 |
+
|
| 489 |
+
Given multiple sorting keys, lexsort returns an array of integer indices
|
| 490 |
+
that describes the sort order by multiple keys. The last key in the
|
| 491 |
+
sequence is used for the primary sort order, ties are broken by the
|
| 492 |
+
second-to-last key, and so on.
|
| 493 |
+
|
| 494 |
+
Parameters
|
| 495 |
+
----------
|
| 496 |
+
keys : (k, m, n, ...) array-like
|
| 497 |
+
The `k` keys to be sorted. The *last* key (e.g, the last
|
| 498 |
+
row if `keys` is a 2D array) is the primary sort key.
|
| 499 |
+
Each element of `keys` along the zeroth axis must be
|
| 500 |
+
an array-like object of the same shape.
|
| 501 |
+
axis : int, optional
|
| 502 |
+
Axis to be indirectly sorted. By default, sort over the last axis
|
| 503 |
+
of each sequence. Separate slices along `axis` sorted over
|
| 504 |
+
independently; see last example.
|
| 505 |
+
|
| 506 |
+
Returns
|
| 507 |
+
-------
|
| 508 |
+
indices : (m, n, ...) ndarray of ints
|
| 509 |
+
Array of indices that sort the keys along the specified axis.
|
| 510 |
+
|
| 511 |
+
See Also
|
| 512 |
+
--------
|
| 513 |
+
argsort : Indirect sort.
|
| 514 |
+
ndarray.sort : In-place sort.
|
| 515 |
+
sort : Return a sorted copy of an array.
|
| 516 |
+
|
| 517 |
+
Examples
|
| 518 |
+
--------
|
| 519 |
+
Sort names: first by surname, then by name.
|
| 520 |
+
|
| 521 |
+
>>> import numpy as np
|
| 522 |
+
>>> surnames = ('Hertz', 'Galilei', 'Hertz')
|
| 523 |
+
>>> first_names = ('Heinrich', 'Galileo', 'Gustav')
|
| 524 |
+
>>> ind = np.lexsort((first_names, surnames))
|
| 525 |
+
>>> ind
|
| 526 |
+
array([1, 2, 0])
|
| 527 |
+
|
| 528 |
+
>>> [surnames[i] + ", " + first_names[i] for i in ind]
|
| 529 |
+
['Galilei, Galileo', 'Hertz, Gustav', 'Hertz, Heinrich']
|
| 530 |
+
|
| 531 |
+
Sort according to two numerical keys, first by elements
|
| 532 |
+
of ``a``, then breaking ties according to elements of ``b``:
|
| 533 |
+
|
| 534 |
+
>>> a = [1, 5, 1, 4, 3, 4, 4] # First sequence
|
| 535 |
+
>>> b = [9, 4, 0, 4, 0, 2, 1] # Second sequence
|
| 536 |
+
>>> ind = np.lexsort((b, a)) # Sort by `a`, then by `b`
|
| 537 |
+
>>> ind
|
| 538 |
+
array([2, 0, 4, 6, 5, 3, 1])
|
| 539 |
+
>>> [(a[i], b[i]) for i in ind]
|
| 540 |
+
[(1, 0), (1, 9), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4)]
|
| 541 |
+
|
| 542 |
+
Compare against `argsort`, which would sort each key independently.
|
| 543 |
+
|
| 544 |
+
>>> np.argsort((b, a), kind='stable')
|
| 545 |
+
array([[2, 4, 6, 5, 1, 3, 0],
|
| 546 |
+
[0, 2, 4, 3, 5, 6, 1]])
|
| 547 |
+
|
| 548 |
+
To sort lexicographically with `argsort`, we would need to provide a
|
| 549 |
+
structured array.
|
| 550 |
+
|
| 551 |
+
>>> x = np.array([(ai, bi) for ai, bi in zip(a, b)],
|
| 552 |
+
... dtype = np.dtype([('x', int), ('y', int)]))
|
| 553 |
+
>>> np.argsort(x) # or np.argsort(x, order=('x', 'y'))
|
| 554 |
+
array([2, 0, 4, 6, 5, 3, 1])
|
| 555 |
+
|
| 556 |
+
The zeroth axis of `keys` always corresponds with the sequence of keys,
|
| 557 |
+
so 2D arrays are treated just like other sequences of keys.
|
| 558 |
+
|
| 559 |
+
>>> arr = np.asarray([b, a])
|
| 560 |
+
>>> ind2 = np.lexsort(arr)
|
| 561 |
+
>>> np.testing.assert_equal(ind2, ind)
|
| 562 |
+
|
| 563 |
+
Accordingly, the `axis` parameter refers to an axis of *each* key, not of
|
| 564 |
+
the `keys` argument itself. For instance, the array ``arr`` is treated as
|
| 565 |
+
a sequence of two 1-D keys, so specifying ``axis=0`` is equivalent to
|
| 566 |
+
using the default axis, ``axis=-1``.
|
| 567 |
+
|
| 568 |
+
>>> np.testing.assert_equal(np.lexsort(arr, axis=0),
|
| 569 |
+
... np.lexsort(arr, axis=-1))
|
| 570 |
+
|
| 571 |
+
For higher-dimensional arrays, the axis parameter begins to matter. The
|
| 572 |
+
resulting array has the same shape as each key, and the values are what
|
| 573 |
+
we would expect if `lexsort` were performed on corresponding slices
|
| 574 |
+
of the keys independently. For instance,
|
| 575 |
+
|
| 576 |
+
>>> x = [[1, 2, 3, 4],
|
| 577 |
+
... [4, 3, 2, 1],
|
| 578 |
+
... [2, 1, 4, 3]]
|
| 579 |
+
>>> y = [[2, 2, 1, 1],
|
| 580 |
+
... [1, 2, 1, 2],
|
| 581 |
+
... [1, 1, 2, 1]]
|
| 582 |
+
>>> np.lexsort((x, y), axis=1)
|
| 583 |
+
array([[2, 3, 0, 1],
|
| 584 |
+
[2, 0, 3, 1],
|
| 585 |
+
[1, 0, 3, 2]])
|
| 586 |
+
|
| 587 |
+
Each row of the result is what we would expect if we were to perform
|
| 588 |
+
`lexsort` on the corresponding row of the keys:
|
| 589 |
+
|
| 590 |
+
>>> for i in range(3):
|
| 591 |
+
... print(np.lexsort((x[i], y[i])))
|
| 592 |
+
[2 3 0 1]
|
| 593 |
+
[2 0 3 1]
|
| 594 |
+
[1 0 3 2]
|
| 595 |
+
|
| 596 |
+
"""
|
| 597 |
+
if isinstance(keys, tuple):
|
| 598 |
+
return keys
|
| 599 |
+
else:
|
| 600 |
+
return (keys,)
|
| 601 |
+
|
| 602 |
+
|
| 603 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.can_cast)
|
| 604 |
+
def can_cast(from_, to, casting="safe"):
|
| 605 |
+
"""
|
| 606 |
+
can_cast(from_, to, casting='safe')
|
| 607 |
+
|
| 608 |
+
Returns True if cast between data types can occur according to the
|
| 609 |
+
casting rule.
|
| 610 |
+
|
| 611 |
+
Parameters
|
| 612 |
+
----------
|
| 613 |
+
from_ : dtype, dtype specifier, NumPy scalar, or array
|
| 614 |
+
Data type, NumPy scalar, or array to cast from.
|
| 615 |
+
to : dtype or dtype specifier
|
| 616 |
+
Data type to cast to.
|
| 617 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
|
| 618 |
+
Controls what kind of data casting may occur.
|
| 619 |
+
|
| 620 |
+
* 'no' means the data types should not be cast at all.
|
| 621 |
+
* 'equiv' means only byte-order changes are allowed.
|
| 622 |
+
* 'safe' means only casts which can preserve values are allowed.
|
| 623 |
+
* 'same_kind' means only safe casts or casts within a kind,
|
| 624 |
+
like float64 to float32, are allowed.
|
| 625 |
+
* 'unsafe' means any data conversions may be done.
|
| 626 |
+
|
| 627 |
+
Returns
|
| 628 |
+
-------
|
| 629 |
+
out : bool
|
| 630 |
+
True if cast can occur according to the casting rule.
|
| 631 |
+
|
| 632 |
+
Notes
|
| 633 |
+
-----
|
| 634 |
+
.. versionchanged:: 2.0
|
| 635 |
+
This function does not support Python scalars anymore and does not
|
| 636 |
+
apply any value-based logic for 0-D arrays and NumPy scalars.
|
| 637 |
+
|
| 638 |
+
See also
|
| 639 |
+
--------
|
| 640 |
+
dtype, result_type
|
| 641 |
+
|
| 642 |
+
Examples
|
| 643 |
+
--------
|
| 644 |
+
Basic examples
|
| 645 |
+
|
| 646 |
+
>>> import numpy as np
|
| 647 |
+
>>> np.can_cast(np.int32, np.int64)
|
| 648 |
+
True
|
| 649 |
+
>>> np.can_cast(np.float64, complex)
|
| 650 |
+
True
|
| 651 |
+
>>> np.can_cast(complex, float)
|
| 652 |
+
False
|
| 653 |
+
|
| 654 |
+
>>> np.can_cast('i8', 'f8')
|
| 655 |
+
True
|
| 656 |
+
>>> np.can_cast('i8', 'f4')
|
| 657 |
+
False
|
| 658 |
+
>>> np.can_cast('i4', 'S4')
|
| 659 |
+
False
|
| 660 |
+
|
| 661 |
+
"""
|
| 662 |
+
return (from_,)
|
| 663 |
+
|
| 664 |
+
|
| 665 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.min_scalar_type)
|
| 666 |
+
def min_scalar_type(a, /):
|
| 667 |
+
"""
|
| 668 |
+
min_scalar_type(a, /)
|
| 669 |
+
|
| 670 |
+
For scalar ``a``, returns the data type with the smallest size
|
| 671 |
+
and smallest scalar kind which can hold its value. For non-scalar
|
| 672 |
+
array ``a``, returns the vector's dtype unmodified.
|
| 673 |
+
|
| 674 |
+
Floating point values are not demoted to integers,
|
| 675 |
+
and complex values are not demoted to floats.
|
| 676 |
+
|
| 677 |
+
Parameters
|
| 678 |
+
----------
|
| 679 |
+
a : scalar or array_like
|
| 680 |
+
The value whose minimal data type is to be found.
|
| 681 |
+
|
| 682 |
+
Returns
|
| 683 |
+
-------
|
| 684 |
+
out : dtype
|
| 685 |
+
The minimal data type.
|
| 686 |
+
|
| 687 |
+
See Also
|
| 688 |
+
--------
|
| 689 |
+
result_type, promote_types, dtype, can_cast
|
| 690 |
+
|
| 691 |
+
Examples
|
| 692 |
+
--------
|
| 693 |
+
>>> import numpy as np
|
| 694 |
+
>>> np.min_scalar_type(10)
|
| 695 |
+
dtype('uint8')
|
| 696 |
+
|
| 697 |
+
>>> np.min_scalar_type(-260)
|
| 698 |
+
dtype('int16')
|
| 699 |
+
|
| 700 |
+
>>> np.min_scalar_type(3.1)
|
| 701 |
+
dtype('float16')
|
| 702 |
+
|
| 703 |
+
>>> np.min_scalar_type(1e50)
|
| 704 |
+
dtype('float64')
|
| 705 |
+
|
| 706 |
+
>>> np.min_scalar_type(np.arange(4, dtype=np.float64))
|
| 707 |
+
dtype('float64')
|
| 708 |
+
|
| 709 |
+
"""
|
| 710 |
+
return (a,)
|
| 711 |
+
|
| 712 |
+
|
| 713 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.result_type)
|
| 714 |
+
def result_type(*arrays_and_dtypes):
|
| 715 |
+
"""
|
| 716 |
+
result_type(*arrays_and_dtypes)
|
| 717 |
+
|
| 718 |
+
Returns the type that results from applying the NumPy
|
| 719 |
+
:ref:`type promotion <arrays.promotion>` rules to the arguments.
|
| 720 |
+
|
| 721 |
+
Parameters
|
| 722 |
+
----------
|
| 723 |
+
arrays_and_dtypes : list of arrays and dtypes
|
| 724 |
+
The operands of some operation whose result type is needed.
|
| 725 |
+
|
| 726 |
+
Returns
|
| 727 |
+
-------
|
| 728 |
+
out : dtype
|
| 729 |
+
The result type.
|
| 730 |
+
|
| 731 |
+
See also
|
| 732 |
+
--------
|
| 733 |
+
dtype, promote_types, min_scalar_type, can_cast
|
| 734 |
+
|
| 735 |
+
Examples
|
| 736 |
+
--------
|
| 737 |
+
>>> import numpy as np
|
| 738 |
+
>>> np.result_type(3, np.arange(7, dtype=np.int8))
|
| 739 |
+
dtype('int8')
|
| 740 |
+
|
| 741 |
+
>>> np.result_type(np.int32, np.complex64)
|
| 742 |
+
dtype('complex128')
|
| 743 |
+
|
| 744 |
+
>>> np.result_type(3.0, -2)
|
| 745 |
+
dtype('float64')
|
| 746 |
+
|
| 747 |
+
"""
|
| 748 |
+
return arrays_and_dtypes
|
| 749 |
+
|
| 750 |
+
|
| 751 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.dot)
|
| 752 |
+
def dot(a, b, out=None):
|
| 753 |
+
"""
|
| 754 |
+
dot(a, b, out=None)
|
| 755 |
+
|
| 756 |
+
Dot product of two arrays. Specifically,
|
| 757 |
+
|
| 758 |
+
- If both `a` and `b` are 1-D arrays, it is inner product of vectors
|
| 759 |
+
(without complex conjugation).
|
| 760 |
+
|
| 761 |
+
- If both `a` and `b` are 2-D arrays, it is matrix multiplication,
|
| 762 |
+
but using :func:`matmul` or ``a @ b`` is preferred.
|
| 763 |
+
|
| 764 |
+
- If either `a` or `b` is 0-D (scalar), it is equivalent to
|
| 765 |
+
:func:`multiply` and using ``numpy.multiply(a, b)`` or ``a * b`` is
|
| 766 |
+
preferred.
|
| 767 |
+
|
| 768 |
+
- If `a` is an N-D array and `b` is a 1-D array, it is a sum product over
|
| 769 |
+
the last axis of `a` and `b`.
|
| 770 |
+
|
| 771 |
+
- If `a` is an N-D array and `b` is an M-D array (where ``M>=2``), it is a
|
| 772 |
+
sum product over the last axis of `a` and the second-to-last axis of
|
| 773 |
+
`b`::
|
| 774 |
+
|
| 775 |
+
dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
|
| 776 |
+
|
| 777 |
+
It uses an optimized BLAS library when possible (see `numpy.linalg`).
|
| 778 |
+
|
| 779 |
+
Parameters
|
| 780 |
+
----------
|
| 781 |
+
a : array_like
|
| 782 |
+
First argument.
|
| 783 |
+
b : array_like
|
| 784 |
+
Second argument.
|
| 785 |
+
out : ndarray, optional
|
| 786 |
+
Output argument. This must have the exact kind that would be returned
|
| 787 |
+
if it was not used. In particular, it must have the right type, must be
|
| 788 |
+
C-contiguous, and its dtype must be the dtype that would be returned
|
| 789 |
+
for `dot(a,b)`. This is a performance feature. Therefore, if these
|
| 790 |
+
conditions are not met, an exception is raised, instead of attempting
|
| 791 |
+
to be flexible.
|
| 792 |
+
|
| 793 |
+
Returns
|
| 794 |
+
-------
|
| 795 |
+
output : ndarray
|
| 796 |
+
Returns the dot product of `a` and `b`. If `a` and `b` are both
|
| 797 |
+
scalars or both 1-D arrays then a scalar is returned; otherwise
|
| 798 |
+
an array is returned.
|
| 799 |
+
If `out` is given, then it is returned.
|
| 800 |
+
|
| 801 |
+
Raises
|
| 802 |
+
------
|
| 803 |
+
ValueError
|
| 804 |
+
If the last dimension of `a` is not the same size as
|
| 805 |
+
the second-to-last dimension of `b`.
|
| 806 |
+
|
| 807 |
+
See Also
|
| 808 |
+
--------
|
| 809 |
+
vdot : Complex-conjugating dot product.
|
| 810 |
+
vecdot : Vector dot product of two arrays.
|
| 811 |
+
tensordot : Sum products over arbitrary axes.
|
| 812 |
+
einsum : Einstein summation convention.
|
| 813 |
+
matmul : '@' operator as method with out parameter.
|
| 814 |
+
linalg.multi_dot : Chained dot product.
|
| 815 |
+
|
| 816 |
+
Examples
|
| 817 |
+
--------
|
| 818 |
+
>>> import numpy as np
|
| 819 |
+
>>> np.dot(3, 4)
|
| 820 |
+
12
|
| 821 |
+
|
| 822 |
+
Neither argument is complex-conjugated:
|
| 823 |
+
|
| 824 |
+
>>> np.dot([2j, 3j], [2j, 3j])
|
| 825 |
+
(-13+0j)
|
| 826 |
+
|
| 827 |
+
For 2-D arrays it is the matrix product:
|
| 828 |
+
|
| 829 |
+
>>> a = [[1, 0], [0, 1]]
|
| 830 |
+
>>> b = [[4, 1], [2, 2]]
|
| 831 |
+
>>> np.dot(a, b)
|
| 832 |
+
array([[4, 1],
|
| 833 |
+
[2, 2]])
|
| 834 |
+
|
| 835 |
+
>>> a = np.arange(3*4*5*6).reshape((3,4,5,6))
|
| 836 |
+
>>> b = np.arange(3*4*5*6)[::-1].reshape((5,4,6,3))
|
| 837 |
+
>>> np.dot(a, b)[2,3,2,1,2,2]
|
| 838 |
+
499128
|
| 839 |
+
>>> sum(a[2,3,2,:] * b[1,2,:,2])
|
| 840 |
+
499128
|
| 841 |
+
|
| 842 |
+
"""
|
| 843 |
+
return (a, b, out)
|
| 844 |
+
|
| 845 |
+
|
| 846 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.vdot)
|
| 847 |
+
def vdot(a, b, /):
|
| 848 |
+
r"""
|
| 849 |
+
vdot(a, b, /)
|
| 850 |
+
|
| 851 |
+
Return the dot product of two vectors.
|
| 852 |
+
|
| 853 |
+
The `vdot` function handles complex numbers differently than `dot`:
|
| 854 |
+
if the first argument is complex, it is replaced by its complex conjugate
|
| 855 |
+
in the dot product calculation. `vdot` also handles multidimensional
|
| 856 |
+
arrays differently than `dot`: it does not perform a matrix product, but
|
| 857 |
+
flattens the arguments to 1-D arrays before taking a vector dot product.
|
| 858 |
+
|
| 859 |
+
Consequently, when the arguments are 2-D arrays of the same shape, this
|
| 860 |
+
function effectively returns their
|
| 861 |
+
`Frobenius inner product <https://en.wikipedia.org/wiki/Frobenius_inner_product>`_
|
| 862 |
+
(also known as the *trace inner product* or the *standard inner product*
|
| 863 |
+
on a vector space of matrices).
|
| 864 |
+
|
| 865 |
+
Parameters
|
| 866 |
+
----------
|
| 867 |
+
a : array_like
|
| 868 |
+
If `a` is complex the complex conjugate is taken before calculation
|
| 869 |
+
of the dot product.
|
| 870 |
+
b : array_like
|
| 871 |
+
Second argument to the dot product.
|
| 872 |
+
|
| 873 |
+
Returns
|
| 874 |
+
-------
|
| 875 |
+
output : ndarray
|
| 876 |
+
Dot product of `a` and `b`. Can be an int, float, or
|
| 877 |
+
complex depending on the types of `a` and `b`.
|
| 878 |
+
|
| 879 |
+
See Also
|
| 880 |
+
--------
|
| 881 |
+
dot : Return the dot product without using the complex conjugate of the
|
| 882 |
+
first argument.
|
| 883 |
+
|
| 884 |
+
Examples
|
| 885 |
+
--------
|
| 886 |
+
>>> import numpy as np
|
| 887 |
+
>>> a = np.array([1+2j,3+4j])
|
| 888 |
+
>>> b = np.array([5+6j,7+8j])
|
| 889 |
+
>>> np.vdot(a, b)
|
| 890 |
+
(70-8j)
|
| 891 |
+
>>> np.vdot(b, a)
|
| 892 |
+
(70+8j)
|
| 893 |
+
|
| 894 |
+
Note that higher-dimensional arrays are flattened!
|
| 895 |
+
|
| 896 |
+
>>> a = np.array([[1, 4], [5, 6]])
|
| 897 |
+
>>> b = np.array([[4, 1], [2, 2]])
|
| 898 |
+
>>> np.vdot(a, b)
|
| 899 |
+
30
|
| 900 |
+
>>> np.vdot(b, a)
|
| 901 |
+
30
|
| 902 |
+
>>> 1*4 + 4*1 + 5*2 + 6*2
|
| 903 |
+
30
|
| 904 |
+
|
| 905 |
+
"""
|
| 906 |
+
return (a, b)
|
| 907 |
+
|
| 908 |
+
|
| 909 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.bincount)
|
| 910 |
+
def bincount(x, /, weights=None, minlength=0):
|
| 911 |
+
"""
|
| 912 |
+
bincount(x, /, weights=None, minlength=0)
|
| 913 |
+
|
| 914 |
+
Count number of occurrences of each value in array of non-negative ints.
|
| 915 |
+
|
| 916 |
+
The number of bins (of size 1) is one larger than the largest value in
|
| 917 |
+
`x`. If `minlength` is specified, there will be at least this number
|
| 918 |
+
of bins in the output array (though it will be longer if necessary,
|
| 919 |
+
depending on the contents of `x`).
|
| 920 |
+
Each bin gives the number of occurrences of its index value in `x`.
|
| 921 |
+
If `weights` is specified the input array is weighted by it, i.e. if a
|
| 922 |
+
value ``n`` is found at position ``i``, ``out[n] += weight[i]`` instead
|
| 923 |
+
of ``out[n] += 1``.
|
| 924 |
+
|
| 925 |
+
Parameters
|
| 926 |
+
----------
|
| 927 |
+
x : array_like, 1 dimension, nonnegative ints
|
| 928 |
+
Input array.
|
| 929 |
+
weights : array_like, optional
|
| 930 |
+
Weights, array of the same shape as `x`.
|
| 931 |
+
minlength : int, optional
|
| 932 |
+
A minimum number of bins for the output array.
|
| 933 |
+
|
| 934 |
+
Returns
|
| 935 |
+
-------
|
| 936 |
+
out : ndarray of ints
|
| 937 |
+
The result of binning the input array.
|
| 938 |
+
The length of `out` is equal to ``np.amax(x)+1``.
|
| 939 |
+
|
| 940 |
+
Raises
|
| 941 |
+
------
|
| 942 |
+
ValueError
|
| 943 |
+
If the input is not 1-dimensional, or contains elements with negative
|
| 944 |
+
values, or if `minlength` is negative.
|
| 945 |
+
TypeError
|
| 946 |
+
If the type of the input is float or complex.
|
| 947 |
+
|
| 948 |
+
See Also
|
| 949 |
+
--------
|
| 950 |
+
histogram, digitize, unique
|
| 951 |
+
|
| 952 |
+
Examples
|
| 953 |
+
--------
|
| 954 |
+
>>> import numpy as np
|
| 955 |
+
>>> np.bincount(np.arange(5))
|
| 956 |
+
array([1, 1, 1, 1, 1])
|
| 957 |
+
>>> np.bincount(np.array([0, 1, 1, 3, 2, 1, 7]))
|
| 958 |
+
array([1, 3, 1, 1, 0, 0, 0, 1])
|
| 959 |
+
|
| 960 |
+
>>> x = np.array([0, 1, 1, 3, 2, 1, 7, 23])
|
| 961 |
+
>>> np.bincount(x).size == np.amax(x)+1
|
| 962 |
+
True
|
| 963 |
+
|
| 964 |
+
The input array needs to be of integer dtype, otherwise a
|
| 965 |
+
TypeError is raised:
|
| 966 |
+
|
| 967 |
+
>>> np.bincount(np.arange(5, dtype=np.float64))
|
| 968 |
+
Traceback (most recent call last):
|
| 969 |
+
...
|
| 970 |
+
TypeError: Cannot cast array data from dtype('float64') to dtype('int64')
|
| 971 |
+
according to the rule 'safe'
|
| 972 |
+
|
| 973 |
+
A possible use of ``bincount`` is to perform sums over
|
| 974 |
+
variable-size chunks of an array, using the ``weights`` keyword.
|
| 975 |
+
|
| 976 |
+
>>> w = np.array([0.3, 0.5, 0.2, 0.7, 1., -0.6]) # weights
|
| 977 |
+
>>> x = np.array([0, 1, 1, 2, 2, 2])
|
| 978 |
+
>>> np.bincount(x, weights=w)
|
| 979 |
+
array([ 0.3, 0.7, 1.1])
|
| 980 |
+
|
| 981 |
+
"""
|
| 982 |
+
return (x, weights)
|
| 983 |
+
|
| 984 |
+
|
| 985 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.ravel_multi_index)
|
| 986 |
+
def ravel_multi_index(multi_index, dims, mode="raise", order="C"):
|
| 987 |
+
"""
|
| 988 |
+
ravel_multi_index(multi_index, dims, mode='raise', order='C')
|
| 989 |
+
|
| 990 |
+
Converts a tuple of index arrays into an array of flat
|
| 991 |
+
indices, applying boundary modes to the multi-index.
|
| 992 |
+
|
| 993 |
+
Parameters
|
| 994 |
+
----------
|
| 995 |
+
multi_index : tuple of array_like
|
| 996 |
+
A tuple of integer arrays, one array for each dimension.
|
| 997 |
+
dims : tuple of ints
|
| 998 |
+
The shape of array into which the indices from ``multi_index`` apply.
|
| 999 |
+
mode : {'raise', 'wrap', 'clip'}, optional
|
| 1000 |
+
Specifies how out-of-bounds indices are handled. Can specify
|
| 1001 |
+
either one mode or a tuple of modes, one mode per index.
|
| 1002 |
+
|
| 1003 |
+
* 'raise' -- raise an error (default)
|
| 1004 |
+
* 'wrap' -- wrap around
|
| 1005 |
+
* 'clip' -- clip to the range
|
| 1006 |
+
|
| 1007 |
+
In 'clip' mode, a negative index which would normally
|
| 1008 |
+
wrap will clip to 0 instead.
|
| 1009 |
+
order : {'C', 'F'}, optional
|
| 1010 |
+
Determines whether the multi-index should be viewed as
|
| 1011 |
+
indexing in row-major (C-style) or column-major
|
| 1012 |
+
(Fortran-style) order.
|
| 1013 |
+
|
| 1014 |
+
Returns
|
| 1015 |
+
-------
|
| 1016 |
+
raveled_indices : ndarray
|
| 1017 |
+
An array of indices into the flattened version of an array
|
| 1018 |
+
of dimensions ``dims``.
|
| 1019 |
+
|
| 1020 |
+
See Also
|
| 1021 |
+
--------
|
| 1022 |
+
unravel_index
|
| 1023 |
+
|
| 1024 |
+
Examples
|
| 1025 |
+
--------
|
| 1026 |
+
>>> import numpy as np
|
| 1027 |
+
>>> arr = np.array([[3,6,6],[4,5,1]])
|
| 1028 |
+
>>> np.ravel_multi_index(arr, (7,6))
|
| 1029 |
+
array([22, 41, 37])
|
| 1030 |
+
>>> np.ravel_multi_index(arr, (7,6), order='F')
|
| 1031 |
+
array([31, 41, 13])
|
| 1032 |
+
>>> np.ravel_multi_index(arr, (4,6), mode='clip')
|
| 1033 |
+
array([22, 23, 19])
|
| 1034 |
+
>>> np.ravel_multi_index(arr, (4,4), mode=('clip','wrap'))
|
| 1035 |
+
array([12, 13, 13])
|
| 1036 |
+
|
| 1037 |
+
>>> np.ravel_multi_index((3,1,4,1), (6,7,8,9))
|
| 1038 |
+
1621
|
| 1039 |
+
"""
|
| 1040 |
+
return multi_index
|
| 1041 |
+
|
| 1042 |
+
|
| 1043 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.unravel_index)
|
| 1044 |
+
def unravel_index(indices, shape, order="C"):
|
| 1045 |
+
"""
|
| 1046 |
+
unravel_index(indices, shape, order='C')
|
| 1047 |
+
|
| 1048 |
+
Converts a flat index or array of flat indices into a tuple
|
| 1049 |
+
of coordinate arrays.
|
| 1050 |
+
|
| 1051 |
+
Parameters
|
| 1052 |
+
----------
|
| 1053 |
+
indices : array_like
|
| 1054 |
+
An integer array whose elements are indices into the flattened
|
| 1055 |
+
version of an array of dimensions ``shape``. Before version 1.6.0,
|
| 1056 |
+
this function accepted just one index value.
|
| 1057 |
+
shape : tuple of ints
|
| 1058 |
+
The shape of the array to use for unraveling ``indices``.
|
| 1059 |
+
order : {'C', 'F'}, optional
|
| 1060 |
+
Determines whether the indices should be viewed as indexing in
|
| 1061 |
+
row-major (C-style) or column-major (Fortran-style) order.
|
| 1062 |
+
|
| 1063 |
+
Returns
|
| 1064 |
+
-------
|
| 1065 |
+
unraveled_coords : tuple of ndarray
|
| 1066 |
+
Each array in the tuple has the same shape as the ``indices``
|
| 1067 |
+
array.
|
| 1068 |
+
|
| 1069 |
+
See Also
|
| 1070 |
+
--------
|
| 1071 |
+
ravel_multi_index
|
| 1072 |
+
|
| 1073 |
+
Examples
|
| 1074 |
+
--------
|
| 1075 |
+
>>> import numpy as np
|
| 1076 |
+
>>> np.unravel_index([22, 41, 37], (7,6))
|
| 1077 |
+
(array([3, 6, 6]), array([4, 5, 1]))
|
| 1078 |
+
>>> np.unravel_index([31, 41, 13], (7,6), order='F')
|
| 1079 |
+
(array([3, 6, 6]), array([4, 5, 1]))
|
| 1080 |
+
|
| 1081 |
+
>>> np.unravel_index(1621, (6,7,8,9))
|
| 1082 |
+
(3, 1, 4, 1)
|
| 1083 |
+
|
| 1084 |
+
"""
|
| 1085 |
+
return (indices,)
|
| 1086 |
+
|
| 1087 |
+
|
| 1088 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.copyto)
|
| 1089 |
+
def copyto(dst, src, casting="same_kind", where=True):
|
| 1090 |
+
"""
|
| 1091 |
+
copyto(dst, src, casting='same_kind', where=True)
|
| 1092 |
+
|
| 1093 |
+
Copies values from one array to another, broadcasting as necessary.
|
| 1094 |
+
|
| 1095 |
+
Raises a TypeError if the `casting` rule is violated, and if
|
| 1096 |
+
`where` is provided, it selects which elements to copy.
|
| 1097 |
+
|
| 1098 |
+
Parameters
|
| 1099 |
+
----------
|
| 1100 |
+
dst : ndarray
|
| 1101 |
+
The array into which values are copied.
|
| 1102 |
+
src : array_like
|
| 1103 |
+
The array from which values are copied.
|
| 1104 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
|
| 1105 |
+
Controls what kind of data casting may occur when copying.
|
| 1106 |
+
|
| 1107 |
+
* 'no' means the data types should not be cast at all.
|
| 1108 |
+
* 'equiv' means only byte-order changes are allowed.
|
| 1109 |
+
* 'safe' means only casts which can preserve values are allowed.
|
| 1110 |
+
* 'same_kind' means only safe casts or casts within a kind,
|
| 1111 |
+
like float64 to float32, are allowed.
|
| 1112 |
+
* 'unsafe' means any data conversions may be done.
|
| 1113 |
+
where : array_like of bool, optional
|
| 1114 |
+
A boolean array which is broadcasted to match the dimensions
|
| 1115 |
+
of `dst`, and selects elements to copy from `src` to `dst`
|
| 1116 |
+
wherever it contains the value True.
|
| 1117 |
+
|
| 1118 |
+
Examples
|
| 1119 |
+
--------
|
| 1120 |
+
>>> import numpy as np
|
| 1121 |
+
>>> A = np.array([4, 5, 6])
|
| 1122 |
+
>>> B = [1, 2, 3]
|
| 1123 |
+
>>> np.copyto(A, B)
|
| 1124 |
+
>>> A
|
| 1125 |
+
array([1, 2, 3])
|
| 1126 |
+
|
| 1127 |
+
>>> A = np.array([[1, 2, 3], [4, 5, 6]])
|
| 1128 |
+
>>> B = [[4, 5, 6], [7, 8, 9]]
|
| 1129 |
+
>>> np.copyto(A, B)
|
| 1130 |
+
>>> A
|
| 1131 |
+
array([[4, 5, 6],
|
| 1132 |
+
[7, 8, 9]])
|
| 1133 |
+
|
| 1134 |
+
"""
|
| 1135 |
+
return (dst, src, where)
|
| 1136 |
+
|
| 1137 |
+
|
| 1138 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.putmask)
|
| 1139 |
+
def putmask(a, /, mask, values):
|
| 1140 |
+
"""
|
| 1141 |
+
putmask(a, /, mask, values)
|
| 1142 |
+
|
| 1143 |
+
Changes elements of an array based on conditional and input values.
|
| 1144 |
+
|
| 1145 |
+
Sets ``a.flat[n] = values[n]`` for each n where ``mask.flat[n]==True``.
|
| 1146 |
+
|
| 1147 |
+
If `values` is not the same size as `a` and `mask` then it will repeat.
|
| 1148 |
+
This gives behavior different from ``a[mask] = values``.
|
| 1149 |
+
|
| 1150 |
+
Parameters
|
| 1151 |
+
----------
|
| 1152 |
+
a : ndarray
|
| 1153 |
+
Target array.
|
| 1154 |
+
mask : array_like
|
| 1155 |
+
Boolean mask array. It has to be the same shape as `a`.
|
| 1156 |
+
values : array_like
|
| 1157 |
+
Values to put into `a` where `mask` is True. If `values` is smaller
|
| 1158 |
+
than `a` it will be repeated.
|
| 1159 |
+
|
| 1160 |
+
See Also
|
| 1161 |
+
--------
|
| 1162 |
+
place, put, take, copyto
|
| 1163 |
+
|
| 1164 |
+
Examples
|
| 1165 |
+
--------
|
| 1166 |
+
>>> import numpy as np
|
| 1167 |
+
>>> x = np.arange(6).reshape(2, 3)
|
| 1168 |
+
>>> np.putmask(x, x>2, x**2)
|
| 1169 |
+
>>> x
|
| 1170 |
+
array([[ 0, 1, 2],
|
| 1171 |
+
[ 9, 16, 25]])
|
| 1172 |
+
|
| 1173 |
+
If `values` is smaller than `a` it is repeated:
|
| 1174 |
+
|
| 1175 |
+
>>> x = np.arange(5)
|
| 1176 |
+
>>> np.putmask(x, x>1, [-33, -44])
|
| 1177 |
+
>>> x
|
| 1178 |
+
array([ 0, 1, -33, -44, -33])
|
| 1179 |
+
|
| 1180 |
+
"""
|
| 1181 |
+
return (a, mask, values)
|
| 1182 |
+
|
| 1183 |
+
|
| 1184 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.packbits)
|
| 1185 |
+
def packbits(a, /, axis=None, bitorder="big"):
|
| 1186 |
+
"""
|
| 1187 |
+
packbits(a, /, axis=None, bitorder='big')
|
| 1188 |
+
|
| 1189 |
+
Packs the elements of a binary-valued array into bits in a uint8 array.
|
| 1190 |
+
|
| 1191 |
+
The result is padded to full bytes by inserting zero bits at the end.
|
| 1192 |
+
|
| 1193 |
+
Parameters
|
| 1194 |
+
----------
|
| 1195 |
+
a : array_like
|
| 1196 |
+
An array of integers or booleans whose elements should be packed to
|
| 1197 |
+
bits.
|
| 1198 |
+
axis : int, optional
|
| 1199 |
+
The dimension over which bit-packing is done.
|
| 1200 |
+
``None`` implies packing the flattened array.
|
| 1201 |
+
bitorder : {'big', 'little'}, optional
|
| 1202 |
+
The order of the input bits. 'big' will mimic bin(val),
|
| 1203 |
+
``[0, 0, 0, 0, 0, 0, 1, 1] => 3 = 0b00000011``, 'little' will
|
| 1204 |
+
reverse the order so ``[1, 1, 0, 0, 0, 0, 0, 0] => 3``.
|
| 1205 |
+
Defaults to 'big'.
|
| 1206 |
+
|
| 1207 |
+
Returns
|
| 1208 |
+
-------
|
| 1209 |
+
packed : ndarray
|
| 1210 |
+
Array of type uint8 whose elements represent bits corresponding to the
|
| 1211 |
+
logical (0 or nonzero) value of the input elements. The shape of
|
| 1212 |
+
`packed` has the same number of dimensions as the input (unless `axis`
|
| 1213 |
+
is None, in which case the output is 1-D).
|
| 1214 |
+
|
| 1215 |
+
See Also
|
| 1216 |
+
--------
|
| 1217 |
+
unpackbits: Unpacks elements of a uint8 array into a binary-valued output
|
| 1218 |
+
array.
|
| 1219 |
+
|
| 1220 |
+
Examples
|
| 1221 |
+
--------
|
| 1222 |
+
>>> import numpy as np
|
| 1223 |
+
>>> a = np.array([[[1,0,1],
|
| 1224 |
+
... [0,1,0]],
|
| 1225 |
+
... [[1,1,0],
|
| 1226 |
+
... [0,0,1]]])
|
| 1227 |
+
>>> b = np.packbits(a, axis=-1)
|
| 1228 |
+
>>> b
|
| 1229 |
+
array([[[160],
|
| 1230 |
+
[ 64]],
|
| 1231 |
+
[[192],
|
| 1232 |
+
[ 32]]], dtype=uint8)
|
| 1233 |
+
|
| 1234 |
+
Note that in binary 160 = 1010 0000, 64 = 0100 0000, 192 = 1100 0000,
|
| 1235 |
+
and 32 = 0010 0000.
|
| 1236 |
+
|
| 1237 |
+
"""
|
| 1238 |
+
return (a,)
|
| 1239 |
+
|
| 1240 |
+
|
| 1241 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.unpackbits)
|
| 1242 |
+
def unpackbits(a, /, axis=None, count=None, bitorder="big"):
|
| 1243 |
+
"""
|
| 1244 |
+
unpackbits(a, /, axis=None, count=None, bitorder='big')
|
| 1245 |
+
|
| 1246 |
+
Unpacks elements of a uint8 array into a binary-valued output array.
|
| 1247 |
+
|
| 1248 |
+
Each element of `a` represents a bit-field that should be unpacked
|
| 1249 |
+
into a binary-valued output array. The shape of the output array is
|
| 1250 |
+
either 1-D (if `axis` is ``None``) or the same shape as the input
|
| 1251 |
+
array with unpacking done along the axis specified.
|
| 1252 |
+
|
| 1253 |
+
Parameters
|
| 1254 |
+
----------
|
| 1255 |
+
a : ndarray, uint8 type
|
| 1256 |
+
Input array.
|
| 1257 |
+
axis : int, optional
|
| 1258 |
+
The dimension over which bit-unpacking is done.
|
| 1259 |
+
``None`` implies unpacking the flattened array.
|
| 1260 |
+
count : int or None, optional
|
| 1261 |
+
The number of elements to unpack along `axis`, provided as a way
|
| 1262 |
+
of undoing the effect of packing a size that is not a multiple
|
| 1263 |
+
of eight. A non-negative number means to only unpack `count`
|
| 1264 |
+
bits. A negative number means to trim off that many bits from
|
| 1265 |
+
the end. ``None`` means to unpack the entire array (the
|
| 1266 |
+
default). Counts larger than the available number of bits will
|
| 1267 |
+
add zero padding to the output. Negative counts must not
|
| 1268 |
+
exceed the available number of bits.
|
| 1269 |
+
bitorder : {'big', 'little'}, optional
|
| 1270 |
+
The order of the returned bits. 'big' will mimic bin(val),
|
| 1271 |
+
``3 = 0b00000011 => [0, 0, 0, 0, 0, 0, 1, 1]``, 'little' will reverse
|
| 1272 |
+
the order to ``[1, 1, 0, 0, 0, 0, 0, 0]``.
|
| 1273 |
+
Defaults to 'big'.
|
| 1274 |
+
|
| 1275 |
+
Returns
|
| 1276 |
+
-------
|
| 1277 |
+
unpacked : ndarray, uint8 type
|
| 1278 |
+
The elements are binary-valued (0 or 1).
|
| 1279 |
+
|
| 1280 |
+
See Also
|
| 1281 |
+
--------
|
| 1282 |
+
packbits : Packs the elements of a binary-valued array into bits in
|
| 1283 |
+
a uint8 array.
|
| 1284 |
+
|
| 1285 |
+
Examples
|
| 1286 |
+
--------
|
| 1287 |
+
>>> import numpy as np
|
| 1288 |
+
>>> a = np.array([[2], [7], [23]], dtype=np.uint8)
|
| 1289 |
+
>>> a
|
| 1290 |
+
array([[ 2],
|
| 1291 |
+
[ 7],
|
| 1292 |
+
[23]], dtype=uint8)
|
| 1293 |
+
>>> b = np.unpackbits(a, axis=1)
|
| 1294 |
+
>>> b
|
| 1295 |
+
array([[0, 0, 0, 0, 0, 0, 1, 0],
|
| 1296 |
+
[0, 0, 0, 0, 0, 1, 1, 1],
|
| 1297 |
+
[0, 0, 0, 1, 0, 1, 1, 1]], dtype=uint8)
|
| 1298 |
+
>>> c = np.unpackbits(a, axis=1, count=-3)
|
| 1299 |
+
>>> c
|
| 1300 |
+
array([[0, 0, 0, 0, 0],
|
| 1301 |
+
[0, 0, 0, 0, 0],
|
| 1302 |
+
[0, 0, 0, 1, 0]], dtype=uint8)
|
| 1303 |
+
|
| 1304 |
+
>>> p = np.packbits(b, axis=0)
|
| 1305 |
+
>>> np.unpackbits(p, axis=0)
|
| 1306 |
+
array([[0, 0, 0, 0, 0, 0, 1, 0],
|
| 1307 |
+
[0, 0, 0, 0, 0, 1, 1, 1],
|
| 1308 |
+
[0, 0, 0, 1, 0, 1, 1, 1],
|
| 1309 |
+
[0, 0, 0, 0, 0, 0, 0, 0],
|
| 1310 |
+
[0, 0, 0, 0, 0, 0, 0, 0],
|
| 1311 |
+
[0, 0, 0, 0, 0, 0, 0, 0],
|
| 1312 |
+
[0, 0, 0, 0, 0, 0, 0, 0],
|
| 1313 |
+
[0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
|
| 1314 |
+
>>> np.array_equal(b, np.unpackbits(p, axis=0, count=b.shape[0]))
|
| 1315 |
+
True
|
| 1316 |
+
|
| 1317 |
+
"""
|
| 1318 |
+
return (a,)
|
| 1319 |
+
|
| 1320 |
+
|
| 1321 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.shares_memory)
|
| 1322 |
+
def shares_memory(a, b, /, max_work=-1):
|
| 1323 |
+
"""
|
| 1324 |
+
shares_memory(a, b, /, max_work=-1)
|
| 1325 |
+
|
| 1326 |
+
Determine if two arrays share memory.
|
| 1327 |
+
|
| 1328 |
+
.. warning::
|
| 1329 |
+
|
| 1330 |
+
This function can be exponentially slow for some inputs, unless
|
| 1331 |
+
`max_work` is set to zero or a positive integer.
|
| 1332 |
+
If in doubt, use `numpy.may_share_memory` instead.
|
| 1333 |
+
|
| 1334 |
+
Parameters
|
| 1335 |
+
----------
|
| 1336 |
+
a, b : ndarray
|
| 1337 |
+
Input arrays
|
| 1338 |
+
max_work : int, optional
|
| 1339 |
+
Effort to spend on solving the overlap problem (maximum number
|
| 1340 |
+
of candidate solutions to consider). The following special
|
| 1341 |
+
values are recognized:
|
| 1342 |
+
|
| 1343 |
+
max_work=-1 (default)
|
| 1344 |
+
The problem is solved exactly. In this case, the function returns
|
| 1345 |
+
True only if there is an element shared between the arrays. Finding
|
| 1346 |
+
the exact solution may take extremely long in some cases.
|
| 1347 |
+
max_work=0
|
| 1348 |
+
Only the memory bounds of a and b are checked.
|
| 1349 |
+
This is equivalent to using ``may_share_memory()``.
|
| 1350 |
+
|
| 1351 |
+
Raises
|
| 1352 |
+
------
|
| 1353 |
+
numpy.exceptions.TooHardError
|
| 1354 |
+
Exceeded max_work.
|
| 1355 |
+
|
| 1356 |
+
Returns
|
| 1357 |
+
-------
|
| 1358 |
+
out : bool
|
| 1359 |
+
|
| 1360 |
+
See Also
|
| 1361 |
+
--------
|
| 1362 |
+
may_share_memory
|
| 1363 |
+
|
| 1364 |
+
Examples
|
| 1365 |
+
--------
|
| 1366 |
+
>>> import numpy as np
|
| 1367 |
+
>>> x = np.array([1, 2, 3, 4])
|
| 1368 |
+
>>> np.shares_memory(x, np.array([5, 6, 7]))
|
| 1369 |
+
False
|
| 1370 |
+
>>> np.shares_memory(x[::2], x)
|
| 1371 |
+
True
|
| 1372 |
+
>>> np.shares_memory(x[::2], x[1::2])
|
| 1373 |
+
False
|
| 1374 |
+
|
| 1375 |
+
Checking whether two arrays share memory is NP-complete, and
|
| 1376 |
+
runtime may increase exponentially in the number of
|
| 1377 |
+
dimensions. Hence, `max_work` should generally be set to a finite
|
| 1378 |
+
number, as it is possible to construct examples that take
|
| 1379 |
+
extremely long to run:
|
| 1380 |
+
|
| 1381 |
+
>>> from numpy.lib.stride_tricks import as_strided
|
| 1382 |
+
>>> x = np.zeros([192163377], dtype=np.int8)
|
| 1383 |
+
>>> x1 = as_strided(
|
| 1384 |
+
... x, strides=(36674, 61119, 85569), shape=(1049, 1049, 1049))
|
| 1385 |
+
>>> x2 = as_strided(
|
| 1386 |
+
... x[64023025:], strides=(12223, 12224, 1), shape=(1049, 1049, 1))
|
| 1387 |
+
>>> np.shares_memory(x1, x2, max_work=1000)
|
| 1388 |
+
Traceback (most recent call last):
|
| 1389 |
+
...
|
| 1390 |
+
numpy.exceptions.TooHardError: Exceeded max_work
|
| 1391 |
+
|
| 1392 |
+
Running ``np.shares_memory(x1, x2)`` without `max_work` set takes
|
| 1393 |
+
around 1 minute for this case. It is possible to find problems
|
| 1394 |
+
that take still significantly longer.
|
| 1395 |
+
|
| 1396 |
+
"""
|
| 1397 |
+
return (a, b)
|
| 1398 |
+
|
| 1399 |
+
|
| 1400 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.may_share_memory)
|
| 1401 |
+
def may_share_memory(a, b, /, max_work=0):
|
| 1402 |
+
"""
|
| 1403 |
+
may_share_memory(a, b, /, max_work=0)
|
| 1404 |
+
|
| 1405 |
+
Determine if two arrays might share memory
|
| 1406 |
+
|
| 1407 |
+
A return of True does not necessarily mean that the two arrays
|
| 1408 |
+
share any element. It just means that they *might*.
|
| 1409 |
+
|
| 1410 |
+
Only the memory bounds of a and b are checked by default.
|
| 1411 |
+
|
| 1412 |
+
Parameters
|
| 1413 |
+
----------
|
| 1414 |
+
a, b : ndarray
|
| 1415 |
+
Input arrays
|
| 1416 |
+
max_work : int, optional
|
| 1417 |
+
Effort to spend on solving the overlap problem. See
|
| 1418 |
+
`shares_memory` for details. Default for ``may_share_memory``
|
| 1419 |
+
is to do a bounds check.
|
| 1420 |
+
|
| 1421 |
+
Returns
|
| 1422 |
+
-------
|
| 1423 |
+
out : bool
|
| 1424 |
+
|
| 1425 |
+
See Also
|
| 1426 |
+
--------
|
| 1427 |
+
shares_memory
|
| 1428 |
+
|
| 1429 |
+
Examples
|
| 1430 |
+
--------
|
| 1431 |
+
>>> import numpy as np
|
| 1432 |
+
>>> np.may_share_memory(np.array([1,2]), np.array([5,8,9]))
|
| 1433 |
+
False
|
| 1434 |
+
>>> x = np.zeros([3, 4])
|
| 1435 |
+
>>> np.may_share_memory(x[:,0], x[:,1])
|
| 1436 |
+
True
|
| 1437 |
+
|
| 1438 |
+
"""
|
| 1439 |
+
return (a, b)
|
| 1440 |
+
|
| 1441 |
+
|
| 1442 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.is_busday)
|
| 1443 |
+
def is_busday(dates, weekmask="1111100", holidays=None, busdaycal=None, out=None):
|
| 1444 |
+
"""
|
| 1445 |
+
is_busday(
|
| 1446 |
+
dates,
|
| 1447 |
+
weekmask='1111100',
|
| 1448 |
+
holidays=None,
|
| 1449 |
+
busdaycal=None,
|
| 1450 |
+
out=None,
|
| 1451 |
+
)
|
| 1452 |
+
|
| 1453 |
+
Calculates which of the given dates are valid days, and which are not.
|
| 1454 |
+
|
| 1455 |
+
Parameters
|
| 1456 |
+
----------
|
| 1457 |
+
dates : array_like of datetime64[D]
|
| 1458 |
+
The array of dates to process.
|
| 1459 |
+
weekmask : str or array_like of bool, optional
|
| 1460 |
+
A seven-element array indicating which of Monday through Sunday are
|
| 1461 |
+
valid days. May be specified as a length-seven list or array, like
|
| 1462 |
+
[1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string
|
| 1463 |
+
like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for
|
| 1464 |
+
weekdays, optionally separated by white space. Valid abbreviations
|
| 1465 |
+
are: Mon Tue Wed Thu Fri Sat Sun
|
| 1466 |
+
holidays : array_like of datetime64[D], optional
|
| 1467 |
+
An array of dates to consider as invalid dates. They may be
|
| 1468 |
+
specified in any order, and NaT (not-a-time) dates are ignored.
|
| 1469 |
+
This list is saved in a normalized form that is suited for
|
| 1470 |
+
fast calculations of valid days.
|
| 1471 |
+
busdaycal : busdaycalendar, optional
|
| 1472 |
+
A `busdaycalendar` object which specifies the valid days. If this
|
| 1473 |
+
parameter is provided, neither weekmask nor holidays may be
|
| 1474 |
+
provided.
|
| 1475 |
+
out : array of bool, optional
|
| 1476 |
+
If provided, this array is filled with the result.
|
| 1477 |
+
|
| 1478 |
+
Returns
|
| 1479 |
+
-------
|
| 1480 |
+
out : array of bool
|
| 1481 |
+
An array with the same shape as ``dates``, containing True for
|
| 1482 |
+
each valid day, and False for each invalid day.
|
| 1483 |
+
|
| 1484 |
+
See Also
|
| 1485 |
+
--------
|
| 1486 |
+
busdaycalendar : An object that specifies a custom set of valid days.
|
| 1487 |
+
busday_offset : Applies an offset counted in valid days.
|
| 1488 |
+
busday_count : Counts how many valid days are in a half-open date range.
|
| 1489 |
+
|
| 1490 |
+
Examples
|
| 1491 |
+
--------
|
| 1492 |
+
>>> import numpy as np
|
| 1493 |
+
>>> # The weekdays are Friday, Saturday, and Monday
|
| 1494 |
+
... np.is_busday(['2011-07-01', '2011-07-02', '2011-07-18'],
|
| 1495 |
+
... holidays=['2011-07-01', '2011-07-04', '2011-07-17'])
|
| 1496 |
+
array([False, False, True])
|
| 1497 |
+
"""
|
| 1498 |
+
return (dates, weekmask, holidays, out)
|
| 1499 |
+
|
| 1500 |
+
|
| 1501 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.busday_offset)
|
| 1502 |
+
def busday_offset(dates, offsets, roll="raise", weekmask="1111100", holidays=None,
|
| 1503 |
+
busdaycal=None, out=None):
|
| 1504 |
+
"""
|
| 1505 |
+
busday_offset(
|
| 1506 |
+
dates,
|
| 1507 |
+
offsets,
|
| 1508 |
+
roll='raise',
|
| 1509 |
+
weekmask='1111100',
|
| 1510 |
+
holidays=None,
|
| 1511 |
+
busdaycal=None,
|
| 1512 |
+
out=None,
|
| 1513 |
+
)
|
| 1514 |
+
|
| 1515 |
+
First adjusts the date to fall on a valid day according to
|
| 1516 |
+
the ``roll`` rule, then applies offsets to the given dates
|
| 1517 |
+
counted in valid days.
|
| 1518 |
+
|
| 1519 |
+
Parameters
|
| 1520 |
+
----------
|
| 1521 |
+
dates : array_like of datetime64[D]
|
| 1522 |
+
The array of dates to process.
|
| 1523 |
+
offsets : array_like of int
|
| 1524 |
+
The array of offsets, which is broadcast with ``dates``.
|
| 1525 |
+
roll : {'raise', 'nat', 'forward', 'following', 'backward', 'preceding', \
|
| 1526 |
+
'modifiedfollowing', 'modifiedpreceding'}, optional
|
| 1527 |
+
How to treat dates that do not fall on a valid day. The default
|
| 1528 |
+
is 'raise'.
|
| 1529 |
+
|
| 1530 |
+
* 'raise' means to raise an exception for an invalid day.
|
| 1531 |
+
* 'nat' means to return a NaT (not-a-time) for an invalid day.
|
| 1532 |
+
* 'forward' and 'following' mean to take the first valid day
|
| 1533 |
+
later in time.
|
| 1534 |
+
* 'backward' and 'preceding' mean to take the first valid day
|
| 1535 |
+
earlier in time.
|
| 1536 |
+
* 'modifiedfollowing' means to take the first valid day
|
| 1537 |
+
later in time unless it is across a Month boundary, in which
|
| 1538 |
+
case to take the first valid day earlier in time.
|
| 1539 |
+
* 'modifiedpreceding' means to take the first valid day
|
| 1540 |
+
earlier in time unless it is across a Month boundary, in which
|
| 1541 |
+
case to take the first valid day later in time.
|
| 1542 |
+
weekmask : str or array_like of bool, optional
|
| 1543 |
+
A seven-element array indicating which of Monday through Sunday are
|
| 1544 |
+
valid days. May be specified as a length-seven list or array, like
|
| 1545 |
+
[1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string
|
| 1546 |
+
like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for
|
| 1547 |
+
weekdays, optionally separated by white space. Valid abbreviations
|
| 1548 |
+
are: Mon Tue Wed Thu Fri Sat Sun
|
| 1549 |
+
holidays : array_like of datetime64[D], optional
|
| 1550 |
+
An array of dates to consider as invalid dates. They may be
|
| 1551 |
+
specified in any order, and NaT (not-a-time) dates are ignored.
|
| 1552 |
+
This list is saved in a normalized form that is suited for
|
| 1553 |
+
fast calculations of valid days.
|
| 1554 |
+
busdaycal : busdaycalendar, optional
|
| 1555 |
+
A `busdaycalendar` object which specifies the valid days. If this
|
| 1556 |
+
parameter is provided, neither weekmask nor holidays may be
|
| 1557 |
+
provided.
|
| 1558 |
+
out : array of datetime64[D], optional
|
| 1559 |
+
If provided, this array is filled with the result.
|
| 1560 |
+
|
| 1561 |
+
Returns
|
| 1562 |
+
-------
|
| 1563 |
+
out : array of datetime64[D]
|
| 1564 |
+
An array with a shape from broadcasting ``dates`` and ``offsets``
|
| 1565 |
+
together, containing the dates with offsets applied.
|
| 1566 |
+
|
| 1567 |
+
See Also
|
| 1568 |
+
--------
|
| 1569 |
+
busdaycalendar : An object that specifies a custom set of valid days.
|
| 1570 |
+
is_busday : Returns a boolean array indicating valid days.
|
| 1571 |
+
busday_count : Counts how many valid days are in a half-open date range.
|
| 1572 |
+
|
| 1573 |
+
Examples
|
| 1574 |
+
--------
|
| 1575 |
+
>>> import numpy as np
|
| 1576 |
+
>>> # First business day in October 2011 (not accounting for holidays)
|
| 1577 |
+
... np.busday_offset('2011-10', 0, roll='forward')
|
| 1578 |
+
np.datetime64('2011-10-03')
|
| 1579 |
+
>>> # Last business day in February 2012 (not accounting for holidays)
|
| 1580 |
+
... np.busday_offset('2012-03', -1, roll='forward')
|
| 1581 |
+
np.datetime64('2012-02-29')
|
| 1582 |
+
>>> # Third Wednesday in January 2011
|
| 1583 |
+
... np.busday_offset('2011-01', 2, roll='forward', weekmask='Wed')
|
| 1584 |
+
np.datetime64('2011-01-19')
|
| 1585 |
+
>>> # 2012 Mother's Day in Canada and the U.S.
|
| 1586 |
+
... np.busday_offset('2012-05', 1, roll='forward', weekmask='Sun')
|
| 1587 |
+
np.datetime64('2012-05-13')
|
| 1588 |
+
|
| 1589 |
+
>>> # First business day on or after a date
|
| 1590 |
+
... np.busday_offset('2011-03-20', 0, roll='forward')
|
| 1591 |
+
np.datetime64('2011-03-21')
|
| 1592 |
+
>>> np.busday_offset('2011-03-22', 0, roll='forward')
|
| 1593 |
+
np.datetime64('2011-03-22')
|
| 1594 |
+
>>> # First business day after a date
|
| 1595 |
+
... np.busday_offset('2011-03-20', 1, roll='backward')
|
| 1596 |
+
np.datetime64('2011-03-21')
|
| 1597 |
+
>>> np.busday_offset('2011-03-22', 1, roll='backward')
|
| 1598 |
+
np.datetime64('2011-03-23')
|
| 1599 |
+
"""
|
| 1600 |
+
return (dates, offsets, weekmask, holidays, out)
|
| 1601 |
+
|
| 1602 |
+
|
| 1603 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.busday_count)
|
| 1604 |
+
def busday_count(begindates, enddates, weekmask="1111100", holidays=(),
|
| 1605 |
+
busdaycal=None, out=None):
|
| 1606 |
+
"""
|
| 1607 |
+
busday_count(
|
| 1608 |
+
begindates,
|
| 1609 |
+
enddates,
|
| 1610 |
+
weekmask='1111100',
|
| 1611 |
+
holidays=[],
|
| 1612 |
+
busdaycal=None,
|
| 1613 |
+
out=None
|
| 1614 |
+
)
|
| 1615 |
+
|
| 1616 |
+
Counts the number of valid days between `begindates` and
|
| 1617 |
+
`enddates`, not including the day of `enddates`.
|
| 1618 |
+
|
| 1619 |
+
If ``enddates`` specifies a date value that is earlier than the
|
| 1620 |
+
corresponding ``begindates`` date value, the count will be negative.
|
| 1621 |
+
|
| 1622 |
+
Parameters
|
| 1623 |
+
----------
|
| 1624 |
+
begindates : array_like of datetime64[D]
|
| 1625 |
+
The array of the first dates for counting.
|
| 1626 |
+
enddates : array_like of datetime64[D]
|
| 1627 |
+
The array of the end dates for counting, which are excluded
|
| 1628 |
+
from the count themselves.
|
| 1629 |
+
weekmask : str or array_like of bool, optional
|
| 1630 |
+
A seven-element array indicating which of Monday through Sunday are
|
| 1631 |
+
valid days. May be specified as a length-seven list or array, like
|
| 1632 |
+
[1,1,1,1,1,0,0]; a length-seven string, like '1111100'; or a string
|
| 1633 |
+
like "Mon Tue Wed Thu Fri", made up of 3-character abbreviations for
|
| 1634 |
+
weekdays, optionally separated by white space. Valid abbreviations
|
| 1635 |
+
are: Mon Tue Wed Thu Fri Sat Sun
|
| 1636 |
+
holidays : array_like of datetime64[D], optional
|
| 1637 |
+
An array of dates to consider as invalid dates. They may be
|
| 1638 |
+
specified in any order, and NaT (not-a-time) dates are ignored.
|
| 1639 |
+
This list is saved in a normalized form that is suited for
|
| 1640 |
+
fast calculations of valid days.
|
| 1641 |
+
busdaycal : busdaycalendar, optional
|
| 1642 |
+
A `busdaycalendar` object which specifies the valid days. If this
|
| 1643 |
+
parameter is provided, neither weekmask nor holidays may be
|
| 1644 |
+
provided.
|
| 1645 |
+
out : array of int, optional
|
| 1646 |
+
If provided, this array is filled with the result.
|
| 1647 |
+
|
| 1648 |
+
Returns
|
| 1649 |
+
-------
|
| 1650 |
+
out : array of int
|
| 1651 |
+
An array with a shape from broadcasting ``begindates`` and ``enddates``
|
| 1652 |
+
together, containing the number of valid days between
|
| 1653 |
+
the begin and end dates.
|
| 1654 |
+
|
| 1655 |
+
See Also
|
| 1656 |
+
--------
|
| 1657 |
+
busdaycalendar : An object that specifies a custom set of valid days.
|
| 1658 |
+
is_busday : Returns a boolean array indicating valid days.
|
| 1659 |
+
busday_offset : Applies an offset counted in valid days.
|
| 1660 |
+
|
| 1661 |
+
Examples
|
| 1662 |
+
--------
|
| 1663 |
+
>>> import numpy as np
|
| 1664 |
+
>>> # Number of weekdays in January 2011
|
| 1665 |
+
... np.busday_count('2011-01', '2011-02')
|
| 1666 |
+
21
|
| 1667 |
+
>>> # Number of weekdays in 2011
|
| 1668 |
+
>>> np.busday_count('2011', '2012')
|
| 1669 |
+
260
|
| 1670 |
+
>>> # Number of Saturdays in 2011
|
| 1671 |
+
... np.busday_count('2011', '2012', weekmask='Sat')
|
| 1672 |
+
53
|
| 1673 |
+
"""
|
| 1674 |
+
return (begindates, enddates, weekmask, holidays, out)
|
| 1675 |
+
|
| 1676 |
+
|
| 1677 |
+
@array_function_from_c_func_and_dispatcher(_multiarray_umath.datetime_as_string)
|
| 1678 |
+
def datetime_as_string(arr, unit=None, timezone="naive", casting="same_kind"):
|
| 1679 |
+
"""
|
| 1680 |
+
datetime_as_string(arr, unit=None, timezone='naive', casting='same_kind')
|
| 1681 |
+
|
| 1682 |
+
Convert an array of datetimes into an array of strings.
|
| 1683 |
+
|
| 1684 |
+
Parameters
|
| 1685 |
+
----------
|
| 1686 |
+
arr : array_like of datetime64
|
| 1687 |
+
The array of UTC timestamps to format.
|
| 1688 |
+
unit : str
|
| 1689 |
+
One of None, 'auto', or
|
| 1690 |
+
a :ref:`datetime unit <arrays.dtypes.dateunits>`.
|
| 1691 |
+
timezone : {'naive', 'UTC', 'local'} or tzinfo
|
| 1692 |
+
Timezone information to use when displaying the datetime. If 'UTC',
|
| 1693 |
+
end with a Z to indicate UTC time. If 'local', convert to the local
|
| 1694 |
+
timezone first, and suffix with a +-#### timezone offset. If a tzinfo
|
| 1695 |
+
object, then do as with 'local', but use the specified timezone.
|
| 1696 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}
|
| 1697 |
+
Casting to allow when changing between datetime units.
|
| 1698 |
+
|
| 1699 |
+
Returns
|
| 1700 |
+
-------
|
| 1701 |
+
str_arr : ndarray
|
| 1702 |
+
An array of strings the same shape as `arr`.
|
| 1703 |
+
|
| 1704 |
+
Examples
|
| 1705 |
+
--------
|
| 1706 |
+
>>> import numpy as np
|
| 1707 |
+
>>> from zoneinfo import ZoneInfo
|
| 1708 |
+
>>> d = np.arange('2002-10-27T04:30', 4*60, 60, dtype='M8[m]')
|
| 1709 |
+
>>> d
|
| 1710 |
+
array(['2002-10-27T04:30', '2002-10-27T05:30', '2002-10-27T06:30',
|
| 1711 |
+
'2002-10-27T07:30'], dtype='datetime64[m]')
|
| 1712 |
+
|
| 1713 |
+
Setting the timezone to UTC shows the same information, but with a Z suffix
|
| 1714 |
+
|
| 1715 |
+
>>> np.datetime_as_string(d, timezone='UTC')
|
| 1716 |
+
array(['2002-10-27T04:30Z', '2002-10-27T05:30Z', '2002-10-27T06:30Z',
|
| 1717 |
+
'2002-10-27T07:30Z'], dtype='<U35')
|
| 1718 |
+
|
| 1719 |
+
Note that we picked datetimes that cross a DST boundary. Passing in a
|
| 1720 |
+
``ZoneInfo`` object will print the appropriate offset
|
| 1721 |
+
|
| 1722 |
+
>>> np.datetime_as_string(d, timezone=ZoneInfo('US/Eastern'))
|
| 1723 |
+
array(['2002-10-27T00:30-0400', '2002-10-27T01:30-0400',
|
| 1724 |
+
'2002-10-27T01:30-0500', '2002-10-27T02:30-0500'], dtype='<U39')
|
| 1725 |
+
|
| 1726 |
+
Passing in a unit will change the precision
|
| 1727 |
+
|
| 1728 |
+
>>> np.datetime_as_string(d, unit='h')
|
| 1729 |
+
array(['2002-10-27T04', '2002-10-27T05', '2002-10-27T06', '2002-10-27T07'],
|
| 1730 |
+
dtype='<U32')
|
| 1731 |
+
>>> np.datetime_as_string(d, unit='s')
|
| 1732 |
+
array(['2002-10-27T04:30:00', '2002-10-27T05:30:00', '2002-10-27T06:30:00',
|
| 1733 |
+
'2002-10-27T07:30:00'], dtype='<U38')
|
| 1734 |
+
|
| 1735 |
+
'casting' can be used to specify whether precision can be changed
|
| 1736 |
+
|
| 1737 |
+
>>> np.datetime_as_string(d, unit='h', casting='safe')
|
| 1738 |
+
Traceback (most recent call last):
|
| 1739 |
+
...
|
| 1740 |
+
TypeError: Cannot create a datetime string as units 'h' from a NumPy
|
| 1741 |
+
datetime with units 'm' according to the rule 'safe'
|
| 1742 |
+
"""
|
| 1743 |
+
return (arr,)
|
v12x/pylib/numpy/_core/numeric.py
ADDED
|
@@ -0,0 +1,2707 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import builtins
|
| 2 |
+
import functools
|
| 3 |
+
import itertools
|
| 4 |
+
import math
|
| 5 |
+
import numbers
|
| 6 |
+
import operator
|
| 7 |
+
import sys
|
| 8 |
+
import warnings
|
| 9 |
+
|
| 10 |
+
import numpy as np
|
| 11 |
+
from numpy.exceptions import AxisError
|
| 12 |
+
|
| 13 |
+
from . import multiarray, numerictypes, numerictypes as nt, overrides, shape_base, umath
|
| 14 |
+
from ._ufunc_config import errstate
|
| 15 |
+
from .multiarray import ( # noqa: F401
|
| 16 |
+
ALLOW_THREADS,
|
| 17 |
+
BUFSIZE,
|
| 18 |
+
CLIP,
|
| 19 |
+
MAXDIMS,
|
| 20 |
+
MAY_SHARE_BOUNDS,
|
| 21 |
+
MAY_SHARE_EXACT,
|
| 22 |
+
RAISE,
|
| 23 |
+
WRAP,
|
| 24 |
+
arange,
|
| 25 |
+
array,
|
| 26 |
+
asanyarray,
|
| 27 |
+
asarray,
|
| 28 |
+
ascontiguousarray,
|
| 29 |
+
asfortranarray,
|
| 30 |
+
broadcast,
|
| 31 |
+
can_cast,
|
| 32 |
+
concatenate,
|
| 33 |
+
copyto,
|
| 34 |
+
dot,
|
| 35 |
+
dtype,
|
| 36 |
+
empty,
|
| 37 |
+
empty_like,
|
| 38 |
+
flatiter,
|
| 39 |
+
from_dlpack,
|
| 40 |
+
frombuffer,
|
| 41 |
+
fromfile,
|
| 42 |
+
fromiter,
|
| 43 |
+
fromstring,
|
| 44 |
+
inner,
|
| 45 |
+
lexsort,
|
| 46 |
+
matmul,
|
| 47 |
+
may_share_memory,
|
| 48 |
+
min_scalar_type,
|
| 49 |
+
ndarray,
|
| 50 |
+
nditer,
|
| 51 |
+
nested_iters,
|
| 52 |
+
normalize_axis_index,
|
| 53 |
+
promote_types,
|
| 54 |
+
putmask,
|
| 55 |
+
result_type,
|
| 56 |
+
shares_memory,
|
| 57 |
+
vdot,
|
| 58 |
+
vecdot,
|
| 59 |
+
where,
|
| 60 |
+
zeros,
|
| 61 |
+
)
|
| 62 |
+
from .overrides import finalize_array_function_like, set_module
|
| 63 |
+
from .umath import NAN, PINF, invert, multiply, sin
|
| 64 |
+
|
| 65 |
+
bitwise_not = invert
|
| 66 |
+
ufunc = type(sin)
|
| 67 |
+
newaxis = None
|
| 68 |
+
|
| 69 |
+
array_function_dispatch = functools.partial(
|
| 70 |
+
overrides.array_function_dispatch, module='numpy')
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
__all__ = [
|
| 74 |
+
'newaxis', 'ndarray', 'flatiter', 'nditer', 'nested_iters', 'ufunc',
|
| 75 |
+
'arange', 'array', 'asarray', 'asanyarray', 'ascontiguousarray',
|
| 76 |
+
'asfortranarray', 'zeros', 'count_nonzero', 'empty', 'broadcast', 'dtype',
|
| 77 |
+
'fromstring', 'fromfile', 'frombuffer', 'from_dlpack', 'where',
|
| 78 |
+
'argwhere', 'copyto', 'concatenate', 'lexsort', 'astype',
|
| 79 |
+
'can_cast', 'promote_types', 'min_scalar_type',
|
| 80 |
+
'result_type', 'isfortran', 'empty_like', 'zeros_like', 'ones_like',
|
| 81 |
+
'correlate', 'convolve', 'inner', 'dot', 'outer', 'vdot', 'roll',
|
| 82 |
+
'rollaxis', 'moveaxis', 'cross', 'tensordot', 'little_endian',
|
| 83 |
+
'fromiter', 'array_equal', 'array_equiv', 'indices', 'fromfunction',
|
| 84 |
+
'isclose', 'isscalar', 'binary_repr', 'base_repr', 'ones',
|
| 85 |
+
'identity', 'allclose', 'putmask',
|
| 86 |
+
'flatnonzero', 'inf', 'nan', 'False_', 'True_', 'bitwise_not',
|
| 87 |
+
'full', 'full_like', 'matmul', 'vecdot', 'shares_memory',
|
| 88 |
+
'may_share_memory']
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def _zeros_like_dispatcher(
|
| 92 |
+
a, dtype=None, order=None, subok=None, shape=None, *, device=None
|
| 93 |
+
):
|
| 94 |
+
return (a,)
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
@array_function_dispatch(_zeros_like_dispatcher)
|
| 98 |
+
def zeros_like(
|
| 99 |
+
a, dtype=None, order='K', subok=True, shape=None, *, device=None
|
| 100 |
+
):
|
| 101 |
+
"""
|
| 102 |
+
Return an array of zeros with the same shape and type as a given array.
|
| 103 |
+
|
| 104 |
+
Parameters
|
| 105 |
+
----------
|
| 106 |
+
a : array_like
|
| 107 |
+
The shape and data-type of `a` define these same attributes of
|
| 108 |
+
the returned array.
|
| 109 |
+
dtype : data-type, optional
|
| 110 |
+
Overrides the data type of the result.
|
| 111 |
+
order : {'C', 'F', 'A', or 'K'}, optional
|
| 112 |
+
Overrides the memory layout of the result. 'C' means C-order,
|
| 113 |
+
'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous,
|
| 114 |
+
'C' otherwise. 'K' means match the layout of `a` as closely
|
| 115 |
+
as possible.
|
| 116 |
+
subok : bool, optional.
|
| 117 |
+
If True, then the newly created array will use the sub-class
|
| 118 |
+
type of `a`, otherwise it will be a base-class array. Defaults
|
| 119 |
+
to True.
|
| 120 |
+
shape : int or sequence of ints, optional.
|
| 121 |
+
Overrides the shape of the result. If order='K' and the number of
|
| 122 |
+
dimensions is unchanged, will try to keep order, otherwise,
|
| 123 |
+
order='C' is implied.
|
| 124 |
+
device : str, optional
|
| 125 |
+
The device on which to place the created array. Default: None.
|
| 126 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 127 |
+
|
| 128 |
+
.. versionadded:: 2.0.0
|
| 129 |
+
|
| 130 |
+
Returns
|
| 131 |
+
-------
|
| 132 |
+
out : ndarray
|
| 133 |
+
Array of zeros with the same shape and type as `a`.
|
| 134 |
+
|
| 135 |
+
See Also
|
| 136 |
+
--------
|
| 137 |
+
empty_like : Return an empty array with shape and type of input.
|
| 138 |
+
ones_like : Return an array of ones with shape and type of input.
|
| 139 |
+
full_like : Return a new array with shape of input filled with value.
|
| 140 |
+
zeros : Return a new array setting values to zero.
|
| 141 |
+
|
| 142 |
+
Examples
|
| 143 |
+
--------
|
| 144 |
+
>>> import numpy as np
|
| 145 |
+
>>> x = np.arange(6)
|
| 146 |
+
>>> x = x.reshape((2, 3))
|
| 147 |
+
>>> x
|
| 148 |
+
array([[0, 1, 2],
|
| 149 |
+
[3, 4, 5]])
|
| 150 |
+
>>> np.zeros_like(x)
|
| 151 |
+
array([[0, 0, 0],
|
| 152 |
+
[0, 0, 0]])
|
| 153 |
+
|
| 154 |
+
>>> y = np.arange(3, dtype=np.float64)
|
| 155 |
+
>>> y
|
| 156 |
+
array([0., 1., 2.])
|
| 157 |
+
>>> np.zeros_like(y)
|
| 158 |
+
array([0., 0., 0.])
|
| 159 |
+
|
| 160 |
+
"""
|
| 161 |
+
res = empty_like(
|
| 162 |
+
a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
|
| 163 |
+
)
|
| 164 |
+
# needed instead of a 0 to get same result as zeros for string dtypes
|
| 165 |
+
z = zeros(1, dtype=res.dtype)
|
| 166 |
+
multiarray.copyto(res, z, casting='unsafe')
|
| 167 |
+
return res
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
@finalize_array_function_like
|
| 171 |
+
@set_module('numpy')
|
| 172 |
+
def ones(shape, dtype=None, order='C', *, device=None, like=None):
|
| 173 |
+
"""
|
| 174 |
+
Return a new array of given shape and type, filled with ones.
|
| 175 |
+
|
| 176 |
+
Parameters
|
| 177 |
+
----------
|
| 178 |
+
shape : int or sequence of ints
|
| 179 |
+
Shape of the new array, e.g., ``(2, 3)`` or ``2``.
|
| 180 |
+
dtype : data-type, optional
|
| 181 |
+
The desired data-type for the array, e.g., `numpy.int8`. Default is
|
| 182 |
+
`numpy.float64`.
|
| 183 |
+
order : {'C', 'F'}, optional, default: C
|
| 184 |
+
Whether to store multi-dimensional data in row-major
|
| 185 |
+
(C-style) or column-major (Fortran-style) order in
|
| 186 |
+
memory.
|
| 187 |
+
device : str, optional
|
| 188 |
+
The device on which to place the created array. Default: None.
|
| 189 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 190 |
+
|
| 191 |
+
.. versionadded:: 2.0.0
|
| 192 |
+
${ARRAY_FUNCTION_LIKE}
|
| 193 |
+
|
| 194 |
+
.. versionadded:: 1.20.0
|
| 195 |
+
|
| 196 |
+
Returns
|
| 197 |
+
-------
|
| 198 |
+
out : ndarray
|
| 199 |
+
Array of ones with the given shape, dtype, and order.
|
| 200 |
+
|
| 201 |
+
See Also
|
| 202 |
+
--------
|
| 203 |
+
ones_like : Return an array of ones with shape and type of input.
|
| 204 |
+
empty : Return a new uninitialized array.
|
| 205 |
+
zeros : Return a new array setting values to zero.
|
| 206 |
+
full : Return a new array of given shape filled with value.
|
| 207 |
+
|
| 208 |
+
Examples
|
| 209 |
+
--------
|
| 210 |
+
>>> import numpy as np
|
| 211 |
+
>>> np.ones(5)
|
| 212 |
+
array([1., 1., 1., 1., 1.])
|
| 213 |
+
|
| 214 |
+
>>> np.ones((5,), dtype=np.int_)
|
| 215 |
+
array([1, 1, 1, 1, 1])
|
| 216 |
+
|
| 217 |
+
>>> np.ones((2, 1))
|
| 218 |
+
array([[1.],
|
| 219 |
+
[1.]])
|
| 220 |
+
|
| 221 |
+
>>> s = (2,2)
|
| 222 |
+
>>> np.ones(s)
|
| 223 |
+
array([[1., 1.],
|
| 224 |
+
[1., 1.]])
|
| 225 |
+
|
| 226 |
+
"""
|
| 227 |
+
if like is not None:
|
| 228 |
+
return _ones_with_like(
|
| 229 |
+
like, shape, dtype=dtype, order=order, device=device
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
a = empty(shape, dtype, order, device=device)
|
| 233 |
+
multiarray.copyto(a, 1, casting='unsafe')
|
| 234 |
+
return a
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
_ones_with_like = array_function_dispatch()(ones)
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def _ones_like_dispatcher(
|
| 241 |
+
a, dtype=None, order=None, subok=None, shape=None, *, device=None
|
| 242 |
+
):
|
| 243 |
+
return (a,)
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
@array_function_dispatch(_ones_like_dispatcher)
|
| 247 |
+
def ones_like(
|
| 248 |
+
a, dtype=None, order='K', subok=True, shape=None, *, device=None
|
| 249 |
+
):
|
| 250 |
+
"""
|
| 251 |
+
Return an array of ones with the same shape and type as a given array.
|
| 252 |
+
|
| 253 |
+
Parameters
|
| 254 |
+
----------
|
| 255 |
+
a : array_like
|
| 256 |
+
The shape and data-type of `a` define these same attributes of
|
| 257 |
+
the returned array.
|
| 258 |
+
dtype : data-type, optional
|
| 259 |
+
Overrides the data type of the result.
|
| 260 |
+
order : {'C', 'F', 'A', or 'K'}, optional
|
| 261 |
+
Overrides the memory layout of the result. 'C' means C-order,
|
| 262 |
+
'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous,
|
| 263 |
+
'C' otherwise. 'K' means match the layout of `a` as closely
|
| 264 |
+
as possible.
|
| 265 |
+
subok : bool, optional.
|
| 266 |
+
If True, then the newly created array will use the sub-class
|
| 267 |
+
type of `a`, otherwise it will be a base-class array. Defaults
|
| 268 |
+
to True.
|
| 269 |
+
shape : int or sequence of ints, optional.
|
| 270 |
+
Overrides the shape of the result. If order='K' and the number of
|
| 271 |
+
dimensions is unchanged, will try to keep order, otherwise,
|
| 272 |
+
order='C' is implied.
|
| 273 |
+
device : str, optional
|
| 274 |
+
The device on which to place the created array. Default: None.
|
| 275 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 276 |
+
|
| 277 |
+
.. versionadded:: 2.0.0
|
| 278 |
+
|
| 279 |
+
Returns
|
| 280 |
+
-------
|
| 281 |
+
out : ndarray
|
| 282 |
+
Array of ones with the same shape and type as `a`.
|
| 283 |
+
|
| 284 |
+
See Also
|
| 285 |
+
--------
|
| 286 |
+
empty_like : Return an empty array with shape and type of input.
|
| 287 |
+
zeros_like : Return an array of zeros with shape and type of input.
|
| 288 |
+
full_like : Return a new array with shape of input filled with value.
|
| 289 |
+
ones : Return a new array setting values to one.
|
| 290 |
+
|
| 291 |
+
Examples
|
| 292 |
+
--------
|
| 293 |
+
>>> import numpy as np
|
| 294 |
+
>>> x = np.arange(6)
|
| 295 |
+
>>> x = x.reshape((2, 3))
|
| 296 |
+
>>> x
|
| 297 |
+
array([[0, 1, 2],
|
| 298 |
+
[3, 4, 5]])
|
| 299 |
+
>>> np.ones_like(x)
|
| 300 |
+
array([[1, 1, 1],
|
| 301 |
+
[1, 1, 1]])
|
| 302 |
+
|
| 303 |
+
>>> y = np.arange(3, dtype=np.float64)
|
| 304 |
+
>>> y
|
| 305 |
+
array([0., 1., 2.])
|
| 306 |
+
>>> np.ones_like(y)
|
| 307 |
+
array([1., 1., 1.])
|
| 308 |
+
|
| 309 |
+
"""
|
| 310 |
+
res = empty_like(
|
| 311 |
+
a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
|
| 312 |
+
)
|
| 313 |
+
multiarray.copyto(res, 1, casting='unsafe')
|
| 314 |
+
return res
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
def _full_dispatcher(
|
| 318 |
+
shape, fill_value, dtype=None, order=None, *, device=None, like=None
|
| 319 |
+
):
|
| 320 |
+
return (like,)
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
@finalize_array_function_like
|
| 324 |
+
@set_module('numpy')
|
| 325 |
+
def full(shape, fill_value, dtype=None, order='C', *, device=None, like=None):
|
| 326 |
+
"""
|
| 327 |
+
Return a new array of given shape and type, filled with `fill_value`.
|
| 328 |
+
|
| 329 |
+
Parameters
|
| 330 |
+
----------
|
| 331 |
+
shape : int or sequence of ints
|
| 332 |
+
Shape of the new array, e.g., ``(2, 3)`` or ``2``.
|
| 333 |
+
fill_value : scalar or array_like
|
| 334 |
+
Fill value.
|
| 335 |
+
dtype : data-type, optional
|
| 336 |
+
The desired data-type for the array The default, None, means
|
| 337 |
+
``np.array(fill_value).dtype``.
|
| 338 |
+
order : {'C', 'F'}, optional
|
| 339 |
+
Whether to store multidimensional data in C- or Fortran-contiguous
|
| 340 |
+
(row- or column-wise) order in memory.
|
| 341 |
+
device : str, optional
|
| 342 |
+
The device on which to place the created array. Default: None.
|
| 343 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 344 |
+
|
| 345 |
+
.. versionadded:: 2.0.0
|
| 346 |
+
${ARRAY_FUNCTION_LIKE}
|
| 347 |
+
|
| 348 |
+
.. versionadded:: 1.20.0
|
| 349 |
+
|
| 350 |
+
Returns
|
| 351 |
+
-------
|
| 352 |
+
out : ndarray
|
| 353 |
+
Array of `fill_value` with the given shape, dtype, and order.
|
| 354 |
+
|
| 355 |
+
See Also
|
| 356 |
+
--------
|
| 357 |
+
full_like : Return a new array with shape of input filled with value.
|
| 358 |
+
empty : Return a new uninitialized array.
|
| 359 |
+
ones : Return a new array setting values to one.
|
| 360 |
+
zeros : Return a new array setting values to zero.
|
| 361 |
+
|
| 362 |
+
Examples
|
| 363 |
+
--------
|
| 364 |
+
>>> import numpy as np
|
| 365 |
+
>>> np.full((2, 2), np.inf)
|
| 366 |
+
array([[inf, inf],
|
| 367 |
+
[inf, inf]])
|
| 368 |
+
>>> np.full((2, 2), 10)
|
| 369 |
+
array([[10, 10],
|
| 370 |
+
[10, 10]])
|
| 371 |
+
|
| 372 |
+
>>> np.full((2, 2), [1, 2])
|
| 373 |
+
array([[1, 2],
|
| 374 |
+
[1, 2]])
|
| 375 |
+
|
| 376 |
+
"""
|
| 377 |
+
if like is not None:
|
| 378 |
+
return _full_with_like(
|
| 379 |
+
like, shape, fill_value, dtype=dtype, order=order, device=device
|
| 380 |
+
)
|
| 381 |
+
|
| 382 |
+
if dtype is None:
|
| 383 |
+
fill_value = asarray(fill_value)
|
| 384 |
+
dtype = fill_value.dtype
|
| 385 |
+
a = empty(shape, dtype, order, device=device)
|
| 386 |
+
multiarray.copyto(a, fill_value, casting='unsafe')
|
| 387 |
+
return a
|
| 388 |
+
|
| 389 |
+
|
| 390 |
+
_full_with_like = array_function_dispatch()(full)
|
| 391 |
+
|
| 392 |
+
|
| 393 |
+
def _full_like_dispatcher(
|
| 394 |
+
a, fill_value, dtype=None, order=None, subok=None, shape=None,
|
| 395 |
+
*, device=None
|
| 396 |
+
):
|
| 397 |
+
return (a,)
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
@array_function_dispatch(_full_like_dispatcher)
|
| 401 |
+
def full_like(
|
| 402 |
+
a, fill_value, dtype=None, order='K', subok=True, shape=None,
|
| 403 |
+
*, device=None
|
| 404 |
+
):
|
| 405 |
+
"""
|
| 406 |
+
Return a full array with the same shape and type as a given array.
|
| 407 |
+
|
| 408 |
+
Parameters
|
| 409 |
+
----------
|
| 410 |
+
a : array_like
|
| 411 |
+
The shape and data-type of `a` define these same attributes of
|
| 412 |
+
the returned array.
|
| 413 |
+
fill_value : array_like
|
| 414 |
+
Fill value.
|
| 415 |
+
dtype : data-type, optional
|
| 416 |
+
Overrides the data type of the result.
|
| 417 |
+
order : {'C', 'F', 'A', or 'K'}, optional
|
| 418 |
+
Overrides the memory layout of the result. 'C' means C-order,
|
| 419 |
+
'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous,
|
| 420 |
+
'C' otherwise. 'K' means match the layout of `a` as closely
|
| 421 |
+
as possible.
|
| 422 |
+
subok : bool, optional.
|
| 423 |
+
If True, then the newly created array will use the sub-class
|
| 424 |
+
type of `a`, otherwise it will be a base-class array. Defaults
|
| 425 |
+
to True.
|
| 426 |
+
shape : int or sequence of ints, optional.
|
| 427 |
+
Overrides the shape of the result. If order='K' and the number of
|
| 428 |
+
dimensions is unchanged, will try to keep order, otherwise,
|
| 429 |
+
order='C' is implied.
|
| 430 |
+
device : str, optional
|
| 431 |
+
The device on which to place the created array. Default: None.
|
| 432 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 433 |
+
|
| 434 |
+
.. versionadded:: 2.0.0
|
| 435 |
+
|
| 436 |
+
Returns
|
| 437 |
+
-------
|
| 438 |
+
out : ndarray
|
| 439 |
+
Array of `fill_value` with the same shape and type as `a`.
|
| 440 |
+
|
| 441 |
+
See Also
|
| 442 |
+
--------
|
| 443 |
+
empty_like : Return an empty array with shape and type of input.
|
| 444 |
+
ones_like : Return an array of ones with shape and type of input.
|
| 445 |
+
zeros_like : Return an array of zeros with shape and type of input.
|
| 446 |
+
full : Return a new array of given shape filled with value.
|
| 447 |
+
|
| 448 |
+
Examples
|
| 449 |
+
--------
|
| 450 |
+
>>> import numpy as np
|
| 451 |
+
>>> x = np.arange(6, dtype=np.int_)
|
| 452 |
+
>>> np.full_like(x, 1)
|
| 453 |
+
array([1, 1, 1, 1, 1, 1])
|
| 454 |
+
>>> np.full_like(x, 0.1)
|
| 455 |
+
array([0, 0, 0, 0, 0, 0])
|
| 456 |
+
>>> np.full_like(x, 0.1, dtype=np.float64)
|
| 457 |
+
array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
|
| 458 |
+
>>> np.full_like(x, np.nan, dtype=np.float64)
|
| 459 |
+
array([nan, nan, nan, nan, nan, nan])
|
| 460 |
+
|
| 461 |
+
>>> y = np.arange(6, dtype=np.float64)
|
| 462 |
+
>>> np.full_like(y, 0.1)
|
| 463 |
+
array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
|
| 464 |
+
|
| 465 |
+
>>> y = np.zeros([2, 2, 3], dtype=np.int_)
|
| 466 |
+
>>> np.full_like(y, [0, 0, 255])
|
| 467 |
+
array([[[ 0, 0, 255],
|
| 468 |
+
[ 0, 0, 255]],
|
| 469 |
+
[[ 0, 0, 255],
|
| 470 |
+
[ 0, 0, 255]]])
|
| 471 |
+
"""
|
| 472 |
+
res = empty_like(
|
| 473 |
+
a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
|
| 474 |
+
)
|
| 475 |
+
multiarray.copyto(res, fill_value, casting='unsafe')
|
| 476 |
+
return res
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
def _count_nonzero_dispatcher(a, axis=None, *, keepdims=None):
|
| 480 |
+
return (a,)
|
| 481 |
+
|
| 482 |
+
|
| 483 |
+
@array_function_dispatch(_count_nonzero_dispatcher)
|
| 484 |
+
def count_nonzero(a, axis=None, *, keepdims=False):
|
| 485 |
+
"""
|
| 486 |
+
Counts the number of non-zero values in the array ``a``.
|
| 487 |
+
|
| 488 |
+
A non-zero value is one that evaluates to truthful in a boolean
|
| 489 |
+
context, including any non-zero number and any string that
|
| 490 |
+
is not empty. This function recursively counts how many elements
|
| 491 |
+
in ``a`` (and its sub-arrays) are non-zero values.
|
| 492 |
+
|
| 493 |
+
Parameters
|
| 494 |
+
----------
|
| 495 |
+
a : array_like
|
| 496 |
+
The array for which to count non-zeros.
|
| 497 |
+
axis : int or tuple, optional
|
| 498 |
+
Axis or tuple of axes along which to count non-zeros.
|
| 499 |
+
Default is None, meaning that non-zeros will be counted
|
| 500 |
+
along a flattened version of ``a``.
|
| 501 |
+
keepdims : bool, optional
|
| 502 |
+
If this is set to True, the axes that are counted are left
|
| 503 |
+
in the result as dimensions with size one. With this option,
|
| 504 |
+
the result will broadcast correctly against the input array.
|
| 505 |
+
|
| 506 |
+
Returns
|
| 507 |
+
-------
|
| 508 |
+
count : int or array of int
|
| 509 |
+
Number of non-zero values in the array along a given axis.
|
| 510 |
+
Otherwise, the total number of non-zero values in the array
|
| 511 |
+
is returned.
|
| 512 |
+
|
| 513 |
+
See Also
|
| 514 |
+
--------
|
| 515 |
+
nonzero : Return the coordinates of all the non-zero values.
|
| 516 |
+
|
| 517 |
+
Examples
|
| 518 |
+
--------
|
| 519 |
+
>>> import numpy as np
|
| 520 |
+
>>> np.count_nonzero(np.eye(4))
|
| 521 |
+
np.int64(4)
|
| 522 |
+
>>> a = np.array([[0, 1, 7, 0],
|
| 523 |
+
... [3, 0, 2, 19]])
|
| 524 |
+
>>> np.count_nonzero(a)
|
| 525 |
+
np.int64(5)
|
| 526 |
+
>>> np.count_nonzero(a, axis=0)
|
| 527 |
+
array([1, 1, 2, 1])
|
| 528 |
+
>>> np.count_nonzero(a, axis=1)
|
| 529 |
+
array([2, 3])
|
| 530 |
+
>>> np.count_nonzero(a, axis=1, keepdims=True)
|
| 531 |
+
array([[2],
|
| 532 |
+
[3]])
|
| 533 |
+
"""
|
| 534 |
+
if axis is None and not keepdims:
|
| 535 |
+
return multiarray.count_nonzero(a)
|
| 536 |
+
|
| 537 |
+
a = asanyarray(a)
|
| 538 |
+
|
| 539 |
+
# This is a performance optimization for character dtypes
|
| 540 |
+
# TODO: this can be removed if the legacy fixed-width string dtypes are ever removed
|
| 541 |
+
if np.issubdtype(a.dtype, np.character):
|
| 542 |
+
a_bool = a != a.dtype.type()
|
| 543 |
+
else:
|
| 544 |
+
a_bool = a.astype(np.bool, copy=False)
|
| 545 |
+
|
| 546 |
+
return a_bool.sum(axis=axis, dtype=np.intp, keepdims=keepdims)
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
@set_module('numpy')
|
| 550 |
+
def isfortran(a):
|
| 551 |
+
"""
|
| 552 |
+
Check if the array is Fortran contiguous but *not* C contiguous.
|
| 553 |
+
|
| 554 |
+
This function is obsolete. If you only want to check if an array is Fortran
|
| 555 |
+
contiguous use ``a.flags.f_contiguous`` instead.
|
| 556 |
+
|
| 557 |
+
Parameters
|
| 558 |
+
----------
|
| 559 |
+
a : ndarray
|
| 560 |
+
Input array.
|
| 561 |
+
|
| 562 |
+
Returns
|
| 563 |
+
-------
|
| 564 |
+
isfortran : bool
|
| 565 |
+
Returns True if the array is Fortran contiguous but *not* C contiguous.
|
| 566 |
+
|
| 567 |
+
|
| 568 |
+
Examples
|
| 569 |
+
--------
|
| 570 |
+
|
| 571 |
+
np.array allows to specify whether the array is written in C-contiguous
|
| 572 |
+
order (last index varies the fastest), or FORTRAN-contiguous order in
|
| 573 |
+
memory (first index varies the fastest).
|
| 574 |
+
|
| 575 |
+
>>> import numpy as np
|
| 576 |
+
>>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C')
|
| 577 |
+
>>> a
|
| 578 |
+
array([[1, 2, 3],
|
| 579 |
+
[4, 5, 6]])
|
| 580 |
+
>>> np.isfortran(a)
|
| 581 |
+
False
|
| 582 |
+
|
| 583 |
+
>>> b = np.array([[1, 2, 3], [4, 5, 6]], order='F')
|
| 584 |
+
>>> b
|
| 585 |
+
array([[1, 2, 3],
|
| 586 |
+
[4, 5, 6]])
|
| 587 |
+
>>> np.isfortran(b)
|
| 588 |
+
True
|
| 589 |
+
|
| 590 |
+
|
| 591 |
+
The transpose of a C-ordered array is a FORTRAN-ordered array.
|
| 592 |
+
|
| 593 |
+
>>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C')
|
| 594 |
+
>>> a
|
| 595 |
+
array([[1, 2, 3],
|
| 596 |
+
[4, 5, 6]])
|
| 597 |
+
>>> np.isfortran(a)
|
| 598 |
+
False
|
| 599 |
+
>>> b = a.T
|
| 600 |
+
>>> b
|
| 601 |
+
array([[1, 4],
|
| 602 |
+
[2, 5],
|
| 603 |
+
[3, 6]])
|
| 604 |
+
>>> np.isfortran(b)
|
| 605 |
+
True
|
| 606 |
+
|
| 607 |
+
C-ordered arrays evaluate as False even if they are also FORTRAN-ordered.
|
| 608 |
+
|
| 609 |
+
>>> np.isfortran(np.array([1, 2], order='F'))
|
| 610 |
+
False
|
| 611 |
+
|
| 612 |
+
"""
|
| 613 |
+
return a.flags.fnc
|
| 614 |
+
|
| 615 |
+
|
| 616 |
+
def _argwhere_dispatcher(a):
|
| 617 |
+
return (a,)
|
| 618 |
+
|
| 619 |
+
|
| 620 |
+
@array_function_dispatch(_argwhere_dispatcher)
|
| 621 |
+
def argwhere(a):
|
| 622 |
+
"""
|
| 623 |
+
Find the indices of array elements that are non-zero, grouped by element.
|
| 624 |
+
|
| 625 |
+
Parameters
|
| 626 |
+
----------
|
| 627 |
+
a : array_like
|
| 628 |
+
Input data.
|
| 629 |
+
|
| 630 |
+
Returns
|
| 631 |
+
-------
|
| 632 |
+
index_array : (N, a.ndim) ndarray
|
| 633 |
+
Indices of elements that are non-zero. Indices are grouped by element.
|
| 634 |
+
This array will have shape ``(N, a.ndim)`` where ``N`` is the number of
|
| 635 |
+
non-zero items.
|
| 636 |
+
|
| 637 |
+
See Also
|
| 638 |
+
--------
|
| 639 |
+
where, nonzero
|
| 640 |
+
|
| 641 |
+
Notes
|
| 642 |
+
-----
|
| 643 |
+
``np.argwhere(a)`` is almost the same as ``np.transpose(np.nonzero(a))``,
|
| 644 |
+
but produces a result of the correct shape for a 0D array.
|
| 645 |
+
|
| 646 |
+
The output of ``argwhere`` is not suitable for indexing arrays.
|
| 647 |
+
For this purpose use ``nonzero(a)`` instead.
|
| 648 |
+
|
| 649 |
+
Examples
|
| 650 |
+
--------
|
| 651 |
+
>>> import numpy as np
|
| 652 |
+
>>> x = np.arange(6).reshape(2,3)
|
| 653 |
+
>>> x
|
| 654 |
+
array([[0, 1, 2],
|
| 655 |
+
[3, 4, 5]])
|
| 656 |
+
>>> np.argwhere(x>1)
|
| 657 |
+
array([[0, 2],
|
| 658 |
+
[1, 0],
|
| 659 |
+
[1, 1],
|
| 660 |
+
[1, 2]])
|
| 661 |
+
|
| 662 |
+
"""
|
| 663 |
+
# nonzero does not behave well on 0d, so promote to 1d
|
| 664 |
+
if np.ndim(a) == 0:
|
| 665 |
+
a = shape_base.atleast_1d(a)
|
| 666 |
+
# then remove the added dimension
|
| 667 |
+
return argwhere(a)[:, :0]
|
| 668 |
+
return transpose(nonzero(a))
|
| 669 |
+
|
| 670 |
+
|
| 671 |
+
def _flatnonzero_dispatcher(a):
|
| 672 |
+
return (a,)
|
| 673 |
+
|
| 674 |
+
|
| 675 |
+
@array_function_dispatch(_flatnonzero_dispatcher)
|
| 676 |
+
def flatnonzero(a):
|
| 677 |
+
"""
|
| 678 |
+
Return indices that are non-zero in the flattened version of a.
|
| 679 |
+
|
| 680 |
+
This is equivalent to ``np.nonzero(np.ravel(a))[0]``.
|
| 681 |
+
|
| 682 |
+
Parameters
|
| 683 |
+
----------
|
| 684 |
+
a : array_like
|
| 685 |
+
Input data.
|
| 686 |
+
|
| 687 |
+
Returns
|
| 688 |
+
-------
|
| 689 |
+
res : ndarray
|
| 690 |
+
Output array, containing the indices of the elements of ``a.ravel()``
|
| 691 |
+
that are non-zero.
|
| 692 |
+
|
| 693 |
+
See Also
|
| 694 |
+
--------
|
| 695 |
+
nonzero : Return the indices of the non-zero elements of the input array.
|
| 696 |
+
ravel : Return a 1-D array containing the elements of the input array.
|
| 697 |
+
|
| 698 |
+
Examples
|
| 699 |
+
--------
|
| 700 |
+
>>> import numpy as np
|
| 701 |
+
>>> x = np.arange(-2, 3)
|
| 702 |
+
>>> x
|
| 703 |
+
array([-2, -1, 0, 1, 2])
|
| 704 |
+
>>> np.flatnonzero(x)
|
| 705 |
+
array([0, 1, 3, 4])
|
| 706 |
+
|
| 707 |
+
Use the indices of the non-zero elements as an index array to extract
|
| 708 |
+
these elements:
|
| 709 |
+
|
| 710 |
+
>>> x.ravel()[np.flatnonzero(x)]
|
| 711 |
+
array([-2, -1, 1, 2])
|
| 712 |
+
|
| 713 |
+
"""
|
| 714 |
+
return np.nonzero(np.ravel(a))[0]
|
| 715 |
+
|
| 716 |
+
|
| 717 |
+
def _correlate_dispatcher(a, v, mode=None):
|
| 718 |
+
return (a, v)
|
| 719 |
+
|
| 720 |
+
|
| 721 |
+
@array_function_dispatch(_correlate_dispatcher)
|
| 722 |
+
def correlate(a, v, mode='valid'):
|
| 723 |
+
r"""
|
| 724 |
+
Cross-correlation of two 1-dimensional sequences.
|
| 725 |
+
|
| 726 |
+
This function computes the correlation as generally defined in signal
|
| 727 |
+
processing texts [1]_:
|
| 728 |
+
|
| 729 |
+
.. math:: c_k = \sum_n a_{n+k} \cdot \overline{v}_n
|
| 730 |
+
|
| 731 |
+
with a and v sequences being zero-padded where necessary and
|
| 732 |
+
:math:`\overline v` denoting complex conjugation.
|
| 733 |
+
|
| 734 |
+
Parameters
|
| 735 |
+
----------
|
| 736 |
+
a, v : array_like
|
| 737 |
+
Input sequences.
|
| 738 |
+
mode : {'valid', 'same', 'full'}, optional
|
| 739 |
+
Refer to the `convolve` docstring. Note that the default
|
| 740 |
+
is 'valid', unlike `convolve`, which uses 'full'.
|
| 741 |
+
|
| 742 |
+
Returns
|
| 743 |
+
-------
|
| 744 |
+
out : ndarray
|
| 745 |
+
Discrete cross-correlation of `a` and `v`.
|
| 746 |
+
|
| 747 |
+
See Also
|
| 748 |
+
--------
|
| 749 |
+
convolve : Discrete, linear convolution of two one-dimensional sequences.
|
| 750 |
+
scipy.signal.correlate : uses FFT which has superior performance
|
| 751 |
+
on large arrays.
|
| 752 |
+
|
| 753 |
+
Notes
|
| 754 |
+
-----
|
| 755 |
+
The definition of correlation above is not unique and sometimes
|
| 756 |
+
correlation may be defined differently. Another common definition is [1]_:
|
| 757 |
+
|
| 758 |
+
.. math:: c'_k = \sum_n a_{n} \cdot \overline{v_{n+k}}
|
| 759 |
+
|
| 760 |
+
which is related to :math:`c_k` by :math:`c'_k = c_{-k}`.
|
| 761 |
+
|
| 762 |
+
`numpy.correlate` may perform slowly in large arrays (i.e. n = 1e5)
|
| 763 |
+
because it does not use the FFT to compute the convolution; in that case,
|
| 764 |
+
`scipy.signal.correlate` might be preferable.
|
| 765 |
+
|
| 766 |
+
References
|
| 767 |
+
----------
|
| 768 |
+
.. [1] Wikipedia, "Cross-correlation",
|
| 769 |
+
https://en.wikipedia.org/wiki/Cross-correlation
|
| 770 |
+
|
| 771 |
+
Examples
|
| 772 |
+
--------
|
| 773 |
+
>>> import numpy as np
|
| 774 |
+
>>> np.correlate([1, 2, 3], [0, 1, 0.5])
|
| 775 |
+
array([3.5])
|
| 776 |
+
>>> np.correlate([1, 2, 3], [0, 1, 0.5], "same")
|
| 777 |
+
array([2. , 3.5, 3. ])
|
| 778 |
+
>>> np.correlate([1, 2, 3], [0, 1, 0.5], "full")
|
| 779 |
+
array([0.5, 2. , 3.5, 3. , 0. ])
|
| 780 |
+
|
| 781 |
+
Using complex sequences:
|
| 782 |
+
|
| 783 |
+
>>> np.correlate([1+1j, 2, 3-1j], [0, 1, 0.5j], 'full')
|
| 784 |
+
array([ 0.5-0.5j, 1.0+0.j , 1.5-1.5j, 3.0-1.j , 0.0+0.j ])
|
| 785 |
+
|
| 786 |
+
Note that you get the time reversed, complex conjugated result
|
| 787 |
+
(:math:`\overline{c_{-k}}`) when the two input sequences a and v change
|
| 788 |
+
places:
|
| 789 |
+
|
| 790 |
+
>>> np.correlate([0, 1, 0.5j], [1+1j, 2, 3-1j], 'full')
|
| 791 |
+
array([ 0.0+0.j , 3.0+1.j , 1.5+1.5j, 1.0+0.j , 0.5+0.5j])
|
| 792 |
+
|
| 793 |
+
"""
|
| 794 |
+
return multiarray.correlate2(a, v, mode)
|
| 795 |
+
|
| 796 |
+
|
| 797 |
+
def _convolve_dispatcher(a, v, mode=None):
|
| 798 |
+
return (a, v)
|
| 799 |
+
|
| 800 |
+
|
| 801 |
+
@array_function_dispatch(_convolve_dispatcher)
|
| 802 |
+
def convolve(a, v, mode='full'):
|
| 803 |
+
"""
|
| 804 |
+
Returns the discrete, linear convolution of two one-dimensional sequences.
|
| 805 |
+
|
| 806 |
+
The convolution operator is often seen in signal processing, where it
|
| 807 |
+
models the effect of a linear time-invariant system on a signal [1]_. In
|
| 808 |
+
probability theory, the sum of two independent random variables is
|
| 809 |
+
distributed according to the convolution of their individual
|
| 810 |
+
distributions.
|
| 811 |
+
|
| 812 |
+
If `v` is longer than `a`, the arrays are swapped before computation.
|
| 813 |
+
|
| 814 |
+
Parameters
|
| 815 |
+
----------
|
| 816 |
+
a : (N,) array_like
|
| 817 |
+
First one-dimensional input array.
|
| 818 |
+
v : (M,) array_like
|
| 819 |
+
Second one-dimensional input array.
|
| 820 |
+
mode : {'full', 'valid', 'same'}, optional
|
| 821 |
+
'full':
|
| 822 |
+
By default, mode is 'full'. This returns the convolution
|
| 823 |
+
at each point of overlap, with an output shape of (N+M-1,). At
|
| 824 |
+
the end-points of the convolution, the signals do not overlap
|
| 825 |
+
completely, and boundary effects may be seen.
|
| 826 |
+
|
| 827 |
+
'same':
|
| 828 |
+
Mode 'same' returns output of length ``max(M, N)``. Boundary
|
| 829 |
+
effects are still visible.
|
| 830 |
+
|
| 831 |
+
'valid':
|
| 832 |
+
Mode 'valid' returns output of length
|
| 833 |
+
``max(M, N) - min(M, N) + 1``. The convolution product is only given
|
| 834 |
+
for points where the signals overlap completely. Values outside
|
| 835 |
+
the signal boundary have no effect.
|
| 836 |
+
|
| 837 |
+
Returns
|
| 838 |
+
-------
|
| 839 |
+
out : ndarray
|
| 840 |
+
Discrete, linear convolution of `a` and `v`.
|
| 841 |
+
|
| 842 |
+
See Also
|
| 843 |
+
--------
|
| 844 |
+
scipy.signal.fftconvolve : Convolve two arrays using the Fast Fourier
|
| 845 |
+
Transform.
|
| 846 |
+
scipy.linalg.toeplitz : Used to construct the convolution operator.
|
| 847 |
+
polymul : Polynomial multiplication. Same output as convolve, but also
|
| 848 |
+
accepts poly1d objects as input.
|
| 849 |
+
|
| 850 |
+
Notes
|
| 851 |
+
-----
|
| 852 |
+
The discrete convolution operation is defined as
|
| 853 |
+
|
| 854 |
+
.. math:: (a * v)_n = \\sum_{m = -\\infty}^{\\infty} a_m v_{n - m}
|
| 855 |
+
|
| 856 |
+
It can be shown that a convolution :math:`x(t) * y(t)` in time/space
|
| 857 |
+
is equivalent to the multiplication :math:`X(f) Y(f)` in the Fourier
|
| 858 |
+
domain, after appropriate padding (padding is necessary to prevent
|
| 859 |
+
circular convolution). Since multiplication is more efficient (faster)
|
| 860 |
+
than convolution, the function `scipy.signal.fftconvolve` exploits the
|
| 861 |
+
FFT to calculate the convolution of large data-sets.
|
| 862 |
+
|
| 863 |
+
References
|
| 864 |
+
----------
|
| 865 |
+
.. [1] Wikipedia, "Convolution",
|
| 866 |
+
https://en.wikipedia.org/wiki/Convolution
|
| 867 |
+
|
| 868 |
+
Examples
|
| 869 |
+
--------
|
| 870 |
+
Note how the convolution operator flips the second array
|
| 871 |
+
before "sliding" the two across one another:
|
| 872 |
+
|
| 873 |
+
>>> import numpy as np
|
| 874 |
+
>>> np.convolve([1, 2, 3], [0, 1, 0.5])
|
| 875 |
+
array([0. , 1. , 2.5, 4. , 1.5])
|
| 876 |
+
|
| 877 |
+
Only return the middle values of the convolution.
|
| 878 |
+
Contains boundary effects, where zeros are taken
|
| 879 |
+
into account:
|
| 880 |
+
|
| 881 |
+
>>> np.convolve([1,2,3],[0,1,0.5], 'same')
|
| 882 |
+
array([1. , 2.5, 4. ])
|
| 883 |
+
|
| 884 |
+
The two arrays are of the same length, so there
|
| 885 |
+
is only one position where they completely overlap:
|
| 886 |
+
|
| 887 |
+
>>> np.convolve([1,2,3],[0,1,0.5], 'valid')
|
| 888 |
+
array([2.5])
|
| 889 |
+
|
| 890 |
+
"""
|
| 891 |
+
a, v = array(a, copy=None, ndmin=1), array(v, copy=None, ndmin=1)
|
| 892 |
+
if len(a) == 0:
|
| 893 |
+
raise ValueError('a cannot be empty')
|
| 894 |
+
if len(v) == 0:
|
| 895 |
+
raise ValueError('v cannot be empty')
|
| 896 |
+
if len(v) > len(a):
|
| 897 |
+
a, v = v, a
|
| 898 |
+
return multiarray.correlate(a, v[::-1], mode)
|
| 899 |
+
|
| 900 |
+
|
| 901 |
+
def _outer_dispatcher(a, b, out=None):
|
| 902 |
+
return (a, b, out)
|
| 903 |
+
|
| 904 |
+
|
| 905 |
+
@array_function_dispatch(_outer_dispatcher)
|
| 906 |
+
def outer(a, b, out=None):
|
| 907 |
+
"""
|
| 908 |
+
Compute the outer product of two vectors.
|
| 909 |
+
|
| 910 |
+
Given two vectors `a` and `b` of length ``M`` and ``N``, respectively,
|
| 911 |
+
the outer product [1]_ is::
|
| 912 |
+
|
| 913 |
+
[[a_0*b_0 a_0*b_1 ... a_0*b_{N-1} ]
|
| 914 |
+
[a_1*b_0 .
|
| 915 |
+
[ ... .
|
| 916 |
+
[a_{M-1}*b_0 a_{M-1}*b_{N-1} ]]
|
| 917 |
+
|
| 918 |
+
Parameters
|
| 919 |
+
----------
|
| 920 |
+
a : (M,) array_like
|
| 921 |
+
First input vector. Input is flattened if
|
| 922 |
+
not already 1-dimensional.
|
| 923 |
+
b : (N,) array_like
|
| 924 |
+
Second input vector. Input is flattened if
|
| 925 |
+
not already 1-dimensional.
|
| 926 |
+
out : (M, N) ndarray, optional
|
| 927 |
+
A location where the result is stored
|
| 928 |
+
|
| 929 |
+
Returns
|
| 930 |
+
-------
|
| 931 |
+
out : (M, N) ndarray
|
| 932 |
+
``out[i, j] = a[i] * b[j]``
|
| 933 |
+
|
| 934 |
+
See also
|
| 935 |
+
--------
|
| 936 |
+
inner
|
| 937 |
+
einsum : ``einsum('i,j->ij', a.ravel(), b.ravel())`` is the equivalent.
|
| 938 |
+
ufunc.outer : A generalization to dimensions other than 1D and other
|
| 939 |
+
operations. ``np.multiply.outer(a.ravel(), b.ravel())``
|
| 940 |
+
is the equivalent.
|
| 941 |
+
linalg.outer : An Array API compatible variation of ``np.outer``,
|
| 942 |
+
which accepts 1-dimensional inputs only.
|
| 943 |
+
tensordot : ``np.tensordot(a.ravel(), b.ravel(), axes=((), ()))``
|
| 944 |
+
is the equivalent.
|
| 945 |
+
|
| 946 |
+
References
|
| 947 |
+
----------
|
| 948 |
+
.. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*, 3rd
|
| 949 |
+
ed., Baltimore, MD, Johns Hopkins University Press, 1996,
|
| 950 |
+
pg. 8.
|
| 951 |
+
|
| 952 |
+
Examples
|
| 953 |
+
--------
|
| 954 |
+
Make a (*very* coarse) grid for computing a Mandelbrot set:
|
| 955 |
+
|
| 956 |
+
>>> import numpy as np
|
| 957 |
+
>>> rl = np.outer(np.ones((5,)), np.linspace(-2, 2, 5))
|
| 958 |
+
>>> rl
|
| 959 |
+
array([[-2., -1., 0., 1., 2.],
|
| 960 |
+
[-2., -1., 0., 1., 2.],
|
| 961 |
+
[-2., -1., 0., 1., 2.],
|
| 962 |
+
[-2., -1., 0., 1., 2.],
|
| 963 |
+
[-2., -1., 0., 1., 2.]])
|
| 964 |
+
>>> im = np.outer(1j*np.linspace(2, -2, 5), np.ones((5,)))
|
| 965 |
+
>>> im
|
| 966 |
+
array([[0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j],
|
| 967 |
+
[0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j],
|
| 968 |
+
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
|
| 969 |
+
[0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j],
|
| 970 |
+
[0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j]])
|
| 971 |
+
>>> grid = rl + im
|
| 972 |
+
>>> grid
|
| 973 |
+
array([[-2.+2.j, -1.+2.j, 0.+2.j, 1.+2.j, 2.+2.j],
|
| 974 |
+
[-2.+1.j, -1.+1.j, 0.+1.j, 1.+1.j, 2.+1.j],
|
| 975 |
+
[-2.+0.j, -1.+0.j, 0.+0.j, 1.+0.j, 2.+0.j],
|
| 976 |
+
[-2.-1.j, -1.-1.j, 0.-1.j, 1.-1.j, 2.-1.j],
|
| 977 |
+
[-2.-2.j, -1.-2.j, 0.-2.j, 1.-2.j, 2.-2.j]])
|
| 978 |
+
|
| 979 |
+
An example using a "vector" of letters:
|
| 980 |
+
|
| 981 |
+
>>> x = np.array(['a', 'b', 'c'], dtype=np.object_)
|
| 982 |
+
>>> np.outer(x, [1, 2, 3])
|
| 983 |
+
array([['a', 'aa', 'aaa'],
|
| 984 |
+
['b', 'bb', 'bbb'],
|
| 985 |
+
['c', 'cc', 'ccc']], dtype=object)
|
| 986 |
+
|
| 987 |
+
"""
|
| 988 |
+
a = asarray(a)
|
| 989 |
+
b = asarray(b)
|
| 990 |
+
return multiply(a.ravel()[:, newaxis], b.ravel()[newaxis, :], out)
|
| 991 |
+
|
| 992 |
+
|
| 993 |
+
def _tensordot_dispatcher(a, b, axes=None):
|
| 994 |
+
return (a, b)
|
| 995 |
+
|
| 996 |
+
|
| 997 |
+
@array_function_dispatch(_tensordot_dispatcher)
|
| 998 |
+
def tensordot(a, b, axes=2):
|
| 999 |
+
"""
|
| 1000 |
+
Compute tensor dot product along specified axes.
|
| 1001 |
+
|
| 1002 |
+
Given two tensors, `a` and `b`, and an array_like object containing
|
| 1003 |
+
two array_like objects, ``(a_axes, b_axes)``, sum the products of
|
| 1004 |
+
`a`'s and `b`'s elements (components) over the axes specified by
|
| 1005 |
+
``a_axes`` and ``b_axes``. The third argument can be a single non-negative
|
| 1006 |
+
integer_like scalar, ``N``; if it is such, then the last ``N`` dimensions
|
| 1007 |
+
of `a` and the first ``N`` dimensions of `b` are summed over.
|
| 1008 |
+
|
| 1009 |
+
Parameters
|
| 1010 |
+
----------
|
| 1011 |
+
a, b : array_like
|
| 1012 |
+
Tensors to "dot".
|
| 1013 |
+
|
| 1014 |
+
axes : int or (2,) array_like
|
| 1015 |
+
* integer_like
|
| 1016 |
+
If an int N, sum over the last N axes of `a` and the first N axes
|
| 1017 |
+
of `b` in order. The sizes of the corresponding axes must match.
|
| 1018 |
+
* (2,) array_like
|
| 1019 |
+
Or, a list of axes to be summed over, first sequence applying to `a`,
|
| 1020 |
+
second to `b`. Both elements array_like must be of the same length.
|
| 1021 |
+
Each axis may appear at most once; repeated axes are not allowed.
|
| 1022 |
+
For example, ``axes=([1, 1], [0, 0])`` is invalid.
|
| 1023 |
+
Returns
|
| 1024 |
+
-------
|
| 1025 |
+
output : ndarray
|
| 1026 |
+
The tensor dot product of the input.
|
| 1027 |
+
|
| 1028 |
+
See Also
|
| 1029 |
+
--------
|
| 1030 |
+
dot, einsum
|
| 1031 |
+
|
| 1032 |
+
Notes
|
| 1033 |
+
-----
|
| 1034 |
+
Three common use cases are:
|
| 1035 |
+
* ``axes = 0`` : tensor product :math:`a\\otimes b`
|
| 1036 |
+
* ``axes = 1`` : tensor dot product :math:`a\\cdot b`
|
| 1037 |
+
* ``axes = 2`` : (default) tensor double contraction :math:`a:b`
|
| 1038 |
+
|
| 1039 |
+
When `axes` is integer_like, the sequence of axes for evaluation
|
| 1040 |
+
will be: from the -Nth axis to the -1th axis in `a`,
|
| 1041 |
+
and from the 0th axis to (N-1)th axis in `b`.
|
| 1042 |
+
For example, ``axes = 2`` is the equal to
|
| 1043 |
+
``axes = [[-2, -1], [0, 1]]``.
|
| 1044 |
+
When N-1 is smaller than 0, or when -N is larger than -1,
|
| 1045 |
+
the element of `a` and `b` are defined as the `axes`.
|
| 1046 |
+
|
| 1047 |
+
When there is more than one axis to sum over - and they are not the last
|
| 1048 |
+
(first) axes of `a` (`b`) - the argument `axes` should consist of
|
| 1049 |
+
two sequences of the same length, with the first axis to sum over given
|
| 1050 |
+
first in both sequences, the second axis second, and so forth.
|
| 1051 |
+
The calculation can be referred to ``numpy.einsum``.
|
| 1052 |
+
|
| 1053 |
+
For example, if ``a.shape == (2, 3, 4)`` and ``b.shape == (3, 4, 5)``,
|
| 1054 |
+
then ``axes=([1, 2], [0, 1])`` sums over the ``(3, 4)`` dimensions of
|
| 1055 |
+
both arrays and produces an output of shape ``(2, 5)``.
|
| 1056 |
+
|
| 1057 |
+
Each summation axis corresponds to a distinct contraction index; repeating
|
| 1058 |
+
an axis (for example ``axes=([1, 1], [0, 0])``) is invalid.
|
| 1059 |
+
|
| 1060 |
+
The shape of the result consists of the non-contracted axes of the
|
| 1061 |
+
first tensor, followed by the non-contracted axes of the second.
|
| 1062 |
+
|
| 1063 |
+
Examples
|
| 1064 |
+
--------
|
| 1065 |
+
An example on integer_like:
|
| 1066 |
+
|
| 1067 |
+
>>> a_0 = np.array([[1, 2], [3, 4]])
|
| 1068 |
+
>>> b_0 = np.array([[5, 6], [7, 8]])
|
| 1069 |
+
>>> c_0 = np.tensordot(a_0, b_0, axes=0)
|
| 1070 |
+
>>> c_0.shape
|
| 1071 |
+
(2, 2, 2, 2)
|
| 1072 |
+
>>> c_0
|
| 1073 |
+
array([[[[ 5, 6],
|
| 1074 |
+
[ 7, 8]],
|
| 1075 |
+
[[10, 12],
|
| 1076 |
+
[14, 16]]],
|
| 1077 |
+
[[[15, 18],
|
| 1078 |
+
[21, 24]],
|
| 1079 |
+
[[20, 24],
|
| 1080 |
+
[28, 32]]]])
|
| 1081 |
+
|
| 1082 |
+
An example on array_like:
|
| 1083 |
+
|
| 1084 |
+
>>> a = np.arange(60.).reshape(3,4,5)
|
| 1085 |
+
>>> b = np.arange(24.).reshape(4,3,2)
|
| 1086 |
+
>>> c = np.tensordot(a,b, axes=([1,0],[0,1]))
|
| 1087 |
+
>>> c.shape
|
| 1088 |
+
(5, 2)
|
| 1089 |
+
>>> c
|
| 1090 |
+
array([[4400., 4730.],
|
| 1091 |
+
[4532., 4874.],
|
| 1092 |
+
[4664., 5018.],
|
| 1093 |
+
[4796., 5162.],
|
| 1094 |
+
[4928., 5306.]])
|
| 1095 |
+
|
| 1096 |
+
A slower but equivalent way of computing the same...
|
| 1097 |
+
|
| 1098 |
+
>>> d = np.zeros((5,2))
|
| 1099 |
+
>>> for i in range(5):
|
| 1100 |
+
... for j in range(2):
|
| 1101 |
+
... for k in range(3):
|
| 1102 |
+
... for n in range(4):
|
| 1103 |
+
... d[i,j] += a[k,n,i] * b[n,k,j]
|
| 1104 |
+
>>> c == d
|
| 1105 |
+
array([[ True, True],
|
| 1106 |
+
[ True, True],
|
| 1107 |
+
[ True, True],
|
| 1108 |
+
[ True, True],
|
| 1109 |
+
[ True, True]])
|
| 1110 |
+
|
| 1111 |
+
An extended example taking advantage of the overloading of + and \\*:
|
| 1112 |
+
|
| 1113 |
+
>>> a = np.array(range(1, 9)).reshape((2, 2, 2))
|
| 1114 |
+
>>> A = np.array(('a', 'b', 'c', 'd'), dtype=np.object_)
|
| 1115 |
+
>>> A = A.reshape((2, 2))
|
| 1116 |
+
>>> a; A
|
| 1117 |
+
array([[[1, 2],
|
| 1118 |
+
[3, 4]],
|
| 1119 |
+
[[5, 6],
|
| 1120 |
+
[7, 8]]])
|
| 1121 |
+
array([['a', 'b'],
|
| 1122 |
+
['c', 'd']], dtype=object)
|
| 1123 |
+
|
| 1124 |
+
>>> np.tensordot(a, A) # third argument default is 2 for double-contraction
|
| 1125 |
+
array(['abbcccdddd', 'aaaaabbbbbbcccccccdddddddd'], dtype=object)
|
| 1126 |
+
|
| 1127 |
+
>>> np.tensordot(a, A, 1)
|
| 1128 |
+
array([[['acc', 'bdd'],
|
| 1129 |
+
['aaacccc', 'bbbdddd']],
|
| 1130 |
+
[['aaaaacccccc', 'bbbbbdddddd'],
|
| 1131 |
+
['aaaaaaacccccccc', 'bbbbbbbdddddddd']]], dtype=object)
|
| 1132 |
+
|
| 1133 |
+
>>> np.tensordot(a, A, 0) # tensor product (result too long to incl.)
|
| 1134 |
+
array([[[[['a', 'b'],
|
| 1135 |
+
['c', 'd']],
|
| 1136 |
+
...
|
| 1137 |
+
|
| 1138 |
+
>>> np.tensordot(a, A, (0, 1))
|
| 1139 |
+
array([[['abbbbb', 'cddddd'],
|
| 1140 |
+
['aabbbbbb', 'ccdddddd']],
|
| 1141 |
+
[['aaabbbbbbb', 'cccddddddd'],
|
| 1142 |
+
['aaaabbbbbbbb', 'ccccdddddddd']]], dtype=object)
|
| 1143 |
+
|
| 1144 |
+
>>> np.tensordot(a, A, (2, 1))
|
| 1145 |
+
array([[['abb', 'cdd'],
|
| 1146 |
+
['aaabbbb', 'cccdddd']],
|
| 1147 |
+
[['aaaaabbbbbb', 'cccccdddddd'],
|
| 1148 |
+
['aaaaaaabbbbbbbb', 'cccccccdddddddd']]], dtype=object)
|
| 1149 |
+
|
| 1150 |
+
>>> np.tensordot(a, A, ((0, 1), (0, 1)))
|
| 1151 |
+
array(['abbbcccccddddddd', 'aabbbbccccccdddddddd'], dtype=object)
|
| 1152 |
+
|
| 1153 |
+
>>> np.tensordot(a, A, ((2, 1), (1, 0)))
|
| 1154 |
+
array(['acccbbdddd', 'aaaaacccccccbbbbbbdddddddd'], dtype=object)
|
| 1155 |
+
|
| 1156 |
+
"""
|
| 1157 |
+
try:
|
| 1158 |
+
iter(axes)
|
| 1159 |
+
except Exception:
|
| 1160 |
+
axes_a = list(range(-axes, 0))
|
| 1161 |
+
axes_b = list(range(axes))
|
| 1162 |
+
else:
|
| 1163 |
+
axes_a, axes_b = axes
|
| 1164 |
+
try:
|
| 1165 |
+
na = len(axes_a)
|
| 1166 |
+
axes_a = list(axes_a)
|
| 1167 |
+
except TypeError:
|
| 1168 |
+
axes_a = [axes_a]
|
| 1169 |
+
na = 1
|
| 1170 |
+
try:
|
| 1171 |
+
nb = len(axes_b)
|
| 1172 |
+
axes_b = list(axes_b)
|
| 1173 |
+
except TypeError:
|
| 1174 |
+
axes_b = [axes_b]
|
| 1175 |
+
nb = 1
|
| 1176 |
+
|
| 1177 |
+
if len(set(axes_a)) != len(axes_a):
|
| 1178 |
+
raise ValueError("duplicate axes are not allowed in tensordot")
|
| 1179 |
+
if len(set(axes_b)) != len(axes_b):
|
| 1180 |
+
raise ValueError("duplicate axes are not allowed in tensordot")
|
| 1181 |
+
|
| 1182 |
+
a, b = asarray(a), asarray(b)
|
| 1183 |
+
as_ = a.shape
|
| 1184 |
+
nda = a.ndim
|
| 1185 |
+
bs = b.shape
|
| 1186 |
+
ndb = b.ndim
|
| 1187 |
+
equal = True
|
| 1188 |
+
if na != nb:
|
| 1189 |
+
equal = False
|
| 1190 |
+
else:
|
| 1191 |
+
for k in range(na):
|
| 1192 |
+
if as_[axes_a[k]] != bs[axes_b[k]]:
|
| 1193 |
+
equal = False
|
| 1194 |
+
break
|
| 1195 |
+
if axes_a[k] < 0:
|
| 1196 |
+
axes_a[k] += nda
|
| 1197 |
+
if axes_b[k] < 0:
|
| 1198 |
+
axes_b[k] += ndb
|
| 1199 |
+
if not equal:
|
| 1200 |
+
raise ValueError("shape-mismatch for sum")
|
| 1201 |
+
|
| 1202 |
+
# Move the axes to sum over to the end of "a"
|
| 1203 |
+
# and to the front of "b"
|
| 1204 |
+
notin = [k for k in range(nda) if k not in axes_a]
|
| 1205 |
+
newaxes_a = notin + axes_a
|
| 1206 |
+
N2 = math.prod(as_[axis] for axis in axes_a)
|
| 1207 |
+
newshape_a = (math.prod(as_[ax] for ax in notin), N2)
|
| 1208 |
+
olda = [as_[axis] for axis in notin]
|
| 1209 |
+
|
| 1210 |
+
notin = [k for k in range(ndb) if k not in axes_b]
|
| 1211 |
+
newaxes_b = axes_b + notin
|
| 1212 |
+
N2 = math.prod(bs[axis] for axis in axes_b)
|
| 1213 |
+
newshape_b = (N2, math.prod(bs[ax] for ax in notin))
|
| 1214 |
+
oldb = [bs[axis] for axis in notin]
|
| 1215 |
+
|
| 1216 |
+
at = a.transpose(newaxes_a).reshape(newshape_a)
|
| 1217 |
+
bt = b.transpose(newaxes_b).reshape(newshape_b)
|
| 1218 |
+
res = dot(at, bt)
|
| 1219 |
+
return res.reshape(olda + oldb)
|
| 1220 |
+
|
| 1221 |
+
|
| 1222 |
+
def _roll_dispatcher(a, shift, axis=None):
|
| 1223 |
+
return (a,)
|
| 1224 |
+
|
| 1225 |
+
|
| 1226 |
+
@array_function_dispatch(_roll_dispatcher)
|
| 1227 |
+
def roll(a, shift, axis=None):
|
| 1228 |
+
"""
|
| 1229 |
+
Roll array elements along a given axis.
|
| 1230 |
+
|
| 1231 |
+
Elements that roll beyond the last position are re-introduced at
|
| 1232 |
+
the first.
|
| 1233 |
+
|
| 1234 |
+
Parameters
|
| 1235 |
+
----------
|
| 1236 |
+
a : array_like
|
| 1237 |
+
Input array.
|
| 1238 |
+
shift : int or tuple of ints
|
| 1239 |
+
The number of places by which elements are shifted. If a tuple,
|
| 1240 |
+
then `axis` must be a tuple of the same size, and each of the
|
| 1241 |
+
given axes is shifted by the corresponding number. If an int
|
| 1242 |
+
while `axis` is a tuple of ints, then the same value is used for
|
| 1243 |
+
all given axes.
|
| 1244 |
+
axis : int or tuple of ints, optional
|
| 1245 |
+
Axis or axes along which elements are shifted. By default, the
|
| 1246 |
+
array is flattened before shifting, after which the original
|
| 1247 |
+
shape is restored.
|
| 1248 |
+
|
| 1249 |
+
Returns
|
| 1250 |
+
-------
|
| 1251 |
+
res : ndarray
|
| 1252 |
+
Output array, with the same shape as `a`.
|
| 1253 |
+
|
| 1254 |
+
See Also
|
| 1255 |
+
--------
|
| 1256 |
+
rollaxis : Roll the specified axis backwards, until it lies in a
|
| 1257 |
+
given position.
|
| 1258 |
+
|
| 1259 |
+
Notes
|
| 1260 |
+
-----
|
| 1261 |
+
Supports rolling over multiple dimensions simultaneously.
|
| 1262 |
+
|
| 1263 |
+
Examples
|
| 1264 |
+
--------
|
| 1265 |
+
>>> import numpy as np
|
| 1266 |
+
>>> x = np.arange(10)
|
| 1267 |
+
>>> np.roll(x, 2)
|
| 1268 |
+
array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
|
| 1269 |
+
>>> np.roll(x, -2)
|
| 1270 |
+
array([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
|
| 1271 |
+
|
| 1272 |
+
>>> x2 = np.reshape(x, (2, 5))
|
| 1273 |
+
>>> x2
|
| 1274 |
+
array([[0, 1, 2, 3, 4],
|
| 1275 |
+
[5, 6, 7, 8, 9]])
|
| 1276 |
+
>>> np.roll(x2, 1)
|
| 1277 |
+
array([[9, 0, 1, 2, 3],
|
| 1278 |
+
[4, 5, 6, 7, 8]])
|
| 1279 |
+
>>> np.roll(x2, -1)
|
| 1280 |
+
array([[1, 2, 3, 4, 5],
|
| 1281 |
+
[6, 7, 8, 9, 0]])
|
| 1282 |
+
>>> np.roll(x2, 1, axis=0)
|
| 1283 |
+
array([[5, 6, 7, 8, 9],
|
| 1284 |
+
[0, 1, 2, 3, 4]])
|
| 1285 |
+
>>> np.roll(x2, -1, axis=0)
|
| 1286 |
+
array([[5, 6, 7, 8, 9],
|
| 1287 |
+
[0, 1, 2, 3, 4]])
|
| 1288 |
+
>>> np.roll(x2, 1, axis=1)
|
| 1289 |
+
array([[4, 0, 1, 2, 3],
|
| 1290 |
+
[9, 5, 6, 7, 8]])
|
| 1291 |
+
>>> np.roll(x2, -1, axis=1)
|
| 1292 |
+
array([[1, 2, 3, 4, 0],
|
| 1293 |
+
[6, 7, 8, 9, 5]])
|
| 1294 |
+
>>> np.roll(x2, (1, 1), axis=(1, 0))
|
| 1295 |
+
array([[9, 5, 6, 7, 8],
|
| 1296 |
+
[4, 0, 1, 2, 3]])
|
| 1297 |
+
>>> np.roll(x2, (2, 1), axis=(1, 0))
|
| 1298 |
+
array([[8, 9, 5, 6, 7],
|
| 1299 |
+
[3, 4, 0, 1, 2]])
|
| 1300 |
+
|
| 1301 |
+
"""
|
| 1302 |
+
a = asanyarray(a)
|
| 1303 |
+
if axis is None:
|
| 1304 |
+
return roll(a.ravel(), shift, 0).reshape(a.shape)
|
| 1305 |
+
|
| 1306 |
+
else:
|
| 1307 |
+
axis = normalize_axis_tuple(axis, a.ndim, allow_duplicate=True)
|
| 1308 |
+
broadcasted = broadcast(shift, axis)
|
| 1309 |
+
if broadcasted.ndim > 1:
|
| 1310 |
+
raise ValueError(
|
| 1311 |
+
"'shift' and 'axis' should be scalars or 1D sequences")
|
| 1312 |
+
shifts = dict.fromkeys(range(a.ndim), 0)
|
| 1313 |
+
for sh, ax in broadcasted:
|
| 1314 |
+
shifts[ax] += int(sh)
|
| 1315 |
+
|
| 1316 |
+
rolls = [((slice(None), slice(None)),)] * a.ndim
|
| 1317 |
+
for ax, offset in shifts.items():
|
| 1318 |
+
offset %= a.shape[ax] or 1 # If `a` is empty, nothing matters.
|
| 1319 |
+
if offset:
|
| 1320 |
+
# (original, result), (original, result)
|
| 1321 |
+
rolls[ax] = ((slice(None, -offset), slice(offset, None)),
|
| 1322 |
+
(slice(-offset, None), slice(None, offset)))
|
| 1323 |
+
|
| 1324 |
+
result = empty_like(a)
|
| 1325 |
+
for indices in itertools.product(*rolls):
|
| 1326 |
+
arr_index, res_index = zip(*indices)
|
| 1327 |
+
result[res_index] = a[arr_index]
|
| 1328 |
+
|
| 1329 |
+
return result
|
| 1330 |
+
|
| 1331 |
+
|
| 1332 |
+
def _rollaxis_dispatcher(a, axis, start=None):
|
| 1333 |
+
return (a,)
|
| 1334 |
+
|
| 1335 |
+
|
| 1336 |
+
@array_function_dispatch(_rollaxis_dispatcher)
|
| 1337 |
+
def rollaxis(a, axis, start=0):
|
| 1338 |
+
"""
|
| 1339 |
+
Roll the specified axis backwards, until it lies in a given position.
|
| 1340 |
+
|
| 1341 |
+
This function continues to be supported for backward compatibility, but you
|
| 1342 |
+
should prefer `moveaxis`. The `moveaxis` function was added in NumPy
|
| 1343 |
+
1.11.
|
| 1344 |
+
|
| 1345 |
+
Parameters
|
| 1346 |
+
----------
|
| 1347 |
+
a : ndarray
|
| 1348 |
+
Input array.
|
| 1349 |
+
axis : int
|
| 1350 |
+
The axis to be rolled. The positions of the other axes do not
|
| 1351 |
+
change relative to one another.
|
| 1352 |
+
start : int, optional
|
| 1353 |
+
When ``start <= axis``, the axis is rolled back until it lies in
|
| 1354 |
+
this position. When ``start > axis``, the axis is rolled until it
|
| 1355 |
+
lies before this position. The default, 0, results in a "complete"
|
| 1356 |
+
roll. The following table describes how negative values of ``start``
|
| 1357 |
+
are interpreted:
|
| 1358 |
+
|
| 1359 |
+
.. table::
|
| 1360 |
+
:align: left
|
| 1361 |
+
|
| 1362 |
+
+-------------------+----------------------+
|
| 1363 |
+
| ``start`` | Normalized ``start`` |
|
| 1364 |
+
+===================+======================+
|
| 1365 |
+
| ``-(arr.ndim+1)`` | raise ``AxisError`` |
|
| 1366 |
+
+-------------------+----------------------+
|
| 1367 |
+
| ``-arr.ndim`` | 0 |
|
| 1368 |
+
+-------------------+----------------------+
|
| 1369 |
+
| |vdots| | |vdots| |
|
| 1370 |
+
+-------------------+----------------------+
|
| 1371 |
+
| ``-1`` | ``arr.ndim-1`` |
|
| 1372 |
+
+-------------------+----------------------+
|
| 1373 |
+
| ``0`` | ``0`` |
|
| 1374 |
+
+-------------------+----------------------+
|
| 1375 |
+
| |vdots| | |vdots| |
|
| 1376 |
+
+-------------------+----------------------+
|
| 1377 |
+
| ``arr.ndim`` | ``arr.ndim`` |
|
| 1378 |
+
+-------------------+----------------------+
|
| 1379 |
+
| ``arr.ndim + 1`` | raise ``AxisError`` |
|
| 1380 |
+
+-------------------+----------------------+
|
| 1381 |
+
|
| 1382 |
+
.. |vdots| unicode:: U+22EE .. Vertical Ellipsis
|
| 1383 |
+
|
| 1384 |
+
Returns
|
| 1385 |
+
-------
|
| 1386 |
+
res : ndarray
|
| 1387 |
+
For NumPy >= 1.10.0 a view of `a` is always returned. For earlier
|
| 1388 |
+
NumPy versions a view of `a` is returned only if the order of the
|
| 1389 |
+
axes is changed, otherwise the input array is returned.
|
| 1390 |
+
|
| 1391 |
+
See Also
|
| 1392 |
+
--------
|
| 1393 |
+
moveaxis : Move array axes to new positions.
|
| 1394 |
+
roll : Roll the elements of an array by a number of positions along a
|
| 1395 |
+
given axis.
|
| 1396 |
+
|
| 1397 |
+
Examples
|
| 1398 |
+
--------
|
| 1399 |
+
>>> import numpy as np
|
| 1400 |
+
>>> a = np.ones((3,4,5,6))
|
| 1401 |
+
>>> np.rollaxis(a, 3, 1).shape
|
| 1402 |
+
(3, 6, 4, 5)
|
| 1403 |
+
>>> np.rollaxis(a, 2).shape
|
| 1404 |
+
(5, 3, 4, 6)
|
| 1405 |
+
>>> np.rollaxis(a, 1, 4).shape
|
| 1406 |
+
(3, 5, 6, 4)
|
| 1407 |
+
|
| 1408 |
+
"""
|
| 1409 |
+
n = a.ndim
|
| 1410 |
+
axis = normalize_axis_index(axis, n)
|
| 1411 |
+
if start < 0:
|
| 1412 |
+
start += n
|
| 1413 |
+
msg = "'%s' arg requires %d <= %s < %d, but %d was passed in"
|
| 1414 |
+
if not (0 <= start < n + 1):
|
| 1415 |
+
raise AxisError(msg % ('start', -n, 'start', n + 1, start))
|
| 1416 |
+
if axis < start:
|
| 1417 |
+
# it's been removed
|
| 1418 |
+
start -= 1
|
| 1419 |
+
if axis == start:
|
| 1420 |
+
return a[...]
|
| 1421 |
+
axes = list(range(n))
|
| 1422 |
+
axes.remove(axis)
|
| 1423 |
+
axes.insert(start, axis)
|
| 1424 |
+
return a.transpose(axes)
|
| 1425 |
+
|
| 1426 |
+
|
| 1427 |
+
@set_module("numpy.lib.array_utils")
|
| 1428 |
+
def normalize_axis_tuple(axis, ndim, argname=None, allow_duplicate=False):
|
| 1429 |
+
"""
|
| 1430 |
+
Normalizes an axis argument into a tuple of non-negative integer axes.
|
| 1431 |
+
|
| 1432 |
+
This handles shorthands such as ``1`` and converts them to ``(1,)``,
|
| 1433 |
+
as well as performing the handling of negative indices covered by
|
| 1434 |
+
`normalize_axis_index`.
|
| 1435 |
+
|
| 1436 |
+
By default, this forbids axes from being specified multiple times.
|
| 1437 |
+
|
| 1438 |
+
Used internally by multi-axis-checking logic.
|
| 1439 |
+
|
| 1440 |
+
Parameters
|
| 1441 |
+
----------
|
| 1442 |
+
axis : int, iterable of int
|
| 1443 |
+
The un-normalized index or indices of the axis.
|
| 1444 |
+
ndim : int
|
| 1445 |
+
The number of dimensions of the array that `axis` should be normalized
|
| 1446 |
+
against.
|
| 1447 |
+
argname : str, optional
|
| 1448 |
+
A prefix to put before the error message, typically the name of the
|
| 1449 |
+
argument.
|
| 1450 |
+
allow_duplicate : bool, optional
|
| 1451 |
+
If False, the default, disallow an axis from being specified twice.
|
| 1452 |
+
|
| 1453 |
+
Returns
|
| 1454 |
+
-------
|
| 1455 |
+
normalized_axes : tuple of int
|
| 1456 |
+
The normalized axis index, such that `0 <= normalized_axis < ndim`
|
| 1457 |
+
|
| 1458 |
+
Raises
|
| 1459 |
+
------
|
| 1460 |
+
AxisError
|
| 1461 |
+
If any axis provided is out of range
|
| 1462 |
+
ValueError
|
| 1463 |
+
If an axis is repeated
|
| 1464 |
+
|
| 1465 |
+
See also
|
| 1466 |
+
--------
|
| 1467 |
+
normalize_axis_index : normalizing a single scalar axis
|
| 1468 |
+
"""
|
| 1469 |
+
# Optimization to speed-up the most common cases.
|
| 1470 |
+
if not isinstance(axis, (tuple, list)):
|
| 1471 |
+
try:
|
| 1472 |
+
axis = [operator.index(axis)]
|
| 1473 |
+
except TypeError:
|
| 1474 |
+
pass
|
| 1475 |
+
# Going via an iterator directly is slower than via list comprehension.
|
| 1476 |
+
axis = tuple(normalize_axis_index(ax, ndim, argname) for ax in axis)
|
| 1477 |
+
if not allow_duplicate and len(set(axis)) != len(axis):
|
| 1478 |
+
if argname:
|
| 1479 |
+
raise ValueError(f'repeated axis in `{argname}` argument')
|
| 1480 |
+
else:
|
| 1481 |
+
raise ValueError('repeated axis')
|
| 1482 |
+
return axis
|
| 1483 |
+
|
| 1484 |
+
|
| 1485 |
+
def _moveaxis_dispatcher(a, source, destination):
|
| 1486 |
+
return (a,)
|
| 1487 |
+
|
| 1488 |
+
|
| 1489 |
+
@array_function_dispatch(_moveaxis_dispatcher)
|
| 1490 |
+
def moveaxis(a, source, destination):
|
| 1491 |
+
"""
|
| 1492 |
+
Move axes of an array to new positions.
|
| 1493 |
+
|
| 1494 |
+
Other axes remain in their original order.
|
| 1495 |
+
|
| 1496 |
+
Parameters
|
| 1497 |
+
----------
|
| 1498 |
+
a : np.ndarray
|
| 1499 |
+
The array whose axes should be reordered.
|
| 1500 |
+
source : int or sequence of int
|
| 1501 |
+
Original positions of the axes to move. These must be unique.
|
| 1502 |
+
destination : int or sequence of int
|
| 1503 |
+
Destination positions for each of the original axes. These must also be
|
| 1504 |
+
unique.
|
| 1505 |
+
|
| 1506 |
+
Returns
|
| 1507 |
+
-------
|
| 1508 |
+
result : np.ndarray
|
| 1509 |
+
Array with moved axes. This array is a view of the input array.
|
| 1510 |
+
|
| 1511 |
+
See Also
|
| 1512 |
+
--------
|
| 1513 |
+
transpose : Permute the dimensions of an array.
|
| 1514 |
+
swapaxes : Interchange two axes of an array.
|
| 1515 |
+
|
| 1516 |
+
Examples
|
| 1517 |
+
--------
|
| 1518 |
+
>>> import numpy as np
|
| 1519 |
+
>>> x = np.zeros((3, 4, 5))
|
| 1520 |
+
>>> np.moveaxis(x, 0, -1).shape
|
| 1521 |
+
(4, 5, 3)
|
| 1522 |
+
>>> np.moveaxis(x, -1, 0).shape
|
| 1523 |
+
(5, 3, 4)
|
| 1524 |
+
|
| 1525 |
+
These all achieve the same result:
|
| 1526 |
+
|
| 1527 |
+
>>> np.transpose(x).shape
|
| 1528 |
+
(5, 4, 3)
|
| 1529 |
+
>>> np.swapaxes(x, 0, -1).shape
|
| 1530 |
+
(5, 4, 3)
|
| 1531 |
+
>>> np.moveaxis(x, [0, 1], [-1, -2]).shape
|
| 1532 |
+
(5, 4, 3)
|
| 1533 |
+
>>> np.moveaxis(x, [0, 1, 2], [-1, -2, -3]).shape
|
| 1534 |
+
(5, 4, 3)
|
| 1535 |
+
|
| 1536 |
+
"""
|
| 1537 |
+
try:
|
| 1538 |
+
# allow duck-array types if they define transpose
|
| 1539 |
+
transpose = a.transpose
|
| 1540 |
+
except AttributeError:
|
| 1541 |
+
a = asarray(a)
|
| 1542 |
+
transpose = a.transpose
|
| 1543 |
+
|
| 1544 |
+
source = normalize_axis_tuple(source, a.ndim, 'source')
|
| 1545 |
+
destination = normalize_axis_tuple(destination, a.ndim, 'destination')
|
| 1546 |
+
if len(source) != len(destination):
|
| 1547 |
+
raise ValueError('`source` and `destination` arguments must have '
|
| 1548 |
+
'the same number of elements')
|
| 1549 |
+
|
| 1550 |
+
order = [n for n in range(a.ndim) if n not in source]
|
| 1551 |
+
|
| 1552 |
+
for dest, src in sorted(zip(destination, source)):
|
| 1553 |
+
order.insert(dest, src)
|
| 1554 |
+
|
| 1555 |
+
result = transpose(order)
|
| 1556 |
+
return result
|
| 1557 |
+
|
| 1558 |
+
|
| 1559 |
+
def _cross_dispatcher(a, b, axisa=None, axisb=None, axisc=None, axis=None):
|
| 1560 |
+
return (a, b)
|
| 1561 |
+
|
| 1562 |
+
|
| 1563 |
+
@array_function_dispatch(_cross_dispatcher)
|
| 1564 |
+
def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None):
|
| 1565 |
+
"""
|
| 1566 |
+
Return the cross product of two (arrays of) vectors.
|
| 1567 |
+
|
| 1568 |
+
The cross product of `a` and `b` in :math:`R^3` is a vector perpendicular
|
| 1569 |
+
to both `a` and `b`. If `a` and `b` are arrays of vectors, the vectors
|
| 1570 |
+
are defined by the last axis of `a` and `b` by default, and these axes
|
| 1571 |
+
must have 3 dimensions.
|
| 1572 |
+
|
| 1573 |
+
Parameters
|
| 1574 |
+
----------
|
| 1575 |
+
a : array_like
|
| 1576 |
+
Components of the first vector(s).
|
| 1577 |
+
b : array_like
|
| 1578 |
+
Components of the second vector(s).
|
| 1579 |
+
axisa : int, optional
|
| 1580 |
+
Axis of `a` that defines the vector(s). By default, the last axis.
|
| 1581 |
+
axisb : int, optional
|
| 1582 |
+
Axis of `b` that defines the vector(s). By default, the last axis.
|
| 1583 |
+
axisc : int, optional
|
| 1584 |
+
Axis of `c` containing the cross product vector(s). By default, the last axis.
|
| 1585 |
+
axis : int, optional
|
| 1586 |
+
If defined, the axis of `a`, `b` and `c` that defines the vector(s)
|
| 1587 |
+
and cross product(s). Overrides `axisa`, `axisb` and `axisc`.
|
| 1588 |
+
|
| 1589 |
+
Returns
|
| 1590 |
+
-------
|
| 1591 |
+
c : ndarray
|
| 1592 |
+
Vector cross product(s).
|
| 1593 |
+
|
| 1594 |
+
Raises
|
| 1595 |
+
------
|
| 1596 |
+
ValueError
|
| 1597 |
+
When the dimension of the vector(s) in `a` or `b` does not equal 3.
|
| 1598 |
+
|
| 1599 |
+
See Also
|
| 1600 |
+
--------
|
| 1601 |
+
inner : Inner product
|
| 1602 |
+
outer : Outer product.
|
| 1603 |
+
linalg.cross : An Array API compatible variation of ``np.cross``.
|
| 1604 |
+
ix_ : Construct index arrays.
|
| 1605 |
+
|
| 1606 |
+
Notes
|
| 1607 |
+
-----
|
| 1608 |
+
Supports full broadcasting of the inputs.
|
| 1609 |
+
|
| 1610 |
+
Examples
|
| 1611 |
+
--------
|
| 1612 |
+
Vector cross-product.
|
| 1613 |
+
|
| 1614 |
+
>>> import numpy as np
|
| 1615 |
+
>>> x = [1, 2, 3]
|
| 1616 |
+
>>> y = [4, 5, 6]
|
| 1617 |
+
>>> np.cross(x, y)
|
| 1618 |
+
array([-3, 6, -3])
|
| 1619 |
+
|
| 1620 |
+
One vector with dimension 2.
|
| 1621 |
+
|
| 1622 |
+
>>> x = [1, 2, 0]
|
| 1623 |
+
>>> y = [4, 5, 6]
|
| 1624 |
+
>>> np.cross(x, y)
|
| 1625 |
+
array([12, -6, -3])
|
| 1626 |
+
|
| 1627 |
+
Both vectors with dimension 2.
|
| 1628 |
+
|
| 1629 |
+
>>> x = [1, 2, 0]
|
| 1630 |
+
>>> y = [4, 5, 0]
|
| 1631 |
+
>>> np.cross(x, y)
|
| 1632 |
+
array([0, 0, -3])
|
| 1633 |
+
|
| 1634 |
+
Multiple vector cross-products. Note that the direction of the cross
|
| 1635 |
+
product vector is defined by the *right-hand rule*.
|
| 1636 |
+
|
| 1637 |
+
>>> x = np.array([[1,2,3], [4,5,6]])
|
| 1638 |
+
>>> y = np.array([[4,5,6], [1,2,3]])
|
| 1639 |
+
>>> np.cross(x, y)
|
| 1640 |
+
array([[-3, 6, -3],
|
| 1641 |
+
[ 3, -6, 3]])
|
| 1642 |
+
|
| 1643 |
+
The orientation of `c` can be changed using the `axisc` keyword.
|
| 1644 |
+
|
| 1645 |
+
>>> np.cross(x, y, axisc=0)
|
| 1646 |
+
array([[-3, 3],
|
| 1647 |
+
[ 6, -6],
|
| 1648 |
+
[-3, 3]])
|
| 1649 |
+
|
| 1650 |
+
Change the vector definition of `x` and `y` using `axisa` and `axisb`.
|
| 1651 |
+
|
| 1652 |
+
>>> x = np.array([[1,2,3], [4,5,6], [7, 8, 9]])
|
| 1653 |
+
>>> y = np.array([[7, 8, 9], [4,5,6], [1,2,3]])
|
| 1654 |
+
>>> np.cross(x, y)
|
| 1655 |
+
array([[ -6, 12, -6],
|
| 1656 |
+
[ 0, 0, 0],
|
| 1657 |
+
[ 6, -12, 6]])
|
| 1658 |
+
>>> np.cross(x, y, axisa=0, axisb=0)
|
| 1659 |
+
array([[-24, 48, -24],
|
| 1660 |
+
[-30, 60, -30],
|
| 1661 |
+
[-36, 72, -36]])
|
| 1662 |
+
|
| 1663 |
+
"""
|
| 1664 |
+
if axis is not None:
|
| 1665 |
+
axisa, axisb, axisc = (axis,) * 3
|
| 1666 |
+
a = asarray(a)
|
| 1667 |
+
b = asarray(b)
|
| 1668 |
+
|
| 1669 |
+
if (a.ndim < 1) or (b.ndim < 1):
|
| 1670 |
+
raise ValueError("At least one array has zero dimension")
|
| 1671 |
+
|
| 1672 |
+
# Check axisa and axisb are within bounds
|
| 1673 |
+
axisa = normalize_axis_index(axisa, a.ndim, msg_prefix='axisa')
|
| 1674 |
+
axisb = normalize_axis_index(axisb, b.ndim, msg_prefix='axisb')
|
| 1675 |
+
|
| 1676 |
+
# Move working axis to the end of the shape
|
| 1677 |
+
a = moveaxis(a, axisa, -1)
|
| 1678 |
+
b = moveaxis(b, axisb, -1)
|
| 1679 |
+
if a.shape[-1] != 3 or b.shape[-1] != 3:
|
| 1680 |
+
raise ValueError(
|
| 1681 |
+
f"Both input arrays must be (arrays of) 3-dimensional vectors, "
|
| 1682 |
+
f"but they are {a.shape[-1]} and {b.shape[-1]} dimensional instead."
|
| 1683 |
+
)
|
| 1684 |
+
|
| 1685 |
+
# Create the output array
|
| 1686 |
+
shape = *broadcast(a[..., 0], b[..., 0]).shape, 3
|
| 1687 |
+
# Check axisc is within bounds
|
| 1688 |
+
axisc = normalize_axis_index(axisc, len(shape), msg_prefix='axisc')
|
| 1689 |
+
dtype = promote_types(a.dtype, b.dtype)
|
| 1690 |
+
cp = empty(shape, dtype)
|
| 1691 |
+
|
| 1692 |
+
# recast arrays as dtype
|
| 1693 |
+
a = a.astype(dtype)
|
| 1694 |
+
b = b.astype(dtype)
|
| 1695 |
+
|
| 1696 |
+
# create local aliases for readability
|
| 1697 |
+
a0 = a[..., 0]
|
| 1698 |
+
a1 = a[..., 1]
|
| 1699 |
+
a2 = a[..., 2]
|
| 1700 |
+
b0 = b[..., 0]
|
| 1701 |
+
b1 = b[..., 1]
|
| 1702 |
+
b2 = b[..., 2]
|
| 1703 |
+
cp0 = cp[..., 0]
|
| 1704 |
+
cp1 = cp[..., 1]
|
| 1705 |
+
cp2 = cp[..., 2]
|
| 1706 |
+
|
| 1707 |
+
# cp0 = a1 * b2 - a2 * b1
|
| 1708 |
+
# cp1 = a2 * b0 - a0 * b2
|
| 1709 |
+
# cp2 = a0 * b1 - a1 * b0
|
| 1710 |
+
multiply(a1, b2, out=cp0)
|
| 1711 |
+
tmp = np.multiply(a2, b1, out=...)
|
| 1712 |
+
cp0 -= tmp
|
| 1713 |
+
multiply(a2, b0, out=cp1)
|
| 1714 |
+
multiply(a0, b2, out=tmp)
|
| 1715 |
+
cp1 -= tmp
|
| 1716 |
+
multiply(a0, b1, out=cp2)
|
| 1717 |
+
multiply(a1, b0, out=tmp)
|
| 1718 |
+
cp2 -= tmp
|
| 1719 |
+
|
| 1720 |
+
return moveaxis(cp, -1, axisc)
|
| 1721 |
+
|
| 1722 |
+
|
| 1723 |
+
little_endian = (sys.byteorder == 'little')
|
| 1724 |
+
|
| 1725 |
+
|
| 1726 |
+
@set_module('numpy')
|
| 1727 |
+
def indices(dimensions, dtype=int, sparse=False):
|
| 1728 |
+
"""
|
| 1729 |
+
Return an array representing the indices of a grid.
|
| 1730 |
+
|
| 1731 |
+
Compute an array where the subarrays contain index values 0, 1, ...
|
| 1732 |
+
varying only along the corresponding axis.
|
| 1733 |
+
|
| 1734 |
+
Parameters
|
| 1735 |
+
----------
|
| 1736 |
+
dimensions : sequence of ints
|
| 1737 |
+
The shape of the grid.
|
| 1738 |
+
dtype : dtype, optional
|
| 1739 |
+
Data type of the result.
|
| 1740 |
+
sparse : boolean, optional
|
| 1741 |
+
Return a sparse representation of the grid instead of a dense
|
| 1742 |
+
representation. Default is False.
|
| 1743 |
+
|
| 1744 |
+
Returns
|
| 1745 |
+
-------
|
| 1746 |
+
grid : one ndarray or tuple of ndarrays
|
| 1747 |
+
If sparse is False:
|
| 1748 |
+
Returns one array of grid indices,
|
| 1749 |
+
``grid.shape = (len(dimensions),) + tuple(dimensions)``.
|
| 1750 |
+
If sparse is True:
|
| 1751 |
+
Returns a tuple of arrays, with
|
| 1752 |
+
``grid[i].shape = (1, ..., 1, dimensions[i], 1, ..., 1)`` with
|
| 1753 |
+
dimensions[i] in the ith place
|
| 1754 |
+
|
| 1755 |
+
See Also
|
| 1756 |
+
--------
|
| 1757 |
+
mgrid, ogrid, meshgrid
|
| 1758 |
+
|
| 1759 |
+
Notes
|
| 1760 |
+
-----
|
| 1761 |
+
The output shape in the dense case is obtained by prepending the number
|
| 1762 |
+
of dimensions in front of the tuple of dimensions, i.e. if `dimensions`
|
| 1763 |
+
is a tuple ``(r0, ..., rN-1)`` of length ``N``, the output shape is
|
| 1764 |
+
``(N, r0, ..., rN-1)``.
|
| 1765 |
+
|
| 1766 |
+
The subarrays ``grid[k]`` contains the N-D array of indices along the
|
| 1767 |
+
``k-th`` axis. Explicitly::
|
| 1768 |
+
|
| 1769 |
+
grid[k, i0, i1, ..., iN-1] = ik
|
| 1770 |
+
|
| 1771 |
+
Examples
|
| 1772 |
+
--------
|
| 1773 |
+
>>> import numpy as np
|
| 1774 |
+
>>> grid = np.indices((2, 3))
|
| 1775 |
+
>>> grid.shape
|
| 1776 |
+
(2, 2, 3)
|
| 1777 |
+
>>> grid[0] # row indices
|
| 1778 |
+
array([[0, 0, 0],
|
| 1779 |
+
[1, 1, 1]])
|
| 1780 |
+
>>> grid[1] # column indices
|
| 1781 |
+
array([[0, 1, 2],
|
| 1782 |
+
[0, 1, 2]])
|
| 1783 |
+
|
| 1784 |
+
The indices can be used as an index into an array.
|
| 1785 |
+
|
| 1786 |
+
>>> x = np.arange(20).reshape(5, 4)
|
| 1787 |
+
>>> row, col = np.indices((2, 3))
|
| 1788 |
+
>>> x[row, col]
|
| 1789 |
+
array([[0, 1, 2],
|
| 1790 |
+
[4, 5, 6]])
|
| 1791 |
+
|
| 1792 |
+
Note that it would be more straightforward in the above example to
|
| 1793 |
+
extract the required elements directly with ``x[:2, :3]``.
|
| 1794 |
+
|
| 1795 |
+
If sparse is set to true, the grid will be returned in a sparse
|
| 1796 |
+
representation.
|
| 1797 |
+
|
| 1798 |
+
>>> i, j = np.indices((2, 3), sparse=True)
|
| 1799 |
+
>>> i.shape
|
| 1800 |
+
(2, 1)
|
| 1801 |
+
>>> j.shape
|
| 1802 |
+
(1, 3)
|
| 1803 |
+
>>> i # row indices
|
| 1804 |
+
array([[0],
|
| 1805 |
+
[1]])
|
| 1806 |
+
>>> j # column indices
|
| 1807 |
+
array([[0, 1, 2]])
|
| 1808 |
+
|
| 1809 |
+
"""
|
| 1810 |
+
dimensions = tuple(dimensions)
|
| 1811 |
+
N = len(dimensions)
|
| 1812 |
+
shape = (1,) * N
|
| 1813 |
+
if sparse:
|
| 1814 |
+
res = ()
|
| 1815 |
+
else:
|
| 1816 |
+
res = empty((N,) + dimensions, dtype=dtype)
|
| 1817 |
+
for i, dim in enumerate(dimensions):
|
| 1818 |
+
idx = arange(dim, dtype=dtype).reshape(
|
| 1819 |
+
shape[:i] + (dim,) + shape[i + 1:]
|
| 1820 |
+
)
|
| 1821 |
+
if sparse:
|
| 1822 |
+
res = res + (idx,)
|
| 1823 |
+
else:
|
| 1824 |
+
res[i] = idx
|
| 1825 |
+
return res
|
| 1826 |
+
|
| 1827 |
+
|
| 1828 |
+
@finalize_array_function_like
|
| 1829 |
+
@set_module('numpy')
|
| 1830 |
+
def fromfunction(function, shape, *, dtype=float, like=None, **kwargs):
|
| 1831 |
+
"""
|
| 1832 |
+
Construct an array by executing a function over each coordinate.
|
| 1833 |
+
|
| 1834 |
+
The resulting array therefore has a value ``fn(x, y, z)`` at
|
| 1835 |
+
coordinate ``(x, y, z)``.
|
| 1836 |
+
|
| 1837 |
+
Parameters
|
| 1838 |
+
----------
|
| 1839 |
+
function : callable
|
| 1840 |
+
The function is called with N parameters, where N is the rank of
|
| 1841 |
+
`shape`. Each parameter represents the coordinates of the array
|
| 1842 |
+
varying along a specific axis. For example, if `shape`
|
| 1843 |
+
were ``(2, 2)``, then the parameters would be
|
| 1844 |
+
``array([[0, 0], [1, 1]])`` and ``array([[0, 1], [0, 1]])``
|
| 1845 |
+
shape : (N,) tuple of ints
|
| 1846 |
+
Shape of the output array, which also determines the shape of
|
| 1847 |
+
the coordinate arrays passed to `function`.
|
| 1848 |
+
dtype : data-type, optional
|
| 1849 |
+
Data-type of the coordinate arrays passed to `function`.
|
| 1850 |
+
By default, `dtype` is float.
|
| 1851 |
+
${ARRAY_FUNCTION_LIKE}
|
| 1852 |
+
|
| 1853 |
+
.. versionadded:: 1.20.0
|
| 1854 |
+
|
| 1855 |
+
Returns
|
| 1856 |
+
-------
|
| 1857 |
+
fromfunction : any
|
| 1858 |
+
The result of the call to `function` is passed back directly.
|
| 1859 |
+
Therefore the shape of `fromfunction` is completely determined by
|
| 1860 |
+
`function`. If `function` returns a scalar value, the shape of
|
| 1861 |
+
`fromfunction` would not match the `shape` parameter.
|
| 1862 |
+
|
| 1863 |
+
See Also
|
| 1864 |
+
--------
|
| 1865 |
+
indices, meshgrid
|
| 1866 |
+
|
| 1867 |
+
Notes
|
| 1868 |
+
-----
|
| 1869 |
+
Keywords other than `dtype` and `like` are passed to `function`.
|
| 1870 |
+
|
| 1871 |
+
Examples
|
| 1872 |
+
--------
|
| 1873 |
+
>>> import numpy as np
|
| 1874 |
+
>>> np.fromfunction(lambda i, j: i, (2, 2), dtype=np.float64)
|
| 1875 |
+
array([[0., 0.],
|
| 1876 |
+
[1., 1.]])
|
| 1877 |
+
|
| 1878 |
+
>>> np.fromfunction(lambda i, j: j, (2, 2), dtype=np.float64)
|
| 1879 |
+
array([[0., 1.],
|
| 1880 |
+
[0., 1.]])
|
| 1881 |
+
|
| 1882 |
+
>>> np.fromfunction(lambda i, j: i == j, (3, 3), dtype=np.int_)
|
| 1883 |
+
array([[ True, False, False],
|
| 1884 |
+
[False, True, False],
|
| 1885 |
+
[False, False, True]])
|
| 1886 |
+
|
| 1887 |
+
>>> np.fromfunction(lambda i, j: i + j, (3, 3), dtype=np.int_)
|
| 1888 |
+
array([[0, 1, 2],
|
| 1889 |
+
[1, 2, 3],
|
| 1890 |
+
[2, 3, 4]])
|
| 1891 |
+
|
| 1892 |
+
"""
|
| 1893 |
+
if like is not None:
|
| 1894 |
+
return _fromfunction_with_like(
|
| 1895 |
+
like, function, shape, dtype=dtype, **kwargs)
|
| 1896 |
+
|
| 1897 |
+
args = indices(shape, dtype=dtype)
|
| 1898 |
+
return function(*args, **kwargs)
|
| 1899 |
+
|
| 1900 |
+
|
| 1901 |
+
_fromfunction_with_like = array_function_dispatch()(fromfunction)
|
| 1902 |
+
|
| 1903 |
+
|
| 1904 |
+
def _frombuffer(buf, dtype, shape, order, axis_order=None):
|
| 1905 |
+
array = frombuffer(buf, dtype=dtype)
|
| 1906 |
+
if order == 'K' and axis_order is not None:
|
| 1907 |
+
return array.reshape(shape, order='C').transpose(axis_order)
|
| 1908 |
+
return array.reshape(shape, order=order)
|
| 1909 |
+
|
| 1910 |
+
|
| 1911 |
+
@set_module('numpy')
|
| 1912 |
+
def isscalar(element):
|
| 1913 |
+
"""
|
| 1914 |
+
Returns True if the type of `element` is a scalar type.
|
| 1915 |
+
|
| 1916 |
+
Parameters
|
| 1917 |
+
----------
|
| 1918 |
+
element : any
|
| 1919 |
+
Input argument, can be of any type and shape.
|
| 1920 |
+
|
| 1921 |
+
Returns
|
| 1922 |
+
-------
|
| 1923 |
+
val : bool
|
| 1924 |
+
True if `element` is a scalar type, False if it is not.
|
| 1925 |
+
|
| 1926 |
+
See Also
|
| 1927 |
+
--------
|
| 1928 |
+
ndim : Get the number of dimensions of an array
|
| 1929 |
+
|
| 1930 |
+
Notes
|
| 1931 |
+
-----
|
| 1932 |
+
If you need a stricter way to identify a *numerical* scalar, use
|
| 1933 |
+
``isinstance(x, numbers.Number)``, as that returns ``False`` for most
|
| 1934 |
+
non-numerical elements such as strings.
|
| 1935 |
+
|
| 1936 |
+
In most cases ``np.ndim(x) == 0`` should be used instead of this function,
|
| 1937 |
+
as that will also return true for 0d arrays. This is how numpy overloads
|
| 1938 |
+
functions in the style of the ``dx`` arguments to `gradient` and
|
| 1939 |
+
the ``bins`` argument to `histogram`. Some key differences:
|
| 1940 |
+
|
| 1941 |
+
+------------------------------------+---------------+-------------------+
|
| 1942 |
+
| x |``isscalar(x)``|``np.ndim(x) == 0``|
|
| 1943 |
+
+====================================+===============+===================+
|
| 1944 |
+
| PEP 3141 numeric objects | ``True`` | ``True`` |
|
| 1945 |
+
| (including builtins) | | |
|
| 1946 |
+
+------------------------------------+---------------+-------------------+
|
| 1947 |
+
| builtin string and buffer objects | ``True`` | ``True`` |
|
| 1948 |
+
+------------------------------------+---------------+-------------------+
|
| 1949 |
+
| other builtin objects, like | ``False`` | ``True`` |
|
| 1950 |
+
| `pathlib.Path`, `Exception`, | | |
|
| 1951 |
+
| the result of `re.compile` | | |
|
| 1952 |
+
+------------------------------------+---------------+-------------------+
|
| 1953 |
+
| third-party objects like | ``False`` | ``True`` |
|
| 1954 |
+
| `matplotlib.figure.Figure` | | |
|
| 1955 |
+
+------------------------------------+---------------+-------------------+
|
| 1956 |
+
| zero-dimensional numpy arrays | ``False`` | ``True`` |
|
| 1957 |
+
+------------------------------------+---------------+-------------------+
|
| 1958 |
+
| other numpy arrays | ``False`` | ``False`` |
|
| 1959 |
+
+------------------------------------+---------------+-------------------+
|
| 1960 |
+
| `list`, `tuple`, and other | ``False`` | ``False`` |
|
| 1961 |
+
| sequence objects | | |
|
| 1962 |
+
+------------------------------------+---------------+-------------------+
|
| 1963 |
+
|
| 1964 |
+
Examples
|
| 1965 |
+
--------
|
| 1966 |
+
>>> import numpy as np
|
| 1967 |
+
|
| 1968 |
+
>>> np.isscalar(3.1)
|
| 1969 |
+
True
|
| 1970 |
+
|
| 1971 |
+
>>> np.isscalar(np.array(3.1))
|
| 1972 |
+
False
|
| 1973 |
+
|
| 1974 |
+
>>> np.isscalar([3.1])
|
| 1975 |
+
False
|
| 1976 |
+
|
| 1977 |
+
>>> np.isscalar(False)
|
| 1978 |
+
True
|
| 1979 |
+
|
| 1980 |
+
>>> np.isscalar('numpy')
|
| 1981 |
+
True
|
| 1982 |
+
|
| 1983 |
+
NumPy supports PEP 3141 numbers:
|
| 1984 |
+
|
| 1985 |
+
>>> from fractions import Fraction
|
| 1986 |
+
>>> np.isscalar(Fraction(5, 17))
|
| 1987 |
+
True
|
| 1988 |
+
>>> from numbers import Number
|
| 1989 |
+
>>> np.isscalar(Number())
|
| 1990 |
+
True
|
| 1991 |
+
|
| 1992 |
+
"""
|
| 1993 |
+
return (isinstance(element, generic)
|
| 1994 |
+
or type(element) in ScalarType
|
| 1995 |
+
or isinstance(element, numbers.Number))
|
| 1996 |
+
|
| 1997 |
+
|
| 1998 |
+
@set_module('numpy')
|
| 1999 |
+
def binary_repr(num, width=None):
|
| 2000 |
+
"""
|
| 2001 |
+
Return the binary representation of the input number as a string.
|
| 2002 |
+
|
| 2003 |
+
For negative numbers, if width is not given, a minus sign is added to the
|
| 2004 |
+
front. If width is given, the two's complement of the number is
|
| 2005 |
+
returned, with respect to that width.
|
| 2006 |
+
|
| 2007 |
+
In a two's-complement system negative numbers are represented by the two's
|
| 2008 |
+
complement of the absolute value. This is the most common method of
|
| 2009 |
+
representing signed integers on computers [1]_. An N-bit two's-complement
|
| 2010 |
+
system can represent every integer in the range
|
| 2011 |
+
:math:`-2^{N-1}` to :math:`+2^{N-1}-1`.
|
| 2012 |
+
|
| 2013 |
+
Parameters
|
| 2014 |
+
----------
|
| 2015 |
+
num : int
|
| 2016 |
+
Only an integer decimal number can be used.
|
| 2017 |
+
width : int, optional
|
| 2018 |
+
The length of the returned string if `num` is positive, or the length
|
| 2019 |
+
of the two's complement if `num` is negative, provided that `width` is
|
| 2020 |
+
at least a sufficient number of bits for `num` to be represented in
|
| 2021 |
+
the designated form. If the `width` value is insufficient, an error is
|
| 2022 |
+
raised.
|
| 2023 |
+
|
| 2024 |
+
Returns
|
| 2025 |
+
-------
|
| 2026 |
+
bin : str
|
| 2027 |
+
Binary representation of `num` or two's complement of `num`.
|
| 2028 |
+
|
| 2029 |
+
See Also
|
| 2030 |
+
--------
|
| 2031 |
+
base_repr: Return a string representation of a number in the given base
|
| 2032 |
+
system.
|
| 2033 |
+
bin: Python's built-in binary representation generator of an integer.
|
| 2034 |
+
|
| 2035 |
+
Notes
|
| 2036 |
+
-----
|
| 2037 |
+
`binary_repr` is equivalent to using `base_repr` with base 2, but about 25x
|
| 2038 |
+
faster.
|
| 2039 |
+
|
| 2040 |
+
References
|
| 2041 |
+
----------
|
| 2042 |
+
.. [1] Wikipedia, "Two's complement",
|
| 2043 |
+
https://en.wikipedia.org/wiki/Two's_complement
|
| 2044 |
+
|
| 2045 |
+
Examples
|
| 2046 |
+
--------
|
| 2047 |
+
>>> import numpy as np
|
| 2048 |
+
>>> np.binary_repr(3)
|
| 2049 |
+
'11'
|
| 2050 |
+
>>> np.binary_repr(-3)
|
| 2051 |
+
'-11'
|
| 2052 |
+
>>> np.binary_repr(3, width=4)
|
| 2053 |
+
'0011'
|
| 2054 |
+
|
| 2055 |
+
The two's complement is returned when the input number is negative and
|
| 2056 |
+
width is specified:
|
| 2057 |
+
|
| 2058 |
+
>>> np.binary_repr(-3, width=3)
|
| 2059 |
+
'101'
|
| 2060 |
+
>>> np.binary_repr(-3, width=5)
|
| 2061 |
+
'11101'
|
| 2062 |
+
|
| 2063 |
+
"""
|
| 2064 |
+
def err_if_insufficient(width, binwidth):
|
| 2065 |
+
if width is not None and width < binwidth:
|
| 2066 |
+
raise ValueError(
|
| 2067 |
+
f"Insufficient bit {width=} provided for {binwidth=}"
|
| 2068 |
+
)
|
| 2069 |
+
|
| 2070 |
+
# Ensure that num is a Python integer to avoid overflow or unwanted
|
| 2071 |
+
# casts to floating point.
|
| 2072 |
+
num = operator.index(num)
|
| 2073 |
+
|
| 2074 |
+
if num == 0:
|
| 2075 |
+
return '0' * (width or 1)
|
| 2076 |
+
|
| 2077 |
+
elif num > 0:
|
| 2078 |
+
binary = f'{num:b}'
|
| 2079 |
+
binwidth = len(binary)
|
| 2080 |
+
outwidth = (binwidth if width is None
|
| 2081 |
+
else builtins.max(binwidth, width))
|
| 2082 |
+
err_if_insufficient(width, binwidth)
|
| 2083 |
+
return binary.zfill(outwidth)
|
| 2084 |
+
|
| 2085 |
+
elif width is None:
|
| 2086 |
+
return f'-{-num:b}'
|
| 2087 |
+
|
| 2088 |
+
else:
|
| 2089 |
+
poswidth = len(f'{-num:b}')
|
| 2090 |
+
|
| 2091 |
+
# See gh-8679: remove extra digit
|
| 2092 |
+
# for numbers at boundaries.
|
| 2093 |
+
if 2**(poswidth - 1) == -num:
|
| 2094 |
+
poswidth -= 1
|
| 2095 |
+
|
| 2096 |
+
twocomp = 2**(poswidth + 1) + num
|
| 2097 |
+
binary = f'{twocomp:b}'
|
| 2098 |
+
binwidth = len(binary)
|
| 2099 |
+
|
| 2100 |
+
outwidth = builtins.max(binwidth, width)
|
| 2101 |
+
err_if_insufficient(width, binwidth)
|
| 2102 |
+
return '1' * (outwidth - binwidth) + binary
|
| 2103 |
+
|
| 2104 |
+
|
| 2105 |
+
@set_module('numpy')
|
| 2106 |
+
def base_repr(number, base=2, padding=0):
|
| 2107 |
+
"""
|
| 2108 |
+
Return a string representation of a number in the given base system.
|
| 2109 |
+
|
| 2110 |
+
Parameters
|
| 2111 |
+
----------
|
| 2112 |
+
number : int
|
| 2113 |
+
The value to convert. Positive and negative values are handled.
|
| 2114 |
+
base : int, optional
|
| 2115 |
+
Convert `number` to the `base` number system. The valid range is 2-36,
|
| 2116 |
+
the default value is 2.
|
| 2117 |
+
padding : int, optional
|
| 2118 |
+
Number of zeros padded on the left. Default is 0 (no padding).
|
| 2119 |
+
|
| 2120 |
+
Returns
|
| 2121 |
+
-------
|
| 2122 |
+
out : str
|
| 2123 |
+
String representation of `number` in `base` system.
|
| 2124 |
+
|
| 2125 |
+
See Also
|
| 2126 |
+
--------
|
| 2127 |
+
binary_repr : Faster version of `base_repr` for base 2.
|
| 2128 |
+
|
| 2129 |
+
Examples
|
| 2130 |
+
--------
|
| 2131 |
+
>>> import numpy as np
|
| 2132 |
+
>>> np.base_repr(5)
|
| 2133 |
+
'101'
|
| 2134 |
+
>>> np.base_repr(6, 5)
|
| 2135 |
+
'11'
|
| 2136 |
+
>>> np.base_repr(7, base=5, padding=3)
|
| 2137 |
+
'00012'
|
| 2138 |
+
|
| 2139 |
+
>>> np.base_repr(10, base=16)
|
| 2140 |
+
'A'
|
| 2141 |
+
>>> np.base_repr(32, base=16)
|
| 2142 |
+
'20'
|
| 2143 |
+
|
| 2144 |
+
"""
|
| 2145 |
+
digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
| 2146 |
+
if base > len(digits):
|
| 2147 |
+
raise ValueError("Bases greater than 36 not handled in base_repr.")
|
| 2148 |
+
elif base < 2:
|
| 2149 |
+
raise ValueError("Bases less than 2 not handled in base_repr.")
|
| 2150 |
+
|
| 2151 |
+
num = abs(int(number))
|
| 2152 |
+
res = []
|
| 2153 |
+
while num:
|
| 2154 |
+
res.append(digits[num % base])
|
| 2155 |
+
num //= base
|
| 2156 |
+
if padding:
|
| 2157 |
+
res.append('0' * padding)
|
| 2158 |
+
if number < 0:
|
| 2159 |
+
res.append('-')
|
| 2160 |
+
return ''.join(reversed(res or '0'))
|
| 2161 |
+
|
| 2162 |
+
|
| 2163 |
+
# These are all essentially abbreviations
|
| 2164 |
+
# These might wind up in a special abbreviations module
|
| 2165 |
+
|
| 2166 |
+
|
| 2167 |
+
def _maketup(descr, val):
|
| 2168 |
+
dt = dtype(descr)
|
| 2169 |
+
# Place val in all scalar tuples:
|
| 2170 |
+
fields = dt.fields
|
| 2171 |
+
if fields is None:
|
| 2172 |
+
return val
|
| 2173 |
+
else:
|
| 2174 |
+
res = [_maketup(fields[name][0], val) for name in dt.names]
|
| 2175 |
+
return tuple(res)
|
| 2176 |
+
|
| 2177 |
+
|
| 2178 |
+
@finalize_array_function_like
|
| 2179 |
+
@set_module('numpy')
|
| 2180 |
+
def identity(n, dtype=None, *, like=None):
|
| 2181 |
+
"""
|
| 2182 |
+
Return the identity array.
|
| 2183 |
+
|
| 2184 |
+
The identity array is a square array with ones on
|
| 2185 |
+
the main diagonal.
|
| 2186 |
+
|
| 2187 |
+
Parameters
|
| 2188 |
+
----------
|
| 2189 |
+
n : int
|
| 2190 |
+
Number of rows (and columns) in `n` x `n` output.
|
| 2191 |
+
dtype : data-type, optional
|
| 2192 |
+
Data-type of the output. Defaults to ``float``.
|
| 2193 |
+
${ARRAY_FUNCTION_LIKE}
|
| 2194 |
+
|
| 2195 |
+
.. versionadded:: 1.20.0
|
| 2196 |
+
|
| 2197 |
+
Returns
|
| 2198 |
+
-------
|
| 2199 |
+
out : ndarray
|
| 2200 |
+
`n` x `n` array with its main diagonal set to one,
|
| 2201 |
+
and all other elements 0.
|
| 2202 |
+
|
| 2203 |
+
Examples
|
| 2204 |
+
--------
|
| 2205 |
+
>>> import numpy as np
|
| 2206 |
+
>>> np.identity(3)
|
| 2207 |
+
array([[1., 0., 0.],
|
| 2208 |
+
[0., 1., 0.],
|
| 2209 |
+
[0., 0., 1.]])
|
| 2210 |
+
|
| 2211 |
+
"""
|
| 2212 |
+
if like is not None:
|
| 2213 |
+
return _identity_with_like(like, n, dtype=dtype)
|
| 2214 |
+
|
| 2215 |
+
from numpy import eye
|
| 2216 |
+
return eye(n, dtype=dtype, like=like)
|
| 2217 |
+
|
| 2218 |
+
|
| 2219 |
+
_identity_with_like = array_function_dispatch()(identity)
|
| 2220 |
+
|
| 2221 |
+
|
| 2222 |
+
def _allclose_dispatcher(a, b, rtol=None, atol=None, equal_nan=None):
|
| 2223 |
+
return (a, b, rtol, atol)
|
| 2224 |
+
|
| 2225 |
+
|
| 2226 |
+
@array_function_dispatch(_allclose_dispatcher)
|
| 2227 |
+
def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
|
| 2228 |
+
"""
|
| 2229 |
+
Returns True if two arrays are element-wise equal within a tolerance.
|
| 2230 |
+
|
| 2231 |
+
The tolerance values are positive, typically very small numbers. The
|
| 2232 |
+
relative difference (`rtol` * abs(`b`)) and the absolute difference
|
| 2233 |
+
`atol` are added together to compare against the absolute difference
|
| 2234 |
+
between `a` and `b`.
|
| 2235 |
+
|
| 2236 |
+
.. warning:: The default `atol` is not appropriate for comparing numbers
|
| 2237 |
+
with magnitudes much smaller than one (see Notes).
|
| 2238 |
+
|
| 2239 |
+
NaNs are treated as equal if they are in the same place and if
|
| 2240 |
+
``equal_nan=True``. Infs are treated as equal if they are in the same
|
| 2241 |
+
place and of the same sign in both arrays.
|
| 2242 |
+
|
| 2243 |
+
Parameters
|
| 2244 |
+
----------
|
| 2245 |
+
a, b : array_like
|
| 2246 |
+
Input arrays to compare.
|
| 2247 |
+
rtol : array_like
|
| 2248 |
+
The relative tolerance parameter (see Notes).
|
| 2249 |
+
atol : array_like
|
| 2250 |
+
The absolute tolerance parameter (see Notes).
|
| 2251 |
+
equal_nan : bool
|
| 2252 |
+
Whether to compare NaN's as equal. If True, NaN's in `a` will be
|
| 2253 |
+
considered equal to NaN's in `b` in the output array.
|
| 2254 |
+
|
| 2255 |
+
Returns
|
| 2256 |
+
-------
|
| 2257 |
+
allclose : bool
|
| 2258 |
+
Returns True if the two arrays are equal within the given
|
| 2259 |
+
tolerance; False otherwise.
|
| 2260 |
+
|
| 2261 |
+
See Also
|
| 2262 |
+
--------
|
| 2263 |
+
isclose, all, any, equal
|
| 2264 |
+
|
| 2265 |
+
Notes
|
| 2266 |
+
-----
|
| 2267 |
+
If the following equation is element-wise True, then allclose returns
|
| 2268 |
+
True.::
|
| 2269 |
+
|
| 2270 |
+
absolute(a - b) <= (atol + rtol * absolute(b))
|
| 2271 |
+
|
| 2272 |
+
The above equation is not symmetric in `a` and `b`, so that
|
| 2273 |
+
``allclose(a, b)`` might be different from ``allclose(b, a)`` in
|
| 2274 |
+
some rare cases.
|
| 2275 |
+
|
| 2276 |
+
The default value of `atol` is not appropriate when the reference value
|
| 2277 |
+
`b` has magnitude smaller than one. For example, it is unlikely that
|
| 2278 |
+
``a = 1e-9`` and ``b = 2e-9`` should be considered "close", yet
|
| 2279 |
+
``allclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure
|
| 2280 |
+
to select `atol` for the use case at hand, especially for defining the
|
| 2281 |
+
threshold below which a non-zero value in `a` will be considered "close"
|
| 2282 |
+
to a very small or zero value in `b`.
|
| 2283 |
+
|
| 2284 |
+
The comparison of `a` and `b` uses standard broadcasting, which
|
| 2285 |
+
means that `a` and `b` need not have the same shape in order for
|
| 2286 |
+
``allclose(a, b)`` to evaluate to True. The same is true for
|
| 2287 |
+
`equal` but not `array_equal`.
|
| 2288 |
+
|
| 2289 |
+
`allclose` is not defined for non-numeric data types.
|
| 2290 |
+
`bool` is considered a numeric data-type for this purpose.
|
| 2291 |
+
|
| 2292 |
+
Examples
|
| 2293 |
+
--------
|
| 2294 |
+
>>> import numpy as np
|
| 2295 |
+
>>> np.allclose([1e10,1e-7], [1.00001e10,1e-8])
|
| 2296 |
+
False
|
| 2297 |
+
|
| 2298 |
+
>>> np.allclose([1e10,1e-8], [1.00001e10,1e-9])
|
| 2299 |
+
True
|
| 2300 |
+
|
| 2301 |
+
>>> np.allclose([1e10,1e-8], [1.0001e10,1e-9])
|
| 2302 |
+
False
|
| 2303 |
+
|
| 2304 |
+
>>> np.allclose([1.0, np.nan], [1.0, np.nan])
|
| 2305 |
+
False
|
| 2306 |
+
|
| 2307 |
+
>>> np.allclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
|
| 2308 |
+
True
|
| 2309 |
+
|
| 2310 |
+
|
| 2311 |
+
"""
|
| 2312 |
+
res = all(isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan))
|
| 2313 |
+
return builtins.bool(res)
|
| 2314 |
+
|
| 2315 |
+
|
| 2316 |
+
def _isclose_dispatcher(a, b, rtol=None, atol=None, equal_nan=None):
|
| 2317 |
+
return (a, b, rtol, atol)
|
| 2318 |
+
|
| 2319 |
+
|
| 2320 |
+
@array_function_dispatch(_isclose_dispatcher)
|
| 2321 |
+
def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
|
| 2322 |
+
"""
|
| 2323 |
+
Returns a boolean array where two arrays are element-wise equal within a
|
| 2324 |
+
tolerance.
|
| 2325 |
+
|
| 2326 |
+
The tolerance values are positive, typically very small numbers. The
|
| 2327 |
+
relative difference (`rtol` * abs(`b`)) and the absolute difference
|
| 2328 |
+
`atol` are added together to compare against the absolute difference
|
| 2329 |
+
between `a` and `b`.
|
| 2330 |
+
|
| 2331 |
+
.. warning:: The default `atol` is not appropriate for comparing numbers
|
| 2332 |
+
with magnitudes much smaller than one (see Notes).
|
| 2333 |
+
|
| 2334 |
+
Parameters
|
| 2335 |
+
----------
|
| 2336 |
+
a, b : array_like
|
| 2337 |
+
Input arrays to compare.
|
| 2338 |
+
rtol : array_like
|
| 2339 |
+
The relative tolerance parameter (see Notes).
|
| 2340 |
+
atol : array_like
|
| 2341 |
+
The absolute tolerance parameter (see Notes).
|
| 2342 |
+
equal_nan : bool
|
| 2343 |
+
Whether to compare NaN's as equal. If True, NaN's in `a` will be
|
| 2344 |
+
considered equal to NaN's in `b` in the output array.
|
| 2345 |
+
|
| 2346 |
+
Returns
|
| 2347 |
+
-------
|
| 2348 |
+
y : array_like
|
| 2349 |
+
Returns a boolean array of where `a` and `b` are equal within the
|
| 2350 |
+
given tolerance. If both `a` and `b` are scalars, returns a single
|
| 2351 |
+
boolean value.
|
| 2352 |
+
|
| 2353 |
+
See Also
|
| 2354 |
+
--------
|
| 2355 |
+
allclose
|
| 2356 |
+
math.isclose
|
| 2357 |
+
|
| 2358 |
+
Notes
|
| 2359 |
+
-----
|
| 2360 |
+
For finite values, isclose uses the following equation to test whether
|
| 2361 |
+
two floating point values are equivalent.::
|
| 2362 |
+
|
| 2363 |
+
absolute(a - b) <= (atol + rtol * absolute(b))
|
| 2364 |
+
|
| 2365 |
+
Unlike the built-in `math.isclose`, the above equation is not symmetric
|
| 2366 |
+
in `a` and `b` -- it assumes `b` is the reference value -- so that
|
| 2367 |
+
`isclose(a, b)` might be different from `isclose(b, a)`.
|
| 2368 |
+
|
| 2369 |
+
The default value of `atol` is not appropriate when the reference value
|
| 2370 |
+
`b` has magnitude smaller than one. For example, it is unlikely that
|
| 2371 |
+
``a = 1e-9`` and ``b = 2e-9`` should be considered "close", yet
|
| 2372 |
+
``isclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure
|
| 2373 |
+
to select `atol` for the use case at hand, especially for defining the
|
| 2374 |
+
threshold below which a non-zero value in `a` will be considered "close"
|
| 2375 |
+
to a very small or zero value in `b`.
|
| 2376 |
+
|
| 2377 |
+
`isclose` is not defined for non-numeric data types.
|
| 2378 |
+
:class:`bool` is considered a numeric data-type for this purpose.
|
| 2379 |
+
|
| 2380 |
+
Examples
|
| 2381 |
+
--------
|
| 2382 |
+
>>> import numpy as np
|
| 2383 |
+
>>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
|
| 2384 |
+
array([ True, False])
|
| 2385 |
+
|
| 2386 |
+
>>> np.isclose([1e10,1e-8], [1.00001e10,1e-9])
|
| 2387 |
+
array([ True, True])
|
| 2388 |
+
|
| 2389 |
+
>>> np.isclose([1e10,1e-8], [1.0001e10,1e-9])
|
| 2390 |
+
array([False, True])
|
| 2391 |
+
|
| 2392 |
+
>>> np.isclose([1.0, np.nan], [1.0, np.nan])
|
| 2393 |
+
array([ True, False])
|
| 2394 |
+
|
| 2395 |
+
>>> np.isclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
|
| 2396 |
+
array([ True, True])
|
| 2397 |
+
|
| 2398 |
+
>>> np.isclose([1e-8, 1e-7], [0.0, 0.0])
|
| 2399 |
+
array([ True, False])
|
| 2400 |
+
|
| 2401 |
+
>>> np.isclose([1e-100, 1e-7], [0.0, 0.0], atol=0.0)
|
| 2402 |
+
array([False, False])
|
| 2403 |
+
|
| 2404 |
+
>>> np.isclose([1e-10, 1e-10], [1e-20, 0.0])
|
| 2405 |
+
array([ True, True])
|
| 2406 |
+
|
| 2407 |
+
>>> np.isclose([1e-10, 1e-10], [1e-20, 0.999999e-10], atol=0.0)
|
| 2408 |
+
array([False, True])
|
| 2409 |
+
|
| 2410 |
+
"""
|
| 2411 |
+
# Turn all but python scalars into arrays.
|
| 2412 |
+
x, y, atol, rtol = (
|
| 2413 |
+
a if isinstance(a, (int, float, complex)) else asanyarray(a)
|
| 2414 |
+
for a in (a, b, atol, rtol))
|
| 2415 |
+
|
| 2416 |
+
# Make sure y is an inexact type to avoid bad behavior on abs(MIN_INT).
|
| 2417 |
+
# This will cause casting of x later. Also, make sure to allow subclasses
|
| 2418 |
+
# (e.g., for numpy.ma).
|
| 2419 |
+
# NOTE: We explicitly allow timedelta, which used to work. This could
|
| 2420 |
+
# possibly be deprecated. See also gh-18286.
|
| 2421 |
+
# timedelta works if `atol` is an integer or also a timedelta.
|
| 2422 |
+
# Although, the default tolerances are unlikely to be useful
|
| 2423 |
+
if (dtype := getattr(y, "dtype", None)) is not None and dtype.kind != "m":
|
| 2424 |
+
dt = multiarray.result_type(y, 1.)
|
| 2425 |
+
y = asanyarray(y, dtype=dt)
|
| 2426 |
+
elif isinstance(y, int):
|
| 2427 |
+
y = float(y)
|
| 2428 |
+
|
| 2429 |
+
# atol and rtol can be arrays
|
| 2430 |
+
if not (np.all(np.isfinite(atol)) and np.all(np.isfinite(rtol))):
|
| 2431 |
+
err_s = np.geterr()["invalid"]
|
| 2432 |
+
err_msg = f"One of rtol or atol is not valid, atol: {atol}, rtol: {rtol}"
|
| 2433 |
+
|
| 2434 |
+
if err_s == "warn":
|
| 2435 |
+
warnings.warn(err_msg, RuntimeWarning, stacklevel=2)
|
| 2436 |
+
elif err_s == "raise":
|
| 2437 |
+
raise FloatingPointError(err_msg)
|
| 2438 |
+
elif err_s == "print":
|
| 2439 |
+
print(err_msg)
|
| 2440 |
+
|
| 2441 |
+
with errstate(invalid='ignore'):
|
| 2442 |
+
|
| 2443 |
+
result = (less_equal(abs(x - y), atol + rtol * abs(y))
|
| 2444 |
+
& isfinite(y)
|
| 2445 |
+
| (x == y))
|
| 2446 |
+
if equal_nan:
|
| 2447 |
+
result |= isnan(x) & isnan(y)
|
| 2448 |
+
|
| 2449 |
+
return result[()] # Flatten 0d arrays to scalars
|
| 2450 |
+
|
| 2451 |
+
|
| 2452 |
+
def _array_equal_dispatcher(a1, a2, equal_nan=None):
|
| 2453 |
+
return (a1, a2)
|
| 2454 |
+
|
| 2455 |
+
|
| 2456 |
+
_no_nan_types = {
|
| 2457 |
+
# should use np.dtype.BoolDType, but as of writing
|
| 2458 |
+
# that fails the reloading test.
|
| 2459 |
+
type(dtype(nt.bool)),
|
| 2460 |
+
type(dtype(nt.int8)),
|
| 2461 |
+
type(dtype(nt.int16)),
|
| 2462 |
+
type(dtype(nt.int32)),
|
| 2463 |
+
type(dtype(nt.int64)),
|
| 2464 |
+
}
|
| 2465 |
+
|
| 2466 |
+
|
| 2467 |
+
def _dtype_cannot_hold_nan(dtype):
|
| 2468 |
+
return type(dtype) in _no_nan_types
|
| 2469 |
+
|
| 2470 |
+
|
| 2471 |
+
@array_function_dispatch(_array_equal_dispatcher)
|
| 2472 |
+
def array_equal(a1, a2, equal_nan=False):
|
| 2473 |
+
"""
|
| 2474 |
+
True if two arrays have the same shape and elements, False otherwise.
|
| 2475 |
+
|
| 2476 |
+
Parameters
|
| 2477 |
+
----------
|
| 2478 |
+
a1, a2 : array_like
|
| 2479 |
+
Input arrays.
|
| 2480 |
+
equal_nan : bool
|
| 2481 |
+
Whether to compare NaN's as equal. If the dtype of a1 and a2 is
|
| 2482 |
+
complex, values will be considered equal if either the real or the
|
| 2483 |
+
imaginary component of a given value is ``nan``.
|
| 2484 |
+
|
| 2485 |
+
Returns
|
| 2486 |
+
-------
|
| 2487 |
+
b : bool
|
| 2488 |
+
Returns True if the arrays are equal.
|
| 2489 |
+
|
| 2490 |
+
See Also
|
| 2491 |
+
--------
|
| 2492 |
+
allclose: Returns True if two arrays are element-wise equal within a
|
| 2493 |
+
tolerance.
|
| 2494 |
+
array_equiv: Returns True if input arrays are shape consistent and all
|
| 2495 |
+
elements equal.
|
| 2496 |
+
|
| 2497 |
+
Examples
|
| 2498 |
+
--------
|
| 2499 |
+
>>> import numpy as np
|
| 2500 |
+
|
| 2501 |
+
>>> np.array_equal([1, 2], [1, 2])
|
| 2502 |
+
True
|
| 2503 |
+
|
| 2504 |
+
>>> np.array_equal(np.array([1, 2]), np.array([1, 2]))
|
| 2505 |
+
True
|
| 2506 |
+
|
| 2507 |
+
>>> np.array_equal([1, 2], [1, 2, 3])
|
| 2508 |
+
False
|
| 2509 |
+
|
| 2510 |
+
>>> np.array_equal([1, 2], [1, 4])
|
| 2511 |
+
False
|
| 2512 |
+
|
| 2513 |
+
>>> a = np.array([1, np.nan])
|
| 2514 |
+
>>> np.array_equal(a, a)
|
| 2515 |
+
False
|
| 2516 |
+
|
| 2517 |
+
>>> np.array_equal(a, a, equal_nan=True)
|
| 2518 |
+
True
|
| 2519 |
+
|
| 2520 |
+
When ``equal_nan`` is True, complex values with nan components are
|
| 2521 |
+
considered equal if either the real *or* the imaginary components are nan.
|
| 2522 |
+
|
| 2523 |
+
>>> a = np.array([1 + 1j])
|
| 2524 |
+
>>> b = a.copy()
|
| 2525 |
+
>>> a.real = np.nan
|
| 2526 |
+
>>> b.imag = np.nan
|
| 2527 |
+
>>> np.array_equal(a, b, equal_nan=True)
|
| 2528 |
+
True
|
| 2529 |
+
"""
|
| 2530 |
+
try:
|
| 2531 |
+
a1, a2 = asarray(a1), asarray(a2)
|
| 2532 |
+
except Exception:
|
| 2533 |
+
return False
|
| 2534 |
+
if a1.shape != a2.shape:
|
| 2535 |
+
return False
|
| 2536 |
+
if not equal_nan:
|
| 2537 |
+
return builtins.bool((asanyarray(a1 == a2)).all())
|
| 2538 |
+
|
| 2539 |
+
if a1 is a2:
|
| 2540 |
+
# nan will compare equal so an array will compare equal to itself.
|
| 2541 |
+
return True
|
| 2542 |
+
|
| 2543 |
+
cannot_have_nan = (_dtype_cannot_hold_nan(a1.dtype)
|
| 2544 |
+
and _dtype_cannot_hold_nan(a2.dtype))
|
| 2545 |
+
if cannot_have_nan:
|
| 2546 |
+
return builtins.bool(asarray(a1 == a2).all())
|
| 2547 |
+
|
| 2548 |
+
# Fast path for a1 and a2 being all NaN arrays
|
| 2549 |
+
a1nan = isnan(a1)
|
| 2550 |
+
if a1nan.all():
|
| 2551 |
+
return builtins.bool(isnan(a2).all())
|
| 2552 |
+
|
| 2553 |
+
equal_or_both_nan = (a1 == a2) | (a1nan & isnan(a2))
|
| 2554 |
+
return builtins.bool(equal_or_both_nan.all())
|
| 2555 |
+
|
| 2556 |
+
|
| 2557 |
+
def _array_equiv_dispatcher(a1, a2):
|
| 2558 |
+
return (a1, a2)
|
| 2559 |
+
|
| 2560 |
+
|
| 2561 |
+
@array_function_dispatch(_array_equiv_dispatcher)
|
| 2562 |
+
def array_equiv(a1, a2):
|
| 2563 |
+
"""
|
| 2564 |
+
Returns True if input arrays are shape consistent and all elements equal.
|
| 2565 |
+
|
| 2566 |
+
Shape consistent means they are either the same shape, or one input array
|
| 2567 |
+
can be broadcasted to create the same shape as the other one.
|
| 2568 |
+
|
| 2569 |
+
Parameters
|
| 2570 |
+
----------
|
| 2571 |
+
a1, a2 : array_like
|
| 2572 |
+
Input arrays.
|
| 2573 |
+
|
| 2574 |
+
Returns
|
| 2575 |
+
-------
|
| 2576 |
+
out : bool
|
| 2577 |
+
True if equivalent, False otherwise.
|
| 2578 |
+
|
| 2579 |
+
Examples
|
| 2580 |
+
--------
|
| 2581 |
+
>>> import numpy as np
|
| 2582 |
+
>>> np.array_equiv([1, 2], [1, 2])
|
| 2583 |
+
True
|
| 2584 |
+
>>> np.array_equiv([1, 2], [1, 3])
|
| 2585 |
+
False
|
| 2586 |
+
|
| 2587 |
+
Showing the shape equivalence:
|
| 2588 |
+
|
| 2589 |
+
>>> np.array_equiv([1, 2], [[1, 2], [1, 2]])
|
| 2590 |
+
True
|
| 2591 |
+
>>> np.array_equiv([1, 2], [[1, 2, 1, 2], [1, 2, 1, 2]])
|
| 2592 |
+
False
|
| 2593 |
+
|
| 2594 |
+
>>> np.array_equiv([1, 2], [[1, 2], [1, 3]])
|
| 2595 |
+
False
|
| 2596 |
+
|
| 2597 |
+
"""
|
| 2598 |
+
try:
|
| 2599 |
+
a1, a2 = asarray(a1), asarray(a2)
|
| 2600 |
+
except Exception:
|
| 2601 |
+
return False
|
| 2602 |
+
try:
|
| 2603 |
+
multiarray.broadcast(a1, a2)
|
| 2604 |
+
except Exception:
|
| 2605 |
+
return False
|
| 2606 |
+
|
| 2607 |
+
return builtins.bool(asanyarray(a1 == a2).all())
|
| 2608 |
+
|
| 2609 |
+
|
| 2610 |
+
def _astype_dispatcher(x, dtype, /, *, copy=None, device=None):
|
| 2611 |
+
return (x, dtype)
|
| 2612 |
+
|
| 2613 |
+
|
| 2614 |
+
@array_function_dispatch(_astype_dispatcher)
|
| 2615 |
+
def astype(x, dtype, /, *, copy=True, device=None):
|
| 2616 |
+
"""
|
| 2617 |
+
Copies an array to a specified data type.
|
| 2618 |
+
|
| 2619 |
+
This function is an Array API compatible alternative to
|
| 2620 |
+
`numpy.ndarray.astype`.
|
| 2621 |
+
|
| 2622 |
+
Parameters
|
| 2623 |
+
----------
|
| 2624 |
+
x : ndarray
|
| 2625 |
+
Input NumPy array to cast. ``array_likes`` are explicitly not
|
| 2626 |
+
supported here.
|
| 2627 |
+
dtype : dtype
|
| 2628 |
+
Data type of the result.
|
| 2629 |
+
copy : bool, optional
|
| 2630 |
+
Specifies whether to copy an array when the specified dtype matches
|
| 2631 |
+
the data type of the input array ``x``. If ``True``, a newly allocated
|
| 2632 |
+
array must always be returned. If ``False`` and the specified dtype
|
| 2633 |
+
matches the data type of the input array, the input array must be
|
| 2634 |
+
returned; otherwise, a newly allocated array must be returned.
|
| 2635 |
+
Defaults to ``True``.
|
| 2636 |
+
device : str, optional
|
| 2637 |
+
The device on which to place the returned array. Default: None.
|
| 2638 |
+
For Array-API interoperability only, so must be ``"cpu"`` if passed.
|
| 2639 |
+
|
| 2640 |
+
.. versionadded:: 2.1.0
|
| 2641 |
+
|
| 2642 |
+
Returns
|
| 2643 |
+
-------
|
| 2644 |
+
out : ndarray
|
| 2645 |
+
An array having the specified data type.
|
| 2646 |
+
|
| 2647 |
+
See Also
|
| 2648 |
+
--------
|
| 2649 |
+
ndarray.astype
|
| 2650 |
+
|
| 2651 |
+
Examples
|
| 2652 |
+
--------
|
| 2653 |
+
>>> import numpy as np
|
| 2654 |
+
>>> arr = np.array([1, 2, 3]); arr
|
| 2655 |
+
array([1, 2, 3])
|
| 2656 |
+
>>> np.astype(arr, np.float64)
|
| 2657 |
+
array([1., 2., 3.])
|
| 2658 |
+
|
| 2659 |
+
Non-copy case:
|
| 2660 |
+
|
| 2661 |
+
>>> arr = np.array([1, 2, 3])
|
| 2662 |
+
>>> arr_noncpy = np.astype(arr, arr.dtype, copy=False)
|
| 2663 |
+
>>> np.shares_memory(arr, arr_noncpy)
|
| 2664 |
+
True
|
| 2665 |
+
|
| 2666 |
+
"""
|
| 2667 |
+
if not (isinstance(x, np.ndarray) or isscalar(x)):
|
| 2668 |
+
raise TypeError(
|
| 2669 |
+
"Input should be a NumPy array or scalar. "
|
| 2670 |
+
f"It is a {type(x)} instead."
|
| 2671 |
+
)
|
| 2672 |
+
if device is not None and device != "cpu":
|
| 2673 |
+
raise ValueError(
|
| 2674 |
+
'Device not understood. Only "cpu" is allowed, but received:'
|
| 2675 |
+
f' {device}'
|
| 2676 |
+
)
|
| 2677 |
+
return x.astype(dtype, copy=copy)
|
| 2678 |
+
|
| 2679 |
+
|
| 2680 |
+
inf = PINF
|
| 2681 |
+
nan = NAN
|
| 2682 |
+
False_ = nt.bool(False)
|
| 2683 |
+
True_ = nt.bool(True)
|
| 2684 |
+
|
| 2685 |
+
|
| 2686 |
+
def extend_all(module):
|
| 2687 |
+
existing = set(__all__)
|
| 2688 |
+
mall = module.__all__
|
| 2689 |
+
for a in mall:
|
| 2690 |
+
if a not in existing:
|
| 2691 |
+
__all__.append(a)
|
| 2692 |
+
|
| 2693 |
+
|
| 2694 |
+
from . import _asarray, _ufunc_config, arrayprint, fromnumeric
|
| 2695 |
+
from ._asarray import *
|
| 2696 |
+
from ._ufunc_config import *
|
| 2697 |
+
from .arrayprint import *
|
| 2698 |
+
from .fromnumeric import *
|
| 2699 |
+
from .numerictypes import *
|
| 2700 |
+
from .umath import *
|
| 2701 |
+
|
| 2702 |
+
extend_all(fromnumeric)
|
| 2703 |
+
extend_all(umath)
|
| 2704 |
+
extend_all(numerictypes)
|
| 2705 |
+
extend_all(arrayprint)
|
| 2706 |
+
extend_all(_asarray)
|
| 2707 |
+
extend_all(_ufunc_config)
|
v12x/pylib/numpy/_core/numerictypes.py
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
numerictypes: Define the numeric type objects
|
| 3 |
+
|
| 4 |
+
This module is designed so "from numerictypes import \\*" is safe.
|
| 5 |
+
Exported symbols include:
|
| 6 |
+
|
| 7 |
+
Dictionary with all registered number types (including aliases):
|
| 8 |
+
sctypeDict
|
| 9 |
+
|
| 10 |
+
Type objects (not all will be available, depends on platform):
|
| 11 |
+
see variable sctypes for which ones you have
|
| 12 |
+
|
| 13 |
+
Bit-width names
|
| 14 |
+
|
| 15 |
+
int8 int16 int32 int64
|
| 16 |
+
uint8 uint16 uint32 uint64
|
| 17 |
+
float16 float32 float64 float96 float128
|
| 18 |
+
complex64 complex128 complex192 complex256
|
| 19 |
+
datetime64 timedelta64
|
| 20 |
+
|
| 21 |
+
c-based names
|
| 22 |
+
|
| 23 |
+
bool
|
| 24 |
+
|
| 25 |
+
object_
|
| 26 |
+
|
| 27 |
+
void, str_
|
| 28 |
+
|
| 29 |
+
byte, ubyte,
|
| 30 |
+
short, ushort
|
| 31 |
+
intc, uintc,
|
| 32 |
+
intp, uintp,
|
| 33 |
+
int_, uint,
|
| 34 |
+
longlong, ulonglong,
|
| 35 |
+
|
| 36 |
+
single, csingle,
|
| 37 |
+
double, cdouble,
|
| 38 |
+
longdouble, clongdouble,
|
| 39 |
+
|
| 40 |
+
As part of the type-hierarchy: xx -- is bit-width
|
| 41 |
+
|
| 42 |
+
generic
|
| 43 |
+
+-> bool (kind=b)
|
| 44 |
+
+-> number
|
| 45 |
+
| +-> integer
|
| 46 |
+
| | +-> signedinteger (intxx) (kind=i)
|
| 47 |
+
| | | byte
|
| 48 |
+
| | | short
|
| 49 |
+
| | | intc
|
| 50 |
+
| | | intp
|
| 51 |
+
| | | int_
|
| 52 |
+
| | | longlong
|
| 53 |
+
| | \\-> unsignedinteger (uintxx) (kind=u)
|
| 54 |
+
| | ubyte
|
| 55 |
+
| | ushort
|
| 56 |
+
| | uintc
|
| 57 |
+
| | uintp
|
| 58 |
+
| | uint
|
| 59 |
+
| | ulonglong
|
| 60 |
+
| +-> inexact
|
| 61 |
+
| +-> floating (floatxx) (kind=f)
|
| 62 |
+
| | half
|
| 63 |
+
| | single
|
| 64 |
+
| | double
|
| 65 |
+
| | longdouble
|
| 66 |
+
| \\-> complexfloating (complexxx) (kind=c)
|
| 67 |
+
| csingle
|
| 68 |
+
| cdouble
|
| 69 |
+
| clongdouble
|
| 70 |
+
+-> flexible
|
| 71 |
+
| +-> character
|
| 72 |
+
| | bytes_ (kind=S)
|
| 73 |
+
| | str_ (kind=U)
|
| 74 |
+
| |
|
| 75 |
+
| \\-> void (kind=V)
|
| 76 |
+
\\-> object_ (not used much) (kind=O)
|
| 77 |
+
|
| 78 |
+
"""
|
| 79 |
+
import numbers
|
| 80 |
+
|
| 81 |
+
from numpy._utils import set_module
|
| 82 |
+
|
| 83 |
+
from . import multiarray as ma
|
| 84 |
+
from ._multiarray_umath import StringDType
|
| 85 |
+
from .multiarray import (
|
| 86 |
+
busday_count,
|
| 87 |
+
busday_offset,
|
| 88 |
+
busdaycalendar,
|
| 89 |
+
datetime_as_string,
|
| 90 |
+
datetime_data,
|
| 91 |
+
dtype,
|
| 92 |
+
is_busday,
|
| 93 |
+
ndarray,
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
# we add more at the bottom
|
| 97 |
+
__all__ = [
|
| 98 |
+
'ScalarType', 'typecodes', 'issubdtype', 'datetime_data',
|
| 99 |
+
'datetime_as_string', 'busday_offset', 'busday_count',
|
| 100 |
+
'is_busday', 'busdaycalendar', 'isdtype'
|
| 101 |
+
]
|
| 102 |
+
|
| 103 |
+
# we don't need all these imports, but we need to keep them for compatibility
|
| 104 |
+
# for users using np._core.numerictypes.UPPER_TABLE
|
| 105 |
+
# we don't export these for import *, but we do want them accessible
|
| 106 |
+
# as numerictypes.bool, etc.
|
| 107 |
+
from builtins import bool, bytes, complex, float, int, object, str # noqa: F401, UP029
|
| 108 |
+
|
| 109 |
+
from ._string_helpers import ( # noqa: F401
|
| 110 |
+
LOWER_TABLE,
|
| 111 |
+
UPPER_TABLE,
|
| 112 |
+
english_capitalize,
|
| 113 |
+
english_lower,
|
| 114 |
+
english_upper,
|
| 115 |
+
)
|
| 116 |
+
from ._type_aliases import allTypes, sctypeDict, sctypes
|
| 117 |
+
|
| 118 |
+
# We use this later
|
| 119 |
+
generic = allTypes['generic']
|
| 120 |
+
|
| 121 |
+
genericTypeRank = ['bool', 'int8', 'uint8', 'int16', 'uint16',
|
| 122 |
+
'int32', 'uint32', 'int64', 'uint64',
|
| 123 |
+
'float16', 'float32', 'float64', 'float96', 'float128',
|
| 124 |
+
'complex64', 'complex128', 'complex192', 'complex256',
|
| 125 |
+
'object']
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
@set_module('numpy')
|
| 129 |
+
def issctype(rep):
|
| 130 |
+
"""
|
| 131 |
+
Determines whether the given object represents a scalar data-type.
|
| 132 |
+
|
| 133 |
+
Parameters
|
| 134 |
+
----------
|
| 135 |
+
rep : any
|
| 136 |
+
If `rep` is an instance of a scalar dtype, True is returned. If not,
|
| 137 |
+
False is returned.
|
| 138 |
+
|
| 139 |
+
Returns
|
| 140 |
+
-------
|
| 141 |
+
out : bool
|
| 142 |
+
Boolean result of check whether `rep` is a scalar dtype.
|
| 143 |
+
|
| 144 |
+
See Also
|
| 145 |
+
--------
|
| 146 |
+
issubsctype, issubdtype, obj2sctype, sctype2char
|
| 147 |
+
|
| 148 |
+
Examples
|
| 149 |
+
--------
|
| 150 |
+
>>> from numpy._core.numerictypes import issctype
|
| 151 |
+
>>> issctype(np.int32)
|
| 152 |
+
True
|
| 153 |
+
>>> issctype(list)
|
| 154 |
+
False
|
| 155 |
+
>>> issctype(1.1)
|
| 156 |
+
False
|
| 157 |
+
|
| 158 |
+
Strings are also a scalar type:
|
| 159 |
+
|
| 160 |
+
>>> issctype(np.dtype(np.str_))
|
| 161 |
+
True
|
| 162 |
+
|
| 163 |
+
"""
|
| 164 |
+
if not isinstance(rep, (type, dtype)):
|
| 165 |
+
return False
|
| 166 |
+
try:
|
| 167 |
+
res = obj2sctype(rep)
|
| 168 |
+
if res and res != object_:
|
| 169 |
+
return True
|
| 170 |
+
else:
|
| 171 |
+
return False
|
| 172 |
+
except Exception:
|
| 173 |
+
return False
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def obj2sctype(rep, default=None):
|
| 177 |
+
"""
|
| 178 |
+
Return the scalar dtype or NumPy equivalent of Python type of an object.
|
| 179 |
+
|
| 180 |
+
Parameters
|
| 181 |
+
----------
|
| 182 |
+
rep : any
|
| 183 |
+
The object of which the type is returned.
|
| 184 |
+
default : any, optional
|
| 185 |
+
If given, this is returned for objects whose types can not be
|
| 186 |
+
determined. If not given, None is returned for those objects.
|
| 187 |
+
|
| 188 |
+
Returns
|
| 189 |
+
-------
|
| 190 |
+
dtype : dtype or Python type
|
| 191 |
+
The data type of `rep`.
|
| 192 |
+
|
| 193 |
+
See Also
|
| 194 |
+
--------
|
| 195 |
+
sctype2char, issctype, issubsctype, issubdtype
|
| 196 |
+
|
| 197 |
+
Examples
|
| 198 |
+
--------
|
| 199 |
+
>>> from numpy._core.numerictypes import obj2sctype
|
| 200 |
+
>>> obj2sctype(np.int32)
|
| 201 |
+
<class 'numpy.int32'>
|
| 202 |
+
>>> obj2sctype(np.array([1., 2.]))
|
| 203 |
+
<class 'numpy.float64'>
|
| 204 |
+
>>> obj2sctype(np.array([1.j]))
|
| 205 |
+
<class 'numpy.complex128'>
|
| 206 |
+
|
| 207 |
+
>>> obj2sctype(dict)
|
| 208 |
+
<class 'numpy.object_'>
|
| 209 |
+
>>> obj2sctype('string')
|
| 210 |
+
|
| 211 |
+
>>> obj2sctype(1, default=list)
|
| 212 |
+
<class 'list'>
|
| 213 |
+
|
| 214 |
+
"""
|
| 215 |
+
# prevent abstract classes being upcast
|
| 216 |
+
if isinstance(rep, type) and issubclass(rep, generic):
|
| 217 |
+
return rep
|
| 218 |
+
# extract dtype from arrays
|
| 219 |
+
if isinstance(rep, ndarray):
|
| 220 |
+
return rep.dtype.type
|
| 221 |
+
# fall back on dtype to convert
|
| 222 |
+
try:
|
| 223 |
+
res = dtype(rep)
|
| 224 |
+
except Exception:
|
| 225 |
+
return default
|
| 226 |
+
else:
|
| 227 |
+
return res.type
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
@set_module('numpy')
|
| 231 |
+
def issubclass_(arg1, arg2):
|
| 232 |
+
"""
|
| 233 |
+
Determine if a class is a subclass of a second class.
|
| 234 |
+
|
| 235 |
+
`issubclass_` is equivalent to the Python built-in ``issubclass``,
|
| 236 |
+
except that it returns False instead of raising a TypeError if one
|
| 237 |
+
of the arguments is not a class.
|
| 238 |
+
|
| 239 |
+
Parameters
|
| 240 |
+
----------
|
| 241 |
+
arg1 : class
|
| 242 |
+
Input class. True is returned if `arg1` is a subclass of `arg2`.
|
| 243 |
+
arg2 : class or tuple of classes.
|
| 244 |
+
Input class. If a tuple of classes, True is returned if `arg1` is a
|
| 245 |
+
subclass of any of the tuple elements.
|
| 246 |
+
|
| 247 |
+
Returns
|
| 248 |
+
-------
|
| 249 |
+
out : bool
|
| 250 |
+
Whether `arg1` is a subclass of `arg2` or not.
|
| 251 |
+
|
| 252 |
+
See Also
|
| 253 |
+
--------
|
| 254 |
+
issubsctype, issubdtype, issctype
|
| 255 |
+
|
| 256 |
+
Examples
|
| 257 |
+
--------
|
| 258 |
+
>>> np.issubclass_(np.int32, int)
|
| 259 |
+
False
|
| 260 |
+
>>> np.issubclass_(np.int32, float)
|
| 261 |
+
False
|
| 262 |
+
>>> np.issubclass_(np.float64, float)
|
| 263 |
+
True
|
| 264 |
+
|
| 265 |
+
"""
|
| 266 |
+
try:
|
| 267 |
+
return issubclass(arg1, arg2)
|
| 268 |
+
except TypeError:
|
| 269 |
+
return False
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
@set_module('numpy')
|
| 273 |
+
def issubsctype(arg1, arg2):
|
| 274 |
+
"""
|
| 275 |
+
Determine if the first argument is a subclass of the second argument.
|
| 276 |
+
|
| 277 |
+
Parameters
|
| 278 |
+
----------
|
| 279 |
+
arg1, arg2 : dtype or dtype specifier
|
| 280 |
+
Data-types.
|
| 281 |
+
|
| 282 |
+
Returns
|
| 283 |
+
-------
|
| 284 |
+
out : bool
|
| 285 |
+
The result.
|
| 286 |
+
|
| 287 |
+
See Also
|
| 288 |
+
--------
|
| 289 |
+
issctype, issubdtype, obj2sctype
|
| 290 |
+
|
| 291 |
+
Examples
|
| 292 |
+
--------
|
| 293 |
+
>>> from numpy._core import issubsctype
|
| 294 |
+
>>> issubsctype('S8', str)
|
| 295 |
+
False
|
| 296 |
+
>>> issubsctype(np.array([1]), int)
|
| 297 |
+
True
|
| 298 |
+
>>> issubsctype(np.array([1]), float)
|
| 299 |
+
False
|
| 300 |
+
|
| 301 |
+
"""
|
| 302 |
+
return issubclass(obj2sctype(arg1), obj2sctype(arg2))
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
class _PreprocessDTypeError(Exception):
|
| 306 |
+
pass
|
| 307 |
+
|
| 308 |
+
|
| 309 |
+
def _preprocess_dtype(dtype):
|
| 310 |
+
"""
|
| 311 |
+
Preprocess dtype argument by:
|
| 312 |
+
1. fetching type from a data type
|
| 313 |
+
2. verifying that types are built-in NumPy dtypes
|
| 314 |
+
"""
|
| 315 |
+
orig_dtype = dtype
|
| 316 |
+
if isinstance(dtype, ma.dtype):
|
| 317 |
+
dtype = dtype.type
|
| 318 |
+
if isinstance(dtype, ndarray) or dtype not in allTypes.values():
|
| 319 |
+
if isinstance(orig_dtype, StringDType) or orig_dtype is StringDType:
|
| 320 |
+
# StringDType's scalar type is the builtin `str`, which is not
|
| 321 |
+
# a NumPy scalar type, so use the DType class to identify it.
|
| 322 |
+
# if we ever fix gh-28165, this should be deleted
|
| 323 |
+
return StringDType
|
| 324 |
+
raise _PreprocessDTypeError
|
| 325 |
+
return dtype
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
@set_module('numpy')
|
| 329 |
+
def isdtype(dtype, kind):
|
| 330 |
+
"""
|
| 331 |
+
Determine if a provided dtype is of a specified data type ``kind``.
|
| 332 |
+
|
| 333 |
+
This function only supports built-in NumPy's data types.
|
| 334 |
+
Third-party dtypes are not yet supported.
|
| 335 |
+
|
| 336 |
+
Parameters
|
| 337 |
+
----------
|
| 338 |
+
dtype : dtype
|
| 339 |
+
The input dtype.
|
| 340 |
+
kind : dtype or str or tuple of dtypes/strs.
|
| 341 |
+
dtype or dtype kind. Allowed dtype kinds are:
|
| 342 |
+
* ``'bool'`` : boolean kind
|
| 343 |
+
* ``'signed integer'`` : signed integer data types
|
| 344 |
+
* ``'unsigned integer'`` : unsigned integer data types
|
| 345 |
+
* ``'integral'`` : integer data types
|
| 346 |
+
* ``'real floating'`` : real-valued floating-point data types
|
| 347 |
+
* ``'complex floating'`` : complex floating-point data types
|
| 348 |
+
* ``'numeric'`` : numeric data types
|
| 349 |
+
|
| 350 |
+
Returns
|
| 351 |
+
-------
|
| 352 |
+
out : bool
|
| 353 |
+
|
| 354 |
+
See Also
|
| 355 |
+
--------
|
| 356 |
+
issubdtype
|
| 357 |
+
|
| 358 |
+
Examples
|
| 359 |
+
--------
|
| 360 |
+
>>> import numpy as np
|
| 361 |
+
>>> np.isdtype(np.float32, np.float64)
|
| 362 |
+
False
|
| 363 |
+
>>> np.isdtype(np.float32, "real floating")
|
| 364 |
+
True
|
| 365 |
+
>>> np.isdtype(np.complex128, ("real floating", "complex floating"))
|
| 366 |
+
True
|
| 367 |
+
|
| 368 |
+
"""
|
| 369 |
+
try:
|
| 370 |
+
dtype = _preprocess_dtype(dtype)
|
| 371 |
+
except _PreprocessDTypeError:
|
| 372 |
+
raise TypeError(
|
| 373 |
+
"dtype argument must be a NumPy dtype, "
|
| 374 |
+
f"but it is a {type(dtype)}."
|
| 375 |
+
) from None
|
| 376 |
+
|
| 377 |
+
input_kinds = kind if isinstance(kind, tuple) else (kind,)
|
| 378 |
+
|
| 379 |
+
processed_kinds = set()
|
| 380 |
+
|
| 381 |
+
for kind in input_kinds:
|
| 382 |
+
if kind == "bool":
|
| 383 |
+
processed_kinds.add(allTypes["bool"])
|
| 384 |
+
elif kind == "signed integer":
|
| 385 |
+
processed_kinds.update(sctypes["int"])
|
| 386 |
+
elif kind == "unsigned integer":
|
| 387 |
+
processed_kinds.update(sctypes["uint"])
|
| 388 |
+
elif kind == "integral":
|
| 389 |
+
processed_kinds.update(sctypes["int"] + sctypes["uint"])
|
| 390 |
+
elif kind == "real floating":
|
| 391 |
+
processed_kinds.update(sctypes["float"])
|
| 392 |
+
elif kind == "complex floating":
|
| 393 |
+
processed_kinds.update(sctypes["complex"])
|
| 394 |
+
elif kind == "numeric":
|
| 395 |
+
processed_kinds.update(
|
| 396 |
+
sctypes["int"] + sctypes["uint"] +
|
| 397 |
+
sctypes["float"] + sctypes["complex"]
|
| 398 |
+
)
|
| 399 |
+
elif isinstance(kind, str):
|
| 400 |
+
raise ValueError(
|
| 401 |
+
"kind argument is a string, but"
|
| 402 |
+
f" {kind!r} is not a known kind name."
|
| 403 |
+
)
|
| 404 |
+
else:
|
| 405 |
+
try:
|
| 406 |
+
kind = _preprocess_dtype(kind)
|
| 407 |
+
except _PreprocessDTypeError:
|
| 408 |
+
raise TypeError(
|
| 409 |
+
"kind argument must be comprised of "
|
| 410 |
+
"NumPy dtypes or strings only, "
|
| 411 |
+
f"but is a {type(kind)}."
|
| 412 |
+
) from None
|
| 413 |
+
processed_kinds.add(kind)
|
| 414 |
+
|
| 415 |
+
return dtype in processed_kinds
|
| 416 |
+
|
| 417 |
+
|
| 418 |
+
@set_module('numpy')
|
| 419 |
+
def issubdtype(arg1, arg2):
|
| 420 |
+
r"""
|
| 421 |
+
Returns True if first argument is a typecode lower/equal in type hierarchy.
|
| 422 |
+
|
| 423 |
+
This is like the builtin :func:`issubclass`, but for `dtype`\ s.
|
| 424 |
+
|
| 425 |
+
Parameters
|
| 426 |
+
----------
|
| 427 |
+
arg1, arg2 : dtype_like
|
| 428 |
+
`dtype` or object coercible to one
|
| 429 |
+
|
| 430 |
+
Returns
|
| 431 |
+
-------
|
| 432 |
+
out : bool
|
| 433 |
+
|
| 434 |
+
See Also
|
| 435 |
+
--------
|
| 436 |
+
:ref:`arrays.scalars` : Overview of the numpy type hierarchy.
|
| 437 |
+
|
| 438 |
+
Examples
|
| 439 |
+
--------
|
| 440 |
+
`issubdtype` can be used to check the type of arrays:
|
| 441 |
+
|
| 442 |
+
>>> ints = np.array([1, 2, 3], dtype=np.int32)
|
| 443 |
+
>>> np.issubdtype(ints.dtype, np.integer)
|
| 444 |
+
True
|
| 445 |
+
>>> np.issubdtype(ints.dtype, np.floating)
|
| 446 |
+
False
|
| 447 |
+
|
| 448 |
+
>>> floats = np.array([1, 2, 3], dtype=np.float32)
|
| 449 |
+
>>> np.issubdtype(floats.dtype, np.integer)
|
| 450 |
+
False
|
| 451 |
+
>>> np.issubdtype(floats.dtype, np.floating)
|
| 452 |
+
True
|
| 453 |
+
|
| 454 |
+
Similar types of different sizes are not subdtypes of each other:
|
| 455 |
+
|
| 456 |
+
>>> np.issubdtype(np.float64, np.float32)
|
| 457 |
+
False
|
| 458 |
+
>>> np.issubdtype(np.float32, np.float64)
|
| 459 |
+
False
|
| 460 |
+
|
| 461 |
+
but both are subtypes of `floating`:
|
| 462 |
+
|
| 463 |
+
>>> np.issubdtype(np.float64, np.floating)
|
| 464 |
+
True
|
| 465 |
+
>>> np.issubdtype(np.float32, np.floating)
|
| 466 |
+
True
|
| 467 |
+
|
| 468 |
+
For convenience, dtype-like objects are allowed too:
|
| 469 |
+
|
| 470 |
+
>>> np.issubdtype('S1', np.bytes_)
|
| 471 |
+
True
|
| 472 |
+
>>> np.issubdtype('i4', np.signedinteger)
|
| 473 |
+
True
|
| 474 |
+
|
| 475 |
+
"""
|
| 476 |
+
if not issubclass_(arg1, generic):
|
| 477 |
+
arg1 = dtype(arg1).type
|
| 478 |
+
if not issubclass_(arg2, generic):
|
| 479 |
+
arg2 = dtype(arg2).type
|
| 480 |
+
|
| 481 |
+
return issubclass(arg1, arg2)
|
| 482 |
+
|
| 483 |
+
|
| 484 |
+
@set_module('numpy')
|
| 485 |
+
def sctype2char(sctype):
|
| 486 |
+
"""
|
| 487 |
+
Return the string representation of a scalar dtype.
|
| 488 |
+
|
| 489 |
+
Parameters
|
| 490 |
+
----------
|
| 491 |
+
sctype : scalar dtype or object
|
| 492 |
+
If a scalar dtype, the corresponding string character is
|
| 493 |
+
returned. If an object, `sctype2char` tries to infer its scalar type
|
| 494 |
+
and then return the corresponding string character.
|
| 495 |
+
|
| 496 |
+
Returns
|
| 497 |
+
-------
|
| 498 |
+
typechar : str
|
| 499 |
+
The string character corresponding to the scalar type.
|
| 500 |
+
|
| 501 |
+
Raises
|
| 502 |
+
------
|
| 503 |
+
ValueError
|
| 504 |
+
If `sctype` is an object for which the type can not be inferred.
|
| 505 |
+
|
| 506 |
+
See Also
|
| 507 |
+
--------
|
| 508 |
+
obj2sctype, issctype, issubsctype, mintypecode
|
| 509 |
+
|
| 510 |
+
Examples
|
| 511 |
+
--------
|
| 512 |
+
>>> from numpy._core.numerictypes import sctype2char
|
| 513 |
+
>>> for sctype in [np.int32, np.double, np.cdouble, np.bytes_, np.ndarray]:
|
| 514 |
+
... print(sctype2char(sctype))
|
| 515 |
+
l # may vary
|
| 516 |
+
d
|
| 517 |
+
D
|
| 518 |
+
S
|
| 519 |
+
O
|
| 520 |
+
|
| 521 |
+
>>> x = np.array([1., 2-1.j])
|
| 522 |
+
>>> sctype2char(x)
|
| 523 |
+
'D'
|
| 524 |
+
>>> sctype2char(list)
|
| 525 |
+
'O'
|
| 526 |
+
|
| 527 |
+
"""
|
| 528 |
+
sctype = obj2sctype(sctype)
|
| 529 |
+
if sctype is None:
|
| 530 |
+
raise ValueError("unrecognized type")
|
| 531 |
+
if sctype not in sctypeDict.values():
|
| 532 |
+
# for compatibility
|
| 533 |
+
raise KeyError(sctype)
|
| 534 |
+
return dtype(sctype).char
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
def _scalar_type_key(typ):
|
| 538 |
+
"""A ``key`` function for `sorted`."""
|
| 539 |
+
dt = dtype(typ)
|
| 540 |
+
return (dt.kind.lower(), dt.itemsize)
|
| 541 |
+
|
| 542 |
+
|
| 543 |
+
ScalarType = [int, float, complex, bool, bytes, str, memoryview]
|
| 544 |
+
ScalarType += sorted(dict.fromkeys(sctypeDict.values()), key=_scalar_type_key)
|
| 545 |
+
ScalarType = tuple(ScalarType)
|
| 546 |
+
|
| 547 |
+
|
| 548 |
+
# Now add the types we've determined to this module
|
| 549 |
+
for key in allTypes:
|
| 550 |
+
globals()[key] = allTypes[key]
|
| 551 |
+
__all__.append(key)
|
| 552 |
+
|
| 553 |
+
del key
|
| 554 |
+
|
| 555 |
+
typecodes = {'Character': 'c',
|
| 556 |
+
'Integer': 'bhilqnp',
|
| 557 |
+
'UnsignedInteger': 'BHILQNP',
|
| 558 |
+
'Float': 'efdg',
|
| 559 |
+
'Complex': 'FDG',
|
| 560 |
+
'AllInteger': 'bBhHiIlLqQnNpP',
|
| 561 |
+
'AllFloat': 'efdgFDG',
|
| 562 |
+
'Datetime': 'Mm',
|
| 563 |
+
'All': '?bhilqnpBHILQNPefdgFDGSUVOMm'}
|
| 564 |
+
|
| 565 |
+
# backwards compatibility --- deprecated name
|
| 566 |
+
# Formal deprecation: Numpy 1.20.0, 2020-10-19 (see numpy/__init__.py)
|
| 567 |
+
typeDict = sctypeDict
|
| 568 |
+
|
| 569 |
+
def _register_types():
|
| 570 |
+
numbers.Integral.register(integer)
|
| 571 |
+
numbers.Complex.register(inexact)
|
| 572 |
+
numbers.Real.register(floating)
|
| 573 |
+
numbers.Number.register(number)
|
| 574 |
+
|
| 575 |
+
|
| 576 |
+
_register_types()
|
v12x/pylib/numpy/_core/overrides.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Implementation of __array_function__ overrides from NEP-18."""
|
| 2 |
+
import collections
|
| 3 |
+
import functools
|
| 4 |
+
import inspect
|
| 5 |
+
|
| 6 |
+
from numpy._core._multiarray_umath import (
|
| 7 |
+
_ArrayFunctionDispatcher,
|
| 8 |
+
_get_implementing_args,
|
| 9 |
+
add_docstring,
|
| 10 |
+
)
|
| 11 |
+
from numpy._utils import set_module # noqa: F401
|
| 12 |
+
from numpy._utils._inspect import getargspec
|
| 13 |
+
|
| 14 |
+
ARRAY_FUNCTIONS = set()
|
| 15 |
+
|
| 16 |
+
array_function_like_doc = (
|
| 17 |
+
"""like : array_like, optional
|
| 18 |
+
Reference object to allow the creation of arrays which are not
|
| 19 |
+
NumPy arrays. If an array-like passed in as ``like`` supports
|
| 20 |
+
the ``__array_function__`` protocol, the result will be defined
|
| 21 |
+
by it. In this case, it ensures the creation of an array object
|
| 22 |
+
compatible with that passed in via this argument."""
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
def get_array_function_like_doc(public_api, docstring_template=""):
|
| 26 |
+
ARRAY_FUNCTIONS.add(public_api)
|
| 27 |
+
docstring = public_api.__doc__ or docstring_template
|
| 28 |
+
return docstring.replace("${ARRAY_FUNCTION_LIKE}", array_function_like_doc)
|
| 29 |
+
|
| 30 |
+
def finalize_array_function_like(public_api):
|
| 31 |
+
public_api.__doc__ = get_array_function_like_doc(public_api)
|
| 32 |
+
return public_api
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
add_docstring(
|
| 36 |
+
_ArrayFunctionDispatcher,
|
| 37 |
+
"""
|
| 38 |
+
Class to wrap functions with checks for __array_function__ overrides.
|
| 39 |
+
|
| 40 |
+
All arguments are required, and can only be passed by position.
|
| 41 |
+
|
| 42 |
+
Parameters
|
| 43 |
+
----------
|
| 44 |
+
dispatcher : function or None
|
| 45 |
+
The dispatcher function that returns a single sequence-like object
|
| 46 |
+
of all arguments relevant. It must have the same signature (except
|
| 47 |
+
the default values) as the actual implementation.
|
| 48 |
+
If ``None``, this is a ``like=`` dispatcher and the
|
| 49 |
+
``_ArrayFunctionDispatcher`` must be called with ``like`` as the
|
| 50 |
+
first (additional and positional) argument.
|
| 51 |
+
implementation : function
|
| 52 |
+
Function that implements the operation on NumPy arrays without
|
| 53 |
+
overrides. Arguments passed calling the ``_ArrayFunctionDispatcher``
|
| 54 |
+
will be forwarded to this (and the ``dispatcher``) as if using
|
| 55 |
+
``*args, **kwargs``.
|
| 56 |
+
|
| 57 |
+
Attributes
|
| 58 |
+
----------
|
| 59 |
+
_implementation : function
|
| 60 |
+
The original implementation passed in.
|
| 61 |
+
""")
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
# exposed for testing purposes; used internally by _ArrayFunctionDispatcher
|
| 65 |
+
add_docstring(
|
| 66 |
+
_get_implementing_args,
|
| 67 |
+
"""
|
| 68 |
+
Collect arguments on which to call __array_function__.
|
| 69 |
+
|
| 70 |
+
Parameters
|
| 71 |
+
----------
|
| 72 |
+
relevant_args : iterable of array-like
|
| 73 |
+
Iterable of possibly array-like arguments to check for
|
| 74 |
+
__array_function__ methods.
|
| 75 |
+
|
| 76 |
+
Returns
|
| 77 |
+
-------
|
| 78 |
+
Sequence of arguments with __array_function__ methods, in the order in
|
| 79 |
+
which they should be called.
|
| 80 |
+
""")
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
ArgSpec = collections.namedtuple('ArgSpec', 'args varargs keywords defaults')
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def verify_matching_signatures(implementation, dispatcher):
|
| 87 |
+
"""Verify that a dispatcher function has the right signature."""
|
| 88 |
+
implementation_spec = ArgSpec(*getargspec(implementation))
|
| 89 |
+
dispatcher_spec = ArgSpec(*getargspec(dispatcher))
|
| 90 |
+
|
| 91 |
+
if (implementation_spec.args != dispatcher_spec.args or
|
| 92 |
+
implementation_spec.varargs != dispatcher_spec.varargs or
|
| 93 |
+
implementation_spec.keywords != dispatcher_spec.keywords or
|
| 94 |
+
(bool(implementation_spec.defaults) !=
|
| 95 |
+
bool(dispatcher_spec.defaults)) or
|
| 96 |
+
(implementation_spec.defaults is not None and
|
| 97 |
+
len(implementation_spec.defaults) !=
|
| 98 |
+
len(dispatcher_spec.defaults))):
|
| 99 |
+
raise RuntimeError(f'implementation and dispatcher for {implementation} have '
|
| 100 |
+
'different function signatures')
|
| 101 |
+
|
| 102 |
+
if implementation_spec.defaults is not None:
|
| 103 |
+
if dispatcher_spec.defaults != (None,) * len(dispatcher_spec.defaults):
|
| 104 |
+
raise RuntimeError('dispatcher functions can only use None for '
|
| 105 |
+
'default argument values')
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def array_function_dispatch(dispatcher=None, module=None, verify=True,
|
| 109 |
+
docs_from_dispatcher=False):
|
| 110 |
+
"""Decorator for adding dispatch with the __array_function__ protocol.
|
| 111 |
+
|
| 112 |
+
See NEP-18 for example usage.
|
| 113 |
+
|
| 114 |
+
Parameters
|
| 115 |
+
----------
|
| 116 |
+
dispatcher : callable or None
|
| 117 |
+
Function that when called like ``dispatcher(*args, **kwargs)`` with
|
| 118 |
+
arguments from the NumPy function call returns an iterable of
|
| 119 |
+
array-like arguments to check for ``__array_function__``.
|
| 120 |
+
|
| 121 |
+
If `None`, the first argument is used as the single `like=` argument
|
| 122 |
+
and not passed on. A function implementing `like=` must call its
|
| 123 |
+
dispatcher with `like` as the first non-keyword argument.
|
| 124 |
+
module : str, optional
|
| 125 |
+
__module__ attribute to set on new function, e.g., ``module='numpy'``.
|
| 126 |
+
By default, module is copied from the decorated function.
|
| 127 |
+
verify : bool, optional
|
| 128 |
+
If True, verify the that the signature of the dispatcher and decorated
|
| 129 |
+
function signatures match exactly: all required and optional arguments
|
| 130 |
+
should appear in order with the same names, but the default values for
|
| 131 |
+
all optional arguments should be ``None``. Only disable verification
|
| 132 |
+
if the dispatcher's signature needs to deviate for some particular
|
| 133 |
+
reason, e.g., because the function has a signature like
|
| 134 |
+
``func(*args, **kwargs)``.
|
| 135 |
+
docs_from_dispatcher : bool, optional
|
| 136 |
+
If True, copy docs from the dispatcher function onto the dispatched
|
| 137 |
+
function, rather than from the implementation. This is useful for
|
| 138 |
+
functions defined in C, which otherwise don't have docstrings.
|
| 139 |
+
|
| 140 |
+
Returns
|
| 141 |
+
-------
|
| 142 |
+
Function suitable for decorating the implementation of a NumPy function.
|
| 143 |
+
|
| 144 |
+
"""
|
| 145 |
+
def decorator(implementation):
|
| 146 |
+
if verify:
|
| 147 |
+
if dispatcher is not None:
|
| 148 |
+
verify_matching_signatures(implementation, dispatcher)
|
| 149 |
+
else:
|
| 150 |
+
# Using __code__ directly similar to verify_matching_signature
|
| 151 |
+
co = implementation.__code__
|
| 152 |
+
last_arg = co.co_argcount + co.co_kwonlyargcount - 1
|
| 153 |
+
last_arg = co.co_varnames[last_arg]
|
| 154 |
+
if last_arg != "like" or co.co_kwonlyargcount == 0:
|
| 155 |
+
raise RuntimeError(
|
| 156 |
+
"__array_function__ expects `like=` to be the last "
|
| 157 |
+
"argument and a keyword-only argument. "
|
| 158 |
+
f"{implementation} does not seem to comply.")
|
| 159 |
+
|
| 160 |
+
if docs_from_dispatcher and dispatcher.__doc__ is not None:
|
| 161 |
+
doc = inspect.cleandoc(dispatcher.__doc__)
|
| 162 |
+
add_docstring(implementation, doc)
|
| 163 |
+
|
| 164 |
+
public_api = _ArrayFunctionDispatcher(dispatcher, implementation)
|
| 165 |
+
functools.update_wrapper(public_api, implementation)
|
| 166 |
+
|
| 167 |
+
if not verify and not getattr(implementation, "__text_signature__", None):
|
| 168 |
+
public_api.__signature__ = inspect.signature(dispatcher)
|
| 169 |
+
|
| 170 |
+
if module is not None:
|
| 171 |
+
public_api.__module__ = module
|
| 172 |
+
|
| 173 |
+
ARRAY_FUNCTIONS.add(public_api)
|
| 174 |
+
|
| 175 |
+
return public_api
|
| 176 |
+
|
| 177 |
+
return decorator
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def array_function_from_dispatcher(
|
| 181 |
+
implementation, module=None, verify=True, docs_from_dispatcher=True):
|
| 182 |
+
"""Like array_function_dispatcher, but with function arguments flipped."""
|
| 183 |
+
|
| 184 |
+
def decorator(dispatcher):
|
| 185 |
+
return array_function_dispatch(
|
| 186 |
+
dispatcher, module, verify=verify,
|
| 187 |
+
docs_from_dispatcher=docs_from_dispatcher)(implementation)
|
| 188 |
+
return decorator
|
v12x/pylib/numpy/_core/printoptions.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Stores and defines the low-level format_options context variable.
|
| 3 |
+
|
| 4 |
+
This is defined in its own file outside of the arrayprint module
|
| 5 |
+
so we can import it from C while initializing the multiarray
|
| 6 |
+
C module during import without introducing circular dependencies.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import sys
|
| 10 |
+
from contextvars import ContextVar
|
| 11 |
+
|
| 12 |
+
__all__ = ["format_options"]
|
| 13 |
+
|
| 14 |
+
default_format_options_dict = {
|
| 15 |
+
"edgeitems": 3, # repr N leading and trailing items of each dimension
|
| 16 |
+
"threshold": 1000, # total items > triggers array summarization
|
| 17 |
+
"floatmode": "maxprec",
|
| 18 |
+
"precision": 8, # precision of floating point representations
|
| 19 |
+
"suppress": False, # suppress printing small floating values in exp format
|
| 20 |
+
"linewidth": 75,
|
| 21 |
+
"nanstr": "nan",
|
| 22 |
+
"infstr": "inf",
|
| 23 |
+
"sign": "-",
|
| 24 |
+
"formatter": None,
|
| 25 |
+
# Internally stored as an int to simplify comparisons; converted from/to
|
| 26 |
+
# str/False on the way in/out.
|
| 27 |
+
'legacy': sys.maxsize,
|
| 28 |
+
'override_repr': None,
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
format_options = ContextVar(
|
| 32 |
+
"format_options", default=default_format_options_dict)
|
v12x/pylib/numpy/_core/records.py
ADDED
|
@@ -0,0 +1,1101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module contains a set of functions for record arrays.
|
| 3 |
+
"""
|
| 4 |
+
import os
|
| 5 |
+
import warnings
|
| 6 |
+
from collections import Counter
|
| 7 |
+
from contextlib import nullcontext
|
| 8 |
+
|
| 9 |
+
from numpy._utils import set_module
|
| 10 |
+
|
| 11 |
+
from . import numeric as sb, numerictypes as nt
|
| 12 |
+
from .arrayprint import _get_legacy_print_mode
|
| 13 |
+
|
| 14 |
+
# All of the functions allow formats to be a dtype
|
| 15 |
+
__all__ = [
|
| 16 |
+
'record', 'recarray', 'format_parser', 'fromarrays', 'fromrecords',
|
| 17 |
+
'fromstring', 'fromfile', 'array', 'find_duplicate',
|
| 18 |
+
]
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
ndarray = sb.ndarray
|
| 22 |
+
|
| 23 |
+
_byteorderconv = {'b': '>',
|
| 24 |
+
'l': '<',
|
| 25 |
+
'n': '=',
|
| 26 |
+
'B': '>',
|
| 27 |
+
'L': '<',
|
| 28 |
+
'N': '=',
|
| 29 |
+
'S': 's',
|
| 30 |
+
's': 's',
|
| 31 |
+
'>': '>',
|
| 32 |
+
'<': '<',
|
| 33 |
+
'=': '=',
|
| 34 |
+
'|': '|',
|
| 35 |
+
'I': '|',
|
| 36 |
+
'i': '|'}
|
| 37 |
+
|
| 38 |
+
# formats regular expression
|
| 39 |
+
# allows multidimensional spec with a tuple syntax in front
|
| 40 |
+
# of the letter code '(2,3)f4' and ' ( 2 , 3 ) f4 '
|
| 41 |
+
# are equally allowed
|
| 42 |
+
|
| 43 |
+
numfmt = nt.sctypeDict
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
@set_module('numpy.rec')
|
| 47 |
+
def find_duplicate(list):
|
| 48 |
+
"""Find duplication in a list, return a list of duplicated elements"""
|
| 49 |
+
return [
|
| 50 |
+
item
|
| 51 |
+
for item, counts in Counter(list).items()
|
| 52 |
+
if counts > 1
|
| 53 |
+
]
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
@set_module('numpy.rec')
|
| 57 |
+
class format_parser:
|
| 58 |
+
"""
|
| 59 |
+
Class to convert formats, names, titles description to a dtype.
|
| 60 |
+
|
| 61 |
+
After constructing the format_parser object, the dtype attribute is
|
| 62 |
+
the converted data-type:
|
| 63 |
+
``dtype = format_parser(formats, names, titles).dtype``
|
| 64 |
+
|
| 65 |
+
Attributes
|
| 66 |
+
----------
|
| 67 |
+
dtype : dtype
|
| 68 |
+
The converted data-type.
|
| 69 |
+
|
| 70 |
+
Parameters
|
| 71 |
+
----------
|
| 72 |
+
formats : str or list of str
|
| 73 |
+
The format description, either specified as a string with
|
| 74 |
+
comma-separated format descriptions in the form ``'f8, i4, S5'``, or
|
| 75 |
+
a list of format description strings in the form
|
| 76 |
+
``['f8', 'i4', 'S5']``.
|
| 77 |
+
names : str or list/tuple of str
|
| 78 |
+
The field names, either specified as a comma-separated string in the
|
| 79 |
+
form ``'col1, col2, col3'``, or as a list or tuple of strings in the
|
| 80 |
+
form ``['col1', 'col2', 'col3']``.
|
| 81 |
+
An empty list can be used, in that case default field names
|
| 82 |
+
('f0', 'f1', ...) are used.
|
| 83 |
+
titles : sequence
|
| 84 |
+
Sequence of title strings. An empty list can be used to leave titles
|
| 85 |
+
out.
|
| 86 |
+
aligned : bool, optional
|
| 87 |
+
If True, align the fields by padding as the C-compiler would.
|
| 88 |
+
Default is False.
|
| 89 |
+
byteorder : str, optional
|
| 90 |
+
If specified, all the fields will be changed to the
|
| 91 |
+
provided byte-order. Otherwise, the default byte-order is
|
| 92 |
+
used. For all available string specifiers, see `dtype.newbyteorder`.
|
| 93 |
+
|
| 94 |
+
See Also
|
| 95 |
+
--------
|
| 96 |
+
numpy.dtype, numpy.typename
|
| 97 |
+
|
| 98 |
+
Examples
|
| 99 |
+
--------
|
| 100 |
+
>>> import numpy as np
|
| 101 |
+
>>> np.rec.format_parser(['<f8', '<i4'], ['col1', 'col2'],
|
| 102 |
+
... ['T1', 'T2']).dtype
|
| 103 |
+
dtype([(('T1', 'col1'), '<f8'), (('T2', 'col2'), '<i4')])
|
| 104 |
+
|
| 105 |
+
`names` and/or `titles` can be empty lists. If `titles` is an empty list,
|
| 106 |
+
titles will simply not appear. If `names` is empty, default field names
|
| 107 |
+
will be used.
|
| 108 |
+
|
| 109 |
+
>>> np.rec.format_parser(['f8', 'i4', 'S5'], ['col1', 'col2', 'col3'],
|
| 110 |
+
... []).dtype
|
| 111 |
+
dtype([('col1', '<f8'), ('col2', '<i4'), ('col3', '<S5')])
|
| 112 |
+
>>> np.rec.format_parser(['<f8', '<i4', '<S5'], [], []).dtype
|
| 113 |
+
dtype([('f0', '<f8'), ('f1', '<i4'), ('f2', 'S5')])
|
| 114 |
+
|
| 115 |
+
"""
|
| 116 |
+
|
| 117 |
+
def __init__(self, formats, names, titles, aligned=False, byteorder=None):
|
| 118 |
+
self._parseFormats(formats, aligned)
|
| 119 |
+
self._setfieldnames(names, titles)
|
| 120 |
+
self._createdtype(byteorder)
|
| 121 |
+
|
| 122 |
+
def _parseFormats(self, formats, aligned=False):
|
| 123 |
+
""" Parse the field formats """
|
| 124 |
+
|
| 125 |
+
if formats is None:
|
| 126 |
+
raise ValueError("Need formats argument")
|
| 127 |
+
if isinstance(formats, list):
|
| 128 |
+
dtype = sb.dtype(
|
| 129 |
+
[
|
| 130 |
+
(f'f{i}', format_)
|
| 131 |
+
for i, format_ in enumerate(formats)
|
| 132 |
+
],
|
| 133 |
+
aligned,
|
| 134 |
+
)
|
| 135 |
+
else:
|
| 136 |
+
dtype = sb.dtype(formats, aligned)
|
| 137 |
+
fields = dtype.fields
|
| 138 |
+
if fields is None:
|
| 139 |
+
dtype = sb.dtype([('f1', dtype)], aligned)
|
| 140 |
+
fields = dtype.fields
|
| 141 |
+
keys = dtype.names
|
| 142 |
+
self._f_formats = [fields[key][0] for key in keys]
|
| 143 |
+
self._offsets = [fields[key][1] for key in keys]
|
| 144 |
+
self._nfields = len(keys)
|
| 145 |
+
|
| 146 |
+
def _setfieldnames(self, names, titles):
|
| 147 |
+
"""convert input field names into a list and assign to the _names
|
| 148 |
+
attribute """
|
| 149 |
+
|
| 150 |
+
if names:
|
| 151 |
+
if type(names) in [list, tuple]:
|
| 152 |
+
pass
|
| 153 |
+
elif isinstance(names, str):
|
| 154 |
+
names = names.split(',')
|
| 155 |
+
else:
|
| 156 |
+
raise NameError(f"illegal input names {repr(names)}")
|
| 157 |
+
|
| 158 |
+
self._names = [n.strip() for n in names[:self._nfields]]
|
| 159 |
+
else:
|
| 160 |
+
self._names = []
|
| 161 |
+
|
| 162 |
+
# if the names are not specified, they will be assigned as
|
| 163 |
+
# "f0, f1, f2,..."
|
| 164 |
+
# if not enough names are specified, they will be assigned as "f[n],
|
| 165 |
+
# f[n+1],..." etc. where n is the number of specified names..."
|
| 166 |
+
self._names += [f'f{i}' for i in range(len(self._names),
|
| 167 |
+
self._nfields)]
|
| 168 |
+
# check for redundant names
|
| 169 |
+
_dup = find_duplicate(self._names)
|
| 170 |
+
if _dup:
|
| 171 |
+
raise ValueError(f"Duplicate field names: {_dup}")
|
| 172 |
+
|
| 173 |
+
if titles:
|
| 174 |
+
self._titles = [n.strip() for n in titles[:self._nfields]]
|
| 175 |
+
else:
|
| 176 |
+
self._titles = []
|
| 177 |
+
titles = []
|
| 178 |
+
|
| 179 |
+
if self._nfields > len(titles):
|
| 180 |
+
self._titles += [None] * (self._nfields - len(titles))
|
| 181 |
+
|
| 182 |
+
def _createdtype(self, byteorder):
|
| 183 |
+
dtype = sb.dtype({
|
| 184 |
+
'names': self._names,
|
| 185 |
+
'formats': self._f_formats,
|
| 186 |
+
'offsets': self._offsets,
|
| 187 |
+
'titles': self._titles,
|
| 188 |
+
})
|
| 189 |
+
if byteorder is not None:
|
| 190 |
+
byteorder = _byteorderconv[byteorder[0]]
|
| 191 |
+
dtype = dtype.newbyteorder(byteorder)
|
| 192 |
+
|
| 193 |
+
self.dtype = dtype
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
class record(nt.void):
|
| 197 |
+
"""A data-type scalar that allows field access as attribute lookup.
|
| 198 |
+
"""
|
| 199 |
+
|
| 200 |
+
# manually set name and module so that this class's type shows up
|
| 201 |
+
# as numpy.record when printed
|
| 202 |
+
__name__ = 'record'
|
| 203 |
+
__module__ = 'numpy'
|
| 204 |
+
|
| 205 |
+
def __repr__(self):
|
| 206 |
+
if _get_legacy_print_mode() <= 113:
|
| 207 |
+
return self.__str__()
|
| 208 |
+
return super().__repr__()
|
| 209 |
+
|
| 210 |
+
def __str__(self):
|
| 211 |
+
if _get_legacy_print_mode() <= 113:
|
| 212 |
+
return str(self.item())
|
| 213 |
+
return super().__str__()
|
| 214 |
+
|
| 215 |
+
def __getattribute__(self, attr):
|
| 216 |
+
if attr in ('setfield', 'getfield', 'dtype'):
|
| 217 |
+
return nt.void.__getattribute__(self, attr)
|
| 218 |
+
try:
|
| 219 |
+
return nt.void.__getattribute__(self, attr)
|
| 220 |
+
except AttributeError:
|
| 221 |
+
pass
|
| 222 |
+
fielddict = nt.void.__getattribute__(self, 'dtype').fields
|
| 223 |
+
res = fielddict.get(attr, None)
|
| 224 |
+
if res:
|
| 225 |
+
obj = self.getfield(*res[:2])
|
| 226 |
+
# if it has fields return a record,
|
| 227 |
+
# otherwise return the object
|
| 228 |
+
try:
|
| 229 |
+
dt = obj.dtype
|
| 230 |
+
except AttributeError:
|
| 231 |
+
# happens if field is Object type
|
| 232 |
+
return obj
|
| 233 |
+
if dt.names is not None:
|
| 234 |
+
return obj.view((self.__class__, obj.dtype))
|
| 235 |
+
return obj
|
| 236 |
+
else:
|
| 237 |
+
raise AttributeError(f"'record' object has no attribute '{attr}'")
|
| 238 |
+
|
| 239 |
+
def __setattr__(self, attr, val):
|
| 240 |
+
if attr in ('setfield', 'getfield', 'dtype'):
|
| 241 |
+
raise AttributeError(f"Cannot set '{attr}' attribute")
|
| 242 |
+
fielddict = nt.void.__getattribute__(self, 'dtype').fields
|
| 243 |
+
res = fielddict.get(attr, None)
|
| 244 |
+
if res:
|
| 245 |
+
return self.setfield(val, *res[:2])
|
| 246 |
+
elif getattr(self, attr, None):
|
| 247 |
+
return nt.void.__setattr__(self, attr, val)
|
| 248 |
+
else:
|
| 249 |
+
raise AttributeError(f"'record' object has no attribute '{attr}'")
|
| 250 |
+
|
| 251 |
+
def __getitem__(self, indx):
|
| 252 |
+
obj = nt.void.__getitem__(self, indx)
|
| 253 |
+
|
| 254 |
+
# copy behavior of record.__getattribute__,
|
| 255 |
+
if isinstance(obj, nt.void) and obj.dtype.names is not None:
|
| 256 |
+
return obj.view((self.__class__, obj.dtype))
|
| 257 |
+
else:
|
| 258 |
+
# return a single element
|
| 259 |
+
return obj
|
| 260 |
+
|
| 261 |
+
def pprint(self):
|
| 262 |
+
"""Pretty-print all fields."""
|
| 263 |
+
# pretty-print all fields
|
| 264 |
+
names = self.dtype.names
|
| 265 |
+
maxlen = max(len(name) for name in names)
|
| 266 |
+
rows = [f"{name:>{maxlen}}: {getattr(self, name)}" for name in names]
|
| 267 |
+
return "\n".join(rows)
|
| 268 |
+
|
| 269 |
+
# The recarray is almost identical to a standard array (which supports
|
| 270 |
+
# named fields already) The biggest difference is that it can use
|
| 271 |
+
# attribute-lookup to find the fields and it is constructed using
|
| 272 |
+
# a record.
|
| 273 |
+
|
| 274 |
+
# If byteorder is given it forces a particular byteorder on all
|
| 275 |
+
# the fields (and any subfields)
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
@set_module("numpy.rec")
|
| 279 |
+
class recarray(ndarray):
|
| 280 |
+
"""Construct an ndarray that allows field access using attributes.
|
| 281 |
+
|
| 282 |
+
Arrays may have a data-types containing fields, analogous
|
| 283 |
+
to columns in a spread sheet. An example is ``[(x, int), (y, float)]``,
|
| 284 |
+
where each entry in the array is a pair of ``(int, float)``. Normally,
|
| 285 |
+
these attributes are accessed using dictionary lookups such as ``arr['x']``
|
| 286 |
+
and ``arr['y']``. Record arrays allow the fields to be accessed as members
|
| 287 |
+
of the array, using ``arr.x`` and ``arr.y``.
|
| 288 |
+
|
| 289 |
+
Parameters
|
| 290 |
+
----------
|
| 291 |
+
shape : tuple
|
| 292 |
+
Shape of output array.
|
| 293 |
+
dtype : data-type, optional
|
| 294 |
+
The desired data-type. By default, the data-type is determined
|
| 295 |
+
from `formats`, `names`, `titles`, `aligned` and `byteorder`.
|
| 296 |
+
formats : list of data-types, optional
|
| 297 |
+
A list containing the data-types for the different columns, e.g.
|
| 298 |
+
``['i4', 'f8', 'i4']``. `formats` does *not* support the new
|
| 299 |
+
convention of using types directly, i.e. ``(int, float, int)``.
|
| 300 |
+
Note that `formats` must be a list, not a tuple.
|
| 301 |
+
Given that `formats` is somewhat limited, we recommend specifying
|
| 302 |
+
`dtype` instead.
|
| 303 |
+
names : tuple of str, optional
|
| 304 |
+
The name of each column, e.g. ``('x', 'y', 'z')``.
|
| 305 |
+
buf : buffer, optional
|
| 306 |
+
By default, a new array is created of the given shape and data-type.
|
| 307 |
+
If `buf` is specified and is an object exposing the buffer interface,
|
| 308 |
+
the array will use the memory from the existing buffer. In this case,
|
| 309 |
+
the `offset` and `strides` keywords are available.
|
| 310 |
+
|
| 311 |
+
Other Parameters
|
| 312 |
+
----------------
|
| 313 |
+
titles : tuple of str, optional
|
| 314 |
+
Aliases for column names. For example, if `names` were
|
| 315 |
+
``('x', 'y', 'z')`` and `titles` is
|
| 316 |
+
``('x_coordinate', 'y_coordinate', 'z_coordinate')``, then
|
| 317 |
+
``arr['x']`` is equivalent to both ``arr.x`` and ``arr.x_coordinate``.
|
| 318 |
+
byteorder : {'<', '>', '='}, optional
|
| 319 |
+
Byte-order for all fields.
|
| 320 |
+
aligned : bool, optional
|
| 321 |
+
Align the fields in memory as the C-compiler would.
|
| 322 |
+
strides : tuple of ints, optional
|
| 323 |
+
Buffer (`buf`) is interpreted according to these strides (strides
|
| 324 |
+
define how many bytes each array element, row, column, etc.
|
| 325 |
+
occupy in memory).
|
| 326 |
+
offset : int, optional
|
| 327 |
+
Start reading buffer (`buf`) from this offset onwards.
|
| 328 |
+
order : {'C', 'F'}, optional
|
| 329 |
+
Row-major (C-style) or column-major (Fortran-style) order.
|
| 330 |
+
|
| 331 |
+
Returns
|
| 332 |
+
-------
|
| 333 |
+
rec : recarray
|
| 334 |
+
Empty array of the given shape and type.
|
| 335 |
+
|
| 336 |
+
See Also
|
| 337 |
+
--------
|
| 338 |
+
numpy.rec.fromrecords : Construct a record array from data.
|
| 339 |
+
numpy.record : fundamental data-type for `recarray`.
|
| 340 |
+
numpy.rec.format_parser : determine data-type from formats, names, titles.
|
| 341 |
+
|
| 342 |
+
Notes
|
| 343 |
+
-----
|
| 344 |
+
This constructor can be compared to ``empty``: it creates a new record
|
| 345 |
+
array but does not fill it with data. To create a record array from data,
|
| 346 |
+
use one of the following methods:
|
| 347 |
+
|
| 348 |
+
1. Create a standard ndarray and convert it to a record array,
|
| 349 |
+
using ``arr.view(np.recarray)``
|
| 350 |
+
2. Use the `buf` keyword.
|
| 351 |
+
3. Use `np.rec.fromrecords`.
|
| 352 |
+
|
| 353 |
+
Examples
|
| 354 |
+
--------
|
| 355 |
+
Create an array with two fields, ``x`` and ``y``:
|
| 356 |
+
|
| 357 |
+
>>> import numpy as np
|
| 358 |
+
>>> x = np.array([(1.0, 2), (3.0, 4)], dtype=[('x', '<f8'), ('y', '<i8')])
|
| 359 |
+
>>> x
|
| 360 |
+
array([(1., 2), (3., 4)], dtype=[('x', '<f8'), ('y', '<i8')])
|
| 361 |
+
|
| 362 |
+
>>> x['x']
|
| 363 |
+
array([1., 3.])
|
| 364 |
+
|
| 365 |
+
View the array as a record array:
|
| 366 |
+
|
| 367 |
+
>>> x = x.view(np.recarray)
|
| 368 |
+
|
| 369 |
+
>>> x.x
|
| 370 |
+
array([1., 3.])
|
| 371 |
+
|
| 372 |
+
>>> x.y
|
| 373 |
+
array([2, 4])
|
| 374 |
+
|
| 375 |
+
Create a new, empty record array:
|
| 376 |
+
|
| 377 |
+
>>> np.recarray((2,),
|
| 378 |
+
... dtype=[('x', int), ('y', float), ('z', int)]) #doctest: +SKIP
|
| 379 |
+
rec.array([(-1073741821, 1.2249118382103472e-301, 24547520),
|
| 380 |
+
(3471280, 1.2134086255804012e-316, 0)],
|
| 381 |
+
dtype=[('x', '<i4'), ('y', '<f8'), ('z', '<i4')])
|
| 382 |
+
|
| 383 |
+
"""
|
| 384 |
+
|
| 385 |
+
def __new__(cls, shape, dtype=None, buf=None, offset=0, strides=None,
|
| 386 |
+
formats=None, names=None, titles=None,
|
| 387 |
+
byteorder=None, aligned=False, order='C'):
|
| 388 |
+
|
| 389 |
+
if dtype is not None:
|
| 390 |
+
descr = sb.dtype(dtype)
|
| 391 |
+
else:
|
| 392 |
+
descr = format_parser(
|
| 393 |
+
formats, names, titles, aligned, byteorder
|
| 394 |
+
).dtype
|
| 395 |
+
|
| 396 |
+
if buf is None:
|
| 397 |
+
self = ndarray.__new__(cls, shape, (record, descr), order=order)
|
| 398 |
+
else:
|
| 399 |
+
self = ndarray.__new__(
|
| 400 |
+
cls, shape, (record, descr), buffer=buf,
|
| 401 |
+
offset=offset, strides=strides, order=order
|
| 402 |
+
)
|
| 403 |
+
return self
|
| 404 |
+
|
| 405 |
+
_set_dtype = None # __array_finalize__ can deal with dtype changes
|
| 406 |
+
|
| 407 |
+
def __array_finalize__(self, obj):
|
| 408 |
+
if (self.dtype.type is not record and
|
| 409 |
+
issubclass(self.dtype.type, nt.void) and
|
| 410 |
+
self.dtype.names is not None):
|
| 411 |
+
# if self.dtype is not np.record, invoke __setattr__ which will
|
| 412 |
+
# convert it to a record if it is a void dtype.
|
| 413 |
+
ndarray._set_dtype(self, sb.dtype((record, self.dtype)))
|
| 414 |
+
|
| 415 |
+
def __getattribute__(self, attr):
|
| 416 |
+
# See if ndarray has this attr, and return it if so. (note that this
|
| 417 |
+
# means a field with the same name as an ndarray attr cannot be
|
| 418 |
+
# accessed by attribute).
|
| 419 |
+
try:
|
| 420 |
+
return object.__getattribute__(self, attr)
|
| 421 |
+
except AttributeError: # attr must be a fieldname
|
| 422 |
+
pass
|
| 423 |
+
|
| 424 |
+
# look for a field with this name
|
| 425 |
+
fielddict = ndarray.__getattribute__(self, 'dtype').fields
|
| 426 |
+
try:
|
| 427 |
+
res = fielddict[attr][:2]
|
| 428 |
+
except (TypeError, KeyError) as e:
|
| 429 |
+
raise AttributeError(f"recarray has no attribute {attr}") from e
|
| 430 |
+
obj = self.getfield(*res)
|
| 431 |
+
|
| 432 |
+
# At this point obj will always be a recarray, since (see
|
| 433 |
+
# PyArray_GetField) the type of obj is inherited. Next, if obj.dtype is
|
| 434 |
+
# non-structured, convert it to an ndarray. Then if obj is structured
|
| 435 |
+
# with void type convert it to the same dtype.type (eg to preserve
|
| 436 |
+
# numpy.record type if present), since nested structured fields do not
|
| 437 |
+
# inherit type. Don't do this for non-void structures though.
|
| 438 |
+
if obj.dtype.names is not None:
|
| 439 |
+
if issubclass(obj.dtype.type, nt.void):
|
| 440 |
+
return obj.view(dtype=(self.dtype.type, obj.dtype))
|
| 441 |
+
return obj
|
| 442 |
+
else:
|
| 443 |
+
return obj.view(ndarray)
|
| 444 |
+
|
| 445 |
+
# Save the dictionary.
|
| 446 |
+
# If the attr is a field name and not in the saved dictionary
|
| 447 |
+
# Undo any "setting" of the attribute and do a setfield
|
| 448 |
+
# Thus, you can't create attributes on-the-fly that are field names.
|
| 449 |
+
def __setattr__(self, attr, val):
|
| 450 |
+
|
| 451 |
+
# Automatically convert (void) structured types to records
|
| 452 |
+
# (but not non-void structures, subarrays, or non-structured voids)
|
| 453 |
+
if (
|
| 454 |
+
attr == 'dtype' and
|
| 455 |
+
issubclass(val.type, nt.void) and
|
| 456 |
+
val.names is not None
|
| 457 |
+
):
|
| 458 |
+
val = sb.dtype((record, val))
|
| 459 |
+
|
| 460 |
+
newattr = attr not in self.__dict__
|
| 461 |
+
try:
|
| 462 |
+
ret = object.__setattr__(self, attr, val)
|
| 463 |
+
except Exception:
|
| 464 |
+
fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
|
| 465 |
+
if attr not in fielddict:
|
| 466 |
+
raise
|
| 467 |
+
else:
|
| 468 |
+
fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
|
| 469 |
+
if attr not in fielddict:
|
| 470 |
+
return ret
|
| 471 |
+
if newattr:
|
| 472 |
+
# We just added this one or this setattr worked on an
|
| 473 |
+
# internal attribute.
|
| 474 |
+
try:
|
| 475 |
+
object.__delattr__(self, attr)
|
| 476 |
+
except Exception:
|
| 477 |
+
return ret
|
| 478 |
+
try:
|
| 479 |
+
res = fielddict[attr][:2]
|
| 480 |
+
except (TypeError, KeyError) as e:
|
| 481 |
+
raise AttributeError(
|
| 482 |
+
f"record array has no attribute {attr}"
|
| 483 |
+
) from e
|
| 484 |
+
return self.setfield(val, *res)
|
| 485 |
+
|
| 486 |
+
def __getitem__(self, indx):
|
| 487 |
+
obj = super().__getitem__(indx)
|
| 488 |
+
|
| 489 |
+
# copy behavior of getattr, except that here
|
| 490 |
+
# we might also be returning a single element
|
| 491 |
+
if isinstance(obj, ndarray):
|
| 492 |
+
if obj.dtype.names is not None:
|
| 493 |
+
obj = obj.view(type(self))
|
| 494 |
+
if issubclass(obj.dtype.type, nt.void):
|
| 495 |
+
return obj.view(dtype=(self.dtype.type, obj.dtype))
|
| 496 |
+
return obj
|
| 497 |
+
else:
|
| 498 |
+
return obj.view(type=ndarray)
|
| 499 |
+
else:
|
| 500 |
+
# return a single element
|
| 501 |
+
return obj
|
| 502 |
+
|
| 503 |
+
def __repr__(self):
|
| 504 |
+
|
| 505 |
+
repr_dtype = self.dtype
|
| 506 |
+
if (
|
| 507 |
+
self.dtype.type is record or
|
| 508 |
+
not issubclass(self.dtype.type, nt.void)
|
| 509 |
+
):
|
| 510 |
+
# If this is a full record array (has numpy.record dtype),
|
| 511 |
+
# or if it has a scalar (non-void) dtype with no records,
|
| 512 |
+
# represent it using the rec.array function. Since rec.array
|
| 513 |
+
# converts dtype to a numpy.record for us, convert back
|
| 514 |
+
# to non-record before printing
|
| 515 |
+
if repr_dtype.type is record:
|
| 516 |
+
repr_dtype = sb.dtype((nt.void, repr_dtype))
|
| 517 |
+
prefix = "rec.array("
|
| 518 |
+
fmt = 'rec.array(%s,%sdtype=%s)'
|
| 519 |
+
else:
|
| 520 |
+
# otherwise represent it using np.array plus a view
|
| 521 |
+
# This should only happen if the user is playing
|
| 522 |
+
# strange games with dtypes.
|
| 523 |
+
prefix = "array("
|
| 524 |
+
fmt = 'array(%s,%sdtype=%s).view(numpy.recarray)'
|
| 525 |
+
|
| 526 |
+
# get data/shape string. logic taken from numeric.array_repr
|
| 527 |
+
if self.size > 0 or self.shape == (0,):
|
| 528 |
+
lst = sb.array2string(
|
| 529 |
+
self, separator=', ', prefix=prefix, suffix=',')
|
| 530 |
+
else:
|
| 531 |
+
# show zero-length shape unless it is (0,)
|
| 532 |
+
lst = f"[], shape={repr(self.shape)}"
|
| 533 |
+
|
| 534 |
+
lf = '\n' + ' ' * len(prefix)
|
| 535 |
+
if _get_legacy_print_mode() <= 113:
|
| 536 |
+
lf = ' ' + lf # trailing space
|
| 537 |
+
return fmt % (lst, lf, repr_dtype)
|
| 538 |
+
|
| 539 |
+
def field(self, attr, val=None):
|
| 540 |
+
if isinstance(attr, int):
|
| 541 |
+
names = ndarray.__getattribute__(self, 'dtype').names
|
| 542 |
+
attr = names[attr]
|
| 543 |
+
|
| 544 |
+
fielddict = ndarray.__getattribute__(self, 'dtype').fields
|
| 545 |
+
|
| 546 |
+
res = fielddict[attr][:2]
|
| 547 |
+
|
| 548 |
+
if val is None:
|
| 549 |
+
obj = self.getfield(*res)
|
| 550 |
+
if obj.dtype.names is not None:
|
| 551 |
+
return obj
|
| 552 |
+
return obj.view(ndarray)
|
| 553 |
+
else:
|
| 554 |
+
return self.setfield(val, *res)
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
def _deprecate_shape_0_as_None(shape):
|
| 558 |
+
if shape == 0:
|
| 559 |
+
warnings.warn(
|
| 560 |
+
"Passing `shape=0` to have the shape be inferred is deprecated, "
|
| 561 |
+
"and in future will be equivalent to `shape=(0,)`. To infer "
|
| 562 |
+
"the shape and suppress this warning, pass `shape=None` instead.",
|
| 563 |
+
FutureWarning, stacklevel=3)
|
| 564 |
+
return None
|
| 565 |
+
else:
|
| 566 |
+
return shape
|
| 567 |
+
|
| 568 |
+
|
| 569 |
+
@set_module("numpy.rec")
|
| 570 |
+
def fromarrays(arrayList, dtype=None, shape=None, formats=None,
|
| 571 |
+
names=None, titles=None, aligned=False, byteorder=None):
|
| 572 |
+
"""Create a record array from a (flat) list of arrays
|
| 573 |
+
|
| 574 |
+
Parameters
|
| 575 |
+
----------
|
| 576 |
+
arrayList : list or tuple
|
| 577 |
+
List of array-like objects (such as lists, tuples,
|
| 578 |
+
and ndarrays).
|
| 579 |
+
dtype : data-type, optional
|
| 580 |
+
valid dtype for all arrays
|
| 581 |
+
shape : int or tuple of ints, optional
|
| 582 |
+
Shape of the resulting array. If not provided, inferred from
|
| 583 |
+
``arrayList[0]``.
|
| 584 |
+
formats, names, titles, aligned, byteorder :
|
| 585 |
+
If `dtype` is ``None``, these arguments are passed to
|
| 586 |
+
`numpy.rec.format_parser` to construct a dtype. See that function for
|
| 587 |
+
detailed documentation.
|
| 588 |
+
|
| 589 |
+
Returns
|
| 590 |
+
-------
|
| 591 |
+
np.recarray
|
| 592 |
+
Record array consisting of given arrayList columns.
|
| 593 |
+
|
| 594 |
+
Examples
|
| 595 |
+
--------
|
| 596 |
+
>>> x1=np.array([1,2,3,4])
|
| 597 |
+
>>> x2=np.array(['a','dd','xyz','12'])
|
| 598 |
+
>>> x3=np.array([1.1,2,3,4])
|
| 599 |
+
>>> r = np.rec.fromarrays([x1,x2,x3],names='a,b,c')
|
| 600 |
+
>>> print(r[1])
|
| 601 |
+
(2, 'dd', 2.0) # may vary
|
| 602 |
+
>>> x1[1]=34
|
| 603 |
+
>>> r.a
|
| 604 |
+
array([1, 2, 3, 4])
|
| 605 |
+
|
| 606 |
+
>>> x1 = np.array([1, 2, 3, 4])
|
| 607 |
+
>>> x2 = np.array(['a', 'dd', 'xyz', '12'])
|
| 608 |
+
>>> x3 = np.array([1.1, 2, 3,4])
|
| 609 |
+
>>> r = np.rec.fromarrays(
|
| 610 |
+
... [x1, x2, x3],
|
| 611 |
+
... dtype=np.dtype([('a', np.int32), ('b', 'S3'), ('c', np.float32)]))
|
| 612 |
+
>>> r
|
| 613 |
+
rec.array([(1, b'a', 1.1), (2, b'dd', 2. ), (3, b'xyz', 3. ),
|
| 614 |
+
(4, b'12', 4. )],
|
| 615 |
+
dtype=[('a', '<i4'), ('b', 'S3'), ('c', '<f4')])
|
| 616 |
+
"""
|
| 617 |
+
|
| 618 |
+
arrayList = [sb.asarray(x) for x in arrayList]
|
| 619 |
+
|
| 620 |
+
# NumPy 1.19.0, 2020-01-01
|
| 621 |
+
shape = _deprecate_shape_0_as_None(shape)
|
| 622 |
+
|
| 623 |
+
if shape is None:
|
| 624 |
+
shape = arrayList[0].shape
|
| 625 |
+
elif isinstance(shape, int):
|
| 626 |
+
shape = (shape,)
|
| 627 |
+
|
| 628 |
+
if formats is None and dtype is None:
|
| 629 |
+
# go through each object in the list to see if it is an ndarray
|
| 630 |
+
# and determine the formats.
|
| 631 |
+
formats = [obj.dtype for obj in arrayList]
|
| 632 |
+
|
| 633 |
+
if dtype is not None:
|
| 634 |
+
descr = sb.dtype(dtype)
|
| 635 |
+
else:
|
| 636 |
+
descr = format_parser(formats, names, titles, aligned, byteorder).dtype
|
| 637 |
+
_names = descr.names
|
| 638 |
+
|
| 639 |
+
# Determine shape from data-type.
|
| 640 |
+
if len(descr) != len(arrayList):
|
| 641 |
+
raise ValueError("mismatch between the number of fields "
|
| 642 |
+
"and the number of arrays")
|
| 643 |
+
|
| 644 |
+
d0 = descr[0].shape
|
| 645 |
+
nn = len(d0)
|
| 646 |
+
if nn > 0:
|
| 647 |
+
shape = shape[:-nn]
|
| 648 |
+
|
| 649 |
+
_array = recarray(shape, descr)
|
| 650 |
+
|
| 651 |
+
# populate the record array (makes a copy)
|
| 652 |
+
for k, obj in enumerate(arrayList):
|
| 653 |
+
nn = descr[k].ndim
|
| 654 |
+
testshape = obj.shape[:obj.ndim - nn]
|
| 655 |
+
name = _names[k]
|
| 656 |
+
if testshape != shape:
|
| 657 |
+
raise ValueError(f'array-shape mismatch in array {k} ("{name}")')
|
| 658 |
+
|
| 659 |
+
_array[name] = obj
|
| 660 |
+
|
| 661 |
+
return _array
|
| 662 |
+
|
| 663 |
+
|
| 664 |
+
@set_module("numpy.rec")
|
| 665 |
+
def fromrecords(recList, dtype=None, shape=None, formats=None, names=None,
|
| 666 |
+
titles=None, aligned=False, byteorder=None):
|
| 667 |
+
"""Create a recarray from a list of records in text form.
|
| 668 |
+
|
| 669 |
+
Parameters
|
| 670 |
+
----------
|
| 671 |
+
recList : sequence
|
| 672 |
+
data in the same field may be heterogeneous - they will be promoted
|
| 673 |
+
to the highest data type.
|
| 674 |
+
dtype : data-type, optional
|
| 675 |
+
valid dtype for all arrays
|
| 676 |
+
shape : int or tuple of ints, optional
|
| 677 |
+
shape of each array.
|
| 678 |
+
formats, names, titles, aligned, byteorder :
|
| 679 |
+
If `dtype` is ``None``, these arguments are passed to
|
| 680 |
+
`numpy.format_parser` to construct a dtype. See that function for
|
| 681 |
+
detailed documentation.
|
| 682 |
+
|
| 683 |
+
If both `formats` and `dtype` are None, then this will auto-detect
|
| 684 |
+
formats. Use list of tuples rather than list of lists for faster
|
| 685 |
+
processing.
|
| 686 |
+
|
| 687 |
+
Returns
|
| 688 |
+
-------
|
| 689 |
+
np.recarray
|
| 690 |
+
record array consisting of given recList rows.
|
| 691 |
+
|
| 692 |
+
Examples
|
| 693 |
+
--------
|
| 694 |
+
>>> r=np.rec.fromrecords([(456,'dbe',1.2),(2,'de',1.3)],
|
| 695 |
+
... names='col1,col2,col3')
|
| 696 |
+
>>> print(r[0])
|
| 697 |
+
(456, 'dbe', 1.2)
|
| 698 |
+
>>> r.col1
|
| 699 |
+
array([456, 2])
|
| 700 |
+
>>> r.col2
|
| 701 |
+
array(['dbe', 'de'], dtype='<U3')
|
| 702 |
+
>>> import pickle
|
| 703 |
+
>>> pickle.loads(pickle.dumps(r))
|
| 704 |
+
rec.array([(456, 'dbe', 1.2), ( 2, 'de', 1.3)],
|
| 705 |
+
dtype=[('col1', '<i8'), ('col2', '<U3'), ('col3', '<f8')])
|
| 706 |
+
"""
|
| 707 |
+
|
| 708 |
+
if formats is None and dtype is None: # slower
|
| 709 |
+
obj = sb.array(recList, dtype=object)
|
| 710 |
+
arrlist = [
|
| 711 |
+
sb.array(obj[..., i].tolist()) for i in range(obj.shape[-1])
|
| 712 |
+
]
|
| 713 |
+
return fromarrays(arrlist, formats=formats, shape=shape, names=names,
|
| 714 |
+
titles=titles, aligned=aligned, byteorder=byteorder)
|
| 715 |
+
|
| 716 |
+
if dtype is not None:
|
| 717 |
+
descr = sb.dtype((record, dtype))
|
| 718 |
+
else:
|
| 719 |
+
descr = format_parser(
|
| 720 |
+
formats, names, titles, aligned, byteorder
|
| 721 |
+
).dtype
|
| 722 |
+
|
| 723 |
+
try:
|
| 724 |
+
retval = sb.array(recList, dtype=descr)
|
| 725 |
+
except (TypeError, ValueError):
|
| 726 |
+
# NumPy 1.19.0, 2020-01-01
|
| 727 |
+
shape = _deprecate_shape_0_as_None(shape)
|
| 728 |
+
if shape is None:
|
| 729 |
+
shape = len(recList)
|
| 730 |
+
if isinstance(shape, int):
|
| 731 |
+
shape = (shape,)
|
| 732 |
+
if len(shape) > 1:
|
| 733 |
+
raise ValueError("Can only deal with 1-d array.")
|
| 734 |
+
_array = recarray(shape, descr)
|
| 735 |
+
for k in range(_array.size):
|
| 736 |
+
_array[k] = tuple(recList[k])
|
| 737 |
+
# list of lists instead of list of tuples ?
|
| 738 |
+
# 2018-02-07, 1.14.1
|
| 739 |
+
warnings.warn(
|
| 740 |
+
"fromrecords expected a list of tuples, may have received a list "
|
| 741 |
+
"of lists instead. In the future that will raise an error",
|
| 742 |
+
FutureWarning, stacklevel=2)
|
| 743 |
+
return _array
|
| 744 |
+
else:
|
| 745 |
+
if shape is not None and retval.shape != shape:
|
| 746 |
+
retval = retval.reshape(shape)
|
| 747 |
+
|
| 748 |
+
res = retval.view(recarray)
|
| 749 |
+
|
| 750 |
+
return res
|
| 751 |
+
|
| 752 |
+
|
| 753 |
+
@set_module("numpy.rec")
|
| 754 |
+
def fromstring(datastring, dtype=None, shape=None, offset=0, formats=None,
|
| 755 |
+
names=None, titles=None, aligned=False, byteorder=None):
|
| 756 |
+
r"""Create a record array from binary data
|
| 757 |
+
|
| 758 |
+
Note that despite the name of this function it does not accept `str`
|
| 759 |
+
instances.
|
| 760 |
+
|
| 761 |
+
Parameters
|
| 762 |
+
----------
|
| 763 |
+
datastring : bytes-like
|
| 764 |
+
Buffer of binary data
|
| 765 |
+
dtype : data-type, optional
|
| 766 |
+
Valid dtype for all arrays
|
| 767 |
+
shape : int or tuple of ints, optional
|
| 768 |
+
Shape of each array.
|
| 769 |
+
offset : int, optional
|
| 770 |
+
Position in the buffer to start reading from.
|
| 771 |
+
formats, names, titles, aligned, byteorder :
|
| 772 |
+
If `dtype` is ``None``, these arguments are passed to
|
| 773 |
+
`numpy.format_parser` to construct a dtype. See that function for
|
| 774 |
+
detailed documentation.
|
| 775 |
+
|
| 776 |
+
|
| 777 |
+
Returns
|
| 778 |
+
-------
|
| 779 |
+
np.recarray
|
| 780 |
+
Record array view into the data in datastring. This will be readonly
|
| 781 |
+
if `datastring` is readonly.
|
| 782 |
+
|
| 783 |
+
See Also
|
| 784 |
+
--------
|
| 785 |
+
numpy.frombuffer
|
| 786 |
+
|
| 787 |
+
Examples
|
| 788 |
+
--------
|
| 789 |
+
>>> a = b'\x01\x02\x03abc'
|
| 790 |
+
>>> np.rec.fromstring(a, dtype='u1,u1,u1,S3')
|
| 791 |
+
rec.array([(1, 2, 3, b'abc')],
|
| 792 |
+
dtype=[('f0', 'u1'), ('f1', 'u1'), ('f2', 'u1'), ('f3', 'S3')])
|
| 793 |
+
|
| 794 |
+
>>> grades_dtype = [('Name', (np.str_, 10)), ('Marks', np.float64),
|
| 795 |
+
... ('GradeLevel', np.int32)]
|
| 796 |
+
>>> grades_array = np.array([('Sam', 33.3, 3), ('Mike', 44.4, 5),
|
| 797 |
+
... ('Aadi', 66.6, 6)], dtype=grades_dtype)
|
| 798 |
+
>>> np.rec.fromstring(grades_array.tobytes(), dtype=grades_dtype)
|
| 799 |
+
rec.array([('Sam', 33.3, 3), ('Mike', 44.4, 5), ('Aadi', 66.6, 6)],
|
| 800 |
+
dtype=[('Name', '<U10'), ('Marks', '<f8'), ('GradeLevel', '<i4')])
|
| 801 |
+
|
| 802 |
+
>>> s = '\x01\x02\x03abc'
|
| 803 |
+
>>> np.rec.fromstring(s, dtype='u1,u1,u1,S3')
|
| 804 |
+
Traceback (most recent call last):
|
| 805 |
+
...
|
| 806 |
+
TypeError: a bytes-like object is required, not 'str'
|
| 807 |
+
"""
|
| 808 |
+
|
| 809 |
+
if dtype is None and formats is None:
|
| 810 |
+
raise TypeError("fromstring() needs a 'dtype' or 'formats' argument")
|
| 811 |
+
|
| 812 |
+
if dtype is not None:
|
| 813 |
+
descr = sb.dtype(dtype)
|
| 814 |
+
else:
|
| 815 |
+
descr = format_parser(formats, names, titles, aligned, byteorder).dtype
|
| 816 |
+
|
| 817 |
+
if descr.hasobject:
|
| 818 |
+
raise ValueError(
|
| 819 |
+
f"Cannot create record array for dtype {descr}. "
|
| 820 |
+
"Arrays containing references are not supported."
|
| 821 |
+
)
|
| 822 |
+
|
| 823 |
+
itemsize = descr.itemsize
|
| 824 |
+
|
| 825 |
+
# NumPy 1.19.0, 2020-01-01
|
| 826 |
+
shape = _deprecate_shape_0_as_None(shape)
|
| 827 |
+
|
| 828 |
+
if shape in (None, -1):
|
| 829 |
+
shape = (len(datastring) - offset) // itemsize
|
| 830 |
+
|
| 831 |
+
_array = recarray(shape, descr, buf=datastring, offset=offset)
|
| 832 |
+
return _array
|
| 833 |
+
|
| 834 |
+
def get_remaining_size(fd):
|
| 835 |
+
pos = fd.tell()
|
| 836 |
+
try:
|
| 837 |
+
fd.seek(0, 2)
|
| 838 |
+
return fd.tell() - pos
|
| 839 |
+
finally:
|
| 840 |
+
fd.seek(pos, 0)
|
| 841 |
+
|
| 842 |
+
|
| 843 |
+
@set_module("numpy.rec")
|
| 844 |
+
def fromfile(fd, dtype=None, shape=None, offset=0, formats=None,
|
| 845 |
+
names=None, titles=None, aligned=False, byteorder=None):
|
| 846 |
+
"""Create an array from binary file data
|
| 847 |
+
|
| 848 |
+
Parameters
|
| 849 |
+
----------
|
| 850 |
+
fd : str or file type
|
| 851 |
+
If file is a string or a path-like object then that file is opened,
|
| 852 |
+
else it is assumed to be a file object. The file object must
|
| 853 |
+
support random access (i.e. it must have tell and seek methods).
|
| 854 |
+
dtype : data-type, optional
|
| 855 |
+
valid dtype for all arrays
|
| 856 |
+
shape : int or tuple of ints, optional
|
| 857 |
+
shape of each array.
|
| 858 |
+
offset : int, optional
|
| 859 |
+
Position in the file to start reading from.
|
| 860 |
+
formats, names, titles, aligned, byteorder :
|
| 861 |
+
If `dtype` is ``None``, these arguments are passed to
|
| 862 |
+
`numpy.format_parser` to construct a dtype. See that function for
|
| 863 |
+
detailed documentation
|
| 864 |
+
|
| 865 |
+
Returns
|
| 866 |
+
-------
|
| 867 |
+
np.recarray
|
| 868 |
+
record array consisting of data enclosed in file.
|
| 869 |
+
|
| 870 |
+
Examples
|
| 871 |
+
--------
|
| 872 |
+
>>> from tempfile import TemporaryFile
|
| 873 |
+
>>> a = np.empty(10,dtype='f8,i4,S5')
|
| 874 |
+
>>> a[5] = (0.5,10,'abcde')
|
| 875 |
+
>>>
|
| 876 |
+
>>> fd=TemporaryFile()
|
| 877 |
+
>>> a = a.view(a.dtype.newbyteorder('<'))
|
| 878 |
+
>>> a.tofile(fd)
|
| 879 |
+
>>>
|
| 880 |
+
>>> _ = fd.seek(0)
|
| 881 |
+
>>> r=np.rec.fromfile(fd, formats='f8,i4,S5', shape=10,
|
| 882 |
+
... byteorder='<')
|
| 883 |
+
>>> print(r[5])
|
| 884 |
+
(0.5, 10, b'abcde')
|
| 885 |
+
>>> r.shape
|
| 886 |
+
(10,)
|
| 887 |
+
"""
|
| 888 |
+
|
| 889 |
+
if dtype is None and formats is None:
|
| 890 |
+
raise TypeError("fromfile() needs a 'dtype' or 'formats' argument")
|
| 891 |
+
|
| 892 |
+
# NumPy 1.19.0, 2020-01-01
|
| 893 |
+
shape = _deprecate_shape_0_as_None(shape)
|
| 894 |
+
|
| 895 |
+
if shape is None:
|
| 896 |
+
shape = (-1,)
|
| 897 |
+
elif isinstance(shape, int):
|
| 898 |
+
shape = (shape,)
|
| 899 |
+
|
| 900 |
+
if hasattr(fd, 'readinto'):
|
| 901 |
+
# GH issue 2504. fd supports io.RawIOBase or io.BufferedIOBase
|
| 902 |
+
# interface. Example of fd: gzip, BytesIO, BufferedReader
|
| 903 |
+
# file already opened
|
| 904 |
+
ctx = nullcontext(fd)
|
| 905 |
+
else:
|
| 906 |
+
# open file
|
| 907 |
+
ctx = open(os.fspath(fd), 'rb')
|
| 908 |
+
|
| 909 |
+
with ctx as fd:
|
| 910 |
+
if offset > 0:
|
| 911 |
+
fd.seek(offset, 1)
|
| 912 |
+
size = get_remaining_size(fd)
|
| 913 |
+
|
| 914 |
+
if dtype is not None:
|
| 915 |
+
descr = sb.dtype(dtype)
|
| 916 |
+
else:
|
| 917 |
+
descr = format_parser(
|
| 918 |
+
formats, names, titles, aligned, byteorder
|
| 919 |
+
).dtype
|
| 920 |
+
|
| 921 |
+
if descr.hasobject:
|
| 922 |
+
raise ValueError(
|
| 923 |
+
f"Cannot create record array for dtype {descr}. "
|
| 924 |
+
"Arrays containing references are not supported."
|
| 925 |
+
)
|
| 926 |
+
|
| 927 |
+
itemsize = descr.itemsize
|
| 928 |
+
|
| 929 |
+
shapeprod = sb.array(shape).prod(dtype=nt.intp)
|
| 930 |
+
shapesize = shapeprod * itemsize
|
| 931 |
+
if shapesize < 0:
|
| 932 |
+
shape = list(shape)
|
| 933 |
+
shape[shape.index(-1)] = size // -shapesize
|
| 934 |
+
shape = tuple(shape)
|
| 935 |
+
shapeprod = sb.array(shape).prod(dtype=nt.intp)
|
| 936 |
+
|
| 937 |
+
nbytes = shapeprod * itemsize
|
| 938 |
+
|
| 939 |
+
if nbytes > size:
|
| 940 |
+
raise ValueError(
|
| 941 |
+
"Not enough bytes left in file for specified "
|
| 942 |
+
"shape and type."
|
| 943 |
+
)
|
| 944 |
+
|
| 945 |
+
# create the array
|
| 946 |
+
_array = recarray(shape, descr)
|
| 947 |
+
nbytesread = fd.readinto(_array.data)
|
| 948 |
+
if nbytesread != nbytes:
|
| 949 |
+
raise OSError("Didn't read as many bytes as expected")
|
| 950 |
+
|
| 951 |
+
return _array
|
| 952 |
+
|
| 953 |
+
|
| 954 |
+
@set_module("numpy.rec")
|
| 955 |
+
def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None,
|
| 956 |
+
names=None, titles=None, aligned=False, byteorder=None, copy=True):
|
| 957 |
+
"""
|
| 958 |
+
Construct a record array from a wide-variety of objects.
|
| 959 |
+
|
| 960 |
+
A general-purpose record array constructor that dispatches to the
|
| 961 |
+
appropriate `recarray` creation function based on the inputs (see Notes).
|
| 962 |
+
|
| 963 |
+
Parameters
|
| 964 |
+
----------
|
| 965 |
+
obj : any
|
| 966 |
+
Input object. See Notes for details on how various input types are
|
| 967 |
+
treated.
|
| 968 |
+
dtype : data-type, optional
|
| 969 |
+
Valid dtype for array.
|
| 970 |
+
shape : int or tuple of ints, optional
|
| 971 |
+
Shape of each array.
|
| 972 |
+
offset : int, optional
|
| 973 |
+
Position in the file or buffer to start reading from.
|
| 974 |
+
strides : tuple of ints, optional
|
| 975 |
+
Buffer (`buf`) is interpreted according to these strides (strides
|
| 976 |
+
define how many bytes each array element, row, column, etc.
|
| 977 |
+
occupy in memory).
|
| 978 |
+
formats, names, titles, aligned, byteorder :
|
| 979 |
+
If `dtype` is ``None``, these arguments are passed to
|
| 980 |
+
`numpy.format_parser` to construct a dtype. See that function for
|
| 981 |
+
detailed documentation.
|
| 982 |
+
copy : bool, optional
|
| 983 |
+
Whether to copy the input object (True), or to use a reference instead.
|
| 984 |
+
This option only applies when the input is an ndarray or recarray.
|
| 985 |
+
Defaults to True.
|
| 986 |
+
|
| 987 |
+
Returns
|
| 988 |
+
-------
|
| 989 |
+
np.recarray
|
| 990 |
+
Record array created from the specified object.
|
| 991 |
+
|
| 992 |
+
Notes
|
| 993 |
+
-----
|
| 994 |
+
If `obj` is ``None``, then call the `~numpy.recarray` constructor. If
|
| 995 |
+
`obj` is a string, then call the `fromstring` constructor. If `obj` is a
|
| 996 |
+
list or a tuple, then if the first object is an `~numpy.ndarray`, call
|
| 997 |
+
`fromarrays`, otherwise call `fromrecords`. If `obj` is a
|
| 998 |
+
`~numpy.recarray`, then make a copy of the data in the recarray
|
| 999 |
+
(if ``copy=True``) and use the new formats, names, and titles. If `obj`
|
| 1000 |
+
is a file, then call `fromfile`. Finally, if obj is an `ndarray`, then
|
| 1001 |
+
return ``obj.view(recarray)``, making a copy of the data if ``copy=True``.
|
| 1002 |
+
|
| 1003 |
+
Examples
|
| 1004 |
+
--------
|
| 1005 |
+
>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
| 1006 |
+
>>> a
|
| 1007 |
+
array([[1, 2, 3],
|
| 1008 |
+
[4, 5, 6],
|
| 1009 |
+
[7, 8, 9]])
|
| 1010 |
+
|
| 1011 |
+
>>> np.rec.array(a)
|
| 1012 |
+
rec.array([[1, 2, 3],
|
| 1013 |
+
[4, 5, 6],
|
| 1014 |
+
[7, 8, 9]],
|
| 1015 |
+
dtype=int64)
|
| 1016 |
+
|
| 1017 |
+
>>> b = [(1, 1), (2, 4), (3, 9)]
|
| 1018 |
+
>>> c = np.rec.array(b, formats = ['i2', 'f2'], names = ('x', 'y'))
|
| 1019 |
+
>>> c
|
| 1020 |
+
rec.array([(1, 1.), (2, 4.), (3, 9.)],
|
| 1021 |
+
dtype=[('x', '<i2'), ('y', '<f2')])
|
| 1022 |
+
|
| 1023 |
+
>>> c.x
|
| 1024 |
+
array([1, 2, 3], dtype=int16)
|
| 1025 |
+
|
| 1026 |
+
>>> c.y
|
| 1027 |
+
array([1., 4., 9.], dtype=float16)
|
| 1028 |
+
|
| 1029 |
+
>>> r = np.rec.array(['abc','def'], names=['col1','col2'])
|
| 1030 |
+
>>> print(r.col1)
|
| 1031 |
+
abc
|
| 1032 |
+
|
| 1033 |
+
>>> r.col1
|
| 1034 |
+
array('abc', dtype='<U3')
|
| 1035 |
+
|
| 1036 |
+
>>> r.col2
|
| 1037 |
+
array('def', dtype='<U3')
|
| 1038 |
+
"""
|
| 1039 |
+
|
| 1040 |
+
if ((isinstance(obj, (type(None), str)) or hasattr(obj, 'readinto')) and
|
| 1041 |
+
formats is None and dtype is None):
|
| 1042 |
+
raise ValueError("Must define formats (or dtype) if object is "
|
| 1043 |
+
"None, string, or an open file")
|
| 1044 |
+
|
| 1045 |
+
kwds = {}
|
| 1046 |
+
if dtype is not None:
|
| 1047 |
+
dtype = sb.dtype(dtype)
|
| 1048 |
+
elif formats is not None:
|
| 1049 |
+
dtype = format_parser(formats, names, titles,
|
| 1050 |
+
aligned, byteorder).dtype
|
| 1051 |
+
else:
|
| 1052 |
+
kwds = {'formats': formats,
|
| 1053 |
+
'names': names,
|
| 1054 |
+
'titles': titles,
|
| 1055 |
+
'aligned': aligned,
|
| 1056 |
+
'byteorder': byteorder
|
| 1057 |
+
}
|
| 1058 |
+
|
| 1059 |
+
if obj is None:
|
| 1060 |
+
if shape is None:
|
| 1061 |
+
raise ValueError("Must define a shape if obj is None")
|
| 1062 |
+
return recarray(shape, dtype, buf=obj, offset=offset, strides=strides)
|
| 1063 |
+
|
| 1064 |
+
elif isinstance(obj, bytes):
|
| 1065 |
+
return fromstring(obj, dtype, shape=shape, offset=offset, **kwds)
|
| 1066 |
+
|
| 1067 |
+
elif isinstance(obj, (list, tuple)):
|
| 1068 |
+
if isinstance(obj[0], (tuple, list)):
|
| 1069 |
+
return fromrecords(obj, dtype=dtype, shape=shape, **kwds)
|
| 1070 |
+
else:
|
| 1071 |
+
return fromarrays(obj, dtype=dtype, shape=shape, **kwds)
|
| 1072 |
+
|
| 1073 |
+
elif isinstance(obj, recarray):
|
| 1074 |
+
if dtype is not None and (obj.dtype != dtype):
|
| 1075 |
+
new = obj.view(dtype)
|
| 1076 |
+
else:
|
| 1077 |
+
new = obj
|
| 1078 |
+
if copy:
|
| 1079 |
+
new = new.copy()
|
| 1080 |
+
return new
|
| 1081 |
+
|
| 1082 |
+
elif hasattr(obj, 'readinto'):
|
| 1083 |
+
return fromfile(obj, dtype=dtype, shape=shape, offset=offset)
|
| 1084 |
+
|
| 1085 |
+
elif isinstance(obj, ndarray):
|
| 1086 |
+
if dtype is not None and (obj.dtype != dtype):
|
| 1087 |
+
new = obj.view(dtype)
|
| 1088 |
+
else:
|
| 1089 |
+
new = obj
|
| 1090 |
+
if copy:
|
| 1091 |
+
new = new.copy()
|
| 1092 |
+
return new.view(recarray)
|
| 1093 |
+
|
| 1094 |
+
else:
|
| 1095 |
+
interface = getattr(obj, "__array_interface__", None)
|
| 1096 |
+
if interface is None or not isinstance(interface, dict):
|
| 1097 |
+
raise ValueError("Unknown input type")
|
| 1098 |
+
obj = sb.array(obj)
|
| 1099 |
+
if dtype is not None and (obj.dtype != dtype):
|
| 1100 |
+
obj = obj.view(dtype)
|
| 1101 |
+
return obj.view(recarray)
|
v12x/pylib/numpy/_core/shape_base.py
ADDED
|
@@ -0,0 +1,996 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__all__ = ['atleast_1d', 'atleast_2d', 'atleast_3d', 'block', 'hstack',
|
| 2 |
+
'stack', 'unstack', 'vstack']
|
| 3 |
+
|
| 4 |
+
import functools
|
| 5 |
+
import itertools
|
| 6 |
+
import operator
|
| 7 |
+
|
| 8 |
+
from . import fromnumeric as _from_nx, numeric as _nx, overrides
|
| 9 |
+
from .multiarray import array, asanyarray, normalize_axis_index
|
| 10 |
+
|
| 11 |
+
array_function_dispatch = functools.partial(
|
| 12 |
+
overrides.array_function_dispatch, module='numpy')
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def _atleast_1d_dispatcher(*arys):
|
| 16 |
+
return arys
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
@array_function_dispatch(_atleast_1d_dispatcher)
|
| 20 |
+
def atleast_1d(*arys):
|
| 21 |
+
"""
|
| 22 |
+
Convert inputs to arrays with at least one dimension.
|
| 23 |
+
|
| 24 |
+
Scalar inputs are converted to 1-dimensional arrays, whilst
|
| 25 |
+
higher-dimensional inputs are preserved.
|
| 26 |
+
|
| 27 |
+
Parameters
|
| 28 |
+
----------
|
| 29 |
+
arys1, arys2, ... : array_like
|
| 30 |
+
One or more input arrays.
|
| 31 |
+
|
| 32 |
+
Returns
|
| 33 |
+
-------
|
| 34 |
+
ret : ndarray
|
| 35 |
+
An array, or tuple of arrays, each with ``a.ndim >= 1``.
|
| 36 |
+
Copies are made only if necessary.
|
| 37 |
+
|
| 38 |
+
See Also
|
| 39 |
+
--------
|
| 40 |
+
atleast_2d, atleast_3d
|
| 41 |
+
|
| 42 |
+
Examples
|
| 43 |
+
--------
|
| 44 |
+
>>> import numpy as np
|
| 45 |
+
>>> np.atleast_1d(1.0)
|
| 46 |
+
array([1.])
|
| 47 |
+
|
| 48 |
+
>>> x = np.arange(9.0).reshape(3,3)
|
| 49 |
+
>>> np.atleast_1d(x)
|
| 50 |
+
array([[0., 1., 2.],
|
| 51 |
+
[3., 4., 5.],
|
| 52 |
+
[6., 7., 8.]])
|
| 53 |
+
>>> np.atleast_1d(x) is x
|
| 54 |
+
True
|
| 55 |
+
|
| 56 |
+
>>> np.atleast_1d(1, [3, 4])
|
| 57 |
+
(array([1]), array([3, 4]))
|
| 58 |
+
|
| 59 |
+
"""
|
| 60 |
+
if len(arys) == 1:
|
| 61 |
+
result = asanyarray(arys[0])
|
| 62 |
+
if result.ndim == 0:
|
| 63 |
+
result = result.reshape(1)
|
| 64 |
+
return result
|
| 65 |
+
res = []
|
| 66 |
+
for ary in arys:
|
| 67 |
+
result = asanyarray(ary)
|
| 68 |
+
if result.ndim == 0:
|
| 69 |
+
result = result.reshape(1)
|
| 70 |
+
res.append(result)
|
| 71 |
+
return tuple(res)
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def _atleast_2d_dispatcher(*arys):
|
| 75 |
+
return arys
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
@array_function_dispatch(_atleast_2d_dispatcher)
|
| 79 |
+
def atleast_2d(*arys):
|
| 80 |
+
"""
|
| 81 |
+
View inputs as arrays with at least two dimensions.
|
| 82 |
+
|
| 83 |
+
Parameters
|
| 84 |
+
----------
|
| 85 |
+
arys1, arys2, ... : array_like
|
| 86 |
+
One or more array-like sequences. Non-array inputs are converted
|
| 87 |
+
to arrays. Arrays that already have two or more dimensions are
|
| 88 |
+
preserved.
|
| 89 |
+
|
| 90 |
+
Returns
|
| 91 |
+
-------
|
| 92 |
+
res, res2, ... : ndarray
|
| 93 |
+
An array, or tuple of arrays, each with ``a.ndim >= 2``.
|
| 94 |
+
Copies are avoided where possible, and views with two or more
|
| 95 |
+
dimensions are returned.
|
| 96 |
+
|
| 97 |
+
See Also
|
| 98 |
+
--------
|
| 99 |
+
atleast_1d, atleast_3d
|
| 100 |
+
|
| 101 |
+
Examples
|
| 102 |
+
--------
|
| 103 |
+
>>> import numpy as np
|
| 104 |
+
>>> np.atleast_2d(3.0)
|
| 105 |
+
array([[3.]])
|
| 106 |
+
|
| 107 |
+
>>> x = np.arange(3.0)
|
| 108 |
+
>>> np.atleast_2d(x)
|
| 109 |
+
array([[0., 1., 2.]])
|
| 110 |
+
>>> np.atleast_2d(x).base is x
|
| 111 |
+
True
|
| 112 |
+
|
| 113 |
+
>>> np.atleast_2d(1, [1, 2], [[1, 2]])
|
| 114 |
+
(array([[1]]), array([[1, 2]]), array([[1, 2]]))
|
| 115 |
+
|
| 116 |
+
"""
|
| 117 |
+
res = []
|
| 118 |
+
for ary in arys:
|
| 119 |
+
ary = asanyarray(ary)
|
| 120 |
+
if ary.ndim == 0:
|
| 121 |
+
result = ary.reshape(1, 1)
|
| 122 |
+
elif ary.ndim == 1:
|
| 123 |
+
result = ary[_nx.newaxis, :]
|
| 124 |
+
else:
|
| 125 |
+
result = ary
|
| 126 |
+
res.append(result)
|
| 127 |
+
if len(res) == 1:
|
| 128 |
+
return res[0]
|
| 129 |
+
else:
|
| 130 |
+
return tuple(res)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def _atleast_3d_dispatcher(*arys):
|
| 134 |
+
return arys
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
@array_function_dispatch(_atleast_3d_dispatcher)
|
| 138 |
+
def atleast_3d(*arys):
|
| 139 |
+
"""
|
| 140 |
+
View inputs as arrays with at least three dimensions.
|
| 141 |
+
|
| 142 |
+
Parameters
|
| 143 |
+
----------
|
| 144 |
+
arys1, arys2, ... : array_like
|
| 145 |
+
One or more array-like sequences. Non-array inputs are converted to
|
| 146 |
+
arrays. Arrays that already have three or more dimensions are
|
| 147 |
+
preserved.
|
| 148 |
+
|
| 149 |
+
Returns
|
| 150 |
+
-------
|
| 151 |
+
res1, res2, ... : ndarray
|
| 152 |
+
An array, or tuple of arrays, each with ``a.ndim >= 3``. Copies are
|
| 153 |
+
avoided where possible, and views with three or more dimensions are
|
| 154 |
+
returned. For example, a 1-D array of shape ``(N,)`` becomes a view
|
| 155 |
+
of shape ``(1, N, 1)``, and a 2-D array of shape ``(M, N)`` becomes a
|
| 156 |
+
view of shape ``(M, N, 1)``.
|
| 157 |
+
|
| 158 |
+
See Also
|
| 159 |
+
--------
|
| 160 |
+
atleast_1d, atleast_2d
|
| 161 |
+
|
| 162 |
+
Examples
|
| 163 |
+
--------
|
| 164 |
+
>>> import numpy as np
|
| 165 |
+
>>> np.atleast_3d(3.0)
|
| 166 |
+
array([[[3.]]])
|
| 167 |
+
|
| 168 |
+
>>> x = np.arange(3.0)
|
| 169 |
+
>>> np.atleast_3d(x).shape
|
| 170 |
+
(1, 3, 1)
|
| 171 |
+
|
| 172 |
+
>>> x = np.arange(12.0).reshape(4,3)
|
| 173 |
+
>>> np.atleast_3d(x).shape
|
| 174 |
+
(4, 3, 1)
|
| 175 |
+
>>> np.atleast_3d(x).base is x.base # x is a reshape, so not base itself
|
| 176 |
+
True
|
| 177 |
+
|
| 178 |
+
>>> for arr in np.atleast_3d([1, 2], [[1, 2]], [[[1, 2]]]):
|
| 179 |
+
... print(arr, arr.shape) # doctest: +SKIP
|
| 180 |
+
...
|
| 181 |
+
[[[1]
|
| 182 |
+
[2]]] (1, 2, 1)
|
| 183 |
+
[[[1]
|
| 184 |
+
[2]]] (1, 2, 1)
|
| 185 |
+
[[[1 2]]] (1, 1, 2)
|
| 186 |
+
|
| 187 |
+
"""
|
| 188 |
+
res = []
|
| 189 |
+
for ary in arys:
|
| 190 |
+
ary = asanyarray(ary)
|
| 191 |
+
if ary.ndim == 0:
|
| 192 |
+
result = ary.reshape(1, 1, 1)
|
| 193 |
+
elif ary.ndim == 1:
|
| 194 |
+
result = ary[_nx.newaxis, :, _nx.newaxis]
|
| 195 |
+
elif ary.ndim == 2:
|
| 196 |
+
result = ary[:, :, _nx.newaxis]
|
| 197 |
+
else:
|
| 198 |
+
result = ary
|
| 199 |
+
res.append(result)
|
| 200 |
+
if len(res) == 1:
|
| 201 |
+
return res[0]
|
| 202 |
+
else:
|
| 203 |
+
return tuple(res)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
def _arrays_for_stack_dispatcher(arrays):
|
| 207 |
+
if not hasattr(arrays, "__getitem__"):
|
| 208 |
+
raise TypeError('arrays to stack must be passed as a "sequence" type '
|
| 209 |
+
'such as list or tuple.')
|
| 210 |
+
|
| 211 |
+
return tuple(arrays)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def _vhstack_dispatcher(tup, *, dtype=None, casting=None):
|
| 215 |
+
return _arrays_for_stack_dispatcher(tup)
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
@array_function_dispatch(_vhstack_dispatcher)
|
| 219 |
+
def vstack(tup, *, dtype=None, casting="same_kind"):
|
| 220 |
+
"""
|
| 221 |
+
Stack arrays in sequence vertically (row wise).
|
| 222 |
+
|
| 223 |
+
This is equivalent to concatenation along the first axis after 1-D arrays
|
| 224 |
+
of shape `(N,)` have been reshaped to `(1,N)`. Rebuilds arrays divided by
|
| 225 |
+
`vsplit`.
|
| 226 |
+
|
| 227 |
+
This function makes most sense for arrays with up to 3 dimensions. For
|
| 228 |
+
instance, for pixel-data with a height (first axis), width (second axis),
|
| 229 |
+
and r/g/b channels (third axis). The functions `concatenate`, `stack` and
|
| 230 |
+
`block` provide more general stacking and concatenation operations.
|
| 231 |
+
|
| 232 |
+
Parameters
|
| 233 |
+
----------
|
| 234 |
+
tup : sequence of ndarrays
|
| 235 |
+
The arrays must have the same shape along all but the first axis.
|
| 236 |
+
1-D arrays must have the same length. In the case of a single
|
| 237 |
+
array_like input, it will be treated as a sequence of arrays; i.e.,
|
| 238 |
+
each element along the zeroth axis is treated as a separate array.
|
| 239 |
+
|
| 240 |
+
dtype : str or dtype
|
| 241 |
+
If provided, the destination array will have this dtype. Cannot be
|
| 242 |
+
provided together with `out`.
|
| 243 |
+
|
| 244 |
+
.. versionadded:: 1.24
|
| 245 |
+
|
| 246 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
|
| 247 |
+
Controls what kind of data casting may occur. Defaults to 'same_kind'.
|
| 248 |
+
|
| 249 |
+
.. versionadded:: 1.24
|
| 250 |
+
|
| 251 |
+
Returns
|
| 252 |
+
-------
|
| 253 |
+
stacked : ndarray
|
| 254 |
+
The array formed by stacking the given arrays, will be at least 2-D.
|
| 255 |
+
|
| 256 |
+
See Also
|
| 257 |
+
--------
|
| 258 |
+
concatenate : Join a sequence of arrays along an existing axis.
|
| 259 |
+
stack : Join a sequence of arrays along a new axis.
|
| 260 |
+
block : Assemble an nd-array from nested lists of blocks.
|
| 261 |
+
hstack : Stack arrays in sequence horizontally (column wise).
|
| 262 |
+
dstack : Stack arrays in sequence depth wise (along third axis).
|
| 263 |
+
column_stack : Stack 1-D arrays as columns into a 2-D array.
|
| 264 |
+
vsplit : Split an array into multiple sub-arrays vertically (row-wise).
|
| 265 |
+
unstack : Split an array into a tuple of sub-arrays along an axis.
|
| 266 |
+
|
| 267 |
+
Examples
|
| 268 |
+
--------
|
| 269 |
+
>>> import numpy as np
|
| 270 |
+
>>> a = np.array([1, 2, 3])
|
| 271 |
+
>>> b = np.array([4, 5, 6])
|
| 272 |
+
>>> np.vstack((a,b))
|
| 273 |
+
array([[1, 2, 3],
|
| 274 |
+
[4, 5, 6]])
|
| 275 |
+
|
| 276 |
+
>>> a = np.array([[1], [2], [3]])
|
| 277 |
+
>>> b = np.array([[4], [5], [6]])
|
| 278 |
+
>>> np.vstack((a,b))
|
| 279 |
+
array([[1],
|
| 280 |
+
[2],
|
| 281 |
+
[3],
|
| 282 |
+
[4],
|
| 283 |
+
[5],
|
| 284 |
+
[6]])
|
| 285 |
+
|
| 286 |
+
"""
|
| 287 |
+
arrs = atleast_2d(*tup)
|
| 288 |
+
if not isinstance(arrs, tuple):
|
| 289 |
+
arrs = (arrs,)
|
| 290 |
+
return _nx.concatenate(arrs, 0, dtype=dtype, casting=casting)
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
@array_function_dispatch(_vhstack_dispatcher)
|
| 294 |
+
def hstack(tup, *, dtype=None, casting="same_kind"):
|
| 295 |
+
"""
|
| 296 |
+
Stack arrays in sequence horizontally (column wise).
|
| 297 |
+
|
| 298 |
+
This is equivalent to concatenation along the second axis, except for 1-D
|
| 299 |
+
arrays where it concatenates along the first axis. Rebuilds arrays divided
|
| 300 |
+
by `hsplit`.
|
| 301 |
+
|
| 302 |
+
This function makes most sense for arrays with up to 3 dimensions. For
|
| 303 |
+
instance, for pixel-data with a height (first axis), width (second axis),
|
| 304 |
+
and r/g/b channels (third axis). The functions `concatenate`, `stack` and
|
| 305 |
+
`block` provide more general stacking and concatenation operations.
|
| 306 |
+
|
| 307 |
+
Parameters
|
| 308 |
+
----------
|
| 309 |
+
tup : sequence of ndarrays
|
| 310 |
+
The arrays must have the same shape along all but the second axis,
|
| 311 |
+
except 1-D arrays which can be any length. In the case of a single
|
| 312 |
+
array_like input, it will be treated as a sequence of arrays; i.e.,
|
| 313 |
+
each element along the zeroth axis is treated as a separate array.
|
| 314 |
+
|
| 315 |
+
dtype : str or dtype
|
| 316 |
+
If provided, the destination array will have this dtype. Cannot be
|
| 317 |
+
provided together with `out`.
|
| 318 |
+
|
| 319 |
+
.. versionadded:: 1.24
|
| 320 |
+
|
| 321 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
|
| 322 |
+
Controls what kind of data casting may occur. Defaults to 'same_kind'.
|
| 323 |
+
|
| 324 |
+
.. versionadded:: 1.24
|
| 325 |
+
|
| 326 |
+
Returns
|
| 327 |
+
-------
|
| 328 |
+
stacked : ndarray
|
| 329 |
+
The array formed by stacking the given arrays.
|
| 330 |
+
|
| 331 |
+
See Also
|
| 332 |
+
--------
|
| 333 |
+
concatenate : Join a sequence of arrays along an existing axis.
|
| 334 |
+
stack : Join a sequence of arrays along a new axis.
|
| 335 |
+
block : Assemble an nd-array from nested lists of blocks.
|
| 336 |
+
vstack : Stack arrays in sequence vertically (row wise).
|
| 337 |
+
dstack : Stack arrays in sequence depth wise (along third axis).
|
| 338 |
+
column_stack : Stack 1-D arrays as columns into a 2-D array.
|
| 339 |
+
hsplit : Split an array into multiple sub-arrays
|
| 340 |
+
horizontally (column-wise).
|
| 341 |
+
unstack : Split an array into a tuple of sub-arrays along an axis.
|
| 342 |
+
|
| 343 |
+
Examples
|
| 344 |
+
--------
|
| 345 |
+
>>> import numpy as np
|
| 346 |
+
>>> a = np.array((1,2,3))
|
| 347 |
+
>>> b = np.array((4,5,6))
|
| 348 |
+
>>> np.hstack((a,b))
|
| 349 |
+
array([1, 2, 3, 4, 5, 6])
|
| 350 |
+
>>> a = np.array([[1],[2],[3]])
|
| 351 |
+
>>> b = np.array([[4],[5],[6]])
|
| 352 |
+
>>> np.hstack((a,b))
|
| 353 |
+
array([[1, 4],
|
| 354 |
+
[2, 5],
|
| 355 |
+
[3, 6]])
|
| 356 |
+
|
| 357 |
+
"""
|
| 358 |
+
arrs = atleast_1d(*tup)
|
| 359 |
+
if not isinstance(arrs, tuple):
|
| 360 |
+
arrs = (arrs,)
|
| 361 |
+
# As a special case, dimension 0 of 1-dimensional arrays is "horizontal"
|
| 362 |
+
if arrs and arrs[0].ndim == 1:
|
| 363 |
+
return _nx.concatenate(arrs, 0, dtype=dtype, casting=casting)
|
| 364 |
+
else:
|
| 365 |
+
return _nx.concatenate(arrs, 1, dtype=dtype, casting=casting)
|
| 366 |
+
|
| 367 |
+
|
| 368 |
+
def _stack_dispatcher(arrays, axis=None, out=None, *,
|
| 369 |
+
dtype=None, casting=None):
|
| 370 |
+
arrays = _arrays_for_stack_dispatcher(arrays)
|
| 371 |
+
if out is not None:
|
| 372 |
+
# optimize for the typical case where only arrays is provided
|
| 373 |
+
arrays = list(arrays)
|
| 374 |
+
arrays.append(out)
|
| 375 |
+
return arrays
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
@array_function_dispatch(_stack_dispatcher)
|
| 379 |
+
def stack(arrays, axis=0, out=None, *, dtype=None, casting="same_kind"):
|
| 380 |
+
"""
|
| 381 |
+
Join a sequence of arrays along a new axis.
|
| 382 |
+
|
| 383 |
+
The ``axis`` parameter specifies the index of the new axis in the
|
| 384 |
+
dimensions of the result. For example, if ``axis=0`` it will be the first
|
| 385 |
+
dimension and if ``axis=-1`` it will be the last dimension.
|
| 386 |
+
|
| 387 |
+
Parameters
|
| 388 |
+
----------
|
| 389 |
+
arrays : sequence of ndarrays
|
| 390 |
+
Each array must have the same shape. In the case of a single ndarray
|
| 391 |
+
array_like input, it will be treated as a sequence of arrays; i.e.,
|
| 392 |
+
each element along the zeroth axis is treated as a separate array.
|
| 393 |
+
|
| 394 |
+
axis : int, optional
|
| 395 |
+
The axis in the result array along which the input arrays are stacked.
|
| 396 |
+
|
| 397 |
+
out : ndarray, optional
|
| 398 |
+
If provided, the destination to place the result. The shape must be
|
| 399 |
+
correct, matching that of what stack would have returned if no
|
| 400 |
+
out argument were specified.
|
| 401 |
+
|
| 402 |
+
dtype : str or dtype
|
| 403 |
+
If provided, the destination array will have this dtype. Cannot be
|
| 404 |
+
provided together with `out`.
|
| 405 |
+
|
| 406 |
+
.. versionadded:: 1.24
|
| 407 |
+
|
| 408 |
+
casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
|
| 409 |
+
Controls what kind of data casting may occur. Defaults to 'same_kind'.
|
| 410 |
+
|
| 411 |
+
.. versionadded:: 1.24
|
| 412 |
+
|
| 413 |
+
|
| 414 |
+
Returns
|
| 415 |
+
-------
|
| 416 |
+
stacked : ndarray
|
| 417 |
+
The stacked array has one more dimension than the input arrays.
|
| 418 |
+
|
| 419 |
+
See Also
|
| 420 |
+
--------
|
| 421 |
+
concatenate : Join a sequence of arrays along an existing axis.
|
| 422 |
+
block : Assemble an nd-array from nested lists of blocks.
|
| 423 |
+
split : Split array into a list of multiple sub-arrays of equal size.
|
| 424 |
+
unstack : Split an array into a tuple of sub-arrays along an axis.
|
| 425 |
+
|
| 426 |
+
Examples
|
| 427 |
+
--------
|
| 428 |
+
>>> import numpy as np
|
| 429 |
+
>>> rng = np.random.default_rng()
|
| 430 |
+
>>> arrays = [rng.normal(size=(3,4)) for _ in range(10)]
|
| 431 |
+
>>> np.stack(arrays, axis=0).shape
|
| 432 |
+
(10, 3, 4)
|
| 433 |
+
|
| 434 |
+
>>> np.stack(arrays, axis=1).shape
|
| 435 |
+
(3, 10, 4)
|
| 436 |
+
|
| 437 |
+
>>> np.stack(arrays, axis=2).shape
|
| 438 |
+
(3, 4, 10)
|
| 439 |
+
|
| 440 |
+
>>> a = np.array([1, 2, 3])
|
| 441 |
+
>>> b = np.array([4, 5, 6])
|
| 442 |
+
>>> np.stack((a, b))
|
| 443 |
+
array([[1, 2, 3],
|
| 444 |
+
[4, 5, 6]])
|
| 445 |
+
|
| 446 |
+
>>> np.stack((a, b), axis=-1)
|
| 447 |
+
array([[1, 4],
|
| 448 |
+
[2, 5],
|
| 449 |
+
[3, 6]])
|
| 450 |
+
|
| 451 |
+
"""
|
| 452 |
+
arrays = [asanyarray(arr) for arr in arrays]
|
| 453 |
+
if not arrays:
|
| 454 |
+
raise ValueError('need at least one array to stack')
|
| 455 |
+
|
| 456 |
+
shapes = {arr.shape for arr in arrays}
|
| 457 |
+
if len(shapes) != 1:
|
| 458 |
+
raise ValueError('all input arrays must have the same shape')
|
| 459 |
+
|
| 460 |
+
result_ndim = arrays[0].ndim + 1
|
| 461 |
+
axis = normalize_axis_index(axis, result_ndim)
|
| 462 |
+
|
| 463 |
+
sl = (slice(None),) * axis + (_nx.newaxis,)
|
| 464 |
+
expanded_arrays = [arr[sl] for arr in arrays]
|
| 465 |
+
return _nx.concatenate(expanded_arrays, axis=axis, out=out,
|
| 466 |
+
dtype=dtype, casting=casting)
|
| 467 |
+
|
| 468 |
+
def _unstack_dispatcher(x, /, *, axis=None):
|
| 469 |
+
return (x,)
|
| 470 |
+
|
| 471 |
+
@array_function_dispatch(_unstack_dispatcher)
|
| 472 |
+
def unstack(x, /, *, axis=0):
|
| 473 |
+
"""
|
| 474 |
+
Split an array into a sequence of arrays along the given axis.
|
| 475 |
+
|
| 476 |
+
The ``axis`` parameter specifies the dimension along which the array will
|
| 477 |
+
be split. For example, if ``axis=0`` (the default) it will be the first
|
| 478 |
+
dimension and if ``axis=-1`` it will be the last dimension.
|
| 479 |
+
|
| 480 |
+
The result is a tuple of arrays split along ``axis``.
|
| 481 |
+
|
| 482 |
+
.. versionadded:: 2.1.0
|
| 483 |
+
|
| 484 |
+
Parameters
|
| 485 |
+
----------
|
| 486 |
+
x : ndarray
|
| 487 |
+
The array to be unstacked.
|
| 488 |
+
axis : int, optional
|
| 489 |
+
Axis along which the array will be split. Default: ``0``.
|
| 490 |
+
|
| 491 |
+
Returns
|
| 492 |
+
-------
|
| 493 |
+
unstacked : tuple of ndarrays
|
| 494 |
+
The unstacked arrays.
|
| 495 |
+
|
| 496 |
+
See Also
|
| 497 |
+
--------
|
| 498 |
+
stack : Join a sequence of arrays along a new axis.
|
| 499 |
+
concatenate : Join a sequence of arrays along an existing axis.
|
| 500 |
+
block : Assemble an nd-array from nested lists of blocks.
|
| 501 |
+
split : Split array into a list of multiple sub-arrays of equal size.
|
| 502 |
+
|
| 503 |
+
Notes
|
| 504 |
+
-----
|
| 505 |
+
``unstack`` serves as the reverse operation of :py:func:`stack`, i.e.,
|
| 506 |
+
``stack(unstack(x, axis=axis), axis=axis) == x``.
|
| 507 |
+
|
| 508 |
+
This function is equivalent to ``tuple(np.moveaxis(x, axis, 0))``, since
|
| 509 |
+
iterating on an array iterates along the first axis.
|
| 510 |
+
|
| 511 |
+
Examples
|
| 512 |
+
--------
|
| 513 |
+
>>> arr = np.arange(24).reshape((2, 3, 4))
|
| 514 |
+
>>> np.unstack(arr)
|
| 515 |
+
(array([[ 0, 1, 2, 3],
|
| 516 |
+
[ 4, 5, 6, 7],
|
| 517 |
+
[ 8, 9, 10, 11]]),
|
| 518 |
+
array([[12, 13, 14, 15],
|
| 519 |
+
[16, 17, 18, 19],
|
| 520 |
+
[20, 21, 22, 23]]))
|
| 521 |
+
>>> np.unstack(arr, axis=1)
|
| 522 |
+
(array([[ 0, 1, 2, 3],
|
| 523 |
+
[12, 13, 14, 15]]),
|
| 524 |
+
array([[ 4, 5, 6, 7],
|
| 525 |
+
[16, 17, 18, 19]]),
|
| 526 |
+
array([[ 8, 9, 10, 11],
|
| 527 |
+
[20, 21, 22, 23]]))
|
| 528 |
+
>>> arr2 = np.stack(np.unstack(arr, axis=1), axis=1)
|
| 529 |
+
>>> arr2.shape
|
| 530 |
+
(2, 3, 4)
|
| 531 |
+
>>> np.all(arr == arr2)
|
| 532 |
+
np.True_
|
| 533 |
+
|
| 534 |
+
"""
|
| 535 |
+
if x.ndim == 0:
|
| 536 |
+
raise ValueError("Input array must be at least 1-d.")
|
| 537 |
+
return tuple(_nx.moveaxis(x, axis, 0))
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
# Internal functions to eliminate the overhead of repeated dispatch in one of
|
| 541 |
+
# the two possible paths inside np.block.
|
| 542 |
+
# Use getattr to protect against __array_function__ being disabled.
|
| 543 |
+
_size = getattr(_from_nx.size, '__wrapped__', _from_nx.size)
|
| 544 |
+
_ndim = getattr(_from_nx.ndim, '__wrapped__', _from_nx.ndim)
|
| 545 |
+
_concatenate = getattr(_from_nx.concatenate,
|
| 546 |
+
'__wrapped__', _from_nx.concatenate)
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
def _block_format_index(index):
|
| 550 |
+
"""
|
| 551 |
+
Convert a list of indices ``[0, 1, 2]`` into ``"arrays[0][1][2]"``.
|
| 552 |
+
"""
|
| 553 |
+
idx_str = ''.join(f'[{i}]' for i in index if i is not None)
|
| 554 |
+
return 'arrays' + idx_str
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
def _block_check_depths_match(arrays, parent_index=[]):
|
| 558 |
+
"""
|
| 559 |
+
Recursive function checking that the depths of nested lists in `arrays`
|
| 560 |
+
all match. Mismatch raises a ValueError as described in the block
|
| 561 |
+
docstring below.
|
| 562 |
+
|
| 563 |
+
The entire index (rather than just the depth) needs to be calculated
|
| 564 |
+
for each innermost list, in case an error needs to be raised, so that
|
| 565 |
+
the index of the offending list can be printed as part of the error.
|
| 566 |
+
|
| 567 |
+
Parameters
|
| 568 |
+
----------
|
| 569 |
+
arrays : nested list of arrays
|
| 570 |
+
The arrays to check
|
| 571 |
+
parent_index : list of int
|
| 572 |
+
The full index of `arrays` within the nested lists passed to
|
| 573 |
+
`_block_check_depths_match` at the top of the recursion.
|
| 574 |
+
|
| 575 |
+
Returns
|
| 576 |
+
-------
|
| 577 |
+
first_index : list of int
|
| 578 |
+
The full index of an element from the bottom of the nesting in
|
| 579 |
+
`arrays`. If any element at the bottom is an empty list, this will
|
| 580 |
+
refer to it, and the last index along the empty axis will be None.
|
| 581 |
+
max_arr_ndim : int
|
| 582 |
+
The maximum of the ndims of the arrays nested in `arrays`.
|
| 583 |
+
final_size: int
|
| 584 |
+
The number of elements in the final array. This is used the motivate
|
| 585 |
+
the choice of algorithm used using benchmarking wisdom.
|
| 586 |
+
|
| 587 |
+
"""
|
| 588 |
+
if isinstance(arrays, tuple):
|
| 589 |
+
# not strictly necessary, but saves us from:
|
| 590 |
+
# - more than one way to do things - no point treating tuples like
|
| 591 |
+
# lists
|
| 592 |
+
# - horribly confusing behaviour that results when tuples are
|
| 593 |
+
# treated like ndarray
|
| 594 |
+
raise TypeError(
|
| 595 |
+
f'{_block_format_index(parent_index)} is a tuple. '
|
| 596 |
+
'Only lists can be used to arrange blocks, and np.block does '
|
| 597 |
+
'not allow implicit conversion from tuple to ndarray.'
|
| 598 |
+
)
|
| 599 |
+
elif isinstance(arrays, list) and len(arrays) > 0:
|
| 600 |
+
idxs_ndims = (_block_check_depths_match(arr, parent_index + [i])
|
| 601 |
+
for i, arr in enumerate(arrays))
|
| 602 |
+
|
| 603 |
+
first_index, max_arr_ndim, final_size = next(idxs_ndims)
|
| 604 |
+
for index, ndim, size in idxs_ndims:
|
| 605 |
+
final_size += size
|
| 606 |
+
if ndim > max_arr_ndim:
|
| 607 |
+
max_arr_ndim = ndim
|
| 608 |
+
if len(index) != len(first_index):
|
| 609 |
+
raise ValueError(
|
| 610 |
+
"List depths are mismatched. First element was at "
|
| 611 |
+
f"depth {len(first_index)}, but there is an element at "
|
| 612 |
+
f"depth {len(index)} ({_block_format_index(index)})"
|
| 613 |
+
)
|
| 614 |
+
# propagate our flag that indicates an empty list at the bottom
|
| 615 |
+
if index[-1] is None:
|
| 616 |
+
first_index = index
|
| 617 |
+
|
| 618 |
+
return first_index, max_arr_ndim, final_size
|
| 619 |
+
elif isinstance(arrays, list) and len(arrays) == 0:
|
| 620 |
+
# We've 'bottomed out' on an empty list
|
| 621 |
+
return parent_index + [None], 0, 0
|
| 622 |
+
else:
|
| 623 |
+
# We've 'bottomed out' - arrays is either a scalar or an array
|
| 624 |
+
size = _size(arrays)
|
| 625 |
+
return parent_index, _ndim(arrays), size
|
| 626 |
+
|
| 627 |
+
|
| 628 |
+
def _atleast_nd(a, ndim):
|
| 629 |
+
# Ensures `a` has at least `ndim` dimensions by prepending
|
| 630 |
+
# ones to `a.shape` as necessary
|
| 631 |
+
return array(a, ndmin=ndim, copy=None, subok=True)
|
| 632 |
+
|
| 633 |
+
|
| 634 |
+
def _accumulate(values):
|
| 635 |
+
return list(itertools.accumulate(values))
|
| 636 |
+
|
| 637 |
+
|
| 638 |
+
def _concatenate_shapes(shapes, axis):
|
| 639 |
+
"""Given array shapes, return the resulting shape and slices prefixes.
|
| 640 |
+
|
| 641 |
+
These help in nested concatenation.
|
| 642 |
+
|
| 643 |
+
Returns
|
| 644 |
+
-------
|
| 645 |
+
shape: tuple of int
|
| 646 |
+
This tuple satisfies::
|
| 647 |
+
|
| 648 |
+
shape, _ = _concatenate_shapes([arr.shape for shape in arrs], axis)
|
| 649 |
+
shape == concatenate(arrs, axis).shape
|
| 650 |
+
|
| 651 |
+
slice_prefixes: tuple of (slice(start, end), )
|
| 652 |
+
For a list of arrays being concatenated, this returns the slice
|
| 653 |
+
in the larger array at axis that needs to be sliced into.
|
| 654 |
+
|
| 655 |
+
For example, the following holds::
|
| 656 |
+
|
| 657 |
+
ret = concatenate([a, b, c], axis)
|
| 658 |
+
_, (sl_a, sl_b, sl_c) = concatenate_slices([a, b, c], axis)
|
| 659 |
+
|
| 660 |
+
ret[(slice(None),) * axis + sl_a] == a
|
| 661 |
+
ret[(slice(None),) * axis + sl_b] == b
|
| 662 |
+
ret[(slice(None),) * axis + sl_c] == c
|
| 663 |
+
|
| 664 |
+
These are called slice prefixes since they are used in the recursive
|
| 665 |
+
blocking algorithm to compute the left-most slices during the
|
| 666 |
+
recursion. Therefore, they must be prepended to rest of the slice
|
| 667 |
+
that was computed deeper in the recursion.
|
| 668 |
+
|
| 669 |
+
These are returned as tuples to ensure that they can quickly be added
|
| 670 |
+
to existing slice tuple without creating a new tuple every time.
|
| 671 |
+
|
| 672 |
+
"""
|
| 673 |
+
# Cache a result that will be reused.
|
| 674 |
+
shape_at_axis = [shape[axis] for shape in shapes]
|
| 675 |
+
|
| 676 |
+
# Take a shape, any shape
|
| 677 |
+
first_shape = shapes[0]
|
| 678 |
+
first_shape_pre = first_shape[:axis]
|
| 679 |
+
first_shape_post = first_shape[axis + 1:]
|
| 680 |
+
|
| 681 |
+
if any(shape[:axis] != first_shape_pre or
|
| 682 |
+
shape[axis + 1:] != first_shape_post for shape in shapes):
|
| 683 |
+
raise ValueError(
|
| 684 |
+
f'Mismatched array shapes in block along axis {axis}.')
|
| 685 |
+
|
| 686 |
+
shape = (first_shape_pre + (sum(shape_at_axis),) + first_shape[axis + 1:])
|
| 687 |
+
|
| 688 |
+
offsets_at_axis = _accumulate(shape_at_axis)
|
| 689 |
+
slice_prefixes = [(slice(start, end),)
|
| 690 |
+
for start, end in zip([0] + offsets_at_axis,
|
| 691 |
+
offsets_at_axis)]
|
| 692 |
+
return shape, slice_prefixes
|
| 693 |
+
|
| 694 |
+
|
| 695 |
+
def _block_info_recursion(arrays, max_depth, result_ndim, depth=0):
|
| 696 |
+
"""
|
| 697 |
+
Returns the shape of the final array, along with a list
|
| 698 |
+
of slices and a list of arrays that can be used for assignment inside the
|
| 699 |
+
new array
|
| 700 |
+
|
| 701 |
+
Parameters
|
| 702 |
+
----------
|
| 703 |
+
arrays : nested list of arrays
|
| 704 |
+
The arrays to check
|
| 705 |
+
max_depth : list of int
|
| 706 |
+
The number of nested lists
|
| 707 |
+
result_ndim : int
|
| 708 |
+
The number of dimensions in thefinal array.
|
| 709 |
+
|
| 710 |
+
Returns
|
| 711 |
+
-------
|
| 712 |
+
shape : tuple of int
|
| 713 |
+
The shape that the final array will take on.
|
| 714 |
+
slices: list of tuple of slices
|
| 715 |
+
The slices into the full array required for assignment. These are
|
| 716 |
+
required to be prepended with ``(Ellipsis, )`` to obtain to correct
|
| 717 |
+
final index.
|
| 718 |
+
arrays: list of ndarray
|
| 719 |
+
The data to assign to each slice of the full array
|
| 720 |
+
|
| 721 |
+
"""
|
| 722 |
+
if depth < max_depth:
|
| 723 |
+
shapes, slices, arrays = zip(
|
| 724 |
+
*[_block_info_recursion(arr, max_depth, result_ndim, depth + 1)
|
| 725 |
+
for arr in arrays])
|
| 726 |
+
|
| 727 |
+
axis = result_ndim - max_depth + depth
|
| 728 |
+
shape, slice_prefixes = _concatenate_shapes(shapes, axis)
|
| 729 |
+
|
| 730 |
+
# Prepend the slice prefix and flatten the slices
|
| 731 |
+
slices = [slice_prefix + the_slice
|
| 732 |
+
for slice_prefix, inner_slices in zip(slice_prefixes, slices)
|
| 733 |
+
for the_slice in inner_slices]
|
| 734 |
+
|
| 735 |
+
# Flatten the array list
|
| 736 |
+
arrays = functools.reduce(operator.add, arrays)
|
| 737 |
+
|
| 738 |
+
return shape, slices, arrays
|
| 739 |
+
else:
|
| 740 |
+
# We've 'bottomed out' - arrays is either a scalar or an array
|
| 741 |
+
# type(arrays) is not list
|
| 742 |
+
# Return the slice and the array inside a list to be consistent with
|
| 743 |
+
# the recursive case.
|
| 744 |
+
arr = _atleast_nd(arrays, result_ndim)
|
| 745 |
+
return arr.shape, [()], [arr]
|
| 746 |
+
|
| 747 |
+
|
| 748 |
+
def _block(arrays, max_depth, result_ndim, depth=0):
|
| 749 |
+
"""
|
| 750 |
+
Internal implementation of block based on repeated concatenation.
|
| 751 |
+
`arrays` is the argument passed to
|
| 752 |
+
block. `max_depth` is the depth of nested lists within `arrays` and
|
| 753 |
+
`result_ndim` is the greatest of the dimensions of the arrays in
|
| 754 |
+
`arrays` and the depth of the lists in `arrays` (see block docstring
|
| 755 |
+
for details).
|
| 756 |
+
"""
|
| 757 |
+
if depth < max_depth:
|
| 758 |
+
arrs = [_block(arr, max_depth, result_ndim, depth + 1)
|
| 759 |
+
for arr in arrays]
|
| 760 |
+
return _concatenate(arrs, axis=-(max_depth - depth))
|
| 761 |
+
else:
|
| 762 |
+
# We've 'bottomed out' - arrays is either a scalar or an array
|
| 763 |
+
# type(arrays) is not list
|
| 764 |
+
return _atleast_nd(arrays, result_ndim)
|
| 765 |
+
|
| 766 |
+
|
| 767 |
+
def _block_dispatcher(arrays):
|
| 768 |
+
# Use type(...) is list to match the behavior of np.block(), which special
|
| 769 |
+
# cases list specifically rather than allowing for generic iterables or
|
| 770 |
+
# tuple. Also, we know that list.__array_function__ will never exist.
|
| 771 |
+
if isinstance(arrays, list):
|
| 772 |
+
for subarrays in arrays:
|
| 773 |
+
yield from _block_dispatcher(subarrays)
|
| 774 |
+
else:
|
| 775 |
+
yield arrays
|
| 776 |
+
|
| 777 |
+
|
| 778 |
+
@array_function_dispatch(_block_dispatcher)
|
| 779 |
+
def block(arrays):
|
| 780 |
+
"""
|
| 781 |
+
Assemble an nd-array from nested lists of blocks.
|
| 782 |
+
|
| 783 |
+
Blocks in the innermost lists are concatenated (see `concatenate`) along
|
| 784 |
+
the last dimension (-1), then these are concatenated along the
|
| 785 |
+
second-last dimension (-2), and so on until the outermost list is reached.
|
| 786 |
+
|
| 787 |
+
Blocks can be of any dimension, but will not be broadcasted using
|
| 788 |
+
the normal rules. Instead, leading axes of size 1 are inserted,
|
| 789 |
+
to make ``block.ndim`` the same for all blocks. This is primarily useful
|
| 790 |
+
for working with scalars, and means that code like ``np.block([v, 1])``
|
| 791 |
+
is valid, where ``v.ndim == 1``.
|
| 792 |
+
|
| 793 |
+
When the nested list is two levels deep, this allows block matrices to be
|
| 794 |
+
constructed from their components.
|
| 795 |
+
|
| 796 |
+
Parameters
|
| 797 |
+
----------
|
| 798 |
+
arrays : nested list of array_like or scalars (but not tuples)
|
| 799 |
+
If passed a single ndarray or scalar (a nested list of depth 0), this
|
| 800 |
+
is returned unmodified (and not copied).
|
| 801 |
+
|
| 802 |
+
Elements shapes must match along the appropriate axes (without
|
| 803 |
+
broadcasting), but leading 1s will be prepended to the shape as
|
| 804 |
+
necessary to make the dimensions match.
|
| 805 |
+
|
| 806 |
+
Returns
|
| 807 |
+
-------
|
| 808 |
+
block_array : ndarray
|
| 809 |
+
The array assembled from the given blocks.
|
| 810 |
+
|
| 811 |
+
The dimensionality of the output is equal to the greatest of:
|
| 812 |
+
|
| 813 |
+
* the dimensionality of all the inputs
|
| 814 |
+
* the depth to which the input list is nested
|
| 815 |
+
|
| 816 |
+
Raises
|
| 817 |
+
------
|
| 818 |
+
ValueError
|
| 819 |
+
* If list depths are mismatched - for instance, ``[[a, b], c]`` is
|
| 820 |
+
illegal, and should be spelt ``[[a, b], [c]]``
|
| 821 |
+
* If lists are empty - for instance, ``[[a, b], []]``
|
| 822 |
+
|
| 823 |
+
See Also
|
| 824 |
+
--------
|
| 825 |
+
concatenate : Join a sequence of arrays along an existing axis.
|
| 826 |
+
stack : Join a sequence of arrays along a new axis.
|
| 827 |
+
vstack : Stack arrays in sequence vertically (row wise).
|
| 828 |
+
hstack : Stack arrays in sequence horizontally (column wise).
|
| 829 |
+
dstack : Stack arrays in sequence depth wise (along third axis).
|
| 830 |
+
column_stack : Stack 1-D arrays as columns into a 2-D array.
|
| 831 |
+
vsplit : Split an array into multiple sub-arrays vertically (row-wise).
|
| 832 |
+
unstack : Split an array into a tuple of sub-arrays along an axis.
|
| 833 |
+
|
| 834 |
+
Notes
|
| 835 |
+
-----
|
| 836 |
+
When called with only scalars, ``np.block`` is equivalent to an ndarray
|
| 837 |
+
call. So ``np.block([[1, 2], [3, 4]])`` is equivalent to
|
| 838 |
+
``np.array([[1, 2], [3, 4]])``.
|
| 839 |
+
|
| 840 |
+
This function does not enforce that the blocks lie on a fixed grid.
|
| 841 |
+
``np.block([[a, b], [c, d]])`` is not restricted to arrays of the form::
|
| 842 |
+
|
| 843 |
+
AAAbb
|
| 844 |
+
AAAbb
|
| 845 |
+
cccDD
|
| 846 |
+
|
| 847 |
+
But is also allowed to produce, for some ``a, b, c, d``::
|
| 848 |
+
|
| 849 |
+
AAAbb
|
| 850 |
+
AAAbb
|
| 851 |
+
cDDDD
|
| 852 |
+
|
| 853 |
+
Since concatenation happens along the last axis first, `block` is *not*
|
| 854 |
+
capable of producing the following directly::
|
| 855 |
+
|
| 856 |
+
AAAbb
|
| 857 |
+
cccbb
|
| 858 |
+
cccDD
|
| 859 |
+
|
| 860 |
+
Matlab's "square bracket stacking", ``[A, B, ...; p, q, ...]``, is
|
| 861 |
+
equivalent to ``np.block([[A, B, ...], [p, q, ...]])``.
|
| 862 |
+
|
| 863 |
+
Examples
|
| 864 |
+
--------
|
| 865 |
+
The most common use of this function is to build a block matrix:
|
| 866 |
+
|
| 867 |
+
>>> import numpy as np
|
| 868 |
+
>>> A = np.eye(2) * 2
|
| 869 |
+
>>> B = np.eye(3) * 3
|
| 870 |
+
>>> np.block([
|
| 871 |
+
... [A, np.zeros((2, 3))],
|
| 872 |
+
... [np.ones((3, 2)), B ]
|
| 873 |
+
... ])
|
| 874 |
+
array([[2., 0., 0., 0., 0.],
|
| 875 |
+
[0., 2., 0., 0., 0.],
|
| 876 |
+
[1., 1., 3., 0., 0.],
|
| 877 |
+
[1., 1., 0., 3., 0.],
|
| 878 |
+
[1., 1., 0., 0., 3.]])
|
| 879 |
+
|
| 880 |
+
With a list of depth 1, `block` can be used as `hstack`:
|
| 881 |
+
|
| 882 |
+
>>> np.block([1, 2, 3]) # hstack([1, 2, 3])
|
| 883 |
+
array([1, 2, 3])
|
| 884 |
+
|
| 885 |
+
>>> a = np.array([1, 2, 3])
|
| 886 |
+
>>> b = np.array([4, 5, 6])
|
| 887 |
+
>>> np.block([a, b, 10]) # hstack([a, b, 10])
|
| 888 |
+
array([ 1, 2, 3, 4, 5, 6, 10])
|
| 889 |
+
|
| 890 |
+
>>> A = np.ones((2, 2), int)
|
| 891 |
+
>>> B = 2 * A
|
| 892 |
+
>>> np.block([A, B]) # hstack([A, B])
|
| 893 |
+
array([[1, 1, 2, 2],
|
| 894 |
+
[1, 1, 2, 2]])
|
| 895 |
+
|
| 896 |
+
With a list of depth 2, `block` can be used in place of `vstack`:
|
| 897 |
+
|
| 898 |
+
>>> a = np.array([1, 2, 3])
|
| 899 |
+
>>> b = np.array([4, 5, 6])
|
| 900 |
+
>>> np.block([[a], [b]]) # vstack([a, b])
|
| 901 |
+
array([[1, 2, 3],
|
| 902 |
+
[4, 5, 6]])
|
| 903 |
+
|
| 904 |
+
>>> A = np.ones((2, 2), int)
|
| 905 |
+
>>> B = 2 * A
|
| 906 |
+
>>> np.block([[A], [B]]) # vstack([A, B])
|
| 907 |
+
array([[1, 1],
|
| 908 |
+
[1, 1],
|
| 909 |
+
[2, 2],
|
| 910 |
+
[2, 2]])
|
| 911 |
+
|
| 912 |
+
It can also be used in place of `atleast_1d` and `atleast_2d`:
|
| 913 |
+
|
| 914 |
+
>>> a = np.array(0)
|
| 915 |
+
>>> b = np.array([1])
|
| 916 |
+
>>> np.block([a]) # atleast_1d(a)
|
| 917 |
+
array([0])
|
| 918 |
+
>>> np.block([b]) # atleast_1d(b)
|
| 919 |
+
array([1])
|
| 920 |
+
|
| 921 |
+
>>> np.block([[a]]) # atleast_2d(a)
|
| 922 |
+
array([[0]])
|
| 923 |
+
>>> np.block([[b]]) # atleast_2d(b)
|
| 924 |
+
array([[1]])
|
| 925 |
+
|
| 926 |
+
|
| 927 |
+
"""
|
| 928 |
+
arrays, list_ndim, result_ndim, final_size = _block_setup(arrays)
|
| 929 |
+
|
| 930 |
+
# It was found through benchmarking that making an array of final size
|
| 931 |
+
# around 256x256 was faster by straight concatenation on a
|
| 932 |
+
# i7-7700HQ processor and dual channel ram 2400MHz.
|
| 933 |
+
# It didn't seem to matter heavily on the dtype used.
|
| 934 |
+
#
|
| 935 |
+
# A 2D array using repeated concatenation requires 2 copies of the array.
|
| 936 |
+
#
|
| 937 |
+
# The fastest algorithm will depend on the ratio of CPU power to memory
|
| 938 |
+
# speed.
|
| 939 |
+
# One can monitor the results of the benchmark
|
| 940 |
+
# https://pv.github.io/numpy-bench/#bench_shape_base.Block2D.time_block2d
|
| 941 |
+
# to tune this parameter until a C version of the `_block_info_recursion`
|
| 942 |
+
# algorithm is implemented which would likely be faster than the python
|
| 943 |
+
# version.
|
| 944 |
+
if list_ndim * final_size > (2 * 512 * 512):
|
| 945 |
+
return _block_slicing(arrays, list_ndim, result_ndim)
|
| 946 |
+
else:
|
| 947 |
+
return _block_concatenate(arrays, list_ndim, result_ndim)
|
| 948 |
+
|
| 949 |
+
|
| 950 |
+
# These helper functions are mostly used for testing.
|
| 951 |
+
# They allow us to write tests that directly call `_block_slicing`
|
| 952 |
+
# or `_block_concatenate` without blocking large arrays to force the wisdom
|
| 953 |
+
# to trigger the desired path.
|
| 954 |
+
def _block_setup(arrays):
|
| 955 |
+
"""
|
| 956 |
+
Returns
|
| 957 |
+
(`arrays`, list_ndim, result_ndim, final_size)
|
| 958 |
+
"""
|
| 959 |
+
bottom_index, arr_ndim, final_size = _block_check_depths_match(arrays)
|
| 960 |
+
list_ndim = len(bottom_index)
|
| 961 |
+
if bottom_index and bottom_index[-1] is None:
|
| 962 |
+
raise ValueError(
|
| 963 |
+
f'List at {_block_format_index(bottom_index)} cannot be empty'
|
| 964 |
+
)
|
| 965 |
+
result_ndim = max(arr_ndim, list_ndim)
|
| 966 |
+
return arrays, list_ndim, result_ndim, final_size
|
| 967 |
+
|
| 968 |
+
|
| 969 |
+
def _block_slicing(arrays, list_ndim, result_ndim):
|
| 970 |
+
shape, slices, arrays = _block_info_recursion(
|
| 971 |
+
arrays, list_ndim, result_ndim)
|
| 972 |
+
dtype = _nx.result_type(*[arr.dtype for arr in arrays])
|
| 973 |
+
|
| 974 |
+
# Test preferring F only in the case that all input arrays are F
|
| 975 |
+
F_order = all(arr.flags['F_CONTIGUOUS'] for arr in arrays)
|
| 976 |
+
C_order = all(arr.flags['C_CONTIGUOUS'] for arr in arrays)
|
| 977 |
+
order = 'F' if F_order and not C_order else 'C'
|
| 978 |
+
result = _nx.empty(shape=shape, dtype=dtype, order=order)
|
| 979 |
+
# Note: In a c implementation, the function
|
| 980 |
+
# PyArray_CreateMultiSortedStridePerm could be used for more advanced
|
| 981 |
+
# guessing of the desired order.
|
| 982 |
+
|
| 983 |
+
for the_slice, arr in zip(slices, arrays):
|
| 984 |
+
result[(Ellipsis,) + the_slice] = arr
|
| 985 |
+
return result
|
| 986 |
+
|
| 987 |
+
|
| 988 |
+
def _block_concatenate(arrays, list_ndim, result_ndim):
|
| 989 |
+
result = _block(arrays, list_ndim, result_ndim)
|
| 990 |
+
if list_ndim == 0:
|
| 991 |
+
# Catch an edge case where _block returns a view because
|
| 992 |
+
# `arrays` is a single numpy array and not a list of numpy arrays.
|
| 993 |
+
# This might copy scalars or lists twice, but this isn't a likely
|
| 994 |
+
# usecase for those interested in performance
|
| 995 |
+
result = result.copy()
|
| 996 |
+
return result
|
v12x/pylib/numpy/_core/strings.py
ADDED
|
@@ -0,0 +1,1813 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module contains a set of functions for vectorized string
|
| 3 |
+
operations.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import functools
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
from numpy import (
|
| 11 |
+
add,
|
| 12 |
+
equal,
|
| 13 |
+
greater,
|
| 14 |
+
greater_equal,
|
| 15 |
+
less,
|
| 16 |
+
less_equal,
|
| 17 |
+
multiply as _multiply_ufunc,
|
| 18 |
+
not_equal,
|
| 19 |
+
)
|
| 20 |
+
from numpy._core.multiarray import _vec_string
|
| 21 |
+
from numpy._core.overrides import array_function_dispatch, set_module
|
| 22 |
+
from numpy._core.umath import (
|
| 23 |
+
_center,
|
| 24 |
+
_expandtabs,
|
| 25 |
+
_expandtabs_length,
|
| 26 |
+
_ljust,
|
| 27 |
+
_lstrip_chars,
|
| 28 |
+
_lstrip_whitespace,
|
| 29 |
+
_partition,
|
| 30 |
+
_partition_index,
|
| 31 |
+
_replace,
|
| 32 |
+
_rjust,
|
| 33 |
+
_rpartition,
|
| 34 |
+
_rpartition_index,
|
| 35 |
+
_rstrip_chars,
|
| 36 |
+
_rstrip_whitespace,
|
| 37 |
+
_slice,
|
| 38 |
+
_strip_chars,
|
| 39 |
+
_strip_whitespace,
|
| 40 |
+
_zfill,
|
| 41 |
+
count as _count_ufunc,
|
| 42 |
+
endswith as _endswith_ufunc,
|
| 43 |
+
find as _find_ufunc,
|
| 44 |
+
index as _index_ufunc,
|
| 45 |
+
isalnum,
|
| 46 |
+
isalpha,
|
| 47 |
+
isdecimal,
|
| 48 |
+
isdigit,
|
| 49 |
+
islower,
|
| 50 |
+
isnumeric,
|
| 51 |
+
isspace,
|
| 52 |
+
istitle,
|
| 53 |
+
isupper,
|
| 54 |
+
rfind as _rfind_ufunc,
|
| 55 |
+
rindex as _rindex_ufunc,
|
| 56 |
+
startswith as _startswith_ufunc,
|
| 57 |
+
str_len,
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def _override___module__():
|
| 62 |
+
for ufunc in [
|
| 63 |
+
isalnum, isalpha, isdecimal, isdigit, islower, isnumeric, isspace,
|
| 64 |
+
istitle, isupper, str_len,
|
| 65 |
+
]:
|
| 66 |
+
ufunc.__module__ = "numpy.strings"
|
| 67 |
+
ufunc.__qualname__ = ufunc.__name__
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
_override___module__()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
__all__ = [
|
| 74 |
+
# UFuncs
|
| 75 |
+
"equal", "not_equal", "less", "less_equal", "greater", "greater_equal",
|
| 76 |
+
"add", "multiply", "isalpha", "isdigit", "isspace", "isalnum", "islower",
|
| 77 |
+
"isupper", "istitle", "isdecimal", "isnumeric", "str_len", "find",
|
| 78 |
+
"rfind", "index", "rindex", "count", "startswith", "endswith", "lstrip",
|
| 79 |
+
"rstrip", "strip", "replace", "expandtabs", "center", "ljust", "rjust",
|
| 80 |
+
"zfill", "partition", "rpartition", "slice",
|
| 81 |
+
|
| 82 |
+
# _vec_string - Will gradually become ufuncs as well
|
| 83 |
+
"upper", "lower", "swapcase", "capitalize", "title",
|
| 84 |
+
|
| 85 |
+
# _vec_string - Will probably not become ufuncs
|
| 86 |
+
"mod", "decode", "encode", "translate",
|
| 87 |
+
|
| 88 |
+
# Removed from namespace until behavior has been crystallized
|
| 89 |
+
# "join", "split", "rsplit", "splitlines",
|
| 90 |
+
]
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
MAX = np.iinfo(np.int64).max
|
| 94 |
+
|
| 95 |
+
array_function_dispatch = functools.partial(
|
| 96 |
+
array_function_dispatch, module='numpy.strings')
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def _get_num_chars(a):
|
| 100 |
+
"""
|
| 101 |
+
Helper function that returns the number of characters per field in
|
| 102 |
+
a string or unicode array. This is to abstract out the fact that
|
| 103 |
+
for a unicode array this is itemsize / 4.
|
| 104 |
+
"""
|
| 105 |
+
if issubclass(a.dtype.type, np.str_):
|
| 106 |
+
return a.itemsize // 4
|
| 107 |
+
return a.itemsize
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def _to_bytes_or_str_array(result, output_dtype_like):
|
| 111 |
+
"""
|
| 112 |
+
Helper function to cast a result back into an array
|
| 113 |
+
with the appropriate dtype if an object array must be used
|
| 114 |
+
as an intermediary.
|
| 115 |
+
"""
|
| 116 |
+
output_dtype_like = np.asarray(output_dtype_like)
|
| 117 |
+
if result.size == 0:
|
| 118 |
+
# Calling asarray & tolist in an empty array would result
|
| 119 |
+
# in losing shape information
|
| 120 |
+
return result.astype(output_dtype_like.dtype)
|
| 121 |
+
ret = np.asarray(result.tolist())
|
| 122 |
+
if isinstance(output_dtype_like.dtype, np.dtypes.StringDType):
|
| 123 |
+
return ret.astype(type(output_dtype_like.dtype))
|
| 124 |
+
return ret.astype(type(output_dtype_like.dtype)(_get_num_chars(ret)))
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def _clean_args(*args):
|
| 128 |
+
"""
|
| 129 |
+
Helper function for delegating arguments to Python string
|
| 130 |
+
functions.
|
| 131 |
+
|
| 132 |
+
Many of the Python string operations that have optional arguments
|
| 133 |
+
do not use 'None' to indicate a default value. In these cases,
|
| 134 |
+
we need to remove all None arguments, and those following them.
|
| 135 |
+
"""
|
| 136 |
+
newargs = []
|
| 137 |
+
for chk in args:
|
| 138 |
+
if chk is None:
|
| 139 |
+
break
|
| 140 |
+
newargs.append(chk)
|
| 141 |
+
return newargs
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def _multiply_dispatcher(a, i):
|
| 145 |
+
return (a,)
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
@set_module("numpy.strings")
|
| 149 |
+
@array_function_dispatch(_multiply_dispatcher)
|
| 150 |
+
def multiply(a, i):
|
| 151 |
+
"""
|
| 152 |
+
Return (a * i), that is string multiple concatenation,
|
| 153 |
+
element-wise.
|
| 154 |
+
|
| 155 |
+
Values in ``i`` of less than 0 are treated as 0 (which yields an
|
| 156 |
+
empty string).
|
| 157 |
+
|
| 158 |
+
Parameters
|
| 159 |
+
----------
|
| 160 |
+
a : array_like, with ``StringDType``, ``bytes_`` or ``str_`` dtype
|
| 161 |
+
|
| 162 |
+
i : array_like, with any integer dtype
|
| 163 |
+
|
| 164 |
+
Returns
|
| 165 |
+
-------
|
| 166 |
+
out : ndarray
|
| 167 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 168 |
+
depending on input types
|
| 169 |
+
|
| 170 |
+
Examples
|
| 171 |
+
--------
|
| 172 |
+
>>> import numpy as np
|
| 173 |
+
>>> a = np.array(["a", "b", "c"])
|
| 174 |
+
>>> np.strings.multiply(a, 3)
|
| 175 |
+
array(['aaa', 'bbb', 'ccc'], dtype='<U3')
|
| 176 |
+
>>> i = np.array([1, 2, 3])
|
| 177 |
+
>>> np.strings.multiply(a, i)
|
| 178 |
+
array(['a', 'bb', 'ccc'], dtype='<U3')
|
| 179 |
+
>>> np.strings.multiply(np.array(['a']), i)
|
| 180 |
+
array(['a', 'aa', 'aaa'], dtype='<U3')
|
| 181 |
+
>>> a = np.array(['a', 'b', 'c', 'd', 'e', 'f']).reshape((2, 3))
|
| 182 |
+
>>> np.strings.multiply(a, 3)
|
| 183 |
+
array([['aaa', 'bbb', 'ccc'],
|
| 184 |
+
['ddd', 'eee', 'fff']], dtype='<U3')
|
| 185 |
+
>>> np.strings.multiply(a, i)
|
| 186 |
+
array([['a', 'bb', 'ccc'],
|
| 187 |
+
['d', 'ee', 'fff']], dtype='<U3')
|
| 188 |
+
|
| 189 |
+
"""
|
| 190 |
+
a = np.asanyarray(a)
|
| 191 |
+
|
| 192 |
+
i = np.asanyarray(i)
|
| 193 |
+
if not np.issubdtype(i.dtype, np.integer):
|
| 194 |
+
raise TypeError(f"unsupported type {i.dtype} for operand 'i'")
|
| 195 |
+
i = np.maximum(i, 0)
|
| 196 |
+
|
| 197 |
+
# delegate to stringdtype loops that also do overflow checking
|
| 198 |
+
if a.dtype.char == "T":
|
| 199 |
+
return a * i
|
| 200 |
+
|
| 201 |
+
a_len = str_len(a)
|
| 202 |
+
|
| 203 |
+
# Ensure we can do a_len * i without overflow.
|
| 204 |
+
if np.any(a_len > sys.maxsize / np.maximum(i, 1)):
|
| 205 |
+
raise OverflowError("Overflow encountered in string multiply")
|
| 206 |
+
|
| 207 |
+
buffersizes = a_len * i
|
| 208 |
+
out_dtype = f"{a.dtype.char}{buffersizes.max()}"
|
| 209 |
+
out = np.empty_like(a, shape=buffersizes.shape, dtype=out_dtype)
|
| 210 |
+
return _multiply_ufunc(a, i, out=out)
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def _mod_dispatcher(a, values):
|
| 214 |
+
return (a, values)
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
@set_module("numpy.strings")
|
| 218 |
+
@array_function_dispatch(_mod_dispatcher)
|
| 219 |
+
def mod(a, values):
|
| 220 |
+
"""
|
| 221 |
+
Return (a % i), that is pre-Python 2.6 string formatting
|
| 222 |
+
(interpolation), element-wise for a pair of array_likes of str
|
| 223 |
+
or unicode.
|
| 224 |
+
|
| 225 |
+
Parameters
|
| 226 |
+
----------
|
| 227 |
+
a : array_like, with ``bytes_`` or ``str_`` dtype
|
| 228 |
+
|
| 229 |
+
values : array_like of values
|
| 230 |
+
These values will be element-wise interpolated into the string.
|
| 231 |
+
|
| 232 |
+
Returns
|
| 233 |
+
-------
|
| 234 |
+
out : ndarray
|
| 235 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 236 |
+
depending on input types
|
| 237 |
+
|
| 238 |
+
Examples
|
| 239 |
+
--------
|
| 240 |
+
>>> import numpy as np
|
| 241 |
+
>>> a = np.array(["NumPy is a %s library"])
|
| 242 |
+
>>> np.strings.mod(a, values=["Python"])
|
| 243 |
+
array(['NumPy is a Python library'], dtype='<U25')
|
| 244 |
+
|
| 245 |
+
>>> a = np.array([b'%d bytes', b'%d bits'])
|
| 246 |
+
>>> values = np.array([8, 64])
|
| 247 |
+
>>> np.strings.mod(a, values)
|
| 248 |
+
array([b'8 bytes', b'64 bits'], dtype='|S7')
|
| 249 |
+
|
| 250 |
+
"""
|
| 251 |
+
return _to_bytes_or_str_array(
|
| 252 |
+
_vec_string(a, np.object_, '__mod__', (values,)), a)
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
@set_module("numpy.strings")
|
| 256 |
+
def find(a, sub, start=0, end=None):
|
| 257 |
+
"""
|
| 258 |
+
For each element, return the lowest index in the string where
|
| 259 |
+
substring ``sub`` is found, such that ``sub`` is contained in the
|
| 260 |
+
range [``start``, ``end``).
|
| 261 |
+
|
| 262 |
+
Parameters
|
| 263 |
+
----------
|
| 264 |
+
a : array_like, with ``StringDType``, ``bytes_`` or ``str_`` dtype
|
| 265 |
+
|
| 266 |
+
sub : array_like, with ``bytes_`` or ``str_`` dtype
|
| 267 |
+
The substring to search for.
|
| 268 |
+
|
| 269 |
+
start, end : array_like, with any integer dtype
|
| 270 |
+
The range to look in, interpreted as in slice notation.
|
| 271 |
+
|
| 272 |
+
Returns
|
| 273 |
+
-------
|
| 274 |
+
y : ndarray
|
| 275 |
+
Output array of ints
|
| 276 |
+
|
| 277 |
+
See Also
|
| 278 |
+
--------
|
| 279 |
+
str.find
|
| 280 |
+
|
| 281 |
+
Examples
|
| 282 |
+
--------
|
| 283 |
+
>>> import numpy as np
|
| 284 |
+
>>> a = np.array(["NumPy is a Python library"])
|
| 285 |
+
>>> np.strings.find(a, "Python")
|
| 286 |
+
array([11])
|
| 287 |
+
|
| 288 |
+
"""
|
| 289 |
+
end = end if end is not None else MAX
|
| 290 |
+
return _find_ufunc(a, sub, start, end)
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
@set_module("numpy.strings")
|
| 294 |
+
def rfind(a, sub, start=0, end=None):
|
| 295 |
+
"""
|
| 296 |
+
For each element, return the highest index in the string where
|
| 297 |
+
substring ``sub`` is found, such that ``sub`` is contained in the
|
| 298 |
+
range [``start``, ``end``).
|
| 299 |
+
|
| 300 |
+
Parameters
|
| 301 |
+
----------
|
| 302 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 303 |
+
|
| 304 |
+
sub : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 305 |
+
The substring to search for.
|
| 306 |
+
|
| 307 |
+
start, end : array_like, with any integer dtype
|
| 308 |
+
The range to look in, interpreted as in slice notation.
|
| 309 |
+
|
| 310 |
+
Returns
|
| 311 |
+
-------
|
| 312 |
+
y : ndarray
|
| 313 |
+
Output array of ints
|
| 314 |
+
|
| 315 |
+
See Also
|
| 316 |
+
--------
|
| 317 |
+
str.rfind
|
| 318 |
+
|
| 319 |
+
Examples
|
| 320 |
+
--------
|
| 321 |
+
>>> import numpy as np
|
| 322 |
+
>>> a = np.array(["Computer Science"])
|
| 323 |
+
>>> np.strings.rfind(a, "Science", start=0, end=None)
|
| 324 |
+
array([9])
|
| 325 |
+
>>> np.strings.rfind(a, "Science", start=0, end=8)
|
| 326 |
+
array([-1])
|
| 327 |
+
>>> b = np.array(["Computer Science", "Science"])
|
| 328 |
+
>>> np.strings.rfind(b, "Science", start=0, end=None)
|
| 329 |
+
array([9, 0])
|
| 330 |
+
|
| 331 |
+
"""
|
| 332 |
+
end = end if end is not None else MAX
|
| 333 |
+
return _rfind_ufunc(a, sub, start, end)
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
@set_module("numpy.strings")
|
| 337 |
+
def index(a, sub, start=0, end=None):
|
| 338 |
+
"""
|
| 339 |
+
Like `find`, but raises :exc:`ValueError` when the substring is not found.
|
| 340 |
+
|
| 341 |
+
Parameters
|
| 342 |
+
----------
|
| 343 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 344 |
+
|
| 345 |
+
sub : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 346 |
+
|
| 347 |
+
start, end : array_like, with any integer dtype, optional
|
| 348 |
+
|
| 349 |
+
Returns
|
| 350 |
+
-------
|
| 351 |
+
out : ndarray
|
| 352 |
+
Output array of ints.
|
| 353 |
+
|
| 354 |
+
See Also
|
| 355 |
+
--------
|
| 356 |
+
find, str.index
|
| 357 |
+
|
| 358 |
+
Examples
|
| 359 |
+
--------
|
| 360 |
+
>>> import numpy as np
|
| 361 |
+
>>> a = np.array(["Computer Science"])
|
| 362 |
+
>>> np.strings.index(a, "Science", start=0, end=None)
|
| 363 |
+
array([9])
|
| 364 |
+
|
| 365 |
+
"""
|
| 366 |
+
end = end if end is not None else MAX
|
| 367 |
+
return _index_ufunc(a, sub, start, end)
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
@set_module("numpy.strings")
|
| 371 |
+
def rindex(a, sub, start=0, end=None):
|
| 372 |
+
"""
|
| 373 |
+
Like `rfind`, but raises :exc:`ValueError` when the substring `sub` is
|
| 374 |
+
not found.
|
| 375 |
+
|
| 376 |
+
Parameters
|
| 377 |
+
----------
|
| 378 |
+
a : array-like, with ``bytes_`` or ``str_`` dtype
|
| 379 |
+
|
| 380 |
+
sub : array-like, with ``bytes_`` or ``str_`` dtype
|
| 381 |
+
|
| 382 |
+
start, end : array-like, with any integer dtype, optional
|
| 383 |
+
|
| 384 |
+
Returns
|
| 385 |
+
-------
|
| 386 |
+
out : ndarray
|
| 387 |
+
Output array of ints.
|
| 388 |
+
|
| 389 |
+
See Also
|
| 390 |
+
--------
|
| 391 |
+
rfind, str.rindex
|
| 392 |
+
|
| 393 |
+
Examples
|
| 394 |
+
--------
|
| 395 |
+
>>> a = np.array(["Computer Science"])
|
| 396 |
+
>>> np.strings.rindex(a, "Science", start=0, end=None)
|
| 397 |
+
array([9])
|
| 398 |
+
|
| 399 |
+
"""
|
| 400 |
+
end = end if end is not None else MAX
|
| 401 |
+
return _rindex_ufunc(a, sub, start, end)
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
@set_module("numpy.strings")
|
| 405 |
+
def count(a, sub, start=0, end=None):
|
| 406 |
+
"""
|
| 407 |
+
Returns an array with the number of non-overlapping occurrences of
|
| 408 |
+
substring ``sub`` in the range [``start``, ``end``).
|
| 409 |
+
|
| 410 |
+
Parameters
|
| 411 |
+
----------
|
| 412 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 413 |
+
|
| 414 |
+
sub : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 415 |
+
The substring to search for.
|
| 416 |
+
|
| 417 |
+
start, end : array_like, with any integer dtype
|
| 418 |
+
The range to look in, interpreted as in slice notation.
|
| 419 |
+
|
| 420 |
+
Returns
|
| 421 |
+
-------
|
| 422 |
+
y : ndarray
|
| 423 |
+
Output array of ints
|
| 424 |
+
|
| 425 |
+
See Also
|
| 426 |
+
--------
|
| 427 |
+
str.count
|
| 428 |
+
|
| 429 |
+
Examples
|
| 430 |
+
--------
|
| 431 |
+
>>> import numpy as np
|
| 432 |
+
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 433 |
+
>>> c
|
| 434 |
+
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
|
| 435 |
+
>>> np.strings.count(c, 'A')
|
| 436 |
+
array([3, 1, 1])
|
| 437 |
+
>>> np.strings.count(c, 'aA')
|
| 438 |
+
array([3, 1, 0])
|
| 439 |
+
>>> np.strings.count(c, 'A', start=1, end=4)
|
| 440 |
+
array([2, 1, 1])
|
| 441 |
+
>>> np.strings.count(c, 'A', start=1, end=3)
|
| 442 |
+
array([1, 0, 0])
|
| 443 |
+
|
| 444 |
+
"""
|
| 445 |
+
end = end if end is not None else MAX
|
| 446 |
+
return _count_ufunc(a, sub, start, end)
|
| 447 |
+
|
| 448 |
+
|
| 449 |
+
@set_module("numpy.strings")
|
| 450 |
+
def startswith(a, prefix, start=0, end=None):
|
| 451 |
+
"""
|
| 452 |
+
Returns a boolean array which is `True` where the string element
|
| 453 |
+
in ``a`` starts with ``prefix``, otherwise `False`.
|
| 454 |
+
|
| 455 |
+
Parameters
|
| 456 |
+
----------
|
| 457 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 458 |
+
|
| 459 |
+
prefix : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 460 |
+
|
| 461 |
+
start, end : array_like, with any integer dtype
|
| 462 |
+
With ``start``, test beginning at that position. With ``end``,
|
| 463 |
+
stop comparing at that position.
|
| 464 |
+
|
| 465 |
+
Returns
|
| 466 |
+
-------
|
| 467 |
+
out : ndarray
|
| 468 |
+
Output array of bools
|
| 469 |
+
|
| 470 |
+
See Also
|
| 471 |
+
--------
|
| 472 |
+
str.startswith
|
| 473 |
+
|
| 474 |
+
Examples
|
| 475 |
+
--------
|
| 476 |
+
>>> import numpy as np
|
| 477 |
+
>>> s = np.array(['foo', 'bar'])
|
| 478 |
+
>>> s
|
| 479 |
+
array(['foo', 'bar'], dtype='<U3')
|
| 480 |
+
>>> np.strings.startswith(s, 'fo')
|
| 481 |
+
array([True, False])
|
| 482 |
+
>>> np.strings.startswith(s, 'o', start=1, end=2)
|
| 483 |
+
array([True, False])
|
| 484 |
+
|
| 485 |
+
"""
|
| 486 |
+
end = end if end is not None else MAX
|
| 487 |
+
return _startswith_ufunc(a, prefix, start, end)
|
| 488 |
+
|
| 489 |
+
|
| 490 |
+
@set_module("numpy.strings")
|
| 491 |
+
def endswith(a, suffix, start=0, end=None):
|
| 492 |
+
"""
|
| 493 |
+
Returns a boolean array which is `True` where the string element
|
| 494 |
+
in ``a`` ends with ``suffix``, otherwise `False`.
|
| 495 |
+
|
| 496 |
+
Parameters
|
| 497 |
+
----------
|
| 498 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 499 |
+
|
| 500 |
+
suffix : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 501 |
+
|
| 502 |
+
start, end : array_like, with any integer dtype
|
| 503 |
+
With ``start``, test beginning at that position. With ``end``,
|
| 504 |
+
stop comparing at that position.
|
| 505 |
+
|
| 506 |
+
Returns
|
| 507 |
+
-------
|
| 508 |
+
out : ndarray
|
| 509 |
+
Output array of bools
|
| 510 |
+
|
| 511 |
+
See Also
|
| 512 |
+
--------
|
| 513 |
+
str.endswith
|
| 514 |
+
|
| 515 |
+
Examples
|
| 516 |
+
--------
|
| 517 |
+
>>> import numpy as np
|
| 518 |
+
>>> s = np.array(['foo', 'bar'])
|
| 519 |
+
>>> s
|
| 520 |
+
array(['foo', 'bar'], dtype='<U3')
|
| 521 |
+
>>> np.strings.endswith(s, 'ar')
|
| 522 |
+
array([False, True])
|
| 523 |
+
>>> np.strings.endswith(s, 'a', start=1, end=2)
|
| 524 |
+
array([False, True])
|
| 525 |
+
|
| 526 |
+
"""
|
| 527 |
+
end = end if end is not None else MAX
|
| 528 |
+
return _endswith_ufunc(a, suffix, start, end)
|
| 529 |
+
|
| 530 |
+
|
| 531 |
+
def _code_dispatcher(a, encoding=None, errors=None):
|
| 532 |
+
return (a,)
|
| 533 |
+
|
| 534 |
+
|
| 535 |
+
@set_module("numpy.strings")
|
| 536 |
+
@array_function_dispatch(_code_dispatcher)
|
| 537 |
+
def decode(a, encoding=None, errors=None):
|
| 538 |
+
r"""
|
| 539 |
+
Calls :meth:`bytes.decode` element-wise.
|
| 540 |
+
|
| 541 |
+
The set of available codecs comes from the Python standard library,
|
| 542 |
+
and may be extended at runtime. For more information, see the
|
| 543 |
+
:mod:`codecs` module.
|
| 544 |
+
|
| 545 |
+
Parameters
|
| 546 |
+
----------
|
| 547 |
+
a : array_like, with ``bytes_`` dtype
|
| 548 |
+
|
| 549 |
+
encoding : str, optional
|
| 550 |
+
The name of an encoding
|
| 551 |
+
|
| 552 |
+
errors : str, optional
|
| 553 |
+
Specifies how to handle encoding errors
|
| 554 |
+
|
| 555 |
+
Returns
|
| 556 |
+
-------
|
| 557 |
+
out : ndarray
|
| 558 |
+
|
| 559 |
+
See Also
|
| 560 |
+
--------
|
| 561 |
+
:py:meth:`bytes.decode`
|
| 562 |
+
|
| 563 |
+
Notes
|
| 564 |
+
-----
|
| 565 |
+
The type of the result will depend on the encoding specified.
|
| 566 |
+
|
| 567 |
+
Examples
|
| 568 |
+
--------
|
| 569 |
+
>>> import numpy as np
|
| 570 |
+
>>> c = np.array([b'\x81\xc1\x81\xc1\x81\xc1', b'@@\x81\xc1@@',
|
| 571 |
+
... b'\x81\x82\xc2\xc1\xc2\x82\x81'])
|
| 572 |
+
>>> c
|
| 573 |
+
array([b'\x81\xc1\x81\xc1\x81\xc1', b'@@\x81\xc1@@',
|
| 574 |
+
b'\x81\x82\xc2\xc1\xc2\x82\x81'], dtype='|S7')
|
| 575 |
+
>>> np.strings.decode(c, encoding='cp037')
|
| 576 |
+
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
|
| 577 |
+
|
| 578 |
+
"""
|
| 579 |
+
return _to_bytes_or_str_array(
|
| 580 |
+
_vec_string(a, np.object_, 'decode', _clean_args(encoding, errors)),
|
| 581 |
+
np.str_(''))
|
| 582 |
+
|
| 583 |
+
|
| 584 |
+
@set_module("numpy.strings")
|
| 585 |
+
@array_function_dispatch(_code_dispatcher)
|
| 586 |
+
def encode(a, encoding=None, errors=None):
|
| 587 |
+
"""
|
| 588 |
+
Calls :meth:`str.encode` element-wise.
|
| 589 |
+
|
| 590 |
+
The set of available codecs comes from the Python standard library,
|
| 591 |
+
and may be extended at runtime. For more information, see the
|
| 592 |
+
:mod:`codecs` module.
|
| 593 |
+
|
| 594 |
+
Parameters
|
| 595 |
+
----------
|
| 596 |
+
a : array_like, with ``StringDType`` or ``str_`` dtype
|
| 597 |
+
|
| 598 |
+
encoding : str, optional
|
| 599 |
+
The name of an encoding
|
| 600 |
+
|
| 601 |
+
errors : str, optional
|
| 602 |
+
Specifies how to handle encoding errors
|
| 603 |
+
|
| 604 |
+
Returns
|
| 605 |
+
-------
|
| 606 |
+
out : ndarray
|
| 607 |
+
|
| 608 |
+
See Also
|
| 609 |
+
--------
|
| 610 |
+
str.encode
|
| 611 |
+
|
| 612 |
+
Notes
|
| 613 |
+
-----
|
| 614 |
+
The type of the result will depend on the encoding specified.
|
| 615 |
+
|
| 616 |
+
Examples
|
| 617 |
+
--------
|
| 618 |
+
>>> import numpy as np
|
| 619 |
+
>>> a = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 620 |
+
>>> np.strings.encode(a, encoding='cp037')
|
| 621 |
+
array([b'\x81\xc1\x81\xc1\x81\xc1', b'@@\x81\xc1@@',
|
| 622 |
+
b'\x81\x82\xc2\xc1\xc2\x82\x81'], dtype='|S7')
|
| 623 |
+
|
| 624 |
+
"""
|
| 625 |
+
return _to_bytes_or_str_array(
|
| 626 |
+
_vec_string(a, np.object_, 'encode', _clean_args(encoding, errors)),
|
| 627 |
+
np.bytes_(b''))
|
| 628 |
+
|
| 629 |
+
|
| 630 |
+
def _expandtabs_dispatcher(a, tabsize=None):
|
| 631 |
+
return (a,)
|
| 632 |
+
|
| 633 |
+
|
| 634 |
+
@set_module("numpy.strings")
|
| 635 |
+
@array_function_dispatch(_expandtabs_dispatcher)
|
| 636 |
+
def expandtabs(a, tabsize=8):
|
| 637 |
+
"""
|
| 638 |
+
Return a copy of each string element where all tab characters are
|
| 639 |
+
replaced by one or more spaces.
|
| 640 |
+
|
| 641 |
+
Calls :meth:`str.expandtabs` element-wise.
|
| 642 |
+
|
| 643 |
+
Return a copy of each string element where all tab characters are
|
| 644 |
+
replaced by one or more spaces, depending on the current column
|
| 645 |
+
and the given `tabsize`. The column number is reset to zero after
|
| 646 |
+
each newline occurring in the string. This doesn't understand other
|
| 647 |
+
non-printing characters or escape sequences.
|
| 648 |
+
|
| 649 |
+
Parameters
|
| 650 |
+
----------
|
| 651 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 652 |
+
Input array
|
| 653 |
+
tabsize : int, optional
|
| 654 |
+
Replace tabs with `tabsize` number of spaces. If not given defaults
|
| 655 |
+
to 8 spaces.
|
| 656 |
+
|
| 657 |
+
Returns
|
| 658 |
+
-------
|
| 659 |
+
out : ndarray
|
| 660 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 661 |
+
depending on input type
|
| 662 |
+
|
| 663 |
+
See Also
|
| 664 |
+
--------
|
| 665 |
+
str.expandtabs
|
| 666 |
+
|
| 667 |
+
Examples
|
| 668 |
+
--------
|
| 669 |
+
>>> import numpy as np
|
| 670 |
+
>>> a = np.array(['\t\tHello\tworld'])
|
| 671 |
+
>>> np.strings.expandtabs(a, tabsize=4) # doctest: +SKIP
|
| 672 |
+
array([' Hello world'], dtype='<U21') # doctest: +SKIP
|
| 673 |
+
|
| 674 |
+
"""
|
| 675 |
+
a = np.asanyarray(a)
|
| 676 |
+
tabsize = np.asanyarray(tabsize)
|
| 677 |
+
|
| 678 |
+
if a.dtype.char == "T":
|
| 679 |
+
return _expandtabs(a, tabsize)
|
| 680 |
+
|
| 681 |
+
buffersizes = _expandtabs_length(a, tabsize)
|
| 682 |
+
out_dtype = f"{a.dtype.char}{buffersizes.max()}"
|
| 683 |
+
out = np.empty_like(a, shape=buffersizes.shape, dtype=out_dtype)
|
| 684 |
+
return _expandtabs(a, tabsize, out=out)
|
| 685 |
+
|
| 686 |
+
|
| 687 |
+
def _just_dispatcher(a, width, fillchar=None):
|
| 688 |
+
return (a,)
|
| 689 |
+
|
| 690 |
+
|
| 691 |
+
@set_module("numpy.strings")
|
| 692 |
+
@array_function_dispatch(_just_dispatcher)
|
| 693 |
+
def center(a, width, fillchar=' '):
|
| 694 |
+
"""
|
| 695 |
+
Return a copy of `a` with its elements centered in a string of
|
| 696 |
+
length `width`.
|
| 697 |
+
|
| 698 |
+
Parameters
|
| 699 |
+
----------
|
| 700 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 701 |
+
|
| 702 |
+
width : array_like, with any integer dtype
|
| 703 |
+
The length of the resulting strings, unless ``width < str_len(a)``.
|
| 704 |
+
fillchar : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 705 |
+
Optional padding character to use (default is space).
|
| 706 |
+
|
| 707 |
+
Returns
|
| 708 |
+
-------
|
| 709 |
+
out : ndarray
|
| 710 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 711 |
+
depending on input types
|
| 712 |
+
|
| 713 |
+
See Also
|
| 714 |
+
--------
|
| 715 |
+
str.center
|
| 716 |
+
|
| 717 |
+
Notes
|
| 718 |
+
-----
|
| 719 |
+
While it is possible for ``a`` and ``fillchar`` to have different dtypes,
|
| 720 |
+
passing a non-ASCII character in ``fillchar`` when ``a`` is of dtype "S"
|
| 721 |
+
is not allowed, and a ``ValueError`` is raised.
|
| 722 |
+
|
| 723 |
+
Examples
|
| 724 |
+
--------
|
| 725 |
+
>>> import numpy as np
|
| 726 |
+
>>> c = np.array(['a1b2','1b2a','b2a1','2a1b']); c
|
| 727 |
+
array(['a1b2', '1b2a', 'b2a1', '2a1b'], dtype='<U4')
|
| 728 |
+
>>> np.strings.center(c, width=9)
|
| 729 |
+
array([' a1b2 ', ' 1b2a ', ' b2a1 ', ' 2a1b '], dtype='<U9')
|
| 730 |
+
>>> np.strings.center(c, width=9, fillchar='*')
|
| 731 |
+
array(['***a1b2**', '***1b2a**', '***b2a1**', '***2a1b**'], dtype='<U9')
|
| 732 |
+
>>> np.strings.center(c, width=1)
|
| 733 |
+
array(['a1b2', '1b2a', 'b2a1', '2a1b'], dtype='<U4')
|
| 734 |
+
|
| 735 |
+
"""
|
| 736 |
+
width = np.asanyarray(width)
|
| 737 |
+
|
| 738 |
+
if not np.issubdtype(width.dtype, np.integer):
|
| 739 |
+
raise TypeError(f"unsupported type {width.dtype} for operand 'width'")
|
| 740 |
+
|
| 741 |
+
a = np.asanyarray(a)
|
| 742 |
+
fillchar = np.asanyarray(fillchar)
|
| 743 |
+
|
| 744 |
+
if np.any(str_len(fillchar) != 1):
|
| 745 |
+
raise TypeError(
|
| 746 |
+
"The fill character must be exactly one character long")
|
| 747 |
+
|
| 748 |
+
if np.result_type(a, fillchar).char == "T":
|
| 749 |
+
return _center(a, width, fillchar)
|
| 750 |
+
|
| 751 |
+
fillchar = fillchar.astype(a.dtype, copy=False)
|
| 752 |
+
width = np.maximum(str_len(a), width)
|
| 753 |
+
out_dtype = f"{a.dtype.char}{width.max()}"
|
| 754 |
+
shape = np.broadcast_shapes(a.shape, width.shape, fillchar.shape)
|
| 755 |
+
out = np.empty_like(a, shape=shape, dtype=out_dtype)
|
| 756 |
+
|
| 757 |
+
return _center(a, width, fillchar, out=out)
|
| 758 |
+
|
| 759 |
+
|
| 760 |
+
@set_module("numpy.strings")
|
| 761 |
+
@array_function_dispatch(_just_dispatcher)
|
| 762 |
+
def ljust(a, width, fillchar=' '):
|
| 763 |
+
"""
|
| 764 |
+
Return an array with the elements of `a` left-justified in a
|
| 765 |
+
string of length `width`.
|
| 766 |
+
|
| 767 |
+
Parameters
|
| 768 |
+
----------
|
| 769 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 770 |
+
|
| 771 |
+
width : array_like, with any integer dtype
|
| 772 |
+
The length of the resulting strings, unless ``width < str_len(a)``.
|
| 773 |
+
fillchar : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 774 |
+
Optional character to use for padding (default is space).
|
| 775 |
+
|
| 776 |
+
Returns
|
| 777 |
+
-------
|
| 778 |
+
out : ndarray
|
| 779 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 780 |
+
depending on input types
|
| 781 |
+
|
| 782 |
+
See Also
|
| 783 |
+
--------
|
| 784 |
+
str.ljust
|
| 785 |
+
|
| 786 |
+
Notes
|
| 787 |
+
-----
|
| 788 |
+
While it is possible for ``a`` and ``fillchar`` to have different dtypes,
|
| 789 |
+
passing a non-ASCII character in ``fillchar`` when ``a`` is of dtype "S"
|
| 790 |
+
is not allowed, and a ``ValueError`` is raised.
|
| 791 |
+
|
| 792 |
+
Examples
|
| 793 |
+
--------
|
| 794 |
+
>>> import numpy as np
|
| 795 |
+
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 796 |
+
>>> np.strings.ljust(c, width=3)
|
| 797 |
+
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
|
| 798 |
+
>>> np.strings.ljust(c, width=9)
|
| 799 |
+
array(['aAaAaA ', ' aA ', 'abBABba '], dtype='<U9')
|
| 800 |
+
|
| 801 |
+
"""
|
| 802 |
+
width = np.asanyarray(width)
|
| 803 |
+
if not np.issubdtype(width.dtype, np.integer):
|
| 804 |
+
raise TypeError(f"unsupported type {width.dtype} for operand 'width'")
|
| 805 |
+
|
| 806 |
+
a = np.asanyarray(a)
|
| 807 |
+
fillchar = np.asanyarray(fillchar)
|
| 808 |
+
|
| 809 |
+
if np.any(str_len(fillchar) != 1):
|
| 810 |
+
raise TypeError(
|
| 811 |
+
"The fill character must be exactly one character long")
|
| 812 |
+
|
| 813 |
+
if np.result_type(a, fillchar).char == "T":
|
| 814 |
+
return _ljust(a, width, fillchar)
|
| 815 |
+
|
| 816 |
+
fillchar = fillchar.astype(a.dtype, copy=False)
|
| 817 |
+
width = np.maximum(str_len(a), width)
|
| 818 |
+
shape = np.broadcast_shapes(a.shape, width.shape, fillchar.shape)
|
| 819 |
+
out_dtype = f"{a.dtype.char}{width.max()}"
|
| 820 |
+
out = np.empty_like(a, shape=shape, dtype=out_dtype)
|
| 821 |
+
|
| 822 |
+
return _ljust(a, width, fillchar, out=out)
|
| 823 |
+
|
| 824 |
+
|
| 825 |
+
@set_module("numpy.strings")
|
| 826 |
+
@array_function_dispatch(_just_dispatcher)
|
| 827 |
+
def rjust(a, width, fillchar=' '):
|
| 828 |
+
"""
|
| 829 |
+
Return an array with the elements of `a` right-justified in a
|
| 830 |
+
string of length `width`.
|
| 831 |
+
|
| 832 |
+
Parameters
|
| 833 |
+
----------
|
| 834 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 835 |
+
|
| 836 |
+
width : array_like, with any integer dtype
|
| 837 |
+
The length of the resulting strings, unless ``width < str_len(a)``.
|
| 838 |
+
fillchar : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 839 |
+
Optional padding character to use (default is space).
|
| 840 |
+
|
| 841 |
+
Returns
|
| 842 |
+
-------
|
| 843 |
+
out : ndarray
|
| 844 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 845 |
+
depending on input types
|
| 846 |
+
|
| 847 |
+
See Also
|
| 848 |
+
--------
|
| 849 |
+
str.rjust
|
| 850 |
+
|
| 851 |
+
Notes
|
| 852 |
+
-----
|
| 853 |
+
While it is possible for ``a`` and ``fillchar`` to have different dtypes,
|
| 854 |
+
passing a non-ASCII character in ``fillchar`` when ``a`` is of dtype "S"
|
| 855 |
+
is not allowed, and a ``ValueError`` is raised.
|
| 856 |
+
|
| 857 |
+
Examples
|
| 858 |
+
--------
|
| 859 |
+
>>> import numpy as np
|
| 860 |
+
>>> a = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 861 |
+
>>> np.strings.rjust(a, width=3)
|
| 862 |
+
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
|
| 863 |
+
>>> np.strings.rjust(a, width=9)
|
| 864 |
+
array([' aAaAaA', ' aA ', ' abBABba'], dtype='<U9')
|
| 865 |
+
|
| 866 |
+
"""
|
| 867 |
+
width = np.asanyarray(width)
|
| 868 |
+
if not np.issubdtype(width.dtype, np.integer):
|
| 869 |
+
raise TypeError(f"unsupported type {width.dtype} for operand 'width'")
|
| 870 |
+
|
| 871 |
+
a = np.asanyarray(a)
|
| 872 |
+
fillchar = np.asanyarray(fillchar)
|
| 873 |
+
|
| 874 |
+
if np.any(str_len(fillchar) != 1):
|
| 875 |
+
raise TypeError(
|
| 876 |
+
"The fill character must be exactly one character long")
|
| 877 |
+
|
| 878 |
+
if np.result_type(a, fillchar).char == "T":
|
| 879 |
+
return _rjust(a, width, fillchar)
|
| 880 |
+
|
| 881 |
+
fillchar = fillchar.astype(a.dtype, copy=False)
|
| 882 |
+
width = np.maximum(str_len(a), width)
|
| 883 |
+
shape = np.broadcast_shapes(a.shape, width.shape, fillchar.shape)
|
| 884 |
+
out_dtype = f"{a.dtype.char}{width.max()}"
|
| 885 |
+
out = np.empty_like(a, shape=shape, dtype=out_dtype)
|
| 886 |
+
|
| 887 |
+
return _rjust(a, width, fillchar, out=out)
|
| 888 |
+
|
| 889 |
+
|
| 890 |
+
def _zfill_dispatcher(a, width):
|
| 891 |
+
return (a,)
|
| 892 |
+
|
| 893 |
+
|
| 894 |
+
@set_module("numpy.strings")
|
| 895 |
+
@array_function_dispatch(_zfill_dispatcher)
|
| 896 |
+
def zfill(a, width):
|
| 897 |
+
"""
|
| 898 |
+
Return the numeric string left-filled with zeros. A leading
|
| 899 |
+
sign prefix (``+``/``-``) is handled by inserting the padding
|
| 900 |
+
after the sign character rather than before.
|
| 901 |
+
|
| 902 |
+
Parameters
|
| 903 |
+
----------
|
| 904 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 905 |
+
|
| 906 |
+
width : array_like, with any integer dtype
|
| 907 |
+
Width of string to left-fill elements in `a`.
|
| 908 |
+
|
| 909 |
+
Returns
|
| 910 |
+
-------
|
| 911 |
+
out : ndarray
|
| 912 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 913 |
+
depending on input type
|
| 914 |
+
|
| 915 |
+
See Also
|
| 916 |
+
--------
|
| 917 |
+
str.zfill
|
| 918 |
+
|
| 919 |
+
Examples
|
| 920 |
+
--------
|
| 921 |
+
>>> import numpy as np
|
| 922 |
+
>>> np.strings.zfill(['1', '-1', '+1'], 3)
|
| 923 |
+
array(['001', '-01', '+01'], dtype='<U3')
|
| 924 |
+
|
| 925 |
+
"""
|
| 926 |
+
width = np.asanyarray(width)
|
| 927 |
+
if not np.issubdtype(width.dtype, np.integer):
|
| 928 |
+
raise TypeError(f"unsupported type {width.dtype} for operand 'width'")
|
| 929 |
+
|
| 930 |
+
a = np.asanyarray(a)
|
| 931 |
+
|
| 932 |
+
if a.dtype.char == "T":
|
| 933 |
+
return _zfill(a, width)
|
| 934 |
+
|
| 935 |
+
width = np.maximum(str_len(a), width)
|
| 936 |
+
shape = np.broadcast_shapes(a.shape, width.shape)
|
| 937 |
+
out_dtype = f"{a.dtype.char}{width.max()}"
|
| 938 |
+
out = np.empty_like(a, shape=shape, dtype=out_dtype)
|
| 939 |
+
return _zfill(a, width, out=out)
|
| 940 |
+
|
| 941 |
+
|
| 942 |
+
@set_module("numpy.strings")
|
| 943 |
+
def lstrip(a, chars=None):
|
| 944 |
+
"""
|
| 945 |
+
For each element in `a`, return a copy with the leading characters
|
| 946 |
+
removed.
|
| 947 |
+
|
| 948 |
+
Parameters
|
| 949 |
+
----------
|
| 950 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 951 |
+
chars : scalar with the same dtype as ``a``, optional
|
| 952 |
+
The ``chars`` argument is a string specifying the set of
|
| 953 |
+
characters to be removed. If ``None``, the ``chars``
|
| 954 |
+
argument defaults to removing whitespace. The ``chars`` argument
|
| 955 |
+
is not a prefix or suffix; rather, all combinations of its
|
| 956 |
+
values are stripped.
|
| 957 |
+
|
| 958 |
+
Returns
|
| 959 |
+
-------
|
| 960 |
+
out : ndarray
|
| 961 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 962 |
+
depending on input types
|
| 963 |
+
|
| 964 |
+
See Also
|
| 965 |
+
--------
|
| 966 |
+
str.lstrip
|
| 967 |
+
|
| 968 |
+
Examples
|
| 969 |
+
--------
|
| 970 |
+
>>> import numpy as np
|
| 971 |
+
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 972 |
+
>>> c
|
| 973 |
+
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
|
| 974 |
+
# The 'a' variable is unstripped from c[1] because of leading whitespace.
|
| 975 |
+
>>> np.strings.lstrip(c, 'a')
|
| 976 |
+
array(['AaAaA', ' aA ', 'bBABba'], dtype='<U7')
|
| 977 |
+
>>> np.strings.lstrip(c, 'A') # leaves c unchanged
|
| 978 |
+
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
|
| 979 |
+
>>> (np.strings.lstrip(c, ' ') == np.strings.lstrip(c, '')).all()
|
| 980 |
+
np.False_
|
| 981 |
+
>>> (np.strings.lstrip(c, ' ') == np.strings.lstrip(c)).all()
|
| 982 |
+
np.True_
|
| 983 |
+
|
| 984 |
+
"""
|
| 985 |
+
if chars is None:
|
| 986 |
+
return _lstrip_whitespace(a)
|
| 987 |
+
return _lstrip_chars(a, chars)
|
| 988 |
+
|
| 989 |
+
|
| 990 |
+
@set_module("numpy.strings")
|
| 991 |
+
def rstrip(a, chars=None):
|
| 992 |
+
"""
|
| 993 |
+
For each element in `a`, return a copy with the trailing characters
|
| 994 |
+
removed.
|
| 995 |
+
|
| 996 |
+
Parameters
|
| 997 |
+
----------
|
| 998 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 999 |
+
chars : scalar with the same dtype as ``a``, optional
|
| 1000 |
+
The ``chars`` argument is a string specifying the set of
|
| 1001 |
+
characters to be removed. If ``None``, the ``chars``
|
| 1002 |
+
argument defaults to removing whitespace. The ``chars`` argument
|
| 1003 |
+
is not a prefix or suffix; rather, all combinations of its
|
| 1004 |
+
values are stripped.
|
| 1005 |
+
|
| 1006 |
+
Returns
|
| 1007 |
+
-------
|
| 1008 |
+
out : ndarray
|
| 1009 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1010 |
+
depending on input types
|
| 1011 |
+
|
| 1012 |
+
See Also
|
| 1013 |
+
--------
|
| 1014 |
+
str.rstrip
|
| 1015 |
+
|
| 1016 |
+
Examples
|
| 1017 |
+
--------
|
| 1018 |
+
>>> import numpy as np
|
| 1019 |
+
>>> c = np.array(['aAaAaA', 'abBABba'])
|
| 1020 |
+
>>> c
|
| 1021 |
+
array(['aAaAaA', 'abBABba'], dtype='<U7')
|
| 1022 |
+
>>> np.strings.rstrip(c, 'a')
|
| 1023 |
+
array(['aAaAaA', 'abBABb'], dtype='<U7')
|
| 1024 |
+
>>> np.strings.rstrip(c, 'A')
|
| 1025 |
+
array(['aAaAa', 'abBABba'], dtype='<U7')
|
| 1026 |
+
|
| 1027 |
+
"""
|
| 1028 |
+
if chars is None:
|
| 1029 |
+
return _rstrip_whitespace(a)
|
| 1030 |
+
return _rstrip_chars(a, chars)
|
| 1031 |
+
|
| 1032 |
+
|
| 1033 |
+
@set_module("numpy.strings")
|
| 1034 |
+
def strip(a, chars=None):
|
| 1035 |
+
"""
|
| 1036 |
+
For each element in `a`, return a copy with the leading and
|
| 1037 |
+
trailing characters removed.
|
| 1038 |
+
|
| 1039 |
+
Parameters
|
| 1040 |
+
----------
|
| 1041 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1042 |
+
chars : scalar with the same dtype as ``a``, optional
|
| 1043 |
+
The ``chars`` argument is a string specifying the set of
|
| 1044 |
+
characters to be removed. If ``None``, the ``chars``
|
| 1045 |
+
argument defaults to removing whitespace. The ``chars`` argument
|
| 1046 |
+
is not a prefix or suffix; rather, all combinations of its
|
| 1047 |
+
values are stripped.
|
| 1048 |
+
|
| 1049 |
+
Returns
|
| 1050 |
+
-------
|
| 1051 |
+
out : ndarray
|
| 1052 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1053 |
+
depending on input types
|
| 1054 |
+
|
| 1055 |
+
See Also
|
| 1056 |
+
--------
|
| 1057 |
+
str.strip
|
| 1058 |
+
|
| 1059 |
+
Examples
|
| 1060 |
+
--------
|
| 1061 |
+
>>> import numpy as np
|
| 1062 |
+
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 1063 |
+
>>> c
|
| 1064 |
+
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
|
| 1065 |
+
>>> np.strings.strip(c)
|
| 1066 |
+
array(['aAaAaA', 'aA', 'abBABba'], dtype='<U7')
|
| 1067 |
+
# 'a' unstripped from c[1] because of leading whitespace.
|
| 1068 |
+
>>> np.strings.strip(c, 'a')
|
| 1069 |
+
array(['AaAaA', ' aA ', 'bBABb'], dtype='<U7')
|
| 1070 |
+
# 'A' unstripped from c[1] because of trailing whitespace.
|
| 1071 |
+
>>> np.strings.strip(c, 'A')
|
| 1072 |
+
array(['aAaAa', ' aA ', 'abBABba'], dtype='<U7')
|
| 1073 |
+
|
| 1074 |
+
"""
|
| 1075 |
+
if chars is None:
|
| 1076 |
+
return _strip_whitespace(a)
|
| 1077 |
+
return _strip_chars(a, chars)
|
| 1078 |
+
|
| 1079 |
+
|
| 1080 |
+
def _unary_op_dispatcher(a):
|
| 1081 |
+
return (a,)
|
| 1082 |
+
|
| 1083 |
+
|
| 1084 |
+
@set_module("numpy.strings")
|
| 1085 |
+
@array_function_dispatch(_unary_op_dispatcher)
|
| 1086 |
+
def upper(a):
|
| 1087 |
+
"""
|
| 1088 |
+
Return an array with the elements converted to uppercase.
|
| 1089 |
+
|
| 1090 |
+
Calls :meth:`str.upper` element-wise.
|
| 1091 |
+
|
| 1092 |
+
For 8-bit strings, this method is locale-dependent.
|
| 1093 |
+
|
| 1094 |
+
Parameters
|
| 1095 |
+
----------
|
| 1096 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1097 |
+
Input array.
|
| 1098 |
+
|
| 1099 |
+
Returns
|
| 1100 |
+
-------
|
| 1101 |
+
out : ndarray
|
| 1102 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1103 |
+
depending on input types
|
| 1104 |
+
|
| 1105 |
+
See Also
|
| 1106 |
+
--------
|
| 1107 |
+
str.upper
|
| 1108 |
+
|
| 1109 |
+
Examples
|
| 1110 |
+
--------
|
| 1111 |
+
>>> import numpy as np
|
| 1112 |
+
>>> c = np.array(['a1b c', '1bca', 'bca1']); c
|
| 1113 |
+
array(['a1b c', '1bca', 'bca1'], dtype='<U5')
|
| 1114 |
+
>>> np.strings.upper(c)
|
| 1115 |
+
array(['A1B C', '1BCA', 'BCA1'], dtype='<U5')
|
| 1116 |
+
|
| 1117 |
+
"""
|
| 1118 |
+
a_arr = np.asarray(a)
|
| 1119 |
+
return _vec_string(a_arr, a_arr.dtype, 'upper')
|
| 1120 |
+
|
| 1121 |
+
|
| 1122 |
+
@set_module("numpy.strings")
|
| 1123 |
+
@array_function_dispatch(_unary_op_dispatcher)
|
| 1124 |
+
def lower(a):
|
| 1125 |
+
"""
|
| 1126 |
+
Return an array with the elements converted to lowercase.
|
| 1127 |
+
|
| 1128 |
+
Call :meth:`str.lower` element-wise.
|
| 1129 |
+
|
| 1130 |
+
For 8-bit strings, this method is locale-dependent.
|
| 1131 |
+
|
| 1132 |
+
Parameters
|
| 1133 |
+
----------
|
| 1134 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1135 |
+
Input array.
|
| 1136 |
+
|
| 1137 |
+
Returns
|
| 1138 |
+
-------
|
| 1139 |
+
out : ndarray
|
| 1140 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1141 |
+
depending on input types
|
| 1142 |
+
|
| 1143 |
+
See Also
|
| 1144 |
+
--------
|
| 1145 |
+
str.lower
|
| 1146 |
+
|
| 1147 |
+
Examples
|
| 1148 |
+
--------
|
| 1149 |
+
>>> import numpy as np
|
| 1150 |
+
>>> c = np.array(['A1B C', '1BCA', 'BCA1']); c
|
| 1151 |
+
array(['A1B C', '1BCA', 'BCA1'], dtype='<U5')
|
| 1152 |
+
>>> np.strings.lower(c)
|
| 1153 |
+
array(['a1b c', '1bca', 'bca1'], dtype='<U5')
|
| 1154 |
+
|
| 1155 |
+
"""
|
| 1156 |
+
a_arr = np.asarray(a)
|
| 1157 |
+
return _vec_string(a_arr, a_arr.dtype, 'lower')
|
| 1158 |
+
|
| 1159 |
+
|
| 1160 |
+
@set_module("numpy.strings")
|
| 1161 |
+
@array_function_dispatch(_unary_op_dispatcher)
|
| 1162 |
+
def swapcase(a):
|
| 1163 |
+
"""
|
| 1164 |
+
Return element-wise a copy of the string with
|
| 1165 |
+
uppercase characters converted to lowercase and vice versa.
|
| 1166 |
+
|
| 1167 |
+
Calls :meth:`str.swapcase` element-wise.
|
| 1168 |
+
|
| 1169 |
+
For 8-bit strings, this method is locale-dependent.
|
| 1170 |
+
|
| 1171 |
+
Parameters
|
| 1172 |
+
----------
|
| 1173 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1174 |
+
Input array.
|
| 1175 |
+
|
| 1176 |
+
Returns
|
| 1177 |
+
-------
|
| 1178 |
+
out : ndarray
|
| 1179 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1180 |
+
depending on input types
|
| 1181 |
+
|
| 1182 |
+
See Also
|
| 1183 |
+
--------
|
| 1184 |
+
str.swapcase
|
| 1185 |
+
|
| 1186 |
+
Examples
|
| 1187 |
+
--------
|
| 1188 |
+
>>> import numpy as np
|
| 1189 |
+
>>> c=np.array(['a1B c','1b Ca','b Ca1','cA1b'],'S5'); c
|
| 1190 |
+
array(['a1B c', '1b Ca', 'b Ca1', 'cA1b'],
|
| 1191 |
+
dtype='|S5')
|
| 1192 |
+
>>> np.strings.swapcase(c)
|
| 1193 |
+
array(['A1b C', '1B cA', 'B cA1', 'Ca1B'],
|
| 1194 |
+
dtype='|S5')
|
| 1195 |
+
|
| 1196 |
+
"""
|
| 1197 |
+
a_arr = np.asarray(a)
|
| 1198 |
+
return _vec_string(a_arr, a_arr.dtype, 'swapcase')
|
| 1199 |
+
|
| 1200 |
+
|
| 1201 |
+
@set_module("numpy.strings")
|
| 1202 |
+
@array_function_dispatch(_unary_op_dispatcher)
|
| 1203 |
+
def capitalize(a):
|
| 1204 |
+
"""
|
| 1205 |
+
Return a copy of ``a`` with only the first character of each element
|
| 1206 |
+
capitalized.
|
| 1207 |
+
|
| 1208 |
+
Calls :meth:`str.capitalize` element-wise.
|
| 1209 |
+
|
| 1210 |
+
For byte strings, this method is locale-dependent.
|
| 1211 |
+
|
| 1212 |
+
Parameters
|
| 1213 |
+
----------
|
| 1214 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1215 |
+
Input array of strings to capitalize.
|
| 1216 |
+
|
| 1217 |
+
Returns
|
| 1218 |
+
-------
|
| 1219 |
+
out : ndarray
|
| 1220 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1221 |
+
depending on input types
|
| 1222 |
+
|
| 1223 |
+
See Also
|
| 1224 |
+
--------
|
| 1225 |
+
str.capitalize
|
| 1226 |
+
|
| 1227 |
+
Examples
|
| 1228 |
+
--------
|
| 1229 |
+
>>> import numpy as np
|
| 1230 |
+
>>> c = np.array(['a1b2','1b2a','b2a1','2a1b'],'S4'); c
|
| 1231 |
+
array(['a1b2', '1b2a', 'b2a1', '2a1b'],
|
| 1232 |
+
dtype='|S4')
|
| 1233 |
+
>>> np.strings.capitalize(c)
|
| 1234 |
+
array(['A1b2', '1b2a', 'B2a1', '2a1b'],
|
| 1235 |
+
dtype='|S4')
|
| 1236 |
+
|
| 1237 |
+
"""
|
| 1238 |
+
a_arr = np.asarray(a)
|
| 1239 |
+
return _vec_string(a_arr, a_arr.dtype, 'capitalize')
|
| 1240 |
+
|
| 1241 |
+
|
| 1242 |
+
@set_module("numpy.strings")
|
| 1243 |
+
@array_function_dispatch(_unary_op_dispatcher)
|
| 1244 |
+
def title(a):
|
| 1245 |
+
"""
|
| 1246 |
+
Return element-wise title cased version of string or unicode.
|
| 1247 |
+
|
| 1248 |
+
Title case words start with uppercase characters, all remaining cased
|
| 1249 |
+
characters are lowercase.
|
| 1250 |
+
|
| 1251 |
+
Calls :meth:`str.title` element-wise.
|
| 1252 |
+
|
| 1253 |
+
For 8-bit strings, this method is locale-dependent.
|
| 1254 |
+
|
| 1255 |
+
Parameters
|
| 1256 |
+
----------
|
| 1257 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1258 |
+
Input array.
|
| 1259 |
+
|
| 1260 |
+
Returns
|
| 1261 |
+
-------
|
| 1262 |
+
out : ndarray
|
| 1263 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1264 |
+
depending on input types
|
| 1265 |
+
|
| 1266 |
+
See Also
|
| 1267 |
+
--------
|
| 1268 |
+
str.title
|
| 1269 |
+
|
| 1270 |
+
Examples
|
| 1271 |
+
--------
|
| 1272 |
+
>>> import numpy as np
|
| 1273 |
+
>>> c=np.array(['a1b c','1b ca','b ca1','ca1b'],'S5'); c
|
| 1274 |
+
array(['a1b c', '1b ca', 'b ca1', 'ca1b'],
|
| 1275 |
+
dtype='|S5')
|
| 1276 |
+
>>> np.strings.title(c)
|
| 1277 |
+
array(['A1B C', '1B Ca', 'B Ca1', 'Ca1B'],
|
| 1278 |
+
dtype='|S5')
|
| 1279 |
+
|
| 1280 |
+
"""
|
| 1281 |
+
a_arr = np.asarray(a)
|
| 1282 |
+
return _vec_string(a_arr, a_arr.dtype, 'title')
|
| 1283 |
+
|
| 1284 |
+
|
| 1285 |
+
def _replace_dispatcher(a, old, new, count=None):
|
| 1286 |
+
return (a,)
|
| 1287 |
+
|
| 1288 |
+
|
| 1289 |
+
@set_module("numpy.strings")
|
| 1290 |
+
@array_function_dispatch(_replace_dispatcher)
|
| 1291 |
+
def replace(a, old, new, count=-1):
|
| 1292 |
+
"""
|
| 1293 |
+
For each element in ``a``, return a copy of the string with
|
| 1294 |
+
occurrences of substring ``old`` replaced by ``new``.
|
| 1295 |
+
|
| 1296 |
+
Parameters
|
| 1297 |
+
----------
|
| 1298 |
+
a : array_like, with ``bytes_`` or ``str_`` dtype
|
| 1299 |
+
|
| 1300 |
+
old, new : array_like, with ``bytes_`` or ``str_`` dtype
|
| 1301 |
+
|
| 1302 |
+
count : array_like, with ``int_`` dtype
|
| 1303 |
+
If the optional argument ``count`` is given, only the first
|
| 1304 |
+
``count`` occurrences are replaced.
|
| 1305 |
+
|
| 1306 |
+
Returns
|
| 1307 |
+
-------
|
| 1308 |
+
out : ndarray
|
| 1309 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1310 |
+
depending on input types
|
| 1311 |
+
|
| 1312 |
+
See Also
|
| 1313 |
+
--------
|
| 1314 |
+
str.replace
|
| 1315 |
+
|
| 1316 |
+
Examples
|
| 1317 |
+
--------
|
| 1318 |
+
>>> import numpy as np
|
| 1319 |
+
>>> a = np.array(["That is a mango", "Monkeys eat mangos"])
|
| 1320 |
+
>>> np.strings.replace(a, 'mango', 'banana')
|
| 1321 |
+
array(['That is a banana', 'Monkeys eat bananas'], dtype='<U19')
|
| 1322 |
+
|
| 1323 |
+
>>> a = np.array(["The dish is fresh", "This is it"])
|
| 1324 |
+
>>> np.strings.replace(a, 'is', 'was')
|
| 1325 |
+
array(['The dwash was fresh', 'Thwas was it'], dtype='<U19')
|
| 1326 |
+
|
| 1327 |
+
"""
|
| 1328 |
+
count = np.asanyarray(count)
|
| 1329 |
+
if not np.issubdtype(count.dtype, np.integer):
|
| 1330 |
+
raise TypeError(f"unsupported type {count.dtype} for operand 'count'")
|
| 1331 |
+
|
| 1332 |
+
arr = np.asanyarray(a)
|
| 1333 |
+
old_dtype = getattr(old, 'dtype', None)
|
| 1334 |
+
old = np.asanyarray(old)
|
| 1335 |
+
new_dtype = getattr(new, 'dtype', None)
|
| 1336 |
+
new = np.asanyarray(new)
|
| 1337 |
+
|
| 1338 |
+
if np.result_type(arr, old, new).char == "T":
|
| 1339 |
+
return _replace(arr, old, new, count)
|
| 1340 |
+
|
| 1341 |
+
a_dt = arr.dtype
|
| 1342 |
+
old = old.astype(old_dtype or a_dt.char, copy=False)
|
| 1343 |
+
new = new.astype(new_dtype or a_dt.char, copy=False)
|
| 1344 |
+
max_int64 = np.iinfo(np.int64).max
|
| 1345 |
+
counts = _count_ufunc(arr, old, 0, max_int64)
|
| 1346 |
+
counts = np.where(count < 0, counts, np.minimum(counts, count))
|
| 1347 |
+
buffersizes = str_len(arr) + counts * (str_len(new) - str_len(old))
|
| 1348 |
+
out_dtype = f"{arr.dtype.char}{buffersizes.max()}"
|
| 1349 |
+
out = np.empty_like(arr, shape=buffersizes.shape, dtype=out_dtype)
|
| 1350 |
+
|
| 1351 |
+
return _replace(arr, old, new, counts, out=out)
|
| 1352 |
+
|
| 1353 |
+
|
| 1354 |
+
def _join_dispatcher(sep, seq):
|
| 1355 |
+
return (sep, seq)
|
| 1356 |
+
|
| 1357 |
+
|
| 1358 |
+
@array_function_dispatch(_join_dispatcher)
|
| 1359 |
+
def _join(sep, seq):
|
| 1360 |
+
"""
|
| 1361 |
+
Return a string which is the concatenation of the strings in the
|
| 1362 |
+
sequence `seq`.
|
| 1363 |
+
|
| 1364 |
+
Calls :meth:`str.join` element-wise.
|
| 1365 |
+
|
| 1366 |
+
Parameters
|
| 1367 |
+
----------
|
| 1368 |
+
sep : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1369 |
+
seq : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1370 |
+
|
| 1371 |
+
Returns
|
| 1372 |
+
-------
|
| 1373 |
+
out : ndarray
|
| 1374 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1375 |
+
depending on input types
|
| 1376 |
+
|
| 1377 |
+
See Also
|
| 1378 |
+
--------
|
| 1379 |
+
str.join
|
| 1380 |
+
|
| 1381 |
+
Examples
|
| 1382 |
+
--------
|
| 1383 |
+
>>> import numpy as np
|
| 1384 |
+
>>> np.strings.join('-', 'osd') # doctest: +SKIP
|
| 1385 |
+
array('o-s-d', dtype='<U5') # doctest: +SKIP
|
| 1386 |
+
|
| 1387 |
+
>>> np.strings.join(['-', '.'], ['ghc', 'osd']) # doctest: +SKIP
|
| 1388 |
+
array(['g-h-c', 'o.s.d'], dtype='<U5') # doctest: +SKIP
|
| 1389 |
+
|
| 1390 |
+
"""
|
| 1391 |
+
return _to_bytes_or_str_array(
|
| 1392 |
+
_vec_string(sep, np.object_, 'join', (seq,)), seq)
|
| 1393 |
+
|
| 1394 |
+
|
| 1395 |
+
def _split_dispatcher(a, sep=None, maxsplit=None):
|
| 1396 |
+
return (a,)
|
| 1397 |
+
|
| 1398 |
+
|
| 1399 |
+
@array_function_dispatch(_split_dispatcher)
|
| 1400 |
+
def _split(a, sep=None, maxsplit=None):
|
| 1401 |
+
"""
|
| 1402 |
+
For each element in `a`, return a list of the words in the
|
| 1403 |
+
string, using `sep` as the delimiter string.
|
| 1404 |
+
|
| 1405 |
+
Calls :meth:`str.split` element-wise.
|
| 1406 |
+
|
| 1407 |
+
Parameters
|
| 1408 |
+
----------
|
| 1409 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1410 |
+
|
| 1411 |
+
sep : str or unicode, optional
|
| 1412 |
+
If `sep` is not specified or None, any whitespace string is a
|
| 1413 |
+
separator.
|
| 1414 |
+
|
| 1415 |
+
maxsplit : int, optional
|
| 1416 |
+
If `maxsplit` is given, at most `maxsplit` splits are done.
|
| 1417 |
+
|
| 1418 |
+
Returns
|
| 1419 |
+
-------
|
| 1420 |
+
out : ndarray
|
| 1421 |
+
Array of list objects
|
| 1422 |
+
|
| 1423 |
+
Examples
|
| 1424 |
+
--------
|
| 1425 |
+
>>> import numpy as np
|
| 1426 |
+
>>> x = np.array("Numpy is nice!")
|
| 1427 |
+
>>> np.strings.split(x, " ") # doctest: +SKIP
|
| 1428 |
+
array(list(['Numpy', 'is', 'nice!']), dtype=object) # doctest: +SKIP
|
| 1429 |
+
|
| 1430 |
+
>>> np.strings.split(x, " ", 1) # doctest: +SKIP
|
| 1431 |
+
array(list(['Numpy', 'is nice!']), dtype=object) # doctest: +SKIP
|
| 1432 |
+
|
| 1433 |
+
See Also
|
| 1434 |
+
--------
|
| 1435 |
+
str.split, rsplit
|
| 1436 |
+
|
| 1437 |
+
"""
|
| 1438 |
+
# This will return an array of lists of different sizes, so we
|
| 1439 |
+
# leave it as an object array
|
| 1440 |
+
return _vec_string(
|
| 1441 |
+
a, np.object_, 'split', [sep] + _clean_args(maxsplit))
|
| 1442 |
+
|
| 1443 |
+
|
| 1444 |
+
@array_function_dispatch(_split_dispatcher)
|
| 1445 |
+
def _rsplit(a, sep=None, maxsplit=None):
|
| 1446 |
+
"""
|
| 1447 |
+
For each element in `a`, return a list of the words in the
|
| 1448 |
+
string, using `sep` as the delimiter string.
|
| 1449 |
+
|
| 1450 |
+
Calls :meth:`str.rsplit` element-wise.
|
| 1451 |
+
|
| 1452 |
+
Except for splitting from the right, `rsplit`
|
| 1453 |
+
behaves like `split`.
|
| 1454 |
+
|
| 1455 |
+
Parameters
|
| 1456 |
+
----------
|
| 1457 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1458 |
+
|
| 1459 |
+
sep : str or unicode, optional
|
| 1460 |
+
If `sep` is not specified or None, any whitespace string
|
| 1461 |
+
is a separator.
|
| 1462 |
+
maxsplit : int, optional
|
| 1463 |
+
If `maxsplit` is given, at most `maxsplit` splits are done,
|
| 1464 |
+
the rightmost ones.
|
| 1465 |
+
|
| 1466 |
+
Returns
|
| 1467 |
+
-------
|
| 1468 |
+
out : ndarray
|
| 1469 |
+
Array of list objects
|
| 1470 |
+
|
| 1471 |
+
See Also
|
| 1472 |
+
--------
|
| 1473 |
+
str.rsplit, split
|
| 1474 |
+
|
| 1475 |
+
Examples
|
| 1476 |
+
--------
|
| 1477 |
+
>>> import numpy as np
|
| 1478 |
+
>>> a = np.array(['aAaAaA', 'abBABba'])
|
| 1479 |
+
>>> np.strings.rsplit(a, 'A') # doctest: +SKIP
|
| 1480 |
+
array([list(['a', 'a', 'a', '']), # doctest: +SKIP
|
| 1481 |
+
list(['abB', 'Bba'])], dtype=object) # doctest: +SKIP
|
| 1482 |
+
|
| 1483 |
+
"""
|
| 1484 |
+
# This will return an array of lists of different sizes, so we
|
| 1485 |
+
# leave it as an object array
|
| 1486 |
+
return _vec_string(
|
| 1487 |
+
a, np.object_, 'rsplit', [sep] + _clean_args(maxsplit))
|
| 1488 |
+
|
| 1489 |
+
|
| 1490 |
+
def _splitlines_dispatcher(a, keepends=None):
|
| 1491 |
+
return (a,)
|
| 1492 |
+
|
| 1493 |
+
|
| 1494 |
+
@array_function_dispatch(_splitlines_dispatcher)
|
| 1495 |
+
def _splitlines(a, keepends=None):
|
| 1496 |
+
"""
|
| 1497 |
+
For each element in `a`, return a list of the lines in the
|
| 1498 |
+
element, breaking at line boundaries.
|
| 1499 |
+
|
| 1500 |
+
Calls :meth:`str.splitlines` element-wise.
|
| 1501 |
+
|
| 1502 |
+
Parameters
|
| 1503 |
+
----------
|
| 1504 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1505 |
+
|
| 1506 |
+
keepends : bool, optional
|
| 1507 |
+
Line breaks are not included in the resulting list unless
|
| 1508 |
+
keepends is given and true.
|
| 1509 |
+
|
| 1510 |
+
Returns
|
| 1511 |
+
-------
|
| 1512 |
+
out : ndarray
|
| 1513 |
+
Array of list objects
|
| 1514 |
+
|
| 1515 |
+
See Also
|
| 1516 |
+
--------
|
| 1517 |
+
str.splitlines
|
| 1518 |
+
|
| 1519 |
+
Examples
|
| 1520 |
+
--------
|
| 1521 |
+
>>> np.char.splitlines("first line\\nsecond line")
|
| 1522 |
+
array(list(['first line', 'second line']), dtype=object)
|
| 1523 |
+
>>> a = np.array(["first\\nsecond", "third\\nfourth"])
|
| 1524 |
+
>>> np.char.splitlines(a)
|
| 1525 |
+
array([list(['first', 'second']), list(['third', 'fourth'])], dtype=object)
|
| 1526 |
+
|
| 1527 |
+
"""
|
| 1528 |
+
return _vec_string(
|
| 1529 |
+
a, np.object_, 'splitlines', _clean_args(keepends))
|
| 1530 |
+
|
| 1531 |
+
|
| 1532 |
+
def _partition_dispatcher(a, sep):
|
| 1533 |
+
return (a,)
|
| 1534 |
+
|
| 1535 |
+
|
| 1536 |
+
@set_module("numpy.strings")
|
| 1537 |
+
@array_function_dispatch(_partition_dispatcher)
|
| 1538 |
+
def partition(a, sep):
|
| 1539 |
+
"""
|
| 1540 |
+
Partition each element in ``a`` around ``sep``.
|
| 1541 |
+
|
| 1542 |
+
For each element in ``a``, split the element at the first
|
| 1543 |
+
occurrence of ``sep``, and return a 3-tuple containing the part
|
| 1544 |
+
before the separator, the separator itself, and the part after
|
| 1545 |
+
the separator. If the separator is not found, the first item of
|
| 1546 |
+
the tuple will contain the whole string, and the second and third
|
| 1547 |
+
ones will be the empty string.
|
| 1548 |
+
|
| 1549 |
+
Parameters
|
| 1550 |
+
----------
|
| 1551 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1552 |
+
Input array
|
| 1553 |
+
sep : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1554 |
+
Separator to split each string element in ``a``.
|
| 1555 |
+
|
| 1556 |
+
Returns
|
| 1557 |
+
-------
|
| 1558 |
+
out : 3-tuple:
|
| 1559 |
+
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
|
| 1560 |
+
part before the separator
|
| 1561 |
+
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
|
| 1562 |
+
separator
|
| 1563 |
+
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
|
| 1564 |
+
part after the separator
|
| 1565 |
+
|
| 1566 |
+
See Also
|
| 1567 |
+
--------
|
| 1568 |
+
str.partition
|
| 1569 |
+
|
| 1570 |
+
Examples
|
| 1571 |
+
--------
|
| 1572 |
+
>>> import numpy as np
|
| 1573 |
+
>>> x = np.array(["Numpy is nice!"])
|
| 1574 |
+
>>> np.strings.partition(x, " ")
|
| 1575 |
+
(array(['Numpy'], dtype='<U5'),
|
| 1576 |
+
array([' '], dtype='<U1'),
|
| 1577 |
+
array(['is nice!'], dtype='<U8'))
|
| 1578 |
+
|
| 1579 |
+
"""
|
| 1580 |
+
a = np.asanyarray(a)
|
| 1581 |
+
sep = np.asanyarray(sep)
|
| 1582 |
+
|
| 1583 |
+
if np.result_type(a, sep).char == "T":
|
| 1584 |
+
return _partition(a, sep)
|
| 1585 |
+
|
| 1586 |
+
sep = sep.astype(a.dtype.char, copy=False)
|
| 1587 |
+
pos = _find_ufunc(a, sep, 0, MAX)
|
| 1588 |
+
a_len = str_len(a)
|
| 1589 |
+
sep_len = str_len(sep)
|
| 1590 |
+
|
| 1591 |
+
not_found = pos < 0
|
| 1592 |
+
buffersizes1 = np.where(not_found, a_len, pos)
|
| 1593 |
+
buffersizes3 = np.where(not_found, 0, a_len - pos - sep_len)
|
| 1594 |
+
|
| 1595 |
+
out_dtype = ",".join([f"{a.dtype.char}{n}" for n in (
|
| 1596 |
+
buffersizes1.max(),
|
| 1597 |
+
1 if np.all(not_found) else sep_len.max(),
|
| 1598 |
+
buffersizes3.max(),
|
| 1599 |
+
)])
|
| 1600 |
+
shape = np.broadcast_shapes(a.shape, sep.shape)
|
| 1601 |
+
out = np.empty_like(a, shape=shape, dtype=out_dtype)
|
| 1602 |
+
return _partition_index(a, sep, pos, out=(out["f0"], out["f1"], out["f2"]))
|
| 1603 |
+
|
| 1604 |
+
|
| 1605 |
+
@set_module("numpy.strings")
|
| 1606 |
+
@array_function_dispatch(_partition_dispatcher)
|
| 1607 |
+
def rpartition(a, sep):
|
| 1608 |
+
"""
|
| 1609 |
+
Partition (split) each element around the right-most separator.
|
| 1610 |
+
|
| 1611 |
+
For each element in ``a``, split the element at the last
|
| 1612 |
+
occurrence of ``sep``, and return a 3-tuple containing the part
|
| 1613 |
+
before the separator, the separator itself, and the part after
|
| 1614 |
+
the separator. If the separator is not found, the third item of
|
| 1615 |
+
the tuple will contain the whole string, and the first and second
|
| 1616 |
+
ones will be the empty string.
|
| 1617 |
+
|
| 1618 |
+
Parameters
|
| 1619 |
+
----------
|
| 1620 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1621 |
+
Input array
|
| 1622 |
+
sep : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1623 |
+
Separator to split each string element in ``a``.
|
| 1624 |
+
|
| 1625 |
+
Returns
|
| 1626 |
+
-------
|
| 1627 |
+
out : 3-tuple:
|
| 1628 |
+
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
|
| 1629 |
+
part before the separator
|
| 1630 |
+
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
|
| 1631 |
+
separator
|
| 1632 |
+
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
|
| 1633 |
+
part after the separator
|
| 1634 |
+
|
| 1635 |
+
See Also
|
| 1636 |
+
--------
|
| 1637 |
+
str.rpartition
|
| 1638 |
+
|
| 1639 |
+
Examples
|
| 1640 |
+
--------
|
| 1641 |
+
>>> import numpy as np
|
| 1642 |
+
>>> a = np.array(['aAaAaA', ' aA ', 'abBABba'])
|
| 1643 |
+
>>> np.strings.rpartition(a, 'A')
|
| 1644 |
+
(array(['aAaAa', ' a', 'abB'], dtype='<U5'),
|
| 1645 |
+
array(['A', 'A', 'A'], dtype='<U1'),
|
| 1646 |
+
array(['', ' ', 'Bba'], dtype='<U3'))
|
| 1647 |
+
|
| 1648 |
+
"""
|
| 1649 |
+
a = np.asanyarray(a)
|
| 1650 |
+
sep = np.asanyarray(sep)
|
| 1651 |
+
|
| 1652 |
+
if np.result_type(a, sep).char == "T":
|
| 1653 |
+
return _rpartition(a, sep)
|
| 1654 |
+
|
| 1655 |
+
sep = sep.astype(a.dtype.char, copy=False)
|
| 1656 |
+
pos = _rfind_ufunc(a, sep, 0, MAX)
|
| 1657 |
+
a_len = str_len(a)
|
| 1658 |
+
sep_len = str_len(sep)
|
| 1659 |
+
|
| 1660 |
+
not_found = pos < 0
|
| 1661 |
+
buffersizes1 = np.where(not_found, 0, pos)
|
| 1662 |
+
buffersizes3 = np.where(not_found, a_len, a_len - pos - sep_len)
|
| 1663 |
+
|
| 1664 |
+
out_dtype = ",".join([f"{a.dtype.char}{n}" for n in (
|
| 1665 |
+
buffersizes1.max(),
|
| 1666 |
+
1 if np.all(not_found) else sep_len.max(),
|
| 1667 |
+
buffersizes3.max(),
|
| 1668 |
+
)])
|
| 1669 |
+
shape = np.broadcast_shapes(a.shape, sep.shape)
|
| 1670 |
+
out = np.empty_like(a, shape=shape, dtype=out_dtype)
|
| 1671 |
+
return _rpartition_index(
|
| 1672 |
+
a, sep, pos, out=(out["f0"], out["f1"], out["f2"]))
|
| 1673 |
+
|
| 1674 |
+
|
| 1675 |
+
def _translate_dispatcher(a, table, deletechars=None):
|
| 1676 |
+
return (a,)
|
| 1677 |
+
|
| 1678 |
+
|
| 1679 |
+
@set_module("numpy.strings")
|
| 1680 |
+
@array_function_dispatch(_translate_dispatcher)
|
| 1681 |
+
def translate(a, table, deletechars=None):
|
| 1682 |
+
"""
|
| 1683 |
+
For each element in `a`, return a copy of the string where all
|
| 1684 |
+
characters occurring in the optional argument `deletechars` are
|
| 1685 |
+
removed, and the remaining characters have been mapped through the
|
| 1686 |
+
given translation table.
|
| 1687 |
+
|
| 1688 |
+
Calls :meth:`str.translate` element-wise.
|
| 1689 |
+
|
| 1690 |
+
Parameters
|
| 1691 |
+
----------
|
| 1692 |
+
a : array-like, with ``bytes_`` or ``str_`` dtype
|
| 1693 |
+
|
| 1694 |
+
table : str of length 256
|
| 1695 |
+
|
| 1696 |
+
deletechars : str
|
| 1697 |
+
|
| 1698 |
+
Returns
|
| 1699 |
+
-------
|
| 1700 |
+
out : ndarray
|
| 1701 |
+
Output array of str or unicode, depending on input type
|
| 1702 |
+
|
| 1703 |
+
See Also
|
| 1704 |
+
--------
|
| 1705 |
+
str.translate
|
| 1706 |
+
|
| 1707 |
+
Examples
|
| 1708 |
+
--------
|
| 1709 |
+
>>> import numpy as np
|
| 1710 |
+
>>> a = np.array(['a1b c', '1bca', 'bca1'])
|
| 1711 |
+
>>> table = a[0].maketrans('abc', '123')
|
| 1712 |
+
>>> deletechars = ' '
|
| 1713 |
+
>>> np.char.translate(a, table, deletechars)
|
| 1714 |
+
array(['112 3', '1231', '2311'], dtype='<U5')
|
| 1715 |
+
|
| 1716 |
+
"""
|
| 1717 |
+
a_arr = np.asarray(a)
|
| 1718 |
+
if issubclass(a_arr.dtype.type, np.str_):
|
| 1719 |
+
return _vec_string(
|
| 1720 |
+
a_arr, a_arr.dtype, 'translate', (table,))
|
| 1721 |
+
else:
|
| 1722 |
+
return _vec_string(
|
| 1723 |
+
a_arr,
|
| 1724 |
+
a_arr.dtype,
|
| 1725 |
+
'translate',
|
| 1726 |
+
[table] + _clean_args(deletechars)
|
| 1727 |
+
)
|
| 1728 |
+
|
| 1729 |
+
@set_module("numpy.strings")
|
| 1730 |
+
def slice(a, start=None, stop=np._NoValue, step=None, /):
|
| 1731 |
+
"""
|
| 1732 |
+
Slice the strings in `a` by slices specified by `start`, `stop`, `step`.
|
| 1733 |
+
Like in the regular Python `slice` object, if only `start` is
|
| 1734 |
+
specified then it is interpreted as the `stop`.
|
| 1735 |
+
|
| 1736 |
+
Parameters
|
| 1737 |
+
----------
|
| 1738 |
+
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
|
| 1739 |
+
Input array
|
| 1740 |
+
|
| 1741 |
+
start : None, an integer or an array of integers
|
| 1742 |
+
The start of the slice, broadcasted to `a`'s shape
|
| 1743 |
+
|
| 1744 |
+
stop : None, an integer or an array of integers
|
| 1745 |
+
The end of the slice, broadcasted to `a`'s shape
|
| 1746 |
+
|
| 1747 |
+
step : None, an integer or an array of integers
|
| 1748 |
+
The step for the slice, broadcasted to `a`'s shape
|
| 1749 |
+
|
| 1750 |
+
Returns
|
| 1751 |
+
-------
|
| 1752 |
+
out : ndarray
|
| 1753 |
+
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
|
| 1754 |
+
depending on input type
|
| 1755 |
+
|
| 1756 |
+
Examples
|
| 1757 |
+
--------
|
| 1758 |
+
>>> import numpy as np
|
| 1759 |
+
>>> a = np.array(['hello', 'world'])
|
| 1760 |
+
>>> np.strings.slice(a, 2)
|
| 1761 |
+
array(['he', 'wo'], dtype='<U5')
|
| 1762 |
+
|
| 1763 |
+
>>> np.strings.slice(a, 2, None)
|
| 1764 |
+
array(['llo', 'rld'], dtype='<U5')
|
| 1765 |
+
|
| 1766 |
+
>>> np.strings.slice(a, 1, 5, 2)
|
| 1767 |
+
array(['el', 'ol'], dtype='<U5')
|
| 1768 |
+
|
| 1769 |
+
One can specify different start/stop/step for different array entries:
|
| 1770 |
+
|
| 1771 |
+
>>> np.strings.slice(a, np.array([1, 2]), np.array([4, 5]))
|
| 1772 |
+
array(['ell', 'rld'], dtype='<U5')
|
| 1773 |
+
|
| 1774 |
+
Negative slices have the same meaning as in regular Python:
|
| 1775 |
+
|
| 1776 |
+
>>> b = np.array(['hello world', 'γεια σου κόσμε', '你好世界', '👋 🌍'],
|
| 1777 |
+
... dtype=np.dtypes.StringDType())
|
| 1778 |
+
>>> np.strings.slice(b, -2)
|
| 1779 |
+
array(['hello wor', 'γεια σου κόσ', '你好', '👋'], dtype=StringDType())
|
| 1780 |
+
|
| 1781 |
+
>>> np.strings.slice(b, -2, None)
|
| 1782 |
+
array(['ld', 'με', '世界', ' 🌍'], dtype=StringDType())
|
| 1783 |
+
|
| 1784 |
+
>>> np.strings.slice(b, [3, -10, 2, -3], [-1, -2, -1, 3])
|
| 1785 |
+
array(['lo worl', ' σου κόσ', '世', '👋 🌍'], dtype=StringDType())
|
| 1786 |
+
|
| 1787 |
+
>>> np.strings.slice(b, None, None, -1)
|
| 1788 |
+
array(['dlrow olleh', 'εμσόκ υοσ αιεγ', '界世好你', '🌍 👋'],
|
| 1789 |
+
dtype=StringDType())
|
| 1790 |
+
|
| 1791 |
+
"""
|
| 1792 |
+
# Just like in the construction of a regular slice object, if only start
|
| 1793 |
+
# is specified then start will become stop, see logic in slice_new.
|
| 1794 |
+
if stop is np._NoValue:
|
| 1795 |
+
stop = start
|
| 1796 |
+
start = None
|
| 1797 |
+
|
| 1798 |
+
# adjust start, stop, step to be integers, see logic in PySlice_Unpack
|
| 1799 |
+
if step is None:
|
| 1800 |
+
step = 1
|
| 1801 |
+
step = np.asanyarray(step)
|
| 1802 |
+
if not np.issubdtype(step.dtype, np.integer):
|
| 1803 |
+
raise TypeError(f"unsupported type {step.dtype} for operand 'step'")
|
| 1804 |
+
if np.any(step == 0):
|
| 1805 |
+
raise ValueError("slice step cannot be zero")
|
| 1806 |
+
|
| 1807 |
+
if start is None:
|
| 1808 |
+
start = np.where(step < 0, np.iinfo(np.intp).max, 0)
|
| 1809 |
+
|
| 1810 |
+
if stop is None:
|
| 1811 |
+
stop = np.where(step < 0, np.iinfo(np.intp).min, np.iinfo(np.intp).max)
|
| 1812 |
+
|
| 1813 |
+
return _slice(a, start, stop, step)
|
v12x/pylib/numpy/_core/tests/_locales.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Provide class for testing in French locale
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
import locale
|
| 5 |
+
import sys
|
| 6 |
+
|
| 7 |
+
import pytest
|
| 8 |
+
|
| 9 |
+
__ALL__ = ['CommaDecimalPointLocale']
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def find_comma_decimal_point_locale():
|
| 13 |
+
"""See if platform has a decimal point as comma locale.
|
| 14 |
+
|
| 15 |
+
Find a locale that uses a comma instead of a period as the
|
| 16 |
+
decimal point.
|
| 17 |
+
|
| 18 |
+
Returns
|
| 19 |
+
-------
|
| 20 |
+
old_locale: str
|
| 21 |
+
Locale when the function was called.
|
| 22 |
+
new_locale: {str, None)
|
| 23 |
+
First French locale found, None if none found.
|
| 24 |
+
|
| 25 |
+
"""
|
| 26 |
+
if sys.platform == 'win32':
|
| 27 |
+
locales = ['FRENCH']
|
| 28 |
+
else:
|
| 29 |
+
locales = ['fr_FR', 'fr_FR.UTF-8', 'fi_FI', 'fi_FI.UTF-8']
|
| 30 |
+
|
| 31 |
+
old_locale = locale.getlocale(locale.LC_NUMERIC)
|
| 32 |
+
new_locale = None
|
| 33 |
+
try:
|
| 34 |
+
for loc in locales:
|
| 35 |
+
try:
|
| 36 |
+
locale.setlocale(locale.LC_NUMERIC, loc)
|
| 37 |
+
new_locale = loc
|
| 38 |
+
break
|
| 39 |
+
except locale.Error:
|
| 40 |
+
pass
|
| 41 |
+
finally:
|
| 42 |
+
locale.setlocale(locale.LC_NUMERIC, locale=old_locale)
|
| 43 |
+
return old_locale, new_locale
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class CommaDecimalPointLocale:
|
| 47 |
+
"""Sets LC_NUMERIC to a locale with comma as decimal point.
|
| 48 |
+
|
| 49 |
+
Classes derived from this class have setup and teardown methods that run
|
| 50 |
+
tests with locale.LC_NUMERIC set to a locale where commas (',') are used as
|
| 51 |
+
the decimal point instead of periods ('.'). On exit the locale is restored
|
| 52 |
+
to the initial locale. It also serves as context manager with the same
|
| 53 |
+
effect. If no such locale is available, the test is skipped.
|
| 54 |
+
|
| 55 |
+
"""
|
| 56 |
+
(cur_locale, tst_locale) = find_comma_decimal_point_locale()
|
| 57 |
+
|
| 58 |
+
def setup_method(self):
|
| 59 |
+
if self.tst_locale is None:
|
| 60 |
+
pytest.skip("No French locale available")
|
| 61 |
+
locale.setlocale(locale.LC_NUMERIC, locale=self.tst_locale)
|
| 62 |
+
|
| 63 |
+
def teardown_method(self):
|
| 64 |
+
locale.setlocale(locale.LC_NUMERIC, locale=self.cur_locale)
|
| 65 |
+
|
| 66 |
+
def __enter__(self):
|
| 67 |
+
if self.tst_locale is None:
|
| 68 |
+
pytest.skip("No French locale available")
|
| 69 |
+
locale.setlocale(locale.LC_NUMERIC, locale=self.tst_locale)
|
| 70 |
+
|
| 71 |
+
def __exit__(self, type, value, traceback):
|
| 72 |
+
locale.setlocale(locale.LC_NUMERIC, locale=self.cur_locale)
|
v12x/pylib/numpy/_core/tests/_natype.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Vendored implementation of pandas.NA, adapted from pandas/_libs/missing.pyx
|
| 2 |
+
#
|
| 3 |
+
# This is vendored to avoid adding pandas as a test dependency.
|
| 4 |
+
|
| 5 |
+
__all__ = ["pd_NA"]
|
| 6 |
+
|
| 7 |
+
import numbers
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def _create_binary_propagating_op(name, is_divmod=False):
|
| 13 |
+
is_cmp = name.strip("_") in ["eq", "ne", "le", "lt", "ge", "gt"]
|
| 14 |
+
|
| 15 |
+
def method(self, other):
|
| 16 |
+
if (
|
| 17 |
+
other is pd_NA
|
| 18 |
+
or isinstance(other, (str, bytes, numbers.Number, np.bool))
|
| 19 |
+
or (isinstance(other, np.ndarray) and not other.shape)
|
| 20 |
+
):
|
| 21 |
+
# Need the other.shape clause to handle NumPy scalars,
|
| 22 |
+
# since we do a setitem on `out` below, which
|
| 23 |
+
# won't work for NumPy scalars.
|
| 24 |
+
if is_divmod:
|
| 25 |
+
return pd_NA, pd_NA
|
| 26 |
+
else:
|
| 27 |
+
return pd_NA
|
| 28 |
+
|
| 29 |
+
elif isinstance(other, np.ndarray):
|
| 30 |
+
out = np.empty(other.shape, dtype=object)
|
| 31 |
+
out[:] = pd_NA
|
| 32 |
+
|
| 33 |
+
if is_divmod:
|
| 34 |
+
return out, out.copy()
|
| 35 |
+
else:
|
| 36 |
+
return out
|
| 37 |
+
|
| 38 |
+
elif is_cmp and isinstance(other, (np.datetime64, np.timedelta64)):
|
| 39 |
+
return pd_NA
|
| 40 |
+
|
| 41 |
+
elif isinstance(other, np.datetime64):
|
| 42 |
+
if name in ["__sub__", "__rsub__"]:
|
| 43 |
+
return pd_NA
|
| 44 |
+
|
| 45 |
+
elif isinstance(other, np.timedelta64):
|
| 46 |
+
if name in ["__sub__", "__rsub__", "__add__", "__radd__"]:
|
| 47 |
+
return pd_NA
|
| 48 |
+
|
| 49 |
+
return NotImplemented
|
| 50 |
+
|
| 51 |
+
method.__name__ = name
|
| 52 |
+
return method
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def _create_unary_propagating_op(name: str):
|
| 56 |
+
def method(self):
|
| 57 |
+
return pd_NA
|
| 58 |
+
|
| 59 |
+
method.__name__ = name
|
| 60 |
+
return method
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
class NAType:
|
| 64 |
+
def __repr__(self) -> str:
|
| 65 |
+
return "<NA>"
|
| 66 |
+
|
| 67 |
+
def __format__(self, format_spec) -> str:
|
| 68 |
+
try:
|
| 69 |
+
return self.__repr__().__format__(format_spec)
|
| 70 |
+
except ValueError:
|
| 71 |
+
return self.__repr__()
|
| 72 |
+
|
| 73 |
+
def __bool__(self):
|
| 74 |
+
raise TypeError("boolean value of NA is ambiguous")
|
| 75 |
+
|
| 76 |
+
def __hash__(self):
|
| 77 |
+
return 2**61 - 1
|
| 78 |
+
|
| 79 |
+
def __reduce__(self):
|
| 80 |
+
return "pd_NA"
|
| 81 |
+
|
| 82 |
+
# Binary arithmetic and comparison ops -> propagate
|
| 83 |
+
|
| 84 |
+
__add__ = _create_binary_propagating_op("__add__")
|
| 85 |
+
__radd__ = _create_binary_propagating_op("__radd__")
|
| 86 |
+
__sub__ = _create_binary_propagating_op("__sub__")
|
| 87 |
+
__rsub__ = _create_binary_propagating_op("__rsub__")
|
| 88 |
+
__mul__ = _create_binary_propagating_op("__mul__")
|
| 89 |
+
__rmul__ = _create_binary_propagating_op("__rmul__")
|
| 90 |
+
__matmul__ = _create_binary_propagating_op("__matmul__")
|
| 91 |
+
__rmatmul__ = _create_binary_propagating_op("__rmatmul__")
|
| 92 |
+
__truediv__ = _create_binary_propagating_op("__truediv__")
|
| 93 |
+
__rtruediv__ = _create_binary_propagating_op("__rtruediv__")
|
| 94 |
+
__floordiv__ = _create_binary_propagating_op("__floordiv__")
|
| 95 |
+
__rfloordiv__ = _create_binary_propagating_op("__rfloordiv__")
|
| 96 |
+
__mod__ = _create_binary_propagating_op("__mod__")
|
| 97 |
+
__rmod__ = _create_binary_propagating_op("__rmod__")
|
| 98 |
+
__divmod__ = _create_binary_propagating_op("__divmod__", is_divmod=True)
|
| 99 |
+
__rdivmod__ = _create_binary_propagating_op("__rdivmod__", is_divmod=True)
|
| 100 |
+
# __lshift__ and __rshift__ are not implemented
|
| 101 |
+
|
| 102 |
+
__eq__ = _create_binary_propagating_op("__eq__")
|
| 103 |
+
__ne__ = _create_binary_propagating_op("__ne__")
|
| 104 |
+
__le__ = _create_binary_propagating_op("__le__")
|
| 105 |
+
__lt__ = _create_binary_propagating_op("__lt__")
|
| 106 |
+
__gt__ = _create_binary_propagating_op("__gt__")
|
| 107 |
+
__ge__ = _create_binary_propagating_op("__ge__")
|
| 108 |
+
|
| 109 |
+
# Unary ops
|
| 110 |
+
|
| 111 |
+
__neg__ = _create_unary_propagating_op("__neg__")
|
| 112 |
+
__pos__ = _create_unary_propagating_op("__pos__")
|
| 113 |
+
__abs__ = _create_unary_propagating_op("__abs__")
|
| 114 |
+
__invert__ = _create_unary_propagating_op("__invert__")
|
| 115 |
+
|
| 116 |
+
# Logical ops using Kleene logic
|
| 117 |
+
|
| 118 |
+
def __and__(self, other):
|
| 119 |
+
if other is False:
|
| 120 |
+
return False
|
| 121 |
+
elif other is True or other is pd_NA:
|
| 122 |
+
return pd_NA
|
| 123 |
+
return NotImplemented
|
| 124 |
+
|
| 125 |
+
__rand__ = __and__
|
| 126 |
+
|
| 127 |
+
def __or__(self, other):
|
| 128 |
+
if other is True:
|
| 129 |
+
return True
|
| 130 |
+
elif other is False or other is pd_NA:
|
| 131 |
+
return pd_NA
|
| 132 |
+
return NotImplemented
|
| 133 |
+
|
| 134 |
+
__ror__ = __or__
|
| 135 |
+
|
| 136 |
+
def __xor__(self, other):
|
| 137 |
+
if other is False or other is True or other is pd_NA:
|
| 138 |
+
return pd_NA
|
| 139 |
+
return NotImplemented
|
| 140 |
+
|
| 141 |
+
__rxor__ = __xor__
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
pd_NA = NAType()
|
v12x/pylib/numpy/_core/tests/examples/cython/setup.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Provide python-space access to the functions exposed in numpy/__init__.pxd
|
| 3 |
+
for testing.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
import Cython
|
| 9 |
+
from Cython.Build import cythonize
|
| 10 |
+
from distutils.core import setup
|
| 11 |
+
from setuptools.extension import Extension
|
| 12 |
+
|
| 13 |
+
import numpy as np
|
| 14 |
+
from numpy._utils import _pep440
|
| 15 |
+
|
| 16 |
+
macros = [
|
| 17 |
+
("NPY_NO_DEPRECATED_API", 0),
|
| 18 |
+
# Require 1.25+ to test datetime additions
|
| 19 |
+
("NPY_TARGET_VERSION", "NPY_2_0_API_VERSION"),
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
checks = Extension(
|
| 23 |
+
"checks",
|
| 24 |
+
sources=[os.path.join('.', "checks.pyx")],
|
| 25 |
+
include_dirs=[np.get_include()],
|
| 26 |
+
define_macros=macros,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
extensions = [checks]
|
| 30 |
+
|
| 31 |
+
compiler_directives = {}
|
| 32 |
+
if _pep440.parse(Cython.__version__) >= _pep440.parse("3.1.0a0"):
|
| 33 |
+
compiler_directives['freethreading_compatible'] = True
|
| 34 |
+
|
| 35 |
+
setup(
|
| 36 |
+
ext_modules=cythonize(
|
| 37 |
+
extensions,
|
| 38 |
+
compiler_directives=compiler_directives)
|
| 39 |
+
)
|
v12x/pylib/numpy/_core/tests/examples/limited_api/setup.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Build an example package using the limited Python C API.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
from setuptools import Extension, setup
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
macros = [("NPY_NO_DEPRECATED_API", 0), ("Py_LIMITED_API", "0x03060000")]
|
| 12 |
+
|
| 13 |
+
limited_api = Extension(
|
| 14 |
+
"limited_api",
|
| 15 |
+
sources=[os.path.join('.', "limited_api.c")],
|
| 16 |
+
include_dirs=[np.get_include()],
|
| 17 |
+
define_macros=macros,
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
extensions = [limited_api]
|
| 21 |
+
|
| 22 |
+
setup(
|
| 23 |
+
ext_modules=extensions
|
| 24 |
+
)
|
v12x/pylib/numpy/_core/tests/test__exceptions.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Tests of the ._exceptions module. Primarily for exercising the __str__ methods.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import pickle
|
| 6 |
+
|
| 7 |
+
import pytest
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
from numpy.exceptions import AxisError
|
| 11 |
+
|
| 12 |
+
_ArrayMemoryError = np._core._exceptions._ArrayMemoryError
|
| 13 |
+
_UFuncNoLoopError = np._core._exceptions._UFuncNoLoopError
|
| 14 |
+
|
| 15 |
+
class TestArrayMemoryError:
|
| 16 |
+
def test_pickling(self):
|
| 17 |
+
""" Test that _ArrayMemoryError can be pickled """
|
| 18 |
+
error = _ArrayMemoryError((1023,), np.dtype(np.uint8))
|
| 19 |
+
res = pickle.loads(pickle.dumps(error))
|
| 20 |
+
assert res._total_size == error._total_size
|
| 21 |
+
|
| 22 |
+
def test_str(self):
|
| 23 |
+
e = _ArrayMemoryError((1023,), np.dtype(np.uint8))
|
| 24 |
+
str(e) # not crashing is enough
|
| 25 |
+
|
| 26 |
+
# testing these properties is easier than testing the full string repr
|
| 27 |
+
def test__size_to_string(self):
|
| 28 |
+
""" Test e._size_to_string """
|
| 29 |
+
f = _ArrayMemoryError._size_to_string
|
| 30 |
+
Ki = 1024
|
| 31 |
+
assert f(0) == '0 bytes'
|
| 32 |
+
assert f(1) == '1 bytes'
|
| 33 |
+
assert f(1023) == '1023 bytes'
|
| 34 |
+
assert f(Ki) == '1.00 KiB'
|
| 35 |
+
assert f(Ki + 1) == '1.00 KiB'
|
| 36 |
+
assert f(10 * Ki) == '10.0 KiB'
|
| 37 |
+
assert f(int(999.4 * Ki)) == '999. KiB'
|
| 38 |
+
assert f(int(1023.4 * Ki)) == '1023. KiB'
|
| 39 |
+
assert f(int(1023.5 * Ki)) == '1.00 MiB'
|
| 40 |
+
assert f(Ki * Ki) == '1.00 MiB'
|
| 41 |
+
|
| 42 |
+
# 1023.9999 Mib should round to 1 GiB
|
| 43 |
+
assert f(int(Ki * Ki * Ki * 0.9999)) == '1.00 GiB'
|
| 44 |
+
assert f(Ki * Ki * Ki * Ki * Ki * Ki) == '1.00 EiB'
|
| 45 |
+
# larger than sys.maxsize, adding larger prefixes isn't going to help
|
| 46 |
+
# anyway.
|
| 47 |
+
assert f(Ki * Ki * Ki * Ki * Ki * Ki * 123456) == '123456. EiB'
|
| 48 |
+
|
| 49 |
+
def test__total_size(self):
|
| 50 |
+
""" Test e._total_size """
|
| 51 |
+
e = _ArrayMemoryError((1,), np.dtype(np.uint8))
|
| 52 |
+
assert e._total_size == 1
|
| 53 |
+
|
| 54 |
+
e = _ArrayMemoryError((2, 4), np.dtype((np.uint64, 16)))
|
| 55 |
+
assert e._total_size == 1024
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
class TestUFuncNoLoopError:
|
| 59 |
+
def test_pickling(self):
|
| 60 |
+
""" Test that _UFuncNoLoopError can be pickled """
|
| 61 |
+
assert isinstance(pickle.dumps(_UFuncNoLoopError), bytes)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
@pytest.mark.parametrize("args", [
|
| 65 |
+
(2, 1, None),
|
| 66 |
+
(2, 1, "test_prefix"),
|
| 67 |
+
("test message",),
|
| 68 |
+
])
|
| 69 |
+
class TestAxisError:
|
| 70 |
+
def test_attr(self, args):
|
| 71 |
+
"""Validate attribute types."""
|
| 72 |
+
exc = AxisError(*args)
|
| 73 |
+
if len(args) == 1:
|
| 74 |
+
assert exc.axis is None
|
| 75 |
+
assert exc.ndim is None
|
| 76 |
+
else:
|
| 77 |
+
axis, ndim, *_ = args
|
| 78 |
+
assert exc.axis == axis
|
| 79 |
+
assert exc.ndim == ndim
|
| 80 |
+
|
| 81 |
+
def test_pickling(self, args):
|
| 82 |
+
"""Test that `AxisError` can be pickled."""
|
| 83 |
+
exc = AxisError(*args)
|
| 84 |
+
exc2 = pickle.loads(pickle.dumps(exc))
|
| 85 |
+
|
| 86 |
+
assert type(exc) is type(exc2)
|
| 87 |
+
for name in ("axis", "ndim", "args"):
|
| 88 |
+
attr1 = getattr(exc, name)
|
| 89 |
+
attr2 = getattr(exc2, name)
|
| 90 |
+
assert attr1 == attr2, name
|
v12x/pylib/numpy/_core/tests/test_abc.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numbers
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
from numpy._core.numerictypes import sctypes
|
| 5 |
+
from numpy.testing import assert_
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class TestABC:
|
| 9 |
+
def test_abstract(self):
|
| 10 |
+
assert_(issubclass(np.number, numbers.Number))
|
| 11 |
+
|
| 12 |
+
assert_(issubclass(np.inexact, numbers.Complex))
|
| 13 |
+
assert_(issubclass(np.complexfloating, numbers.Complex))
|
| 14 |
+
assert_(issubclass(np.floating, numbers.Real))
|
| 15 |
+
|
| 16 |
+
assert_(issubclass(np.integer, numbers.Integral))
|
| 17 |
+
assert_(issubclass(np.signedinteger, numbers.Integral))
|
| 18 |
+
assert_(issubclass(np.unsignedinteger, numbers.Integral))
|
| 19 |
+
|
| 20 |
+
def test_floats(self):
|
| 21 |
+
for t in sctypes['float']:
|
| 22 |
+
assert_(isinstance(t(), numbers.Real),
|
| 23 |
+
f"{t.__name__} is not instance of Real")
|
| 24 |
+
assert_(issubclass(t, numbers.Real),
|
| 25 |
+
f"{t.__name__} is not subclass of Real")
|
| 26 |
+
assert_(not isinstance(t(), numbers.Rational),
|
| 27 |
+
f"{t.__name__} is instance of Rational")
|
| 28 |
+
assert_(not issubclass(t, numbers.Rational),
|
| 29 |
+
f"{t.__name__} is subclass of Rational")
|
| 30 |
+
|
| 31 |
+
def test_complex(self):
|
| 32 |
+
for t in sctypes['complex']:
|
| 33 |
+
assert_(isinstance(t(), numbers.Complex),
|
| 34 |
+
f"{t.__name__} is not instance of Complex")
|
| 35 |
+
assert_(issubclass(t, numbers.Complex),
|
| 36 |
+
f"{t.__name__} is not subclass of Complex")
|
| 37 |
+
assert_(not isinstance(t(), numbers.Real),
|
| 38 |
+
f"{t.__name__} is instance of Real")
|
| 39 |
+
assert_(not issubclass(t, numbers.Real),
|
| 40 |
+
f"{t.__name__} is subclass of Real")
|
| 41 |
+
|
| 42 |
+
def test_int(self):
|
| 43 |
+
for t in sctypes['int']:
|
| 44 |
+
assert_(isinstance(t(), numbers.Integral),
|
| 45 |
+
f"{t.__name__} is not instance of Integral")
|
| 46 |
+
assert_(issubclass(t, numbers.Integral),
|
| 47 |
+
f"{t.__name__} is not subclass of Integral")
|
| 48 |
+
|
| 49 |
+
def test_uint(self):
|
| 50 |
+
for t in sctypes['uint']:
|
| 51 |
+
assert_(isinstance(t(), numbers.Integral),
|
| 52 |
+
f"{t.__name__} is not instance of Integral")
|
| 53 |
+
assert_(issubclass(t, numbers.Integral),
|
| 54 |
+
f"{t.__name__} is not subclass of Integral")
|
v12x/pylib/numpy/_core/tests/test_api.py
ADDED
|
@@ -0,0 +1,668 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
import numpy._core.umath as ncu
|
| 7 |
+
from numpy._core._rational_tests import rational, rational2
|
| 8 |
+
from numpy.lib import stride_tricks
|
| 9 |
+
from numpy.testing import (
|
| 10 |
+
HAS_REFCOUNT,
|
| 11 |
+
assert_,
|
| 12 |
+
assert_array_equal,
|
| 13 |
+
assert_equal,
|
| 14 |
+
assert_raises,
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_array_array():
|
| 19 |
+
tobj = type(object)
|
| 20 |
+
ones11 = np.ones((1, 1), np.float64)
|
| 21 |
+
tndarray = type(ones11)
|
| 22 |
+
# Test is_ndarray
|
| 23 |
+
assert_equal(np.array(ones11, dtype=np.float64), ones11)
|
| 24 |
+
if HAS_REFCOUNT:
|
| 25 |
+
old_refcount = sys.getrefcount(tndarray)
|
| 26 |
+
np.array(ones11)
|
| 27 |
+
assert_equal(old_refcount, sys.getrefcount(tndarray))
|
| 28 |
+
|
| 29 |
+
# test None
|
| 30 |
+
assert_equal(np.array(None, dtype=np.float64),
|
| 31 |
+
np.array(np.nan, dtype=np.float64))
|
| 32 |
+
if HAS_REFCOUNT:
|
| 33 |
+
old_refcount = sys.getrefcount(tobj)
|
| 34 |
+
np.array(None, dtype=np.float64)
|
| 35 |
+
assert_equal(old_refcount, sys.getrefcount(tobj))
|
| 36 |
+
|
| 37 |
+
# test scalar
|
| 38 |
+
assert_equal(np.array(1.0, dtype=np.float64),
|
| 39 |
+
np.ones((), dtype=np.float64))
|
| 40 |
+
if HAS_REFCOUNT:
|
| 41 |
+
old_refcount = sys.getrefcount(np.float64)
|
| 42 |
+
np.array(np.array(1.0, dtype=np.float64), dtype=np.float64)
|
| 43 |
+
assert_equal(old_refcount, sys.getrefcount(np.float64))
|
| 44 |
+
|
| 45 |
+
# test string
|
| 46 |
+
S2 = np.dtype((bytes, 2))
|
| 47 |
+
S3 = np.dtype((bytes, 3))
|
| 48 |
+
S5 = np.dtype((bytes, 5))
|
| 49 |
+
assert_equal(np.array(b"1.0", dtype=np.float64),
|
| 50 |
+
np.ones((), dtype=np.float64))
|
| 51 |
+
assert_equal(np.array(b"1.0").dtype, S3)
|
| 52 |
+
assert_equal(np.array(b"1.0", dtype=bytes).dtype, S3)
|
| 53 |
+
assert_equal(np.array(b"1.0", dtype=S2), np.array(b"1."))
|
| 54 |
+
assert_equal(np.array(b"1", dtype=S5), np.ones((), dtype=S5))
|
| 55 |
+
|
| 56 |
+
# test string
|
| 57 |
+
U2 = np.dtype((str, 2))
|
| 58 |
+
U3 = np.dtype((str, 3))
|
| 59 |
+
U5 = np.dtype((str, 5))
|
| 60 |
+
assert_equal(np.array("1.0", dtype=np.float64),
|
| 61 |
+
np.ones((), dtype=np.float64))
|
| 62 |
+
assert_equal(np.array("1.0").dtype, U3)
|
| 63 |
+
assert_equal(np.array("1.0", dtype=str).dtype, U3)
|
| 64 |
+
assert_equal(np.array("1.0", dtype=U2), np.array("1."))
|
| 65 |
+
assert_equal(np.array("1", dtype=U5), np.ones((), dtype=U5))
|
| 66 |
+
|
| 67 |
+
builtins = getattr(__builtins__, '__dict__', __builtins__)
|
| 68 |
+
assert_(hasattr(builtins, 'get'))
|
| 69 |
+
|
| 70 |
+
# test memoryview
|
| 71 |
+
dat = np.array(memoryview(b'1.0'), dtype=np.float64)
|
| 72 |
+
assert_equal(dat, [49.0, 46.0, 48.0])
|
| 73 |
+
assert_(dat.dtype.type is np.float64)
|
| 74 |
+
|
| 75 |
+
dat = np.array(memoryview(b'1.0'))
|
| 76 |
+
assert_equal(dat, [49, 46, 48])
|
| 77 |
+
assert_(dat.dtype.type is np.uint8)
|
| 78 |
+
|
| 79 |
+
# test array interface
|
| 80 |
+
a = np.array(100.0, dtype=np.float64)
|
| 81 |
+
o = type("o", (object,),
|
| 82 |
+
{"__array_interface__": a.__array_interface__})
|
| 83 |
+
assert_equal(np.array(o, dtype=np.float64), a)
|
| 84 |
+
|
| 85 |
+
# test array_struct interface
|
| 86 |
+
a = np.array([(1, 4.0, 'Hello'), (2, 6.0, 'World')],
|
| 87 |
+
dtype=[('f0', int), ('f1', float), ('f2', str)])
|
| 88 |
+
o = type("o", (object,),
|
| 89 |
+
{"__array_struct__": a.__array_struct__})
|
| 90 |
+
# wasn't what I expected... is np.array(o) supposed to equal a ?
|
| 91 |
+
# instead we get an array([...], dtype=">V18")
|
| 92 |
+
assert_equal(bytes(np.array(o).data), bytes(a.data))
|
| 93 |
+
|
| 94 |
+
# test __array__
|
| 95 |
+
def custom__array__(self, dtype=None, copy=None):
|
| 96 |
+
return np.array(100.0, dtype=dtype, copy=copy)
|
| 97 |
+
|
| 98 |
+
o = type("o", (object,), {"__array__": custom__array__})()
|
| 99 |
+
assert_equal(np.array(o, dtype=np.float64), np.array(100.0, np.float64))
|
| 100 |
+
|
| 101 |
+
# test recursion
|
| 102 |
+
nested = 1.5
|
| 103 |
+
for i in range(ncu.MAXDIMS):
|
| 104 |
+
nested = [nested]
|
| 105 |
+
|
| 106 |
+
# no error
|
| 107 |
+
np.array(nested)
|
| 108 |
+
|
| 109 |
+
# Exceeds recursion limit
|
| 110 |
+
assert_raises(ValueError, np.array, [nested], dtype=np.float64)
|
| 111 |
+
|
| 112 |
+
# Try with lists...
|
| 113 |
+
# float32
|
| 114 |
+
assert_equal(np.array([None] * 10, dtype=np.float32),
|
| 115 |
+
np.full((10,), np.nan, dtype=np.float32))
|
| 116 |
+
assert_equal(np.array([[None]] * 10, dtype=np.float32),
|
| 117 |
+
np.full((10, 1), np.nan, dtype=np.float32))
|
| 118 |
+
assert_equal(np.array([[None] * 10], dtype=np.float32),
|
| 119 |
+
np.full((1, 10), np.nan, dtype=np.float32))
|
| 120 |
+
assert_equal(np.array([[None] * 10] * 10, dtype=np.float32),
|
| 121 |
+
np.full((10, 10), np.nan, dtype=np.float32))
|
| 122 |
+
# float64
|
| 123 |
+
assert_equal(np.array([None] * 10, dtype=np.float64),
|
| 124 |
+
np.full((10,), np.nan, dtype=np.float64))
|
| 125 |
+
assert_equal(np.array([[None]] * 10, dtype=np.float64),
|
| 126 |
+
np.full((10, 1), np.nan, dtype=np.float64))
|
| 127 |
+
assert_equal(np.array([[None] * 10], dtype=np.float64),
|
| 128 |
+
np.full((1, 10), np.nan, dtype=np.float64))
|
| 129 |
+
assert_equal(np.array([[None] * 10] * 10, dtype=np.float64),
|
| 130 |
+
np.full((10, 10), np.nan, dtype=np.float64))
|
| 131 |
+
|
| 132 |
+
assert_equal(np.array([1.0] * 10, dtype=np.float64),
|
| 133 |
+
np.ones((10,), dtype=np.float64))
|
| 134 |
+
assert_equal(np.array([[1.0]] * 10, dtype=np.float64),
|
| 135 |
+
np.ones((10, 1), dtype=np.float64))
|
| 136 |
+
assert_equal(np.array([[1.0] * 10], dtype=np.float64),
|
| 137 |
+
np.ones((1, 10), dtype=np.float64))
|
| 138 |
+
assert_equal(np.array([[1.0] * 10] * 10, dtype=np.float64),
|
| 139 |
+
np.ones((10, 10), dtype=np.float64))
|
| 140 |
+
|
| 141 |
+
# Try with tuples
|
| 142 |
+
assert_equal(np.array((None,) * 10, dtype=np.float64),
|
| 143 |
+
np.full((10,), np.nan, dtype=np.float64))
|
| 144 |
+
assert_equal(np.array([(None,)] * 10, dtype=np.float64),
|
| 145 |
+
np.full((10, 1), np.nan, dtype=np.float64))
|
| 146 |
+
assert_equal(np.array([(None,) * 10], dtype=np.float64),
|
| 147 |
+
np.full((1, 10), np.nan, dtype=np.float64))
|
| 148 |
+
assert_equal(np.array([(None,) * 10] * 10, dtype=np.float64),
|
| 149 |
+
np.full((10, 10), np.nan, dtype=np.float64))
|
| 150 |
+
|
| 151 |
+
assert_equal(np.array((1.0,) * 10, dtype=np.float64),
|
| 152 |
+
np.ones((10,), dtype=np.float64))
|
| 153 |
+
assert_equal(np.array([(1.0,)] * 10, dtype=np.float64),
|
| 154 |
+
np.ones((10, 1), dtype=np.float64))
|
| 155 |
+
assert_equal(np.array([(1.0,) * 10], dtype=np.float64),
|
| 156 |
+
np.ones((1, 10), dtype=np.float64))
|
| 157 |
+
assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64),
|
| 158 |
+
np.ones((10, 10), dtype=np.float64))
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
|
| 162 |
+
def test___array___refcount():
|
| 163 |
+
class MyArray:
|
| 164 |
+
def __init__(self, dtype):
|
| 165 |
+
self.val = np.array(-1, dtype=dtype)
|
| 166 |
+
|
| 167 |
+
def __array__(self, dtype=None, copy=None):
|
| 168 |
+
return self.val.__array__(dtype=dtype, copy=copy)
|
| 169 |
+
|
| 170 |
+
# test all possible scenarios:
|
| 171 |
+
# dtype(none | same | different) x copy(true | false | none)
|
| 172 |
+
dt = np.dtype(np.int32)
|
| 173 |
+
old_refcount = sys.getrefcount(dt)
|
| 174 |
+
np.array(MyArray(dt))
|
| 175 |
+
assert_equal(old_refcount, sys.getrefcount(dt))
|
| 176 |
+
np.array(MyArray(dt), dtype=dt)
|
| 177 |
+
assert_equal(old_refcount, sys.getrefcount(dt))
|
| 178 |
+
np.array(MyArray(dt), copy=None)
|
| 179 |
+
assert_equal(old_refcount, sys.getrefcount(dt))
|
| 180 |
+
np.array(MyArray(dt), dtype=dt, copy=None)
|
| 181 |
+
assert_equal(old_refcount, sys.getrefcount(dt))
|
| 182 |
+
dt2 = np.dtype(np.int16)
|
| 183 |
+
old_refcount2 = sys.getrefcount(dt2)
|
| 184 |
+
np.array(MyArray(dt), dtype=dt2)
|
| 185 |
+
assert_equal(old_refcount2, sys.getrefcount(dt2))
|
| 186 |
+
np.array(MyArray(dt), dtype=dt2, copy=None)
|
| 187 |
+
assert_equal(old_refcount2, sys.getrefcount(dt2))
|
| 188 |
+
with pytest.raises(ValueError):
|
| 189 |
+
np.array(MyArray(dt), dtype=dt2, copy=False)
|
| 190 |
+
assert_equal(old_refcount2, sys.getrefcount(dt2))
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
@pytest.mark.parametrize("rat_cls", [rational, rational2])
|
| 194 |
+
@pytest.mark.parametrize("array", [True, False])
|
| 195 |
+
def test_array_impossible_casts(array, rat_cls):
|
| 196 |
+
# All builtin types can be forcibly cast, at least theoretically,
|
| 197 |
+
# but user dtypes cannot necessarily.
|
| 198 |
+
rt = rat_cls(1, 2)
|
| 199 |
+
if array:
|
| 200 |
+
rt = np.array(rt)
|
| 201 |
+
with assert_raises(TypeError):
|
| 202 |
+
np.array(rt, dtype="M8")
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
def test_array_astype():
|
| 206 |
+
a = np.arange(6, dtype='f4').reshape(2, 3)
|
| 207 |
+
# Default behavior: allows unsafe casts, keeps memory layout,
|
| 208 |
+
# always copies.
|
| 209 |
+
b = a.astype('i4')
|
| 210 |
+
assert_equal(a, b)
|
| 211 |
+
assert_equal(b.dtype, np.dtype('i4'))
|
| 212 |
+
assert_equal(a.strides, b.strides)
|
| 213 |
+
b = a.T.astype('i4')
|
| 214 |
+
assert_equal(a.T, b)
|
| 215 |
+
assert_equal(b.dtype, np.dtype('i4'))
|
| 216 |
+
assert_equal(a.T.strides, b.strides)
|
| 217 |
+
b = a.astype('f4')
|
| 218 |
+
assert_equal(a, b)
|
| 219 |
+
assert_(not (a is b))
|
| 220 |
+
|
| 221 |
+
# copy=False parameter skips a copy
|
| 222 |
+
b = a.astype('f4', copy=False)
|
| 223 |
+
assert_(a is b)
|
| 224 |
+
|
| 225 |
+
# order parameter allows overriding of the memory layout,
|
| 226 |
+
# forcing a copy if the layout is wrong
|
| 227 |
+
b = a.astype('f4', order='F', copy=False)
|
| 228 |
+
assert_equal(a, b)
|
| 229 |
+
assert_(not (a is b))
|
| 230 |
+
assert_(b.flags.f_contiguous)
|
| 231 |
+
|
| 232 |
+
b = a.astype('f4', order='C', copy=False)
|
| 233 |
+
assert_equal(a, b)
|
| 234 |
+
assert_(a is b)
|
| 235 |
+
assert_(b.flags.c_contiguous)
|
| 236 |
+
|
| 237 |
+
# casting parameter allows catching bad casts
|
| 238 |
+
b = a.astype('c8', casting='safe')
|
| 239 |
+
assert_equal(a, b)
|
| 240 |
+
assert_equal(b.dtype, np.dtype('c8'))
|
| 241 |
+
|
| 242 |
+
assert_raises(TypeError, a.astype, 'i4', casting='safe')
|
| 243 |
+
|
| 244 |
+
# subok=False passes through a non-subclassed array
|
| 245 |
+
b = a.astype('f4', subok=0, copy=False)
|
| 246 |
+
assert_(a is b)
|
| 247 |
+
|
| 248 |
+
class MyNDArray(np.ndarray):
|
| 249 |
+
pass
|
| 250 |
+
|
| 251 |
+
a = np.array([[0, 1, 2], [3, 4, 5]], dtype='f4').view(MyNDArray)
|
| 252 |
+
|
| 253 |
+
# subok=True passes through a subclass
|
| 254 |
+
b = a.astype('f4', subok=True, copy=False)
|
| 255 |
+
assert_(a is b)
|
| 256 |
+
|
| 257 |
+
# subok=True is default, and creates a subtype on a cast
|
| 258 |
+
b = a.astype('i4', copy=False)
|
| 259 |
+
assert_equal(a, b)
|
| 260 |
+
assert_equal(type(b), MyNDArray)
|
| 261 |
+
|
| 262 |
+
# subok=False never returns a subclass
|
| 263 |
+
b = a.astype('f4', subok=False, copy=False)
|
| 264 |
+
assert_equal(a, b)
|
| 265 |
+
assert_(not (a is b))
|
| 266 |
+
assert_(type(b) is not MyNDArray)
|
| 267 |
+
|
| 268 |
+
# Make sure converting from string object to fixed length string
|
| 269 |
+
# does not truncate.
|
| 270 |
+
a = np.array([b'a' * 100], dtype='O')
|
| 271 |
+
b = a.astype('S')
|
| 272 |
+
assert_equal(a, b)
|
| 273 |
+
assert_equal(b.dtype, np.dtype('S100'))
|
| 274 |
+
a = np.array(['a' * 100], dtype='O')
|
| 275 |
+
b = a.astype('U')
|
| 276 |
+
assert_equal(a, b)
|
| 277 |
+
assert_equal(b.dtype, np.dtype('U100'))
|
| 278 |
+
|
| 279 |
+
# Same test as above but for strings shorter than 64 characters
|
| 280 |
+
a = np.array([b'a' * 10], dtype='O')
|
| 281 |
+
b = a.astype('S')
|
| 282 |
+
assert_equal(a, b)
|
| 283 |
+
assert_equal(b.dtype, np.dtype('S10'))
|
| 284 |
+
a = np.array(['a' * 10], dtype='O')
|
| 285 |
+
b = a.astype('U')
|
| 286 |
+
assert_equal(a, b)
|
| 287 |
+
assert_equal(b.dtype, np.dtype('U10'))
|
| 288 |
+
|
| 289 |
+
a = np.array(123456789012345678901234567890, dtype='O').astype('S')
|
| 290 |
+
assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30'))
|
| 291 |
+
a = np.array(123456789012345678901234567890, dtype='O').astype('U')
|
| 292 |
+
assert_array_equal(a, np.array('1234567890' * 3, dtype='U30'))
|
| 293 |
+
|
| 294 |
+
a = np.array([123456789012345678901234567890], dtype='O').astype('S')
|
| 295 |
+
assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30'))
|
| 296 |
+
a = np.array([123456789012345678901234567890], dtype='O').astype('U')
|
| 297 |
+
assert_array_equal(a, np.array('1234567890' * 3, dtype='U30'))
|
| 298 |
+
|
| 299 |
+
a = np.array(123456789012345678901234567890, dtype='S')
|
| 300 |
+
assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30'))
|
| 301 |
+
a = np.array(123456789012345678901234567890, dtype='U')
|
| 302 |
+
assert_array_equal(a, np.array('1234567890' * 3, dtype='U30'))
|
| 303 |
+
|
| 304 |
+
a = np.array('a\u0140', dtype='U')
|
| 305 |
+
b = np.ndarray(buffer=a, dtype='uint32', shape=2)
|
| 306 |
+
assert_(b.size == 2)
|
| 307 |
+
|
| 308 |
+
a = np.array([1000], dtype='i4')
|
| 309 |
+
assert_raises(TypeError, a.astype, 'S1', casting='safe')
|
| 310 |
+
|
| 311 |
+
a = np.array(1000, dtype='i4')
|
| 312 |
+
assert_raises(TypeError, a.astype, 'U1', casting='safe')
|
| 313 |
+
|
| 314 |
+
# gh-24023
|
| 315 |
+
assert_raises(TypeError, a.astype)
|
| 316 |
+
|
| 317 |
+
@pytest.mark.parametrize("dt", ["S", "U"])
|
| 318 |
+
def test_array_astype_to_string_discovery_empty(dt):
|
| 319 |
+
# See also gh-19085
|
| 320 |
+
arr = np.array([""], dtype=object)
|
| 321 |
+
# Note, the itemsize is the `0 -> 1` logic, which should change.
|
| 322 |
+
# The important part the test is rather that it does not error.
|
| 323 |
+
assert arr.astype(dt).dtype.itemsize == np.dtype(f"{dt}1").itemsize
|
| 324 |
+
|
| 325 |
+
# check the same thing for `np.can_cast` (since it accepts arrays)
|
| 326 |
+
assert np.can_cast(arr, dt, casting="unsafe")
|
| 327 |
+
assert not np.can_cast(arr, dt, casting="same_kind")
|
| 328 |
+
# as well as for the object as a descriptor:
|
| 329 |
+
assert np.can_cast("O", dt, casting="unsafe")
|
| 330 |
+
|
| 331 |
+
@pytest.mark.parametrize("dt", ["d", "f", "S13", "U32"])
|
| 332 |
+
def test_array_astype_to_void(dt):
|
| 333 |
+
dt = np.dtype(dt)
|
| 334 |
+
arr = np.array([], dtype=dt)
|
| 335 |
+
assert arr.astype("V").dtype.itemsize == dt.itemsize
|
| 336 |
+
|
| 337 |
+
def test_object_array_astype_to_void():
|
| 338 |
+
# This is different to `test_array_astype_to_void` as object arrays
|
| 339 |
+
# are inspected. The default void is "V8" (8 is the length of double)
|
| 340 |
+
arr = np.array([], dtype="O").astype("V")
|
| 341 |
+
assert arr.dtype == "V8"
|
| 342 |
+
|
| 343 |
+
@pytest.mark.parametrize("t",
|
| 344 |
+
np._core.sctypes['uint'] +
|
| 345 |
+
np._core.sctypes['int'] +
|
| 346 |
+
np._core.sctypes['float']
|
| 347 |
+
)
|
| 348 |
+
def test_array_astype_warning(t):
|
| 349 |
+
# test ComplexWarning when casting from complex to float or int
|
| 350 |
+
a = np.array(10, dtype=np.complex128)
|
| 351 |
+
pytest.warns(np.exceptions.ComplexWarning, a.astype, t)
|
| 352 |
+
|
| 353 |
+
@pytest.mark.parametrize(["dtype", "out_dtype"],
|
| 354 |
+
[(np.bytes_, np.bool),
|
| 355 |
+
(np.str_, np.bool),
|
| 356 |
+
(np.dtype("S10,S9"), np.dtype("?,?")),
|
| 357 |
+
# The following also checks unaligned unicode access:
|
| 358 |
+
(np.dtype("S7,U9"), np.dtype("?,?"))])
|
| 359 |
+
def test_string_to_boolean_cast(dtype, out_dtype):
|
| 360 |
+
# Only the last two (empty) strings are falsy (the `\0` is stripped):
|
| 361 |
+
arr = np.array(
|
| 362 |
+
["10", "10\0\0\0", "0\0\0", "0", "False", " ", "", "\0"],
|
| 363 |
+
dtype=dtype)
|
| 364 |
+
expected = np.array(
|
| 365 |
+
[True, True, True, True, True, True, False, False],
|
| 366 |
+
dtype=out_dtype)
|
| 367 |
+
assert_array_equal(arr.astype(out_dtype), expected)
|
| 368 |
+
# As it's similar, check that nonzero behaves the same (structs are
|
| 369 |
+
# nonzero if all entries are)
|
| 370 |
+
assert_array_equal(np.nonzero(arr), np.nonzero(expected))
|
| 371 |
+
|
| 372 |
+
@pytest.mark.parametrize("str_type", [str, bytes, np.str_])
|
| 373 |
+
@pytest.mark.parametrize("scalar_type",
|
| 374 |
+
[np.complex64, np.complex128, np.clongdouble])
|
| 375 |
+
def test_string_to_complex_cast(str_type, scalar_type):
|
| 376 |
+
value = scalar_type(b"1+3j")
|
| 377 |
+
assert scalar_type(value) == 1 + 3j
|
| 378 |
+
assert np.array([value], dtype=object).astype(scalar_type)[()] == 1 + 3j
|
| 379 |
+
assert np.array(value).astype(scalar_type)[()] == 1 + 3j
|
| 380 |
+
arr = np.zeros(1, dtype=scalar_type)
|
| 381 |
+
arr[0] = value
|
| 382 |
+
assert arr[0] == 1 + 3j
|
| 383 |
+
|
| 384 |
+
@pytest.mark.parametrize("dtype", np.typecodes["AllFloat"])
|
| 385 |
+
def test_none_to_nan_cast(dtype):
|
| 386 |
+
# Note that at the time of writing this test, the scalar constructors
|
| 387 |
+
# reject None
|
| 388 |
+
arr = np.zeros(1, dtype=dtype)
|
| 389 |
+
arr[0] = None
|
| 390 |
+
assert np.isnan(arr)[0]
|
| 391 |
+
assert np.isnan(np.array(None, dtype=dtype))[()]
|
| 392 |
+
assert np.isnan(np.array([None], dtype=dtype))[0]
|
| 393 |
+
assert np.isnan(np.array(None).astype(dtype))[()]
|
| 394 |
+
|
| 395 |
+
def test_copyto_fromscalar():
|
| 396 |
+
a = np.arange(6, dtype='f4').reshape(2, 3)
|
| 397 |
+
|
| 398 |
+
# Simple copy
|
| 399 |
+
np.copyto(a, 1.5)
|
| 400 |
+
assert_equal(a, 1.5)
|
| 401 |
+
np.copyto(a.T, 2.5)
|
| 402 |
+
assert_equal(a, 2.5)
|
| 403 |
+
|
| 404 |
+
# Where-masked copy
|
| 405 |
+
mask = np.array([[0, 1, 0], [0, 0, 1]], dtype='?')
|
| 406 |
+
np.copyto(a, 3.5, where=mask)
|
| 407 |
+
assert_equal(a, [[2.5, 3.5, 2.5], [2.5, 2.5, 3.5]])
|
| 408 |
+
mask = np.array([[0, 1], [1, 1], [1, 0]], dtype='?')
|
| 409 |
+
np.copyto(a.T, 4.5, where=mask)
|
| 410 |
+
assert_equal(a, [[2.5, 4.5, 4.5], [4.5, 4.5, 3.5]])
|
| 411 |
+
|
| 412 |
+
def test_copyto():
|
| 413 |
+
a = np.arange(6, dtype='i4').reshape(2, 3)
|
| 414 |
+
|
| 415 |
+
# Simple copy
|
| 416 |
+
np.copyto(a, [[3, 1, 5], [6, 2, 1]])
|
| 417 |
+
assert_equal(a, [[3, 1, 5], [6, 2, 1]])
|
| 418 |
+
|
| 419 |
+
# Overlapping copy should work
|
| 420 |
+
np.copyto(a[:, :2], a[::-1, 1::-1])
|
| 421 |
+
assert_equal(a, [[2, 6, 5], [1, 3, 1]])
|
| 422 |
+
|
| 423 |
+
# Defaults to 'same_kind' casting
|
| 424 |
+
assert_raises(TypeError, np.copyto, a, 1.5)
|
| 425 |
+
|
| 426 |
+
# Force a copy with 'unsafe' casting, truncating 1.5 to 1
|
| 427 |
+
np.copyto(a, 1.5, casting='unsafe')
|
| 428 |
+
assert_equal(a, 1)
|
| 429 |
+
|
| 430 |
+
# Copying with a mask
|
| 431 |
+
np.copyto(a, 3, where=[True, False, True])
|
| 432 |
+
assert_equal(a, [[3, 1, 3], [3, 1, 3]])
|
| 433 |
+
|
| 434 |
+
# Casting rule still applies with a mask
|
| 435 |
+
assert_raises(TypeError, np.copyto, a, 3.5, where=[True, False, True])
|
| 436 |
+
|
| 437 |
+
# Lists of integer 0's and 1's is ok too
|
| 438 |
+
np.copyto(a, 4.0, casting='unsafe', where=[[0, 1, 1], [1, 0, 0]])
|
| 439 |
+
assert_equal(a, [[3, 4, 4], [4, 1, 3]])
|
| 440 |
+
|
| 441 |
+
# Overlapping copy with mask should work
|
| 442 |
+
np.copyto(a[:, :2], a[::-1, 1::-1], where=[[0, 1], [1, 1]])
|
| 443 |
+
assert_equal(a, [[3, 4, 4], [4, 3, 3]])
|
| 444 |
+
|
| 445 |
+
# 'dst' must be an array
|
| 446 |
+
assert_raises(TypeError, np.copyto, [1, 2, 3], [2, 3, 4])
|
| 447 |
+
|
| 448 |
+
|
| 449 |
+
def test_copyto_overlapping_where_false_no_leak():
|
| 450 |
+
# gh-31968: overlapping copyto with scalar where=False used to leak the
|
| 451 |
+
# overlap temp (missing Py_DECREF on the early-return path). No refcount
|
| 452 |
+
# assertion is made here; a leak sanitizer build is expected to catch
|
| 453 |
+
# the regression.
|
| 454 |
+
a = np.arange(36, dtype=object).reshape(6, 6)
|
| 455 |
+
original = a.copy()
|
| 456 |
+
np.copyto(a, a[::-1, :], where=False)
|
| 457 |
+
# where=False must write nothing
|
| 458 |
+
assert_array_equal(a, original)
|
| 459 |
+
|
| 460 |
+
|
| 461 |
+
def test_copyto_cast_safety():
|
| 462 |
+
with pytest.raises(TypeError):
|
| 463 |
+
np.copyto(np.arange(3), 3., casting="safe")
|
| 464 |
+
|
| 465 |
+
# Can put integer and float scalars safely (and equiv):
|
| 466 |
+
np.copyto(np.arange(3), 3, casting="equiv")
|
| 467 |
+
np.copyto(np.arange(3.), 3., casting="equiv")
|
| 468 |
+
# And also with less precision safely:
|
| 469 |
+
np.copyto(np.arange(3, dtype="uint8"), 3, casting="safe")
|
| 470 |
+
np.copyto(np.arange(3., dtype="float32"), 3., casting="safe")
|
| 471 |
+
|
| 472 |
+
# But not equiv:
|
| 473 |
+
with pytest.raises(TypeError):
|
| 474 |
+
np.copyto(np.arange(3, dtype="uint8"), 3, casting="equiv")
|
| 475 |
+
|
| 476 |
+
with pytest.raises(TypeError):
|
| 477 |
+
np.copyto(np.arange(3., dtype="float32"), 3., casting="equiv")
|
| 478 |
+
|
| 479 |
+
# As a special thing, object is equiv currently:
|
| 480 |
+
np.copyto(np.arange(3, dtype=object), 3, casting="equiv")
|
| 481 |
+
|
| 482 |
+
# The following raises an overflow error/gives a warning but not
|
| 483 |
+
# type error (due to casting), though:
|
| 484 |
+
with pytest.raises(OverflowError):
|
| 485 |
+
np.copyto(np.arange(3), 2**80, casting="safe")
|
| 486 |
+
|
| 487 |
+
with pytest.warns(RuntimeWarning):
|
| 488 |
+
np.copyto(np.arange(3, dtype=np.float32), 2e300, casting="safe")
|
| 489 |
+
|
| 490 |
+
|
| 491 |
+
def test_copyto_permute():
|
| 492 |
+
# test explicit overflow case
|
| 493 |
+
pad = 500
|
| 494 |
+
l = [True] * pad + [True, True, True, True]
|
| 495 |
+
r = np.zeros(len(l) - pad)
|
| 496 |
+
d = np.ones(len(l) - pad)
|
| 497 |
+
mask = np.array(l)[pad:]
|
| 498 |
+
np.copyto(r, d, where=mask[::-1])
|
| 499 |
+
|
| 500 |
+
# test all permutation of possible masks, 9 should be sufficient for
|
| 501 |
+
# current 4 byte unrolled code
|
| 502 |
+
power = 9
|
| 503 |
+
d = np.ones(power)
|
| 504 |
+
for i in range(2**power):
|
| 505 |
+
r = np.zeros(power)
|
| 506 |
+
l = [(i & x) != 0 for x in range(power)]
|
| 507 |
+
mask = np.array(l)
|
| 508 |
+
np.copyto(r, d, where=mask)
|
| 509 |
+
assert_array_equal(r == 1, l)
|
| 510 |
+
assert_equal(r.sum(), sum(l))
|
| 511 |
+
|
| 512 |
+
r = np.zeros(power)
|
| 513 |
+
np.copyto(r, d, where=mask[::-1])
|
| 514 |
+
assert_array_equal(r == 1, l[::-1])
|
| 515 |
+
assert_equal(r.sum(), sum(l))
|
| 516 |
+
|
| 517 |
+
r = np.zeros(power)
|
| 518 |
+
np.copyto(r[::2], d[::2], where=mask[::2])
|
| 519 |
+
assert_array_equal(r[::2] == 1, l[::2])
|
| 520 |
+
assert_equal(r[::2].sum(), sum(l[::2]))
|
| 521 |
+
|
| 522 |
+
r = np.zeros(power)
|
| 523 |
+
np.copyto(r[::2], d[::2], where=mask[::-2])
|
| 524 |
+
assert_array_equal(r[::2] == 1, l[::-2])
|
| 525 |
+
assert_equal(r[::2].sum(), sum(l[::-2]))
|
| 526 |
+
|
| 527 |
+
for c in [0xFF, 0x7F, 0x02, 0x10]:
|
| 528 |
+
r = np.zeros(power)
|
| 529 |
+
mask = np.array(l)
|
| 530 |
+
imask = np.array(l).view(np.uint8)
|
| 531 |
+
imask[mask != 0] = c
|
| 532 |
+
np.copyto(r, d, where=mask)
|
| 533 |
+
assert_array_equal(r == 1, l)
|
| 534 |
+
assert_equal(r.sum(), sum(l))
|
| 535 |
+
|
| 536 |
+
r = np.zeros(power)
|
| 537 |
+
np.copyto(r, d, where=True)
|
| 538 |
+
assert_equal(r.sum(), r.size)
|
| 539 |
+
r = np.ones(power)
|
| 540 |
+
d = np.zeros(power)
|
| 541 |
+
np.copyto(r, d, where=False)
|
| 542 |
+
assert_equal(r.sum(), r.size)
|
| 543 |
+
|
| 544 |
+
def test_copy_order():
|
| 545 |
+
a = np.arange(24).reshape(2, 1, 3, 4)
|
| 546 |
+
b = a.copy(order='F')
|
| 547 |
+
c = np.arange(24).reshape(2, 1, 4, 3).swapaxes(2, 3)
|
| 548 |
+
|
| 549 |
+
def check_copy_result(x, y, ccontig, fcontig, strides=False):
|
| 550 |
+
assert_(not (x is y))
|
| 551 |
+
assert_equal(x, y)
|
| 552 |
+
assert_equal(res.flags.c_contiguous, ccontig)
|
| 553 |
+
assert_equal(res.flags.f_contiguous, fcontig)
|
| 554 |
+
|
| 555 |
+
# Validate the initial state of a, b, and c
|
| 556 |
+
assert_(a.flags.c_contiguous)
|
| 557 |
+
assert_(not a.flags.f_contiguous)
|
| 558 |
+
assert_(not b.flags.c_contiguous)
|
| 559 |
+
assert_(b.flags.f_contiguous)
|
| 560 |
+
assert_(not c.flags.c_contiguous)
|
| 561 |
+
assert_(not c.flags.f_contiguous)
|
| 562 |
+
|
| 563 |
+
# Copy with order='C'
|
| 564 |
+
res = a.copy(order='C')
|
| 565 |
+
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
|
| 566 |
+
res = b.copy(order='C')
|
| 567 |
+
check_copy_result(res, b, ccontig=True, fcontig=False, strides=False)
|
| 568 |
+
res = c.copy(order='C')
|
| 569 |
+
check_copy_result(res, c, ccontig=True, fcontig=False, strides=False)
|
| 570 |
+
res = np.copy(a, order='C')
|
| 571 |
+
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
|
| 572 |
+
res = np.copy(b, order='C')
|
| 573 |
+
check_copy_result(res, b, ccontig=True, fcontig=False, strides=False)
|
| 574 |
+
res = np.copy(c, order='C')
|
| 575 |
+
check_copy_result(res, c, ccontig=True, fcontig=False, strides=False)
|
| 576 |
+
|
| 577 |
+
# Copy with order='F'
|
| 578 |
+
res = a.copy(order='F')
|
| 579 |
+
check_copy_result(res, a, ccontig=False, fcontig=True, strides=False)
|
| 580 |
+
res = b.copy(order='F')
|
| 581 |
+
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
|
| 582 |
+
res = c.copy(order='F')
|
| 583 |
+
check_copy_result(res, c, ccontig=False, fcontig=True, strides=False)
|
| 584 |
+
res = np.copy(a, order='F')
|
| 585 |
+
check_copy_result(res, a, ccontig=False, fcontig=True, strides=False)
|
| 586 |
+
res = np.copy(b, order='F')
|
| 587 |
+
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
|
| 588 |
+
res = np.copy(c, order='F')
|
| 589 |
+
check_copy_result(res, c, ccontig=False, fcontig=True, strides=False)
|
| 590 |
+
|
| 591 |
+
# Copy with order='K'
|
| 592 |
+
res = a.copy(order='K')
|
| 593 |
+
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
|
| 594 |
+
res = b.copy(order='K')
|
| 595 |
+
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
|
| 596 |
+
res = c.copy(order='K')
|
| 597 |
+
check_copy_result(res, c, ccontig=False, fcontig=False, strides=True)
|
| 598 |
+
res = np.copy(a, order='K')
|
| 599 |
+
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
|
| 600 |
+
res = np.copy(b, order='K')
|
| 601 |
+
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
|
| 602 |
+
res = np.copy(c, order='K')
|
| 603 |
+
check_copy_result(res, c, ccontig=False, fcontig=False, strides=True)
|
| 604 |
+
|
| 605 |
+
def test_contiguous_flags():
|
| 606 |
+
a = np.ones((4, 4, 1))[::2, :, :]
|
| 607 |
+
a = stride_tricks.as_strided(a, strides=a.strides[:2] + (-123,))
|
| 608 |
+
b = np.ones((2, 2, 1, 2, 2)).swapaxes(3, 4)
|
| 609 |
+
|
| 610 |
+
def check_contig(a, ccontig, fcontig):
|
| 611 |
+
assert_(a.flags.c_contiguous == ccontig)
|
| 612 |
+
assert_(a.flags.f_contiguous == fcontig)
|
| 613 |
+
|
| 614 |
+
# Check if new arrays are correct:
|
| 615 |
+
check_contig(a, False, False)
|
| 616 |
+
check_contig(b, False, False)
|
| 617 |
+
check_contig(np.empty((2, 2, 0, 2, 2)), True, True)
|
| 618 |
+
check_contig(np.array([[[1], [2]]], order='F'), True, True)
|
| 619 |
+
check_contig(np.empty((2, 2)), True, False)
|
| 620 |
+
check_contig(np.empty((2, 2), order='F'), False, True)
|
| 621 |
+
|
| 622 |
+
# Check that np.array creates correct contiguous flags:
|
| 623 |
+
check_contig(np.array(a, copy=None), False, False)
|
| 624 |
+
check_contig(np.array(a, copy=None, order='C'), True, False)
|
| 625 |
+
check_contig(np.array(a, ndmin=4, copy=None, order='F'), False, True)
|
| 626 |
+
|
| 627 |
+
# Check slicing update of flags and :
|
| 628 |
+
check_contig(a[0], True, True)
|
| 629 |
+
check_contig(a[None, ::4, ..., None], True, True)
|
| 630 |
+
check_contig(b[0, 0, ...], False, True)
|
| 631 |
+
check_contig(b[:, :, 0:0, :, :], True, True)
|
| 632 |
+
|
| 633 |
+
# Test ravel and squeeze.
|
| 634 |
+
check_contig(a.ravel(), True, True)
|
| 635 |
+
check_contig(np.ones((1, 3, 1)).squeeze(), True, True)
|
| 636 |
+
|
| 637 |
+
def test_broadcast_arrays():
|
| 638 |
+
# Test user defined dtypes
|
| 639 |
+
dtype = 'u4,u4,u4'
|
| 640 |
+
a = np.array([(1, 2, 3)], dtype=dtype)
|
| 641 |
+
b = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype=dtype)
|
| 642 |
+
result = np.broadcast_arrays(a, b)
|
| 643 |
+
assert_equal(result[0], np.array([(1, 2, 3), (1, 2, 3), (1, 2, 3)], dtype=dtype))
|
| 644 |
+
assert_equal(result[1], np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype=dtype))
|
| 645 |
+
|
| 646 |
+
@pytest.mark.parametrize(["shape", "fill_value", "expected_output"],
|
| 647 |
+
[((2, 2), [5.0, 6.0], np.array([[5.0, 6.0], [5.0, 6.0]])),
|
| 648 |
+
((3, 2), [1.0, 2.0], np.array([[1.0, 2.0], [1.0, 2.0], [1.0, 2.0]]))])
|
| 649 |
+
def test_full_from_list(shape, fill_value, expected_output):
|
| 650 |
+
output = np.full(shape, fill_value)
|
| 651 |
+
assert_equal(output, expected_output)
|
| 652 |
+
|
| 653 |
+
def test_astype_copyflag():
|
| 654 |
+
# test the various copyflag options
|
| 655 |
+
arr = np.arange(10, dtype=np.intp)
|
| 656 |
+
|
| 657 |
+
res_true = arr.astype(np.intp, copy=True)
|
| 658 |
+
assert not np.shares_memory(arr, res_true)
|
| 659 |
+
|
| 660 |
+
res_false = arr.astype(np.intp, copy=False)
|
| 661 |
+
assert np.shares_memory(arr, res_false)
|
| 662 |
+
|
| 663 |
+
res_false_float = arr.astype(np.float64, copy=False)
|
| 664 |
+
assert not np.shares_memory(arr, res_false_float)
|
| 665 |
+
|
| 666 |
+
# _CopyMode enum isn't allowed
|
| 667 |
+
assert_raises(ValueError, arr.astype, np.float64,
|
| 668 |
+
copy=np._CopyMode.NEVER)
|
v12x/pylib/numpy/_core/tests/test_argparse.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Tests for the private NumPy argument parsing functionality.
|
| 3 |
+
They mainly exists to ensure good test coverage without having to try the
|
| 4 |
+
weirder cases on actual numpy functions but test them in one place.
|
| 5 |
+
|
| 6 |
+
The test function is defined in C to be equivalent to (errors may not always
|
| 7 |
+
match exactly, and could be adjusted):
|
| 8 |
+
|
| 9 |
+
def func(arg1, /, arg2, *, arg3):
|
| 10 |
+
i = integer(arg1) # reproducing the 'i' parsing in Python.
|
| 11 |
+
return None
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
import threading
|
| 15 |
+
|
| 16 |
+
import pytest
|
| 17 |
+
|
| 18 |
+
import numpy as np
|
| 19 |
+
from numpy._core._multiarray_tests import (
|
| 20 |
+
argparse_example_function as func,
|
| 21 |
+
threaded_argparse_example_function as thread_func,
|
| 22 |
+
)
|
| 23 |
+
from numpy.testing import IS_WASM
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
@pytest.mark.skipif(IS_WASM, reason="wasm doesn't have support for threads")
|
| 27 |
+
def test_thread_safe_argparse_cache():
|
| 28 |
+
b = threading.Barrier(8)
|
| 29 |
+
|
| 30 |
+
def call_thread_func():
|
| 31 |
+
b.wait()
|
| 32 |
+
thread_func(arg1=3, arg2=None)
|
| 33 |
+
|
| 34 |
+
tasks = [threading.Thread(target=call_thread_func) for _ in range(8)]
|
| 35 |
+
[t.start() for t in tasks]
|
| 36 |
+
[t.join() for t in tasks]
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def test_invalid_integers():
|
| 40 |
+
with pytest.raises(TypeError,
|
| 41 |
+
match="integer argument expected, got float"):
|
| 42 |
+
func(1.)
|
| 43 |
+
with pytest.raises(OverflowError):
|
| 44 |
+
func(2**100)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def test_missing_arguments():
|
| 48 |
+
with pytest.raises(TypeError,
|
| 49 |
+
match="missing required positional argument 0"):
|
| 50 |
+
func()
|
| 51 |
+
with pytest.raises(TypeError,
|
| 52 |
+
match="missing required positional argument 0"):
|
| 53 |
+
func(arg2=1, arg3=4)
|
| 54 |
+
with pytest.raises(TypeError,
|
| 55 |
+
match=r"missing required argument \'arg2\' \(pos 1\)"):
|
| 56 |
+
func(1, arg3=5)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def test_too_many_positional():
|
| 60 |
+
# the second argument is positional but can be passed as keyword.
|
| 61 |
+
with pytest.raises(TypeError,
|
| 62 |
+
match="takes from 2 to 3 positional arguments but 4 were given"):
|
| 63 |
+
func(1, 2, 3, 4)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def test_multiple_values():
|
| 67 |
+
with pytest.raises(TypeError,
|
| 68 |
+
match=r"given by name \('arg2'\) and position \(position 1\)"):
|
| 69 |
+
func(1, 2, arg2=3)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def test_string_fallbacks():
|
| 73 |
+
# We can (currently?) use numpy strings to test the "slow" fallbacks
|
| 74 |
+
# that should normally not be taken due to string interning.
|
| 75 |
+
arg2 = np.str_("arg2")
|
| 76 |
+
missing_arg = np.str_("missing_arg")
|
| 77 |
+
func(1, **{arg2: 3})
|
| 78 |
+
with pytest.raises(TypeError,
|
| 79 |
+
match="got an unexpected keyword argument 'missing_arg'"):
|
| 80 |
+
func(2, **{missing_arg: 3})
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def test_too_many_arguments_method_forwarding():
|
| 84 |
+
# Not directly related to the standard argument parsing, but we sometimes
|
| 85 |
+
# forward methods to Python: arr.mean() calls np._core._methods._mean()
|
| 86 |
+
# This adds code coverage for this `npy_forward_method`.
|
| 87 |
+
arr = np.arange(3)
|
| 88 |
+
args = range(1000)
|
| 89 |
+
with pytest.raises(TypeError):
|
| 90 |
+
arr.mean(*args)
|
v12x/pylib/numpy/_core/tests/test_array_api_info.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
|
| 5 |
+
info = np.__array_namespace_info__()
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_capabilities():
|
| 9 |
+
caps = info.capabilities()
|
| 10 |
+
assert caps["boolean indexing"] is True
|
| 11 |
+
assert caps["data-dependent shapes"] is True
|
| 12 |
+
|
| 13 |
+
# This will be added in the 2024.12 release of the array API standard.
|
| 14 |
+
|
| 15 |
+
# assert caps["max rank"] == 64
|
| 16 |
+
# np.zeros((1,)*64)
|
| 17 |
+
# with pytest.raises(ValueError):
|
| 18 |
+
# np.zeros((1,)*65)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def test_default_device():
|
| 22 |
+
assert info.default_device() == "cpu" == np.asarray(0).device
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def test_default_dtypes():
|
| 26 |
+
dtypes = info.default_dtypes()
|
| 27 |
+
assert dtypes["real floating"] == np.float64 == np.asarray(0.0).dtype
|
| 28 |
+
assert dtypes["complex floating"] == np.complex128 == \
|
| 29 |
+
np.asarray(0.0j).dtype
|
| 30 |
+
assert dtypes["integral"] == np.intp == np.asarray(0).dtype
|
| 31 |
+
assert dtypes["indexing"] == np.intp == np.argmax(np.zeros(10)).dtype
|
| 32 |
+
|
| 33 |
+
with pytest.raises(ValueError, match="Device not understood"):
|
| 34 |
+
info.default_dtypes(device="gpu")
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def test_dtypes_all():
|
| 38 |
+
dtypes = info.dtypes()
|
| 39 |
+
assert dtypes == {
|
| 40 |
+
"bool": np.bool_,
|
| 41 |
+
"int8": np.int8,
|
| 42 |
+
"int16": np.int16,
|
| 43 |
+
"int32": np.int32,
|
| 44 |
+
"int64": np.int64,
|
| 45 |
+
"uint8": np.uint8,
|
| 46 |
+
"uint16": np.uint16,
|
| 47 |
+
"uint32": np.uint32,
|
| 48 |
+
"uint64": np.uint64,
|
| 49 |
+
"float32": np.float32,
|
| 50 |
+
"float64": np.float64,
|
| 51 |
+
"complex64": np.complex64,
|
| 52 |
+
"complex128": np.complex128,
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
dtype_categories = {
|
| 57 |
+
"bool": {"bool": np.bool_},
|
| 58 |
+
"signed integer": {
|
| 59 |
+
"int8": np.int8,
|
| 60 |
+
"int16": np.int16,
|
| 61 |
+
"int32": np.int32,
|
| 62 |
+
"int64": np.int64,
|
| 63 |
+
},
|
| 64 |
+
"unsigned integer": {
|
| 65 |
+
"uint8": np.uint8,
|
| 66 |
+
"uint16": np.uint16,
|
| 67 |
+
"uint32": np.uint32,
|
| 68 |
+
"uint64": np.uint64,
|
| 69 |
+
},
|
| 70 |
+
"integral": ("signed integer", "unsigned integer"),
|
| 71 |
+
"real floating": {"float32": np.float32, "float64": np.float64},
|
| 72 |
+
"complex floating": {"complex64": np.complex64, "complex128":
|
| 73 |
+
np.complex128},
|
| 74 |
+
"numeric": ("integral", "real floating", "complex floating"),
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
@pytest.mark.parametrize("kind", dtype_categories)
|
| 79 |
+
def test_dtypes_kind(kind):
|
| 80 |
+
expected = dtype_categories[kind]
|
| 81 |
+
if isinstance(expected, tuple):
|
| 82 |
+
assert info.dtypes(kind=kind) == info.dtypes(kind=expected)
|
| 83 |
+
else:
|
| 84 |
+
assert info.dtypes(kind=kind) == expected
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def test_dtypes_tuple():
|
| 88 |
+
dtypes = info.dtypes(kind=("bool", "integral"))
|
| 89 |
+
assert dtypes == {
|
| 90 |
+
"bool": np.bool_,
|
| 91 |
+
"int8": np.int8,
|
| 92 |
+
"int16": np.int16,
|
| 93 |
+
"int32": np.int32,
|
| 94 |
+
"int64": np.int64,
|
| 95 |
+
"uint8": np.uint8,
|
| 96 |
+
"uint16": np.uint16,
|
| 97 |
+
"uint32": np.uint32,
|
| 98 |
+
"uint64": np.uint64,
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def test_dtypes_invalid_kind():
|
| 103 |
+
with pytest.raises(ValueError, match="unsupported kind"):
|
| 104 |
+
info.dtypes(kind="invalid")
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def test_dtypes_invalid_device():
|
| 108 |
+
with pytest.raises(ValueError, match="Device not understood"):
|
| 109 |
+
info.dtypes(device="gpu")
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def test_devices():
|
| 113 |
+
assert info.devices() == ("cpu",)
|
v12x/pylib/numpy/_core/tests/test_array_coercion.py
ADDED
|
@@ -0,0 +1,943 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Tests for array coercion, mainly through testing `np.array` results directly.
|
| 3 |
+
Note that other such tests exist, e.g., in `test_api.py` and many corner-cases
|
| 4 |
+
are tested (sometimes indirectly) elsewhere.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from itertools import permutations, product
|
| 8 |
+
|
| 9 |
+
import pytest
|
| 10 |
+
from pytest import param
|
| 11 |
+
|
| 12 |
+
import numpy as np
|
| 13 |
+
import numpy._core._multiarray_umath as ncu
|
| 14 |
+
from numpy._core._rational_tests import rational, rational2
|
| 15 |
+
from numpy.testing import IS_64BIT, assert_array_equal
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def arraylikes():
|
| 19 |
+
"""Test parameters for functions converting an array into various array-likes."""
|
| 20 |
+
|
| 21 |
+
params = []
|
| 22 |
+
|
| 23 |
+
# base array:
|
| 24 |
+
def ndarray(a):
|
| 25 |
+
return a
|
| 26 |
+
|
| 27 |
+
params.append(param(ndarray, id="ndarray"))
|
| 28 |
+
|
| 29 |
+
# subclass:
|
| 30 |
+
class MyArr(np.ndarray):
|
| 31 |
+
pass
|
| 32 |
+
|
| 33 |
+
def subclass(a):
|
| 34 |
+
return a.view(MyArr)
|
| 35 |
+
|
| 36 |
+
params.append(subclass)
|
| 37 |
+
|
| 38 |
+
class _SequenceLike:
|
| 39 |
+
# Older NumPy versions, sometimes cared whether a protocol array was
|
| 40 |
+
# also _SequenceLike. This shouldn't matter, but keep it for now
|
| 41 |
+
# for __array__ and not the others.
|
| 42 |
+
def __len__(self):
|
| 43 |
+
raise TypeError
|
| 44 |
+
|
| 45 |
+
def __getitem__(self, _, /):
|
| 46 |
+
raise TypeError
|
| 47 |
+
|
| 48 |
+
# Array-interface
|
| 49 |
+
class ArrayDunder(_SequenceLike):
|
| 50 |
+
def __init__(self, a):
|
| 51 |
+
self.a = a
|
| 52 |
+
|
| 53 |
+
def __array__(self, dtype=None, copy=None):
|
| 54 |
+
if dtype is None:
|
| 55 |
+
return self.a
|
| 56 |
+
return self.a.astype(dtype)
|
| 57 |
+
|
| 58 |
+
params.append(param(ArrayDunder, id="__array__"))
|
| 59 |
+
|
| 60 |
+
# memory-view
|
| 61 |
+
params.append(param(memoryview, id="memoryview"))
|
| 62 |
+
|
| 63 |
+
# Array-interface
|
| 64 |
+
class ArrayInterface:
|
| 65 |
+
def __init__(self, a):
|
| 66 |
+
self.a = a # need to hold on to keep interface valid
|
| 67 |
+
self.__array_interface__ = a.__array_interface__
|
| 68 |
+
|
| 69 |
+
params.append(param(ArrayInterface, id="__array_interface__"))
|
| 70 |
+
|
| 71 |
+
# Array-Struct
|
| 72 |
+
class ArrayStruct:
|
| 73 |
+
def __init__(self, a):
|
| 74 |
+
self.a = a # need to hold on to keep struct valid
|
| 75 |
+
self.__array_struct__ = a.__array_struct__
|
| 76 |
+
|
| 77 |
+
params.append(param(ArrayStruct, id="__array_struct__"))
|
| 78 |
+
|
| 79 |
+
return params
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def scalar_instances(times=True, extended_precision=True, user_dtype=True):
|
| 83 |
+
# Hard-coded list of scalar instances.
|
| 84 |
+
# Floats:
|
| 85 |
+
yield param(np.sqrt(np.float16(5)), id="float16")
|
| 86 |
+
yield param(np.sqrt(np.float32(5)), id="float32")
|
| 87 |
+
yield param(np.sqrt(np.float64(5)), id="float64")
|
| 88 |
+
if extended_precision:
|
| 89 |
+
yield param(np.sqrt(np.longdouble(5)), id="longdouble")
|
| 90 |
+
|
| 91 |
+
# Complex:
|
| 92 |
+
yield param(np.sqrt(np.complex64(2 + 3j)), id="complex64")
|
| 93 |
+
yield param(np.sqrt(np.complex128(2 + 3j)), id="complex128")
|
| 94 |
+
if extended_precision:
|
| 95 |
+
yield param(np.sqrt(np.clongdouble(2 + 3j)), id="clongdouble")
|
| 96 |
+
|
| 97 |
+
# Bool:
|
| 98 |
+
yield param(np.bool(0), id="bool")
|
| 99 |
+
|
| 100 |
+
# Integers:
|
| 101 |
+
yield param(np.int8(2), id="int8")
|
| 102 |
+
yield param(np.int16(2), id="int16")
|
| 103 |
+
yield param(np.int32(2), id="int32")
|
| 104 |
+
yield param(np.int64(2), id="int64")
|
| 105 |
+
|
| 106 |
+
yield param(np.uint8(2), id="uint8")
|
| 107 |
+
yield param(np.uint16(2), id="uint16")
|
| 108 |
+
yield param(np.uint32(2), id="uint32")
|
| 109 |
+
yield param(np.uint64(2), id="uint64")
|
| 110 |
+
|
| 111 |
+
# Rational:
|
| 112 |
+
if user_dtype:
|
| 113 |
+
yield param(rational(1, 2), id="rational")
|
| 114 |
+
yield param(rational2(1, 2), id="rational2")
|
| 115 |
+
|
| 116 |
+
# Cannot create a structured void scalar directly:
|
| 117 |
+
structured = np.array([(1, 3)], "i,i")[0]
|
| 118 |
+
assert isinstance(structured, np.void)
|
| 119 |
+
assert structured.dtype == np.dtype("i,i")
|
| 120 |
+
yield param(structured, id="structured")
|
| 121 |
+
|
| 122 |
+
if times:
|
| 123 |
+
# Datetimes and timedelta
|
| 124 |
+
yield param(np.timedelta64(2, "ns"), id="timedelta64[ns]")
|
| 125 |
+
yield param(np.timedelta64(23, "s"), id="timedelta64[s]")
|
| 126 |
+
yield param(np.timedelta64("NaT", "s"), id="timedelta64[s](NaT)")
|
| 127 |
+
|
| 128 |
+
yield param(np.datetime64("NaT", "D"), id="datetime64[D](NaT)")
|
| 129 |
+
yield param(np.datetime64("2020-06-07 12:43", "ms"), id="datetime64[ms]")
|
| 130 |
+
|
| 131 |
+
# Strings and unstructured void:
|
| 132 |
+
yield param(np.bytes_(b"1234"), id="bytes")
|
| 133 |
+
yield param(np.str_("2345"), id="unicode")
|
| 134 |
+
yield param(np.void(b"4321"), id="unstructured_void")
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def is_parametric_dtype(dtype):
|
| 138 |
+
"""Returns True if the dtype is a parametric legacy dtype (itemsize
|
| 139 |
+
is 0, or a datetime without units)
|
| 140 |
+
"""
|
| 141 |
+
if dtype.itemsize == 0:
|
| 142 |
+
return True
|
| 143 |
+
if issubclass(dtype.type, (np.datetime64, np.timedelta64)):
|
| 144 |
+
if dtype.name.endswith("64"):
|
| 145 |
+
# Generic time units
|
| 146 |
+
return True
|
| 147 |
+
return False
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class TestStringDiscovery:
|
| 151 |
+
@pytest.mark.parametrize("obj",
|
| 152 |
+
[object(), 1.2, 10**43, None, "string"],
|
| 153 |
+
ids=["object", "1.2", "10**43", "None", "string"])
|
| 154 |
+
def test_basic_stringlength(self, obj):
|
| 155 |
+
length = len(str(obj))
|
| 156 |
+
expected = np.dtype(f"S{length}")
|
| 157 |
+
|
| 158 |
+
assert np.array(obj, dtype="S").dtype == expected
|
| 159 |
+
assert np.array([obj], dtype="S").dtype == expected
|
| 160 |
+
|
| 161 |
+
# A nested array is also discovered correctly
|
| 162 |
+
arr = np.array(obj, dtype="O")
|
| 163 |
+
assert np.array(arr, dtype="S").dtype == expected
|
| 164 |
+
# Also if we use the dtype class
|
| 165 |
+
assert np.array(arr, dtype=type(expected)).dtype == expected
|
| 166 |
+
# Check that .astype() behaves identical
|
| 167 |
+
assert arr.astype("S").dtype == expected
|
| 168 |
+
# The DType class is accepted by `.astype()`
|
| 169 |
+
assert arr.astype(type(np.dtype("S"))).dtype == expected
|
| 170 |
+
|
| 171 |
+
@pytest.mark.parametrize("obj",
|
| 172 |
+
[object(), 1.2, 10**43, None, "string"],
|
| 173 |
+
ids=["object", "1.2", "10**43", "None", "string"])
|
| 174 |
+
def test_nested_arrays_stringlength(self, obj):
|
| 175 |
+
length = len(str(obj))
|
| 176 |
+
expected = np.dtype(f"S{length}")
|
| 177 |
+
arr = np.array(obj, dtype="O")
|
| 178 |
+
assert np.array([arr, arr], dtype="S").dtype == expected
|
| 179 |
+
|
| 180 |
+
@pytest.mark.parametrize("arraylike", arraylikes())
|
| 181 |
+
def test_unpack_first_level(self, arraylike):
|
| 182 |
+
# We unpack exactly one level of array likes
|
| 183 |
+
obj = np.array([None])
|
| 184 |
+
obj[0] = np.array(1.2)
|
| 185 |
+
# the length of the included item, not of the float dtype
|
| 186 |
+
length = len(str(obj[0]))
|
| 187 |
+
expected = np.dtype(f"S{length}")
|
| 188 |
+
|
| 189 |
+
obj = arraylike(obj)
|
| 190 |
+
# casting to string usually calls str(obj)
|
| 191 |
+
arr = np.array([obj], dtype="S")
|
| 192 |
+
assert arr.shape == (1, 1)
|
| 193 |
+
assert arr.dtype == expected
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
class TestScalarDiscovery:
|
| 197 |
+
def test_void_special_case(self):
|
| 198 |
+
# Void dtypes with structures discover tuples as elements
|
| 199 |
+
arr = np.array((1, 2, 3), dtype="i,i,i")
|
| 200 |
+
assert arr.shape == ()
|
| 201 |
+
arr = np.array([(1, 2, 3)], dtype="i,i,i")
|
| 202 |
+
assert arr.shape == (1,)
|
| 203 |
+
|
| 204 |
+
def test_char_special_case(self):
|
| 205 |
+
arr = np.array("string", dtype="c")
|
| 206 |
+
assert arr.shape == (6,)
|
| 207 |
+
assert arr.dtype.char == "c"
|
| 208 |
+
arr = np.array(["string"], dtype="c")
|
| 209 |
+
assert arr.shape == (1, 6)
|
| 210 |
+
assert arr.dtype.char == "c"
|
| 211 |
+
|
| 212 |
+
def test_char_special_case_deep(self):
|
| 213 |
+
# Check that the character special case errors correctly if the
|
| 214 |
+
# array is too deep:
|
| 215 |
+
nested = ["string"] # 2 dimensions (due to string being sequence)
|
| 216 |
+
for i in range(ncu.MAXDIMS - 2):
|
| 217 |
+
nested = [nested]
|
| 218 |
+
|
| 219 |
+
arr = np.array(nested, dtype='c')
|
| 220 |
+
assert arr.shape == (1,) * (ncu.MAXDIMS - 1) + (6,)
|
| 221 |
+
with pytest.raises(ValueError):
|
| 222 |
+
np.array([nested], dtype="c")
|
| 223 |
+
|
| 224 |
+
def test_unknown_object(self):
|
| 225 |
+
arr = np.array(object())
|
| 226 |
+
assert arr.shape == ()
|
| 227 |
+
assert arr.dtype == np.dtype("O")
|
| 228 |
+
|
| 229 |
+
@pytest.mark.parametrize("scalar", list(scalar_instances()))
|
| 230 |
+
def test_scalar(self, scalar):
|
| 231 |
+
arr = np.array(scalar)
|
| 232 |
+
assert arr.shape == ()
|
| 233 |
+
assert arr.dtype == scalar.dtype
|
| 234 |
+
|
| 235 |
+
arr = np.array([[scalar, scalar]])
|
| 236 |
+
assert arr.shape == (1, 2)
|
| 237 |
+
assert arr.dtype == scalar.dtype
|
| 238 |
+
|
| 239 |
+
# Additionally to string this test also runs into a corner case
|
| 240 |
+
# with datetime promotion (the difference is the promotion order).
|
| 241 |
+
@pytest.mark.filterwarnings("ignore:Promotion of numbers:FutureWarning")
|
| 242 |
+
def test_scalar_promotion(self):
|
| 243 |
+
for sc1, sc2 in product(scalar_instances(), scalar_instances()):
|
| 244 |
+
sc1, sc2 = sc1.values[0], sc2.values[0]
|
| 245 |
+
# test all combinations:
|
| 246 |
+
try:
|
| 247 |
+
arr = np.array([sc1, sc2])
|
| 248 |
+
except (TypeError, ValueError):
|
| 249 |
+
# The promotion between two times can fail
|
| 250 |
+
# XFAIL (ValueError): Some object casts are currently undefined
|
| 251 |
+
continue
|
| 252 |
+
assert arr.shape == (2,)
|
| 253 |
+
try:
|
| 254 |
+
dt1, dt2 = sc1.dtype, sc2.dtype
|
| 255 |
+
expected_dtype = np.promote_types(dt1, dt2)
|
| 256 |
+
assert arr.dtype == expected_dtype
|
| 257 |
+
except TypeError as e:
|
| 258 |
+
# Will currently always go to object dtype
|
| 259 |
+
assert arr.dtype == np.dtype("O")
|
| 260 |
+
|
| 261 |
+
@pytest.mark.parametrize("scalar", list(scalar_instances()))
|
| 262 |
+
def test_scalar_coercion(self, scalar):
|
| 263 |
+
# This tests various scalar coercion paths, mainly for the numerical
|
| 264 |
+
# types. It includes some paths not directly related to `np.array`.
|
| 265 |
+
if isinstance(scalar, np.inexact):
|
| 266 |
+
# Ensure we have a full-precision number if available
|
| 267 |
+
scalar = type(scalar)((scalar * 2)**0.5)
|
| 268 |
+
|
| 269 |
+
# Use casting from object:
|
| 270 |
+
arr = np.array(scalar, dtype=object).astype(scalar.dtype)
|
| 271 |
+
|
| 272 |
+
# Test various ways to create an array containing this scalar:
|
| 273 |
+
arr1 = np.array(scalar).reshape(1)
|
| 274 |
+
arr2 = np.array([scalar])
|
| 275 |
+
arr3 = np.empty(1, dtype=scalar.dtype)
|
| 276 |
+
arr3[0] = scalar
|
| 277 |
+
arr4 = np.empty(1, dtype=scalar.dtype)
|
| 278 |
+
arr4[:] = [scalar]
|
| 279 |
+
# All of these methods should yield the same results
|
| 280 |
+
assert_array_equal(arr, arr1)
|
| 281 |
+
assert_array_equal(arr, arr2)
|
| 282 |
+
assert_array_equal(arr, arr3)
|
| 283 |
+
assert_array_equal(arr, arr4)
|
| 284 |
+
|
| 285 |
+
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
|
| 286 |
+
@pytest.mark.parametrize("cast_to", list(scalar_instances()))
|
| 287 |
+
def test_scalar_coercion_same_as_cast_and_assignment(self, cast_to):
|
| 288 |
+
"""
|
| 289 |
+
Test that in most cases:
|
| 290 |
+
* `np.array(scalar, dtype=dtype)`
|
| 291 |
+
* `np.empty((), dtype=dtype)[()] = scalar`
|
| 292 |
+
* `np.array(scalar).astype(dtype)`
|
| 293 |
+
should behave the same. The only exceptions are parametric dtypes
|
| 294 |
+
(mainly datetime/timedelta without unit) and void without fields.
|
| 295 |
+
"""
|
| 296 |
+
dtype = cast_to.dtype # use to parametrize only the target dtype
|
| 297 |
+
|
| 298 |
+
for scalar in scalar_instances(times=False):
|
| 299 |
+
scalar = scalar.values[0]
|
| 300 |
+
|
| 301 |
+
if dtype.type == np.void:
|
| 302 |
+
if scalar.dtype.fields is not None and dtype.fields is None:
|
| 303 |
+
# Here, coercion to "V6" works, but the cast fails.
|
| 304 |
+
# Since the types are identical, SETITEM takes care of
|
| 305 |
+
# this, but has different rules than the cast.
|
| 306 |
+
with pytest.raises(TypeError):
|
| 307 |
+
np.array(scalar).astype(dtype)
|
| 308 |
+
np.array(scalar, dtype=dtype)
|
| 309 |
+
np.array([scalar], dtype=dtype)
|
| 310 |
+
continue
|
| 311 |
+
|
| 312 |
+
# The main test, we first try to use casting and if it succeeds
|
| 313 |
+
# continue below testing that things are the same, otherwise
|
| 314 |
+
# test that the alternative paths at least also fail.
|
| 315 |
+
try:
|
| 316 |
+
cast = np.array(scalar).astype(dtype)
|
| 317 |
+
except (TypeError, ValueError, RuntimeError):
|
| 318 |
+
# coercion should also raise (error type may change)
|
| 319 |
+
with pytest.raises(Exception): # noqa: B017
|
| 320 |
+
np.array(scalar, dtype=dtype)
|
| 321 |
+
|
| 322 |
+
if (isinstance(scalar, rational) and
|
| 323 |
+
np.issubdtype(dtype, np.signedinteger)):
|
| 324 |
+
return
|
| 325 |
+
|
| 326 |
+
with pytest.raises(Exception): # noqa: B017
|
| 327 |
+
np.array([scalar], dtype=dtype)
|
| 328 |
+
# assignment should also raise
|
| 329 |
+
res = np.zeros((), dtype=dtype)
|
| 330 |
+
with pytest.raises(Exception): # noqa: B017
|
| 331 |
+
res[()] = scalar
|
| 332 |
+
|
| 333 |
+
return
|
| 334 |
+
|
| 335 |
+
# Non error path:
|
| 336 |
+
arr = np.array(scalar, dtype=dtype)
|
| 337 |
+
assert_array_equal(arr, cast)
|
| 338 |
+
# assignment behaves the same
|
| 339 |
+
ass = np.zeros((), dtype=dtype)
|
| 340 |
+
ass[()] = scalar
|
| 341 |
+
assert_array_equal(ass, cast)
|
| 342 |
+
|
| 343 |
+
@pytest.mark.parametrize("pyscalar", [10, 10.32, 10.14j, 10**100])
|
| 344 |
+
def test_pyscalar_subclasses(self, pyscalar):
|
| 345 |
+
"""NumPy arrays are read/write which means that anything but invariant
|
| 346 |
+
behaviour is on thin ice. However, we currently are happy to discover
|
| 347 |
+
subclasses of Python float, int, complex the same as the base classes.
|
| 348 |
+
This should potentially be deprecated.
|
| 349 |
+
"""
|
| 350 |
+
class MyScalar(type(pyscalar)):
|
| 351 |
+
pass
|
| 352 |
+
|
| 353 |
+
res = np.array(MyScalar(pyscalar))
|
| 354 |
+
expected = np.array(pyscalar)
|
| 355 |
+
assert_array_equal(res, expected)
|
| 356 |
+
|
| 357 |
+
@pytest.mark.parametrize("dtype_char", np.typecodes["All"])
|
| 358 |
+
def test_default_dtype_instance(self, dtype_char):
|
| 359 |
+
if dtype_char in "SU":
|
| 360 |
+
dtype = np.dtype(dtype_char + "1")
|
| 361 |
+
elif dtype_char == "V":
|
| 362 |
+
# Legacy behaviour was to use V8. The reason was float64 being the
|
| 363 |
+
# default dtype and that having 8 bytes.
|
| 364 |
+
dtype = np.dtype("V8")
|
| 365 |
+
else:
|
| 366 |
+
dtype = np.dtype(dtype_char)
|
| 367 |
+
|
| 368 |
+
discovered_dtype, _ = ncu._discover_array_parameters([], type(dtype))
|
| 369 |
+
|
| 370 |
+
assert discovered_dtype == dtype
|
| 371 |
+
assert discovered_dtype.itemsize == dtype.itemsize
|
| 372 |
+
|
| 373 |
+
@pytest.mark.parametrize("dtype", np.typecodes["Integer"])
|
| 374 |
+
@pytest.mark.parametrize(["scalar", "error"],
|
| 375 |
+
[(np.float64(np.nan), ValueError),
|
| 376 |
+
(np.array(-1).astype(np.ulonglong)[()], OverflowError)])
|
| 377 |
+
def test_scalar_to_int_coerce_does_not_cast(self, dtype, scalar, error):
|
| 378 |
+
"""
|
| 379 |
+
Signed integers are currently different in that they do not cast other
|
| 380 |
+
NumPy scalar, but instead use scalar.__int__(). The hardcoded
|
| 381 |
+
exception to this rule is `np.array(scalar, dtype=integer)`.
|
| 382 |
+
"""
|
| 383 |
+
dtype = np.dtype(dtype)
|
| 384 |
+
|
| 385 |
+
# This is a special case using casting logic. It warns for the NaN
|
| 386 |
+
# but allows the cast (giving undefined behaviour).
|
| 387 |
+
with np.errstate(invalid="ignore"):
|
| 388 |
+
coerced = np.array(scalar, dtype=dtype)
|
| 389 |
+
cast = np.array(scalar).astype(dtype)
|
| 390 |
+
assert_array_equal(coerced, cast)
|
| 391 |
+
|
| 392 |
+
# However these fail:
|
| 393 |
+
with pytest.raises(error):
|
| 394 |
+
np.array([scalar], dtype=dtype)
|
| 395 |
+
with pytest.raises(error):
|
| 396 |
+
cast[()] = scalar
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
class TestTimeScalars:
|
| 400 |
+
@pytest.mark.parametrize("dtype", [np.int64, np.float32])
|
| 401 |
+
@pytest.mark.parametrize("scalar",
|
| 402 |
+
[param(np.timedelta64("NaT", "s"), id="timedelta64[s](NaT)"),
|
| 403 |
+
param(np.timedelta64(123, "s"), id="timedelta64[s]"),
|
| 404 |
+
param(np.datetime64("NaT", "D"), id="datetime64[D](NaT)"),
|
| 405 |
+
param(np.datetime64(1, "D"), id="datetime64[D]")],)
|
| 406 |
+
def test_coercion_basic(self, dtype, scalar):
|
| 407 |
+
# Note the `[scalar]` is there because np.array(scalar) uses stricter
|
| 408 |
+
# `scalar.__int__()` rules for backward compatibility right now.
|
| 409 |
+
arr = np.array(scalar, dtype=dtype)
|
| 410 |
+
cast = np.array(scalar).astype(dtype)
|
| 411 |
+
assert_array_equal(arr, cast)
|
| 412 |
+
|
| 413 |
+
ass = np.ones((), dtype=dtype)
|
| 414 |
+
if issubclass(dtype, np.integer):
|
| 415 |
+
with pytest.raises(TypeError):
|
| 416 |
+
# raises, as would np.array([scalar], dtype=dtype), this is
|
| 417 |
+
# conversion from times, but behaviour of integers.
|
| 418 |
+
ass[()] = scalar
|
| 419 |
+
else:
|
| 420 |
+
ass[()] = scalar
|
| 421 |
+
assert_array_equal(ass, cast)
|
| 422 |
+
|
| 423 |
+
@pytest.mark.parametrize("dtype", [np.int64, np.float32])
|
| 424 |
+
@pytest.mark.parametrize("value, unit", [param(123, "ns", id="timedelta64[ns]")])
|
| 425 |
+
def test_coercion_timedelta_convert_to_number(self, dtype, value, unit):
|
| 426 |
+
# Only "ns" and "generic" timedeltas can be converted to numbers
|
| 427 |
+
# so these are slightly special.
|
| 428 |
+
scalar = np.timedelta64(value, unit)
|
| 429 |
+
arr = np.array(scalar, dtype=dtype)
|
| 430 |
+
cast = np.array(scalar).astype(dtype)
|
| 431 |
+
ass = np.ones((), dtype=dtype)
|
| 432 |
+
ass[()] = scalar # raises, as would np.array([scalar], dtype=dtype)
|
| 433 |
+
|
| 434 |
+
assert_array_equal(arr, cast)
|
| 435 |
+
assert_array_equal(cast, cast)
|
| 436 |
+
|
| 437 |
+
@pytest.mark.parametrize("dtype", [np.int64, np.float32])
|
| 438 |
+
@pytest.mark.parametrize("value, unit",
|
| 439 |
+
[param(12, "generic", id="timedelta64[generic]")])
|
| 440 |
+
def test_coercion_generic_timedelta_convert_to_number(self, dtype, value, unit):
|
| 441 |
+
with pytest.warns(
|
| 442 |
+
DeprecationWarning,
|
| 443 |
+
match="The 'generic' unit for NumPy timedelta is deprecated",
|
| 444 |
+
):
|
| 445 |
+
scalar = np.timedelta64(value, unit)
|
| 446 |
+
arr = np.array(scalar, dtype=dtype)
|
| 447 |
+
cast = np.array(scalar).astype(dtype)
|
| 448 |
+
ass = np.ones((), dtype=dtype)
|
| 449 |
+
ass[()] = scalar # raises, as would np.array([scalar], dtype=dtype)
|
| 450 |
+
|
| 451 |
+
assert_array_equal(arr, cast)
|
| 452 |
+
assert_array_equal(cast, cast)
|
| 453 |
+
|
| 454 |
+
@pytest.mark.parametrize("dtype", ["S6", "U6"])
|
| 455 |
+
@pytest.mark.parametrize(["val", "unit"],
|
| 456 |
+
[param(123, "s", id="[s]"), param(123, "D", id="[D]")])
|
| 457 |
+
def test_coercion_assignment_datetime(self, val, unit, dtype):
|
| 458 |
+
# String from datetime64 assignment is currently special cased to
|
| 459 |
+
# never use casting. This is because casting will error in this
|
| 460 |
+
# case, and traditionally in most cases the behaviour is maintained
|
| 461 |
+
# like this. (`np.array(scalar, dtype="U6")` would have failed before)
|
| 462 |
+
# TODO: This discrepancy _should_ be resolved, either by relaxing the
|
| 463 |
+
# cast, or by deprecating the first part.
|
| 464 |
+
scalar = np.datetime64(val, unit)
|
| 465 |
+
dtype = np.dtype(dtype)
|
| 466 |
+
cut_string = dtype.type(str(scalar)[:6])
|
| 467 |
+
|
| 468 |
+
arr = np.array(scalar, dtype=dtype)
|
| 469 |
+
assert arr[()] == cut_string
|
| 470 |
+
ass = np.ones((), dtype=dtype)
|
| 471 |
+
ass[()] = scalar
|
| 472 |
+
assert ass[()] == cut_string
|
| 473 |
+
|
| 474 |
+
with pytest.raises(RuntimeError):
|
| 475 |
+
# However, unlike the above assignment using `str(scalar)[:6]`
|
| 476 |
+
# due to being handled by the string DType and not be casting
|
| 477 |
+
# the explicit cast fails:
|
| 478 |
+
np.array(scalar).astype(dtype)
|
| 479 |
+
|
| 480 |
+
@pytest.mark.parametrize(["val", "unit"],
|
| 481 |
+
[param(123, "s", id="[s]"), param(123, "D", id="[D]")])
|
| 482 |
+
def test_coercion_assignment_timedelta(self, val, unit):
|
| 483 |
+
scalar = np.timedelta64(val, unit)
|
| 484 |
+
|
| 485 |
+
# Unlike datetime64, timedelta allows the unsafe cast:
|
| 486 |
+
np.array(scalar, dtype="S6")
|
| 487 |
+
cast = np.array(scalar).astype("S6")
|
| 488 |
+
ass = np.ones((), dtype="S6")
|
| 489 |
+
ass[()] = scalar
|
| 490 |
+
expected = scalar.astype("S")[:6]
|
| 491 |
+
assert cast[()] == expected
|
| 492 |
+
assert ass[()] == expected
|
| 493 |
+
|
| 494 |
+
class TestNested:
|
| 495 |
+
def test_nested_simple(self):
|
| 496 |
+
initial = [1.2]
|
| 497 |
+
nested = initial
|
| 498 |
+
for i in range(ncu.MAXDIMS - 1):
|
| 499 |
+
nested = [nested]
|
| 500 |
+
|
| 501 |
+
arr = np.array(nested, dtype="float64")
|
| 502 |
+
assert arr.shape == (1,) * ncu.MAXDIMS
|
| 503 |
+
with pytest.raises(ValueError):
|
| 504 |
+
np.array([nested], dtype="float64")
|
| 505 |
+
|
| 506 |
+
with pytest.raises(ValueError, match=".*would exceed the maximum"):
|
| 507 |
+
np.array([nested]) # user must ask for `object` explicitly
|
| 508 |
+
|
| 509 |
+
arr = np.array([nested], dtype=object)
|
| 510 |
+
assert arr.dtype == np.dtype("O")
|
| 511 |
+
assert arr.shape == (1,) * ncu.MAXDIMS
|
| 512 |
+
assert arr.item() is initial
|
| 513 |
+
|
| 514 |
+
def test_pathological_self_containing(self):
|
| 515 |
+
# Test that this also works for two nested sequences
|
| 516 |
+
l = []
|
| 517 |
+
l.append(l)
|
| 518 |
+
arr = np.array([l, l, l], dtype=object)
|
| 519 |
+
assert arr.shape == (3,) + (1,) * (ncu.MAXDIMS - 1)
|
| 520 |
+
|
| 521 |
+
# Also check a ragged case:
|
| 522 |
+
arr = np.array([l, [None], l], dtype=object)
|
| 523 |
+
assert arr.shape == (3, 1)
|
| 524 |
+
|
| 525 |
+
@pytest.mark.parametrize("arraylike", arraylikes())
|
| 526 |
+
def test_nested_arraylikes(self, arraylike):
|
| 527 |
+
# We try storing an array like into an array, but the array-like
|
| 528 |
+
# will have too many dimensions. This means the shape discovery
|
| 529 |
+
# decides that the array-like must be treated as an object (a special
|
| 530 |
+
# case of ragged discovery). The result will be an array with one
|
| 531 |
+
# dimension less than the maximum dimensions, and the array being
|
| 532 |
+
# assigned to it (which does work for object or if `float(arraylike)`
|
| 533 |
+
# works).
|
| 534 |
+
initial = arraylike(np.ones((1, 1)))
|
| 535 |
+
|
| 536 |
+
nested = initial
|
| 537 |
+
for i in range(ncu.MAXDIMS - 1):
|
| 538 |
+
nested = [nested]
|
| 539 |
+
|
| 540 |
+
with pytest.raises(ValueError, match=".*would exceed the maximum"):
|
| 541 |
+
# It will refuse to assign the array into
|
| 542 |
+
np.array(nested, dtype="float64")
|
| 543 |
+
|
| 544 |
+
# If this is object, we end up assigning a (1, 1) array into (1,)
|
| 545 |
+
# (due to running out of dimensions), this is currently supported but
|
| 546 |
+
# a special case which is not ideal.
|
| 547 |
+
arr = np.array(nested, dtype=object)
|
| 548 |
+
assert arr.shape == (1,) * ncu.MAXDIMS
|
| 549 |
+
assert arr.item() == np.array(initial).item()
|
| 550 |
+
|
| 551 |
+
@pytest.mark.parametrize("arraylike", arraylikes())
|
| 552 |
+
def test_uneven_depth_ragged(self, arraylike):
|
| 553 |
+
arr = np.arange(4).reshape((2, 2))
|
| 554 |
+
arr = arraylike(arr)
|
| 555 |
+
|
| 556 |
+
# Array is ragged in the second dimension already:
|
| 557 |
+
out = np.array([arr, [arr]], dtype=object)
|
| 558 |
+
assert out.shape == (2,)
|
| 559 |
+
assert out[0] is arr
|
| 560 |
+
assert type(out[1]) is list
|
| 561 |
+
|
| 562 |
+
# Array is ragged in the third dimension:
|
| 563 |
+
with pytest.raises(ValueError):
|
| 564 |
+
# This is a broadcast error during assignment, because
|
| 565 |
+
# the array shape would be (2, 2, 2) but `arr[0, 0] = arr` fails.
|
| 566 |
+
np.array([arr, [arr, arr]], dtype=object)
|
| 567 |
+
|
| 568 |
+
def test_empty_sequence(self):
|
| 569 |
+
arr = np.array([[], [1], [[1]]], dtype=object)
|
| 570 |
+
assert arr.shape == (3,)
|
| 571 |
+
|
| 572 |
+
# The empty sequence stops further dimension discovery, so the
|
| 573 |
+
# result shape will be (0,) which leads to an error during:
|
| 574 |
+
with pytest.raises(ValueError):
|
| 575 |
+
np.array([[], np.empty((0, 1))], dtype=object)
|
| 576 |
+
|
| 577 |
+
def test_array_of_different_depths(self):
|
| 578 |
+
# When multiple arrays (or array-likes) are included in a
|
| 579 |
+
# sequences and have different depth, we currently discover
|
| 580 |
+
# as many dimensions as they share. (see also gh-17224)
|
| 581 |
+
arr = np.zeros((3, 2))
|
| 582 |
+
mismatch_first_dim = np.zeros((1, 2))
|
| 583 |
+
mismatch_second_dim = np.zeros((3, 3))
|
| 584 |
+
|
| 585 |
+
dtype, shape = ncu._discover_array_parameters(
|
| 586 |
+
[arr, mismatch_second_dim], dtype=np.dtype("O"))
|
| 587 |
+
assert shape == (2, 3)
|
| 588 |
+
|
| 589 |
+
dtype, shape = ncu._discover_array_parameters(
|
| 590 |
+
[arr, mismatch_first_dim], dtype=np.dtype("O"))
|
| 591 |
+
assert shape == (2,)
|
| 592 |
+
# The second case is currently supported because the arrays
|
| 593 |
+
# can be stored as objects:
|
| 594 |
+
res = np.asarray([arr, mismatch_first_dim], dtype=np.dtype("O"))
|
| 595 |
+
assert res[0] is arr
|
| 596 |
+
assert res[1] is mismatch_first_dim
|
| 597 |
+
|
| 598 |
+
|
| 599 |
+
class TestBadSequences:
|
| 600 |
+
# These are tests for bad objects passed into `np.array`, in general
|
| 601 |
+
# these have undefined behaviour. In the old code they partially worked
|
| 602 |
+
# when now they will fail. We could (and maybe should) create a copy
|
| 603 |
+
# of all sequences to be safe against bad-actors.
|
| 604 |
+
|
| 605 |
+
def test_growing_list(self):
|
| 606 |
+
# List to coerce, `mylist` will append to it during coercion
|
| 607 |
+
obj = []
|
| 608 |
+
|
| 609 |
+
class mylist(list):
|
| 610 |
+
def __len__(self):
|
| 611 |
+
obj.append([1, 2])
|
| 612 |
+
return super().__len__()
|
| 613 |
+
|
| 614 |
+
obj.append(mylist([1, 2]))
|
| 615 |
+
|
| 616 |
+
with pytest.raises(RuntimeError):
|
| 617 |
+
np.array(obj)
|
| 618 |
+
|
| 619 |
+
# Note: We do not test a shrinking list. These do very evil things
|
| 620 |
+
# and the only way to fix them would be to copy all sequences.
|
| 621 |
+
# (which may be a real option in the future).
|
| 622 |
+
|
| 623 |
+
def test_mutated_list(self):
|
| 624 |
+
# List to coerce, `mylist` will mutate the first element
|
| 625 |
+
obj = []
|
| 626 |
+
|
| 627 |
+
class mylist(list):
|
| 628 |
+
def __len__(self):
|
| 629 |
+
obj[0] = [2, 3] # replace with a different list.
|
| 630 |
+
return super().__len__()
|
| 631 |
+
|
| 632 |
+
obj.append([2, 3])
|
| 633 |
+
obj.append(mylist([1, 2]))
|
| 634 |
+
# Does not crash:
|
| 635 |
+
np.array(obj)
|
| 636 |
+
|
| 637 |
+
def test_replace_0d_array(self):
|
| 638 |
+
# List to coerce, `mylist` will mutate the first element
|
| 639 |
+
obj = []
|
| 640 |
+
|
| 641 |
+
class baditem:
|
| 642 |
+
def __len__(self):
|
| 643 |
+
obj[0][0] = 2 # replace with a different list.
|
| 644 |
+
raise ValueError("not actually a sequence!")
|
| 645 |
+
|
| 646 |
+
def __getitem__(self, _, /):
|
| 647 |
+
pass
|
| 648 |
+
|
| 649 |
+
# Runs into a corner case in the new code, the `array(2)` is cached
|
| 650 |
+
# so replacing it invalidates the cache.
|
| 651 |
+
obj.append([np.array(2), baditem()])
|
| 652 |
+
with pytest.raises(RuntimeError):
|
| 653 |
+
np.array(obj)
|
| 654 |
+
|
| 655 |
+
|
| 656 |
+
class TestArrayLikes:
|
| 657 |
+
@pytest.mark.parametrize("arraylike", arraylikes())
|
| 658 |
+
def test_0d_object_special_case(self, arraylike):
|
| 659 |
+
arr = np.array(0.)
|
| 660 |
+
obj = arraylike(arr)
|
| 661 |
+
# A single array-like is always converted:
|
| 662 |
+
res = np.array(obj, dtype=object)
|
| 663 |
+
assert_array_equal(arr, res)
|
| 664 |
+
|
| 665 |
+
# But a single 0-D nested array-like never:
|
| 666 |
+
res = np.array([obj], dtype=object)
|
| 667 |
+
assert res[0] is obj
|
| 668 |
+
|
| 669 |
+
@pytest.mark.parametrize("arraylike", arraylikes())
|
| 670 |
+
@pytest.mark.parametrize("arr", [np.array(0.), np.arange(4)])
|
| 671 |
+
def test_object_assignment_special_case(self, arraylike, arr):
|
| 672 |
+
obj = arraylike(arr)
|
| 673 |
+
empty = np.arange(1, dtype=object)
|
| 674 |
+
empty[:] = [obj]
|
| 675 |
+
assert empty[0] is obj
|
| 676 |
+
|
| 677 |
+
def test_0d_generic_special_case(self):
|
| 678 |
+
class ArraySubclass(np.ndarray):
|
| 679 |
+
def __float__(self):
|
| 680 |
+
raise TypeError("e.g. quantities raise on this")
|
| 681 |
+
|
| 682 |
+
arr = np.array(0.)
|
| 683 |
+
obj = arr.view(ArraySubclass)
|
| 684 |
+
res = np.array(obj)
|
| 685 |
+
# The subclass is simply cast:
|
| 686 |
+
assert_array_equal(arr, res)
|
| 687 |
+
|
| 688 |
+
# If the 0-D array-like is included, __float__ is currently
|
| 689 |
+
# guaranteed to be used. We may want to change that, quantities
|
| 690 |
+
# and masked arrays half make use of this.
|
| 691 |
+
with pytest.raises(TypeError):
|
| 692 |
+
np.array([obj])
|
| 693 |
+
|
| 694 |
+
# The same holds for memoryview:
|
| 695 |
+
obj = memoryview(arr)
|
| 696 |
+
res = np.array(obj)
|
| 697 |
+
assert_array_equal(arr, res)
|
| 698 |
+
with pytest.raises(ValueError):
|
| 699 |
+
# The error type does not matter much here.
|
| 700 |
+
np.array([obj])
|
| 701 |
+
|
| 702 |
+
def test_arraylike_classes(self):
|
| 703 |
+
# The classes of array-likes should generally be acceptable to be
|
| 704 |
+
# stored inside a numpy (object) array. This tests all of the
|
| 705 |
+
# special attributes (since all are checked during coercion).
|
| 706 |
+
arr = np.array(np.int64)
|
| 707 |
+
assert arr[()] is np.int64
|
| 708 |
+
arr = np.array([np.int64])
|
| 709 |
+
assert arr[0] is np.int64
|
| 710 |
+
|
| 711 |
+
# This also works for properties/unbound methods:
|
| 712 |
+
class ArrayLike:
|
| 713 |
+
@property
|
| 714 |
+
def __array_interface__(self):
|
| 715 |
+
pass
|
| 716 |
+
|
| 717 |
+
@property
|
| 718 |
+
def __array_struct__(self):
|
| 719 |
+
pass
|
| 720 |
+
|
| 721 |
+
def __array__(self, dtype=None, copy=None):
|
| 722 |
+
pass
|
| 723 |
+
|
| 724 |
+
arr = np.array(ArrayLike)
|
| 725 |
+
assert arr[()] is ArrayLike
|
| 726 |
+
arr = np.array([ArrayLike])
|
| 727 |
+
assert arr[0] is ArrayLike
|
| 728 |
+
|
| 729 |
+
@pytest.mark.skipif(not IS_64BIT, reason="Needs 64bit platform")
|
| 730 |
+
@pytest.mark.thread_unsafe(reason="large slow test in parallel")
|
| 731 |
+
def test_too_large_array_error_paths(self):
|
| 732 |
+
"""Test the error paths, including for memory leaks"""
|
| 733 |
+
arr = np.array(0, dtype="uint8")
|
| 734 |
+
# Guarantees that a contiguous copy won't work:
|
| 735 |
+
arr = np.broadcast_to(arr, 2**62)
|
| 736 |
+
|
| 737 |
+
for i in range(5):
|
| 738 |
+
# repeat, to ensure caching cannot have an effect:
|
| 739 |
+
with pytest.raises(MemoryError):
|
| 740 |
+
np.array(arr)
|
| 741 |
+
with pytest.raises(MemoryError):
|
| 742 |
+
np.array([arr])
|
| 743 |
+
|
| 744 |
+
@pytest.mark.parametrize("attribute",
|
| 745 |
+
["__array_interface__", "__array__", "__array_struct__"])
|
| 746 |
+
@pytest.mark.parametrize("error", [RecursionError, MemoryError])
|
| 747 |
+
def test_bad_array_like_attributes(self, attribute, error):
|
| 748 |
+
# RecursionError and MemoryError are considered fatal. All errors
|
| 749 |
+
# (except AttributeError) should probably be raised in the future,
|
| 750 |
+
# but shapely made use of it, so it will require a deprecation.
|
| 751 |
+
|
| 752 |
+
class BadInterface:
|
| 753 |
+
def __getattr__(self, attr):
|
| 754 |
+
if attr == attribute:
|
| 755 |
+
raise error
|
| 756 |
+
super().__getattr__(attr)
|
| 757 |
+
|
| 758 |
+
with pytest.raises(error):
|
| 759 |
+
np.array(BadInterface())
|
| 760 |
+
|
| 761 |
+
@pytest.mark.parametrize("error", [RecursionError, MemoryError])
|
| 762 |
+
def test_bad_array_like_bad_length(self, error):
|
| 763 |
+
# RecursionError and MemoryError are considered "critical" in
|
| 764 |
+
# sequences. We could expand this more generally though. (NumPy 1.20)
|
| 765 |
+
class BadSequence:
|
| 766 |
+
def __len__(self):
|
| 767 |
+
raise error
|
| 768 |
+
|
| 769 |
+
def __getitem__(self, _, /):
|
| 770 |
+
# must have getitem to be a Sequence
|
| 771 |
+
return 1
|
| 772 |
+
|
| 773 |
+
with pytest.raises(error):
|
| 774 |
+
np.array(BadSequence())
|
| 775 |
+
|
| 776 |
+
def test_array_interface_descr_optional(self):
|
| 777 |
+
# The descr should be optional regression test for gh-27249
|
| 778 |
+
arr = np.ones(10, dtype="V10")
|
| 779 |
+
iface = arr.__array_interface__
|
| 780 |
+
iface.pop("descr")
|
| 781 |
+
|
| 782 |
+
class MyClass:
|
| 783 |
+
__array_interface__ = iface
|
| 784 |
+
|
| 785 |
+
assert_array_equal(np.asarray(MyClass), arr)
|
| 786 |
+
|
| 787 |
+
|
| 788 |
+
class TestAsArray:
|
| 789 |
+
"""Test expected behaviors of ``asarray``."""
|
| 790 |
+
|
| 791 |
+
def test_dtype_identity(self):
|
| 792 |
+
"""Confirm the intended behavior for *dtype* kwarg.
|
| 793 |
+
|
| 794 |
+
The result of ``asarray()`` should have the dtype provided through the
|
| 795 |
+
keyword argument, when used. This forces unique array handles to be
|
| 796 |
+
produced for unique np.dtype objects, but (for equivalent dtypes), the
|
| 797 |
+
underlying data (the base object) is shared with the original array
|
| 798 |
+
object.
|
| 799 |
+
|
| 800 |
+
Ref https://github.com/numpy/numpy/issues/1468
|
| 801 |
+
"""
|
| 802 |
+
int_array = np.array([1, 2, 3], dtype='i')
|
| 803 |
+
assert np.asarray(int_array) is int_array
|
| 804 |
+
|
| 805 |
+
# The character code resolves to the singleton dtype object provided
|
| 806 |
+
# by the numpy package.
|
| 807 |
+
assert np.asarray(int_array, dtype='i') is int_array
|
| 808 |
+
|
| 809 |
+
# Derive a dtype from n.dtype('i'), but add a metadata object to force
|
| 810 |
+
# the dtype to be distinct.
|
| 811 |
+
unequal_type = np.dtype('i', metadata={'spam': True})
|
| 812 |
+
annotated_int_array = np.asarray(int_array, dtype=unequal_type)
|
| 813 |
+
assert annotated_int_array is not int_array
|
| 814 |
+
assert annotated_int_array.base is int_array
|
| 815 |
+
# Create an equivalent descriptor with a new and distinct dtype
|
| 816 |
+
# instance.
|
| 817 |
+
equivalent_requirement = np.dtype('i', metadata={'spam': True})
|
| 818 |
+
annotated_int_array_alt = np.asarray(annotated_int_array,
|
| 819 |
+
dtype=equivalent_requirement)
|
| 820 |
+
assert unequal_type == equivalent_requirement
|
| 821 |
+
assert unequal_type is not equivalent_requirement
|
| 822 |
+
assert annotated_int_array_alt is not annotated_int_array
|
| 823 |
+
assert annotated_int_array_alt.dtype is equivalent_requirement
|
| 824 |
+
|
| 825 |
+
# Check the same logic for a pair of C types whose equivalence may vary
|
| 826 |
+
# between computing environments.
|
| 827 |
+
# Find an equivalent pair.
|
| 828 |
+
integer_type_codes = ('i', 'l', 'q')
|
| 829 |
+
integer_dtypes = [np.dtype(code) for code in integer_type_codes]
|
| 830 |
+
typeA = None
|
| 831 |
+
typeB = None
|
| 832 |
+
for typeA, typeB in permutations(integer_dtypes, r=2):
|
| 833 |
+
if typeA == typeB:
|
| 834 |
+
assert typeA is not typeB
|
| 835 |
+
break
|
| 836 |
+
assert isinstance(typeA, np.dtype) and isinstance(typeB, np.dtype)
|
| 837 |
+
|
| 838 |
+
# These ``asarray()`` calls may produce a new view or a copy,
|
| 839 |
+
# but never the same object.
|
| 840 |
+
long_int_array = np.asarray(int_array, dtype='l')
|
| 841 |
+
long_long_int_array = np.asarray(int_array, dtype='q')
|
| 842 |
+
assert long_int_array is not int_array
|
| 843 |
+
assert long_long_int_array is not int_array
|
| 844 |
+
assert np.asarray(long_int_array, dtype='q') is not long_int_array
|
| 845 |
+
array_a = np.asarray(int_array, dtype=typeA)
|
| 846 |
+
assert typeA == typeB
|
| 847 |
+
assert typeA is not typeB
|
| 848 |
+
assert array_a.dtype is typeA
|
| 849 |
+
assert array_a is not np.asarray(array_a, dtype=typeB)
|
| 850 |
+
assert np.asarray(array_a, dtype=typeB).dtype is typeB
|
| 851 |
+
assert array_a is np.asarray(array_a, dtype=typeB).base
|
| 852 |
+
|
| 853 |
+
|
| 854 |
+
class TestSpecialAttributeLookupFailure:
|
| 855 |
+
# An exception was raised while fetching the attribute
|
| 856 |
+
|
| 857 |
+
class WeirdArrayLike:
|
| 858 |
+
@property
|
| 859 |
+
def __array__(self, dtype=None, copy=None):
|
| 860 |
+
raise RuntimeError("oops!")
|
| 861 |
+
|
| 862 |
+
class WeirdArrayInterface:
|
| 863 |
+
@property
|
| 864 |
+
def __array_interface__(self):
|
| 865 |
+
raise RuntimeError("oops!")
|
| 866 |
+
|
| 867 |
+
def test_deprecated(self):
|
| 868 |
+
with pytest.raises(RuntimeError):
|
| 869 |
+
np.array(self.WeirdArrayLike())
|
| 870 |
+
with pytest.raises(RuntimeError):
|
| 871 |
+
np.array(self.WeirdArrayInterface())
|
| 872 |
+
|
| 873 |
+
|
| 874 |
+
def test_subarray_from_array_construction():
|
| 875 |
+
# Arrays are more complex, since they "broadcast" on success:
|
| 876 |
+
arr = np.array([1, 2])
|
| 877 |
+
|
| 878 |
+
res = arr.astype("2i")
|
| 879 |
+
assert_array_equal(res, [[1, 1], [2, 2]])
|
| 880 |
+
|
| 881 |
+
res = np.array(arr, dtype="(2,)i")
|
| 882 |
+
|
| 883 |
+
assert_array_equal(res, [[1, 1], [2, 2]])
|
| 884 |
+
|
| 885 |
+
res = np.array([[(1,), (2,)], arr], dtype="2i")
|
| 886 |
+
assert_array_equal(res, [[[1, 1], [2, 2]], [[1, 1], [2, 2]]])
|
| 887 |
+
|
| 888 |
+
# Also try a multi-dimensional example:
|
| 889 |
+
arr = np.arange(5 * 2).reshape(5, 2)
|
| 890 |
+
expected = np.broadcast_to(arr[:, :, np.newaxis, np.newaxis], (5, 2, 2, 2))
|
| 891 |
+
|
| 892 |
+
res = arr.astype("(2,2)f")
|
| 893 |
+
assert_array_equal(res, expected)
|
| 894 |
+
|
| 895 |
+
res = np.array(arr, dtype="(2,2)f")
|
| 896 |
+
assert_array_equal(res, expected)
|
| 897 |
+
|
| 898 |
+
|
| 899 |
+
def test_empty_string():
|
| 900 |
+
# Empty strings are unfortunately often converted to S1 and we need to
|
| 901 |
+
# make sure we are filling the S1 and not the (possibly) detected S0
|
| 902 |
+
# result. This should likely just return S0 and if not maybe the decision
|
| 903 |
+
# to return S1 should be moved.
|
| 904 |
+
res = np.array([""] * 10, dtype="S")
|
| 905 |
+
assert_array_equal(res, np.array("\0", "S1"))
|
| 906 |
+
assert res.dtype == "S1"
|
| 907 |
+
|
| 908 |
+
arr = np.array([""] * 10, dtype=object)
|
| 909 |
+
|
| 910 |
+
res = arr.astype("S")
|
| 911 |
+
assert_array_equal(res, b"")
|
| 912 |
+
assert res.dtype == "S1"
|
| 913 |
+
|
| 914 |
+
res = np.array(arr, dtype="S")
|
| 915 |
+
assert_array_equal(res, b"")
|
| 916 |
+
# TODO: This is arguably weird/wrong, but seems old:
|
| 917 |
+
assert res.dtype == f"S{np.dtype('O').itemsize}"
|
| 918 |
+
|
| 919 |
+
res = np.array([[""] * 10, arr], dtype="S")
|
| 920 |
+
assert_array_equal(res, b"")
|
| 921 |
+
assert res.shape == (2, 10)
|
| 922 |
+
assert res.dtype == "S1"
|
| 923 |
+
|
| 924 |
+
|
| 925 |
+
@pytest.mark.parametrize("dtype", ["S", "U", object])
|
| 926 |
+
@pytest.mark.parametrize("res_dt,hug_val",
|
| 927 |
+
[("float16", "1e30"), ("float32", "1e200")])
|
| 928 |
+
def test_string_to_float_coercion_errors(dtype, res_dt, hug_val):
|
| 929 |
+
# This test primarily tests setitem
|
| 930 |
+
val = np.array(["3M"], dtype=dtype)[0] # use the scalar
|
| 931 |
+
|
| 932 |
+
with pytest.raises(ValueError):
|
| 933 |
+
np.array(val, dtype=res_dt)
|
| 934 |
+
|
| 935 |
+
val = np.array([hug_val], dtype=dtype)[0] # use the scalar
|
| 936 |
+
|
| 937 |
+
with np.errstate(all="warn"):
|
| 938 |
+
with pytest.warns(RuntimeWarning):
|
| 939 |
+
np.array(val, dtype=res_dt)
|
| 940 |
+
|
| 941 |
+
with np.errstate(all="raise"):
|
| 942 |
+
with pytest.raises(FloatingPointError):
|
| 943 |
+
np.array(val, dtype=res_dt)
|
v12x/pylib/numpy/_core/tests/test_array_interface.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import sysconfig
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
from numpy.testing import IS_EDITABLE, IS_WASM, extbuild
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture
|
| 11 |
+
def get_module(tmp_path):
|
| 12 |
+
""" Some codes to generate data and manage temporary buffers use when
|
| 13 |
+
sharing with numpy via the array interface protocol.
|
| 14 |
+
"""
|
| 15 |
+
if sys.platform.startswith('cygwin'):
|
| 16 |
+
pytest.skip('link fails on cygwin')
|
| 17 |
+
if IS_WASM:
|
| 18 |
+
pytest.skip("Can't build module inside Wasm")
|
| 19 |
+
if IS_EDITABLE:
|
| 20 |
+
pytest.skip("Can't build module for editable install")
|
| 21 |
+
|
| 22 |
+
prologue = '''
|
| 23 |
+
#include <Python.h>
|
| 24 |
+
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
| 25 |
+
#include <numpy/arrayobject.h>
|
| 26 |
+
#include <stdio.h>
|
| 27 |
+
#include <math.h>
|
| 28 |
+
|
| 29 |
+
NPY_NO_EXPORT
|
| 30 |
+
void delete_array_struct(PyObject *cap) {
|
| 31 |
+
|
| 32 |
+
/* get the array interface structure */
|
| 33 |
+
PyArrayInterface *inter = (PyArrayInterface*)
|
| 34 |
+
PyCapsule_GetPointer(cap, NULL);
|
| 35 |
+
|
| 36 |
+
/* get the buffer by which data was shared */
|
| 37 |
+
double *ptr = (double*)PyCapsule_GetContext(cap);
|
| 38 |
+
|
| 39 |
+
/* for the purposes of the regression test set the elements
|
| 40 |
+
to nan */
|
| 41 |
+
for (npy_intp i = 0; i < inter->shape[0]; ++i)
|
| 42 |
+
ptr[i] = nan("");
|
| 43 |
+
|
| 44 |
+
/* free the shared buffer */
|
| 45 |
+
free(ptr);
|
| 46 |
+
|
| 47 |
+
/* free the array interface structure */
|
| 48 |
+
free(inter->shape);
|
| 49 |
+
free(inter);
|
| 50 |
+
|
| 51 |
+
fprintf(stderr, "delete_array_struct\\ncap = %ld inter = %ld"
|
| 52 |
+
" ptr = %ld\\n", (long)cap, (long)inter, (long)ptr);
|
| 53 |
+
}
|
| 54 |
+
'''
|
| 55 |
+
|
| 56 |
+
functions = [
|
| 57 |
+
("new_array_struct", "METH_VARARGS", """
|
| 58 |
+
|
| 59 |
+
long long n_elem = 0;
|
| 60 |
+
double value = 0.0;
|
| 61 |
+
|
| 62 |
+
if (!PyArg_ParseTuple(args, "Ld", &n_elem, &value)) {
|
| 63 |
+
Py_RETURN_NONE;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
/* allocate and initialize the data to share with numpy */
|
| 67 |
+
long long n_bytes = n_elem*sizeof(double);
|
| 68 |
+
double *data = (double*)malloc(n_bytes);
|
| 69 |
+
|
| 70 |
+
if (!data) {
|
| 71 |
+
PyErr_Format(PyExc_MemoryError,
|
| 72 |
+
"Failed to malloc %lld bytes", n_bytes);
|
| 73 |
+
|
| 74 |
+
Py_RETURN_NONE;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
for (long long i = 0; i < n_elem; ++i) {
|
| 78 |
+
data[i] = value;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
/* calculate the shape and stride */
|
| 82 |
+
int nd = 1;
|
| 83 |
+
|
| 84 |
+
npy_intp *ss = (npy_intp*)malloc(2*nd*sizeof(npy_intp));
|
| 85 |
+
npy_intp *shape = ss;
|
| 86 |
+
npy_intp *stride = ss + nd;
|
| 87 |
+
|
| 88 |
+
shape[0] = n_elem;
|
| 89 |
+
stride[0] = sizeof(double);
|
| 90 |
+
|
| 91 |
+
/* construct the array interface */
|
| 92 |
+
PyArrayInterface *inter = (PyArrayInterface*)
|
| 93 |
+
malloc(sizeof(PyArrayInterface));
|
| 94 |
+
|
| 95 |
+
memset(inter, 0, sizeof(PyArrayInterface));
|
| 96 |
+
|
| 97 |
+
inter->two = 2;
|
| 98 |
+
inter->nd = nd;
|
| 99 |
+
inter->typekind = 'f';
|
| 100 |
+
inter->itemsize = sizeof(double);
|
| 101 |
+
inter->shape = shape;
|
| 102 |
+
inter->strides = stride;
|
| 103 |
+
inter->data = data;
|
| 104 |
+
inter->flags = NPY_ARRAY_WRITEABLE | NPY_ARRAY_NOTSWAPPED |
|
| 105 |
+
NPY_ARRAY_ALIGNED | NPY_ARRAY_C_CONTIGUOUS;
|
| 106 |
+
|
| 107 |
+
/* package into a capsule */
|
| 108 |
+
PyObject *cap = PyCapsule_New(inter, NULL, delete_array_struct);
|
| 109 |
+
|
| 110 |
+
/* save the pointer to the data */
|
| 111 |
+
PyCapsule_SetContext(cap, data);
|
| 112 |
+
|
| 113 |
+
fprintf(stderr, "new_array_struct\\ncap = %ld inter = %ld"
|
| 114 |
+
" ptr = %ld\\n", (long)cap, (long)inter, (long)data);
|
| 115 |
+
|
| 116 |
+
return cap;
|
| 117 |
+
""")
|
| 118 |
+
]
|
| 119 |
+
|
| 120 |
+
more_init = "import_array();"
|
| 121 |
+
|
| 122 |
+
try:
|
| 123 |
+
import array_interface_testing
|
| 124 |
+
return array_interface_testing
|
| 125 |
+
except ImportError:
|
| 126 |
+
pass
|
| 127 |
+
|
| 128 |
+
# if it does not exist, build and load it
|
| 129 |
+
if sysconfig.get_platform() == "win-arm64":
|
| 130 |
+
pytest.skip("Meson unable to find MSVC linker on win-arm64")
|
| 131 |
+
return extbuild.build_and_import_extension('array_interface_testing',
|
| 132 |
+
functions,
|
| 133 |
+
prologue=prologue,
|
| 134 |
+
include_dirs=[np.get_include()],
|
| 135 |
+
build_dir=tmp_path,
|
| 136 |
+
more_init=more_init)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
@pytest.mark.slow
|
| 140 |
+
def test_cstruct(get_module):
|
| 141 |
+
|
| 142 |
+
class data_source:
|
| 143 |
+
"""
|
| 144 |
+
This class is for testing the timing of the PyCapsule destructor
|
| 145 |
+
invoked when numpy release its reference to the shared data as part of
|
| 146 |
+
the numpy array interface protocol. If the PyCapsule destructor is
|
| 147 |
+
called early the shared data is freed and invalid memory accesses will
|
| 148 |
+
occur.
|
| 149 |
+
"""
|
| 150 |
+
|
| 151 |
+
def __init__(self, size, value):
|
| 152 |
+
self.size = size
|
| 153 |
+
self.value = value
|
| 154 |
+
|
| 155 |
+
@property
|
| 156 |
+
def __array_struct__(self):
|
| 157 |
+
return get_module.new_array_struct(self.size, self.value)
|
| 158 |
+
|
| 159 |
+
# write to the same stream as the C code
|
| 160 |
+
stderr = sys.__stderr__
|
| 161 |
+
|
| 162 |
+
# used to validate the shared data.
|
| 163 |
+
expected_value = -3.1415
|
| 164 |
+
multiplier = -10000.0
|
| 165 |
+
|
| 166 |
+
# create some data to share with numpy via the array interface
|
| 167 |
+
# assign the data an expected value.
|
| 168 |
+
stderr.write(' ---- create an object to share data ---- \n')
|
| 169 |
+
buf = data_source(256, expected_value)
|
| 170 |
+
stderr.write(' ---- OK!\n\n')
|
| 171 |
+
|
| 172 |
+
# share the data
|
| 173 |
+
stderr.write(' ---- share data via the array interface protocol ---- \n')
|
| 174 |
+
arr = np.array(buf, copy=False)
|
| 175 |
+
stderr.write(f'arr.__array_interface___ = {str(arr.__array_interface__)}\n')
|
| 176 |
+
stderr.write(f'arr.base = {str(arr.base)}\n')
|
| 177 |
+
stderr.write(' ---- OK!\n\n')
|
| 178 |
+
|
| 179 |
+
# release the source of the shared data. this will not release the data
|
| 180 |
+
# that was shared with numpy, that is done in the PyCapsule destructor.
|
| 181 |
+
stderr.write(' ---- destroy the object that shared data ---- \n')
|
| 182 |
+
buf = None
|
| 183 |
+
stderr.write(' ---- OK!\n\n')
|
| 184 |
+
|
| 185 |
+
# check that we got the expected data. If the PyCapsule destructor we
|
| 186 |
+
# defined was prematurely called then this test will fail because our
|
| 187 |
+
# destructor sets the elements of the array to NaN before free'ing the
|
| 188 |
+
# buffer. Reading the values here may also cause a SEGV
|
| 189 |
+
assert np.allclose(arr, expected_value)
|
| 190 |
+
|
| 191 |
+
# read the data. If the PyCapsule destructor we defined was prematurely
|
| 192 |
+
# called then reading the values here may cause a SEGV and will be reported
|
| 193 |
+
# as invalid reads by valgrind
|
| 194 |
+
stderr.write(' ---- read shared data ---- \n')
|
| 195 |
+
stderr.write(f'arr = {str(arr)}\n')
|
| 196 |
+
stderr.write(' ---- OK!\n\n')
|
| 197 |
+
|
| 198 |
+
# write to the shared buffer. If the shared data was prematurely deleted
|
| 199 |
+
# this will may cause a SEGV and valgrind will report invalid writes
|
| 200 |
+
stderr.write(' ---- modify shared data ---- \n')
|
| 201 |
+
arr *= multiplier
|
| 202 |
+
expected_value *= multiplier
|
| 203 |
+
stderr.write(f'arr.__array_interface___ = {str(arr.__array_interface__)}\n')
|
| 204 |
+
stderr.write(f'arr.base = {str(arr.base)}\n')
|
| 205 |
+
stderr.write(' ---- OK!\n\n')
|
| 206 |
+
|
| 207 |
+
# read the data. If the shared data was prematurely deleted this
|
| 208 |
+
# will may cause a SEGV and valgrind will report invalid reads
|
| 209 |
+
stderr.write(' ---- read modified shared data ---- \n')
|
| 210 |
+
stderr.write(f'arr = {str(arr)}\n')
|
| 211 |
+
stderr.write(' ---- OK!\n\n')
|
| 212 |
+
|
| 213 |
+
# check that we got the expected data. If the PyCapsule destructor we
|
| 214 |
+
# defined was prematurely called then this test will fail because our
|
| 215 |
+
# destructor sets the elements of the array to NaN before free'ing the
|
| 216 |
+
# buffer. Reading the values here may also cause a SEGV
|
| 217 |
+
assert np.allclose(arr, expected_value)
|
| 218 |
+
|
| 219 |
+
# free the shared data, the PyCapsule destructor should run here
|
| 220 |
+
stderr.write(' ---- free shared data ---- \n')
|
| 221 |
+
arr = None
|
| 222 |
+
stderr.write(' ---- OK!\n\n')
|
v12x/pylib/numpy/_core/tests/test_arraymethod.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This file tests the generic aspects of ArrayMethod. At the time of writing
|
| 3 |
+
this is private API, but when added, public API may be added here.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import types
|
| 7 |
+
from typing import Any
|
| 8 |
+
|
| 9 |
+
import pytest
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
from numpy._core._multiarray_umath import _get_castingimpl as get_castingimpl
|
| 13 |
+
|
| 14 |
+
# accessing `numpy.char.charray` will issue a deprecation warning
|
| 15 |
+
from numpy._core.defchararray import chararray
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class TestResolveDescriptors:
|
| 19 |
+
# Test mainly error paths of the resolve_descriptors function,
|
| 20 |
+
# note that the `casting_unittests` tests exercise this non-error paths.
|
| 21 |
+
|
| 22 |
+
# Casting implementations are the main/only current user:
|
| 23 |
+
method = get_castingimpl(type(np.dtype("d")), type(np.dtype("f")))
|
| 24 |
+
|
| 25 |
+
@pytest.mark.parametrize("args", [
|
| 26 |
+
(True,), # Not a tuple.
|
| 27 |
+
((None,)), # Too few elements
|
| 28 |
+
((None, None, None),), # Too many
|
| 29 |
+
((None, None),), # Input dtype is None, which is invalid.
|
| 30 |
+
((np.dtype("d"), True),), # Output dtype is not a dtype
|
| 31 |
+
((np.dtype("f"), None),), # Input dtype does not match method
|
| 32 |
+
])
|
| 33 |
+
def test_invalid_arguments(self, args):
|
| 34 |
+
with pytest.raises(TypeError):
|
| 35 |
+
self.method._resolve_descriptors(*args)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
class TestSimpleStridedCall:
|
| 39 |
+
# Test mainly error paths of the resolve_descriptors function,
|
| 40 |
+
# note that the `casting_unittests` tests exercise this non-error paths.
|
| 41 |
+
|
| 42 |
+
# Casting implementations are the main/only current user:
|
| 43 |
+
method = get_castingimpl(type(np.dtype("d")), type(np.dtype("f")))
|
| 44 |
+
|
| 45 |
+
@pytest.mark.parametrize(["args", "error"], [
|
| 46 |
+
((True,), TypeError), # Not a tuple
|
| 47 |
+
(((None,),), TypeError), # Too few elements
|
| 48 |
+
((None, None), TypeError), # Inputs are not arrays.
|
| 49 |
+
(((None, None, None),), TypeError), # Too many
|
| 50 |
+
(((np.arange(3), np.arange(3)),), TypeError), # Incorrect dtypes
|
| 51 |
+
(((np.ones(3, dtype=">d"), np.ones(3, dtype="<f")),),
|
| 52 |
+
TypeError), # Does not support byte-swapping
|
| 53 |
+
(((np.ones((2, 2), dtype="d"), np.ones((2, 2), dtype="f")),),
|
| 54 |
+
ValueError), # not 1-D
|
| 55 |
+
(((np.ones(3, dtype="d"), np.ones(4, dtype="f")),),
|
| 56 |
+
ValueError), # different length
|
| 57 |
+
(((np.frombuffer(b"\0x00" * 3 * 2, dtype="d"),
|
| 58 |
+
np.frombuffer(b"\0x00" * 3, dtype="f")),),
|
| 59 |
+
ValueError), # output not writeable
|
| 60 |
+
])
|
| 61 |
+
def test_invalid_arguments(self, args, error):
|
| 62 |
+
# This is private API, which may be modified freely
|
| 63 |
+
with pytest.raises(error):
|
| 64 |
+
self.method._simple_strided_call(*args)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
@pytest.mark.parametrize(
|
| 68 |
+
"cls", [np.ndarray, np.recarray, chararray, np.matrix, np.memmap]
|
| 69 |
+
)
|
| 70 |
+
class TestClassGetItem:
|
| 71 |
+
def test_class_getitem(self, cls: type[np.ndarray]) -> None:
|
| 72 |
+
"""Test `ndarray.__class_getitem__`."""
|
| 73 |
+
alias = cls[Any, Any]
|
| 74 |
+
assert isinstance(alias, types.GenericAlias)
|
| 75 |
+
assert alias.__origin__ is cls
|
| 76 |
+
|
| 77 |
+
@pytest.mark.parametrize("arg_len", range(4))
|
| 78 |
+
def test_subscript_tup(self, cls: type[np.ndarray], arg_len: int) -> None:
|
| 79 |
+
arg_tup = (Any,) * arg_len
|
| 80 |
+
if arg_len in (1, 2):
|
| 81 |
+
assert cls[arg_tup]
|
| 82 |
+
else:
|
| 83 |
+
match = f"Too {'few' if arg_len == 0 else 'many'} arguments"
|
| 84 |
+
with pytest.raises(TypeError, match=match):
|
| 85 |
+
cls[arg_tup]
|
v12x/pylib/numpy/_core/tests/test_arrayobject.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
from numpy._core._rational_tests import rational, rational2
|
| 7 |
+
from numpy.testing import HAS_REFCOUNT, assert_array_equal
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_matrix_transpose_raises_error_for_1d():
|
| 11 |
+
msg = "matrix transpose with ndim < 2 is undefined"
|
| 12 |
+
arr = np.arange(48)
|
| 13 |
+
with pytest.raises(ValueError, match=msg):
|
| 14 |
+
arr.mT
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def test_matrix_transpose_equals_transpose_2d():
|
| 18 |
+
arr = np.arange(48).reshape((6, 8))
|
| 19 |
+
assert_array_equal(arr.T, arr.mT)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
ARRAY_SHAPES_TO_TEST = (
|
| 23 |
+
(5, 2),
|
| 24 |
+
(5, 2, 3),
|
| 25 |
+
(5, 2, 3, 4),
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
@pytest.mark.parametrize("shape", ARRAY_SHAPES_TO_TEST)
|
| 30 |
+
def test_matrix_transpose_equals_swapaxes(shape):
|
| 31 |
+
num_of_axes = len(shape)
|
| 32 |
+
vec = np.arange(shape[-1])
|
| 33 |
+
arr = np.broadcast_to(vec, shape)
|
| 34 |
+
tgt = np.swapaxes(arr, num_of_axes - 2, num_of_axes - 1)
|
| 35 |
+
mT = arr.mT
|
| 36 |
+
assert_array_equal(tgt, mT)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class MyArr(np.ndarray):
|
| 40 |
+
def __array_wrap__(self, arr, context=None, return_scalar=None):
|
| 41 |
+
return super().__array_wrap__(arr, context, return_scalar)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class MyArrNoWrap(np.ndarray):
|
| 45 |
+
pass
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
@pytest.mark.parametrize("subclass_self", [np.ndarray, MyArr, MyArrNoWrap])
|
| 49 |
+
@pytest.mark.parametrize("subclass_arr", [np.ndarray, MyArr, MyArrNoWrap])
|
| 50 |
+
def test_array_wrap(subclass_self, subclass_arr):
|
| 51 |
+
# NumPy should allow `__array_wrap__` to be called on arrays, it's logic
|
| 52 |
+
# is designed in a way that:
|
| 53 |
+
#
|
| 54 |
+
# * Subclasses never return scalars by default (to preserve their
|
| 55 |
+
# information). They can choose to if they wish.
|
| 56 |
+
# * NumPy returns scalars, if `return_scalar` is passed as True to allow
|
| 57 |
+
# manual calls to `arr.__array_wrap__` to do the right thing.
|
| 58 |
+
# * The type of the input should be ignored (it should be a base-class
|
| 59 |
+
# array, but I am not sure this is guaranteed).
|
| 60 |
+
|
| 61 |
+
arr = np.arange(3).view(subclass_self)
|
| 62 |
+
|
| 63 |
+
arr0d = np.array(3, dtype=np.int8).view(subclass_arr)
|
| 64 |
+
# With third argument True, ndarray allows "decay" to scalar.
|
| 65 |
+
# (I don't think NumPy would pass `None`, but it seems clear to support)
|
| 66 |
+
if subclass_self is np.ndarray:
|
| 67 |
+
assert type(arr.__array_wrap__(arr0d, None, True)) is np.int8
|
| 68 |
+
else:
|
| 69 |
+
assert type(arr.__array_wrap__(arr0d, None, True)) is type(arr)
|
| 70 |
+
|
| 71 |
+
# Otherwise, result should be viewed as the subclass
|
| 72 |
+
assert type(arr.__array_wrap__(arr0d)) is type(arr)
|
| 73 |
+
assert type(arr.__array_wrap__(arr0d, None, None)) is type(arr)
|
| 74 |
+
assert type(arr.__array_wrap__(arr0d, None, False)) is type(arr)
|
| 75 |
+
|
| 76 |
+
# Non 0-D array can't be converted to scalar, so we ignore that
|
| 77 |
+
arr1d = np.array([3], dtype=np.int8).view(subclass_arr)
|
| 78 |
+
assert type(arr.__array_wrap__(arr1d, None, True)) is type(arr)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
|
| 82 |
+
def test_cleanup_with_refs_non_contig():
|
| 83 |
+
# Regression test, leaked the dtype (but also good for rest)
|
| 84 |
+
dtype = np.dtype("O,i")
|
| 85 |
+
obj = object()
|
| 86 |
+
expected_ref_dtype = sys.getrefcount(dtype)
|
| 87 |
+
expected_ref_obj = sys.getrefcount(obj)
|
| 88 |
+
proto = np.full((3, 4, 5, 6, 7), np.array((obj, 2), dtype=dtype))
|
| 89 |
+
# Give array a non-trivial order to exercise more cleanup paths.
|
| 90 |
+
arr = proto.transpose((2, 0, 3, 1, 4)).copy("K")
|
| 91 |
+
del proto, arr
|
| 92 |
+
|
| 93 |
+
actual_ref_dtype = sys.getrefcount(dtype)
|
| 94 |
+
actual_ref_obj = sys.getrefcount(obj)
|
| 95 |
+
assert actual_ref_dtype == expected_ref_dtype
|
| 96 |
+
assert actual_ref_obj == actual_ref_dtype
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
@pytest.mark.parametrize("dtype",
|
| 100 |
+
list("?bhilqnpBHILQNPefdgSUV") +
|
| 101 |
+
["M8[ns]", "m8[ns]", rational, rational2])
|
| 102 |
+
def test_real_imag_attributes_non_complex(dtype):
|
| 103 |
+
dtype = np.dtype(dtype)
|
| 104 |
+
|
| 105 |
+
a = np.array([[1, 2, 3], [4, 5, 6]]).astype(dtype)
|
| 106 |
+
assert a.real is a
|
| 107 |
+
# One could imagine broadcasting, but doesn't right now:
|
| 108 |
+
imag = a.imag
|
| 109 |
+
assert imag.strides == a.strides
|
| 110 |
+
assert imag.dtype == a.dtype
|
| 111 |
+
# This part is rather unclear:
|
| 112 |
+
assert (imag == np.zeros((), dtype=a.dtype)).all()
|
| 113 |
+
assert imag.flags.writeable is False
|
| 114 |
+
|
| 115 |
+
class myarr(np.ndarray):
|
| 116 |
+
def __array_finalize__(self, obj):
|
| 117 |
+
self.finalized_with = obj
|
| 118 |
+
|
| 119 |
+
ma = a.view(myarr)
|
| 120 |
+
assert ma.real is ma
|
| 121 |
+
assert type(ma.imag) is myarr
|
| 122 |
+
assert ma.imag.finalized_with is ma
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
@pytest.mark.parametrize("dtype,real_dt",
|
| 126 |
+
[(">c8", ">f4"), ("c16", "f8"), ("clongdouble", "longdouble")])
|
| 127 |
+
@pytest.mark.parametrize("variation", ["transpose", "set_writeable"])
|
| 128 |
+
def test_real_imag_attributes_complex(dtype, real_dt, variation):
|
| 129 |
+
a = np.array([[1, 2j, 3], [4, 5j, 6]]).astype(dtype)
|
| 130 |
+
real = np.array([[1, 0, 3], [4, 0, 6]], dtype=real_dt)
|
| 131 |
+
imag = np.array([[0, 2, 0], [0, 5, 0]], dtype=real_dt)
|
| 132 |
+
|
| 133 |
+
if variation == "transpose":
|
| 134 |
+
a = a.T
|
| 135 |
+
real = real.T
|
| 136 |
+
imag = imag.T
|
| 137 |
+
elif variation == "set_writeable":
|
| 138 |
+
a.flags.writeable = False
|
| 139 |
+
|
| 140 |
+
assert_array_equal(a.real, real)
|
| 141 |
+
assert_array_equal(a.imag, imag)
|
| 142 |
+
assert a.real.dtype == real_dt
|
| 143 |
+
assert a.imag.dtype == real_dt
|
| 144 |
+
assert np.may_share_memory(a.real, a)
|
| 145 |
+
assert np.may_share_memory(a.imag, a)
|
| 146 |
+
assert a.real.flags.writeable == a.flags.writeable
|
| 147 |
+
assert a.imag.flags.writeable == a.flags.writeable
|
| 148 |
+
|
| 149 |
+
class myarr(np.ndarray):
|
| 150 |
+
def __array_finalize__(self, obj):
|
| 151 |
+
self.finalized_with = obj
|
| 152 |
+
|
| 153 |
+
ma = a.view(myarr)
|
| 154 |
+
assert ma.real.finalized_with is ma
|
| 155 |
+
assert ma.imag.finalized_with is ma
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def test_real_imag_attributes_object():
|
| 159 |
+
a = np.array([[1, 0.5 + 2j, 3, int], [4, 5j, "string", {}]], dtype=object)
|
| 160 |
+
|
| 161 |
+
# NOTE(seberg): doing something for non-numbers is guesswork...
|
| 162 |
+
real = np.array([[1, 0.5, 3, int.real], [4, 0, "string", {}]], dtype=object)
|
| 163 |
+
imag = np.array([[0, 2, 0, int.imag], [0, 5, 0, 0]], dtype=object)
|
| 164 |
+
|
| 165 |
+
assert_array_equal(a.real, real)
|
| 166 |
+
assert_array_equal(a.imag, imag)
|
| 167 |
+
assert a.real.dtype == object
|
| 168 |
+
assert a.imag.dtype == object
|
| 169 |
+
assert not np.may_share_memory(a.real, a)
|
| 170 |
+
assert not np.may_share_memory(a.imag, a)
|
| 171 |
+
assert not a.real.flags.writeable
|
| 172 |
+
assert not a.imag.flags.writeable
|
| 173 |
+
|
| 174 |
+
# Object returns new arrays via ufuncs, so call wrap
|
| 175 |
+
class myarr(np.ndarray):
|
| 176 |
+
def __array_wrap__(self, *args, **kwargs):
|
| 177 |
+
ret = super().__array_wrap__(*args, **kwargs)
|
| 178 |
+
ret.wrap_called = True
|
| 179 |
+
return ret
|
| 180 |
+
|
| 181 |
+
ma = a.view(myarr)
|
| 182 |
+
assert ma.real.wrap_called
|
| 183 |
+
assert ma.imag.wrap_called
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
@pytest.mark.parametrize("ufunc,attr", [
|
| 187 |
+
(np._core.umath.real, "real"), (np._core.umath.imag, "imag")])
|
| 188 |
+
def test_real_imag_ufunc_minimal(ufunc, attr):
|
| 189 |
+
with pytest.raises(TypeError):
|
| 190 |
+
ufunc(np.array([1, 2, 3])) # non-complex or object raises
|
| 191 |
+
|
| 192 |
+
arr = np.array([1 + 2j, 3 + 4j])
|
| 193 |
+
res = ufunc(arr)
|
| 194 |
+
assert_array_equal(res, getattr(arr, attr), strict=True)
|
| 195 |
+
|
| 196 |
+
arr = np.array([1 + 2j, 3 + 4j], dtype=object)
|
| 197 |
+
res = ufunc(arr)
|
| 198 |
+
assert_array_equal(res, getattr(arr, attr), strict=True)
|
v12x/pylib/numpy/_core/tests/test_arrayprint.py
ADDED
|
@@ -0,0 +1,1363 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gc
|
| 2 |
+
import sys
|
| 3 |
+
import textwrap
|
| 4 |
+
|
| 5 |
+
import pytest
|
| 6 |
+
from hypothesis import given
|
| 7 |
+
from hypothesis.extra import numpy as hynp
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
from numpy._core._rational_tests import rational, rational2
|
| 11 |
+
from numpy._core.arrayprint import _typelessdata
|
| 12 |
+
from numpy._utils import _pep440
|
| 13 |
+
from numpy.testing import (
|
| 14 |
+
HAS_REFCOUNT,
|
| 15 |
+
IS_WASM,
|
| 16 |
+
assert_,
|
| 17 |
+
assert_array_equal,
|
| 18 |
+
assert_equal,
|
| 19 |
+
assert_raises,
|
| 20 |
+
assert_raises_regex,
|
| 21 |
+
)
|
| 22 |
+
from numpy.testing._private.utils import run_threaded
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class TestArrayRepr:
|
| 26 |
+
def test_nan_inf(self):
|
| 27 |
+
x = np.array([np.nan, np.inf])
|
| 28 |
+
assert_equal(repr(x), 'array([nan, inf])')
|
| 29 |
+
|
| 30 |
+
def test_subclass(self):
|
| 31 |
+
class sub(np.ndarray):
|
| 32 |
+
pass
|
| 33 |
+
|
| 34 |
+
# one dimensional
|
| 35 |
+
x1d = np.array([1, 2]).view(sub)
|
| 36 |
+
assert_equal(repr(x1d), 'sub([1, 2])')
|
| 37 |
+
|
| 38 |
+
# two dimensional
|
| 39 |
+
x2d = np.array([[1, 2], [3, 4]]).view(sub)
|
| 40 |
+
assert_equal(repr(x2d),
|
| 41 |
+
'sub([[1, 2],\n'
|
| 42 |
+
' [3, 4]])')
|
| 43 |
+
|
| 44 |
+
# two dimensional with flexible dtype
|
| 45 |
+
xstruct = np.ones((2, 2), dtype=[('a', '<i4')]).view(sub)
|
| 46 |
+
assert_equal(repr(xstruct),
|
| 47 |
+
"sub([[(1,), (1,)],\n"
|
| 48 |
+
" [(1,), (1,)]], dtype=[('a', '<i4')])"
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
@pytest.mark.xfail(reason="See gh-10544")
|
| 52 |
+
def test_object_subclass(self):
|
| 53 |
+
class sub(np.ndarray):
|
| 54 |
+
def __new__(cls, inp):
|
| 55 |
+
obj = np.asarray(inp).view(cls)
|
| 56 |
+
return obj
|
| 57 |
+
|
| 58 |
+
def __getitem__(self, ind):
|
| 59 |
+
ret = super().__getitem__(ind)
|
| 60 |
+
return sub(ret)
|
| 61 |
+
|
| 62 |
+
# test that object + subclass is OK:
|
| 63 |
+
x = sub([None, None])
|
| 64 |
+
assert_equal(repr(x), 'sub([None, None], dtype=object)')
|
| 65 |
+
assert_equal(str(x), '[None None]')
|
| 66 |
+
|
| 67 |
+
x = sub([None, sub([None, None])])
|
| 68 |
+
assert_equal(repr(x),
|
| 69 |
+
'sub([None, sub([None, None], dtype=object)], dtype=object)')
|
| 70 |
+
assert_equal(str(x), '[None sub([None, None], dtype=object)]')
|
| 71 |
+
|
| 72 |
+
def test_0d_object_subclass(self):
|
| 73 |
+
# make sure that subclasses which return 0ds instead
|
| 74 |
+
# of scalars don't cause infinite recursion in str
|
| 75 |
+
class sub(np.ndarray):
|
| 76 |
+
def __new__(cls, inp):
|
| 77 |
+
obj = np.asarray(inp).view(cls)
|
| 78 |
+
return obj
|
| 79 |
+
|
| 80 |
+
def __getitem__(self, ind):
|
| 81 |
+
ret = super().__getitem__(ind)
|
| 82 |
+
return sub(ret)
|
| 83 |
+
|
| 84 |
+
x = sub(1)
|
| 85 |
+
assert_equal(repr(x), 'sub(1)')
|
| 86 |
+
assert_equal(str(x), '1')
|
| 87 |
+
|
| 88 |
+
x = sub([1, 1])
|
| 89 |
+
assert_equal(repr(x), 'sub([1, 1])')
|
| 90 |
+
assert_equal(str(x), '[1 1]')
|
| 91 |
+
|
| 92 |
+
# check it works properly with object arrays too
|
| 93 |
+
x = sub(None)
|
| 94 |
+
assert_equal(repr(x), 'sub(None, dtype=object)')
|
| 95 |
+
assert_equal(str(x), 'None')
|
| 96 |
+
|
| 97 |
+
# plus recursive object arrays (even depth > 1)
|
| 98 |
+
y = sub(None)
|
| 99 |
+
x[()] = y
|
| 100 |
+
y[()] = x
|
| 101 |
+
assert_equal(repr(x),
|
| 102 |
+
'sub(sub(sub(..., dtype=object), dtype=object), dtype=object)')
|
| 103 |
+
assert_equal(str(x), '...')
|
| 104 |
+
x[()] = 0 # resolve circular references for garbage collector
|
| 105 |
+
|
| 106 |
+
# nested 0d-subclass-object
|
| 107 |
+
x = sub(None)
|
| 108 |
+
x[()] = sub(None)
|
| 109 |
+
assert_equal(repr(x), 'sub(sub(None, dtype=object), dtype=object)')
|
| 110 |
+
assert_equal(str(x), 'None')
|
| 111 |
+
|
| 112 |
+
# gh-10663
|
| 113 |
+
class DuckCounter(np.ndarray):
|
| 114 |
+
def __getitem__(self, item):
|
| 115 |
+
result = super().__getitem__(item)
|
| 116 |
+
if not isinstance(result, DuckCounter):
|
| 117 |
+
result = result[...].view(DuckCounter)
|
| 118 |
+
return result
|
| 119 |
+
|
| 120 |
+
def to_string(self):
|
| 121 |
+
return {0: 'zero', 1: 'one', 2: 'two'}.get(self.item(), 'many')
|
| 122 |
+
|
| 123 |
+
def __str__(self):
|
| 124 |
+
if self.shape == ():
|
| 125 |
+
return self.to_string()
|
| 126 |
+
else:
|
| 127 |
+
fmt = {'all': lambda x: x.to_string()}
|
| 128 |
+
return np.array2string(self, formatter=fmt)
|
| 129 |
+
|
| 130 |
+
dc = np.arange(5).view(DuckCounter)
|
| 131 |
+
assert_equal(str(dc), "[zero one two many many]")
|
| 132 |
+
assert_equal(str(dc[0]), "zero")
|
| 133 |
+
|
| 134 |
+
def test_self_containing(self):
|
| 135 |
+
arr0d = np.array(None)
|
| 136 |
+
arr0d[()] = arr0d
|
| 137 |
+
assert_equal(repr(arr0d),
|
| 138 |
+
'array(array(..., dtype=object), dtype=object)')
|
| 139 |
+
arr0d[()] = 0 # resolve recursion for garbage collector
|
| 140 |
+
|
| 141 |
+
arr1d = np.array([None, None])
|
| 142 |
+
arr1d[1] = arr1d
|
| 143 |
+
assert_equal(repr(arr1d),
|
| 144 |
+
'array([None, array(..., dtype=object)], dtype=object)')
|
| 145 |
+
arr1d[1] = 0 # resolve recursion for garbage collector
|
| 146 |
+
|
| 147 |
+
first = np.array(None)
|
| 148 |
+
second = np.array(None)
|
| 149 |
+
first[()] = second
|
| 150 |
+
second[()] = first
|
| 151 |
+
assert_equal(repr(first),
|
| 152 |
+
'array(array(array(..., dtype=object), dtype=object), dtype=object)')
|
| 153 |
+
first[()] = 0 # resolve circular references for garbage collector
|
| 154 |
+
|
| 155 |
+
def test_containing_list(self):
|
| 156 |
+
# printing square brackets directly would be ambiguous
|
| 157 |
+
arr1d = np.array([None, None])
|
| 158 |
+
arr1d[0] = [1, 2]
|
| 159 |
+
arr1d[1] = [3]
|
| 160 |
+
assert_equal(repr(arr1d),
|
| 161 |
+
'array([list([1, 2]), list([3])], dtype=object)')
|
| 162 |
+
|
| 163 |
+
def test_void_scalar_recursion(self):
|
| 164 |
+
# gh-9345
|
| 165 |
+
repr(np.void(b'test')) # RecursionError ?
|
| 166 |
+
|
| 167 |
+
def test_fieldless_structured(self):
|
| 168 |
+
# gh-10366
|
| 169 |
+
no_fields = np.dtype([])
|
| 170 |
+
arr_no_fields = np.empty(4, dtype=no_fields)
|
| 171 |
+
assert_equal(repr(arr_no_fields), 'array([(), (), (), ()], dtype=[])')
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
class TestComplexArray:
|
| 175 |
+
def test_str(self):
|
| 176 |
+
rvals = [0, 1, -1, np.inf, -np.inf, np.nan]
|
| 177 |
+
cvals = [complex(rp, ip) for rp in rvals for ip in rvals]
|
| 178 |
+
dtypes = [np.complex64, np.cdouble, np.clongdouble]
|
| 179 |
+
actual = [str(np.array([c], dt)) for c in cvals for dt in dtypes]
|
| 180 |
+
wanted = [
|
| 181 |
+
'[0.+0.j]', '[0.+0.j]', '[0.+0.j]',
|
| 182 |
+
'[0.+1.j]', '[0.+1.j]', '[0.+1.j]',
|
| 183 |
+
'[0.-1.j]', '[0.-1.j]', '[0.-1.j]',
|
| 184 |
+
'[0.+infj]', '[0.+infj]', '[0.+infj]',
|
| 185 |
+
'[0.-infj]', '[0.-infj]', '[0.-infj]',
|
| 186 |
+
'[0.+nanj]', '[0.+nanj]', '[0.+nanj]',
|
| 187 |
+
'[1.+0.j]', '[1.+0.j]', '[1.+0.j]',
|
| 188 |
+
'[1.+1.j]', '[1.+1.j]', '[1.+1.j]',
|
| 189 |
+
'[1.-1.j]', '[1.-1.j]', '[1.-1.j]',
|
| 190 |
+
'[1.+infj]', '[1.+infj]', '[1.+infj]',
|
| 191 |
+
'[1.-infj]', '[1.-infj]', '[1.-infj]',
|
| 192 |
+
'[1.+nanj]', '[1.+nanj]', '[1.+nanj]',
|
| 193 |
+
'[-1.+0.j]', '[-1.+0.j]', '[-1.+0.j]',
|
| 194 |
+
'[-1.+1.j]', '[-1.+1.j]', '[-1.+1.j]',
|
| 195 |
+
'[-1.-1.j]', '[-1.-1.j]', '[-1.-1.j]',
|
| 196 |
+
'[-1.+infj]', '[-1.+infj]', '[-1.+infj]',
|
| 197 |
+
'[-1.-infj]', '[-1.-infj]', '[-1.-infj]',
|
| 198 |
+
'[-1.+nanj]', '[-1.+nanj]', '[-1.+nanj]',
|
| 199 |
+
'[inf+0.j]', '[inf+0.j]', '[inf+0.j]',
|
| 200 |
+
'[inf+1.j]', '[inf+1.j]', '[inf+1.j]',
|
| 201 |
+
'[inf-1.j]', '[inf-1.j]', '[inf-1.j]',
|
| 202 |
+
'[inf+infj]', '[inf+infj]', '[inf+infj]',
|
| 203 |
+
'[inf-infj]', '[inf-infj]', '[inf-infj]',
|
| 204 |
+
'[inf+nanj]', '[inf+nanj]', '[inf+nanj]',
|
| 205 |
+
'[-inf+0.j]', '[-inf+0.j]', '[-inf+0.j]',
|
| 206 |
+
'[-inf+1.j]', '[-inf+1.j]', '[-inf+1.j]',
|
| 207 |
+
'[-inf-1.j]', '[-inf-1.j]', '[-inf-1.j]',
|
| 208 |
+
'[-inf+infj]', '[-inf+infj]', '[-inf+infj]',
|
| 209 |
+
'[-inf-infj]', '[-inf-infj]', '[-inf-infj]',
|
| 210 |
+
'[-inf+nanj]', '[-inf+nanj]', '[-inf+nanj]',
|
| 211 |
+
'[nan+0.j]', '[nan+0.j]', '[nan+0.j]',
|
| 212 |
+
'[nan+1.j]', '[nan+1.j]', '[nan+1.j]',
|
| 213 |
+
'[nan-1.j]', '[nan-1.j]', '[nan-1.j]',
|
| 214 |
+
'[nan+infj]', '[nan+infj]', '[nan+infj]',
|
| 215 |
+
'[nan-infj]', '[nan-infj]', '[nan-infj]',
|
| 216 |
+
'[nan+nanj]', '[nan+nanj]', '[nan+nanj]']
|
| 217 |
+
|
| 218 |
+
for res, val in zip(actual, wanted):
|
| 219 |
+
assert_equal(res, val)
|
| 220 |
+
|
| 221 |
+
class TestArray2String:
|
| 222 |
+
def test_basic(self):
|
| 223 |
+
"""Basic test of array2string."""
|
| 224 |
+
a = np.arange(3)
|
| 225 |
+
assert_(np.array2string(a) == '[0 1 2]')
|
| 226 |
+
assert_(np.array2string(a, max_line_width=4, legacy='1.13') == '[0 1\n 2]')
|
| 227 |
+
assert_(np.array2string(a, max_line_width=4) == '[0\n 1\n 2]')
|
| 228 |
+
|
| 229 |
+
def test_unexpected_kwarg(self):
|
| 230 |
+
# ensure than an appropriate TypeError
|
| 231 |
+
# is raised when array2string receives
|
| 232 |
+
# an unexpected kwarg
|
| 233 |
+
|
| 234 |
+
with assert_raises_regex(TypeError, 'nonsense'):
|
| 235 |
+
np.array2string(np.array([1, 2, 3]),
|
| 236 |
+
nonsense=None)
|
| 237 |
+
|
| 238 |
+
def test_format_function(self):
|
| 239 |
+
"""Test custom format function for each element in array."""
|
| 240 |
+
def _format_function(x):
|
| 241 |
+
if np.abs(x) < 1:
|
| 242 |
+
return '.'
|
| 243 |
+
elif np.abs(x) < 2:
|
| 244 |
+
return 'o'
|
| 245 |
+
else:
|
| 246 |
+
return 'O'
|
| 247 |
+
|
| 248 |
+
x = np.arange(3)
|
| 249 |
+
x_hex = "[0x0 0x1 0x2]"
|
| 250 |
+
x_oct = "[0o0 0o1 0o2]"
|
| 251 |
+
assert_(np.array2string(x, formatter={'all': _format_function}) ==
|
| 252 |
+
"[. o O]")
|
| 253 |
+
assert_(np.array2string(x, formatter={'int_kind': _format_function}) ==
|
| 254 |
+
"[. o O]")
|
| 255 |
+
assert_(np.array2string(x, formatter={'all': lambda x: f"{x:.4f}"}) ==
|
| 256 |
+
"[0.0000 1.0000 2.0000]")
|
| 257 |
+
assert_equal(np.array2string(x, formatter={'int': hex}),
|
| 258 |
+
x_hex)
|
| 259 |
+
assert_equal(np.array2string(x, formatter={'int': oct}),
|
| 260 |
+
x_oct)
|
| 261 |
+
|
| 262 |
+
x = np.arange(3.)
|
| 263 |
+
assert_(np.array2string(x, formatter={'float_kind': lambda x: f"{x:.2f}"}) ==
|
| 264 |
+
"[0.00 1.00 2.00]")
|
| 265 |
+
assert_(np.array2string(x, formatter={'float': lambda x: f"{x:.2f}"}) ==
|
| 266 |
+
"[0.00 1.00 2.00]")
|
| 267 |
+
|
| 268 |
+
s = np.array(['abc', 'def'])
|
| 269 |
+
assert_(np.array2string(s, formatter={'numpystr': lambda s: s * 2}) ==
|
| 270 |
+
'[abcabc defdef]')
|
| 271 |
+
|
| 272 |
+
def test_structure_format_mixed(self):
|
| 273 |
+
dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
|
| 274 |
+
x = np.array([('Sarah', (8.0, 7.0)), ('John', (6.0, 7.0))], dtype=dt)
|
| 275 |
+
assert_equal(np.array2string(x),
|
| 276 |
+
"[('Sarah', [8., 7.]) ('John', [6., 7.])]")
|
| 277 |
+
|
| 278 |
+
np.set_printoptions(legacy='1.13')
|
| 279 |
+
try:
|
| 280 |
+
# for issue #5692
|
| 281 |
+
A = np.zeros(shape=10, dtype=[("A", "M8[s]")])
|
| 282 |
+
A[5:].fill(np.datetime64('NaT', 'D'))
|
| 283 |
+
date_string = '1970-01-01T00:00:00'
|
| 284 |
+
assert_equal(
|
| 285 |
+
np.array2string(A),
|
| 286 |
+
textwrap.dedent(f"""\
|
| 287 |
+
[('{date_string}',) ('{date_string}',) ('{date_string}',)
|
| 288 |
+
('{date_string}',) ('{date_string}',) ('NaT',) ('NaT',)
|
| 289 |
+
('NaT',) ('NaT',) ('NaT',)]""")
|
| 290 |
+
)
|
| 291 |
+
finally:
|
| 292 |
+
np.set_printoptions(legacy=False)
|
| 293 |
+
|
| 294 |
+
# same again, but with non-legacy behavior
|
| 295 |
+
assert_equal(
|
| 296 |
+
np.array2string(A),
|
| 297 |
+
textwrap.dedent("""\
|
| 298 |
+
[('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',)
|
| 299 |
+
('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',)
|
| 300 |
+
('1970-01-01T00:00:00',) ( 'NaT',)
|
| 301 |
+
( 'NaT',) ( 'NaT',)
|
| 302 |
+
( 'NaT',) ( 'NaT',)]""")
|
| 303 |
+
)
|
| 304 |
+
|
| 305 |
+
# and again, with timedeltas
|
| 306 |
+
A = np.full(10, 123456, dtype=[("A", "m8[s]")])
|
| 307 |
+
A[5:].fill(np.datetime64('NaT', 'D'))
|
| 308 |
+
assert_equal(
|
| 309 |
+
np.array2string(A),
|
| 310 |
+
textwrap.dedent("""\
|
| 311 |
+
[(123456,) (123456,) (123456,) (123456,) (123456,) ( 'NaT',) ( 'NaT',)
|
| 312 |
+
( 'NaT',) ( 'NaT',) ( 'NaT',)]""")
|
| 313 |
+
)
|
| 314 |
+
|
| 315 |
+
def test_structure_format_int(self):
|
| 316 |
+
# See #8160
|
| 317 |
+
struct_int = np.array([([1, -1],), ([123, 1],)],
|
| 318 |
+
dtype=[('B', 'i4', 2)])
|
| 319 |
+
assert_equal(np.array2string(struct_int),
|
| 320 |
+
"[([ 1, -1],) ([123, 1],)]")
|
| 321 |
+
struct_2dint = np.array([([[0, 1], [2, 3]],), ([[12, 0], [0, 0]],)],
|
| 322 |
+
dtype=[('B', 'i4', (2, 2))])
|
| 323 |
+
assert_equal(np.array2string(struct_2dint),
|
| 324 |
+
"[([[ 0, 1], [ 2, 3]],) ([[12, 0], [ 0, 0]],)]")
|
| 325 |
+
|
| 326 |
+
def test_structure_format_float(self):
|
| 327 |
+
# See #8172
|
| 328 |
+
array_scalar = np.array(
|
| 329 |
+
(1., 2.1234567890123456789, 3.), dtype=('f8,f8,f8'))
|
| 330 |
+
assert_equal(np.array2string(array_scalar), "(1., 2.12345679, 3.)")
|
| 331 |
+
|
| 332 |
+
def test_unstructured_void_repr(self):
|
| 333 |
+
a = np.array([27, 91, 50, 75, 7, 65, 10, 8, 27, 91, 51, 49, 109, 82, 101, 100],
|
| 334 |
+
dtype='u1').view('V8')
|
| 335 |
+
assert_equal(repr(a[0]),
|
| 336 |
+
r"np.void(b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08')")
|
| 337 |
+
assert_equal(str(a[0]), r"b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08'")
|
| 338 |
+
assert_equal(repr(a),
|
| 339 |
+
r"array([b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08',"
|
| 340 |
+
"\n"
|
| 341 |
+
r" b'\x1B\x5B\x33\x31\x6D\x52\x65\x64'], dtype='|V8')")
|
| 342 |
+
|
| 343 |
+
assert_equal(eval(repr(a), vars(np)), a)
|
| 344 |
+
assert_equal(eval(repr(a[0]), {'np': np}), a[0])
|
| 345 |
+
|
| 346 |
+
def test_edgeitems_kwarg(self):
|
| 347 |
+
# previously the global print options would be taken over the kwarg
|
| 348 |
+
arr = np.zeros(3, int)
|
| 349 |
+
assert_equal(
|
| 350 |
+
np.array2string(arr, edgeitems=1, threshold=0),
|
| 351 |
+
"[0 ... 0]"
|
| 352 |
+
)
|
| 353 |
+
|
| 354 |
+
def test_summarize_1d(self):
|
| 355 |
+
A = np.arange(1001)
|
| 356 |
+
strA = '[ 0 1 2 ... 998 999 1000]'
|
| 357 |
+
assert_equal(str(A), strA)
|
| 358 |
+
|
| 359 |
+
reprA = 'array([ 0, 1, 2, ..., 998, 999, 1000])'
|
| 360 |
+
try:
|
| 361 |
+
np.set_printoptions(legacy='2.1')
|
| 362 |
+
assert_equal(repr(A), reprA)
|
| 363 |
+
finally:
|
| 364 |
+
np.set_printoptions(legacy=False)
|
| 365 |
+
|
| 366 |
+
assert_equal(repr(A), reprA.replace(')', ', shape=(1001,))'))
|
| 367 |
+
|
| 368 |
+
def test_summarize_2d(self):
|
| 369 |
+
A = np.arange(1002).reshape(2, 501)
|
| 370 |
+
strA = '[[ 0 1 2 ... 498 499 500]\n' \
|
| 371 |
+
' [ 501 502 503 ... 999 1000 1001]]'
|
| 372 |
+
assert_equal(str(A), strA)
|
| 373 |
+
|
| 374 |
+
reprA = 'array([[ 0, 1, 2, ..., 498, 499, 500],\n' \
|
| 375 |
+
' [ 501, 502, 503, ..., 999, 1000, 1001]])'
|
| 376 |
+
try:
|
| 377 |
+
np.set_printoptions(legacy='2.1')
|
| 378 |
+
assert_equal(repr(A), reprA)
|
| 379 |
+
finally:
|
| 380 |
+
np.set_printoptions(legacy=False)
|
| 381 |
+
|
| 382 |
+
assert_equal(repr(A), reprA.replace(')', ', shape=(2, 501))'))
|
| 383 |
+
|
| 384 |
+
def test_summarize_2d_dtype(self):
|
| 385 |
+
A = np.arange(1002, dtype='i2').reshape(2, 501)
|
| 386 |
+
strA = '[[ 0 1 2 ... 498 499 500]\n' \
|
| 387 |
+
' [ 501 502 503 ... 999 1000 1001]]'
|
| 388 |
+
assert_equal(str(A), strA)
|
| 389 |
+
|
| 390 |
+
reprA = ('array([[ 0, 1, 2, ..., 498, 499, 500],\n'
|
| 391 |
+
' [ 501, 502, 503, ..., 999, 1000, 1001]],\n'
|
| 392 |
+
' shape=(2, 501), dtype=int16)')
|
| 393 |
+
assert_equal(repr(A), reprA)
|
| 394 |
+
|
| 395 |
+
def test_summarize_structure(self):
|
| 396 |
+
A = (np.arange(2002, dtype="<i8").reshape(2, 1001)
|
| 397 |
+
.view([('i', "<i8", (1001,))]))
|
| 398 |
+
strA = ("[[([ 0, 1, 2, ..., 998, 999, 1000],)]\n"
|
| 399 |
+
" [([1001, 1002, 1003, ..., 1999, 2000, 2001],)]]")
|
| 400 |
+
assert_equal(str(A), strA)
|
| 401 |
+
|
| 402 |
+
reprA = ("array([[([ 0, 1, 2, ..., 998, 999, 1000],)],\n"
|
| 403 |
+
" [([1001, 1002, 1003, ..., 1999, 2000, 2001],)]],\n"
|
| 404 |
+
" dtype=[('i', '<i8', (1001,))])")
|
| 405 |
+
assert_equal(repr(A), reprA)
|
| 406 |
+
|
| 407 |
+
B = np.ones(2002, dtype=">i8").view([('i', ">i8", (2, 1001))])
|
| 408 |
+
strB = "[([[1, 1, 1, ..., 1, 1, 1], [1, 1, 1, ..., 1, 1, 1]],)]"
|
| 409 |
+
assert_equal(str(B), strB)
|
| 410 |
+
|
| 411 |
+
reprB = (
|
| 412 |
+
"array([([[1, 1, 1, ..., 1, 1, 1], [1, 1, 1, ..., 1, 1, 1]],)],\n"
|
| 413 |
+
" dtype=[('i', '>i8', (2, 1001))])"
|
| 414 |
+
)
|
| 415 |
+
assert_equal(repr(B), reprB)
|
| 416 |
+
|
| 417 |
+
C = (np.arange(22, dtype="<i8").reshape(2, 11)
|
| 418 |
+
.view([('i1', "<i8"), ('i10', "<i8", (10,))]))
|
| 419 |
+
strC = "[[( 0, [ 1, ..., 10])]\n [(11, [12, ..., 21])]]"
|
| 420 |
+
assert_equal(np.array2string(C, threshold=1, edgeitems=1), strC)
|
| 421 |
+
|
| 422 |
+
def test_linewidth(self):
|
| 423 |
+
a = np.full(6, 1)
|
| 424 |
+
|
| 425 |
+
def make_str(a, width, **kw):
|
| 426 |
+
return np.array2string(a, separator="", max_line_width=width, **kw)
|
| 427 |
+
|
| 428 |
+
assert_equal(make_str(a, 8, legacy='1.13'), '[111111]')
|
| 429 |
+
assert_equal(make_str(a, 7, legacy='1.13'), '[111111]')
|
| 430 |
+
assert_equal(make_str(a, 5, legacy='1.13'), '[1111\n'
|
| 431 |
+
' 11]')
|
| 432 |
+
|
| 433 |
+
assert_equal(make_str(a, 8), '[111111]')
|
| 434 |
+
assert_equal(make_str(a, 7), '[11111\n'
|
| 435 |
+
' 1]')
|
| 436 |
+
assert_equal(make_str(a, 5), '[111\n'
|
| 437 |
+
' 111]')
|
| 438 |
+
|
| 439 |
+
b = a[None, None, :]
|
| 440 |
+
|
| 441 |
+
assert_equal(make_str(b, 12, legacy='1.13'), '[[[111111]]]')
|
| 442 |
+
assert_equal(make_str(b, 9, legacy='1.13'), '[[[111111]]]')
|
| 443 |
+
assert_equal(make_str(b, 8, legacy='1.13'), '[[[11111\n'
|
| 444 |
+
' 1]]]')
|
| 445 |
+
|
| 446 |
+
assert_equal(make_str(b, 12), '[[[111111]]]')
|
| 447 |
+
assert_equal(make_str(b, 9), '[[[111\n'
|
| 448 |
+
' 111]]]')
|
| 449 |
+
assert_equal(make_str(b, 8), '[[[11\n'
|
| 450 |
+
' 11\n'
|
| 451 |
+
' 11]]]')
|
| 452 |
+
|
| 453 |
+
def test_wide_element(self):
|
| 454 |
+
a = np.array(['xxxxx'])
|
| 455 |
+
assert_equal(
|
| 456 |
+
np.array2string(a, max_line_width=5),
|
| 457 |
+
"['xxxxx']"
|
| 458 |
+
)
|
| 459 |
+
assert_equal(
|
| 460 |
+
np.array2string(a, max_line_width=5, legacy='1.13'),
|
| 461 |
+
"[ 'xxxxx']"
|
| 462 |
+
)
|
| 463 |
+
|
| 464 |
+
def test_multiline_repr(self):
|
| 465 |
+
class MultiLine:
|
| 466 |
+
def __repr__(self):
|
| 467 |
+
return "Line 1\nLine 2"
|
| 468 |
+
|
| 469 |
+
a = np.array([[None, MultiLine()], [MultiLine(), None]])
|
| 470 |
+
|
| 471 |
+
assert_equal(
|
| 472 |
+
np.array2string(a),
|
| 473 |
+
'[[None Line 1\n'
|
| 474 |
+
' Line 2]\n'
|
| 475 |
+
' [Line 1\n'
|
| 476 |
+
' Line 2 None]]'
|
| 477 |
+
)
|
| 478 |
+
assert_equal(
|
| 479 |
+
np.array2string(a, max_line_width=5),
|
| 480 |
+
'[[None\n'
|
| 481 |
+
' Line 1\n'
|
| 482 |
+
' Line 2]\n'
|
| 483 |
+
' [Line 1\n'
|
| 484 |
+
' Line 2\n'
|
| 485 |
+
' None]]'
|
| 486 |
+
)
|
| 487 |
+
assert_equal(
|
| 488 |
+
repr(a),
|
| 489 |
+
'array([[None, Line 1\n'
|
| 490 |
+
' Line 2],\n'
|
| 491 |
+
' [Line 1\n'
|
| 492 |
+
' Line 2, None]], dtype=object)'
|
| 493 |
+
)
|
| 494 |
+
|
| 495 |
+
class MultiLineLong:
|
| 496 |
+
def __repr__(self):
|
| 497 |
+
return "Line 1\nLooooooooooongestLine2\nLongerLine 3"
|
| 498 |
+
|
| 499 |
+
a = np.array([[None, MultiLineLong()], [MultiLineLong(), None]])
|
| 500 |
+
assert_equal(
|
| 501 |
+
repr(a),
|
| 502 |
+
'array([[None, Line 1\n'
|
| 503 |
+
' LooooooooooongestLine2\n'
|
| 504 |
+
' LongerLine 3 ],\n'
|
| 505 |
+
' [Line 1\n'
|
| 506 |
+
' LooooooooooongestLine2\n'
|
| 507 |
+
' LongerLine 3 , None]], dtype=object)'
|
| 508 |
+
)
|
| 509 |
+
assert_equal(
|
| 510 |
+
np.array_repr(a, 20),
|
| 511 |
+
'array([[None,\n'
|
| 512 |
+
' Line 1\n'
|
| 513 |
+
' LooooooooooongestLine2\n'
|
| 514 |
+
' LongerLine 3 ],\n'
|
| 515 |
+
' [Line 1\n'
|
| 516 |
+
' LooooooooooongestLine2\n'
|
| 517 |
+
' LongerLine 3 ,\n'
|
| 518 |
+
' None]],\n'
|
| 519 |
+
' dtype=object)'
|
| 520 |
+
)
|
| 521 |
+
|
| 522 |
+
def test_nested_array_repr(self):
|
| 523 |
+
a = np.empty((2, 2), dtype=object)
|
| 524 |
+
a[0, 0] = np.eye(2)
|
| 525 |
+
a[0, 1] = np.eye(3)
|
| 526 |
+
a[1, 0] = None
|
| 527 |
+
a[1, 1] = np.ones((3, 1))
|
| 528 |
+
assert_equal(
|
| 529 |
+
repr(a),
|
| 530 |
+
'array([[array([[1., 0.],\n'
|
| 531 |
+
' [0., 1.]]), array([[1., 0., 0.],\n'
|
| 532 |
+
' [0., 1., 0.],\n'
|
| 533 |
+
' [0., 0., 1.]])],\n'
|
| 534 |
+
' [None, array([[1.],\n'
|
| 535 |
+
' [1.],\n'
|
| 536 |
+
' [1.]])]], dtype=object)'
|
| 537 |
+
)
|
| 538 |
+
|
| 539 |
+
@given(hynp.from_dtype(np.dtype("U")))
|
| 540 |
+
def test_any_text(self, text):
|
| 541 |
+
# This test checks that, given any value that can be represented in an
|
| 542 |
+
# array of dtype("U") (i.e. unicode string), ...
|
| 543 |
+
a = np.array([text, text, text])
|
| 544 |
+
# casting a list of them to an array does not e.g. truncate the value
|
| 545 |
+
assert_equal(a[0], text)
|
| 546 |
+
text = text.item() # use raw python strings for repr below
|
| 547 |
+
# and that np.array2string puts a newline in the expected location
|
| 548 |
+
expected_repr = f"[{text!r} {text!r}\n {text!r}]"
|
| 549 |
+
result = np.array2string(a, max_line_width=len(repr(text)) * 2 + 3)
|
| 550 |
+
assert_equal(result, expected_repr)
|
| 551 |
+
|
| 552 |
+
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
|
| 553 |
+
@pytest.mark.thread_unsafe(reason="garbage collector is global state")
|
| 554 |
+
def test_refcount(self):
|
| 555 |
+
# make sure we do not hold references to the array due to a recursive
|
| 556 |
+
# closure (gh-10620)
|
| 557 |
+
gc.disable()
|
| 558 |
+
a = np.arange(2)
|
| 559 |
+
r1 = sys.getrefcount(a)
|
| 560 |
+
np.array2string(a)
|
| 561 |
+
np.array2string(a)
|
| 562 |
+
r2 = sys.getrefcount(a)
|
| 563 |
+
gc.collect()
|
| 564 |
+
gc.enable()
|
| 565 |
+
assert_(r1 == r2)
|
| 566 |
+
|
| 567 |
+
def test_with_sign(self):
|
| 568 |
+
# mixed negative and positive value array
|
| 569 |
+
a = np.array([-2, 0, 3])
|
| 570 |
+
assert_equal(
|
| 571 |
+
np.array2string(a, sign='+'),
|
| 572 |
+
'[-2 +0 +3]'
|
| 573 |
+
)
|
| 574 |
+
assert_equal(
|
| 575 |
+
np.array2string(a, sign='-'),
|
| 576 |
+
'[-2 0 3]'
|
| 577 |
+
)
|
| 578 |
+
assert_equal(
|
| 579 |
+
np.array2string(a, sign=' '),
|
| 580 |
+
'[-2 0 3]'
|
| 581 |
+
)
|
| 582 |
+
# all non-negative array
|
| 583 |
+
a = np.array([2, 0, 3])
|
| 584 |
+
assert_equal(
|
| 585 |
+
np.array2string(a, sign='+'),
|
| 586 |
+
'[+2 +0 +3]'
|
| 587 |
+
)
|
| 588 |
+
assert_equal(
|
| 589 |
+
np.array2string(a, sign='-'),
|
| 590 |
+
'[2 0 3]'
|
| 591 |
+
)
|
| 592 |
+
assert_equal(
|
| 593 |
+
np.array2string(a, sign=' '),
|
| 594 |
+
'[ 2 0 3]'
|
| 595 |
+
)
|
| 596 |
+
# all negative array
|
| 597 |
+
a = np.array([-2, -1, -3])
|
| 598 |
+
assert_equal(
|
| 599 |
+
np.array2string(a, sign='+'),
|
| 600 |
+
'[-2 -1 -3]'
|
| 601 |
+
)
|
| 602 |
+
assert_equal(
|
| 603 |
+
np.array2string(a, sign='-'),
|
| 604 |
+
'[-2 -1 -3]'
|
| 605 |
+
)
|
| 606 |
+
assert_equal(
|
| 607 |
+
np.array2string(a, sign=' '),
|
| 608 |
+
'[-2 -1 -3]'
|
| 609 |
+
)
|
| 610 |
+
# 2d array mixed negative and positive
|
| 611 |
+
a = np.array([[10, -1, 1, 1], [10, 10, 10, 10]])
|
| 612 |
+
assert_equal(
|
| 613 |
+
np.array2string(a, sign='+'),
|
| 614 |
+
'[[+10 -1 +1 +1]\n [+10 +10 +10 +10]]'
|
| 615 |
+
)
|
| 616 |
+
assert_equal(
|
| 617 |
+
np.array2string(a, sign='-'),
|
| 618 |
+
'[[10 -1 1 1]\n [10 10 10 10]]'
|
| 619 |
+
)
|
| 620 |
+
assert_equal(
|
| 621 |
+
np.array2string(a, sign=' '),
|
| 622 |
+
'[[10 -1 1 1]\n [10 10 10 10]]'
|
| 623 |
+
)
|
| 624 |
+
# 2d array all positive
|
| 625 |
+
a = np.array([[10, 0, 1, 1], [10, 10, 10, 10]])
|
| 626 |
+
assert_equal(
|
| 627 |
+
np.array2string(a, sign='+'),
|
| 628 |
+
'[[+10 +0 +1 +1]\n [+10 +10 +10 +10]]'
|
| 629 |
+
)
|
| 630 |
+
assert_equal(
|
| 631 |
+
np.array2string(a, sign='-'),
|
| 632 |
+
'[[10 0 1 1]\n [10 10 10 10]]'
|
| 633 |
+
)
|
| 634 |
+
assert_equal(
|
| 635 |
+
np.array2string(a, sign=' '),
|
| 636 |
+
'[[ 10 0 1 1]\n [ 10 10 10 10]]'
|
| 637 |
+
)
|
| 638 |
+
# 2d array all negative
|
| 639 |
+
a = np.array([[-10, -1, -1, -1], [-10, -10, -10, -10]])
|
| 640 |
+
assert_equal(
|
| 641 |
+
np.array2string(a, sign='+'),
|
| 642 |
+
'[[-10 -1 -1 -1]\n [-10 -10 -10 -10]]'
|
| 643 |
+
)
|
| 644 |
+
assert_equal(
|
| 645 |
+
np.array2string(a, sign='-'),
|
| 646 |
+
'[[-10 -1 -1 -1]\n [-10 -10 -10 -10]]'
|
| 647 |
+
)
|
| 648 |
+
assert_equal(
|
| 649 |
+
np.array2string(a, sign=' '),
|
| 650 |
+
'[[-10 -1 -1 -1]\n [-10 -10 -10 -10]]'
|
| 651 |
+
)
|
| 652 |
+
|
| 653 |
+
|
| 654 |
+
class TestPrintOptions:
|
| 655 |
+
"""Test getting and setting global print options."""
|
| 656 |
+
|
| 657 |
+
def setup_method(self):
|
| 658 |
+
self.oldopts = np.get_printoptions()
|
| 659 |
+
|
| 660 |
+
def teardown_method(self):
|
| 661 |
+
np.set_printoptions(**self.oldopts)
|
| 662 |
+
|
| 663 |
+
def test_basic(self):
|
| 664 |
+
x = np.array([1.5, 0, 1.234567890])
|
| 665 |
+
assert_equal(repr(x), "array([1.5 , 0. , 1.23456789])")
|
| 666 |
+
ret = np.set_printoptions(precision=4)
|
| 667 |
+
assert_equal(repr(x), "array([1.5 , 0. , 1.2346])")
|
| 668 |
+
assert ret is None
|
| 669 |
+
|
| 670 |
+
def test_precision_zero(self):
|
| 671 |
+
np.set_printoptions(precision=0)
|
| 672 |
+
for values, string in (
|
| 673 |
+
([0.], "0."), ([.3], "0."), ([-.3], "-0."), ([.7], "1."),
|
| 674 |
+
([1.5], "2."), ([-1.5], "-2."), ([-15.34], "-15."),
|
| 675 |
+
([100.], "100."), ([.2, -1, 122.51], " 0., -1., 123."),
|
| 676 |
+
([0], "0"), ([-12], "-12"), ([complex(.3, -.7)], "0.-1.j")):
|
| 677 |
+
x = np.array(values)
|
| 678 |
+
assert_equal(repr(x), f"array([{string}])")
|
| 679 |
+
|
| 680 |
+
def test_formatter(self):
|
| 681 |
+
x = np.arange(3)
|
| 682 |
+
np.set_printoptions(formatter={'all': lambda x: str(x - 1)})
|
| 683 |
+
assert_equal(repr(x), "array([-1, 0, 1])")
|
| 684 |
+
|
| 685 |
+
def test_formatter_reset(self):
|
| 686 |
+
x = np.arange(3)
|
| 687 |
+
np.set_printoptions(formatter={'all': lambda x: str(x - 1)})
|
| 688 |
+
assert_equal(repr(x), "array([-1, 0, 1])")
|
| 689 |
+
np.set_printoptions(formatter={'int': None})
|
| 690 |
+
assert_equal(repr(x), "array([0, 1, 2])")
|
| 691 |
+
|
| 692 |
+
np.set_printoptions(formatter={'all': lambda x: str(x - 1)})
|
| 693 |
+
assert_equal(repr(x), "array([-1, 0, 1])")
|
| 694 |
+
np.set_printoptions(formatter={'all': None})
|
| 695 |
+
assert_equal(repr(x), "array([0, 1, 2])")
|
| 696 |
+
|
| 697 |
+
np.set_printoptions(formatter={'int': lambda x: str(x - 1)})
|
| 698 |
+
assert_equal(repr(x), "array([-1, 0, 1])")
|
| 699 |
+
np.set_printoptions(formatter={'int_kind': None})
|
| 700 |
+
assert_equal(repr(x), "array([0, 1, 2])")
|
| 701 |
+
|
| 702 |
+
x = np.arange(3.)
|
| 703 |
+
np.set_printoptions(formatter={'float': lambda x: str(x - 1)})
|
| 704 |
+
assert_equal(repr(x), "array([-1.0, 0.0, 1.0])")
|
| 705 |
+
np.set_printoptions(formatter={'float_kind': None})
|
| 706 |
+
assert_equal(repr(x), "array([0., 1., 2.])")
|
| 707 |
+
|
| 708 |
+
def test_override_repr(self):
|
| 709 |
+
x = np.arange(3)
|
| 710 |
+
np.set_printoptions(override_repr=lambda x: "FOO")
|
| 711 |
+
assert_equal(repr(x), "FOO")
|
| 712 |
+
np.set_printoptions(override_repr=None)
|
| 713 |
+
assert_equal(repr(x), "array([0, 1, 2])")
|
| 714 |
+
|
| 715 |
+
with np.printoptions(override_repr=lambda x: "BAR"):
|
| 716 |
+
assert_equal(repr(x), "BAR")
|
| 717 |
+
assert_equal(repr(x), "array([0, 1, 2])")
|
| 718 |
+
|
| 719 |
+
def test_0d_arrays(self):
|
| 720 |
+
assert_equal(str(np.array('café', '<U4')), 'café')
|
| 721 |
+
|
| 722 |
+
assert_equal(repr(np.array('café', '<U4')),
|
| 723 |
+
"array('café', dtype='<U4')")
|
| 724 |
+
assert_equal(str(np.array('test', np.str_)), 'test')
|
| 725 |
+
|
| 726 |
+
a = np.zeros(1, dtype=[('a', '<i4', (3,))])
|
| 727 |
+
assert_equal(str(a[0]), '([0, 0, 0],)')
|
| 728 |
+
|
| 729 |
+
assert_equal(repr(np.datetime64('2005-02-25')[...]),
|
| 730 |
+
"array('2005-02-25', dtype='datetime64[D]')")
|
| 731 |
+
|
| 732 |
+
assert_equal(repr(np.timedelta64('10', 'Y')[...]),
|
| 733 |
+
"array(10, dtype='timedelta64[Y]')")
|
| 734 |
+
|
| 735 |
+
# repr of 0d arrays is affected by printoptions
|
| 736 |
+
x = np.array(1)
|
| 737 |
+
np.set_printoptions(formatter={'all': lambda x: "test"})
|
| 738 |
+
assert_equal(repr(x), "array(test)")
|
| 739 |
+
# str is unaffected
|
| 740 |
+
assert_equal(str(x), "1")
|
| 741 |
+
|
| 742 |
+
# check it works
|
| 743 |
+
np.array2string(np.array(1.), legacy='1.13')
|
| 744 |
+
|
| 745 |
+
def test_float_spacing(self):
|
| 746 |
+
x = np.array([1., 2., 3.])
|
| 747 |
+
y = np.array([1., 2., -10.])
|
| 748 |
+
z = np.array([100., 2., -1.])
|
| 749 |
+
w = np.array([-100., 2., 1.])
|
| 750 |
+
|
| 751 |
+
assert_equal(repr(x), 'array([1., 2., 3.])')
|
| 752 |
+
assert_equal(repr(y), 'array([ 1., 2., -10.])')
|
| 753 |
+
assert_equal(repr(np.array(y[0])), 'array(1.)')
|
| 754 |
+
assert_equal(repr(np.array(y[-1])), 'array(-10.)')
|
| 755 |
+
assert_equal(repr(z), 'array([100., 2., -1.])')
|
| 756 |
+
assert_equal(repr(w), 'array([-100., 2., 1.])')
|
| 757 |
+
|
| 758 |
+
assert_equal(repr(np.array([np.nan, np.inf])), 'array([nan, inf])')
|
| 759 |
+
assert_equal(repr(np.array([np.nan, -np.inf])), 'array([ nan, -inf])')
|
| 760 |
+
|
| 761 |
+
x = np.array([np.inf, 100000, 1.1234])
|
| 762 |
+
y = np.array([np.inf, 100000, -1.1234])
|
| 763 |
+
z = np.array([np.inf, 1.1234, -1e120])
|
| 764 |
+
np.set_printoptions(precision=2)
|
| 765 |
+
assert_equal(repr(x), 'array([ inf, 1.00e+05, 1.12e+00])')
|
| 766 |
+
assert_equal(repr(y), 'array([ inf, 1.00e+05, -1.12e+00])')
|
| 767 |
+
assert_equal(repr(z), 'array([ inf, 1.12e+000, -1.00e+120])')
|
| 768 |
+
|
| 769 |
+
def test_bool_spacing(self):
|
| 770 |
+
assert_equal(repr(np.array([True, True])),
|
| 771 |
+
'array([ True, True])')
|
| 772 |
+
assert_equal(repr(np.array([True, False])),
|
| 773 |
+
'array([ True, False])')
|
| 774 |
+
assert_equal(repr(np.array([True])),
|
| 775 |
+
'array([ True])')
|
| 776 |
+
assert_equal(repr(np.array(True)),
|
| 777 |
+
'array(True)')
|
| 778 |
+
assert_equal(repr(np.array(False)),
|
| 779 |
+
'array(False)')
|
| 780 |
+
|
| 781 |
+
def test_sign_spacing(self):
|
| 782 |
+
a = np.arange(4.)
|
| 783 |
+
b = np.array([1.234e9])
|
| 784 |
+
c = np.array([1.0 + 1.0j, 1.123456789 + 1.123456789j], dtype='c16')
|
| 785 |
+
|
| 786 |
+
assert_equal(repr(a), 'array([0., 1., 2., 3.])')
|
| 787 |
+
assert_equal(repr(np.array(1.)), 'array(1.)')
|
| 788 |
+
assert_equal(repr(b), 'array([1.234e+09])')
|
| 789 |
+
assert_equal(repr(np.array([0.])), 'array([0.])')
|
| 790 |
+
assert_equal(repr(c),
|
| 791 |
+
"array([1. +1.j , 1.12345679+1.12345679j])")
|
| 792 |
+
assert_equal(repr(np.array([0., -0.])), 'array([ 0., -0.])')
|
| 793 |
+
|
| 794 |
+
np.set_printoptions(sign=' ')
|
| 795 |
+
assert_equal(repr(a), 'array([ 0., 1., 2., 3.])')
|
| 796 |
+
assert_equal(repr(np.array(1.)), 'array( 1.)')
|
| 797 |
+
assert_equal(repr(b), 'array([ 1.234e+09])')
|
| 798 |
+
assert_equal(repr(c),
|
| 799 |
+
"array([ 1. +1.j , 1.12345679+1.12345679j])")
|
| 800 |
+
assert_equal(repr(np.array([0., -0.])), 'array([ 0., -0.])')
|
| 801 |
+
|
| 802 |
+
np.set_printoptions(sign='+')
|
| 803 |
+
assert_equal(repr(a), 'array([+0., +1., +2., +3.])')
|
| 804 |
+
assert_equal(repr(np.array(1.)), 'array(+1.)')
|
| 805 |
+
assert_equal(repr(b), 'array([+1.234e+09])')
|
| 806 |
+
assert_equal(repr(c),
|
| 807 |
+
"array([+1. +1.j , +1.12345679+1.12345679j])")
|
| 808 |
+
|
| 809 |
+
np.set_printoptions(legacy='1.13')
|
| 810 |
+
assert_equal(repr(a), 'array([ 0., 1., 2., 3.])')
|
| 811 |
+
assert_equal(repr(b), 'array([ 1.23400000e+09])')
|
| 812 |
+
assert_equal(repr(-b), 'array([ -1.23400000e+09])')
|
| 813 |
+
assert_equal(repr(np.array(1.)), 'array(1.0)')
|
| 814 |
+
assert_equal(repr(np.array([0.])), 'array([ 0.])')
|
| 815 |
+
assert_equal(repr(c),
|
| 816 |
+
"array([ 1.00000000+1.j , 1.12345679+1.12345679j])")
|
| 817 |
+
# gh-10383
|
| 818 |
+
assert_equal(str(np.array([-1., 10])), "[ -1. 10.]")
|
| 819 |
+
|
| 820 |
+
assert_raises(TypeError, np.set_printoptions, wrongarg=True)
|
| 821 |
+
|
| 822 |
+
def test_float_overflow_nowarn(self):
|
| 823 |
+
# make sure internal computations in FloatingFormat don't
|
| 824 |
+
# warn about overflow
|
| 825 |
+
repr(np.array([1e4, 0.1], dtype='f2'))
|
| 826 |
+
|
| 827 |
+
def test_sign_spacing_structured(self):
|
| 828 |
+
a = np.ones(2, dtype='<f,<f')
|
| 829 |
+
assert_equal(repr(a),
|
| 830 |
+
"array([(1., 1.), (1., 1.)], dtype=[('f0', '<f4'), ('f1', '<f4')])")
|
| 831 |
+
assert_equal(repr(a[0]),
|
| 832 |
+
"np.void((1.0, 1.0), dtype=[('f0', '<f4'), ('f1', '<f4')])")
|
| 833 |
+
|
| 834 |
+
def test_floatmode(self):
|
| 835 |
+
x = np.array([0.6104, 0.922, 0.457, 0.0906, 0.3733, 0.007244,
|
| 836 |
+
0.5933, 0.947, 0.2383, 0.4226], dtype=np.float16)
|
| 837 |
+
y = np.array([0.2918820979355541, 0.5064172631089138,
|
| 838 |
+
0.2848750619642916, 0.4342965294660567,
|
| 839 |
+
0.7326538397312751, 0.3459503329096204,
|
| 840 |
+
0.0862072768214508, 0.39112753029631175],
|
| 841 |
+
dtype=np.float64)
|
| 842 |
+
z = np.arange(6, dtype=np.float16) / 10
|
| 843 |
+
c = np.array([1.0 + 1.0j, 1.123456789 + 1.123456789j], dtype='c16')
|
| 844 |
+
|
| 845 |
+
# also make sure 1e23 is right (is between two fp numbers)
|
| 846 |
+
w = np.array([f'1e{i}' for i in range(25)], dtype=np.float64)
|
| 847 |
+
# note: we construct w from the strings `1eXX` instead of doing
|
| 848 |
+
# `10.**arange(24)` because it turns out the two are not equivalent in
|
| 849 |
+
# python. On some architectures `1e23 != 10.**23`.
|
| 850 |
+
wp = np.array([1.234e1, 1e2, 1e123])
|
| 851 |
+
|
| 852 |
+
# unique mode
|
| 853 |
+
np.set_printoptions(floatmode='unique')
|
| 854 |
+
assert_equal(repr(x),
|
| 855 |
+
"array([0.6104 , 0.922 , 0.457 , 0.0906 , 0.3733 , 0.007244,\n"
|
| 856 |
+
" 0.5933 , 0.947 , 0.2383 , 0.4226 ], dtype=float16)")
|
| 857 |
+
assert_equal(repr(y),
|
| 858 |
+
"array([0.2918820979355541 , 0.5064172631089138 , 0.2848750619642916 ,\n"
|
| 859 |
+
" 0.4342965294660567 , 0.7326538397312751 , 0.3459503329096204 ,\n"
|
| 860 |
+
" 0.0862072768214508 , 0.39112753029631175])")
|
| 861 |
+
assert_equal(repr(z),
|
| 862 |
+
"array([0. , 0.1, 0.2, 0.3, 0.4, 0.5], dtype=float16)")
|
| 863 |
+
assert_equal(repr(w),
|
| 864 |
+
"array([1.e+00, 1.e+01, 1.e+02, 1.e+03, 1.e+04, 1.e+05, 1.e+06, 1.e+07,\n"
|
| 865 |
+
" 1.e+08, 1.e+09, 1.e+10, 1.e+11, 1.e+12, 1.e+13, 1.e+14, 1.e+15,\n"
|
| 866 |
+
" 1.e+16, 1.e+17, 1.e+18, 1.e+19, 1.e+20, 1.e+21, 1.e+22, 1.e+23,\n"
|
| 867 |
+
" 1.e+24])")
|
| 868 |
+
assert_equal(repr(wp), "array([1.234e+001, 1.000e+002, 1.000e+123])")
|
| 869 |
+
assert_equal(repr(c),
|
| 870 |
+
"array([1. +1.j , 1.123456789+1.123456789j])")
|
| 871 |
+
|
| 872 |
+
# maxprec mode, precision=8
|
| 873 |
+
np.set_printoptions(floatmode='maxprec', precision=8)
|
| 874 |
+
assert_equal(repr(x),
|
| 875 |
+
"array([0.6104 , 0.922 , 0.457 , 0.0906 , 0.3733 , 0.007244,\n"
|
| 876 |
+
" 0.5933 , 0.947 , 0.2383 , 0.4226 ], dtype=float16)")
|
| 877 |
+
assert_equal(repr(y),
|
| 878 |
+
"array([0.2918821 , 0.50641726, 0.28487506, 0.43429653, 0.73265384,\n"
|
| 879 |
+
" 0.34595033, 0.08620728, 0.39112753])")
|
| 880 |
+
assert_equal(repr(z),
|
| 881 |
+
"array([0. , 0.1, 0.2, 0.3, 0.4, 0.5], dtype=float16)")
|
| 882 |
+
assert_equal(repr(w[::5]),
|
| 883 |
+
"array([1.e+00, 1.e+05, 1.e+10, 1.e+15, 1.e+20])")
|
| 884 |
+
assert_equal(repr(wp), "array([1.234e+001, 1.000e+002, 1.000e+123])")
|
| 885 |
+
assert_equal(repr(c),
|
| 886 |
+
"array([1. +1.j , 1.12345679+1.12345679j])")
|
| 887 |
+
|
| 888 |
+
# fixed mode, precision=4
|
| 889 |
+
np.set_printoptions(floatmode='fixed', precision=4)
|
| 890 |
+
assert_equal(repr(x),
|
| 891 |
+
"array([0.6104, 0.9219, 0.4570, 0.0906, 0.3733, 0.0072, 0.5933, 0.9468,\n"
|
| 892 |
+
" 0.2383, 0.4226], dtype=float16)")
|
| 893 |
+
assert_equal(repr(y),
|
| 894 |
+
"array([0.2919, 0.5064, 0.2849, 0.4343, 0.7327, 0.3460, 0.0862, 0.3911])")
|
| 895 |
+
assert_equal(repr(z),
|
| 896 |
+
"array([0.0000, 0.1000, 0.2000, 0.3000, 0.3999, 0.5000], dtype=float16)")
|
| 897 |
+
assert_equal(repr(w[::5]),
|
| 898 |
+
"array([1.0000e+00, 1.0000e+05, 1.0000e+10, 1.0000e+15, 1.0000e+20])")
|
| 899 |
+
assert_equal(repr(wp), "array([1.2340e+001, 1.0000e+002, 1.0000e+123])")
|
| 900 |
+
assert_equal(repr(np.zeros(3)), "array([0.0000, 0.0000, 0.0000])")
|
| 901 |
+
assert_equal(repr(c),
|
| 902 |
+
"array([1.0000+1.0000j, 1.1235+1.1235j])")
|
| 903 |
+
# for larger precision, representation error becomes more apparent:
|
| 904 |
+
np.set_printoptions(floatmode='fixed', precision=8)
|
| 905 |
+
assert_equal(repr(z),
|
| 906 |
+
"array([0.00000000, 0.09997559, 0.19995117, 0.30004883, 0.39990234,\n"
|
| 907 |
+
" 0.50000000], dtype=float16)")
|
| 908 |
+
|
| 909 |
+
# maxprec_equal mode, precision=8
|
| 910 |
+
np.set_printoptions(floatmode='maxprec_equal', precision=8)
|
| 911 |
+
assert_equal(repr(x),
|
| 912 |
+
"array([0.610352, 0.921875, 0.457031, 0.090576, 0.373291, 0.007244,\n"
|
| 913 |
+
" 0.593262, 0.946777, 0.238281, 0.422607], dtype=float16)")
|
| 914 |
+
assert_equal(repr(y),
|
| 915 |
+
"array([0.29188210, 0.50641726, 0.28487506, 0.43429653, 0.73265384,\n"
|
| 916 |
+
" 0.34595033, 0.08620728, 0.39112753])")
|
| 917 |
+
assert_equal(repr(z),
|
| 918 |
+
"array([0.0, 0.1, 0.2, 0.3, 0.4, 0.5], dtype=float16)")
|
| 919 |
+
assert_equal(repr(w[::5]),
|
| 920 |
+
"array([1.e+00, 1.e+05, 1.e+10, 1.e+15, 1.e+20])")
|
| 921 |
+
assert_equal(repr(wp), "array([1.234e+001, 1.000e+002, 1.000e+123])")
|
| 922 |
+
assert_equal(repr(c),
|
| 923 |
+
"array([1.00000000+1.00000000j, 1.12345679+1.12345679j])")
|
| 924 |
+
|
| 925 |
+
# test unique special case (gh-18609)
|
| 926 |
+
a = np.float64.fromhex('-1p-97')
|
| 927 |
+
assert_equal(np.float64(np.array2string(a, floatmode='unique')), a)
|
| 928 |
+
|
| 929 |
+
test_cases_gh_28679 = [
|
| 930 |
+
(np.half([999, 999]), "[999. 999.]"),
|
| 931 |
+
(np.half([999, 1000]), "[9.99e+02 1.00e+03]"),
|
| 932 |
+
(np.single([999999, 999999]), "[999999. 999999.]"),
|
| 933 |
+
(np.single([999999, -1000000]), "[ 9.99999e+05 -1.00000e+06]"),
|
| 934 |
+
(
|
| 935 |
+
np.complex64([999999 + 999999j, 999999 + 999999j]),
|
| 936 |
+
"[999999.+999999.j 999999.+999999.j]"
|
| 937 |
+
),
|
| 938 |
+
(
|
| 939 |
+
np.complex64([999999 + 999999j, 999999 + -1000000j]),
|
| 940 |
+
"[999999.+9.99999e+05j 999999.-1.00000e+06j]"
|
| 941 |
+
),
|
| 942 |
+
]
|
| 943 |
+
|
| 944 |
+
@pytest.mark.parametrize("input_array, expected_str", test_cases_gh_28679)
|
| 945 |
+
def test_gh_28679(self, input_array, expected_str):
|
| 946 |
+
# test cutoff to exponent notation for half, single, and complex64
|
| 947 |
+
assert_equal(str(input_array), expected_str)
|
| 948 |
+
|
| 949 |
+
test_cases_legacy_2_2 = [
|
| 950 |
+
(np.half([1.e3, 1.e4, 65504]), "[ 1000. 10000. 65504.]"),
|
| 951 |
+
(np.single([1.e6, 1.e7]), "[ 1000000. 10000000.]"),
|
| 952 |
+
(np.single([1.e7, 1.e8]), "[1.e+07 1.e+08]"),
|
| 953 |
+
]
|
| 954 |
+
|
| 955 |
+
@pytest.mark.parametrize("input_array, expected_str", test_cases_legacy_2_2)
|
| 956 |
+
def test_legacy_2_2_mode(self, input_array, expected_str):
|
| 957 |
+
# test legacy cutoff to exponent notation for half and single
|
| 958 |
+
with np.printoptions(legacy='2.2'):
|
| 959 |
+
assert_equal(str(input_array), expected_str)
|
| 960 |
+
|
| 961 |
+
@pytest.mark.parametrize("legacy", ['1.13', '1.21', '1.25', '2.1', '2.2'])
|
| 962 |
+
def test_legacy_get_options(self, legacy):
|
| 963 |
+
# test legacy get options works okay
|
| 964 |
+
with np.printoptions(legacy=legacy):
|
| 965 |
+
p_opt = np.get_printoptions()
|
| 966 |
+
assert_equal(p_opt["legacy"], legacy)
|
| 967 |
+
|
| 968 |
+
def test_legacy_mode_scalars(self):
|
| 969 |
+
# in legacy mode, str of floats get truncated, and complex scalars
|
| 970 |
+
# use * for non-finite imaginary part
|
| 971 |
+
np.set_printoptions(legacy='1.13')
|
| 972 |
+
assert_equal(str(np.float64(1.123456789123456789)), '1.12345678912')
|
| 973 |
+
assert_equal(str(np.complex128(complex(1, np.nan))), '(1+nan*j)')
|
| 974 |
+
|
| 975 |
+
np.set_printoptions(legacy=False)
|
| 976 |
+
assert_equal(str(np.float64(1.123456789123456789)),
|
| 977 |
+
'1.1234567891234568')
|
| 978 |
+
assert_equal(str(np.complex128(complex(1, np.nan))), '(1+nanj)')
|
| 979 |
+
|
| 980 |
+
def test_legacy_stray_comma(self):
|
| 981 |
+
np.set_printoptions(legacy='1.13')
|
| 982 |
+
assert_equal(str(np.arange(10000)), '[ 0 1 2 ..., 9997 9998 9999]')
|
| 983 |
+
|
| 984 |
+
np.set_printoptions(legacy=False)
|
| 985 |
+
assert_equal(str(np.arange(10000)), '[ 0 1 2 ... 9997 9998 9999]')
|
| 986 |
+
|
| 987 |
+
def test_dtype_linewidth_wrapping(self):
|
| 988 |
+
np.set_printoptions(linewidth=75)
|
| 989 |
+
assert_equal(repr(np.arange(10, 20., dtype='f4')),
|
| 990 |
+
"array([10., 11., 12., 13., 14., 15., 16., 17., 18., 19.], dtype=float32)")
|
| 991 |
+
assert_equal(repr(np.arange(10, 23., dtype='f4')), textwrap.dedent("""\
|
| 992 |
+
array([10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22.],
|
| 993 |
+
dtype=float32)"""))
|
| 994 |
+
|
| 995 |
+
styp = '<U4'
|
| 996 |
+
assert_equal(repr(np.ones(3, dtype=styp)),
|
| 997 |
+
f"array(['1', '1', '1'], dtype='{styp}')")
|
| 998 |
+
assert_equal(repr(np.ones(12, dtype=styp)), textwrap.dedent(f"""\
|
| 999 |
+
array(['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1'],
|
| 1000 |
+
dtype='{styp}')"""))
|
| 1001 |
+
|
| 1002 |
+
@pytest.mark.parametrize(
|
| 1003 |
+
['native'],
|
| 1004 |
+
[
|
| 1005 |
+
('bool',),
|
| 1006 |
+
('uint8',),
|
| 1007 |
+
('uint16',),
|
| 1008 |
+
('uint32',),
|
| 1009 |
+
('uint64',),
|
| 1010 |
+
('int8',),
|
| 1011 |
+
('int16',),
|
| 1012 |
+
('int32',),
|
| 1013 |
+
('int64',),
|
| 1014 |
+
('float16',),
|
| 1015 |
+
('float32',),
|
| 1016 |
+
('float64',),
|
| 1017 |
+
('U1',), # 4-byte width string
|
| 1018 |
+
],
|
| 1019 |
+
)
|
| 1020 |
+
def test_dtype_endianness_repr(self, native):
|
| 1021 |
+
'''
|
| 1022 |
+
there was an issue where
|
| 1023 |
+
repr(array([0], dtype='<u2')) and repr(array([0], dtype='>u2'))
|
| 1024 |
+
both returned the same thing:
|
| 1025 |
+
array([0], dtype=uint16)
|
| 1026 |
+
even though their dtypes have different endianness.
|
| 1027 |
+
'''
|
| 1028 |
+
native_dtype = np.dtype(native)
|
| 1029 |
+
non_native_dtype = native_dtype.newbyteorder()
|
| 1030 |
+
non_native_repr = repr(np.array([1], non_native_dtype))
|
| 1031 |
+
native_repr = repr(np.array([1], native_dtype))
|
| 1032 |
+
# preserve the sensible default of only showing dtype if nonstandard
|
| 1033 |
+
assert ('dtype' in native_repr) ^ (native_dtype in _typelessdata),\
|
| 1034 |
+
("an array's repr should show dtype if and only if the type "
|
| 1035 |
+
'of the array is NOT one of the standard types '
|
| 1036 |
+
'(e.g., int32, bool, float64).')
|
| 1037 |
+
if non_native_dtype.itemsize > 1:
|
| 1038 |
+
# if the type is >1 byte, the non-native endian version
|
| 1039 |
+
# must show endianness.
|
| 1040 |
+
assert non_native_repr != native_repr
|
| 1041 |
+
assert f"dtype='{non_native_dtype.byteorder}" in non_native_repr
|
| 1042 |
+
|
| 1043 |
+
def test_linewidth_repr(self):
|
| 1044 |
+
a = np.full(7, fill_value=2)
|
| 1045 |
+
np.set_printoptions(linewidth=17)
|
| 1046 |
+
assert_equal(
|
| 1047 |
+
repr(a),
|
| 1048 |
+
textwrap.dedent("""\
|
| 1049 |
+
array([2, 2, 2,
|
| 1050 |
+
2, 2, 2,
|
| 1051 |
+
2])""")
|
| 1052 |
+
)
|
| 1053 |
+
np.set_printoptions(linewidth=17, legacy='1.13')
|
| 1054 |
+
assert_equal(
|
| 1055 |
+
repr(a),
|
| 1056 |
+
textwrap.dedent("""\
|
| 1057 |
+
array([2, 2, 2,
|
| 1058 |
+
2, 2, 2, 2])""")
|
| 1059 |
+
)
|
| 1060 |
+
|
| 1061 |
+
a = np.full(8, fill_value=2)
|
| 1062 |
+
|
| 1063 |
+
np.set_printoptions(linewidth=18, legacy=False)
|
| 1064 |
+
assert_equal(
|
| 1065 |
+
repr(a),
|
| 1066 |
+
textwrap.dedent("""\
|
| 1067 |
+
array([2, 2, 2,
|
| 1068 |
+
2, 2, 2,
|
| 1069 |
+
2, 2])""")
|
| 1070 |
+
)
|
| 1071 |
+
|
| 1072 |
+
np.set_printoptions(linewidth=18, legacy='1.13')
|
| 1073 |
+
assert_equal(
|
| 1074 |
+
repr(a),
|
| 1075 |
+
textwrap.dedent("""\
|
| 1076 |
+
array([2, 2, 2, 2,
|
| 1077 |
+
2, 2, 2, 2])""")
|
| 1078 |
+
)
|
| 1079 |
+
|
| 1080 |
+
def test_linewidth_str(self):
|
| 1081 |
+
a = np.full(18, fill_value=2)
|
| 1082 |
+
np.set_printoptions(linewidth=18)
|
| 1083 |
+
assert_equal(
|
| 1084 |
+
str(a),
|
| 1085 |
+
textwrap.dedent("""\
|
| 1086 |
+
[2 2 2 2 2 2 2 2
|
| 1087 |
+
2 2 2 2 2 2 2 2
|
| 1088 |
+
2 2]""")
|
| 1089 |
+
)
|
| 1090 |
+
np.set_printoptions(linewidth=18, legacy='1.13')
|
| 1091 |
+
assert_equal(
|
| 1092 |
+
str(a),
|
| 1093 |
+
textwrap.dedent("""\
|
| 1094 |
+
[2 2 2 2 2 2 2 2 2
|
| 1095 |
+
2 2 2 2 2 2 2 2 2]""")
|
| 1096 |
+
)
|
| 1097 |
+
|
| 1098 |
+
def test_edgeitems(self):
|
| 1099 |
+
np.set_printoptions(edgeitems=1, threshold=1)
|
| 1100 |
+
a = np.arange(27).reshape((3, 3, 3))
|
| 1101 |
+
assert_equal(
|
| 1102 |
+
repr(a),
|
| 1103 |
+
textwrap.dedent("""\
|
| 1104 |
+
array([[[ 0, ..., 2],
|
| 1105 |
+
...,
|
| 1106 |
+
[ 6, ..., 8]],
|
| 1107 |
+
|
| 1108 |
+
...,
|
| 1109 |
+
|
| 1110 |
+
[[18, ..., 20],
|
| 1111 |
+
...,
|
| 1112 |
+
[24, ..., 26]]], shape=(3, 3, 3))""")
|
| 1113 |
+
)
|
| 1114 |
+
|
| 1115 |
+
b = np.zeros((3, 3, 1, 1))
|
| 1116 |
+
assert_equal(
|
| 1117 |
+
repr(b),
|
| 1118 |
+
textwrap.dedent("""\
|
| 1119 |
+
array([[[[0.]],
|
| 1120 |
+
|
| 1121 |
+
...,
|
| 1122 |
+
|
| 1123 |
+
[[0.]]],
|
| 1124 |
+
|
| 1125 |
+
|
| 1126 |
+
...,
|
| 1127 |
+
|
| 1128 |
+
|
| 1129 |
+
[[[0.]],
|
| 1130 |
+
|
| 1131 |
+
...,
|
| 1132 |
+
|
| 1133 |
+
[[0.]]]], shape=(3, 3, 1, 1))""")
|
| 1134 |
+
)
|
| 1135 |
+
|
| 1136 |
+
# 1.13 had extra trailing spaces, and was missing newlines
|
| 1137 |
+
try:
|
| 1138 |
+
np.set_printoptions(legacy='1.13')
|
| 1139 |
+
assert_equal(repr(a), (
|
| 1140 |
+
"array([[[ 0, ..., 2],\n"
|
| 1141 |
+
" ..., \n"
|
| 1142 |
+
" [ 6, ..., 8]],\n"
|
| 1143 |
+
"\n"
|
| 1144 |
+
" ..., \n"
|
| 1145 |
+
" [[18, ..., 20],\n"
|
| 1146 |
+
" ..., \n"
|
| 1147 |
+
" [24, ..., 26]]])")
|
| 1148 |
+
)
|
| 1149 |
+
assert_equal(repr(b), (
|
| 1150 |
+
"array([[[[ 0.]],\n"
|
| 1151 |
+
"\n"
|
| 1152 |
+
" ..., \n"
|
| 1153 |
+
" [[ 0.]]],\n"
|
| 1154 |
+
"\n"
|
| 1155 |
+
"\n"
|
| 1156 |
+
" ..., \n"
|
| 1157 |
+
" [[[ 0.]],\n"
|
| 1158 |
+
"\n"
|
| 1159 |
+
" ..., \n"
|
| 1160 |
+
" [[ 0.]]]])")
|
| 1161 |
+
)
|
| 1162 |
+
finally:
|
| 1163 |
+
np.set_printoptions(legacy=False)
|
| 1164 |
+
|
| 1165 |
+
def test_edgeitems_structured(self):
|
| 1166 |
+
np.set_printoptions(edgeitems=1, threshold=1)
|
| 1167 |
+
A = np.arange(5 * 2 * 3, dtype="<i8").view([('i', "<i8", (5, 2, 3))])
|
| 1168 |
+
reprA = (
|
| 1169 |
+
"array([([[[ 0, ..., 2], [ 3, ..., 5]], ..., "
|
| 1170 |
+
"[[24, ..., 26], [27, ..., 29]]],)],\n"
|
| 1171 |
+
" dtype=[('i', '<i8', (5, 2, 3))])"
|
| 1172 |
+
)
|
| 1173 |
+
assert_equal(repr(A), reprA)
|
| 1174 |
+
|
| 1175 |
+
def test_bad_args(self):
|
| 1176 |
+
assert_raises(ValueError, np.set_printoptions, threshold=float('nan'))
|
| 1177 |
+
assert_raises(TypeError, np.set_printoptions, threshold='1')
|
| 1178 |
+
assert_raises(TypeError, np.set_printoptions, threshold=b'1')
|
| 1179 |
+
|
| 1180 |
+
assert_raises(TypeError, np.set_printoptions, precision='1')
|
| 1181 |
+
assert_raises(TypeError, np.set_printoptions, precision=1.5)
|
| 1182 |
+
|
| 1183 |
+
def test_unicode_object_array():
|
| 1184 |
+
expected = "array(['é'], dtype=object)"
|
| 1185 |
+
x = np.array(['\xe9'], dtype=object)
|
| 1186 |
+
assert_equal(repr(x), expected)
|
| 1187 |
+
|
| 1188 |
+
|
| 1189 |
+
class TestContextManager:
|
| 1190 |
+
def test_ctx_mgr(self):
|
| 1191 |
+
# test that context manager actually works
|
| 1192 |
+
with np.printoptions(precision=2):
|
| 1193 |
+
s = str(np.array([2.0]) / 3)
|
| 1194 |
+
assert_equal(s, '[0.67]')
|
| 1195 |
+
|
| 1196 |
+
def test_ctx_mgr_restores(self):
|
| 1197 |
+
# test that print options are actually restored
|
| 1198 |
+
opts = np.get_printoptions()
|
| 1199 |
+
with np.printoptions(precision=opts['precision'] - 1,
|
| 1200 |
+
linewidth=opts['linewidth'] - 4):
|
| 1201 |
+
pass
|
| 1202 |
+
assert_equal(np.get_printoptions(), opts)
|
| 1203 |
+
|
| 1204 |
+
def test_ctx_mgr_exceptions(self):
|
| 1205 |
+
# test that print options are restored even if an exception is raised
|
| 1206 |
+
opts = np.get_printoptions()
|
| 1207 |
+
try:
|
| 1208 |
+
with np.printoptions(precision=2, linewidth=11):
|
| 1209 |
+
raise ValueError
|
| 1210 |
+
except ValueError:
|
| 1211 |
+
pass
|
| 1212 |
+
assert_equal(np.get_printoptions(), opts)
|
| 1213 |
+
|
| 1214 |
+
def test_ctx_mgr_as_smth(self):
|
| 1215 |
+
opts = {"precision": 2}
|
| 1216 |
+
with np.printoptions(**opts) as ctx:
|
| 1217 |
+
saved_opts = ctx.copy()
|
| 1218 |
+
assert_equal({k: saved_opts[k] for k in opts}, opts)
|
| 1219 |
+
|
| 1220 |
+
|
| 1221 |
+
@pytest.mark.parametrize("dtype", "bhilqpBHILQPefdgFDG")
|
| 1222 |
+
@pytest.mark.parametrize("value", [0, 1])
|
| 1223 |
+
def test_scalar_repr_numbers(dtype, value):
|
| 1224 |
+
# Test NEP 51 scalar repr (and legacy option) for numeric types
|
| 1225 |
+
dtype = np.dtype(dtype)
|
| 1226 |
+
scalar = np.array(value, dtype=dtype)[()]
|
| 1227 |
+
assert isinstance(scalar, np.generic)
|
| 1228 |
+
|
| 1229 |
+
string = str(scalar)
|
| 1230 |
+
repr_string = string.strip("()") # complex may have extra brackets
|
| 1231 |
+
representation = repr(scalar)
|
| 1232 |
+
if dtype.char == "g":
|
| 1233 |
+
assert representation == f"np.longdouble('{repr_string}')"
|
| 1234 |
+
elif dtype.char == 'G':
|
| 1235 |
+
assert representation == f"np.clongdouble('{repr_string}')"
|
| 1236 |
+
else:
|
| 1237 |
+
normalized_name = np.dtype(f"{dtype.kind}{dtype.itemsize}").type.__name__
|
| 1238 |
+
assert representation == f"np.{normalized_name}({repr_string})"
|
| 1239 |
+
|
| 1240 |
+
with np.printoptions(legacy="1.25"):
|
| 1241 |
+
assert repr(scalar) == string
|
| 1242 |
+
|
| 1243 |
+
|
| 1244 |
+
@pytest.mark.parametrize("scalar, legacy_repr, representation", [
|
| 1245 |
+
(np.True_, "True", "np.True_"),
|
| 1246 |
+
(np.bytes_(b'a'), "b'a'", "np.bytes_(b'a')"),
|
| 1247 |
+
(np.str_('a'), "'a'", "np.str_('a')"),
|
| 1248 |
+
(np.datetime64("2012"),
|
| 1249 |
+
"numpy.datetime64('2012')", "np.datetime64('2012')"),
|
| 1250 |
+
(np.timedelta64(1, 's'), "numpy.timedelta64(1,'s')", "np.timedelta64(1,'s')"),
|
| 1251 |
+
(np.void((True, 2), dtype="?,<i8"),
|
| 1252 |
+
"(True, 2)",
|
| 1253 |
+
"np.void((True, 2), dtype=[('f0', '?'), ('f1', '<i8')])"),
|
| 1254 |
+
(np.void((1, 2), dtype="<f8,>f4"),
|
| 1255 |
+
"(1., 2.)",
|
| 1256 |
+
"np.void((1.0, 2.0), dtype=[('f0', '<f8'), ('f1', '>f4')])"),
|
| 1257 |
+
(np.void(b'a'), r"void(b'\x61')", r"np.void(b'\x61')"),
|
| 1258 |
+
])
|
| 1259 |
+
def test_scalar_repr_special(scalar, legacy_repr, representation):
|
| 1260 |
+
# Test NEP 51 scalar repr (and legacy option) for numeric types
|
| 1261 |
+
assert repr(scalar) == representation
|
| 1262 |
+
|
| 1263 |
+
with np.printoptions(legacy="1.25"):
|
| 1264 |
+
assert repr(scalar) == legacy_repr
|
| 1265 |
+
|
| 1266 |
+
def test_scalar_void_float_str():
|
| 1267 |
+
# Note that based on this currently we do not print the same as a tuple
|
| 1268 |
+
# would, since the tuple would include the repr() inside for floats, but
|
| 1269 |
+
# we do not do that.
|
| 1270 |
+
scalar = np.void((1.0, 2.0), dtype=[('f0', '<f8'), ('f1', '>f4')])
|
| 1271 |
+
assert str(scalar) == "(1.0, 2.0)"
|
| 1272 |
+
|
| 1273 |
+
@pytest.mark.skipif(IS_WASM, reason="wasm doesn't support asyncio")
|
| 1274 |
+
def test_printoptions_asyncio_safe():
|
| 1275 |
+
asyncio = pytest.importorskip("asyncio")
|
| 1276 |
+
|
| 1277 |
+
b = asyncio.Barrier(2)
|
| 1278 |
+
|
| 1279 |
+
async def legacy_113():
|
| 1280 |
+
np.set_printoptions(legacy='1.13', precision=12)
|
| 1281 |
+
await b.wait()
|
| 1282 |
+
po = np.get_printoptions()
|
| 1283 |
+
assert po['legacy'] == '1.13'
|
| 1284 |
+
assert po['precision'] == 12
|
| 1285 |
+
orig_linewidth = po['linewidth']
|
| 1286 |
+
with np.printoptions(linewidth=34, legacy='1.21'):
|
| 1287 |
+
po = np.get_printoptions()
|
| 1288 |
+
assert po['legacy'] == '1.21'
|
| 1289 |
+
assert po['precision'] == 12
|
| 1290 |
+
assert po['linewidth'] == 34
|
| 1291 |
+
po = np.get_printoptions()
|
| 1292 |
+
assert po['linewidth'] == orig_linewidth
|
| 1293 |
+
assert po['legacy'] == '1.13'
|
| 1294 |
+
assert po['precision'] == 12
|
| 1295 |
+
|
| 1296 |
+
async def legacy_125():
|
| 1297 |
+
np.set_printoptions(legacy='1.25', precision=7)
|
| 1298 |
+
await b.wait()
|
| 1299 |
+
po = np.get_printoptions()
|
| 1300 |
+
assert po['legacy'] == '1.25'
|
| 1301 |
+
assert po['precision'] == 7
|
| 1302 |
+
orig_linewidth = po['linewidth']
|
| 1303 |
+
with np.printoptions(linewidth=6, legacy='1.13'):
|
| 1304 |
+
po = np.get_printoptions()
|
| 1305 |
+
assert po['legacy'] == '1.13'
|
| 1306 |
+
assert po['precision'] == 7
|
| 1307 |
+
assert po['linewidth'] == 6
|
| 1308 |
+
po = np.get_printoptions()
|
| 1309 |
+
assert po['linewidth'] == orig_linewidth
|
| 1310 |
+
assert po['legacy'] == '1.25'
|
| 1311 |
+
assert po['precision'] == 7
|
| 1312 |
+
|
| 1313 |
+
async def main():
|
| 1314 |
+
await asyncio.gather(legacy_125(), legacy_125())
|
| 1315 |
+
|
| 1316 |
+
loop = asyncio.new_event_loop()
|
| 1317 |
+
asyncio.run(main())
|
| 1318 |
+
loop.close()
|
| 1319 |
+
|
| 1320 |
+
@pytest.mark.skipif(IS_WASM, reason="wasm doesn't support threads")
|
| 1321 |
+
@pytest.mark.thread_unsafe(reason="test is already explicitly multi-threaded")
|
| 1322 |
+
def test_multithreaded_array_printing():
|
| 1323 |
+
# the dragon4 implementation uses a static scratch space for performance
|
| 1324 |
+
# reasons this test makes sure it is set up in a thread-safe manner
|
| 1325 |
+
|
| 1326 |
+
run_threaded(TestPrintOptions().test_floatmode, 500)
|
| 1327 |
+
|
| 1328 |
+
|
| 1329 |
+
def test_user_defined_floating_dtype_printing_does_not_corrupt_precision():
|
| 1330 |
+
"""
|
| 1331 |
+
Ensure that array printing does not use NumPy Dragon4 formatting
|
| 1332 |
+
for user-defined floating dtypes, which would silently truncate
|
| 1333 |
+
precision to float64.
|
| 1334 |
+
"""
|
| 1335 |
+
# Quaddtype (<=1.0.0) may have a bug that leads to test failures elsewhere
|
| 1336 |
+
# (this may also be an interplay of numpy/quaddtype but let's hope new
|
| 1337 |
+
# quaddtype versions will fix it.)
|
| 1338 |
+
from importlib.metadata import version
|
| 1339 |
+
|
| 1340 |
+
try:
|
| 1341 |
+
quaddtype_version = version("numpy_quaddtype")
|
| 1342 |
+
except Exception:
|
| 1343 |
+
pytest.skip("numpy_quaddtype not installed")
|
| 1344 |
+
else:
|
| 1345 |
+
if _pep440.Version(quaddtype_version) <= _pep440.Version("1.0.0"):
|
| 1346 |
+
pytest.skip("critical bug in quaddtype during import")
|
| 1347 |
+
|
| 1348 |
+
numpy_quaddtype = pytest.importorskip("numpy_quaddtype")
|
| 1349 |
+
|
| 1350 |
+
pi_str = "3.14159265358979323846264338327950288"
|
| 1351 |
+
arr = np.array([pi_str], dtype=QuadPrecDType())
|
| 1352 |
+
res = np.array(str(arr).strip("[] "), dtype=QuadPrecDType())
|
| 1353 |
+
# Check that the string representation round-trips correctly.
|
| 1354 |
+
assert_array_equal(res, arr)
|
| 1355 |
+
|
| 1356 |
+
|
| 1357 |
+
@pytest.mark.parametrize("sctype", [np.int8, np.float32, rational, rational2])
|
| 1358 |
+
def test_array_dtype_short_repr(sctype):
|
| 1359 |
+
# Mainly test that rational/rational2 (both legacy dtypes) use short repr
|
| 1360 |
+
# which in the end should just be the name for these (not default dtypes).
|
| 1361 |
+
arr = np.zeros(1, dtype=sctype)
|
| 1362 |
+
res = repr(arr)
|
| 1363 |
+
assert f"dtype={sctype.__name__}" in res
|
v12x/pylib/numpy/_core/tests/test_casting_floatingpoint_errors.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
from pytest import param
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
from numpy.testing import IS_WASM
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def values_and_dtypes():
|
| 9 |
+
"""
|
| 10 |
+
Generate value+dtype pairs that generate floating point errors during
|
| 11 |
+
casts. The invalid casts to integers will generate "invalid" value
|
| 12 |
+
warnings, the float casts all generate "overflow".
|
| 13 |
+
|
| 14 |
+
(The Python int/float paths don't need to get tested in all the same
|
| 15 |
+
situations, but it does not hurt.)
|
| 16 |
+
"""
|
| 17 |
+
# Casting to float16:
|
| 18 |
+
yield param(70000, "float16", id="int-to-f2")
|
| 19 |
+
yield param("70000", "float16", id="str-to-f2")
|
| 20 |
+
yield param(70000.0, "float16", id="float-to-f2")
|
| 21 |
+
yield param(np.longdouble(70000.), "float16", id="longdouble-to-f2")
|
| 22 |
+
yield param(np.float64(70000.), "float16", id="double-to-f2")
|
| 23 |
+
yield param(np.float32(70000.), "float16", id="float-to-f2")
|
| 24 |
+
# Casting to float32:
|
| 25 |
+
yield param(10**100, "float32", id="int-to-f4")
|
| 26 |
+
yield param(1e100, "float32", id="float-to-f2")
|
| 27 |
+
yield param(np.longdouble(1e300), "float32", id="longdouble-to-f2")
|
| 28 |
+
yield param(np.float64(1e300), "float32", id="double-to-f2")
|
| 29 |
+
# Casting to float64:
|
| 30 |
+
# If longdouble is double-double, its max can be rounded down to the double
|
| 31 |
+
# max. So we correct the double spacing (a bit weird, admittedly):
|
| 32 |
+
max_ld = np.finfo(np.longdouble).max
|
| 33 |
+
spacing = np.spacing(np.nextafter(np.finfo("f8").max, 0))
|
| 34 |
+
if max_ld - spacing > np.finfo("f8").max:
|
| 35 |
+
yield param(np.finfo(np.longdouble).max, "float64",
|
| 36 |
+
id="longdouble-to-f8")
|
| 37 |
+
|
| 38 |
+
# Cast to complex32:
|
| 39 |
+
yield param(2e300, "complex64", id="float-to-c8")
|
| 40 |
+
yield param(2e300 + 0j, "complex64", id="complex-to-c8")
|
| 41 |
+
yield param(2e300j, "complex64", id="complex-to-c8")
|
| 42 |
+
yield param(np.longdouble(2e300), "complex64", id="longdouble-to-c8")
|
| 43 |
+
|
| 44 |
+
# Invalid float to integer casts:
|
| 45 |
+
with np.errstate(over="ignore"):
|
| 46 |
+
for to_dt in np.typecodes["AllInteger"]:
|
| 47 |
+
for value in [np.inf, np.nan]:
|
| 48 |
+
for from_dt in np.typecodes["AllFloat"]:
|
| 49 |
+
from_dt = np.dtype(from_dt)
|
| 50 |
+
from_val = from_dt.type(value)
|
| 51 |
+
|
| 52 |
+
yield param(from_val, to_dt, id=f"{from_val}-to-{to_dt}")
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def check_operations(dtype, value):
|
| 56 |
+
"""
|
| 57 |
+
There are many dedicated paths in NumPy which cast and should check for
|
| 58 |
+
floating point errors which occurred during those casts.
|
| 59 |
+
"""
|
| 60 |
+
if dtype.kind != 'i':
|
| 61 |
+
# These assignments use the stricter setitem logic:
|
| 62 |
+
def assignment():
|
| 63 |
+
arr = np.empty(3, dtype=dtype)
|
| 64 |
+
arr[0] = value
|
| 65 |
+
|
| 66 |
+
yield assignment
|
| 67 |
+
|
| 68 |
+
def fill():
|
| 69 |
+
arr = np.empty(3, dtype=dtype)
|
| 70 |
+
arr.fill(value)
|
| 71 |
+
|
| 72 |
+
yield fill
|
| 73 |
+
|
| 74 |
+
def copyto_scalar():
|
| 75 |
+
arr = np.empty(3, dtype=dtype)
|
| 76 |
+
np.copyto(arr, value, casting="unsafe")
|
| 77 |
+
|
| 78 |
+
yield copyto_scalar
|
| 79 |
+
|
| 80 |
+
def copyto():
|
| 81 |
+
arr = np.empty(3, dtype=dtype)
|
| 82 |
+
np.copyto(arr, np.array([value, value, value]), casting="unsafe")
|
| 83 |
+
|
| 84 |
+
yield copyto
|
| 85 |
+
|
| 86 |
+
def copyto_scalar_masked():
|
| 87 |
+
arr = np.empty(3, dtype=dtype)
|
| 88 |
+
np.copyto(arr, value, casting="unsafe",
|
| 89 |
+
where=[True, False, True])
|
| 90 |
+
|
| 91 |
+
yield copyto_scalar_masked
|
| 92 |
+
|
| 93 |
+
def copyto_masked():
|
| 94 |
+
arr = np.empty(3, dtype=dtype)
|
| 95 |
+
np.copyto(arr, np.array([value, value, value]), casting="unsafe",
|
| 96 |
+
where=[True, False, True])
|
| 97 |
+
|
| 98 |
+
yield copyto_masked
|
| 99 |
+
|
| 100 |
+
def direct_cast():
|
| 101 |
+
np.array([value, value, value]).astype(dtype)
|
| 102 |
+
|
| 103 |
+
yield direct_cast
|
| 104 |
+
|
| 105 |
+
def direct_cast_nd_strided():
|
| 106 |
+
arr = np.full((5, 5, 5), fill_value=value)[:, ::2, :]
|
| 107 |
+
arr.astype(dtype)
|
| 108 |
+
|
| 109 |
+
yield direct_cast_nd_strided
|
| 110 |
+
|
| 111 |
+
def boolean_array_assignment():
|
| 112 |
+
arr = np.empty(3, dtype=dtype)
|
| 113 |
+
arr[[True, False, True]] = np.array([value, value])
|
| 114 |
+
|
| 115 |
+
yield boolean_array_assignment
|
| 116 |
+
|
| 117 |
+
def integer_array_assignment():
|
| 118 |
+
arr = np.empty(3, dtype=dtype)
|
| 119 |
+
values = np.array([value, value])
|
| 120 |
+
|
| 121 |
+
arr[[0, 1]] = values
|
| 122 |
+
|
| 123 |
+
yield integer_array_assignment
|
| 124 |
+
|
| 125 |
+
def integer_array_assignment_with_subspace():
|
| 126 |
+
arr = np.empty((5, 3), dtype=dtype)
|
| 127 |
+
values = np.array([value, value, value])
|
| 128 |
+
|
| 129 |
+
arr[[0, 2]] = values
|
| 130 |
+
|
| 131 |
+
yield integer_array_assignment_with_subspace
|
| 132 |
+
|
| 133 |
+
def flat_assignment():
|
| 134 |
+
arr = np.empty((3,), dtype=dtype)
|
| 135 |
+
values = np.array([value, value, value])
|
| 136 |
+
arr.flat[:] = values
|
| 137 |
+
|
| 138 |
+
yield flat_assignment
|
| 139 |
+
|
| 140 |
+
@pytest.mark.skipif(IS_WASM, reason="no wasm fp exception support")
|
| 141 |
+
@pytest.mark.parametrize(["value", "dtype"], list(values_and_dtypes()))
|
| 142 |
+
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
|
| 143 |
+
def test_floatingpoint_errors_casting(dtype, value):
|
| 144 |
+
dtype = np.dtype(dtype)
|
| 145 |
+
for operation in check_operations(dtype, value):
|
| 146 |
+
dtype = np.dtype(dtype)
|
| 147 |
+
|
| 148 |
+
match = "invalid" if dtype.kind in 'iu' else "overflow"
|
| 149 |
+
with pytest.warns(RuntimeWarning, match=match):
|
| 150 |
+
operation()
|
| 151 |
+
|
| 152 |
+
with np.errstate(all="raise"):
|
| 153 |
+
with pytest.raises(FloatingPointError, match=match):
|
| 154 |
+
operation()
|
v12x/pylib/numpy/_core/tests/test_casting_unittests.py
ADDED
|
@@ -0,0 +1,970 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
The tests exercise the casting machinery in a more low-level manner.
|
| 3 |
+
The reason is mostly to test a new implementation of the casting machinery.
|
| 4 |
+
|
| 5 |
+
Unlike most tests in NumPy, these are closer to unit-tests rather
|
| 6 |
+
than integration tests.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import ctypes
|
| 10 |
+
import enum
|
| 11 |
+
import random
|
| 12 |
+
import textwrap
|
| 13 |
+
import warnings
|
| 14 |
+
|
| 15 |
+
import pytest
|
| 16 |
+
|
| 17 |
+
import numpy as np
|
| 18 |
+
from numpy._core._multiarray_umath import _get_castingimpl as get_castingimpl
|
| 19 |
+
from numpy.lib.stride_tricks import as_strided
|
| 20 |
+
from numpy.testing import assert_array_equal, assert_equal
|
| 21 |
+
|
| 22 |
+
# Simple skips object, parametric and long double (unsupported by struct)
|
| 23 |
+
simple_dtypes = "?bhilqBHILQefdFD"
|
| 24 |
+
if np.dtype("l").itemsize != np.dtype("q").itemsize:
|
| 25 |
+
# Remove l and L, the table was generated with 64bit linux in mind.
|
| 26 |
+
simple_dtypes = simple_dtypes.replace("l", "").replace("L", "")
|
| 27 |
+
simple_dtypes = [type(np.dtype(c)) for c in simple_dtypes]
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def simple_dtype_instances():
|
| 31 |
+
params = []
|
| 32 |
+
for dtype_class in simple_dtypes:
|
| 33 |
+
dt = dtype_class()
|
| 34 |
+
params.append(pytest.param(dt, id=str(dt)))
|
| 35 |
+
if dt.byteorder != "|":
|
| 36 |
+
dt = dt.newbyteorder()
|
| 37 |
+
params.append(pytest.param(dt, id=str(dt)))
|
| 38 |
+
return params
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def get_expected_stringlength(dtype):
|
| 42 |
+
"""Returns the string length when casting the basic dtypes to strings.
|
| 43 |
+
"""
|
| 44 |
+
if dtype == np.bool:
|
| 45 |
+
return 5
|
| 46 |
+
if dtype.kind in "iu":
|
| 47 |
+
if dtype.itemsize == 1:
|
| 48 |
+
length = 3
|
| 49 |
+
elif dtype.itemsize == 2:
|
| 50 |
+
length = 5
|
| 51 |
+
elif dtype.itemsize == 4:
|
| 52 |
+
length = 10
|
| 53 |
+
elif dtype.itemsize == 8:
|
| 54 |
+
length = 20
|
| 55 |
+
else:
|
| 56 |
+
raise AssertionError(f"did not find expected length for {dtype}")
|
| 57 |
+
|
| 58 |
+
if dtype.kind == "i":
|
| 59 |
+
length += 1 # adds one character for the sign
|
| 60 |
+
|
| 61 |
+
return length
|
| 62 |
+
|
| 63 |
+
# Note: Can't do dtype comparison for longdouble on windows
|
| 64 |
+
if dtype.char == "g":
|
| 65 |
+
return 48
|
| 66 |
+
elif dtype.char == "G":
|
| 67 |
+
return 48 * 2
|
| 68 |
+
elif dtype.kind == "f":
|
| 69 |
+
return 32 # also for half apparently.
|
| 70 |
+
elif dtype.kind == "c":
|
| 71 |
+
return 32 * 2
|
| 72 |
+
|
| 73 |
+
raise AssertionError(f"did not find expected length for {dtype}")
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
class Casting(enum.IntEnum):
|
| 77 |
+
no = 0
|
| 78 |
+
equiv = 1
|
| 79 |
+
safe = 2
|
| 80 |
+
same_kind = 3
|
| 81 |
+
unsafe = 4
|
| 82 |
+
same_value = 64
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
same_value_dtypes = tuple(type(np.dtype(c)) for c in "?bhilqBHILQefdgFDG")
|
| 86 |
+
|
| 87 |
+
def _get_cancast_table():
|
| 88 |
+
table = textwrap.dedent("""
|
| 89 |
+
X ? b h i l q B H I L Q e f d g F D G S U V O M m
|
| 90 |
+
? # = = = = = = = = = = = = = = = = = = = = = . =
|
| 91 |
+
b . # = = = = . . . . . = = = = = = = = = = = . =
|
| 92 |
+
h . ~ # = = = . . . . . ~ = = = = = = = = = = . =
|
| 93 |
+
i . ~ ~ # = = . . . . . ~ ~ = = ~ = = = = = = . =
|
| 94 |
+
l . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
|
| 95 |
+
q . ~ ~ ~ # # . . . . . ~ ~ = = ~ = = = = = = . =
|
| 96 |
+
B . ~ = = = = # = = = = = = = = = = = = = = = . =
|
| 97 |
+
H . ~ ~ = = = ~ # = = = ~ = = = = = = = = = = . =
|
| 98 |
+
I . ~ ~ ~ = = ~ ~ # = = ~ ~ = = ~ = = = = = = . =
|
| 99 |
+
L . ~ ~ ~ ~ ~ ~ ~ ~ # # ~ ~ = = ~ = = = = = = . ~
|
| 100 |
+
Q . ~ ~ ~ ~ ~ ~ ~ ~ # # ~ ~ = = ~ = = = = = = . ~
|
| 101 |
+
e . . . . . . . . . . . # = = = = = = = = = = . .
|
| 102 |
+
f . . . . . . . . . . . ~ # = = = = = = = = = . .
|
| 103 |
+
d . . . . . . . . . . . ~ ~ # = ~ = = = = = = . .
|
| 104 |
+
g . . . . . . . . . . . ~ ~ ~ # ~ ~ = = = = = . .
|
| 105 |
+
F . . . . . . . . . . . . . . . # = = = = = = . .
|
| 106 |
+
D . . . . . . . . . . . . . . . ~ # = = = = = . .
|
| 107 |
+
G . . . . . . . . . . . . . . . ~ ~ # = = = = . .
|
| 108 |
+
S . . . . . . . . . . . . . . . . . . # = = = . .
|
| 109 |
+
U . . . . . . . . . . . . . . . . . . . # = = . .
|
| 110 |
+
V . . . . . . . . . . . . . . . . . . . . # = . .
|
| 111 |
+
O . . . . . . . . . . . . . . . . . . . . = # . .
|
| 112 |
+
M . . . . . . . . . . . . . . . . . . . . = = # .
|
| 113 |
+
m . . . . . . . . . . . . . . . . . . . . = = . #
|
| 114 |
+
""").strip().split("\n")
|
| 115 |
+
dtypes = [type(np.dtype(c)) for c in table[0][2::2]]
|
| 116 |
+
|
| 117 |
+
convert_cast = {".": Casting.unsafe, "~": Casting.same_kind,
|
| 118 |
+
"=": Casting.safe, "#": Casting.equiv,
|
| 119 |
+
" ": -1}
|
| 120 |
+
|
| 121 |
+
cancast = {}
|
| 122 |
+
for from_dt, row in zip(dtypes, table[1:]):
|
| 123 |
+
cancast[from_dt] = {}
|
| 124 |
+
for to_dt, c in zip(dtypes, row[2::2]):
|
| 125 |
+
cancast[from_dt][to_dt] = convert_cast[c]
|
| 126 |
+
# Of the types checked, numeric cast support same-value
|
| 127 |
+
if from_dt in same_value_dtypes and to_dt in same_value_dtypes:
|
| 128 |
+
cancast[from_dt][to_dt] |= Casting.same_value
|
| 129 |
+
|
| 130 |
+
return cancast
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
CAST_TABLE = _get_cancast_table()
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
class TestChanges:
|
| 137 |
+
"""
|
| 138 |
+
These test cases exercise some behaviour changes
|
| 139 |
+
"""
|
| 140 |
+
@pytest.mark.parametrize("string", ["S", "U"])
|
| 141 |
+
@pytest.mark.parametrize("floating", ["e", "f", "d", "g"])
|
| 142 |
+
def test_float_to_string(self, floating, string):
|
| 143 |
+
assert np.can_cast(floating, string)
|
| 144 |
+
# 100 is long enough to hold any formatted floating
|
| 145 |
+
assert np.can_cast(floating, f"{string}100")
|
| 146 |
+
|
| 147 |
+
def test_to_void(self):
|
| 148 |
+
# But in general, we do consider these safe:
|
| 149 |
+
assert np.can_cast("d", "V")
|
| 150 |
+
assert np.can_cast("S20", "V")
|
| 151 |
+
|
| 152 |
+
# Do not consider it a safe cast if the void is too smaller:
|
| 153 |
+
assert not np.can_cast("d", "V1")
|
| 154 |
+
assert not np.can_cast("S20", "V1")
|
| 155 |
+
assert not np.can_cast("U1", "V1")
|
| 156 |
+
# Structured to unstructured is just like any other:
|
| 157 |
+
assert np.can_cast("d,i", "V", casting="same_kind")
|
| 158 |
+
# Unstructured void to unstructured is actually no cast at all:
|
| 159 |
+
assert np.can_cast("V3", "V", casting="no")
|
| 160 |
+
assert np.can_cast("V0", "V", casting="no")
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
class TestCasting:
|
| 164 |
+
size = 1500 # Best larger than NPY_LOWLEVEL_BUFFER_BLOCKSIZE * itemsize
|
| 165 |
+
|
| 166 |
+
def get_data(self, dtype1, dtype2):
|
| 167 |
+
if dtype2 is None or dtype1.itemsize >= dtype2.itemsize:
|
| 168 |
+
length = self.size // dtype1.itemsize
|
| 169 |
+
else:
|
| 170 |
+
length = self.size // dtype2.itemsize
|
| 171 |
+
|
| 172 |
+
# Assume that the base array is well enough aligned for all inputs.
|
| 173 |
+
arr1 = np.empty(length, dtype=dtype1)
|
| 174 |
+
assert arr1.flags.c_contiguous
|
| 175 |
+
assert arr1.flags.aligned
|
| 176 |
+
|
| 177 |
+
values = [random.randrange(-128, 128) for _ in range(length)]
|
| 178 |
+
|
| 179 |
+
for i, value in enumerate(values):
|
| 180 |
+
# Use item assignment to ensure this is not using casting:
|
| 181 |
+
if value < 0 and dtype1.kind == "u":
|
| 182 |
+
# Manually rollover unsigned integers (-1 -> int.max)
|
| 183 |
+
value = value + np.iinfo(dtype1).max + 1
|
| 184 |
+
arr1[i] = value
|
| 185 |
+
|
| 186 |
+
if dtype2 is None:
|
| 187 |
+
if dtype1.char == "?":
|
| 188 |
+
values = [bool(v) for v in values]
|
| 189 |
+
return arr1, values
|
| 190 |
+
|
| 191 |
+
if dtype2.char == "?":
|
| 192 |
+
values = [bool(v) for v in values]
|
| 193 |
+
|
| 194 |
+
arr2 = np.empty(length, dtype=dtype2)
|
| 195 |
+
assert arr2.flags.c_contiguous
|
| 196 |
+
assert arr2.flags.aligned
|
| 197 |
+
|
| 198 |
+
for i, value in enumerate(values):
|
| 199 |
+
# Use item assignment to ensure this is not using casting:
|
| 200 |
+
if value < 0 and dtype2.kind == "u":
|
| 201 |
+
# Manually rollover unsigned integers (-1 -> int.max)
|
| 202 |
+
value = value + np.iinfo(dtype2).max + 1
|
| 203 |
+
arr2[i] = value
|
| 204 |
+
|
| 205 |
+
return arr1, arr2, values
|
| 206 |
+
|
| 207 |
+
def get_data_variation(self, arr1, arr2, aligned=True, contig=True):
|
| 208 |
+
"""
|
| 209 |
+
Returns a copy of arr1 that may be non-contiguous or unaligned, and a
|
| 210 |
+
matching array for arr2 (although not a copy).
|
| 211 |
+
"""
|
| 212 |
+
if contig:
|
| 213 |
+
stride1 = arr1.dtype.itemsize
|
| 214 |
+
stride2 = arr2.dtype.itemsize
|
| 215 |
+
elif aligned:
|
| 216 |
+
stride1 = 2 * arr1.dtype.itemsize
|
| 217 |
+
stride2 = 2 * arr2.dtype.itemsize
|
| 218 |
+
else:
|
| 219 |
+
stride1 = arr1.dtype.itemsize + 1
|
| 220 |
+
stride2 = arr2.dtype.itemsize + 1
|
| 221 |
+
|
| 222 |
+
max_size1 = len(arr1) * 3 * arr1.dtype.itemsize + 1
|
| 223 |
+
max_size2 = len(arr2) * 3 * arr2.dtype.itemsize + 1
|
| 224 |
+
from_bytes = np.zeros(max_size1, dtype=np.uint8)
|
| 225 |
+
to_bytes = np.zeros(max_size2, dtype=np.uint8)
|
| 226 |
+
|
| 227 |
+
# Sanity check that the above is large enough:
|
| 228 |
+
assert stride1 * len(arr1) <= from_bytes.nbytes
|
| 229 |
+
assert stride2 * len(arr2) <= to_bytes.nbytes
|
| 230 |
+
|
| 231 |
+
if aligned:
|
| 232 |
+
new1 = as_strided(from_bytes[:-1].view(arr1.dtype),
|
| 233 |
+
arr1.shape, (stride1,))
|
| 234 |
+
new2 = as_strided(to_bytes[:-1].view(arr2.dtype),
|
| 235 |
+
arr2.shape, (stride2,))
|
| 236 |
+
else:
|
| 237 |
+
new1 = as_strided(from_bytes[1:].view(arr1.dtype),
|
| 238 |
+
arr1.shape, (stride1,))
|
| 239 |
+
new2 = as_strided(to_bytes[1:].view(arr2.dtype),
|
| 240 |
+
arr2.shape, (stride2,))
|
| 241 |
+
|
| 242 |
+
new1[...] = arr1
|
| 243 |
+
|
| 244 |
+
if not contig:
|
| 245 |
+
# Ensure we did not overwrite bytes that should not be written:
|
| 246 |
+
offset = arr1.dtype.itemsize if aligned else 0
|
| 247 |
+
buf = from_bytes[offset::stride1].tobytes()
|
| 248 |
+
assert buf.count(b"\0") == len(buf)
|
| 249 |
+
|
| 250 |
+
if contig:
|
| 251 |
+
assert new1.flags.c_contiguous
|
| 252 |
+
assert new2.flags.c_contiguous
|
| 253 |
+
else:
|
| 254 |
+
assert not new1.flags.c_contiguous
|
| 255 |
+
assert not new2.flags.c_contiguous
|
| 256 |
+
|
| 257 |
+
if aligned:
|
| 258 |
+
assert new1.flags.aligned
|
| 259 |
+
assert new2.flags.aligned
|
| 260 |
+
else:
|
| 261 |
+
assert not new1.flags.aligned or new1.dtype.alignment == 1
|
| 262 |
+
assert not new2.flags.aligned or new2.dtype.alignment == 1
|
| 263 |
+
|
| 264 |
+
return new1, new2
|
| 265 |
+
|
| 266 |
+
@pytest.mark.parametrize("from_Dt", simple_dtypes)
|
| 267 |
+
def test_simple_cancast(self, from_Dt):
|
| 268 |
+
for to_Dt in simple_dtypes:
|
| 269 |
+
cast = get_castingimpl(from_Dt, to_Dt)
|
| 270 |
+
|
| 271 |
+
for from_dt in [from_Dt(), from_Dt().newbyteorder()]:
|
| 272 |
+
default = cast._resolve_descriptors((from_dt, None))[1][1]
|
| 273 |
+
assert default == to_Dt()
|
| 274 |
+
del default
|
| 275 |
+
|
| 276 |
+
for to_dt in [to_Dt(), to_Dt().newbyteorder()]:
|
| 277 |
+
casting, (from_res, to_res), view_off = (
|
| 278 |
+
cast._resolve_descriptors((from_dt, to_dt)))
|
| 279 |
+
assert type(from_res) is from_Dt
|
| 280 |
+
assert type(to_res) is to_Dt
|
| 281 |
+
if view_off is not None:
|
| 282 |
+
# If a view is acceptable, this is "no" casting
|
| 283 |
+
# and byte order must be matching.
|
| 284 |
+
assert casting == Casting.no | Casting.same_value
|
| 285 |
+
# The above table lists this as "equivalent", perhaps
|
| 286 |
+
# with "same_value"
|
| 287 |
+
v = CAST_TABLE[from_Dt][to_Dt] & ~Casting.same_value
|
| 288 |
+
assert Casting.equiv == v
|
| 289 |
+
# Note that to_res may not be the same as from_dt
|
| 290 |
+
assert from_res.isnative == to_res.isnative
|
| 291 |
+
else:
|
| 292 |
+
if from_Dt == to_Dt:
|
| 293 |
+
# Note that to_res may not be the same as from_dt
|
| 294 |
+
assert from_res.isnative != to_res.isnative
|
| 295 |
+
assert casting == CAST_TABLE[from_Dt][to_Dt]
|
| 296 |
+
|
| 297 |
+
if from_Dt is to_Dt:
|
| 298 |
+
assert from_dt is from_res
|
| 299 |
+
assert to_dt is to_res
|
| 300 |
+
|
| 301 |
+
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
|
| 302 |
+
@pytest.mark.parametrize("from_dt", simple_dtype_instances())
|
| 303 |
+
def test_simple_direct_casts(self, from_dt):
|
| 304 |
+
"""
|
| 305 |
+
This test checks numeric direct casts for dtypes supported also by the
|
| 306 |
+
struct module (plus complex). It tries to be test a wide range of
|
| 307 |
+
inputs, but skips over possibly undefined behaviour (e.g. int rollover).
|
| 308 |
+
Longdouble and CLongdouble are tested, but only using double precision.
|
| 309 |
+
|
| 310 |
+
If this test creates issues, it should possibly just be simplified
|
| 311 |
+
or even removed (checking whether unaligned/non-contiguous casts give
|
| 312 |
+
the same results is useful, though).
|
| 313 |
+
"""
|
| 314 |
+
for to_dt in simple_dtype_instances():
|
| 315 |
+
to_dt = to_dt.values[0]
|
| 316 |
+
cast = get_castingimpl(type(from_dt), type(to_dt))
|
| 317 |
+
|
| 318 |
+
# print("from_dt", from_dt, "to_dt", to_dt)
|
| 319 |
+
casting, (from_res, to_res), view_off = cast._resolve_descriptors(
|
| 320 |
+
(from_dt, to_dt))
|
| 321 |
+
|
| 322 |
+
if from_res is not from_dt or to_res is not to_dt:
|
| 323 |
+
# Do not test this case, it is handled in multiple steps,
|
| 324 |
+
# each of which should is tested individually.
|
| 325 |
+
return
|
| 326 |
+
|
| 327 |
+
safe = casting <= Casting.safe
|
| 328 |
+
del from_res, to_res, casting
|
| 329 |
+
|
| 330 |
+
arr1, arr2, values = self.get_data(from_dt, to_dt)
|
| 331 |
+
|
| 332 |
+
# print("2", arr1, arr2, cast)
|
| 333 |
+
cast._simple_strided_call((arr1, arr2))
|
| 334 |
+
# print("3")
|
| 335 |
+
|
| 336 |
+
# Check via python list
|
| 337 |
+
assert arr2.tolist() == values
|
| 338 |
+
|
| 339 |
+
# Check that the same results are achieved for strided loops
|
| 340 |
+
arr1_o, arr2_o = self.get_data_variation(arr1, arr2, True, False)
|
| 341 |
+
cast._simple_strided_call((arr1_o, arr2_o))
|
| 342 |
+
|
| 343 |
+
assert_array_equal(arr2_o, arr2)
|
| 344 |
+
assert arr2_o.tobytes() == arr2.tobytes()
|
| 345 |
+
|
| 346 |
+
# Check if alignment makes a difference, but only if supported
|
| 347 |
+
# and only if the alignment can be wrong
|
| 348 |
+
if ((from_dt.alignment == 1 and to_dt.alignment == 1) or
|
| 349 |
+
not cast._supports_unaligned):
|
| 350 |
+
return
|
| 351 |
+
|
| 352 |
+
arr1_o, arr2_o = self.get_data_variation(arr1, arr2, False, True)
|
| 353 |
+
cast._simple_strided_call((arr1_o, arr2_o))
|
| 354 |
+
|
| 355 |
+
assert_array_equal(arr2_o, arr2)
|
| 356 |
+
assert arr2_o.tobytes() == arr2.tobytes()
|
| 357 |
+
|
| 358 |
+
arr1_o, arr2_o = self.get_data_variation(arr1, arr2, False, False)
|
| 359 |
+
cast._simple_strided_call((arr1_o, arr2_o))
|
| 360 |
+
|
| 361 |
+
assert_array_equal(arr2_o, arr2)
|
| 362 |
+
assert arr2_o.tobytes() == arr2.tobytes()
|
| 363 |
+
|
| 364 |
+
del arr1_o, arr2_o, cast
|
| 365 |
+
|
| 366 |
+
@pytest.mark.parametrize("from_Dt", simple_dtypes)
|
| 367 |
+
def test_numeric_to_times(self, from_Dt):
|
| 368 |
+
# We currently only implement contiguous loops, so only need to
|
| 369 |
+
# test those.
|
| 370 |
+
from_dt = from_Dt()
|
| 371 |
+
|
| 372 |
+
time_dtypes = [np.dtype("M8"), np.dtype("M8[ms]"), np.dtype("M8[4D]"),
|
| 373 |
+
np.dtype("m8"), np.dtype("m8[ms]"), np.dtype("m8[4D]")]
|
| 374 |
+
for time_dt in time_dtypes:
|
| 375 |
+
cast = get_castingimpl(type(from_dt), type(time_dt))
|
| 376 |
+
|
| 377 |
+
casting, (from_res, to_res), view_off = cast._resolve_descriptors(
|
| 378 |
+
(from_dt, time_dt))
|
| 379 |
+
|
| 380 |
+
assert from_res is from_dt
|
| 381 |
+
assert to_res is time_dt
|
| 382 |
+
del from_res, to_res
|
| 383 |
+
|
| 384 |
+
assert casting & CAST_TABLE[from_Dt][type(time_dt)]
|
| 385 |
+
assert view_off is None
|
| 386 |
+
|
| 387 |
+
int64_dt = np.dtype(np.int64)
|
| 388 |
+
arr1, arr2, values = self.get_data(from_dt, int64_dt)
|
| 389 |
+
arr2 = arr2.view(time_dt)
|
| 390 |
+
arr2[...] = np.datetime64("NaT", "D")
|
| 391 |
+
|
| 392 |
+
if time_dt == np.dtype("M8"):
|
| 393 |
+
# This is a bit of a strange path, and could probably be removed
|
| 394 |
+
arr1[-1] = 0 # ensure at least one value is not NaT
|
| 395 |
+
|
| 396 |
+
# The cast currently succeeds, but the values are invalid:
|
| 397 |
+
cast._simple_strided_call((arr1, arr2))
|
| 398 |
+
with pytest.raises(ValueError):
|
| 399 |
+
str(arr2[-1]) # e.g. conversion to string fails
|
| 400 |
+
return
|
| 401 |
+
|
| 402 |
+
cast._simple_strided_call((arr1, arr2))
|
| 403 |
+
|
| 404 |
+
assert [int(v) for v in arr2.tolist()] == values
|
| 405 |
+
|
| 406 |
+
# Check that the same results are achieved for strided loops
|
| 407 |
+
arr1_o, arr2_o = self.get_data_variation(arr1, arr2, True, False)
|
| 408 |
+
cast._simple_strided_call((arr1_o, arr2_o))
|
| 409 |
+
|
| 410 |
+
assert_array_equal(arr2_o, arr2)
|
| 411 |
+
assert arr2_o.tobytes() == arr2.tobytes()
|
| 412 |
+
|
| 413 |
+
@pytest.mark.parametrize(
|
| 414 |
+
["from_dt", "to_dt", "expected_casting", "expected_view_off",
|
| 415 |
+
"nom", "denom"],
|
| 416 |
+
[("M8[ns]", None, Casting.no, 0, 1, 1),
|
| 417 |
+
(str(np.dtype("M8[ns]").newbyteorder()), None,
|
| 418 |
+
Casting.equiv, None, 1, 1),
|
| 419 |
+
("M8", "M8[ms]", Casting.safe, 0, 1, 1),
|
| 420 |
+
# should be invalid cast:
|
| 421 |
+
("M8[ms]", "M8", Casting.unsafe, None, 1, 1),
|
| 422 |
+
("M8[5ms]", "M8[5ms]", Casting.no, 0, 1, 1),
|
| 423 |
+
("M8[ns]", "M8[ms]", Casting.same_kind, None, 1, 10**6),
|
| 424 |
+
("M8[ms]", "M8[ns]", Casting.safe, None, 10**6, 1),
|
| 425 |
+
("M8[ms]", "M8[7ms]", Casting.same_kind, None, 1, 7),
|
| 426 |
+
("M8[4D]", "M8[1M]", Casting.same_kind, None, None,
|
| 427 |
+
# give full values based on NumPy 1.19.x
|
| 428 |
+
[-2**63, 0, -1, 1314, -1315, 564442610]),
|
| 429 |
+
("m8[ns]", None, Casting.no, 0, 1, 1),
|
| 430 |
+
(str(np.dtype("m8[ns]").newbyteorder()), None,
|
| 431 |
+
Casting.equiv, None, 1, 1),
|
| 432 |
+
("m8", "m8[ms]", Casting.safe, 0, 1, 1),
|
| 433 |
+
# should be invalid cast:
|
| 434 |
+
("m8[5ms]", "m8[5ms]", Casting.no, 0, 1, 1),
|
| 435 |
+
("m8[ns]", "m8[ms]", Casting.same_kind, None, 1, 10**6),
|
| 436 |
+
("m8[ms]", "m8[ns]", Casting.safe, None, 10**6, 1),
|
| 437 |
+
("m8[ms]", "m8[7ms]", Casting.same_kind, None, 1, 7),
|
| 438 |
+
("m8[4D]", "m8[1M]", Casting.unsafe, None, None,
|
| 439 |
+
# give full values based on NumPy 1.19.x
|
| 440 |
+
[-2**63, 0, 0, 1314, -1315, 564442610])])
|
| 441 |
+
def test_time_to_time(self, from_dt, to_dt,
|
| 442 |
+
expected_casting, expected_view_off,
|
| 443 |
+
nom, denom):
|
| 444 |
+
from_dt = np.dtype(from_dt)
|
| 445 |
+
if to_dt is not None:
|
| 446 |
+
to_dt = np.dtype(to_dt)
|
| 447 |
+
|
| 448 |
+
# Test a few values for casting (results generated with NumPy 1.19)
|
| 449 |
+
values = np.array([-2**63, 1, 2**63 - 1, 10000, -10000, 2**32])
|
| 450 |
+
values = values.astype(np.dtype("int64").newbyteorder(from_dt.byteorder))
|
| 451 |
+
assert values.dtype.byteorder == from_dt.byteorder
|
| 452 |
+
assert np.isnat(values.view(from_dt)[0])
|
| 453 |
+
|
| 454 |
+
DType = type(from_dt)
|
| 455 |
+
cast = get_castingimpl(DType, DType)
|
| 456 |
+
casting, (from_res, to_res), view_off = cast._resolve_descriptors(
|
| 457 |
+
(from_dt, to_dt))
|
| 458 |
+
assert from_res is from_dt
|
| 459 |
+
assert to_res is to_dt or to_dt is None
|
| 460 |
+
assert casting == expected_casting
|
| 461 |
+
assert view_off == expected_view_off
|
| 462 |
+
|
| 463 |
+
if nom is not None:
|
| 464 |
+
expected_out = (values * nom // denom).view(to_res)
|
| 465 |
+
if to_dt == np.dtype("M8"):
|
| 466 |
+
with pytest.warns(
|
| 467 |
+
DeprecationWarning,
|
| 468 |
+
match="The 'generic' unit for NumPy timedelta is deprecated",
|
| 469 |
+
):
|
| 470 |
+
expected_out[0] = "NaT"
|
| 471 |
+
else:
|
| 472 |
+
expected_out[0] = "NaT"
|
| 473 |
+
else:
|
| 474 |
+
expected_out = np.empty_like(values)
|
| 475 |
+
expected_out[...] = denom
|
| 476 |
+
expected_out = expected_out.view(to_dt)
|
| 477 |
+
|
| 478 |
+
orig_arr = values.view(from_dt)
|
| 479 |
+
orig_out = np.empty_like(expected_out)
|
| 480 |
+
|
| 481 |
+
if casting == Casting.unsafe and (to_dt == "m8" or to_dt == "M8"):
|
| 482 |
+
# Casting from non-generic to generic units is an error and should
|
| 483 |
+
# probably be reported as an invalid cast earlier.
|
| 484 |
+
with pytest.raises(ValueError):
|
| 485 |
+
cast._simple_strided_call((orig_arr, orig_out))
|
| 486 |
+
return
|
| 487 |
+
|
| 488 |
+
for aligned in [True, True]:
|
| 489 |
+
for contig in [True, True]:
|
| 490 |
+
arr, out = self.get_data_variation(
|
| 491 |
+
orig_arr, orig_out, aligned, contig)
|
| 492 |
+
out[...] = 0
|
| 493 |
+
try:
|
| 494 |
+
cast._simple_strided_call((arr, out))
|
| 495 |
+
except OverflowError:
|
| 496 |
+
# Extreme values (e.g. INT64_MAX) can overflow when
|
| 497 |
+
# scaled by the unit conversion factor. gh-16352
|
| 498 |
+
break
|
| 499 |
+
assert_array_equal(out.view("int64"), expected_out.view("int64"))
|
| 500 |
+
|
| 501 |
+
def string_with_modified_length(self, dtype, change_length):
|
| 502 |
+
fact = 1 if dtype.char == "S" else 4
|
| 503 |
+
length = dtype.itemsize // fact + change_length
|
| 504 |
+
return np.dtype(f"{dtype.byteorder}{dtype.char}{length}")
|
| 505 |
+
|
| 506 |
+
@pytest.mark.parametrize("other_DT", simple_dtypes)
|
| 507 |
+
@pytest.mark.parametrize("string_char", ["S", "U"])
|
| 508 |
+
def test_string_cancast(self, other_DT, string_char):
|
| 509 |
+
fact = 1 if string_char == "S" else 4
|
| 510 |
+
|
| 511 |
+
string_DT = type(np.dtype(string_char))
|
| 512 |
+
cast = get_castingimpl(other_DT, string_DT)
|
| 513 |
+
|
| 514 |
+
other_dt = other_DT()
|
| 515 |
+
expected_length = get_expected_stringlength(other_dt)
|
| 516 |
+
string_dt = np.dtype(f"{string_char}{expected_length}")
|
| 517 |
+
|
| 518 |
+
safety, (res_other_dt, res_dt), view_off = cast._resolve_descriptors(
|
| 519 |
+
(other_dt, None))
|
| 520 |
+
assert res_dt.itemsize == expected_length * fact
|
| 521 |
+
assert safety == Casting.safe # we consider to string casts "safe"
|
| 522 |
+
assert view_off is None
|
| 523 |
+
assert isinstance(res_dt, string_DT)
|
| 524 |
+
|
| 525 |
+
# These casts currently implement changing the string length, so
|
| 526 |
+
# check the cast-safety for too long/fixed string lengths:
|
| 527 |
+
for change_length in [-1, 0, 1]:
|
| 528 |
+
if change_length >= 0:
|
| 529 |
+
expected_safety = Casting.safe
|
| 530 |
+
else:
|
| 531 |
+
expected_safety = Casting.same_kind
|
| 532 |
+
|
| 533 |
+
to_dt = self.string_with_modified_length(string_dt, change_length)
|
| 534 |
+
safety, (_, res_dt), view_off = cast._resolve_descriptors(
|
| 535 |
+
(other_dt, to_dt))
|
| 536 |
+
assert res_dt is to_dt
|
| 537 |
+
assert safety == expected_safety
|
| 538 |
+
assert view_off is None
|
| 539 |
+
|
| 540 |
+
# The opposite direction is always considered unsafe:
|
| 541 |
+
cast = get_castingimpl(string_DT, other_DT)
|
| 542 |
+
|
| 543 |
+
safety, _, view_off = cast._resolve_descriptors((string_dt, other_dt))
|
| 544 |
+
assert safety == Casting.unsafe
|
| 545 |
+
assert view_off is None
|
| 546 |
+
|
| 547 |
+
cast = get_castingimpl(string_DT, other_DT)
|
| 548 |
+
safety, (_, res_dt), view_off = cast._resolve_descriptors(
|
| 549 |
+
(string_dt, None))
|
| 550 |
+
assert safety == Casting.unsafe
|
| 551 |
+
assert view_off is None
|
| 552 |
+
assert other_dt is res_dt # returns the singleton for simple dtypes
|
| 553 |
+
|
| 554 |
+
@pytest.mark.parametrize("string_char", ["S", "U"])
|
| 555 |
+
@pytest.mark.parametrize("other_dt", simple_dtype_instances())
|
| 556 |
+
def test_simple_string_casts_roundtrip(self, other_dt, string_char):
|
| 557 |
+
"""
|
| 558 |
+
Tests casts from and to string by checking the roundtripping property.
|
| 559 |
+
|
| 560 |
+
The test also covers some string to string casts (but not all).
|
| 561 |
+
|
| 562 |
+
If this test creates issues, it should possibly just be simplified
|
| 563 |
+
or even removed (checking whether unaligned/non-contiguous casts give
|
| 564 |
+
the same results is useful, though).
|
| 565 |
+
"""
|
| 566 |
+
string_DT = type(np.dtype(string_char))
|
| 567 |
+
|
| 568 |
+
cast = get_castingimpl(type(other_dt), string_DT)
|
| 569 |
+
cast_back = get_castingimpl(string_DT, type(other_dt))
|
| 570 |
+
_, (res_other_dt, string_dt), _ = cast._resolve_descriptors(
|
| 571 |
+
(other_dt, None))
|
| 572 |
+
|
| 573 |
+
if res_other_dt is not other_dt:
|
| 574 |
+
# do not support non-native byteorder, skip test in that case
|
| 575 |
+
assert other_dt.byteorder != res_other_dt.byteorder
|
| 576 |
+
return
|
| 577 |
+
|
| 578 |
+
orig_arr, values = self.get_data(other_dt, None)
|
| 579 |
+
str_arr = np.zeros(len(orig_arr), dtype=string_dt)
|
| 580 |
+
string_dt_short = self.string_with_modified_length(string_dt, -1)
|
| 581 |
+
str_arr_short = np.zeros(len(orig_arr), dtype=string_dt_short)
|
| 582 |
+
string_dt_long = self.string_with_modified_length(string_dt, 1)
|
| 583 |
+
str_arr_long = np.zeros(len(orig_arr), dtype=string_dt_long)
|
| 584 |
+
|
| 585 |
+
assert not cast._supports_unaligned # if support is added, should test
|
| 586 |
+
assert not cast_back._supports_unaligned
|
| 587 |
+
|
| 588 |
+
for contig in [True, False]:
|
| 589 |
+
other_arr, str_arr = self.get_data_variation(
|
| 590 |
+
orig_arr, str_arr, True, contig)
|
| 591 |
+
_, str_arr_short = self.get_data_variation(
|
| 592 |
+
orig_arr, str_arr_short.copy(), True, contig)
|
| 593 |
+
_, str_arr_long = self.get_data_variation(
|
| 594 |
+
orig_arr, str_arr_long, True, contig)
|
| 595 |
+
|
| 596 |
+
cast._simple_strided_call((other_arr, str_arr))
|
| 597 |
+
|
| 598 |
+
cast._simple_strided_call((other_arr, str_arr_short))
|
| 599 |
+
assert_array_equal(str_arr.astype(string_dt_short), str_arr_short)
|
| 600 |
+
|
| 601 |
+
cast._simple_strided_call((other_arr, str_arr_long))
|
| 602 |
+
assert_array_equal(str_arr, str_arr_long)
|
| 603 |
+
|
| 604 |
+
if other_dt.kind == "b":
|
| 605 |
+
# Booleans do not roundtrip
|
| 606 |
+
continue
|
| 607 |
+
|
| 608 |
+
other_arr[...] = 0
|
| 609 |
+
cast_back._simple_strided_call((str_arr, other_arr))
|
| 610 |
+
assert_array_equal(orig_arr, other_arr)
|
| 611 |
+
|
| 612 |
+
other_arr[...] = 0
|
| 613 |
+
cast_back._simple_strided_call((str_arr_long, other_arr))
|
| 614 |
+
assert_array_equal(orig_arr, other_arr)
|
| 615 |
+
|
| 616 |
+
@pytest.mark.parametrize("other_dt", ["S8", "<U8", ">U8"])
|
| 617 |
+
@pytest.mark.parametrize("string_char", ["S", "U"])
|
| 618 |
+
def test_string_to_string_cancast(self, other_dt, string_char):
|
| 619 |
+
other_dt = np.dtype(other_dt)
|
| 620 |
+
|
| 621 |
+
fact = 1 if string_char == "S" else 4
|
| 622 |
+
div = 1 if other_dt.char == "S" else 4
|
| 623 |
+
|
| 624 |
+
string_DT = type(np.dtype(string_char))
|
| 625 |
+
cast = get_castingimpl(type(other_dt), string_DT)
|
| 626 |
+
|
| 627 |
+
expected_length = other_dt.itemsize // div
|
| 628 |
+
string_dt = np.dtype(f"{string_char}{expected_length}")
|
| 629 |
+
|
| 630 |
+
safety, (res_other_dt, res_dt), view_off = cast._resolve_descriptors(
|
| 631 |
+
(other_dt, None))
|
| 632 |
+
assert res_dt.itemsize == expected_length * fact
|
| 633 |
+
assert isinstance(res_dt, string_DT)
|
| 634 |
+
|
| 635 |
+
expected_view_off = None
|
| 636 |
+
if other_dt.char == string_char:
|
| 637 |
+
if other_dt.isnative:
|
| 638 |
+
expected_safety = Casting.no
|
| 639 |
+
expected_view_off = 0
|
| 640 |
+
else:
|
| 641 |
+
expected_safety = Casting.equiv
|
| 642 |
+
elif string_char == "U":
|
| 643 |
+
expected_safety = Casting.safe
|
| 644 |
+
else:
|
| 645 |
+
expected_safety = Casting.unsafe
|
| 646 |
+
|
| 647 |
+
assert view_off == expected_view_off
|
| 648 |
+
assert expected_safety == safety
|
| 649 |
+
|
| 650 |
+
for change_length in [-1, 0, 1]:
|
| 651 |
+
to_dt = self.string_with_modified_length(string_dt, change_length)
|
| 652 |
+
safety, (_, res_dt), view_off = cast._resolve_descriptors(
|
| 653 |
+
(other_dt, to_dt))
|
| 654 |
+
|
| 655 |
+
assert res_dt is to_dt
|
| 656 |
+
if change_length <= 0:
|
| 657 |
+
assert view_off == expected_view_off
|
| 658 |
+
else:
|
| 659 |
+
assert view_off is None
|
| 660 |
+
if expected_safety == Casting.unsafe:
|
| 661 |
+
assert safety == expected_safety
|
| 662 |
+
elif change_length < 0:
|
| 663 |
+
assert safety == Casting.same_kind
|
| 664 |
+
elif change_length == 0:
|
| 665 |
+
assert safety == expected_safety
|
| 666 |
+
elif change_length > 0:
|
| 667 |
+
assert safety == Casting.safe
|
| 668 |
+
|
| 669 |
+
@pytest.mark.parametrize("order1", [">", "<"])
|
| 670 |
+
@pytest.mark.parametrize("order2", [">", "<"])
|
| 671 |
+
def test_unicode_byteswapped_cast(self, order1, order2):
|
| 672 |
+
# Very specific tests (not using the castingimpl directly)
|
| 673 |
+
# that tests unicode bytedwaps including for unaligned array data.
|
| 674 |
+
dtype1 = np.dtype(f"{order1}U30")
|
| 675 |
+
dtype2 = np.dtype(f"{order2}U30")
|
| 676 |
+
data1 = np.empty(30 * 4 + 1, dtype=np.uint8)[1:].view(dtype1)
|
| 677 |
+
data2 = np.empty(30 * 4 + 1, dtype=np.uint8)[1:].view(dtype2)
|
| 678 |
+
if dtype1.alignment != 1:
|
| 679 |
+
# alignment should always be >1, but skip the check if not
|
| 680 |
+
assert not data1.flags.aligned
|
| 681 |
+
assert not data2.flags.aligned
|
| 682 |
+
|
| 683 |
+
element = "this is a ünicode string‽"
|
| 684 |
+
data1[()] = element
|
| 685 |
+
# Test both `data1` and `data1.copy()` (which should be aligned)
|
| 686 |
+
for data in [data1, data1.copy()]:
|
| 687 |
+
data2[...] = data1
|
| 688 |
+
assert data2[()] == element
|
| 689 |
+
assert data2.copy()[()] == element
|
| 690 |
+
|
| 691 |
+
def test_void_to_string_special_case(self):
|
| 692 |
+
# Cover a small special case in void to string casting that could
|
| 693 |
+
# probably just as well be turned into an error (compare
|
| 694 |
+
# `test_object_to_parametric_internal_error` below).
|
| 695 |
+
assert np.array([], dtype="V5").astype("S").dtype.itemsize == 5
|
| 696 |
+
assert np.array([], dtype="V5").astype("U").dtype.itemsize == 4 * 5
|
| 697 |
+
|
| 698 |
+
def test_object_to_parametric_internal_error(self):
|
| 699 |
+
# We reject casting from object to a parametric type, without
|
| 700 |
+
# figuring out the correct instance first.
|
| 701 |
+
object_dtype = type(np.dtype(object))
|
| 702 |
+
other_dtype = type(np.dtype(str))
|
| 703 |
+
cast = get_castingimpl(object_dtype, other_dtype)
|
| 704 |
+
with pytest.raises(TypeError,
|
| 705 |
+
match="casting from object to the parametric DType"):
|
| 706 |
+
cast._resolve_descriptors((np.dtype("O"), None))
|
| 707 |
+
|
| 708 |
+
@pytest.mark.parametrize("dtype", simple_dtype_instances())
|
| 709 |
+
def test_object_and_simple_resolution(self, dtype):
|
| 710 |
+
# Simple test to exercise the cast when no instance is specified
|
| 711 |
+
object_dtype = type(np.dtype(object))
|
| 712 |
+
cast = get_castingimpl(object_dtype, type(dtype))
|
| 713 |
+
|
| 714 |
+
safety, (_, res_dt), view_off = cast._resolve_descriptors(
|
| 715 |
+
(np.dtype("O"), dtype))
|
| 716 |
+
assert safety == Casting.unsafe
|
| 717 |
+
assert view_off is None
|
| 718 |
+
assert res_dt is dtype
|
| 719 |
+
|
| 720 |
+
safety, (_, res_dt), view_off = cast._resolve_descriptors(
|
| 721 |
+
(np.dtype("O"), None))
|
| 722 |
+
assert safety == Casting.unsafe
|
| 723 |
+
assert view_off is None
|
| 724 |
+
assert res_dt == dtype.newbyteorder("=")
|
| 725 |
+
|
| 726 |
+
@pytest.mark.parametrize("dtype", simple_dtype_instances())
|
| 727 |
+
def test_simple_to_object_resolution(self, dtype):
|
| 728 |
+
# Simple test to exercise the cast when no instance is specified
|
| 729 |
+
object_dtype = type(np.dtype(object))
|
| 730 |
+
cast = get_castingimpl(type(dtype), object_dtype)
|
| 731 |
+
|
| 732 |
+
safety, (_, res_dt), view_off = cast._resolve_descriptors(
|
| 733 |
+
(dtype, None))
|
| 734 |
+
assert safety == Casting.safe
|
| 735 |
+
assert view_off is None
|
| 736 |
+
assert res_dt is np.dtype("O")
|
| 737 |
+
|
| 738 |
+
@pytest.mark.parametrize("casting", ["no", "unsafe"])
|
| 739 |
+
def test_void_and_structured_with_subarray(self, casting):
|
| 740 |
+
# test case corresponding to gh-19325
|
| 741 |
+
dtype = np.dtype([("foo", "<f4", (3, 2))])
|
| 742 |
+
expected = casting == "unsafe"
|
| 743 |
+
assert np.can_cast("V4", dtype, casting=casting) == expected
|
| 744 |
+
assert np.can_cast(dtype, "V4", casting=casting) == expected
|
| 745 |
+
|
| 746 |
+
@pytest.mark.parametrize(["to_dt", "expected_off"],
|
| 747 |
+
[ # Same as `from_dt` but with both fields shifted:
|
| 748 |
+
(np.dtype({"names": ["a", "b"], "formats": ["i4", "f4"],
|
| 749 |
+
"offsets": [0, 4]}), 2),
|
| 750 |
+
# Additional change of the names
|
| 751 |
+
(np.dtype({"names": ["b", "a"], "formats": ["i4", "f4"],
|
| 752 |
+
"offsets": [0, 4]}), 2),
|
| 753 |
+
# Incompatible field offset change
|
| 754 |
+
(np.dtype({"names": ["b", "a"], "formats": ["i4", "f4"],
|
| 755 |
+
"offsets": [0, 6]}), None)])
|
| 756 |
+
def test_structured_field_offsets(self, to_dt, expected_off):
|
| 757 |
+
# This checks the cast-safety and view offset for swapped and "shifted"
|
| 758 |
+
# fields which are viewable
|
| 759 |
+
from_dt = np.dtype({"names": ["a", "b"],
|
| 760 |
+
"formats": ["i4", "f4"],
|
| 761 |
+
"offsets": [2, 6]})
|
| 762 |
+
cast = get_castingimpl(type(from_dt), type(to_dt))
|
| 763 |
+
safety, _, view_off = cast._resolve_descriptors((from_dt, to_dt))
|
| 764 |
+
if from_dt.names == to_dt.names:
|
| 765 |
+
assert safety == Casting.equiv
|
| 766 |
+
else:
|
| 767 |
+
assert safety == Casting.safe
|
| 768 |
+
# Shifting the original data pointer by -2 will align both by
|
| 769 |
+
# effectively adding 2 bytes of spacing before `from_dt`.
|
| 770 |
+
assert view_off == expected_off
|
| 771 |
+
|
| 772 |
+
@pytest.mark.parametrize(("from_dt", "to_dt", "expected_off"), [
|
| 773 |
+
# Subarray cases:
|
| 774 |
+
("i", "(1,1)i", 0),
|
| 775 |
+
("(1,1)i", "i", 0),
|
| 776 |
+
("(2,1)i", "(2,1)i", 0),
|
| 777 |
+
# field cases (field to field is tested explicitly also):
|
| 778 |
+
# Not considered viewable, because a negative offset would allow
|
| 779 |
+
# may structured dtype to indirectly access invalid memory.
|
| 780 |
+
("i", {"names": ["a"], "formats": ["i"], "offsets": [2]}, None),
|
| 781 |
+
({"names": ["a"], "formats": ["i"], "offsets": [2]}, "i", 2),
|
| 782 |
+
# Currently considered not viewable, due to multiple fields
|
| 783 |
+
# even though they overlap (maybe we should not allow that?)
|
| 784 |
+
("i", {"names": ["a", "b"], "formats": ["i", "i"], "offsets": [2, 2]},
|
| 785 |
+
None),
|
| 786 |
+
# different number of fields can't work, should probably just fail
|
| 787 |
+
# so it never reports "viewable":
|
| 788 |
+
("i,i", "i,i,i", None),
|
| 789 |
+
# Unstructured void cases:
|
| 790 |
+
("i4", "V3", 0), # void smaller or equal
|
| 791 |
+
("i4", "V4", 0), # void smaller or equal
|
| 792 |
+
("i4", "V10", None), # void is larger (no view)
|
| 793 |
+
("O", "V4", None), # currently reject objects for view here.
|
| 794 |
+
("O", "V8", None), # currently reject objects for view here.
|
| 795 |
+
("V4", "V3", 0),
|
| 796 |
+
("V4", "V4", 0),
|
| 797 |
+
("V3", "V4", None),
|
| 798 |
+
# Note that currently void-to-other cast goes via byte-strings
|
| 799 |
+
# and is not a "view" based cast like the opposite direction:
|
| 800 |
+
("V4", "i4", None),
|
| 801 |
+
# completely invalid/impossible cast:
|
| 802 |
+
("i,i", "i,i,i", None),
|
| 803 |
+
])
|
| 804 |
+
def test_structured_view_offsets_parametric(
|
| 805 |
+
self, from_dt, to_dt, expected_off):
|
| 806 |
+
# TODO: While this test is fairly thorough, right now, it does not
|
| 807 |
+
# really test some paths that may have nonzero offsets (they don't
|
| 808 |
+
# really exists).
|
| 809 |
+
from_dt = np.dtype(from_dt)
|
| 810 |
+
to_dt = np.dtype(to_dt)
|
| 811 |
+
cast = get_castingimpl(type(from_dt), type(to_dt))
|
| 812 |
+
_, _, view_off = cast._resolve_descriptors((from_dt, to_dt))
|
| 813 |
+
assert view_off == expected_off
|
| 814 |
+
|
| 815 |
+
@pytest.mark.parametrize("dtype", np.typecodes["All"])
|
| 816 |
+
def test_object_casts_NULL_None_equivalence(self, dtype):
|
| 817 |
+
# None to <other> casts may succeed or fail, but a NULL'ed array must
|
| 818 |
+
# behave the same as one filled with None's.
|
| 819 |
+
arr_normal = np.array([None] * 5)
|
| 820 |
+
arr_NULLs = np.empty_like(arr_normal)
|
| 821 |
+
ctypes.memset(arr_NULLs.ctypes.data, 0, arr_NULLs.nbytes)
|
| 822 |
+
# If the check fails (maybe it should) the test would lose its purpose:
|
| 823 |
+
assert arr_NULLs.tobytes() == b"\x00" * arr_NULLs.nbytes
|
| 824 |
+
|
| 825 |
+
try:
|
| 826 |
+
if dtype == "M":
|
| 827 |
+
dtype = "M[D]"
|
| 828 |
+
expected = arr_normal.astype(dtype)
|
| 829 |
+
except TypeError:
|
| 830 |
+
with pytest.raises(TypeError):
|
| 831 |
+
arr_NULLs.astype(dtype)
|
| 832 |
+
else:
|
| 833 |
+
assert_array_equal(expected, arr_NULLs.astype(dtype))
|
| 834 |
+
|
| 835 |
+
@pytest.mark.parametrize("dtype",
|
| 836 |
+
np.typecodes["AllInteger"] + np.typecodes["AllFloat"])
|
| 837 |
+
def test_nonstandard_bool_to_other(self, dtype):
|
| 838 |
+
# simple test for casting bool_ to numeric types, which should not
|
| 839 |
+
# expose the detail that NumPy bools can sometimes take values other
|
| 840 |
+
# than 0 and 1. See also gh-19514.
|
| 841 |
+
nonstandard_bools = np.array([0, 3, -7], dtype=np.int8).view(bool)
|
| 842 |
+
res = nonstandard_bools.astype(dtype)
|
| 843 |
+
expected = [0, 1, 1]
|
| 844 |
+
assert_array_equal(res, expected)
|
| 845 |
+
|
| 846 |
+
@pytest.mark.parametrize("to_dtype",
|
| 847 |
+
np.typecodes["AllInteger"] + np.typecodes["AllFloat"])
|
| 848 |
+
@pytest.mark.parametrize("from_dtype",
|
| 849 |
+
np.typecodes["AllInteger"] + np.typecodes["AllFloat"])
|
| 850 |
+
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
|
| 851 |
+
def test_same_value_overflow(self, from_dtype, to_dtype):
|
| 852 |
+
if from_dtype == to_dtype:
|
| 853 |
+
return
|
| 854 |
+
top1 = 0
|
| 855 |
+
top2 = 0
|
| 856 |
+
try:
|
| 857 |
+
top1 = np.iinfo(from_dtype).max
|
| 858 |
+
except ValueError:
|
| 859 |
+
top1 = np.finfo(from_dtype).max
|
| 860 |
+
try:
|
| 861 |
+
top2 = np.iinfo(to_dtype).max
|
| 862 |
+
except ValueError:
|
| 863 |
+
top2 = np.finfo(to_dtype).max
|
| 864 |
+
# No need to test if top2 > top1, since the test will also do the
|
| 865 |
+
# reverse dtype matching. Catch then warning if the comparison warns,
|
| 866 |
+
# i.e. np.int16(65535) < np.float16(6.55e4)
|
| 867 |
+
with warnings.catch_warnings(record=True):
|
| 868 |
+
warnings.simplefilter("always", RuntimeWarning)
|
| 869 |
+
if top2 >= top1:
|
| 870 |
+
# will be tested when the dtypes are reversed
|
| 871 |
+
return
|
| 872 |
+
# Happy path
|
| 873 |
+
arr1 = np.array([0] * 10, dtype=from_dtype)
|
| 874 |
+
arr2 = np.array([0] * 10, dtype=to_dtype)
|
| 875 |
+
arr1_astype = arr1.astype(to_dtype, casting='same_value')
|
| 876 |
+
assert_equal(arr1_astype, arr2, strict=True)
|
| 877 |
+
# Make it overflow, both aligned and unaligned
|
| 878 |
+
arr1[0] = top1
|
| 879 |
+
aligned = np.empty(arr1.itemsize * arr1.size + 1, 'uint8')
|
| 880 |
+
unaligned = aligned[1:].view(arr1.dtype)
|
| 881 |
+
unaligned[:] = arr1
|
| 882 |
+
with pytest.raises(ValueError):
|
| 883 |
+
# Casting float to float with overflow should raise
|
| 884 |
+
# RuntimeWarning (fperror)
|
| 885 |
+
# Casting float to int with overflow sometimes raises
|
| 886 |
+
# RuntimeWarning (fperror)
|
| 887 |
+
# Casting with overflow and 'same_value', should raise ValueError
|
| 888 |
+
with warnings.catch_warnings(record=True) as w:
|
| 889 |
+
warnings.simplefilter("always", RuntimeWarning)
|
| 890 |
+
arr1.astype(to_dtype, casting='same_value')
|
| 891 |
+
assert len(w) < 2
|
| 892 |
+
with pytest.raises(ValueError):
|
| 893 |
+
# again, unaligned
|
| 894 |
+
with warnings.catch_warnings(record=True) as w:
|
| 895 |
+
warnings.simplefilter("always", RuntimeWarning)
|
| 896 |
+
unaligned.astype(to_dtype, casting='same_value')
|
| 897 |
+
assert len(w) < 2
|
| 898 |
+
|
| 899 |
+
@pytest.mark.parametrize("to_dtype",
|
| 900 |
+
np.typecodes["AllInteger"])
|
| 901 |
+
@pytest.mark.parametrize("from_dtype",
|
| 902 |
+
np.typecodes["AllFloat"])
|
| 903 |
+
@pytest.mark.filterwarnings("ignore::RuntimeWarning")
|
| 904 |
+
def test_same_value_float_to_int(self, from_dtype, to_dtype):
|
| 905 |
+
# Should not raise, since the values can round trip
|
| 906 |
+
arr1 = np.arange(10, dtype=from_dtype)
|
| 907 |
+
aligned = np.empty(arr1.itemsize * arr1.size + 1, 'uint8')
|
| 908 |
+
unaligned = aligned[1:].view(arr1.dtype)
|
| 909 |
+
unaligned[:] = arr1
|
| 910 |
+
arr2 = np.arange(10, dtype=to_dtype)
|
| 911 |
+
assert_array_equal(arr1.astype(to_dtype, casting='same_value'), arr2)
|
| 912 |
+
assert_array_equal(unaligned.astype(to_dtype, casting='same_value'), arr2)
|
| 913 |
+
|
| 914 |
+
# Should raise, since values cannot round trip. Might warn too about
|
| 915 |
+
# FPE errors
|
| 916 |
+
arr1_66 = arr1 + 0.666
|
| 917 |
+
unaligned_66 = unaligned + 0.66
|
| 918 |
+
with pytest.raises(ValueError):
|
| 919 |
+
arr1_66.astype(to_dtype, casting='same_value')
|
| 920 |
+
with pytest.raises(ValueError):
|
| 921 |
+
unaligned_66.astype(to_dtype, casting='same_value')
|
| 922 |
+
|
| 923 |
+
@pytest.mark.parametrize("to_dtype",
|
| 924 |
+
np.typecodes["AllInteger"])
|
| 925 |
+
@pytest.mark.parametrize("from_dtype",
|
| 926 |
+
np.typecodes["AllFloat"])
|
| 927 |
+
@pytest.mark.filterwarnings("ignore::RuntimeWarning")
|
| 928 |
+
def test_same_value_float_to_int_scalar(self, from_dtype, to_dtype):
|
| 929 |
+
# Should not raise, since the values can round trip
|
| 930 |
+
s1 = np.array(10, dtype=from_dtype)
|
| 931 |
+
assert s1.astype(to_dtype, casting='same_value') == 10
|
| 932 |
+
|
| 933 |
+
# Should raise, since values cannot round trip
|
| 934 |
+
s1_66 = s1 + 0.666
|
| 935 |
+
with pytest.raises(ValueError):
|
| 936 |
+
s1_66.astype(to_dtype, casting='same_value')
|
| 937 |
+
|
| 938 |
+
@pytest.mark.parametrize("value", [np.nan, np.inf, -np.inf])
|
| 939 |
+
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
|
| 940 |
+
@pytest.mark.filterwarnings("ignore::RuntimeWarning")
|
| 941 |
+
def test_same_value_naninf(self, value):
|
| 942 |
+
# These work, but may trigger FPE warnings on macOS
|
| 943 |
+
np.array([value], dtype=np.half).astype(np.cdouble, casting='same_value')
|
| 944 |
+
np.array([value], dtype=np.half).astype(np.double, casting='same_value')
|
| 945 |
+
np.array([value], dtype=np.float32).astype(np.cdouble, casting='same_value')
|
| 946 |
+
np.array([value], dtype=np.float32).astype(np.double, casting='same_value')
|
| 947 |
+
np.array([value], dtype=np.float32).astype(np.half, casting='same_value')
|
| 948 |
+
np.array([value], dtype=np.complex64).astype(np.half, casting='same_value')
|
| 949 |
+
# These fail
|
| 950 |
+
with pytest.raises(ValueError):
|
| 951 |
+
np.array([value], dtype=np.half).astype(np.int64, casting='same_value')
|
| 952 |
+
with pytest.raises(ValueError):
|
| 953 |
+
np.array([value], dtype=np.complex64).astype(np.int64, casting='same_value')
|
| 954 |
+
with pytest.raises(ValueError):
|
| 955 |
+
np.array([value], dtype=np.float32).astype(np.int64, casting='same_value')
|
| 956 |
+
|
| 957 |
+
@pytest.mark.filterwarnings("ignore::numpy.exceptions.ComplexWarning")
|
| 958 |
+
def test_same_value_complex(self):
|
| 959 |
+
arr = np.array([complex(1, 1)], dtype=np.cdouble)
|
| 960 |
+
# This works
|
| 961 |
+
arr.astype(np.complex64, casting='same_value')
|
| 962 |
+
# Casting with a non-zero imag part fails
|
| 963 |
+
with pytest.raises(ValueError):
|
| 964 |
+
arr.astype(np.float32, casting='same_value')
|
| 965 |
+
|
| 966 |
+
def test_same_value_scalar(self):
|
| 967 |
+
i = np.array(123, dtype=np.int64)
|
| 968 |
+
f = np.array(123, dtype=np.float64)
|
| 969 |
+
assert i.astype(np.float64, casting='same_value') == f
|
| 970 |
+
assert f.astype(np.int64, casting='same_value') == f
|
v12x/pylib/numpy/_core/tests/test_conversion_utils.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Tests for numpy/_core/src/multiarray/conversion_utils.c
|
| 3 |
+
"""
|
| 4 |
+
import re
|
| 5 |
+
|
| 6 |
+
import pytest
|
| 7 |
+
|
| 8 |
+
import numpy._core._multiarray_tests as mt
|
| 9 |
+
from numpy._core.multiarray import CLIP, RAISE, WRAP
|
| 10 |
+
from numpy.testing import assert_raises
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class StringConverterTestCase:
|
| 14 |
+
allow_bytes = True
|
| 15 |
+
case_insensitive = True
|
| 16 |
+
exact_match = False
|
| 17 |
+
warn = True
|
| 18 |
+
|
| 19 |
+
def _check_value_error(self, val):
|
| 20 |
+
pattern = fr'\(got {re.escape(repr(val))}\)'
|
| 21 |
+
with pytest.raises(ValueError, match=pattern) as exc:
|
| 22 |
+
self.conv(val)
|
| 23 |
+
|
| 24 |
+
def _check_conv_assert_warn(self, val, expected):
|
| 25 |
+
if self.warn:
|
| 26 |
+
with assert_raises(ValueError) as exc:
|
| 27 |
+
assert self.conv(val) == expected
|
| 28 |
+
else:
|
| 29 |
+
assert self.conv(val) == expected
|
| 30 |
+
|
| 31 |
+
def _check(self, val, expected):
|
| 32 |
+
"""Takes valid non-deprecated inputs for converters,
|
| 33 |
+
runs converters on inputs, checks correctness of outputs,
|
| 34 |
+
warnings and errors"""
|
| 35 |
+
assert self.conv(val) == expected
|
| 36 |
+
|
| 37 |
+
if self.allow_bytes:
|
| 38 |
+
assert self.conv(val.encode('ascii')) == expected
|
| 39 |
+
else:
|
| 40 |
+
with pytest.raises(TypeError):
|
| 41 |
+
self.conv(val.encode('ascii'))
|
| 42 |
+
|
| 43 |
+
if len(val) != 1:
|
| 44 |
+
if self.exact_match:
|
| 45 |
+
self._check_value_error(val[:1])
|
| 46 |
+
self._check_value_error(val + '\0')
|
| 47 |
+
else:
|
| 48 |
+
self._check_conv_assert_warn(val[:1], expected)
|
| 49 |
+
|
| 50 |
+
if self.case_insensitive:
|
| 51 |
+
if val != val.lower():
|
| 52 |
+
self._check_conv_assert_warn(val.lower(), expected)
|
| 53 |
+
if val != val.upper():
|
| 54 |
+
self._check_conv_assert_warn(val.upper(), expected)
|
| 55 |
+
else:
|
| 56 |
+
if val != val.lower():
|
| 57 |
+
self._check_value_error(val.lower())
|
| 58 |
+
if val != val.upper():
|
| 59 |
+
self._check_value_error(val.upper())
|
| 60 |
+
|
| 61 |
+
def test_wrong_type(self):
|
| 62 |
+
# common cases which apply to all the below
|
| 63 |
+
with pytest.raises(TypeError):
|
| 64 |
+
self.conv({})
|
| 65 |
+
with pytest.raises(TypeError):
|
| 66 |
+
self.conv([])
|
| 67 |
+
|
| 68 |
+
def test_wrong_value(self):
|
| 69 |
+
# nonsense strings
|
| 70 |
+
self._check_value_error('')
|
| 71 |
+
self._check_value_error('\N{greek small letter pi}')
|
| 72 |
+
|
| 73 |
+
if self.allow_bytes:
|
| 74 |
+
self._check_value_error(b'')
|
| 75 |
+
# bytes which can't be converted to strings via utf8
|
| 76 |
+
self._check_value_error(b"\xFF")
|
| 77 |
+
if self.exact_match:
|
| 78 |
+
self._check_value_error("there's no way this is supported")
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
class TestByteorderConverter(StringConverterTestCase):
|
| 82 |
+
""" Tests of PyArray_ByteorderConverter """
|
| 83 |
+
conv = mt.run_byteorder_converter
|
| 84 |
+
warn = False
|
| 85 |
+
|
| 86 |
+
def test_valid(self):
|
| 87 |
+
for s in ['big', '>']:
|
| 88 |
+
self._check(s, 'NPY_BIG')
|
| 89 |
+
for s in ['little', '<']:
|
| 90 |
+
self._check(s, 'NPY_LITTLE')
|
| 91 |
+
for s in ['native', '=']:
|
| 92 |
+
self._check(s, 'NPY_NATIVE')
|
| 93 |
+
for s in ['ignore', '|']:
|
| 94 |
+
self._check(s, 'NPY_IGNORE')
|
| 95 |
+
for s in ['swap']:
|
| 96 |
+
self._check(s, 'NPY_SWAP')
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
class TestSortkindConverter(StringConverterTestCase):
|
| 100 |
+
""" Tests of PyArray_SortkindConverter """
|
| 101 |
+
conv = mt.run_sortkind_converter
|
| 102 |
+
warn = False
|
| 103 |
+
|
| 104 |
+
def test_valid(self):
|
| 105 |
+
self._check('quicksort', 'NPY_QUICKSORT')
|
| 106 |
+
self._check('heapsort', 'NPY_HEAPSORT')
|
| 107 |
+
self._check('mergesort', 'NPY_STABLESORT') # alias
|
| 108 |
+
self._check('stable', 'NPY_STABLESORT')
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
class TestSelectkindConverter(StringConverterTestCase):
|
| 112 |
+
""" Tests of PyArray_SelectkindConverter """
|
| 113 |
+
conv = mt.run_selectkind_converter
|
| 114 |
+
case_insensitive = False
|
| 115 |
+
exact_match = True
|
| 116 |
+
|
| 117 |
+
def test_valid(self):
|
| 118 |
+
self._check('introselect', 'NPY_INTROSELECT')
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
class TestSearchsideConverter(StringConverterTestCase):
|
| 122 |
+
""" Tests of PyArray_SearchsideConverter """
|
| 123 |
+
conv = mt.run_searchside_converter
|
| 124 |
+
|
| 125 |
+
def test_valid(self):
|
| 126 |
+
self._check('left', 'NPY_SEARCHLEFT')
|
| 127 |
+
self._check('right', 'NPY_SEARCHRIGHT')
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
class TestOrderConverter(StringConverterTestCase):
|
| 131 |
+
""" Tests of PyArray_OrderConverter """
|
| 132 |
+
conv = mt.run_order_converter
|
| 133 |
+
warn = False
|
| 134 |
+
|
| 135 |
+
def test_valid(self):
|
| 136 |
+
self._check('c', 'NPY_CORDER')
|
| 137 |
+
self._check('f', 'NPY_FORTRANORDER')
|
| 138 |
+
self._check('a', 'NPY_ANYORDER')
|
| 139 |
+
self._check('k', 'NPY_KEEPORDER')
|
| 140 |
+
|
| 141 |
+
def test_flatten_invalid_order(self):
|
| 142 |
+
# invalid after gh-14596
|
| 143 |
+
with pytest.raises(ValueError):
|
| 144 |
+
self.conv('Z')
|
| 145 |
+
for order in [False, True, 0, 8]:
|
| 146 |
+
with pytest.raises(TypeError):
|
| 147 |
+
self.conv(order)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class TestClipmodeConverter(StringConverterTestCase):
|
| 151 |
+
""" Tests of PyArray_ClipmodeConverter """
|
| 152 |
+
conv = mt.run_clipmode_converter
|
| 153 |
+
|
| 154 |
+
def test_valid(self):
|
| 155 |
+
self._check('clip', 'NPY_CLIP')
|
| 156 |
+
self._check('wrap', 'NPY_WRAP')
|
| 157 |
+
self._check('raise', 'NPY_RAISE')
|
| 158 |
+
|
| 159 |
+
# integer values allowed here
|
| 160 |
+
assert self.conv(CLIP) == 'NPY_CLIP'
|
| 161 |
+
assert self.conv(WRAP) == 'NPY_WRAP'
|
| 162 |
+
assert self.conv(RAISE) == 'NPY_RAISE'
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
class TestCastingConverter(StringConverterTestCase):
|
| 166 |
+
""" Tests of PyArray_CastingConverter """
|
| 167 |
+
conv = mt.run_casting_converter
|
| 168 |
+
case_insensitive = False
|
| 169 |
+
exact_match = True
|
| 170 |
+
|
| 171 |
+
def test_valid(self):
|
| 172 |
+
self._check("no", "NPY_NO_CASTING")
|
| 173 |
+
self._check("equiv", "NPY_EQUIV_CASTING")
|
| 174 |
+
self._check("safe", "NPY_SAFE_CASTING")
|
| 175 |
+
self._check("unsafe", "NPY_UNSAFE_CASTING")
|
| 176 |
+
self._check("same_kind", "NPY_SAME_KIND_CASTING")
|
| 177 |
+
|
| 178 |
+
def test_invalid(self):
|
| 179 |
+
# Currently, 'same_value' is supported only in ndarray.astype
|
| 180 |
+
self._check_value_error("same_value")
|
| 181 |
+
|
| 182 |
+
class TestIntpConverter:
|
| 183 |
+
""" Tests of PyArray_IntpConverter """
|
| 184 |
+
conv = mt.run_intp_converter
|
| 185 |
+
|
| 186 |
+
def test_basic(self):
|
| 187 |
+
assert self.conv(1) == (1,)
|
| 188 |
+
assert self.conv((1, 2)) == (1, 2)
|
| 189 |
+
assert self.conv([1, 2]) == (1, 2)
|
| 190 |
+
assert self.conv(()) == ()
|
| 191 |
+
|
| 192 |
+
def test_none(self):
|
| 193 |
+
with pytest.raises(TypeError):
|
| 194 |
+
assert self.conv(None) == ()
|
| 195 |
+
|
| 196 |
+
def test_float(self):
|
| 197 |
+
with pytest.raises(TypeError):
|
| 198 |
+
self.conv(1.0)
|
| 199 |
+
with pytest.raises(TypeError):
|
| 200 |
+
self.conv([1, 1.0])
|
| 201 |
+
|
| 202 |
+
def test_too_large(self):
|
| 203 |
+
with pytest.raises(ValueError):
|
| 204 |
+
self.conv(2**64)
|
| 205 |
+
|
| 206 |
+
def test_too_many_dims(self):
|
| 207 |
+
assert self.conv([1] * 64) == (1,) * 64
|
| 208 |
+
with pytest.raises(ValueError):
|
| 209 |
+
self.conv([1] * 65)
|
v12x/pylib/numpy/_core/tests/test_cpu_dispatcher.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from numpy._core import _umath_tests
|
| 2 |
+
from numpy._core._multiarray_umath import (
|
| 3 |
+
__cpu_baseline__,
|
| 4 |
+
__cpu_dispatch__,
|
| 5 |
+
__cpu_features__,
|
| 6 |
+
)
|
| 7 |
+
from numpy.testing import assert_equal
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_dispatcher():
|
| 11 |
+
"""
|
| 12 |
+
Testing the utilities of the CPU dispatcher
|
| 13 |
+
"""
|
| 14 |
+
targets = (
|
| 15 |
+
"X86_V2", "X86_V3",
|
| 16 |
+
"VSX", "VSX2", "VSX3",
|
| 17 |
+
"NEON", "ASIMD", "ASIMDHP",
|
| 18 |
+
"VX", "VXE", "LSX", "RVV"
|
| 19 |
+
)
|
| 20 |
+
highest_sfx = "" # no suffix for the baseline
|
| 21 |
+
all_sfx = []
|
| 22 |
+
for feature in reversed(targets):
|
| 23 |
+
# skip baseline features, by the default `CCompilerOpt` do not generate
|
| 24 |
+
# separated objects for the baseline, just one object combined all of them
|
| 25 |
+
# via 'baseline' option within the configuration statements.
|
| 26 |
+
if feature in __cpu_baseline__:
|
| 27 |
+
continue
|
| 28 |
+
# check compiler and running machine support
|
| 29 |
+
if feature not in __cpu_dispatch__ or not __cpu_features__[feature]:
|
| 30 |
+
continue
|
| 31 |
+
|
| 32 |
+
if not highest_sfx:
|
| 33 |
+
highest_sfx = "_" + feature
|
| 34 |
+
all_sfx.append("func" + "_" + feature)
|
| 35 |
+
|
| 36 |
+
test = _umath_tests.test_dispatch()
|
| 37 |
+
assert_equal(test["func"], "func" + highest_sfx)
|
| 38 |
+
assert_equal(test["var"], "var" + highest_sfx)
|
| 39 |
+
|
| 40 |
+
if highest_sfx:
|
| 41 |
+
assert_equal(test["func_xb"], "func" + highest_sfx)
|
| 42 |
+
assert_equal(test["var_xb"], "var" + highest_sfx)
|
| 43 |
+
else:
|
| 44 |
+
assert_equal(test["func_xb"], "nobase")
|
| 45 |
+
assert_equal(test["var_xb"], "nobase")
|
| 46 |
+
|
| 47 |
+
all_sfx.append("func") # add the baseline
|
| 48 |
+
assert_equal(test["all"], all_sfx)
|
v12x/pylib/numpy/_core/tests/test_cpu_features.py
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import pathlib
|
| 3 |
+
import platform
|
| 4 |
+
import re
|
| 5 |
+
import subprocess
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
import pytest
|
| 9 |
+
|
| 10 |
+
from numpy._core._multiarray_umath import (
|
| 11 |
+
__cpu_baseline__,
|
| 12 |
+
__cpu_dispatch__,
|
| 13 |
+
__cpu_features__,
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def assert_features_equal(actual, desired, fname):
|
| 18 |
+
__tracebackhide__ = True # Hide traceback for py.test
|
| 19 |
+
actual, desired = str(actual), str(desired)
|
| 20 |
+
if actual == desired:
|
| 21 |
+
return
|
| 22 |
+
detected = str(__cpu_features__).replace("'", "")
|
| 23 |
+
try:
|
| 24 |
+
with open("/proc/cpuinfo") as fd:
|
| 25 |
+
cpuinfo = fd.read(2048)
|
| 26 |
+
except Exception as err:
|
| 27 |
+
cpuinfo = str(err)
|
| 28 |
+
|
| 29 |
+
try:
|
| 30 |
+
import subprocess
|
| 31 |
+
auxv = subprocess.check_output(['/bin/true'], env={"LD_SHOW_AUXV": "1"})
|
| 32 |
+
auxv = auxv.decode()
|
| 33 |
+
except Exception as err:
|
| 34 |
+
auxv = str(err)
|
| 35 |
+
|
| 36 |
+
import textwrap
|
| 37 |
+
error_report = textwrap.indent(
|
| 38 |
+
f"""
|
| 39 |
+
###########################################
|
| 40 |
+
### Extra debugging information
|
| 41 |
+
###########################################
|
| 42 |
+
-------------------------------------------
|
| 43 |
+
--- NumPy Detections
|
| 44 |
+
-------------------------------------------
|
| 45 |
+
{detected}
|
| 46 |
+
-------------------------------------------
|
| 47 |
+
--- SYS / CPUINFO
|
| 48 |
+
-------------------------------------------
|
| 49 |
+
{cpuinfo}....
|
| 50 |
+
-------------------------------------------
|
| 51 |
+
--- SYS / AUXV
|
| 52 |
+
-------------------------------------------
|
| 53 |
+
{auxv}
|
| 54 |
+
""", prefix='\r')
|
| 55 |
+
|
| 56 |
+
raise AssertionError(
|
| 57 |
+
"Failure Detection\n"
|
| 58 |
+
f" NAME: '{fname}'\n"
|
| 59 |
+
f" ACTUAL: {actual}\n"
|
| 60 |
+
f" DESIRED: {desired}\n"
|
| 61 |
+
f"{error_report}")
|
| 62 |
+
|
| 63 |
+
def _text_to_list(txt):
|
| 64 |
+
out = txt.strip("][\n").replace("'", "").split(', ')
|
| 65 |
+
return None if out[0] == "" else out
|
| 66 |
+
|
| 67 |
+
class AbstractTest:
|
| 68 |
+
features = []
|
| 69 |
+
features_groups = {}
|
| 70 |
+
features_map = {}
|
| 71 |
+
features_flags = set()
|
| 72 |
+
|
| 73 |
+
def load_flags(self):
|
| 74 |
+
# a hook
|
| 75 |
+
pass
|
| 76 |
+
|
| 77 |
+
def test_features(self):
|
| 78 |
+
self.load_flags()
|
| 79 |
+
for gname, features in self.features_groups.items():
|
| 80 |
+
test_features = [self.cpu_have(f) for f in features]
|
| 81 |
+
assert_features_equal(
|
| 82 |
+
__cpu_features__.get(gname),
|
| 83 |
+
all(test_features),
|
| 84 |
+
gname,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
for feature_name in self.features:
|
| 88 |
+
cpu_have = self.cpu_have(feature_name)
|
| 89 |
+
npy_have = __cpu_features__.get(feature_name)
|
| 90 |
+
assert_features_equal(npy_have, cpu_have, feature_name)
|
| 91 |
+
|
| 92 |
+
def cpu_have(self, feature_name):
|
| 93 |
+
map_names = self.features_map.get(feature_name, feature_name)
|
| 94 |
+
if isinstance(map_names, str):
|
| 95 |
+
return map_names in self.features_flags
|
| 96 |
+
return any(f in self.features_flags for f in map_names)
|
| 97 |
+
|
| 98 |
+
def load_flags_cpuinfo(self, magic_key):
|
| 99 |
+
self.features_flags = self.get_cpuinfo_item(magic_key)
|
| 100 |
+
|
| 101 |
+
def get_cpuinfo_item(self, magic_key):
|
| 102 |
+
values = set()
|
| 103 |
+
with open('/proc/cpuinfo') as fd:
|
| 104 |
+
for line in fd:
|
| 105 |
+
if not line.startswith(magic_key):
|
| 106 |
+
continue
|
| 107 |
+
flags_value = [s.strip() for s in line.split(':', 1)]
|
| 108 |
+
if len(flags_value) == 2:
|
| 109 |
+
values = values.union(flags_value[1].upper().split())
|
| 110 |
+
return values
|
| 111 |
+
|
| 112 |
+
def load_flags_auxv(self):
|
| 113 |
+
auxv = subprocess.check_output(['/bin/true'], env={"LD_SHOW_AUXV": "1"})
|
| 114 |
+
for at in auxv.split(b'\n'):
|
| 115 |
+
if not at.startswith(b"AT_HWCAP"):
|
| 116 |
+
continue
|
| 117 |
+
hwcap_value = [s.strip() for s in at.split(b':', 1)]
|
| 118 |
+
if len(hwcap_value) == 2:
|
| 119 |
+
self.features_flags = self.features_flags.union(
|
| 120 |
+
hwcap_value[1].upper().decode().split()
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
@pytest.mark.skipif(
|
| 124 |
+
sys.platform == 'emscripten',
|
| 125 |
+
reason=(
|
| 126 |
+
"The subprocess module is not available on WASM platforms and"
|
| 127 |
+
" therefore this test class cannot be properly executed."
|
| 128 |
+
),
|
| 129 |
+
)
|
| 130 |
+
@pytest.mark.thread_unsafe(
|
| 131 |
+
reason="setup & tmp_path_factory threads-unsafe, modifies environment variables",
|
| 132 |
+
)
|
| 133 |
+
class TestEnvPrivation:
|
| 134 |
+
cwd = pathlib.Path(__file__).parent.resolve()
|
| 135 |
+
env = os.environ.copy()
|
| 136 |
+
_enable = os.environ.pop('NPY_ENABLE_CPU_FEATURES', None)
|
| 137 |
+
_disable = os.environ.pop('NPY_DISABLE_CPU_FEATURES', None)
|
| 138 |
+
SUBPROCESS_ARGS = {"cwd": cwd, "capture_output": True, "text": True, "check": True}
|
| 139 |
+
unavailable_feats = [
|
| 140 |
+
feat for feat in __cpu_dispatch__ if not __cpu_features__[feat]
|
| 141 |
+
]
|
| 142 |
+
UNAVAILABLE_FEAT = (
|
| 143 |
+
None if len(unavailable_feats) == 0
|
| 144 |
+
else unavailable_feats[0]
|
| 145 |
+
)
|
| 146 |
+
BASELINE_FEAT = None if len(__cpu_baseline__) == 0 else __cpu_baseline__[0]
|
| 147 |
+
SCRIPT = """
|
| 148 |
+
def main():
|
| 149 |
+
from numpy._core._multiarray_umath import (
|
| 150 |
+
__cpu_features__,
|
| 151 |
+
__cpu_dispatch__
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
detected = [feat for feat in __cpu_dispatch__ if __cpu_features__[feat]]
|
| 155 |
+
print(detected)
|
| 156 |
+
|
| 157 |
+
if __name__ == "__main__":
|
| 158 |
+
main()
|
| 159 |
+
"""
|
| 160 |
+
|
| 161 |
+
@pytest.fixture(autouse=True)
|
| 162 |
+
def setup_class(self, tmp_path_factory):
|
| 163 |
+
file = tmp_path_factory.mktemp("runtime_test_script")
|
| 164 |
+
file /= "_runtime_detect.py"
|
| 165 |
+
file.write_text(self.SCRIPT)
|
| 166 |
+
self.file = file
|
| 167 |
+
|
| 168 |
+
def _run(self):
|
| 169 |
+
return subprocess.run(
|
| 170 |
+
[sys.executable, self.file],
|
| 171 |
+
env=self.env,
|
| 172 |
+
**self.SUBPROCESS_ARGS,
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
# Helper function mimicking pytest.raises for subprocess call
|
| 176 |
+
def _expect_error(
|
| 177 |
+
self,
|
| 178 |
+
msg,
|
| 179 |
+
err_type,
|
| 180 |
+
no_error_msg="Failed to generate error"
|
| 181 |
+
):
|
| 182 |
+
try:
|
| 183 |
+
self._run()
|
| 184 |
+
except subprocess.CalledProcessError as e:
|
| 185 |
+
assertion_message = f"Expected: {msg}\nGot: {e.stderr}"
|
| 186 |
+
assert re.search(msg, e.stderr), assertion_message
|
| 187 |
+
|
| 188 |
+
assertion_message = (
|
| 189 |
+
f"Expected error of type: {err_type}; see full "
|
| 190 |
+
f"error:\n{e.stderr}"
|
| 191 |
+
)
|
| 192 |
+
assert re.search(err_type, e.stderr), assertion_message
|
| 193 |
+
else:
|
| 194 |
+
assert False, no_error_msg
|
| 195 |
+
|
| 196 |
+
def setup_method(self):
|
| 197 |
+
"""Ensure that the environment is reset"""
|
| 198 |
+
self.env = os.environ.copy()
|
| 199 |
+
|
| 200 |
+
def test_runtime_feature_selection(self):
|
| 201 |
+
"""
|
| 202 |
+
Ensure that when selecting `NPY_ENABLE_CPU_FEATURES`, only the
|
| 203 |
+
features exactly specified are dispatched.
|
| 204 |
+
"""
|
| 205 |
+
|
| 206 |
+
# Capture runtime-enabled features
|
| 207 |
+
out = self._run()
|
| 208 |
+
non_baseline_features = _text_to_list(out.stdout)
|
| 209 |
+
|
| 210 |
+
if non_baseline_features is None:
|
| 211 |
+
pytest.skip(
|
| 212 |
+
"No dispatchable features outside of baseline detected."
|
| 213 |
+
)
|
| 214 |
+
feature = non_baseline_features[0]
|
| 215 |
+
|
| 216 |
+
# Capture runtime-enabled features when `NPY_ENABLE_CPU_FEATURES` is
|
| 217 |
+
# specified
|
| 218 |
+
self.env['NPY_ENABLE_CPU_FEATURES'] = feature
|
| 219 |
+
out = self._run()
|
| 220 |
+
enabled_features = _text_to_list(out.stdout)
|
| 221 |
+
|
| 222 |
+
# Ensure that only one feature is enabled, and it is exactly the one
|
| 223 |
+
# specified by `NPY_ENABLE_CPU_FEATURES`
|
| 224 |
+
assert set(enabled_features) == {feature}
|
| 225 |
+
|
| 226 |
+
if len(non_baseline_features) < 2:
|
| 227 |
+
pytest.skip("Only one non-baseline feature detected.")
|
| 228 |
+
# Capture runtime-enabled features when `NPY_ENABLE_CPU_FEATURES` is
|
| 229 |
+
# specified
|
| 230 |
+
self.env['NPY_ENABLE_CPU_FEATURES'] = ",".join(non_baseline_features)
|
| 231 |
+
out = self._run()
|
| 232 |
+
enabled_features = _text_to_list(out.stdout)
|
| 233 |
+
|
| 234 |
+
# Ensure that both features are enabled, and they are exactly the ones
|
| 235 |
+
# specified by `NPY_ENABLE_CPU_FEATURES`
|
| 236 |
+
assert set(enabled_features) == set(non_baseline_features)
|
| 237 |
+
|
| 238 |
+
@pytest.mark.parametrize("enabled, disabled",
|
| 239 |
+
[
|
| 240 |
+
("feature", "feature"),
|
| 241 |
+
("feature", "same"),
|
| 242 |
+
])
|
| 243 |
+
def test_both_enable_disable_set(self, enabled, disabled):
|
| 244 |
+
"""
|
| 245 |
+
Ensure that when both environment variables are set then an
|
| 246 |
+
ImportError is thrown
|
| 247 |
+
"""
|
| 248 |
+
self.env['NPY_ENABLE_CPU_FEATURES'] = enabled
|
| 249 |
+
self.env['NPY_DISABLE_CPU_FEATURES'] = disabled
|
| 250 |
+
msg = "Both NPY_DISABLE_CPU_FEATURES and NPY_ENABLE_CPU_FEATURES"
|
| 251 |
+
err_type = "ImportError"
|
| 252 |
+
self._expect_error(msg, err_type)
|
| 253 |
+
|
| 254 |
+
@pytest.mark.skipif(
|
| 255 |
+
not __cpu_dispatch__,
|
| 256 |
+
reason=(
|
| 257 |
+
"NPY_*_CPU_FEATURES only parsed if "
|
| 258 |
+
"`__cpu_dispatch__` is non-empty"
|
| 259 |
+
)
|
| 260 |
+
)
|
| 261 |
+
@pytest.mark.parametrize("action", ["ENABLE", "DISABLE"])
|
| 262 |
+
def test_variable_too_long(self, action):
|
| 263 |
+
"""
|
| 264 |
+
Test that an error is thrown if the environment variables are too long
|
| 265 |
+
to be processed. Current limit is 1024, but this may change later.
|
| 266 |
+
"""
|
| 267 |
+
MAX_VAR_LENGTH = 1024
|
| 268 |
+
# Actual length is MAX_VAR_LENGTH + 1 due to null-termination
|
| 269 |
+
self.env[f'NPY_{action}_CPU_FEATURES'] = "t" * MAX_VAR_LENGTH
|
| 270 |
+
msg = (
|
| 271 |
+
f"Length of environment variable 'NPY_{action}_CPU_FEATURES' is "
|
| 272 |
+
f"{MAX_VAR_LENGTH + 1}, only {MAX_VAR_LENGTH} accepted"
|
| 273 |
+
)
|
| 274 |
+
err_type = "RuntimeError"
|
| 275 |
+
self._expect_error(msg, err_type)
|
| 276 |
+
|
| 277 |
+
@pytest.mark.skipif(
|
| 278 |
+
not __cpu_dispatch__,
|
| 279 |
+
reason=(
|
| 280 |
+
"NPY_*_CPU_FEATURES only parsed if "
|
| 281 |
+
"`__cpu_dispatch__` is non-empty"
|
| 282 |
+
)
|
| 283 |
+
)
|
| 284 |
+
@pytest.mark.parametrize("action", ["ENABLE", "DISABLE"])
|
| 285 |
+
def test_max_length_nonexistent_feature(self, action):
|
| 286 |
+
"""
|
| 287 |
+
Test that the maximum accepted environment variable length can be
|
| 288 |
+
processed even if the whole value is an invalid feature name.
|
| 289 |
+
"""
|
| 290 |
+
MAX_VAR_LENGTH = 1024
|
| 291 |
+
self.env[f'NPY_{action}_CPU_FEATURES'] = "t" * (MAX_VAR_LENGTH - 1)
|
| 292 |
+
self._run()
|
| 293 |
+
|
| 294 |
+
@pytest.mark.skipif(
|
| 295 |
+
not __cpu_dispatch__,
|
| 296 |
+
reason=(
|
| 297 |
+
"NPY_*_CPU_FEATURES only parsed if "
|
| 298 |
+
"`__cpu_dispatch__` is non-empty"
|
| 299 |
+
)
|
| 300 |
+
)
|
| 301 |
+
def test_impossible_feature_disable(self):
|
| 302 |
+
"""
|
| 303 |
+
Test that a RuntimeError is thrown if an impossible feature-disabling
|
| 304 |
+
request is made. This includes disabling a baseline feature.
|
| 305 |
+
"""
|
| 306 |
+
|
| 307 |
+
if self.BASELINE_FEAT is None:
|
| 308 |
+
pytest.skip("There are no unavailable features to test with")
|
| 309 |
+
bad_feature = self.BASELINE_FEAT
|
| 310 |
+
self.env['NPY_DISABLE_CPU_FEATURES'] = bad_feature
|
| 311 |
+
msg = (
|
| 312 |
+
f"You cannot disable CPU feature '{bad_feature}', since it is "
|
| 313 |
+
"part of the baseline optimizations"
|
| 314 |
+
)
|
| 315 |
+
err_type = "RuntimeError"
|
| 316 |
+
self._expect_error(msg, err_type)
|
| 317 |
+
|
| 318 |
+
def test_impossible_feature_enable(self):
|
| 319 |
+
"""
|
| 320 |
+
Test that a RuntimeError is thrown if an impossible feature-enabling
|
| 321 |
+
request is made. This includes enabling a feature not supported by the
|
| 322 |
+
machine, or disabling a baseline optimization.
|
| 323 |
+
"""
|
| 324 |
+
|
| 325 |
+
if self.UNAVAILABLE_FEAT is None:
|
| 326 |
+
pytest.skip("There are no unavailable features to test with")
|
| 327 |
+
bad_feature = self.UNAVAILABLE_FEAT
|
| 328 |
+
self.env['NPY_ENABLE_CPU_FEATURES'] = bad_feature
|
| 329 |
+
msg = (
|
| 330 |
+
f"You cannot enable CPU features \\({bad_feature}\\), since "
|
| 331 |
+
"they are not supported by your machine."
|
| 332 |
+
)
|
| 333 |
+
err_type = "RuntimeError"
|
| 334 |
+
self._expect_error(msg, err_type)
|
| 335 |
+
|
| 336 |
+
# Ensure that it fails even when providing garbage in addition
|
| 337 |
+
feats = f"{bad_feature}, Foobar"
|
| 338 |
+
self.env['NPY_ENABLE_CPU_FEATURES'] = feats
|
| 339 |
+
msg = (
|
| 340 |
+
f"You cannot enable CPU features \\({bad_feature}\\), since they "
|
| 341 |
+
"are not supported by your machine."
|
| 342 |
+
)
|
| 343 |
+
self._expect_error(msg, err_type)
|
| 344 |
+
|
| 345 |
+
if self.BASELINE_FEAT is not None:
|
| 346 |
+
# Ensure that only the bad feature gets reported
|
| 347 |
+
feats = f"{bad_feature}, {self.BASELINE_FEAT}"
|
| 348 |
+
self.env['NPY_ENABLE_CPU_FEATURES'] = feats
|
| 349 |
+
msg = (
|
| 350 |
+
f"You cannot enable CPU features \\({bad_feature}\\), since "
|
| 351 |
+
"they are not supported by your machine."
|
| 352 |
+
)
|
| 353 |
+
self._expect_error(msg, err_type)
|
| 354 |
+
|
| 355 |
+
@pytest.mark.parametrize("action", ["ENABLE", "DISABLE"])
|
| 356 |
+
def test_repeated_unavailable_feature(self, action):
|
| 357 |
+
"""
|
| 358 |
+
Test that repeated unavailable features can be processed without
|
| 359 |
+
overflowing the diagnostic buffer.
|
| 360 |
+
"""
|
| 361 |
+
if self.UNAVAILABLE_FEAT is None:
|
| 362 |
+
pytest.skip("There are no unavailable features to test with")
|
| 363 |
+
|
| 364 |
+
bad_feature = self.UNAVAILABLE_FEAT
|
| 365 |
+
feature_repeats = 1024 // (len(bad_feature) + 1)
|
| 366 |
+
self.env[f'NPY_{action}_CPU_FEATURES'] = ",".join(
|
| 367 |
+
[bad_feature] * feature_repeats
|
| 368 |
+
)
|
| 369 |
+
|
| 370 |
+
if action == "ENABLE":
|
| 371 |
+
msg = "You cannot enable CPU features"
|
| 372 |
+
err_type = "RuntimeError"
|
| 373 |
+
self._expect_error(msg, err_type)
|
| 374 |
+
else:
|
| 375 |
+
self._run()
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
is_linux = sys.platform.startswith('linux')
|
| 379 |
+
is_cygwin = sys.platform.startswith('cygwin')
|
| 380 |
+
machine = platform.machine()
|
| 381 |
+
is_x86 = re.match(r"^(amd64|x86|i386|i686)", machine, re.IGNORECASE)
|
| 382 |
+
@pytest.mark.skipif(
|
| 383 |
+
not (is_linux or is_cygwin) or not is_x86,
|
| 384 |
+
reason="Only for Linux and x86",
|
| 385 |
+
)
|
| 386 |
+
class Test_X86_Features(AbstractTest):
|
| 387 |
+
features = []
|
| 388 |
+
|
| 389 |
+
features_groups = {
|
| 390 |
+
"X86_V2": [
|
| 391 |
+
"SSE", "SSE2", "SSE3", "SSSE3", "SSE41", "SSE42",
|
| 392 |
+
"POPCNT", "LAHF", "CX16"
|
| 393 |
+
],
|
| 394 |
+
}
|
| 395 |
+
features_groups["X86_V3"] = features_groups["X86_V2"] + [
|
| 396 |
+
"AVX", "AVX2", "FMA3", "BMI", "BMI2",
|
| 397 |
+
"LZCNT", "F16C", "MOVBE"
|
| 398 |
+
]
|
| 399 |
+
features_groups["X86_V4"] = features_groups["X86_V3"] + [
|
| 400 |
+
"AVX512F", "AVX512CD", "AVX512BW", "AVX512DQ", "AVX512VL"
|
| 401 |
+
]
|
| 402 |
+
features_groups["AVX512_ICL"] = features_groups["X86_V4"] + [
|
| 403 |
+
"AVX512IFMA", "AVX512VBMI", "AVX512VNNI",
|
| 404 |
+
"AVX512VBMI2", "AVX512BITALG", "AVX512VPOPCNTDQ",
|
| 405 |
+
"VAES", "VPCLMULQDQ", "GFNI"
|
| 406 |
+
]
|
| 407 |
+
features_groups["AVX512_SPR"] = (
|
| 408 |
+
features_groups["AVX512_ICL"] + ["AVX512FP16", "AVX512BF16"]
|
| 409 |
+
)
|
| 410 |
+
|
| 411 |
+
features_map = {
|
| 412 |
+
"SSE3": "PNI", "SSE41": "SSE4_1", "SSE42": "SSE4_2", "FMA3": "FMA",
|
| 413 |
+
"BMI": "BMI1", "LZCNT": "ABM", "LAHF": "LAHF_LM",
|
| 414 |
+
"AVX512VNNI": "AVX512_VNNI", "AVX512BITALG": "AVX512_BITALG",
|
| 415 |
+
"AVX512VBMI2": "AVX512_VBMI2", "AVX5124FMAPS": "AVX512_4FMAPS",
|
| 416 |
+
"AVX5124VNNIW": "AVX512_4VNNIW", "AVX512VPOPCNTDQ": "AVX512_VPOPCNTDQ",
|
| 417 |
+
"AVX512FP16": "AVX512_FP16", "AVX512BF16": "AVX512_BF16"
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
def load_flags(self):
|
| 421 |
+
self.load_flags_cpuinfo("flags")
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
is_power = re.match(r"^(powerpc|ppc)64", machine, re.IGNORECASE)
|
| 425 |
+
@pytest.mark.skipif(not is_linux or not is_power, reason="Only for Linux and Power")
|
| 426 |
+
class Test_POWER_Features(AbstractTest):
|
| 427 |
+
features = ["VSX", "VSX2", "VSX3", "VSX4"]
|
| 428 |
+
features_map = {
|
| 429 |
+
"VSX": "ARCH_2_06",
|
| 430 |
+
"VSX2": "ARCH_2_07",
|
| 431 |
+
"VSX3": "ARCH_3_00",
|
| 432 |
+
"VSX4": "ARCH_3_1B"
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
def load_flags(self):
|
| 436 |
+
self.load_flags_auxv()
|
| 437 |
+
platform = self._get_platform()
|
| 438 |
+
|
| 439 |
+
if platform:
|
| 440 |
+
power_match = re.search(r'power(\d+)', platform, re.IGNORECASE)
|
| 441 |
+
if power_match:
|
| 442 |
+
power_gen = int(power_match.group(1))
|
| 443 |
+
if power_gen >= 7:
|
| 444 |
+
self.features_flags.add("ARCH_2_06")
|
| 445 |
+
if power_gen >= 8:
|
| 446 |
+
self.features_flags.add("ARCH_2_07")
|
| 447 |
+
if power_gen >= 9:
|
| 448 |
+
self.features_flags.add("ARCH_3_00")
|
| 449 |
+
if power_gen >= 10:
|
| 450 |
+
self.features_flags.add("ARCH_3_1B")
|
| 451 |
+
|
| 452 |
+
def _get_platform(self):
|
| 453 |
+
"""Get the AT_PLATFORM value from AUXV"""
|
| 454 |
+
try:
|
| 455 |
+
auxv = subprocess.check_output(['/bin/true'], env={"LD_SHOW_AUXV": "1"})
|
| 456 |
+
for line in auxv.split(b'\n'):
|
| 457 |
+
if line.startswith(b'AT_PLATFORM'):
|
| 458 |
+
parts = line.split(b':', 1)
|
| 459 |
+
if len(parts) == 2:
|
| 460 |
+
return parts[1].strip().decode().lower()
|
| 461 |
+
except Exception:
|
| 462 |
+
pass
|
| 463 |
+
return None
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
is_zarch = re.match(r"^(s390x)", machine, re.IGNORECASE)
|
| 467 |
+
@pytest.mark.skipif(not is_linux or not is_zarch,
|
| 468 |
+
reason="Only for Linux and IBM Z")
|
| 469 |
+
class Test_ZARCH_Features(AbstractTest):
|
| 470 |
+
features = ["VX", "VXE", "VXE2"]
|
| 471 |
+
|
| 472 |
+
def load_flags(self):
|
| 473 |
+
self.load_flags_cpuinfo("features")
|
| 474 |
+
|
| 475 |
+
|
| 476 |
+
is_arm = re.match(r"^(arm|aarch64)", machine, re.IGNORECASE)
|
| 477 |
+
@pytest.mark.skipif(not is_linux or not is_arm, reason="Only for Linux and ARM")
|
| 478 |
+
class Test_ARM_Features(AbstractTest):
|
| 479 |
+
features = [
|
| 480 |
+
"SVE", "NEON", "ASIMD", "FPHP", "ASIMDHP", "ASIMDDP", "ASIMDFHM"
|
| 481 |
+
]
|
| 482 |
+
features_groups = {
|
| 483 |
+
"NEON_FP16": ["NEON", "HALF"],
|
| 484 |
+
"NEON_VFPV4": ["NEON", "VFPV4"],
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
def load_flags(self):
|
| 488 |
+
self.load_flags_cpuinfo("Features")
|
| 489 |
+
arch = self.get_cpuinfo_item("CPU architecture")
|
| 490 |
+
# in case of mounting virtual filesystem of aarch64 kernel without linux32
|
| 491 |
+
is_rootfs_v8 = (
|
| 492 |
+
not re.match(r"^armv[0-9]+l$", machine) and
|
| 493 |
+
(int('0' + next(iter(arch))) > 7 if arch else 0)
|
| 494 |
+
)
|
| 495 |
+
if re.match(r"^(aarch64|AARCH64)", machine) or is_rootfs_v8:
|
| 496 |
+
self.features_map = {
|
| 497 |
+
"NEON": "ASIMD", "HALF": "ASIMD", "VFPV4": "ASIMD"
|
| 498 |
+
}
|
| 499 |
+
else:
|
| 500 |
+
self.features_map = {
|
| 501 |
+
# ELF auxiliary vector and /proc/cpuinfo on Linux kernel(armv8 aarch32)
|
| 502 |
+
# doesn't provide information about ASIMD
|
| 503 |
+
# so we assume that ASIMD is supported
|
| 504 |
+
# if the kernel reports any one of the following ARM8 features.
|
| 505 |
+
"ASIMD": ("AES", "SHA1", "SHA2", "PMULL", "CRC32")
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
|
| 509 |
+
is_loongarch = re.match(r"^(loongarch)", machine, re.IGNORECASE)
|
| 510 |
+
@pytest.mark.skipif(
|
| 511 |
+
not is_linux or not is_loongarch,
|
| 512 |
+
reason="Only for Linux and LoongArch",
|
| 513 |
+
)
|
| 514 |
+
class Test_LOONGARCH_Features(AbstractTest):
|
| 515 |
+
features = ["LSX"]
|
| 516 |
+
|
| 517 |
+
def load_flags(self):
|
| 518 |
+
self.load_flags_cpuinfo("Features")
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
is_riscv = re.match(r"^(riscv)", machine, re.IGNORECASE)
|
| 522 |
+
@pytest.mark.skipif(not is_linux or not is_riscv, reason="Only for Linux and RISC-V")
|
| 523 |
+
class Test_RISCV_Features(AbstractTest):
|
| 524 |
+
features = ["RVV"]
|
| 525 |
+
|
| 526 |
+
def load_flags(self):
|
| 527 |
+
self.load_flags_auxv()
|
| 528 |
+
if not self.features_flags:
|
| 529 |
+
# Let the test fail and dump if we cannot read HWCAP.
|
| 530 |
+
return
|
| 531 |
+
hwcap = int(next(iter(self.features_flags)), 16)
|
| 532 |
+
if hwcap & (1 << 21): # HWCAP_RISCV_V
|
| 533 |
+
self.features_flags.add("RVV")
|
v12x/pylib/numpy/_core/tests/test_custom_dtypes.py
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tempfile import NamedTemporaryFile
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
from numpy._core._multiarray_umath import (
|
| 7 |
+
_discover_array_parameters as discover_array_params,
|
| 8 |
+
_get_sfloat_dtype,
|
| 9 |
+
)
|
| 10 |
+
from numpy.testing import assert_array_equal
|
| 11 |
+
|
| 12 |
+
SF = _get_sfloat_dtype()
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class TestSFloat:
|
| 16 |
+
def _get_array(self, scaling, aligned=True):
|
| 17 |
+
if not aligned:
|
| 18 |
+
a = np.empty(3 * 8 + 1, dtype=np.uint8)[1:]
|
| 19 |
+
a = a.view(np.float64)
|
| 20 |
+
a[:] = [1., 2., 3.]
|
| 21 |
+
else:
|
| 22 |
+
a = np.array([1., 2., 3.])
|
| 23 |
+
|
| 24 |
+
a *= 1. / scaling # the casting code also uses the reciprocal.
|
| 25 |
+
return a.view(SF(scaling))
|
| 26 |
+
|
| 27 |
+
def test_sfloat_rescaled(self):
|
| 28 |
+
sf = SF(1.)
|
| 29 |
+
sf2 = sf.scaled_by(2.)
|
| 30 |
+
assert sf2.get_scaling() == 2.
|
| 31 |
+
sf6 = sf2.scaled_by(3.)
|
| 32 |
+
assert sf6.get_scaling() == 6.
|
| 33 |
+
|
| 34 |
+
def test_class_discovery(self):
|
| 35 |
+
# This does not test much, since we always discover the scaling as 1.
|
| 36 |
+
# But most of NumPy (when writing) does not understand DType classes
|
| 37 |
+
dt, _ = discover_array_params([1., 2., 3.], dtype=SF)
|
| 38 |
+
assert dt == SF(1.)
|
| 39 |
+
|
| 40 |
+
@pytest.mark.parametrize("scaling", [1., -1., 2.])
|
| 41 |
+
def test_scaled_float_from_floats(self, scaling):
|
| 42 |
+
a = np.array([1., 2., 3.], dtype=SF(scaling))
|
| 43 |
+
|
| 44 |
+
assert a.dtype.get_scaling() == scaling
|
| 45 |
+
assert_array_equal(scaling * a.view(np.float64), [1., 2., 3.])
|
| 46 |
+
|
| 47 |
+
def test_structured_field_byteswap_raises(self):
|
| 48 |
+
# a field (or subarray field) whose dtype lacks the legacy copyswap
|
| 49 |
+
# slot cannot be byteswapped; previously this segfaulted via the
|
| 50 |
+
# unguarded field copyswap calls in VOID_copyswapn
|
| 51 |
+
arr = np.zeros(2, dtype=[("a", "i4"), ("v", SF(1.))])
|
| 52 |
+
with pytest.raises(TypeError, match="does not implement copyswap"):
|
| 53 |
+
arr.byteswap()
|
| 54 |
+
|
| 55 |
+
subarr = np.zeros(2, dtype=[("v", SF(1.), (2,))])
|
| 56 |
+
with pytest.raises(TypeError, match="does not implement copyswap"):
|
| 57 |
+
subarr.byteswap()
|
| 58 |
+
|
| 59 |
+
def test_byteswap_raises(self):
|
| 60 |
+
# a top-level DType without the legacy copyswap slot does not
|
| 61 |
+
# support byteswapping
|
| 62 |
+
arr = np.zeros(2, dtype=SF(1.))
|
| 63 |
+
with pytest.raises(TypeError, match="does not implement copyswap"):
|
| 64 |
+
arr.byteswap()
|
| 65 |
+
|
| 66 |
+
# the in-place writeability check fires before the missing-slot
|
| 67 |
+
# check, matching the behavior for dtypes that fill the slot
|
| 68 |
+
arr.flags.writeable = False
|
| 69 |
+
with pytest.raises(ValueError, match="array to be byte-swapped"):
|
| 70 |
+
arr.byteswap(inplace=True)
|
| 71 |
+
|
| 72 |
+
def test_structured_field_place_and_flat_raise(self):
|
| 73 |
+
# requests that need to copy through the missing legacy copyswap
|
| 74 |
+
# slot raise instead of crashing
|
| 75 |
+
arr = np.zeros(2, dtype=[("v", SF(1.))])
|
| 76 |
+
with pytest.raises(TypeError, match="does not implement copyswap"):
|
| 77 |
+
np.place(arr, [True, False], arr[:1])
|
| 78 |
+
with pytest.raises(TypeError, match="does not implement copyswap"):
|
| 79 |
+
arr.flat = arr[:1]
|
| 80 |
+
|
| 81 |
+
# both stop copying as soon as the error is detected, so elements
|
| 82 |
+
# after the first (failing) one keep their values, even for fields
|
| 83 |
+
# that could have been copied
|
| 84 |
+
marr = np.zeros(3, dtype=[("a", "i4"), ("v", SF(1.))])
|
| 85 |
+
marr["a"] = [5, 6, 7]
|
| 86 |
+
src = marr[:1].copy()
|
| 87 |
+
src["a"] = 1
|
| 88 |
+
with pytest.raises(TypeError, match="does not implement copyswap"):
|
| 89 |
+
marr.flat = src
|
| 90 |
+
assert marr["a"].tolist()[1:] == [6, 7]
|
| 91 |
+
with pytest.raises(TypeError, match="does not implement copyswap"):
|
| 92 |
+
np.place(marr, [True, True, True], src)
|
| 93 |
+
assert marr["a"].tolist()[1:] == [6, 7]
|
| 94 |
+
|
| 95 |
+
def test_structured_field_sort_raises(self):
|
| 96 |
+
# VOID_compare called the field's legacy compare slot, which
|
| 97 |
+
# new-style DTypes do not fill
|
| 98 |
+
arr = np.zeros(3, dtype=[("v", SF(1.))])
|
| 99 |
+
with pytest.raises(TypeError, match="does not support comparison"):
|
| 100 |
+
np.sort(arr, order="v")
|
| 101 |
+
|
| 102 |
+
# packed fields are misaligned; the compare == NULL check fires
|
| 103 |
+
# before VOID_compare's alignment handling, so this exits through
|
| 104 |
+
# the same guard as the aligned case above and never reaches the
|
| 105 |
+
# misaligned buffer path (which would call the missing copyswap
|
| 106 |
+
# slot); it checks that the guard keeps covering that layout
|
| 107 |
+
packed_dt = np.dtype({"names": ["a", "v"],
|
| 108 |
+
"formats": ["u1", SF(1.)],
|
| 109 |
+
"offsets": [0, 1], "itemsize": 17})
|
| 110 |
+
with pytest.raises(TypeError, match="does not support comparison"):
|
| 111 |
+
np.sort(np.zeros(3, dtype=packed_dt), order="v")
|
| 112 |
+
|
| 113 |
+
def test_structured_setitem_uses_cast_path(self):
|
| 114 |
+
# scalar assignment between equivalent structured dtypes used to
|
| 115 |
+
# segfault in the copyswap fast path; it now falls back to casting
|
| 116 |
+
arr = np.zeros(2, dtype=[("v", SF(1.))])
|
| 117 |
+
arr["v"] = np.array([1., 2.]).view(SF(1.))
|
| 118 |
+
arr[0] = arr[1]
|
| 119 |
+
assert arr["v"].view(np.float64).tolist() == [2., 2.]
|
| 120 |
+
|
| 121 |
+
def test_structured_setitem_nested_uses_cast_path(self):
|
| 122 |
+
# for a nested field the copyswap slot is VOID_copyswap, which
|
| 123 |
+
# fails on the inner sfloat field only after it is called; the
|
| 124 |
+
# error must not leak out of a successful-looking assignment and
|
| 125 |
+
# the copy falls back to the casting path like the flat case
|
| 126 |
+
arr = np.zeros(2, dtype=[("a", "i4"), ("nested", [("v", SF(1.))])])
|
| 127 |
+
arr["a"] = [1, 2]
|
| 128 |
+
arr["nested"]["v"] = np.array([1., 2.]).view(SF(1.))
|
| 129 |
+
arr[0] = arr[1]
|
| 130 |
+
assert arr["a"].tolist() == [2, 2]
|
| 131 |
+
assert arr["nested"]["v"].view(np.float64).tolist() == [2., 2.]
|
| 132 |
+
|
| 133 |
+
# same for a subarray field of an sfloat dtype
|
| 134 |
+
arr = np.zeros(2, dtype=[("sub", SF(1.), (2,))])
|
| 135 |
+
arr["sub"] = np.array([[1., 2.], [3., 4.]]).view(SF(1.))
|
| 136 |
+
arr[0] = arr[1]
|
| 137 |
+
assert arr["sub"].view(np.float64).tolist() == [[3., 4.], [3., 4.]]
|
| 138 |
+
|
| 139 |
+
def test_repr(self):
|
| 140 |
+
# Check the repr, mainly to cover the code paths:
|
| 141 |
+
assert repr(SF(scaling=1.)) == "_ScaledFloatTestDType(scaling=1.0)"
|
| 142 |
+
|
| 143 |
+
def test_dtype_str(self):
|
| 144 |
+
assert SF(1.).str == "_ScaledFloatTestDType(scaling=1.0)"
|
| 145 |
+
|
| 146 |
+
def test_dtype_name(self):
|
| 147 |
+
assert SF(1.).name == "_ScaledFloatTestDType64"
|
| 148 |
+
|
| 149 |
+
def test_sfloat_structured_dtype_printing(self):
|
| 150 |
+
dt = np.dtype([("id", int), ("value", SF(0.5))])
|
| 151 |
+
# repr of structured dtypes need special handling because the
|
| 152 |
+
# implementation bypasses the object repr
|
| 153 |
+
assert "('value', '_ScaledFloatTestDType64')" in repr(dt)
|
| 154 |
+
|
| 155 |
+
@pytest.mark.parametrize("scaling", [1., -1., 2.])
|
| 156 |
+
def test_sfloat_from_float(self, scaling):
|
| 157 |
+
a = np.array([1., 2., 3.]).astype(dtype=SF(scaling))
|
| 158 |
+
|
| 159 |
+
assert a.dtype.get_scaling() == scaling
|
| 160 |
+
assert_array_equal(scaling * a.view(np.float64), [1., 2., 3.])
|
| 161 |
+
|
| 162 |
+
@pytest.mark.parametrize("aligned", [True, False])
|
| 163 |
+
@pytest.mark.parametrize("scaling", [1., -1., 2.])
|
| 164 |
+
def test_sfloat_getitem(self, aligned, scaling):
|
| 165 |
+
a = self._get_array(1., aligned)
|
| 166 |
+
assert a.tolist() == [1., 2., 3.]
|
| 167 |
+
|
| 168 |
+
@pytest.mark.parametrize("aligned", [True, False])
|
| 169 |
+
def test_sfloat_casts(self, aligned):
|
| 170 |
+
a = self._get_array(1., aligned)
|
| 171 |
+
|
| 172 |
+
assert np.can_cast(a, SF(-1.), casting="equiv")
|
| 173 |
+
assert not np.can_cast(a, SF(-1.), casting="no")
|
| 174 |
+
na = a.astype(SF(-1.))
|
| 175 |
+
assert_array_equal(-1 * na.view(np.float64), a.view(np.float64))
|
| 176 |
+
|
| 177 |
+
assert np.can_cast(a, SF(2.), casting="same_kind")
|
| 178 |
+
assert not np.can_cast(a, SF(2.), casting="safe")
|
| 179 |
+
a2 = a.astype(SF(2.))
|
| 180 |
+
assert_array_equal(2 * a2.view(np.float64), a.view(np.float64))
|
| 181 |
+
|
| 182 |
+
@pytest.mark.parametrize("aligned", [True, False])
|
| 183 |
+
def test_sfloat_cast_internal_errors(self, aligned):
|
| 184 |
+
a = self._get_array(2e300, aligned)
|
| 185 |
+
|
| 186 |
+
with pytest.raises(TypeError,
|
| 187 |
+
match="error raised inside the core-loop: non-finite factor!"):
|
| 188 |
+
a.astype(SF(2e-300))
|
| 189 |
+
|
| 190 |
+
def test_sfloat_promotion(self):
|
| 191 |
+
assert np.result_type(SF(2.), SF(3.)) == SF(3.)
|
| 192 |
+
assert np.result_type(SF(3.), SF(2.)) == SF(3.)
|
| 193 |
+
# Float64 -> SF(1.) and then promotes normally, so both of this work:
|
| 194 |
+
assert np.result_type(SF(3.), np.float64) == SF(3.)
|
| 195 |
+
assert np.result_type(np.float64, SF(0.5)) == SF(1.)
|
| 196 |
+
|
| 197 |
+
# Test an undefined promotion:
|
| 198 |
+
with pytest.raises(TypeError):
|
| 199 |
+
np.result_type(SF(1.), np.int64)
|
| 200 |
+
|
| 201 |
+
def test_basic_multiply(self):
|
| 202 |
+
a = self._get_array(2.)
|
| 203 |
+
b = self._get_array(4.)
|
| 204 |
+
|
| 205 |
+
res = a * b
|
| 206 |
+
# multiplies dtype scaling and content separately:
|
| 207 |
+
assert res.dtype.get_scaling() == 8.
|
| 208 |
+
expected_view = a.view(np.float64) * b.view(np.float64)
|
| 209 |
+
assert_array_equal(res.view(np.float64), expected_view)
|
| 210 |
+
|
| 211 |
+
def test_possible_and_impossible_reduce(self):
|
| 212 |
+
# For reductions to work, the first and last operand must have the
|
| 213 |
+
# same dtype. For this parametric DType that is not necessarily true.
|
| 214 |
+
a = self._get_array(2.)
|
| 215 |
+
# Addition reduction works (as of writing requires to pass initial
|
| 216 |
+
# because setting a scaled-float from the default `0` fails).
|
| 217 |
+
res = np.add.reduce(a, initial=0.)
|
| 218 |
+
assert res == a.astype(np.float64).sum()
|
| 219 |
+
|
| 220 |
+
# But each multiplication changes the factor, so a reduction is not
|
| 221 |
+
# possible (the relaxed version of the old refusal to handle any
|
| 222 |
+
# flexible dtype).
|
| 223 |
+
with pytest.raises(TypeError,
|
| 224 |
+
match="the resolved dtypes are not compatible"):
|
| 225 |
+
np.multiply.reduce(a)
|
| 226 |
+
|
| 227 |
+
def test_basic_ufunc_at(self):
|
| 228 |
+
float_a = np.array([1., 2., 3.])
|
| 229 |
+
b = self._get_array(2.)
|
| 230 |
+
|
| 231 |
+
float_b = b.view(np.float64).copy()
|
| 232 |
+
np.multiply.at(float_b, [1, 1, 1], float_a)
|
| 233 |
+
np.multiply.at(b, [1, 1, 1], float_a)
|
| 234 |
+
|
| 235 |
+
assert_array_equal(b.view(np.float64), float_b)
|
| 236 |
+
|
| 237 |
+
def test_basic_multiply_promotion(self):
|
| 238 |
+
float_a = np.array([1., 2., 3.])
|
| 239 |
+
b = self._get_array(2.)
|
| 240 |
+
|
| 241 |
+
res1 = float_a * b
|
| 242 |
+
res2 = b * float_a
|
| 243 |
+
|
| 244 |
+
# one factor is one, so we get the factor of b:
|
| 245 |
+
assert res1.dtype == res2.dtype == b.dtype
|
| 246 |
+
expected_view = float_a * b.view(np.float64)
|
| 247 |
+
assert_array_equal(res1.view(np.float64), expected_view)
|
| 248 |
+
assert_array_equal(res2.view(np.float64), expected_view)
|
| 249 |
+
|
| 250 |
+
# Check that promotion works when `out` is used:
|
| 251 |
+
np.multiply(b, float_a, out=res2)
|
| 252 |
+
with pytest.raises(TypeError):
|
| 253 |
+
# The promoter accepts this (maybe it should not), but the SFloat
|
| 254 |
+
# result cannot be cast to integer:
|
| 255 |
+
np.multiply(b, float_a, out=np.arange(3))
|
| 256 |
+
|
| 257 |
+
def test_basic_addition(self):
|
| 258 |
+
a = self._get_array(2.)
|
| 259 |
+
b = self._get_array(4.)
|
| 260 |
+
|
| 261 |
+
res = a + b
|
| 262 |
+
# addition uses the type promotion rules for the result:
|
| 263 |
+
assert res.dtype == np.result_type(a.dtype, b.dtype)
|
| 264 |
+
expected_view = (a.astype(res.dtype).view(np.float64) +
|
| 265 |
+
b.astype(res.dtype).view(np.float64))
|
| 266 |
+
assert_array_equal(res.view(np.float64), expected_view)
|
| 267 |
+
|
| 268 |
+
def test_addition_cast_safety(self):
|
| 269 |
+
"""The addition method is special for the scaled float, because it
|
| 270 |
+
includes the "cast" between different factors, thus cast-safety
|
| 271 |
+
is influenced by the implementation.
|
| 272 |
+
"""
|
| 273 |
+
a = self._get_array(2.)
|
| 274 |
+
b = self._get_array(-2.)
|
| 275 |
+
c = self._get_array(3.)
|
| 276 |
+
|
| 277 |
+
# sign change is "equiv":
|
| 278 |
+
np.add(a, b, casting="equiv")
|
| 279 |
+
with pytest.raises(TypeError):
|
| 280 |
+
np.add(a, b, casting="no")
|
| 281 |
+
|
| 282 |
+
# Different factor is "same_kind" (default) so check that "safe" fails
|
| 283 |
+
with pytest.raises(TypeError):
|
| 284 |
+
np.add(a, c, casting="safe")
|
| 285 |
+
|
| 286 |
+
# Check that casting the output fails also (done by the ufunc here)
|
| 287 |
+
with pytest.raises(TypeError):
|
| 288 |
+
np.add(a, a, out=c, casting="safe")
|
| 289 |
+
|
| 290 |
+
def test_sfloat_histogram_passes_dtype_class(self):
|
| 291 |
+
# Regression test for gh-31447.
|
| 292 |
+
#
|
| 293 |
+
# ``_unsigned_subtract`` used to forward a DType instance (from
|
| 294 |
+
# ``np.result_type``) to ``np.subtract``; the ufunc dispatcher
|
| 295 |
+
# rejects instances of non-legacy user DTypes.
|
| 296 |
+
#
|
| 297 |
+
# Expected behaviour:
|
| 298 |
+
# pre-fix: TypeError "Cannot pass a new user DType instance ..."
|
| 299 |
+
# post-fix: TypeError "ufunc 'subtract' did not contain a loop"
|
| 300 |
+
# (SF has no subtract loop; once the dispatcher
|
| 301 |
+
# accepts the DType class, the missing-loop error
|
| 302 |
+
# surfaces.)
|
| 303 |
+
from numpy.lib._histograms_impl import _unsigned_subtract
|
| 304 |
+
a = np.array([3.]).view(SF(1.))
|
| 305 |
+
b = np.array([1.]).view(SF(1.))
|
| 306 |
+
with pytest.raises(TypeError,
|
| 307 |
+
match="ufunc 'subtract' did not contain a loop"):
|
| 308 |
+
_unsigned_subtract(a, b)
|
| 309 |
+
|
| 310 |
+
@pytest.mark.parametrize("ufunc",
|
| 311 |
+
[np.logical_and, np.logical_or, np.logical_xor])
|
| 312 |
+
def test_logical_ufuncs_casts_to_bool(self, ufunc):
|
| 313 |
+
a = self._get_array(2.)
|
| 314 |
+
a[0] = 0. # make sure first element is considered False.
|
| 315 |
+
|
| 316 |
+
float_equiv = a.astype(float)
|
| 317 |
+
expected = ufunc(float_equiv, float_equiv)
|
| 318 |
+
res = ufunc(a, a)
|
| 319 |
+
assert_array_equal(res, expected)
|
| 320 |
+
|
| 321 |
+
# also check that the same works for reductions:
|
| 322 |
+
expected = ufunc.reduce(float_equiv)
|
| 323 |
+
res = ufunc.reduce(a)
|
| 324 |
+
assert_array_equal(res, expected)
|
| 325 |
+
|
| 326 |
+
# The output casting does not match the bool, bool -> bool loop:
|
| 327 |
+
with pytest.raises(TypeError):
|
| 328 |
+
ufunc(a, a, out=np.empty(a.shape, dtype=int), casting="equiv")
|
| 329 |
+
|
| 330 |
+
def test_wrapped_and_wrapped_reductions(self):
|
| 331 |
+
a = self._get_array(2.)
|
| 332 |
+
float_equiv = a.astype(float)
|
| 333 |
+
|
| 334 |
+
expected = np.hypot(float_equiv, float_equiv)
|
| 335 |
+
res = np.hypot(a, a)
|
| 336 |
+
assert res.dtype == a.dtype
|
| 337 |
+
res_float = res.view(np.float64) * 2
|
| 338 |
+
assert_array_equal(res_float, expected)
|
| 339 |
+
|
| 340 |
+
# Also check reduction (keepdims, due to incorrect getitem)
|
| 341 |
+
res = np.hypot.reduce(a, keepdims=True)
|
| 342 |
+
assert res.dtype == a.dtype
|
| 343 |
+
expected = np.hypot.reduce(float_equiv, keepdims=True)
|
| 344 |
+
assert res.view(np.float64) * 2 == expected
|
| 345 |
+
|
| 346 |
+
def test_sort(self):
|
| 347 |
+
a = self._get_array(1.)
|
| 348 |
+
a = a[::-1] # reverse it
|
| 349 |
+
|
| 350 |
+
a.sort()
|
| 351 |
+
assert_array_equal(a.view(np.float64), [1., 2., 3.])
|
| 352 |
+
|
| 353 |
+
a = self._get_array(1.)
|
| 354 |
+
a = a[::-1] # reverse it
|
| 355 |
+
|
| 356 |
+
sorted_a = np.sort(a)
|
| 357 |
+
assert_array_equal(sorted_a.view(np.float64), [1., 2., 3.])
|
| 358 |
+
# original is unchanged
|
| 359 |
+
assert_array_equal(a.view(np.float64), [3., 2., 1.])
|
| 360 |
+
|
| 361 |
+
a = self._get_array(0.5) # different factor
|
| 362 |
+
a = a[::2][::-1] # non-contiguous
|
| 363 |
+
sorted_a = np.sort(a)
|
| 364 |
+
assert_array_equal(sorted_a.view(np.float64), [2., 6.])
|
| 365 |
+
# original is unchanged
|
| 366 |
+
assert_array_equal(a.view(np.float64), [6., 2.])
|
| 367 |
+
|
| 368 |
+
a = self._get_array(0.5, aligned=False)
|
| 369 |
+
a = a[::-1] # reverse it
|
| 370 |
+
sorted_a = np.sort(a)
|
| 371 |
+
assert_array_equal(sorted_a.view(np.float64), [2., 4., 6.])
|
| 372 |
+
# original is unchanged
|
| 373 |
+
assert_array_equal(a.view(np.float64), [6., 4., 2.])
|
| 374 |
+
|
| 375 |
+
sorted_a = np.sort(a, stable=True)
|
| 376 |
+
assert_array_equal(sorted_a.view(np.float64), [2., 4., 6.])
|
| 377 |
+
# original is unchanged
|
| 378 |
+
assert_array_equal(a.view(np.float64), [6., 4., 2.])
|
| 379 |
+
|
| 380 |
+
sorted_a = np.sort(a, stable=False)
|
| 381 |
+
assert_array_equal(sorted_a.view(np.float64), [2., 4., 6.])
|
| 382 |
+
# original is unchanged
|
| 383 |
+
assert_array_equal(a.view(np.float64), [6., 4., 2.])
|
| 384 |
+
|
| 385 |
+
def test_argsort(self):
|
| 386 |
+
a = self._get_array(1.)
|
| 387 |
+
a = a[::-1] # reverse it
|
| 388 |
+
|
| 389 |
+
indices = np.argsort(a)
|
| 390 |
+
assert_array_equal(indices, [2, 1, 0])
|
| 391 |
+
# original is unchanged
|
| 392 |
+
assert_array_equal(a.view(np.float64), [3., 2., 1.])
|
| 393 |
+
|
| 394 |
+
a = self._get_array(0.5)
|
| 395 |
+
a = a[::2][::-1] # reverse it
|
| 396 |
+
indices = np.argsort(a)
|
| 397 |
+
assert_array_equal(indices, [1, 0])
|
| 398 |
+
# original is unchanged
|
| 399 |
+
assert_array_equal(a.view(np.float64), [6., 2.])
|
| 400 |
+
|
| 401 |
+
a = self._get_array(0.5, aligned=False)
|
| 402 |
+
a = a[::-1] # reverse it
|
| 403 |
+
indices = np.argsort(a)
|
| 404 |
+
assert_array_equal(indices, [2, 1, 0])
|
| 405 |
+
# original is unchanged
|
| 406 |
+
assert_array_equal(a.view(np.float64), [6., 4., 2.])
|
| 407 |
+
|
| 408 |
+
sorted_indices = np.argsort(a, stable=True)
|
| 409 |
+
assert_array_equal(sorted_indices, [2, 1, 0])
|
| 410 |
+
# original is unchanged
|
| 411 |
+
assert_array_equal(a.view(np.float64), [6., 4., 2.])
|
| 412 |
+
|
| 413 |
+
sorted_indices = np.argsort(a, stable=False)
|
| 414 |
+
assert_array_equal(sorted_indices, [2, 1, 0])
|
| 415 |
+
# original is unchanged
|
| 416 |
+
assert_array_equal(a.view(np.float64), [6., 4., 2.])
|
| 417 |
+
|
| 418 |
+
def test_astype_class(self):
|
| 419 |
+
# Very simple test that we accept `.astype()` also on the class.
|
| 420 |
+
# ScaledFloat always returns the default descriptor, but it does
|
| 421 |
+
# check the relevant code paths.
|
| 422 |
+
arr = np.array([1., 2., 3.], dtype=object)
|
| 423 |
+
|
| 424 |
+
res = arr.astype(SF) # passing the class class
|
| 425 |
+
expected = arr.astype(SF(1.)) # above will have discovered 1. scaling
|
| 426 |
+
assert_array_equal(res.view(np.float64), expected.view(np.float64))
|
| 427 |
+
|
| 428 |
+
def test_creation_class(self):
|
| 429 |
+
# passing in a dtype class should return
|
| 430 |
+
# the default descriptor
|
| 431 |
+
arr1 = np.array([1., 2., 3.], dtype=SF)
|
| 432 |
+
assert arr1.dtype == SF(1.)
|
| 433 |
+
arr2 = np.array([1., 2., 3.], dtype=SF(1.))
|
| 434 |
+
assert_array_equal(arr1.view(np.float64), arr2.view(np.float64))
|
| 435 |
+
assert arr1.dtype == arr2.dtype
|
| 436 |
+
|
| 437 |
+
assert np.empty(3, dtype=SF).dtype == SF(1.)
|
| 438 |
+
assert np.empty_like(arr1, dtype=SF).dtype == SF(1.)
|
| 439 |
+
assert np.zeros(3, dtype=SF).dtype == SF(1.)
|
| 440 |
+
assert np.zeros_like(arr1, dtype=SF).dtype == SF(1.)
|
| 441 |
+
|
| 442 |
+
@pytest.mark.thread_unsafe(
|
| 443 |
+
reason="_ScaledFloatTestDType setup is thread-unsafe (gh-29850)"
|
| 444 |
+
)
|
| 445 |
+
def test_np_save_load(self):
|
| 446 |
+
# this monkeypatch is needed because pickle
|
| 447 |
+
# uses the repr of a type to reconstruct it
|
| 448 |
+
np._ScaledFloatTestDType = SF
|
| 449 |
+
|
| 450 |
+
arr = np.array([1.0, 2.0, 3.0], dtype=SF(1.0))
|
| 451 |
+
|
| 452 |
+
# adapted from RoundtripTest.roundtrip in np.save tests
|
| 453 |
+
with NamedTemporaryFile("wb", delete=False, suffix=".npz") as f:
|
| 454 |
+
with pytest.warns(UserWarning) as record:
|
| 455 |
+
np.savez(f.name, arr)
|
| 456 |
+
|
| 457 |
+
assert len(record) == 1
|
| 458 |
+
|
| 459 |
+
with np.load(f.name, allow_pickle=True) as data:
|
| 460 |
+
larr = data["arr_0"]
|
| 461 |
+
assert_array_equal(arr.view(np.float64), larr.view(np.float64))
|
| 462 |
+
assert larr.dtype == arr.dtype == SF(1.0)
|
| 463 |
+
|
| 464 |
+
del np._ScaledFloatTestDType
|
| 465 |
+
|
| 466 |
+
def test_flatiter(self):
|
| 467 |
+
arr = np.array([1.0, 2.0, 3.0], dtype=SF(1.0))
|
| 468 |
+
|
| 469 |
+
for i, val in enumerate(arr.flat):
|
| 470 |
+
assert arr[i] == val
|
| 471 |
+
|
| 472 |
+
@pytest.mark.parametrize(
|
| 473 |
+
"index", [
|
| 474 |
+
[1, 2], ..., slice(None, 2, None),
|
| 475 |
+
np.array([True, True, False]), np.array([0, 1])
|
| 476 |
+
], ids=["int_list", "ellipsis", "slice", "bool_array", "int_array"])
|
| 477 |
+
def test_flatiter_index(self, index):
|
| 478 |
+
arr = np.array([1.0, 2.0, 3.0], dtype=SF(1.0))
|
| 479 |
+
np.testing.assert_array_equal(
|
| 480 |
+
arr[index].view(np.float64), arr.flat[index].view(np.float64))
|
| 481 |
+
|
| 482 |
+
arr2 = arr.copy()
|
| 483 |
+
arr[index] = 5.0
|
| 484 |
+
arr2.flat[index] = 5.0
|
| 485 |
+
np.testing.assert_array_equal(
|
| 486 |
+
arr.view(np.float64), arr2.view(np.float64))
|
| 487 |
+
|
| 488 |
+
def test_conjugate(self):
|
| 489 |
+
# Also user dtype can just return self if conjugate should be no-op.
|
| 490 |
+
arr = np.array([1.0, 2.0, 3.0], dtype=SF(1.0))
|
| 491 |
+
assert arr.conjugate() is arr
|
| 492 |
+
|
| 493 |
+
|
| 494 |
+
@pytest.mark.thread_unsafe(
|
| 495 |
+
reason="_ScaledFloatTestDType setup is thread-unsafe (gh-29850)"
|
| 496 |
+
)
|
| 497 |
+
def test_type_pickle():
|
| 498 |
+
# can't actually unpickle, but we can pickle (if in namespace)
|
| 499 |
+
import pickle
|
| 500 |
+
|
| 501 |
+
np._ScaledFloatTestDType = SF
|
| 502 |
+
|
| 503 |
+
s = pickle.dumps(SF)
|
| 504 |
+
res = pickle.loads(s)
|
| 505 |
+
assert res is SF
|
| 506 |
+
|
| 507 |
+
del np._ScaledFloatTestDType
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
def test_is_numeric():
|
| 511 |
+
assert SF._is_numeric
|