Skip to content

Commit 593a7d4

Browse files
committed
BF: work around np.allclose float128 bug
Numpy 1.9.2 allclose thinks that np.inf in float128 precision is not allclose to itself. Work round with expanded assert_allclose_safely function.
1 parent b0a8006 commit 593a7d4

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

nibabel/testing/__init__.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,19 @@ def assert_dt_equal(a, b):
3737
def assert_allclose_safely(a, b, match_nans=True):
3838
""" Allclose in integers go all wrong for large integers
3939
"""
40-
a = np.asarray(a)
41-
b = np.asarray(b)
40+
a = np.atleast_1d(a) # 0d arrays cannot be indexed
41+
a, b = np.broadcast_arrays(a, b)
4242
if match_nans:
4343
nans = np.isnan(a)
4444
np.testing.assert_array_equal(nans, np.isnan(b))
45-
if np.any(nans):
46-
nans = np.logical_not(nans)
47-
a = a[nans]
48-
b = b[nans]
45+
to_test = ~nans
46+
else:
47+
to_test = np.ones(a.shape, dtype=bool)
48+
# Deal with float128 inf comparisons (bug in numpy 1.9.2)
49+
# np.allclose(np.float128(np.inf), np.float128(np.inf)) == False
50+
to_test = to_test & (a != b)
51+
a = a[to_test]
52+
b = b[to_test]
4953
if a.dtype.kind in 'ui':
5054
a = a.astype(float)
5155
if b.dtype.kind in 'ui':

nibabel/tests/test_testing.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
from warnings import warn, simplefilter
77

8-
from ..testing import catch_warn_reset
8+
import numpy as np
99

10-
from nose.tools import assert_equal
10+
from ..testing import catch_warn_reset, assert_allclose_safely
11+
12+
from nose.tools import assert_equal, assert_raises
1113

1214

1315
def assert_warn_len_equal(mod, n_in_context):
@@ -46,3 +48,39 @@ def test_catch_warn_reset():
4648
simplefilter('ignore')
4749
warn('Another warning')
4850
assert_warn_len_equal(my_mod, 2)
51+
52+
53+
def test_assert_allclose_safely():
54+
# Test the safe version of allclose
55+
assert_allclose_safely([1, 1], [1, 1])
56+
assert_allclose_safely(1, 1)
57+
assert_allclose_safely(1, [1, 1])
58+
assert_allclose_safely([1, 1], 1 + 1e-6)
59+
assert_raises(AssertionError, assert_allclose_safely, [1, 1], 1 + 1e-4)
60+
# Broadcastable matrices
61+
a = np.ones((2, 3))
62+
b = np.ones((3, 2, 3))
63+
eps = np.finfo(np.float).eps
64+
a[0, 0] = 1 + eps
65+
assert_allclose_safely(a, b)
66+
a[0, 0] = 1 + 1.1e-5
67+
assert_raises(AssertionError, assert_allclose_safely, a, b)
68+
# Nans in same place
69+
a[0, 0] = np.nan
70+
b[:, 0, 0] = np.nan
71+
assert_allclose_safely(a, b)
72+
# Never equal with nans present, if not matching nans
73+
assert_raises(AssertionError,
74+
assert_allclose_safely, a, b,
75+
match_nans=False)
76+
b[0, 0, 0] = 1
77+
assert_raises(AssertionError, assert_allclose_safely, a, b)
78+
# Test allcloseness of inf, especially np.float128 infs
79+
for dtt in (np.float32, np.float64, np.float128):
80+
a = np.array([-np.inf, 1, np.inf], dtype=dtt)
81+
b = np.array([-np.inf, 1, np.inf], dtype=dtt)
82+
assert_allclose_safely(a, b)
83+
b[1] = 0
84+
assert_raises(AssertionError, assert_allclose_safely, a, b)
85+
# Empty compares equal to empty
86+
assert_allclose_safely([], [])

0 commit comments

Comments
 (0)