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

1import functools 

2import warnings 

3 

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 

16 

17 

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 ] 

24 

25 

26array_function_dispatch = functools.partial( 

27 overrides.array_function_dispatch, module='numpy') 

28 

29 

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)) 

39 

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)) 

49 

50 return tuple(fancy_index) 

51 

52 

53def _take_along_axis_dispatcher(arr, indices, axis): 

54 return (arr, indices) 

55 

56 

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. 

61 

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. 

65 

66 Functions returning an index along an axis, like `argsort` and 

67 `argpartition`, produce suitable indices for this function. 

68 

69 .. versionadded:: 1.15.0 

70 

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`. 

83 

84 Returns 

85 ------- 

86 out: ndarray (Ni..., J, Nk...) 

87 The indexed result. 

88 

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:: 

93 

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) 

97 

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]] 

105 

106 Equivalently, eliminating the inner loop, the last two lines would be:: 

107 

108 out_1d[:] = a_1d[indices_1d] 

109 

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 

115 

116 Examples 

117 -------- 

118 

119 For this sample array 

120 

121 >>> a = np.array([[10, 30, 20], [60, 40, 50]]) 

122 

123 We can sort either by using sort directly, or argsort and this function 

124 

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]]) 

135 

136 The same works for max and min, if you maintain the trivial dimension 

137 with ``keepdims``: 

138 

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]]) 

149 

150 If we want to get the max and min at the same time, we can stack the 

151 indices first 

152 

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 

171 

172 # use the fancy index 

173 return arr[_make_along_axis_idx(arr_shape, indices, axis)] 

174 

175 

176def _put_along_axis_dispatcher(arr, indices, values, axis): 

177 return (arr, indices, values) 

178 

179 

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. 

184 

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. 

188 

189 Functions returning an index along an axis, like `argsort` and 

190 `argpartition`, produce suitable indices for this function. 

191 

192 .. versionadded:: 1.15.0 

193 

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. 

208 

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:: 

213 

214 Ni, M, Nk = a.shape[:axis], a.shape[axis], a.shape[axis+1:] 

215 J = indices.shape[axis] # Need not equal M 

216 

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] 

224 

225 Equivalently, eliminating the inner loop, the last two lines would be:: 

226 

227 a_1d[indices_1d] = values_1d 

228 

229 See Also 

230 -------- 

231 take_along_axis : 

232 Take values from the input array by matching 1d index and data slices 

233 

234 Examples 

235 -------- 

236 

237 For this sample array 

238 

239 >>> a = np.array([[10, 30, 20], [60, 40, 50]]) 

240 

241 We can replace the maximum values with: 

242 

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]]) 

251 

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 

261 

262 # use the fancy index 

263 arr[_make_along_axis_idx(arr_shape, indices, axis)] = values 

264 

265 

266def _apply_along_axis_dispatcher(func1d, axis, arr, *args, **kwargs): 

267 return (arr,) 

268 

269 

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. 

274 

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`. 

277 

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:: 

280 

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] 

288 

289 Equivalently, eliminating the inner loop, this can be expressed as:: 

290 

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]) 

295 

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`. 

309 

310 .. versionadded:: 1.9.0 

311 

312 

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`. 

321 

322 See Also 

323 -------- 

324 apply_over_axes : Apply a function repeatedly over multiple axes. 

325 

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.]) 

336 

337 For a function that returns a 1D array, the number of dimensions in 

338 `outarr` is the same as `arr`. 

339 

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]]) 

345 

346 For a function that returns a higher dimensional array, those dimensions 

347 are inserted in place of the `axis` dimension. 

348 

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] 

364 

365 nd = arr.ndim 

366 axis = normalize_axis_index(axis, nd) 

367 

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]) 

371 

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) 

376 

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)) 

385 

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) 

395 

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 ) 

403 

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)) 

408 

409 res = transpose(buff, buff_permute) 

410 return conv.wrap(res) 

411 

412 

413def _apply_over_axes_dispatcher(func, a, axes): 

414 return (a,) 

415 

416 

417@array_function_dispatch(_apply_over_axes_dispatcher) 

418def apply_over_axes(func, a, axes): 

