136 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
| /**
 | |
|  * @file    ISAM2-inl.h
 | |
|  * @brief   Incremental update functionality (ISAM2) for BayesTree, with fluid relinearization.
 | |
|  * @author  Michael Kaess
 | |
|  */
 | |
| 
 | |
| #include <boost/foreach.hpp>
 | |
| #include <boost/assign/std/list.hpp> // for operator +=
 | |
| using namespace boost::assign;
 | |
| 
 | |
| #include <set>
 | |
| 
 | |
| #include "NonlinearFactorGraph.h"
 | |
| #include "GaussianFactor.h"
 | |
| #include "VectorConfig.h"
 | |
| 
 | |
| #include "Conditional.h"
 | |
| #include "BayesTree-inl.h"
 | |
| #include "ISAM2.h"
 | |
| 
 | |
| namespace gtsam {
 | |
| 
 | |
| 	using namespace std;
 | |
| 
 | |
| 	/** Create an empty Bayes Tree */
 | |
| 	template<class Conditional, class Config>
 | |
| 	ISAM2<Conditional, Config>::ISAM2() : BayesTree<Conditional>() {}
 | |
| 
 | |
| 	/** Create a Bayes Tree from a nonlinear factor graph */
 | |
| 	template<class Conditional, class Config>
 | |
| 	ISAM2<Conditional, Config>::ISAM2(const NonlinearFactorGraph<Config>& nlfg, const Ordering& ordering, const Config& config)
 | |
| 	: BayesTree<Conditional>(nlfg.linearize(config).eliminate(ordering)), nonlinearFactors_(nlfg), config_(config) {}
 | |
| 
 | |
| 	/* ************************************************************************* */
 | |
| 	template<class Conditional, class Config>
 | |
| 	void ISAM2<Conditional, Config>::update_internal(const NonlinearFactorGraph<Config>& newFactors,
 | |
| 			const Config& config, Cliques& orphans) {
 | |
| 
 | |
| 		// copy variables into config_, but don't overwrite existing entries (current linearization point!)
 | |
| 		for (typename Config::const_iterator it = config.begin(); it!=config.end(); it++) {
 | |
| 			if (!config_.contains(it->first)) {
 | |
| 				config_.insert(it->first, it->second);
 | |
| 			}
 | |
| 		}
 | |
| 		nonlinearFactors_.push_back(newFactors);
 | |
| 
 | |
| 		FactorGraph<GaussianFactor> newFactorsLinearized = newFactors.linearize(config_);
 | |
| 
 | |
| 		// Remove the contaminated part of the Bayes tree
 | |
| 		FactorGraph<GaussianFactor> affectedFactors;
 | |
| 		boost::tie(affectedFactors, orphans) = this->removeTop(newFactorsLinearized);
 | |
| 
 | |
| 
 | |
| #if 1
 | |
| 		// find the corresponding original nonlinear factors, and relinearize them
 | |
| 		NonlinearFactorGraph<Config> nonlinearAffectedFactors;
 | |
| 		set<int> idxs; // avoid duplicates by putting index into set
 | |
| 		BOOST_FOREACH(FactorGraph<GaussianFactor>::sharedFactor fac, affectedFactors) {
 | |
| 			// retrieve correspondent factor from nonlinearFactors_
 | |
| 			Ordering keys = fac->keys();
 | |
| 			BOOST_FOREACH(string key, keys) {
 | |
| 				list<int> indices = nonlinearFactors_.factors(key);
 | |
| 				BOOST_FOREACH(int idx, indices) {
 | |
| 					// todo - only insert index if factor is subset of keys... not needed once we do relinearization - but then how to deal with overlap with orphans?
 | |
| 					bool subset = true;
 | |
| 					BOOST_FOREACH(string k, nonlinearFactors_[idx]->keys()) {
 | |
| 						if (find(keys.begin(), keys.end(), k)==keys.end()) subset = false;
 | |
| 					}
 | |
| 					if (subset) {
 | |
| 						idxs.insert(idx);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		BOOST_FOREACH(int idx, idxs) {
 | |
| 			nonlinearAffectedFactors.push_back(nonlinearFactors_[idx]);
 | |
| 		}
 | |
| 		FactorGraph<GaussianFactor> factors = nonlinearAffectedFactors.linearize(config_);
 | |
| 
 | |
| 		// add the new factors themselves
 | |
| 		factors.push_back(newFactorsLinearized);
 | |
| #endif
 | |
| 
 | |
| 		affectedFactors.push_back(newFactorsLinearized);
 | |
| 
 | |
| 		// create an ordering for the new and contaminated factors
 | |
| 		Ordering ordering;
 | |
| 		if (true) {
 | |
| 			ordering = /*affectedF*/factors.getOrdering();
 | |
| 		} else {
 | |
| 			list<string> keys = /*affectedF*/factors.keys();
 | |
| 			keys.sort(); // todo: correct sorting order?
 | |
| 			ordering = keys;
 | |
| 		}
 | |
| 
 | |
| 		// eliminate into a Bayes net
 | |
| 		BayesNet<Conditional> bayesNet = eliminate<GaussianFactor, Conditional>(affectedFactors,ordering);
 | |
| 
 | |
| #if 1
 | |
| 		BayesNet<Conditional> bayesNetTest = eliminate<GaussianFactor, Conditional>(factors,ordering); // todo - debug only
 | |
| 		if (!bayesNet.equals(bayesNetTest)) {
 | |
| 			printf("differ\n");
 | |
| 			bayesNet.print();
 | |
| 			bayesNetTest.print();
 | |
| 			exit(42);
 | |
| 		}
 | |
| #endif
 | |
| 
 | |
| 		// insert conditionals back in, straight into the topless bayesTree
 | |
| 		typename BayesNet<Conditional>::const_reverse_iterator rit;
 | |
| 		for ( rit=bayesNet.rbegin(); rit != bayesNet.rend(); ++rit )
 | |
| 			this->insert(*rit);
 | |
| 
 | |
| 		int count = 0;
 | |
| 		// add orphans to the bottom of the new tree
 | |
| 		BOOST_FOREACH(sharedClique orphan, orphans) {
 | |
| 
 | |
| 			string key = orphan->separator_.front();
 | |
| 			sharedClique parent = (*this)[key];
 | |
| 
 | |
| 			parent->children_ += orphan;
 | |
| 			orphan->parent_ = parent; // set new parent!
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	template<class Conditional, class Config>
 | |
| 	void ISAM2<Conditional, Config>::update(const NonlinearFactorGraph<Config>& newFactors, const Config& config) {
 | |
| 		Cliques orphans;
 | |
| 		this->update_internal(newFactors, config, orphans);
 | |
| 	}
 | |
| 
 | |
| /* ************************************************************************* */
 | |
| 
 | |
| }
 | |
| /// namespace gtsam
 |