[Scipy-svn] r5081 - in trunk/scipy/cluster: . tests

scipy-svn@scip... scipy-svn@scip...
Wed Nov 12 22:03:58 CST 2008


Author: damian.eads
Date: 2008-11-12 22:03:56 -0600 (Wed, 12 Nov 2008)
New Revision: 5081

Modified:
   trunk/scipy/cluster/hierarchy.py
   trunk/scipy/cluster/tests/test_hierarchy.py
Log:
Wrote tests for correspond and numobs_linkage.

Modified: trunk/scipy/cluster/hierarchy.py
===================================================================
--- trunk/scipy/cluster/hierarchy.py	2008-11-13 04:00:24 UTC (rev 5080)
+++ trunk/scipy/cluster/hierarchy.py	2008-11-13 04:03:56 UTC (rev 5081)
@@ -96,8 +96,8 @@
 +------------------+-------------------------------------------------+
 |is_monotonic      |checks if a linkage is monotonic.                |
 +------------------+-------------------------------------------------+
-|Z_y_correspond    |checks for validity of distance matrix given a   |
-|                  |linkage.                                         |
+|correspond        |checks whether a condensed distance matrix       |
+|                  |corresponds with a linkage                       |
 +------------------+-------------------------------------------------+
 |numobs_linkage    |the number of observations corresponding to a    |
 |                  |linkage matrix.                                  |
@@ -590,7 +590,7 @@
     s = y.shape
     if len(s) == 1:
         distance.is_valid_y(y, throw=True, name='y')
-        d = np.ceil(np.sqrt(s[0] * 2))
+        d = distance.numobs_y(y)
         if method not in _cpy_non_euclid_methods.keys():
             raise ValueError("Valid methods when the raw observations are omitted are 'single', 'complete', 'weighted', and 'average'.")
         # Since the C code does not support striding using strides.
@@ -1205,6 +1205,8 @@
                 raise ValueError('Linkage matrix \'%s\' must have 4 columns.' % name)
             else:
                 raise ValueError('Linkage matrix must have 4 columns.')