419 """ 

420 Apply a function repeatedly over multiple axes. 

421 

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. 

428 

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. 

437 

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. 

444 

445 See Also 

446 -------- 

447 apply_along_axis : 

448 Apply a function to 1-D slices of an array along the given axis. 

449 

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. 

455 

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]]]) 

466 

467 Sum over axes 0 and 2. The result has same number of dimensions 

468 as the original array: 

469 

470 >>> np.apply_over_axes(np.sum, a, [0,2]) 

471 array([[[ 60], 

472 [ 92], 

473 [124]]]) 

474 

475 Tuple axis arguments to ufuncs are equivalent: 

476 

477 >>> np.sum(a, axis=(0,2), keepdims=True) 

478 array([[[ 60], 

479 [ 92], 

480 [124]]]) 

481 

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 

502 

503 

504def _expand_dims_dispatcher(a, axis): 

505 return (a,) 

506 

507 

508@array_function_dispatch(_expand_dims_dispatcher) 

509def expand_dims(a, axis): 

510 """ 

511 Expand the shape of an array. 

512 

513 Insert a new axis that will appear at the `axis` position in the expanded 

514 array shape. 

515 

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. 

522 

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. 

527 

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`. 

532 

533 Returns 

534 ------- 

535 result : ndarray 

536 View of `a` with the number of dimensions increased. 

537 

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 

543 

544 Examples 

545 -------- 

546 >>> x = np.array([1, 2]) 

547 >>> x.shape 

548 (2,) 

549 

550 The following is equivalent to ``x[np.newaxis, :]`` or ``x[np.newaxis]``: 

551 

552 >>> y = np.expand_dims(x, axis=0) 

553 >>> y 

554 array([[1, 2]]) 

555 >>> y.shape 

556 (1, 2) 

557 

558 The following is equivalent to ``x[:, np.newaxis]``: 

559 

560 >>> y = np.expand_dims(x, axis=1) 

561 >>> y 

562 array([[1], 

563 [2]]) 

564 >>> y.shape 

565 (2, 1) 

566 

567 ``axis`` may also be a tuple: 

568 

569 >>> y = np.expand_dims(x, axis=(0, 1)) 

570 >>> y 

571 array([[[1, 2]]]) 

572 

573 >>> y = np.expand_dims(x, axis=(2, 0)) 

574 >>> y 

575 array([[[1], 

576 [2]]]) 

577 

578 Note that some examples may use ``None`` instead of ``np.newaxis``. These 

579 are the same objects: 

580 

581 >>> np.newaxis is None 

582 True 

583 

584 """ 

585 if isinstance(a, matrix): 

586 a = asarray(a) 

587 else: 

588 a = asanyarray(a) 

589 

590 if type(axis) not in (tuple, list): 

591 axis = (axis,) 

592 

593 out_ndim = len(axis) + a.ndim 

594 axis = normalize_axis_tuple(axis, out_ndim) 

595 

596 shape_it = iter(a.shape) 

597 shape = [1 if ax in axis else next(shape_it) for ax in range(out_ndim)] 

598 

599 return a.reshape(shape) 

600 

601 

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) 

613 

614 

615row_stack.__doc__ = vstack.__doc__ 

616 

617 

618def _column_stack_dispatcher(tup): 

619 return _arrays_for_stack_dispatcher(tup) 

620 

621 

622@array_function_dispatch(_column_stack_dispatcher) 

623def column_stack(tup): 

624 """ 

625 Stack 1-D arrays as columns into a 2-D array. 

626 

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. 

631 

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. 

636 

637 Returns 

638 ------- 

639 stacked : 2-D array 

640 The array formed by stacking the given arrays. 

641 

642 See Also 

643 -------- 

644 stack, hstack, vstack, concatenate 

645 

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]]) 

654 

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) 

663 

664 

665def _dstack_dispatcher(tup): 

666 return _arrays_for_stack_dispatcher(tup) 

667 

668 

669@array_function_dispatch(_dstack_dispatcher) 

670def dstack(tup): 

671 """ 

672 Stack arrays in sequence depth wise (along third axis). 

673 

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`. 

678 

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. 

683 

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. 

689 

690 Returns 

691 ------- 

692 stacked : ndarray 

693 The array formed by stacking the given arrays, will be at least 3-D. 

694 

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. 

704 

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]]]) 

713 

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]]]) 

720 

