annotate DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/lib/arraypad.py @ 118:770eb830ec19 emscripten

Typo fix
author Chris Cannam
date Wed, 18 May 2016 16:14:08 +0100
parents 2a2c65a20a8b
children
rev   line source
Chris@87 1 """
Chris@87 2 The arraypad module contains a group of functions to pad values onto the edges
Chris@87 3 of an n-dimensional array.
Chris@87 4
Chris@87 5 """
Chris@87 6 from __future__ import division, absolute_import, print_function
Chris@87 7
Chris@87 8 import numpy as np
Chris@87 9 from numpy.compat import long
Chris@87 10
Chris@87 11
Chris@87 12 __all__ = ['pad']
Chris@87 13
Chris@87 14
Chris@87 15 ###############################################################################
Chris@87 16 # Private utility functions.
Chris@87 17
Chris@87 18
Chris@87 19 def _arange_ndarray(arr, shape, axis, reverse=False):
Chris@87 20 """
Chris@87 21 Create an ndarray of `shape` with increments along specified `axis`
Chris@87 22
Chris@87 23 Parameters
Chris@87 24 ----------
Chris@87 25 arr : ndarray
Chris@87 26 Input array of arbitrary shape.
Chris@87 27 shape : tuple of ints
Chris@87 28 Shape of desired array. Should be equivalent to `arr.shape` except
Chris@87 29 `shape[axis]` which may have any positive value.
Chris@87 30 axis : int
Chris@87 31 Axis to increment along.
Chris@87 32 reverse : bool
Chris@87 33 If False, increment in a positive fashion from 1 to `shape[axis]`,
Chris@87 34 inclusive. If True, the bounds are the same but the order reversed.
Chris@87 35
Chris@87 36 Returns
Chris@87 37 -------
Chris@87 38 padarr : ndarray
Chris@87 39 Output array sized to pad `arr` along `axis`, with linear range from
Chris@87 40 1 to `shape[axis]` along specified `axis`.
Chris@87 41
Chris@87 42 Notes
Chris@87 43 -----
Chris@87 44 The range is deliberately 1-indexed for this specific use case. Think of
Chris@87 45 this algorithm as broadcasting `np.arange` to a single `axis` of an
Chris@87 46 arbitrarily shaped ndarray.
Chris@87 47
Chris@87 48 """
Chris@87 49 initshape = tuple(1 if i != axis else shape[axis]
Chris@87 50 for (i, x) in enumerate(arr.shape))
Chris@87 51 if not reverse:
Chris@87 52 padarr = np.arange(1, shape[axis] + 1)
Chris@87 53 else:
Chris@87 54 padarr = np.arange(shape[axis], 0, -1)
Chris@87 55 padarr = padarr.reshape(initshape)
Chris@87 56 for i, dim in enumerate(shape):
Chris@87 57 if padarr.shape[i] != dim:
Chris@87 58 padarr = padarr.repeat(dim, axis=i)
Chris@87 59 return padarr
Chris@87 60
Chris@87 61
Chris@87 62 def _round_ifneeded(arr, dtype):
Chris@87 63 """
Chris@87 64 Rounds arr inplace if destination dtype is integer.
Chris@87 65
Chris@87 66 Parameters
Chris@87 67 ----------
Chris@87 68 arr : ndarray
Chris@87 69 Input array.
Chris@87 70 dtype : dtype
Chris@87 71 The dtype of the destination array.
Chris@87 72
Chris@87 73 """
Chris@87 74 if np.issubdtype(dtype, np.integer):
Chris@87 75 arr.round(out=arr)
Chris@87 76
Chris@87 77
Chris@87 78 def _prepend_const(arr, pad_amt, val, axis=-1):
Chris@87 79 """
Chris@87 80 Prepend constant `val` along `axis` of `arr`.
Chris@87 81
Chris@87 82 Parameters
Chris@87 83 ----------
Chris@87 84 arr : ndarray
Chris@87 85 Input array of arbitrary shape.
Chris@87 86 pad_amt : int
Chris@87 87 Amount of padding to prepend.
Chris@87 88 val : scalar
Chris@87 89 Constant value to use. For best results should be of type `arr.dtype`;
Chris@87 90 if not `arr.dtype` will be cast to `arr.dtype`.
Chris@87 91 axis : int
Chris@87 92 Axis along which to pad `arr`.
Chris@87 93
Chris@87 94 Returns
Chris@87 95 -------
Chris@87 96 padarr : ndarray
Chris@87 97 Output array, with `pad_amt` constant `val` prepended along `axis`.
Chris@87 98
Chris@87 99 """
Chris@87 100 if pad_amt == 0:
Chris@87 101 return arr
Chris@87 102 padshape = tuple(x if i != axis else pad_amt
Chris@87 103 for (i, x) in enumerate(arr.shape))
Chris@87 104 if val == 0:
Chris@87 105 return np.concatenate((np.zeros(padshape, dtype=arr.dtype), arr),
Chris@87 106 axis=axis)
Chris@87 107 else:
Chris@87 108 return np.concatenate(((np.zeros(padshape) + val).astype(arr.dtype),
Chris@87 109 arr), axis=axis)
Chris@87 110
Chris@87 111
Chris@87 112 def _append_const(arr, pad_amt, val, axis=-1):
Chris@87 113 """
Chris@87 114 Append constant `val` along `axis` of `arr`.
Chris@87 115
Chris@87 116 Parameters
Chris@87 117 ----------
Chris@87 118 arr : ndarray
Chris@87 119 Input array of arbitrary shape.
Chris@87 120 pad_amt : int
Chris@87 121 Amount of padding to append.
Chris@87 122 val : scalar
Chris@87 123 Constant value to use. For best results should be of type `arr.dtype`;
Chris@87 124 if not `arr.dtype` will be cast to `arr.dtype`.
Chris@87 125 axis : int
Chris@87 126 Axis along which to pad `arr`.
Chris@87 127
Chris@87 128 Returns
Chris@87 129 -------
Chris@87 130 padarr : ndarray
Chris@87 131 Output array, with `pad_amt` constant `val` appended along `axis`.
Chris@87 132
Chris@87 133 """
Chris@87 134 if pad_amt == 0:
Chris@87 135 return arr
Chris@87 136 padshape = tuple(x if i != axis else pad_amt
Chris@87 137 for (i, x) in enumerate(arr.shape))
Chris@87 138 if val == 0:
Chris@87 139 return np.concatenate((arr, np.zeros(padshape, dtype=arr.dtype)),
Chris@87 140 axis=axis)
Chris@87 141 else:
Chris@87 142 return np.concatenate(
Chris@87 143 (arr, (np.zeros(padshape) + val).astype(arr.dtype)), axis=axis)
Chris@87 144
Chris@87 145
Chris@87 146 def _prepend_edge(arr, pad_amt, axis=-1):
Chris@87 147 """
Chris@87 148 Prepend `pad_amt` to `arr` along `axis` by extending edge values.
Chris@87 149
Chris@87 150 Parameters
Chris@87 151 ----------
Chris@87 152 arr : ndarray
Chris@87 153 Input array of arbitrary shape.
Chris@87 154 pad_amt : int
Chris@87 155 Amount of padding to prepend.
Chris@87 156 axis : int
Chris@87 157 Axis along which to pad `arr`.
Chris@87 158
Chris@87 159 Returns
Chris@87 160 -------
Chris@87 161 padarr : ndarray
Chris@87 162 Output array, extended by `pad_amt` edge values appended along `axis`.
Chris@87 163
Chris@87 164 """
Chris@87 165 if pad_amt == 0:
Chris@87 166 return arr
Chris@87 167
Chris@87 168 edge_slice = tuple(slice(None) if i != axis else 0
Chris@87 169 for (i, x) in enumerate(arr.shape))
Chris@87 170
Chris@87 171 # Shape to restore singleton dimension after slicing
Chris@87 172 pad_singleton = tuple(x if i != axis else 1
Chris@87 173 for (i, x) in enumerate(arr.shape))
Chris@87 174 edge_arr = arr[edge_slice].reshape(pad_singleton)
Chris@87 175 return np.concatenate((edge_arr.repeat(pad_amt, axis=axis), arr),
Chris@87 176 axis=axis)
Chris@87 177
Chris@87 178
Chris@87 179 def _append_edge(arr, pad_amt, axis=-1):
Chris@87 180 """
Chris@87 181 Append `pad_amt` to `arr` along `axis` by extending edge values.
Chris@87 182
Chris@87 183 Parameters
Chris@87 184 ----------
Chris@87 185 arr : ndarray
Chris@87 186 Input array of arbitrary shape.
Chris@87 187 pad_amt : int
Chris@87 188 Amount of padding to append.
Chris@87 189 axis : int
Chris@87 190 Axis along which to pad `arr`.
Chris@87 191
Chris@87 192 Returns
Chris@87 193 -------
Chris@87 194 padarr : ndarray
Chris@87 195 Output array, extended by `pad_amt` edge values prepended along
Chris@87 196 `axis`.
Chris@87 197
Chris@87 198 """
Chris@87 199 if pad_amt == 0:
Chris@87 200 return arr
Chris@87 201
Chris@87 202 edge_slice = tuple(slice(None) if i != axis else arr.shape[axis] - 1
Chris@87 203 for (i, x) in enumerate(arr.shape))
Chris@87 204
Chris@87 205 # Shape to restore singleton dimension after slicing
Chris@87 206 pad_singleton = tuple(x if i != axis else 1
Chris@87 207 for (i, x) in enumerate(arr.shape))
Chris@87 208 edge_arr = arr[edge_slice].reshape(pad_singleton)
Chris@87 209 return np.concatenate((arr, edge_arr.repeat(pad_amt, axis=axis)),
Chris@87 210 axis=axis)
Chris@87 211
Chris@87 212
Chris@87 213 def _prepend_ramp(arr, pad_amt, end, axis=-1):
Chris@87 214 """
Chris@87 215 Prepend linear ramp along `axis`.
Chris@87 216
Chris@87 217 Parameters
Chris@87 218 ----------
Chris@87 219 arr : ndarray
Chris@87 220 Input array of arbitrary shape.
Chris@87 221 pad_amt : int
Chris@87 222 Amount of padding to prepend.
Chris@87 223 end : scalar
Chris@87 224 Constal value to use. For best results should be of type `arr.dtype`;
Chris@87 225 if not `arr.dtype` will be cast to `arr.dtype`.
Chris@87 226 axis : int
Chris@87 227 Axis along which to pad `arr`.
Chris@87 228
Chris@87 229 Returns
Chris@87 230 -------
Chris@87 231 padarr : ndarray
Chris@87 232 Output array, with `pad_amt` values prepended along `axis`. The
Chris@87 233 prepended region ramps linearly from the edge value to `end`.
Chris@87 234
Chris@87 235 """
Chris@87 236 if pad_amt == 0:
Chris@87 237 return arr
Chris@87 238
Chris@87 239 # Generate shape for final concatenated array
Chris@87 240 padshape = tuple(x if i != axis else pad_amt
Chris@87 241 for (i, x) in enumerate(arr.shape))
Chris@87 242
Chris@87 243 # Generate an n-dimensional array incrementing along `axis`
Chris@87 244 ramp_arr = _arange_ndarray(arr, padshape, axis,
Chris@87 245 reverse=True).astype(np.float64)
Chris@87 246
Chris@87 247 # Appropriate slicing to extract n-dimensional edge along `axis`
Chris@87 248 edge_slice = tuple(slice(None) if i != axis else 0
Chris@87 249 for (i, x) in enumerate(arr.shape))
Chris@87 250
Chris@87 251 # Shape to restore singleton dimension after slicing
Chris@87 252 pad_singleton = tuple(x if i != axis else 1
Chris@87 253 for (i, x) in enumerate(arr.shape))
Chris@87 254
Chris@87 255 # Extract edge, reshape to original rank, and extend along `axis`
Chris@87 256 edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis)
Chris@87 257
Chris@87 258 # Linear ramp
Chris@87 259 slope = (end - edge_pad) / float(pad_amt)
Chris@87 260 ramp_arr = ramp_arr * slope
Chris@87 261 ramp_arr += edge_pad
Chris@87 262 _round_ifneeded(ramp_arr, arr.dtype)
Chris@87 263
Chris@87 264 # Ramp values will most likely be float, cast them to the same type as arr
Chris@87 265 return np.concatenate((ramp_arr.astype(arr.dtype), arr), axis=axis)
Chris@87 266
Chris@87 267
Chris@87 268 def _append_ramp(arr, pad_amt, end, axis=-1):
Chris@87 269 """
Chris@87 270 Append linear ramp along `axis`.
Chris@87 271
Chris@87 272 Parameters
Chris@87 273 ----------
Chris@87 274 arr : ndarray
Chris@87 275 Input array of arbitrary shape.
Chris@87 276 pad_amt : int
Chris@87 277 Amount of padding to append.
Chris@87 278 end : scalar
Chris@87 279 Constal value to use. For best results should be of type `arr.dtype`;
Chris@87 280 if not `arr.dtype` will be cast to `arr.dtype`.
Chris@87 281 axis : int
Chris@87 282 Axis along which to pad `arr`.
Chris@87 283
Chris@87 284 Returns
Chris@87 285 -------
Chris@87 286 padarr : ndarray
Chris@87 287 Output array, with `pad_amt` values appended along `axis`. The
Chris@87 288 appended region ramps linearly from the edge value to `end`.
Chris@87 289
Chris@87 290 """
Chris@87 291 if pad_amt == 0:
Chris@87 292 return arr
Chris@87 293
Chris@87 294 # Generate shape for final concatenated array
Chris@87 295 padshape = tuple(x if i != axis else pad_amt
Chris@87 296 for (i, x) in enumerate(arr.shape))
Chris@87 297
Chris@87 298 # Generate an n-dimensional array incrementing along `axis`
Chris@87 299 ramp_arr = _arange_ndarray(arr, padshape, axis,
Chris@87 300 reverse=False).astype(np.float64)
Chris@87 301
Chris@87 302 # Slice a chunk from the edge to calculate stats on
Chris@87 303 edge_slice = tuple(slice(None) if i != axis else -1
Chris@87 304 for (i, x) in enumerate(arr.shape))
Chris@87 305
Chris@87 306 # Shape to restore singleton dimension after slicing
Chris@87 307 pad_singleton = tuple(x if i != axis else 1
Chris@87 308 for (i, x) in enumerate(arr.shape))
Chris@87 309
Chris@87 310 # Extract edge, reshape to original rank, and extend along `axis`
Chris@87 311 edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis)
Chris@87 312
Chris@87 313 # Linear ramp
Chris@87 314 slope = (end - edge_pad) / float(pad_amt)
Chris@87 315 ramp_arr = ramp_arr * slope
Chris@87 316 ramp_arr += edge_pad
Chris@87 317 _round_ifneeded(ramp_arr, arr.dtype)
Chris@87 318
Chris@87 319 # Ramp values will most likely be float, cast them to the same type as arr
Chris@87 320 return np.concatenate((arr, ramp_arr.astype(arr.dtype)), axis=axis)
Chris@87 321
Chris@87 322
Chris@87 323 def _prepend_max(arr, pad_amt, num, axis=-1):
Chris@87 324 """
Chris@87 325 Prepend `pad_amt` maximum values along `axis`.
Chris@87 326
Chris@87 327 Parameters
Chris@87 328 ----------
Chris@87 329 arr : ndarray
Chris@87 330 Input array of arbitrary shape.
Chris@87 331 pad_amt : int
Chris@87 332 Amount of padding to prepend.
Chris@87 333 num : int
Chris@87 334 Depth into `arr` along `axis` to calculate maximum.
Chris@87 335 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 336 axis : int
Chris@87 337 Axis along which to pad `arr`.
Chris@87 338
Chris@87 339 Returns
Chris@87 340 -------
Chris@87 341 padarr : ndarray
Chris@87 342 Output array, with `pad_amt` values appended along `axis`. The
Chris@87 343 prepended region is the maximum of the first `num` values along
Chris@87 344 `axis`.
Chris@87 345
Chris@87 346 """
Chris@87 347 if pad_amt == 0:
Chris@87 348 return arr
Chris@87 349
Chris@87 350 # Equivalent to edge padding for single value, so do that instead
Chris@87 351 if num == 1:
Chris@87 352 return _prepend_edge(arr, pad_amt, axis)
Chris@87 353
Chris@87 354 # Use entire array if `num` is too large
Chris@87 355 if num is not None:
Chris@87 356 if num >= arr.shape[axis]:
Chris@87 357 num = None
Chris@87 358
Chris@87 359 # Slice a chunk from the edge to calculate stats on
Chris@87 360 max_slice = tuple(slice(None) if i != axis else slice(num)
Chris@87 361 for (i, x) in enumerate(arr.shape))
Chris@87 362
Chris@87 363 # Shape to restore singleton dimension after slicing
Chris@87 364 pad_singleton = tuple(x if i != axis else 1
Chris@87 365 for (i, x) in enumerate(arr.shape))
Chris@87 366
Chris@87 367 # Extract slice, calculate max, reshape to add singleton dimension back
Chris@87 368 max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton)
Chris@87 369
Chris@87 370 # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt`
Chris@87 371 return np.concatenate((max_chunk.repeat(pad_amt, axis=axis), arr),
Chris@87 372 axis=axis)
Chris@87 373
Chris@87 374
Chris@87 375 def _append_max(arr, pad_amt, num, axis=-1):
Chris@87 376 """
Chris@87 377 Pad one `axis` of `arr` with the maximum of the last `num` elements.
Chris@87 378
Chris@87 379 Parameters
Chris@87 380 ----------
Chris@87 381 arr : ndarray
Chris@87 382 Input array of arbitrary shape.
Chris@87 383 pad_amt : int
Chris@87 384 Amount of padding to append.
Chris@87 385 num : int
Chris@87 386 Depth into `arr` along `axis` to calculate maximum.
Chris@87 387 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 388 axis : int
Chris@87 389 Axis along which to pad `arr`.
Chris@87 390
Chris@87 391 Returns
Chris@87 392 -------
Chris@87 393 padarr : ndarray
Chris@87 394 Output array, with `pad_amt` values appended along `axis`. The
Chris@87 395 appended region is the maximum of the final `num` values along `axis`.
Chris@87 396
Chris@87 397 """
Chris@87 398 if pad_amt == 0:
Chris@87 399 return arr
Chris@87 400
Chris@87 401 # Equivalent to edge padding for single value, so do that instead
Chris@87 402 if num == 1:
Chris@87 403 return _append_edge(arr, pad_amt, axis)
Chris@87 404
Chris@87 405 # Use entire array if `num` is too large
Chris@87 406 if num is not None:
Chris@87 407 if num >= arr.shape[axis]:
Chris@87 408 num = None
Chris@87 409
Chris@87 410 # Slice a chunk from the edge to calculate stats on
Chris@87 411 end = arr.shape[axis] - 1
Chris@87 412 if num is not None:
Chris@87 413 max_slice = tuple(
Chris@87 414 slice(None) if i != axis else slice(end, end - num, -1)
Chris@87 415 for (i, x) in enumerate(arr.shape))
Chris@87 416 else:
Chris@87 417 max_slice = tuple(slice(None) for x in arr.shape)
Chris@87 418
Chris@87 419 # Shape to restore singleton dimension after slicing
Chris@87 420 pad_singleton = tuple(x if i != axis else 1
Chris@87 421 for (i, x) in enumerate(arr.shape))
Chris@87 422
Chris@87 423 # Extract slice, calculate max, reshape to add singleton dimension back
Chris@87 424 max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton)
Chris@87 425
Chris@87 426 # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt`
Chris@87 427 return np.concatenate((arr, max_chunk.repeat(pad_amt, axis=axis)),
Chris@87 428 axis=axis)
Chris@87 429
Chris@87 430
Chris@87 431 def _prepend_mean(arr, pad_amt, num, axis=-1):
Chris@87 432 """
Chris@87 433 Prepend `pad_amt` mean values along `axis`.
Chris@87 434
Chris@87 435 Parameters
Chris@87 436 ----------
Chris@87 437 arr : ndarray
Chris@87 438 Input array of arbitrary shape.
Chris@87 439 pad_amt : int
Chris@87 440 Amount of padding to prepend.
Chris@87 441 num : int
Chris@87 442 Depth into `arr` along `axis` to calculate mean.
Chris@87 443 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 444 axis : int
Chris@87 445 Axis along which to pad `arr`.
Chris@87 446
Chris@87 447 Returns
Chris@87 448 -------
Chris@87 449 padarr : ndarray
Chris@87 450 Output array, with `pad_amt` values prepended along `axis`. The
Chris@87 451 prepended region is the mean of the first `num` values along `axis`.
Chris@87 452
Chris@87 453 """
Chris@87 454 if pad_amt == 0:
Chris@87 455 return arr
Chris@87 456
Chris@87 457 # Equivalent to edge padding for single value, so do that instead
Chris@87 458 if num == 1:
Chris@87 459 return _prepend_edge(arr, pad_amt, axis)
Chris@87 460
Chris@87 461 # Use entire array if `num` is too large
Chris@87 462 if num is not None:
Chris@87 463 if num >= arr.shape[axis]:
Chris@87 464 num = None
Chris@87 465
Chris@87 466 # Slice a chunk from the edge to calculate stats on
Chris@87 467 mean_slice = tuple(slice(None) if i != axis else slice(num)
Chris@87 468 for (i, x) in enumerate(arr.shape))
Chris@87 469
Chris@87 470 # Shape to restore singleton dimension after slicing
Chris@87 471 pad_singleton = tuple(x if i != axis else 1
Chris@87 472 for (i, x) in enumerate(arr.shape))
Chris@87 473
Chris@87 474 # Extract slice, calculate mean, reshape to add singleton dimension back
Chris@87 475 mean_chunk = arr[mean_slice].mean(axis).reshape(pad_singleton)
Chris@87 476 _round_ifneeded(mean_chunk, arr.dtype)
Chris@87 477
Chris@87 478 # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt`
Chris@87 479 return np.concatenate((mean_chunk.repeat(pad_amt, axis).astype(arr.dtype),
Chris@87 480 arr), axis=axis)
Chris@87 481
Chris@87 482
Chris@87 483 def _append_mean(arr, pad_amt, num, axis=-1):
Chris@87 484 """
Chris@87 485 Append `pad_amt` mean values along `axis`.
Chris@87 486
Chris@87 487 Parameters
Chris@87 488 ----------
Chris@87 489 arr : ndarray
Chris@87 490 Input array of arbitrary shape.
Chris@87 491 pad_amt : int
Chris@87 492 Amount of padding to append.
Chris@87 493 num : int
Chris@87 494 Depth into `arr` along `axis` to calculate mean.
Chris@87 495 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 496 axis : int
Chris@87 497 Axis along which to pad `arr`.
Chris@87 498
Chris@87 499 Returns
Chris@87 500 -------
Chris@87 501 padarr : ndarray
Chris@87 502 Output array, with `pad_amt` values appended along `axis`. The
Chris@87 503 appended region is the maximum of the final `num` values along `axis`.
Chris@87 504
Chris@87 505 """
Chris@87 506 if pad_amt == 0:
Chris@87 507 return arr
Chris@87 508
Chris@87 509 # Equivalent to edge padding for single value, so do that instead
Chris@87 510 if num == 1:
Chris@87 511 return _append_edge(arr, pad_amt, axis)
Chris@87 512
Chris@87 513 # Use entire array if `num` is too large
Chris@87 514 if num is not None:
Chris@87 515 if num >= arr.shape[axis]:
Chris@87 516 num = None
Chris@87 517
Chris@87 518 # Slice a chunk from the edge to calculate stats on
Chris@87 519 end = arr.shape[axis] - 1
Chris@87 520 if num is not None:
Chris@87 521 mean_slice = tuple(
Chris@87 522 slice(None) if i != axis else slice(end, end - num, -1)
Chris@87 523 for (i, x) in enumerate(arr.shape))
Chris@87 524 else:
Chris@87 525 mean_slice = tuple(slice(None) for x in arr.shape)
Chris@87 526
Chris@87 527 # Shape to restore singleton dimension after slicing
Chris@87 528 pad_singleton = tuple(x if i != axis else 1
Chris@87 529 for (i, x) in enumerate(arr.shape))
Chris@87 530
Chris@87 531 # Extract slice, calculate mean, reshape to add singleton dimension back
Chris@87 532 mean_chunk = arr[mean_slice].mean(axis=axis).reshape(pad_singleton)
Chris@87 533 _round_ifneeded(mean_chunk, arr.dtype)
Chris@87 534
Chris@87 535 # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt`
Chris@87 536 return np.concatenate(
Chris@87 537 (arr, mean_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis)
Chris@87 538
Chris@87 539
Chris@87 540 def _prepend_med(arr, pad_amt, num, axis=-1):
Chris@87 541 """
Chris@87 542 Prepend `pad_amt` median values along `axis`.
Chris@87 543
Chris@87 544 Parameters
Chris@87 545 ----------
Chris@87 546 arr : ndarray
Chris@87 547 Input array of arbitrary shape.
Chris@87 548 pad_amt : int
Chris@87 549 Amount of padding to prepend.
Chris@87 550 num : int
Chris@87 551 Depth into `arr` along `axis` to calculate median.
Chris@87 552 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 553 axis : int
Chris@87 554 Axis along which to pad `arr`.
Chris@87 555
Chris@87 556 Returns
Chris@87 557 -------
Chris@87 558 padarr : ndarray
Chris@87 559 Output array, with `pad_amt` values prepended along `axis`. The
Chris@87 560 prepended region is the median of the first `num` values along `axis`.
Chris@87 561
Chris@87 562 """
Chris@87 563 if pad_amt == 0:
Chris@87 564 return arr
Chris@87 565
Chris@87 566 # Equivalent to edge padding for single value, so do that instead
Chris@87 567 if num == 1:
Chris@87 568 return _prepend_edge(arr, pad_amt, axis)
Chris@87 569
Chris@87 570 # Use entire array if `num` is too large
Chris@87 571 if num is not None:
Chris@87 572 if num >= arr.shape[axis]:
Chris@87 573 num = None
Chris@87 574
Chris@87 575 # Slice a chunk from the edge to calculate stats on
Chris@87 576 med_slice = tuple(slice(None) if i != axis else slice(num)
Chris@87 577 for (i, x) in enumerate(arr.shape))
Chris@87 578
Chris@87 579 # Shape to restore singleton dimension after slicing
Chris@87 580 pad_singleton = tuple(x if i != axis else 1
Chris@87 581 for (i, x) in enumerate(arr.shape))
Chris@87 582
Chris@87 583 # Extract slice, calculate median, reshape to add singleton dimension back
Chris@87 584 med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton)
Chris@87 585 _round_ifneeded(med_chunk, arr.dtype)
Chris@87 586
Chris@87 587 # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt`
Chris@87 588 return np.concatenate(
Chris@87 589 (med_chunk.repeat(pad_amt, axis).astype(arr.dtype), arr), axis=axis)
Chris@87 590
Chris@87 591
Chris@87 592 def _append_med(arr, pad_amt, num, axis=-1):
Chris@87 593 """
Chris@87 594 Append `pad_amt` median values along `axis`.
Chris@87 595
Chris@87 596 Parameters
Chris@87 597 ----------
Chris@87 598 arr : ndarray
Chris@87 599 Input array of arbitrary shape.
Chris@87 600 pad_amt : int
Chris@87 601 Amount of padding to append.
Chris@87 602 num : int
Chris@87 603 Depth into `arr` along `axis` to calculate median.
Chris@87 604 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 605 axis : int
Chris@87 606 Axis along which to pad `arr`.
Chris@87 607
Chris@87 608 Returns
Chris@87 609 -------
Chris@87 610 padarr : ndarray
Chris@87 611 Output array, with `pad_amt` values appended along `axis`. The
Chris@87 612 appended region is the median of the final `num` values along `axis`.
Chris@87 613
Chris@87 614 """
Chris@87 615 if pad_amt == 0:
Chris@87 616 return arr
Chris@87 617
Chris@87 618 # Equivalent to edge padding for single value, so do that instead
Chris@87 619 if num == 1:
Chris@87 620 return _append_edge(arr, pad_amt, axis)
Chris@87 621
Chris@87 622 # Use entire array if `num` is too large
Chris@87 623 if num is not None:
Chris@87 624 if num >= arr.shape[axis]:
Chris@87 625 num = None
Chris@87 626
Chris@87 627 # Slice a chunk from the edge to calculate stats on
Chris@87 628 end = arr.shape[axis] - 1
Chris@87 629 if num is not None:
Chris@87 630 med_slice = tuple(
Chris@87 631 slice(None) if i != axis else slice(end, end - num, -1)
Chris@87 632 for (i, x) in enumerate(arr.shape))
Chris@87 633 else:
Chris@87 634 med_slice = tuple(slice(None) for x in arr.shape)
Chris@87 635
Chris@87 636 # Shape to restore singleton dimension after slicing
Chris@87 637 pad_singleton = tuple(x if i != axis else 1
Chris@87 638 for (i, x) in enumerate(arr.shape))
Chris@87 639
Chris@87 640 # Extract slice, calculate median, reshape to add singleton dimension back
Chris@87 641 med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton)
Chris@87 642 _round_ifneeded(med_chunk, arr.dtype)
Chris@87 643
Chris@87 644 # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt`
Chris@87 645 return np.concatenate(
Chris@87 646 (arr, med_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis)
Chris@87 647
Chris@87 648
Chris@87 649 def _prepend_min(arr, pad_amt, num, axis=-1):
Chris@87 650 """
Chris@87 651 Prepend `pad_amt` minimum values along `axis`.
Chris@87 652
Chris@87 653 Parameters
Chris@87 654 ----------
Chris@87 655 arr : ndarray
Chris@87 656 Input array of arbitrary shape.
Chris@87 657 pad_amt : int
Chris@87 658 Amount of padding to prepend.
Chris@87 659 num : int
Chris@87 660 Depth into `arr` along `axis` to calculate minimum.
Chris@87 661 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 662 axis : int
Chris@87 663 Axis along which to pad `arr`.
Chris@87 664
Chris@87 665 Returns
Chris@87 666 -------
Chris@87 667 padarr : ndarray
Chris@87 668 Output array, with `pad_amt` values prepended along `axis`. The
Chris@87 669 prepended region is the minimum of the first `num` values along
Chris@87 670 `axis`.
Chris@87 671
Chris@87 672 """
Chris@87 673 if pad_amt == 0:
Chris@87 674 return arr
Chris@87 675
Chris@87 676 # Equivalent to edge padding for single value, so do that instead
Chris@87 677 if num == 1:
Chris@87 678 return _prepend_edge(arr, pad_amt, axis)
Chris@87 679
Chris@87 680 # Use entire array if `num` is too large
Chris@87 681 if num is not None:
Chris@87 682 if num >= arr.shape[axis]:
Chris@87 683 num = None
Chris@87 684
Chris@87 685 # Slice a chunk from the edge to calculate stats on
Chris@87 686 min_slice = tuple(slice(None) if i != axis else slice(num)
Chris@87 687 for (i, x) in enumerate(arr.shape))
Chris@87 688
Chris@87 689 # Shape to restore singleton dimension after slicing
Chris@87 690 pad_singleton = tuple(x if i != axis else 1
Chris@87 691 for (i, x) in enumerate(arr.shape))
Chris@87 692
Chris@87 693 # Extract slice, calculate min, reshape to add singleton dimension back
Chris@87 694 min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton)
Chris@87 695
Chris@87 696 # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt`
Chris@87 697 return np.concatenate((min_chunk.repeat(pad_amt, axis=axis), arr),
Chris@87 698 axis=axis)
Chris@87 699
Chris@87 700
Chris@87 701 def _append_min(arr, pad_amt, num, axis=-1):
Chris@87 702 """
Chris@87 703 Append `pad_amt` median values along `axis`.
Chris@87 704
Chris@87 705 Parameters
Chris@87 706 ----------
Chris@87 707 arr : ndarray
Chris@87 708 Input array of arbitrary shape.
Chris@87 709 pad_amt : int
Chris@87 710 Amount of padding to append.
Chris@87 711 num : int
Chris@87 712 Depth into `arr` along `axis` to calculate minimum.
Chris@87 713 Range: [1, `arr.shape[axis]`] or None (entire axis)
Chris@87 714 axis : int
Chris@87 715 Axis along which to pad `arr`.
Chris@87 716
Chris@87 717 Returns
Chris@87 718 -------
Chris@87 719 padarr : ndarray
Chris@87 720 Output array, with `pad_amt` values appended along `axis`. The
Chris@87 721 appended region is the minimum of the final `num` values along `axis`.
Chris@87 722
Chris@87 723 """
Chris@87 724 if pad_amt == 0:
Chris@87 725 return arr
Chris@87 726
Chris@87 727 # Equivalent to edge padding for single value, so do that instead
Chris@87 728 if num == 1:
Chris@87 729 return _append_edge(arr, pad_amt, axis)
Chris@87 730
Chris@87 731 # Use entire array if `num` is too large
Chris@87 732 if num is not None:
Chris@87 733 if num >= arr.shape[axis]:
Chris@87 734 num = None
Chris@87 735
Chris@87 736 # Slice a chunk from the edge to calculate stats on
Chris@87 737 end = arr.shape[axis] - 1
Chris@87 738 if num is not None:
Chris@87 739 min_slice = tuple(
Chris@87 740 slice(None) if i != axis else slice(end, end - num, -1)
Chris@87 741 for (i, x) in enumerate(arr.shape))
Chris@87 742 else:
Chris@87 743 min_slice = tuple(slice(None) for x in arr.shape)
Chris@87 744
Chris@87 745 # Shape to restore singleton dimension after slicing
Chris@87 746 pad_singleton = tuple(x if i != axis else 1
Chris@87 747 for (i, x) in enumerate(arr.shape))
Chris@87 748
Chris@87 749 # Extract slice, calculate min, reshape to add singleton dimension back
Chris@87 750 min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton)
Chris@87 751
Chris@87 752 # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt`
Chris@87 753 return np.concatenate((arr, min_chunk.repeat(pad_amt, axis=axis)),
Chris@87 754 axis=axis)
Chris@87 755
Chris@87 756
Chris@87 757 def _pad_ref(arr, pad_amt, method, axis=-1):
Chris@87 758 """
Chris@87 759 Pad `axis` of `arr` by reflection.
Chris@87 760
Chris@87 761 Parameters
Chris@87 762 ----------
Chris@87 763 arr : ndarray
Chris@87 764 Input array of arbitrary shape.
Chris@87 765 pad_amt : tuple of ints, length 2
Chris@87 766 Padding to (prepend, append) along `axis`.
Chris@87 767 method : str
Chris@87 768 Controls method of reflection; options are 'even' or 'odd'.
Chris@87 769 axis : int
Chris@87 770 Axis along which to pad `arr`.
Chris@87 771
Chris@87 772 Returns
Chris@87 773 -------
Chris@87 774 padarr : ndarray
Chris@87 775 Output array, with `pad_amt[0]` values prepended and `pad_amt[1]`
Chris@87 776 values appended along `axis`. Both regions are padded with reflected
Chris@87 777 values from the original array.
Chris@87 778
Chris@87 779 Notes
Chris@87 780 -----
Chris@87 781 This algorithm does not pad with repetition, i.e. the edges are not
Chris@87 782 repeated in the reflection. For that behavior, use `method='symmetric'`.
Chris@87 783
Chris@87 784 The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
Chris@87 785 single function, lest the indexing tricks in non-integer multiples of the
Chris@87 786 original shape would violate repetition in the final iteration.
Chris@87 787
Chris@87 788 """
Chris@87 789 # Implicit booleanness to test for zero (or None) in any scalar type
Chris@87 790 if pad_amt[0] == 0 and pad_amt[1] == 0:
Chris@87 791 return arr
Chris@87 792
Chris@87 793 ##########################################################################
Chris@87 794 # Prepended region
Chris@87 795
Chris@87 796 # Slice off a reverse indexed chunk from near edge to pad `arr` before
Chris@87 797 ref_slice = tuple(slice(None) if i != axis else slice(pad_amt[0], 0, -1)
Chris@87 798 for (i, x) in enumerate(arr.shape))
Chris@87 799
Chris@87 800 ref_chunk1 = arr[ref_slice]
Chris@87 801
Chris@87 802 # Shape to restore singleton dimension after slicing
Chris@87 803 pad_singleton = tuple(x if i != axis else 1
Chris@87 804 for (i, x) in enumerate(arr.shape))
Chris@87 805 if pad_amt[0] == 1:
Chris@87 806 ref_chunk1 = ref_chunk1.reshape(pad_singleton)
Chris@87 807
Chris@87 808 # Memory/computationally more expensive, only do this if `method='odd'`
Chris@87 809 if 'odd' in method and pad_amt[0] > 0:
Chris@87 810 edge_slice1 = tuple(slice(None) if i != axis else 0
Chris@87 811 for (i, x) in enumerate(arr.shape))
Chris@87 812 edge_chunk = arr[edge_slice1].reshape(pad_singleton)
Chris@87 813 ref_chunk1 = 2 * edge_chunk - ref_chunk1
Chris@87 814 del edge_chunk
Chris@87 815
Chris@87 816 ##########################################################################
Chris@87 817 # Appended region
Chris@87 818
Chris@87 819 # Slice off a reverse indexed chunk from far edge to pad `arr` after
Chris@87 820 start = arr.shape[axis] - pad_amt[1] - 1
Chris@87 821 end = arr.shape[axis] - 1
Chris@87 822 ref_slice = tuple(slice(None) if i != axis else slice(start, end)
Chris@87 823 for (i, x) in enumerate(arr.shape))
Chris@87 824 rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1)
Chris@87 825 for (i, x) in enumerate(arr.shape))
Chris@87 826 ref_chunk2 = arr[ref_slice][rev_idx]
Chris@87 827
Chris@87 828 if pad_amt[1] == 1:
Chris@87 829 ref_chunk2 = ref_chunk2.reshape(pad_singleton)
Chris@87 830
Chris@87 831 if 'odd' in method:
Chris@87 832 edge_slice2 = tuple(slice(None) if i != axis else -1
Chris@87 833 for (i, x) in enumerate(arr.shape))
Chris@87 834 edge_chunk = arr[edge_slice2].reshape(pad_singleton)
Chris@87 835 ref_chunk2 = 2 * edge_chunk - ref_chunk2
Chris@87 836 del edge_chunk
Chris@87 837
Chris@87 838 # Concatenate `arr` with both chunks, extending along `axis`
Chris@87 839 return np.concatenate((ref_chunk1, arr, ref_chunk2), axis=axis)
Chris@87 840
Chris@87 841
Chris@87 842 def _pad_sym(arr, pad_amt, method, axis=-1):
Chris@87 843 """
Chris@87 844 Pad `axis` of `arr` by symmetry.
Chris@87 845
Chris@87 846 Parameters
Chris@87 847 ----------
Chris@87 848 arr : ndarray
Chris@87 849 Input array of arbitrary shape.
Chris@87 850 pad_amt : tuple of ints, length 2
Chris@87 851 Padding to (prepend, append) along `axis`.
Chris@87 852 method : str
Chris@87 853 Controls method of symmetry; options are 'even' or 'odd'.
Chris@87 854 axis : int
Chris@87 855 Axis along which to pad `arr`.
Chris@87 856
Chris@87 857 Returns
Chris@87 858 -------
Chris@87 859 padarr : ndarray
Chris@87 860 Output array, with `pad_amt[0]` values prepended and `pad_amt[1]`
Chris@87 861 values appended along `axis`. Both regions are padded with symmetric
Chris@87 862 values from the original array.
Chris@87 863
Chris@87 864 Notes
Chris@87 865 -----
Chris@87 866 This algorithm DOES pad with repetition, i.e. the edges are repeated.
Chris@87 867 For a method that does not repeat edges, use `method='reflect'`.
Chris@87 868
Chris@87 869 The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
Chris@87 870 single function, lest the indexing tricks in non-integer multiples of the
Chris@87 871 original shape would violate repetition in the final iteration.
Chris@87 872
Chris@87 873 """
Chris@87 874 # Implicit booleanness to test for zero (or None) in any scalar type
Chris@87 875 if pad_amt[0] == 0 and pad_amt[1] == 0:
Chris@87 876 return arr
Chris@87 877
Chris@87 878 ##########################################################################
Chris@87 879 # Prepended region
Chris@87 880
Chris@87 881 # Slice off a reverse indexed chunk from near edge to pad `arr` before
Chris@87 882 sym_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[0])
Chris@87 883 for (i, x) in enumerate(arr.shape))
Chris@87 884 rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1)
Chris@87 885 for (i, x) in enumerate(arr.shape))
Chris@87 886 sym_chunk1 = arr[sym_slice][rev_idx]
Chris@87 887
Chris@87 888 # Shape to restore singleton dimension after slicing
Chris@87 889 pad_singleton = tuple(x if i != axis else 1
Chris@87 890 for (i, x) in enumerate(arr.shape))
Chris@87 891 if pad_amt[0] == 1:
Chris@87 892 sym_chunk1 = sym_chunk1.reshape(pad_singleton)
Chris@87 893
Chris@87 894 # Memory/computationally more expensive, only do this if `method='odd'`
Chris@87 895 if 'odd' in method and pad_amt[0] > 0:
Chris@87 896 edge_slice1 = tuple(slice(None) if i != axis else 0
Chris@87 897 for (i, x) in enumerate(arr.shape))
Chris@87 898 edge_chunk = arr[edge_slice1].reshape(pad_singleton)
Chris@87 899 sym_chunk1 = 2 * edge_chunk - sym_chunk1
Chris@87 900 del edge_chunk
Chris@87 901
Chris@87 902 ##########################################################################
Chris@87 903 # Appended region
Chris@87 904
Chris@87 905 # Slice off a reverse indexed chunk from far edge to pad `arr` after
Chris@87 906 start = arr.shape[axis] - pad_amt[1]
Chris@87 907 end = arr.shape[axis]
Chris@87 908 sym_slice = tuple(slice(None) if i != axis else slice(start, end)
Chris@87 909 for (i, x) in enumerate(arr.shape))
Chris@87 910 sym_chunk2 = arr[sym_slice][rev_idx]
Chris@87 911
Chris@87 912 if pad_amt[1] == 1:
Chris@87 913 sym_chunk2 = sym_chunk2.reshape(pad_singleton)
Chris@87 914
Chris@87 915 if 'odd' in method:
Chris@87 916 edge_slice2 = tuple(slice(None) if i != axis else -1
Chris@87 917 for (i, x) in enumerate(arr.shape))
Chris@87 918 edge_chunk = arr[edge_slice2].reshape(pad_singleton)
Chris@87 919 sym_chunk2 = 2 * edge_chunk - sym_chunk2
Chris@87 920 del edge_chunk
Chris@87 921
Chris@87 922 # Concatenate `arr` with both chunks, extending along `axis`
Chris@87 923 return np.concatenate((sym_chunk1, arr, sym_chunk2), axis=axis)
Chris@87 924
Chris@87 925
Chris@87 926 def _pad_wrap(arr, pad_amt, axis=-1):
Chris@87 927 """
Chris@87 928 Pad `axis` of `arr` via wrapping.
Chris@87 929
Chris@87 930 Parameters
Chris@87 931 ----------
Chris@87 932 arr : ndarray
Chris@87 933 Input array of arbitrary shape.
Chris@87 934 pad_amt : tuple of ints, length 2
Chris@87 935 Padding to (prepend, append) along `axis`.
Chris@87 936 axis : int
Chris@87 937 Axis along which to pad `arr`.
Chris@87 938
Chris@87 939 Returns
Chris@87 940 -------
Chris@87 941 padarr : ndarray
Chris@87 942 Output array, with `pad_amt[0]` values prepended and `pad_amt[1]`
Chris@87 943 values appended along `axis`. Both regions are padded wrapped values
Chris@87 944 from the opposite end of `axis`.
Chris@87 945
Chris@87 946 Notes
Chris@87 947 -----
Chris@87 948 This method of padding is also known as 'tile' or 'tiling'.
Chris@87 949
Chris@87 950 The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
Chris@87 951 single function, lest the indexing tricks in non-integer multiples of the
Chris@87 952 original shape would violate repetition in the final iteration.
Chris@87 953
Chris@87 954 """
Chris@87 955 # Implicit booleanness to test for zero (or None) in any scalar type
Chris@87 956 if pad_amt[0] == 0 and pad_amt[1] == 0:
Chris@87 957 return arr
Chris@87 958
Chris@87 959 ##########################################################################
Chris@87 960 # Prepended region
Chris@87 961
Chris@87 962 # Slice off a reverse indexed chunk from near edge to pad `arr` before
Chris@87 963 start = arr.shape[axis] - pad_amt[0]
Chris@87 964 end = arr.shape[axis]
Chris@87 965 wrap_slice = tuple(slice(None) if i != axis else slice(start, end)
Chris@87 966 for (i, x) in enumerate(arr.shape))
Chris@87 967 wrap_chunk1 = arr[wrap_slice]
Chris@87 968
Chris@87 969 # Shape to restore singleton dimension after slicing
Chris@87 970 pad_singleton = tuple(x if i != axis else 1
Chris@87 971 for (i, x) in enumerate(arr.shape))
Chris@87 972 if pad_amt[0] == 1:
Chris@87 973 wrap_chunk1 = wrap_chunk1.reshape(pad_singleton)
Chris@87 974
Chris@87 975 ##########################################################################
Chris@87 976 # Appended region
Chris@87 977
Chris@87 978 # Slice off a reverse indexed chunk from far edge to pad `arr` after
Chris@87 979 wrap_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[1])
Chris@87 980 for (i, x) in enumerate(arr.shape))
Chris@87 981 wrap_chunk2 = arr[wrap_slice]
Chris@87 982
Chris@87 983 if pad_amt[1] == 1:
Chris@87 984 wrap_chunk2 = wrap_chunk2.reshape(pad_singleton)
Chris@87 985
Chris@87 986 # Concatenate `arr` with both chunks, extending along `axis`
Chris@87 987 return np.concatenate((wrap_chunk1, arr, wrap_chunk2), axis=axis)
Chris@87 988
Chris@87 989
Chris@87 990 def _normalize_shape(narray, shape):
Chris@87 991 """
Chris@87 992 Private function which does some checks and normalizes the possibly
Chris@87 993 much simpler representations of 'pad_width', 'stat_length',
Chris@87 994 'constant_values', 'end_values'.
Chris@87 995
Chris@87 996 Parameters
Chris@87 997 ----------
Chris@87 998 narray : ndarray
Chris@87 999 Input ndarray
Chris@87 1000 shape : {sequence, int}, optional
Chris@87 1001 The width of padding (pad_width) or the number of elements on the
Chris@87 1002 edge of the narray used for statistics (stat_length).
Chris@87 1003 ((before_1, after_1), ... (before_N, after_N)) unique number of
Chris@87 1004 elements for each axis where `N` is rank of `narray`.
Chris@87 1005 ((before, after),) yields same before and after constants for each
Chris@87 1006 axis.
Chris@87 1007 (constant,) or int is a shortcut for before = after = constant for
Chris@87 1008 all axes.
Chris@87 1009
Chris@87 1010 Returns
Chris@87 1011 -------
Chris@87 1012 _normalize_shape : tuple of tuples
Chris@87 1013 int => ((int, int), (int, int), ...)
Chris@87 1014 [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...)
Chris@87 1015 ((int1, int2), (int3, int4), ...) => no change
Chris@87 1016 [[int1, int2], ] => ((int1, int2), (int1, int2), ...)
Chris@87 1017 ((int1, int2), ) => ((int1, int2), (int1, int2), ...)
Chris@87 1018 [[int , ], ] => ((int, int), (int, int), ...)
Chris@87 1019 ((int , ), ) => ((int, int), (int, int), ...)
Chris@87 1020
Chris@87 1021 """
Chris@87 1022 normshp = None
Chris@87 1023 shapelen = len(np.shape(narray))
Chris@87 1024 if (isinstance(shape, int)) or shape is None:
Chris@87 1025 normshp = ((shape, shape), ) * shapelen
Chris@87 1026 elif (isinstance(shape, (tuple, list))
Chris@87 1027 and isinstance(shape[0], (tuple, list))
Chris@87 1028 and len(shape) == shapelen):
Chris@87 1029 normshp = shape
Chris@87 1030 for i in normshp:
Chris@87 1031 if len(i) != 2:
Chris@87 1032 fmt = "Unable to create correctly shaped tuple from %s"
Chris@87 1033 raise ValueError(fmt % (normshp,))
Chris@87 1034 elif (isinstance(shape, (tuple, list))
Chris@87 1035 and isinstance(shape[0], (int, float, long))
Chris@87 1036 and len(shape) == 1):
Chris@87 1037 normshp = ((shape[0], shape[0]), ) * shapelen
Chris@87 1038 elif (isinstance(shape, (tuple, list))
Chris@87 1039 and isinstance(shape[0], (int, float, long))
Chris@87 1040 and len(shape) == 2):
Chris@87 1041 normshp = (shape, ) * shapelen
Chris@87 1042 if normshp is None:
Chris@87 1043 fmt = "Unable to create correctly shaped tuple from %s"
Chris@87 1044 raise ValueError(fmt % (shape,))
Chris@87 1045 return normshp
Chris@87 1046
Chris@87 1047
Chris@87 1048 def _validate_lengths(narray, number_elements):
Chris@87 1049 """
Chris@87 1050 Private function which does some checks and reformats pad_width and
Chris@87 1051 stat_length using _normalize_shape.
Chris@87 1052
Chris@87 1053 Parameters
Chris@87 1054 ----------
Chris@87 1055 narray : ndarray
Chris@87 1056 Input ndarray
Chris@87 1057 number_elements : {sequence, int}, optional
Chris@87 1058 The width of padding (pad_width) or the number of elements on the edge
Chris@87 1059 of the narray used for statistics (stat_length).
Chris@87 1060 ((before_1, after_1), ... (before_N, after_N)) unique number of
Chris@87 1061 elements for each axis.
Chris@87 1062 ((before, after),) yields same before and after constants for each
Chris@87 1063 axis.
Chris@87 1064 (constant,) or int is a shortcut for before = after = constant for all
Chris@87 1065 axes.
Chris@87 1066
Chris@87 1067 Returns
Chris@87 1068 -------
Chris@87 1069 _validate_lengths : tuple of tuples
Chris@87 1070 int => ((int, int), (int, int), ...)
Chris@87 1071 [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...)
Chris@87 1072 ((int1, int2), (int3, int4), ...) => no change
Chris@87 1073 [[int1, int2], ] => ((int1, int2), (int1, int2), ...)
Chris@87 1074 ((int1, int2), ) => ((int1, int2), (int1, int2), ...)
Chris@87 1075 [[int , ], ] => ((int, int), (int, int), ...)
Chris@87 1076 ((int , ), ) => ((int, int), (int, int), ...)
Chris@87 1077
Chris@87 1078 """
Chris@87 1079 normshp = _normalize_shape(narray, number_elements)
Chris@87 1080 for i in normshp:
Chris@87 1081 chk = [1 if x is None else x for x in i]
Chris@87 1082 chk = [1 if x >= 0 else -1 for x in chk]
Chris@87 1083 if (chk[0] < 0) or (chk[1] < 0):
Chris@87 1084 fmt = "%s cannot contain negative values."
Chris@87 1085 raise ValueError(fmt % (number_elements,))
Chris@87 1086 return normshp
Chris@87 1087
Chris@87 1088
Chris@87 1089 ###############################################################################
Chris@87 1090 # Public functions
Chris@87 1091
Chris@87 1092
Chris@87 1093 def pad(array, pad_width, mode=None, **kwargs):
Chris@87 1094 """
Chris@87 1095 Pads an array.
Chris@87 1096
Chris@87 1097 Parameters
Chris@87 1098 ----------
Chris@87 1099 array : array_like of rank N
Chris@87 1100 Input array
Chris@87 1101 pad_width : {sequence, int}
Chris@87 1102 Number of values padded to the edges of each axis.
Chris@87 1103 ((before_1, after_1), ... (before_N, after_N)) unique pad widths
Chris@87 1104 for each axis.
Chris@87 1105 ((before, after),) yields same before and after pad for each axis.
Chris@87 1106 (pad,) or int is a shortcut for before = after = pad width for all
Chris@87 1107 axes.
Chris@87 1108 mode : {str, function}
Chris@87 1109 One of the following string values or a user supplied function.
Chris@87 1110
Chris@87 1111 'constant'
Chris@87 1112 Pads with a constant value.
Chris@87 1113 'edge'
Chris@87 1114 Pads with the edge values of array.
Chris@87 1115 'linear_ramp'
Chris@87 1116 Pads with the linear ramp between end_value and the
Chris@87 1117 array edge value.
Chris@87 1118 'maximum'
Chris@87 1119 Pads with the maximum value of all or part of the
Chris@87 1120 vector along each axis.
Chris@87 1121 'mean'
Chris@87 1122 Pads with the mean value of all or part of the
Chris@87 1123 vector along each axis.
Chris@87 1124 'median'
Chris@87 1125 Pads with the median value of all or part of the
Chris@87 1126 vector along each axis.
Chris@87 1127 'minimum'
Chris@87 1128 Pads with the minimum value of all or part of the
Chris@87 1129 vector along each axis.
Chris@87 1130 'reflect'
Chris@87 1131 Pads with the reflection of the vector mirrored on
Chris@87 1132 the first and last values of the vector along each
Chris@87 1133 axis.
Chris@87 1134 'symmetric'
Chris@87 1135 Pads with the reflection of the vector mirrored
Chris@87 1136 along the edge of the array.
Chris@87 1137 'wrap'
Chris@87 1138 Pads with the wrap of the vector along the axis.
Chris@87 1139 The first values are used to pad the end and the
Chris@87 1140 end values are used to pad the beginning.
Chris@87 1141 <function>
Chris@87 1142 Padding function, see Notes.
Chris@87 1143 stat_length : {sequence, int}, optional
Chris@87 1144 Used in 'maximum', 'mean', 'median', and 'minimum'. Number of
Chris@87 1145 values at edge of each axis used to calculate the statistic value.
Chris@87 1146
Chris@87 1147 ((before_1, after_1), ... (before_N, after_N)) unique statistic
Chris@87 1148 lengths for each axis.
Chris@87 1149
Chris@87 1150 ((before, after),) yields same before and after statistic lengths
Chris@87 1151 for each axis.
Chris@87 1152
Chris@87 1153 (stat_length,) or int is a shortcut for before = after = statistic
Chris@87 1154 length for all axes.
Chris@87 1155
Chris@87 1156 Default is ``None``, to use the entire axis.
Chris@87 1157 constant_values : {sequence, int}, optional
Chris@87 1158 Used in 'constant'. The values to set the padded values for each
Chris@87 1159 axis.
Chris@87 1160
Chris@87 1161 ((before_1, after_1), ... (before_N, after_N)) unique pad constants
Chris@87 1162 for each axis.
Chris@87 1163
Chris@87 1164 ((before, after),) yields same before and after constants for each
Chris@87 1165 axis.
Chris@87 1166
Chris@87 1167 (constant,) or int is a shortcut for before = after = constant for
Chris@87 1168 all axes.
Chris@87 1169
Chris@87 1170 Default is 0.
Chris@87 1171 end_values : {sequence, int}, optional
Chris@87 1172 Used in 'linear_ramp'. The values used for the ending value of the
Chris@87 1173 linear_ramp and that will form the edge of the padded array.
Chris@87 1174
Chris@87 1175 ((before_1, after_1), ... (before_N, after_N)) unique end values
Chris@87 1176 for each axis.
Chris@87 1177
Chris@87 1178 ((before, after),) yields same before and after end values for each
Chris@87 1179 axis.
Chris@87 1180
Chris@87 1181 (constant,) or int is a shortcut for before = after = end value for
Chris@87 1182 all axes.
Chris@87 1183
Chris@87 1184 Default is 0.
Chris@87 1185 reflect_type : str {'even', 'odd'}, optional
Chris@87 1186 Used in 'reflect', and 'symmetric'. The 'even' style is the
Chris@87 1187 default with an unaltered reflection around the edge value. For
Chris@87 1188 the 'odd' style, the extented part of the array is created by
Chris@87 1189 subtracting the reflected values from two times the edge value.
Chris@87 1190
Chris@87 1191 Returns
Chris@87 1192 -------
Chris@87 1193 pad : ndarray
Chris@87 1194 Padded array of rank equal to `array` with shape increased
Chris@87 1195 according to `pad_width`.
Chris@87 1196
Chris@87 1197 Notes
Chris@87 1198 -----
Chris@87 1199 .. versionadded:: 1.7.0
Chris@87 1200
Chris@87 1201 For an array with rank greater than 1, some of the padding of later
Chris@87 1202 axes is calculated from padding of previous axes. This is easiest to
Chris@87 1203 think about with a rank 2 array where the corners of the padded array
Chris@87 1204 are calculated by using padded values from the first axis.
Chris@87 1205
Chris@87 1206 The padding function, if used, should return a rank 1 array equal in
Chris@87 1207 length to the vector argument with padded values replaced. It has the
Chris@87 1208 following signature::
Chris@87 1209
Chris@87 1210 padding_func(vector, iaxis_pad_width, iaxis, **kwargs)
Chris@87 1211
Chris@87 1212 where
Chris@87 1213
Chris@87 1214 vector : ndarray
Chris@87 1215 A rank 1 array already padded with zeros. Padded values are
Chris@87 1216 vector[:pad_tuple[0]] and vector[-pad_tuple[1]:].
Chris@87 1217 iaxis_pad_width : tuple
Chris@87 1218 A 2-tuple of ints, iaxis_pad_width[0] represents the number of
Chris@87 1219 values padded at the beginning of vector where
Chris@87 1220 iaxis_pad_width[1] represents the number of values padded at
Chris@87 1221 the end of vector.
Chris@87 1222 iaxis : int
Chris@87 1223 The axis currently being calculated.
Chris@87 1224 kwargs : misc
Chris@87 1225 Any keyword arguments the function requires.
Chris@87 1226
Chris@87 1227 Examples
Chris@87 1228 --------
Chris@87 1229 >>> a = [1, 2, 3, 4, 5]
Chris@87 1230 >>> np.lib.pad(a, (2,3), 'constant', constant_values=(4,6))
Chris@87 1231 array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6])
Chris@87 1232
Chris@87 1233 >>> np.lib.pad(a, (2,3), 'edge')
Chris@87 1234 array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5])
Chris@87 1235
Chris@87 1236 >>> np.lib.pad(a, (2,3), 'linear_ramp', end_values=(5,-4))
Chris@87 1237 array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4])
Chris@87 1238
Chris@87 1239 >>> np.lib.pad(a, (2,), 'maximum')
Chris@87 1240 array([5, 5, 1, 2, 3, 4, 5, 5, 5])
Chris@87 1241
Chris@87 1242 >>> np.lib.pad(a, (2,), 'mean')
Chris@87 1243 array([3, 3, 1, 2, 3, 4, 5, 3, 3])
Chris@87 1244
Chris@87 1245 >>> np.lib.pad(a, (2,), 'median')
Chris@87 1246 array([3, 3, 1, 2, 3, 4, 5, 3, 3])
Chris@87 1247
Chris@87 1248 >>> a = [[1,2], [3,4]]
Chris@87 1249 >>> np.lib.pad(a, ((3, 2), (2, 3)), 'minimum')
Chris@87 1250 array([[1, 1, 1, 2, 1, 1, 1],
Chris@87 1251 [1, 1, 1, 2, 1, 1, 1],
Chris@87 1252 [1, 1, 1, 2, 1, 1, 1],
Chris@87 1253 [1, 1, 1, 2, 1, 1, 1],
Chris@87 1254 [3, 3, 3, 4, 3, 3, 3],
Chris@87 1255 [1, 1, 1, 2, 1, 1, 1],
Chris@87 1256 [1, 1, 1, 2, 1, 1, 1]])
Chris@87 1257
Chris@87 1258 >>> a = [1, 2, 3, 4, 5]
Chris@87 1259 >>> np.lib.pad(a, (2,3), 'reflect')
Chris@87 1260 array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2])
Chris@87 1261
Chris@87 1262 >>> np.lib.pad(a, (2,3), 'reflect', reflect_type='odd')
Chris@87 1263 array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8])
Chris@87 1264
Chris@87 1265 >>> np.lib.pad(a, (2,3), 'symmetric')
Chris@87 1266 array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3])
Chris@87 1267
Chris@87 1268 >>> np.lib.pad(a, (2,3), 'symmetric', reflect_type='odd')
Chris@87 1269 array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7])
Chris@87 1270
Chris@87 1271 >>> np.lib.pad(a, (2,3), 'wrap')
Chris@87 1272 array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3])
Chris@87 1273
Chris@87 1274 >>> def padwithtens(vector, pad_width, iaxis, kwargs):
Chris@87 1275 ... vector[:pad_width[0]] = 10
Chris@87 1276 ... vector[-pad_width[1]:] = 10
Chris@87 1277 ... return vector
Chris@87 1278
Chris@87 1279 >>> a = np.arange(6)
Chris@87 1280 >>> a = a.reshape((2,3))
Chris@87 1281
Chris@87 1282 >>> np.lib.pad(a, 2, padwithtens)
Chris@87 1283 array([[10, 10, 10, 10, 10, 10, 10],
Chris@87 1284 [10, 10, 10, 10, 10, 10, 10],
Chris@87 1285 [10, 10, 0, 1, 2, 10, 10],
Chris@87 1286 [10, 10, 3, 4, 5, 10, 10],
Chris@87 1287 [10, 10, 10, 10, 10, 10, 10],
Chris@87 1288 [10, 10, 10, 10, 10, 10, 10]])
Chris@87 1289 """
Chris@87 1290
Chris@87 1291 narray = np.array(array)
Chris@87 1292 pad_width = _validate_lengths(narray, pad_width)
Chris@87 1293
Chris@87 1294 allowedkwargs = {
Chris@87 1295 'constant': ['constant_values'],
Chris@87 1296 'edge': [],
Chris@87 1297 'linear_ramp': ['end_values'],
Chris@87 1298 'maximum': ['stat_length'],
Chris@87 1299 'mean': ['stat_length'],
Chris@87 1300 'median': ['stat_length'],
Chris@87 1301 'minimum': ['stat_length'],
Chris@87 1302 'reflect': ['reflect_type'],
Chris@87 1303 'symmetric': ['reflect_type'],
Chris@87 1304 'wrap': [],
Chris@87 1305 }
Chris@87 1306
Chris@87 1307 kwdefaults = {
Chris@87 1308 'stat_length': None,
Chris@87 1309 'constant_values': 0,
Chris@87 1310 'end_values': 0,
Chris@87 1311 'reflect_type': 'even',
Chris@87 1312 }
Chris@87 1313
Chris@87 1314 if isinstance(mode, str):
Chris@87 1315 # Make sure have allowed kwargs appropriate for mode
Chris@87 1316 for key in kwargs:
Chris@87 1317 if key not in allowedkwargs[mode]:
Chris@87 1318 raise ValueError('%s keyword not in allowed keywords %s' %
Chris@87 1319 (key, allowedkwargs[mode]))
Chris@87 1320
Chris@87 1321 # Set kwarg defaults
Chris@87 1322 for kw in allowedkwargs[mode]:
Chris@87 1323 kwargs.setdefault(kw, kwdefaults[kw])
Chris@87 1324
Chris@87 1325 # Need to only normalize particular keywords.
Chris@87 1326 for i in kwargs:
Chris@87 1327 if i == 'stat_length':
Chris@87 1328 kwargs[i] = _validate_lengths(narray, kwargs[i])
Chris@87 1329 if i in ['end_values', 'constant_values']:
Chris@87 1330 kwargs[i] = _normalize_shape(narray, kwargs[i])
Chris@87 1331 elif mode is None:
Chris@87 1332 raise ValueError('Keyword "mode" must be a function or one of %s.' %
Chris@87 1333 (list(allowedkwargs.keys()),))
Chris@87 1334 else:
Chris@87 1335 # Drop back to old, slower np.apply_along_axis mode for user-supplied
Chris@87 1336 # vector function
Chris@87 1337 function = mode
Chris@87 1338
Chris@87 1339 # Create a new padded array
Chris@87 1340 rank = list(range(len(narray.shape)))
Chris@87 1341 total_dim_increase = [np.sum(pad_width[i]) for i in rank]
Chris@87 1342 offset_slices = [slice(pad_width[i][0],
Chris@87 1343 pad_width[i][0] + narray.shape[i])
Chris@87 1344 for i in rank]
Chris@87 1345 new_shape = np.array(narray.shape) + total_dim_increase
Chris@87 1346 newmat = np.zeros(new_shape, narray.dtype)
Chris@87 1347
Chris@87 1348 # Insert the original array into the padded array
Chris@87 1349 newmat[offset_slices] = narray
Chris@87 1350
Chris@87 1351 # This is the core of pad ...
Chris@87 1352 for iaxis in rank:
Chris@87 1353 np.apply_along_axis(function,
Chris@87 1354 iaxis,
Chris@87 1355 newmat,
Chris@87 1356 pad_width[iaxis],
Chris@87 1357 iaxis,
Chris@87 1358 kwargs)
Chris@87 1359 return newmat
Chris@87 1360
Chris@87 1361 # If we get here, use new padding method
Chris@87 1362 newmat = narray.copy()
Chris@87 1363
Chris@87 1364 # API preserved, but completely new algorithm which pads by building the
Chris@87 1365 # entire block to pad before/after `arr` with in one step, for each axis.
Chris@87 1366 if mode == 'constant':
Chris@87 1367 for axis, ((pad_before, pad_after), (before_val, after_val)) \
Chris@87 1368 in enumerate(zip(pad_width, kwargs['constant_values'])):
Chris@87 1369 newmat = _prepend_const(newmat, pad_before, before_val, axis)
Chris@87 1370 newmat = _append_const(newmat, pad_after, after_val, axis)
Chris@87 1371
Chris@87 1372 elif mode == 'edge':
Chris@87 1373 for axis, (pad_before, pad_after) in enumerate(pad_width):
Chris@87 1374 newmat = _prepend_edge(newmat, pad_before, axis)
Chris@87 1375 newmat = _append_edge(newmat, pad_after, axis)
Chris@87 1376
Chris@87 1377 elif mode == 'linear_ramp':
Chris@87 1378 for axis, ((pad_before, pad_after), (before_val, after_val)) \
Chris@87 1379 in enumerate(zip(pad_width, kwargs['end_values'])):
Chris@87 1380 newmat = _prepend_ramp(newmat, pad_before, before_val, axis)
Chris@87 1381 newmat = _append_ramp(newmat, pad_after, after_val, axis)
Chris@87 1382
Chris@87 1383 elif mode == 'maximum':
Chris@87 1384 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
Chris@87 1385 in enumerate(zip(pad_width, kwargs['stat_length'])):
Chris@87 1386 newmat = _prepend_max(newmat, pad_before, chunk_before, axis)
Chris@87 1387 newmat = _append_max(newmat, pad_after, chunk_after, axis)
Chris@87 1388
Chris@87 1389 elif mode == 'mean':
Chris@87 1390 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
Chris@87 1391 in enumerate(zip(pad_width, kwargs['stat_length'])):
Chris@87 1392 newmat = _prepend_mean(newmat, pad_before, chunk_before, axis)
Chris@87 1393 newmat = _append_mean(newmat, pad_after, chunk_after, axis)
Chris@87 1394
Chris@87 1395 elif mode == 'median':
Chris@87 1396 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
Chris@87 1397 in enumerate(zip(pad_width, kwargs['stat_length'])):
Chris@87 1398 newmat = _prepend_med(newmat, pad_before, chunk_before, axis)
Chris@87 1399 newmat = _append_med(newmat, pad_after, chunk_after, axis)
Chris@87 1400
Chris@87 1401 elif mode == 'minimum':
Chris@87 1402 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
Chris@87 1403 in enumerate(zip(pad_width, kwargs['stat_length'])):
Chris@87 1404 newmat = _prepend_min(newmat, pad_before, chunk_before, axis)
Chris@87 1405 newmat = _append_min(newmat, pad_after, chunk_after, axis)
Chris@87 1406
Chris@87 1407 elif mode == 'reflect':
Chris@87 1408 for axis, (pad_before, pad_after) in enumerate(pad_width):
Chris@87 1409 # Recursive padding along any axis where `pad_amt` is too large
Chris@87 1410 # for indexing tricks. We can only safely pad the original axis
Chris@87 1411 # length, to keep the period of the reflections consistent.
Chris@87 1412 if ((pad_before > 0) or
Chris@87 1413 (pad_after > 0)) and newmat.shape[axis] == 1:
Chris@87 1414 # Extending singleton dimension for 'reflect' is legacy
Chris@87 1415 # behavior; it really should raise an error.
Chris@87 1416 newmat = _prepend_edge(newmat, pad_before, axis)
Chris@87 1417 newmat = _append_edge(newmat, pad_after, axis)
Chris@87 1418 continue
Chris@87 1419
Chris@87 1420 method = kwargs['reflect_type']
Chris@87 1421 safe_pad = newmat.shape[axis] - 1
Chris@87 1422 while ((pad_before > safe_pad) or (pad_after > safe_pad)):
Chris@87 1423 offset = 0
Chris@87 1424 pad_iter_b = min(safe_pad,
Chris@87 1425 safe_pad * (pad_before // safe_pad))
Chris@87 1426 pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad))
Chris@87 1427 newmat = _pad_ref(newmat, (pad_iter_b,
Chris@87 1428 pad_iter_a), method, axis)
Chris@87 1429 pad_before -= pad_iter_b
Chris@87 1430 pad_after -= pad_iter_a
Chris@87 1431 if pad_iter_b > 0:
Chris@87 1432 offset += 1
Chris@87 1433 if pad_iter_a > 0:
Chris@87 1434 offset += 1
Chris@87 1435 safe_pad += pad_iter_b + pad_iter_a
Chris@87 1436 newmat = _pad_ref(newmat, (pad_before, pad_after), method, axis)
Chris@87 1437
Chris@87 1438 elif mode == 'symmetric':
Chris@87 1439 for axis, (pad_before, pad_after) in enumerate(pad_width):
Chris@87 1440 # Recursive padding along any axis where `pad_amt` is too large
Chris@87 1441 # for indexing tricks. We can only safely pad the original axis
Chris@87 1442 # length, to keep the period of the reflections consistent.
Chris@87 1443 method = kwargs['reflect_type']
Chris@87 1444 safe_pad = newmat.shape[axis]
Chris@87 1445 while ((pad_before > safe_pad) or
Chris@87 1446 (pad_after > safe_pad)):
Chris@87 1447 pad_iter_b = min(safe_pad,
Chris@87 1448 safe_pad * (pad_before // safe_pad))
Chris@87 1449 pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad))
Chris@87 1450 newmat = _pad_sym(newmat, (pad_iter_b,
Chris@87 1451 pad_iter_a), method, axis)
Chris@87 1452 pad_before -= pad_iter_b
Chris@87 1453 pad_after -= pad_iter_a
Chris@87 1454 safe_pad += pad_iter_b + pad_iter_a
Chris@87 1455 newmat = _pad_sym(newmat, (pad_before, pad_after), method, axis)
Chris@87 1456
Chris@87 1457 elif mode == 'wrap':
Chris@87 1458 for axis, (pad_before, pad_after) in enumerate(pad_width):
Chris@87 1459 # Recursive padding along any axis where `pad_amt` is too large
Chris@87 1460 # for indexing tricks. We can only safely pad the original axis
Chris@87 1461 # length, to keep the period of the reflections consistent.
Chris@87 1462 safe_pad = newmat.shape[axis]
Chris@87 1463 while ((pad_before > safe_pad) or
Chris@87 1464 (pad_after > safe_pad)):
Chris@87 1465 pad_iter_b = min(safe_pad,
Chris@87 1466 safe_pad * (pad_before // safe_pad))
Chris@87 1467 pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad))
Chris@87 1468 newmat = _pad_wrap(newmat, (pad_iter_b, pad_iter_a), axis)
Chris@87 1469
Chris@87 1470 pad_before -= pad_iter_b
Chris@87 1471 pad_after -= pad_iter_a
Chris@87 1472 safe_pad += pad_iter_b + pad_iter_a
Chris@87 1473 newmat = _pad_wrap(newmat, (pad_before, pad_after), axis)
Chris@87 1474
Chris@87 1475 return newmat