| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * JunctionTree-inl.h | 
					
						
							| 
									
										
										
										
											2010-07-14 23:22:37 +08:00
										 |  |  |  * Created on: Feb 4, 2010 | 
					
						
							|  |  |  |  * @Author: Kai Ni | 
					
						
							|  |  |  |  * @Author: Frank Dellaert | 
					
						
							|  |  |  |  * @brief: The junction tree, template bodies | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 07:00:03 +08:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-20 01:23:19 +08:00
										 |  |  | #include <gtsam/inference/SymbolicFactorGraph.h>
 | 
					
						
							|  |  |  | #include <gtsam/inference/BayesTree-inl.h>
 | 
					
						
							|  |  |  | #include <gtsam/inference/JunctionTree.h>
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | #include <gtsam/inference/inference-inl.h>
 | 
					
						
							|  |  |  | #include <gtsam/inference/VariableSlots-inl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/foreach.hpp>
 | 
					
						
							|  |  |  | #include <boost/pool/pool_alloc.hpp>
 | 
					
						
							|  |  |  | #include <boost/lambda/bind.hpp>
 | 
					
						
							|  |  |  | #include <boost/lambda/lambda.hpp>
 | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-07-09 15:31:15 +08:00
										 |  |  | 	template <class FG> | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	JunctionTree<FG>::JunctionTree(const FG& fg) { | 
					
						
							|  |  |  | 	  tic("JT 1  constructor"); | 
					
						
							| 
									
										
										
										
											2010-07-14 12:32:58 +08:00
										 |  |  | 		// Symbolic factorization: GaussianFactorGraph -> SymbolicFactorGraph
 | 
					
						
							|  |  |  | 		// -> SymbolicBayesNet -> SymbolicBayesTree
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		tic("JT 1.1  symbolic elimination"); | 
					
						
							|  |  |  | 		SymbolicBayesNet::shared_ptr sbn = Inference::EliminateSymbolic(fg); | 
					
						
							|  |  |  |     toc("JT 1.1  symbolic elimination"); | 
					
						
							|  |  |  |     tic("JT 1.2  symbolic BayesTree"); | 
					
						
							|  |  |  | 		SymbolicBayesTree sbt(*sbn); | 
					
						
							|  |  |  | 		toc("JT 1.2  symbolic BayesTree"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// distribute factors
 | 
					
						
							|  |  |  |     tic("JT 1.3  distributeFactors"); | 
					
						
							| 
									
										
										
										
											2010-07-14 12:32:58 +08:00
										 |  |  | 		this->root_ = distributeFactors(fg, sbt.root()); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     toc("JT 1.3  distributeFactors"); | 
					
						
							|  |  |  | 		toc("JT 1  constructor"); | 
					
						
							| 
									
										
										
										
											2010-07-09 15:31:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-07-14 12:32:58 +08:00
										 |  |  | 	template<class FG> | 
					
						
							|  |  |  | 	typename JunctionTree<FG>::sharedClique JunctionTree<FG>::distributeFactors( | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 			const FG& fg, const typename SymbolicBayesTree::sharedClique& bayesClique) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  // Build "target" index.  This is an index for each variable of the factors
 | 
					
						
							|  |  |  | 	  // that involve this variable as their *lowest-ordered* variable.  For each
 | 
					
						
							|  |  |  | 	  // factor, it is the lowest-ordered variable of that factor that pulls the
 | 
					
						
							|  |  |  | 	  // factor into elimination, after which all of the information in the
 | 
					
						
							|  |  |  | 	  // factor is contained in the eliminated factors that are passed up the
 | 
					
						
							|  |  |  | 	  // tree as elimination continues.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  // Two stages - first build an array of the lowest-ordered variable in each
 | 
					
						
							|  |  |  | 	  // factor and find the last variable to be eliminated.
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	  vector<Index> lowestOrdered(fg.size()); | 
					
						
							|  |  |  | 	  Index maxVar = 0; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	  for(size_t i=0; i<fg.size(); ++i) | 
					
						
							|  |  |  | 	    if(fg[i]) { | 
					
						
							|  |  |  | 	      typename FG::factor_type::const_iterator min = std::min_element(fg[i]->begin(), fg[i]->end()); | 
					
						
							|  |  |  | 	      if(min == fg[i]->end()) | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	        lowestOrdered[i] = numeric_limits<Index>::max(); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	      else { | 
					
						
							|  |  |  | 	        lowestOrdered[i] = *min; | 
					
						
							|  |  |  | 	        maxVar = std::max(maxVar, *min); | 
					
						
							|  |  |  | 	      } | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  // Now add each factor to the list corresponding to its lowest-ordered
 | 
					
						
							|  |  |  | 	  // variable.
 | 
					
						
							|  |  |  | 	  vector<list<size_t, boost::fast_pool_allocator<size_t> > > targets(maxVar+1); | 
					
						
							|  |  |  | 	  for(size_t i=0; i<lowestOrdered.size(); ++i) | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	    if(lowestOrdered[i] != numeric_limits<Index>::max()) | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	      targets[lowestOrdered[i]].push_back(i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  // Now call the recursive distributeFactors
 | 
					
						
							|  |  |  | 	  return distributeFactors(fg, targets, bayesClique); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-09 15:31:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |   /* ************************************************************************* */ | 
					
						
							|  |  |  | 	template<class FG> | 
					
						
							|  |  |  | 	typename JunctionTree<FG>::sharedClique JunctionTree<FG>::distributeFactors(const FG& fg, | 
					
						
							|  |  |  | 	    const std::vector<std::list<size_t,boost::fast_pool_allocator<size_t> > >& targets, | 
					
						
							|  |  |  |       const SymbolicBayesTree::sharedClique& bayesClique) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  if(bayesClique) { | 
					
						
							|  |  |  | 	    // create a new clique in the junction tree
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	    list<Index> frontals = bayesClique->ordering(); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	    sharedClique clique(new Clique(frontals.begin(), frontals.end(), bayesClique->separator_.begin(), bayesClique->separator_.end())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    // count the factors for this cluster to pre-allocate space
 | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      size_t nFactors = 0; | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	      BOOST_FOREACH(const Index frontal, clique->frontal) { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	        // There may be less variables in "targets" than there really are if
 | 
					
						
							|  |  |  | 	        // some of the highest-numbered variables do not pull in any factors.
 | 
					
						
							|  |  |  | 	        if(frontal < targets.size()) | 
					
						
							|  |  |  | 	          nFactors += targets[frontal].size(); } | 
					
						
							|  |  |  | 	      clique->reserve(nFactors); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    // add the factors to this cluster
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  | 	    BOOST_FOREACH(const Index frontal, clique->frontal) { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	      if(frontal < targets.size()) { | 
					
						
							|  |  |  | 	        BOOST_FOREACH(const size_t factorI, targets[frontal]) { | 
					
						
							|  |  |  | 	          clique->push_back(fg[factorI]); } } } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    // recursively call the children
 | 
					
						
							|  |  |  | 	    BOOST_FOREACH(const typename SymbolicBayesTree::sharedClique bayesChild, bayesClique->children()) { | 
					
						
							|  |  |  | 	      sharedClique child = distributeFactors(fg, targets, bayesChild); | 
					
						
							|  |  |  | 	      clique->addChild(child); | 
					
						
							|  |  |  | 	      child->parent() = clique; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    return clique; | 
					
						
							|  |  |  | 	  } else | 
					
						
							|  |  |  | 	    return sharedClique(); | 
					
						
							| 
									
										
										
										
											2010-07-09 15:31:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	template <class FG> | 
					
						
							|  |  |  | 	pair<typename JunctionTree<FG>::BayesTree::sharedClique, typename FG::sharedFactor> | 
					
						
							|  |  |  | 	JunctionTree<FG>::eliminateOneClique(const boost::shared_ptr<const Clique>& current) const { | 
					
						
							| 
									
										
										
										
											2010-07-11 15:30:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | 		FG fg; // factor graph will be assembled from local factors and marginalized children
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		fg.reserve(current->size() + current->children().size()); | 
					
						
							|  |  |  | 		fg.push_back(*current); // add the local factors
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // receive the factors from the child and its clique point
 | 
					
						
							|  |  |  |     list<typename BayesTree::sharedClique> children; | 
					
						
							|  |  |  | 		BOOST_FOREACH(const boost::shared_ptr<const Clique>& child, current->children()) { | 
					
						
							|  |  |  | 		  pair<typename BayesTree::sharedClique, typename FG::sharedFactor> tree_factor( | 
					
						
							|  |  |  | 		      eliminateOneClique(child)); | 
					
						
							|  |  |  |       children.push_back(tree_factor.first); | 
					
						
							|  |  |  | 			fg.push_back(tree_factor.second); | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// eliminate the combined factors
 | 
					
						
							|  |  |  | 		// warning: fg is being eliminated in-place and will contain marginal afterwards
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		tic("JT 2.1 VariableSlots"); | 
					
						
							|  |  |  | 		VariableSlots variableSlots(fg); | 
					
						
							|  |  |  |     toc("JT 2.1 VariableSlots"); | 
					
						
							|  |  |  | #ifndef NDEBUG
 | 
					
						
							|  |  |  |     // Debug check that the keys found in the factors match the frontal and
 | 
					
						
							|  |  |  |     // separator keys of the clique.
 | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |     list<Index> allKeys; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     allKeys.insert(allKeys.end(), current->frontal.begin(), current->frontal.end()); | 
					
						
							|  |  |  |     allKeys.insert(allKeys.end(), current->separator.begin(), current->separator.end()); | 
					
						
							| 
									
										
										
										
											2010-10-12 05:14:35 +08:00
										 |  |  |     vector<Index> varslotsKeys(variableSlots.size()); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     std::transform(variableSlots.begin(), variableSlots.end(), varslotsKeys.begin(), | 
					
						
							|  |  |  |         boost::lambda::bind(&VariableSlots::iterator::value_type::first, boost::lambda::_1)); | 
					
						
							|  |  |  |     assert(std::equal(allKeys.begin(), allKeys.end(), varslotsKeys.begin())); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Now that we know which factors and variables, and where variables
 | 
					
						
							|  |  |  |     // come from and go to, create and eliminate the new joint factor.
 | 
					
						
							|  |  |  |     tic("JT 2.2 Combine"); | 
					
						
							|  |  |  |     typename FG::sharedFactor jointFactor = FG::factor_type::Combine(fg, variableSlots); | 
					
						
							|  |  |  |     toc("JT 2.2 Combine"); | 
					
						
							|  |  |  |     tic("JT 2.3 Eliminate"); | 
					
						
							|  |  |  |     typename FG::bayesnet_type::shared_ptr fragment = jointFactor->eliminate(current->frontal.size()); | 
					
						
							|  |  |  |     toc("JT 2.3 Eliminate"); | 
					
						
							|  |  |  |     assert(std::equal(jointFactor->begin(), jointFactor->end(), current->separator.begin())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tic("JT 2.4 Update tree"); | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | 		// create a new clique corresponding the combined factors
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		typename BayesTree::sharedClique new_clique(new typename BayesTree::Clique(*fragment)); | 
					
						
							| 
									
										
										
										
											2010-07-31 15:19:03 +08:00
										 |  |  | 		new_clique->children_ = children; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		BOOST_FOREACH(typename BayesTree::sharedClique& childRoot, children) | 
					
						
							| 
									
										
										
										
											2010-07-31 15:19:03 +08:00
										 |  |  | 			childRoot->parent_ = new_clique; | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		new_clique->cachedFactor() = jointFactor; | 
					
						
							|  |  |  |     toc("JT 2.4 Update tree"); | 
					
						
							|  |  |  | 		return make_pair(new_clique, jointFactor); | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	template <class FG> | 
					
						
							|  |  |  | 	typename JunctionTree<FG>::BayesTree::sharedClique JunctionTree<FG>::eliminate() const { | 
					
						
							|  |  |  | 	  if(this->root()) { | 
					
						
							|  |  |  | 	    tic("JT 2 eliminate"); | 
					
						
							|  |  |  | 	    pair<typename BayesTree::sharedClique, typename FG::sharedFactor> ret = this->eliminateOneClique(this->root()); | 
					
						
							|  |  |  | 	    if (ret.second->size() != 0) | 
					
						
							|  |  |  | 	      throw runtime_error("JuntionTree::eliminate: elimination failed because of factors left over!"); | 
					
						
							|  |  |  | 	    toc("JT 2 eliminate"); | 
					
						
							|  |  |  | 	    return ret.first; | 
					
						
							|  |  |  | 	  } else | 
					
						
							|  |  |  | 	    return typename BayesTree::sharedClique(); | 
					
						
							| 
									
										
										
										
											2010-07-08 05:41:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } //namespace gtsam
 |