diff options
Diffstat (limited to 'numpy/lib')
-rw-r--r-- | numpy/lib/format.py | 30 | ||||
-rw-r--r-- | numpy/lib/function_base.py | 8 | ||||
-rw-r--r-- | numpy/lib/tests/test_function_base.py | 72 | ||||
-rw-r--r-- | numpy/lib/twodim_base.py | 2 |
4 files changed, 101 insertions, 11 deletions
diff --git a/numpy/lib/format.py b/numpy/lib/format.py index cb2d511af..4e6e731c1 100644 --- a/numpy/lib/format.py +++ b/numpy/lib/format.py @@ -280,14 +280,26 @@ def dtype_to_descr(dtype): return dtype.str def descr_to_dtype(descr): - ''' - descr may be stored as dtype.descr, which is a list of - (name, format, [shape]) tuples where format may be a str or a tuple. - Offsets are not explicitly saved, rather empty fields with - name, format == '', '|Vn' are added as padding. - - This function reverses the process, eliminating the empty padding fields. - ''' + """ + Returns a dtype based off the given description. + + This is essentially the reverse of `dtype_to_descr()`. It will remove + the valueless padding fields created by, i.e. simple fields like + dtype('float32'), and then convert the description to its corresponding + dtype. + + Parameters + ---------- + descr : object + The object retreived by dtype.descr. Can be passed to + `numpy.dtype()` in order to replicate the input dtype. + + Returns + ------- + dtype : dtype + The dtype constructed by the description. + + """ if isinstance(descr, str): # No padding removal needed return numpy.dtype(descr) @@ -820,7 +832,7 @@ def open_memmap(filename, mode='r+', dtype=None, shape=None, See Also -------- - memmap + numpy.memmap """ if isfileobj(filename): diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index cf6f4891c..1053598b1 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -3879,7 +3879,13 @@ def _quantile_is_valid(q): def _lerp(a, b, t, out=None): """ Linearly interpolate from a to b by a factor of t """ - return add(a*(1 - t), b*t, out=out) + diff_b_a = subtract(b, a) + # asanyarray is a stop-gap until gh-13105 + lerp_interpolation = asanyarray(add(a, diff_b_a*t, out=out)) + subtract(b, diff_b_a * (1 - t), out=lerp_interpolation, where=t>=0.5) + if lerp_interpolation.ndim == 0 and out is None: + lerp_interpolation = lerp_interpolation[()] # unpack 0d arrays + return lerp_interpolation def _quantile_ureduce_func(a, q, axis=None, out=None, overwrite_input=False, diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 9ba0be56a..eb2fc3311 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -5,6 +5,10 @@ import decimal from fractions import Fraction import math import pytest +import hypothesis +from hypothesis.extra.numpy import arrays +import hypothesis.strategies as st + import numpy as np from numpy import ma @@ -3104,6 +3108,74 @@ class TestQuantile: np.quantile(np.arange(100.), p, interpolation="midpoint") assert_array_equal(p, p0) + def test_quantile_monotonic(self): + # GH 14685 + # test that the return value of quantile is monotonic if p0 is ordered + p0 = np.arange(0, 1, 0.01) + quantile = np.quantile(np.array([0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 1, 1, 9, 9, 9, + 8, 8, 7]) * 0.1, p0) + assert_equal(np.sort(quantile), quantile) + + @hypothesis.given( + arr=arrays(dtype=np.float64, + shape=st.integers(min_value=3, max_value=1000), + elements=st.floats(allow_infinity=False, allow_nan=False, + min_value=-1e300, max_value=1e300))) + def test_quantile_monotonic_hypo(self, arr): + p0 = np.arange(0, 1, 0.01) + quantile = np.quantile(arr, p0) + assert_equal(np.sort(quantile), quantile) + + +class TestLerp: + @hypothesis.given(t0=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + t1=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + a = st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300), + b = st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300)) + def test_lerp_monotonic(self, t0, t1, a, b): + l0 = np.lib.function_base._lerp(a, b, t0) + l1 = np.lib.function_base._lerp(a, b, t1) + if t0 == t1 or a == b: + assert l0 == l1 # uninteresting + elif (t0 < t1) == (a < b): + assert l0 <= l1 + else: + assert l0 >= l1 + + @hypothesis.given(t=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + a=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300), + b=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300)) + def test_lerp_bounded(self, t, a, b): + if a <= b: + assert a <= np.lib.function_base._lerp(a, b, t) <= b + else: + assert b <= np.lib.function_base._lerp(a, b, t) <= a + + @hypothesis.given(t=st.floats(allow_nan=False, allow_infinity=False, + min_value=0, max_value=1), + a=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300), + b=st.floats(allow_nan=False, allow_infinity=False, + min_value=-1e300, max_value=1e300)) + def test_lerp_symmetric(self, t, a, b): + # double subtraction is needed to remove the extra precision of t < 0.5 + left = np.lib.function_base._lerp(a, b, 1 - (1 - t)) + right = np.lib.function_base._lerp(b, a, 1 - t) + assert left == right + + def test_lerp_0d_inputs(self): + a = np.array(2) + b = np.array(5) + t = np.array(0.2) + assert np.lib.function_base._lerp(a, b, t) == 2.6 + class TestMedian: diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py index 320a24856..2bb4c78a5 100644 --- a/numpy/lib/twodim_base.py +++ b/numpy/lib/twodim_base.py @@ -441,7 +441,7 @@ def triu(m, k=0): """ Upper triangle of an array. - Return a copy of a matrix with the elements below the `k`-th diagonal + Return a copy of an array with the elements below the `k`-th diagonal zeroed. Please refer to the documentation for `tril` for further details. |