Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/numpy/lib/arraypad.py: 6%

218 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2The arraypad module contains a group of functions to pad values onto the edges 

3of an n-dimensional array. 

4 

5""" 

6import numpy as np 

7from numpy.core.overrides import array_function_dispatch 

8from numpy.lib.index_tricks import ndindex 

9 

10 

11__all__ = ['pad'] 

12 

13 

14############################################################################### 

15# Private utility functions. 

16 

17 

18def _round_if_needed(arr, dtype): 

19 """ 

20 Rounds arr inplace if destination dtype is integer. 

21 

22 Parameters 

23 ---------- 

24 arr : ndarray 

25 Input array. 

26 dtype : dtype 

27 The dtype of the destination array. 

28 """ 

29 if np.issubdtype(dtype, np.integer): 

30 arr.round(out=arr) 

31 

32 

33def _slice_at_axis(sl, axis): 

34 """ 

35 Construct tuple of slices to slice an array in the given dimension. 

36 

37 Parameters 

38 ---------- 

39 sl : slice 

40 The slice for the given dimension. 

41 axis : int 

42 The axis to which `sl` is applied. All other dimensions are left 

43 "unsliced". 

44 

45 Returns 

46 ------- 

47 sl : tuple of slices 

48 A tuple with slices matching `shape` in length. 

49 

50 Examples 

51 -------- 

52 >>> _slice_at_axis(slice(None, 3, -1), 1) 

53 (slice(None, None, None), slice(None, 3, -1), (...,)) 

54 """ 

55 return (slice(None),) * axis + (sl,) + (...,) 

56 

57 

58def _view_roi(array, original_area_slice, axis): 

59 """ 

60 Get a view of the current region of interest during iterative padding. 

61 

62 When padding multiple dimensions iteratively corner values are 

63 unnecessarily overwritten multiple times. This function reduces the 

64 working area for the first dimensions so that corners are excluded. 

65 

66 Parameters 

67 ---------- 

68 array : ndarray 

69 The array with the region of interest. 

70 original_area_slice : tuple of slices 

71 Denotes the area with original values of the unpadded array. 

72 axis : int 

73 The currently padded dimension assuming that `axis` is padded before 

74 `axis` + 1. 

75 

76 Returns 

77 ------- 

78 roi : ndarray 

79 The region of interest of the original `array`. 

80 """ 

81 axis += 1 

82 sl = (slice(None),) * axis + original_area_slice[axis:] 

83 return array[sl] 

84 

85 

86def _pad_simple(array, pad_width, fill_value=None): 

87 """ 

88 Pad array on all sides with either a single value or undefined values. 

89 

90 Parameters 

91 ---------- 

92 array : ndarray 

93 Array to grow. 

94 pad_width : sequence of tuple[int, int] 

95 Pad width on both sides for each dimension in `arr`. 

96 fill_value : scalar, optional 

97 If provided the padded area is filled with this value, otherwise 

98 the pad area left undefined. 

99 

100 Returns 

101 ------- 

102 padded : ndarray 

103 The padded array with the same dtype as`array`. Its order will default 

104 to C-style if `array` is not F-contiguous. 

105 original_area_slice : tuple 

106 A tuple of slices pointing to the area of the original array. 

107 """ 

108 # Allocate grown array 

109 new_shape = tuple( 

110 left + size + right 

111 for size, (left, right) in zip(array.shape, pad_width) 

112 ) 

113 order = 'F' if array.flags.fnc else 'C' # Fortran and not also C-order 

114 padded = np.empty(new_shape, dtype=array.dtype, order=order) 

115 

116 if fill_value is not None: 

117 padded.fill(fill_value) 

118 

119 # Copy old array into correct space 

120 original_area_slice = tuple( 

121 slice(left, left + size) 

122 for size, (left, right) in zip(array.shape, pad_width) 

123 ) 

124 padded[original_area_slice] = array 

125 

126 return padded, original_area_slice 

127 

128 

129def _set_pad_area(padded, axis, width_pair, value_pair): 

130 """ 

131 Set empty-padded area in given dimension. 

132 

133 Parameters 

134 ---------- 

135 padded : ndarray 

136 Array with the pad area which is modified inplace. 

137 axis : int 

138 Dimension with the pad area to set. 

