From 08c6e9c142e619ac5175b6a13342ba2f2c571ddd Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Thu, 10 Nov 2022 11:54:21 -0800 Subject: TST: Skip tests that are not currently supported in wasm --- numpy/lib/tests/test_function_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 88d4987e6..c5b31ebf4 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -15,7 +15,7 @@ from numpy import ma from numpy.testing import ( assert_, assert_equal, assert_array_equal, assert_almost_equal, assert_array_almost_equal, assert_raises, assert_allclose, IS_PYPY, - assert_warns, assert_raises_regex, suppress_warnings, HAS_REFCOUNT, + assert_warns, assert_raises_regex, suppress_warnings, HAS_REFCOUNT, IS_WASM ) import numpy.lib.function_base as nfb from numpy.random import rand @@ -3754,6 +3754,7 @@ class TestMedian: b[2] = np.nan assert_equal(np.median(a, (0, 2)), b) + @pytest.mark.skipif(IS_WASM, reason="fp errors don't work correctly") def test_empty(self): # mean(empty array) emits two warnings: empty slice and divide by 0 a = np.array([], dtype=float) -- cgit v1.2.1 From 91432a36a3611c2374ea9e2d45592f0ac5e71adb Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Fri, 2 Dec 2022 16:09:33 -0700 Subject: BUG: `keepdims=True` is ignored if `out` is not `None` in `numpy.median()`, `numpy.percentile()`, and `numpy.quantile()`. Closes #22714, #22544. --- numpy/lib/tests/test_function_base.py | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index c5b31ebf4..1bb4c4efa 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -25,6 +25,7 @@ from numpy.lib import ( i0, insert, interp, kaiser, meshgrid, msort, piecewise, place, rot90, select, setxor1d, sinc, trapz, trim_zeros, unwrap, unique, vectorize ) +from numpy.core.numeric import normalize_axis_tuple def get_mat(n): @@ -3331,6 +3332,32 @@ class TestPercentile: assert_equal(np.percentile(d, [1, 7], axis=(0, 3), keepdims=True).shape, (2, 1, 5, 7, 1)) + @pytest.mark.parametrize('q', [7, [1, 7]]) + @pytest.mark.parametrize( + argnames='axis', + argvalues=[ + None, + 1, + (1,), + (0, 1), + (-3, -1), + ] + ) + def test_keepdims_out(self, q, axis): + d = np.ones((3, 5, 7, 11)) + if axis is None: + shape_out = (1,) * d.ndim + else: + axis_norm = normalize_axis_tuple(axis, d.ndim) + shape_out = tuple( + 1 if i in axis_norm else d.shape[i] for i in range(d.ndim)) + shape_out = np.shape(q) + shape_out + + out = np.empty(shape_out) + result = np.percentile(d, q, axis=axis, keepdims=True, out=out) + assert result is out + assert_equal(result.shape, shape_out) + def test_out(self): o = np.zeros((4,)) d = np.ones((3, 4)) @@ -3843,6 +3870,29 @@ class TestMedian: assert_equal(np.median(d, axis=(0, 1, 3), keepdims=True).shape, (1, 1, 7, 1)) + @pytest.mark.parametrize( + argnames='axis', + argvalues=[ + None, + 1, + (1, ), + (0, 1), + (-3, -1), + ] + ) + def test_keepdims_out(self, axis): + d = np.ones((3, 5, 7, 11)) + if axis is None: + shape_out = (1,) * d.ndim + else: + axis_norm = normalize_axis_tuple(axis, d.ndim) + shape_out = tuple( + 1 if i in axis_norm else d.shape[i] for i in range(d.ndim)) + out = np.empty(shape_out) + result = np.median(d, axis=axis, keepdims=True, out=out) + assert result is out + assert_equal(result.shape, shape_out) + class TestAdd_newdoc_ufunc: -- cgit v1.2.1 From b3c0960a54c81a26bd07912dda96db9e356b34d1 Mon Sep 17 00:00:00 2001 From: Matteo Raso <33975162+MatteoRaso@users.noreply.github.com> Date: Thu, 8 Dec 2022 07:01:59 -0500 Subject: BUG: Quantile function on complex number now throws an error (#22652) (#22703) Since percentile is more or less identical to quantile, I also made it throw an error if it receives a complex input. I also made nanquantile and nanpercentile throw errors as well. * Made the changes recommended by seberg * Fixed a test for PR 22703 * Fixed tests for quantile * Shortened some more lines * Fixup more lines Co-authored-by: Sebastian Berg --- numpy/lib/tests/test_function_base.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 1bb4c4efa..e38a187d8 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -2973,6 +2973,14 @@ class TestPercentile: o = np.ones((1,)) np.percentile(d, 5, None, o, False, 'linear') + def test_complex(self): + arr_c = np.array([0.5+3.0j, 2.1+0.5j, 1.6+2.3j], dtype='G') + assert_raises(TypeError, np.percentile, arr_c, 0.5) + arr_c = np.array([0.5+3.0j, 2.1+0.5j, 1.6+2.3j], dtype='D') + assert_raises(TypeError, np.percentile, arr_c, 0.5) + arr_c = np.array([0.5+3.0j, 2.1+0.5j, 1.6+2.3j], dtype='F') + assert_raises(TypeError, np.percentile, arr_c, 0.5) + def test_2D(self): x = np.array([[1, 1, 1], [1, 1, 1], @@ -2981,7 +2989,7 @@ class TestPercentile: [1, 1, 1]]) assert_array_equal(np.percentile(x, 50, axis=0), [1, 1, 1]) - @pytest.mark.parametrize("dtype", np.typecodes["AllFloat"]) + @pytest.mark.parametrize("dtype", np.typecodes["Float"]) def test_linear_nan_1D(self, dtype): # METHOD 1 of H&F arr = np.asarray([15.0, np.NAN, 35.0, 40.0, 50.0], dtype=dtype) @@ -2998,9 +3006,6 @@ class TestPercentile: (np.float32, np.float32), (np.float64, np.float64), (np.longdouble, np.longdouble), - (np.complex64, np.complex64), - (np.complex128, np.complex128), - (np.clongdouble, np.clongdouble), (np.dtype("O"), np.float64)] @pytest.mark.parametrize(["input_dtype", "expected_dtype"], H_F_TYPE_CODES) @@ -3040,7 +3045,7 @@ class TestPercentile: np.testing.assert_equal(np.asarray(actual).dtype, np.dtype(expected_dtype)) - TYPE_CODES = np.typecodes["AllInteger"] + np.typecodes["AllFloat"] + "O" + TYPE_CODES = np.typecodes["AllInteger"] + np.typecodes["Float"] + "O" @pytest.mark.parametrize("dtype", TYPE_CODES) def test_lower_higher(self, dtype): @@ -3517,6 +3522,15 @@ class TestQuantile: x = np.arange(8) assert_equal(np.quantile(x, Fraction(1, 2)), Fraction(7, 2)) + def test_complex(self): + #See gh-22652 + arr_c = np.array([0.5+3.0j, 2.1+0.5j, 1.6+2.3j], dtype='G') + assert_raises(TypeError, np.quantile, arr_c, 0.5) + arr_c = np.array([0.5+3.0j, 2.1+0.5j, 1.6+2.3j], dtype='D') + assert_raises(TypeError, np.quantile, arr_c, 0.5) + arr_c = np.array([0.5+3.0j, 2.1+0.5j, 1.6+2.3j], dtype='F') + assert_raises(TypeError, np.quantile, arr_c, 0.5) + def test_no_p_overwrite(self): # this is worth retesting, because quantile does not make a copy p0 = np.array([0, 0.75, 0.25, 0.5, 1.0]) -- cgit v1.2.1 From dfc4c174d6a0e16da154d525db2fc29ce569f1b4 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Wed, 14 Dec 2022 15:02:58 +0100 Subject: TST: Remove outdated xfail from quantile tests There should be more tests for this, but this now passes. --- numpy/lib/tests/test_function_base.py | 1 - 1 file changed, 1 deletion(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index e38a187d8..ecba35f2d 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -3484,7 +3484,6 @@ class TestQuantile: assert_equal(np.quantile(x, 1), 3.5) assert_equal(np.quantile(x, 0.5), 1.75) - @pytest.mark.xfail(reason="See gh-19154") def test_correct_quantile_value(self): a = np.array([True]) tf_quant = np.quantile(True, False) -- cgit v1.2.1 From 88cdaa21aea87ec7d56d1d583500ab2659a5e65e Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Wed, 18 Jan 2023 02:25:00 -0500 Subject: BUG: Added __name__ atribute to vectorize class (#23021) --- numpy/lib/tests/test_function_base.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index ecba35f2d..69e4c4848 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1780,6 +1780,13 @@ class TestVectorize: assert_equal(type(r), subclass) assert_equal(r, m * v) + def test_name(self): + #See gh-23021 + @np.vectorize + def f2(a, b): + return a + b + + assert f2.__name__ == 'f2' class TestLeaks: class A: -- cgit v1.2.1 From ade008bf5fba3cbc43ffbdf5ee261953a8a71a3a Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 21 Jan 2023 20:20:30 -0500 Subject: ENH: Enabled use of numpy.vectorize as decorator (#9477) Most of this code comes from PR-9593, but with the default value for pyfunc being numpy._NoValue instead of None, no override of __new__, and no effort to make subclassing possible. Co-Authored-By: Michael Lamparski --- numpy/lib/tests/test_function_base.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 69e4c4848..169484a09 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1788,6 +1788,36 @@ class TestVectorize: assert f2.__name__ == 'f2' + def test_decorator(self): + @vectorize + def addsubtract(a, b): + if a > b: + return a - b + else: + return a + b + + r = addsubtract([0, 3, 6, 9], [1, 3, 5, 7]) + assert_array_equal(r, [1, 6, 1, 2]) + + def test_signature_otypes_decorator(self): + @vectorize(signature='(n)->(n)', otypes=['float64']) + def f(x): + return x + + r = f([1, 2, 3]) + assert_equal(r.dtype, np.dtype('float64')) + assert_array_equal(r, [1, 2, 3]) + assert f.__name__ == 'f' + + def test_positional_regression_9477(self): + # This supplies the first keyword argument as a positional, + # to ensure that they are still properly forwarded after the + # enhancement for #9477 + f = vectorize((lambda x: x), ['float64']) + r = f([2]) + assert_equal(r.dtype, np.dtype('float64')) + + class TestLeaks: class A: iters = 20 -- cgit v1.2.1 From 84596aeec1682de93d82c60b53726838b29ad311 Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Fri, 27 Jan 2023 02:03:00 -0500 Subject: Added test for vectorize decorator project This test makes sure a function's docstring is properly preserved after calling the vectorize decorator. --- numpy/lib/tests/test_function_base.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 169484a09..6499b78b7 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1799,6 +1799,14 @@ class TestVectorize: r = addsubtract([0, 3, 6, 9], [1, 3, 5, 7]) assert_array_equal(r, [1, 6, 1, 2]) + def test_docstring(self): + @vectorize + def f(x): + """Docstring""" + return x + + assert f.__doc__ == "Docstring" + def test_signature_otypes_decorator(self): @vectorize(signature='(n)->(n)', otypes=['float64']) def f(x): -- cgit v1.2.1 From 7a2ded1522305cfbab4e34a18198f3cbcae7755c Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Wed, 8 Feb 2023 20:39:55 -0500 Subject: Added a test for positional args (PR-23061) --- numpy/lib/tests/test_function_base.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 6499b78b7..b56d776cb 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1817,6 +1817,17 @@ class TestVectorize: assert_array_equal(r, [1, 2, 3]) assert f.__name__ == 'f' + def test_decorator_positional_args(self): + A = np.vectorize(abs, ['float64'], "return float absolute value") + y1 = A([1, -1, 0, 0.3, 5]) + + @vectorize(['float64'], "return float absolute value") + def myabs(a): + return abs(a) + + y2 = myabs([1, -1, 0, 0.3, 5]) + assert_array_equal(y1, y2) + def test_positional_regression_9477(self): # This supplies the first keyword argument as a positional, # to ensure that they are still properly forwarded after the -- cgit v1.2.1 From 4b82e29a18cd2c17b258bab0e2d937ab2157377b Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Thu, 9 Feb 2023 22:59:46 -0500 Subject: @vectorize now requires arguments to specify keywords This reverses commit 7a2ded1522305 --- numpy/lib/tests/test_function_base.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index b56d776cb..416a9431b 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1817,16 +1817,15 @@ class TestVectorize: assert_array_equal(r, [1, 2, 3]) assert f.__name__ == 'f' - def test_decorator_positional_args(self): - A = np.vectorize(abs, ['float64'], "return float absolute value") - y1 = A([1, -1, 0, 0.3, 5]) - - @vectorize(['float64'], "return float absolute value") - def myabs(a): - return abs(a) - - y2 = myabs([1, -1, 0, 0.3, 5]) - assert_array_equal(y1, y2) + def test_bad_input(self): + with assert_raises(TypeError): + A = np.vectorize(pyfunc = 3) + + def test_no_keywords(self): + with assert_raises(TypeError): + @np.vectorize("string") + def foo(): + return "bar" def test_positional_regression_9477(self): # This supplies the first keyword argument as a positional, -- cgit v1.2.1 From c03e84044a05f0b2358a1cbfc4158e83cba4b835 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 26 Jan 2023 12:16:23 +0100 Subject: API: Modify `gradient` to return a tuple rather than a list This change is staged for NumPy 2.0, I assume we could get away with it otherwise, but it is a nice example and probably not pressing. --- numpy/lib/tests/test_function_base.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index ecba35f2d..fb98a94cd 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1217,6 +1217,13 @@ class TestGradient: dfdx = gradient(f, x) assert_array_equal(dfdx, [0.5, 0.5]) + def test_return_type(self): + res = np.gradient(([1, 2], [2, 3])) + if np._numpy2_behavior: + assert type(res) is tuple + else: + assert type(res) is list + class TestAngle: -- cgit v1.2.1 From 9d5eafe596e75e30a85c01ed62bb5bea9389adc8 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Fri, 10 Feb 2023 15:51:57 +0100 Subject: MAINT: Use `np._using_numpy2_behavior()` and initialize it in C --- numpy/lib/tests/test_function_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index fb98a94cd..cc8003f61 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1219,7 +1219,7 @@ class TestGradient: def test_return_type(self): res = np.gradient(([1, 2], [2, 3])) - if np._numpy2_behavior: + if np._using_numpy2_behavior(): assert type(res) is tuple else: assert type(res) is list -- cgit v1.2.1 From 9990f98f2e9e1a55f5d42206cbc6709a3efff418 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 2 Mar 2023 14:57:43 +0000 Subject: DEP: deprecate `product`, `cumproduct`, `sometrue`, `alltrue` [skip cirrus] --- numpy/lib/tests/test_function_base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index cc8003f61..3ec46735c 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -229,8 +229,8 @@ class TestAny: def test_nd(self): y1 = [[0, 0, 0], [0, 1, 0], [1, 1, 0]] assert_(np.any(y1)) - assert_array_equal(np.sometrue(y1, axis=0), [1, 1, 0]) - assert_array_equal(np.sometrue(y1, axis=1), [0, 1, 1]) + assert_array_equal(np.any(y1, axis=0), [1, 1, 0]) + assert_array_equal(np.any(y1, axis=1), [0, 1, 1]) class TestAll: @@ -247,8 +247,8 @@ class TestAll: def test_nd(self): y1 = [[0, 0, 1], [0, 1, 1], [1, 1, 1]] assert_(not np.all(y1)) - assert_array_equal(np.alltrue(y1, axis=0), [0, 0, 1]) - assert_array_equal(np.alltrue(y1, axis=1), [0, 0, 1]) + assert_array_equal(np.all(y1, axis=0), [0, 0, 1]) + assert_array_equal(np.all(y1, axis=1), [0, 0, 1]) class TestCopy: -- cgit v1.2.1 From ed1732410f51293e4c5f63dcf162d9f1d417335a Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Mon, 27 Mar 2023 09:36:25 +0300 Subject: Revert "ENH: Enabled the use of numpy.vectorize as a decorator" --- numpy/lib/tests/test_function_base.py | 55 ----------------------------------- 1 file changed, 55 deletions(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 97ca13bfb..3ec46735c 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1787,61 +1787,6 @@ class TestVectorize: assert_equal(type(r), subclass) assert_equal(r, m * v) - def test_name(self): - #See gh-23021 - @np.vectorize - def f2(a, b): - return a + b - - assert f2.__name__ == 'f2' - - def test_decorator(self): - @vectorize - def addsubtract(a, b): - if a > b: - return a - b - else: - return a + b - - r = addsubtract([0, 3, 6, 9], [1, 3, 5, 7]) - assert_array_equal(r, [1, 6, 1, 2]) - - def test_docstring(self): - @vectorize - def f(x): - """Docstring""" - return x - - assert f.__doc__ == "Docstring" - - def test_signature_otypes_decorator(self): - @vectorize(signature='(n)->(n)', otypes=['float64']) - def f(x): - return x - - r = f([1, 2, 3]) - assert_equal(r.dtype, np.dtype('float64')) - assert_array_equal(r, [1, 2, 3]) - assert f.__name__ == 'f' - - def test_bad_input(self): - with assert_raises(TypeError): - A = np.vectorize(pyfunc = 3) - - def test_no_keywords(self): - with assert_raises(TypeError): - @np.vectorize("string") - def foo(): - return "bar" - - def test_positional_regression_9477(self): - # This supplies the first keyword argument as a positional, - # to ensure that they are still properly forwarded after the - # enhancement for #9477 - f = vectorize((lambda x: x), ['float64']) - r = f([2]) - assert_equal(r.dtype, np.dtype('float64')) - class TestLeaks: class A: -- cgit v1.2.1 From dfaa72d72453b8738ec711180e03da824651e46b Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 1 Apr 2023 21:45:16 -0400 Subject: Fixed edge case where pyfunc has no attribute `__name__` --- numpy/lib/tests/test_function_base.py | 80 +++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 12 deletions(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 3ec46735c..6f4449c68 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -8,7 +8,7 @@ import pytest import hypothesis from hypothesis.extra.numpy import arrays import hypothesis.strategies as st - +from functools import partial import numpy as np from numpy import ma @@ -229,8 +229,8 @@ class TestAny: def test_nd(self): y1 = [[0, 0, 0], [0, 1, 0], [1, 1, 0]] assert_(np.any(y1)) - assert_array_equal(np.any(y1, axis=0), [1, 1, 0]) - assert_array_equal(np.any(y1, axis=1), [0, 1, 1]) + assert_array_equal(np.sometrue(y1, axis=0), [1, 1, 0]) + assert_array_equal(np.sometrue(y1, axis=1), [0, 1, 1]) class TestAll: @@ -247,8 +247,8 @@ class TestAll: def test_nd(self): y1 = [[0, 0, 1], [0, 1, 1], [1, 1, 1]] assert_(not np.all(y1)) - assert_array_equal(np.all(y1, axis=0), [0, 0, 1]) - assert_array_equal(np.all(y1, axis=1), [0, 0, 1]) + assert_array_equal(np.alltrue(y1, axis=0), [0, 0, 1]) + assert_array_equal(np.alltrue(y1, axis=1), [0, 0, 1]) class TestCopy: @@ -1217,13 +1217,6 @@ class TestGradient: dfdx = gradient(f, x) assert_array_equal(dfdx, [0.5, 0.5]) - def test_return_type(self): - res = np.gradient(([1, 2], [2, 3])) - if np._using_numpy2_behavior(): - assert type(res) is tuple - else: - assert type(res) is list - class TestAngle: @@ -1787,6 +1780,69 @@ class TestVectorize: assert_equal(type(r), subclass) assert_equal(r, m * v) + def test_name(self): + #See gh-23021 + @np.vectorize + def f2(a, b): + return a + b + + assert f2.__name__ == 'f2' + + def test_decorator(self): + @vectorize + def addsubtract(a, b): + if a > b: + return a - b + else: + return a + b + + r = addsubtract([0, 3, 6, 9], [1, 3, 5, 7]) + assert_array_equal(r, [1, 6, 1, 2]) + + def test_docstring(self): + @vectorize + def f(x): + """Docstring""" + return x + + assert f.__doc__ == "Docstring" + + def test_partial(self): + def foo(x, y): + return x + y + + bar = partial(foo, 3) + vbar = np.vectorize(bar) + assert vbar(1) == 4 + + def test_signature_otypes_decorator(self): + @vectorize(signature='(n)->(n)', otypes=['float64']) + def f(x): + return x + + r = f([1, 2, 3]) + assert_equal(r.dtype, np.dtype('float64')) + assert_array_equal(r, [1, 2, 3]) + assert f.__name__ == 'f' + + def test_bad_input(self): + with assert_raises(TypeError): + A = np.vectorize(pyfunc = 3) + + def test_no_keywords(self): + with assert_raises(TypeError): + @np.vectorize("string") + def foo(): + return "bar" + + def test_positional_regression_9477(self): + # This supplies the first keyword argument as a positional, + # to ensure that they are still properly forwarded after the + # enhancement for #9477 + f = vectorize((lambda x: x), ['float64']) + r = f([2]) + assert_equal(r.dtype, np.dtype('float64')) + class TestLeaks: class A: -- cgit v1.2.1 From cf07cd7c715d42913c4d92d0a8bef128fd2e8367 Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 1 Apr 2023 21:51:59 -0400 Subject: Fixed docstring test --- numpy/lib/tests/test_function_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 6f4449c68..df0c4a003 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1805,7 +1805,8 @@ class TestVectorize: """Docstring""" return x - assert f.__doc__ == "Docstring" + if sys.flags.optimize < 2: + assert f.__doc__ == "Docstring" def test_partial(self): def foo(x, y): -- cgit v1.2.1 From f283fe07eb302df130c5dafaf07d06a8fb9c34fd Mon Sep 17 00:00:00 2001 From: Matteo Raso Date: Sat, 1 Apr 2023 23:11:26 -0400 Subject: Fixed failing tests --- numpy/lib/tests/test_function_base.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index df0c4a003..09d1195ad 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -229,8 +229,8 @@ class TestAny: def test_nd(self): y1 = [[0, 0, 0], [0, 1, 0], [1, 1, 0]] assert_(np.any(y1)) - assert_array_equal(np.sometrue(y1, axis=0), [1, 1, 0]) - assert_array_equal(np.sometrue(y1, axis=1), [0, 1, 1]) + assert_array_equal(np.any(y1, axis=0), [1, 1, 0]) + assert_array_equal(np.any(y1, axis=1), [0, 1, 1]) class TestAll: @@ -247,8 +247,8 @@ class TestAll: def test_nd(self): y1 = [[0, 0, 1], [0, 1, 1], [1, 1, 1]] assert_(not np.all(y1)) - assert_array_equal(np.alltrue(y1, axis=0), [0, 0, 1]) - assert_array_equal(np.alltrue(y1, axis=1), [0, 0, 1]) + assert_array_equal(np.all(y1, axis=0), [0, 0, 1]) + assert_array_equal(np.all(y1, axis=1), [0, 0, 1]) class TestCopy: @@ -1217,6 +1217,13 @@ class TestGradient: dfdx = gradient(f, x) assert_array_equal(dfdx, [0.5, 0.5]) + def test_return_type(self): + res = np.gradient(([1, 2], [2, 3])) + if np._using_numpy2_behavior(): + assert type(res) is tuple + else: + assert type(res) is list + class TestAngle: -- cgit v1.2.1 From 30c047cdb2e0c0b233e5dc3b61c081ce1f6df3d3 Mon Sep 17 00:00:00 2001 From: Christian Lorentzen Date: Fri, 28 Apr 2023 13:34:53 +0200 Subject: TST: add tests for numpy.quantile (#23129) This PR adds additional tests for quantiles: 1. Identification equation $E[V(q, Y)] = 0$ 2. Adding a constant $c > 0$: $q(c + Y) = c + q(Y)$ 3. Multiplying by a constant $c > 0$: $q(c \cdot Y) = c \cdot q(y)$ 4. Multiplying by $-1$: $q_{\alpha}(-Y) = -q_{1-\alpha}(Y)$ (Note by seberg as reviewer: These tests are fairly complex, but may be useful for future development. But if they seem too complicated, they are probably not really vital and could be shortened or removed.) --- numpy/lib/tests/test_function_base.py | 105 ++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 5 deletions(-) (limited to 'numpy/lib/tests/test_function_base.py') diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 09d1195ad..b0944ec85 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -3538,9 +3538,20 @@ class TestPercentile: np.percentile([1, 2, 3, 4.0], q) +quantile_methods = [ + 'inverted_cdf', 'averaged_inverted_cdf', 'closest_observation', + 'interpolated_inverted_cdf', 'hazen', 'weibull', 'linear', + 'median_unbiased', 'normal_unbiased', 'nearest', 'lower', 'higher', + 'midpoint'] + + class TestQuantile: # most of this is already tested by TestPercentile + def V(self, x, y, alpha): + # Identification function used in several tests. + return (x >= y) - alpha + def test_max_ulp(self): x = [0.0, 0.2, 0.4] a = np.quantile(x, 0.45) @@ -3619,11 +3630,7 @@ class TestQuantile: method="nearest") assert res.dtype == dtype - @pytest.mark.parametrize("method", - ['inverted_cdf', 'averaged_inverted_cdf', 'closest_observation', - 'interpolated_inverted_cdf', 'hazen', 'weibull', 'linear', - 'median_unbiased', 'normal_unbiased', - 'nearest', 'lower', 'higher', 'midpoint']) + @pytest.mark.parametrize("method", quantile_methods) def test_quantile_monotonic(self, method): # GH 14685 # test that the return value of quantile is monotonic if p0 is ordered @@ -3654,6 +3661,94 @@ class TestQuantile: assert np.isscalar(actual) assert_equal(np.quantile(a, 0.5), np.nan) + @pytest.mark.parametrize("method", quantile_methods) + @pytest.mark.parametrize("alpha", [0.2, 0.5, 0.9]) + def test_quantile_identification_equation(self, method, alpha): + # Test that the identification equation holds for the empirical + # CDF: + # E[V(x, Y)] = 0 <=> x is quantile + # with Y the random variable for which we have observed values and + # V(x, y) the canonical identification function for the quantile (at + # level alpha), see + # https://doi.org/10.48550/arXiv.0912.0902 + rng = np.random.default_rng(4321) + # We choose n and alpha such that we cover 3 cases: + # - n * alpha is an integer + # - n * alpha is a float that gets rounded down + # - n * alpha is a float that gest rounded up + n = 102 # n * alpha = 20.4, 51. , 91.8 + y = rng.random(n) + x = np.quantile(y, alpha, method=method) + if method in ("higher",): + # These methods do not fulfill the identification equation. + assert np.abs(np.mean(self.V(x, y, alpha))) > 0.1 / n + elif int(n * alpha) == n * alpha: + # We can expect exact results, up to machine precision. + assert_allclose(np.mean(self.V(x, y, alpha)), 0, atol=1e-14) + else: + # V = (x >= y) - alpha cannot sum to zero exactly but within + # "sample precision". + assert_allclose(np.mean(self.V(x, y, alpha)), 0, + atol=1 / n / np.amin([alpha, 1 - alpha])) + + @pytest.mark.parametrize("method", quantile_methods) + @pytest.mark.parametrize("alpha", [0.2, 0.5, 0.9]) + def test_quantile_add_and_multiply_constant(self, method, alpha): + # Test that + # 1. quantile(c + x) = c + quantile(x) + # 2. quantile(c * x) = c * quantile(x) + # 3. quantile(-x) = -quantile(x, 1 - alpha) + # On empirical quantiles, this equation does not hold exactly. + # Koenker (2005) "Quantile Regression" Chapter 2.2.3 calls these + # properties equivariance. + rng = np.random.default_rng(4321) + # We choose n and alpha such that we have cases for + # - n * alpha is an integer + # - n * alpha is a float that gets rounded down + # - n * alpha is a float that gest rounded up + n = 102 # n * alpha = 20.4, 51. , 91.8 + y = rng.random(n) + q = np.quantile(y, alpha, method=method) + c = 13.5 + + # 1 + assert_allclose(np.quantile(c + y, alpha, method=method), c + q) + # 2 + assert_allclose(np.quantile(c * y, alpha, method=method), c * q) + # 3 + q = -np.quantile(-y, 1 - alpha, method=method) + if method == "inverted_cdf": + if ( + n * alpha == int(n * alpha) + or np.round(n * alpha) == int(n * alpha) + 1 + ): + assert_allclose(q, np.quantile(y, alpha, method="higher")) + else: + assert_allclose(q, np.quantile(y, alpha, method="lower")) + elif method == "closest_observation": + if n * alpha == int(n * alpha): + assert_allclose(q, np.quantile(y, alpha, method="higher")) + elif np.round(n * alpha) == int(n * alpha) + 1: + assert_allclose( + q, np.quantile(y, alpha + 1/n, method="higher")) + else: + assert_allclose(q, np.quantile(y, alpha, method="lower")) + elif method == "interpolated_inverted_cdf": + assert_allclose(q, np.quantile(y, alpha + 1/n, method=method)) + elif method == "nearest": + if n * alpha == int(n * alpha): + assert_allclose(q, np.quantile(y, alpha + 1/n, method=method)) + else: + assert_allclose(q, np.quantile(y, alpha, method=method)) + elif method == "lower": + assert_allclose(q, np.quantile(y, alpha, method="higher")) + elif method == "higher": + assert_allclose(q, np.quantile(y, alpha, method="lower")) + else: + # "averaged_inverted_cdf", "hazen", "weibull", "linear", + # "median_unbiased", "normal_unbiased", "midpoint" + assert_allclose(q, np.quantile(y, alpha, method=method)) + class TestLerp: @hypothesis.given(t0=st.floats(allow_nan=False, allow_infinity=False, -- cgit v1.2.1