Eric-Yyvuw commited on
Commit
cd4a856
·
verified ·
1 Parent(s): 26079cd

sync 2026-10-29 07:40 GMT (part 3)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. v12x/pylib/numpy/_array_api_info.py +349 -0
  2. v12x/pylib/numpy/_configtool.py +39 -0
  3. v12x/pylib/numpy/_core/__init__.py +203 -0
  4. v12x/pylib/numpy/_core/_add_newdocs.py +0 -0
  5. v12x/pylib/numpy/_core/_add_newdocs_scalars.py +381 -0
  6. v12x/pylib/numpy/_core/_asarray.py +130 -0
  7. v12x/pylib/numpy/_core/_dtype.py +366 -0
  8. v12x/pylib/numpy/_core/_dtype_ctypes.py +120 -0
  9. v12x/pylib/numpy/_core/_exceptions.py +162 -0
  10. v12x/pylib/numpy/_core/_internal.py +964 -0
  11. v12x/pylib/numpy/_core/_methods.py +252 -0
  12. v12x/pylib/numpy/_core/_string_helpers.py +100 -0
  13. v12x/pylib/numpy/_core/_type_aliases.py +130 -0
  14. v12x/pylib/numpy/_core/_ufunc_config.py +515 -0
  15. v12x/pylib/numpy/_core/arrayprint.py +1788 -0
  16. v12x/pylib/numpy/_core/cversions.py +13 -0
  17. v12x/pylib/numpy/_core/defchararray.py +1429 -0
  18. v12x/pylib/numpy/_core/einsumfunc.py +1647 -0
  19. v12x/pylib/numpy/_core/fromnumeric.py +0 -0
  20. v12x/pylib/numpy/_core/function_base.py +547 -0
  21. v12x/pylib/numpy/_core/getlimits.py +449 -0
  22. v12x/pylib/numpy/_core/memmap.py +362 -0
  23. v12x/pylib/numpy/_core/multiarray.py +1743 -0
  24. v12x/pylib/numpy/_core/numeric.py +2707 -0
  25. v12x/pylib/numpy/_core/numerictypes.py +576 -0
  26. v12x/pylib/numpy/_core/overrides.py +188 -0
  27. v12x/pylib/numpy/_core/printoptions.py +32 -0
  28. v12x/pylib/numpy/_core/records.py +1101 -0
  29. v12x/pylib/numpy/_core/shape_base.py +996 -0
  30. v12x/pylib/numpy/_core/strings.py +1813 -0
  31. v12x/pylib/numpy/_core/tests/_locales.py +72 -0
  32. v12x/pylib/numpy/_core/tests/_natype.py +144 -0
  33. v12x/pylib/numpy/_core/tests/examples/cython/setup.py +39 -0
  34. v12x/pylib/numpy/_core/tests/examples/limited_api/setup.py +24 -0
  35. v12x/pylib/numpy/_core/tests/test__exceptions.py +90 -0
  36. v12x/pylib/numpy/_core/tests/test_abc.py +54 -0
  37. v12x/pylib/numpy/_core/tests/test_api.py +668 -0
  38. v12x/pylib/numpy/_core/tests/test_argparse.py +90 -0
  39. v12x/pylib/numpy/_core/tests/test_array_api_info.py +113 -0
  40. v12x/pylib/numpy/_core/tests/test_array_coercion.py +943 -0
  41. v12x/pylib/numpy/_core/tests/test_array_interface.py +222 -0
  42. v12x/pylib/numpy/_core/tests/test_arraymethod.py +85 -0
  43. v12x/pylib/numpy/_core/tests/test_arrayobject.py +198 -0
  44. v12x/pylib/numpy/_core/tests/test_arrayprint.py +1363 -0
  45. v12x/pylib/numpy/_core/tests/test_casting_floatingpoint_errors.py +154 -0
  46. v12x/pylib/numpy/_core/tests/test_casting_unittests.py +970 -0
  47. v12x/pylib/numpy/_core/tests/test_conversion_utils.py +209 -0
  48. v12x/pylib/numpy/_core/tests/test_cpu_dispatcher.py +48 -0
  49. v12x/pylib/numpy/_core/tests/test_cpu_features.py +533 -0
  50. 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