139 width_pair : (int, int) 

140 Pair of widths that mark the pad area on both sides in the given 

141 dimension. 

142 value_pair : tuple of scalars or ndarrays 

143 Values inserted into the pad area on each side. It must match or be 

144 broadcastable to the shape of `arr`. 

145 """ 

146 left_slice = _slice_at_axis(slice(None, width_pair[0]), axis) 

147 padded[left_slice] = value_pair[0] 

148 

149 right_slice = _slice_at_axis( 

150 slice(padded.shape[axis] - width_pair[1], None), axis) 

151 padded[right_slice] = value_pair[1] 

152 

153 

154def _get_edges(padded, axis, width_pair): 

155 """ 

156 Retrieve edge values from empty-padded array in given dimension. 

157 

158 Parameters 

159 ---------- 

160 padded : ndarray 

161 Empty-padded array. 

162 axis : int 

163 Dimension in which the edges are considered. 

164 width_pair : (int, int) 

165 Pair of widths that mark the pad area on both sides in the given 

166 dimension. 

167 

168 Returns 

169 ------- 

170 left_edge, right_edge : ndarray 

171 Edge values of the valid area in `padded` in the given dimension. Its 

172 shape will always match `padded` except for the dimension given by 

173 `axis` which will have a length of 1. 

174 """ 

175 left_index = width_pair[0] 

176 left_slice = _slice_at_axis(slice(left_index, left_index + 1), axis) 

177 left_edge = padded[left_slice] 

178 

179 right_index = padded.shape[axis] - width_pair[1] 

180 right_slice = _slice_at_axis(slice(right_index - 1, right_index), axis) 

181 right_edge = padded[right_slice] 

182 

183 return left_edge, right_edge 

184 

185 

186def _get_linear_ramps(padded, axis, width_pair, end_value_pair): 

187 """ 

188 Construct linear ramps for empty-padded array in given dimension. 

189 

190 Parameters 

191 ---------- 

192 padded : ndarray 

193 Empty-padded array. 

194 axis : int 

195 Dimension in which the ramps are constructed. 

196 width_pair : (int, int) 

197 Pair of widths that mark the pad area on both sides in the given 

198 dimension. 

199 end_value_pair : (scalar, scalar) 

200 End values for the linear ramps which form the edge of the fully padded 

201 array. These values are included in the linear ramps. 

202 

203 Returns 

204 ------- 

205 left_ramp, right_ramp : ndarray 

206 Linear ramps to set on both sides of `padded`. 

207 """ 

208 edge_pair = _get_edges(padded, axis, width_pair) 

209 

210 left_ramp, right_ramp = ( 

211 np.linspace( 

212 start=end_value, 

213 stop=edge.squeeze(axis), # Dimension is replaced by linspace 

214 num=width, 

215 endpoint=False, 

216 dtype=padded.dtype, 

217 axis=axis 

218 ) 

219 for end_value, edge, width in zip( 

220 end_value_pair, edge_pair, width_pair 

221 ) 

222 ) 

223 

224 # Reverse linear space in appropriate dimension 

225 right_ramp = right_ramp[_slice_at_axis(slice(None, None, -1), axis)] 

226 

227 return left_ramp, right_ramp 

228 

229 

230def _get_stats(padded, axis, width_pair, length_pair, stat_func): 

231 """ 

232 Calculate statistic for the empty-padded array in given dimension. 

233 

234 Parameters 

235 ---------- 

236 padded : ndarray 

237 Empty-padded array. 

238 axis : int 

239 Dimension in which the statistic is calculated. 

240 width_pair : (int, int) 

241 Pair of widths that mark the pad area on both sides in the given 

242 dimension. 

243 length_pair : 2-element sequence of None or int 

244 Gives the number of values in valid area from each side that is 

245 taken into account when calculating the statistic. If None the entire 

246 valid area in `padded` is considered. 

247 stat_func : function 

248 Function to compute statistic. The expected signature is 

249 ``stat_func(x: ndarray, axis: int, keepdims: bool) -> ndarray``. 

250 

251 Returns 

252 ------- 

253 left_stat, right_stat : ndarray 

254 Calculated statistic for both sides of `padded`. 

