Home  · Classes  · Annotated Classes  · Modules  · Members  · Namespaces  · Related Pages

HierarchicalClustering.h

Go to the documentation of this file.
00001 // --------------------------------------------------------------------------
00002 //                   OpenMS -- Open-Source Mass Spectrometry
00003 // --------------------------------------------------------------------------
00004 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
00005 // ETH Zurich, and Freie Universitaet Berlin 2002-2012.
00006 //
00007 // This software is released under a three-clause BSD license:
00008 //  * Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 //  * Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribution.
00013 //  * Neither the name of any author or any participating institution
00014 //    may be used to endorse or promote products derived from this software
00015 //    without specific prior written permission.
00016 // For a full list of authors, refer to the file AUTHORS.
00017 // --------------------------------------------------------------------------
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
00022 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
00025 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00026 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00027 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00028 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 //
00030 // --------------------------------------------------------------------------
00031 // $Maintainer: Lars Nilse $
00032 // $Authors: Bastian Blank $
00033 // --------------------------------------------------------------------------
00034 
00035 #include <cmath>
00036 #include <limits>
00037 #include <map>
00038 #include <queue>
00039 #include <boost/unordered/unordered_set.hpp>
00040 
00041 #include <OpenMS/COMPARISON/CLUSTERING/HashGrid.h>
00042 #include <OpenMS/CONCEPT/Types.h>
00043 
00044 #ifndef OPENMS_COMPARISON_CLUSTERING_HIERARCHICALCLUSTERING_H
00045 #define OPENMS_COMPARISON_CLUSTERING_HIERARCHICALCLUSTERING_H
00046 
00047 namespace OpenMS
00048 {
00066   template <typename PointRef>
00067   class HierarchicalClustering
00068   {
00069 public:
00074     typedef DPosition<2, DoubleReal> PointCoordinate;
00075 
00080     class BoundingBox :
00081       public std::pair<PointCoordinate, PointCoordinate>
00082     {
00083 public:
00084       BoundingBox(const PointCoordinate & p) :
00085         std::pair<PointCoordinate, PointCoordinate>(std::make_pair(p, p))
00086       {}
00087 
00088       BoundingBox(const BoundingBox & b) :
00089         std::pair<PointCoordinate, PointCoordinate>(b)
00090       {}
00091 
00092       PointCoordinate size() const
00093       {
00094         return this->second - this->first;
00095       }
00096 
00098       BoundingBox & operator|=(const BoundingBox & rhs)
00099       {
00100         typename PointCoordinate::iterator lit;
00101         typename PointCoordinate::const_iterator rit;
00102 
00103         // Calculate lower bound
00104         lit = this->first.begin(); rit = rhs.first.begin();
00105         for (; lit != this->first.end(); ++lit, ++rit) *lit = std::min(*lit, *rit);
00106 
00107         // Calculate upper bound
00108         lit = this->second.begin(); rit = rhs.second.begin();
00109         for (; lit != this->second.end(); ++lit, ++rit) *lit = std::max(*lit, *rit);
00110 
00111         return *this;
00112       }
00113 
00115       BoundingBox operator|(const BoundingBox & rhs) const
00116       {
00117         BoundingBox ret(*this);
00118         ret |= rhs;
00119         return ret;
00120       }
00121 
00122       operator PointCoordinate() const
00123       {
00124         // (first + second) / 2
00125         return coordScalarDiv_(this->first + this->second, 2);
00126       }
00127     };
00128 
00133     class Cluster :
00134       public boost::unordered_multimap<PointCoordinate, PointRef>
00135     {
00136 public:
00137       BoundingBox bbox;
00138 
00139       Cluster(const BoundingBox & bbox) :
00140         bbox(bbox)
00141       {}
00142     };
00143 
00147     typedef HashGrid<Cluster> Grid;
00148 
00154     Grid grid;
00155 
00156 protected:
00158     class TreeNode
00159     {
00160 public:
00161       const PointCoordinate coord;
00162       const BoundingBox bbox;
00163       TreeNode * left, * right;
00164       UInt points;
00165       const bool center;
00166       const PointRef ref;
00167 
00168       TreeNode(const PointCoordinate & coord, const PointRef & ref, bool center) :
00169         coord(coord), bbox(coord), left(0), right(0), points(1), center(center), ref(ref)
00170       {}
00171 
00172       TreeNode(const PointCoordinate & coord, const BoundingBox & bbox, TreeNode * left, TreeNode * right) :
00173         coord(coord), bbox(bbox),
00174         left(left), right(right),
00175         points(left->points + right->points),
00176         center(left->center && right->center),
00177         ref(PointRef())
00178       {}
00179     };
00180 
00181     typedef std::map<typename Grid::CellIndex, std::pair<typename Grid::CellContent *, bool> > ClusterCells;
00182     typedef boost::unordered_set<TreeNode *> ClusterTrees;
00183 
00185     class TreeDistance
00186     {
00187 public:
00188       DoubleReal distance;
00189       TreeNode * left, * right;
00190 
00191       TreeDistance(const DoubleReal & distance, TreeNode * left, TreeNode * right) :
00192         distance(distance), left(left), right(right)
00193       {}
00194 
00195       bool operator>(const TreeDistance & rhs) const
00196       {
00197         return distance > rhs.distance;
00198       }
00199 
00200     };
00201 
00203     typedef std::priority_queue<TreeDistance, std::vector<TreeDistance>, std::greater<TreeDistance> > TreeDistanceQueue;
00204 
00205 public:
00210     HierarchicalClustering(const PointCoordinate & cluster_dimension) :
00211       grid(cluster_dimension)
00212     {}
00213 
00220     typename Grid::cell_iterator insertPoint(const PointCoordinate & d, const PointRef & ref)
00221     {
00222       typename Grid::cell_iterator it = insertCluster_(d);
00223       it->second.insert(std::make_pair(d, ref));
00224       return it;
00225     }
00226 
00230     void cluster()
00231     {
00232       // Collect coordinates of all active cells
00233       std::vector<typename Grid::CellIndex> cells;
00234       for (typename Grid::const_grid_iterator it = grid.grid_begin(); it != grid.grid_end(); ++it)
00235         cells.push_back(it->first);
00236       // Cluster each available cell
00237       for (typename std::vector<typename Grid::CellIndex>::const_iterator it = cells.begin(); it != cells.end(); ++it)
00238         clusterIndex_(*it);
00239     }
00240 
00241 protected:
00247     template <class P>
00248     typename Grid::cell_iterator insertCluster_(const P & p)
00249     {
00250       return grid.insert(std::make_pair(p, Cluster(p)));
00251     }
00252 
00257     void clusterIndex_(const typename Grid::CellIndex & p);
00258 
00267     void gridCells5x5_(typename Grid::CellIndex cur, ClusterCells & cells);
00268 
00276     void gridCell_(const typename Grid::CellIndex & cur, ClusterCells & cells, bool center = false, bool ignore_missing = true)
00277     {
00278       try
00279       {
00280         cells.insert(std::make_pair(cur, std::make_pair(&grid.grid_at(cur), center)));
00281       }
00282       catch (std::out_of_range &)
00283       {
00284         if (!ignore_missing) throw;
00285       }
00286     }
00287 
00291     void addTreeDistance_(TreeNode * tree, ClusterTrees & trees, TreeDistanceQueue & dists)
00292     {
00293       // Infinity: no valid distance
00294       DoubleReal dist_min = std::numeric_limits<DoubleReal>::infinity();
00295       typename ClusterTrees::const_iterator dist_it = trees.end();
00296 
00297       // Generate minimal distance to existing trees
00298       for (typename ClusterTrees::const_iterator it = trees.begin(); it != trees.end(); ++it)
00299       {
00300         if (tree == *it) continue;
00301         DoubleReal dist = treeDistance_(tree, *it);
00302         if (dist < dist_min)
00303         {
00304           dist_min = dist;
00305           dist_it = it;
00306         }
00307       }
00308 
00309       // Insert distance if valid one found.
00310       if (dist_it != trees.end()) dists.push(TreeDistance(dist_min, tree, *dist_it));
00311 
00312       // Insert tree.
00313       trees.insert(tree);
00314     }
00315 
00322     DoubleReal treeDistance_(TreeNode * left, TreeNode * right)
00323     {
00324       const BoundingBox bbox = left->bbox | right->bbox;
00325       if (coordElemGreater_(bbox.size(), grid.cell_dimension))
00326       {
00327         return std::numeric_limits<DoubleReal>::infinity();
00328       }
00329 
00330       const PointCoordinate left_scaled = coordElemDiv_(left->coord, grid.cell_dimension);
00331       const PointCoordinate right_scaled = coordElemDiv_(right->coord, grid.cell_dimension);
00332       return coordDist_(left_scaled, right_scaled);
00333     }
00334 
00341     void tree2Cluster_(const TreeNode * tree, Cluster & cluster)
00342     {
00343       if (tree->left && tree->right)
00344       {
00345         tree2Cluster_(tree->left, cluster);
00346         tree2Cluster_(tree->right, cluster);
00347       }
00348       else
00349       {
00350         cluster.insert(std::make_pair(tree->bbox.first, tree->ref));
00351       }
00352       delete tree->left;
00353       delete tree->right;
00354     }
00355 
00361     void tree2Points_(const TreeNode * tree)
00362     {
00363       if (tree->left && tree->right)
00364       {
00365         tree2Points_(tree->left);
00366         tree2Points_(tree->right);
00367       }
00368       else
00369       {
00370         insertPoint(tree->bbox.first, tree->ref);
00371       }
00372       delete tree->left;
00373       delete tree->right;
00374     }
00375 
00376     static PointCoordinate coordScalarDiv_(const PointCoordinate & lhs, const DoubleReal & rhs)
00377     {
00378       PointCoordinate ret;
00379       typename PointCoordinate::iterator it = ret.begin();
00380       typename PointCoordinate::const_iterator lit = lhs.begin();
00381       for (; it != ret.end(); ++it, ++lit) *it = *lit / rhs;
00382       return ret;
00383     }
00384 
00385     static PointCoordinate coordElemDiv_(const PointCoordinate & lhs, const PointCoordinate & rhs)
00386     {
00387       PointCoordinate ret;
00388       typename PointCoordinate::iterator it = ret.begin();
00389       typename PointCoordinate::const_iterator lit = lhs.begin(), rit = rhs.begin();
00390       for (; it != ret.end(); ++it, ++lit, ++rit) *it = *lit / *rit;
00391       return ret;
00392     }
00393 
00394     static bool coordElemGreater_(const PointCoordinate & lhs, const PointCoordinate & rhs)
00395     {
00396       typename PointCoordinate::const_iterator lit = lhs.begin(), rit = rhs.begin();
00397       for (; lit != lhs.end(); ++lit, ++rit)
00398       {
00399         if (*lit > *rit) return true;
00400       }
00401       return false;
00402     }
00403 
00404     static DoubleReal coordDist_(const PointCoordinate & lhs, const PointCoordinate & rhs)
00405     {
00406       DoubleReal ret = 0;
00407       PointCoordinate p = lhs - rhs;
00408       typename PointCoordinate::const_iterator it = p.begin();
00409       for (; it != p.end(); ++it) ret += std::pow(*it, 2.);
00410       return std::sqrt(ret);
00411     }
00412 
00413   };
00414 
00415   template <typename I>
00416   void HierarchicalClustering<I>::clusterIndex_(const typename Grid::CellIndex & cur)
00417   {
00418     ClusterCells cells;
00419     ClusterTrees trees;
00420     TreeDistanceQueue dists;
00421 
00422     // Collect all cells we need
00423     try
00424     {
00425       gridCells5x5_(cur, cells);
00426     }
00427     catch (std::out_of_range &)
00428     {
00429       return;
00430     }
00431 
00432     // Collect and remove existing points from cells
00433     for (typename ClusterCells::iterator cell_it = cells.begin(); cell_it != cells.end(); ++cell_it)
00434     {
00435       typename Grid::CellContent & cell_cur = *cell_it->second.first;
00436       const bool & cell_center = cell_it->second.second;
00437 
00438       // Iterate per cluster
00439       typename Grid::cell_iterator cluster_tmp_it = cell_cur.begin();
00440       while (cluster_tmp_it != cell_cur.end())
00441       {
00442         typename Grid::cell_iterator cluster_it = cluster_tmp_it;
00443         ++cluster_tmp_it;
00444 
00445         // Check if it is not yet a cluster, aka have only one point
00446         if (cluster_it->second.size() == 1)
00447         {
00448           // Add each point to hash grid
00449           for (typename Cluster::const_iterator point_it = cluster_it->second.begin(); point_it != cluster_it->second.end(); ++point_it)
00450           {
00451             const PointCoordinate & coord = point_it->first;
00452             TreeNode * tree(new TreeNode(coord, point_it->second, cell_center));
00453             addTreeDistance_(tree, trees, dists);
00454           }
00455 
00456           // Remove point from hash grid cell
00457           cell_cur.erase(cluster_it);
00458         }
00459       }
00460     }
00461 
00462     // Try to join two subsets with minimum distance
00463     while (!dists.empty())
00464     {
00465       const typename TreeDistanceQueue::value_type cur_dist = dists.top();
00466       TreeNode * tree_left(cur_dist.left), *tree_right(cur_dist.right);
00467       dists.pop();
00468 
00469       // Check if both trees are not yet used with a smaller distance
00470       Size count_left = trees.count(tree_left), count_right = trees.count(tree_right);
00471       if (count_left && count_right)
00472       {
00473         trees.erase(tree_left);
00474         trees.erase(tree_right);
00475 
00476         const BoundingBox bbox = tree_left->bbox | tree_right->bbox;
00477 
00478         // Arithmethic mean: (left * left.points + right * right.points) / (left.points + right.points)
00479         const PointCoordinate & left = tree_left->coord, & right = tree_right->coord;
00480         const UInt & left_points = tree_left->points, & right_points = tree_right->points;
00481         const PointCoordinate coord = coordScalarDiv_(left * left_points + right * right_points, left_points + right_points);
00482 
00483         TreeNode * tree(new TreeNode(coord, bbox, tree_left, tree_right));
00484 
00485         addTreeDistance_(tree, trees, dists);
00486       }
00487       // Re-add a distance for the tree not yet used.
00488       // Otherwise this subset is lost even if it is not yet maximal.
00489       else if (count_left)
00490         addTreeDistance_(tree_left, trees, dists);
00491       else if (count_right)
00492         addTreeDistance_(tree_right, trees, dists);
00493     }
00494 
00495     // Add data back to grid
00496     for (typename ClusterTrees::iterator tree_it = trees.begin(); tree_it != trees.end(); ++tree_it)
00497     {
00498       // We got a finished tree with all points in the center, add cluster at centroid
00499       if ((**tree_it).center)
00500       {
00501         Cluster & cluster = insertCluster_((**tree_it).bbox)->second;
00502         tree2Cluster_(*tree_it, cluster);
00503       }
00504       // We got a finished tree but not all points in the center, readd as single points
00505       else
00506       {
00507         tree2Points_(*tree_it);
00508       }
00509       delete *tree_it;
00510     }
00511   }
00512 
00513   template <typename I>
00514   void HierarchicalClustering<I>::gridCells5x5_(typename Grid::CellIndex base, ClusterCells & cells)
00515   {
00516     // (0, 0)
00517     gridCell_(base, cells, true, false);
00518 
00519     typename Grid::CellIndex cur = base;
00520     cur[0] -= 2;
00521     // (-2, -2)
00522     cur[1] -= 2; gridCell_(cur, cells);
00523     // (-2, -1)
00524     cur[1] += 1; gridCell_(cur, cells);
00525     // (-2, 0)
00526     cur[1] += 1; gridCell_(cur, cells);
00527     // (-2, 1)
00528     cur[1] += 1; gridCell_(cur, cells);
00529     // (-2, 2)
00530     cur[1] += 1; gridCell_(cur, cells);
00531 
00532     cur = base; cur[0] -= 1;
00533     // (-1, -2)
00534     cur[1] -= 2; gridCell_(cur, cells);
00535     // (-1, -1)
00536     cur[1] += 1; gridCell_(cur, cells, true);
00537     // (-1, 0)
00538     cur[1] += 1; gridCell_(cur, cells, true);
00539     // (-1, 1)
00540     cur[1] += 1; gridCell_(cur, cells, true);
00541     // (-1, 2)
00542     cur[1] += 1; gridCell_(cur, cells);
00543 
00544     cur = base;
00545     // (0, -2)
00546     cur[1] -= 2; gridCell_(cur, cells);
00547     // (0, -1)
00548     cur[1] += 1; gridCell_(cur, cells, true);
00549     // (0, 0)
00550     cur[1] += 1;
00551     // (0, 1)
00552     cur[1] += 1; gridCell_(cur, cells, true);
00553     // (0, 2)
00554     cur[1] += 1; gridCell_(cur, cells);
00555 
00556     cur = base; cur[0] += 1;
00557     // (1, -2)
00558     cur[1] -= 2; gridCell_(cur, cells);
00559     // (1, -1)
00560     cur[1] += 1; gridCell_(cur, cells, true);
00561     // (1, 0)
00562     cur[1] += 1; gridCell_(cur, cells, true);
00563     // (1, 1)
00564     cur[1] += 1; gridCell_(cur, cells, true);
00565     // (1, 2)
00566     cur[1] += 1; gridCell_(cur, cells);
00567 
00568     cur = base; cur[0] += 2;
00569     // (2, -2)
00570     cur[1] -= 2; gridCell_(cur, cells);
00571     // (2, -1)
00572     cur[1] += 1; gridCell_(cur, cells);
00573     // (2, 0)
00574     cur[1] += 1; gridCell_(cur, cells);
00575     // (2, 1)
00576     cur[1] += 1; gridCell_(cur, cells);
00577     // (2, 2)
00578     cur[1] += 1; gridCell_(cur, cells);
00579   }
00580 
00581 }
00582 
00583 #endif /* OPENMS_COMPARISON_CLUSTERING_HIERARCHICALCLUSTERING_H */

OpenMS / TOPP release 1.10.0 Documentation generated on Thu Mar 7 2013 09:42:40 using doxygen 1.7.1