From 48892386597f40759917d68056a76fda48a8621d Mon Sep 17 00:00:00 2001 From: Alix Damman Date: Thu, 15 Feb 2018 14:23:28 +0100 Subject: [PATCH] fix #488 : added rtol and atol arguments to LArray.equals in order to test equality between two arrays within a relative or absolute tolerance --- doc/source/changes/version_0_28.rst.inc | 24 +++++++++++++- larray/core/array.py | 42 ++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/doc/source/changes/version_0_28.rst.inc b/doc/source/changes/version_0_28.rst.inc index f789cf1a5..d8c827108 100644 --- a/doc/source/changes/version_0_28.rst.inc +++ b/doc/source/changes/version_0_28.rst.inc @@ -231,7 +231,29 @@ Miscellaneous improvements >>> arr = read_csv('arr.csv', nb_axes=3) - Closes :issue:`548`: + Closes :issue:`548`. + +* added the relative tolerance `rtol` and the absolute tolerance `atol` arguments to the `LArray.equals` method. + These two arguments can be used to test the equality between two arrays within a given relative or + absolute tolerance: + + >>> arr1 = LArray([6., 8.], "a=a0,a1") + >>> arr1 + a a0 a1 + 6.0 8.0 + >>> arr2 = LArray([5.999, 8.001], "a=a0,a1") + >>> arr2 + a a0 a1 + 5.999 8.001 + >>> arr1.equals(arr2) + False + >>> # equals returns True if abs(array1 - array2) <= (atol + rtol * abs(array2)) + >>> arr1.equals(arr2, atol=0.01) + True + >>> arr1.equals(arr2, rtol=0.01) + True + + Closes :issue:`488`. * renamed argument `transpose` by `wide` in `to_csv` method. diff --git a/larray/core/array.py b/larray/core/array.py index 185927a3b..2aabc07f3 100644 --- a/larray/core/array.py +++ b/larray/core/array.py @@ -5225,7 +5225,7 @@ def __int__(self): def __float__(self): return self.data.__float__() - def equals(self, other, nan_equals=False): + def equals(self, other, rtol=0, atol=0, nan_equals=False): """ Compares self with another array and returns True if they have the same axes and elements, False otherwise. @@ -5233,6 +5233,10 @@ def equals(self, other, nan_equals=False): ---------- other: LArray-like Input array. aslarray() is used on a non-LArray input. + rtol : float or int, optional + The relative tolerance parameter (see Notes). Defaults to 0. + atol : float or int, optional + The absolute tolerance parameter (see Notes). Defaults to 0. nan_equals: boolean, optional Whether or not to consider nan values at the same positions in the two arrays as equal. By default, an array containing nan values is never equal to another array, even if that other array @@ -5244,6 +5248,15 @@ def equals(self, other, nan_equals=False): bool Returns True if self is equal to other. + Notes + ----- + For finite values, equals uses the following equation to test whether two values are equal: + + absolute(array1 - array2) <= (atol + rtol * absolute(array2)) + + The above equation is not symmetric in array1 and array2, so that equals(array1, array2) might be different + from equals(array2, array1) in some rare cases. + Examples -------- >>> arr1 = ndtest((2, 3)) @@ -5261,6 +5274,24 @@ def equals(self, other, nan_equals=False): >>> arr1.equals(arr3) False + Test equality between two arrays within a given tolerance range. + Return True if absolute(array1 - array2) <= (atol + rtol * absolute(array2)). + + >>> arr1 = LArray([6., 8.], "a=a0,a1") + >>> arr1 + a a0 a1 + 6.0 8.0 + >>> arr2 = LArray([5.999, 8.001], "a=a0,a1") + >>> arr2 + a a0 a1 + 5.999 8.001 + >>> arr1.equals(arr2) + False + >>> arr1.equals(arr2, atol=0.01) + True + >>> arr1.equals(arr2, rtol=0.01) + True + Arrays with nan values >>> arr1 = ndtest((2, 3), dtype=float) @@ -5283,10 +5314,13 @@ def equals(self, other, nan_equals=False): other = aslarray(other) except Exception: return False - if nan_equals: - return self.axes == other.axes and all(nan_equal(self, other)) + if rtol == 0 and atol == 0: + if nan_equals: + return self.axes == other.axes and all(nan_equal(self, other)) + else: + return self.axes == other.axes and np.array_equal(np.asarray(self), np.asarray(other)) else: - return self.axes == other.axes and np.array_equal(np.asarray(self), np.asarray(other)) + return self.axes == other.axes and np.allclose(np.asarray(self), np.asarray(other), rtol, atol, nan_equals) def divnot0(self, other): """Divides array by other, but returns 0.0 where other is 0.