255 """ 

256 # Calculate indices of the edges of the area with original values 

257 left_index = width_pair[0] 

258 right_index = padded.shape[axis] - width_pair[1] 

259 # as well as its length 

260 max_length = right_index - left_index 

261 

262 # Limit stat_lengths to max_length 

263 left_length, right_length = length_pair 

264 if left_length is None or max_length < left_length: 

265 left_length = max_length 

266 if right_length is None or max_length < right_length: 

267 right_length = max_length 

268 

269 if (left_length == 0 or right_length == 0) \ 

270 and stat_func in {np.amax, np.amin}: 

271 # amax and amin can't operate on an empty array, 

272 # raise a more descriptive warning here instead of the default one 

273 raise ValueError("stat_length of 0 yields no value for padding") 

274 

275 # Calculate statistic for the left side 

276 left_slice = _slice_at_axis( 

277 slice(left_index, left_index + left_length), axis) 

278 left_chunk = padded[left_slice] 

279 left_stat = stat_func(left_chunk, axis=axis, keepdims=True) 

280 _round_if_needed(left_stat, padded.dtype) 

281 

282 if left_length == right_length == max_length: 

283 # return early as right_stat must be identical to left_stat 

284 return left_stat, left_stat 

285 

286 # Calculate statistic for the right side 

287 right_slice = _slice_at_axis( 

288 slice(right_index - right_length, right_index), axis) 

289 right_chunk = padded[right_slice] 

290 right_stat = stat_func(right_chunk, axis=axis, keepdims=True) 

291 _round_if_needed(right_stat, padded.dtype) 

292 

293 return left_stat, right_stat 

294 

295 

296def _set_reflect_both(padded, axis, width_pair, method, include_edge=False): 

297 """ 

298 Pad `axis` of `arr` with reflection. 

299 

300 Parameters 

301 ---------- 

302 padded : ndarray 

303 Input array of arbitrary shape. 

304 axis : int 

305 Axis along which to pad `arr`. 

306 width_pair : (int, int) 

307 Pair of widths that mark the pad area on both sides in the given 

308 dimension. 

309 method : str 

310 Controls method of reflection; options are 'even' or 'odd'. 

311 include_edge : bool 

312 If true, edge value is included in reflection, otherwise the edge 

313 value forms the symmetric axis to the reflection. 

314 

315 Returns 

316 ------- 

317 pad_amt : tuple of ints, length 2 

318 New index positions of padding to do along the `axis`. If these are 

319 both 0, padding is done in this dimension. 

320 """ 

321 left_pad, right_pad = width_pair 

322 old_length = padded.shape[axis] - right_pad - left_pad 

323 

324 if include_edge: 

325 # Edge is included, we need to offset the pad amount by 1 

326 edge_offset = 1 

327 else: 

328 edge_offset = 0 # Edge is not included, no need to offset pad amount 

329 old_length -= 1 # but must be omitted from the chunk 

330 

331 if left_pad > 0: 

332 # Pad with reflected values on left side: 

333 # First limit chunk size which can't be larger than pad area 

334 chunk_length = min(old_length, left_pad) 

335 # Slice right to left, stop on or next to edge, start relative to stop 

336 stop = left_pad - edge_offset 

337 start = stop + chunk_length 

338 left_slice = _slice_at_axis(slice(start, stop, -1), axis) 

339 left_chunk = padded[left_slice] 

340 

341 if method == "odd": 

342 # Negate chunk and align with edge 

343 edge_slice = _slice_at_axis(slice(left_pad, left_pad + 1), axis) 

344 left_chunk = 2 * padded[edge_slice] - left_chunk 

345 

346 # Insert chunk into padded area 

347 start = left_pad - chunk_length 

348 stop = left_pad 

349 pad_area = _slice_at_axis(slice(start, stop), axis) 

350 padded[pad_area] = left_chunk 

351 # Adjust pointer to left edge for next iteration 

352 left_pad -= chunk_length 

353 

354 if right_pad > 0: 

355 # Pad with reflected values on right side: 

356 # First limit chunk size which can't be larger than pad area 

357 chunk_length = min(old_length, right_pad) 

358 # Slice right to left, start on or next to edge, stop relative to start 

359 start = -right_pad + edge_offset - 2 

360 stop = start - chunk_length 

361 right_slice = _slice_at_axis(slice(start, stop, -1), axis) 

362 right_chunk = padded[right_slice] 

363 

364 if method == "odd": 

365 # Negate chunk and align with edge 

366 edge_slice = _slice_at_axis( 

367 slice(-right_pad - 1, -right_pad), axis) 

368 right_chunk = 2 * padded[edge_slice] - right_chunk 

369 

370 # Insert chunk into padded area 

371 start = padded.shape[axis] - right_pad 

372 stop = start + chunk_length 

373 pad_area = _slice_at_axis(slice(start, stop), axis) 

374 padded[pad_area] = right_chunk 

375 # Adjust pointer to right edge for next iteration 

376 right_pad -= chunk_length 

377 

378 return left_pad, right_pad 

379 

380 

381def _set_wrap_both(padded, axis, width_pair): 

382 """ 

