Skip to content

Commit

Permalink
Merge pull request #413 from davidhassell/dask-allclose
Browse files Browse the repository at this point in the history
dask: `Data.allclose`
  • Loading branch information
davidhassell authored Jun 22, 2022
2 parents bf6b5f7 + 36baa69 commit c49b1b1
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 33 deletions.
38 changes: 17 additions & 21 deletions cf/data/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -5323,55 +5323,51 @@ def all(self, axis=None, keepdims=True, split_every=None):
d.override_units(_units_None, inplace=True)
return d

@daskified(_DASKIFIED_VERBOSE)
def allclose(self, y, rtol=None, atol=None):
"""Returns True if two broadcastable arrays have equal values,
False otherwise.
"""Whether an array is element-wise equal within a tolerance.
Return True if the data is broadcastable to array *y* and
element-wise equal within a tolerance.
Two real numbers ``x`` and ``y`` are considered equal if
``|x-y|<=atol+rtol|y|``, where ``atol`` (the tolerance on absolute
differences) and ``rtol`` (the tolerance on relative differences)
are positive, typically very small numbers. See the *atol* and
*rtol* parameters.
{{equals tolerance}}
.. seealso:: `all`, `any`, `isclose`
:Parameters:
y: data_like
The data to compare.
atol: `float`, optional
The absolute tolerance for all numerical comparisons. By
default the value returned by the `atol` function is used.
{{rtol: number, optional}}
rtol: `float`, optional
The relative tolerance for all numerical comparisons. By
default the value returned by the `rtol` function is used.
{{atol: number, optional}}
:Returns:
`bool`
`Data`
A scalar boolean array that is `True` if the two arrays
are equal within the given tolerance, or `False`
otherwise.
**Examples**
>>> d = cf.Data([1000, 2500], 'metre')
>>> e = cf.Data([1, 2.5], 'km')
>>> d.allclose(e)
>>> bool(d.allclose(e))
True
>>> d = cf.Data(['ab', 'cdef'])
>>> d.allclose([[['ab', 'cdef']]])
True
>>> d.allclose(e)
>>> bool(d.allclose([[['ab', 'cdef']]]))
True
>>> d = cf.Data([[1000, 2500], [1000, 2500]], 'metre')
>>> e = cf.Data([1, 2.5], 'km')
>>> d.allclose(e)
>>> bool(d.allclose(e))
True
>>> d = cf.Data([1, 1, 1], 's')
>>> d.allclose(1)
>>> bool(d.allclose(1))
True
"""
Expand Down
62 changes: 50 additions & 12 deletions cf/test/test_Data.py
Original file line number Diff line number Diff line change
Expand Up @@ -2042,12 +2042,12 @@ def test_Data_BINARY_AND_UNARY_OPERATORS(self):
)

try:
d ** x
d**x
except Exception:
pass
else:
message = "Failed in {!r}**{!r}".format(d, x)
self.assertTrue((d ** x).all(), message)
self.assertTrue((d**x).all(), message)
# --- End: for

for a0 in arrays:
Expand Down Expand Up @@ -2121,12 +2121,12 @@ def test_Data_BINARY_AND_UNARY_OPERATORS(self):
)

try:
x ** d
x**d
except Exception:
pass
else:
message = "Failed in {}**{!r}".format(x, d)
self.assertTrue((x ** d).all(), message)
self.assertTrue((x**d).all(), message)

a = a0.copy()
try:
Expand Down Expand Up @@ -2241,12 +2241,12 @@ def test_Data_BINARY_AND_UNARY_OPERATORS(self):
)

try:
d ** x
d**x
except Exception:
pass
else:
self.assertTrue(
(x ** d).all(), "{}**{}".format(x, repr(d))
(x**d).all(), "{}**{}".format(x, repr(d))
)

self.assertTrue(
Expand Down Expand Up @@ -2529,7 +2529,7 @@ def test_Data_func(self):
if self.test_only and inspect.stack()[0][3] not in self.test_only:
return

a = np.array([[np.e, np.e ** 2, np.e ** 3.5], [0, 1, np.e ** -1]])
a = np.array([[np.e, np.e**2, np.e**3.5], [0, 1, np.e**-1]])

# Using sine as an example function to apply
b = np.sin(a)
Expand Down Expand Up @@ -2577,7 +2577,7 @@ def test_Data_log(self):
return

# Test natural log, base e
a = np.array([[np.e, np.e ** 2, np.e ** 3.5], [0, 1, np.e ** -1]])
a = np.array([[np.e, np.e**2, np.e**3.5], [0, 1, np.e**-1]])
b = np.log(a)
c = cf.Data(a, "s")
d = c.log()
Expand All @@ -2591,15 +2591,15 @@ def test_Data_log(self):
self.assertEqual(c.shape, b.shape)

# Test another base, using 10 as an example (special managed case)
a = np.array([[10, 100, 10 ** 3.5], [0, 1, 0.1]])
a = np.array([[10, 100, 10**3.5], [0, 1, 0.1]])
b = np.log10(a)
c = cf.Data(a, "s")
d = c.log(base=10)
self.assertTrue((d.array == b).all())
self.assertEqual(d.shape, b.shape)

# Test an arbitrary base, using 4 (not a special managed case like 10)
a = np.array([[4, 16, 4 ** 3.5], [0, 1, 0.25]])
a = np.array([[4, 16, 4**3.5], [0, 1, 0.25]])
b = np.log(a) / np.log(4) # the numpy way, using log rules from school
c = cf.Data(a, "s")
d = c.log(base=4)
Expand Down Expand Up @@ -3645,7 +3645,7 @@ def test_Data_collapse_units(self):
self.assertEqual(func().Units, d.Units)

for func in (d.sum_of_squares, d.var):
self.assertEqual(func().Units, d.Units ** 2)
self.assertEqual(func().Units, d.Units**2)

for func in (d.sum_of_weights, d.sum_of_weights2):
self.assertEqual(func().Units, cf.Units())
Expand All @@ -3654,7 +3654,7 @@ def test_Data_collapse_units(self):
w = cf.Data(1, "m")
self.assertEqual(d.integral(weights=w).Units, d.Units * w.Units)
self.assertEqual(d.sum_of_weights(weights=w).Units, w.Units)
self.assertEqual(d.sum_of_weights2(weights=w).Units, w.Units ** 2)
self.assertEqual(d.sum_of_weights2(weights=w).Units, w.Units**2)

# Dimensionless data
d = cf.Data([1, 2])
Expand Down Expand Up @@ -3790,6 +3790,44 @@ def test_Data_set_units(self):
with self.assertRaises(ValueError):
d.set_units("km")

def test_Data_allclose(self):
d = cf.Data(1, "m")
for x in (1, [1], np.array([[1]]), da.from_array(1), cf.Data(1)):
self.assertTrue(d.allclose(x).array)

d = cf.Data([1000, 2500], "metre")
e = cf.Data([1, 2.5], "km")
self.assertTrue(d.allclose(e))

e = cf.Data([1, 999], "km")
self.assertFalse(d.allclose(e))

d = cf.Data([[1000, 2500], [1000, 2500]], "metre")
e = cf.Data([1, 2.5], "km")
self.assertTrue(d.allclose(e))

d = cf.Data(["ab", "cdef"])
e = [[["ab", "cdef"]]]
self.assertTrue(d.allclose(e))

d = cf.Data([1, 1, 1], "s")
e = 1
self.assertTrue(d.allclose(e))

# Incompatible units
with self.assertRaises(ValueError):
d.allclose(cf.Data([1, 1, 1], "m"))

# Not broadcastable
with self.assertRaises(ValueError):
d.allclose([1, 2])

# Incompatible units
d = cf.Data([[1000, 2500]], "m")
e = cf.Data([1, 2.5], "s")
with self.assertRaises(ValueError):
d.allclose(e)

def test_Data_isclose(self):
d = cf.Data(1, "m")
for x in (1, [1], np.array([[1]]), da.from_array(1), cf.Data(1)):
Expand Down

0 comments on commit c49b1b1

Please sign in to comment.