dask-array 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. dask_array/__init__.py +228 -0
  2. dask_array/_backends.py +76 -0
  3. dask_array/_backends_array.py +99 -0
  4. dask_array/_blockwise.py +1410 -0
  5. dask_array/_broadcast.py +272 -0
  6. dask_array/_chunk.py +445 -0
  7. dask_array/_chunk_types.py +54 -0
  8. dask_array/_collection.py +1644 -0
  9. dask_array/_concatenate.py +331 -0
  10. dask_array/_core_utils.py +1365 -0
  11. dask_array/_dispatch.py +141 -0
  12. dask_array/_einsum.py +277 -0
  13. dask_array/_expr.py +544 -0
  14. dask_array/_expr_flow.py +586 -0
  15. dask_array/_gufunc.py +805 -0
  16. dask_array/_histogram.py +617 -0
  17. dask_array/_map_blocks.py +652 -0
  18. dask_array/_new_collection.py +10 -0
  19. dask_array/_numpy_compat.py +135 -0
  20. dask_array/_overlap.py +1159 -0
  21. dask_array/_rechunk.py +1050 -0
  22. dask_array/_reshape.py +710 -0
  23. dask_array/_routines.py +102 -0
  24. dask_array/_shuffle.py +448 -0
  25. dask_array/_stack.py +264 -0
  26. dask_array/_svg.py +291 -0
  27. dask_array/_templates.py +29 -0
  28. dask_array/_test_utils.py +257 -0
  29. dask_array/_ufunc.py +385 -0
  30. dask_array/_utils.py +349 -0
  31. dask_array/_visualize.py +223 -0
  32. dask_array/_xarray.py +337 -0
  33. dask_array/core/__init__.py +34 -0
  34. dask_array/core/_blockwise_funcs.py +312 -0
  35. dask_array/core/_conversion.py +422 -0
  36. dask_array/core/_from_graph.py +97 -0
  37. dask_array/creation/__init__.py +71 -0
  38. dask_array/creation/_arange.py +121 -0
  39. dask_array/creation/_diag.py +116 -0
  40. dask_array/creation/_diagonal.py +241 -0
  41. dask_array/creation/_eye.py +103 -0
  42. dask_array/creation/_linspace.py +102 -0
  43. dask_array/creation/_mesh.py +134 -0
  44. dask_array/creation/_ones_zeros.py +454 -0
  45. dask_array/creation/_pad.py +270 -0
  46. dask_array/creation/_repeat.py +55 -0
  47. dask_array/creation/_tile.py +36 -0
  48. dask_array/creation/_tri.py +28 -0
  49. dask_array/creation/_utils.py +296 -0
  50. dask_array/fft.py +320 -0
  51. dask_array/io/__init__.py +39 -0
  52. dask_array/io/_base.py +10 -0
  53. dask_array/io/_from_array.py +257 -0
  54. dask_array/io/_from_delayed.py +95 -0
  55. dask_array/io/_from_graph.py +54 -0
  56. dask_array/io/_from_npy_stack.py +67 -0
  57. dask_array/io/_store.py +336 -0
  58. dask_array/io/_tiledb.py +159 -0
  59. dask_array/io/_to_npy_stack.py +65 -0
  60. dask_array/io/_zarr.py +449 -0
  61. dask_array/linalg/__init__.py +39 -0
  62. dask_array/linalg/_cholesky.py +234 -0
  63. dask_array/linalg/_lu.py +300 -0
  64. dask_array/linalg/_norm.py +94 -0
  65. dask_array/linalg/_qr.py +601 -0
  66. dask_array/linalg/_solve.py +349 -0
  67. dask_array/linalg/_svd.py +394 -0
  68. dask_array/linalg/_tensordot.py +334 -0
  69. dask_array/linalg/_utils.py +74 -0
  70. dask_array/manipulation/__init__.py +45 -0
  71. dask_array/manipulation/_expand.py +321 -0
  72. dask_array/manipulation/_flip.py +92 -0
  73. dask_array/manipulation/_roll.py +78 -0
  74. dask_array/manipulation/_transpose.py +309 -0
  75. dask_array/random/__init__.py +125 -0
  76. dask_array/random/_choice.py +181 -0
  77. dask_array/random/_expr.py +256 -0
  78. dask_array/random/_generator.py +441 -0
  79. dask_array/random/_random_state.py +259 -0
  80. dask_array/random/_utils.py +84 -0
  81. dask_array/reductions/__init__.py +84 -0
  82. dask_array/reductions/_arg_reduction.py +130 -0
  83. dask_array/reductions/_common.py +1082 -0
  84. dask_array/reductions/_cumulative.py +522 -0
  85. dask_array/reductions/_percentile.py +261 -0
  86. dask_array/reductions/_reduction.py +725 -0
  87. dask_array/reductions/_trace.py +56 -0
  88. dask_array/routines/__init__.py +133 -0
  89. dask_array/routines/_apply.py +84 -0
  90. dask_array/routines/_bincount.py +112 -0
  91. dask_array/routines/_broadcast.py +111 -0
  92. dask_array/routines/_coarsen.py +115 -0
  93. dask_array/routines/_diff.py +79 -0
  94. dask_array/routines/_gradient.py +158 -0
  95. dask_array/routines/_indexing.py +65 -0
  96. dask_array/routines/_insert_delete.py +132 -0
  97. dask_array/routines/_misc.py +122 -0
  98. dask_array/routines/_nonzero.py +72 -0
  99. dask_array/routines/_search.py +123 -0
  100. dask_array/routines/_select.py +113 -0
  101. dask_array/routines/_statistics.py +171 -0
  102. dask_array/routines/_topk.py +82 -0
  103. dask_array/routines/_triangular.py +74 -0
  104. dask_array/routines/_unique.py +232 -0
  105. dask_array/routines/_where.py +62 -0
  106. dask_array/slicing/__init__.py +67 -0
  107. dask_array/slicing/_basic.py +550 -0
  108. dask_array/slicing/_blocks.py +138 -0
  109. dask_array/slicing/_bool_index.py +145 -0
  110. dask_array/slicing/_setitem.py +329 -0
  111. dask_array/slicing/_squeeze.py +101 -0
  112. dask_array/slicing/_utils.py +1133 -0
  113. dask_array/slicing/_vindex.py +282 -0
  114. dask_array/stacking/__init__.py +15 -0
  115. dask_array/stacking/_block.py +83 -0
  116. dask_array/stacking/_simple.py +58 -0
  117. dask_array/templates/array.html.j2 +48 -0
  118. dask_array/tests/__init__.py +0 -0
  119. dask_array/tests/conftest.py +22 -0
  120. dask_array/tests/test_api.py +40 -0
  121. dask_array/tests/test_binary_op_chunks.py +107 -0
  122. dask_array/tests/test_coarse_slice_through_blockwise.py +362 -0
  123. dask_array/tests/test_collection.py +799 -0
  124. dask_array/tests/test_creation.py +1102 -0
  125. dask_array/tests/test_expr_flow.py +143 -0
  126. dask_array/tests/test_linalg.py +1130 -0
  127. dask_array/tests/test_map_blocks_multi_output.py +104 -0
  128. dask_array/tests/test_rechunk_pushdown.py +214 -0
  129. dask_array/tests/test_reductions.py +1091 -0
  130. dask_array/tests/test_routines.py +2853 -0
  131. dask_array/tests/test_shuffle_chunks.py +67 -0
  132. dask_array/tests/test_slice_pushdown.py +968 -0
  133. dask_array/tests/test_slice_through_blockwise.py +678 -0
  134. dask_array/tests/test_slice_through_overlap.py +366 -0
  135. dask_array/tests/test_slice_through_reshape.py +272 -0
  136. dask_array/tests/test_slicing.py +839 -0
  137. dask_array/tests/test_transpose_slice_pushdown.py +208 -0
  138. dask_array/tests/test_visualize.py +94 -0
  139. dask_array/tests/test_xarray.py +193 -0
  140. dask_array-0.1.0.dist-info/METADATA +48 -0
  141. dask_array-0.1.0.dist-info/RECORD +144 -0
  142. dask_array-0.1.0.dist-info/WHEEL +4 -0
  143. dask_array-0.1.0.dist-info/entry_points.txt +2 -0
  144. dask_array-0.1.0.dist-info/licenses/LICENSE +29 -0
@@ -0,0 +1,1644 @@
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import operator
5
+ import warnings
6
+
7
+ import numpy as np
8
+
9
+ from dask import config
10
+ from dask_array import _chunk as chunk
11
+ from dask_array._new_collection import new_collection
12
+ from dask_array._expr import ArrayExpr
13
+ from dask_array.manipulation._transpose import Transpose
14
+ from dask_array._chunk_types import is_valid_chunk_type
15
+ from dask.base import DaskMethodsMixin, is_dask_collection, named_schedulers
16
+ from dask.core import flatten
17
+ from dask.utils import format_bytes, has_keyword, key_split, typename
18
+
19
+ from dask_array._templates import get_template
20
+
21
+ try:
22
+ ARRAY_TEMPLATE = get_template("array.html.j2")
23
+ except ImportError:
24
+ ARRAY_TEMPLATE = None
25
+
26
+ # Import blockwise functions from their module
27
+ # Import broadcast
28
+ from dask_array._broadcast import broadcast_to
29
+
30
+ # Import concatenate and stacking
31
+ from dask_array._concatenate import concatenate
32
+ from dask_array._stack import stack
33
+ from dask_array.core._blockwise_funcs import blockwise, elemwise
34
+
35
+ # Import core conversion functions from their module
36
+ from dask_array.core._conversion import (
37
+ array,
38
+ asanyarray,
39
+ asarray,
40
+ from_array,
41
+ )
42
+ from dask_array.core._from_graph import from_graph
43
+
44
+ # Import manipulation functions
45
+ from dask_array.manipulation._expand import (
46
+ atleast_1d,
47
+ atleast_2d,
48
+ atleast_3d,
49
+ expand_dims,
50
+ )
51
+ from dask_array.manipulation._flip import flip, fliplr, flipud, rot90
52
+ from dask_array.manipulation._roll import roll
53
+ from dask_array.manipulation._transpose import (
54
+ moveaxis,
55
+ rollaxis,
56
+ transpose,
57
+ )
58
+ from dask_array.stacking._block import block
59
+ from dask_array.stacking._simple import dstack, hstack, vstack
60
+
61
+ # Type imports
62
+ from dask_array._core_utils import (
63
+ _HANDLED_FUNCTIONS,
64
+ T_IntOrNaN,
65
+ _get_chunk_shape,
66
+ _should_delegate,
67
+ cached_max,
68
+ check_if_handled_given_other,
69
+ finalize,
70
+ )
71
+
72
+ __all__ = [
73
+ "Array",
74
+ "array",
75
+ "asanyarray",
76
+ "asarray",
77
+ "atleast_1d",
78
+ "atleast_2d",
79
+ "atleast_3d",
80
+ "block",
81
+ "blockwise",
82
+ "broadcast_to",
83
+ "concatenate",
84
+ "dstack",
85
+ "elemwise",
86
+ "expand_dims",
87
+ "flip",
88
+ "fliplr",
89
+ "flipud",
90
+ "from_array",
91
+ "from_graph",
92
+ "hstack",
93
+ "moveaxis",
94
+ "ravel",
95
+ "rechunk",
96
+ "reshape",
97
+ "reshape_blockwise",
98
+ "roll",
99
+ "rollaxis",
100
+ "rot90",
101
+ "squeeze",
102
+ "stack",
103
+ "swapaxes",
104
+ "transpose",
105
+ "vstack",
106
+ ]
107
+
108
+
109
+ class Array(DaskMethodsMixin):
110
+ __dask_scheduler__ = staticmethod(named_schedulers.get("threads", named_schedulers["sync"]))
111
+ __dask_optimize__ = staticmethod(lambda dsk, keys, **kwargs: dsk)
112
+ __array_priority__ = 11 # higher than numpy.ndarray and numpy.matrix
113
+
114
+ def __init__(self, expr):
115
+ self._expr = expr
116
+
117
+ @property
118
+ def expr(self) -> ArrayExpr:
119
+ return self._expr
120
+
121
+ @property
122
+ def _name(self):
123
+ return self.expr._name
124
+
125
+ def __dask_postcompute__(self):
126
+ return finalize, ()
127
+
128
+ def __dask_postpersist__(self):
129
+ state = self.expr.lower_completely()
130
+ # Use original array's meta like legacy implementation
131
+ meta = self._meta
132
+ if meta is None:
133
+ # Fallback to synthetic meta if original is also None
134
+ meta = np.empty((0,) * state.ndim, dtype=state.dtype)
135
+ # Use self.chunks to preserve nan chunks for unknown-sized operations
136
+ return from_graph, (
137
+ meta,
138
+ self.chunks,
139
+ # FIXME: This is using keys of the unoptimized graph
140
+ list(flatten(state.__dask_keys__())),
141
+ key_split(state._name),
142
+ )
143
+
144
+ @property
145
+ def dask(self):
146
+ return self.__dask_graph__()
147
+
148
+ def __dask_graph__(self):
149
+ out = self.expr.lower_completely()
150
+ return out.__dask_graph__()
151
+
152
+ def __dask_keys__(self):
153
+ out = self.expr.lower_completely()
154
+ return out.__dask_keys__()
155
+
156
+ def __dask_tokenize__(self):
157
+ return "Array", self.expr._name
158
+
159
+ def compute(self, **kwargs):
160
+ return DaskMethodsMixin.compute(self.optimize(), **kwargs)
161
+
162
+ def persist(self, **kwargs):
163
+ return DaskMethodsMixin.persist(self.optimize(), **kwargs)
164
+
165
+ def optimize(self):
166
+ return new_collection(self.expr.optimize())
167
+
168
+ def simplify(self):
169
+ return new_collection(self.expr.simplify())
170
+
171
+ def pprint(self):
172
+ """Pretty print the expression tree.
173
+
174
+ Uses rich table format if rich is installed, otherwise falls back
175
+ to the basic tree representation.
176
+ """
177
+ self.expr.pprint()
178
+
179
+ def visualize(self, tasks: bool = False, **kwargs): # type: ignore[override]
180
+ """Visualize the expression or task graph.
181
+
182
+ Parameters
183
+ ----------
184
+ tasks : bool
185
+ Whether to visualize the task graph. By default
186
+ the expression graph will be visualized instead.
187
+ **kwargs
188
+ Additional arguments passed to the visualizer.
189
+ """
190
+ # color= options require task graph visualization
191
+ if tasks or kwargs.get("color"):
192
+ return super().visualize(**kwargs)
193
+ return self.expr.visualize(**kwargs)
194
+
195
+ @property
196
+ def _meta(self):
197
+ return self.expr._meta
198
+
199
+ @property
200
+ def dtype(self):
201
+ return self.expr.dtype
202
+
203
+ @property
204
+ def shape(self):
205
+ return self.expr.shape
206
+
207
+ @property
208
+ def chunks(self):
209
+ return self.expr.chunks
210
+
211
+ @chunks.setter
212
+ def chunks(self, chunks):
213
+ raise TypeError(
214
+ "Can not set chunks directly\n\n"
215
+ "Please use the rechunk method instead:\n"
216
+ f" x.rechunk({chunks})\n\n"
217
+ "Documentation\n"
218
+ "-------------\n"
219
+ "https://docs.dask.org/en/latest/generated/dask.array.rechunk.html"
220
+ )
221
+
222
+ @property
223
+ def _chunks(self):
224
+ """Internal access to chunks (for compatibility with tests)."""
225
+ return self.expr.chunks
226
+
227
+ @_chunks.setter
228
+ def _chunks(self, chunks):
229
+ """Set chunks by wrapping the expression with ChunksOverride.
230
+
231
+ This is primarily for internal use and testing when simulating
232
+ arrays with unknown chunk sizes.
233
+ """
234
+ from dask_array._expr import ChunksOverride
235
+
236
+ self._expr = ChunksOverride(self._expr, chunks)
237
+
238
+ @property
239
+ def chunksize(self) -> tuple:
240
+ return tuple(cached_max(c) for c in self.chunks)
241
+
242
+ @property
243
+ def ndim(self):
244
+ return self.expr.ndim
245
+
246
+ @property
247
+ def numblocks(self):
248
+ return self.expr.numblocks
249
+
250
+ @property
251
+ def npartitions(self):
252
+ from math import prod
253
+
254
+ return prod(self.numblocks)
255
+
256
+ def compute_chunk_sizes(self):
257
+ """
258
+ Compute the chunk sizes for a Dask array. This is especially useful
259
+ when the chunk sizes are unknown (e.g., when indexing one Dask array
260
+ with another).
261
+
262
+ Notes
263
+ -----
264
+ This function modifies the Dask array in-place.
265
+
266
+ Examples
267
+ --------
268
+ >>> import dask_array as da
269
+ >>> import numpy as np
270
+ >>> x = da.from_array([-2, -1, 0, 1, 2], chunks=2)
271
+ >>> x.chunks
272
+ ((2, 2, 1),)
273
+ >>> y = x[x <= 0]
274
+ >>> y.chunks
275
+ ((nan, nan, nan),)
276
+ >>> y.compute_chunk_sizes() # in-place computation
277
+ dask.array<getitem, shape=(3,), dtype=int64, chunksize=(2,), chunktype=numpy.ndarray>
278
+ >>> y.chunks
279
+ ((2, 1, 0),)
280
+ """
281
+ from dask.base import compute
282
+
283
+ chunk_shapes = self.map_blocks(
284
+ _get_chunk_shape,
285
+ dtype=int,
286
+ chunks=tuple(len(c) * (1,) for c in self.chunks) + ((self.ndim,),),
287
+ new_axis=self.ndim,
288
+ )
289
+
290
+ c = []
291
+ for i in range(self.ndim):
292
+ s = self.ndim * [0] + [i]
293
+ s[i] = slice(None)
294
+ s = tuple(s)
295
+
296
+ c.append(tuple(chunk_shapes[s]))
297
+
298
+ # `map_blocks` assigns numpy dtypes
299
+ # cast chunk dimensions back to python int before returning
300
+ new_chunks = tuple(tuple(int(chunk) for chunk in chunks) for chunks in compute(tuple(c))[0])
301
+
302
+ # In the expression system, wrap with ChunksOverride to set the new chunks
303
+ from dask_array._expr import ChunksOverride
304
+
305
+ self._expr = ChunksOverride(self._expr, new_chunks)
306
+
307
+ return self
308
+
309
+ @property
310
+ def _key_array(self):
311
+ return np.array(self.__dask_keys__(), dtype=object)
312
+
313
+ @property
314
+ def blocks(self):
315
+ from dask_array.slicing._blocks import BlockView
316
+
317
+ return BlockView(self)
318
+
319
+ @property
320
+ def partitions(self):
321
+ """Slice an array by partitions. Alias of dask array .blocks attribute."""
322
+ return self.blocks
323
+
324
+ @property
325
+ def size(self) -> T_IntOrNaN:
326
+ return self.expr.size
327
+
328
+ @property
329
+ def nbytes(self) -> T_IntOrNaN:
330
+ """Number of bytes in array"""
331
+ return self.size * self.dtype.itemsize
332
+
333
+ @property
334
+ def itemsize(self) -> int:
335
+ """Length of one array element in bytes"""
336
+ return self.dtype.itemsize
337
+
338
+ @property
339
+ def name(self):
340
+ return self.expr.name
341
+
342
+ def __len__(self):
343
+ return self.expr.__len__()
344
+
345
+ def __repr__(self):
346
+ name = self.name.rsplit("-", 1)[0]
347
+ return "dask.array<{}, shape={}, dtype={}, chunksize={}, chunktype={}.{}>".format(
348
+ name,
349
+ self.shape,
350
+ self.dtype,
351
+ self.chunksize,
352
+ type(self._meta).__module__.split(".")[0],
353
+ type(self._meta).__name__,
354
+ )
355
+
356
+ def _repr_html_(self):
357
+ if ARRAY_TEMPLATE is None:
358
+ return repr(self)
359
+
360
+ try:
361
+ grid = self.to_svg(size=config.get("array.svg.size", 120))
362
+ except NotImplementedError:
363
+ grid = ""
364
+
365
+ if "sparse" in typename(type(self._meta)):
366
+ nbytes = None
367
+ cbytes = None
368
+ elif not math.isnan(self.nbytes):
369
+ nbytes = format_bytes(self.nbytes)
370
+ cbytes = format_bytes(math.prod(self.chunksize) * self.dtype.itemsize)
371
+ else:
372
+ nbytes = "unknown"
373
+ cbytes = "unknown"
374
+
375
+ # Expression flow summary and diagram
376
+ from dask_array._expr_flow import build_flow_graph, render_flow_svg, count_operations
377
+
378
+ try:
379
+ nodes, edges = build_flow_graph(self._expr)
380
+ n_expr = count_operations(self._expr)
381
+ expr_flow = render_flow_svg(self._expr) if nodes else ""
382
+ except Exception:
383
+ n_expr = 1
384
+ expr_flow = ""
385
+
386
+ return ARRAY_TEMPLATE.render(
387
+ array=self,
388
+ grid=grid,
389
+ nbytes=nbytes,
390
+ cbytes=cbytes,
391
+ n_expr=n_expr,
392
+ expr_flow=expr_flow,
393
+ )
394
+
395
+ def __bool__(self):
396
+ if self.size > 1:
397
+ raise ValueError(f"The truth value of a {self.__class__.__name__} is ambiguous. Use a.any() or a.all().")
398
+ return bool(self.compute())
399
+
400
+ def _scalarfunc(self, cast_type):
401
+ if self.size > 1:
402
+ raise TypeError("Only length-1 arrays can be converted to Python scalars")
403
+ else:
404
+ return cast_type(self.compute().item())
405
+
406
+ def __int__(self):
407
+ return self._scalarfunc(int)
408
+
409
+ def __float__(self):
410
+ return self._scalarfunc(float)
411
+
412
+ def __complex__(self):
413
+ return self._scalarfunc(complex)
414
+
415
+ def __index__(self):
416
+ return self._scalarfunc(operator.index)
417
+
418
+ def __array__(self, dtype=None, copy=None, **kwargs):
419
+ import warnings
420
+
421
+ if kwargs:
422
+ warnings.warn(
423
+ f"Extra keyword arguments {kwargs} are ignored and won't be accepted in the future",
424
+ FutureWarning,
425
+ )
426
+ if copy is False:
427
+ warnings.warn(
428
+ "Can't acquire a memory view of a Dask array. This will raise in the future.",
429
+ FutureWarning,
430
+ )
431
+ x = self.compute()
432
+ return np.asarray(x, dtype=dtype)
433
+
434
+ def __iter__(self):
435
+ for i in range(len(self)):
436
+ yield self[i]
437
+
438
+ def __getitem__(self, index):
439
+ # Field access, e.g. x['a'] or x[['a', 'b']]
440
+ if isinstance(index, str) or (isinstance(index, list) and index and all(isinstance(i, str) for i in index)):
441
+ from dask_array._chunk import getitem
442
+
443
+ if isinstance(index, str):
444
+ dt = self.dtype[index]
445
+ else:
446
+ dt = np.dtype(
447
+ {
448
+ "names": index,
449
+ "formats": [self.dtype.fields[name][0] for name in index],
450
+ "offsets": [self.dtype.fields[name][1] for name in index],
451
+ "itemsize": self.dtype.itemsize,
452
+ }
453
+ )
454
+
455
+ if dt.shape:
456
+ new_axis = list(range(self.ndim, self.ndim + len(dt.shape)))
457
+ chunks = self.chunks + tuple((i,) for i in dt.shape)
458
+ return self.map_blocks(getitem, index, dtype=dt.base, chunks=chunks, new_axis=new_axis)
459
+ else:
460
+ return self.map_blocks(getitem, index, dtype=dt)
461
+
462
+ if not isinstance(index, tuple):
463
+ index = (index,)
464
+
465
+ from dask_array.slicing import (
466
+ normalize_index,
467
+ slice_array,
468
+ slice_with_int_dask_array,
469
+ )
470
+
471
+ index2 = normalize_index(index, self.shape)
472
+
473
+ dependencies = {self.name}
474
+ for i in index2:
475
+ if isinstance(i, Array):
476
+ dependencies.add(i.name)
477
+
478
+ if any(isinstance(i, Array) and i.dtype.kind in "iu" for i in index2):
479
+ self, index2 = slice_with_int_dask_array(self, index2)
480
+ if any(isinstance(i, Array) and i.dtype == bool for i in index2):
481
+ from dask_array.slicing import slice_with_bool_dask_array
482
+
483
+ self, index2 = slice_with_bool_dask_array(self, index2)
484
+
485
+ if all(isinstance(i, slice) and i == slice(None) for i in index2):
486
+ return self
487
+
488
+ result = slice_array(self.expr, index2)
489
+ return new_collection(result)
490
+
491
+ def __setitem__(self, key, value):
492
+ from dask_array._core_utils import unknown_chunk_message
493
+
494
+ # Handle np.ma.masked assignment
495
+ if value is np.ma.masked:
496
+ value = np.ma.masked_all((), dtype=self.dtype)
497
+
498
+ # Check for NaN/inf in integer arrays
499
+ if not is_dask_collection(value) and self.dtype.kind in "iu":
500
+ if np.isnan(value).any():
501
+ raise ValueError("cannot convert float NaN to integer")
502
+ if np.isinf(value).any():
503
+ raise ValueError("cannot convert float infinity to integer")
504
+
505
+ # Suppress dtype broadcasting; __setitem__ can't change the dtype.
506
+ value = asanyarray(value, dtype=self.dtype)
507
+
508
+ # Handle 1D integer array index case
509
+ if isinstance(key, Array) and (
510
+ key.dtype.kind in "iu" or (key.dtype == bool and key.ndim == 1 and self.ndim > 1)
511
+ ):
512
+ key = (key,)
513
+
514
+ # Use "where" method for any dask Array key (matches legacy behavior)
515
+ if isinstance(key, Array):
516
+ from dask_array._broadcast import broadcast_to
517
+
518
+ left_shape = np.array(key.shape)
519
+ right_shape = np.array(self.shape)
520
+
521
+ # Treat unknown shapes as matching
522
+ match = left_shape == right_shape
523
+ match |= np.isnan(left_shape) | np.isnan(right_shape)
524
+
525
+ if not match.all():
526
+ raise IndexError(f"boolean index shape {key.shape} must match indexed array's {self.shape}.")
527
+
528
+ # If value has ndim > 0, they must be broadcastable to self.shape[idx].
529
+ if value.ndim:
530
+ value = broadcast_to(value, self[key].shape)
531
+
532
+ from dask_array.routines._where import where
533
+
534
+ y = where(key, value, self)
535
+ self._expr = y.expr
536
+ return
537
+
538
+ # Check for unknown chunks
539
+ if np.isnan(self.shape).any():
540
+ raise ValueError(f"Arrays chunk sizes are unknown. {unknown_chunk_message}")
541
+
542
+ # Validate indices and value shape eagerly (before creating lazy expression)
543
+ import math
544
+
545
+ from dask_array.slicing._utils import parse_assignment_indices
546
+
547
+ indices, implied_shape, _, implied_shape_positions = parse_assignment_indices(key, self.shape)
548
+ value_shape = value.shape
549
+
550
+ # Validate value shape vs implied shape (from setitem_array validation)
551
+ if 0 in implied_shape and value_shape and max(value_shape) > 1:
552
+ raise ValueError(
553
+ f"shape mismatch: value array of shape {value_shape} "
554
+ "could not be broadcast to indexing result "
555
+ f"of shape {tuple(implied_shape)}"
556
+ )
557
+
558
+ value_ndim = len(value_shape)
559
+ offset = len(implied_shape) - value_ndim
560
+ if offset >= 0:
561
+ array_common_shape = implied_shape[offset:]
562
+ value_common_shape = value_shape
563
+ implied_positions = implied_shape_positions[offset:]
564
+ else:
565
+ value_offset = -offset
566
+ array_common_shape = implied_shape
567
+ value_common_shape = value_shape[value_offset:]
568
+ implied_positions = implied_shape_positions
569
+ # All extra leading dimensions must have size 1
570
+ if value_shape[:value_offset] != (1,) * value_offset:
571
+ raise ValueError(
572
+ f"could not broadcast input array from shape{value_shape} into shape {tuple(implied_shape)}"
573
+ )
574
+
575
+ # Check shape compatibility for each dimension
576
+ for _, (a, b, j) in enumerate(zip(array_common_shape, value_common_shape, implied_positions)):
577
+ index = indices[j]
578
+ if is_dask_collection(index) and getattr(index, "dtype", None) == bool:
579
+ # For dask boolean index, value size must not exceed index size
580
+ if not math.isnan(b) and b > index.size:
581
+ raise ValueError(
582
+ f"shape mismatch: value array dimension size of {b} is "
583
+ "greater then corresponding boolean index size of "
584
+ f"{index.size}"
585
+ )
586
+ elif b != 1 and a != b and not math.isnan(a):
587
+ raise ValueError(
588
+ f"shape mismatch: value array of shape {value_shape} "
589
+ "could not be broadcast to indexing result of shape "
590
+ f"{tuple(implied_shape)}"
591
+ )
592
+
593
+ # Use SetItem expression for other index types
594
+ from dask_array.slicing import SetItem
595
+
596
+ value_expr = value.expr if isinstance(value, Array) else value
597
+ y = new_collection(SetItem(self.expr, key, value_expr))
598
+ self._expr = y.expr
599
+
600
+ @check_if_handled_given_other
601
+ def __add__(self, other):
602
+ return elemwise(operator.add, self, other)
603
+
604
+ @check_if_handled_given_other
605
+ def __radd__(self, other):
606
+ return elemwise(operator.add, other, self)
607
+
608
+ @check_if_handled_given_other
609
+ def __mul__(self, other):
610
+ return elemwise(operator.mul, self, other)
611
+
612
+ @check_if_handled_given_other
613
+ def __rmul__(self, other):
614
+ return elemwise(operator.mul, other, self)
615
+
616
+ @check_if_handled_given_other
617
+ def __sub__(self, other):
618
+ return elemwise(operator.sub, self, other)
619
+
620
+ @check_if_handled_given_other
621
+ def __rsub__(self, other):
622
+ return elemwise(operator.sub, other, self)
623
+
624
+ @check_if_handled_given_other
625
+ def __pow__(self, other):
626
+ return elemwise(operator.pow, self, other)
627
+
628
+ @check_if_handled_given_other
629
+ def __rpow__(self, other):
630
+ return elemwise(operator.pow, other, self)
631
+
632
+ @check_if_handled_given_other
633
+ def __truediv__(self, other):
634
+ return elemwise(operator.truediv, self, other)
635
+
636
+ @check_if_handled_given_other
637
+ def __rtruediv__(self, other):
638
+ return elemwise(operator.truediv, other, self)
639
+
640
+ @check_if_handled_given_other
641
+ def __floordiv__(self, other):
642
+ return elemwise(operator.floordiv, self, other)
643
+
644
+ @check_if_handled_given_other
645
+ def __rfloordiv__(self, other):
646
+ return elemwise(operator.floordiv, other, self)
647
+
648
+ def __abs__(self):
649
+ return elemwise(operator.abs, self)
650
+
651
+ @check_if_handled_given_other
652
+ def __and__(self, other):
653
+ return elemwise(operator.and_, self, other)
654
+
655
+ @check_if_handled_given_other
656
+ def __rand__(self, other):
657
+ return elemwise(operator.and_, other, self)
658
+
659
+ @check_if_handled_given_other
660
+ def __div__(self, other):
661
+ return elemwise(operator.div, self, other)
662
+
663
+ @check_if_handled_given_other
664
+ def __rdiv__(self, other):
665
+ return elemwise(operator.div, other, self)
666
+
667
+ @check_if_handled_given_other
668
+ def __eq__(self, other):
669
+ return elemwise(operator.eq, self, other)
670
+
671
+ @check_if_handled_given_other
672
+ def __gt__(self, other):
673
+ return elemwise(operator.gt, self, other)
674
+
675
+ @check_if_handled_given_other
676
+ def __ge__(self, other):
677
+ return elemwise(operator.ge, self, other)
678
+
679
+ def __invert__(self):
680
+ return elemwise(operator.invert, self)
681
+
682
+ @check_if_handled_given_other
683
+ def __lshift__(self, other):
684
+ return elemwise(operator.lshift, self, other)
685
+
686
+ @check_if_handled_given_other
687
+ def __rlshift__(self, other):
688
+ return elemwise(operator.lshift, other, self)
689
+
690
+ @check_if_handled_given_other
691
+ def __lt__(self, other):
692
+ return elemwise(operator.lt, self, other)
693
+
694
+ @check_if_handled_given_other
695
+ def __le__(self, other):
696
+ return elemwise(operator.le, self, other)
697
+
698
+ @check_if_handled_given_other
699
+ def __mod__(self, other):
700
+ return elemwise(operator.mod, self, other)
701
+
702
+ @check_if_handled_given_other
703
+ def __rmod__(self, other):
704
+ return elemwise(operator.mod, other, self)
705
+
706
+ @check_if_handled_given_other
707
+ def __ne__(self, other):
708
+ return elemwise(operator.ne, self, other)
709
+
710
+ def __neg__(self):
711
+ return elemwise(operator.neg, self)
712
+
713
+ @check_if_handled_given_other
714
+ def __or__(self, other):
715
+ return elemwise(operator.or_, self, other)
716
+
717
+ def __pos__(self):
718
+ return self
719
+
720
+ @check_if_handled_given_other
721
+ def __ror__(self, other):
722
+ return elemwise(operator.or_, other, self)
723
+
724
+ @check_if_handled_given_other
725
+ def __rshift__(self, other):
726
+ return elemwise(operator.rshift, self, other)
727
+
728
+ @check_if_handled_given_other
729
+ def __rrshift__(self, other):
730
+ return elemwise(operator.rshift, other, self)
731
+
732
+ @check_if_handled_given_other
733
+ def __xor__(self, other):
734
+ return elemwise(operator.xor, self, other)
735
+
736
+ @check_if_handled_given_other
737
+ def __rxor__(self, other):
738
+ return elemwise(operator.xor, other, self)
739
+
740
+ @check_if_handled_given_other
741
+ def __matmul__(self, other):
742
+ from dask_array.linalg import matmul
743
+
744
+ return matmul(self, other)
745
+
746
+ @check_if_handled_given_other
747
+ def __rmatmul__(self, other):
748
+ from dask_array.linalg import matmul
749
+
750
+ return matmul(other, self)
751
+
752
+ @check_if_handled_given_other
753
+ def __divmod__(self, other):
754
+ from dask_array._ufunc import divmod
755
+
756
+ return divmod(self, other)
757
+
758
+ @check_if_handled_given_other
759
+ def __rdivmod__(self, other):
760
+ from dask_array._ufunc import divmod
761
+
762
+ return divmod(other, self)
763
+
764
+ def __array_function__(self, func, types, args, kwargs):
765
+ import dask_array as module
766
+ from dask.base import compute
767
+
768
+ def handle_nonmatching_names(func, args, kwargs):
769
+ if func not in _HANDLED_FUNCTIONS:
770
+ warnings.warn(
771
+ f"The `{func.__module__}.{func.__name__}` function "
772
+ "is not implemented by Dask array. "
773
+ "You may want to use the da.map_blocks function "
774
+ "or something similar to silence this warning. "
775
+ "Your code may stop working in a future release.",
776
+ FutureWarning,
777
+ )
778
+ # Need to convert to array object (e.g. numpy.ndarray or
779
+ # cupy.ndarray) as needed, so we can call the NumPy function
780
+ # again and it gets the chance to dispatch to the right
781
+ # implementation.
782
+ args, kwargs = compute(args, kwargs)
783
+ return func(*args, **kwargs)
784
+
785
+ return _HANDLED_FUNCTIONS[func](*args, **kwargs)
786
+
787
+ # First, verify that all types are handled by Dask. Otherwise, return NotImplemented.
788
+ if not all(
789
+ # Accept our own superclasses as recommended by NEP-13
790
+ # (https://numpy.org/neps/nep-0013-ufunc-overrides.html#subclass-hierarchies)
791
+ issubclass(type(self), type_) or is_valid_chunk_type(type_)
792
+ for type_ in types
793
+ ):
794
+ return NotImplemented
795
+
796
+ # Now try to find a matching function name. If that doesn't work, we may
797
+ # be dealing with an alias or a function that's simply not in the Dask API.
798
+ # Handle aliases via the _HANDLED_FUNCTIONS dict mapping, and warn otherwise.
799
+ for submodule in func.__module__.split(".")[1:]:
800
+ try:
801
+ module = getattr(module, submodule)
802
+ except AttributeError:
803
+ return handle_nonmatching_names(func, args, kwargs)
804
+
805
+ if not hasattr(module, func.__name__):
806
+ return handle_nonmatching_names(func, args, kwargs)
807
+
808
+ da_func = getattr(module, func.__name__)
809
+ if da_func is func:
810
+ return handle_nonmatching_names(func, args, kwargs)
811
+
812
+ # If ``like`` is contained in ``da_func``'s signature, add ``like=self``
813
+ # to the kwargs dictionary.
814
+ if has_keyword(da_func, "like"):
815
+ kwargs["like"] = self
816
+
817
+ return da_func(*args, **kwargs)
818
+
819
+ def transpose(self, *axes):
820
+ from collections.abc import Iterable
821
+
822
+ if not axes:
823
+ axes = None
824
+ elif len(axes) == 1 and isinstance(axes[0], Iterable):
825
+ axes = axes[0]
826
+
827
+ if axes:
828
+ if len(axes) != self.ndim:
829
+ raise ValueError("axes don't match array")
830
+ axes = tuple(d + self.ndim if d < 0 else d for d in axes)
831
+ else:
832
+ axes = tuple(range(self.ndim))[::-1]
833
+
834
+ # Identity transpose - return self
835
+ if axes == tuple(range(self.ndim)):
836
+ return self
837
+
838
+ return new_collection(Transpose(self, axes))
839
+
840
+ @property
841
+ def T(self):
842
+ return self.transpose()
843
+
844
+ @property
845
+ def A(self):
846
+ return self
847
+
848
+ def swapaxes(self, axis1, axis2):
849
+ """Interchange two axes of an array.
850
+
851
+ Refer to :func:`dask.array.swapaxes` for full documentation.
852
+ """
853
+ return swapaxes(self, axis1, axis2)
854
+
855
+ def squeeze(self, axis=None):
856
+ """Remove axes of length one from array.
857
+
858
+ Refer to :func:`dask.array.squeeze` for full documentation.
859
+ """
860
+ return squeeze(self, axis=axis)
861
+
862
+ def reshape(self, *shape, merge_chunks=True, limit=None):
863
+ """Reshape the array to a new shape.
864
+
865
+ Refer to :func:`dask.array.reshape` for full documentation.
866
+ """
867
+ if len(shape) == 1 and isinstance(shape[0], (tuple, list)):
868
+ shape = shape[0]
869
+ return reshape(self, shape, merge_chunks=merge_chunks, limit=limit)
870
+
871
+ def flatten(self):
872
+ """Return a copy of the array collapsed into one dimension.
873
+
874
+ Returns
875
+ -------
876
+ dask Array
877
+ A 1-D array with the same data as self.
878
+ """
879
+ return reshape(self, (-1,))
880
+
881
+ def ravel(self):
882
+ """Return a flattened array.
883
+
884
+ Returns
885
+ -------
886
+ dask Array
887
+ A 1-D array with the same data as self.
888
+ """
889
+ return reshape(self, (-1,))
890
+
891
+ def repeat(self, repeats, axis=None):
892
+ """Repeat elements of an array.
893
+
894
+ Refer to :func:`dask.array.repeat` for full documentation.
895
+ """
896
+ from dask_array.creation import repeat
897
+
898
+ return repeat(self, repeats, axis)
899
+
900
+ def choose(self, choices):
901
+ """Use an index array to construct a new array from a set of choices.
902
+
903
+ Refer to :func:`dask.array.choose` for full documentation.
904
+
905
+ See Also
906
+ --------
907
+ dask.array.choose : equivalent function
908
+ """
909
+ from dask_array._routines import choose
910
+
911
+ return choose(self, choices)
912
+
913
+ def nonzero(self):
914
+ """Return the indices of the elements that are non-zero.
915
+
916
+ Refer to :func:`dask.array.nonzero` for full documentation.
917
+
918
+ See Also
919
+ --------
920
+ dask.array.nonzero : equivalent function
921
+ """
922
+ from dask_array._routines import nonzero
923
+
924
+ return nonzero(self)
925
+
926
+ def round(self, decimals=0):
927
+ """Return array with each element rounded to the given number of decimals.
928
+
929
+ Refer to :func:`dask.array.round` for full documentation.
930
+
931
+ See Also
932
+ --------
933
+ dask.array.round : equivalent function
934
+ """
935
+ from dask_array._routines import round
936
+
937
+ return round(self, decimals=decimals)
938
+
939
+ def rechunk(
940
+ self,
941
+ chunks="auto",
942
+ threshold=None,
943
+ block_size_limit=None,
944
+ balance=False,
945
+ method=None,
946
+ ):
947
+ return rechunk(self, chunks, threshold, block_size_limit, balance, method)
948
+
949
+ def shuffle(self, indexer, axis, chunks="auto"):
950
+ from dask_array._shuffle import shuffle
951
+
952
+ return shuffle(self, indexer, axis, chunks)
953
+
954
+ def _vindex(self, key):
955
+ from dask_array.slicing import _numpy_vindex, _vindex
956
+ from dask.base import is_dask_collection
957
+
958
+ if not isinstance(key, tuple):
959
+ key = (key,)
960
+ if any(k is None for k in key):
961
+ raise IndexError(f"vindex does not support indexing with None (np.newaxis), got {key}")
962
+ if all(isinstance(k, slice) for k in key):
963
+ if all(k.indices(d) == slice(0, d).indices(d) for k, d in zip(key, self.shape)):
964
+ return self
965
+ raise IndexError(
966
+ "vindex requires at least one non-slice to vectorize over "
967
+ "when the slices are not over the entire array (i.e, x[:]). "
968
+ f"Use normal slicing instead when only using slices. Got: {key}"
969
+ )
970
+ elif any(is_dask_collection(k) for k in key):
971
+ if math.prod(self.numblocks) == 1 and len(key) == 1 and self.ndim == 1:
972
+ idxr = key[0]
973
+ # we can broadcast in this case
974
+ return idxr.map_blocks(_numpy_vindex, self, dtype=self.dtype, chunks=idxr.chunks)
975
+ else:
976
+ raise IndexError(
977
+ "vindex does not support indexing with dask objects. Call compute "
978
+ f"on the indexer first to get an evalurated array. Got: {key}"
979
+ )
980
+ return _vindex(self, *key)
981
+
982
+ @property
983
+ def vindex(self):
984
+ """Vectorized indexing with broadcasting.
985
+
986
+ This is equivalent to numpy's advanced indexing, using arrays that are
987
+ broadcast against each other. This allows for pointwise indexing:
988
+
989
+ >>> import dask_array as da
990
+ >>> x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
991
+ >>> x = da.from_array(x, chunks=2)
992
+ >>> x.vindex[[0, 1, 2], [0, 1, 2]].compute()
993
+ array([1, 5, 9])
994
+
995
+ Mixed basic/advanced indexing with slices/arrays is also supported. The
996
+ order of dimensions in the result follows those proposed for
997
+ `ndarray.vindex <https://github.com/numpy/numpy/pull/6256>`_:
998
+ the subspace spanned by arrays is followed by all slices.
999
+
1000
+ Note: ``vindex`` provides more general functionality than standard
1001
+ indexing, but it also has fewer optimizations and can be significantly
1002
+ slower.
1003
+ """
1004
+ from dask.utils import IndexCallable
1005
+
1006
+ return IndexCallable(self._vindex)
1007
+
1008
+ def store(self, target, **kwargs):
1009
+ """Store array in array-like object.
1010
+
1011
+ Refer to :func:`dask.array.store` for full documentation.
1012
+ """
1013
+ from dask_array.io import store
1014
+
1015
+ return store([self], [target], **kwargs)
1016
+
1017
+ def to_zarr(self, *args, **kwargs):
1018
+ """Save array to the zarr storage format
1019
+
1020
+ See https://zarr.readthedocs.io for details about the format.
1021
+
1022
+ Refer to :func:`dask.array.to_zarr` for full documentation.
1023
+
1024
+ See also
1025
+ --------
1026
+ dask.array.to_zarr : equivalent function
1027
+ """
1028
+ from dask_array.io import to_zarr
1029
+
1030
+ return to_zarr(self, *args, **kwargs)
1031
+
1032
+ def to_tiledb(self, uri, *args, **kwargs):
1033
+ """Save array to the TileDB storage manager
1034
+
1035
+ See https://docs.tiledb.io for details about the format and engine.
1036
+
1037
+ Refer to :func:`dask.array.to_tiledb` for full documentation.
1038
+
1039
+ See also
1040
+ --------
1041
+ dask.array.to_tiledb : equivalent function
1042
+ """
1043
+ from dask_array.io._tiledb import to_tiledb
1044
+
1045
+ return to_tiledb(self, uri, *args, **kwargs)
1046
+
1047
+ def to_hdf5(self, filename, datapath, **kwargs):
1048
+ """Store array in HDF5 file
1049
+
1050
+ >>> x.to_hdf5('myfile.hdf5', '/x') # doctest: +SKIP
1051
+
1052
+ Optionally provide arguments as though to ``h5py.File.create_dataset``
1053
+
1054
+ >>> x.to_hdf5('myfile.hdf5', '/x', compression='lzf', shuffle=True) # doctest: +SKIP
1055
+
1056
+ See Also
1057
+ --------
1058
+ dask_array.to_hdf5
1059
+ h5py.File.create_dataset
1060
+ """
1061
+ from dask_array.io._store import to_hdf5
1062
+
1063
+ return to_hdf5(filename, datapath, self, **kwargs)
1064
+
1065
+ def to_backend(self, backend: str | None = None, **kwargs):
1066
+ """Move to a new Array backend
1067
+
1068
+ Parameters
1069
+ ----------
1070
+ backend : str, Optional
1071
+ The name of the new backend to move to. The default
1072
+ is the current "array.backend" configuration.
1073
+
1074
+ Returns
1075
+ -------
1076
+ Array
1077
+ """
1078
+ from dask_array.creation._utils import to_backend
1079
+
1080
+ return to_backend(self, backend=backend, **kwargs) # type: ignore[arg-type]
1081
+
1082
+ def to_svg(self, size=500):
1083
+ """Convert chunks from Dask Array into an SVG Image
1084
+
1085
+ Parameters
1086
+ ----------
1087
+ size : int
1088
+ Rough size of the image
1089
+
1090
+ Returns
1091
+ -------
1092
+ str
1093
+ An svg string depicting the array as a grid of chunks
1094
+ """
1095
+ from dask_array._svg import svg
1096
+
1097
+ return svg(self.chunks, size=size)
1098
+
1099
+ def copy(self):
1100
+ """Copy array. This is a no-op for dask arrays, which are immutable."""
1101
+ return Array(self._expr)
1102
+
1103
+ def __deepcopy__(self, memo):
1104
+ c = self.copy()
1105
+ memo[id(self)] = c
1106
+ return c
1107
+
1108
+ def to_delayed(self, optimize_graph=True):
1109
+ """Convert into an array of :class:`dask.delayed.Delayed` objects, one per chunk.
1110
+
1111
+ Parameters
1112
+ ----------
1113
+ optimize_graph : bool, optional
1114
+ If True [default], the graph is optimized before converting into
1115
+ :class:`dask.delayed.Delayed` objects.
1116
+
1117
+ See Also
1118
+ --------
1119
+ dask.array.from_delayed
1120
+ """
1121
+ from dask.delayed import Delayed
1122
+ from dask.utils import ndeepmap
1123
+
1124
+ keys = self.__dask_keys__()
1125
+ graph = self.__dask_graph__()
1126
+ if optimize_graph:
1127
+ graph = self.__dask_optimize__(graph, keys)
1128
+ L = ndeepmap(self.ndim, lambda k: Delayed(k, graph), keys)
1129
+ return np.array(L, dtype=object)
1130
+
1131
+ def to_dask_dataframe(self, columns=None, index=None, meta=None):
1132
+ """Convert dask Array to dask Dataframe
1133
+
1134
+ Parameters
1135
+ ----------
1136
+ columns: list or string
1137
+ list of column names if DataFrame, single string if Series
1138
+ index : dask.dataframe.Index, optional
1139
+ An optional *dask* Index to use for the output Series or DataFrame.
1140
+
1141
+ The default output index depends on whether the array has any unknown
1142
+ chunks. If there are any unknown chunks, the output has ``None``
1143
+ for all the divisions (one per chunk). If all the chunks are known,
1144
+ a default index with known divisions is created.
1145
+
1146
+ Specifying ``index`` can be useful if you're conforming a Dask Array
1147
+ to an existing dask Series or DataFrame, and you would like the
1148
+ indices to match.
1149
+ meta : object, optional
1150
+ An optional `meta` parameter can be passed for dask
1151
+ to specify the concrete dataframe type to use for partitions of
1152
+ the Dask dataframe. By default, pandas DataFrame is used.
1153
+
1154
+ See Also
1155
+ --------
1156
+ dask.dataframe.from_dask_array
1157
+ """
1158
+ from dask.dataframe.dask_expr._array import from_dask_array_expr
1159
+
1160
+ return from_dask_array_expr(self, columns=columns, index=index, meta=meta)
1161
+
1162
+ def sum(self, axis=None, dtype=None, keepdims=False, split_every=None, out=None):
1163
+ """
1164
+ Return the sum of the array elements over the given axis.
1165
+
1166
+ Refer to :func:`dask.array.sum` for full documentation.
1167
+
1168
+ See Also
1169
+ --------
1170
+ dask.array.sum : equivalent function
1171
+ """
1172
+ from dask_array.reductions import sum
1173
+
1174
+ return sum(
1175
+ self,
1176
+ axis=axis,
1177
+ dtype=dtype,
1178
+ keepdims=keepdims,
1179
+ split_every=split_every,
1180
+ out=out,
1181
+ )
1182
+
1183
+ def mean(self, axis=None, dtype=None, keepdims=False, split_every=None, out=None):
1184
+ """Returns the average of the array elements along given axis.
1185
+
1186
+ Refer to :func:`dask.array.mean` for full documentation.
1187
+
1188
+ See Also
1189
+ --------
1190
+ dask.array.mean : equivalent function
1191
+ """
1192
+ from dask_array.reductions import mean
1193
+
1194
+ return mean(
1195
+ self,
1196
+ axis=axis,
1197
+ dtype=dtype,
1198
+ keepdims=keepdims,
1199
+ split_every=split_every,
1200
+ out=out,
1201
+ )
1202
+
1203
+ def std(self, axis=None, dtype=None, keepdims=False, ddof=0, split_every=None, out=None):
1204
+ """Returns the standard deviation of the array elements along given axis.
1205
+
1206
+ Refer to :func:`dask.array.std` for full documentation.
1207
+
1208
+ See Also
1209
+ --------
1210
+ dask.array.std : equivalent function
1211
+ """
1212
+ from dask_array.reductions import std
1213
+
1214
+ return std(
1215
+ self,
1216
+ axis=axis,
1217
+ dtype=dtype,
1218
+ keepdims=keepdims,
1219
+ ddof=ddof,
1220
+ split_every=split_every,
1221
+ out=out,
1222
+ )
1223
+
1224
+ def var(self, axis=None, dtype=None, keepdims=False, ddof=0, split_every=None, out=None):
1225
+ """Returns the variance of the array elements, along given axis.
1226
+
1227
+ Refer to :func:`dask.array.var` for full documentation.
1228
+
1229
+ See Also
1230
+ --------
1231
+ dask.array.var : equivalent function
1232
+ """
1233
+ from dask_array.reductions import var
1234
+
1235
+ return var(
1236
+ self,
1237
+ axis=axis,
1238
+ dtype=dtype,
1239
+ keepdims=keepdims,
1240
+ ddof=ddof,
1241
+ split_every=split_every,
1242
+ out=out,
1243
+ )
1244
+
1245
+ def moment(
1246
+ self,
1247
+ order,
1248
+ axis=None,
1249
+ dtype=None,
1250
+ keepdims=False,
1251
+ ddof=0,
1252
+ split_every=None,
1253
+ out=None,
1254
+ ):
1255
+ """Calculate the nth centralized moment.
1256
+
1257
+ Refer to :func:`dask.array.moment` for the full documentation.
1258
+
1259
+ See Also
1260
+ --------
1261
+ dask.array.moment : equivalent function
1262
+ """
1263
+ from dask_array.reductions import moment
1264
+
1265
+ return moment(
1266
+ self,
1267
+ order,
1268
+ axis=axis,
1269
+ dtype=dtype,
1270
+ keepdims=keepdims,
1271
+ ddof=ddof,
1272
+ split_every=split_every,
1273
+ out=out,
1274
+ )
1275
+
1276
+ def prod(self, axis=None, dtype=None, keepdims=False, split_every=None, out=None):
1277
+ """Return the product of the array elements over the given axis
1278
+
1279
+ Refer to :func:`dask.array.prod` for full documentation.
1280
+
1281
+ See Also
1282
+ --------
1283
+ dask.array.prod : equivalent function
1284
+ """
1285
+ from dask_array.reductions import prod
1286
+
1287
+ return prod(
1288
+ self,
1289
+ axis=axis,
1290
+ dtype=dtype,
1291
+ keepdims=keepdims,
1292
+ split_every=split_every,
1293
+ out=out,
1294
+ )
1295
+
1296
+ def any(self, axis=None, keepdims=False, split_every=None, out=None):
1297
+ """Returns True if any of the elements evaluate to True.
1298
+
1299
+ Refer to :func:`dask.array.any` for full documentation.
1300
+
1301
+ See Also
1302
+ --------
1303
+ dask.array.any : equivalent function
1304
+ """
1305
+ from dask_array.reductions import any
1306
+
1307
+ return any(self, axis=axis, keepdims=keepdims, split_every=split_every, out=out)
1308
+
1309
+ def all(self, axis=None, keepdims=False, split_every=None, out=None):
1310
+ """Returns True if all elements evaluate to True.
1311
+
1312
+ Refer to :func:`dask.array.all` for full documentation.
1313
+
1314
+ See Also
1315
+ --------
1316
+ dask.array.all : equivalent function
1317
+ """
1318
+ from dask_array.reductions import all
1319
+
1320
+ return all(self, axis=axis, keepdims=keepdims, split_every=split_every, out=out)
1321
+
1322
+ def min(self, axis=None, keepdims=False, split_every=None, out=None):
1323
+ """Return the minimum along a given axis.
1324
+
1325
+ Refer to :func:`dask.array.min` for full documentation.
1326
+
1327
+ See Also
1328
+ --------
1329
+ dask.array.min : equivalent function
1330
+ """
1331
+ from dask_array.reductions import min
1332
+
1333
+ return min(self, axis=axis, keepdims=keepdims, split_every=split_every, out=out)
1334
+
1335
+ def max(self, axis=None, keepdims=False, split_every=None, out=None):
1336
+ """Return the maximum along a given axis.
1337
+
1338
+ Refer to :func:`dask.array.max` for full documentation.
1339
+
1340
+ See Also
1341
+ --------
1342
+ dask.array.max : equivalent function
1343
+ """
1344
+ from dask_array.reductions import max
1345
+
1346
+ return max(self, axis=axis, keepdims=keepdims, split_every=split_every, out=out)
1347
+
1348
+ def argmin(self, axis=None, *, keepdims=False, split_every=None, out=None):
1349
+ """Return indices of the minimum values along the given axis.
1350
+
1351
+ Refer to :func:`dask.array.argmin` for full documentation.
1352
+
1353
+ See Also
1354
+ --------
1355
+ dask.array.argmin : equivalent function
1356
+ """
1357
+ from dask_array.reductions import argmin
1358
+
1359
+ return argmin(self, axis=axis, keepdims=keepdims, split_every=split_every, out=out)
1360
+
1361
+ def argmax(self, axis=None, *, keepdims=False, split_every=None, out=None):
1362
+ """Return indices of the maximum values along the given axis.
1363
+
1364
+ Refer to :func:`dask.array.argmax` for full documentation.
1365
+
1366
+ See Also
1367
+ --------
1368
+ dask.array.argmax : equivalent function
1369
+ """
1370
+ from dask_array.reductions import argmax
1371
+
1372
+ return argmax(self, axis=axis, keepdims=keepdims, split_every=split_every, out=out)
1373
+
1374
+ def topk(self, k, axis=-1, split_every=None):
1375
+ """The top k elements of an array.
1376
+
1377
+ Refer to :func:`dask.array.topk` for full documentation.
1378
+
1379
+ See Also
1380
+ --------
1381
+ dask.array.topk : equivalent function
1382
+ """
1383
+ from dask_array._routines import topk
1384
+
1385
+ return topk(self, k, axis=axis, split_every=split_every)
1386
+
1387
+ def argtopk(self, k, axis=-1, split_every=None):
1388
+ """The indices of the top k elements of an array.
1389
+
1390
+ Refer to :func:`dask.array.argtopk` for full documentation.
1391
+
1392
+ See Also
1393
+ --------
1394
+ dask.array.argtopk : equivalent function
1395
+ """
1396
+ from dask_array._routines import argtopk
1397
+
1398
+ return argtopk(self, k, axis=axis, split_every=split_every)
1399
+
1400
+ def cumsum(self, axis, dtype=None, out=None, *, method="sequential"):
1401
+ """Return the cumulative sum of the elements along the given axis.
1402
+
1403
+ Refer to :func:`dask.array.cumsum` for full documentation.
1404
+
1405
+ See Also
1406
+ --------
1407
+ dask.array.cumsum : equivalent function
1408
+ """
1409
+ from dask_array.reductions import cumsum
1410
+
1411
+ return cumsum(self, axis=axis, dtype=dtype, out=out, method=method)
1412
+
1413
+ def cumprod(self, axis, dtype=None, out=None, *, method="sequential"):
1414
+ """Return the cumulative product of the elements along the given axis.
1415
+
1416
+ Refer to :func:`dask.array.cumprod` for full documentation.
1417
+
1418
+ See Also
1419
+ --------
1420
+ dask.array.cumprod : equivalent function
1421
+ """
1422
+ from dask_array.reductions import cumprod
1423
+
1424
+ return cumprod(self, axis=axis, dtype=dtype, out=out, method=method)
1425
+
1426
+ def trace(self, offset=0, axis1=0, axis2=1, dtype=None):
1427
+ """Return the sum along diagonals of the array.
1428
+
1429
+ Refer to :func:`dask.array.trace` for full documentation.
1430
+
1431
+ See Also
1432
+ --------
1433
+ dask.array.trace : equivalent function
1434
+ """
1435
+ from dask_array.reductions import trace
1436
+
1437
+ return trace(self, offset=offset, axis1=axis1, axis2=axis2, dtype=dtype)
1438
+
1439
+ def dot(self, other):
1440
+ """Dot product of self and other.
1441
+
1442
+ Refer to :func:`dask.array.tensordot` for full documentation.
1443
+
1444
+ See Also
1445
+ --------
1446
+ dask.array.dot : equivalent function
1447
+ """
1448
+ from dask_array.linalg import tensordot
1449
+
1450
+ return tensordot(self, other, axes=((self.ndim - 1,), (other.ndim - 2,)))
1451
+
1452
+ def astype(self, dtype, **kwargs):
1453
+ """Copy of the array, cast to a specified type.
1454
+
1455
+ Parameters
1456
+ ----------
1457
+ dtype : str or dtype
1458
+ Typecode or data-type to which the array is cast.
1459
+ casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
1460
+ Controls what kind of data casting may occur. Defaults to 'unsafe'
1461
+ for backwards compatibility.
1462
+
1463
+ * 'no' means the data types should not be cast at all.
1464
+ * 'equiv' means only byte-order changes are allowed.
1465
+ * 'safe' means only casts which can preserve values are allowed.
1466
+ * 'same_kind' means only safe casts or casts within a kind,
1467
+ like float64 to float32, are allowed.
1468
+ * 'unsafe' means any data conversions may be done.
1469
+ copy : bool, optional
1470
+ By default, astype always returns a newly allocated array. If this
1471
+ is set to False and the `dtype` requirement is satisfied, the input
1472
+ array is returned instead of a copy.
1473
+
1474
+ .. note::
1475
+
1476
+ Dask does not respect the contiguous memory layout of the array,
1477
+ and will ignore the ``order`` keyword argument.
1478
+ The default order is 'C' contiguous.
1479
+ """
1480
+ kwargs.pop("order", None) # `order` is not respected, so we remove this kwarg
1481
+ # Scalars don't take `casting` or `copy` kwargs - as such we only pass
1482
+ # them to `map_blocks` if specified by user (different than defaults).
1483
+ extra = set(kwargs) - {"casting", "copy"}
1484
+ if extra:
1485
+ raise TypeError(f"astype does not take the following keyword arguments: {list(extra)}")
1486
+ casting = kwargs.get("casting", "unsafe")
1487
+ dtype = np.dtype(dtype)
1488
+ if self.dtype == dtype:
1489
+ return self
1490
+ elif not np.can_cast(self.dtype, dtype, casting=casting):
1491
+ raise TypeError(f"Cannot cast array from {self.dtype!r} to {dtype!r} according to the rule {casting!r}")
1492
+ return elemwise(chunk.astype, self, dtype=dtype, astype_dtype=dtype, **kwargs)
1493
+
1494
+ def map_blocks(self, func, *args, **kwargs):
1495
+ from dask_array._map_blocks import map_blocks
1496
+
1497
+ return map_blocks(func, self, *args, **kwargs)
1498
+
1499
+ @property
1500
+ def _elemwise(self):
1501
+ return elemwise
1502
+
1503
+ @property
1504
+ def real(self):
1505
+ from dask_array._ufunc import real
1506
+
1507
+ return real(self)
1508
+
1509
+ @property
1510
+ def imag(self):
1511
+ from dask_array._ufunc import imag
1512
+
1513
+ return imag(self)
1514
+
1515
+ def conj(self):
1516
+ """Complex-conjugate all elements.
1517
+
1518
+ Refer to :func:`dask.array.conj` for full documentation.
1519
+
1520
+ See Also
1521
+ --------
1522
+ dask.array.conj : equivalent function
1523
+ """
1524
+ from dask_array._ufunc import conj
1525
+
1526
+ return conj(self)
1527
+
1528
+ def clip(self, min=None, max=None):
1529
+ """Return an array whose values are limited to ``[min, max]``.
1530
+ One of max or min must be given.
1531
+
1532
+ Refer to :func:`dask.array.clip` for full documentation.
1533
+
1534
+ See Also
1535
+ --------
1536
+ dask.array.clip : equivalent function
1537
+ """
1538
+ from dask_array._ufunc import clip
1539
+
1540
+ return clip(self, min, max)
1541
+
1542
+ def view(self, dtype=None, order="C"):
1543
+ """Get a view of the array as a new data type
1544
+
1545
+ Parameters
1546
+ ----------
1547
+ dtype:
1548
+ The dtype by which to view the array.
1549
+ The default, None, results in the view having the same data-type
1550
+ as the original array.
1551
+ order: string
1552
+ 'C' or 'F' (Fortran) ordering
1553
+
1554
+ This reinterprets the bytes of the array under a new dtype. If that
1555
+ dtype does not have the same size as the original array then the shape
1556
+ will change.
1557
+
1558
+ Beware that both numpy and dask.array can behave oddly when taking
1559
+ shape-changing views of arrays under Fortran ordering. Under some
1560
+ versions of NumPy this function will fail when taking shape-changing
1561
+ views of Fortran ordered arrays if the first dimension has chunks of
1562
+ size one.
1563
+ """
1564
+ if dtype is None:
1565
+ dtype = self.dtype
1566
+ else:
1567
+ dtype = np.dtype(dtype)
1568
+ mult = self.dtype.itemsize / dtype.itemsize
1569
+
1570
+ def _ensure_int(f):
1571
+ i = int(f)
1572
+ if i != f:
1573
+ raise ValueError(f"Could not coerce {f:f} to integer")
1574
+ return i
1575
+
1576
+ if order == "C":
1577
+ chunks = self.chunks[:-1] + (tuple(_ensure_int(c * mult) for c in self.chunks[-1]),)
1578
+ elif order == "F":
1579
+ chunks = (tuple(_ensure_int(c * mult) for c in self.chunks[0]),) + self.chunks[1:]
1580
+ else:
1581
+ raise ValueError("Order must be one of 'C' or 'F'")
1582
+
1583
+ return self.map_blocks(chunk.view, dtype, order=order, dtype=dtype, chunks=chunks)
1584
+
1585
+ def __array_ufunc__(self, numpy_ufunc, method, *inputs, **kwargs):
1586
+ out = kwargs.get("out", ())
1587
+ for x in inputs + out:
1588
+ if _should_delegate(self, x):
1589
+ return NotImplemented
1590
+
1591
+ if method == "__call__":
1592
+ if numpy_ufunc is np.matmul:
1593
+ from dask_array.linalg import matmul
1594
+
1595
+ # special case until apply_gufunc handles optional dimensions
1596
+ return matmul(*inputs, **kwargs)
1597
+ if numpy_ufunc.signature is not None:
1598
+ from dask_array._gufunc import apply_gufunc
1599
+
1600
+ return apply_gufunc(numpy_ufunc, numpy_ufunc.signature, *inputs, **kwargs)
1601
+ if numpy_ufunc.nout > 1:
1602
+ from dask_array import _ufunc as ufunc
1603
+
1604
+ try:
1605
+ da_ufunc = getattr(ufunc, numpy_ufunc.__name__)
1606
+ except AttributeError:
1607
+ return NotImplemented
1608
+ return da_ufunc(*inputs, **kwargs)
1609
+ else:
1610
+ return elemwise(numpy_ufunc, *inputs, **kwargs)
1611
+ elif method == "outer":
1612
+ from dask_array import _ufunc as ufunc
1613
+
1614
+ try:
1615
+ da_ufunc = getattr(ufunc, numpy_ufunc.__name__)
1616
+ except AttributeError:
1617
+ return NotImplemented
1618
+ return da_ufunc.outer(*inputs, **kwargs)
1619
+ else:
1620
+ return NotImplemented
1621
+
1622
+ def map_overlap(self, func, depth, boundary=None, trim=True, **kwargs):
1623
+ """Map a function over blocks of the array with some overlap
1624
+
1625
+ Refer to :func:`dask.array.map_overlap` for full documentation.
1626
+
1627
+ See Also
1628
+ --------
1629
+ dask.array.map_overlap : equivalent function
1630
+ """
1631
+ from dask_array._overlap import map_overlap
1632
+
1633
+ return map_overlap(func, self, depth=depth, boundary=boundary, trim=trim, **kwargs)
1634
+
1635
+
1636
+ # Import rechunk, reshape, ravel from their modules
1637
+ from dask_array._rechunk import rechunk
1638
+ from dask_array._reshape import ravel, reshape, reshape_blockwise
1639
+
1640
+ # Import swapaxes
1641
+ from dask_array.manipulation._transpose import swapaxes
1642
+
1643
+ # Import squeeze from its module
1644
+ from dask_array.slicing import squeeze