383 Pad `axis` of `arr` with wrapped values. 

384 

385 Parameters 

386 ---------- 

387 padded : ndarray 

388 Input array of arbitrary shape. 

389 axis : int 

390 Axis along which to pad `arr`. 

391 width_pair : (int, int) 

392 Pair of widths that mark the pad area on both sides in the given 

393 dimension. 

394 

395 Returns 

396 ------- 

397 pad_amt : tuple of ints, length 2 

398 New index positions of padding to do along the `axis`. If these are 

399 both 0, padding is done in this dimension. 

400 """ 

401 left_pad, right_pad = width_pair 

402 period = padded.shape[axis] - right_pad - left_pad 

403 

404 # If the current dimension of `arr` doesn't contain enough valid values 

405 # (not part of the undefined pad area) we need to pad multiple times. 

406 # Each time the pad area shrinks on both sides which is communicated with 

407 # these variables. 

408 new_left_pad = 0 

409 new_right_pad = 0 

410 

411 if left_pad > 0: 

412 # Pad with wrapped values on left side 

413 # First slice chunk from right side of the non-pad area. 

414 # Use min(period, left_pad) to ensure that chunk is not larger than 

415 # pad area 

416 right_slice = _slice_at_axis( 

417 slice(-right_pad - min(period, left_pad), 

418 -right_pad if right_pad != 0 else None), 

419 axis 

420 ) 

421 right_chunk = padded[right_slice] 

422 

423 if left_pad > period: 

424 # Chunk is smaller than pad area 

425 pad_area = _slice_at_axis(slice(left_pad - period, left_pad), axis) 

426 new_left_pad = left_pad - period 

427 else: 

428 # Chunk matches pad area 

429 pad_area = _slice_at_axis(slice(None, left_pad), axis) 

430 padded[pad_area] = right_chunk 

431 

432 if right_pad > 0: 

433 # Pad with wrapped values on right side 

434 # First slice chunk from left side of the non-pad area. 

435 # Use min(period, right_pad) to ensure that chunk is not larger than 

436 # pad area 

437 left_slice = _slice_at_axis( 

438 slice(left_pad, left_pad + min(period, right_pad),), axis) 

439 left_chunk = padded[left_slice] 

440 

441 if right_pad > period: 

442 # Chunk is smaller than pad area 

443 pad_area = _slice_at_axis( 

444 slice(-right_pad, -right_pad + period), axis) 

445 new_right_pad = right_pad - period 

446 else: 

447 # Chunk matches pad area 

448 pad_area = _slice_at_axis(slice(-right_pad, None), axis) 

449 padded[pad_area] = left_chunk 

450 

451 return new_left_pad, new_right_pad 

452 

453 

454def _as_pairs(x, ndim, as_index=False): 

455 """ 

456 Broadcast `x` to an array with the shape (`ndim`, 2). 

457 

458 A helper function for `pad` that prepares and validates arguments like 

459 `pad_width` for iteration in pairs. 

460 

461 Parameters 

462 ---------- 

463 x : {None, scalar, array-like} 

464 The object to broadcast to the shape (`ndim`, 2). 

465 ndim : int 

466 Number of pairs the broadcasted `x` will have. 

467 as_index : bool, optional 

468 If `x` is not None, try to round each element of `x` to an integer 

469 (dtype `np.intp`) and ensure every element is positive. 

470 

471 Returns 

472 ------- 

473 pairs : nested iterables, shape (`ndim`, 2) 

474 The broadcasted version of `x`. 

