Repository: scipy/scipy

Issue:
BUG: find_peaks_cwt test failures in 32-bit Linux wheels
The combination of Linux + 32-bit + somewhat-older versions of NumPy seems to cause the failures.

[Example Travis test matrix](https://travis-ci.org/MacPython/scipy-wheels/builds/614182055?utm_source=github_status&utm_medium=notification)

```
=================================== FAILURES ===================================
____________________ TestFindPeaksCwt.test_find_peaks_exact ____________________
[gw0] linux -- Python 3.5.7 /venv/bin/python

self = <scipy.signal.tests.test_peak_finding.TestFindPeaksCwt object at 0xe8fd7dcc>

    def test_find_peaks_exact(self):
        """
        Generate a series of gaussians and attempt to find the peak locations.
        """
        sigmas = [5.0, 3.0, 10.0, 20.0, 10.0, 50.0]
        num_points = 500
        test_data, act_locs = _gen_gaussians_even(sigmas, num_points)
        widths = np.arange(0.1, max(sigmas))
        found_locs = find_peaks_cwt(test_data, widths, gap_thresh=2, min_snr=0,
                                         min_length=None)
        np.testing.assert_array_equal(found_locs, act_locs,
>                       "Found maximum locations did not equal those expected")
E       AssertionError: 
E       Arrays are not equal
E       Found maximum locations did not equal those expected
E       (mismatch 100.0%)
E        x: array([ 72, 143, 215, 286, 358, 429], dtype=int32)
E        y: array([ 71, 142, 214, 285, 357, 428])

act_locs   = array([ 71, 142, 214, 285, 357, 428])
found_locs = array([ 72, 143, 215, 286, 358, 429], dtype=int32)
num_points = 500
self       = <scipy.signal.tests.test_peak_finding.TestFindPeaksCwt object at 0xe8fd7dcc>
sigmas     = [5.0, 3.0, 10.0, 20.0, 10.0, 50.0]
test_data  = array([  1.50549685e-32,   2.11937869e-32,   2.98119127e-32,
         4.19009319e-32,   5.88450706e-32,   8.25750906e-....75099657e-01,
         1.66027806e-01,   1.57300074e-01,   1.48911963e-01,
         1.40858421e-01,   1.33133885e-01])
widths     = array([  0.1,   1.1,   2.1,   3.1,   4.1,   5.1,   6.1,   7.1,   8.1,
         9.1,  10.1,  11.1,  12.1,  13.1,  14.1,... 35.1,
        36.1,  37.1,  38.1,  39.1,  40.1,  41.1,  42.1,  43.1,  44.1,
        45.1,  46.1,  47.1,  48.1,  49.1])

/venv/lib/python3.5/site-packages/scipy/signal/tests/test_peak_finding.py:789: AssertionError
__________________ TestFindPeaksCwt.test_find_peaks_withnoise __________________
[gw0] linux -- Python 3.5.7 /venv/bin/python

self = <scipy.signal.tests.test_peak_finding.TestFindPeaksCwt object at 0xe8fdb16c>

    def test_find_peaks_withnoise(self):
        """
        Verify that peak locations are (approximately) found
        for a series of gaussians with added noise.
        """
        sigmas = [5.0, 3.0, 10.0, 20.0, 10.0, 50.0]
        num_points = 500
        test_data, act_locs = _gen_gaussians_even(sigmas, num_points)
        widths = np.arange(0.1, max(sigmas))
        noise_amp = 0.07
        np.random.seed(18181911)
        test_data += (np.random.rand(num_points) - 0.5)*(2*noise_amp)
        found_locs = find_peaks_cwt(test_data, widths, min_length=15,
                                         gap_thresh=1, min_snr=noise_amp / 5)
    
        np.testing.assert_equal(len(found_locs), len(act_locs), 'Different number' +
                                'of peaks found than expected')
        diffs = np.abs(found_locs - act_locs)
        max_diffs = np.array(sigmas) / 5
        np.testing.assert_array_less(diffs, max_diffs, 'Maximum location differed' +
>                                    'by more than %s' % (max_diffs))
E       AssertionError: 
E       Arrays are not less-ordered
E       Maximum location differedby more than [  1.    0.6   2.    4.    2.   10. ]
E       (mismatch 33.33333333333333%)
E        x: array([1, 1, 1, 3, 1, 0])
E        y: array([  1. ,   0.6,   2. ,   4. ,   2. ,  10. ])

act_locs   = array([ 71, 142, 214, 285, 357, 428])
diffs      = array([1, 1, 1, 3, 1, 0])
found_locs = array([ 72, 143, 215, 288, 358, 428], dtype=int32)
max_diffs  = array([  1. ,   0.6,   2. ,   4. ,   2. ,  10. ])
noise_amp  = 0.07
num_points = 500
self       = <scipy.signal.tests.test_peak_finding.TestFindPeaksCwt object at 0xe8fdb16c>
sigmas     = [5.0, 3.0, 10.0, 20.0, 10.0, 50.0]
test_data  = array([  6.78864387e-02,  -2.00643540e-02,  -3.27414303e-02,
         1.19094918e-02,   5.52614013e-02,   6.31457252e-....28751325e-01,
         2.10417219e-01,   1.06335978e-01,   1.70557941e-01,
         1.30800895e-01,   2.02734269e-01])
widths     = array([  0.1,   1.1,   2.1,   3.1,   4.1,   5.1,   6.1,   7.1,   8.1,
         9.1,  10.1,  11.1,  12.1,  13.1,  14.1,... 35.1,
        36.1,  37.1,  38.1,  39.1,  40.1,  41.1,  42.1,  43.1,  44.1,
        45.1,  46.1,  47.1,  48.1,  49.1])

/venv/lib/python3.5/site-packages/scipy/signal/tests/test_peak_finding.py:811: AssertionError
```


Discussion:
This should be due to gh-7076. There a backwards-incompatible bug fix was made that would have changed the results: https://github.com/scipy/scipy/pull/7076#pullrequestreview-306639720

In the first test failure some peak locations are shifted by 1. That could be just noise or also an improvement, needs checking.  The differences in the second failure are larger.

@tylerjereddy I think for `1.4.0rc1` you can just add a `skipif` if you are blocked on this. I'll try to look into it tonight.
Note that this issue is still showing up in master branch cron jobs for the SciPy wheels repo & our 1.4.0 release will contain the skips on these tests for the 32-bit Linux case.

If it gets cleaned up eventually we can consider backporting a fix to 1.4.x series release.
Both failures still persist on master branch + master wheels repo for Python 3.7 + Linux + 32-bit only:
https://api.travis-ci.org/v3/job/642208593/log.txt
This is still true on master branch wheel builds for Python 3.7 + Linux + 32-bit only.

Resolving patch:
diff --git a/scipy/signal/_peak_finding.py b/scipy/signal/_peak_finding.py
--- a/scipy/signal/_peak_finding.py
+++ b/scipy/signal/_peak_finding.py
@@ -1288,7 +1288,7 @@ def find_peaks_cwt(vector, widths, wavelet=None, max_distances=None,
     if wavelet is None:
         wavelet = ricker
 
-    cwt_dat = cwt(vector, wavelet, widths)
+    cwt_dat = cwt(vector, wavelet, widths, window_size=window_size)
     ridge_lines = _identify_ridge_lines(cwt_dat, max_distances, gap_thresh)
     filtered = _filter_ridge_lines(cwt_dat, ridge_lines, min_length=min_length,
                                    window_size=window_size, min_snr=min_snr,
diff --git a/scipy/signal/wavelets.py b/scipy/signal/wavelets.py
--- a/scipy/signal/wavelets.py
+++ b/scipy/signal/wavelets.py
@@ -456,6 +456,8 @@ def cwt(data, wavelet, widths, dtype=None, **kwargs):
     ...            vmax=abs(cwtmatr).max(), vmin=-abs(cwtmatr).max())
     >>> plt.show()
     """
+    if wavelet == ricker:
+        window_size = kwargs.pop('window_size', None)
     # Determine output type
     if dtype is None:
         if np.asarray(wavelet(1, widths[0], **kwargs)).dtype.char in 'FDG':
@@ -466,6 +468,14 @@ def cwt(data, wavelet, widths, dtype=None, **kwargs):
     output = np.zeros((len(widths), len(data)), dtype=dtype)
     for ind, width in enumerate(widths):
         N = np.min([10 * width, len(data)])
+        # the conditional block below and the window_size
+        # kwarg pop above may be removed eventually; these
+        # are shims for 32-bit arch + NumPy <= 1.14.5 to
+        # address gh-11095
+        if wavelet == ricker and window_size is None:
+            ceil = np.ceil(N)
+            if ceil != N:
+                N = int(N)
         wavelet_data = np.conj(wavelet(N, width, **kwargs)[::-1])
         output[ind] = convolve(data, wavelet_data, mode='same')
     return output


Test patch: