| 
									
										
										
										
											2010-07-14 23:22:37 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * EliminationTree-inl.h | 
					
						
							|  |  |  |  * Created on: Feb 4, 2010 | 
					
						
							|  |  |  |  * @Author: Kai Ni | 
					
						
							|  |  |  |  * @Author: Frank Dellaert | 
					
						
							|  |  |  |  * @brief: The elimination tree, template bodies | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-15 07:48:51 +08:00
										 |  |  | #include <stdexcept>
 | 
					
						
							| 
									
										
										
										
											2010-07-15 09:41:26 +08:00
										 |  |  | #include <functional>
 | 
					
						
							| 
									
										
										
										
											2010-07-14 23:22:37 +08:00
										 |  |  | #include <boost/foreach.hpp>
 | 
					
						
							| 
									
										
										
										
											2010-08-20 01:23:19 +08:00
										 |  |  | #include <gtsam/inference/EliminationTree.h>
 | 
					
						
							| 
									
										
										
										
											2010-07-14 23:22:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | //	template<class FG>
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | //	void EliminationTree<FG>::add(const FG& fg, Index j) {
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | //		sharedNode node(new Node(fg, j));
 | 
					
						
							|  |  |  | //		add(node);
 | 
					
						
							|  |  |  | //	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* ************************************************************************* */ | 
					
						
							|  |  |  |   template<class FG> | 
					
						
							|  |  |  |   void EliminationTree<FG>::add(const sharedNode& node) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert(node->frontal.size() == 1); | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |     Index j = node->frontal.front(); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Make a node and put it in the nodes_ array:
 | 
					
						
							|  |  |  |     nodes_[j] = node; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // if the separator is empty, this is the root
 | 
					
						
							|  |  |  |     if (node->separator.empty()) { | 
					
						
							|  |  |  |       this->root_ = node; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       // find parent by iterating over all separator keys, and taking the lowest
 | 
					
						
							|  |  |  |       // one in the ordering. That is the index of the parent clique.
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |       vector<Index>::const_iterator parentIndex = min_element(node->separator.begin(), node->separator.end()); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |       assert(parentIndex != node->separator.end()); | 
					
						
							|  |  |  |       // attach to parent
 | 
					
						
							|  |  |  |       sharedNode& parent = nodes_[*parentIndex]; | 
					
						
							|  |  |  |       if (!parent) throw | 
					
						
							|  |  |  |           invalid_argument("EliminationTree::add: parent clique does not exist"); | 
					
						
							|  |  |  |       node->parent() = parent; | 
					
						
							|  |  |  |       parent->addChild(node); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-07-15 07:48:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | //	template<class FG>
 | 
					
						
							|  |  |  | //	EliminationTree<FG>::EliminationTree(const OrderedGraphs& graphs) :
 | 
					
						
							|  |  |  | //		nrVariables_(graphs.size()), nodes_(nrVariables_) {
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		// Get ordering by (map first graphs)
 | 
					
						
							|  |  |  | //		Ordering ordering;
 | 
					
						
							|  |  |  | //		transform(graphs.begin(), graphs.end(), back_inserter(ordering),
 | 
					
						
							|  |  |  | //				_Select1st<typename OrderedGraphs::value_type> ());
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		// Create a temporary map from key to ordering index
 | 
					
						
							|  |  |  | //		IndexTable<Symbol> indexTable(ordering);
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		// Go over the collection in reverse elimination order
 | 
					
						
							|  |  |  | //		// and add one node for every of the n variables.
 | 
					
						
							|  |  |  | //		BOOST_REVERSE_FOREACH(const NamedGraph& namedGraph, graphs)
 | 
					
						
							|  |  |  | //			add(namedGraph.second, namedGraph.first, indexTable);
 | 
					
						
							|  |  |  | //	}
 | 
					
						
							| 
									
										
										
										
											2010-07-15 07:48:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							|  |  |  | 	template<class FG> | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	EliminationTree<FG>::EliminationTree(FG& fg) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  static const bool debug = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  // If the factor graph is empty, return an empty index because inside this
 | 
					
						
							|  |  |  | 	  // if block we assume at least one factor.
 | 
					
						
							|  |  |  | 	  if(fg.size() > 0) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    vector<deque<size_t> > clusters; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    // Build clusters
 | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      // Find highest-numbered variable
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	      Index maxVar = 0; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	      BOOST_FOREACH(const typename FG::sharedFactor& factor, fg) { | 
					
						
							|  |  |  | 	        if(factor) { | 
					
						
							|  |  |  | 	          typename FG::factor_type::const_iterator maxj = std::max_element(factor->begin(), factor->end()); | 
					
						
							|  |  |  | 	          if(maxj != factor->end() && *maxj > maxVar) maxVar = *maxj; | 
					
						
							|  |  |  | 	        } | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	      // Build index mapping from variable id to factor index - we only use
 | 
					
						
							|  |  |  | 	      // the first variable because after this variable is eliminated the
 | 
					
						
							|  |  |  | 	      // factor will no longer exist.
 | 
					
						
							|  |  |  | 	      clusters.resize(maxVar+1); | 
					
						
							|  |  |  | 	      for(size_t fi=0; fi<fg.size(); ++fi) | 
					
						
							|  |  |  | 	        if(fg[fi] && !fg[fi]->keys().empty()) { | 
					
						
							|  |  |  | 	          typename FG::factor_type::const_iterator firstvar = std::min_element(fg[fi]->begin(), fg[fi]->end()); | 
					
						
							|  |  |  | 	          assert(firstvar != fg[fi]->end()); | 
					
						
							|  |  |  | 	          clusters[*firstvar].push_back(fi); | 
					
						
							|  |  |  | 	        } | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    // Create column index that will be modified during elimination - this is
 | 
					
						
							|  |  |  | 	    // not the most efficient way of doing this, a modified version of
 | 
					
						
							|  |  |  | 	    // Gilbert01bit would be more efficient.
 | 
					
						
							|  |  |  | 	    vector<deque<size_t> > columnIndex = clusters; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    nrVariables_ = columnIndex.size(); | 
					
						
							|  |  |  | 	    nodes_.resize(nrVariables_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    // Loop over all variables and get factors that are connected
 | 
					
						
							|  |  |  | 	    OrderedGraphs graphs; | 
					
						
							|  |  |  | 	    Nodes nodesToAdd; nodesToAdd.reserve(columnIndex.size()); | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	    for(Index j=0; j<columnIndex.size(); ++j) { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	      if(debug) cout << "Eliminating " << j << endl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	      // The factor index of the new joint factor
 | 
					
						
							|  |  |  | 	      size_t jointFactorI = fg.size(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	      // Get all of the factors associated with the variable.
 | 
					
						
							|  |  |  |         // If the factor has not already been removed - I think this is
 | 
					
						
							|  |  |  |         // somehow equivalent to the "find root" computation in Gilbert01bit.
 | 
					
						
							|  |  |  | 	      vector<size_t> involvedFactors; involvedFactors.reserve(columnIndex[j].size()); | 
					
						
							|  |  |  | 	      BOOST_FOREACH(const size_t factorI, columnIndex[j]) { | 
					
						
							|  |  |  | 	        if(fg[factorI]) involvedFactors.push_back(factorI); | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	      if(!involvedFactors.empty()) { | 
					
						
							|  |  |  | 	        // Compute a mapping (called variableSlots) *from* each involved
 | 
					
						
							|  |  |  | 	        // variable that will be in the new joint factor *to* the slot in each
 | 
					
						
							|  |  |  | 	        // removed factor in which that variable appears.  For each variable,
 | 
					
						
							|  |  |  | 	        // this is stored as a vector of slot numbers, stored in order of the
 | 
					
						
							|  |  |  | 	        // removed factors.  The slot number is the max integer value if the
 | 
					
						
							|  |  |  | 	        // factor does not involve that variable.
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	        typedef map<Index, vector<Index> > VariableSlots; | 
					
						
							|  |  |  | 	        map<Index, vector<Index> > variableSlots; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	        FG removedFactors; removedFactors.reserve(involvedFactors.size()); | 
					
						
							|  |  |  | 	        size_t jointFactorPos = 0; | 
					
						
							|  |  |  | 	        BOOST_FOREACH(const size_t factorI, involvedFactors) { | 
					
						
							|  |  |  | 	          // Remove the factor from the factor graph
 | 
					
						
							|  |  |  | 	          assert(fg[factorI]); | 
					
						
							|  |  |  | 	          const typename FG::factor_type& removedFactor(*fg[factorI]); | 
					
						
							|  |  |  | 	          assert(removedFactors.size() == jointFactorPos); | 
					
						
							|  |  |  | 	          removedFactors.push_back(fg[factorI]); | 
					
						
							|  |  |  | 	          fg.remove(factorI); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	          Index factorVarSlot = 0; | 
					
						
							|  |  |  | 	          BOOST_FOREACH(const Index involvedVariable, removedFactor.keys()) { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	            // Set the slot in this factor for this variable.  If the
 | 
					
						
							|  |  |  | 	            // variable was not already discovered, create an array for it
 | 
					
						
							|  |  |  | 	            // that we'll fill with the slot indices for each factor that
 | 
					
						
							|  |  |  | 	            // we're combining.  Initially we put the max integer value in
 | 
					
						
							|  |  |  | 	            // the array entry for each factor that will indicate the factor
 | 
					
						
							|  |  |  | 	            // does not involve the variable.
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	            static vector<Index> empty; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	            VariableSlots::iterator thisVarSlots = variableSlots.insert(make_pair(involvedVariable,empty)).first; | 
					
						
							|  |  |  | 	            if(thisVarSlots->second.empty()) | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	              thisVarSlots->second.resize(involvedFactors.size(), numeric_limits<Index>::max()); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	            thisVarSlots->second[jointFactorPos] = factorVarSlot; | 
					
						
							|  |  |  | 	            if(debug) cout << "  var " << involvedVariable << " rowblock " << jointFactorPos << " comes from factor " << factorI << " slot " << factorVarSlot << endl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	            ++ factorVarSlot; | 
					
						
							|  |  |  | 	          } | 
					
						
							|  |  |  | 	          ++ jointFactorPos; | 
					
						
							|  |  |  | 	        } | 
					
						
							|  |  |  | 	        assert(variableSlots.begin()->first == j); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	        // Now that we know which factors and variables, and where variables
 | 
					
						
							|  |  |  | 	        // come from and go to, create and eliminate the new joint factor.
 | 
					
						
							|  |  |  | 	        typename FG::sharedFactor jointFactor = FG::factor_type::Combine(removedFactors, variableSlots); | 
					
						
							|  |  |  | 	        assert(*jointFactor->begin() == j); | 
					
						
							|  |  |  | 	        typename FG::factor_type::Conditional::shared_ptr conditional = jointFactor->eliminateFirst(); | 
					
						
							|  |  |  | 	        assert(conditional->key() == j); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	        // Add the eliminated joint factor to the partially-eliminated factor graph
 | 
					
						
							|  |  |  | 	        fg.push_back(jointFactor); | 
					
						
							|  |  |  | 	        assert(jointFactorI == fg.size()-1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // Add the joint factor to the column index for this variable if
 | 
					
						
							|  |  |  |           // it's not already added and it's not the variable we're about to
 | 
					
						
							|  |  |  |           // eliminate.
 | 
					
						
							|  |  |  | 	        if(!jointFactor->keys().empty()) | 
					
						
							|  |  |  | 	          columnIndex[jointFactor->front()].push_back(jointFactorI); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	        // Create the new node, although it's parent and children will not be
 | 
					
						
							|  |  |  | 	        // computed yet.
 | 
					
						
							|  |  |  | 	        // todo: use cluster factors instead of removedFactors here.
 | 
					
						
							|  |  |  | 	        nodesToAdd.push_back(typename Node::shared_ptr(new Node(removedFactors, conditional->key(), | 
					
						
							|  |  |  | 	            conditional->beginParents(), conditional->endParents()))); | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    // Go over the collection in reverse elimination order
 | 
					
						
							|  |  |  | 	    // and add one node for every of the n variables.
 | 
					
						
							|  |  |  | 	    BOOST_REVERSE_FOREACH(const sharedNode& node, nodesToAdd) { | 
					
						
							|  |  |  | 	      add(node); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if(debug) this->print("Completed elimination tree: "); | 
					
						
							|  |  |  | 	  } | 
					
						
							| 
									
										
										
										
											2010-07-14 23:22:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-15 07:48:51 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-07-14 23:22:37 +08:00
										 |  |  | } //namespace gtsam
 |