475 

476 Raises 

477 ------ 

478 ValueError 

479 If `as_index` is True and `x` contains negative elements. 

480 Or if `x` is not broadcastable to the shape (`ndim`, 2). 

481 """ 

482 if x is None: 

483 # Pass through None as a special case, otherwise np.round(x) fails 

484 # with an AttributeError 

485 return ((None, None),) * ndim 

486 

487 x = np.array(x) 

488 if as_index: 

489 x = np.round(x).astype(np.intp, copy=False) 

490 

491 if x.ndim < 3: 

492 # Optimization: Possibly use faster paths for cases where `x` has 

493 # only 1 or 2 elements. `np.broadcast_to` could handle these as well 

494 # but is currently slower 

495 

496 if x.size == 1: 

497 # x was supplied as a single value 

498 x = x.ravel() # Ensure x[0] works for x.ndim == 0, 1, 2 

499 if as_index and x < 0: 

500 raise ValueError("index can't contain negative values") 

501 return ((x[0], x[0]),) * ndim 

502 

503 if x.size == 2 and x.shape != (2, 1): 

504 # x was supplied with a single value for each side 

505 # but except case when each dimension has a single value 

506 # which should be broadcasted to a pair, 

507 # e.g. [[1], [2]] -> [[1, 1], [2, 2]] not [[1, 2], [1, 2]] 

508 x = x.ravel() # Ensure x[0], x[1] works 

509 if as_index and (x[0] < 0 or x[1] < 0): 

510 raise ValueError("index can't contain negative values") 

511 return ((x[0], x[1]),) * ndim 

512 

513 if as_index and x.min() < 0: 

514 raise ValueError("index can't contain negative values") 

515 

516 # Converting the array with `tolist` seems to improve performance 

517 # when iterating and indexing the result (see usage in `pad`) 

518 return np.broadcast_to(x, (ndim, 2)).tolist() 

519 

520 

521def _pad_dispatcher(array, pad_width, mode=None, **kwargs): 

522 return (array,) 

523 

524 

525############################################################################### 

526# Public functions 

527 

528 

529@array_function_dispatch(_pad_dispatcher, module='numpy') 

530def pad(array, pad_width, mode='constant', **kwargs): 

531 """ 

532 Pad an array. 

533 

534 Parameters 

535 ---------- 

536 array : array_like of rank N 

537 The array to pad. 

538 pad_width : {sequence, array_like, int} 

539 Number of values padded to the edges of each axis. 

540 ((before_1, after_1), ... (before_N, after_N)) unique pad widths 

541 for each axis. 

542 ((before, after),) yields same before and after pad for each axis. 

543 (pad,) or int is a shortcut for before = after = pad width for all 

544 axes. 

545 mode : str or function, optional 

546 One of the following string values or a user supplied function. 

547 

548 'constant' (default) 

549 Pads with a constant value. 

550 'edge' 

551 Pads with the edge values of array. 

552 'linear_ramp' 

553 Pads with the linear ramp between end_value and the 

554 array edge value. 

555 'maximum' 

556 Pads with the maximum value of all or part of the 

557 vector along each axis. 

558 'mean' 

559 Pads with the mean value of all or part of the 

560 vector along each axis. 

561 'median' 

562 Pads with the median value of all or part of the 

563 vector along each axis. 

564 'minimum' 

565 Pads with the minimum value of all or part of the 

566 vector along each axis. 

567 'reflect' 

568 Pads with the reflection of the vector mirrored on 

569 the first and last values of the vector along each 

570 axis. 

571 'symmetric' 

572 Pads with the reflection of the vector mirrored 

573 along the edge of the array. 

574 'wrap' 

575 Pads with the wrap of the vector along the axis. 

576 The first values are used to pad the end and the 

577 end values are used to pad the beginning. 

578 'empty' 

579 Pads with undefined values. 

580 

581 .. versionadded:: 1.17 

582 

583 <function> 

584 Padding function, see Notes. 

585 stat_length : sequence or int, optional 

586 Used in 'maximum', 'mean', 'median', and 'minimum'. Number of 

587 values at edge of each axis used to calculate the statistic value. 

588 

589 ((before_1, after_1), ... (before_N, after_N)) unique statistic 

590 lengths for each axis. 

591 

