| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @file    Permutation.h | 
					
						
							|  |  |  |  * @brief    | 
					
						
							|  |  |  |  * @author  Richard Roberts | 
					
						
							|  |  |  |  * @created Sep 12, 2010 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <gtsam/base/types.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <vector>
 | 
					
						
							| 
									
										
										
										
											2010-10-10 11:10:03 +08:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | #include <boost/shared_ptr.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Inference; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * A permutation reorders variables, for example to reduce fill-in during | 
					
						
							|  |  |  |  * elimination.  To save computation, the permutation can be applied to | 
					
						
							|  |  |  |  * the necessary data structures only once, then multiple computations | 
					
						
							|  |  |  |  * performed on the permuted problem.  For example, in an iterative | 
					
						
							|  |  |  |  * non-linear setting, a permutation can be created from the symbolic graph | 
					
						
							|  |  |  |  * structure and applied to the ordering of nonlinear variables once, so | 
					
						
							|  |  |  |  * that linearized factor graphs are already correctly ordered and need | 
					
						
							|  |  |  |  * not be permuted. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * For convenience, there is also a helper class "Permuted" that transforms | 
					
						
							|  |  |  |  * arguments supplied through the square-bracket [] operator through the | 
					
						
							|  |  |  |  * permutation.  Note that this helper class stores a reference to the original | 
					
						
							|  |  |  |  * container. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class Permutation { | 
					
						
							|  |  |  | protected: | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   std::vector<Index> rangeIndices_; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |   typedef boost::shared_ptr<Permutation> shared_ptr; | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   typedef std::vector<Index>::const_iterator const_iterator; | 
					
						
							|  |  |  |   typedef std::vector<Index>::iterator iterator; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Create an empty permutation.  This cannot do anything, but you can later | 
					
						
							|  |  |  |    * assign to it. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   Permutation() {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Create an uninitialized permutation.  You must assign all values using the | 
					
						
							|  |  |  |    * square bracket [] operator or they will be undefined! | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   Permutation(Index nVars) : rangeIndices_(nVars) {} | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Permute the given variable, i.e. determine it's new index after the | 
					
						
							|  |  |  |    * permutation. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   Index operator[](Index variable) const { check(variable); return rangeIndices_[variable]; } | 
					
						
							|  |  |  |   Index& operator[](Index variable) { check(variable); return rangeIndices_[variable]; } | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * The number of variables in the range of this permutation, i.e. the output | 
					
						
							|  |  |  |    * space. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   Index size() const { return rangeIndices_.size(); } | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /** Whether the permutation contains any entries */ | 
					
						
							|  |  |  |   bool empty() const { return rangeIndices_.empty(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Resize the permutation.  You must fill in the new entries if new new size | 
					
						
							|  |  |  |    * is larger than the old one.  If the new size is smaller, entries from the | 
					
						
							|  |  |  |    * end are discarded. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   void resize(size_t newSize) { rangeIndices_.resize(newSize); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Return an identity permutation. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   static Permutation Identity(Index nVars); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-10 11:10:03 +08:00
										 |  |  |   /**
 | 
					
						
							|  |  |  |    * Create a permutation that pulls the given variables to the front while | 
					
						
							|  |  |  |    * pushing the rest to the back. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   static Permutation PullToFront(const std::vector<Index>& toFront, size_t size); | 
					
						
							| 
									
										
										
										
											2010-10-10 11:10:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-12 00:02:01 +08:00
										 |  |  |   /**
 | 
					
						
							|  |  |  |    * Create a permutation that pulls the given variables to the front while | 
					
						
							|  |  |  |    * pushing the rest to the back. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   static Permutation PushToBack(const std::vector<Index>& toBack, size_t size); | 
					
						
							| 
									
										
										
										
											2010-10-12 00:02:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |   iterator begin() { return rangeIndices_.begin(); } | 
					
						
							|  |  |  |   const_iterator begin() const { return rangeIndices_.begin(); } | 
					
						
							|  |  |  |   iterator end() { return rangeIndices_.end(); } | 
					
						
							|  |  |  |   const_iterator end() const { return rangeIndices_.end(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Print for debugging */ | 
					
						
							|  |  |  |   void print(const std::string& str = "Permutation: ") const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Equals */ | 
					
						
							|  |  |  |   bool equals(const Permutation& rhs) const { return rangeIndices_ == rhs.rangeIndices_; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Syntactic sugar for accessing another container through a permutation. | 
					
						
							|  |  |  |    * Allows the syntax: | 
					
						
							|  |  |  |    *   Permuted<Container> permuted(permutation, container); | 
					
						
							|  |  |  |    *   permuted[index1]; | 
					
						
							|  |  |  |    *   permuted[index2]; | 
					
						
							|  |  |  |    * which is equivalent to: | 
					
						
							|  |  |  |    *   container[permutation[index1]]; | 
					
						
							|  |  |  |    *   container[permutation[index2]]; | 
					
						
							|  |  |  |    * but more concise. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Permute the permutation, p1.permute(p2)[i] is equivalent to p2[p1[i]]. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   Permutation::shared_ptr permute(const Permutation& permutation) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * A partial permutation, reorders the variables selected by selector through | 
					
						
							|  |  |  |    * partialPermutation.  selector and partialPermutation should have the same | 
					
						
							|  |  |  |    * size, this is checked if NDEBUG is not defined. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   Permutation::shared_ptr partialPermutation(const Permutation& selector, const Permutation& partialPermutation) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * Return the inverse permutation.  This is only possible if this is a non- | 
					
						
							|  |  |  |    * reducing permutation, that is, (*this)[i] < this->size() for all i<size(). | 
					
						
							|  |  |  |    * If NDEBUG is not defined, this conditional will be checked. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   Permutation::shared_ptr inverse() const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |   void check(Index variable) const { assert(variable < rangeIndices_.size()); } | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   friend class Inference; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Definition of Permuted class, see above comment for details. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename Container, typename ValueType = typename Container::value_reference_type> | 
					
						
							|  |  |  | class Permuted { | 
					
						
							|  |  |  |   Permutation permutation_; | 
					
						
							|  |  |  |   Container& container_; | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |   typedef ValueType value_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Construct as a permuted view on the Container.  The permutation is copied
 | 
					
						
							|  |  |  |    * but only a reference to the container is stored. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   Permuted(const Permutation& permutation, Container& container) : permutation_(permutation), container_(container) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Construct as a view on the Container with an identity permutation.  Only
 | 
					
						
							|  |  |  |    * a reference to the container is stored. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   Permuted(Container& container) : permutation_(Permutation::Identity(container.size())), container_(container) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Access the container through the permutation */ | 
					
						
							|  |  |  |   value_type operator[](size_t index) const { return container_[permutation_[index]]; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //  /** Access the container through the permutation (const version) */
 | 
					
						
							|  |  |  | //  const_value_type operator[](size_t index) const;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Permute this view by applying a permutation to the underlying permutation */ | 
					
						
							|  |  |  |   void permute(const Permutation& permutation) { assert(permutation.size() == this->size()); permutation_ = *permutation_.permute(permutation); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Access the underlying container */ | 
					
						
							|  |  |  |   Container* operator->() { return &container_; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Access the underlying container (const version) */ | 
					
						
							|  |  |  |   const Container* operator->() const { return &container_; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Size of the underlying container */ | 
					
						
							|  |  |  |   size_t size() const { return container_.size(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Access to the underlying container */ | 
					
						
							|  |  |  |   Container& container() { return container_; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Access to the underlying container (const version) */ | 
					
						
							|  |  |  |   const Container& container() const { return container_; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** Access the underlying permutation */ | 
					
						
							|  |  |  |   Permutation& permutation() { return permutation_; } | 
					
						
							|  |  |  |   const Permutation& permutation() const { return permutation_; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |