From a43726772b4ed04b18d3f58488302e36a40b91e8 Mon Sep 17 00:00:00 2001 From: John Muradeli Date: Sun, 13 Aug 2023 13:22:27 +0400 Subject: [PATCH 1/3] DOC: add warning to `allclose`, revise "Notes" in `isclose` See #10161 (latest comments, ~8/13/2023) 1: Add `isclose`'s warning to `allclose` 2: Revise `isclose`'s "Notes" on `atol` to emphasize its poorness and better explain its purpose 3: Add revised `isclose` note to `allclose` --- numpy/core/numeric.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index 21f47bf196bf..d16533a665bd 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -701,7 +701,7 @@ def correlate(a, v, mode='valid'): `numpy.correlate` may perform slowly in large arrays (i.e. n = 1e5) because it does not use the FFT to compute the convolution; in that case, `scipy.signal.correlate` might be preferable. - + References ---------- .. [1] Wikipedia, "Cross-correlation", @@ -1587,7 +1587,7 @@ def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None): if (a.ndim < 1) or (b.ndim < 1): raise ValueError("At least one array has zero dimension") - + # Check axisa and axisb are within bounds axisa = normalize_axis_index(axisa, a.ndim, msg_prefix='axisa') axisb = normalize_axis_index(axisb, b.ndim, msg_prefix='axisb') @@ -2186,6 +2186,9 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): ``equal_nan=True``. Infs are treated as equal if they are in the same place and of the same sign in both arrays. + .. warning:: The default `atol` is not appropriate for comparing numbers + that are much smaller than one (see Notes). + Parameters ---------- a, b : array_like @@ -2221,6 +2224,14 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): ``allclose(a, b)`` might be different from ``allclose(b, a)`` in some rare cases. + The default value of `atol` is not appropriate unless all input values + are on order of unity. E.g., `allclose(1e-9, 2e-9)` is `True`. `atol` is + used exclusively for determining whether a non-zero value in `a` is close + to a zero value in `b`. If the expected input values are significantly + smaller than one, it can result in false positives. `atol` should be + carefully selected for the use case at hand. `atol=0` will result in `False` + if either `a` or `b` contains a zero. + The comparison of `a` and `b` uses standard broadcasting, which means that `a` and `b` need not have the same shape in order for ``allclose(a, b)`` to evaluate to True. The same is true for @@ -2300,13 +2311,15 @@ def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): Unlike the built-in `math.isclose`, the above equation is not symmetric in `a` and `b` -- it assumes `b` is the reference value -- so that - `isclose(a, b)` might be different from `isclose(b, a)`. Furthermore, - the default value of atol is not zero, and is used to determine what - small values should be considered close to zero. The default value is - appropriate for expected values of order unity: if the expected values - are significantly smaller than one, it can result in false positives. - `atol` should be carefully selected for the use case at hand. A zero value - for `atol` will result in `False` if either `a` or `b` is zero. + `isclose(a, b)` might be different from `isclose(b, a)`. + + The default value of `atol` is not appropriate unless all input values + are on order of unity. E.g., `allclose(1e-9, 2e-9)` is `True`. `atol` is + used exclusively for determining whether a non-zero value in `a` is close + to a zero value in `b`. If the expected input values are significantly + smaller than one, it can result in false positives. `atol` should be + carefully selected for the use case at hand. `atol=0` will result in `False` + if either `a` or `b` contains a zero. `isclose` is not defined for non-numeric data types. `bool` is considered a numeric data-type for this purpose. From c82eceb16fafbef413bddf35ba064063a33772de Mon Sep 17 00:00:00 2001 From: John Muradeli Date: Sun, 13 Aug 2023 13:26:04 +0400 Subject: [PATCH 2/3] satisfy max line length 79 --- numpy/core/numeric.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index d16533a665bd..77ef4870f00d 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -2229,8 +2229,8 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): used exclusively for determining whether a non-zero value in `a` is close to a zero value in `b`. If the expected input values are significantly smaller than one, it can result in false positives. `atol` should be - carefully selected for the use case at hand. `atol=0` will result in `False` - if either `a` or `b` contains a zero. + carefully selected for the use case at hand. `atol=0` will result in + `False` if either `a` or `b` contains a zero. The comparison of `a` and `b` uses standard broadcasting, which means that `a` and `b` need not have the same shape in order for @@ -2318,8 +2318,8 @@ def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): used exclusively for determining whether a non-zero value in `a` is close to a zero value in `b`. If the expected input values are significantly smaller than one, it can result in false positives. `atol` should be - carefully selected for the use case at hand. `atol=0` will result in `False` - if either `a` or `b` contains a zero. + carefully selected for the use case at hand. `atol=0` will result in + `False` if either `a` or `b` contains a zero. `isclose` is not defined for non-numeric data types. `bool` is considered a numeric data-type for this purpose. From eb3c78f319b60fe11472c282076c9bc6a932d4eb Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Sat, 30 Dec 2023 14:06:35 -0800 Subject: [PATCH 3/3] DOC: isclose/allclose: fixup [skip ci] --- numpy/_core/numeric.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/numpy/_core/numeric.py b/numpy/_core/numeric.py index 0b689f5110b6..6df13cc7aaf4 100644 --- a/numpy/_core/numeric.py +++ b/numpy/_core/numeric.py @@ -2236,7 +2236,9 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): `b` has magnitude smaller than one. For example, it is unlikely that ``a = 1e-9`` and ``b = 2e-9`` should be considered "close", yet ``allclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure - to select `atol` for the use case at hand. + to select `atol` for the use case at hand, especially for defining the + threshold below which a non-zero value in `a` will be considered "close" + to a very small or zero value in `b`. The comparison of `a` and `b` uses standard broadcasting, which means that `a` and `b` need not have the same shape in order for @@ -2322,8 +2324,10 @@ def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False): The default value of `atol` is not appropriate when the reference value `b` has magnitude smaller than one. For example, it is unlikely that ``a = 1e-9`` and ``b = 2e-9`` should be considered "close", yet - ``allclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure - to select `atol` for the use case at hand. + ``isclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure + to select `atol` for the use case at hand, especially for defining the + threshold below which a non-zero value in `a` will be considered "close" + to a very small or zero value in `b`. `isclose` is not defined for non-numeric data types. :class:`bool` is considered a numeric data-type for this purpose.