diff options
author | Matti Picus <matti.picus@gmail.com> | 2021-03-18 22:48:42 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-18 22:48:42 +0200 |
commit | ddbff082e0bab0e3580be9f2f275418595879022 (patch) | |
tree | 4a9859df268db7e5d35f9bc1087cedc32b7888ef | |
parent | 9c68c2f7b1b2128a3b4af2134565f60d286fa8b9 (diff) | |
parent | 89de3d9d21e38e4070681e455d98575df3f3b51f (diff) | |
download | numpy-ddbff082e0bab0e3580be9f2f275418595879022.tar.gz |
Merge pull request #17492 from aitikgupta/unwanted-mode-dep
DEP: Shift correlate mode parsing to C and deprecate inexact matches
-rw-r--r-- | doc/release/upcoming_changes/17492.deprecation.rst | 7 | ||||
-rw-r--r-- | numpy/core/include/numpy/ndarraytypes.h | 6 | ||||
-rw-r--r-- | numpy/core/numeric.py | 13 | ||||
-rw-r--r-- | numpy/core/src/multiarray/conversion_utils.c | 72 | ||||
-rw-r--r-- | numpy/core/src/multiarray/conversion_utils.h | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_numeric.py | 42 |
7 files changed, 127 insertions, 20 deletions
diff --git a/doc/release/upcoming_changes/17492.deprecation.rst b/doc/release/upcoming_changes/17492.deprecation.rst new file mode 100644 index 000000000..50005aed7 --- /dev/null +++ b/doc/release/upcoming_changes/17492.deprecation.rst @@ -0,0 +1,7 @@ +Inexact matches for `numpy.convolve` and `numpy.correlate` are deprecated +------------------------------------------------------------------------- + +`numpy.convolve` and `numpy.correlate` now emits a warning when there are case +insensitive and/or inexact matches found for ``mode`` argument in the functions. +Pass full ``"same"``, ``"valid"``, ``"full"`` strings instead of +``"s"``, ``"v"``, ``"f"`` for the ``mode`` argument. diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h index a731e7f15..dacb72022 100644 --- a/numpy/core/include/numpy/ndarraytypes.h +++ b/numpy/core/include/numpy/ndarraytypes.h @@ -236,6 +236,12 @@ typedef enum { NPY_RAISE=2 } NPY_CLIPMODE; +typedef enum { + NPY_VALID=0, + NPY_SAME=1, + NPY_FULL=2 +} NPY_CORRELATEMODE; + /* The special not-a-time (NaT) value */ #define NPY_DATETIME_NAT NPY_MIN_INT64 diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index 7675386e7..a6ee9eba9 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -662,17 +662,6 @@ def flatnonzero(a): return np.nonzero(np.ravel(a))[0] -_mode_from_name_dict = {'v': 0, - 's': 1, - 'f': 2} - - -def _mode_from_name(mode): - if isinstance(mode, str): - return _mode_from_name_dict[mode.lower()[0]] - return mode - - def _correlate_dispatcher(a, v, mode=None): return (a, v) @@ -748,7 +737,6 @@ def correlate(a, v, mode='valid'): array([ 0.0+0.j , 3.0+1.j , 1.5+1.5j, 1.0+0.j , 0.5+0.5j]) """ - mode = _mode_from_name(mode) return multiarray.correlate2(a, v, mode) @@ -852,7 +840,6 @@ def convolve(a, v, mode='full'): raise ValueError('a cannot be empty') if len(v) == 0: raise ValueError('v cannot be empty') - mode = _mode_from_name(mode) return multiarray.correlate(a, v[::-1], mode) diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index dd18f71fd..3c4c21ded 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -715,6 +715,78 @@ PyArray_ConvertClipmodeSequence(PyObject *object, NPY_CLIPMODE *modes, int n) return NPY_SUCCEED; } +static int correlatemode_parser(char const *str, Py_ssize_t length, void *data) +{ + NPY_CORRELATEMODE *val = (NPY_CORRELATEMODE *)data; + int is_exact = 0; + + if (length < 1) { + return -1; + } + if (str[0] == 'V' || str[0] == 'v') { + *val = NPY_VALID; + is_exact = (length == 5 && strcmp(str, "valid") == 0); + } + else if (str[0] == 'S' || str[0] == 's') { + *val = NPY_SAME; + is_exact = (length == 4 && strcmp(str, "same") == 0); + } + else if (str[0] == 'F' || str[0] == 'f') { + *val = NPY_FULL; + is_exact = (length == 4 && strcmp(str, "full") == 0); + } + else { + return -1; + } + + /* Filters out the case sensitive/non-exact + * match inputs and other inputs and outputs DeprecationWarning + */ + if (!is_exact) { + /* Numpy 1.21, 2021-01-19 */ + if (DEPRECATE("inexact matches and case insensitive matches for " + "convolve/correlate mode are deprecated, please " + "use one of 'valid', 'same', or 'full' instead.") < 0) { + return -1; + } + } + + return 0; +} + +/* + * Convert an object to NPY_VALID / NPY_SAME / NPY_FULL + */ +NPY_NO_EXPORT int +PyArray_CorrelatemodeConverter(PyObject *object, NPY_CORRELATEMODE *val) +{ + if (PyUnicode_Check(object)) { + return string_converter_helper( + object, (void *)val, correlatemode_parser, "mode", + "must be one of 'valid', 'same', or 'full'"); + } + + else { + /* For users passing integers */ + int number = PyArray_PyIntAsInt(object); + if (error_converting(number)) { + PyErr_SetString(PyExc_TypeError, + "convolve/correlate mode not understood"); + return NPY_FAIL; + } + if (number <= (int) NPY_FULL + && number >= (int) NPY_VALID) { + *val = (NPY_CORRELATEMODE) number; + return NPY_SUCCEED; + } + else { + PyErr_Format(PyExc_ValueError, + "integer convolve/correlate mode must be 0, 1, or 2"); + return NPY_FAIL; + } + } +} + static int casting_parser(char const *str, Py_ssize_t length, void *data) { NPY_CASTING *casting = (NPY_CASTING *)data; diff --git a/numpy/core/src/multiarray/conversion_utils.h b/numpy/core/src/multiarray/conversion_utils.h index bee0c6064..7d1871c43 100644 --- a/numpy/core/src/multiarray/conversion_utils.h +++ b/numpy/core/src/multiarray/conversion_utils.h @@ -43,6 +43,9 @@ NPY_NO_EXPORT PyObject * PyArray_IntTupleFromIntp(int len, npy_intp const *vals); NPY_NO_EXPORT int +PyArray_CorrelatemodeConverter(PyObject *object, NPY_CORRELATEMODE *val); + +NPY_NO_EXPORT int PyArray_SelectkindConverter(PyObject *obj, NPY_SELECTKIND *selectkind); /* diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index a0f7afeb5..12705dc19 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -2839,7 +2839,7 @@ array_correlate(PyObject *NPY_UNUSED(dummy), if (npy_parse_arguments("correlate", args, len_args, kwnames, "a", NULL, &a0, "v", NULL, &shape, - "|mode", &PyArray_PythonPyIntFromInt, &mode, + "|mode", &PyArray_CorrelatemodeConverter, &mode, NULL, NULL, NULL) < 0) { return NULL; } @@ -2857,7 +2857,7 @@ array_correlate2(PyObject *NPY_UNUSED(dummy), if (npy_parse_arguments("correlate2", args, len_args, kwnames, "a", NULL, &a0, "v", NULL, &shape, - "|mode", &PyArray_PythonPyIntFromInt, &mode, + "|mode", &PyArray_CorrelatemodeConverter, &mode, NULL, NULL, NULL) < 0) { return NULL; } diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 8d3cec708..aba90ece5 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -296,6 +296,7 @@ class TestNonarrayArgs: B[0] = 1j assert_almost_equal(np.var(B), 0.25) + class TestIsscalar: def test_isscalar(self): assert_(np.isscalar(3.1)) @@ -2362,8 +2363,8 @@ class TestClip: base_shape=shape, # Commenting out the min_dims line allows zero-dimensional arrays, # and zero-dimensional arrays containing NaN make the test fail. - min_dims=1 - + min_dims=1 + ) ) amin = data.draw( @@ -2896,10 +2897,10 @@ class TestCorrelate: self.x = np.array([1, 2, 3, 4, 5], dtype=dt) self.xs = np.arange(1, 20)[::3] self.y = np.array([-1, -2, -3], dtype=dt) - self.z1 = np.array([ -3., -8., -14., -20., -26., -14., -5.], dtype=dt) + self.z1 = np.array([-3., -8., -14., -20., -26., -14., -5.], dtype=dt) self.z1_4 = np.array([-2., -5., -8., -11., -14., -5.], dtype=dt) - self.z1r = np.array([-15., -22., -22., -16., -10., -4., -1.], dtype=dt) - self.z2 = np.array([-5., -14., -26., -20., -14., -8., -3.], dtype=dt) + self.z1r = np.array([-15., -22., -22., -16., -10., -4., -1.], dtype=dt) + self.z2 = np.array([-5., -14., -26., -20., -14., -8., -3.], dtype=dt) self.z2r = np.array([-1., -4., -10., -16., -22., -22., -15.], dtype=dt) self.zs = np.array([-3., -14., -30., -48., -66., -84., -102., -54., -19.], dtype=dt) @@ -2947,6 +2948,22 @@ class TestCorrelate: with pytest.raises(ValueError): np.correlate(np.ones(1000), np.array([]), mode='full') + def test_mode(self): + d = np.ones(100) + k = np.ones(3) + default_mode = np.correlate(d, k, mode='valid') + with assert_warns(DeprecationWarning): + valid_mode = np.correlate(d, k, mode='v') + assert_array_equal(valid_mode, default_mode) + # integer mode + with assert_raises(ValueError): + np.correlate(d, k, mode=-1) + assert_array_equal(np.correlate(d, k, mode=0), valid_mode) + # illegal arguments + with assert_raises(TypeError): + np.correlate(d, k, mode=None) + + class TestConvolve: def test_object(self): d = [1.] * 100 @@ -2960,6 +2977,21 @@ class TestConvolve: assert_array_equal(d, np.ones(100)) assert_array_equal(k, np.ones(3)) + def test_mode(self): + d = np.ones(100) + k = np.ones(3) + default_mode = np.convolve(d, k, mode='full') + with assert_warns(DeprecationWarning): + full_mode = np.convolve(d, k, mode='f') + assert_array_equal(full_mode, default_mode) + # integer mode + with assert_raises(ValueError): + np.convolve(d, k, mode=-1) + assert_array_equal(np.convolve(d, k, mode=2), full_mode) + # illegal arguments + with assert_raises(TypeError): + np.convolve(d, k, mode=None) + class TestArgwhere: |