490 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
		
		
			
		
	
	
			490 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
|  | /**
 | ||
|  |  * @file   FactorGraph-inl.h | ||
|  |  * This is a template definition file, include it where needed (only!) | ||
|  |  * so that the appropriate code is generated and link errors avoided. | ||
|  |  * @brief  Factor Graph Base Class | ||
|  |  * @author Carlos Nieto | ||
|  |  * @author Frank Dellaert | ||
|  |  * @author Alireza Fathi | ||
|  |  * @author Michael Kaess | ||
|  |  */ | ||
|  | 
 | ||
|  | #pragma once
 | ||
|  | 
 | ||
|  | #include <list>
 | ||
|  | #include <sstream>
 | ||
|  | #include <stdexcept>
 | ||
|  | #include <functional>
 | ||
|  | 
 | ||
|  | #include <boost/foreach.hpp>
 | ||
|  | #include <boost/tuple/tuple.hpp>
 | ||
|  | #include <boost/format.hpp>
 | ||
|  | #include <boost/graph/prim_minimum_spanning_tree.hpp>
 | ||
|  | #include "ccolamd.h"
 | ||
|  | #include "Ordering.h"
 | ||
|  | #include "FactorGraph.h"
 | ||
|  | #include "graph-inl.h"
 | ||
|  | #include "DSF.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #define INSTANTIATE_FACTOR_GRAPH(F) \
 | ||
|  |   template class FactorGraph<F>; \ | ||
|  |   /*template boost::shared_ptr<F> removeAndCombineFactors(FactorGraph<F>&, const std::string&);*/ \ | ||
|  |   template FactorGraph<F> combine(const FactorGraph<F>&, const FactorGraph<F>&); | ||
|  | 
 | ||
|  | using namespace std; | ||
|  | 
 | ||
|  | namespace gtsam { | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | template<class Conditional> | ||
|  | FactorGraph<Factor>::FactorGraph(const BayesNet<Conditional>& bayesNet) | ||
|  | { | ||
|  | 	typename BayesNet<Conditional>::const_iterator it = bayesNet.begin(); | ||
|  | 	for(; it != bayesNet.end(); it++) { | ||
|  | 		sharedFactor factor(new Factor(*it)); | ||
|  | 		push_back(factor); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | void FactorGraph<Factor>::print(const string& s) const { | ||
|  | 	cout << s << endl; | ||
|  | 	printf("size: %d\n", (int) size()); | ||
|  | 	for (size_t i = 0; i < factors_.size(); i++) { | ||
|  | 		stringstream ss; | ||
|  | 		ss << "factor " << i << ":"; | ||
|  | 		if (factors_[i] != NULL) factors_[i]->print(ss.str()); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | bool FactorGraph<Factor>::equals | ||
|  | 	(const FactorGraph<Factor>& fg, double tol) const { | ||
|  | 	/** check whether the two factor graphs have the same number of factors_ */ | ||
|  | 	if (factors_.size() != fg.size()) return false; | ||
|  | 
 | ||
|  | 	/** check whether the factors_ are the same */ | ||
|  | 	for (size_t i = 0; i < factors_.size(); i++) { | ||
|  | 		// TODO: Doesn't this force order of factor insertion?
 | ||
|  | 		sharedFactor f1 = factors_[i], f2 = fg.factors_[i]; | ||
|  | 		if (f1 == NULL && f2 == NULL) continue; | ||
|  | 		if (f1 == NULL || f2 == NULL) return false; | ||
|  | 		if (!f1->equals(*f2, tol)) return false; | ||
|  | 	} | ||
|  | 	return true; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | size_t FactorGraph<Factor>::nrFactors() const { | ||
|  | 	size_t size_ = 0; | ||
|  | 	for (const_iterator factor = factors_.begin(); factor != factors_.end(); factor++) | ||
|  | 		if (*factor != NULL) size_++; | ||
|  | 	return size_; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | void FactorGraph<Factor>::push_back(sharedFactor factor) { | ||
|  | 	factors_.push_back(factor);                  // add the actual factor
 | ||
|  | 	if (factor==NULL) return; | ||
|  | 
 | ||
|  | 	size_t i = factors_.size() - 1;                 // index of factor
 | ||
|  | 	associateFactor(i, factor); | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | void FactorGraph<Factor>::push_back(const FactorGraph<Factor>& factors) { | ||
|  | 	const_iterator factor = factors.begin(); | ||
|  | 	for (; factor!= factors.end(); factor++) | ||
|  | 		push_back(*factor); | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | void FactorGraph<Factor>::replace(size_t index, sharedFactor factor) { | ||
|  |   if(index >= factors_.size()) | ||
|  |     throw invalid_argument(boost::str(boost::format( | ||
|  |         "Factor graph does not contain a factor with index %d.") % index)); | ||
|  |   //if(factors_[index] == NULL)
 | ||
|  |   //  throw invalid_argument(boost::str(boost::format(
 | ||
|  |   //      "Factor with index %d is NULL." % index)));
 | ||
|  | 
 | ||
|  |   if(factors_[index] != NULL) { | ||
|  |     // Remove this factor from its variables' index lists
 | ||
|  |     BOOST_FOREACH(const Symbol& key, factors_[index]->keys()) { | ||
|  |     	indices_.at(key).remove(index); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   // Replace the factor
 | ||
|  |   factors_[index] = factor; | ||
|  |   associateFactor(index, factor); | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | Ordering FactorGraph<Factor>::keys() const { | ||
|  | 	Ordering keys; | ||
|  | 	transform(indices_.begin(), indices_.end(), | ||
|  | 			back_inserter(keys), _Select1st<Indices::value_type>()); | ||
|  | 	return keys; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | std::pair<FactorGraph<Factor>, set<Symbol> > FactorGraph<Factor>::removeSingletons() { | ||
|  | 	FactorGraph<Factor> singletonGraph; | ||
|  | 	set<Symbol> singletons; | ||
|  | 
 | ||
|  | 	while(true) { | ||
|  | 		// find all the singleton variables
 | ||
|  | 		Ordering new_singletons; | ||
|  | 		Symbol key; | ||
|  | 		list<size_t> indices; | ||
|  | 		BOOST_FOREACH(boost::tie(key, indices), indices_) { | ||
|  | 			// find out the number of factors associated with the current key
 | ||
|  | 			size_t numValidFactors = 0; | ||
|  | 			BOOST_FOREACH(const size_t& i, indices) | ||
|  | 				if (factors_[i]!=NULL) numValidFactors++; | ||
|  | 
 | ||
|  | 			if (numValidFactors == 1) { | ||
|  | 				new_singletons.push_back(key); | ||
|  | 				BOOST_FOREACH(const size_t& i, indices) | ||
|  | 					if (factors_[i]!=NULL) singletonGraph.push_back(factors_[i]); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		singletons.insert(new_singletons.begin(), new_singletons.end()); | ||
|  | 
 | ||
|  | 		BOOST_FOREACH(const Symbol& singleton, new_singletons) | ||
|  | 			findAndRemoveFactors<vector<boost::shared_ptr<Factor> > >(singleton); | ||
|  | 
 | ||
|  | 		// exit when there are no more singletons
 | ||
|  | 		if (new_singletons.empty()) break; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return make_pair(singletonGraph, singletons); | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | /**
 | ||
|  |  * Call colamd given a column-major symbolic matrix A | ||
|  |  * @param n_col colamd arg 1: number of rows in A | ||
|  |  * @param n_row colamd arg 2: number of columns in A | ||
|  |  * @param nrNonZeros number of non-zero entries in A | ||
|  |  * @param columns map from keys to a sparse column of non-zero row indices | ||
|  |  * @param lastKeys set of keys that should appear last in the ordering | ||
|  |  */ | ||
|  | template <class Key> | ||
|  | void colamd(int n_col, int n_row, int nrNonZeros, const map<Key, vector<int> >& columns, | ||
|  | 		Ordering& ordering, const set<Symbol>& lastKeys) { | ||
|  | 
 | ||
|  | 	// Convert to compressed column major format colamd wants it in (== MATLAB format!)
 | ||
|  | 	int Alen = ccolamd_recommended(nrNonZeros, n_row, n_col);     /* colamd arg 3: size of the array A */ | ||
|  | 	int * A = new int[Alen];      /* colamd arg 4: row indices of A, of size Alen */ | ||
|  | 	int * p = new int[n_col + 1]; /* colamd arg 5: column pointers of A, of size n_col+1 */ | ||
|  | 	int * cmember = new int[n_col];  /* Constraint set of A, of size n_col */ | ||
|  | 
 | ||
|  | 	p[0] = 0; | ||
|  | 	int j = 1; | ||
|  | 	int count = 0; | ||
|  | 	typedef typename map<Key, vector<int> >::const_iterator iterator; | ||
|  | 	bool front_exists = false; | ||
|  | 	vector<Key> initialOrder; | ||
|  | 	for(iterator it = columns.begin(); it != columns.end(); it++) { | ||
|  | 		const Key& key = it->first; | ||
|  | 		const vector<int>& column = it->second; | ||
|  | 		initialOrder.push_back(key); | ||
|  | 		BOOST_FOREACH(int i, column) A[count++] = i; // copy sparse column
 | ||
|  | 		p[j] = count; // column j (base 1) goes from A[j-1] to A[j]-1
 | ||
|  | 		if (lastKeys.find(key)==lastKeys.end()) { | ||
|  | 			cmember[j-1] = 0; | ||
|  | 			front_exists = true; | ||
|  | 		} else { | ||
|  | 			cmember[j-1] = 1; // force lastKeys to be at the end
 | ||
|  | 		} | ||
|  | 		j+=1; | ||
|  | 	} | ||
|  | 	if (!front_exists) { // if only 1 entries, set everything to 0...
 | ||
|  | 		for(int j = 0; j < n_col; j++) | ||
|  | 			cmember[j] = 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	double* knobs = NULL;    /* colamd arg 6: parameters (uses defaults if NULL) */ | ||
|  | 	int stats[CCOLAMD_STATS]; /* colamd arg 7: colamd output statistics and error codes */ | ||
|  | 
 | ||
|  | 	// call colamd, result will be in p *************************************************
 | ||
|  | 	/* TODO: returns (1) if successful, (0) otherwise*/ | ||
|  | 	::ccolamd(n_row, n_col, Alen, A, p, knobs, stats, cmember); | ||
|  | 	// **********************************************************************************
 | ||
|  | 	delete [] A; // delete symbolic A
 | ||
|  | 	delete [] cmember; | ||
|  | 
 | ||
|  | 	// Convert elimination ordering in p to an ordering
 | ||
|  | 	for(int j = 0; j < n_col; j++) | ||
|  | 		ordering.push_back(initialOrder[p[j]]); | ||
|  | 	delete [] p; // delete colamd result vector
 | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | void FactorGraph<Factor>::getOrdering(Ordering& ordering, const set<Symbol>& lastKeys, | ||
|  | 		boost::optional<const set<Symbol>&> interested) const { | ||
|  | 
 | ||
|  | 	// A factor graph is really laid out in row-major format, each factor a row
 | ||
|  | 	// Below, we compute a symbolic matrix stored in sparse columns.
 | ||
|  | 	map<Symbol, vector<int> > columns; // map from keys to a sparse column of non-zero row indices
 | ||
|  | 	int nrNonZeros = 0;             // number of non-zero entries
 | ||
|  | 	int n_row = 0;                  /* colamd arg 1: number of rows in A */ | ||
|  | 
 | ||
|  | 	// loop over all factors = rows
 | ||
|  | 	bool hasInterested = interested.is_initialized(); | ||
|  | 	bool inserted; | ||
|  | 	BOOST_FOREACH(const sharedFactor& factor, factors_) { | ||
|  | 		if (factor==NULL) continue; | ||
|  | 		list<Symbol> keys = factor->keys(); | ||
|  | 		inserted = false; | ||
|  | 		BOOST_FOREACH(const Symbol& key, keys) { | ||
|  | 			if (!hasInterested || interested->find(key) != interested->end()) { | ||
|  | 				columns[key].push_back(n_row); | ||
|  | 				nrNonZeros++; | ||
|  | 				inserted = true; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		if (inserted) n_row++; | ||
|  | 	} | ||
|  | 	int n_col = (int)(columns.size()); /* colamd arg 2: number of columns in A */ | ||
|  | 	if(n_col != 0) | ||
|  | 		colamd(n_col, n_row, nrNonZeros, columns, ordering, lastKeys); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | boost::shared_ptr<Ordering> FactorGraph<Factor>::getOrdering_() const{ | ||
|  | 	boost::shared_ptr<Ordering> ordering(new Ordering); | ||
|  | 	set<Symbol> lastKeys; | ||
|  | 	getOrdering(*ordering, lastKeys); | ||
|  | 	return ordering; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | Ordering FactorGraph<Factor>::getOrdering() const { | ||
|  | 	Ordering ordering; | ||
|  | 	set<Symbol> lastKeys; | ||
|  | 	getOrdering(ordering, lastKeys); | ||
|  | 	return ordering; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | Ordering FactorGraph<Factor>::getOrdering(const set<Symbol>& interested) const { | ||
|  | 	Ordering ordering; | ||
|  | 	set<Symbol> lastKeys; | ||
|  | 	getOrdering(ordering, lastKeys, interested); | ||
|  | 	return ordering; | ||
|  | } | ||
|  | 
 | ||
|  | template<class Factor> | ||
|  | Ordering FactorGraph<Factor>::getConstrainedOrdering(const set<Symbol>& lastKeys) const { | ||
|  | 	Ordering ordering; | ||
|  | 	getOrdering(ordering, lastKeys); | ||
|  | 	return ordering; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | /** O(1)                                                                     */ | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | list<size_t> FactorGraph<Factor>::factors(const Symbol& key) const { | ||
|  | 	return indices_.at(key); | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | /** find all non-NULL factors for a variable, then set factors to NULL       */ | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> template<class Factors> | ||
|  | Factors FactorGraph<Factor>::findAndRemoveFactors(const Symbol& key) { | ||
|  | 
 | ||
|  | 	// find all factor indices associated with the key
 | ||
|  | 	Indices::const_iterator it = indices_.find(key); | ||
|  | 	if (it==indices_.end()) | ||
|  | 		throw std::invalid_argument( | ||
|  | 				"FactorGraph::findAndRemoveFactors: key " | ||
|  | 				+ (string)key + " not found"); | ||
|  | 	const list<size_t>& factorsAssociatedWithKey = it->second; | ||
|  | 
 | ||
|  | 	Factors found; | ||
|  | 	BOOST_FOREACH(const size_t& i, factorsAssociatedWithKey) { | ||
|  | 		sharedFactor& fi = factors_.at(i); // throws exception !
 | ||
|  | 		if(fi == NULL) continue; // skip NULL factors
 | ||
|  | 		found.push_back(fi);     // add to found
 | ||
|  | 		fi.reset();              // set factor to NULL == remove(i)
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	indices_.erase(key); | ||
|  | 
 | ||
|  | 	return found; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | void FactorGraph<Factor>::associateFactor(size_t index, const sharedFactor& factor) { | ||
|  |   const list<Symbol> keys = factor->keys();          // get keys for factor
 | ||
|  |   // rtodo: Can optimize factor->keys to return a const reference
 | ||
|  | 
 | ||
|  |   BOOST_FOREACH(const Symbol& key, keys)             // for each key push i onto list
 | ||
|  | 			indices_[key].push_back(index); | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> void FactorGraph<Factor>::checkGraphConsistency() const { | ||
|  |   // Consistency check for debugging
 | ||
|  | 
 | ||
|  | 	// Make sure each factor is listed in its variables index lists
 | ||
|  |   for(size_t i=0; i<factors_.size(); i++) { | ||
|  |   	if(factors_[i] == NULL) { | ||
|  |   		cout << "** Warning: factor " << i << " is NULL" << endl; | ||
|  |   	} else { | ||
|  |   		// Get involved variables
 | ||
|  |   		list<Symbol> keys = factors_[i]->keys(); | ||
|  | 
 | ||
|  |   		// Make sure each involved variable is listed as being associated with this factor
 | ||
|  |   		BOOST_FOREACH(const Symbol& var, keys) { | ||
|  |   			if(std::find(indices_.at(var).begin(), indices_.at(var).end(), i) == indices_.at(var).end()) | ||
|  |   				cout << "*** Factor graph inconsistency: " << (string)var << " is not mapped to factor " << i << endl; | ||
|  |   		} | ||
|  |   	} | ||
|  |   } | ||
|  | 
 | ||
|  |   // Make sure each factor listed for a variable actually involves that variable
 | ||
|  |   BOOST_FOREACH(const SymbolMap<list<size_t> >::value_type& var, indices_) { | ||
|  |   	BOOST_FOREACH(size_t i, var.second) { | ||
|  |   		if(i >= factors_.size()) { | ||
|  |   			cout << "*** Factor graph inconsistency: " << (string)var.first << " lists factor " << | ||
|  |   					i << " but the graph does not contain this many factors." << endl; | ||
|  |   		} | ||
|  |   		if(factors_[i] == NULL) { | ||
|  |   			cout << "*** Factor graph inconsistency: " << (string)var.first << " lists factor " << | ||
|  |   					i << " but this factor is set to NULL." << endl; | ||
|  |   		} | ||
|  |     	list<Symbol> keys = factors_[i]->keys(); | ||
|  |   		if(std::find(keys.begin(), keys.end(), var.first) == keys.end()) { | ||
|  |   			cout << "*** Factor graph inconsistency: " << (string)var.first << " lists factor " << | ||
|  |   					i << " but this factor does not involve this variable." << endl; | ||
|  |   		} | ||
|  |   	} | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> template <class Key, class Factor2> | ||
|  | PredecessorMap<Key> FactorGraph<Factor>::findMinimumSpanningTree() const { | ||
|  | 
 | ||
|  | 	SDGraph<Key> g = gtsam::toBoostGraph<FactorGraph<Factor>, Factor2, Key>(*this); | ||
|  | 
 | ||
|  | 	// find minimum spanning tree
 | ||
|  | 	vector<typename SDGraph<Key>::Vertex> p_map(boost::num_vertices(g)); | ||
|  | 	prim_minimum_spanning_tree(g, &p_map[0]); | ||
|  | 
 | ||
|  | 	// convert edge to string pairs
 | ||
|  | 	PredecessorMap<Key> tree; | ||
|  | 	typename SDGraph<Key>::vertex_iterator itVertex = boost::vertices(g).first; | ||
|  | 	typename vector<typename SDGraph<Key>::Vertex>::iterator vi; | ||
|  | 	for (vi = p_map.begin(); vi!=p_map.end(); itVertex++, vi++) { | ||
|  | 		Key key = boost::get(boost::vertex_name, g, *itVertex); | ||
|  | 		Key parent = boost::get(boost::vertex_name, g, *vi); | ||
|  | 		tree.insert(key, parent); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return tree; | ||
|  | } | ||
|  | 
 | ||
|  | template<class Factor> template <class Key, class Factor2> | ||
|  | void FactorGraph<Factor>::split(const PredecessorMap<Key>& tree, FactorGraph<Factor>& Ab1, FactorGraph<Factor>& Ab2) const{ | ||
|  | 
 | ||
|  | 	BOOST_FOREACH(const sharedFactor& factor, factors_){ | ||
|  | 		if (factor->keys().size() > 2) | ||
|  | 			throw(invalid_argument("split: only support factors with at most two keys")); | ||
|  | 
 | ||
|  | 		if (factor->keys().size() == 1) { | ||
|  | 			Ab1.push_back(factor); | ||
|  | 			continue; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		boost::shared_ptr<Factor2> factor2 = boost::dynamic_pointer_cast<Factor2>(factor); | ||
|  | 		if (!factor2) continue; | ||
|  | 
 | ||
|  | 		Key key1 = factor2->key1(); | ||
|  | 		Key key2 = factor2->key2(); | ||
|  | 		// if the tree contains the key
 | ||
|  | 		if ((tree.find(key1) != tree.end() && tree.find(key1)->second.compare(key2) == 0) || | ||
|  | 			(tree.find(key2) != tree.end() && tree.find(key2)->second.compare(key1) == 0)) | ||
|  | 			Ab1.push_back(factor2); | ||
|  | 		else | ||
|  | 			Ab2.push_back(factor2); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | std::pair<FactorGraph<Factor>, FactorGraph<Factor> > FactorGraph<Factor>::splitMinimumSpanningTree() const { | ||
|  | 	//	create an empty factor graph T (tree) and factor graph C (constraints)
 | ||
|  | 	FactorGraph<Factor> T; | ||
|  | 	FactorGraph<Factor> C; | ||
|  | 	DSF<Symbol> dsf(keys()); | ||
|  | 
 | ||
|  | 	//	while G is nonempty and T is not yet spanning
 | ||
|  | 	for (size_t i=0;i<size();i++) { | ||
|  | 		const sharedFactor& f = factors_[i]; | ||
|  | 
 | ||
|  | 		// retrieve the labels of all the keys
 | ||
|  | 		set<Symbol> labels; | ||
|  | 		BOOST_FOREACH(const Symbol& key, f->keys()) | ||
|  | 			labels.insert(dsf.findSet(key)); | ||
|  | 
 | ||
|  | 		//	if that factor connects two different trees, then add it to T
 | ||
|  | 		if (labels.size() > 1) { | ||
|  | 			T.push_back(f); | ||
|  | 			set<Symbol>::const_iterator it = labels.begin(); | ||
|  | 			Symbol root = *it; | ||
|  | 			for (it++; it!=labels.end(); it++) | ||
|  | 				dsf = dsf.makeUnion(root, *it); | ||
|  | 		} else //	otherwise add that factor to C
 | ||
|  | 			C.push_back(f); | ||
|  | 	} | ||
|  | 	return make_pair(T,C); | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | /* find factors and remove them from the factor graph: O(n)                  */ | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> boost::shared_ptr<Factor> | ||
|  | removeAndCombineFactors(FactorGraph<Factor>& factorGraph, const Symbol& key) | ||
|  | { | ||
|  | 	typedef vector<boost::shared_ptr<Factor> > Factors; | ||
|  | 	Factors found = factorGraph.template findAndRemoveFactors<Factors>(key); | ||
|  | 	boost::shared_ptr<Factor> new_factor(new Factor(found)); | ||
|  | 	return new_factor; | ||
|  | } | ||
|  | 
 | ||
|  | /* ************************************************************************* */ | ||
|  | template<class Factor> | ||
|  | FactorGraph<Factor> combine(const FactorGraph<Factor>& fg1, const FactorGraph<Factor>& fg2) { | ||
|  | 	// create new linear factor graph equal to the first one
 | ||
|  | 	FactorGraph<Factor> fg = fg1; | ||
|  | 
 | ||
|  | 	// add the second factors_ in the graph
 | ||
|  | 	fg.push_back(fg2); | ||
|  | 
 | ||
|  | 	return fg; | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace gtsam
 |