[Scipy-svn] r5186 - in trunk/scipy/cluster: . tests
scipy-svn at scipy.org
scipy-svn at scipy.org
Mon Nov 24 23:23:51 EST 2008
Author: damian.eads
Date: 2008-11-24 22:23:49 -0600 (Mon, 24 Nov 2008)
New Revision: 5186
Modified:
trunk/scipy/cluster/hierarchy.py
trunk/scipy/cluster/tests/test_hierarchy.py
Log:
Covered a few more edge conditions for scipy.cluster.hierarchy.is_valid_linkage.
Modified: trunk/scipy/cluster/hierarchy.py
===================================================================
--- trunk/scipy/cluster/hierarchy.py 2008-11-25 03:41:51 UTC (rev 5185)
+++ trunk/scipy/cluster/hierarchy.py 2008-11-25 04:23:49 UTC (rev 5186)
@@ -1231,6 +1231,21 @@
raise ValueError('Linkage \'%s\' contains negative counts.' % name)
else:
raise ValueError('Linkage contains negative counts.')
+ if _check_hierarchy_uses_cluster_before_formed(Z):
+ if name:
+ raise ValueError('Linkage \'%s\' uses non-singleton cluster before its formed.' % name)
+ else:
+ raise ValueError('Linkage uses non-singleton cluster before its formed.')
+ if _check_hierarchy_uses_cluster_more_than_once(Z):
+ if name:
+ raise ValueError('Linkage \'%s\' uses the same cluster more than once.' % name)
+ else:
+ raise ValueError('Linkage uses the same cluster more than once.')
+ if _check_hierarchy_not_all_clusters_used(Z):
+ if name:
+ raise ValueError('Linkage \'%s\' does not use all clusters.' % name)
+ else:
+ raise ValueError('Linkage does not use all clusters.')
except Exception, e:
if throw:
raise
@@ -1239,6 +1254,32 @@
valid = False
return valid
+def _check_hierarchy_uses_cluster_before_formed(Z):
+ n = Z.shape[0] + 1
+ for i in xrange(0, n - 1):
+ if Z[i, 0] >= n + i or Z[i, 1] >= n + i:
+ return True
+ return False
+
+def _check_hierarchy_uses_cluster_more_than_once(Z):
+ n = Z.shape[0] + 1
+ chosen = set([])
+ for i in xrange(0, n - 1):
+ if (Z[i, 0] in chosen) or (Z[i, 1] in chosen) or Z[i, 0] == Z[i, 1]:
+ return True
+ chosen.add(Z[i, 0])
+ chosen.add(Z[i, 1])
+ return False
+
+def _check_hierarchy_not_all_clusters_used(Z):
+ n = Z.shape[0] + 1
+ chosen = set([])
+ for i in xrange(0, n - 1):
+ chosen.add(int(Z[i, 0]))
+ chosen.add(int(Z[i, 1]))
+ must_chosen = set(range(0, 2 * n - 2))
+ return len(must_chosen.difference(chosen)) > 0
+
def num_obs_linkage(Z):
"""
Returns the number of original observations of the linkage matrix
Modified: trunk/scipy/cluster/tests/test_hierarchy.py
===================================================================
--- trunk/scipy/cluster/tests/test_hierarchy.py 2008-11-25 03:41:51 UTC (rev 5185)
+++ trunk/scipy/cluster/tests/test_hierarchy.py 2008-11-25 04:23:49 UTC (rev 5186)
@@ -547,23 +547,27 @@
Z = np.asarray([[0, 1, 3.0, 2],
[3, 2, 4.0, 3]], dtype=np.int)
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(TypeError, is_valid_linkage, Z, throw=True)
def test_is_valid_linkage_5_columns(self):
"Tests is_valid_linkage(Z) with 5 columns."
Z = np.asarray([[0, 1, 3.0, 2, 5],
[3, 2, 4.0, 3, 3]], dtype=np.double)
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
def test_is_valid_linkage_3_columns(self):
"Tests is_valid_linkage(Z) with 3 columns."
Z = np.asarray([[0, 1, 3.0],
[3, 2, 4.0]], dtype=np.double)
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
def test_is_valid_linkage_empty(self):
"Tests is_valid_linkage(Z) with empty linkage."
Z = np.zeros((0, 4), dtype=np.double)
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
def test_is_valid_linkage_1x4(self):
"Tests is_valid_linkage(Z) on linkage over 2 observations."
@@ -576,6 +580,35 @@
[3, 2, 4.0, 3]], dtype=np.double)
self.failUnless(is_valid_linkage(Z) == True)
+ def test_is_valid_linkage_2x4_before1(self):
+ "Tests is_valid_linkage(Z) on linkage over 3 observations with clusters used before they're formed (case 1)."
+ Z = np.asarray([[0, 4, 3.0, 2],
+ [2, 3, 4.0, 3]], dtype=np.double)
+ self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
+
+
+ def test_is_valid_linkage_2x4_before2(self):
+ "Tests is_valid_linkage(Z) on linkage over 3 observations with clusters used before they're formed (case 1)."
+ Z = np.asarray([[0, 1, 3.0, 2],
+ [2, 5, 4.0, 3]], dtype=np.double)
+ self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
+
+ def test_is_valid_linkage_2x4_twice1(self):
+ "Tests is_valid_linkage(Z) on linkage over 3 observations with clusters used twice (case 1)."
+ Z = np.asarray([[0, 1, 3.0, 2],
+ [3, 3, 4.0, 3]], dtype=np.double)
+ self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
+
+ def test_is_valid_linkage_2x4_twice2(self):
+ "Tests is_valid_linkage(Z) on linkage over 3 observations with clusters used twice (case 1)."
+ Z = np.asarray([[0, 1, 3.0, 2],
+ [0, 1, 4.0, 3]], dtype=np.double)
+ self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
+
def test_is_valid_linkage_4_and_up(self):
"Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3)."
for i in xrange(4, 15, 3):
@@ -590,6 +623,7 @@
Z = linkage(y)
Z[int(i/2),0] = -2
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
def test_is_valid_linkage_4_and_up_neg_index_right(self):
"Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3) with negative indices (right)."
@@ -598,6 +632,7 @@
Z = linkage(y)
Z[int(i/2),1] = -2
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
def test_is_valid_linkage_4_and_up_neg_dist(self):
"Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3) with negative distances."
@@ -606,6 +641,7 @@
Z = linkage(y)
Z[int(i/2),2] = -0.5
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
def test_is_valid_linkage_4_and_up_neg_counts(self):
"Tests is_valid_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3) with negative counts."
@@ -614,6 +650,7 @@
Z = linkage(y)
Z[int(i/2),3] = -2
self.failUnless(is_valid_linkage(Z) == False)
+ self.failUnlessRaises(ValueError, is_valid_linkage, Z, throw=True)
class TestNumObsLinkage(TestCase):
@@ -718,28 +755,28 @@
"Tests is_monotonic(Z) on 3x4 linkage. Expecting True."
Z = np.asarray([[0, 1, 0.3, 2],
[2, 3, 0.4, 2],
- [3, 4, 0.6, 4]], dtype=np.double)
+ [4, 5, 0.6, 4]], dtype=np.double)
self.failUnless(is_monotonic(Z) == True)
def test_is_monotonic_3x4_F1(self):
"Tests is_monotonic(Z) on 3x4 linkage (case 1). Expecting False."
Z = np.asarray([[0, 1, 0.3, 2],
[2, 3, 0.2, 2],
- [3, 4, 0.6, 4]], dtype=np.double)
+ [4, 5, 0.6, 4]], dtype=np.double)
self.failUnless(is_monotonic(Z) == False)
def test_is_monotonic_3x4_F2(self):
"Tests is_monotonic(Z) on 3x4 linkage (case 2). Expecting False."
Z = np.asarray([[0, 1, 0.8, 2],
[2, 3, 0.4, 2],
- [3, 4, 0.6, 4]], dtype=np.double)
+ [4, 5, 0.6, 4]], dtype=np.double)
self.failUnless(is_monotonic(Z) == False)
def test_is_monotonic_3x4_F3(self):
"Tests is_monotonic(Z) on 3x4 linkage (case 3). Expecting False"
Z = np.asarray([[0, 1, 0.3, 2],
[2, 3, 0.4, 2],
- [3, 4, 0.2, 4]], dtype=np.double)
+ [4, 5, 0.2, 4]], dtype=np.double)
self.failUnless(is_monotonic(Z) == False)
def test_is_monotonic_tdist_linkage(self):
More information about the Scipy-svn
mailing list