Merged into trunk from branch combineandeliminate
parent
f661baacbb
commit
d9935519f9
|
|
@ -44,11 +44,11 @@ EliminationTree<FACTOR>::eliminate_(Conditionals& conditionals) const {
|
|||
factors.push_back(child->eliminate_(conditionals)); }
|
||||
|
||||
// Combine all factors (from this node and from subtrees) into a joint factor
|
||||
sharedFactor jointFactor(FACTOR::Combine(factors, VariableSlots(factors)));
|
||||
assert(jointFactor->front() == this->key_);
|
||||
conditionals[this->key_] = jointFactor->eliminateFirst();
|
||||
pair<typename BayesNet::shared_ptr, typename FACTOR::shared_ptr> eliminated(
|
||||
FACTOR::CombineAndEliminate(factors, 1));
|
||||
conditionals[this->key_] = eliminated.first->front();
|
||||
|
||||
return jointFactor;
|
||||
return eliminated.second;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
#include <gtsam/inference/FactorBase-inl.h>
|
||||
#include <gtsam/inference/IndexFactor.h>
|
||||
#include <gtsam/inference/VariableSlots.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
|
|
@ -25,6 +28,14 @@ template class FactorBase<Index>;
|
|||
|
||||
IndexFactor::IndexFactor(const IndexConditional& c) : Base(static_cast<const Base>(c)) {}
|
||||
|
||||
pair<typename BayesNet<IndexConditional>::shared_ptr, IndexFactor::shared_ptr> IndexFactor::CombineAndEliminate(
|
||||
const FactorGraph<This>& factors, size_t nrFrontals) {
|
||||
pair<typename BayesNet<Conditional>::shared_ptr, shared_ptr> result;
|
||||
result.second = Combine(factors, VariableSlots(factors));
|
||||
result.first = result.second->eliminate(nrFrontals);
|
||||
return result;
|
||||
}
|
||||
|
||||
IndexFactor::shared_ptr IndexFactor::Combine(
|
||||
const FactorGraph<This>& factors, const FastMap<Index, std::vector<Index> >& variableSlots) {
|
||||
return Base::Combine<This>(factors, variableSlots); }
|
||||
|
|
|
|||
|
|
@ -62,6 +62,12 @@ public:
|
|||
/** Construct n-way factor */
|
||||
IndexFactor(std::set<Index> js) : Base(js) {}
|
||||
|
||||
/**
|
||||
* Combine and eliminate several factors.
|
||||
*/
|
||||
static std::pair<typename BayesNet<Conditional>::shared_ptr, shared_ptr> CombineAndEliminate(
|
||||
const FactorGraph<This>& factors, size_t nrFrontals=1);
|
||||
|
||||
/** Create a combined joint factor (new style for EliminationTree). */
|
||||
static shared_ptr
|
||||
Combine(const FactorGraph<This>& factors, const FastMap<Index, std::vector<Index> >& variableSlots);
|
||||
|
|
|
|||
|
|
@ -163,41 +163,26 @@ namespace gtsam {
|
|||
|
||||
// eliminate the combined factors
|
||||
// warning: fg is being eliminated in-place and will contain marginal afterwards
|
||||
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.
|
||||
list<Index> allKeys;
|
||||
allKeys.insert(allKeys.end(), current->frontal.begin(), current->frontal.end());
|
||||
allKeys.insert(allKeys.end(), current->separator.begin(), current->separator.end());
|
||||
vector<Index> varslotsKeys(variableSlots.size());
|
||||
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::Combine(fg, variableSlots);
|
||||
toc("JT 2.2 Combine");
|
||||
tic("JT 2.3 Eliminate");
|
||||
typename BayesNet<typename FG::Factor::Conditional>::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.2 CombineAndEliminate");
|
||||
pair<typename BayesNet<typename FG::Factor::Conditional>::shared_ptr, typename FG::sharedFactor> eliminated(
|
||||
FG::Factor::CombineAndEliminate(fg, current->frontal.size()));
|
||||
toc("JT 2.2 CombineAndEliminate");
|
||||
|
||||
assert(std::equal(eliminated.second->begin(), eliminated.second->end(), current->separator.begin()));
|
||||
|
||||
tic("JT 2.4 Update tree");
|
||||
// create a new clique corresponding the combined factors
|
||||
typename BayesTree::sharedClique new_clique(new typename BayesTree::Clique(*fragment));
|
||||
typename BayesTree::sharedClique new_clique(new typename BayesTree::Clique(*eliminated.first));
|
||||
new_clique->children_ = children;
|
||||
|
||||
BOOST_FOREACH(typename BayesTree::sharedClique& childRoot, children)
|
||||
childRoot->parent_ = new_clique;
|
||||
|
||||
toc("JT 2.4 Update tree");
|
||||
return make_pair(new_clique, jointFactor);
|
||||
return make_pair(new_clique, eliminated.second);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
|
|
|||
|
|
@ -16,6 +16,14 @@
|
|||
* @author Christian Potthast
|
||||
*/
|
||||
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/base/FastMap.h>
|
||||
#include <gtsam/base/cholesky.h>
|
||||
#include <gtsam/linear/GaussianConditional.h>
|
||||
#include <gtsam/linear/GaussianFactor.h>
|
||||
#include <gtsam/linear/GaussianFactorGraph.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
|
@ -28,12 +36,9 @@
|
|||
#include <boost/numeric/ublas/io.hpp>
|
||||
#include <boost/numeric/ublas/matrix_proxy.hpp>
|
||||
#include <boost/numeric/ublas/vector_proxy.hpp>
|
||||
#include <boost/numeric/ublas/blas.hpp>
|
||||
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/linear/GaussianConditional.h>
|
||||
#include <gtsam/linear/GaussianFactor.h>
|
||||
#include <gtsam/linear/GaussianFactorGraph.h>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -313,6 +318,291 @@ GaussianFactor::sparse(const Dimensions& columnIndices) const {
|
|||
return boost::tuple<list<int>, list<int>, list<double> >(I,J,S);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactor GaussianFactor::whiten() const {
|
||||
GaussianFactor result(*this);
|
||||
result.model_->WhitenInPlace(result.matrix_);
|
||||
result.model_ = noiseModel::Unit::Create(result.model_->dim());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
struct SlotEntry {
|
||||
size_t slot;
|
||||
size_t dimension;
|
||||
SlotEntry(size_t _slot, size_t _dimension) : slot(_slot), dimension(_dimension) {}
|
||||
};
|
||||
|
||||
typedef FastMap<Index, SlotEntry> Scatter;
|
||||
|
||||
/* ************************************************************************* */
|
||||
static FastMap<Index, SlotEntry> findScatterAndDims(const FactorGraph<GaussianFactor>& factors) {
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
// The "scatter" is a map from global variable indices to slot indices in the
|
||||
// union of involved variables. We also include the dimensionality of the
|
||||
// variable.
|
||||
|
||||
Scatter scatter;
|
||||
|
||||
// First do the set union.
|
||||
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
|
||||
for(GaussianFactor::const_iterator variable = factor->begin(); variable != factor->end(); ++variable) {
|
||||
scatter.insert(make_pair(*variable, SlotEntry(0, factor->getDim(variable))));
|
||||
}
|
||||
}
|
||||
|
||||
// Next fill in the slot indices (we can only get these after doing the set
|
||||
// union.
|
||||
size_t slot = 0;
|
||||
BOOST_FOREACH(Scatter::value_type& var_slot, scatter) {
|
||||
var_slot.second.slot = (slot ++);
|
||||
if(debug)
|
||||
cout << "scatter[" << var_slot.first << "] = (slot " << var_slot.second.slot << ", dim " << var_slot.second.dimension << ")" << endl;
|
||||
}
|
||||
|
||||
return scatter;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
static MatrixColMajor formAbTAb(const FactorGraph<GaussianFactor>& factors, const Scatter& scatter) {
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
tic("CombineAndEliminate: 3.1 varStarts");
|
||||
// Determine scalar indices of each variable
|
||||
vector<size_t> varStarts;
|
||||
varStarts.reserve(scatter.size() + 2);
|
||||
varStarts.push_back(0);
|
||||
BOOST_FOREACH(const Scatter::value_type& var_slot, scatter) {
|
||||
varStarts.push_back(varStarts.back() + var_slot.second.dimension);
|
||||
}
|
||||
// This is for the r.h.s. vector
|
||||
varStarts.push_back(varStarts.back() + 1);
|
||||
toc("CombineAndEliminate: 3.1 varStarts");
|
||||
|
||||
// Allocate and zero matrix for Ab' * Ab
|
||||
MatrixColMajor ATA(ublas::zero_matrix<double>(varStarts.back(), varStarts.back()));
|
||||
|
||||
tic("CombineAndEliminate: 3.2 updates");
|
||||
// Do blockwise low-rank updates to Ab' * Ab for each factor. Here, we
|
||||
// only update the upper triangle because this is all that Cholesky uses.
|
||||
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) {
|
||||
|
||||
// Whiten the factor first so it has a unit diagonal noise model
|
||||
GaussianFactor whitenedFactor(factor->whiten());
|
||||
|
||||
if(debug) whitenedFactor.print("whitened factor: ");
|
||||
|
||||
for(GaussianFactor::const_iterator var2 = whitenedFactor.begin(); var2 != whitenedFactor.end(); ++var2) {
|
||||
assert(scatter.find(*var2) != scatter.end());
|
||||
size_t vj = scatter.find(*var2)->second.slot;
|
||||
for(GaussianFactor::const_iterator var1 = whitenedFactor.begin(); var1 <= var2; ++var1) {
|
||||
assert(scatter.find(*var1) != scatter.end());
|
||||
size_t vi = scatter.find(*var1)->second.slot;
|
||||
if(debug) cout << "Updating block " << vi << ", " << vj << endl;
|
||||
if(debug) cout << "Updating (" << varStarts[vi] << ":" << varStarts[vi+1] << ", " <<
|
||||
varStarts[vj] << ":" << varStarts[vj+1] << ") from A" << *var1 << "' * A" << *var2 << endl;
|
||||
ublas::project(ATA,
|
||||
ublas::range(varStarts[vi], varStarts[vi+1]), ublas::range(varStarts[vj], varStarts[vj+1])) +=
|
||||
ublas::prod(ublas::trans(whitenedFactor.getA(var1)), whitenedFactor.getA(var2));
|
||||
}
|
||||
}
|
||||
|
||||
// Update r.h.s. vector
|
||||
size_t vj = scatter.size();
|
||||
for(GaussianFactor::const_iterator var1 = whitenedFactor.begin(); var1 < whitenedFactor.end(); ++var1) {
|
||||
assert(scatter.find(*var1) != scatter.end());
|
||||
size_t vi = scatter.find(*var1)->second.slot;
|
||||
if(debug) cout << "Updating block " << vi << ", " << vj << endl;
|
||||
if(debug) cout << "Updating (" << varStarts[vi] << ":" << varStarts[vi+1] << ", " <<
|
||||
varStarts[vj] << ":" << varStarts[vj+1] << ") from A" << *var1 << "' * b" << endl;
|
||||
ublas::matrix_column<MatrixColMajor> col(ATA, varStarts[vj]);
|
||||
ublas::subrange(col, varStarts[vi], varStarts[vi+1]) +=
|
||||
ublas::prod(ublas::trans(whitenedFactor.getA(var1)), whitenedFactor.getb());
|
||||
}
|
||||
|
||||
size_t vi = scatter.size();
|
||||
if(debug) cout << "Updating block " << vi << ", " << vj << endl;
|
||||
if(debug) cout << "Updating (" << varStarts[vi] << ":" << varStarts[vi+1] << ", " <<
|
||||
varStarts[vj] << ":" << varStarts[vj+1] << ") from b" << "' * b" << endl;
|
||||
ATA(varStarts[vi], varStarts[vj]) += ublas::inner_prod(whitenedFactor.getb(), whitenedFactor.getb());
|
||||
}
|
||||
toc("CombineAndEliminate: 3.2 updates");
|
||||
|
||||
return ATA;
|
||||
}
|
||||
|
||||
GaussianBayesNet::shared_ptr GaussianFactor::splitEliminatedFactor(size_t nrFrontals, const vector<Index>& keys) {
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
const size_t maxrank = Ab_.size1();
|
||||
|
||||
// Check for rank-deficiency that would prevent back-substitution
|
||||
if(maxrank < Ab_.range(0, nrFrontals).size2()) {
|
||||
stringstream ss;
|
||||
ss << "Problem is rank-deficient, discovered while eliminating frontal variables";
|
||||
for(size_t i=0; i<nrFrontals; ++i)
|
||||
ss << " " << keys[i];
|
||||
throw invalid_argument(ss.str());
|
||||
}
|
||||
|
||||
if(debug) gtsam::print(Matrix(Ab_.range(0, Ab_.nBlocks())), "remaining Ab: ");
|
||||
|
||||
// Extract conditionals
|
||||
tic("CombineAndEliminate: 5.1 cond Rd");
|
||||
GaussianBayesNet::shared_ptr conditionals(new GaussianBayesNet());
|
||||
for(size_t j=0; j<nrFrontals; ++j) {
|
||||
// Temporarily restrict the matrix view to the conditional blocks of the
|
||||
// eliminated Ab_ matrix to create the GaussianConditional from it.
|
||||
size_t varDim = Ab_(0).size2();
|
||||
Ab_.rowEnd() = Ab_.rowStart() + varDim;
|
||||
|
||||
// Zero the entries below the diagonal (this relies on the matrix being
|
||||
// column-major).
|
||||
{
|
||||
ABlock remainingMatrix(Ab_.range(0, Ab_.nBlocks()));
|
||||
if(remainingMatrix.size1() > 1)
|
||||
for(size_t j = 0; j < remainingMatrix.size1() - 1; ++j)
|
||||
memset(&remainingMatrix(j+1, j), 0, sizeof(remainingMatrix(0,0)) * (remainingMatrix.size1() - j - 1));
|
||||
}
|
||||
|
||||
const ublas::scalar_vector<double> sigmas(varDim, 1.0);
|
||||
conditionals->push_back(boost::make_shared<Conditional>(keys.begin()+j, keys.end(), 1, Ab_, sigmas));
|
||||
if(debug) conditionals->back()->print("Extracted conditional: ");
|
||||
Ab_.rowStart() += varDim;
|
||||
Ab_.firstBlock() += 1;
|
||||
if(debug) cout << "rowStart = " << Ab_.rowStart() << ", rowEnd = " << Ab_.rowEnd() << endl;
|
||||
}
|
||||
toc("CombineAndEliminate: 5.1 cond Rd");
|
||||
|
||||
// Take lower-right block of Ab_ to get the new factor
|
||||
tic("CombineAndEliminate: 5.2 remaining factor");
|
||||
Ab_.rowEnd() = maxrank;
|
||||
|
||||
// Assign the keys
|
||||
keys_.assign(keys.begin() + nrFrontals, keys.end());
|
||||
|
||||
// Zero the entries below the diagonal (this relies on the matrix being
|
||||
// column-major).
|
||||
{
|
||||
ABlock remainingMatrix(Ab_.range(0, Ab_.nBlocks()));
|
||||
if(remainingMatrix.size1() > 1)
|
||||
for(size_t j = 0; j < remainingMatrix.size1() - 1; ++j)
|
||||
memset(&remainingMatrix(j+1, j), 0, sizeof(remainingMatrix(0,0)) * (remainingMatrix.size1() - j - 1));
|
||||
}
|
||||
|
||||
// Make a unit diagonal noise model
|
||||
model_ = noiseModel::Unit::Create(Ab_.size1());
|
||||
if(debug) this->print("Eliminated factor: ");
|
||||
toc("CombineAndEliminate: 5.2 remaining factor");
|
||||
|
||||
// todo SL: deal with "dead" pivot columns!!!
|
||||
tic("CombineAndEliminate: 5.3 rowstarts");
|
||||
size_t varpos = 0;
|
||||
firstNonzeroBlocks_.resize(numberOfRows());
|
||||
for(size_t row=0; row<numberOfRows(); ++row) {
|
||||
if(debug) cout << "row " << row << " varpos " << varpos << " Ab_.offset(varpos)=" << Ab_.offset(varpos) << " Ab_.offset(varpos+1)=" << Ab_.offset(varpos+1) << endl;
|
||||
while(varpos < keys_.size() && Ab_.offset(varpos+1) <= row)
|
||||
++ varpos;
|
||||
firstNonzeroBlocks_[row] = varpos;
|
||||
if(debug) cout << "firstNonzeroVars_[" << row << "] = " << firstNonzeroBlocks_[row] << endl;
|
||||
}
|
||||
toc("CombineAndEliminate: 5.3 rowstarts");
|
||||
|
||||
return conditionals;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
pair<GaussianBayesNet::shared_ptr, GaussianFactor::shared_ptr> GaussianFactor::CombineAndEliminate(
|
||||
const FactorGraph<GaussianFactor>& factors, size_t nrFrontals, SolveMethod solveMethod) {
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
SolveMethod correctedSolveMethod = solveMethod;
|
||||
|
||||
// Check for constrained noise models
|
||||
if(correctedSolveMethod != SOLVE_QR) {
|
||||
BOOST_FOREACH(const shared_ptr& factor, factors) {
|
||||
if(factor->model_->isConstrained()) {
|
||||
correctedSolveMethod = SOLVE_QR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(correctedSolveMethod == SOLVE_QR) {
|
||||
shared_ptr jointFactor(Combine(factors, VariableSlots(factors)));
|
||||
GaussianBayesNet::shared_ptr gbn(jointFactor->eliminate(nrFrontals, SOLVE_QR));
|
||||
return make_pair(gbn, jointFactor);
|
||||
} else if(correctedSolveMethod == SOLVE_CHOLESKY) {
|
||||
|
||||
// Find the scatter and variable dimensions
|
||||
tic("CombineAndEliminate: 1 find scatter");
|
||||
Scatter scatter(findScatterAndDims(factors));
|
||||
toc("CombineAndEliminate: 1 find scatter");
|
||||
|
||||
// Pull out keys and dimensions
|
||||
tic("CombineAndEliminate: 2 keys");
|
||||
vector<Index> keys(scatter.size());
|
||||
vector<size_t> dimensions(scatter.size() + 1);
|
||||
BOOST_FOREACH(const Scatter::value_type& var_slot, scatter) {
|
||||
keys[var_slot.second.slot] = var_slot.first;
|
||||
dimensions[var_slot.second.slot] = var_slot.second.dimension;
|
||||
}
|
||||
// This is for the r.h.s. vector
|
||||
dimensions.back() = 1;
|
||||
toc("CombineAndEliminate: 2 keys");
|
||||
|
||||
// Form Ab' * Ab
|
||||
tic("CombineAndEliminate: 3 Ab'*Ab");
|
||||
MatrixColMajor ATA(formAbTAb(factors, scatter));
|
||||
if(debug) gtsam::print(ATA, "Ab' * Ab: ");
|
||||
toc("CombineAndEliminate: 3 Ab'*Ab");
|
||||
|
||||
// Do Cholesky, note that after this, the lower triangle still contains
|
||||
// some untouched non-zeros that should be zero. We zero them while
|
||||
// extracting submatrices next.
|
||||
tic("CombineAndEliminate: 4 Cholesky careful");
|
||||
size_t maxrank = choleskyCareful(ATA);
|
||||
if(maxrank > ATA.size2() - 1)
|
||||
maxrank = ATA.size2() - 1;
|
||||
if(debug) {
|
||||
gtsam::print(ATA, "chol(Ab' * Ab): ");
|
||||
cout << "maxrank = " << maxrank << endl;
|
||||
}
|
||||
toc("CombineAndEliminate: 4 Cholesky careful");
|
||||
|
||||
// Create the remaining factor and swap in the matrix and block structure.
|
||||
// We declare a reference Ab to the block matrix in the remaining factor to
|
||||
// refer to below.
|
||||
GaussianFactor::shared_ptr remainingFactor(new GaussianFactor());
|
||||
BlockAb& Ab(remainingFactor->Ab_);
|
||||
{
|
||||
BlockAb newAb(ATA, dimensions.begin(), dimensions.end());
|
||||
newAb.rowEnd() = maxrank;
|
||||
newAb.swap(Ab);
|
||||
}
|
||||
|
||||
// Extract conditionals and fill in details of the remaining factor
|
||||
tic("CombineAndEliminate: 5 Split");
|
||||
GaussianBayesNet::shared_ptr conditionals(remainingFactor->splitEliminatedFactor(nrFrontals, keys));
|
||||
if(debug) {
|
||||
conditionals->print("Extracted conditionals: ");
|
||||
remainingFactor->print("Eliminated factor: ");
|
||||
}
|
||||
toc("CombineAndEliminate: 5 Split");
|
||||
|
||||
return make_pair(conditionals, remainingFactor);
|
||||
|
||||
} else {
|
||||
assert(false);
|
||||
return make_pair(GaussianBayesNet::shared_ptr(), shared_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditional::shared_ptr GaussianFactor::eliminateFirst(SolveMethod solveMethod) {
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace gtsam {
|
|||
protected:
|
||||
SharedDiagonal model_; // Gaussian noise model with diagonal covariance matrix
|
||||
std::vector<size_t> firstNonzeroBlocks_;
|
||||
AbMatrix matrix_; // the full matrix correponding to the factor
|
||||
AbMatrix matrix_; // the full matrix corresponding to the factor
|
||||
BlockAb Ab_; // the block view of the full matrix
|
||||
|
||||
public:
|
||||
|
|
@ -163,6 +163,13 @@ namespace gtsam {
|
|||
*/
|
||||
void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
/**
|
||||
* Whiten the matrix and r.h.s. so that the noise model is unit diagonal.
|
||||
* This throws an exception if the noise model cannot whiten, e.g. if it is
|
||||
* constrained.
|
||||
*/
|
||||
GaussianFactor whiten() const;
|
||||
|
||||
/**
|
||||
* Named constructor for combining a set of factors with pre-computed set of variables.
|
||||
*/
|
||||
|
|
@ -171,15 +178,19 @@ namespace gtsam {
|
|||
/**
|
||||
* Combine and eliminate several factors.
|
||||
*/
|
||||
// static std::pair<GaussianBayesNet::shared_ptr, shared_ptr> CombineAndEliminate(
|
||||
// const FactorGraph<GaussianFactor>& factors, const VariableSlots& variableSlots,
|
||||
// size_t nrFrontals=1, SolveMethod solveMethod = SOLVE_QR);
|
||||
static std::pair<GaussianBayesNet::shared_ptr, shared_ptr> CombineAndEliminate(
|
||||
const FactorGraph<GaussianFactor>& factors, size_t nrFrontals=1, SolveMethod solveMethod = SOLVE_QR);
|
||||
|
||||
protected:
|
||||
|
||||
/** Internal debug check to make sure variables are sorted */
|
||||
void assertInvariants() const;
|
||||
|
||||
/** Internal helper function to extract conditionals from a factor that was
|
||||
* just numerically eliminated.
|
||||
*/
|
||||
GaussianBayesNet::shared_ptr splitEliminatedFactor(size_t nrFrontals, const std::vector<Index>& keys);
|
||||
|
||||
public:
|
||||
|
||||
/** get a copy of sigmas */
|
||||
|
|
|
|||
|
|
@ -184,6 +184,55 @@ TEST(GaussianFactor, Combine2)
|
|||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactor, CombineAndEliminate)
|
||||
{
|
||||
Matrix A01 = Matrix_(3,3,
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
|
||||
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
|
||||
|
||||
Matrix A10 = Matrix_(3,3,
|
||||
2.0, 0.0, 0.0,
|
||||
0.0, 2.0, 0.0,
|
||||
0.0, 0.0, 2.0);
|
||||
Matrix A11 = Matrix_(3,3,
|
||||
-2.0, 0.0, 0.0,
|
||||
0.0, -2.0, 0.0,
|
||||
0.0, 0.0, -2.0);
|
||||
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
|
||||
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
|
||||
|
||||
Matrix A21 = Matrix_(3,3,
|
||||
3.0, 0.0, 0.0,
|
||||
0.0, 3.0, 0.0,
|
||||
0.0, 0.0, 3.0);
|
||||
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
|
||||
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
|
||||
|
||||
GaussianFactorGraph gfg;
|
||||
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true));
|
||||
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
|
||||
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
|
||||
|
||||
Matrix zero3x3 = zeros(3,3);
|
||||
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3);
|
||||
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21);
|
||||
Vector b = gtsam::concatVectors(3, &b1, &b0, &b2);
|
||||
Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2);
|
||||
|
||||
GaussianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
|
||||
GaussianBayesNet expectedBN(*expectedFactor.eliminate(1, GaussianFactor::SOLVE_QR));
|
||||
|
||||
pair<GaussianBayesNet::shared_ptr, GaussianFactor::shared_ptr> actual(
|
||||
GaussianFactor::CombineAndEliminate(gfg, 1, GaussianFactor::SOLVE_CHOLESKY));
|
||||
|
||||
EXPECT(assert_equal(expectedBN, *actual.first));
|
||||
EXPECT(assert_equal(expectedFactor, *actual.second));
|
||||
}
|
||||
|
||||
///* ************************************************************************* */
|
||||
//TEST( GaussianFactor, operators )
|
||||
//{
|
||||
|
|
|
|||
Loading…
Reference in New Issue