592 ((before, after),) yields same before and after statistic lengths 

593 for each axis. 

594 

595 (stat_length,) or int is a shortcut for before = after = statistic 

596 length for all axes. 

597 

598 Default is ``None``, to use the entire axis. 

599 constant_values : sequence or scalar, optional 

600 Used in 'constant'. The values to set the padded values for each 

601 axis. 

602 

603 ``((before_1, after_1), ... (before_N, after_N))`` unique pad constants 

604 for each axis. 

605 

606 ``((before, after),)`` yields same before and after constants for each 

607 axis. 

608 

609 ``(constant,)`` or ``constant`` is a shortcut for ``before = after = constant`` for 

610 all axes. 

611 

612 Default is 0. 

613 end_values : sequence or scalar, optional 

614 Used in 'linear_ramp'. The values used for the ending value of the 

615 linear_ramp and that will form the edge of the padded array. 

616 

617 ``((before_1, after_1), ... (before_N, after_N))`` unique end values 

618 for each axis. 

619 

620 ``((before, after),)`` yields same before and after end values for each 

621 axis. 

622 

623 ``(constant,)`` or ``constant`` is a shortcut for ``before = after = constant`` for 

624 all axes. 

625 

626 Default is 0. 

627 reflect_type : {'even', 'odd'}, optional 

628 Used in 'reflect', and 'symmetric'. The 'even' style is the 

629 default with an unaltered reflection around the edge value. For 

630 the 'odd' style, the extended part of the array is created by 

631 subtracting the reflected values from two times the edge value. 

632 

633 Returns 

634 ------- 

635 pad : ndarray 

636 Padded array of rank equal to `array` with shape increased 

637 according to `pad_width`. 

638 

639 Notes 

640 ----- 

641 .. versionadded:: 1.7.0 

642 

643 For an array with rank greater than 1, some of the padding of later 

644 axes is calculated from padding of previous axes. This is easiest to 

645 think about with a rank 2 array where the corners of the padded array 

646 are calculated by using padded values from the first axis. 

647 

648 The padding function, if used, should modify a rank 1 array in-place. It 

649 has the following signature:: 

650 

651 padding_func(vector, iaxis_pad_width, iaxis, kwargs) 

652 

653 where 

654 

655 vector : ndarray 

656 A rank 1 array already padded with zeros. Padded values are 

657 vector[:iaxis_pad_width[0]] and vector[-iaxis_pad_width[1]:]. 

658 iaxis_pad_width : tuple 

659 A 2-tuple of ints, iaxis_pad_width[0] represents the number of 

660 values padded at the beginning of vector where 

661 iaxis_pad_width[1] represents the number of values padded at 

662 the end of vector. 

663 iaxis : int 

664 The axis currently being calculated. 

665 kwargs : dict 

666 Any keyword arguments the function requires. 

667 

668 Examples 

669 -------- 

670 >>> a = [1, 2, 3, 4, 5] 

671 >>> np.pad(a, (2, 3), 'constant', constant_values=(4, 6)) 

672 array([4, 4, 1, ..., 6, 6, 6]) 

673 

674 >>> np.pad(a, (2, 3), 'edge') 

675 array([1, 1, 1, ..., 5, 5, 5]) 

676 

677 >>> np.pad(a, (2, 3), 'linear_ramp', end_values=(5, -4)) 

678 array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4]) 

679 

680 >>> np.pad(a, (2,), 'maximum') 

681 array([5, 5, 1, 2, 3, 4, 5, 5, 5]) 

682 

683 >>> np.pad(a, (2,), 'mean') 

684 array([3, 3, 1, 2, 3, 4, 5, 3, 3]) 

685 

686 >>> np.pad(a, (2,), 'median') 

687 array([3, 3, 1, 2, 3, 4, 5, 3, 3]) 

688 

689 >>> a = [[1, 2], [3, 4]] 

690 >>> np.pad(a, ((3, 2), (2, 3)), 'minimum') 

691 array([[1, 1, 1, 2, 1, 1, 1], 

692 [1, 1, 1, 2, 1, 1, 1], 

693 [1, 1, 1, 2, 1, 1, 1], 

694 [1, 1, 1, 2, 1, 1, 1], 

695 [3, 3, 3, 4, 3, 3, 3], 

696 [1, 1, 1, 2, 1, 1, 1], 

697 [1, 1, 1, 2, 1, 1, 1]]) 