+        if Z.shape[0] == 0:
+            raise ValueError('Linkage must be over at least one observation.')
         n = Z.shape[0]
         if n > 1:
             if ((Z[:,0] < 0).any() or
@@ -1238,7 +1240,7 @@
     is_valid_linkage(Z, throw=True, name='Z')
     return (Z.shape[0] + 1)
 
-def Z_y_correspond(Z, Y):
+def correspond(Z, Y):
     """
     Checks if a linkage matrix Z and condensed distance matrix
     Y could possibly correspond to one another.
@@ -1262,6 +1264,8 @@
             A boolean indicating whether the linkage matrix and distance
             matrix could possibly correspond to one another.
     """
+    is_valid_linkage(Z, throw=True)
+    distance.is_valid_y(Y, throw=True)
     Z = np.asarray(Z, order='c')
     Y = np.asarray(Y, order='c')
     return distance.numobs_y(Y) == numobs_linkage(Z)

Modified: trunk/scipy/cluster/tests/test_hierarchy.py
===================================================================
--- trunk/scipy/cluster/tests/test_hierarchy.py	2008-11-13 04:00:24 UTC (rev 5080)
+++ trunk/scipy/cluster/tests/test_hierarchy.py	2008-11-13 04:03:56 UTC (rev 5081)
@@ -38,7 +38,7 @@
 import numpy as np
 from numpy.testing import *
 
-from scipy.cluster.hierarchy import linkage, from_mlab_linkage, to_mlab_linkage, numobs_linkage, inconsistent, cophenet, from_mlab_linkage, fclusterdata, fcluster, is_isomorphic, single, complete, average, weighted, centroid, median, ward, leaders
+from scipy.cluster.hierarchy import linkage, from_mlab_linkage, to_mlab_linkage, numobs_linkage, inconsistent, cophenet, from_mlab_linkage, fclusterdata, fcluster, is_isomorphic, single, complete, average, weighted, centroid, median, ward, leaders, numobs_linkage, correspond
 from scipy.spatial.distance import squareform, pdist, numobs_dm, numobs_y
 
 _tdist = np.array([[0,    662,  877,  255,  412,  996],
@@ -135,6 +135,11 @@
 
 class TestLinkage(TestCase):
 
+    def test_linkage_empty_distance_matrix(self):
+        "Tests linkage(Y) where Y is a 0x4 linkage matrix. Exception expected."
+        y = np.zeros((0,))
+        self.failUnlessRaises(ValueError, linkage, y)
+
     ################### linkage
     def test_linkage_single_tdist(self):
         "Tests linkage(Y, 'single') on the tdist data set."
@@ -537,7 +542,6 @@
         for k in xrange(0, 3):
             self.help_is_isomorphic_randperm(1000, 5)
 
-
     def test_is_isomorphic_6A(self):
         "Tests is_isomorphic on test case #5A (1000 observations, 2 random clusters, random permutation of the labeling, slightly nonisomorphic.) Run 3 times."
         for k in xrange(0, 3):
@@ -567,6 +571,61 @@
         self.failUnless(is_isomorphic(a, b) == (not noniso))
         self.failUnless(is_isomorphic(b, a) == (not noniso))
 
+class TestNumObsLinkage(TestCase):
+
+    def test_numobs_linkage_empty(self):
+        "Tests numobs_linkage(Z) with empty linkage."
+        Z = np.zeros((0, 4), dtype=np.double)
+        self.failUnlessRaises(ValueError, numobs_linkage, Z)
+
+
+    def test_numobs_linkage_1x4(self):
+        "Tests numobs_linkage(Z) on linkage over 2 observations."
+        Z = np.asarray([[0,   1, 3.0, 2]], dtype=np.double)
+        self.failUnless(numobs_linkage(Z) == 2)
+
+    def test_numobs_linkage_2x4(self):
+        "Tests numobs_linkage(Z) on linkage over 3 observations."
+        Z = np.asarray([[0,   1, 3.0, 2],
+                        [3,   2, 4.0, 3]], dtype=np.double)
+        self.failUnless(numobs_linkage(Z) == 3)
+
+    def test_numobs_linkage_4_and_up(self):
+        "Tests numobs_linkage(Z) on linkage on observation sets between sizes 4 and 15 (step size 3)."
+        for i in xrange(4, 15, 3):
+            y = np.random.rand(i*(i-1)/2)
+            Z = linkage(y)
+            self.failUnless(numobs_linkage(Z) == i)
+
+class TestCorrespond(TestCase):
+
+    def test_correspond_empty(self):
+        "Tests correspond(Z, y) with empty linkage and condensed distance matrix."
+        y = np.zeros((0,))
+        Z = np.zeros((0,4))
+        self.failUnlessRaises(ValueError, correspond, Z, y)
+
+    def test_correspond_2_and_up(self):
+        "Tests correspond(Z, y) on linkage and CDMs over observation sets of different sizes."
+        for i in xrange(2, 4):
+            y = np.random.rand(i*(i-1)/2)
+            Z = linkage(y)
+            self.failUnless(correspond(Z, y))
+        for i in xrange(4, 15, 3):
+            y = np.random.rand(i*(i-1)/2)
+            Z = linkage(y)
+            self.failUnless(correspond(Z, y))
+
+    def test_correspond_4_and_up(self):
+        "Tests correspond(Z, y) on linkage and CDMs over observation sets between sizes 4 and 15 (step size 3)."
+        for (i, j) in zip(range(2, 4), range(3, 5)) + zip(range(3, 5), range(2, 4)):
+            y = np.random.rand(i*(i-1)/2)
+            y2 = np.random.rand(j*(j-1)/2)
+            Z = linkage(y)
+            Z2 = linkage(y2)
+            self.failUnless(correspond(Z, y2) == False)
+            self.failUnless(correspond(Z2, y) == False)
+
 def help_single_inconsistent_depth(self, i):
     Y = squareform(_tdist)
     Z = linkage(Y, 'single')



More information about the Scipy-svn mailing list