Skip to content

Commit 8f92d5e

Browse files
committed
Better to be right, the coverage difference in minimal in practice.
1 parent 5fd497e commit 8f92d5e

File tree

1 file changed

+45
-42
lines changed

1 file changed

+45
-42
lines changed

hdbscan/hdbscan_.py

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,49 +40,52 @@
4040
FAST_METRICS = KDTree.valid_metrics + BallTree.valid_metrics
4141

4242
# Supporting numpy prior to version 1.7 is a little painful ...
43-
def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
44-
45-
def within_tol(x, y, atol, rtol):
46-
with np.errstate(invalid='ignore'):
47-
result = np.less_equal(abs(x-y), atol + rtol * abs(y))
48-
if np.isscalar(a) and np.isscalar(b):
49-
result = bool(result)
50-
return result
51-
52-
x = np.array(a, copy=False, subok=True, ndmin=1)
53-
y = np.array(b, copy=False, subok=True, ndmin=1)
54-
55-
# Make sure y is an inexact type to avoid bad behavior on abs(MIN_INT).
56-
# This will cause casting of x later. Also, make sure to allow subclasses
57-
# (e.g., for numpy.ma).
58-
dt = np.core.multiarray.result_type(y, 1.)
59-
y = np.array(y, dtype=dt, copy=False, subok=True)
60-
61-
xfin = np.isfinite(x)
62-
yfin = np.isfinite(y)
63-
if np.all(xfin) and np.all(yfin):
64-
return within_tol(x, y, atol, rtol)
65-
else:
66-
finite = xfin & yfin
67-
cond = np.zeros_like(finite, subok=True)
68-
# Because we're using boolean indexing, x & y must be the same shape.
69-
# Ideally, we'd just do x, y = broadcast_arrays(x, y). It's in
70-
# lib.stride_tricks, though, so we can't import it here.
71-
x = x * np.ones_like(cond)
72-
y = y * np.ones_like(cond)
73-
# Avoid subtraction with infinite/nan values...
74-
cond[finite] = within_tol(x[finite], y[finite], atol, rtol)
75-
# Check for equality of infinite values...
76-
cond[~finite] = (x[~finite] == y[~finite])
77-
if equal_nan:
78-
# Make NaN == NaN
79-
both_nan = np.isnan(x) & np.isnan(y)
80-
cond[both_nan] = both_nan[both_nan]
81-
82-
if np.isscalar(a) and np.isscalar(b):
83-
return bool(cond)
43+
if hasattr(np, 'isclose'):
44+
from numpy import isclose
45+
else:
46+
def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
47+
48+
def within_tol(x, y, atol, rtol):
49+
with np.errstate(invalid='ignore'):
50+
result = np.less_equal(abs(x-y), atol + rtol * abs(y))
51+
if np.isscalar(a) and np.isscalar(b):
52+
result = bool(result)
53+
return result
54+
55+
x = np.array(a, copy=False, subok=True, ndmin=1)
56+
y = np.array(b, copy=False, subok=True, ndmin=1)
57+
58+
# Make sure y is an inexact type to avoid bad behavior on abs(MIN_INT).
59+
# This will cause casting of x later. Also, make sure to allow subclasses
60+
# (e.g., for numpy.ma).
61+
dt = np.core.multiarray.result_type(y, 1.)
62+
y = np.array(y, dtype=dt, copy=False, subok=True)
63+
64+
xfin = np.isfinite(x)
65+
yfin = np.isfinite(y)
66+
if np.all(xfin) and np.all(yfin):
67+
return within_tol(x, y, atol, rtol)
8468
else:
85-
return cond
69+
finite = xfin & yfin
70+
cond = np.zeros_like(finite, subok=True)
71+
# Because we're using boolean indexing, x & y must be the same shape.
72+
# Ideally, we'd just do x, y = broadcast_arrays(x, y). It's in
73+
# lib.stride_tricks, though, so we can't import it here.
74+
x = x * np.ones_like(cond)
75+
y = y * np.ones_like(cond)
76+
# Avoid subtraction with infinite/nan values...
77+
cond[finite] = within_tol(x[finite], y[finite], atol, rtol)
78+
# Check for equality of infinite values...
79+
cond[~finite] = (x[~finite] == y[~finite])
80+
if equal_nan:
81+
# Make NaN == NaN
82+
both_nan = np.isnan(x) & np.isnan(y)
83+
cond[both_nan] = both_nan[both_nan]
84+
85+
if np.isscalar(a) and np.isscalar(b):
86+
return bool(cond)
87+
else:
88+
return cond
8689

8790

8891
def _tree_to_labels(X, single_linkage_tree, min_cluster_size=10, allow_single_cluster=False):

0 commit comments

Comments
 (0)