Fixed bugs in iSAM2 leaf marginalization found in HMF testing - set of factors to remove, adding new leaf clique from remaining variables. Also relies on bug fix in BayesTree::removeClique a couple of commits ago.
parent
fe8fc6dd24
commit
72db4793c5
|
@ -792,6 +792,7 @@ void ISAM2::experimentalMarginalizeLeaves(const FastList<Key>& leafKeys)
|
|||
BOOST_FOREACH(Key key, leafKeys) {
|
||||
indices.insert(ordering_[key]);
|
||||
}
|
||||
FastSet<Index> origIndices = indices;
|
||||
|
||||
// For each clique containing variables to be marginalized, we need to
|
||||
// reeliminate the marginalized variables and add their linear contribution
|
||||
|
@ -823,7 +824,7 @@ void ISAM2::experimentalMarginalizeLeaves(const FastList<Key>& leafKeys)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Now loop over the indices
|
||||
// Now loop over the indices, the iterator jI is advanced inside the loop.
|
||||
FastSet<size_t> factorIndicesToRemove;
|
||||
GaussianFactorGraph factorsToAdd;
|
||||
for(FastSet<Index>::iterator jI = indices.begin(); jI != indices.end(); )
|
||||
|
@ -834,22 +835,19 @@ void ISAM2::experimentalMarginalizeLeaves(const FastList<Key>& leafKeys)
|
|||
FastMap<sharedClique,Index>::iterator clique_lastIndex = cliquesToMarginalize.find(nodes_[*jI]);
|
||||
assert(clique_lastIndex != cliquesToMarginalize.end()); // Assert that we indexed the clique
|
||||
|
||||
const size_t originalnFrontals = clique_lastIndex->first->conditional()->nrFrontals();
|
||||
|
||||
// Check that the clique has no children
|
||||
if(!clique_lastIndex->first->children().empty())
|
||||
throw MarginalizeNonleafException(ordering_.key(*jI), params_.keyFormatter);
|
||||
|
||||
// Mark factors to be removed
|
||||
BOOST_FOREACH(size_t i, variableIndex_[*jI]) {
|
||||
factorIndicesToRemove.insert(i);
|
||||
}
|
||||
|
||||
// Check that all previous variables in the clique are also being eliminated and no later ones.
|
||||
// At the same time, remove the indices marginalized with this clique from the indices set.
|
||||
// This is where the iterator j is advanced.
|
||||
size_t nFrontals = 0;
|
||||
{
|
||||
bool foundLast = false;
|
||||
BOOST_FOREACH(Index cliqueVar, *clique_lastIndex->first->conditional()) {
|
||||
BOOST_FOREACH(Index cliqueVar, clique_lastIndex->first->conditional()->frontals()) {
|
||||
if(!foundLast && indices.find(cliqueVar) == indices.end())
|
||||
throw MarginalizeNonleafException(ordering_.key(j), params_.keyFormatter);
|
||||
if(foundLast && indices.find(cliqueVar) != indices.end())
|
||||
|
@ -863,6 +861,10 @@ void ISAM2::experimentalMarginalizeLeaves(const FastList<Key>& leafKeys)
|
|||
}
|
||||
if(cliqueVar == clique_lastIndex->second)
|
||||
foundLast = true;
|
||||
// Mark factors to be removed
|
||||
BOOST_FOREACH(size_t i, variableIndex_[cliqueVar]) {
|
||||
factorIndicesToRemove.insert(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -876,11 +878,31 @@ void ISAM2::experimentalMarginalizeLeaves(const FastList<Key>& leafKeys)
|
|||
EliminateQR(cliqueGraph, nFrontals) :
|
||||
EliminatePreferCholesky(cliqueGraph, nFrontals);
|
||||
|
||||
// Now we discard the conditional part and add the marginal part back into
|
||||
// the graph. Also we need to rebuild the leaf clique using the marginal.
|
||||
|
||||
// Add the marginal into the factor graph
|
||||
factorsToAdd.push_back(eliminationResult.second);
|
||||
|
||||
// Get the parent of the clique to be removed
|
||||
sharedClique parent = clique_lastIndex->first->parent();
|
||||
|
||||
// Remove the clique
|
||||
this->removeClique(clique_lastIndex->first);
|
||||
|
||||
// Add a new leaf clique if necessary
|
||||
const size_t newnFrontals = originalnFrontals - nFrontals;
|
||||
if(newnFrontals > 0) {
|
||||
// Do the elimination for the new leaf clique
|
||||
GaussianFactorGraph newCliqueGraph;
|
||||
newCliqueGraph.push_back(eliminationResult.second);
|
||||
pair<Clique::sharedConditional, GaussianFactor::shared_ptr> newEliminationResult =
|
||||
params_.factorization==ISAM2Params::QR ?
|
||||
EliminateQR(newCliqueGraph, newnFrontals) :
|
||||
EliminatePreferCholesky(newCliqueGraph, newnFrontals);
|
||||
// Create and add the new clique
|
||||
this->addClique(ISAM2Clique::Create(newEliminationResult), parent);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any factors touching the marginalized-out variables
|
||||
|
@ -893,6 +915,7 @@ void ISAM2::experimentalMarginalizeLeaves(const FastList<Key>& leafKeys)
|
|||
if(params_.cacheLinearizedFactors)
|
||||
linearFactors_.remove(i);
|
||||
}
|
||||
variableIndex_.remove(removedFactorIndices, removedFactors);
|
||||
|
||||
// Add the new factors and fix linearization points of involved variables
|
||||
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factorsToAdd) {
|
||||
|
@ -907,7 +930,6 @@ void ISAM2::experimentalMarginalizeLeaves(const FastList<Key>& leafKeys)
|
|||
variableIndex_.augment(factorsToAdd); // Augment the variable index
|
||||
|
||||
// Remove the marginalized variables
|
||||
variableIndex_.remove(removedFactorIndices, removedFactors);
|
||||
Impl::RemoveVariables(FastSet<Key>(leafKeys.begin(), leafKeys.end()), root_, theta_, variableIndex_, delta_, deltaNewton_, RgProd_,
|
||||
deltaReplacedMask_, ordering_, nodes_, linearFactors_, fixedVariables_);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
#include <gtsam/base/LieVector.h>
|
||||
#include <gtsam/geometry/Point2.h>
|
||||
#include <gtsam/geometry/Pose2.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraph.h>
|
||||
|
@ -832,41 +833,99 @@ TEST(ISAM2, slamlike_solution_partial_relinearization_check)
|
|||
CHECK(isam_check(fullgraph, fullinit, isam, *this, result_));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST_UNSAFE(ISAM2, marginalizeLeaves)
|
||||
{
|
||||
// Create isam2
|
||||
ISAM2 isam = createSlamlikeISAM2();
|
||||
|
||||
// Get linearization point
|
||||
Values soln = isam.calculateBestEstimate();
|
||||
|
||||
// Calculate expected marginal
|
||||
GaussianFactorGraph isamAsGraph(isam);
|
||||
GaussianSequentialSolver solver(isamAsGraph);
|
||||
namespace {
|
||||
bool checkMarginalizeLeaves(ISAM2& isam, const FastList<Key>& leafKeys) {
|
||||
Matrix expectedAugmentedHessian, expected3AugmentedHessian;
|
||||
vector<Index> toKeep;
|
||||
const Index lastVar = isam.getOrdering().size() - 1;
|
||||
for(Index i=0; i<=lastVar; ++i)
|
||||
if(i != isam.getOrdering()[0])
|
||||
if(find(leafKeys.begin(), leafKeys.end(), isam.getOrdering().key(i)) == leafKeys.end())
|
||||
toKeep.push_back(i);
|
||||
GaussianFactorGraph marginalgfg = *solver.jointFactorGraph(toKeep);
|
||||
vector<Index> toFrontI;
|
||||
toFrontI.push_back(isam.getOrdering()[0]);
|
||||
Permutation toFront = Permutation::PullToFront(toFrontI, lastVar+1);
|
||||
marginalgfg.permuteWithInverse(*toFront.inverse());
|
||||
Matrix expectedAugmentedHessian = marginalgfg.augmentedHessian();
|
||||
|
||||
// Marginalize
|
||||
FastList<Key> marginalizeKeys;
|
||||
marginalizeKeys.push_back(isam.getOrdering().key(0));
|
||||
isam.experimentalMarginalizeLeaves(marginalizeKeys);
|
||||
// Calculate expected marginal from iSAM2 tree
|
||||
GaussianFactorGraph isamAsGraph(isam);
|
||||
GaussianSequentialSolver solver(isamAsGraph);
|
||||
GaussianFactorGraph marginalgfg = *solver.jointFactorGraph(toKeep);
|
||||
expectedAugmentedHessian = marginalgfg.augmentedHessian();
|
||||
|
||||
//// Calculate expected marginal from cached linear factors
|
||||
//assert(isam.params().cacheLinearizedFactors);
|
||||
//GaussianSequentialSolver solver2(isam.linearFactors_, isam.params().factorization == ISAM2Params::QR);
|
||||
//expected2AugmentedHessian = solver2.jointFactorGraph(toKeep)->augmentedHessian();
|
||||
|
||||
// Calculate expected marginal from original nonlinear factors
|
||||
GaussianSequentialSolver solver3(
|
||||
*isam.getFactorsUnsafe().linearize(isam.getLinearizationPoint(), isam.getOrdering()),
|
||||
isam.params().factorization == ISAM2Params::QR);
|
||||
expected3AugmentedHessian = solver3.jointFactorGraph(toKeep)->augmentedHessian();
|
||||
|
||||
// Do marginalization
|
||||
isam.experimentalMarginalizeLeaves(leafKeys);
|
||||
|
||||
// Check
|
||||
GaussianFactorGraph actualMarginalGraph(isam);
|
||||
Matrix actualAugmentedHessian = actualMarginalGraph.augmentedHessian();
|
||||
//Matrix actual2AugmentedHessian = linearFactors_.augmentedHessian();
|
||||
Matrix actual3AugmentedHessian = isam.getFactorsUnsafe().linearize(
|
||||
isam.getLinearizationPoint(), isam.getOrdering())->augmentedHessian();
|
||||
assert(actualAugmentedHessian.unaryExpr(std::ptr_fun(&std::isfinite<double>)).all());
|
||||
|
||||
LONGS_EQUAL(lastVar-1, isam.getOrdering().size()-1);
|
||||
EXPECT(assert_equal(expectedAugmentedHessian, actualAugmentedHessian));
|
||||
// Check full marginalization
|
||||
bool treeEqual = assert_equal(expectedAugmentedHessian, actualAugmentedHessian, 1e-6);
|
||||
//bool linEqual = assert_equal(expected2AugmentedHessian, actualAugmentedHessian, 1e-6);
|
||||
bool nonlinEqual = assert_equal(expected3AugmentedHessian, actualAugmentedHessian, 1e-6);
|
||||
//bool linCorrect = assert_equal(expected3AugmentedHessian, expected2AugmentedHessian, 1e-6);
|
||||
//actual2AugmentedHessian.bottomRightCorner(1,1) = expected3AugmentedHessian.bottomRightCorner(1,1); bool afterLinCorrect = assert_equal(expected3AugmentedHessian, actual2AugmentedHessian, 1e-6);
|
||||
actual3AugmentedHessian.bottomRightCorner(1,1) = expected3AugmentedHessian.bottomRightCorner(1,1); bool afterNonlinCorrect = assert_equal(expected3AugmentedHessian, actual3AugmentedHessian, 1e-6);
|
||||
|
||||
bool ok = treeEqual && /*linEqual &&*/ nonlinEqual && /*linCorrect &&*/ /*afterLinCorrect &&*/ afterNonlinCorrect;
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST_UNSAFE(ISAM2, marginalizeLeaves)
|
||||
{
|
||||
ISAM2 isam;
|
||||
|
||||
NonlinearFactorGraph factors;
|
||||
factors.add(PriorFactor<LieVector>(0, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
|
||||
factors.add(BetweenFactor<LieVector>(0, 1, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
factors.add(BetweenFactor<LieVector>(1, 2, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
factors.add(BetweenFactor<LieVector>(0, 2, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
|
||||
factors.add(BetweenFactor<LieVector>(2, 3, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
|
||||
factors.add(BetweenFactor<LieVector>(3, 4, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
factors.add(BetweenFactor<LieVector>(4, 5, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
factors.add(BetweenFactor<LieVector>(3, 5, LieVector(0.0), noiseModel::Unit::Create(1)));
|
||||
|
||||
Values values;
|
||||
values.insert(0, LieVector(0.0));
|
||||
values.insert(1, LieVector(0.0));
|
||||
values.insert(2, LieVector(0.0));
|
||||
values.insert(3, LieVector(0.0));
|
||||
values.insert(4, LieVector(0.0));
|
||||
values.insert(5, LieVector(0.0));
|
||||
|
||||
isam.update(factors, values);
|
||||
|
||||
FastList<Key> leafKeys;
|
||||
leafKeys.push_back(0);
|
||||
EXPECT(checkMarginalizeLeaves(isam, leafKeys));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST_UNSAFE(ISAM2, marginalizeLeaves2)
|
||||
{
|
||||
// Create isam2
|
||||
ISAM2 isam = createSlamlikeISAM2();
|
||||
|
||||
// Marginalize
|
||||
FastList<Key> marginalizeKeys;
|
||||
marginalizeKeys.push_back(isam.getOrdering().key(0));
|
||||
EXPECT(checkMarginalizeLeaves(isam, marginalizeKeys));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
|
Loading…
Reference in New Issue