From d6929d44099f69b3fc7ea2cd570f9657d3045a91 Mon Sep 17 00:00:00 2001 From: Richard Roberts Date: Mon, 15 Nov 2010 23:01:50 +0000 Subject: [PATCH] Storing variable index in solver, saved between nonlinear iterations --- gtsam/inference/EliminationTree-inl.h | 1 + .../inference/GenericMultifrontalSolver-inl.h | 21 +- gtsam/inference/GenericMultifrontalSolver.h | 29 +- gtsam/inference/GenericSequentialSolver-inl.h | 35 ++- gtsam/inference/GenericSequentialSolver.h | 26 +- gtsam/inference/JunctionTree-inl.h | 269 +++++++++--------- gtsam/inference/JunctionTree.h | 17 +- gtsam/inference/tests/testJunctionTree.cpp | 1 + gtsam/linear/GaussianFactorGraph.cpp | 18 -- gtsam/linear/GaussianFactorGraph.h | 7 - gtsam/linear/GaussianJunctionTree.h | 6 +- gtsam/linear/GaussianMultifrontalSolver.cpp | 24 +- gtsam/linear/GaussianMultifrontalSolver.h | 21 +- gtsam/linear/GaussianSequentialSolver.cpp | 22 +- gtsam/linear/GaussianSequentialSolver.h | 19 +- gtsam/linear/SubgraphSolver-inl.h | 8 +- gtsam/linear/SubgraphSolver.h | 4 +- gtsam/nonlinear/NonlinearOptimizer-inl.h | 21 +- gtsam/nonlinear/NonlinearOptimizer.h | 2 +- tests/testGaussianFactorGraph.cpp | 30 +- 20 files changed, 354 insertions(+), 227 deletions(-) diff --git a/gtsam/inference/EliminationTree-inl.h b/gtsam/inference/EliminationTree-inl.h index 3e797ee1e..04374bfd3 100644 --- a/gtsam/inference/EliminationTree-inl.h +++ b/gtsam/inference/EliminationTree-inl.h @@ -4,6 +4,7 @@ * @author Frank Dellaert * @created Oct 13, 2010 */ +#pragma once #include #include diff --git a/gtsam/inference/GenericMultifrontalSolver-inl.h b/gtsam/inference/GenericMultifrontalSolver-inl.h index b60ed6d18..dc9e67ad2 100644 --- a/gtsam/inference/GenericMultifrontalSolver-inl.h +++ b/gtsam/inference/GenericMultifrontalSolver-inl.h @@ -33,14 +33,31 @@ namespace gtsam { /* ************************************************************************* */ template GenericMultifrontalSolver::GenericMultifrontalSolver(const FactorGraph& factorGraph) : - junctionTree_(factorGraph) {} + structure_(new VariableIndex(factorGraph)), junctionTree_(new JUNCTIONTREE(factorGraph, *structure_)) {} + +/* ************************************************************************* */ +template +GenericMultifrontalSolver::GenericMultifrontalSolver(const typename FactorGraph::shared_ptr& factorGraph) : + structure_(new VariableIndex(*factorGraph)), junctionTree_(new JUNCTIONTREE(*factorGraph, *structure_)) {} + +/* ************************************************************************* */ +template +GenericMultifrontalSolver::GenericMultifrontalSolver( + const typename FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex) : + structure_(variableIndex), junctionTree_(new JUNCTIONTREE(*factorGraph, *structure_)) {} + +/* ************************************************************************* */ +template +void GenericMultifrontalSolver::replaceFactors(const typename FactorGraph::shared_ptr& factorGraph) { + junctionTree_.reset(new JUNCTIONTREE(*factorGraph, *structure_)); +} /* ************************************************************************* */ template typename JUNCTIONTREE::BayesTree::shared_ptr GenericMultifrontalSolver::eliminate() const { typename JUNCTIONTREE::BayesTree::shared_ptr bayesTree(new typename JUNCTIONTREE::BayesTree); - bayesTree->insert(junctionTree_.eliminate()); + bayesTree->insert(junctionTree_->eliminate()); return bayesTree; } diff --git a/gtsam/inference/GenericMultifrontalSolver.h b/gtsam/inference/GenericMultifrontalSolver.h index e68505a76..d23773b52 100644 --- a/gtsam/inference/GenericMultifrontalSolver.h +++ b/gtsam/inference/GenericMultifrontalSolver.h @@ -31,17 +31,40 @@ class GenericMultifrontalSolver { protected: + // Column structure of the factor graph + VariableIndex::shared_ptr structure_; + // Junction tree that performs elimination. - JUNCTIONTREE junctionTree_; + typename JUNCTIONTREE::shared_ptr junctionTree_; public: /** - * Construct the solver for a factor graph. This builds the elimination - * tree, which already does some of the symbolic work of elimination. + * Construct the solver for a factor graph. This builds the junction + * tree, which already does some of the work of elimination. */ GenericMultifrontalSolver(const FactorGraph& factorGraph); + /** + * Construct the solver for a factor graph. This builds the junction + * tree, which already does some of the work of elimination. + */ + GenericMultifrontalSolver(const typename FactorGraph::shared_ptr& factorGraph); + + /** + * Construct the solver with a shared pointer to a factor graph and to a + * VariableIndex. The solver will store these pointers, so this constructor + * is the fastest. + */ + GenericMultifrontalSolver(const typename FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex); + + /** + * Replace the factor graph with a new one having the same structure. The + * This function can be used if the numerical part of the factors changes, + * such as during relinearization or adjusting of noise models. + */ + void replaceFactors(const typename FactorGraph::shared_ptr& factorGraph); + /** * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. diff --git a/gtsam/inference/GenericSequentialSolver-inl.h b/gtsam/inference/GenericSequentialSolver-inl.h index cdd67041f..1530113d7 100644 --- a/gtsam/inference/GenericSequentialSolver-inl.h +++ b/gtsam/inference/GenericSequentialSolver-inl.h @@ -31,9 +31,30 @@ namespace gtsam { /* ************************************************************************* */ template GenericSequentialSolver::GenericSequentialSolver(const FactorGraph& factorGraph) : - structure_(factorGraph), - eliminationTree_(EliminationTree::Create(factorGraph, structure_)) { - factors_.push_back(factorGraph); + factors_(new FactorGraph(factorGraph)), structure_(new VariableIndex(factorGraph)), + eliminationTree_(EliminationTree::Create(*factors_, *structure_)) {} + +/* ************************************************************************* */ +template +GenericSequentialSolver::GenericSequentialSolver(const typename FactorGraph::shared_ptr& factorGraph) : + factors_(factorGraph), structure_(new VariableIndex(*factorGraph)), + eliminationTree_(EliminationTree::Create(*factors_, *structure_)) {} + +/* ************************************************************************* */ +template +GenericSequentialSolver::GenericSequentialSolver(const typename FactorGraph::shared_ptr& factorGraph, + const VariableIndex::shared_ptr& variableIndex) : + factors_(factorGraph), structure_(variableIndex), + eliminationTree_(EliminationTree::Create(*factors_, *structure_)) {} + +/* ************************************************************************* */ +template +void GenericSequentialSolver::replaceFactors(const typename FactorGraph::shared_ptr& factorGraph) { + // Reset this shared pointer first to deallocate if possible - for big + // problems there may not be enough memory to store two copies. + eliminationTree_.reset(); + factors_ = factorGraph; + eliminationTree_ = EliminationTree::Create(*factors_, *structure_); } /* ************************************************************************* */ @@ -47,23 +68,23 @@ template typename FactorGraph::shared_ptr GenericSequentialSolver::jointFactorGraph(const std::vector& js) const { // Compute a COLAMD permutation with the marginal variable constrained to the end. - Permutation::shared_ptr permutation(Inference::PermutationCOLAMD(structure_, js)); + Permutation::shared_ptr permutation(Inference::PermutationCOLAMD(*structure_, js)); Permutation::shared_ptr permutationInverse(permutation->inverse()); // Permute the factors - NOTE that this permutes the original factors, not // copies. Other parts of the code may hold shared_ptr's to these factors so // we must undo the permutation before returning. - BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, factors_) { + BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, *factors_) { if(factor) factor->permuteWithInverse(*permutationInverse); } // Eliminate all variables typename BayesNet::shared_ptr bayesNet( - EliminationTree::Create(factors_)->eliminate()); + EliminationTree::Create(*factors_)->eliminate()); // Undo the permuation on the original factors and on the structure. - BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, factors_) { + BOOST_FOREACH(const typename FACTOR::shared_ptr& factor, *factors_) { if(factor) factor->permuteWithInverse(*permutation); } diff --git a/gtsam/inference/GenericSequentialSolver.h b/gtsam/inference/GenericSequentialSolver.h index c606013a6..b1671261e 100644 --- a/gtsam/inference/GenericSequentialSolver.h +++ b/gtsam/inference/GenericSequentialSolver.h @@ -32,10 +32,10 @@ class GenericSequentialSolver { protected: // Store the original factors for computing marginals - FactorGraph factors_; + typename FactorGraph::shared_ptr factors_; // Column structure of the factor graph - VariableIndex structure_; + VariableIndex::shared_ptr structure_; // Elimination tree that performs elimination. typename EliminationTree::shared_ptr eliminationTree_; @@ -44,10 +44,30 @@ public: /** * Construct the solver for a factor graph. This builds the elimination - * tree, which already does some of the symbolic work of elimination. + * tree, which already does some of the work of elimination. */ GenericSequentialSolver(const FactorGraph& factorGraph); + /** + * Construct the solver for a factor graph. This builds the elimination + * tree, which already does some of the work of elimination. + */ + GenericSequentialSolver(const typename FactorGraph::shared_ptr& factorGraph); + + /** + * Construct the solver with a shared pointer to a factor graph and to a + * VariableIndex. The solver will store these pointers, so this constructor + * is the fastest. + */ + GenericSequentialSolver(const typename FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex); + + /** + * Replace the factor graph with a new one having the same structure. The + * This function can be used if the numerical part of the factors changes, + * such as during relinearization or adjusting of noise models. + */ + void replaceFactors(const typename FactorGraph::shared_ptr& factorGraph); + /** * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. diff --git a/gtsam/inference/JunctionTree-inl.h b/gtsam/inference/JunctionTree-inl.h index bfb1252e6..b1f54c4c6 100644 --- a/gtsam/inference/JunctionTree-inl.h +++ b/gtsam/inference/JunctionTree-inl.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -35,129 +35,136 @@ namespace gtsam { - using namespace std; - - /* ************************************************************************* */ - template - JunctionTree::JunctionTree(const FG& fg) { - tic("JT 1 constructor"); - // Symbolic factorization: GaussianFactorGraph -> SymbolicFactorGraph - // -> SymbolicBayesNet -> SymbolicBayesTree - tic("JT 1.1 symbolic elimination"); - SymbolicBayesNet::shared_ptr sbn = SymbolicSequentialSolver(fg).eliminate(); -// SymbolicFactorGraph sfg(fg); -// SymbolicBayesNet::shared_ptr sbn_orig = Inference::Eliminate(sfg); -// assert(assert_equal(*sbn, *sbn_orig)); - toc("JT 1.1 symbolic elimination"); - tic("JT 1.2 symbolic BayesTree"); - SymbolicBayesTree sbt(*sbn); - toc("JT 1.2 symbolic BayesTree"); - - // distribute factors - tic("JT 1.3 distributeFactors"); - this->root_ = distributeFactors(fg, sbt.root()); - toc("JT 1.3 distributeFactors"); - toc("JT 1 constructor"); - } - - /* ************************************************************************* */ - template - typename JunctionTree::sharedClique JunctionTree::distributeFactors( - const FG& fg, const typename SymbolicBayesTree::sharedClique& bayesClique) { - - // Build "target" index. This is an index for each variable of the factors - // that involve this variable as their *lowest-ordered* variable. For each - // factor, it is the lowest-ordered variable of that factor that pulls the - // factor into elimination, after which all of the information in the - // factor is contained in the eliminated factors that are passed up the - // tree as elimination continues. - - // Two stages - first build an array of the lowest-ordered variable in each - // factor and find the last variable to be eliminated. - vector lowestOrdered(fg.size()); - Index maxVar = 0; - for(size_t i=0; ibegin(), fg[i]->end()); - if(min == fg[i]->end()) - lowestOrdered[i] = numeric_limits::max(); - else { - lowestOrdered[i] = *min; - maxVar = std::max(maxVar, *min); - } - } - - // Now add each factor to the list corresponding to its lowest-ordered - // variable. - vector > > targets(maxVar+1); - for(size_t i=0; i::max()) - targets[lowestOrdered[i]].push_back(i); - - // Now call the recursive distributeFactors - return distributeFactors(fg, targets, bayesClique); - } + using namespace std; /* ************************************************************************* */ - template - typename JunctionTree::sharedClique JunctionTree::distributeFactors(const FG& fg, - const std::vector > >& targets, + template + void JunctionTree::construct(const FG& fg, const VariableIndex& variableIndex) { + tic("JT 1 constructor"); + tic("JT 1.1 symbolic elimination"); + SymbolicBayesNet::shared_ptr sbn = EliminationTree::Create(fg, variableIndex)->eliminate(); + toc("JT 1.1 symbolic elimination"); + tic("JT 1.2 symbolic BayesTree"); + SymbolicBayesTree sbt(*sbn); + toc("JT 1.2 symbolic BayesTree"); + + // distribute factors + tic("JT 1.3 distributeFactors"); + this->root_ = distributeFactors(fg, sbt.root()); + toc("JT 1.3 distributeFactors"); + toc("JT 1 constructor"); + } + + /* ************************************************************************* */ + template + JunctionTree::JunctionTree(const FG& fg) { + construct(fg, VariableIndex(fg)); + } + + /* ************************************************************************* */ + template + JunctionTree::JunctionTree(const FG& fg, const VariableIndex& variableIndex) { + construct(fg, variableIndex); + } + + /* ************************************************************************* */ + template + typename JunctionTree::sharedClique JunctionTree::distributeFactors( + const FG& fg, const typename SymbolicBayesTree::sharedClique& bayesClique) { + + // Build "target" index. This is an index for each variable of the factors + // that involve this variable as their *lowest-ordered* variable. For each + // factor, it is the lowest-ordered variable of that factor that pulls the + // factor into elimination, after which all of the information in the + // factor is contained in the eliminated factors that are passed up the + // tree as elimination continues. + + // Two stages - first build an array of the lowest-ordered variable in each + // factor and find the last variable to be eliminated. + vector lowestOrdered(fg.size()); + Index maxVar = 0; + for(size_t i=0; ibegin(), fg[i]->end()); + if(min == fg[i]->end()) + lowestOrdered[i] = numeric_limits::max(); + else { + lowestOrdered[i] = *min; + maxVar = std::max(maxVar, *min); + } + } + + // Now add each factor to the list corresponding to its lowest-ordered + // variable. + vector > > targets(maxVar+1); + for(size_t i=0; i::max()) + targets[lowestOrdered[i]].push_back(i); + + // Now call the recursive distributeFactors + return distributeFactors(fg, targets, bayesClique); + } + + /* ************************************************************************* */ + template + typename JunctionTree::sharedClique JunctionTree::distributeFactors(const FG& fg, + const std::vector > >& targets, const SymbolicBayesTree::sharedClique& bayesClique) { - if(bayesClique) { - // create a new clique in the junction tree - list frontals = bayesClique->ordering(); - sharedClique clique(new Clique(frontals.begin(), frontals.end(), bayesClique->separator_.begin(), bayesClique->separator_.end())); + if(bayesClique) { + // create a new clique in the junction tree + list frontals = bayesClique->ordering(); + sharedClique clique(new Clique(frontals.begin(), frontals.end(), bayesClique->separator_.begin(), bayesClique->separator_.end())); - // count the factors for this cluster to pre-allocate space - { - size_t nFactors = 0; - BOOST_FOREACH(const Index frontal, clique->frontal) { - // There may be less variables in "targets" than there really are if - // some of the highest-numbered variables do not pull in any factors. - if(frontal < targets.size()) - nFactors += targets[frontal].size(); } - clique->reserve(nFactors); - } - // add the factors to this cluster - BOOST_FOREACH(const Index frontal, clique->frontal) { - if(frontal < targets.size()) { - BOOST_FOREACH(const size_t factorI, targets[frontal]) { - clique->push_back(fg[factorI]); } } } + // count the factors for this cluster to pre-allocate space + { + size_t nFactors = 0; + BOOST_FOREACH(const Index frontal, clique->frontal) { + // There may be less variables in "targets" than there really are if + // some of the highest-numbered variables do not pull in any factors. + if(frontal < targets.size()) + nFactors += targets[frontal].size(); } + clique->reserve(nFactors); + } + // add the factors to this cluster + BOOST_FOREACH(const Index frontal, clique->frontal) { + if(frontal < targets.size()) { + BOOST_FOREACH(const size_t factorI, targets[frontal]) { + clique->push_back(fg[factorI]); } } } - // recursively call the children - BOOST_FOREACH(const typename SymbolicBayesTree::sharedClique bayesChild, bayesClique->children()) { - sharedClique child = distributeFactors(fg, targets, bayesChild); - clique->addChild(child); - child->parent() = clique; - } - return clique; - } else - return sharedClique(); - } + // recursively call the children + BOOST_FOREACH(const typename SymbolicBayesTree::sharedClique bayesChild, bayesClique->children()) { + sharedClique child = distributeFactors(fg, targets, bayesChild); + clique->addChild(child); + child->parent() = clique; + } + return clique; + } else + return sharedClique(); + } - /* ************************************************************************* */ - template - pair::BayesTree::sharedClique, typename FG::sharedFactor> - JunctionTree::eliminateOneClique(const boost::shared_ptr& current) const { + /* ************************************************************************* */ + template + pair::BayesTree::sharedClique, typename FG::sharedFactor> + JunctionTree::eliminateOneClique(const boost::shared_ptr& current) const { - FG fg; // factor graph will be assembled from local factors and marginalized children - fg.reserve(current->size() + current->children().size()); - fg.push_back(*current); // add the local factors + FG fg; // factor graph will be assembled from local factors and marginalized children + fg.reserve(current->size() + current->children().size()); + fg.push_back(*current); // add the local factors // receive the factors from the child and its clique point list children; - BOOST_FOREACH(const boost::shared_ptr& child, current->children()) { - pair tree_factor( - eliminateOneClique(child)); + BOOST_FOREACH(const boost::shared_ptr& child, current->children()) { + pair tree_factor( + eliminateOneClique(child)); children.push_back(tree_factor.first); - fg.push_back(tree_factor.second); - } + fg.push_back(tree_factor.second); + } - // eliminate the combined factors - // warning: fg is being eliminated in-place and will contain marginal afterwards - tic("JT 2.1 VariableSlots"); - VariableSlots variableSlots(fg); + // 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 @@ -182,29 +189,29 @@ namespace gtsam { assert(std::equal(jointFactor->begin(), jointFactor->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)); - new_clique->children_ = children; + // create a new clique corresponding the combined factors + typename BayesTree::sharedClique new_clique(new typename BayesTree::Clique(*fragment)); + new_clique->children_ = children; - BOOST_FOREACH(typename BayesTree::sharedClique& childRoot, children) - childRoot->parent_ = new_clique; + 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, jointFactor); + } - /* ************************************************************************* */ - template - typename JunctionTree::BayesTree::sharedClique JunctionTree::eliminate() const { - if(this->root()) { - tic("JT 2 eliminate"); - pair ret = this->eliminateOneClique(this->root()); - if (ret.second->size() != 0) - throw runtime_error("JuntionTree::eliminate: elimination failed because of factors left over!"); - toc("JT 2 eliminate"); - return ret.first; - } else - return typename BayesTree::sharedClique(); - } + /* ************************************************************************* */ + template + typename JunctionTree::BayesTree::sharedClique JunctionTree::eliminate() const { + if(this->root()) { + tic("JT 2 eliminate"); + pair ret = this->eliminateOneClique(this->root()); + if (ret.second->size() != 0) + throw runtime_error("JuntionTree::eliminate: elimination failed because of factors left over!"); + toc("JT 2 eliminate"); + return ret.first; + } else + return typename BayesTree::sharedClique(); + } } //namespace gtsam diff --git a/gtsam/inference/JunctionTree.h b/gtsam/inference/JunctionTree.h index b1de1e9af..df6fb6e6e 100644 --- a/gtsam/inference/JunctionTree.h +++ b/gtsam/inference/JunctionTree.h @@ -48,6 +48,8 @@ namespace gtsam { typedef class BayesTree BayesTree; + typedef boost::shared_ptr > shared_ptr; + // And we will frequently refer to a symbolic Bayes tree typedef gtsam::BayesTree SymbolicBayesTree; @@ -64,14 +66,19 @@ namespace gtsam { std::pair eliminateOneClique(const boost::shared_ptr& clique) const; - public: - // constructor - JunctionTree() { - } + // internal constructor + void construct(const FG& fg, const VariableIndex& variableIndex); - // constructor given a factor graph and the elimination ordering + public: + /** Default constructor */ + JunctionTree() {} + + /** Construct from a factor graph. Computes a variable index. */ JunctionTree(const FG& fg); + /** Construct from a factor graph and a pre-computed variable index. */ + JunctionTree(const FG& fg, const VariableIndex& variableIndex); + // eliminate the factors in the subgraphs typename BayesTree::sharedClique eliminate() const; diff --git a/gtsam/inference/tests/testJunctionTree.cpp b/gtsam/inference/tests/testJunctionTree.cpp index 5c0de817f..21c020f40 100644 --- a/gtsam/inference/tests/testJunctionTree.cpp +++ b/gtsam/inference/tests/testJunctionTree.cpp @@ -31,6 +31,7 @@ using namespace boost::assign; #include #include #include +#include using namespace gtsam; diff --git a/gtsam/linear/GaussianFactorGraph.cpp b/gtsam/linear/GaussianFactorGraph.cpp index 106d3bb9f..ca2b93f04 100644 --- a/gtsam/linear/GaussianFactorGraph.cpp +++ b/gtsam/linear/GaussianFactorGraph.cpp @@ -146,24 +146,6 @@ GaussianFactorGraph GaussianFactorGraph::combine2(const GaussianFactorGraph& lfg return fg; } -/* ************************************************************************* */ -GaussianFactorGraph GaussianFactorGraph::add_priors(double sigma, const vector& dimensions) const { - - // start with this factor graph - GaussianFactorGraph result = *this; - - // for each of the variables, add a prior - for(Index j=0; j &M, GaussianFactorGraph &Ab1, GaussianFactorGraph &Ab2) const { //typedef sharedFactor F ; diff --git a/gtsam/linear/GaussianFactorGraph.h b/gtsam/linear/GaussianFactorGraph.h index 1a02167c7..c0d0dbcc0 100644 --- a/gtsam/linear/GaussianFactorGraph.h +++ b/gtsam/linear/GaussianFactorGraph.h @@ -151,13 +151,6 @@ namespace gtsam { */ void combine(const GaussianFactorGraph &lfg); - - /** - * Add zero-mean i.i.d. Gaussian prior terms to each variable - * @param sigma Standard deviation of Gaussian - */ - GaussianFactorGraph add_priors(double sigma, const std::vector& dimensions) const; - /** * Split a Gaussian factor graph into two, according to M * M keeps the vertex indices of edges of A1. The others belong to A2. diff --git a/gtsam/linear/GaussianJunctionTree.h b/gtsam/linear/GaussianJunctionTree.h index d76ed6974..ed5e08d5d 100644 --- a/gtsam/linear/GaussianJunctionTree.h +++ b/gtsam/linear/GaussianJunctionTree.h @@ -43,11 +43,15 @@ namespace gtsam { public : + /** Default constructor */ GaussianJunctionTree() : Base() {} - // constructor + /** Constructor from a factor graph. Builds a VariableIndex. */ GaussianJunctionTree(const GaussianFactorGraph& fg) : Base(fg) {} + /** Construct from a factor graph and a pre-computed variable index. */ + GaussianJunctionTree(const GaussianFactorGraph& fg, const VariableIndex& variableIndex) : Base(fg, variableIndex) {} + // optimize the linear graph VectorValues optimize() const; }; // GaussianJunctionTree diff --git a/gtsam/linear/GaussianMultifrontalSolver.cpp b/gtsam/linear/GaussianMultifrontalSolver.cpp index 163e4de8a..80d00b3b6 100644 --- a/gtsam/linear/GaussianMultifrontalSolver.cpp +++ b/gtsam/linear/GaussianMultifrontalSolver.cpp @@ -31,17 +31,23 @@ GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraph& factorGraph) { - return shared_ptr(new GaussianMultifrontalSolver(factorGraph)); -} +GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraph::shared_ptr& factorGraph) : + Base(factorGraph) {} + +/* ************************************************************************* */ +GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex) : + Base(factorGraph, variableIndex) {} /* ************************************************************************* */ GaussianMultifrontalSolver::shared_ptr -GaussianMultifrontalSolver::update(const FactorGraph& factorGraph) const { - // We do not yet have code written to update the junction tree, so we just - // create a new solver. - return Create(factorGraph); +GaussianMultifrontalSolver::Create(const FactorGraph::shared_ptr& factorGraph, + const VariableIndex::shared_ptr& variableIndex) { + return shared_ptr(new GaussianMultifrontalSolver(factorGraph, variableIndex)); +} + +/* ************************************************************************* */ +void GaussianMultifrontalSolver::replaceFactors(const FactorGraph::shared_ptr& factorGraph) { + Base::replaceFactors(factorGraph); } /* ************************************************************************* */ @@ -51,7 +57,7 @@ BayesTree::shared_ptr GaussianMultifrontalSolver::eliminate /* ************************************************************************* */ VectorValues::shared_ptr GaussianMultifrontalSolver::optimize() const { - return VectorValues::shared_ptr(new VectorValues(junctionTree_.optimize())); + return VectorValues::shared_ptr(new VectorValues(junctionTree_->optimize())); } /* ************************************************************************* */ diff --git a/gtsam/linear/GaussianMultifrontalSolver.h b/gtsam/linear/GaussianMultifrontalSolver.h index 1fb010a9e..021c6bb76 100644 --- a/gtsam/linear/GaussianMultifrontalSolver.h +++ b/gtsam/linear/GaussianMultifrontalSolver.h @@ -54,15 +54,28 @@ public: /** * Construct the solver for a factor graph. This builds the elimination - * tree, which already does some of the symbolic work of elimination. + * tree, which already does some of the work of elimination. */ GaussianMultifrontalSolver(const FactorGraph& factorGraph); /** - * Named constructor that returns a shared_ptr. This builds the junction + * Construct the solver for a factor graph. This builds the elimination + * tree, which already does some of the work of elimination. + */ + GaussianMultifrontalSolver(const FactorGraph::shared_ptr& factorGraph); + + /** + * Construct the solver with a shared pointer to a factor graph and to a + * VariableIndex. The solver will store these pointers, so this constructor + * is the fastest. + */ + GaussianMultifrontalSolver(const FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex); + + /** + * Named constructor to return a shared_ptr. This builds the elimination * tree, which already does some of the symbolic work of elimination. */ - static shared_ptr Create(const FactorGraph& factorGraph); + static shared_ptr Create(const FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex); /** * Return a new solver that solves the given factor graph, which must have @@ -71,7 +84,7 @@ public: * used in cases where the numerical values of the linear problem change, * e.g. during iterative nonlinear optimization. */ - shared_ptr update(const FactorGraph& factorGraph) const; + void replaceFactors(const FactorGraph::shared_ptr& factorGraph); /** * Eliminate the factor graph sequentially. Uses a column elimination tree diff --git a/gtsam/linear/GaussianSequentialSolver.cpp b/gtsam/linear/GaussianSequentialSolver.cpp index a77e1e28b..508400a79 100644 --- a/gtsam/linear/GaussianSequentialSolver.cpp +++ b/gtsam/linear/GaussianSequentialSolver.cpp @@ -31,15 +31,23 @@ GaussianSequentialSolver::GaussianSequentialSolver(const FactorGraph& factorGraph) { - return shared_ptr(new GaussianSequentialSolver(factorGraph)); +GaussianSequentialSolver::GaussianSequentialSolver(const FactorGraph::shared_ptr& factorGraph) : + Base(factorGraph) {} + +/* ************************************************************************* */ +GaussianSequentialSolver::GaussianSequentialSolver(const FactorGraph::shared_ptr& factorGraph, + const VariableIndex::shared_ptr& variableIndex) : + Base(factorGraph, variableIndex) {} + +/* ************************************************************************* */ +GaussianSequentialSolver::shared_ptr GaussianSequentialSolver::Create( + const FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex) { + return shared_ptr(new GaussianSequentialSolver(factorGraph, variableIndex)); } /* ************************************************************************* */ -GaussianSequentialSolver::shared_ptr GaussianSequentialSolver::update(const FactorGraph& factorGraph) const { - // We do not yet have code written to update the elimination tree, so we just - // create a new solver. - return Create(factorGraph); +void GaussianSequentialSolver::replaceFactors(const FactorGraph::shared_ptr& factorGraph) { + Base::replaceFactors(factorGraph); } /* ************************************************************************* */ @@ -52,7 +60,7 @@ VectorValues::shared_ptr GaussianSequentialSolver::optimize() const { static const bool debug = false; - if(debug) this->factors_.print("GaussianSequentialSolver, eliminating "); + if(debug) this->factors_->print("GaussianSequentialSolver, eliminating "); if(debug) this->eliminationTree_->print("GaussianSequentialSolver, elimination tree "); // Eliminate using the elimination tree diff --git a/gtsam/linear/GaussianSequentialSolver.h b/gtsam/linear/GaussianSequentialSolver.h index 06e101f7e..1b02d8316 100644 --- a/gtsam/linear/GaussianSequentialSolver.h +++ b/gtsam/linear/GaussianSequentialSolver.h @@ -61,15 +61,28 @@ public: /** * Construct the solver for a factor graph. This builds the elimination - * tree, which already does some of the symbolic work of elimination. + * tree, which already does some of the work of elimination. */ GaussianSequentialSolver(const FactorGraph& factorGraph); + /** + * Construct the solver for a factor graph. This builds the elimination + * tree, which already does some of the work of elimination. + */ + GaussianSequentialSolver(const FactorGraph::shared_ptr& factorGraph); + + /** + * Construct the solver with a shared pointer to a factor graph and to a + * VariableIndex. The solver will store these pointers, so this constructor + * is the fastest. + */ + GaussianSequentialSolver(const FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex); + /** * Named constructor to return a shared_ptr. This builds the elimination * tree, which already does some of the symbolic work of elimination. */ - static shared_ptr Create(const FactorGraph& factorGraph); + static shared_ptr Create(const FactorGraph::shared_ptr& factorGraph, const VariableIndex::shared_ptr& variableIndex); /** * Return a new solver that solves the given factor graph, which must have @@ -78,7 +91,7 @@ public: * used in cases where the numerical values of the linear problem change, * e.g. during iterative nonlinear optimization. */ - shared_ptr update(const FactorGraph& factorGraph) const; + void replaceFactors(const FactorGraph::shared_ptr& factorGraph); /** * Eliminate the factor graph sequentially. Uses a column elimination tree diff --git a/gtsam/linear/SubgraphSolver-inl.h b/gtsam/linear/SubgraphSolver-inl.h index afd388a8a..8d32f5c36 100644 --- a/gtsam/linear/SubgraphSolver-inl.h +++ b/gtsam/linear/SubgraphSolver-inl.h @@ -27,14 +27,13 @@ using namespace std; namespace gtsam { template -typename SubgraphSolver::shared_ptr -SubgraphSolver::update(const LINEAR &graph) const { +void SubgraphSolver::replaceFactors(const typename LINEAR::shared_ptr &graph) { shared_linear Ab1 = boost::make_shared(), Ab2 = boost::make_shared(); if (parameters_->verbosity()) cout << "split the graph ..."; - graph.split(pairs_, *Ab1, *Ab2) ; + graph->split(pairs_, *Ab1, *Ab2) ; if (parameters_->verbosity()) cout << ",with " << Ab1->size() << " and " << Ab2->size() << " factors" << endl; // // Add a HardConstraint to the root, otherwise the root will be singular @@ -48,8 +47,7 @@ SubgraphSolver::update(const LINEAR &graph) const { SubgraphPreconditioner::sharedBayesNet Rc1 = EliminationTree::Create(sacrificialAb1)->eliminate(); SubgraphPreconditioner::sharedValues xbar = gtsam::optimize_(*Rc1); - shared_preconditioner pc = boost::make_shared(Ab1,Ab2,Rc1,xbar); - return boost::make_shared(ordering_, pairs_, pc, parameters_) ; + pc_ = boost::make_shared(Ab1,Ab2,Rc1,xbar); } template diff --git a/gtsam/linear/SubgraphSolver.h b/gtsam/linear/SubgraphSolver.h index 1e2423fe9..14a460be6 100644 --- a/gtsam/linear/SubgraphSolver.h +++ b/gtsam/linear/SubgraphSolver.h @@ -57,7 +57,7 @@ namespace gtsam { SubgraphSolver(const GRAPH& G, const VALUES& theta0, const Parameters ¶meters = Parameters()): IterativeSolver(parameters){ initialize(G,theta0); } - SubgraphSolver(const LINEAR &GFG) { + SubgraphSolver(const typename LINEAR::shared_ptr& GFG) { std::cout << "[SubgraphSolver] Unexpected usage.." << std::endl; throw std::runtime_error("SubgraphSolver: gaussian factor graph initialization not supported"); } @@ -71,7 +71,7 @@ namespace gtsam { sharedParameters parameters = boost::make_shared()) : IterativeSolver(parameters), ordering_(ordering), pairs_(pairs), pc_(pc) {} - shared_ptr update(const LINEAR &graph) const ; + void replaceFactors(const typename LINEAR::shared_ptr &graph); VectorValues::shared_ptr optimize() const ; shared_ordering ordering() const { return ordering_; } diff --git a/gtsam/nonlinear/NonlinearOptimizer-inl.h b/gtsam/nonlinear/NonlinearOptimizer-inl.h index d7c475bc6..1f1a11a94 100644 --- a/gtsam/nonlinear/NonlinearOptimizer-inl.h +++ b/gtsam/nonlinear/NonlinearOptimizer-inl.h @@ -115,7 +115,7 @@ namespace gtsam { boost::shared_ptr linearized = graph_->linearize(*values_, *ordering_); shared_solver newSolver = solver_; - if(newSolver) newSolver = newSolver->update(*linearized); + if(newSolver) newSolver->replaceFactors(linearized); else newSolver.reset(new S(*linearized)); VectorValues delta = *newSolver->optimize(); @@ -209,11 +209,24 @@ namespace gtsam { if (verbosity >= Parameters::TRYLAMBDA) cout << "trying lambda = " << lambda << endl; // add prior-factors - L damped = linear.add_priors(1.0/sqrt(lambda), *dimensions_); - if (verbosity >= Parameters::DAMPED) damped.print("damped"); + typename L::shared_ptr damped(new L(linear)); + { + double sigma = 1.0 / sqrt(lambda); + damped->reserve(damped->size() + dimensions_->size()); + // for each of the variables, add a prior + for(Index j=0; jsize(); ++j) { + size_t dim = (*dimensions_)[j]; + Matrix A = eye(dim); + Vector b = zero(dim); + SharedDiagonal model = noiseModel::Isotropic::Sigma(dim,sigma); + GaussianFactor::shared_ptr prior(new GaussianFactor(j, A, b, model)); + damped->push_back(prior); + } + } + if (verbosity >= Parameters::DAMPED) damped->print("damped"); // solve - if(solver_) solver_ = solver_->update(damped); + if(solver_) solver_->replaceFactors(damped); else solver_.reset(new S(damped)); VectorValues delta = *solver_->optimize(); diff --git a/gtsam/nonlinear/NonlinearOptimizer.h b/gtsam/nonlinear/NonlinearOptimizer.h index cc4dbd5c8..ddb31e503 100644 --- a/gtsam/nonlinear/NonlinearOptimizer.h +++ b/gtsam/nonlinear/NonlinearOptimizer.h @@ -71,7 +71,7 @@ namespace gtsam { typedef boost::shared_ptr shared_values; typedef boost::shared_ptr shared_graph; typedef boost::shared_ptr shared_ordering; - typedef boost::shared_ptr shared_solver; + typedef boost::shared_ptr shared_solver; typedef NonlinearOptimizationParameters Parameters; typedef boost::shared_ptr shared_parameters ; diff --git a/tests/testGaussianFactorGraph.cpp b/tests/testGaussianFactorGraph.cpp index 484fda5d0..1a4cd9ccf 100644 --- a/tests/testGaussianFactorGraph.cpp +++ b/tests/testGaussianFactorGraph.cpp @@ -339,21 +339,21 @@ TEST( GaussianFactorGraph, eliminateAll ) // CHECK(assert_equal(expected,actual,tol)); //} -/* ************************************************************************* */ -TEST( GaussianFactorGraph, add_priors ) -{ - Ordering ordering; ordering += "l1","x1","x2"; - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - GaussianFactorGraph actual = fg.add_priors(3, vector(3,2)); - GaussianFactorGraph expected = createGaussianFactorGraph(ordering); - Matrix A = eye(2); - Vector b = zero(2); - SharedDiagonal sigma = sharedSigma(2,3.0); - expected.push_back(GaussianFactor::shared_ptr(new GaussianFactor(ordering["l1"],A,b,sigma))); - expected.push_back(GaussianFactor::shared_ptr(new GaussianFactor(ordering["x1"],A,b,sigma))); - expected.push_back(GaussianFactor::shared_ptr(new GaussianFactor(ordering["x2"],A,b,sigma))); - CHECK(assert_equal(expected,actual)); -} +///* ************************************************************************* */ +//TEST( GaussianFactorGraph, add_priors ) +//{ +// Ordering ordering; ordering += "l1","x1","x2"; +// GaussianFactorGraph fg = createGaussianFactorGraph(ordering); +// GaussianFactorGraph actual = fg.add_priors(3, vector(3,2)); +// GaussianFactorGraph expected = createGaussianFactorGraph(ordering); +// Matrix A = eye(2); +// Vector b = zero(2); +// SharedDiagonal sigma = sharedSigma(2,3.0); +// expected.push_back(GaussianFactor::shared_ptr(new GaussianFactor(ordering["l1"],A,b,sigma))); +// expected.push_back(GaussianFactor::shared_ptr(new GaussianFactor(ordering["x1"],A,b,sigma))); +// expected.push_back(GaussianFactor::shared_ptr(new GaussianFactor(ordering["x2"],A,b,sigma))); +// CHECK(assert_equal(expected,actual)); +//} /* ************************************************************************* */ TEST( GaussianFactorGraph, copying )