| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @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 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-07 02:25:04 +08:00
										 |  |  | #include <list>
 | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | #include <sstream>
 | 
					
						
							| 
									
										
										
										
											2009-11-18 05:47:42 +08:00
										 |  |  | #include <stdexcept>
 | 
					
						
							| 
									
										
										
										
											2009-11-20 22:18:26 +08:00
										 |  |  | #include <functional>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | #include <boost/foreach.hpp>
 | 
					
						
							|  |  |  | #include <boost/tuple/tuple.hpp>
 | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | #include <colamd/colamd.h>
 | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | #include "Ordering.h"
 | 
					
						
							|  |  |  | #include "FactorGraph.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-12 12:56:30 +08:00
										 |  |  | // trick from some reading group
 | 
					
						
							|  |  |  | #define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-23 05:33:00 +08:00
										 |  |  | using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-05 12:56:59 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 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++) { | 
					
						
							| 
									
										
										
										
											2009-11-08 03:31:39 +08:00
										 |  |  | 		sharedFactor factor(new Factor(*it)); | 
					
						
							| 
									
										
										
										
											2009-11-05 12:56:59 +08:00
										 |  |  | 		push_back(factor); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | template<class Factor> | 
					
						
							|  |  |  | void FactorGraph<Factor>::print(const string& s) const { | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 	cout << s << endl; | 
					
						
							|  |  |  | 	printf("size: %d\n", (int) size()); | 
					
						
							|  |  |  | 	for (int i = 0; i < factors_.size(); i++) { | 
					
						
							|  |  |  | 		stringstream ss; | 
					
						
							|  |  |  | 		ss << "factor " << i << ":"; | 
					
						
							|  |  |  | 		if (factors_[i] != NULL) factors_[i]->print(ss.str()); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | template<class Factor> | 
					
						
							|  |  |  | bool FactorGraph<Factor>::equals | 
					
						
							|  |  |  | 	(const FactorGraph<Factor>& fg, double tol) const { | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 	/** 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?
 | 
					
						
							| 
									
										
										
										
											2009-11-08 03:31:39 +08:00
										 |  |  | 		sharedFactor f1 = factors_[i], f2 = fg.factors_[i]; | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 		if (f1 == NULL && f2 == NULL) continue; | 
					
						
							|  |  |  | 		if (f1 == NULL || f2 == NULL) return false; | 
					
						
							|  |  |  | 		if (!f1->equals(*f2, tol)) return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | template<class Factor> | 
					
						
							|  |  |  | size_t FactorGraph<Factor>::nrFactors() const { | 
					
						
							|  |  |  | 	int size_ = 0; | 
					
						
							|  |  |  | 	for (const_iterator factor = factors_.begin(); factor != factors_.end(); factor++) | 
					
						
							|  |  |  | 		if (*factor != NULL) size_++; | 
					
						
							|  |  |  | 	return size_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | template<class Factor> | 
					
						
							| 
									
										
										
										
											2009-11-08 03:31:39 +08:00
										 |  |  | void FactorGraph<Factor>::push_back(sharedFactor factor) { | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | 	factors_.push_back(factor);                  // add the actual factor
 | 
					
						
							| 
									
										
										
										
											2009-10-29 12:49:13 +08:00
										 |  |  | 	if (factor==NULL) return; | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int i = factors_.size() - 1;                 // index of factor
 | 
					
						
							|  |  |  | 	list<string> keys = factor->keys();          // get keys for factor
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BOOST_FOREACH(string key, keys){             // for each key push i onto list
 | 
					
						
							| 
									
										
										
										
											2009-10-23 05:33:00 +08:00
										 |  |  | 		Indices::iterator it = indices_.find(key); // old list for that key (if exists)
 | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | 		if (it==indices_.end()){                   // there's no list yet
 | 
					
						
							|  |  |  | 			list<int> indices(1,i);                  // so make one
 | 
					
						
							|  |  |  | 			indices_.insert(make_pair(key,indices)); // insert new indices into factorMap
 | 
					
						
							| 
									
										
										
										
											2009-10-23 05:33:00 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | 		else { | 
					
						
							|  |  |  | 			list<int> *indices_ptr = &(it->second);  // get the list
 | 
					
						
							|  |  |  | 			indices_ptr->push_back(i);               // add the index i to it
 | 
					
						
							| 
									
										
										
										
											2009-10-23 05:33:00 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:34:07 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-12 12:56:30 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | template<class Factor> | 
					
						
							|  |  |  | Ordering FactorGraph<Factor>::keys() const { | 
					
						
							|  |  |  | 	Ordering keys; | 
					
						
							| 
									
										
										
										
											2009-11-20 22:18:26 +08:00
										 |  |  | 	transform(indices_.begin(), indices_.end(), | 
					
						
							|  |  |  | 			back_inserter(keys), _Select1st<Indices::value_type>()); | 
					
						
							| 
									
										
										
										
											2009-11-12 12:56:30 +08:00
										 |  |  | 	return keys; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-23 05:33:00 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * 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 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template <class Key> | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | Ordering colamd(int n_col, int n_row, int nrNonZeros, const map<Key, vector<int> >& columns) { | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Convert to compressed column major format colamd wants it in (== MATLAB format!)
 | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 	vector<Key> initialOrder; | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 	int Alen = nrNonZeros*30;     /* colamd arg 3: size of the array A TODO: use Tim's function ! */ | 
					
						
							|  |  |  | 	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 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p[0] = 0; | 
					
						
							|  |  |  | 	int j = 1; | 
					
						
							|  |  |  | 	int count = 0; | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 	typedef typename map<Key, vector<int> >::const_iterator iterator; | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 	for(iterator it = columns.begin(); it != columns.end(); it++) { | 
					
						
							|  |  |  | 		const Key& key = it->first; | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 		const vector<int>& column = it->second; | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 		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
 | 
					
						
							|  |  |  | 		j+=1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	double* knobs = NULL;    /* colamd arg 6: parameters (uses defaults if NULL) */ | 
					
						
							|  |  |  | 	int stats[COLAMD_STATS]; /* colamd arg 7: colamd output statistics and error codes */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// call colamd, result will be in p *************************************************
 | 
					
						
							|  |  |  | 	/* TODO: returns (1) if successful, (0) otherwise*/ | 
					
						
							|  |  |  | 	::colamd(n_row, n_col, Alen, A, p, knobs, stats); | 
					
						
							|  |  |  | 	// **********************************************************************************
 | 
					
						
							|  |  |  | 	delete [] A; // delete symbolic A
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Convert elimination ordering in p to an ordering
 | 
					
						
							|  |  |  | 	Ordering result; | 
					
						
							|  |  |  | 	for(int j = 0; j < n_col; j++) | 
					
						
							|  |  |  | 		result.push_back(initialOrder[j]); | 
					
						
							|  |  |  | 	delete [] p; // delete colamd result vector
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | template<class Factor> | 
					
						
							|  |  |  | Ordering FactorGraph<Factor>::getOrdering() const { | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 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.
 | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | 	typedef string Key;             // default case  with string keys
 | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 	map<Key, vector<int> > columns; // map from keys to a sparse column of non-zero row indices
 | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 	int nrNonZeros = 0;             // number of non-zero entries
 | 
					
						
							|  |  |  | 	int n_row = factors_.size();    /* colamd arg 1: number of rows in A */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// loop over all factors = rows
 | 
					
						
							|  |  |  | 	for (int i = 0; i < n_row; i++) { | 
					
						
							| 
									
										
										
										
											2009-10-28 04:22:02 +08:00
										 |  |  | 		if (factors_[i]==NULL) continue; | 
					
						
							| 
									
										
										
										
											2009-10-26 06:27:18 +08:00
										 |  |  | 		list<Key> keys = factors_[i]->keys(); | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | 		BOOST_FOREACH(Key key, keys) columns[key].push_back(i); | 
					
						
							|  |  |  | 		nrNonZeros+= keys.size(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	int n_col = (int)(columns.size()); /* colamd arg 2: number of columns in A */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(n_col == 0) | 
					
						
							|  |  |  | 		return Ordering(); // empty ordering
 | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return colamd(n_col, n_row, nrNonZeros, columns); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 12:49:13 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | /** O(1)                                                                     */ | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | template<class Factor> | 
					
						
							|  |  |  | list<int> FactorGraph<Factor>::factors(const string& key) const { | 
					
						
							|  |  |  | 	Indices::const_iterator it = indices_.find(key); | 
					
						
							|  |  |  | 	return it->second; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | /** find all non-NULL factors for a variable, then set factors to NULL       */ | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | template<class Factor> | 
					
						
							|  |  |  | vector<boost::shared_ptr<Factor> > | 
					
						
							| 
									
										
										
										
											2009-10-29 13:39:13 +08:00
										 |  |  | FactorGraph<Factor>::findAndRemoveFactors(const string& key) { | 
					
						
							| 
									
										
										
										
											2009-11-08 03:31:39 +08:00
										 |  |  | 	vector<sharedFactor> found; | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Indices::iterator it = indices_.find(key); | 
					
						
							|  |  |  | 	if (it == indices_.end()) | 
					
						
							| 
									
										
										
										
											2009-11-08 03:31:39 +08:00
										 |  |  | 		throw(invalid_argument | 
					
						
							| 
									
										
										
										
											2009-10-29 13:39:13 +08:00
										 |  |  | 				("FactorGraph::findAndRemoveFactors invalid key: " + key)); | 
					
						
							| 
									
										
										
										
											2009-10-29 12:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	list<int> *indices_ptr; // pointer to indices list in indices_ map
 | 
					
						
							|  |  |  | 	indices_ptr = &(it->second); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BOOST_FOREACH(int i, *indices_ptr) { | 
					
						
							|  |  |  | 		if(factors_[i] == NULL) continue; // skip NULL factors
 | 
					
						
							|  |  |  | 		found.push_back(factors_[i]);     // add to found
 | 
					
						
							|  |  |  | 		factors_[i].reset();              // set factor to NULL.
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return found; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 13:39:13 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | /* find factors and remove them from the factor graph: O(n)                  */ | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-11-11 13:12:45 +08:00
										 |  |  | template<class Factor> boost::shared_ptr<Factor> | 
					
						
							|  |  |  | removeAndCombineFactors(FactorGraph<Factor>& factorGraph, const string& key) | 
					
						
							| 
									
										
										
										
											2009-10-29 13:39:13 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-11 13:12:45 +08:00
										 |  |  | 	vector<boost::shared_ptr<Factor> > found = factorGraph.findAndRemoveFactors(key); | 
					
						
							|  |  |  | 	boost::shared_ptr<Factor> new_factor(new Factor(found)); | 
					
						
							| 
									
										
										
										
											2009-10-29 13:39:13 +08:00
										 |  |  | 	return new_factor; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-11-08 10:50:19 +08:00
										 |  |  | template<class Factor> | 
					
						
							|  |  |  | FactorGraph<Factor> combine(const FactorGraph<Factor>& fg1, const FactorGraph<Factor>& fg2) { | 
					
						
							|  |  |  | 	// create new linear factor graph equal to the first one
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:34:07 +08:00
										 |  |  | 	FactorGraph<Factor> fg = fg1; | 
					
						
							| 
									
										
										
										
											2009-11-08 10:50:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// add the second factors_ in the graph
 | 
					
						
							| 
									
										
										
										
											2009-11-19 14:34:07 +08:00
										 |  |  | 	fg.push_back(fg2); | 
					
						
							| 
									
										
										
										
											2009-11-08 10:50:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return fg; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-13 12:13:03 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | } |