Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numpy/lib/_shape_base_impl.py: 24%
254 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-09 06:12 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-09 06:12 +0000
1import functools
2import warnings
4import numpy._core.numeric as _nx
5from numpy._core.numeric import asarray, zeros, zeros_like, array, asanyarray
6from numpy._core.fromnumeric import reshape, transpose
7from numpy._core.multiarray import normalize_axis_index
8from numpy._core._multiarray_umath import _array_converter
9from numpy._core import overrides
10from numpy._core import vstack, atleast_3d
11from numpy._core.numeric import normalize_axis_tuple
12from numpy._core.overrides import set_module
13from numpy._core.shape_base import _arrays_for_stack_dispatcher
14from numpy.lib._index_tricks_impl import ndindex
15from numpy.matrixlib.defmatrix import matrix # this raises all the right alarm bells
18__all__ = [
19 'column_stack', 'row_stack', 'dstack', 'array_split', 'split',
20 'hsplit', 'vsplit', 'dsplit', 'apply_over_axes', 'expand_dims',
21 'apply_along_axis', 'kron', 'tile', 'take_along_axis',
22 'put_along_axis'
23 ]
26array_function_dispatch = functools.partial(
27 overrides.array_function_dispatch, module='numpy')
30def _make_along_axis_idx(arr_shape, indices, axis):
31 # compute dimensions to iterate over
32 if not _nx.issubdtype(indices.dtype, _nx.integer):
33 raise IndexError('`indices` must be an integer array')
34 if len(arr_shape) != indices.ndim:
35 raise ValueError(
36 "`indices` and `arr` must have the same number of dimensions")
37 shape_ones = (1,) * indices.ndim
38 dest_dims = list(range(axis)) + [None] + list(range(axis+1, indices.ndim))
40 # build a fancy index, consisting of orthogonal aranges, with the
41 # requested index inserted at the right location
42 fancy_index = []
43 for dim, n in zip(dest_dims, arr_shape):
44 if dim is None:
45 fancy_index.append(indices)
46 else:
47 ind_shape = shape_ones[:dim] + (-1,) + shape_ones[dim+1:]
48 fancy_index.append(_nx.arange(n).reshape(ind_shape))
50 return tuple(fancy_index)
53def _take_along_axis_dispatcher(arr, indices, axis):
54 return (arr, indices)
57@array_function_dispatch(_take_along_axis_dispatcher)
58def take_along_axis(arr, indices, axis):
59 """
60 Take values from the input array by matching 1d index and data slices.
62 This iterates over matching 1d slices oriented along the specified axis in
63 the index and data arrays, and uses the former to look up values in the
64 latter. These slices can be different lengths.
66 Functions returning an index along an axis, like `argsort` and
67 `argpartition`, produce suitable indices for this function.
69 .. versionadded:: 1.15.0
71 Parameters
72 ----------
73 arr : ndarray (Ni..., M, Nk...)
74 Source array
75 indices : ndarray (Ni..., J, Nk...)
76 Indices to take along each 1d slice of `arr`. This must match the
77 dimension of arr, but dimensions Ni and Nj only need to broadcast
78 against `arr`.
79 axis : int
80 The axis to take 1d slices along. If axis is None, the input array is
81 treated as if it had first been flattened to 1d, for consistency with
82 `sort` and `argsort`.
84 Returns
85 -------
86 out: ndarray (Ni..., J, Nk...)
87 The indexed result.
89 Notes
90 -----
91 This is equivalent to (but faster than) the following use of `ndindex` and
92 `s_`, which sets each of ``ii`` and ``kk`` to a tuple of indices::
94 Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:]
95 J = indices.shape[axis] # Need not equal M
96 out = np.empty(Ni + (J,) + Nk)
98 for ii in ndindex(Ni):
99 for kk in ndindex(Nk):
100 a_1d = a [ii + s_[:,] + kk]
101 indices_1d = indices[ii + s_[:,] + kk]
102 out_1d = out [ii + s_[:,] + kk]
103 for j in range(J):
104 out_1d[j] = a_1d[indices_1d[j]]
106 Equivalently, eliminating the inner loop, the last two lines would be::
108 out_1d[:] = a_1d[indices_1d]
110 See Also
111 --------
112 take : Take along an axis, using the same indices for every 1d slice
113 put_along_axis :
114 Put values into the destination array by matching 1d index and data slices
116 Examples
117 --------
119 For this sample array
121 >>> a = np.array([[10, 30, 20], [60, 40, 50]])
123 We can sort either by using sort directly, or argsort and this function
125 >>> np.sort(a, axis=1)
126 array([[10, 20, 30],
127 [40, 50, 60]])
128 >>> ai = np.argsort(a, axis=1)
129 >>> ai
130 array([[0, 2, 1],
131 [1, 2, 0]])
132 >>> np.take_along_axis(a, ai, axis=1)
133 array([[10, 20, 30],
134 [40, 50, 60]])
136 The same works for max and min, if you maintain the trivial dimension
137 with ``keepdims``:
139 >>> np.max(a, axis=1, keepdims=True)
140 array([[30],
141 [60]])
142 >>> ai = np.argmax(a, axis=1, keepdims=True)
143 >>> ai
144 array([[1],
145 [0]])
146 >>> np.take_along_axis(a, ai, axis=1)
147 array([[30],
148 [60]])
150 If we want to get the max and min at the same time, we can stack the
151 indices first
153 >>> ai_min = np.argmin(a, axis=1, keepdims=True)
154 >>> ai_max = np.argmax(a, axis=1, keepdims=True)
155 >>> ai = np.concatenate([ai_min, ai_max], axis=1)
156 >>> ai
157 array([[0, 1],
158 [1, 0]])
159 >>> np.take_along_axis(a, ai, axis=1)
160 array([[10, 30],
161 [40, 60]])
162 """
163 # normalize inputs
164 if axis is None:
165 arr = arr.flat
166 arr_shape = (len(arr),) # flatiter has no .shape
167 axis = 0
168 else:
169 axis = normalize_axis_index(axis, arr.ndim)
170 arr_shape = arr.shape
172 # use the fancy index
173 return arr[_make_along_axis_idx(arr_shape, indices, axis)]
176def _put_along_axis_dispatcher(arr, indices, values, axis):
177 return (arr, indices, values)
180@array_function_dispatch(_put_along_axis_dispatcher)
181def put_along_axis(arr, indices, values, axis):
182 """
183 Put values into the destination array by matching 1d index and data slices.
185 This iterates over matching 1d slices oriented along the specified axis in
186 the index and data arrays, and uses the former to place values into the
187 latter. These slices can be different lengths.
189 Functions returning an index along an axis, like `argsort` and
190 `argpartition`, produce suitable indices for this function.
192 .. versionadded:: 1.15.0
194 Parameters
195 ----------
196 arr : ndarray (Ni..., M, Nk...)
197 Destination array.
198 indices : ndarray (Ni..., J, Nk...)
199 Indices to change along each 1d slice of `arr`. This must match the
200 dimension of arr, but dimensions in Ni and Nj may be 1 to broadcast
201 against `arr`.
202 values : array_like (Ni..., J, Nk...)
203 values to insert at those indices. Its shape and dimension are
204 broadcast to match that of `indices`.
205 axis : int
206 The axis to take 1d slices along. If axis is None, the destination
207 array is treated as if a flattened 1d view had been created of it.
209 Notes
210 -----
211 This is equivalent to (but faster than) the following use of `ndindex` and
212 `s_`, which sets each of ``ii`` and ``kk`` to a tuple of indices::
214 Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:]
215 J = indices.shape[axis] # Need not equal M
217 for ii in ndindex(Ni):
218 for kk in ndindex(Nk):
219 a_1d = a [ii + s_[:,] + kk]
220 indices_1d = indices[ii + s_[:,] + kk]
221 values_1d = values [ii + s_[:,] + kk]
222 for j in range(J):
223 a_1d[indices_1d[j]] = values_1d[j]
225 Equivalently, eliminating the inner loop, the last two lines would be::
227 a_1d[indices_1d] = values_1d
229 See Also
230 --------
231 take_along_axis :
232 Take values from the input array by matching 1d index and data slices
234 Examples
235 --------
237 For this sample array
239 >>> a = np.array([[10, 30, 20], [60, 40, 50]])
241 We can replace the maximum values with:
243 >>> ai = np.argmax(a, axis=1, keepdims=True)
244 >>> ai
245 array([[1],
246 [0]])
247 >>> np.put_along_axis(a, ai, 99, axis=1)
248 >>> a
249 array([[10, 99, 20],
250 [99, 40, 50]])
252 """
253 # normalize inputs
254 if axis is None:
255 arr = arr.flat
256 axis = 0
257 arr_shape = (len(arr),) # flatiter has no .shape
258 else:
259 axis = normalize_axis_index(axis, arr.ndim)
260 arr_shape = arr.shape
262 # use the fancy index
263 arr[_make_along_axis_idx(arr_shape, indices, axis)] = values
266def _apply_along_axis_dispatcher(func1d, axis, arr, *args, **kwargs):
267 return (arr,)
270@array_function_dispatch(_apply_along_axis_dispatcher)
271def apply_along_axis(func1d, axis, arr, *args, **kwargs):
272 """
273 Apply a function to 1-D slices along the given axis.
275 Execute `func1d(a, *args, **kwargs)` where `func1d` operates on 1-D arrays
276 and `a` is a 1-D slice of `arr` along `axis`.
278 This is equivalent to (but faster than) the following use of `ndindex` and
279 `s_`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of indices::
281 Ni, Nk = a.shape[:axis], a.shape[axis+1:]
282 for ii in ndindex(Ni):
283 for kk in ndindex(Nk):
284 f = func1d(arr[ii + s_[:,] + kk])
285 Nj = f.shape
286 for jj in ndindex(Nj):
287 out[ii + jj + kk] = f[jj]
289 Equivalently, eliminating the inner loop, this can be expressed as::
291 Ni, Nk = a.shape[:axis], a.shape[axis+1:]
292 for ii in ndindex(Ni):
293 for kk in ndindex(Nk):
294 out[ii + s_[...,] + kk] = func1d(arr[ii + s_[:,] + kk])
296 Parameters
297 ----------
298 func1d : function (M,) -> (Nj...)
299 This function should accept 1-D arrays. It is applied to 1-D
300 slices of `arr` along the specified axis.
301 axis : integer
302 Axis along which `arr` is sliced.
303 arr : ndarray (Ni..., M, Nk...)
304 Input array.
305 args : any
306 Additional arguments to `func1d`.
307 kwargs : any
308 Additional named arguments to `func1d`.
310 .. versionadded:: 1.9.0
313 Returns
314 -------
315 out : ndarray (Ni..., Nj..., Nk...)
316 The output array. The shape of `out` is identical to the shape of
317 `arr`, except along the `axis` dimension. This axis is removed, and
318 replaced with new dimensions equal to the shape of the return value
319 of `func1d`. So if `func1d` returns a scalar `out` will have one
320 fewer dimensions than `arr`.
322 See Also
323 --------
324 apply_over_axes : Apply a function repeatedly over multiple axes.
326 Examples
327 --------
328 >>> def my_func(a):
329 ... \"\"\"Average first and last element of a 1-D array\"\"\"
330 ... return (a[0] + a[-1]) * 0.5
331 >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]])
332 >>> np.apply_along_axis(my_func, 0, b)
333 array([4., 5., 6.])
334 >>> np.apply_along_axis(my_func, 1, b)
335 array([2., 5., 8.])
337 For a function that returns a 1D array, the number of dimensions in
338 `outarr` is the same as `arr`.
340 >>> b = np.array([[8,1,7], [4,3,9], [5,2,6]])
341 >>> np.apply_along_axis(sorted, 1, b)
342 array([[1, 7, 8],
343 [3, 4, 9],
344 [2, 5, 6]])
346 For a function that returns a higher dimensional array, those dimensions
347 are inserted in place of the `axis` dimension.
349 >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]])
350 >>> np.apply_along_axis(np.diag, -1, b)
351 array([[[1, 0, 0],
352 [0, 2, 0],
353 [0, 0, 3]],
354 [[4, 0, 0],
355 [0, 5, 0],
356 [0, 0, 6]],
357 [[7, 0, 0],
358 [0, 8, 0],
359 [0, 0, 9]]])
360 """
361 # handle negative axes
362 conv = _array_converter(arr)
363 arr = conv[0]
365 nd = arr.ndim
366 axis = normalize_axis_index(axis, nd)
368 # arr, with the iteration axis at the end
369 in_dims = list(range(nd))
370 inarr_view = transpose(arr, in_dims[:axis] + in_dims[axis+1:] + [axis])
372 # compute indices for the iteration axes, and append a trailing ellipsis to
373 # prevent 0d arrays decaying to scalars, which fixes gh-8642
374 inds = ndindex(inarr_view.shape[:-1])
375 inds = (ind + (Ellipsis,) for ind in inds)
377 # invoke the function on the first item
378 try:
379 ind0 = next(inds)
380 except StopIteration:
381 raise ValueError(
382 'Cannot apply_along_axis when any iteration dimensions are 0'
383 ) from None
384 res = asanyarray(func1d(inarr_view[ind0], *args, **kwargs))
386 # build a buffer for storing evaluations of func1d.
387 # remove the requested axis, and add the new ones on the end.
388 # laid out so that each write is contiguous.
389 # for a tuple index inds, buff[inds] = func1d(inarr_view[inds])
390 if not isinstance(res, matrix):
391 buff = zeros_like(res, shape=inarr_view.shape[:-1] + res.shape)
392 else:
393 # Matrices are nasty with reshaping, so do not preserve them here.
394 buff = zeros(inarr_view.shape[:-1] + res.shape, dtype=res.dtype)
396 # permutation of axes such that out = buff.transpose(buff_permute)
397 buff_dims = list(range(buff.ndim))
398 buff_permute = (
399 buff_dims[0 : axis] +
400 buff_dims[buff.ndim-res.ndim : buff.ndim] +
401 buff_dims[axis : buff.ndim-res.ndim]
402 )
404 # save the first result, then compute and save all remaining results
405 buff[ind0] = res
406 for ind in inds:
407 buff[ind] = asanyarray(func1d(inarr_view[ind], *args, **kwargs))
409 res = transpose(buff, buff_permute)
410 return conv.wrap(res)
413def _apply_over_axes_dispatcher(func, a, axes):
414 return (a,)
417@array_function_dispatch(_apply_over_axes_dispatcher)
418def apply_over_axes(func, a, axes):
419 """
420 Apply a function repeatedly over multiple axes.
422 `func` is called as `res = func(a, axis)`, where `axis` is the first
423 element of `axes`. The result `res` of the function call must have
424 either the same dimensions as `a` or one less dimension. If `res`
425 has one less dimension than `a`, a dimension is inserted before
426 `axis`. The call to `func` is then repeated for each axis in `axes`,
427 with `res` as the first argument.
429 Parameters
430 ----------
431 func : function
432 This function must take two arguments, `func(a, axis)`.
433 a : array_like
434 Input array.
435 axes : array_like
436 Axes over which `func` is applied; the elements must be integers.
438 Returns
439 -------
440 apply_over_axis : ndarray
441 The output array. The number of dimensions is the same as `a`,
442 but the shape can be different. This depends on whether `func`
443 changes the shape of its output with respect to its input.
445 See Also
446 --------
447 apply_along_axis :
448 Apply a function to 1-D slices of an array along the given axis.
450 Notes
451 -----
452 This function is equivalent to tuple axis arguments to reorderable ufuncs
453 with keepdims=True. Tuple axis arguments to ufuncs have been available since
454 version 1.7.0.
456 Examples
457 --------
458 >>> a = np.arange(24).reshape(2,3,4)
459 >>> a
460 array([[[ 0, 1, 2, 3],
461 [ 4, 5, 6, 7],
462 [ 8, 9, 10, 11]],
463 [[12, 13, 14, 15],
464 [16, 17, 18, 19],
465 [20, 21, 22, 23]]])
467 Sum over axes 0 and 2. The result has same number of dimensions
468 as the original array:
470 >>> np.apply_over_axes(np.sum, a, [0,2])
471 array([[[ 60],
472 [ 92],
473 [124]]])
475 Tuple axis arguments to ufuncs are equivalent:
477 >>> np.sum(a, axis=(0,2), keepdims=True)
478 array([[[ 60],
479 [ 92],
480 [124]]])
482 """
483 val = asarray(a)
484 N = a.ndim
485 if array(axes).ndim == 0:
486 axes = (axes,)
487 for axis in axes:
488 if axis < 0:
489 axis = N + axis
490 args = (val, axis)
491 res = func(*args)
492 if res.ndim == val.ndim:
493 val = res
494 else:
495 res = expand_dims(res, axis)
496 if res.ndim == val.ndim:
497 val = res
498 else:
499 raise ValueError("function is not returning "
500 "an array of the correct shape")
501 return val
504def _expand_dims_dispatcher(a, axis):
505 return (a,)
508@array_function_dispatch(_expand_dims_dispatcher)
509def expand_dims(a, axis):
510 """
511 Expand the shape of an array.
513 Insert a new axis that will appear at the `axis` position in the expanded
514 array shape.
516 Parameters
517 ----------
518 a : array_like
519 Input array.
520 axis : int or tuple of ints
521 Position in the expanded axes where the new axis (or axes) is placed.
523 .. deprecated:: 1.13.0
524 Passing an axis where ``axis > a.ndim`` will be treated as
525 ``axis == a.ndim``, and passing ``axis < -a.ndim - 1`` will
526 be treated as ``axis == 0``. This behavior is deprecated.
528 .. versionchanged:: 1.18.0
529 A tuple of axes is now supported. Out of range axes as
530 described above are now forbidden and raise an
531 `~exceptions.AxisError`.
533 Returns
534 -------
535 result : ndarray
536 View of `a` with the number of dimensions increased.
538 See Also
539 --------
540 squeeze : The inverse operation, removing singleton dimensions
541 reshape : Insert, remove, and combine dimensions, and resize existing ones
542 atleast_1d, atleast_2d, atleast_3d
544 Examples
545 --------
546 >>> x = np.array([1, 2])
547 >>> x.shape
548 (2,)
550 The following is equivalent to ``x[np.newaxis, :]`` or ``x[np.newaxis]``:
552 >>> y = np.expand_dims(x, axis=0)
553 >>> y
554 array([[1, 2]])
555 >>> y.shape
556 (1, 2)
558 The following is equivalent to ``x[:, np.newaxis]``:
560 >>> y = np.expand_dims(x, axis=1)
561 >>> y
562 array([[1],
563 [2]])
564 >>> y.shape
565 (2, 1)
567 ``axis`` may also be a tuple:
569 >>> y = np.expand_dims(x, axis=(0, 1))
570 >>> y
571 array([[[1, 2]]])
573 >>> y = np.expand_dims(x, axis=(2, 0))
574 >>> y
575 array([[[1],
576 [2]]])
578 Note that some examples may use ``None`` instead of ``np.newaxis``. These
579 are the same objects:
581 >>> np.newaxis is None
582 True
584 """
585 if isinstance(a, matrix):
586 a = asarray(a)
587 else:
588 a = asanyarray(a)
590 if type(axis) not in (tuple, list):
591 axis = (axis,)
593 out_ndim = len(axis) + a.ndim
594 axis = normalize_axis_tuple(axis, out_ndim)
596 shape_it = iter(a.shape)
597 shape = [1 if ax in axis else next(shape_it) for ax in range(out_ndim)]
599 return a.reshape(shape)
602# NOTE: Remove once deprecation period passes
603@set_module("numpy")
604def row_stack(tup, *, dtype=None, casting="same_kind"):
605 # Deprecated in NumPy 2.0, 2023-08-18
606 warnings.warn(
607 "`row_stack` alias is deprecated. "
608 "Use `np.vstack` directly.",
609 DeprecationWarning,
610 stacklevel=2
611 )
612 return vstack(tup, dtype=dtype, casting=casting)
615row_stack.__doc__ = vstack.__doc__
618def _column_stack_dispatcher(tup):
619 return _arrays_for_stack_dispatcher(tup)
622@array_function_dispatch(_column_stack_dispatcher)
623def column_stack(tup):
624 """
625 Stack 1-D arrays as columns into a 2-D array.
627 Take a sequence of 1-D arrays and stack them as columns
628 to make a single 2-D array. 2-D arrays are stacked as-is,
629 just like with `hstack`. 1-D arrays are turned into 2-D columns
630 first.
632 Parameters
633 ----------
634 tup : sequence of 1-D or 2-D arrays.
635 Arrays to stack. All of them must have the same first dimension.
637 Returns
638 -------
639 stacked : 2-D array
640 The array formed by stacking the given arrays.
642 See Also
643 --------
644 stack, hstack, vstack, concatenate
646 Examples
647 --------
648 >>> a = np.array((1,2,3))
649 >>> b = np.array((2,3,4))
650 >>> np.column_stack((a,b))
651 array([[1, 2],
652 [2, 3],
653 [3, 4]])
655 """
656 arrays = []
657 for v in tup:
658 arr = asanyarray(v)
659 if arr.ndim < 2:
660 arr = array(arr, copy=None, subok=True, ndmin=2).T
661 arrays.append(arr)
662 return _nx.concatenate(arrays, 1)
665def _dstack_dispatcher(tup):
666 return _arrays_for_stack_dispatcher(tup)
669@array_function_dispatch(_dstack_dispatcher)
670def dstack(tup):
671 """
672 Stack arrays in sequence depth wise (along third axis).
674 This is equivalent to concatenation along the third axis after 2-D arrays
675 of shape `(M,N)` have been reshaped to `(M,N,1)` and 1-D arrays of shape
676 `(N,)` have been reshaped to `(1,N,1)`. Rebuilds arrays divided by
677 `dsplit`.
679 This function makes most sense for arrays with up to 3 dimensions. For
680 instance, for pixel-data with a height (first axis), width (second axis),
681 and r/g/b channels (third axis). The functions `concatenate`, `stack` and
682 `block` provide more general stacking and concatenation operations.
684 Parameters
685 ----------
686 tup : sequence of arrays
687 The arrays must have the same shape along all but the third axis.
688 1-D or 2-D arrays must have the same shape.
690 Returns
691 -------
692 stacked : ndarray
693 The array formed by stacking the given arrays, will be at least 3-D.
695 See Also
696 --------
697 concatenate : Join a sequence of arrays along an existing axis.
698 stack : Join a sequence of arrays along a new axis.
699 block : Assemble an nd-array from nested lists of blocks.
700 vstack : Stack arrays in sequence vertically (row wise).
701 hstack : Stack arrays in sequence horizontally (column wise).
702 column_stack : Stack 1-D arrays as columns into a 2-D array.
703 dsplit : Split array along third axis.
705 Examples
706 --------
707 >>> a = np.array((1,2,3))
708 >>> b = np.array((2,3,4))
709 >>> np.dstack((a,b))
710 array([[[1, 2],
711 [2, 3],
712 [3, 4]]])
714 >>> a = np.array([[1],[2],[3]])
715 >>> b = np.array([[2],[3],[4]])
716 >>> np.dstack((a,b))
717 array([[[1, 2]],
718 [[2, 3]],
719 [[3, 4]]])
721 """
722 arrs = atleast_3d(*tup)
723 if not isinstance(arrs, tuple):
724 arrs = (arrs,)
725 return _nx.concatenate(arrs, 2)
728def _replace_zero_by_x_arrays(sub_arys):
729 for i in range(len(sub_arys)):
730 if _nx.ndim(sub_arys[i]) == 0:
731 sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype)
732 elif _nx.sometrue(_nx.equal(_nx.shape(sub_arys[i]), 0)):
733 sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype)
734 return sub_arys
737def _array_split_dispatcher(ary, indices_or_sections, axis=None):
738 return (ary, indices_or_sections)
741@array_function_dispatch(_array_split_dispatcher)
742def array_split(ary, indices_or_sections, axis=0):
743 """
744 Split an array into multiple sub-arrays.
746 Please refer to the ``split`` documentation. The only difference
747 between these functions is that ``array_split`` allows
748 `indices_or_sections` to be an integer that does *not* equally
749 divide the axis. For an array of length l that should be split
750 into n sections, it returns l % n sub-arrays of size l//n + 1
751 and the rest of size l//n.
753 See Also
754 --------
755 split : Split array into multiple sub-arrays of equal size.
757 Examples
758 --------
759 >>> x = np.arange(8.0)
760 >>> np.array_split(x, 3)
761 [array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7.])]
763 >>> x = np.arange(9)
764 >>> np.array_split(x, 4)
765 [array([0, 1, 2]), array([3, 4]), array([5, 6]), array([7, 8])]
767 """
768 try:
769 Ntotal = ary.shape[axis]
770 except AttributeError:
771 Ntotal = len(ary)
772 try:
773 # handle array case.
774 Nsections = len(indices_or_sections) + 1
775 div_points = [0] + list(indices_or_sections) + [Ntotal]
776 except TypeError:
777 # indices_or_sections is a scalar, not an array.
778 Nsections = int(indices_or_sections)
779 if Nsections <= 0:
780 raise ValueError('number sections must be larger than 0.') from None
781 Neach_section, extras = divmod(Ntotal, Nsections)
782 section_sizes = ([0] +
783 extras * [Neach_section+1] +
784 (Nsections-extras) * [Neach_section])
785 div_points = _nx.array(section_sizes, dtype=_nx.intp).cumsum()
787 sub_arys = []
788 sary = _nx.swapaxes(ary, axis, 0)
789 for i in range(Nsections):
790 st = div_points[i]
791 end = div_points[i + 1]
792 sub_arys.append(_nx.swapaxes(sary[st:end], axis, 0))
794 return sub_arys
797def _split_dispatcher(ary, indices_or_sections, axis=None):
798 return (ary, indices_or_sections)
801@array_function_dispatch(_split_dispatcher)
802def split(ary, indices_or_sections, axis=0):
803 """
804 Split an array into multiple sub-arrays as views into `ary`.
806 Parameters
807 ----------
808 ary : ndarray
809 Array to be divided into sub-arrays.
810 indices_or_sections : int or 1-D array
811 If `indices_or_sections` is an integer, N, the array will be divided
812 into N equal arrays along `axis`. If such a split is not possible,
813 an error is raised.
815 If `indices_or_sections` is a 1-D array of sorted integers, the entries
816 indicate where along `axis` the array is split. For example,
817 ``[2, 3]`` would, for ``axis=0``, result in
819 - ary[:2]
820 - ary[2:3]
821 - ary[3:]
823 If an index exceeds the dimension of the array along `axis`,
824 an empty sub-array is returned correspondingly.
825 axis : int, optional
826 The axis along which to split, default is 0.
828 Returns
829 -------
830 sub-arrays : list of ndarrays
831 A list of sub-arrays as views into `ary`.
833 Raises
834 ------
835 ValueError
836 If `indices_or_sections` is given as an integer, but
837 a split does not result in equal division.
839 See Also
840 --------
841 array_split : Split an array into multiple sub-arrays of equal or
842 near-equal size. Does not raise an exception if
843 an equal division cannot be made.
844 hsplit : Split array into multiple sub-arrays horizontally (column-wise).
845 vsplit : Split array into multiple sub-arrays vertically (row wise).
846 dsplit : Split array into multiple sub-arrays along the 3rd axis (depth).
847 concatenate : Join a sequence of arrays along an existing axis.
848 stack : Join a sequence of arrays along a new axis.
849 hstack : Stack arrays in sequence horizontally (column wise).
850 vstack : Stack arrays in sequence vertically (row wise).
851 dstack : Stack arrays in sequence depth wise (along third dimension).
853 Examples
854 --------
855 >>> x = np.arange(9.0)
856 >>> np.split(x, 3)
857 [array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7., 8.])]
859 >>> x = np.arange(8.0)
860 >>> np.split(x, [3, 5, 6, 10])
861 [array([0., 1., 2.]),
862 array([3., 4.]),
863 array([5.]),
864 array([6., 7.]),
865 array([], dtype=float64)]
867 """
868 try:
869 len(indices_or_sections)
870 except TypeError:
871 sections = indices_or_sections
872 N = ary.shape[axis]
873 if N % sections:
874 raise ValueError(
875 'array split does not result in an equal division') from None
876 return array_split(ary, indices_or_sections, axis)
879def _hvdsplit_dispatcher(ary, indices_or_sections):
880 return (ary, indices_or_sections)
883@array_function_dispatch(_hvdsplit_dispatcher)
884def hsplit(ary, indices_or_sections):
885 """
886 Split an array into multiple sub-arrays horizontally (column-wise).
888 Please refer to the `split` documentation. `hsplit` is equivalent
889 to `split` with ``axis=1``, the array is always split along the second
890 axis except for 1-D arrays, where it is split at ``axis=0``.
892 See Also
893 --------
894 split : Split an array into multiple sub-arrays of equal size.
896 Examples
897 --------
898 >>> x = np.arange(16.0).reshape(4, 4)
899 >>> x
900 array([[ 0., 1., 2., 3.],
901 [ 4., 5., 6., 7.],
902 [ 8., 9., 10., 11.],
903 [12., 13., 14., 15.]])
904 >>> np.hsplit(x, 2)
905 [array([[ 0., 1.],
906 [ 4., 5.],
907 [ 8., 9.],
908 [12., 13.]]),
909 array([[ 2., 3.],
910 [ 6., 7.],
911 [10., 11.],
912 [14., 15.]])]
913 >>> np.hsplit(x, np.array([3, 6]))
914 [array([[ 0., 1., 2.],
915 [ 4., 5., 6.],
916 [ 8., 9., 10.],
917 [12., 13., 14.]]),
918 array([[ 3.],
919 [ 7.],
920 [11.],
921 [15.]]),
922 array([], shape=(4, 0), dtype=float64)]
924 With a higher dimensional array the split is still along the second axis.
926 >>> x = np.arange(8.0).reshape(2, 2, 2)
927 >>> x
928 array([[[0., 1.],
929 [2., 3.]],
930 [[4., 5.],
931 [6., 7.]]])
932 >>> np.hsplit(x, 2)
933 [array([[[0., 1.]],
934 [[4., 5.]]]),
935 array([[[2., 3.]],
936 [[6., 7.]]])]
938 With a 1-D array, the split is along axis 0.
940 >>> x = np.array([0, 1, 2, 3, 4, 5])
941 >>> np.hsplit(x, 2)
942 [array([0, 1, 2]), array([3, 4, 5])]
944 """
945 if _nx.ndim(ary) == 0:
946 raise ValueError('hsplit only works on arrays of 1 or more dimensions')
947 if ary.ndim > 1:
948 return split(ary, indices_or_sections, 1)
949 else:
950 return split(ary, indices_or_sections, 0)
953@array_function_dispatch(_hvdsplit_dispatcher)
954def vsplit(ary, indices_or_sections):
955 """
956 Split an array into multiple sub-arrays vertically (row-wise).
958 Please refer to the ``split`` documentation. ``vsplit`` is equivalent
959 to ``split`` with `axis=0` (default), the array is always split along the
960 first axis regardless of the array dimension.
962 See Also
963 --------
964 split : Split an array into multiple sub-arrays of equal size.
966 Examples
967 --------
968 >>> x = np.arange(16.0).reshape(4, 4)
969 >>> x
970 array([[ 0., 1., 2., 3.],
971 [ 4., 5., 6., 7.],
972 [ 8., 9., 10., 11.],
973 [12., 13., 14., 15.]])
974 >>> np.vsplit(x, 2)
975 [array([[0., 1., 2., 3.],
976 [4., 5., 6., 7.]]),
977 array([[ 8., 9., 10., 11.],
978 [12., 13., 14., 15.]])]
979 >>> np.vsplit(x, np.array([3, 6]))
980 [array([[ 0., 1., 2., 3.],
981 [ 4., 5., 6., 7.],
982 [ 8., 9., 10., 11.]]),
983 array([[12., 13., 14., 15.]]),
984 array([], shape=(0, 4), dtype=float64)]
986 With a higher dimensional array the split is still along the first axis.
988 >>> x = np.arange(8.0).reshape(2, 2, 2)
989 >>> x
990 array([[[0., 1.],
991 [2., 3.]],
992 [[4., 5.],
993 [6., 7.]]])
994 >>> np.vsplit(x, 2)
995 [array([[[0., 1.],
996 [2., 3.]]]),
997 array([[[4., 5.],
998 [6., 7.]]])]
1000 """
1001 if _nx.ndim(ary) < 2:
1002 raise ValueError('vsplit only works on arrays of 2 or more dimensions')
1003 return split(ary, indices_or_sections, 0)
1006@array_function_dispatch(_hvdsplit_dispatcher)
1007def dsplit(ary, indices_or_sections):
1008 """
1009 Split array into multiple sub-arrays along the 3rd axis (depth).
1011 Please refer to the `split` documentation. `dsplit` is equivalent
1012 to `split` with ``axis=2``, the array is always split along the third
1013 axis provided the array dimension is greater than or equal to 3.
1015 See Also
1016 --------
1017 split : Split an array into multiple sub-arrays of equal size.
1019 Examples
1020 --------
1021 >>> x = np.arange(16.0).reshape(2, 2, 4)
1022 >>> x
1023 array([[[ 0., 1., 2., 3.],
1024 [ 4., 5., 6., 7.]],
1025 [[ 8., 9., 10., 11.],
1026 [12., 13., 14., 15.]]])
1027 >>> np.dsplit(x, 2)
1028 [array([[[ 0., 1.],
1029 [ 4., 5.]],
1030 [[ 8., 9.],
1031 [12., 13.]]]), array([[[ 2., 3.],
1032 [ 6., 7.]],
1033 [[10., 11.],
1034 [14., 15.]]])]
1035 >>> np.dsplit(x, np.array([3, 6]))
1036 [array([[[ 0., 1., 2.],
1037 [ 4., 5., 6.]],
1038 [[ 8., 9., 10.],
1039 [12., 13., 14.]]]),
1040 array([[[ 3.],
1041 [ 7.]],
1042 [[11.],
1043 [15.]]]),
1044 array([], shape=(2, 2, 0), dtype=float64)]
1045 """
1046 if _nx.ndim(ary) < 3:
1047 raise ValueError('dsplit only works on arrays of 3 or more dimensions')
1048 return split(ary, indices_or_sections, 2)
1051def get_array_wrap(*args):
1052 """Find the wrapper for the array with the highest priority.
1054 In case of ties, leftmost wins. If no wrapper is found, return None.
1056 .. deprecated:: 2.0
1057 """
1059 # Deprecated in NumPy 2.0, 2023-07-11
1060 warnings.warn(
1061 "`get_array_wrap` is deprecated. "
1062 "(deprecated in NumPy 2.0)",
1063 DeprecationWarning,
1064 stacklevel=2
1065 )
1067 wrappers = sorted((getattr(x, '__array_priority__', 0), -i,
1068 x.__array_wrap__) for i, x in enumerate(args)
1069 if hasattr(x, '__array_wrap__'))
1070 if wrappers:
1071 return wrappers[-1][-1]
1072 return None
1075def _kron_dispatcher(a, b):
1076 return (a, b)
1079@array_function_dispatch(_kron_dispatcher)
1080def kron(a, b):
1081 """
1082 Kronecker product of two arrays.
1084 Computes the Kronecker product, a composite array made of blocks of the
1085 second array scaled by the first.
1087 Parameters
1088 ----------
1089 a, b : array_like
1091 Returns
1092 -------
1093 out : ndarray
1095 See Also
1096 --------
1097 outer : The outer product
1099 Notes
1100 -----
1101 The function assumes that the number of dimensions of `a` and `b`
1102 are the same, if necessary prepending the smallest with ones.
1103 If ``a.shape = (r0,r1,..,rN)`` and ``b.shape = (s0,s1,...,sN)``,
1104 the Kronecker product has shape ``(r0*s0, r1*s1, ..., rN*SN)``.
1105 The elements are products of elements from `a` and `b`, organized
1106 explicitly by::
1108 kron(a,b)[k0,k1,...,kN] = a[i0,i1,...,iN] * b[j0,j1,...,jN]
1110 where::
1112 kt = it * st + jt, t = 0,...,N
1114 In the common 2-D case (N=1), the block structure can be visualized::
1116 [[ a[0,0]*b, a[0,1]*b, ... , a[0,-1]*b ],
1117 [ ... ... ],
1118 [ a[-1,0]*b, a[-1,1]*b, ... , a[-1,-1]*b ]]
1121 Examples
1122 --------
1123 >>> np.kron([1,10,100], [5,6,7])
1124 array([ 5, 6, 7, ..., 500, 600, 700])
1125 >>> np.kron([5,6,7], [1,10,100])
1126 array([ 5, 50, 500, ..., 7, 70, 700])
1128 >>> np.kron(np.eye(2), np.ones((2,2)))
1129 array([[1., 1., 0., 0.],
1130 [1., 1., 0., 0.],
1131 [0., 0., 1., 1.],
1132 [0., 0., 1., 1.]])
1134 >>> a = np.arange(100).reshape((2,5,2,5))
1135 >>> b = np.arange(24).reshape((2,3,4))
1136 >>> c = np.kron(a,b)
1137 >>> c.shape
1138 (2, 10, 6, 20)
1139 >>> I = (1,3,0,2)
1140 >>> J = (0,2,1)
1141 >>> J1 = (0,) + J # extend to ndim=4
1142 >>> S1 = (1,) + b.shape
1143 >>> K = tuple(np.array(I) * np.array(S1) + np.array(J1))
1144 >>> c[K] == a[I]*b[J]
1145 True
1147 """
1148 # Working:
1149 # 1. Equalise the shapes by prepending smaller array with 1s
1150 # 2. Expand shapes of both the arrays by adding new axes at
1151 # odd positions for 1st array and even positions for 2nd
1152 # 3. Compute the product of the modified array
1153 # 4. The inner most array elements now contain the rows of
1154 # the Kronecker product
1155 # 5. Reshape the result to kron's shape, which is same as
1156 # product of shapes of the two arrays.
1157 b = asanyarray(b)
1158 a = array(a, copy=None, subok=True, ndmin=b.ndim)
1159 is_any_mat = isinstance(a, matrix) or isinstance(b, matrix)
1160 ndb, nda = b.ndim, a.ndim
1161 nd = max(ndb, nda)
1163 if (nda == 0 or ndb == 0):
1164 return _nx.multiply(a, b)
1166 as_ = a.shape
1167 bs = b.shape
1168 if not a.flags.contiguous:
1169 a = reshape(a, as_)
1170 if not b.flags.contiguous:
1171 b = reshape(b, bs)
1173 # Equalise the shapes by prepending smaller one with 1s
1174 as_ = (1,)*max(0, ndb-nda) + as_
1175 bs = (1,)*max(0, nda-ndb) + bs
1177 # Insert empty dimensions
1178 a_arr = expand_dims(a, axis=tuple(range(ndb-nda)))
1179 b_arr = expand_dims(b, axis=tuple(range(nda-ndb)))
1181 # Compute the product
1182 a_arr = expand_dims(a_arr, axis=tuple(range(1, nd*2, 2)))
1183 b_arr = expand_dims(b_arr, axis=tuple(range(0, nd*2, 2)))
1184 # In case of `mat`, convert result to `array`
1185 result = _nx.multiply(a_arr, b_arr, subok=(not is_any_mat))
1187 # Reshape back
1188 result = result.reshape(_nx.multiply(as_, bs))
1190 return result if not is_any_mat else matrix(result, copy=False)
1193def _tile_dispatcher(A, reps):
1194 return (A, reps)
1197@array_function_dispatch(_tile_dispatcher)
1198def tile(A, reps):
1199 """
1200 Construct an array by repeating A the number of times given by reps.
1202 If `reps` has length ``d``, the result will have dimension of
1203 ``max(d, A.ndim)``.
1205 If ``A.ndim < d``, `A` is promoted to be d-dimensional by prepending new
1206 axes. So a shape (3,) array is promoted to (1, 3) for 2-D replication,
1207 or shape (1, 1, 3) for 3-D replication. If this is not the desired
1208 behavior, promote `A` to d-dimensions manually before calling this
1209 function.
1211 If ``A.ndim > d``, `reps` is promoted to `A`.ndim by prepending 1's to it.
1212 Thus for an `A` of shape (2, 3, 4, 5), a `reps` of (2, 2) is treated as
1213 (1, 1, 2, 2).
1215 Note : Although tile may be used for broadcasting, it is strongly
1216 recommended to use numpy's broadcasting operations and functions.
1218 Parameters
1219 ----------
1220 A : array_like
1221 The input array.
1222 reps : array_like
1223 The number of repetitions of `A` along each axis.
1225 Returns
1226 -------
1227 c : ndarray
1228 The tiled output array.
1230 See Also
1231 --------
1232 repeat : Repeat elements of an array.
1233 broadcast_to : Broadcast an array to a new shape
1235 Examples
1236 --------
1237 >>> a = np.array([0, 1, 2])
1238 >>> np.tile(a, 2)
1239 array([0, 1, 2, 0, 1, 2])
1240 >>> np.tile(a, (2, 2))
1241 array([[0, 1, 2, 0, 1, 2],
1242 [0, 1, 2, 0, 1, 2]])
1243 >>> np.tile(a, (2, 1, 2))
1244 array([[[0, 1, 2, 0, 1, 2]],
1245 [[0, 1, 2, 0, 1, 2]]])
1247 >>> b = np.array([[1, 2], [3, 4]])
1248 >>> np.tile(b, 2)
1249 array([[1, 2, 1, 2],
1250 [3, 4, 3, 4]])
1251 >>> np.tile(b, (2, 1))
1252 array([[1, 2],
1253 [3, 4],
1254 [1, 2],
1255 [3, 4]])
1257 >>> c = np.array([1,2,3,4])
1258 >>> np.tile(c,(4,1))
1259 array([[1, 2, 3, 4],
1260 [1, 2, 3, 4],
1261 [1, 2, 3, 4],
1262 [1, 2, 3, 4]])
1263 """
1264 try:
1265 tup = tuple(reps)
1266 except TypeError:
1267 tup = (reps,)
1268 d = len(tup)
1269 if all(x == 1 for x in tup) and isinstance(A, _nx.ndarray):
1270 # Fixes the problem that the function does not make a copy if A is a
1271 # numpy array and the repetitions are 1 in all dimensions
1272 return _nx.array(A, copy=True, subok=True, ndmin=d)
1273 else:
1274 # Note that no copy of zero-sized arrays is made. However since they
1275 # have no data there is no risk of an inadvertent overwrite.
1276 c = _nx.array(A, copy=None, subok=True, ndmin=d)
1277 if (d < c.ndim):
1278 tup = (1,)*(c.ndim-d) + tup
1279 shape_out = tuple(s*t for s, t in zip(c.shape, tup))
1280 n = c.size
1281 if n > 0:
1282 for dim_in, nrep in zip(c.shape, tup):
1283 if nrep != 1:
1284 c = c.reshape(-1, n).repeat(nrep, 0)
1285 n //= dim_in
1286 return c.reshape(shape_out)