| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2009-11-01 03:53:20 +08:00
										 |  |  |  * @file   GaussianBayesNet.cpp | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |  * @brief  Chordal Bayes Net, the result of eliminating a factor graph | 
					
						
							|  |  |  |  * @author Frank Dellaert | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <boost/foreach.hpp>
 | 
					
						
							|  |  |  | #include <boost/tuple/tuple.hpp>
 | 
					
						
							| 
									
										
										
										
											2009-10-27 22:14:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | #include <gtsam/base/Matrix-inl.h>
 | 
					
						
							| 
									
										
										
										
											2010-08-20 01:23:19 +08:00
										 |  |  | #include <gtsam/linear/GaussianBayesNet.h>
 | 
					
						
							|  |  |  | #include <gtsam/linear/VectorConfig.h>
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | using namespace std; | 
					
						
							|  |  |  | using namespace gtsam; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-30 12:54:11 +08:00
										 |  |  | // Explicitly instantiate so we don't have to include everywhere
 | 
					
						
							| 
									
										
										
										
											2010-08-20 01:23:19 +08:00
										 |  |  | #include <gtsam/inference/BayesNet-inl.h>
 | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | template class BayesNet<GaussianConditional>; | 
					
						
							| 
									
										
										
										
											2009-10-30 12:54:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | // trick from some reading group
 | 
					
						
							|  |  |  | #define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) 
 | 
					
						
							| 
									
										
										
										
											2009-11-02 11:50:30 +08:00
										 |  |  | #define REVERSE_FOREACH_PAIR( KEY, VAL, COL) BOOST_REVERSE_FOREACH (boost::tie(KEY,VAL),COL)
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | GaussianBayesNet scalarGaussian(varid_t key, double mu, double sigma) { | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | 	GaussianBayesNet bn; | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | 	GaussianConditional::shared_ptr | 
					
						
							| 
									
										
										
										
											2010-01-27 12:39:35 +08:00
										 |  |  | 		conditional(new GaussianConditional(key, Vector_(1,mu)/sigma, eye(1)/sigma, ones(1))); | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | 	bn.push_back(conditional); | 
					
						
							|  |  |  | 	return bn; | 
					
						
							| 
									
										
										
										
											2009-11-09 06:50:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | GaussianBayesNet simpleGaussian(varid_t key, const Vector& mu, double sigma) { | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | 	GaussianBayesNet bn; | 
					
						
							| 
									
										
										
										
											2009-11-09 06:50:26 +08:00
										 |  |  | 	size_t n = mu.size(); | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | 	GaussianConditional::shared_ptr | 
					
						
							| 
									
										
										
										
											2010-01-27 12:39:35 +08:00
										 |  |  | 		conditional(new GaussianConditional(key, mu/sigma, eye(n)/sigma, ones(n))); | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | 	bn.push_back(conditional); | 
					
						
							|  |  |  | 	return bn; | 
					
						
							| 
									
										
										
										
											2009-11-09 06:50:26 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-11-12 14:09:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | void push_front(GaussianBayesNet& bn, varid_t key, Vector d, Matrix R, | 
					
						
							|  |  |  | 		varid_t name1, Matrix S, Vector sigmas) { | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | 	GaussianConditional::shared_ptr cg(new GaussianConditional(key, d, R, name1, S, sigmas)); | 
					
						
							| 
									
										
										
										
											2009-11-12 14:09:03 +08:00
										 |  |  | 	bn.push_front(cg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | void push_front(GaussianBayesNet& bn, varid_t key, Vector d, Matrix R, | 
					
						
							|  |  |  | 		varid_t name1, Matrix S, varid_t name2, Matrix T, Vector sigmas) { | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | 	GaussianConditional::shared_ptr cg(new GaussianConditional(key, d, R, name1, S, name2, T, sigmas)); | 
					
						
							| 
									
										
										
										
											2009-11-12 14:09:03 +08:00
										 |  |  | 	bn.push_front(cg); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-11-09 06:50:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | boost::shared_ptr<VectorConfig> allocateVectorConfig(const GaussianBayesNet& bn) { | 
					
						
							|  |  |  |   vector<size_t> dimensions(bn.size()); | 
					
						
							|  |  |  |   varid_t var = 0; | 
					
						
							|  |  |  |   BOOST_FOREACH(const boost::shared_ptr<const GaussianConditional> conditional, bn) { | 
					
						
							|  |  |  |     dimensions[var++] = conditional->get_R().size1(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return boost::shared_ptr<VectorConfig>(new VectorConfig(dimensions)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 06:50:26 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | VectorConfig optimize(const GaussianBayesNet& bn) | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-01-19 18:46:12 +08:00
										 |  |  |   return *optimize_(bn); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | boost::shared_ptr<VectorConfig> optimize_(const GaussianBayesNet& bn) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	boost::shared_ptr<VectorConfig> result(allocateVectorConfig(bn)); | 
					
						
							| 
									
										
										
										
											2010-01-19 18:46:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |   /** solve each node in turn in topological sort order (parents first)*/ | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | 	BOOST_REVERSE_FOREACH(GaussianConditional::shared_ptr cg, bn) { | 
					
						
							| 
									
										
										
										
											2010-01-19 18:46:12 +08:00
										 |  |  |     Vector x = cg->solve(*result); // Solve for that variable
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     (*result)[cg->key()] = x;   // store result in partial solution
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-09 10:37:58 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | VectorConfig backSubstitute(const GaussianBayesNet& bn, const VectorConfig& y) { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	VectorConfig x(y); | 
					
						
							| 
									
										
										
										
											2010-01-31 12:39:41 +08:00
										 |  |  | 	backSubstituteInPlace(bn,x); | 
					
						
							|  |  |  | 	return x; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas)
 | 
					
						
							|  |  |  | void backSubstituteInPlace(const GaussianBayesNet& bn, VectorConfig& y) { | 
					
						
							|  |  |  | 	VectorConfig& x = y; | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 	/** solve each node in turn in topological sort order (parents first)*/ | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	BOOST_REVERSE_FOREACH(const boost::shared_ptr<const GaussianConditional> cg, bn) { | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 		// i^th part of R*x=y, x=inv(R)*y
 | 
					
						
							|  |  |  | 		// (Rii*xi + R_i*x(i+1:))./si = yi <-> xi = inv(Rii)*(yi.*si - R_i*x(i+1:))
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		varid_t i = cg->key(); | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 		Vector zi = emul(y[i],cg->get_sigmas()); | 
					
						
							|  |  |  | 		GaussianConditional::const_iterator it; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		for (it = cg->beginParents(); it!= cg->endParents(); it++) { | 
					
						
							|  |  |  | 			multiplyAdd(-1.0,cg->get_S(it),x[*it],zi); | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-02-17 11:29:12 +08:00
										 |  |  | 		x[i] = gtsam::backSubstituteUpper(cg->get_R(), zi); | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-09 10:37:58 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // gy=inv(L)*gx by solving L*gy=gx.
 | 
					
						
							|  |  |  | // gy=inv(R'*inv(Sigma))*gx
 | 
					
						
							|  |  |  | // gz'*R'=gx', gy = gz.*sigmas
 | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | VectorConfig backSubstituteTranspose(const GaussianBayesNet& bn, | 
					
						
							|  |  |  | 		const VectorConfig& gx) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize gy from gx
 | 
					
						
							| 
									
										
										
										
											2010-02-17 11:29:12 +08:00
										 |  |  | 	// TODO: used to insert zeros if gx did not have an entry for a variable in bn
 | 
					
						
							|  |  |  | 	VectorConfig gy = gx; | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// we loop from first-eliminated to last-eliminated
 | 
					
						
							|  |  |  | 	// i^th part of L*gy=gx is done block-column by block-column of L
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	BOOST_FOREACH(const boost::shared_ptr<const GaussianConditional> cg, bn) { | 
					
						
							|  |  |  | 		varid_t j = cg->key(); | 
					
						
							| 
									
										
										
										
											2010-02-17 11:29:12 +08:00
										 |  |  | 		gy[j] = gtsam::backSubstituteUpper(gy[j],cg->get_R()); | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 		GaussianConditional::const_iterator it; | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		for (it = cg->beginParents(); it!= cg->endParents(); it++) { | 
					
						
							|  |  |  | 			const varid_t i = *it; | 
					
						
							|  |  |  | 			transposeMultiplyAdd(-1.0,cg->get_S(it),gy[j],gy[i]); | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Scale gy
 | 
					
						
							|  |  |  | 	BOOST_FOREACH(GaussianConditional::shared_ptr cg, bn) { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 		varid_t j = cg->key(); | 
					
						
							| 
									
										
										
										
											2010-02-17 11:29:12 +08:00
										 |  |  | 		gy[j] = emul(gy[j],cg->get_sigmas()); | 
					
						
							| 
									
										
										
										
											2009-12-31 01:13:24 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return gy; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | /* ************************************************************************* */   | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | pair<Matrix,Vector> matrix(const GaussianBayesNet& bn)  { | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // add the dimensions of all variables to get matrix dimension
 | 
					
						
							|  |  |  |   // and at the same time create a mapping from keys to indices
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |   size_t N=0; map<varid_t,size_t> mapping; | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  |   BOOST_FOREACH(GaussianConditional::shared_ptr cg,bn) { | 
					
						
							| 
									
										
										
										
											2009-11-02 11:50:30 +08:00
										 |  |  |     mapping.insert(make_pair(cg->key(),N)); | 
					
						
							|  |  |  |     N += cg->dim(); | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // create matrix and copy in values
 | 
					
						
							|  |  |  |   Matrix R = zeros(N,N); | 
					
						
							|  |  |  |   Vector d(N); | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |   varid_t key; size_t I; | 
					
						
							| 
									
										
										
										
											2009-11-02 11:50:30 +08:00
										 |  |  |   FOREACH_PAIR(key,I,mapping) { | 
					
						
							|  |  |  |     // find corresponding conditional
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     boost::shared_ptr<const GaussianConditional> cg = bn[key]; | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2010-01-05 22:14:49 +08:00
										 |  |  |     // get sigmas
 | 
					
						
							|  |  |  |     Vector sigmas = cg->get_sigmas(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |     // get RHS and copy to d
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     GaussianConditional::const_d_type d_ = cg->get_d(); | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |     const size_t n = d_.size(); | 
					
						
							|  |  |  |     for (size_t i=0;i<n;i++) | 
					
						
							| 
									
										
										
										
											2010-01-05 22:14:49 +08:00
										 |  |  |       d(I+i) = d_(i)/sigmas(i); | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // get leading R matrix and copy to R
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     GaussianConditional::const_r_type R_ = cg->get_R(); | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |     for (size_t i=0;i<n;i++) | 
					
						
							|  |  |  |       for(size_t j=0;j<n;j++) | 
					
						
							| 
									
										
										
										
											2010-01-05 22:14:49 +08:00
										 |  |  |       	R(I+i,I+j) = R_(i,j)/sigmas(i); | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // loop over S matrices and copy them into R
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     GaussianConditional::const_iterator keyS = cg->beginParents(); | 
					
						
							|  |  |  |     for (; keyS!=cg->endParents(); keyS++) { | 
					
						
							|  |  |  |       Matrix S = cg->get_S(keyS);                   // get S matrix
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |       const size_t m = S.size1(), n = S.size2(); // find S size
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |       const size_t J = mapping[*keyS];     // find column index
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |       for (size_t i=0;i<m;i++) | 
					
						
							| 
									
										
										
										
											2009-11-02 11:50:30 +08:00
										 |  |  |       	for(size_t j=0;j<n;j++) | 
					
						
							| 
									
										
										
										
											2010-01-05 22:14:49 +08:00
										 |  |  |       		R(I+i,J+j) = S(i,j)/sigmas(i); | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  |     } // keyS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   } // keyI
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return make_pair(R,d); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-08 11:56:49 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | VectorConfig rhs(const GaussianBayesNet& bn) { | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  | 	boost::shared_ptr<VectorConfig> result(allocateVectorConfig(bn)); | 
					
						
							|  |  |  |   BOOST_FOREACH(boost::shared_ptr<const GaussianConditional> cg,bn) { | 
					
						
							|  |  |  |   	varid_t key = cg->key(); | 
					
						
							| 
									
										
										
										
											2010-03-08 11:56:49 +08:00
										 |  |  |   	// get sigmas
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     const Vector& sigmas = cg->get_sigmas(); | 
					
						
							| 
									
										
										
										
											2010-03-08 11:56:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // get RHS and copy to d
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |     GaussianConditional::const_d_type d = cg->get_d(); | 
					
						
							|  |  |  |     (*result)[key] = ediv_(d,sigmas); // TODO ediv_? I think not
 | 
					
						
							| 
									
										
										
										
											2010-03-08 11:56:49 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-09 06:04:47 +08:00
										 |  |  |   return *result; | 
					
						
							| 
									
										
										
										
											2010-03-08 11:56:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-22 06:23:24 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2009-11-09 15:04:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | } // namespace gtsam
 |