From efa5770abcb81fc3bb6a60742450b18cbc54ce83 Mon Sep 17 00:00:00 2001 From: Michael Tarnawa Date: Tue, 2 Feb 2021 13:57:50 +0100 Subject: [PATCH] add isfinite, isinf, isnan --- CHANGELOG.md | 3 +- heat/core/logical.py | 58 +++++++++++++++++++ heat/core/tests/test_logical.py | 99 +++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 582b088762..3dd8cc01a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ - [#679](https://github.com/helmholtz-analytics/heat/pull/679) New feature: ``histc()`` and ``histogram()`` ### Linear Algebra - [#658](https://github.com/helmholtz-analytics/heat/pull/658) Bugfix: `matmul` on GPU will cast away from `int`s to `float`s for the operation and cast back upon its completion. This may result in numerical inaccuracies for very large `int64` DNDarrays -### ... +### Logical +- [#711](https://github.com/helmholtz-analytics/heat/pull/711) `isfinite()`, `isinf()`, `isnan()` ## Bug fixes - [#709](https://github.com/helmholtz-analytics/heat/pull/709) Set the encoding for README.md in setup.py explicitly. diff --git a/heat/core/logical.py b/heat/core/logical.py index 6088322e69..cc5bd4abfb 100644 --- a/heat/core/logical.py +++ b/heat/core/logical.py @@ -14,6 +14,9 @@ "allclose", "any", "isclose", + "isfinite", + "isinf", + "isnan", "logical_and", "logical_not", "logical_or", @@ -217,6 +220,61 @@ def isclose(x, y, rtol=1e-05, atol=1e-08, equal_nan=False): return result +def isfinite(x): + """ + Test element-wise for finiteness (not infinity or not Not a Number) and return result as a boolean array. + + Parameters + ---------- + x : DNDarray + out : DNDarray + + Examples + -------- + >>> ht.isfinite(ht.array([1, ht.inf, -ht.inf, ht.nan])) + DNDarray([ True, False, False, False], dtype=ht.bool, device=cpu:0, split=None) + """ + return _operations.__local_op(torch.isfinite, x, None, no_cast=True) + + +def isinf(x): + """ + Test element-wise for positive or negative infinity and return result as a boolean array. + + Parameters + ---------- + x : DNDarray + out : DNDarray + + Examples + -------- + >>> ht.isinf(ht.array([1, ht.inf, -ht.inf, ht.nan])) + DNDarray([False, True, True, False], dtype=ht.bool, device=cpu:0, split=None) + """ + return _operations.__local_op(torch.isinf, x, None, no_cast=True) + + +def isnan(x): + """ + Test element-wise for NaN and return result as a boolean array. + + Parameters + ---------- + x : DNDarray + out : DNDarray + + Returns + ------- + DNDarray + + Examples + -------- + >>> ht.isnan(ht.array([1, ht.inf, -ht.inf, ht.nan])) + DNDarray([False, False, False, True], dtype=ht.bool, device=cpu:0, split=None) + """ + return _operations.__local_op(torch.isnan, x, None, no_cast=True) + + def logical_and(t1, t2): """ Compute the truth value of t1 AND t2 element-wise. diff --git a/heat/core/tests/test_logical.py b/heat/core/tests/test_logical.py index 269c23f280..842bbaf933 100644 --- a/heat/core/tests/test_logical.py +++ b/heat/core/tests/test_logical.py @@ -242,6 +242,105 @@ def test_isclose(self): with self.assertRaises(TypeError): ht.isclose("?", a) + def test_isfinite(self): + a = ht.array([1, ht.inf, -ht.inf, ht.nan]) + s = ht.array([True, False, False, False]) + r = ht.isfinite(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.array([1, ht.inf, -ht.inf, ht.nan], split=0) + s = ht.array([True, False, False, False], split=0) + r = ht.isfinite(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.ones((6, 6), dtype=ht.bool, split=0) + s = ht.ones((6, 6), dtype=ht.bool, split=0) + r = ht.isfinite(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.ones((5, 5), dtype=ht.int, split=1) + s = ht.ones((5, 5), dtype=ht.bool, split=1) + r = ht.isfinite(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + def test_isinf(self): + a = ht.array([1, ht.inf, -ht.inf, ht.nan]) + s = ht.array([False, True, True, False]) + r = ht.isinf(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.array([1, ht.inf, -ht.inf, ht.nan], split=0) + s = ht.array([False, True, True, False], split=0) + r = ht.isinf(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.ones((6, 6), dtype=ht.bool, split=0) + s = ht.zeros((6, 6), dtype=ht.bool, split=0) + r = ht.isinf(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.ones((5, 5), dtype=ht.int, split=1) + s = ht.zeros((5, 5), dtype=ht.bool, split=1) + r = ht.isinf(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + def test_isnan(self): + a = ht.array([1, ht.inf, -ht.inf, ht.nan]) + s = ht.array([False, False, False, True]) + r = ht.isnan(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.array([1, ht.inf, -ht.inf, ht.nan], split=0) + s = ht.array([False, False, False, True], split=0) + r = ht.isnan(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.ones((6, 6), dtype=ht.bool, split=0) + s = ht.zeros((6, 6), dtype=ht.bool, split=0) + r = ht.isnan(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + + a = ht.ones((5, 5), dtype=ht.int, split=1) + s = ht.zeros((5, 5), dtype=ht.bool, split=1) + r = ht.isnan(a) + self.assertEqual(r.shape, s.shape) + self.assertEqual(r.dtype, s.dtype) + self.assertEqual(r.device, s.device) + self.assertTrue(ht.equal(r, s)) + def test_logical_and(self): first_tensor = ht.array([[True, True], [False, False]]) second_tensor = ht.array([[True, False], [True, False]])