698 

699 >>> a = [1, 2, 3, 4, 5] 

700 >>> np.pad(a, (2, 3), 'reflect') 

701 array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2]) 

702 

703 >>> np.pad(a, (2, 3), 'reflect', reflect_type='odd') 

704 array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]) 

705 

706 >>> np.pad(a, (2, 3), 'symmetric') 

707 array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3]) 

708 

709 >>> np.pad(a, (2, 3), 'symmetric', reflect_type='odd') 

710 array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7]) 

711 

712 >>> np.pad(a, (2, 3), 'wrap') 

713 array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3]) 

714 

715 >>> def pad_with(vector, pad_width, iaxis, kwargs): 

716 ... pad_value = kwargs.get('padder', 10) 

717 ... vector[:pad_width[0]] = pad_value 

718 ... vector[-pad_width[1]:] = pad_value 

719 >>> a = np.arange(6) 

720 >>> a = a.reshape((2, 3)) 

721 >>> np.pad(a, 2, pad_with) 

722 array([[10, 10, 10, 10, 10, 10, 10], 

723 [10, 10, 10, 10, 10, 10, 10], 

724 [10, 10, 0, 1, 2, 10, 10], 

725 [10, 10, 3, 4, 5, 10, 10], 

726 [10, 10, 10, 10, 10, 10, 10], 

727 [10, 10, 10, 10, 10, 10, 10]]) 

728 >>> np.pad(a, 2, pad_with, padder=100) 

729 array([[100, 100, 100, 100, 100, 100, 100], 

730 [100, 100, 100, 100, 100, 100, 100], 

731 [100, 100, 0, 1, 2, 100, 100], 

732 [100, 100, 3, 4, 5, 100, 100], 

733 [100, 100, 100, 100, 100, 100, 100], 

734 [100, 100, 100, 100, 100, 100, 100]]) 