721 """ 

722 arrs = atleast_3d(*tup) 

723 if not isinstance(arrs, tuple): 

724 arrs = (arrs,) 

725 return _nx.concatenate(arrs, 2) 

726 

727 

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 

735 

736 

737def _array_split_dispatcher(ary, indices_or_sections, axis=None): 

738 return (ary, indices_or_sections) 

739 

740 

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. 

745 

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. 

752 

753 See Also 

754 -------- 

755 split : Split array into multiple sub-arrays of equal size. 

756 

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.])] 

762 

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])] 

766 

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() 

786 

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)) 

793 

794 return sub_arys 

795 

796 

797def _split_dispatcher(ary, indices_or_sections, axis=None): 

798 return (ary, indices_or_sections) 

799 

800 

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`. 

805 

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. 

814 

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 

818 

819 - ary[:2] 

820 - ary[2:3] 

821 - ary[3:] 

822 

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. 

827 

828 Returns 

829 ------- 

830 sub-arrays : list of ndarrays 

831 A list of sub-arrays as views into `ary`. 

832 

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. 

838 

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). 

852 

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.])] 

858 

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)] 

866 

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) 

877 

878 

879def _hvdsplit_dispatcher(ary, indices_or_sections): 

880 return (ary, indices_or_sections) 

881 

882 

883@array_function_dispatch(_hvdsplit_dispatcher) 

884def hsplit(ary, indices_or_sections): 

885 """ 

886 Split an array into multiple sub-arrays horizontally (column-wise). 

887 

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``. 

891 

892 See Also 

893 -------- 

894 split : Split an array into multiple sub-arrays of equal size. 

895 

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)] 

923 

924 With a higher dimensional array the split is still along the second axis. 

925 

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.]]])] 

937 

938 With a 1-D array, the split is along axis 0. 

939 

940 >>> x = np.array([0, 1, 2, 3, 4, 5]) 

941 >>> np.hsplit(x, 2) 

942 [array([0, 1, 2]), array([3, 4, 5])] 

943 

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) 

951 

952 

953@array_function_dispatch(_hvdsplit_dispatcher) 

954def vsplit(ary, indices_or_sections): 

955 """ 

956 Split an array into multiple sub-arrays vertically (row-wise). 

957 

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. 

961 

962 See Also 

963 -------- 

964 split : Split an array into multiple sub-arrays of equal size. 

965 

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)] 

985 

986 With a higher dimensional array the split is still along the first axis. 

987 

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.]]])] 

999 

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) 

1004 

1005 

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). 

1010 

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. 

1014 

1015 See Also 

1016 -------- 

1017 split : Split an array into multiple sub-arrays of equal size. 

1018 

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) 

1049 

1050 

1051def get_array_wrap(*args): 

1052 """Find the wrapper for the array with the highest priority. 

1053 

1054 In case of ties, leftmost wins. If no wrapper is found, return None. 

1055 

1056 .. deprecated:: 2.0 

1057 """ 

1058 

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 ) 

1066 

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 

1073 

1074 

1075def _kron_dispatcher(a, b): 

1076 return (a, b) 

1077 

1078 

1079@array_function_dispatch(_kron_dispatcher) 

1080def kron(a, b): 

1081 """ 

1082 Kronecker product of two arrays. 

1083 

1084 Computes the Kronecker product, a composite array made of blocks of the 

1085 second array scaled by the first. 

1086 

1087 Parameters 

1088 ---------- 

1089 a, b : array_like 

1090 

1091 Returns 

1092 ------- 

1093 out : ndarray 

1094 

1095 See Also 

1096 -------- 

1097 outer : The outer product 

1098 

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:: 

1107 

1108 kron(a,b)[k0,k1,...,kN] = a[i0,i1,...,iN] * b[j0,j1,...,jN] 

1109 

1110 where:: 

1111 

1112 kt = it * st + jt, t = 0,...,N 

1113 

1114 In the common 2-D case (N=1), the block structure can be visualized:: 

1115 

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 ]] 

1119 

1120 

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]) 

1127 

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.]]) 

1133 

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 

1146 

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) 

1162 

1163 if (nda == 0 or ndb == 0): 

1164 return _nx.multiply(a, b) 

1165 

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) 

1172 

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 

1176 

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))) 

1180 

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)) 

1186 

1187 # Reshape back 

1188 result = result.reshape(_nx.multiply(as_, bs)) 

1189 

1190 return result if not is_any_mat else matrix(result, copy=False) 

1191 

1192 

1193def _tile_dispatcher(A, reps): 

1194 return (A, reps) 

1195 

1196 

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. 

1201 

1202 If `reps` has length ``d``, the result will have dimension of 

1203 ``max(d, A.ndim)``. 

1204 

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. 

1210 

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). 

1214 

1215 Note : Although tile may be used for broadcasting, it is strongly 

1216 recommended to use numpy's broadcasting operations and functions. 

1217 

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. 

1224 

1225 Returns 

1226 ------- 

1227 c : ndarray 

1228 The tiled output array. 

1229 

1230 See Also 

1231 -------- 

1232 repeat : Repeat elements of an array. 

1233 broadcast_to : Broadcast an array to a new shape 

1234 

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]]]) 

1246 

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]]) 

1256 

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)