Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numpy/core/shape_base.py: 24%
185 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-03 06:39 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-03 06:39 +0000
1__all__ = ['atleast_1d', 'atleast_2d', 'atleast_3d', 'block', 'hstack',
2 'stack', 'vstack']
4import functools
5import itertools
6import operator
7import warnings
9from . import numeric as _nx
10from . import overrides
11from .multiarray import array, asanyarray, normalize_axis_index
12from . import fromnumeric as _from_nx
15array_function_dispatch = functools.partial(
16 overrides.array_function_dispatch, module='numpy')
19def _atleast_1d_dispatcher(*arys):
20 return arys
23@array_function_dispatch(_atleast_1d_dispatcher)
24def atleast_1d(*arys):
25 """
26 Convert inputs to arrays with at least one dimension.
28 Scalar inputs are converted to 1-dimensional arrays, whilst
29 higher-dimensional inputs are preserved.
31 Parameters
32 ----------
33 arys1, arys2, ... : array_like
34 One or more input arrays.
36 Returns
37 -------
38 ret : ndarray
39 An array, or list of arrays, each with ``a.ndim >= 1``.
40 Copies are made only if necessary.
42 See Also
43 --------
44 atleast_2d, atleast_3d
46 Examples
47 --------
48 >>> np.atleast_1d(1.0)
49 array([1.])
51 >>> x = np.arange(9.0).reshape(3,3)
52 >>> np.atleast_1d(x)
53 array([[0., 1., 2.],
54 [3., 4., 5.],
55 [6., 7., 8.]])
56 >>> np.atleast_1d(x) is x
57 True
59 >>> np.atleast_1d(1, [3, 4])
60 [array([1]), array([3, 4])]
62 """
63 res = []
64 for ary in arys:
65 ary = asanyarray(ary)
66 if ary.ndim == 0:
67 result = ary.reshape(1)
68 else:
69 result = ary
70 res.append(result)
71 if len(res) == 1:
72 return res[0]
73 else:
74 return res
77def _atleast_2d_dispatcher(*arys):
78 return arys
81@array_function_dispatch(_atleast_2d_dispatcher)
82def atleast_2d(*arys):
83 """
84 View inputs as arrays with at least two dimensions.
86 Parameters
87 ----------
88 arys1, arys2, ... : array_like
89 One or more array-like sequences. Non-array inputs are converted
90 to arrays. Arrays that already have two or more dimensions are
91 preserved.
93 Returns
94 -------
95 res, res2, ... : ndarray
96 An array, or list of arrays, each with ``a.ndim >= 2``.
97 Copies are avoided where possible, and views with two or more
98 dimensions are returned.
100 See Also
101 --------
102 atleast_1d, atleast_3d
104 Examples
105 --------
106 >>> np.atleast_2d(3.0)
107 array([[3.]])
109 >>> x = np.arange(3.0)
110 >>> np.atleast_2d(x)
111 array([[0., 1., 2.]])
112 >>> np.atleast_2d(x).base is x
113 True
115 >>> np.atleast_2d(1, [1, 2], [[1, 2]])
116 [array([[1]]), array([[1, 2]]), array([[1, 2]])]
118 """
119 res = []
120 for ary in arys:
121 ary = asanyarray(ary)
122 if ary.ndim == 0:
123 result = ary.reshape(1, 1)
124 elif ary.ndim == 1:
125 result = ary[_nx.newaxis, :]
126 else:
127 result = ary
128 res.append(result)
129 if len(res) == 1:
130 return res[0]
131 else:
132 return res
135def _atleast_3d_dispatcher(*arys):
136 return arys
139@array_function_dispatch(_atleast_3d_dispatcher)
140def atleast_3d(*arys):
141 """
142 View inputs as arrays with at least three dimensions.
144 Parameters
145 ----------
146 arys1, arys2, ... : array_like
147 One or more array-like sequences. Non-array inputs are converted to
148 arrays. Arrays that already have three or more dimensions are
149 preserved.
151 Returns
152 -------
153 res1, res2, ... : ndarray
154 An array, or list of arrays, each with ``a.ndim >= 3``. Copies are
155 avoided where possible, and views with three or more dimensions are
156 returned. For example, a 1-D array of shape ``(N,)`` becomes a view
157 of shape ``(1, N, 1)``, and a 2-D array of shape ``(M, N)`` becomes a
158 view of shape ``(M, N, 1)``.
160 See Also
161 --------
162 atleast_1d, atleast_2d
164 Examples
165 --------
166 >>> np.atleast_3d(3.0)
167 array([[[3.]]])
169 >>> x = np.arange(3.0)
170 >>> np.atleast_3d(x).shape
171 (1, 3, 1)
173 >>> x = np.arange(12.0).reshape(4,3)
174 >>> np.atleast_3d(x).shape
175 (4, 3, 1)
176 >>> np.atleast_3d(x).base is x.base # x is a reshape, so not base itself
177 True
179 >>> for arr in np.atleast_3d([1, 2], [[1, 2]], [[[1, 2]]]):
180 ... print(arr, arr.shape) # doctest: +SKIP
181 ...
182 [[[1]
183 [2]]] (1, 2, 1)
184 [[[1]
185 [2]]] (1, 2, 1)
186 [[[1 2]]] (1, 1, 2)
188 """
189 res = []
190 for ary in arys:
191 ary = asanyarray(ary)
192 if ary.ndim == 0:
193 result = ary.reshape(1, 1, 1)
194 elif ary.ndim == 1:
195 result = ary[_nx.newaxis, :, _nx.newaxis]
196 elif ary.ndim == 2:
197 result = ary[:, :, _nx.newaxis]
198 else:
199 result = ary
200 res.append(result)
201 if len(res) == 1:
202 return res[0]
203 else:
204 return res
207def _arrays_for_stack_dispatcher(arrays):
208 if not hasattr(arrays, "__getitem__"):
209 raise TypeError('arrays to stack must be passed as a "sequence" type '
210 'such as list or tuple.')
212 return tuple(arrays)
215def _vhstack_dispatcher(tup, *, dtype=None, casting=None):
216 return _arrays_for_stack_dispatcher(tup)
219@array_function_dispatch(_vhstack_dispatcher)
220def vstack(tup, *, dtype=None, casting="same_kind"):
221 """
222 Stack arrays in sequence vertically (row wise).
224 This is equivalent to concatenation along the first axis after 1-D arrays
225 of shape `(N,)` have been reshaped to `(1,N)`. Rebuilds arrays divided by
226 `vsplit`.
228 This function makes most sense for arrays with up to 3 dimensions. For
229 instance, for pixel-data with a height (first axis), width (second axis),
230 and r/g/b channels (third axis). The functions `concatenate`, `stack` and
231 `block` provide more general stacking and concatenation operations.
233 ``np.row_stack`` is an alias for `vstack`. They are the same function.
235 Parameters
236 ----------
237 tup : sequence of ndarrays
238 The arrays must have the same shape along all but the first axis.
239 1-D arrays must have the same length.
241 dtype : str or dtype
242 If provided, the destination array will have this dtype. Cannot be
243 provided together with `out`.
245 .. versionadded:: 1.24
247 casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
248 Controls what kind of data casting may occur. Defaults to 'same_kind'.
250 .. versionadded:: 1.24
252 Returns
253 -------
254 stacked : ndarray
255 The array formed by stacking the given arrays, will be at least 2-D.
257 See Also
258 --------
259 concatenate : Join a sequence of arrays along an existing axis.
260 stack : Join a sequence of arrays along a new axis.
261 block : Assemble an nd-array from nested lists of blocks.
262 hstack : Stack arrays in sequence horizontally (column wise).
263 dstack : Stack arrays in sequence depth wise (along third axis).
264 column_stack : Stack 1-D arrays as columns into a 2-D array.
265 vsplit : Split an array into multiple sub-arrays vertically (row-wise).
267 Examples
268 --------
269 >>> a = np.array([1, 2, 3])
270 >>> b = np.array([4, 5, 6])
271 >>> np.vstack((a,b))
272 array([[1, 2, 3],
273 [4, 5, 6]])
275 >>> a = np.array([[1], [2], [3]])
276 >>> b = np.array([[4], [5], [6]])
277 >>> np.vstack((a,b))
278 array([[1],
279 [2],
280 [3],
281 [4],
282 [5],
283 [6]])
285 """
286 arrs = atleast_2d(*tup)
287 if not isinstance(arrs, list):
288 arrs = [arrs]
289 return _nx.concatenate(arrs, 0, dtype=dtype, casting=casting)
292@array_function_dispatch(_vhstack_dispatcher)
293def hstack(tup, *, dtype=None, casting="same_kind"):
294 """
295 Stack arrays in sequence horizontally (column wise).
297 This is equivalent to concatenation along the second axis, except for 1-D
298 arrays where it concatenates along the first axis. Rebuilds arrays divided
299 by `hsplit`.
301 This function makes most sense for arrays with up to 3 dimensions. For
302 instance, for pixel-data with a height (first axis), width (second axis),
303 and r/g/b channels (third axis). The functions `concatenate`, `stack` and
304 `block` provide more general stacking and concatenation operations.
306 Parameters
307 ----------
308 tup : sequence of ndarrays
309 The arrays must have the same shape along all but the second axis,
310 except 1-D arrays which can be any length.
312 dtype : str or dtype
313 If provided, the destination array will have this dtype. Cannot be
314 provided together with `out`.
316 .. versionadded:: 1.24
318 casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
319 Controls what kind of data casting may occur. Defaults to 'same_kind'.
321 .. versionadded:: 1.24
323 Returns
324 -------
325 stacked : ndarray
326 The array formed by stacking the given arrays.
328 See Also
329 --------
330 concatenate : Join a sequence of arrays along an existing axis.
331 stack : Join a sequence of arrays along a new axis.
332 block : Assemble an nd-array from nested lists of blocks.
333 vstack : Stack arrays in sequence vertically (row wise).
334 dstack : Stack arrays in sequence depth wise (along third axis).
335 column_stack : Stack 1-D arrays as columns into a 2-D array.
336 hsplit : Split an array into multiple sub-arrays horizontally (column-wise).
338 Examples
339 --------
340 >>> a = np.array((1,2,3))
341 >>> b = np.array((4,5,6))
342 >>> np.hstack((a,b))
343 array([1, 2, 3, 4, 5, 6])
344 >>> a = np.array([[1],[2],[3]])
345 >>> b = np.array([[4],[5],[6]])
346 >>> np.hstack((a,b))
347 array([[1, 4],
348 [2, 5],
349 [3, 6]])
351 """
352 arrs = atleast_1d(*tup)
353 if not isinstance(arrs, list):
354 arrs = [arrs]
355 # As a special case, dimension 0 of 1-dimensional arrays is "horizontal"
356 if arrs and arrs[0].ndim == 1:
357 return _nx.concatenate(arrs, 0, dtype=dtype, casting=casting)
358 else:
359 return _nx.concatenate(arrs, 1, dtype=dtype, casting=casting)
362def _stack_dispatcher(arrays, axis=None, out=None, *,
363 dtype=None, casting=None):
364 arrays = _arrays_for_stack_dispatcher(arrays)
365 if out is not None:
366 # optimize for the typical case where only arrays is provided
367 arrays = list(arrays)
368 arrays.append(out)
369 return arrays
372@array_function_dispatch(_stack_dispatcher)
373def stack(arrays, axis=0, out=None, *, dtype=None, casting="same_kind"):
374 """
375 Join a sequence of arrays along a new axis.
377 The ``axis`` parameter specifies the index of the new axis in the
378 dimensions of the result. For example, if ``axis=0`` it will be the first
379 dimension and if ``axis=-1`` it will be the last dimension.
381 .. versionadded:: 1.10.0
383 Parameters
384 ----------
385 arrays : sequence of array_like
386 Each array must have the same shape.
388 axis : int, optional
389 The axis in the result array along which the input arrays are stacked.
391 out : ndarray, optional
392 If provided, the destination to place the result. The shape must be
393 correct, matching that of what stack would have returned if no
394 out argument were specified.
396 dtype : str or dtype
397 If provided, the destination array will have this dtype. Cannot be
398 provided together with `out`.
400 .. versionadded:: 1.24
402 casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
403 Controls what kind of data casting may occur. Defaults to 'same_kind'.
405 .. versionadded:: 1.24
408 Returns
409 -------
410 stacked : ndarray
411 The stacked array has one more dimension than the input arrays.
413 See Also
414 --------
415 concatenate : Join a sequence of arrays along an existing axis.
416 block : Assemble an nd-array from nested lists of blocks.
417 split : Split array into a list of multiple sub-arrays of equal size.
419 Examples
420 --------
421 >>> arrays = [np.random.randn(3, 4) for _ in range(10)]
422 >>> np.stack(arrays, axis=0).shape
423 (10, 3, 4)
425 >>> np.stack(arrays, axis=1).shape
426 (3, 10, 4)
428 >>> np.stack(arrays, axis=2).shape
429 (3, 4, 10)
431 >>> a = np.array([1, 2, 3])
432 >>> b = np.array([4, 5, 6])
433 >>> np.stack((a, b))
434 array([[1, 2, 3],
435 [4, 5, 6]])
437 >>> np.stack((a, b), axis=-1)
438 array([[1, 4],
439 [2, 5],
440 [3, 6]])
442 """
443 arrays = [asanyarray(arr) for arr in arrays]
444 if not arrays:
445 raise ValueError('need at least one array to stack')
447 shapes = {arr.shape for arr in arrays}
448 if len(shapes) != 1:
449 raise ValueError('all input arrays must have the same shape')
451 result_ndim = arrays[0].ndim + 1
452 axis = normalize_axis_index(axis, result_ndim)
454 sl = (slice(None),) * axis + (_nx.newaxis,)
455 expanded_arrays = [arr[sl] for arr in arrays]
456 return _nx.concatenate(expanded_arrays, axis=axis, out=out,
457 dtype=dtype, casting=casting)
460# Internal functions to eliminate the overhead of repeated dispatch in one of
461# the two possible paths inside np.block.
462# Use getattr to protect against __array_function__ being disabled.
463_size = getattr(_from_nx.size, '__wrapped__', _from_nx.size)
464_ndim = getattr(_from_nx.ndim, '__wrapped__', _from_nx.ndim)
465_concatenate = getattr(_from_nx.concatenate,
466 '__wrapped__', _from_nx.concatenate)
469def _block_format_index(index):
470 """
471 Convert a list of indices ``[0, 1, 2]`` into ``"arrays[0][1][2]"``.
472 """
473 idx_str = ''.join('[{}]'.format(i) for i in index if i is not None)
474 return 'arrays' + idx_str
477def _block_check_depths_match(arrays, parent_index=[]):
478 """
479 Recursive function checking that the depths of nested lists in `arrays`
480 all match. Mismatch raises a ValueError as described in the block
481 docstring below.
483 The entire index (rather than just the depth) needs to be calculated
484 for each innermost list, in case an error needs to be raised, so that
485 the index of the offending list can be printed as part of the error.
487 Parameters
488 ----------
489 arrays : nested list of arrays
490 The arrays to check
491 parent_index : list of int
492 The full index of `arrays` within the nested lists passed to
493 `_block_check_depths_match` at the top of the recursion.
495 Returns
496 -------
497 first_index : list of int
498 The full index of an element from the bottom of the nesting in
499 `arrays`. If any element at the bottom is an empty list, this will
500 refer to it, and the last index along the empty axis will be None.
501 max_arr_ndim : int
502 The maximum of the ndims of the arrays nested in `arrays`.
503 final_size: int
504 The number of elements in the final array. This is used the motivate
505 the choice of algorithm used using benchmarking wisdom.
507 """
508 if type(arrays) is tuple:
509 # not strictly necessary, but saves us from:
510 # - more than one way to do things - no point treating tuples like
511 # lists
512 # - horribly confusing behaviour that results when tuples are
513 # treated like ndarray
514 raise TypeError(
515 '{} is a tuple. '
516 'Only lists can be used to arrange blocks, and np.block does '
517 'not allow implicit conversion from tuple to ndarray.'.format(
518 _block_format_index(parent_index)
519 )
520 )
521 elif type(arrays) is list and len(arrays) > 0:
522 idxs_ndims = (_block_check_depths_match(arr, parent_index + [i])
523 for i, arr in enumerate(arrays))
525 first_index, max_arr_ndim, final_size = next(idxs_ndims)
526 for index, ndim, size in idxs_ndims:
527 final_size += size
528 if ndim > max_arr_ndim:
529 max_arr_ndim = ndim
530 if len(index) != len(first_index):
531 raise ValueError(
532 "List depths are mismatched. First element was at depth "
533 "{}, but there is an element at depth {} ({})".format(
534 len(first_index),
535 len(index),
536 _block_format_index(index)
537 )
538 )
539 # propagate our flag that indicates an empty list at the bottom
540 if index[-1] is None:
541 first_index = index
543 return first_index, max_arr_ndim, final_size
544 elif type(arrays) is list and len(arrays) == 0:
545 # We've 'bottomed out' on an empty list
546 return parent_index + [None], 0, 0
547 else:
548 # We've 'bottomed out' - arrays is either a scalar or an array
549 size = _size(arrays)
550 return parent_index, _ndim(arrays), size
553def _atleast_nd(a, ndim):
554 # Ensures `a` has at least `ndim` dimensions by prepending
555 # ones to `a.shape` as necessary
556 return array(a, ndmin=ndim, copy=False, subok=True)
559def _accumulate(values):
560 return list(itertools.accumulate(values))
563def _concatenate_shapes(shapes, axis):
564 """Given array shapes, return the resulting shape and slices prefixes.
566 These help in nested concatenation.
568 Returns
569 -------
570 shape: tuple of int
571 This tuple satisfies::
573 shape, _ = _concatenate_shapes([arr.shape for shape in arrs], axis)
574 shape == concatenate(arrs, axis).shape
576 slice_prefixes: tuple of (slice(start, end), )
577 For a list of arrays being concatenated, this returns the slice
578 in the larger array at axis that needs to be sliced into.
580 For example, the following holds::
582 ret = concatenate([a, b, c], axis)
583 _, (sl_a, sl_b, sl_c) = concatenate_slices([a, b, c], axis)
585 ret[(slice(None),) * axis + sl_a] == a
586 ret[(slice(None),) * axis + sl_b] == b
587 ret[(slice(None),) * axis + sl_c] == c
589 These are called slice prefixes since they are used in the recursive
590 blocking algorithm to compute the left-most slices during the
591 recursion. Therefore, they must be prepended to rest of the slice
592 that was computed deeper in the recursion.
594 These are returned as tuples to ensure that they can quickly be added
595 to existing slice tuple without creating a new tuple every time.
597 """
598 # Cache a result that will be reused.
599 shape_at_axis = [shape[axis] for shape in shapes]
601 # Take a shape, any shape
602 first_shape = shapes[0]
603 first_shape_pre = first_shape[:axis]
604 first_shape_post = first_shape[axis+1:]
606 if any(shape[:axis] != first_shape_pre or
607 shape[axis+1:] != first_shape_post for shape in shapes):
608 raise ValueError(
609 'Mismatched array shapes in block along axis {}.'.format(axis))
611 shape = (first_shape_pre + (sum(shape_at_axis),) + first_shape[axis+1:])
613 offsets_at_axis = _accumulate(shape_at_axis)
614 slice_prefixes = [(slice(start, end),)
615 for start, end in zip([0] + offsets_at_axis,
616 offsets_at_axis)]
617 return shape, slice_prefixes
620def _block_info_recursion(arrays, max_depth, result_ndim, depth=0):
621 """
622 Returns the shape of the final array, along with a list
623 of slices and a list of arrays that can be used for assignment inside the
624 new array
626 Parameters
627 ----------
628 arrays : nested list of arrays
629 The arrays to check
630 max_depth : list of int
631 The number of nested lists
632 result_ndim : int
633 The number of dimensions in thefinal array.
635 Returns
636 -------
637 shape : tuple of int
638 The shape that the final array will take on.
639 slices: list of tuple of slices
640 The slices into the full array required for assignment. These are
641 required to be prepended with ``(Ellipsis, )`` to obtain to correct
642 final index.
643 arrays: list of ndarray
644 The data to assign to each slice of the full array
646 """
647 if depth < max_depth:
648 shapes, slices, arrays = zip(
649 *[_block_info_recursion(arr, max_depth, result_ndim, depth+1)
650 for arr in arrays])
652 axis = result_ndim - max_depth + depth
653 shape, slice_prefixes = _concatenate_shapes(shapes, axis)
655 # Prepend the slice prefix and flatten the slices
656 slices = [slice_prefix + the_slice
657 for slice_prefix, inner_slices in zip(slice_prefixes, slices)
658 for the_slice in inner_slices]
660 # Flatten the array list
661 arrays = functools.reduce(operator.add, arrays)
663 return shape, slices, arrays
664 else:
665 # We've 'bottomed out' - arrays is either a scalar or an array
666 # type(arrays) is not list
667 # Return the slice and the array inside a list to be consistent with
668 # the recursive case.
669 arr = _atleast_nd(arrays, result_ndim)
670 return arr.shape, [()], [arr]
673def _block(arrays, max_depth, result_ndim, depth=0):
674 """
675 Internal implementation of block based on repeated concatenation.
676 `arrays` is the argument passed to
677 block. `max_depth` is the depth of nested lists within `arrays` and
678 `result_ndim` is the greatest of the dimensions of the arrays in
679 `arrays` and the depth of the lists in `arrays` (see block docstring
680 for details).
681 """
682 if depth < max_depth:
683 arrs = [_block(arr, max_depth, result_ndim, depth+1)
684 for arr in arrays]
685 return _concatenate(arrs, axis=-(max_depth-depth))
686 else:
687 # We've 'bottomed out' - arrays is either a scalar or an array
688 # type(arrays) is not list
689 return _atleast_nd(arrays, result_ndim)
692def _block_dispatcher(arrays):
693 # Use type(...) is list to match the behavior of np.block(), which special
694 # cases list specifically rather than allowing for generic iterables or
695 # tuple. Also, we know that list.__array_function__ will never exist.
696 if type(arrays) is list:
697 for subarrays in arrays:
698 yield from _block_dispatcher(subarrays)
699 else:
700 yield arrays
703@array_function_dispatch(_block_dispatcher)
704def block(arrays):
705 """
706 Assemble an nd-array from nested lists of blocks.
708 Blocks in the innermost lists are concatenated (see `concatenate`) along
709 the last dimension (-1), then these are concatenated along the
710 second-last dimension (-2), and so on until the outermost list is reached.
712 Blocks can be of any dimension, but will not be broadcasted using the normal
713 rules. Instead, leading axes of size 1 are inserted, to make ``block.ndim``
714 the same for all blocks. This is primarily useful for working with scalars,
715 and means that code like ``np.block([v, 1])`` is valid, where
716 ``v.ndim == 1``.
718 When the nested list is two levels deep, this allows block matrices to be
719 constructed from their components.
721 .. versionadded:: 1.13.0
723 Parameters
724 ----------
725 arrays : nested list of array_like or scalars (but not tuples)
726 If passed a single ndarray or scalar (a nested list of depth 0), this
727 is returned unmodified (and not copied).
729 Elements shapes must match along the appropriate axes (without
730 broadcasting), but leading 1s will be prepended to the shape as
731 necessary to make the dimensions match.
733 Returns
734 -------
735 block_array : ndarray
736 The array assembled from the given blocks.
738 The dimensionality of the output is equal to the greatest of:
739 * the dimensionality of all the inputs
740 * the depth to which the input list is nested
742 Raises
743 ------
744 ValueError
745 * If list depths are mismatched - for instance, ``[[a, b], c]`` is
746 illegal, and should be spelt ``[[a, b], [c]]``
747 * If lists are empty - for instance, ``[[a, b], []]``
749 See Also
750 --------
751 concatenate : Join a sequence of arrays along an existing axis.
752 stack : Join a sequence of arrays along a new axis.
753 vstack : Stack arrays in sequence vertically (row wise).
754 hstack : Stack arrays in sequence horizontally (column wise).
755 dstack : Stack arrays in sequence depth wise (along third axis).
756 column_stack : Stack 1-D arrays as columns into a 2-D array.
757 vsplit : Split an array into multiple sub-arrays vertically (row-wise).
759 Notes
760 -----
762 When called with only scalars, ``np.block`` is equivalent to an ndarray
763 call. So ``np.block([[1, 2], [3, 4]])`` is equivalent to
764 ``np.array([[1, 2], [3, 4]])``.
766 This function does not enforce that the blocks lie on a fixed grid.
767 ``np.block([[a, b], [c, d]])`` is not restricted to arrays of the form::
769 AAAbb
770 AAAbb
771 cccDD
773 But is also allowed to produce, for some ``a, b, c, d``::
775 AAAbb
776 AAAbb
777 cDDDD
779 Since concatenation happens along the last axis first, `block` is _not_
780 capable of producing the following directly::
782 AAAbb
783 cccbb
784 cccDD
786 Matlab's "square bracket stacking", ``[A, B, ...; p, q, ...]``, is
787 equivalent to ``np.block([[A, B, ...], [p, q, ...]])``.
789 Examples
790 --------
791 The most common use of this function is to build a block matrix
793 >>> A = np.eye(2) * 2
794 >>> B = np.eye(3) * 3
795 >>> np.block([
796 ... [A, np.zeros((2, 3))],
797 ... [np.ones((3, 2)), B ]
798 ... ])
799 array([[2., 0., 0., 0., 0.],
800 [0., 2., 0., 0., 0.],
801 [1., 1., 3., 0., 0.],
802 [1., 1., 0., 3., 0.],
803 [1., 1., 0., 0., 3.]])
805 With a list of depth 1, `block` can be used as `hstack`
807 >>> np.block([1, 2, 3]) # hstack([1, 2, 3])
808 array([1, 2, 3])
810 >>> a = np.array([1, 2, 3])
811 >>> b = np.array([4, 5, 6])
812 >>> np.block([a, b, 10]) # hstack([a, b, 10])
813 array([ 1, 2, 3, 4, 5, 6, 10])
815 >>> A = np.ones((2, 2), int)
816 >>> B = 2 * A
817 >>> np.block([A, B]) # hstack([A, B])
818 array([[1, 1, 2, 2],
819 [1, 1, 2, 2]])
821 With a list of depth 2, `block` can be used in place of `vstack`:
823 >>> a = np.array([1, 2, 3])
824 >>> b = np.array([4, 5, 6])
825 >>> np.block([[a], [b]]) # vstack([a, b])
826 array([[1, 2, 3],
827 [4, 5, 6]])
829 >>> A = np.ones((2, 2), int)
830 >>> B = 2 * A
831 >>> np.block([[A], [B]]) # vstack([A, B])
832 array([[1, 1],
833 [1, 1],
834 [2, 2],
835 [2, 2]])
837 It can also be used in places of `atleast_1d` and `atleast_2d`
839 >>> a = np.array(0)
840 >>> b = np.array([1])
841 >>> np.block([a]) # atleast_1d(a)
842 array([0])
843 >>> np.block([b]) # atleast_1d(b)
844 array([1])
846 >>> np.block([[a]]) # atleast_2d(a)
847 array([[0]])
848 >>> np.block([[b]]) # atleast_2d(b)
849 array([[1]])
852 """
853 arrays, list_ndim, result_ndim, final_size = _block_setup(arrays)
855 # It was found through benchmarking that making an array of final size
856 # around 256x256 was faster by straight concatenation on a
857 # i7-7700HQ processor and dual channel ram 2400MHz.
858 # It didn't seem to matter heavily on the dtype used.
859 #
860 # A 2D array using repeated concatenation requires 2 copies of the array.
861 #
862 # The fastest algorithm will depend on the ratio of CPU power to memory
863 # speed.
864 # One can monitor the results of the benchmark
865 # https://pv.github.io/numpy-bench/#bench_shape_base.Block2D.time_block2d
866 # to tune this parameter until a C version of the `_block_info_recursion`
867 # algorithm is implemented which would likely be faster than the python
868 # version.
869 if list_ndim * final_size > (2 * 512 * 512):
870 return _block_slicing(arrays, list_ndim, result_ndim)
871 else:
872 return _block_concatenate(arrays, list_ndim, result_ndim)
875# These helper functions are mostly used for testing.
876# They allow us to write tests that directly call `_block_slicing`
877# or `_block_concatenate` without blocking large arrays to force the wisdom
878# to trigger the desired path.
879def _block_setup(arrays):
880 """
881 Returns
882 (`arrays`, list_ndim, result_ndim, final_size)
883 """
884 bottom_index, arr_ndim, final_size = _block_check_depths_match(arrays)
885 list_ndim = len(bottom_index)
886 if bottom_index and bottom_index[-1] is None:
887 raise ValueError(
888 'List at {} cannot be empty'.format(
889 _block_format_index(bottom_index)
890 )
891 )
892 result_ndim = max(arr_ndim, list_ndim)
893 return arrays, list_ndim, result_ndim, final_size
896def _block_slicing(arrays, list_ndim, result_ndim):
897 shape, slices, arrays = _block_info_recursion(
898 arrays, list_ndim, result_ndim)
899 dtype = _nx.result_type(*[arr.dtype for arr in arrays])
901 # Test preferring F only in the case that all input arrays are F
902 F_order = all(arr.flags['F_CONTIGUOUS'] for arr in arrays)
903 C_order = all(arr.flags['C_CONTIGUOUS'] for arr in arrays)
904 order = 'F' if F_order and not C_order else 'C'
905 result = _nx.empty(shape=shape, dtype=dtype, order=order)
906 # Note: In a c implementation, the function
907 # PyArray_CreateMultiSortedStridePerm could be used for more advanced
908 # guessing of the desired order.
910 for the_slice, arr in zip(slices, arrays):
911 result[(Ellipsis,) + the_slice] = arr
912 return result
915def _block_concatenate(arrays, list_ndim, result_ndim):
916 result = _block(arrays, list_ndim, result_ndim)
917 if list_ndim == 0:
918 # Catch an edge case where _block returns a view because
919 # `arrays` is a single numpy array and not a list of numpy arrays.
920 # This might copy scalars or lists twice, but this isn't a likely
921 # usecase for those interested in performance
922 result = result.copy()
923 return result