735 """ 

736 array = np.asarray(array) 

737 pad_width = np.asarray(pad_width) 

738 

739 if not pad_width.dtype.kind == 'i': 

740 raise TypeError('`pad_width` must be of integral type.') 

741 

742 # Broadcast to shape (array.ndim, 2) 

743 pad_width = _as_pairs(pad_width, array.ndim, as_index=True) 

744 

745 if callable(mode): 

746 # Old behavior: Use user-supplied function with np.apply_along_axis 

747 function = mode 

748 # Create a new zero padded array 

749 padded, _ = _pad_simple(array, pad_width, fill_value=0) 

750 # And apply along each axis 

751 

752 for axis in range(padded.ndim): 

753 # Iterate using ndindex as in apply_along_axis, but assuming that 

754 # function operates inplace on the padded array. 

755 

756 # view with the iteration axis at the end 

757 view = np.moveaxis(padded, axis, -1) 

758 

759 # compute indices for the iteration axes, and append a trailing 

760 # ellipsis to prevent 0d arrays decaying to scalars (gh-8642) 

761 inds = ndindex(view.shape[:-1]) 

762 inds = (ind + (Ellipsis,) for ind in inds) 

763 for ind in inds: 

764 function(view[ind], pad_width[axis], axis, kwargs) 

765 

766 return padded 

767 

768 # Make sure that no unsupported keywords were passed for the current mode 

769 allowed_kwargs = { 

770 'empty': [], 'edge': [], 'wrap': [], 

771 'constant': ['constant_values'], 

772 'linear_ramp': ['end_values'], 

773 'maximum': ['stat_length'], 

774 'mean': ['stat_length'], 

775 'median': ['stat_length'], 

776 'minimum': ['stat_length'], 

777 'reflect': ['reflect_type'], 

778 'symmetric': ['reflect_type'], 

779 } 

780 try: 

781 unsupported_kwargs = set(kwargs) - set(allowed_kwargs[mode]) 

782 except KeyError: 

783 raise ValueError("mode '{}' is not supported".format(mode)) from None 

784 if unsupported_kwargs: 

785 raise ValueError("unsupported keyword arguments for mode '{}': {}" 

786 .format(mode, unsupported_kwargs)) 

787 

788 stat_functions = {"maximum": np.amax, "minimum": np.amin, 

789 "mean": np.mean, "median": np.median} 

790 

791 # Create array with final shape and original values 

792 # (padded area is undefined) 

793 padded, original_area_slice = _pad_simple(array, pad_width) 

794 # And prepare iteration over all dimensions 

795 # (zipping may be more readable than using enumerate) 

796 axes = range(padded.ndim) 

797 

798 if mode == "constant": 

799 values = kwargs.get("constant_values", 0) 

800 values = _as_pairs(values, padded.ndim) 

801 for axis, width_pair, value_pair in zip(axes, pad_width, values): 

802 roi = _view_roi(padded, original_area_slice, axis) 

803 _set_pad_area(roi, axis, width_pair, value_pair) 

804 

805 elif mode == "empty": 

806 pass # Do nothing as _pad_simple already returned the correct result 

807 

808 elif array.size == 0: 

809 # Only modes "constant" and "empty" can extend empty axes, all other 

810 # modes depend on `array` not being empty 

811 # -> ensure every empty axis is only "padded with 0" 

812 for axis, width_pair in zip(axes, pad_width): 

813 if array.shape[axis] == 0 and any(width_pair): 

814 raise ValueError( 

815 "can't extend empty axis {} using modes other than " 

816 "'constant' or 'empty'".format(axis) 

817 ) 

818 # passed, don't need to do anything more as _pad_simple already 

819 # returned the correct result 

820 

821 elif mode == "edge": 

822 for axis, width_pair in zip(axes, pad_width): 

823 roi = _view_roi(padded, original_area_slice, axis) 

824 edge_pair = _get_edges(roi, axis, width_pair) 

825 _set_pad_area(roi, axis, width_pair, edge_pair) 

826 

827 elif mode == "linear_ramp": 

828 end_values = kwargs.get("end_values", 0) 

829 end_values = _as_pairs(end_values, padded.ndim) 

830 for axis, width_pair, value_pair in zip(axes, pad_width, end_values): 

831 roi = _view_roi(padded, original_area_slice, axis) 

832 ramp_pair = _get_linear_ramps(roi, axis, width_pair, value_pair) 

833 _set_pad_area(roi, axis, width_pair, ramp_pair) 

834 

835 elif mode in stat_functions: 

836 func = stat_functions[mode] 

837 length = kwargs.get("stat_length", None) 

838 length = _as_pairs(length, padded.ndim, as_index=True) 

839 for axis, width_pair, length_pair in zip(axes, pad_width, length): 

840 roi = _view_roi(padded, original_area_slice, axis) 

841 stat_pair = _get_stats(roi, axis, width_pair, length_pair, func) 

842 _set_pad_area(roi, axis, width_pair, stat_pair) 

843 

844 elif mode in {"reflect", "symmetric"}: 

845 method = kwargs.get("reflect_type", "even") 

846 include_edge = True if mode == "symmetric" else False 

847 for axis, (left_index, right_index) in zip(axes, pad_width): 

848 if array.shape[axis] == 1 and (left_index > 0 or right_index > 0): 

849 # Extending singleton dimension for 'reflect' is legacy 

850 # behavior; it really should raise an error. 

851 edge_pair = _get_edges(padded, axis, (left_index, right_index)) 

852 _set_pad_area( 

853 padded, axis, (left_index, right_index), edge_pair) 

854 continue 

855 

856 roi = _view_roi(padded, original_area_slice, axis) 

857 while left_index > 0 or right_index > 0: 

858 # Iteratively pad until dimension is filled with reflected 

859 # values. This is necessary if the pad area is larger than 

860 # the length of the original values in the current dimension. 

861 left_index, right_index = _set_reflect_both( 

862 roi, axis, (left_index, right_index), 

863 method, include_edge 

864 ) 

865 

866 elif mode == "wrap": 

867 for axis, (left_index, right_index) in zip(axes, pad_width): 

868 roi = _view_roi(padded, original_area_slice, axis) 

869 while left_index > 0 or right_index > 0: 

870 # Iteratively pad until dimension is filled with wrapped 

871 # values. This is necessary if the pad area is larger than 

872 # the length of the original values in the current dimension. 

873 left_index, right_index = _set_wrap_both( 

874 roi, axis, (left_index, right_index)) 

875 

876 return padded