| 
									
										
										
										
											2013-10-27 01:57:03 +08:00
										 |  |  | /* ----------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * GTSAM Copyright 2010, Georgia Tech Research Corporation,  | 
					
						
							|  |  |  |  * Atlanta, Georgia 30332-0415 | 
					
						
							|  |  |  |  * All Rights Reserved | 
					
						
							|  |  |  |  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * See LICENSE for the license information | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * -------------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @file DSFMap.h | 
					
						
							|  |  |  |  * @date Oct 26, 2013 | 
					
						
							|  |  |  |  * @author Frank Dellaert | 
					
						
							|  |  |  |  * @brief Allow for arbitrary type in DSF | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <map>
 | 
					
						
							| 
									
										
										
										
											2013-10-27 06:22:31 +08:00
										 |  |  | #include <set>
 | 
					
						
							| 
									
										
										
										
											2013-10-29 02:07:19 +08:00
										 |  |  | #include <cstdlib>        // Provides size_t
 | 
					
						
							| 
									
										
										
										
											2013-10-27 01:57:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Disjoint set forest using an STL map data structure underneath | 
					
						
							| 
									
										
										
										
											2013-10-27 10:50:47 +08:00
										 |  |  |  * Uses rank compression and union by rank, iterator version | 
					
						
							| 
									
										
										
										
											2013-10-27 01:57:03 +08:00
										 |  |  |  * @addtogroup base | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<class KEY> | 
					
						
							|  |  |  | class DSFMap { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-27 10:18:42 +08:00
										 |  |  | protected: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-31 00:44:46 +08:00
										 |  |  |   /// We store the forest in an STL map, but parents are done with pointers
 | 
					
						
							|  |  |  |   struct Entry { | 
					
						
							|  |  |  |     typename std::map<KEY, Entry>::iterator parent_; | 
					
						
							|  |  |  |     size_t rank_; | 
					
						
							|  |  |  |     Entry() {} | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2013-10-27 10:50:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-30 20:15:43 +08:00
										 |  |  |     typedef typename std::map<KEY, Entry> Map; | 
					
						
							| 
									
										
										
										
											2014-10-31 00:44:46 +08:00
										 |  |  |   typedef typename Map::iterator iterator; | 
					
						
							|  |  |  |   mutable Map entries_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Given key, find iterator to initial entry
 | 
					
						
							|  |  |  |   iterator find__(const KEY& key) const { | 
					
						
							|  |  |  |     static const Entry empty; | 
					
						
							|  |  |  |     iterator it = entries_.find(key); | 
					
						
							|  |  |  |     // if key does not exist, create and return itself
 | 
					
						
							|  |  |  |     if (it == entries_.end()) { | 
					
						
							|  |  |  |       it = entries_.insert(std::make_pair(key, empty)).first; | 
					
						
							|  |  |  |       it->second.parent_ = it; | 
					
						
							|  |  |  |       it->second.rank_ = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return it; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Given iterator to initial entry, find the root Entry
 | 
					
						
							|  |  |  |   iterator find_(const iterator& it) const { | 
					
						
							|  |  |  |     // follow parent pointers until we reach set representative
 | 
					
						
							|  |  |  |     iterator& parent = it->second.parent_; | 
					
						
							|  |  |  |     if (parent != it) | 
					
						
							|  |  |  |       parent = find_(parent); // not yet, recurse!
 | 
					
						
							|  |  |  |     return parent; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Given key, find the root Entry
 | 
					
						
							|  |  |  |   inline iterator find_(const KEY& key) const { | 
					
						
							|  |  |  |     iterator initial = find__(key); | 
					
						
							|  |  |  |     return find_(initial); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-27 10:50:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-27 10:18:42 +08:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-10-27 10:50:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-31 00:44:46 +08:00
										 |  |  |   typedef std::set<KEY> Set; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// constructor
 | 
					
						
							|  |  |  |   DSFMap() { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Given key, find the representative key for the set in which it lives
 | 
					
						
							|  |  |  |   inline KEY find(const KEY& key) const { | 
					
						
							|  |  |  |     iterator root = find_(key); | 
					
						
							|  |  |  |     return root->first; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Merge two sets
 | 
					
						
							|  |  |  |   void merge(const KEY& x, const KEY& y) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // straight from http://en.wikipedia.org/wiki/Disjoint-set_data_structure
 | 
					
						
							|  |  |  |     iterator xRoot = find_(x); | 
					
						
							|  |  |  |     iterator yRoot = find_(y); | 
					
						
							|  |  |  |     if (xRoot == yRoot) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Merge sets
 | 
					
						
							|  |  |  |     if (xRoot->second.rank_ < yRoot->second.rank_) | 
					
						
							|  |  |  |       xRoot->second.parent_ = yRoot; | 
					
						
							|  |  |  |     else if (xRoot->second.rank_ > yRoot->second.rank_) | 
					
						
							|  |  |  |       yRoot->second.parent_ = xRoot; | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       yRoot->second.parent_ = xRoot; | 
					
						
							|  |  |  |       xRoot->second.rank_ = xRoot->second.rank_ + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// return all sets, i.e. a partition of all elements
 | 
					
						
							|  |  |  |   std::map<KEY, Set> sets() const { | 
					
						
							|  |  |  |     std::map<KEY, Set> sets; | 
					
						
							|  |  |  |     iterator it = entries_.begin(); | 
					
						
							|  |  |  |     for (; it != entries_.end(); it++) { | 
					
						
							|  |  |  |       iterator root = find_(it); | 
					
						
							|  |  |  |       sets[root->first].insert(it->first); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return sets; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-27 06:22:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-27 01:57:03 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |