Skip to content

Commit 99cbfc3

Browse files
authored
Merge pull request #854 from Hrafz/bugfix/pad-zero-width
BUG: fix pywt.pad for a zero pad width in 'smooth' and 'antisymmetric' (gh-589)
2 parents 2a963f1 + de9984d commit 99cbfc3

2 files changed

Lines changed: 39 additions & 5 deletions

File tree

pywt/_dwt.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ def pad(x, pad_widths, mode):
442442
pad_widths = np.array(pad_widths)
443443
pad_widths = np.round(pad_widths).astype(np.intp, copy=False)
444444
if pad_widths.min() < 0:
445-
raise ValueError("pad_widths must be > 0")
445+
raise ValueError("pad_widths must be >= 0")
446446
pad_widths = np.broadcast_to(pad_widths, (x.ndim, 2)).tolist()
447447

448448
if mode in ['symmetric', 'reflect']:
@@ -468,9 +468,12 @@ def pad_smooth(vector, pad_width, iaxis, kwargs):
468468
left + np.arange(pad_width[0], 0, -1) * slope_left
469469

470470
# smooth extension to right
471-
right = vector[-pad_width[1] - 1]
472-
slope_right = (right - vector[-pad_width[1] - 2])
473-
vector[-pad_width[1]:] = \
471+
# Note: indices are measured from the start of the vector so that
472+
# a pad width of 0 gives an empty slice rather than the full one.
473+
iright = vector.size - pad_width[1] - 1
474+
right = vector[iright]
475+
slope_right = (right - vector[iright - 1])
476+
vector[iright + 1:] = \
474477
right + np.arange(1, pad_width[1] + 1) * slope_right
475478
return vector
476479
xp = np.pad(x, pad_widths, pad_smooth)
@@ -481,7 +484,7 @@ def pad_antisymmetric(vector, pad_width, iaxis, kwargs):
481484
npad_l, npad_r = pad_width
482485
vsize_nonpad = vector.size - npad_l - npad_r
483486
# Note: must modify vector in-place
484-
vector[:] = np.pad(vector[pad_width[0]:-pad_width[-1]],
487+
vector[:] = np.pad(vector[npad_l:vector.size - npad_r],
485488
pad_width, mode='symmetric')
486489
vp = vector
487490
r_edge = npad_l + vsize_nonpad - 1

pywt/tests/test_dwt_idwt.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,37 @@ def test_pad_1d():
279279
pywt.pad(x, (4, 4), 'periodic'))
280280

281281

282+
def test_pad_zero_width():
283+
# zero pad width is a no-op for all modes except 'periodization', which
284+
# also promotes odd-length axes to even length (gh-589)
285+
for ndim in [1, 2, 3]:
286+
x = np.arange(3.0**ndim).reshape((3, ) * ndim)
287+
for mode in pywt.Modes.modes:
288+
if mode == 'periodization':
289+
continue
290+
assert_array_equal(pywt.pad(x, 0, mode), x,
291+
err_msg=f"mode={mode}, ndim={ndim}")
292+
293+
294+
def test_pad_one_sided():
295+
# a zero pad width on only one side of the axis (gh-589)
296+
x = [1, 2, 3]
297+
assert_array_equal(pywt.pad(x, (2, 0), 'smooth'), [-1, 0, 1, 2, 3])
298+
assert_array_equal(pywt.pad(x, (0, 2), 'smooth'), [1, 2, 3, 4, 5])
299+
assert_array_equal(pywt.pad(x, (2, 0), 'antisymmetric'), [-2, -1, 1, 2, 3])
300+
assert_array_equal(pywt.pad(x, (0, 2), 'antisymmetric'), [1, 2, 3, -3, -2])
301+
302+
# one-sided padding matches the corresponding slice of two-sided padding
303+
for mode in pywt.Modes.modes:
304+
if mode == 'periodization':
305+
continue
306+
two_sided = pywt.pad(x, (4, 6), mode)
307+
assert_array_equal(pywt.pad(x, (4, 0), mode), two_sided[:-6],
308+
err_msg=f"mode={mode}")
309+
assert_array_equal(pywt.pad(x, (0, 6), mode), two_sided[4:],
310+
err_msg=f"mode={mode}")
311+
312+
282313
def test_pad_errors():
283314
# negative pad width
284315
x = [1, 2, 3]

0 commit comments

Comments
 (0)