diff --git a/examples/UnorderedLinear.cpp b/examples/UnorderedLinear.cpp index f61c96035..896b1c696 100644 --- a/examples/UnorderedLinear.cpp +++ b/examples/UnorderedLinear.cpp @@ -1,13 +1,13 @@ #include #include -#include -#include -#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -129,28 +129,28 @@ ISAM2 solveWithOldISAM2(const NonlinearFactorGraph& measurements) } /* ************************************************************************* */ -GaussianFactorGraphUnordered convertToUnordered(const GaussianFactorGraph& gfg, const Ordering& ordering) +GaussianFactorGraph convertToUnordered(const GaussianFactorGraphOrdered& gfg, const OrderingOrdered& ordering) { - GaussianFactorGraphUnordered gfgu; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, gfg) + GaussianFactorGraph gfgu; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, gfg) { vector > terms; - const JacobianFactor& jacobian = dynamic_cast(*factor); - for(GaussianFactor::const_iterator term = jacobian.begin(); term != jacobian.end(); ++term) + const JacobianFactorOrdered& jacobian = dynamic_cast(*factor); + for(GaussianFactorOrdered::const_iterator term = jacobian.begin(); term != jacobian.end(); ++term) { terms.push_back(make_pair( ordering.key(*term), jacobian.getA(term))); } - gfgu.add(JacobianFactorUnordered(terms, jacobian.getb(), jacobian.get_model())); + gfgu.add(JacobianFactor(terms, jacobian.getb(), jacobian.get_model())); } return gfgu; } /* ************************************************************************* */ -void compareSolutions(const VectorValues& orderedSoln, const Ordering& ordering, const VectorValuesUnordered& unorderedSoln) +void compareSolutions(const VectorValuesOrdered& orderedSoln, const OrderingOrdered& ordering, const VectorValues& unorderedSoln) { if(orderedSoln.size() != unorderedSoln.size()) { @@ -159,7 +159,7 @@ void compareSolutions(const VectorValues& orderedSoln, const Ordering& ordering, else { double maxErr = 0.0; - BOOST_FOREACH(const VectorValuesUnordered::KeyValuePair& v, unorderedSoln) + BOOST_FOREACH(const VectorValues::KeyValuePair& v, unorderedSoln) { Vector orderedV = orderedSoln[ordering[v.first]]; maxErr = std::max(maxErr, (orderedV - v.second).cwiseAbs().maxCoeff()); @@ -217,30 +217,30 @@ int main(int argc, char *argv[]) // Get linear graph cout << "Converting to unordered linear graph" << endl; - Ordering ordering = *isamsoln.orderingArbitrary(); - Ordering orderingCOLAMD = *nlfg.orderingCOLAMD(isamsoln); - GaussianFactorGraph gfg = *nlfg.linearize(isamsoln, ordering); - GaussianFactorGraphUnordered gfgu = convertToUnordered(gfg, ordering); + OrderingOrdered ordering = *isamsoln.orderingArbitrary(); + OrderingOrdered orderingCOLAMD = *nlfg.orderingCOLAMD(isamsoln); + GaussianFactorGraphOrdered gfg = *nlfg.linearize(isamsoln, ordering); + GaussianFactorGraph gfgu = convertToUnordered(gfg, ordering); - //OrderingUnordered orderingUnordered; + //Ordering orderingUnordered; //for(Index j = 0; j < ordering.size(); ++j) // orderingUnordered.push_back(ordering.key(j)); // Solve linear graph cout << "Optimizing unordered graph" << endl; - VectorValuesUnordered unorderedSolnFinal; + VectorValues unorderedSolnFinal; { gttic_(Solve_unordered); - VectorValuesUnordered unorderedSoln; + VectorValues unorderedSoln; for(size_t i = 0; i < 1; ++i) { - gttic_(VariableIndex); - VariableIndexUnordered vi(gfgu); - gttoc_(VariableIndex); + gttic_(VariableIndexOrdered); + VariableIndex vi(gfgu); + gttoc_(VariableIndexOrdered); gttic_(COLAMD); - OrderingUnordered orderingUnordered = OrderingUnordered::COLAMD(vi); + Ordering orderingUnordered = Ordering::COLAMD(vi); gttoc_(COLAMD); gttic_(eliminate); - GaussianBayesTreeUnordered::shared_ptr bt = gfgu.eliminateMultifrontal(orderingUnordered); + GaussianBayesTree::shared_ptr bt = gfgu.eliminateMultifrontal(orderingUnordered); gttoc_(eliminate); gttic_(optimize); unorderedSoln = bt->optimize(); @@ -252,22 +252,22 @@ int main(int argc, char *argv[]) // Solve linear graph with old code cout << "Optimizing using old ordered code" << endl; - VectorValues orderedSolnFinal; + VectorValuesOrdered orderedSolnFinal; { - Ordering orderingToUse = ordering; - GaussianFactorGraph::shared_ptr orderedGraph = nlfg.linearize(isamsoln, *nlfg.orderingCOLAMD(isamsoln)); + OrderingOrdered orderingToUse = ordering; + GaussianFactorGraphOrdered::shared_ptr orderedGraph = nlfg.linearize(isamsoln, *nlfg.orderingCOLAMD(isamsoln)); gttic_(Solve_ordered); - VectorValues orderedSoln; + VectorValuesOrdered orderedSoln; for(size_t i = 0; i < 1; ++i) { - gttic_(VariableIndex); - boost::shared_ptr vi = boost::make_shared(gfg); - gttoc_(VariableIndex); + gttic_(VariableIndexOrdered); + boost::shared_ptr vi = boost::make_shared(gfg); + gttoc_(VariableIndexOrdered); gttic_(COLAMD); boost::shared_ptr permutation = inference::PermutationCOLAMD(*vi); orderingToUse.permuteInPlace(*permutation); gttoc_(COLAMD); gttic_(eliminate); - boost::shared_ptr bt = GaussianMultifrontalSolver(*orderedGraph, true).eliminate(); + boost::shared_ptr bt = GaussianMultifrontalSolver(*orderedGraph, true).eliminate(); gttoc_(eliminate); gttic_(optimize); orderedSoln = optimize(*bt); @@ -280,8 +280,8 @@ int main(int argc, char *argv[]) // Compare results compareSolutions(orderedSolnFinal, orderingCOLAMD, unorderedSolnFinal); - //GaussianEliminationTreeUnordered(gfgu, orderingUnordered).print("ETree: "); - //GaussianJunctionTreeUnordered(GaussianEliminationTreeUnordered(gfgu, OrderingUnordered::COLAMD(gfgu))).print("JTree: "); + //GaussianEliminationTree(gfgu, orderingUnordered).print("ETree: "); + //GaussianJunctionTree(GaussianEliminationTree(gfgu, Ordering::COLAMD(gfgu))).print("JTree: "); //gfgu.eliminateMultifrontal(orderingUnordered)->print("BayesTree: "); tictoc_print_(); diff --git a/examples/elaboratePoint2KalmanFilter.cpp b/examples/elaboratePoint2KalmanFilter.cpp index 3c18b220a..b4c86c0b7 100644 --- a/examples/elaboratePoint2KalmanFilter.cpp +++ b/examples/elaboratePoint2KalmanFilter.cpp @@ -22,11 +22,11 @@ #include #include -#include +#include #include #include -#include -#include +#include +#include #include #include @@ -38,10 +38,10 @@ int main() { // [code below basically does SRIF with Cholesky] // Create a factor graph to perform the inference - GaussianFactorGraph::shared_ptr linearFactorGraph(new GaussianFactorGraph); + GaussianFactorGraphOrdered::shared_ptr linearFactorGraph(new GaussianFactorGraphOrdered); // Create the desired ordering - Ordering::shared_ptr ordering(new Ordering); + OrderingOrdered::shared_ptr ordering(new OrderingOrdered); // Create a structure to hold the linearization points Values linearizationPoints; @@ -110,10 +110,10 @@ int main() { // Solve the linear factor graph, converting it into a linear Bayes Network ( P(x0,x1) = P(x0|x1)*P(x1) ) GaussianSequentialSolver solver0(*linearFactorGraph); - GaussianBayesNet::shared_ptr linearBayesNet = solver0.eliminate(); + GaussianBayesNetOrdered::shared_ptr linearBayesNet = solver0.eliminate(); // Extract the current estimate of x1,P1 from the Bayes Network - VectorValues result = optimize(*linearBayesNet); + VectorValuesOrdered result = optimize(*linearBayesNet); Point2 x1_predict = linearizationPoints.at(x1).retract(result[ordering->at(x1)]); x1_predict.print("X1 Predict"); @@ -123,7 +123,7 @@ int main() { // Create a new, empty graph and add the prior from the previous step - linearFactorGraph = GaussianFactorGraph::shared_ptr(new GaussianFactorGraph); + linearFactorGraph = GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered); // Convert the root conditional, P(x1) in this case, into a Prior for the next step // Some care must be done here, as the linearization point in future steps will be different @@ -138,13 +138,13 @@ int main() { // -> b'' = b' - F(dx1' - dx1'') // = || F*dx1'' - (b' - F(dx1' - dx1'')) ||^2 // = || F*dx1'' - (b' - F(x_predict - x_inital)) ||^2 - const GaussianConditional::shared_ptr& cg0 = linearBayesNet->back(); + const GaussianConditionalOrdered::shared_ptr& cg0 = linearBayesNet->back(); assert(cg0->nrFrontals() == 1); assert(cg0->nrParents() == 0); linearFactorGraph->add(0, cg0->get_R(), cg0->get_d() - cg0->get_R()*result[ordering->at(x1)], noiseModel::Diagonal::Sigmas(cg0->get_sigmas(), true)); // Create the desired ordering - ordering = Ordering::shared_ptr(new Ordering); + ordering = OrderingOrdered::shared_ptr(new OrderingOrdered); ordering->insert(x1, 0); // Now, a measurement, z1, has been received, and the Kalman Filter should be "Updated"/"Corrected" @@ -199,22 +199,22 @@ int main() { // Wash, rinse, repeat for another time step // Create a new, empty graph and add the prior from the previous step - linearFactorGraph = GaussianFactorGraph::shared_ptr(new GaussianFactorGraph); + linearFactorGraph = GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered); // Convert the root conditional, P(x1) in this case, into a Prior for the next step // The linearization point of this prior must be moved to the new estimate of x, and the key/index needs to be reset to 0, // the first key in the next iteration - const GaussianConditional::shared_ptr& cg1 = linearBayesNet->back(); + const GaussianConditionalOrdered::shared_ptr& cg1 = linearBayesNet->back(); assert(cg1->nrFrontals() == 1); assert(cg1->nrParents() == 0); - JacobianFactor tmpPrior1 = JacobianFactor(*cg1); + JacobianFactorOrdered tmpPrior1 = JacobianFactorOrdered(*cg1); linearFactorGraph->add(0, tmpPrior1.getA(tmpPrior1.begin()), tmpPrior1.getb() - tmpPrior1.getA(tmpPrior1.begin()) * result[ordering->at(x1)], tmpPrior1.get_model()); // Create a key for the new state Symbol x2('x',2); // Create the desired ordering - ordering = Ordering::shared_ptr(new Ordering); + ordering = OrderingOrdered::shared_ptr(new OrderingOrdered); ordering->insert(x1, 0); ordering->insert(x2, 1); @@ -243,17 +243,17 @@ int main() { // Now add the next measurement // Create a new, empty graph and add the prior from the previous step - linearFactorGraph = GaussianFactorGraph::shared_ptr(new GaussianFactorGraph); + linearFactorGraph = GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered); // Convert the root conditional, P(x1) in this case, into a Prior for the next step - const GaussianConditional::shared_ptr& cg2 = linearBayesNet->back(); + const GaussianConditionalOrdered::shared_ptr& cg2 = linearBayesNet->back(); assert(cg2->nrFrontals() == 1); assert(cg2->nrParents() == 0); - JacobianFactor tmpPrior2 = JacobianFactor(*cg2); + JacobianFactorOrdered tmpPrior2 = JacobianFactorOrdered(*cg2); linearFactorGraph->add(0, tmpPrior2.getA(tmpPrior2.begin()), tmpPrior2.getb() - tmpPrior2.getA(tmpPrior2.begin()) * result[ordering->at(x2)], tmpPrior2.get_model()); // Create the desired ordering - ordering = Ordering::shared_ptr(new Ordering); + ordering = OrderingOrdered::shared_ptr(new OrderingOrdered); ordering->insert(x2, 0); // And update using z2 ... @@ -290,20 +290,20 @@ int main() { // Wash, rinse, repeat for a third time step // Create a new, empty graph and add the prior from the previous step - linearFactorGraph = GaussianFactorGraph::shared_ptr(new GaussianFactorGraph); + linearFactorGraph = GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered); // Convert the root conditional, P(x1) in this case, into a Prior for the next step - const GaussianConditional::shared_ptr& cg3 = linearBayesNet->back(); + const GaussianConditionalOrdered::shared_ptr& cg3 = linearBayesNet->back(); assert(cg3->nrFrontals() == 1); assert(cg3->nrParents() == 0); - JacobianFactor tmpPrior3 = JacobianFactor(*cg3); + JacobianFactorOrdered tmpPrior3 = JacobianFactorOrdered(*cg3); linearFactorGraph->add(0, tmpPrior3.getA(tmpPrior3.begin()), tmpPrior3.getb() - tmpPrior3.getA(tmpPrior3.begin()) * result[ordering->at(x2)], tmpPrior3.get_model()); // Create a key for the new state Symbol x3('x',3); // Create the desired ordering - ordering = Ordering::shared_ptr(new Ordering); + ordering = OrderingOrdered::shared_ptr(new OrderingOrdered); ordering->insert(x2, 0); ordering->insert(x3, 1); @@ -332,17 +332,17 @@ int main() { // Now add the next measurement // Create a new, empty graph and add the prior from the previous step - linearFactorGraph = GaussianFactorGraph::shared_ptr(new GaussianFactorGraph); + linearFactorGraph = GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered); // Convert the root conditional, P(x1) in this case, into a Prior for the next step - const GaussianConditional::shared_ptr& cg4 = linearBayesNet->back(); + const GaussianConditionalOrdered::shared_ptr& cg4 = linearBayesNet->back(); assert(cg4->nrFrontals() == 1); assert(cg4->nrParents() == 0); - JacobianFactor tmpPrior4 = JacobianFactor(*cg4); + JacobianFactorOrdered tmpPrior4 = JacobianFactorOrdered(*cg4); linearFactorGraph->add(0, tmpPrior4.getA(tmpPrior4.begin()), tmpPrior4.getb() - tmpPrior4.getA(tmpPrior4.begin()) * result[ordering->at(x3)], tmpPrior4.get_model()); // Create the desired ordering - ordering = Ordering::shared_ptr(new Ordering); + ordering = OrderingOrdered::shared_ptr(new OrderingOrdered); ordering->insert(x3, 0); // And update using z3 ... diff --git a/gtsam/discrete/DecisionTreeFactor.cpp b/gtsam/discrete/DecisionTreeFactor.cpp index 1eb428669..c4c2afedd 100644 --- a/gtsam/discrete/DecisionTreeFactor.cpp +++ b/gtsam/discrete/DecisionTreeFactor.cpp @@ -45,14 +45,14 @@ namespace gtsam { /* ************************************************************************* */ bool DecisionTreeFactor::equals(const This& other, double tol) const { - return IndexFactor::equals(other, tol) && Potentials::equals(other, tol); + return IndexFactorOrdered::equals(other, tol) && Potentials::equals(other, tol); } /* ************************************************************************* */ void DecisionTreeFactor::print(const string& s, const IndexFormatter& formatter) const { cout << s; - IndexFactor::print("IndexFactor:",formatter); + IndexFactorOrdered::print("IndexFactor:",formatter); Potentials::print("Potentials:",formatter); } diff --git a/gtsam/discrete/DiscreteBayesNet.cpp b/gtsam/discrete/DiscreteBayesNet.cpp index 98a61f7bd..f0a32ed64 100644 --- a/gtsam/discrete/DiscreteBayesNet.cpp +++ b/gtsam/discrete/DiscreteBayesNet.cpp @@ -18,13 +18,13 @@ #include #include -#include +#include #include namespace gtsam { // Explicitly instantiate so we don't have to include everywhere - template class BayesNet ; + template class BayesNetOrdered ; /* ************************************************************************* */ void add_front(DiscreteBayesNet& bayesNet, const Signature& s) { diff --git a/gtsam/discrete/DiscreteBayesNet.h b/gtsam/discrete/DiscreteBayesNet.h index 9c30d800a..aa7692142 100644 --- a/gtsam/discrete/DiscreteBayesNet.h +++ b/gtsam/discrete/DiscreteBayesNet.h @@ -20,12 +20,12 @@ #include #include #include -#include +#include #include namespace gtsam { - typedef BayesNet DiscreteBayesNet; + typedef BayesNetOrdered DiscreteBayesNet; /** Add a DiscreteCondtional */ GTSAM_EXPORT void add(DiscreteBayesNet&, const Signature& s); diff --git a/gtsam/discrete/DiscreteConditional.cpp b/gtsam/discrete/DiscreteConditional.cpp index ebf8c0c04..e0afd6354 100644 --- a/gtsam/discrete/DiscreteConditional.cpp +++ b/gtsam/discrete/DiscreteConditional.cpp @@ -37,14 +37,14 @@ namespace gtsam { /* ******************************************************************************** */ DiscreteConditional::DiscreteConditional(const size_t nrFrontals, const DecisionTreeFactor& f) : - IndexConditional(f.keys(), nrFrontals), Potentials( + IndexConditionalOrdered(f.keys(), nrFrontals), Potentials( f / (*f.sum(nrFrontals))) { } /* ******************************************************************************** */ DiscreteConditional::DiscreteConditional(const DecisionTreeFactor& joint, const DecisionTreeFactor& marginal) : - IndexConditional(joint.keys(), joint.size() - marginal.size()), Potentials( + IndexConditionalOrdered(joint.keys(), joint.size() - marginal.size()), Potentials( ISDEBUG("DiscreteConditional::COUNT") ? joint : joint / marginal) { if (ISDEBUG("DiscreteConditional::DiscreteConditional")) cout << (firstFrontalKey()) << endl; //TODO Print all keys @@ -52,20 +52,20 @@ namespace gtsam { /* ******************************************************************************** */ DiscreteConditional::DiscreteConditional(const Signature& signature) : - IndexConditional(signature.indices(), 1), Potentials( + IndexConditionalOrdered(signature.indices(), 1), Potentials( signature.discreteKeysParentsFirst(), signature.cpt()) { } /* ******************************************************************************** */ void DiscreteConditional::print(const std::string& s, const IndexFormatter& formatter) const { std::cout << s << std::endl; - IndexConditional::print(s, formatter); + IndexConditionalOrdered::print(s, formatter); Potentials::print(s); } /* ******************************************************************************** */ bool DiscreteConditional::equals(const DiscreteConditional& other, double tol) const { - return IndexConditional::equals(other, tol) + return IndexConditionalOrdered::equals(other, tol) && Potentials::equals(other, tol); } @@ -197,7 +197,7 @@ namespace gtsam { /* ******************************************************************************** */ void DiscreteConditional::permuteWithInverse(const Permutation& inversePermutation){ - IndexConditional::permuteWithInverse(inversePermutation); + IndexConditionalOrdered::permuteWithInverse(inversePermutation); Potentials::permuteWithInverse(inversePermutation); } diff --git a/gtsam/discrete/DiscreteConditional.h b/gtsam/discrete/DiscreteConditional.h index a14fa9ae7..3b46542ef 100644 --- a/gtsam/discrete/DiscreteConditional.h +++ b/gtsam/discrete/DiscreteConditional.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include @@ -30,13 +30,13 @@ namespace gtsam { * Discrete Conditional Density * Derives from DecisionTreeFactor */ - class GTSAM_EXPORT DiscreteConditional: public IndexConditional, public Potentials { + class GTSAM_EXPORT DiscreteConditional: public IndexConditionalOrdered, public Potentials { public: // typedefs needed to play nice with gtsam typedef DiscreteFactor FactorType; typedef boost::shared_ptr shared_ptr; - typedef IndexConditional Base; + typedef IndexConditionalOrdered Base; /** A map from keys to values */ typedef Assignment Values; diff --git a/gtsam/discrete/DiscreteFactor.h b/gtsam/discrete/DiscreteFactor.h index 6adb1278b..a9a1ac0cf 100644 --- a/gtsam/discrete/DiscreteFactor.h +++ b/gtsam/discrete/DiscreteFactor.h @@ -19,7 +19,7 @@ #pragma once #include -#include +#include namespace gtsam { @@ -30,7 +30,7 @@ namespace gtsam { * Base class for discrete probabilistic factors * The most general one is the derived DecisionTreeFactor */ - class GTSAM_EXPORT DiscreteFactor: public IndexFactor { + class GTSAM_EXPORT DiscreteFactor: public IndexFactorOrdered { public: @@ -47,23 +47,23 @@ namespace gtsam { /// Construct n-way factor DiscreteFactor(const std::vector& js) : - IndexFactor(js) { + IndexFactorOrdered(js) { } /// Construct unary factor DiscreteFactor(Index j) : - IndexFactor(j) { + IndexFactorOrdered(j) { } /// Construct binary factor DiscreteFactor(Index j1, Index j2) : - IndexFactor(j1, j2) { + IndexFactorOrdered(j1, j2) { } /// construct from container template DiscreteFactor(KeyIterator beginKey, KeyIterator endKey) : - IndexFactor(beginKey, endKey) { + IndexFactorOrdered(beginKey, endKey) { } public: @@ -85,7 +85,7 @@ namespace gtsam { virtual void print(const std::string& s = "DiscreteFactor\n", const IndexFormatter& formatter =DefaultIndexFormatter) const { - IndexFactor::print(s,formatter); + IndexFactorOrdered::print(s,formatter); } /// @} @@ -105,14 +105,14 @@ namespace gtsam { * to already be inverted. */ virtual void permuteWithInverse(const Permutation& inversePermutation){ - IndexFactor::permuteWithInverse(inversePermutation); + IndexFactorOrdered::permuteWithInverse(inversePermutation); } /** * Apply a reduction, which is a remapping of variable indices. */ virtual void reduceWithInverse(const internal::Reduction& inverseReduction) { - IndexFactor::reduceWithInverse(inverseReduction); + IndexFactorOrdered::reduceWithInverse(inverseReduction); } /// @} diff --git a/gtsam/discrete/DiscreteFactorGraph.cpp b/gtsam/discrete/DiscreteFactorGraph.cpp index 5c4d815fb..642a87eca 100644 --- a/gtsam/discrete/DiscreteFactorGraph.cpp +++ b/gtsam/discrete/DiscreteFactorGraph.cpp @@ -19,14 +19,14 @@ //#define ENABLE_TIMING #include #include -#include +#include #include namespace gtsam { // Explicitly instantiate so we don't have to include everywhere - template class FactorGraph ; - template class EliminationTree ; + template class FactorGraphOrdered ; + template class EliminationTreeOrdered ; /* ************************************************************************* */ DiscreteFactorGraph::DiscreteFactorGraph() { @@ -34,8 +34,8 @@ namespace gtsam { /* ************************************************************************* */ DiscreteFactorGraph::DiscreteFactorGraph( - const BayesNet& bayesNet) : - FactorGraph(bayesNet) { + const BayesNetOrdered& bayesNet) : + FactorGraphOrdered(bayesNet) { } /* ************************************************************************* */ @@ -95,7 +95,7 @@ namespace gtsam { /* ************************************************************************* */ std::pair // - EliminateDiscrete(const FactorGraph& factors, size_t num) { + EliminateDiscrete(const FactorGraphOrdered& factors, size_t num) { // PRODUCT: multiply all factors gttic(product); diff --git a/gtsam/discrete/DiscreteFactorGraph.h b/gtsam/discrete/DiscreteFactorGraph.h index 7078662f7..b2da2d519 100644 --- a/gtsam/discrete/DiscreteFactorGraph.h +++ b/gtsam/discrete/DiscreteFactorGraph.h @@ -20,13 +20,13 @@ #include #include -#include +#include #include #include namespace gtsam { -class DiscreteFactorGraph: public FactorGraph { +class DiscreteFactorGraph: public FactorGraphOrdered { public: /** A map from keys to values */ @@ -39,12 +39,12 @@ public: /** Constructor from a factor graph of GaussianFactor or a derived type */ template - DiscreteFactorGraph(const FactorGraph& fg) { + DiscreteFactorGraph(const FactorGraphOrdered& fg) { push_back(fg); } /** construct from a BayesNet */ - GTSAM_EXPORT DiscreteFactorGraph(const BayesNet& bayesNet); + GTSAM_EXPORT DiscreteFactorGraph(const BayesNetOrdered& bayesNet); template void add(const DiscreteKey& j, SOURCE table) { @@ -90,7 +90,7 @@ public: /** Main elimination function for DiscreteFactorGraph */ GTSAM_EXPORT std::pair, DecisionTreeFactor::shared_ptr> -EliminateDiscrete(const FactorGraph& factors, +EliminateDiscrete(const FactorGraphOrdered& factors, size_t nrFrontals = 1); } // namespace gtsam diff --git a/gtsam/discrete/DiscreteMarginals.h b/gtsam/discrete/DiscreteMarginals.h index 411e4a4dd..c55f5956a 100644 --- a/gtsam/discrete/DiscreteMarginals.h +++ b/gtsam/discrete/DiscreteMarginals.h @@ -32,7 +32,7 @@ namespace gtsam { protected: - BayesTree bayesTree_; + BayesTreeOrdered bayesTree_; public: @@ -40,7 +40,7 @@ namespace gtsam { * @param graph The factor graph defining the full joint density on all variables. */ DiscreteMarginals(const DiscreteFactorGraph& graph) { - typedef JunctionTree DiscreteJT; + typedef JunctionTreeOrdered DiscreteJT; GenericMultifrontalSolver solver(graph); bayesTree_ = *solver.eliminate(&EliminateDiscrete); } diff --git a/gtsam/discrete/DiscreteSequentialSolver.h b/gtsam/discrete/DiscreteSequentialSolver.h index 36cf25545..8c007968e 100644 --- a/gtsam/discrete/DiscreteSequentialSolver.h +++ b/gtsam/discrete/DiscreteSequentialSolver.h @@ -47,7 +47,7 @@ namespace gtsam { * Construct the solver for a factor graph. This builds the elimination * tree, which already does some of the work of elimination. */ - DiscreteSequentialSolver(const FactorGraph& factorGraph) : + DiscreteSequentialSolver(const FactorGraphOrdered& factorGraph) : Base(factorGraph) { } @@ -57,12 +57,12 @@ namespace gtsam { * is the fastest. */ DiscreteSequentialSolver( - const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex) : + const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex) : Base(factorGraph, variableIndex) { } - const EliminationTree& eliminationTree() const { + const EliminationTreeOrdered& eliminationTree() const { return *eliminationTree_; } @@ -70,7 +70,7 @@ namespace gtsam { * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. */ - BayesNet::shared_ptr eliminate() const { + BayesNetOrdered::shared_ptr eliminate() const { return Base::eliminate(&EliminateDiscrete); } diff --git a/gtsam/discrete/Potentials.h b/gtsam/discrete/Potentials.h index 33e266c91..1f190da82 100644 --- a/gtsam/discrete/Potentials.h +++ b/gtsam/discrete/Potentials.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include diff --git a/gtsam/discrete/tests/testDiscreteBayesTree.cpp b/gtsam/discrete/tests/testDiscreteBayesTree.cpp index e3a771940..eb8d3b3a6 100644 --- a/gtsam/discrete/tests/testDiscreteBayesTree.cpp +++ b/gtsam/discrete/tests/testDiscreteBayesTree.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include using namespace boost::assign; @@ -32,13 +32,13 @@ static bool debug = false; /** * Custom clique class to debug shortcuts */ -class Clique: public BayesTreeCliqueBase { +class Clique: public BayesTreeCliqueBaseOrdered { protected: public: - typedef BayesTreeCliqueBase Base; + typedef BayesTreeCliqueBaseOrdered Base; typedef boost::shared_ptr shared_ptr; // Constructors @@ -56,7 +56,7 @@ public: /// print index signature only void printSignature(const std::string& s = "Clique: ", const IndexFormatter& indexFormatter = DefaultIndexFormatter) const { - ((IndexConditional::shared_ptr) conditional_)->print(s, indexFormatter); + ((IndexConditionalOrdered::shared_ptr) conditional_)->print(s, indexFormatter); } /// evaluate value of sub-tree @@ -70,7 +70,7 @@ public: }; -typedef BayesTree DiscreteBayesTree; +typedef BayesTreeOrdered DiscreteBayesTree; /* ************************************************************************* */ double evaluate(const DiscreteBayesTree& tree, diff --git a/gtsam/discrete/tests/testDiscreteFactorGraph.cpp b/gtsam/discrete/tests/testDiscreteFactorGraph.cpp index f1b29a757..e30d3bb61 100644 --- a/gtsam/discrete/tests/testDiscreteFactorGraph.cpp +++ b/gtsam/discrete/tests/testDiscreteFactorGraph.cpp @@ -60,7 +60,7 @@ TEST_UNSAFE( DiscreteFactorGraph, debugScheduler) { // DiscreteSequentialSolver solver(graph); // solver.print("solver:"); - EliminationTree eliminationTree = solver.eliminationTree(); + EliminationTreeOrdered eliminationTree = solver.eliminationTree(); // eliminationTree.print("Elimination tree: "); eliminationTree.eliminate(EliminateDiscrete); // solver.optimize(); @@ -155,7 +155,7 @@ TEST( DiscreteFactorGraph, test) // GTSAM_PRINT(expected); // Test elimination tree - const EliminationTree& etree = solver.eliminationTree(); + const EliminationTreeOrdered& etree = solver.eliminationTree(); DiscreteBayesNet::shared_ptr actual = etree.eliminate(&EliminateDiscrete); EXPECT(assert_equal(expected, *actual)); @@ -221,16 +221,16 @@ TEST( DiscreteFactorGraph, testMPE_Darwiche09book_p244) // EXPECT_DOUBLES_EQUAL(0.4, (*root)(*actualMPE), 1e-9); // Let us create the Bayes tree here, just for fun, because we don't use it now - typedef JunctionTree JT; + typedef JunctionTreeOrdered JT; GenericMultifrontalSolver solver(graph); - BayesTree::shared_ptr bayesTree = solver.eliminate(&EliminateDiscrete); + BayesTreeOrdered::shared_ptr bayesTree = solver.eliminate(&EliminateDiscrete); // bayesTree->print("Bayes Tree"); EXPECT_LONGS_EQUAL(2,bayesTree->size()); #ifdef OLD // Create the elimination tree manually -VariableIndex structure(graph); -typedef EliminationTree ETree; +VariableIndexOrdered structure(graph); +typedef EliminationTreeOrdered ETree; ETree::shared_ptr eTree = ETree::Create(graph, structure); //eTree->print(">>>>>>>>>>> Elimination Tree <<<<<<<<<<<<<<<<<"); diff --git a/gtsam/discrete/tests/testDiscreteMarginals.cpp b/gtsam/discrete/tests/testDiscreteMarginals.cpp index 5ca26200f..a66ee0de2 100644 --- a/gtsam/discrete/tests/testDiscreteMarginals.cpp +++ b/gtsam/discrete/tests/testDiscreteMarginals.cpp @@ -119,9 +119,9 @@ TEST_UNSAFE( DiscreteMarginals, truss ) { graph.add(key[0] & key[2] & key[4],"2 2 2 2 1 1 1 1"); graph.add(key[1] & key[3] & key[4],"1 1 1 1 2 2 2 2"); graph.add(key[2] & key[3] & key[4],"1 1 1 1 1 1 1 1"); - typedef JunctionTree JT; + typedef JunctionTreeOrdered JT; GenericMultifrontalSolver solver(graph); - BayesTree::shared_ptr bayesTree = solver.eliminate(&EliminateDiscrete); + BayesTreeOrdered::shared_ptr bayesTree = solver.eliminate(&EliminateDiscrete); // bayesTree->print("Bayes Tree"); typedef BayesTreeClique Clique; diff --git a/gtsam/inference/BayesNetUnordered-inst.h b/gtsam/inference/BayesNet-inst.h similarity index 80% rename from gtsam/inference/BayesNetUnordered-inst.h rename to gtsam/inference/BayesNet-inst.h index fa9096051..db9c29519 100644 --- a/gtsam/inference/BayesNetUnordered-inst.h +++ b/gtsam/inference/BayesNet-inst.h @@ -18,8 +18,8 @@ #pragma once -#include -#include +#include +#include #include #include @@ -28,14 +28,14 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesNetUnordered::print(const std::string& s, const KeyFormatter& formatter) const + void BayesNet::print(const std::string& s, const KeyFormatter& formatter) const { Base::print(s, formatter); } /* ************************************************************************* */ template - void BayesNetUnordered::saveGraph(const std::string &s, const KeyFormatter& keyFormatter) const + void BayesNet::saveGraph(const std::string &s, const KeyFormatter& keyFormatter) const { std::ofstream of(s.c_str()); of << "digraph G{\n"; diff --git a/gtsam/inference/BayesNet.h b/gtsam/inference/BayesNet.h index ad39da301..62072ee18 100644 --- a/gtsam/inference/BayesNet.h +++ b/gtsam/inference/BayesNet.h @@ -1,244 +1,72 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file BayesNet.h - * @brief Bayes network - * @author Frank Dellaert - */ - -// \callgraph - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace gtsam { - -/** - * A BayesNet is a list of conditionals, stored in elimination order, i.e. - * leaves first, parents last. GaussianBayesNet and SymbolicBayesNet are - * defined as typedefs of this class, using GaussianConditional and - * IndexConditional as the CONDITIONAL template argument. - * - * todo: Symbolic using Index is a misnomer. - * todo: how to handle Bayes nets with an optimize function? Currently using global functions. - * \nosubgrouping - */ -template -class BayesNet { - -public: - - typedef typename boost::shared_ptr > shared_ptr; - - /** We store shared pointers to Conditional densities */ - typedef typename CONDITIONAL::KeyType KeyType; - typedef typename boost::shared_ptr sharedConditional; - typedef typename boost::shared_ptr const_sharedConditional; - typedef typename std::list Conditionals; - - typedef typename Conditionals::iterator iterator; - typedef typename Conditionals::reverse_iterator reverse_iterator; - typedef typename Conditionals::const_iterator const_iterator; - typedef typename Conditionals::const_reverse_iterator const_reverse_iterator; - -protected: - - /** - * Conditional densities are stored in reverse topological sort order (i.e., leaves first, - * parents last), which corresponds to the elimination ordering if so obtained, - * and is consistent with the column (block) ordering of an upper triangular matrix. - */ - Conditionals conditionals_; - -public: - - /// @name Standard Constructors - /// @{ - - /** Default constructor as an empty BayesNet */ - BayesNet() {}; - - /** convert from a derived type */ - template - BayesNet(const BayesNet& bn) { - conditionals_.assign(bn.begin(), bn.end()); - } - - /** BayesNet with 1 conditional */ - explicit BayesNet(const sharedConditional& conditional) { push_back(conditional); } - - /// @} - /// @name Testable - /// @{ - - /** print */ - void print(const std::string& s = "", - const IndexFormatter& formatter = DefaultIndexFormatter) const; - - /** check equality */ - bool equals(const BayesNet& other, double tol = 1e-9) const; - - /// @} - /// @name Standard Interface - /// @{ - - /** size is the number of nodes */ - size_t size() const { - return conditionals_.size(); - } - - /** @return true if there are no conditionals/nodes */ - bool empty() const { - return conditionals_.empty(); - } - - /** print statistics */ - void printStats(const std::string& s = "") const; - - /** save dot graph */ - void saveGraph(const std::string &s, const IndexFormatter& indexFormatter = - DefaultIndexFormatter) const; - - /** return keys in reverse topological sort order, i.e., elimination order */ - FastList ordering() const; - - /** SLOW O(n) random access to Conditional by key */ - sharedConditional operator[](Index key) const; - - /** return last node in ordering */ - boost::shared_ptr front() const { return conditionals_.front(); } - - /** return last node in ordering */ - boost::shared_ptr back() const { return conditionals_.back(); } - - /** return iterators. FD: breaks encapsulation? */ - const_iterator begin() const {return conditionals_.begin();} ///& bn); - - /// push_front an entire Bayes net - void push_front(const BayesNet& bn); - - /** += syntax for push_back, e.g. bayesNet += c1, c2, c3 - * @param conditional The conditional to add to the back of the BayesNet - */ - boost::assign::list_inserter >, sharedConditional> - operator+=(const sharedConditional& conditional) { - return boost::assign::make_list_inserter(boost::assign_detail::call_push_back >(*this))(conditional); } - - /** - * pop_front: remove node at the bottom, used in marginalization - * For example P(ABC)=P(A|BC)P(B|C)P(C) becomes P(BC)=P(B|C)P(C) - */ - void pop_front() {conditionals_.pop_front();} - - /** Permute the variables in the BayesNet */ - void permuteWithInverse(const Permutation& inversePermutation); - - iterator begin() {return conditionals_.begin();} /// - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(conditionals_); - } - - /// @} -}; // BayesNet - -} // namespace gtsam - -#include +/* ---------------------------------------------------------------------------- + +* GTSAM Copyright 2010, Georgia Tech Research Corporation, +* Atlanta, Georgia 30332-0415 +* All Rights Reserved +* Authors: Frank Dellaert, et al. (see THANKS for the full author list) + +* See LICENSE for the license information + +* -------------------------------------------------------------------------- */ + +/** +* @file BayesNet.h +* @brief Bayes network +* @author Frank Dellaert +* @author Richard Roberts +*/ + +#pragma once + +#include + +#include + +namespace gtsam { + + /** + * A BayesNet is a tree of conditionals, stored in elimination order. + * + * todo: how to handle Bayes nets with an optimize function? Currently using global functions. + * \nosubgrouping + */ + template + class BayesNet : public FactorGraph { + + private: + + typedef FactorGraph Base; + + public: + typedef typename boost::shared_ptr sharedConditional; ///< A shared pointer to a conditional + + protected: + /// @name Standard Constructors + /// @{ + + /** Default constructor as an empty BayesNet */ + BayesNet() {}; + + /** Construct from iterator over conditionals */ + template + BayesNet(ITERATOR firstConditional, ITERATOR lastConditional) : Base(firstConditional, lastConditional) {} + + /// @} + + public: + /// @name Testable + /// @{ + + /** print out graph */ + void print(const std::string& s = "BayesNet", + const KeyFormatter& formatter = DefaultKeyFormatter) const; + + /// @} + + /// @name Standard Interface + /// @{ + + void saveGraph(const std::string &s, const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; + }; + +} \ No newline at end of file diff --git a/gtsam/inference/BayesNet-inl.h b/gtsam/inference/BayesNetOrdered-inl.h similarity index 86% rename from gtsam/inference/BayesNet-inl.h rename to gtsam/inference/BayesNetOrdered-inl.h index f0e26c98b..bdf07942b 100644 --- a/gtsam/inference/BayesNet-inl.h +++ b/gtsam/inference/BayesNetOrdered-inl.h @@ -34,7 +34,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesNet::print(const std::string& s, + void BayesNetOrdered::print(const std::string& s, const IndexFormatter& formatter) const { std::cout << s; BOOST_REVERSE_FOREACH(sharedConditional conditional, conditionals_) @@ -43,7 +43,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool BayesNet::equals(const BayesNet& cbn, double tol) const { + bool BayesNetOrdered::equals(const BayesNetOrdered& cbn, double tol) const { if (size() != cbn.size()) return false; return std::equal(conditionals_.begin(), conditionals_.end(), @@ -52,7 +52,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesNet::printStats(const std::string& s) const { + void BayesNetOrdered::printStats(const std::string& s) const { const size_t n = conditionals_.size(); size_t max_size = 0; @@ -69,7 +69,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesNet::saveGraph(const std::string &s, + void BayesNetOrdered::saveGraph(const std::string &s, const IndexFormatter& indexFormatter) const { std::ofstream of(s.c_str()); of << "digraph G{\n"; @@ -88,7 +88,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesNet::const_iterator BayesNet::find( + typename BayesNetOrdered::const_iterator BayesNetOrdered::find( Index key) const { for (const_iterator it = begin(); it != end(); ++it) if (std::find((*it)->beginFrontals(), (*it)->endFrontals(), key) @@ -99,7 +99,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesNet::iterator BayesNet::find( + typename BayesNetOrdered::iterator BayesNetOrdered::find( Index key) { for (iterator it = begin(); it != end(); ++it) if (std::find((*it)->beginFrontals(), (*it)->endFrontals(), key) @@ -110,7 +110,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesNet::permuteWithInverse( + void BayesNetOrdered::permuteWithInverse( const Permutation& inversePermutation) { BOOST_FOREACH(sharedConditional conditional, conditionals_) { conditional->permuteWithInverse(inversePermutation); @@ -119,21 +119,21 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesNet::push_back(const BayesNet& bn) { + void BayesNetOrdered::push_back(const BayesNetOrdered& bn) { BOOST_FOREACH(sharedConditional conditional,bn.conditionals_) push_back(conditional); } /* ************************************************************************* */ template - void BayesNet::push_front(const BayesNet& bn) { + void BayesNetOrdered::push_front(const BayesNetOrdered& bn) { BOOST_FOREACH(sharedConditional conditional,bn.conditionals_) push_front(conditional); } /* ************************************************************************* */ template - void BayesNet::popLeaf(iterator conditional) { + void BayesNetOrdered::popLeaf(iterator conditional) { #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS BOOST_FOREACH(typename CONDITIONAL::shared_ptr checkConditional, conditionals_) { BOOST_FOREACH(Index key, (*conditional)->frontals()) { @@ -148,7 +148,7 @@ namespace gtsam { /* ************************************************************************* */ template - FastList BayesNet::ordering() const { + FastList BayesNetOrdered::ordering() const { FastList ord; BOOST_FOREACH(sharedConditional conditional,conditionals_) ord.insert(ord.begin(), conditional->beginFrontals(), @@ -174,7 +174,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesNet::sharedConditional BayesNet::operator[]( + typename BayesNetOrdered::sharedConditional BayesNetOrdered::operator[]( Index key) const { BOOST_FOREACH(typename CONDITIONAL::shared_ptr conditional, conditionals_) { typename CONDITIONAL::const_iterator it = std::find( diff --git a/gtsam/inference/BayesNetOrdered.h b/gtsam/inference/BayesNetOrdered.h new file mode 100644 index 000000000..073e2e88b --- /dev/null +++ b/gtsam/inference/BayesNetOrdered.h @@ -0,0 +1,244 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file BayesNet.h + * @brief Bayes network + * @author Frank Dellaert + */ + +// \callgraph + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace gtsam { + +/** + * A BayesNet is a list of conditionals, stored in elimination order, i.e. + * leaves first, parents last. GaussianBayesNet and SymbolicBayesNet are + * defined as typedefs of this class, using GaussianConditional and + * IndexConditional as the CONDITIONAL template argument. + * + * todo: Symbolic using Index is a misnomer. + * todo: how to handle Bayes nets with an optimize function? Currently using global functions. + * \nosubgrouping + */ +template +class BayesNetOrdered { + +public: + + typedef typename boost::shared_ptr > shared_ptr; + + /** We store shared pointers to Conditional densities */ + typedef typename CONDITIONAL::KeyType KeyType; + typedef typename boost::shared_ptr sharedConditional; + typedef typename boost::shared_ptr const_sharedConditional; + typedef typename std::list Conditionals; + + typedef typename Conditionals::iterator iterator; + typedef typename Conditionals::reverse_iterator reverse_iterator; + typedef typename Conditionals::const_iterator const_iterator; + typedef typename Conditionals::const_reverse_iterator const_reverse_iterator; + +protected: + + /** + * Conditional densities are stored in reverse topological sort order (i.e., leaves first, + * parents last), which corresponds to the elimination ordering if so obtained, + * and is consistent with the column (block) ordering of an upper triangular matrix. + */ + Conditionals conditionals_; + +public: + + /// @name Standard Constructors + /// @{ + + /** Default constructor as an empty BayesNet */ + BayesNetOrdered() {}; + + /** convert from a derived type */ + template + BayesNetOrdered(const BayesNetOrdered& bn) { + conditionals_.assign(bn.begin(), bn.end()); + } + + /** BayesNet with 1 conditional */ + explicit BayesNetOrdered(const sharedConditional& conditional) { push_back(conditional); } + + /// @} + /// @name Testable + /// @{ + + /** print */ + void print(const std::string& s = "", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /** check equality */ + bool equals(const BayesNetOrdered& other, double tol = 1e-9) const; + + /// @} + /// @name Standard Interface + /// @{ + + /** size is the number of nodes */ + size_t size() const { + return conditionals_.size(); + } + + /** @return true if there are no conditionals/nodes */ + bool empty() const { + return conditionals_.empty(); + } + + /** print statistics */ + void printStats(const std::string& s = "") const; + + /** save dot graph */ + void saveGraph(const std::string &s, const IndexFormatter& indexFormatter = + DefaultIndexFormatter) const; + + /** return keys in reverse topological sort order, i.e., elimination order */ + FastList ordering() const; + + /** SLOW O(n) random access to Conditional by key */ + sharedConditional operator[](Index key) const; + + /** return last node in ordering */ + boost::shared_ptr front() const { return conditionals_.front(); } + + /** return last node in ordering */ + boost::shared_ptr back() const { return conditionals_.back(); } + + /** return iterators. FD: breaks encapsulation? */ + const_iterator begin() const {return conditionals_.begin();} ///& bn); + + /// push_front an entire Bayes net + void push_front(const BayesNetOrdered& bn); + + /** += syntax for push_back, e.g. bayesNet += c1, c2, c3 + * @param conditional The conditional to add to the back of the BayesNet + */ + boost::assign::list_inserter >, sharedConditional> + operator+=(const sharedConditional& conditional) { + return boost::assign::make_list_inserter(boost::assign_detail::call_push_back >(*this))(conditional); } + + /** + * pop_front: remove node at the bottom, used in marginalization + * For example P(ABC)=P(A|BC)P(B|C)P(C) becomes P(BC)=P(B|C)P(C) + */ + void pop_front() {conditionals_.pop_front();} + + /** Permute the variables in the BayesNet */ + void permuteWithInverse(const Permutation& inversePermutation); + + iterator begin() {return conditionals_.begin();} /// + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(conditionals_); + } + + /// @} +}; // BayesNet + +} // namespace gtsam + +#include diff --git a/gtsam/inference/BayesNetUnordered.h b/gtsam/inference/BayesNetUnordered.h deleted file mode 100644 index f10ace87a..000000000 --- a/gtsam/inference/BayesNetUnordered.h +++ /dev/null @@ -1,72 +0,0 @@ -/* ---------------------------------------------------------------------------- - -* GTSAM Copyright 2010, Georgia Tech Research Corporation, -* Atlanta, Georgia 30332-0415 -* All Rights Reserved -* Authors: Frank Dellaert, et al. (see THANKS for the full author list) - -* See LICENSE for the license information - -* -------------------------------------------------------------------------- */ - -/** -* @file BayesNet.h -* @brief Bayes network -* @author Frank Dellaert -* @author Richard Roberts -*/ - -#pragma once - -#include - -#include - -namespace gtsam { - - /** - * A BayesNet is a tree of conditionals, stored in elimination order. - * - * todo: how to handle Bayes nets with an optimize function? Currently using global functions. - * \nosubgrouping - */ - template - class BayesNetUnordered : public FactorGraphUnordered { - - private: - - typedef FactorGraphUnordered Base; - - public: - typedef typename boost::shared_ptr sharedConditional; ///< A shared pointer to a conditional - - protected: - /// @name Standard Constructors - /// @{ - - /** Default constructor as an empty BayesNet */ - BayesNetUnordered() {}; - - /** Construct from iterator over conditionals */ - template - BayesNetUnordered(ITERATOR firstConditional, ITERATOR lastConditional) : Base(firstConditional, lastConditional) {} - - /// @} - - public: - /// @name Testable - /// @{ - - /** print out graph */ - void print(const std::string& s = "BayesNet", - const KeyFormatter& formatter = DefaultKeyFormatter) const; - - /// @} - - /// @name Standard Interface - /// @{ - - void saveGraph(const std::string &s, const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; - }; - -} \ No newline at end of file diff --git a/gtsam/inference/BayesTreeUnordered-inst.h b/gtsam/inference/BayesTree-inst.h similarity index 83% rename from gtsam/inference/BayesTreeUnordered-inst.h rename to gtsam/inference/BayesTree-inst.h index a072781e5..0a238267b 100644 --- a/gtsam/inference/BayesTreeUnordered-inst.h +++ b/gtsam/inference/BayesTree-inst.h @@ -20,7 +20,7 @@ #pragma once -#include +#include #include #include @@ -34,8 +34,8 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTreeUnordered::CliqueData - BayesTreeUnordered::getCliqueData() const { + typename BayesTree::CliqueData + BayesTree::getCliqueData() const { CliqueData data; BOOST_FOREACH(const sharedClique& root, roots_) getCliqueData(data, root); @@ -44,7 +44,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::getCliqueData(CliqueData& data, sharedClique clique) const { + void BayesTree::getCliqueData(CliqueData& data, sharedClique clique) const { data.conditionalSizes.push_back(clique->conditional()->nrFrontals()); data.separatorSizes.push_back(clique->conditional()->nrParents()); BOOST_FOREACH(sharedClique c, clique->children) { @@ -54,7 +54,7 @@ namespace gtsam { /* ************************************************************************* */ template - size_t BayesTreeUnordered::numCachedSeparatorMarginals() const { + size_t BayesTree::numCachedSeparatorMarginals() const { size_t count = 0; BOOST_FOREACH(const sharedClique& root, roots_) count += root->numCachedSeparatorMarginals(); @@ -63,7 +63,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::saveGraph(const std::string &s, const KeyFormatter& keyFormatter) const { + void BayesTree::saveGraph(const std::string &s, const KeyFormatter& keyFormatter) const { if (roots_.empty()) throw std::invalid_argument("the root of Bayes tree has not been initialized!"); std::ofstream of(s.c_str()); of<< "digraph G{\n"; @@ -75,7 +75,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::saveGraph(std::ostream &s, sharedClique clique, const KeyFormatter& indexFormatter, int parentnum) const { + void BayesTree::saveGraph(std::ostream &s, sharedClique clique, const KeyFormatter& indexFormatter, int parentnum) const { static int num = 0; bool first = true; std::stringstream out; @@ -111,7 +111,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::CliqueStats::print(const std::string& s) const { + void BayesTree::CliqueStats::print(const std::string& s) const { std::cout << s << "avg Conditional Size: " << avgConditionalSize << std::endl << "max Conditional Size: " << maxConditionalSize << std::endl @@ -121,8 +121,8 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTreeUnordered::CliqueStats - BayesTreeUnordered::CliqueData::getStats() const + typename BayesTree::CliqueStats + BayesTree::CliqueData::getStats() const { CliqueStats stats; @@ -149,7 +149,7 @@ namespace gtsam { /* ************************************************************************* */ template - size_t BayesTreeUnordered::size() const { + size_t BayesTree::size() const { size_t size = 0; BOOST_FOREACH(const sharedClique& clique, roots_) size += clique->treeSize(); @@ -158,7 +158,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::addClique(const sharedClique& clique, const sharedClique& parent_clique) { + void BayesTree::addClique(const sharedClique& clique, const sharedClique& parent_clique) { BOOST_FOREACH(Index j, clique->conditional()->frontals()) nodes_[j] = clique; if (parent_clique != NULL) { @@ -171,7 +171,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTreeUnordered::sharedClique BayesTreeUnordered::addClique( + typename BayesTree::sharedClique BayesTree::addClique( const sharedConditional& conditional, std::list& child_cliques) { sharedClique new_clique(new Clique(conditional)); @@ -186,7 +186,7 @@ namespace gtsam { /* ************************************************************************* */ namespace { template - int _pushClique(FactorGraphUnordered& fg, const boost::shared_ptr& clique) { + int _pushClique(FactorGraph& fg, const boost::shared_ptr& clique) { fg.push_back(clique->conditional_); return 0; } @@ -194,7 +194,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::addFactorsToGraph(FactorGraphUnordered& graph) const + void BayesTree::addFactorsToGraph(FactorGraph& graph) const { // Traverse the BayesTree and add all conditionals to this graph int data = 0; // Unused @@ -203,7 +203,7 @@ namespace gtsam { /* ************************************************************************* */ template - BayesTreeUnordered::BayesTreeUnordered(const This& other) { + BayesTree::BayesTree(const This& other) { *this = other; } @@ -224,7 +224,7 @@ namespace gtsam { /* ************************************************************************* */ template - BayesTreeUnordered& BayesTreeUnordered::operator=(const This& other) { + BayesTree& BayesTree::operator=(const This& other) { this->clear(); boost::shared_ptr rootContainer = boost::make_shared(); treeTraversal::DepthFirstForest(other, rootContainer, BayesTreeCloneForestVisitorPre); @@ -237,7 +237,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::print(const std::string& s, const KeyFormatter& keyFormatter) const { + void BayesTree::print(const std::string& s, const KeyFormatter& keyFormatter) const { std::cout << s << ": cliques: " << size() << ", variables: " << nodes_.size() << std::endl; treeTraversal::PrintForest(*this, s, keyFormatter); } @@ -246,8 +246,8 @@ namespace gtsam { // binary predicate to test equality of a pair for use in equals template bool check_sharedCliques( - const std::pair::sharedClique>& v1, - const std::pair::sharedClique>& v2 + const std::pair::sharedClique>& v1, + const std::pair::sharedClique>& v2 ) { return v1.first == v2.first && ((!v1.second && !v2.second) || (v1.second && v2.second && v1.second->equals(*v2.second))); @@ -255,7 +255,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool BayesTreeUnordered::equals(const BayesTreeUnordered& other, double tol) const { + bool BayesTree::equals(const BayesTree& other, double tol) const { return size()==other.size() && std::equal(nodes_.begin(), nodes_.end(), other.nodes_.begin(), &check_sharedCliques); } @@ -263,7 +263,7 @@ namespace gtsam { /* ************************************************************************* */ template template - Key BayesTreeUnordered::findParentClique(const CONTAINER& parents) const { + Key BayesTree::findParentClique(const CONTAINER& parents) const { typename CONTAINER::const_iterator lowestOrderedParent = min_element(parents.begin(), parents.end()); assert(lowestOrderedParent != parents.end()); return *lowestOrderedParent; @@ -271,18 +271,18 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::fillNodesIndex(const sharedClique& subtree) { + void BayesTree::fillNodesIndex(const sharedClique& subtree) { // Add each frontal variable of this root node BOOST_FOREACH(const Key& j, subtree->conditional()->frontals()) { nodes_[j] = subtree; } // Fill index for each child - typedef typename BayesTreeUnordered::sharedClique sharedClique; + typedef typename BayesTree::sharedClique sharedClique; BOOST_FOREACH(const sharedClique& child, subtree->children) { fillNodesIndex(child); } } /* ************************************************************************* */ template - void BayesTreeUnordered::insertRoot(const sharedClique& subtree) { + void BayesTree::insertRoot(const sharedClique& subtree) { roots_.push_back(subtree); // Add to roots fillNodesIndex(subtree); // Populate nodes index } @@ -291,8 +291,8 @@ namespace gtsam { // First finds clique marginal then marginalizes that /* ************************************************************************* */ template - typename BayesTreeUnordered::sharedConditional - BayesTreeUnordered::marginalFactor(Key j, const Eliminate& function) const + typename BayesTree::sharedConditional + BayesTree::marginalFactor(Key j, const Eliminate& function) const { gttic(BayesTree_marginalFactor); @@ -304,7 +304,7 @@ namespace gtsam { // Now, marginalize out everything that is not variable j BayesNetType marginalBN = *cliqueMarginal.marginalMultifrontalBayesNet( - OrderingUnordered(cref_list_of<1,Key>(j)), boost::none, function); + Ordering(cref_list_of<1,Key>(j)), boost::none, function); // The Bayes net should contain only one conditional for variable j, so return it return marginalBN.front(); @@ -314,8 +314,8 @@ namespace gtsam { // Find two cliques, their joint, then marginalizes /* ************************************************************************* */ template - typename BayesTreeUnordered::sharedFactorGraph - BayesTreeUnordered::joint(Key j1, Key j2, const Eliminate& function) const + typename BayesTree::sharedFactorGraph + BayesTree::joint(Key j1, Key j2, const Eliminate& function) const { gttic(BayesTree_joint); return boost::make_shared(*jointBayesNet(j1, j2, function)); @@ -323,8 +323,8 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTreeUnordered::sharedBayesNet - BayesTreeUnordered::jointBayesNet(Key j1, Key j2, const Eliminate& function) const + typename BayesTree::sharedBayesNet + BayesTree::jointBayesNet(Key j1, Key j2, const Eliminate& function) const { gttic(BayesTree_jointBayesNet); // get clique C1 and C2 @@ -385,7 +385,7 @@ namespace gtsam { // Factor into C1\B | B. sharedFactorGraph temp_remaining; boost::tie(p_C1_B, temp_remaining) = - FactorGraphType(p_C1_Bred).eliminatePartialMultifrontal(OrderingUnordered(C1_minus_B), function); + FactorGraphType(p_C1_Bred).eliminatePartialMultifrontal(Ordering(C1_minus_B), function); } shared_ptr p_C2_B; { std::vector C2_minus_B; { @@ -397,7 +397,7 @@ namespace gtsam { // Factor into C2\B | B. sharedFactorGraph temp_remaining; boost::tie(p_C2_B, temp_remaining) = - FactorGraphType(p_C2_Bred).eliminatePartialMultifrontal(OrderingUnordered(C2_minus_B), function); + FactorGraphType(p_C2_Bred).eliminatePartialMultifrontal(Ordering(C2_minus_B), function); } gttoc(Full_root_factoring); @@ -413,12 +413,12 @@ namespace gtsam { p_BC1C2 += C2->conditional(); // now, marginalize out everything that is not variable j1 or j2 - return p_BC1C2.marginalMultifrontalBayesNet(OrderingUnordered(cref_list_of<2,Key>(j1)(j2)), boost::none, function); + return p_BC1C2.marginalMultifrontalBayesNet(Ordering(cref_list_of<2,Key>(j1)(j2)), boost::none, function); } /* ************************************************************************* */ template - void BayesTreeUnordered::clear() { + void BayesTree::clear() { // Remove all nodes and clear the root pointer nodes_.clear(); roots_.clear(); @@ -426,7 +426,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::deleteCachedShortcuts() { + void BayesTree::deleteCachedShortcuts() { BOOST_FOREACH(const sharedClique& root, roots_) { root->deleteCachedShortcuts(); } @@ -434,7 +434,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::removeClique(sharedClique clique) + void BayesTree::removeClique(sharedClique clique) { if (clique->isRoot()) { std::vector::iterator root = std::find(roots_.begin(), roots_.end(), clique); @@ -458,7 +458,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::removePath(sharedClique clique, BayesNetType& bn, Cliques& orphans) + void BayesTree::removePath(sharedClique clique, BayesNetType& bn, Cliques& orphans) { // base case is NULL, if so we do nothing and return empties above if (clique!=NULL) { @@ -483,7 +483,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeUnordered::removeTop(const std::vector& keys, BayesNetType& bn, Cliques& orphans) + void BayesTree::removeTop(const std::vector& keys, BayesNetType& bn, Cliques& orphans) { // process each key of the new factor BOOST_FOREACH(const Key& j, keys) @@ -505,7 +505,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTreeUnordered::Cliques BayesTreeUnordered::removeSubtree( + typename BayesTree::Cliques BayesTree::removeSubtree( const sharedClique& subtree) { // Result clique list diff --git a/gtsam/inference/BayesTree.h b/gtsam/inference/BayesTree.h index 9e487d0a2..e6e0e4482 100644 --- a/gtsam/inference/BayesTree.h +++ b/gtsam/inference/BayesTree.h @@ -1,418 +1,259 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file BayesTree.h - * @brief Bayes Tree is a tree of cliques of a Bayes Chain - * @author Frank Dellaert - */ - -// \callgraph - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace gtsam { - - // Forward declaration of BayesTreeClique which is defined below BayesTree in this file - template struct BayesTreeClique; - - /** - * Bayes tree - * @tparam CONDITIONAL The type of the conditional densities, i.e. the type of node in the underlying Bayes chain, - * which could be a ConditionalProbabilityTable, a GaussianConditional, or a SymbolicConditional. - * @tparam CLIQUE The type of the clique data structure, defaults to BayesTreeClique, normally do not change this - * as it is only used when developing special versions of BayesTree, e.g. for ISAM2. - * - * \addtogroup Multifrontal - * \nosubgrouping - */ - template > - class BayesTree { - - public: - - typedef BayesTree This; - typedef boost::shared_ptr > shared_ptr; - typedef boost::shared_ptr sharedConditional; - typedef boost::shared_ptr > sharedBayesNet; - typedef CONDITIONAL ConditionalType; - typedef typename CONDITIONAL::FactorType FactorType; - typedef typename FactorGraph::Eliminate Eliminate; - - typedef CLIQUE Clique; ///< The clique type, normally BayesTreeClique - - // typedef for shared pointers to cliques - typedef boost::shared_ptr sharedClique; - - // A convenience class for a list of shared cliques - struct Cliques : public FastList { - void print(const std::string& s = "Cliques", - const IndexFormatter& indexFormatter = DefaultIndexFormatter) const; - bool equals(const Cliques& other, double tol = 1e-9) const; - }; - - /** clique statistics */ - struct CliqueStats { - double avgConditionalSize; - std::size_t maxConditionalSize; - double avgSeparatorSize; - std::size_t maxSeparatorSize; - void print(const std::string& s = "") const ; - }; - - /** store all the sizes */ - struct CliqueData { - std::vector conditionalSizes; - std::vector separatorSizes; - CliqueStats getStats() const; - }; - - /** Map from indices to Clique */ - typedef std::vector Nodes; - - protected: - - /** Map from indices to Clique */ - Nodes nodes_; - - /** Root clique */ - sharedClique root_; - - public: - - /// @name Standard Constructors - /// @{ - - /** Create an empty Bayes Tree */ - BayesTree() {} - - /** Create a Bayes Tree from a Bayes Net (requires CONDITIONAL is IndexConditional *or* CONDITIONAL::Combine) */ - explicit BayesTree(const BayesNet& bayesNet); - - /** Copy constructor */ - BayesTree(const This& other); - - /** Assignment operator */ - This& operator=(const This& other); - - /// @} - /// @name Advanced Constructors - /// @{ - - /** - * Create a Bayes Tree from a Bayes Net and some subtrees. The Bayes net corresponds to the - * new root clique and the subtrees are connected to the root clique. - */ - BayesTree(const BayesNet& bayesNet, std::list > subtrees); - - /** Destructor */ - virtual ~BayesTree() {} - - /// @} - /// @name Testable - /// @{ - - /** check equality */ - bool equals(const BayesTree& other, double tol = 1e-9) const; - - /** print */ - void print(const std::string& s = "", - const IndexFormatter& indexFormatter = DefaultIndexFormatter ) const; - - /// @} - /// @name Standard Interface - /// @{ - - /** - * Find parent clique of a conditional. It will look at all parents and - * return the one with the lowest index in the ordering. - */ - template - Index findParentClique(const CONTAINER& parents) const; - - /** number of cliques */ - inline size_t size() const { - if(root_) - return root_->treeSize(); - else - return 0; - } - - /** number of nodes */ - inline size_t nrNodes() const { return nodes_.size(); } - - /** Check if there are any cliques in the tree */ - inline bool empty() const { - return nodes_.empty(); - } - - /** return nodes */ - const Nodes& nodes() const { return nodes_; } - - /** return root clique */ - const sharedClique& root() const { return root_; } - - /** find the clique that contains the variable with Index j */ - inline sharedClique operator[](Index j) const { - return nodes_.at(j); - } - - /** alternate syntax for matlab: find the clique that contains the variable with Index j */ - inline sharedClique clique(Index j) const { - return nodes_.at(j); - } - - /** Gather data on all cliques */ - CliqueData getCliqueData() const; - - /** Collect number of cliques with cached separator marginals */ - size_t numCachedSeparatorMarginals() const; - - /** return marginal on any variable */ - typename FactorType::shared_ptr marginalFactor(Index j, Eliminate function) const; - - /** - * return marginal on any variable, as a Bayes Net - * NOTE: this function calls marginal, and then eliminates it into a Bayes Net - * This is more expensive than the above function - */ - typename BayesNet::shared_ptr marginalBayesNet(Index j, Eliminate function) const; - - /** - * return joint on two variables - * Limitation: can only calculate joint if cliques are disjoint or one of them is root - */ - typename FactorGraph::shared_ptr joint(Index j1, Index j2, Eliminate function) const; - - /** - * return joint on two variables as a BayesNet - * Limitation: can only calculate joint if cliques are disjoint or one of them is root - */ - typename BayesNet::shared_ptr jointBayesNet(Index j1, Index j2, Eliminate function) const; - - /** - * Read only with side effects - */ - - /** saves the Tree to a text file in GraphViz format */ - void saveGraph(const std::string& s, const IndexFormatter& indexFormatter = DefaultIndexFormatter ) const; - - /// @} - /// @name Advanced Interface - /// @{ - - /** Access the root clique (non-const version) */ - sharedClique& root() { return root_; } - - /** Access the nodes (non-cost version) */ - Nodes& nodes() { return nodes_; } - - /** Remove all nodes */ - void clear(); - - /** Clear all shortcut caches - use before timing on marginal calculation to avoid residual cache data */ - void deleteCachedShortcuts() { - root_->deleteCachedShortcuts(); - } - - /** Apply a permutation to the full tree - also updates the nodes structure */ - void permuteWithInverse(const Permutation& inversePermutation); - - /** - * Remove path from clique to root and return that path as factors - * plus a list of orphaned subtree roots. Used in removeTop below. - */ - void removePath(sharedClique clique, BayesNet& bn, Cliques& orphans); - - /** - * Given a list of indices, turn "contaminated" part of the tree back into a factor graph. - * Factors and orphans are added to the in/out arguments. - */ - template - void removeTop(const CONTAINER& indices, BayesNet& bn, Cliques& orphans); - - /** - * Remove the requested subtree. */ - Cliques removeSubtree(const sharedClique& subtree); - - /** - * Hang a new subtree off of the existing tree. This finds the appropriate - * parent clique for the subtree (which may be the root), and updates the - * nodes index with the new cliques in the subtree. None of the frontal - * variables in the subtree may appear in the separators of the existing - * BayesTree. - */ - void insert(const sharedClique& subtree); - - /** Insert a new conditional - * This function only applies for Symbolic case with IndexCondtional, - * We make it static so that it won't be compiled in GaussianConditional case. - * */ - static void insert(BayesTree& bayesTree, const sharedConditional& conditional); - - /** - * Insert a new clique corresponding to the given Bayes net. - * It is the caller's responsibility to decide whether the given Bayes net is a valid clique, - * i.e. all the variables (frontal and separator) are connected - */ - sharedClique insert(const sharedConditional& clique, - std::list& children, bool isRootClique = false); - - /** - * Create a clone of this object as a shared pointer - * Necessary for inheritance in matlab interface - */ - virtual shared_ptr clone() const { - return shared_ptr(new This(*this)); - } - - protected: - - /** private helper method for saving the Tree to a text file in GraphViz format */ - void saveGraph(std::ostream &s, sharedClique clique, const IndexFormatter& indexFormatter, - int parentnum = 0) const; - - /** Gather data on a single clique */ - void getCliqueData(CliqueData& stats, sharedClique clique) const; - - /** remove a clique: warning, can result in a forest */ - void removeClique(sharedClique clique); - - /** add a clique (top down) */ - sharedClique addClique(const sharedConditional& conditional, const sharedClique& parent_clique = sharedClique()); - - /** add a clique (top down) */ - void addClique(const sharedClique& clique, const sharedClique& parent_clique = sharedClique()); - - /** add a clique (bottom up) */ - sharedClique addClique(const sharedConditional& conditional, std::list& child_cliques); - - /** - * Add a conditional to the front of a clique, i.e. a conditional whose - * parents are already in the clique or its separators. This function does - * not check for this condition, it just updates the data structures. - */ - static void addToCliqueFront(BayesTree& bayesTree, - const sharedConditional& conditional, const sharedClique& clique); - - /** Fill the nodes index for a subtree */ - void fillNodesIndex(const sharedClique& subtree); - - /** Helper function to build a non-symbolic tree (e.g. Gaussian) using a - * symbolic tree, used in the BT(BN) constructor. - */ - void recursiveTreeBuild(const boost::shared_ptr >& symbolic, - const std::vector >& conditionals, - const typename BayesTree::sharedClique& parent); - - private: - - /** deep copy to another tree */ - void cloneTo(This& newTree) const; - - /** deep copy to another tree */ - void cloneTo(This& newTree, const sharedClique& subtree, const sharedClique& parent) const; - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(nodes_); - ar & BOOST_SERIALIZATION_NVP(root_); - } - - /// @} - - }; // BayesTree - - - /* ************************************************************************* */ - template - void _BayesTree_dim_adder( - std::vector& dims, - const typename BayesTree::sharedClique& clique) { - - if(clique) { - // Add dims from this clique - for(typename CONDITIONAL::const_iterator it = (*clique)->beginFrontals(); it != (*clique)->endFrontals(); ++it) - dims[*it] = (*clique)->dim(it); - - // Traverse children - typedef typename BayesTree::sharedClique sharedClique; - BOOST_FOREACH(const sharedClique& child, clique->children()) { - _BayesTree_dim_adder(dims, child); - } - } - } - - /* ************************************************************************* */ - template - boost::shared_ptr allocateVectorValues(const BayesTree& bt) { - std::vector dimensions(bt.nodes().size(), 0); - _BayesTree_dim_adder(dimensions, bt.root()); - return boost::shared_ptr(new VectorValues(dimensions)); - } - - - /* ************************************************************************* */ - /** - * A Clique in the tree is an incomplete Bayes net: the variables - * in the Bayes net are the frontal nodes, and the variables conditioned - * on are the separator. We also have pointers up and down the tree. - * - * Since our Conditional class already handles multiple frontal variables, - * this Clique contains exactly 1 conditional. - * - * This is the default clique type in a BayesTree, but some algorithms, like - * iSAM2 (see ISAM2Clique), use a different clique type in order to store - * extra data along with the clique. - */ - template - struct BayesTreeClique : public BayesTreeCliqueBase, CONDITIONAL> { - public: - typedef CONDITIONAL ConditionalType; - typedef BayesTreeClique This; - typedef BayesTreeCliqueBase Base; - typedef boost::shared_ptr shared_ptr; - typedef boost::weak_ptr weak_ptr; - BayesTreeClique() {} - BayesTreeClique(const typename ConditionalType::shared_ptr& conditional) : Base(conditional) {} - BayesTreeClique(const std::pair& result) : Base(result) {} - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); - } - }; - -} /// namespace gtsam - -#include -#include +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file BayesTree.h + * @brief Bayes Tree is a tree of cliques of a Bayes Chain + * @author Frank Dellaert + */ + +// \callgraph + +#pragma once + +#include +#include + +#include +#include +#include + +namespace gtsam { + + // Forward declarations + template class FactorGraph; + + /** + * Bayes tree + * @tparam CONDITIONAL The type of the conditional densities, i.e. the type of node in the underlying Bayes chain, + * which could be a ConditionalProbabilityTable, a GaussianConditional, or a SymbolicConditional. + * @tparam CLIQUE The type of the clique data structure, defaults to BayesTreeClique, normally do not change this + * as it is only used when developing special versions of BayesTree, e.g. for ISAM2. + * + * \addtogroup Multifrontal + * \nosubgrouping + */ + template + class BayesTree + { + protected: + typedef BayesTree This; + typedef boost::shared_ptr shared_ptr; + + public: + typedef CLIQUE Clique; ///< The clique type, normally BayesTreeClique + typedef boost::shared_ptr sharedClique; ///< Shared pointer to a clique + typedef Clique Node; ///< Synonym for Clique (TODO: remove) + typedef sharedClique sharedNode; ///< Synonym for sharedClique (TODO: remove) + typedef typename CLIQUE::ConditionalType ConditionalType; + typedef boost::shared_ptr sharedConditional; + typedef typename CLIQUE::BayesNetType BayesNetType; + typedef boost::shared_ptr sharedBayesNet; + typedef typename CLIQUE::FactorType FactorType; + typedef boost::shared_ptr sharedFactor; + typedef typename CLIQUE::FactorGraphType FactorGraphType; + typedef boost::shared_ptr sharedFactorGraph; + typedef typename FactorGraphType::Eliminate Eliminate; + typedef typename CLIQUE::EliminationTraits EliminationTraits; + + /** A convenience class for a list of shared cliques */ + typedef FastList Cliques; + + /** clique statistics */ + struct CliqueStats { + double avgConditionalSize; + std::size_t maxConditionalSize; + double avgSeparatorSize; + std::size_t maxSeparatorSize; + void print(const std::string& s = "") const ; + }; + + /** store all the sizes */ + struct CliqueData { + std::vector conditionalSizes; + std::vector separatorSizes; + CliqueStats getStats() const; + }; + + /** Map from keys to Clique */ + typedef FastMap Nodes; + + protected: + + /** Map from indices to Clique */ + Nodes nodes_; + + /** Root cliques */ + std::vector roots_; + + /// @name Standard Constructors + /// @{ + + /** Create an empty Bayes Tree */ + BayesTree() {} + + /** Copy constructor */ + BayesTree(const This& other); + + /// @} + + /** Assignment operator */ + This& operator=(const This& other); + + /// @name Testable + /// @{ + + /** check equality */ + bool equals(const This& other, double tol = 1e-9) const; + + public: + /** print */ + void print(const std::string& s = "", + const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; + /// @} + + /// @name Standard Interface + /// @{ + + /** number of cliques */ + size_t size() const; + + /** Check if there are any cliques in the tree */ + inline bool empty() const { + return nodes_.empty(); + } + + /** return nodes */ + const Nodes& nodes() const { return nodes_; } + + /** Access node by variable */ + const sharedNode operator[](Key j) const { return nodes_.at(j); } + + /** return root cliques */ + const std::vector& roots() const { return roots_; } + + /** alternate syntax for matlab: find the clique that contains the variable with Index j */ + const sharedClique& clique(Key j) const { + Nodes::const_iterator c = nodes_.find(j); + if(c == nodes_.end()) + throw std::out_of_range("Requested the BayesTree clique for a key that is not in the BayesTree"); + else + return c->second; + } + + /** Gather data on all cliques */ + CliqueData getCliqueData() const; + + /** Collect number of cliques with cached separator marginals */ + size_t numCachedSeparatorMarginals() const; + + /** Return marginal on any variable. Note that this actually returns a conditional, for which a + * solution may be directly obtained by calling .solve() on the returned object. + * Alternatively, it may be directly used as its factor base class. For example, for Gaussian + * systems, this returns a GaussianConditional, which inherits from JacobianFactor and + * GaussianFactor. */ + sharedConditional marginalFactor(Key j, const Eliminate& function = EliminationTraits::DefaultEliminate) const; + + /** + * return joint on two variables + * Limitation: can only calculate joint if cliques are disjoint or one of them is root + */ + sharedFactorGraph joint(Index j1, Index j2, const Eliminate& function = EliminationTraits::DefaultEliminate) const; + + /** + * return joint on two variables as a BayesNet + * Limitation: can only calculate joint if cliques are disjoint or one of them is root + */ + sharedBayesNet jointBayesNet(Index j1, Index j2, const Eliminate& function = EliminationTraits::DefaultEliminate) const; + + /** + * Read only with side effects + */ + + /** saves the Tree to a text file in GraphViz format */ + void saveGraph(const std::string& s, const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; + + /// @} + /// @name Advanced Interface + /// @{ + + /** + * Find parent clique of a conditional. It will look at all parents and + * return the one with the lowest index in the ordering. + */ + template + Index findParentClique(const CONTAINER& parents) const; + + /** Remove all nodes */ + void clear(); + + /** Clear all shortcut caches - use before timing on marginal calculation to avoid residual cache data */ + void deleteCachedShortcuts(); + + /** + * Remove path from clique to root and return that path as factors + * plus a list of orphaned subtree roots. Used in removeTop below. + */ + void removePath(sharedClique clique, BayesNetType& bn, Cliques& orphans); + + /** + * Given a list of indices, turn "contaminated" part of the tree back into a factor graph. + * Factors and orphans are added to the in/out arguments. + */ + void removeTop(const std::vector& keys, BayesNetType& bn, Cliques& orphans); + + /** + * Remove the requested subtree. */ + Cliques removeSubtree(const sharedClique& subtree); + + /** Insert a new subtree with known parent clique. This function does not check that the + * specified parent is the correct parent. This function updates all of the internal data + * structures associated with adding a subtree, such as populating the nodes index. */ + void insertRoot(const sharedClique& subtree); + + /** add a clique (top down) */ + void addClique(const sharedClique& clique, const sharedClique& parent_clique = sharedClique()); + + /** Add all cliques in this BayesTree to the specified factor graph */ + void addFactorsToGraph(FactorGraph& graph) const; + + protected: + + /** private helper method for saving the Tree to a text file in GraphViz format */ + void saveGraph(std::ostream &s, sharedClique clique, const KeyFormatter& keyFormatter, + int parentnum = 0) const; + + /** Gather data on a single clique */ + void getCliqueData(CliqueData& stats, sharedClique clique) const; + + /** remove a clique: warning, can result in a forest */ + void removeClique(sharedClique clique); + + /** add a clique (bottom up) */ + sharedClique addClique(const sharedConditional& conditional, std::list& child_cliques); + + /** Fill the nodes index for a subtree */ + void fillNodesIndex(const sharedClique& subtree); + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(nodes_); + ar & BOOST_SERIALIZATION_NVP(root_); + } + + /// @} + + }; // BayesTree + +} /// namespace gtsam diff --git a/gtsam/inference/BayesTreeCliqueBaseUnordered-inst.h b/gtsam/inference/BayesTreeCliqueBase-inst.h similarity index 78% rename from gtsam/inference/BayesTreeCliqueBaseUnordered-inst.h rename to gtsam/inference/BayesTreeCliqueBase-inst.h index 3e8a2cc6a..243f8adbd 100644 --- a/gtsam/inference/BayesTreeCliqueBaseUnordered-inst.h +++ b/gtsam/inference/BayesTreeCliqueBase-inst.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include @@ -24,7 +24,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool BayesTreeCliqueBaseUnordered::equals( + bool BayesTreeCliqueBase::equals( const DERIVED& other, double tol = 1e-9) const { return (!conditional_ && !other.conditional()) @@ -34,7 +34,7 @@ namespace gtsam { /* ************************************************************************* */ template std::vector - BayesTreeCliqueBaseUnordered::separator_setminus_B(const derived_ptr& B) const + BayesTreeCliqueBase::separator_setminus_B(const derived_ptr& B) const { FastSet p_F_S_parents(this->conditional()->beginParents(), this->conditional()->endParents()); FastSet indicesB(B->conditional()->begin(), B->conditional()->end()); @@ -46,7 +46,7 @@ namespace gtsam { /* ************************************************************************* */ template - std::vector BayesTreeCliqueBaseUnordered::shortcut_indices( + std::vector BayesTreeCliqueBase::shortcut_indices( const derived_ptr& B, const FactorGraphType& p_Cp_B) const { gttic(shortcut_indices); @@ -65,7 +65,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeCliqueBaseUnordered::print( + void BayesTreeCliqueBase::print( const std::string& s, const KeyFormatter& keyFormatter) const { conditional_->print(s, keyFormatter); @@ -73,7 +73,7 @@ namespace gtsam { /* ************************************************************************* */ template - size_t BayesTreeCliqueBaseUnordered::treeSize() const { + size_t BayesTreeCliqueBase::treeSize() const { size_t size = 1; BOOST_FOREACH(const derived_ptr& child, children) size += child->treeSize(); @@ -82,7 +82,7 @@ namespace gtsam { /* ************************************************************************* */ template - size_t BayesTreeCliqueBaseUnordered::numCachedSeparatorMarginals() const + size_t BayesTreeCliqueBase::numCachedSeparatorMarginals() const { if (!cachedSeparatorMarginal_) return 0; @@ -100,10 +100,10 @@ namespace gtsam { // P(Sp|R) as \int P(Fp|Sp) P(Sp|R), where Fp are the frontal nodes in p /* ************************************************************************* */ template - typename BayesTreeCliqueBaseUnordered::BayesNetType - BayesTreeCliqueBaseUnordered::shortcut(const derived_ptr& B, Eliminate function) const + typename BayesTreeCliqueBase::BayesNetType + BayesTreeCliqueBase::shortcut(const derived_ptr& B, Eliminate function) const { - gttic(BayesTreeCliqueBaseUnordered_shortcut); + gttic(BayesTreeCliqueBase_shortcut); // We only calculate the shortcut when this clique is not B // and when the S\B is not empty std::vector S_setminus_B = separator_setminus_B(B); @@ -111,9 +111,9 @@ namespace gtsam { { // Obtain P(Cp||B) = P(Fp|Sp) * P(Sp||B) as a factor graph derived_ptr parent(parent_.lock()); - gttoc(BayesTreeCliqueBaseUnordered_shortcut); + gttoc(BayesTreeCliqueBase_shortcut); FactorGraphType p_Cp_B(parent->shortcut(B, function)); // P(Sp||B) - gttic(BayesTreeCliqueBaseUnordered_shortcut); + gttic(BayesTreeCliqueBase_shortcut); p_Cp_B += parent->conditional_; // P(Fp|Sp) // Determine the variables we want to keepSet, S union B @@ -121,7 +121,7 @@ namespace gtsam { // Marginalize out everything except S union B BayesNetType result = *p_Cp_B.marginalMultifrontalBayesNet( - OrderingUnordered(keep), boost::none, function); + Ordering(keep), boost::none, function); // Finally, we only want to have S\B variables in the Bayes net, so size_t nrFrontals = S_setminus_B.size(); @@ -140,14 +140,14 @@ namespace gtsam { // P(C) = P(F|S) P(S) /* ************************************************************************* */ template - typename BayesTreeCliqueBaseUnordered::FactorGraphType - BayesTreeCliqueBaseUnordered::separatorMarginal(Eliminate function) const + typename BayesTreeCliqueBase::FactorGraphType + BayesTreeCliqueBase::separatorMarginal(Eliminate function) const { - gttic(BayesTreeCliqueBaseUnordered_separatorMarginal); + gttic(BayesTreeCliqueBase_separatorMarginal); // Check if the Separator marginal was already calculated if (!cachedSeparatorMarginal_) { - gttic(BayesTreeCliqueBaseUnordered_separatorMarginal_cachemiss); + gttic(BayesTreeCliqueBase_separatorMarginal_cachemiss); // If this is the root, there is no separator if (parent_.expired() /*(if we're the root)*/) { @@ -160,17 +160,17 @@ namespace gtsam { // Obtain P(S) = \int P(Cp) = \int P(Fp|Sp) P(Sp) // initialize P(Cp) with the parent separator marginal derived_ptr parent(parent_.lock()); - gttoc(BayesTreeCliqueBaseUnordered_separatorMarginal_cachemiss); // Flatten recursion in timing outline - gttoc(BayesTreeCliqueBaseUnordered_separatorMarginal); + gttoc(BayesTreeCliqueBase_separatorMarginal_cachemiss); // Flatten recursion in timing outline + gttoc(BayesTreeCliqueBase_separatorMarginal); FactorGraphType p_Cp(parent->separatorMarginal(function)); // P(Sp) - gttic(BayesTreeCliqueBaseUnordered_separatorMarginal); - gttic(BayesTreeCliqueBaseUnordered_separatorMarginal_cachemiss); + gttic(BayesTreeCliqueBase_separatorMarginal); + gttic(BayesTreeCliqueBase_separatorMarginal_cachemiss); // now add the parent conditional p_Cp += parent->conditional_; // P(Fp|Sp) // The variables we want to keepSet are exactly the ones in S std::vector indicesS(this->conditional()->beginParents(), this->conditional()->endParents()); - cachedSeparatorMarginal_ = *p_Cp.marginalMultifrontalBayesNet(OrderingUnordered(indicesS), boost::none, function); + cachedSeparatorMarginal_ = *p_Cp.marginalMultifrontalBayesNet(Ordering(indicesS), boost::none, function); } } @@ -183,10 +183,10 @@ namespace gtsam { // P(C) = P(F|S) P(S) /* ************************************************************************* */ template - typename BayesTreeCliqueBaseUnordered::FactorGraphType - BayesTreeCliqueBaseUnordered::marginal2(Eliminate function) const + typename BayesTreeCliqueBase::FactorGraphType + BayesTreeCliqueBase::marginal2(Eliminate function) const { - gttic(BayesTreeCliqueBaseUnordered_marginal2); + gttic(BayesTreeCliqueBase_marginal2); // initialize with separator marginal P(S) FactorGraphType p_C = this->separatorMarginal(function); // add the conditional P(F|S) @@ -196,7 +196,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeCliqueBaseUnordered::deleteCachedShortcuts() { + void BayesTreeCliqueBase::deleteCachedShortcuts() { // When a shortcut is requested, all of the shortcuts between it and the // root are also generated. So, if this clique's cached shortcut is set, diff --git a/gtsam/inference/BayesTreeCliqueBase.h b/gtsam/inference/BayesTreeCliqueBase.h index 5e06aea1c..872539a90 100644 --- a/gtsam/inference/BayesTreeCliqueBase.h +++ b/gtsam/inference/BayesTreeCliqueBase.h @@ -1,273 +1,162 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file BayesTreeCliqueBase.h - * @brief Base class for cliques of a BayesTree - * @author Richard Roberts and Frank Dellaert - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace gtsam { - template class BayesTree; -} - -namespace gtsam { - - /** - * This is the base class for BayesTree cliques. The default and standard - * derived type is BayesTreeClique, but some algorithms, like iSAM2, use a - * different clique type in order to store extra data along with the clique. - * - * This class is templated on the derived class (i.e. the curiously recursive - * template pattern). The advantage of this over using virtual classes is - * that it avoids the need for casting to get the derived type. This is - * possible because all cliques in a BayesTree are the same type - if they - * were not then we'd need a virtual class. - * - * @tparam DERIVED The derived clique type. - * @tparam CONDITIONAL The conditional type. - * \nosubgrouping - */ - template - struct BayesTreeCliqueBase { - - public: - typedef BayesTreeCliqueBase This; - typedef DERIVED DerivedType; - typedef CONDITIONAL ConditionalType; - typedef boost::shared_ptr sharedConditional; - typedef boost::shared_ptr shared_ptr; - typedef boost::weak_ptr weak_ptr; - typedef boost::shared_ptr derived_ptr; - typedef boost::weak_ptr derived_weak_ptr; - typedef typename ConditionalType::FactorType FactorType; - typedef typename FactorGraph::Eliminate Eliminate; - - protected: - - /// @name Standard Constructors - /// @{ - - /** Default constructor */ - BayesTreeCliqueBase() {} - - /** Construct from a conditional, leaving parent and child pointers uninitialized */ - BayesTreeCliqueBase(const sharedConditional& conditional); - - /** Construct from an elimination result, which is a pair */ - BayesTreeCliqueBase( - const std::pair >& result); - - /// @} - - /// This stores the Cached separator margnal P(S) - mutable boost::optional > cachedSeparatorMarginal_; - - public: - sharedConditional conditional_; - derived_weak_ptr parent_; - FastList children_; - - /// @name Testable - /// @{ - - /** check equality */ - bool equals(const This& other, double tol = 1e-9) const { - return (!conditional_ && !other.conditional()) - || conditional_->equals(*other.conditional(), tol); - } - - /** print this node */ - void print(const std::string& s = "", const IndexFormatter& indexFormatter = - DefaultIndexFormatter) const; - - /** print this node and entire subtree below it */ - void printTree(const std::string& indent = "", - const IndexFormatter& indexFormatter = DefaultIndexFormatter) const; - - /// @} - /// @name Standard Interface - /// @{ - - /** Access the conditional */ - const sharedConditional& conditional() const { - return conditional_; - } - - /** is this the root of a Bayes tree ? */ - inline bool isRoot() const { - return parent_.expired(); - } - - /** The size of subtree rooted at this clique, i.e., nr of Cliques */ - size_t treeSize() const; - - /** Collect number of cliques with cached separator marginals */ - size_t numCachedSeparatorMarginals() const; - - /** The arrow operator accesses the conditional */ - const ConditionalType* operator->() const { - return conditional_.get(); - } - - /** return the const reference of children */ - const std::list& children() const { - return children_; - } - - /** return a shared_ptr to the parent clique */ - derived_ptr parent() const { - return parent_.lock(); - } - - /// @} - /// @name Advanced Interface - /// @{ - - /** The arrow operator accesses the conditional */ - ConditionalType* operator->() { - return conditional_.get(); - } - - /** return the reference of children non-const version*/ - FastList& children() { - return children_; - } - - /** Construct shared_ptr from a conditional, leaving parent and child pointers uninitialized */ - static derived_ptr Create(const sharedConditional& conditional) { - return boost::make_shared(conditional); - } - - /** Construct shared_ptr from a FactorGraph::EliminationResult. In this class - * the conditional part is kept and the factor part is ignored, but in derived clique - * types, such as ISAM2Clique, the factor part is kept as a cached factor. - * @param result An elimination result, which is a pair - */ - static derived_ptr Create(const std::pair >& result) { - return boost::make_shared(result); - } - - /** Returns a new clique containing a copy of the conditional but without - * the parent and child clique pointers. - */ - derived_ptr clone() const { - return Create(sharedConditional(new ConditionalType(*conditional_))); - } - - /** Permute the variables in the whole subtree rooted at this clique */ - void permuteWithInverse(const Permutation& inversePermutation); - - /** Permute variables when they only appear in the separators. In this - * case the running intersection property will be used to prevent always - * traversing the whole tree. Returns whether any separator variables in - * this subtree were reordered. - */ - bool reduceSeparatorWithInverse(const internal::Reduction& inverseReduction); - - /** return the conditional P(S|Root) on the separator given the root */ - BayesNet shortcut(derived_ptr root, Eliminate function) const; - - /** return the marginal P(S) on the separator */ - FactorGraph separatorMarginal(derived_ptr root, Eliminate function) const; - - /** return the marginal P(C) of the clique, using marginal caching */ - FactorGraph marginal2(derived_ptr root, Eliminate function) const; - - /** - * This deletes the cached shortcuts of all cliques (subtree) below this clique. - * This is performed when the bayes tree is modified. - */ - void deleteCachedShortcuts(); - - const boost::optional >& cachedSeparatorMarginal() const { - return cachedSeparatorMarginal_; } - - friend class BayesTree ; - - protected: - - /// assert invariants that have to hold in a clique - void assertInvariants() const; - - /// Calculate set \f$ S \setminus B \f$ for shortcut calculations - std::vector separator_setminus_B(derived_ptr B) const; - - /// Calculate set \f$ S_p \cap B \f$ for shortcut calculations - std::vector parent_separator_intersection_B(derived_ptr B) const; - - /** - * Determine variable indices to keep in recursive separator shortcut calculation - * The factor graph p_Cp_B has keys from the parent clique Cp and from B. - * But we only keep the variables not in S union B. - */ - std::vector shortcut_indices(derived_ptr B, - const FactorGraph& p_Cp_B) const; - - /** Non-recursive delete cached shortcuts and marginals - internal only. */ - void deleteCachedShortcutsNonRecursive() { cachedSeparatorMarginal_ = boost::none; } - - private: - - /** - * Cliques cannot be copied except by the clone() method, which does not - * copy the parent and child pointers. - */ - BayesTreeCliqueBase(const This& other) { - assert(false); - } - - /** Cliques cannot be copied except by the clone() method, which does not - * copy the parent and child pointers. - */ - This& operator=(const This& other) { - assert(false); - return *this; - } - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(conditional_); - ar & BOOST_SERIALIZATION_NVP(parent_); - ar & BOOST_SERIALIZATION_NVP(children_); - } - - /// @} - - }; - // \struct Clique - - template - const DERIVED* asDerived( - const BayesTreeCliqueBase* base) { - return static_cast(base); - } - - template - DERIVED* asDerived(BayesTreeCliqueBase* base) { - return static_cast(base); - } - -} +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file BayesTreeCliqueBase.h + * @brief Base class for cliques of a BayesTree + * @author Richard Roberts and Frank Dellaert + */ + +#pragma once + +#include + +namespace gtsam { + + // Forward declarations + template class BayesTree; + template struct EliminationTraits; + + /** + * This is the base class for BayesTree cliques. The default and standard derived type is + * BayesTreeClique, but some algorithms, like iSAM2, use a different clique type in order to store + * extra data along with the clique. + * + * This class is templated on the derived class (i.e. the curiously recursive template pattern). + * The advantage of this over using virtual classes is that it avoids the need for casting to get + * the derived type. This is possible because all cliques in a BayesTree are the same type - if + * they were not then we'd need a virtual class. + * + * @tparam DERIVED The derived clique type. + * @tparam CONDITIONAL The conditional type. + * \nosubgrouping */ + template + class BayesTreeCliqueBase + { + private: + typedef BayesTreeCliqueBase This; + typedef DERIVED DerivedType; + typedef EliminationTraits EliminationTraits; + typedef boost::shared_ptr shared_ptr; + typedef boost::weak_ptr weak_ptr; + typedef boost::shared_ptr derived_ptr; + typedef boost::weak_ptr derived_weak_ptr; + + public: + typedef FACTORGRAPH FactorGraphType; + typedef typename EliminationTraits::BayesNetType BayesNetType; + typedef typename BayesNetType::ConditionalType ConditionalType; + typedef boost::shared_ptr sharedConditional; + typedef typename FactorGraphType::FactorType FactorType; + typedef typename FactorGraphType::Eliminate Eliminate; + + protected: + + /// @name Standard Constructors + /// @{ + + /** Default constructor */ + BayesTreeCliqueBase() {} + + /** Construct from a conditional, leaving parent and child pointers uninitialized */ + BayesTreeCliqueBase(const sharedConditional& conditional) : conditional_(conditional) {} + + /// @} + + /// This stores the Cached separator margnal P(S) + mutable boost::optional cachedSeparatorMarginal_; + + public: + sharedConditional conditional_; + derived_weak_ptr parent_; + std::vector children; + + /// @name Testable + /// @{ + + /** check equality */ + bool equals(const DERIVED& other, double tol = 1e-9) const; + + /** print this node */ + void print(const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; + + /// @} + /// @name Standard Interface + /// @{ + + /** Access the conditional */ + const sharedConditional& conditional() const { return conditional_; } + + /** is this the root of a Bayes tree ? */ + inline bool isRoot() const { return parent_.expired(); } + + /** The size of subtree rooted at this clique, i.e., nr of Cliques */ + size_t treeSize() const; + + /** Collect number of cliques with cached separator marginals */ + size_t numCachedSeparatorMarginals() const; + + /** return a shared_ptr to the parent clique */ + derived_ptr parent() const { return parent_.lock(); } + + /// @} + /// @name Advanced Interface + /// @{ + + /** return the conditional P(S|Root) on the separator given the root */ + BayesNetType shortcut(const derived_ptr& root, Eliminate function = EliminationTraits::DefaultEliminate) const; + + /** return the marginal P(S) on the separator */ + FactorGraphType separatorMarginal(Eliminate function = EliminationTraits::DefaultEliminate) const; + + /** return the marginal P(C) of the clique, using marginal caching */ + FactorGraphType marginal2(Eliminate function = EliminationTraits::DefaultEliminate) const; + + /** + * This deletes the cached shortcuts of all cliques (subtree) below this clique. + * This is performed when the bayes tree is modified. + */ + void deleteCachedShortcuts(); + + const boost::optional& cachedSeparatorMarginal() const { + return cachedSeparatorMarginal_; } + + friend class BayesTree; + + protected: + + /// Calculate set \f$ S \setminus B \f$ for shortcut calculations + std::vector separator_setminus_B(const derived_ptr& B) const; + + /** Determine variable indices to keep in recursive separator shortcut calculation The factor + * graph p_Cp_B has keys from the parent clique Cp and from B. But we only keep the variables + * not in S union B. */ + std::vector shortcut_indices(const derived_ptr& B, const FactorGraphType& p_Cp_B) const; + + /** Non-recursive delete cached shortcuts and marginals - internal only. */ + void deleteCachedShortcutsNonRecursive() { cachedSeparatorMarginal_ = boost::none; } + + private: + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(conditional_); + ar & BOOST_SERIALIZATION_NVP(parent_); + ar & BOOST_SERIALIZATION_NVP(children_); + } + + /// @} + + }; + +} diff --git a/gtsam/inference/BayesTreeCliqueBase-inl.h b/gtsam/inference/BayesTreeCliqueBaseOrdered-inl.h similarity index 85% rename from gtsam/inference/BayesTreeCliqueBase-inl.h rename to gtsam/inference/BayesTreeCliqueBaseOrdered-inl.h index e2ac492b7..1d2ccb57b 100644 --- a/gtsam/inference/BayesTreeCliqueBase-inl.h +++ b/gtsam/inference/BayesTreeCliqueBaseOrdered-inl.h @@ -23,12 +23,12 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeCliqueBase::assertInvariants() const { + void BayesTreeCliqueBaseOrdered::assertInvariants() const { } /* ************************************************************************* */ template - std::vector BayesTreeCliqueBase::separator_setminus_B( + std::vector BayesTreeCliqueBaseOrdered::separator_setminus_B( derived_ptr B) const { sharedConditional p_F_S = this->conditional(); std::vector &indicesB = B->conditional()->keys(); @@ -40,8 +40,8 @@ namespace gtsam { /* ************************************************************************* */ template - std::vector BayesTreeCliqueBase::shortcut_indices( - derived_ptr B, const FactorGraph& p_Cp_B) const + std::vector BayesTreeCliqueBaseOrdered::shortcut_indices( + derived_ptr B, const FactorGraphOrdered& p_Cp_B) const { gttic(shortcut_indices); std::set allKeys = p_Cp_B.keys(); @@ -60,7 +60,7 @@ namespace gtsam { /* ************************************************************************* */ template - BayesTreeCliqueBase::BayesTreeCliqueBase( + BayesTreeCliqueBaseOrdered::BayesTreeCliqueBaseOrdered( const sharedConditional& conditional) : conditional_(conditional) { assertInvariants(); @@ -68,7 +68,7 @@ namespace gtsam { /* ************************************************************************* */ template - BayesTreeCliqueBase::BayesTreeCliqueBase( + BayesTreeCliqueBaseOrdered::BayesTreeCliqueBaseOrdered( const std::pair >& result) : conditional_(result.first) { @@ -77,14 +77,14 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeCliqueBase::print(const std::string& s, + void BayesTreeCliqueBaseOrdered::print(const std::string& s, const IndexFormatter& indexFormatter) const { conditional_->print(s, indexFormatter); } /* ************************************************************************* */ template - size_t BayesTreeCliqueBase::treeSize() const { + size_t BayesTreeCliqueBaseOrdered::treeSize() const { size_t size = 1; BOOST_FOREACH(const derived_ptr& child, children_) size += child->treeSize(); @@ -93,7 +93,7 @@ namespace gtsam { /* ************************************************************************* */ template - size_t BayesTreeCliqueBase::numCachedSeparatorMarginals() const { + size_t BayesTreeCliqueBaseOrdered::numCachedSeparatorMarginals() const { if (!cachedSeparatorMarginal_) return 0; @@ -106,7 +106,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeCliqueBase::printTree( + void BayesTreeCliqueBaseOrdered::printTree( const std::string& indent, const IndexFormatter& indexFormatter) const { asDerived(this)->print(indent, indexFormatter); BOOST_FOREACH(const derived_ptr& child, children_) @@ -115,7 +115,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeCliqueBase::permuteWithInverse( + void BayesTreeCliqueBaseOrdered::permuteWithInverse( const Permutation& inversePermutation) { conditional_->permuteWithInverse(inversePermutation); BOOST_FOREACH(const derived_ptr& child, children_) { @@ -126,7 +126,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool BayesTreeCliqueBase::reduceSeparatorWithInverse( + bool BayesTreeCliqueBaseOrdered::reduceSeparatorWithInverse( const internal::Reduction& inverseReduction) { bool changed = conditional_->reduceSeparatorWithInverse(inverseReduction); @@ -150,7 +150,7 @@ namespace gtsam { // P(Sp|R) as \int P(Fp|Sp) P(Sp|R), where Fp are the frontal nodes in p /* ************************************************************************* */ template - BayesNet BayesTreeCliqueBase::shortcut( + BayesNetOrdered BayesTreeCliqueBaseOrdered::shortcut( derived_ptr B, Eliminate function) const { gttic(BayesTreeCliqueBase_shortcut); @@ -163,7 +163,7 @@ namespace gtsam { // Obtain P(Cp||B) = P(Fp|Sp) * P(Sp||B) as a factor graph derived_ptr parent(parent_.lock()); gttoc(BayesTreeCliqueBase_shortcut); - FactorGraph p_Cp_B(parent->shortcut(B, function)); // P(Sp||B) + FactorGraphOrdered p_Cp_B(parent->shortcut(B, function)); // P(Sp||B) gttic(BayesTreeCliqueBase_shortcut); p_Cp_B.push_back(parent->conditional()->toFactor()); // P(Fp|Sp) @@ -184,7 +184,7 @@ namespace gtsam { // Finally, we only want to have S\B variables in the Bayes net, so size_t nrFrontals = S_setminus_B.size(); - BayesNet result = *solver.conditionalBayesNet(keep, nrFrontals, function); + BayesNetOrdered result = *solver.conditionalBayesNet(keep, nrFrontals, function); // Undo the reduction gttic(Undo_Reduce); @@ -197,7 +197,7 @@ namespace gtsam { return result; } else { - return BayesNet(); + return BayesNetOrdered(); } } @@ -206,7 +206,7 @@ namespace gtsam { // P(C) = P(F|S) P(S) /* ************************************************************************* */ template - FactorGraph::FactorType> BayesTreeCliqueBase< + FactorGraphOrdered::FactorType> BayesTreeCliqueBaseOrdered< DERIVED, CONDITIONAL>::separatorMarginal(derived_ptr R, Eliminate function) const { gttic(BayesTreeCliqueBase_separatorMarginal); @@ -216,7 +216,7 @@ namespace gtsam { // If this is the root, there is no separator if (R.get() == this) { // we are root, return empty - FactorGraph empty; + FactorGraphOrdered empty; cachedSeparatorMarginal_ = empty; } else { // Obtain P(S) = \int P(Cp) = \int P(Fp|Sp) P(Sp) @@ -224,7 +224,7 @@ namespace gtsam { derived_ptr parent(parent_.lock()); gttoc(BayesTreeCliqueBase_separatorMarginal_cachemiss); // Flatten recursion in timing outline gttoc(BayesTreeCliqueBase_separatorMarginal); - FactorGraph p_Cp(parent->separatorMarginal(R, function)); // P(Sp) + FactorGraphOrdered p_Cp(parent->separatorMarginal(R, function)); // P(Sp) gttic(BayesTreeCliqueBase_separatorMarginal); gttic(BayesTreeCliqueBase_separatorMarginal_cachemiss); // now add the parent conditional @@ -269,12 +269,12 @@ namespace gtsam { // P(C) = P(F|S) P(S) /* ************************************************************************* */ template - FactorGraph::FactorType> BayesTreeCliqueBase< + FactorGraphOrdered::FactorType> BayesTreeCliqueBaseOrdered< DERIVED, CONDITIONAL>::marginal2(derived_ptr R, Eliminate function) const { gttic(BayesTreeCliqueBase_marginal2); // initialize with separator marginal P(S) - FactorGraph p_C(this->separatorMarginal(R, function)); + FactorGraphOrdered p_C(this->separatorMarginal(R, function)); // add the conditional P(F|S) p_C.push_back(this->conditional()->toFactor()); return p_C; @@ -282,7 +282,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTreeCliqueBase::deleteCachedShortcuts() { + void BayesTreeCliqueBaseOrdered::deleteCachedShortcuts() { // When a shortcut is requested, all of the shortcuts between it and the // root are also generated. So, if this clique's cached shortcut is set, diff --git a/gtsam/inference/BayesTreeCliqueBaseOrdered.h b/gtsam/inference/BayesTreeCliqueBaseOrdered.h new file mode 100644 index 000000000..e663c92af --- /dev/null +++ b/gtsam/inference/BayesTreeCliqueBaseOrdered.h @@ -0,0 +1,273 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file BayesTreeCliqueBase.h + * @brief Base class for cliques of a BayesTree + * @author Richard Roberts and Frank Dellaert + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace gtsam { + template class BayesTreeOrdered; +} + +namespace gtsam { + + /** + * This is the base class for BayesTree cliques. The default and standard + * derived type is BayesTreeClique, but some algorithms, like iSAM2, use a + * different clique type in order to store extra data along with the clique. + * + * This class is templated on the derived class (i.e. the curiously recursive + * template pattern). The advantage of this over using virtual classes is + * that it avoids the need for casting to get the derived type. This is + * possible because all cliques in a BayesTree are the same type - if they + * were not then we'd need a virtual class. + * + * @tparam DERIVED The derived clique type. + * @tparam CONDITIONAL The conditional type. + * \nosubgrouping + */ + template + struct BayesTreeCliqueBaseOrdered { + + public: + typedef BayesTreeCliqueBaseOrdered This; + typedef DERIVED DerivedType; + typedef CONDITIONAL ConditionalType; + typedef boost::shared_ptr sharedConditional; + typedef boost::shared_ptr shared_ptr; + typedef boost::weak_ptr weak_ptr; + typedef boost::shared_ptr derived_ptr; + typedef boost::weak_ptr derived_weak_ptr; + typedef typename ConditionalType::FactorType FactorType; + typedef typename FactorGraphOrdered::Eliminate Eliminate; + + protected: + + /// @name Standard Constructors + /// @{ + + /** Default constructor */ + BayesTreeCliqueBaseOrdered() {} + + /** Construct from a conditional, leaving parent and child pointers uninitialized */ + BayesTreeCliqueBaseOrdered(const sharedConditional& conditional); + + /** Construct from an elimination result, which is a pair */ + BayesTreeCliqueBaseOrdered( + const std::pair >& result); + + /// @} + + /// This stores the Cached separator margnal P(S) + mutable boost::optional > cachedSeparatorMarginal_; + + public: + sharedConditional conditional_; + derived_weak_ptr parent_; + FastList children_; + + /// @name Testable + /// @{ + + /** check equality */ + bool equals(const This& other, double tol = 1e-9) const { + return (!conditional_ && !other.conditional()) + || conditional_->equals(*other.conditional(), tol); + } + + /** print this node */ + void print(const std::string& s = "", const IndexFormatter& indexFormatter = + DefaultIndexFormatter) const; + + /** print this node and entire subtree below it */ + void printTree(const std::string& indent = "", + const IndexFormatter& indexFormatter = DefaultIndexFormatter) const; + + /// @} + /// @name Standard Interface + /// @{ + + /** Access the conditional */ + const sharedConditional& conditional() const { + return conditional_; + } + + /** is this the root of a Bayes tree ? */ + inline bool isRoot() const { + return parent_.expired(); + } + + /** The size of subtree rooted at this clique, i.e., nr of Cliques */ + size_t treeSize() const; + + /** Collect number of cliques with cached separator marginals */ + size_t numCachedSeparatorMarginals() const; + + /** The arrow operator accesses the conditional */ + const ConditionalType* operator->() const { + return conditional_.get(); + } + + /** return the const reference of children */ + const std::list& children() const { + return children_; + } + + /** return a shared_ptr to the parent clique */ + derived_ptr parent() const { + return parent_.lock(); + } + + /// @} + /// @name Advanced Interface + /// @{ + + /** The arrow operator accesses the conditional */ + ConditionalType* operator->() { + return conditional_.get(); + } + + /** return the reference of children non-const version*/ + FastList& children() { + return children_; + } + + /** Construct shared_ptr from a conditional, leaving parent and child pointers uninitialized */ + static derived_ptr Create(const sharedConditional& conditional) { + return boost::make_shared(conditional); + } + + /** Construct shared_ptr from a FactorGraph::EliminationResult. In this class + * the conditional part is kept and the factor part is ignored, but in derived clique + * types, such as ISAM2Clique, the factor part is kept as a cached factor. + * @param result An elimination result, which is a pair + */ + static derived_ptr Create(const std::pair >& result) { + return boost::make_shared(result); + } + + /** Returns a new clique containing a copy of the conditional but without + * the parent and child clique pointers. + */ + derived_ptr clone() const { + return Create(sharedConditional(new ConditionalType(*conditional_))); + } + + /** Permute the variables in the whole subtree rooted at this clique */ + void permuteWithInverse(const Permutation& inversePermutation); + + /** Permute variables when they only appear in the separators. In this + * case the running intersection property will be used to prevent always + * traversing the whole tree. Returns whether any separator variables in + * this subtree were reordered. + */ + bool reduceSeparatorWithInverse(const internal::Reduction& inverseReduction); + + /** return the conditional P(S|Root) on the separator given the root */ + BayesNetOrdered shortcut(derived_ptr root, Eliminate function) const; + + /** return the marginal P(S) on the separator */ + FactorGraphOrdered separatorMarginal(derived_ptr root, Eliminate function) const; + + /** return the marginal P(C) of the clique, using marginal caching */ + FactorGraphOrdered marginal2(derived_ptr root, Eliminate function) const; + + /** + * This deletes the cached shortcuts of all cliques (subtree) below this clique. + * This is performed when the bayes tree is modified. + */ + void deleteCachedShortcuts(); + + const boost::optional >& cachedSeparatorMarginal() const { + return cachedSeparatorMarginal_; } + + friend class BayesTreeOrdered ; + + protected: + + /// assert invariants that have to hold in a clique + void assertInvariants() const; + + /// Calculate set \f$ S \setminus B \f$ for shortcut calculations + std::vector separator_setminus_B(derived_ptr B) const; + + /// Calculate set \f$ S_p \cap B \f$ for shortcut calculations + std::vector parent_separator_intersection_B(derived_ptr B) const; + + /** + * Determine variable indices to keep in recursive separator shortcut calculation + * The factor graph p_Cp_B has keys from the parent clique Cp and from B. + * But we only keep the variables not in S union B. + */ + std::vector shortcut_indices(derived_ptr B, + const FactorGraphOrdered& p_Cp_B) const; + + /** Non-recursive delete cached shortcuts and marginals - internal only. */ + void deleteCachedShortcutsNonRecursive() { cachedSeparatorMarginal_ = boost::none; } + + private: + + /** + * Cliques cannot be copied except by the clone() method, which does not + * copy the parent and child pointers. + */ + BayesTreeCliqueBaseOrdered(const This& other) { + assert(false); + } + + /** Cliques cannot be copied except by the clone() method, which does not + * copy the parent and child pointers. + */ + This& operator=(const This& other) { + assert(false); + return *this; + } + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(conditional_); + ar & BOOST_SERIALIZATION_NVP(parent_); + ar & BOOST_SERIALIZATION_NVP(children_); + } + + /// @} + + }; + // \struct Clique + + template + const DERIVED* asDerived( + const BayesTreeCliqueBaseOrdered* base) { + return static_cast(base); + } + + template + DERIVED* asDerived(BayesTreeCliqueBaseOrdered* base) { + return static_cast(base); + } + +} diff --git a/gtsam/inference/BayesTreeCliqueBaseUnordered.h b/gtsam/inference/BayesTreeCliqueBaseUnordered.h deleted file mode 100644 index 9b0d1d657..000000000 --- a/gtsam/inference/BayesTreeCliqueBaseUnordered.h +++ /dev/null @@ -1,162 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file BayesTreeCliqueBase.h - * @brief Base class for cliques of a BayesTree - * @author Richard Roberts and Frank Dellaert - */ - -#pragma once - -#include - -namespace gtsam { - - // Forward declarations - template class BayesTreeUnordered; - template struct EliminationTraits; - - /** - * This is the base class for BayesTree cliques. The default and standard derived type is - * BayesTreeClique, but some algorithms, like iSAM2, use a different clique type in order to store - * extra data along with the clique. - * - * This class is templated on the derived class (i.e. the curiously recursive template pattern). - * The advantage of this over using virtual classes is that it avoids the need for casting to get - * the derived type. This is possible because all cliques in a BayesTree are the same type - if - * they were not then we'd need a virtual class. - * - * @tparam DERIVED The derived clique type. - * @tparam CONDITIONAL The conditional type. - * \nosubgrouping */ - template - class BayesTreeCliqueBaseUnordered - { - private: - typedef BayesTreeCliqueBaseUnordered This; - typedef DERIVED DerivedType; - typedef EliminationTraits EliminationTraits; - typedef boost::shared_ptr shared_ptr; - typedef boost::weak_ptr weak_ptr; - typedef boost::shared_ptr derived_ptr; - typedef boost::weak_ptr derived_weak_ptr; - - public: - typedef FACTORGRAPH FactorGraphType; - typedef typename EliminationTraits::BayesNetType BayesNetType; - typedef typename BayesNetType::ConditionalType ConditionalType; - typedef boost::shared_ptr sharedConditional; - typedef typename FactorGraphType::FactorType FactorType; - typedef typename FactorGraphType::Eliminate Eliminate; - - protected: - - /// @name Standard Constructors - /// @{ - - /** Default constructor */ - BayesTreeCliqueBaseUnordered() {} - - /** Construct from a conditional, leaving parent and child pointers uninitialized */ - BayesTreeCliqueBaseUnordered(const sharedConditional& conditional) : conditional_(conditional) {} - - /// @} - - /// This stores the Cached separator margnal P(S) - mutable boost::optional cachedSeparatorMarginal_; - - public: - sharedConditional conditional_; - derived_weak_ptr parent_; - std::vector children; - - /// @name Testable - /// @{ - - /** check equality */ - bool equals(const DERIVED& other, double tol = 1e-9) const; - - /** print this node */ - void print(const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; - - /// @} - /// @name Standard Interface - /// @{ - - /** Access the conditional */ - const sharedConditional& conditional() const { return conditional_; } - - /** is this the root of a Bayes tree ? */ - inline bool isRoot() const { return parent_.expired(); } - - /** The size of subtree rooted at this clique, i.e., nr of Cliques */ - size_t treeSize() const; - - /** Collect number of cliques with cached separator marginals */ - size_t numCachedSeparatorMarginals() const; - - /** return a shared_ptr to the parent clique */ - derived_ptr parent() const { return parent_.lock(); } - - /// @} - /// @name Advanced Interface - /// @{ - - /** return the conditional P(S|Root) on the separator given the root */ - BayesNetType shortcut(const derived_ptr& root, Eliminate function = EliminationTraits::DefaultEliminate) const; - - /** return the marginal P(S) on the separator */ - FactorGraphType separatorMarginal(Eliminate function = EliminationTraits::DefaultEliminate) const; - - /** return the marginal P(C) of the clique, using marginal caching */ - FactorGraphType marginal2(Eliminate function = EliminationTraits::DefaultEliminate) const; - - /** - * This deletes the cached shortcuts of all cliques (subtree) below this clique. - * This is performed when the bayes tree is modified. - */ - void deleteCachedShortcuts(); - - const boost::optional& cachedSeparatorMarginal() const { - return cachedSeparatorMarginal_; } - - friend class BayesTreeUnordered; - - protected: - - /// Calculate set \f$ S \setminus B \f$ for shortcut calculations - std::vector separator_setminus_B(const derived_ptr& B) const; - - /** Determine variable indices to keep in recursive separator shortcut calculation The factor - * graph p_Cp_B has keys from the parent clique Cp and from B. But we only keep the variables - * not in S union B. */ - std::vector shortcut_indices(const derived_ptr& B, const FactorGraphType& p_Cp_B) const; - - /** Non-recursive delete cached shortcuts and marginals - internal only. */ - void deleteCachedShortcutsNonRecursive() { cachedSeparatorMarginal_ = boost::none; } - - private: - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(conditional_); - ar & BOOST_SERIALIZATION_NVP(parent_); - ar & BOOST_SERIALIZATION_NVP(children_); - } - - /// @} - - }; - -} diff --git a/gtsam/inference/BayesTree-inl.h b/gtsam/inference/BayesTreeOrdered-inl.h similarity index 80% rename from gtsam/inference/BayesTree-inl.h rename to gtsam/inference/BayesTreeOrdered-inl.h index d5592ed2a..4a73b5d17 100644 --- a/gtsam/inference/BayesTree-inl.h +++ b/gtsam/inference/BayesTreeOrdered-inl.h @@ -23,8 +23,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -40,8 +40,8 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTree::CliqueData - BayesTree::getCliqueData() const { + typename BayesTreeOrdered::CliqueData + BayesTreeOrdered::getCliqueData() const { CliqueData data; getCliqueData(data, root_); return data; @@ -49,7 +49,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::getCliqueData(CliqueData& data, sharedClique clique) const { + void BayesTreeOrdered::getCliqueData(CliqueData& data, sharedClique clique) const { data.conditionalSizes.push_back((*clique)->nrFrontals()); data.separatorSizes.push_back((*clique)->nrParents()); BOOST_FOREACH(sharedClique c, clique->children_) { @@ -59,13 +59,13 @@ namespace gtsam { /* ************************************************************************* */ template - size_t BayesTree::numCachedSeparatorMarginals() const { + size_t BayesTreeOrdered::numCachedSeparatorMarginals() const { return (root_) ? root_->numCachedSeparatorMarginals() : 0; } /* ************************************************************************* */ template - void BayesTree::saveGraph(const std::string &s, const IndexFormatter& indexFormatter) const { + void BayesTreeOrdered::saveGraph(const std::string &s, const IndexFormatter& indexFormatter) const { if (!root_.get()) throw std::invalid_argument("the root of Bayes tree has not been initialized!"); std::ofstream of(s.c_str()); of<< "digraph G{\n"; @@ -76,7 +76,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::saveGraph(std::ostream &s, sharedClique clique, const IndexFormatter& indexFormatter, int parentnum) const { + void BayesTreeOrdered::saveGraph(std::ostream &s, sharedClique clique, const IndexFormatter& indexFormatter, int parentnum) const { static int num = 0; bool first = true; std::stringstream out; @@ -112,7 +112,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::CliqueStats::print(const std::string& s) const { + void BayesTreeOrdered::CliqueStats::print(const std::string& s) const { std::cout << s <<"avg Conditional Size: " << avgConditionalSize << std::endl << "max Conditional Size: " << maxConditionalSize << std::endl @@ -122,8 +122,8 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTree::CliqueStats - BayesTree::CliqueData::getStats() const { + typename BayesTreeOrdered::CliqueStats + BayesTreeOrdered::CliqueData::getStats() const { CliqueStats stats; double sum = 0.0; @@ -149,7 +149,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::Cliques::print(const std::string& s, const IndexFormatter& indexFormatter) const { + void BayesTreeOrdered::Cliques::print(const std::string& s, const IndexFormatter& indexFormatter) const { std::cout << s << ":\n"; BOOST_FOREACH(sharedClique clique, *this) clique->printTree("", indexFormatter); @@ -157,14 +157,14 @@ namespace gtsam { /* ************************************************************************* */ template - bool BayesTree::Cliques::equals(const Cliques& other, double tol) const { + bool BayesTreeOrdered::Cliques::equals(const Cliques& other, double tol) const { return other == *this; } /* ************************************************************************* */ template - typename BayesTree::sharedClique - BayesTree::addClique(const sharedConditional& conditional, const sharedClique& parent_clique) { + typename BayesTreeOrdered::sharedClique + BayesTreeOrdered::addClique(const sharedConditional& conditional, const sharedClique& parent_clique) { sharedClique new_clique(new Clique(conditional)); addClique(new_clique, parent_clique); return new_clique; @@ -172,7 +172,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::addClique(const sharedClique& clique, const sharedClique& parent_clique) { + void BayesTreeOrdered::addClique(const sharedClique& clique, const sharedClique& parent_clique) { nodes_.resize(std::max((*clique)->lastFrontalKey()+1, nodes_.size())); BOOST_FOREACH(Index j, (*clique)->frontals()) nodes_[j] = clique; @@ -188,7 +188,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTree::sharedClique BayesTree::addClique( + typename BayesTreeOrdered::sharedClique BayesTreeOrdered::addClique( const sharedConditional& conditional, std::list& child_cliques) { sharedClique new_clique(new Clique(conditional)); nodes_.resize(std::max(conditional->lastFrontalKey()+1, nodes_.size())); @@ -203,7 +203,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::permuteWithInverse(const Permutation& inversePermutation) { + void BayesTreeOrdered::permuteWithInverse(const Permutation& inversePermutation) { // recursively permute the cliques and internal conditionals if (root_) root_->permuteWithInverse(inversePermutation); @@ -212,7 +212,7 @@ namespace gtsam { Index maxIndex = *std::max_element(inversePermutation.begin(), inversePermutation.end()); // Update the nodes structure - typename BayesTree::Nodes newNodes(maxIndex+1); + typename BayesTreeOrdered::Nodes newNodes(maxIndex+1); // inversePermutation.applyToCollection(newNodes, nodes_); // Uses the forward, rather than inverse permutation for(size_t i = 0; i < nodes_.size(); ++i) newNodes[inversePermutation[i]] = nodes_[i]; @@ -222,7 +222,7 @@ namespace gtsam { /* ************************************************************************* */ template - inline void BayesTree::addToCliqueFront(BayesTree& bayesTree, const sharedConditional& conditional, const sharedClique& clique) { + inline void BayesTreeOrdered::addToCliqueFront(BayesTreeOrdered& bayesTree, const sharedConditional& conditional, const sharedClique& clique) { static const bool debug = false; #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS // Debug check to make sure the conditional variable is ordered lower than @@ -249,7 +249,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::removeClique(sharedClique clique) { + void BayesTreeOrdered::removeClique(sharedClique clique) { if (clique->isRoot()) root_.reset(); @@ -271,9 +271,9 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::recursiveTreeBuild(const boost::shared_ptr >& symbolic, + void BayesTreeOrdered::recursiveTreeBuild(const boost::shared_ptr >& symbolic, const std::vector >& conditionals, - const typename BayesTree::sharedClique& parent) { + const typename BayesTreeOrdered::sharedClique& parent) { // Helper function to build a non-symbolic tree (e.g. Gaussian) using a // symbolic tree, used in the BT(BN) constructor. @@ -282,21 +282,21 @@ namespace gtsam { FastList cliqueConditionals; BOOST_FOREACH(Index j, symbolic->conditional()->frontals()) { cliqueConditionals.push_back(conditionals[j]); } - typename BayesTree::sharedClique thisClique(new CLIQUE(CONDITIONAL::Combine(cliqueConditionals.begin(), cliqueConditionals.end()))); + typename BayesTreeOrdered::sharedClique thisClique(new CLIQUE(CONDITIONAL::Combine(cliqueConditionals.begin(), cliqueConditionals.end()))); // Add the new clique with the current parent this->addClique(thisClique, parent); // Build the children, whose parent is the new clique - BOOST_FOREACH(const BayesTree::sharedClique& child, symbolic->children()) { + BOOST_FOREACH(const BayesTreeOrdered::sharedClique& child, symbolic->children()) { this->recursiveTreeBuild(child, conditionals, thisClique); } } /* ************************************************************************* */ template - BayesTree::BayesTree(const BayesNet& bayesNet) { + BayesTreeOrdered::BayesTreeOrdered(const BayesNetOrdered& bayesNet) { // First generate symbolic BT to determine clique structure - BayesTree sbt(bayesNet); + BayesTreeOrdered sbt(bayesNet); // Build index of variables to conditionals std::vector > conditionals(sbt.root()->conditional()->frontals().back() + 1); @@ -317,21 +317,21 @@ namespace gtsam { /* ************************************************************************* */ template<> - inline BayesTree::BayesTree(const BayesNet& bayesNet) { - BayesNet::const_reverse_iterator rit; + inline BayesTreeOrdered::BayesTreeOrdered(const BayesNetOrdered& bayesNet) { + BayesNetOrdered::const_reverse_iterator rit; for ( rit=bayesNet.rbegin(); rit != bayesNet.rend(); ++rit ) insert(*this, *rit); } /* ************************************************************************* */ template - BayesTree::BayesTree(const BayesNet& bayesNet, std::list > subtrees) { + BayesTreeOrdered::BayesTreeOrdered(const BayesNetOrdered& bayesNet, std::list > subtrees) { if (bayesNet.size() == 0) throw std::invalid_argument("BayesTree::insert: empty bayes net!"); // get the roots of child subtrees and merge their nodes_ std::list childRoots; - typedef BayesTree Tree; + typedef BayesTreeOrdered Tree; BOOST_FOREACH(const Tree& subtree, subtrees) { nodes_.assign(subtree.nodes_.begin(), subtree.nodes_.end()); childRoots.push_back(subtree.root()); @@ -339,7 +339,7 @@ namespace gtsam { // create a new clique and add all the conditionals to the clique sharedClique new_clique; - typename BayesNet::sharedConditional conditional; + typename BayesNetOrdered::sharedConditional conditional; BOOST_REVERSE_FOREACH(conditional, bayesNet) { if (!new_clique.get()) new_clique = addClique(conditional,childRoots); @@ -352,13 +352,13 @@ namespace gtsam { /* ************************************************************************* */ template - BayesTree::BayesTree(const This& other) { + BayesTreeOrdered::BayesTreeOrdered(const This& other) { *this = other; } /* ************************************************************************* */ template - BayesTree& BayesTree::operator=(const This& other) { + BayesTreeOrdered& BayesTreeOrdered::operator=(const This& other) { this->clear(); other.cloneTo(*this); return *this; @@ -366,7 +366,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::print(const std::string& s, const IndexFormatter& indexFormatter) const { + void BayesTreeOrdered::print(const std::string& s, const IndexFormatter& indexFormatter) const { if (root_.use_count() == 0) { std::cout << "WARNING: BayesTree.print encountered a forest..." << std::endl; return; @@ -380,15 +380,15 @@ namespace gtsam { // binary predicate to test equality of a pair for use in equals template bool check_sharedCliques( - const typename BayesTree::sharedClique& v1, - const typename BayesTree::sharedClique& v2 + const typename BayesTreeOrdered::sharedClique& v1, + const typename BayesTreeOrdered::sharedClique& v2 ) { return (!v1 && !v2) || (v1 && v2 && v1->equals(*v2)); } /* ************************************************************************* */ template - bool BayesTree::equals(const BayesTree& other, + bool BayesTreeOrdered::equals(const BayesTreeOrdered& other, double tol) const { return size()==other.size() && std::equal(nodes_.begin(), nodes_.end(), other.nodes_.begin(), &check_sharedCliques); @@ -397,7 +397,7 @@ namespace gtsam { /* ************************************************************************* */ template template - inline Index BayesTree::findParentClique(const CONTAINER& parents) const { + inline Index BayesTreeOrdered::findParentClique(const CONTAINER& parents) const { typename CONTAINER::const_iterator lowestOrderedParent = min_element(parents.begin(), parents.end()); assert(lowestOrderedParent != parents.end()); return *lowestOrderedParent; @@ -405,7 +405,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::insert(BayesTree& bayesTree, const sharedConditional& conditional) + void BayesTreeOrdered::insert(BayesTreeOrdered& bayesTree, const sharedConditional& conditional) { static const bool debug = false; @@ -442,7 +442,7 @@ namespace gtsam { /* ************************************************************************* */ //TODO: remove this function after removing TSAM.cpp template - typename BayesTree::sharedClique BayesTree::insert( + typename BayesTreeOrdered::sharedClique BayesTreeOrdered::insert( const sharedConditional& clique, std::list& children, bool isRootClique) { if (clique->nrFrontals() == 0) @@ -457,18 +457,18 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::fillNodesIndex(const sharedClique& subtree) { + void BayesTreeOrdered::fillNodesIndex(const sharedClique& subtree) { // Add each frontal variable of this root node BOOST_FOREACH(const Index& j, subtree->conditional()->frontals()) { nodes_[j] = subtree; } // Fill index for each child - typedef typename BayesTree::sharedClique sharedClique; + typedef typename BayesTreeOrdered::sharedClique sharedClique; BOOST_FOREACH(const sharedClique& child, subtree->children_) { fillNodesIndex(child); } } /* ************************************************************************* */ template - void BayesTree::insert(const sharedClique& subtree) { + void BayesTreeOrdered::insert(const sharedClique& subtree) { if(subtree) { // Find the parent clique of the new subtree. By the running intersection // property, those separator variables in the subtree that are ordered @@ -497,7 +497,7 @@ namespace gtsam { // First finds clique marginal then marginalizes that /* ************************************************************************* */ template - typename CONDITIONAL::FactorType::shared_ptr BayesTree::marginalFactor( + typename CONDITIONAL::FactorType::shared_ptr BayesTreeOrdered::marginalFactor( Index j, Eliminate function) const { gttic(BayesTree_marginalFactor); @@ -507,9 +507,9 @@ namespace gtsam { // calculate or retrieve its marginal P(C) = P(F,S) #ifdef OLD_SHORTCUT_MARGINALS - FactorGraph cliqueMarginal = clique->marginal(root_,function); + FactorGraphOrdered cliqueMarginal = clique->marginal(root_,function); #else - FactorGraph cliqueMarginal = clique->marginal2(root_,function); + FactorGraphOrdered cliqueMarginal = clique->marginal2(root_,function); #endif // Reduce the variable indices to start at zero @@ -535,13 +535,13 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesNet::shared_ptr BayesTree::marginalBayesNet( + typename BayesNetOrdered::shared_ptr BayesTreeOrdered::marginalBayesNet( Index j, Eliminate function) const { gttic(BayesTree_marginalBayesNet); // calculate marginal as a factor graph - FactorGraph fg; + FactorGraphOrdered fg; fg.push_back(this->marginalFactor(j,function)); // Reduce the variable indices to start at zero @@ -553,7 +553,7 @@ namespace gtsam { gttoc(Reduce); // eliminate factor graph marginal to a Bayes net - boost::shared_ptr > bn = GenericSequentialSolver(fg).eliminate(function); + boost::shared_ptr > bn = GenericSequentialSolver(fg).eliminate(function); // Undo the reduction gttic(Undo_Reduce); @@ -568,8 +568,8 @@ namespace gtsam { // Find two cliques, their joint, then marginalizes /* ************************************************************************* */ template - typename FactorGraph::shared_ptr - BayesTree::joint(Index j1, Index j2, Eliminate function) const { + typename FactorGraphOrdered::shared_ptr + BayesTreeOrdered::joint(Index j1, Index j2, Eliminate function) const { gttic(BayesTree_joint); // get clique C1 and C2 @@ -605,13 +605,13 @@ namespace gtsam { // Compute marginal on lowest common ancestor clique gttic(LCA_marginal); - FactorGraph p_B = B->marginal2(this->root(), function); + FactorGraphOrdered p_B = B->marginal2(this->root(), function); gttoc(LCA_marginal); // Compute shortcuts of the requested cliques given the lowest common ancestor gttic(Clique_shortcuts); - BayesNet p_C1_Bred = C1->shortcut(B, function); - BayesNet p_C2_Bred = C2->shortcut(B, function); + BayesNetOrdered p_C1_Bred = C1->shortcut(B, function); + BayesNetOrdered p_C2_Bred = C2->shortcut(B, function); gttoc(Clique_shortcuts); // Factor the shortcuts to be conditioned on the full root @@ -625,8 +625,8 @@ namespace gtsam { C1_minus_B.assign(C1_minus_B_set.begin(), C1_minus_B_set.end()); } // Factor into C1\B | B. - FactorGraph temp_remaining; - boost::tie(p_C1_B, temp_remaining) = FactorGraph(p_C1_Bred).eliminate(C1_minus_B, function); + FactorGraphOrdered temp_remaining; + boost::tie(p_C1_B, temp_remaining) = FactorGraphOrdered(p_C1_Bred).eliminate(C1_minus_B, function); } sharedConditional p_C2_B; { std::vector C2_minus_B; { @@ -636,14 +636,14 @@ namespace gtsam { C2_minus_B.assign(C2_minus_B_set.begin(), C2_minus_B_set.end()); } // Factor into C2\B | B. - FactorGraph temp_remaining; - boost::tie(p_C2_B, temp_remaining) = FactorGraph(p_C2_Bred).eliminate(C2_minus_B, function); + FactorGraphOrdered temp_remaining; + boost::tie(p_C2_B, temp_remaining) = FactorGraphOrdered(p_C2_Bred).eliminate(C2_minus_B, function); } gttoc(Full_root_factoring); gttic(Variable_joint); // Build joint on all involved variables - FactorGraph p_BC1C2; + FactorGraphOrdered p_BC1C2; p_BC1C2.push_back(p_B); p_BC1C2.push_back(p_C1_B->toFactor()); p_BC1C2.push_back(p_C2_B->toFactor()); @@ -663,7 +663,7 @@ namespace gtsam { // now, marginalize out everything that is not variable j GenericSequentialSolver solver(p_BC1C2); - boost::shared_ptr > result = solver.jointFactorGraph(js, function); + boost::shared_ptr > result = solver.jointFactorGraph(js, function); // Undo the reduction gttic(Undo_Reduce); @@ -678,7 +678,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesNet::shared_ptr BayesTree::jointBayesNet( + typename BayesNetOrdered::shared_ptr BayesTreeOrdered::jointBayesNet( Index j1, Index j2, Eliminate function) const { // eliminate factor graph marginal to a Bayes net @@ -688,7 +688,7 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::clear() { + void BayesTreeOrdered::clear() { // Remove all nodes and clear the root pointer nodes_.clear(); root_.reset(); @@ -696,8 +696,8 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::removePath(sharedClique clique, - BayesNet& bn, typename BayesTree::Cliques& orphans) { + void BayesTreeOrdered::removePath(sharedClique clique, + BayesNetOrdered& bn, typename BayesTreeOrdered::Cliques& orphans) { // base case is NULL, if so we do nothing and return empties above if (clique!=NULL) { @@ -722,8 +722,8 @@ namespace gtsam { /* ************************************************************************* */ template template - void BayesTree::removeTop(const CONTAINER& keys, - BayesNet& bn, typename BayesTree::Cliques& orphans) { + void BayesTreeOrdered::removeTop(const CONTAINER& keys, + BayesNetOrdered& bn, typename BayesTreeOrdered::Cliques& orphans) { // process each key of the new factor BOOST_FOREACH(const Index& j, keys) { @@ -746,7 +746,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTree::Cliques BayesTree::removeSubtree( + typename BayesTreeOrdered::Cliques BayesTreeOrdered::removeSubtree( const sharedClique& subtree) { // Result clique list @@ -783,14 +783,14 @@ namespace gtsam { /* ************************************************************************* */ template - void BayesTree::cloneTo(This& newTree) const { + void BayesTreeOrdered::cloneTo(This& newTree) const { if(root()) cloneTo(newTree, root(), sharedClique()); } /* ************************************************************************* */ template - void BayesTree::cloneTo( + void BayesTreeOrdered::cloneTo( This& newTree, const sharedClique& subtree, const sharedClique& parent) const { sharedClique newClique(subtree->clone()); newTree.addClique(newClique, parent); diff --git a/gtsam/inference/BayesTreeOrdered.h b/gtsam/inference/BayesTreeOrdered.h new file mode 100644 index 000000000..5d09368ad --- /dev/null +++ b/gtsam/inference/BayesTreeOrdered.h @@ -0,0 +1,418 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file BayesTree.h + * @brief Bayes Tree is a tree of cliques of a Bayes Chain + * @author Frank Dellaert + */ + +// \callgraph + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace gtsam { + + // Forward declaration of BayesTreeClique which is defined below BayesTree in this file + template struct BayesTreeClique; + + /** + * Bayes tree + * @tparam CONDITIONAL The type of the conditional densities, i.e. the type of node in the underlying Bayes chain, + * which could be a ConditionalProbabilityTable, a GaussianConditional, or a SymbolicConditional. + * @tparam CLIQUE The type of the clique data structure, defaults to BayesTreeClique, normally do not change this + * as it is only used when developing special versions of BayesTree, e.g. for ISAM2. + * + * \addtogroup Multifrontal + * \nosubgrouping + */ + template > + class BayesTreeOrdered { + + public: + + typedef BayesTreeOrdered This; + typedef boost::shared_ptr > shared_ptr; + typedef boost::shared_ptr sharedConditional; + typedef boost::shared_ptr > sharedBayesNet; + typedef CONDITIONAL ConditionalType; + typedef typename CONDITIONAL::FactorType FactorType; + typedef typename FactorGraphOrdered::Eliminate Eliminate; + + typedef CLIQUE Clique; ///< The clique type, normally BayesTreeClique + + // typedef for shared pointers to cliques + typedef boost::shared_ptr sharedClique; + + // A convenience class for a list of shared cliques + struct Cliques : public FastList { + void print(const std::string& s = "Cliques", + const IndexFormatter& indexFormatter = DefaultIndexFormatter) const; + bool equals(const Cliques& other, double tol = 1e-9) const; + }; + + /** clique statistics */ + struct CliqueStats { + double avgConditionalSize; + std::size_t maxConditionalSize; + double avgSeparatorSize; + std::size_t maxSeparatorSize; + void print(const std::string& s = "") const ; + }; + + /** store all the sizes */ + struct CliqueData { + std::vector conditionalSizes; + std::vector separatorSizes; + CliqueStats getStats() const; + }; + + /** Map from indices to Clique */ + typedef std::vector Nodes; + + protected: + + /** Map from indices to Clique */ + Nodes nodes_; + + /** Root clique */ + sharedClique root_; + + public: + + /// @name Standard Constructors + /// @{ + + /** Create an empty Bayes Tree */ + BayesTreeOrdered() {} + + /** Create a Bayes Tree from a Bayes Net (requires CONDITIONAL is IndexConditional *or* CONDITIONAL::Combine) */ + explicit BayesTreeOrdered(const BayesNetOrdered& bayesNet); + + /** Copy constructor */ + BayesTreeOrdered(const This& other); + + /** Assignment operator */ + This& operator=(const This& other); + + /// @} + /// @name Advanced Constructors + /// @{ + + /** + * Create a Bayes Tree from a Bayes Net and some subtrees. The Bayes net corresponds to the + * new root clique and the subtrees are connected to the root clique. + */ + BayesTreeOrdered(const BayesNetOrdered& bayesNet, std::list > subtrees); + + /** Destructor */ + virtual ~BayesTreeOrdered() {} + + /// @} + /// @name Testable + /// @{ + + /** check equality */ + bool equals(const BayesTreeOrdered& other, double tol = 1e-9) const; + + /** print */ + void print(const std::string& s = "", + const IndexFormatter& indexFormatter = DefaultIndexFormatter ) const; + + /// @} + /// @name Standard Interface + /// @{ + + /** + * Find parent clique of a conditional. It will look at all parents and + * return the one with the lowest index in the ordering. + */ + template + Index findParentClique(const CONTAINER& parents) const; + + /** number of cliques */ + inline size_t size() const { + if(root_) + return root_->treeSize(); + else + return 0; + } + + /** number of nodes */ + inline size_t nrNodes() const { return nodes_.size(); } + + /** Check if there are any cliques in the tree */ + inline bool empty() const { + return nodes_.empty(); + } + + /** return nodes */ + const Nodes& nodes() const { return nodes_; } + + /** return root clique */ + const sharedClique& root() const { return root_; } + + /** find the clique that contains the variable with Index j */ + inline sharedClique operator[](Index j) const { + return nodes_.at(j); + } + + /** alternate syntax for matlab: find the clique that contains the variable with Index j */ + inline sharedClique clique(Index j) const { + return nodes_.at(j); + } + + /** Gather data on all cliques */ + CliqueData getCliqueData() const; + + /** Collect number of cliques with cached separator marginals */ + size_t numCachedSeparatorMarginals() const; + + /** return marginal on any variable */ + typename FactorType::shared_ptr marginalFactor(Index j, Eliminate function) const; + + /** + * return marginal on any variable, as a Bayes Net + * NOTE: this function calls marginal, and then eliminates it into a Bayes Net + * This is more expensive than the above function + */ + typename BayesNetOrdered::shared_ptr marginalBayesNet(Index j, Eliminate function) const; + + /** + * return joint on two variables + * Limitation: can only calculate joint if cliques are disjoint or one of them is root + */ + typename FactorGraphOrdered::shared_ptr joint(Index j1, Index j2, Eliminate function) const; + + /** + * return joint on two variables as a BayesNet + * Limitation: can only calculate joint if cliques are disjoint or one of them is root + */ + typename BayesNetOrdered::shared_ptr jointBayesNet(Index j1, Index j2, Eliminate function) const; + + /** + * Read only with side effects + */ + + /** saves the Tree to a text file in GraphViz format */ + void saveGraph(const std::string& s, const IndexFormatter& indexFormatter = DefaultIndexFormatter ) const; + + /// @} + /// @name Advanced Interface + /// @{ + + /** Access the root clique (non-const version) */ + sharedClique& root() { return root_; } + + /** Access the nodes (non-cost version) */ + Nodes& nodes() { return nodes_; } + + /** Remove all nodes */ + void clear(); + + /** Clear all shortcut caches - use before timing on marginal calculation to avoid residual cache data */ + void deleteCachedShortcuts() { + root_->deleteCachedShortcuts(); + } + + /** Apply a permutation to the full tree - also updates the nodes structure */ + void permuteWithInverse(const Permutation& inversePermutation); + + /** + * Remove path from clique to root and return that path as factors + * plus a list of orphaned subtree roots. Used in removeTop below. + */ + void removePath(sharedClique clique, BayesNetOrdered& bn, Cliques& orphans); + + /** + * Given a list of indices, turn "contaminated" part of the tree back into a factor graph. + * Factors and orphans are added to the in/out arguments. + */ + template + void removeTop(const CONTAINER& indices, BayesNetOrdered& bn, Cliques& orphans); + + /** + * Remove the requested subtree. */ + Cliques removeSubtree(const sharedClique& subtree); + + /** + * Hang a new subtree off of the existing tree. This finds the appropriate + * parent clique for the subtree (which may be the root), and updates the + * nodes index with the new cliques in the subtree. None of the frontal + * variables in the subtree may appear in the separators of the existing + * BayesTree. + */ + void insert(const sharedClique& subtree); + + /** Insert a new conditional + * This function only applies for Symbolic case with IndexCondtional, + * We make it static so that it won't be compiled in GaussianConditional case. + * */ + static void insert(BayesTreeOrdered& bayesTree, const sharedConditional& conditional); + + /** + * Insert a new clique corresponding to the given Bayes net. + * It is the caller's responsibility to decide whether the given Bayes net is a valid clique, + * i.e. all the variables (frontal and separator) are connected + */ + sharedClique insert(const sharedConditional& clique, + std::list& children, bool isRootClique = false); + + /** + * Create a clone of this object as a shared pointer + * Necessary for inheritance in matlab interface + */ + virtual shared_ptr clone() const { + return shared_ptr(new This(*this)); + } + + protected: + + /** private helper method for saving the Tree to a text file in GraphViz format */ + void saveGraph(std::ostream &s, sharedClique clique, const IndexFormatter& indexFormatter, + int parentnum = 0) const; + + /** Gather data on a single clique */ + void getCliqueData(CliqueData& stats, sharedClique clique) const; + + /** remove a clique: warning, can result in a forest */ + void removeClique(sharedClique clique); + + /** add a clique (top down) */ + sharedClique addClique(const sharedConditional& conditional, const sharedClique& parent_clique = sharedClique()); + + /** add a clique (top down) */ + void addClique(const sharedClique& clique, const sharedClique& parent_clique = sharedClique()); + + /** add a clique (bottom up) */ + sharedClique addClique(const sharedConditional& conditional, std::list& child_cliques); + + /** + * Add a conditional to the front of a clique, i.e. a conditional whose + * parents are already in the clique or its separators. This function does + * not check for this condition, it just updates the data structures. + */ + static void addToCliqueFront(BayesTreeOrdered& bayesTree, + const sharedConditional& conditional, const sharedClique& clique); + + /** Fill the nodes index for a subtree */ + void fillNodesIndex(const sharedClique& subtree); + + /** Helper function to build a non-symbolic tree (e.g. Gaussian) using a + * symbolic tree, used in the BT(BN) constructor. + */ + void recursiveTreeBuild(const boost::shared_ptr >& symbolic, + const std::vector >& conditionals, + const typename BayesTreeOrdered::sharedClique& parent); + + private: + + /** deep copy to another tree */ + void cloneTo(This& newTree) const; + + /** deep copy to another tree */ + void cloneTo(This& newTree, const sharedClique& subtree, const sharedClique& parent) const; + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(nodes_); + ar & BOOST_SERIALIZATION_NVP(root_); + } + + /// @} + + }; // BayesTree + + + /* ************************************************************************* */ + template + void _BayesTree_dim_adder( + std::vector& dims, + const typename BayesTreeOrdered::sharedClique& clique) { + + if(clique) { + // Add dims from this clique + for(typename CONDITIONAL::const_iterator it = (*clique)->beginFrontals(); it != (*clique)->endFrontals(); ++it) + dims[*it] = (*clique)->dim(it); + + // Traverse children + typedef typename BayesTreeOrdered::sharedClique sharedClique; + BOOST_FOREACH(const sharedClique& child, clique->children()) { + _BayesTree_dim_adder(dims, child); + } + } + } + + /* ************************************************************************* */ + template + boost::shared_ptr allocateVectorValues(const BayesTreeOrdered& bt) { + std::vector dimensions(bt.nodes().size(), 0); + _BayesTree_dim_adder(dimensions, bt.root()); + return boost::shared_ptr(new VectorValuesOrdered(dimensions)); + } + + + /* ************************************************************************* */ + /** + * A Clique in the tree is an incomplete Bayes net: the variables + * in the Bayes net are the frontal nodes, and the variables conditioned + * on are the separator. We also have pointers up and down the tree. + * + * Since our Conditional class already handles multiple frontal variables, + * this Clique contains exactly 1 conditional. + * + * This is the default clique type in a BayesTree, but some algorithms, like + * iSAM2 (see ISAM2Clique), use a different clique type in order to store + * extra data along with the clique. + */ + template + struct BayesTreeClique : public BayesTreeCliqueBaseOrdered, CONDITIONAL> { + public: + typedef CONDITIONAL ConditionalType; + typedef BayesTreeClique This; + typedef BayesTreeCliqueBaseOrdered Base; + typedef boost::shared_ptr shared_ptr; + typedef boost::weak_ptr weak_ptr; + BayesTreeClique() {} + BayesTreeClique(const typename ConditionalType::shared_ptr& conditional) : Base(conditional) {} + BayesTreeClique(const std::pair& result) : Base(result) {} + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); + } + }; + +} /// namespace gtsam + +#include +#include diff --git a/gtsam/inference/BayesTreeUnordered.h b/gtsam/inference/BayesTreeUnordered.h deleted file mode 100644 index 2788aa7d2..000000000 --- a/gtsam/inference/BayesTreeUnordered.h +++ /dev/null @@ -1,259 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file BayesTree.h - * @brief Bayes Tree is a tree of cliques of a Bayes Chain - * @author Frank Dellaert - */ - -// \callgraph - -#pragma once - -#include -#include - -#include -#include -#include - -namespace gtsam { - - // Forward declarations - template class FactorGraphUnordered; - - /** - * Bayes tree - * @tparam CONDITIONAL The type of the conditional densities, i.e. the type of node in the underlying Bayes chain, - * which could be a ConditionalProbabilityTable, a GaussianConditional, or a SymbolicConditional. - * @tparam CLIQUE The type of the clique data structure, defaults to BayesTreeClique, normally do not change this - * as it is only used when developing special versions of BayesTree, e.g. for ISAM2. - * - * \addtogroup Multifrontal - * \nosubgrouping - */ - template - class BayesTreeUnordered - { - protected: - typedef BayesTreeUnordered This; - typedef boost::shared_ptr shared_ptr; - - public: - typedef CLIQUE Clique; ///< The clique type, normally BayesTreeClique - typedef boost::shared_ptr sharedClique; ///< Shared pointer to a clique - typedef Clique Node; ///< Synonym for Clique (TODO: remove) - typedef sharedClique sharedNode; ///< Synonym for sharedClique (TODO: remove) - typedef typename CLIQUE::ConditionalType ConditionalType; - typedef boost::shared_ptr sharedConditional; - typedef typename CLIQUE::BayesNetType BayesNetType; - typedef boost::shared_ptr sharedBayesNet; - typedef typename CLIQUE::FactorType FactorType; - typedef boost::shared_ptr sharedFactor; - typedef typename CLIQUE::FactorGraphType FactorGraphType; - typedef boost::shared_ptr sharedFactorGraph; - typedef typename FactorGraphType::Eliminate Eliminate; - typedef typename CLIQUE::EliminationTraits EliminationTraits; - - /** A convenience class for a list of shared cliques */ - typedef FastList Cliques; - - /** clique statistics */ - struct CliqueStats { - double avgConditionalSize; - std::size_t maxConditionalSize; - double avgSeparatorSize; - std::size_t maxSeparatorSize; - void print(const std::string& s = "") const ; - }; - - /** store all the sizes */ - struct CliqueData { - std::vector conditionalSizes; - std::vector separatorSizes; - CliqueStats getStats() const; - }; - - /** Map from keys to Clique */ - typedef FastMap Nodes; - - protected: - - /** Map from indices to Clique */ - Nodes nodes_; - - /** Root cliques */ - std::vector roots_; - - /// @name Standard Constructors - /// @{ - - /** Create an empty Bayes Tree */ - BayesTreeUnordered() {} - - /** Copy constructor */ - BayesTreeUnordered(const This& other); - - /// @} - - /** Assignment operator */ - This& operator=(const This& other); - - /// @name Testable - /// @{ - - /** check equality */ - bool equals(const This& other, double tol = 1e-9) const; - - public: - /** print */ - void print(const std::string& s = "", - const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; - /// @} - - /// @name Standard Interface - /// @{ - - /** number of cliques */ - size_t size() const; - - /** Check if there are any cliques in the tree */ - inline bool empty() const { - return nodes_.empty(); - } - - /** return nodes */ - const Nodes& nodes() const { return nodes_; } - - /** Access node by variable */ - const sharedNode operator[](Key j) const { return nodes_.at(j); } - - /** return root cliques */ - const std::vector& roots() const { return roots_; } - - /** alternate syntax for matlab: find the clique that contains the variable with Index j */ - const sharedClique& clique(Key j) const { - Nodes::const_iterator c = nodes_.find(j); - if(c == nodes_.end()) - throw std::out_of_range("Requested the BayesTree clique for a key that is not in the BayesTree"); - else - return c->second; - } - - /** Gather data on all cliques */ - CliqueData getCliqueData() const; - - /** Collect number of cliques with cached separator marginals */ - size_t numCachedSeparatorMarginals() const; - - /** Return marginal on any variable. Note that this actually returns a conditional, for which a - * solution may be directly obtained by calling .solve() on the returned object. - * Alternatively, it may be directly used as its factor base class. For example, for Gaussian - * systems, this returns a GaussianConditional, which inherits from JacobianFactor and - * GaussianFactor. */ - sharedConditional marginalFactor(Key j, const Eliminate& function = EliminationTraits::DefaultEliminate) const; - - /** - * return joint on two variables - * Limitation: can only calculate joint if cliques are disjoint or one of them is root - */ - sharedFactorGraph joint(Index j1, Index j2, const Eliminate& function = EliminationTraits::DefaultEliminate) const; - - /** - * return joint on two variables as a BayesNet - * Limitation: can only calculate joint if cliques are disjoint or one of them is root - */ - sharedBayesNet jointBayesNet(Index j1, Index j2, const Eliminate& function = EliminationTraits::DefaultEliminate) const; - - /** - * Read only with side effects - */ - - /** saves the Tree to a text file in GraphViz format */ - void saveGraph(const std::string& s, const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; - - /// @} - /// @name Advanced Interface - /// @{ - - /** - * Find parent clique of a conditional. It will look at all parents and - * return the one with the lowest index in the ordering. - */ - template - Index findParentClique(const CONTAINER& parents) const; - - /** Remove all nodes */ - void clear(); - - /** Clear all shortcut caches - use before timing on marginal calculation to avoid residual cache data */ - void deleteCachedShortcuts(); - - /** - * Remove path from clique to root and return that path as factors - * plus a list of orphaned subtree roots. Used in removeTop below. - */ - void removePath(sharedClique clique, BayesNetType& bn, Cliques& orphans); - - /** - * Given a list of indices, turn "contaminated" part of the tree back into a factor graph. - * Factors and orphans are added to the in/out arguments. - */ - void removeTop(const std::vector& keys, BayesNetType& bn, Cliques& orphans); - - /** - * Remove the requested subtree. */ - Cliques removeSubtree(const sharedClique& subtree); - - /** Insert a new subtree with known parent clique. This function does not check that the - * specified parent is the correct parent. This function updates all of the internal data - * structures associated with adding a subtree, such as populating the nodes index. */ - void insertRoot(const sharedClique& subtree); - - /** add a clique (top down) */ - void addClique(const sharedClique& clique, const sharedClique& parent_clique = sharedClique()); - - /** Add all cliques in this BayesTree to the specified factor graph */ - void addFactorsToGraph(FactorGraphUnordered& graph) const; - - protected: - - /** private helper method for saving the Tree to a text file in GraphViz format */ - void saveGraph(std::ostream &s, sharedClique clique, const KeyFormatter& keyFormatter, - int parentnum = 0) const; - - /** Gather data on a single clique */ - void getCliqueData(CliqueData& stats, sharedClique clique) const; - - /** remove a clique: warning, can result in a forest */ - void removeClique(sharedClique clique); - - /** add a clique (bottom up) */ - sharedClique addClique(const sharedConditional& conditional, std::list& child_cliques); - - /** Fill the nodes index for a subtree */ - void fillNodesIndex(const sharedClique& subtree); - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(nodes_); - ar & BOOST_SERIALIZATION_NVP(root_); - } - - /// @} - - }; // BayesTree - -} /// namespace gtsam diff --git a/gtsam/inference/ClusterTree-inl.h b/gtsam/inference/ClusterTreeOrdered-inl.h similarity index 83% rename from gtsam/inference/ClusterTree-inl.h rename to gtsam/inference/ClusterTreeOrdered-inl.h index 5be1383c4..193a6ba4e 100644 --- a/gtsam/inference/ClusterTree-inl.h +++ b/gtsam/inference/ClusterTreeOrdered-inl.h @@ -22,7 +22,7 @@ #include #include -#include +#include namespace gtsam { @@ -31,32 +31,32 @@ namespace gtsam { * ************************************************************************* */ template template - ClusterTree::Cluster::Cluster(const FG& fg, Index key, Iterator firstSeparator, Iterator lastSeparator) : + ClusterTreeOrdered::Cluster::Cluster(const FG& fg, Index key, Iterator firstSeparator, Iterator lastSeparator) : FG(fg), frontal(1, key), separator(firstSeparator, lastSeparator) {} /* ************************************************************************* */ template template - ClusterTree::Cluster::Cluster( + ClusterTreeOrdered::Cluster::Cluster( const FG& fg, FRONTALIT firstFrontal, FRONTALIT lastFrontal, SEPARATORIT firstSeparator, SEPARATORIT lastSeparator) : FG(fg), frontal(firstFrontal, lastFrontal), separator(firstSeparator, lastSeparator) {} /* ************************************************************************* */ template template - ClusterTree::Cluster::Cluster( + ClusterTreeOrdered::Cluster::Cluster( FRONTALIT firstFrontal, FRONTALIT lastFrontal, SEPARATORIT firstSeparator, SEPARATORIT lastSeparator) : frontal(firstFrontal, lastFrontal), separator(firstSeparator, lastSeparator) {} /* ************************************************************************* */ template - void ClusterTree::Cluster::addChild(typename ClusterTree::Cluster::shared_ptr child) { + void ClusterTreeOrdered::Cluster::addChild(typename ClusterTreeOrdered::Cluster::shared_ptr child) { children_.push_back(child); } /* ************************************************************************* */ template - bool ClusterTree::Cluster::equals(const Cluster& other) const { + bool ClusterTreeOrdered::Cluster::equals(const Cluster& other) const { if (frontal != other.frontal) return false; if (separator != other.separator) return false; if (children_.size() != other.children_.size()) return false; @@ -71,7 +71,7 @@ namespace gtsam { /* ************************************************************************* */ template - void ClusterTree::Cluster::print(const std::string& indent, + void ClusterTreeOrdered::Cluster::print(const std::string& indent, const IndexFormatter& formatter) const { std::cout << indent; BOOST_FOREACH(const Index key, frontal) @@ -84,7 +84,7 @@ namespace gtsam { /* ************************************************************************* */ template - void ClusterTree::Cluster::printTree(const std::string& indent, + void ClusterTreeOrdered::Cluster::printTree(const std::string& indent, const IndexFormatter& formatter) const { print(indent, formatter); BOOST_FOREACH(const shared_ptr& child, children_) @@ -95,7 +95,7 @@ namespace gtsam { * ClusterTree * ************************************************************************* */ template - void ClusterTree::print(const std::string& str, + void ClusterTreeOrdered::print(const std::string& str, const IndexFormatter& formatter) const { std::cout << str << std::endl; if (root_) root_->printTree("", formatter); @@ -103,7 +103,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool ClusterTree::equals(const ClusterTree& other, double tol) const { + bool ClusterTreeOrdered::equals(const ClusterTreeOrdered& other, double tol) const { if (!root_ && !other.root_) return true; if (!root_ || !other.root_) return false; return root_->equals(*other.root_); diff --git a/gtsam/inference/ClusterTree.h b/gtsam/inference/ClusterTreeOrdered.h similarity index 95% rename from gtsam/inference/ClusterTree.h rename to gtsam/inference/ClusterTreeOrdered.h index b88929878..6e575e1be 100644 --- a/gtsam/inference/ClusterTree.h +++ b/gtsam/inference/ClusterTreeOrdered.h @@ -38,7 +38,7 @@ namespace gtsam { * \nosubgrouping */ template - class ClusterTree { + class ClusterTreeOrdered { public: // Access to factor types typedef typename FG::KeyType KeyType; @@ -113,7 +113,7 @@ namespace gtsam { /// @{ /// constructor of empty tree - ClusterTree() {} + ClusterTreeOrdered() {} /// @} /// @name Standard Interface @@ -130,7 +130,7 @@ namespace gtsam { void print(const std::string& str="", const IndexFormatter& formatter = DefaultIndexFormatter) const; /** check equality */ - bool equals(const ClusterTree& other, double tol = 1e-9) const; + bool equals(const ClusterTreeOrdered& other, double tol = 1e-9) const; /// @} @@ -138,4 +138,4 @@ namespace gtsam { } // namespace gtsam -#include +#include diff --git a/gtsam/inference/ConditionalUnordered-inst.h b/gtsam/inference/Conditional-inst.h similarity index 81% rename from gtsam/inference/ConditionalUnordered-inst.h rename to gtsam/inference/Conditional-inst.h index 11ae7f7a5..4069a6e2a 100644 --- a/gtsam/inference/ConditionalUnordered-inst.h +++ b/gtsam/inference/Conditional-inst.h @@ -21,13 +21,13 @@ #include #include -#include +#include namespace gtsam { /* ************************************************************************* */ template - void ConditionalUnordered::print(const std::string& s, const KeyFormatter& formatter) const { + void Conditional::print(const std::string& s, const KeyFormatter& formatter) const { std::cout << s << " P("; BOOST_FOREACH(Key key, frontals()) std::cout << " " << formatter(key); @@ -40,7 +40,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool ConditionalUnordered::equals(const This& c, double tol = 1e-9) const + bool Conditional::equals(const This& c, double tol = 1e-9) const { return nrFrontals_ == c.nrFrontals_; } diff --git a/gtsam/inference/Conditional.h b/gtsam/inference/Conditional.h index 0e3e98361..067cdd802 100644 --- a/gtsam/inference/Conditional.h +++ b/gtsam/inference/Conditional.h @@ -1,266 +1,147 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file Conditional.h - * @brief Base class for conditional densities - * @author Frank Dellaert - */ - -// \callgraph -#pragma once - -#include - -#include - -#include -#include - -namespace gtsam { - - /** - * Base class for conditional densities, templated on KEY type. This class - * provides storage for the keys involved in a conditional, and iterators and - * access to the frontal and separator keys. - * - * Derived classes *must* redefine the Factor and shared_ptr typedefs to refer - * to the associated factor type and shared_ptr type of the derived class. See - * IndexConditional and GaussianConditional for examples. - * \nosubgrouping - */ - template - class Conditional: public gtsam::Factor { - - private: - - /** Create keys by adding key in front */ - template - static std::vector MakeKeys(KEY key, ITERATOR firstParent, - ITERATOR lastParent) { - std::vector keys((lastParent - firstParent) + 1); - std::copy(firstParent, lastParent, keys.begin() + 1); - keys[0] = key; - return keys; - } - - protected: - - /** The first nFrontal variables are frontal and the rest are parents. */ - size_t nrFrontals_; - - // Calls the base class assertInvariants, which checks for unique keys - void assertInvariants() const { - Factor::assertInvariants(); - } - - public: - - typedef KEY KeyType; - typedef Conditional This; - typedef Factor Base; - - /** - * Typedef to the factor type that produces this conditional and that this - * conditional can be converted to using a factor constructor. Derived - * classes must redefine this. - */ - typedef gtsam::Factor FactorType; - - /** A shared_ptr to this class. Derived classes must redefine this. */ - typedef boost::shared_ptr shared_ptr; - - /** Iterator over keys */ - typedef typename FactorType::iterator iterator; - - /** Const iterator over keys */ - typedef typename FactorType::const_iterator const_iterator; - - /** View of the frontal keys (call frontals()) */ - typedef boost::iterator_range Frontals; - - /** View of the separator keys (call parents()) */ - typedef boost::iterator_range Parents; - - /// @name Standard Constructors - /// @{ - - /** Empty Constructor to make serialization possible */ - Conditional() : - nrFrontals_(0) { - assertInvariants(); - } - - /** No parents */ - Conditional(KeyType key) : - FactorType(key), nrFrontals_(1) { - assertInvariants(); - } - - /** Single parent */ - Conditional(KeyType key, KeyType parent) : - FactorType(key, parent), nrFrontals_(1) { - assertInvariants(); - } - - /** Two parents */ - Conditional(KeyType key, KeyType parent1, KeyType parent2) : - FactorType(key, parent1, parent2), nrFrontals_(1) { - assertInvariants(); - } - - /** Three parents */ - Conditional(KeyType key, KeyType parent1, KeyType parent2, KeyType parent3) : - FactorType(key, parent1, parent2, parent3), nrFrontals_(1) { - assertInvariants(); - } - - /// @} - /// @name Advanced Constructors - /// @{ - - /** Constructor from a frontal variable and a vector of parents */ - Conditional(KeyType key, const std::vector& parents) : - FactorType(MakeKeys(key, parents.begin(), parents.end())), nrFrontals_( - 1) { - assertInvariants(); - } - - /** Constructor from keys and nr of frontal variables */ - Conditional(const std::vector& keys, size_t nrFrontals) : - FactorType(keys), nrFrontals_(nrFrontals) { - assertInvariants(); - } - - /** Constructor from keys and nr of frontal variables */ - Conditional(const std::list& keys, size_t nrFrontals) : - FactorType(keys.begin(),keys.end()), nrFrontals_(nrFrontals) { - assertInvariants(); - } - - /// @} - /// @name Testable - /// @{ - - /** print with optional formatter */ - void print(const std::string& s = "Conditional", - const IndexFormatter& formatter = DefaultIndexFormatter) const; - - /** check equality */ - template - bool equals(const DERIVED& c, double tol = 1e-9) const { - return nrFrontals_ == c.nrFrontals_ && FactorType::equals(c, tol); - } - - /// @} - /// @name Standard Interface - /// @{ - - /** return the number of frontals */ - size_t nrFrontals() const { - return nrFrontals_; - } - - /** return the number of parents */ - size_t nrParents() const { - return FactorType::size() - nrFrontals_; - } - - /** Special accessor when there is only one frontal variable. */ - KeyType firstFrontalKey() const { - assert(nrFrontals_>0); - return FactorType::front(); - } - KeyType lastFrontalKey() const { - assert(nrFrontals_>0); - return *(endFrontals() - 1); - } - - /** return a view of the frontal keys */ - Frontals frontals() const { - return boost::make_iterator_range(beginFrontals(), endFrontals()); - } - - /** return a view of the parent keys */ - Parents parents() const { - return boost::make_iterator_range(beginParents(), endParents()); - } - - /** Iterators over frontal and parent variables. */ - const_iterator beginFrontals() const { - return FactorType::begin(); - } /// frontals() { - return boost::make_iterator_range(beginFrontals(), endFrontals()); - } - - ///TODO: comment - boost::iterator_range parents() { - return boost::make_iterator_range(beginParents(), endParents()); - } - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); - ar & BOOST_SERIALIZATION_NVP(nrFrontals_); - } - - /// @} - - }; - - /* ************************************************************************* */ - template - void Conditional::print(const std::string& s, - const IndexFormatter& formatter) const { - std::cout << s << " P("; - BOOST_FOREACH(KeyType key, frontals()) - std::cout << " " << formatter(key); - if (nrParents() > 0) - std::cout << " |"; - BOOST_FOREACH(KeyType parent, parents()) - std::cout << " " << formatter(parent); - std::cout << ")" << std::endl; - } - -} // gtsam +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file Conditional.h + * @brief Base class for conditional densities + * @author Frank Dellaert + */ + +// \callgraph +#pragma once + +#include + +#include + +namespace gtsam { + + /** + * Base class for conditional densities, templated on KEY type. This class + * provides storage for the keys involved in a conditional, and iterators and + * access to the frontal and separator keys. + * + * Derived classes *must* redefine the Factor and shared_ptr typedefs to refer + * to the associated factor type and shared_ptr type of the derived class. See + * IndexConditional and GaussianConditional for examples. + * \nosubgrouping + */ + template + class Conditional + { + protected: + /** The first nrFrontal variables are frontal and the rest are parents. */ + size_t nrFrontals_; + + private: + /// Typedef to this class + typedef Conditional This; + + public: + /** View of the frontal keys (call frontals()) */ + typedef boost::iterator_range Frontals; + + /** View of the separator keys (call parents()) */ + typedef boost::iterator_range Parents; + + protected: + /// @name Standard Constructors + /// @{ + + /** Empty Constructor to make serialization possible */ + Conditional() : nrFrontals_(0) {} + + /** Constructor */ + Conditional(size_t nrFrontals) : nrFrontals_(nrFrontals) {} + + /// @} + /// @name Testable + /// @{ + + /** print with optional formatter */ + void print(const std::string& s = "Conditional", const KeyFormatter& formatter = DefaultKeyFormatter) const; + + /** check equality */ + bool equals(const This& c, double tol = 1e-9) const; + + /// @} + + public: + /// @name Standard Interface + /// @{ + + /** return the number of frontals */ + size_t nrFrontals() const { return nrFrontals_; } + + /** return the number of parents */ + size_t nrParents() const { return asFactor().size() - nrFrontals_; } + + /** Convenience function to get the first frontal key */ + Key firstFrontalKey() const { + if(nrFrontals_ > 0) + return asFactor().front(); + else + throw std::invalid_argument("Requested Conditional::firstFrontalKey from a conditional with zero frontal keys"); + } + + /** return a view of the frontal keys */ + Frontals frontals() const { return boost::make_iterator_range(beginFrontals(), endFrontals()); } + + /** return a view of the parent keys */ + Parents parents() const { return boost::make_iterator_range(beginParents(), endParents()); } + + /** Iterator pointing to first frontal key. */ + typename FACTOR::const_iterator beginFrontals() const { return asFactor().begin(); } + + /** Iterator pointing past the last frontal key. */ + typename FACTOR::const_iterator endFrontals() const { return asFactor().begin() + nrFrontals_; } + + /** Iterator pointing to the first parent key. */ + typename FACTOR::const_iterator beginParents() const { return endFrontals(); } + + /** Iterator pointing past the last parent key. */ + typename FACTOR::const_iterator endParents() const { return asFactor().end(); } + + /// @} + /// @name Advanced Interface + /// @{ + + /** Mutable iterator pointing to first frontal key. */ + typename FACTOR::iterator beginFrontals() { return asFactor().begin(); } + + /** Mutable iterator pointing past the last frontal key. */ + typename FACTOR::iterator endFrontals() { return asFactor().begin() + nrFrontals_; } + + /** Mutable iterator pointing to the first parent key. */ + typename FACTOR::iterator beginParents() { return asFactor().begin() + nrFrontals_; } + + /** Mutable iterator pointing past the last parent key. */ + typename FACTOR::iterator endParents() { return asFactor().end(); } + + private: + // Cast to factor type (non-const) (casts down to derived conditional type, then up to factor type) + FACTOR& asFactor() { return static_cast(static_cast(*this)); } + + // Cast to derived type (const) (casts down to derived conditional type, then up to factor type) + const FACTOR& asFactor() const { return static_cast(static_cast(*this)); } + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(nrFrontals_); + } + + /// @} + + }; + +} // gtsam diff --git a/gtsam/inference/ConditionalOrdered.h b/gtsam/inference/ConditionalOrdered.h new file mode 100644 index 000000000..69c0db79b --- /dev/null +++ b/gtsam/inference/ConditionalOrdered.h @@ -0,0 +1,266 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file Conditional.h + * @brief Base class for conditional densities + * @author Frank Dellaert + */ + +// \callgraph +#pragma once + +#include + +#include + +#include +#include + +namespace gtsam { + + /** + * Base class for conditional densities, templated on KEY type. This class + * provides storage for the keys involved in a conditional, and iterators and + * access to the frontal and separator keys. + * + * Derived classes *must* redefine the Factor and shared_ptr typedefs to refer + * to the associated factor type and shared_ptr type of the derived class. See + * IndexConditional and GaussianConditional for examples. + * \nosubgrouping + */ + template + class ConditionalOrdered: public gtsam::FactorOrdered { + + private: + + /** Create keys by adding key in front */ + template + static std::vector MakeKeys(KEY key, ITERATOR firstParent, + ITERATOR lastParent) { + std::vector keys((lastParent - firstParent) + 1); + std::copy(firstParent, lastParent, keys.begin() + 1); + keys[0] = key; + return keys; + } + + protected: + + /** The first nFrontal variables are frontal and the rest are parents. */ + size_t nrFrontals_; + + // Calls the base class assertInvariants, which checks for unique keys + void assertInvariants() const { + FactorOrdered::assertInvariants(); + } + + public: + + typedef KEY KeyType; + typedef ConditionalOrdered This; + typedef FactorOrdered Base; + + /** + * Typedef to the factor type that produces this conditional and that this + * conditional can be converted to using a factor constructor. Derived + * classes must redefine this. + */ + typedef gtsam::FactorOrdered FactorType; + + /** A shared_ptr to this class. Derived classes must redefine this. */ + typedef boost::shared_ptr shared_ptr; + + /** Iterator over keys */ + typedef typename FactorType::iterator iterator; + + /** Const iterator over keys */ + typedef typename FactorType::const_iterator const_iterator; + + /** View of the frontal keys (call frontals()) */ + typedef boost::iterator_range Frontals; + + /** View of the separator keys (call parents()) */ + typedef boost::iterator_range Parents; + + /// @name Standard Constructors + /// @{ + + /** Empty Constructor to make serialization possible */ + ConditionalOrdered() : + nrFrontals_(0) { + assertInvariants(); + } + + /** No parents */ + ConditionalOrdered(KeyType key) : + FactorType(key), nrFrontals_(1) { + assertInvariants(); + } + + /** Single parent */ + ConditionalOrdered(KeyType key, KeyType parent) : + FactorType(key, parent), nrFrontals_(1) { + assertInvariants(); + } + + /** Two parents */ + ConditionalOrdered(KeyType key, KeyType parent1, KeyType parent2) : + FactorType(key, parent1, parent2), nrFrontals_(1) { + assertInvariants(); + } + + /** Three parents */ + ConditionalOrdered(KeyType key, KeyType parent1, KeyType parent2, KeyType parent3) : + FactorType(key, parent1, parent2, parent3), nrFrontals_(1) { + assertInvariants(); + } + + /// @} + /// @name Advanced Constructors + /// @{ + + /** Constructor from a frontal variable and a vector of parents */ + ConditionalOrdered(KeyType key, const std::vector& parents) : + FactorType(MakeKeys(key, parents.begin(), parents.end())), nrFrontals_( + 1) { + assertInvariants(); + } + + /** Constructor from keys and nr of frontal variables */ + ConditionalOrdered(const std::vector& keys, size_t nrFrontals) : + FactorType(keys), nrFrontals_(nrFrontals) { + assertInvariants(); + } + + /** Constructor from keys and nr of frontal variables */ + ConditionalOrdered(const std::list& keys, size_t nrFrontals) : + FactorType(keys.begin(),keys.end()), nrFrontals_(nrFrontals) { + assertInvariants(); + } + + /// @} + /// @name Testable + /// @{ + + /** print with optional formatter */ + void print(const std::string& s = "Conditional", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /** check equality */ + template + bool equals(const DERIVED& c, double tol = 1e-9) const { + return nrFrontals_ == c.nrFrontals_ && FactorType::equals(c, tol); + } + + /// @} + /// @name Standard Interface + /// @{ + + /** return the number of frontals */ + size_t nrFrontals() const { + return nrFrontals_; + } + + /** return the number of parents */ + size_t nrParents() const { + return FactorType::size() - nrFrontals_; + } + + /** Special accessor when there is only one frontal variable. */ + KeyType firstFrontalKey() const { + assert(nrFrontals_>0); + return FactorType::front(); + } + KeyType lastFrontalKey() const { + assert(nrFrontals_>0); + return *(endFrontals() - 1); + } + + /** return a view of the frontal keys */ + Frontals frontals() const { + return boost::make_iterator_range(beginFrontals(), endFrontals()); + } + + /** return a view of the parent keys */ + Parents parents() const { + return boost::make_iterator_range(beginParents(), endParents()); + } + + /** Iterators over frontal and parent variables. */ + const_iterator beginFrontals() const { + return FactorType::begin(); + } /// frontals() { + return boost::make_iterator_range(beginFrontals(), endFrontals()); + } + + ///TODO: comment + boost::iterator_range parents() { + return boost::make_iterator_range(beginParents(), endParents()); + } + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); + ar & BOOST_SERIALIZATION_NVP(nrFrontals_); + } + + /// @} + + }; + + /* ************************************************************************* */ + template + void ConditionalOrdered::print(const std::string& s, + const IndexFormatter& formatter) const { + std::cout << s << " P("; + BOOST_FOREACH(KeyType key, frontals()) + std::cout << " " << formatter(key); + if (nrParents() > 0) + std::cout << " |"; + BOOST_FOREACH(KeyType parent, parents()) + std::cout << " " << formatter(parent); + std::cout << ")" << std::endl; + } + +} // gtsam diff --git a/gtsam/inference/ConditionalUnordered.h b/gtsam/inference/ConditionalUnordered.h deleted file mode 100644 index 68724e982..000000000 --- a/gtsam/inference/ConditionalUnordered.h +++ /dev/null @@ -1,147 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file Conditional.h - * @brief Base class for conditional densities - * @author Frank Dellaert - */ - -// \callgraph -#pragma once - -#include - -#include - -namespace gtsam { - - /** - * Base class for conditional densities, templated on KEY type. This class - * provides storage for the keys involved in a conditional, and iterators and - * access to the frontal and separator keys. - * - * Derived classes *must* redefine the Factor and shared_ptr typedefs to refer - * to the associated factor type and shared_ptr type of the derived class. See - * IndexConditional and GaussianConditional for examples. - * \nosubgrouping - */ - template - class ConditionalUnordered - { - protected: - /** The first nrFrontal variables are frontal and the rest are parents. */ - size_t nrFrontals_; - - private: - /// Typedef to this class - typedef ConditionalUnordered This; - - public: - /** View of the frontal keys (call frontals()) */ - typedef boost::iterator_range Frontals; - - /** View of the separator keys (call parents()) */ - typedef boost::iterator_range Parents; - - protected: - /// @name Standard Constructors - /// @{ - - /** Empty Constructor to make serialization possible */ - ConditionalUnordered() : nrFrontals_(0) {} - - /** Constructor */ - ConditionalUnordered(size_t nrFrontals) : nrFrontals_(nrFrontals) {} - - /// @} - /// @name Testable - /// @{ - - /** print with optional formatter */ - void print(const std::string& s = "Conditional", const KeyFormatter& formatter = DefaultKeyFormatter) const; - - /** check equality */ - bool equals(const This& c, double tol = 1e-9) const; - - /// @} - - public: - /// @name Standard Interface - /// @{ - - /** return the number of frontals */ - size_t nrFrontals() const { return nrFrontals_; } - - /** return the number of parents */ - size_t nrParents() const { return asFactor().size() - nrFrontals_; } - - /** Convenience function to get the first frontal key */ - Key firstFrontalKey() const { - if(nrFrontals_ > 0) - return asFactor().front(); - else - throw std::invalid_argument("Requested Conditional::firstFrontalKey from a conditional with zero frontal keys"); - } - - /** return a view of the frontal keys */ - Frontals frontals() const { return boost::make_iterator_range(beginFrontals(), endFrontals()); } - - /** return a view of the parent keys */ - Parents parents() const { return boost::make_iterator_range(beginParents(), endParents()); } - - /** Iterator pointing to first frontal key. */ - typename FACTOR::const_iterator beginFrontals() const { return asFactor().begin(); } - - /** Iterator pointing past the last frontal key. */ - typename FACTOR::const_iterator endFrontals() const { return asFactor().begin() + nrFrontals_; } - - /** Iterator pointing to the first parent key. */ - typename FACTOR::const_iterator beginParents() const { return endFrontals(); } - - /** Iterator pointing past the last parent key. */ - typename FACTOR::const_iterator endParents() const { return asFactor().end(); } - - /// @} - /// @name Advanced Interface - /// @{ - - /** Mutable iterator pointing to first frontal key. */ - typename FACTOR::iterator beginFrontals() { return asFactor().begin(); } - - /** Mutable iterator pointing past the last frontal key. */ - typename FACTOR::iterator endFrontals() { return asFactor().begin() + nrFrontals_; } - - /** Mutable iterator pointing to the first parent key. */ - typename FACTOR::iterator beginParents() { return asFactor().begin() + nrFrontals_; } - - /** Mutable iterator pointing past the last parent key. */ - typename FACTOR::iterator endParents() { return asFactor().end(); } - - private: - // Cast to factor type (non-const) (casts down to derived conditional type, then up to factor type) - FACTOR& asFactor() { return static_cast(static_cast(*this)); } - - // Cast to derived type (const) (casts down to derived conditional type, then up to factor type) - const FACTOR& asFactor() const { return static_cast(static_cast(*this)); } - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(nrFrontals_); - } - - /// @} - - }; - -} // gtsam diff --git a/gtsam/inference/EliminateableFactorGraph-inst.h b/gtsam/inference/EliminateableFactorGraph-inst.h index 88546c5cc..646152a9d 100644 --- a/gtsam/inference/EliminateableFactorGraph-inst.h +++ b/gtsam/inference/EliminateableFactorGraph-inst.h @@ -44,13 +44,13 @@ namespace gtsam { // If no VariableIndex provided, compute one and call this function again IMPORTANT: we check // for no variable index first so that it's always computed if we need to call COLAMD because // no Ordering is provided. - return eliminateSequential(ordering, function, VariableIndexUnordered(asDerived())); + return eliminateSequential(ordering, function, VariableIndex(asDerived())); } else /*if(!ordering)*/ { // If no Ordering provided, compute one and call this function again. We are guaranteed to // have a VariableIndex already here because we computed one if needed in the previous 'else' // block. - return eliminateSequential(OrderingUnordered::COLAMD(*variableIndex), function); + return eliminateSequential(Ordering::COLAMD(*variableIndex), function); } } @@ -75,13 +75,13 @@ namespace gtsam { // If no VariableIndex provided, compute one and call this function again IMPORTANT: we check // for no variable index first so that it's always computed if we need to call COLAMD because // no Ordering is provided. - return eliminateMultifrontal(ordering, function, VariableIndexUnordered(asDerived())); + return eliminateMultifrontal(ordering, function, VariableIndex(asDerived())); } else /*if(!ordering)*/ { // If no Ordering provided, compute one and call this function again. We are guaranteed to // have a VariableIndex already here because we computed one if needed in the previous 'else' // block. - return eliminateMultifrontal(OrderingUnordered::COLAMD(*variableIndex), function); + return eliminateMultifrontal(Ordering::COLAMD(*variableIndex), function); } } @@ -89,7 +89,7 @@ namespace gtsam { template std::pair::BayesNetType>, boost::shared_ptr > EliminateableFactorGraph::eliminatePartialSequential( - const OrderingUnordered& ordering, const Eliminate& function, OptionalVariableIndex variableIndex) const + const Ordering& ordering, const Eliminate& function, OptionalVariableIndex variableIndex) const { if(variableIndex) { gttic(eliminatePartialSequential); @@ -97,7 +97,7 @@ namespace gtsam { return EliminationTreeType(asDerived(), *variableIndex, ordering).eliminate(function); } else { // If no variable index is provided, compute one and call this function again - return eliminatePartialSequential(ordering, function, VariableIndexUnordered(asDerived())); + return eliminatePartialSequential(ordering, function, VariableIndex(asDerived())); } } @@ -105,7 +105,7 @@ namespace gtsam { template std::pair::BayesTreeType>, boost::shared_ptr > EliminateableFactorGraph::eliminatePartialMultifrontal( - const OrderingUnordered& ordering, const Eliminate& function, OptionalVariableIndex variableIndex) const + const Ordering& ordering, const Eliminate& function, OptionalVariableIndex variableIndex) const { if(variableIndex) { gttic(eliminatePartialMultifrontal); @@ -113,7 +113,7 @@ namespace gtsam { return JunctionTreeType(EliminationTreeType(asDerived(), *variableIndex, ordering)).eliminate(function); } else { // If no variable index is provided, compute one and call this function again - return eliminatePartialMultifrontal(ordering, function, VariableIndexUnordered(asDerived())); + return eliminatePartialMultifrontal(ordering, function, VariableIndex(asDerived())); } } @@ -121,7 +121,7 @@ namespace gtsam { template boost::shared_ptr::BayesNetType> EliminateableFactorGraph::marginalMultifrontalBayesNet( - boost::variant&> variables, + boost::variant&> variables, OptionalOrdering marginalizedVariableOrdering, const Eliminate& function = EliminationTraits::DefaultEliminate, OptionalVariableIndex variableIndex = boost::none) const @@ -136,7 +136,7 @@ namespace gtsam { std::pair, boost::shared_ptr > eliminated = eliminatePartialMultifrontal(*marginalizedVariableOrdering, function, *variableIndex); - if(const OrderingUnordered* varsAsOrdering = boost::get(&variables)) + if(const Ordering* varsAsOrdering = boost::get(&variables)) { // An ordering was also provided for the unmarginalized variables, so we can also // eliminate them in the order requested. @@ -152,25 +152,25 @@ namespace gtsam { { // No ordering was provided for the marginalized variables, so order them using constrained // COLAMD. - bool unmarginalizedAreOrdered = (boost::get(&variables) != 0); + bool unmarginalizedAreOrdered = (boost::get(&variables) != 0); const std::vector* variablesOrOrdering = unmarginalizedAreOrdered ? - boost::get(&variables) : boost::get&>(&variables); + boost::get(&variables) : boost::get&>(&variables); - OrderingUnordered totalOrdering = - OrderingUnordered::COLAMDConstrainedLast(*variableIndex, *variablesOrOrdering, unmarginalizedAreOrdered); + Ordering totalOrdering = + Ordering::COLAMDConstrainedLast(*variableIndex, *variablesOrOrdering, unmarginalizedAreOrdered); // Split up ordering const size_t nVars = variablesOrOrdering->size(); - OrderingUnordered marginalizationOrdering(totalOrdering.begin(), totalOrdering.end() - nVars); - OrderingUnordered marginalVarsOrdering(totalOrdering.end() - nVars, totalOrdering.end()); + Ordering marginalizationOrdering(totalOrdering.begin(), totalOrdering.end() - nVars); + Ordering marginalVarsOrdering(totalOrdering.end() - nVars, totalOrdering.end()); // Call this function again with the computed orderings return marginalMultifrontalBayesNet(marginalVarsOrdering, marginalizationOrdering, function, *variableIndex); } } else { // If no variable index is provided, compute one and call this function again - return marginalMultifrontalBayesNet(variables, marginalizedVariableOrdering, function, VariableIndexUnordered(asDerived())); + return marginalMultifrontalBayesNet(variables, marginalizedVariableOrdering, function, VariableIndex(asDerived())); } } diff --git a/gtsam/inference/EliminateableFactorGraph.h b/gtsam/inference/EliminateableFactorGraph.h index a62f5af8a..cc6e9b128 100644 --- a/gtsam/inference/EliminateableFactorGraph.h +++ b/gtsam/inference/EliminateableFactorGraph.h @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include namespace gtsam { @@ -43,7 +43,7 @@ namespace gtsam { // typedef MyJunctionTree JunctionTreeType; ///< Type of Junction tree (e.g. GaussianJunctionTree) // static pair, shared_ptr // DefaultEliminate( - // const MyFactorGraph& factors, const OrderingUnordered& keys); ///< The default dense elimination function + // const MyFactorGraph& factors, const Ordering& keys); ///< The default dense elimination function }; @@ -85,13 +85,13 @@ namespace gtsam { typedef std::pair, boost::shared_ptr<_FactorType> > EliminationResult; /// The function type that does a single dense elimination step on a subgraph. - typedef boost::function Eliminate; + typedef boost::function Eliminate; /// Typedef for an optional ordering as an argument to elimination functions - typedef boost::optional OptionalOrdering; + typedef boost::optional OptionalOrdering; /// Typedef for an optional variable index as an argument to elimination functions - typedef boost::optional OptionalVariableIndex; + typedef boost::optional OptionalVariableIndex; /** Do sequential elimination of all variables to produce a Bayes net. If an ordering is not * provided, the ordering provided by COLAMD will be used. @@ -149,7 +149,7 @@ namespace gtsam { * B = X\backslash A \f$. */ std::pair, boost::shared_ptr > eliminatePartialSequential( - const OrderingUnordered& ordering, + const Ordering& ordering, const Eliminate& function = EliminationTraits::DefaultEliminate, OptionalVariableIndex variableIndex = boost::none) const; @@ -169,7 +169,7 @@ namespace gtsam { * factor graph, and \f$ B = X\backslash A \f$. */ std::pair, boost::shared_ptr > eliminatePartialMultifrontal( - const OrderingUnordered& ordering, + const Ordering& ordering, const Eliminate& function = EliminationTraits::DefaultEliminate, OptionalVariableIndex variableIndex = boost::none) const; @@ -195,7 +195,7 @@ namespace gtsam { * @param variableIndex Optional pre-computed VariableIndex for the factor graph, if not * provided one will be computed. */ boost::shared_ptr marginalMultifrontalBayesNet( - boost::variant&> variables, + boost::variant&> variables, OptionalOrdering marginalizedVariableOrdering = boost::none, const Eliminate& function = EliminationTraits::DefaultEliminate, OptionalVariableIndex variableIndex = boost::none) const; diff --git a/gtsam/inference/EliminationTreeUnordered-inst.h b/gtsam/inference/EliminationTree-inst.h similarity index 87% rename from gtsam/inference/EliminationTreeUnordered-inst.h rename to gtsam/inference/EliminationTree-inst.h index d1f2e79d7..f4b77efa7 100644 --- a/gtsam/inference/EliminationTreeUnordered-inst.h +++ b/gtsam/inference/EliminationTree-inst.h @@ -24,17 +24,17 @@ #include #include -#include -#include -#include +#include +#include +#include #include namespace gtsam { /* ************************************************************************* */ template - typename EliminationTreeUnordered::sharedFactor - EliminationTreeUnordered::Node::eliminate( + typename EliminationTree::sharedFactor + EliminationTree::Node::eliminate( const boost::shared_ptr& output, const Eliminate& function, const std::vector& childrenResults) const { @@ -51,7 +51,7 @@ namespace gtsam { // Do dense elimination step std::vector keyAsVector(1); keyAsVector[0] = key; std::pair, boost::shared_ptr > eliminationResult = - function(gatheredFactors, OrderingUnordered(keyAsVector)); + function(gatheredFactors, Ordering(keyAsVector)); // Add conditional to BayesNet output->push_back(eliminationResult.first); @@ -62,7 +62,7 @@ namespace gtsam { /* ************************************************************************* */ template - void EliminationTreeUnordered::Node::print( + void EliminationTree::Node::print( const std::string& str, const KeyFormatter& keyFormatter) const { std::cout << str << "(" << keyFormatter(key) << ")\n"; @@ -77,8 +77,8 @@ namespace gtsam { /* ************************************************************************* */ template - EliminationTreeUnordered::EliminationTreeUnordered(const FactorGraphType& graph, - const VariableIndexUnordered& structure, const OrderingUnordered& order) + EliminationTree::EliminationTree(const FactorGraphType& graph, + const VariableIndex& structure, const Ordering& order) { gttic(EliminationTree_Contructor); @@ -100,7 +100,7 @@ namespace gtsam { for (size_t j = 0; j < n; j++) { // Retrieve the factors involving this variable and create the current node - const VariableIndexUnordered::Factors& factors = structure[order[j]]; + const VariableIndex::Factors& factors = structure[order[j]]; nodes[j] = boost::make_shared(); nodes[j]->key = order[j]; @@ -157,20 +157,20 @@ namespace gtsam { /* ************************************************************************* */ template - EliminationTreeUnordered::EliminationTreeUnordered( - const FactorGraphType& factorGraph, const OrderingUnordered& order) + EliminationTree::EliminationTree( + const FactorGraphType& factorGraph, const Ordering& order) { gttic(ET_Create2); // Build variable index first - const VariableIndexUnordered variableIndex(factorGraph); + const VariableIndex variableIndex(factorGraph); This temp(factorGraph, variableIndex, order); this->swap(temp); // Swap in the tree, and temp will be deleted } /* ************************************************************************* */ template - EliminationTreeUnordered& - EliminationTreeUnordered::operator=(const EliminationTreeUnordered& other) + EliminationTree& + EliminationTree::operator=(const EliminationTree& other) { // Start by duplicating the tree. roots_ = treeTraversal::CloneForest(other); @@ -185,7 +185,7 @@ namespace gtsam { /* ************************************************************************* */ template std::pair, boost::shared_ptr > - EliminationTreeUnordered::eliminate(Eliminate function) const + EliminationTree::eliminate(Eliminate function) const { gttic(EliminationTree_eliminate); // Allocate result @@ -205,14 +205,14 @@ namespace gtsam { /* ************************************************************************* */ template - void EliminationTreeUnordered::print(const std::string& name, const KeyFormatter& formatter) const + void EliminationTree::print(const std::string& name, const KeyFormatter& formatter) const { treeTraversal::PrintForest(*this, name, formatter); } /* ************************************************************************* */ template - bool EliminationTreeUnordered::equals(const This& expected, double tol) const + bool EliminationTree::equals(const This& expected, double tol) const { // Depth-first-traversal stacks std::stack > stack1, stack2; @@ -281,7 +281,7 @@ namespace gtsam { /* ************************************************************************* */ template - void EliminationTreeUnordered::swap(This& other) { + void EliminationTree::swap(This& other) { roots_.swap(other.roots_); remainingFactors_.swap(other.remainingFactors_); } diff --git a/gtsam/inference/EliminationTree.h b/gtsam/inference/EliminationTree.h index 9be5f5b6a..fd19e0a65 100644 --- a/gtsam/inference/EliminationTree.h +++ b/gtsam/inference/EliminationTree.h @@ -1,187 +1,167 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file EliminationTree.h - * @author Frank Dellaert - * @date Oct 13, 2010 - */ -#pragma once - -#include - -#include -#include -#include -#include - -class EliminationTreeTester; // for unit tests, see testEliminationTree -namespace gtsam { template class BayesNet; } - -namespace gtsam { - -/** - * An elimination tree is a data structure used intermediately during - * elimination. In future versions it will be used to save work between - * multiple eliminations. - * - * When a variable is eliminated, a new factor is created by combining that - * variable's neighboring factors. The new combined factor involves the combined - * factors' involved variables. When the lowest-ordered one of those variables - * is eliminated, it consumes that combined factor. In the elimination tree, - * that lowest-ordered variable is the parent of the variable that was eliminated to - * produce the combined factor. This yields a tree in general, and not a chain - * because of the implicit sparse structure of the resulting Bayes net. - * - * This structure is examined even more closely in a JunctionTree, which - * additionally identifies cliques in the chordal Bayes net. - * \nosubgrouping - */ -template -class EliminationTree { - -public: - - typedef EliminationTree This; ///< This class - typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class - typedef typename boost::shared_ptr sharedFactor; ///< Shared pointer to a factor - typedef gtsam::BayesNet BayesNet; ///< The BayesNet corresponding to FACTOR - typedef FACTOR Factor; - typedef typename FACTOR::KeyType KeyType; - - /** Typedef for an eliminate subroutine */ - typedef typename FactorGraph::Eliminate Eliminate; - -private: - - /** concept check */ - GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR) - - typedef FastList Factors; - typedef FastList SubTrees; - typedef std::vector Conditionals; - - Index key_; ///< index associated with root // FIXME: doesn't this require that "Index" is the type of keys in the generic factor? - Factors factors_; ///< factors associated with root - SubTrees subTrees_; ///< sub-trees - -public: - - /// @name Standard Constructors - /// @{ - - /** - * Named constructor to build the elimination tree of a factor graph using - * pre-computed column structure. - * @param factorGraph The factor graph for which to build the elimination tree - * @param structure The set of factors involving each variable. If this is not - * precomputed, you can call the Create(const FactorGraph&) - * named constructor instead. - * @return The elimination tree - */ - template - static shared_ptr Create(const FactorGraph& factorGraph, const VariableIndex& structure); - - /** Named constructor to build the elimination tree of a factor graph. Note - * that this has to compute the column structure as a VariableIndex, so if you - * already have this precomputed, use the Create(const FactorGraph&, const VariableIndex&) - * named constructor instead. - * @param factorGraph The factor graph for which to build the elimination tree - */ - template - static shared_ptr Create(const FactorGraph& factorGraph); - - /// @} - /// @name Standard Interface - /// @{ - - /** Eliminate the factors to a Bayes Net - * @param function The function to use to eliminate, see the namespace functions - * in GaussianFactorGraph.h - * @return The BayesNet resulting from elimination - */ - typename BayesNet::shared_ptr eliminate(Eliminate function) const; - - /** Eliminate the factors to a Bayes Net and return the remaining factor - * @param function The function to use to eliminate, see the namespace functions - * in GaussianFactorGraph.h - * @return The BayesNet resulting from elimination and the remaining factor - */ - typename BayesNet::shared_ptr eliminatePartial(Eliminate function, size_t nrToEliminate) const; - - /// @} - /// @name Testable - /// @{ - - /** Print the tree to cout */ - void print(const std::string& name = "EliminationTree: ", - const IndexFormatter& formatter = DefaultIndexFormatter) const; - - /** Test whether the tree is equal to another */ - bool equals(const EliminationTree& other, double tol = 1e-9) const; - - /// @} - -private: - - /** default constructor, private, as you should use Create below */ - EliminationTree(Index key = 0) : key_(key) {} - - /** - * Static internal function to build a vector of parent pointers using the - * algorithm of Gilbert et al., 2001, BIT. - */ - static std::vector ComputeParents(const VariableIndex& structure); - - /** add a factor, for Create use only */ - void add(const sharedFactor& factor) { factors_.push_back(factor); } - - /** add a subtree, for Create use only */ - void add(const shared_ptr& child) { subTrees_.push_back(child); } - - /** - * Recursive routine that eliminates the factors arranged in an elimination tree - * @param Conditionals is a vector of shared pointers that will be modified in place - */ - sharedFactor eliminate_(Eliminate function, Conditionals& conditionals) const; - - /// Allow access to constructor and add methods for testing purposes - friend class ::EliminationTreeTester; - -}; - - -/** - * An exception thrown when attempting to eliminate a disconnected factor - * graph, which is not currently possible in gtsam. If you need to work with - * disconnected graphs, a workaround is to create zero-information factors to - * bridge the disconnects. To do this, create any factor type (e.g. - * BetweenFactor or RangeFactor) with the noise model - * sharedPrecision(dim, 0.0), where \c dim is the appropriate - * dimensionality for that factor. - */ -struct DisconnectedGraphException : public std::exception { - DisconnectedGraphException() {} - virtual ~DisconnectedGraphException() throw() {} - - /// Returns the string "Attempting to eliminate a disconnected graph - this is not currently possible in gtsam." - virtual const char* what() const throw() { - return - "Attempting to eliminate a disconnected graph - this is not currently possible in\n" - "GTSAM. You may add \"empty\" BetweenFactor's to join disconnected graphs, these\n" - "will affect the symbolic structure and solving complexity of the graph but not\n" - "the solution. To do this, create BetweenFactor's with zero-precision noise\n" - "models, i.e. noiseModel::Isotropic::Precision(n, 0.0);\n"; } -}; - -} - -#include +/* ---------------------------------------------------------------------------- + +* GTSAM Copyright 2010, Georgia Tech Research Corporation, +* Atlanta, Georgia 30332-0415 +* All Rights Reserved +* Authors: Frank Dellaert, et al. (see THANKS for the full author list) + +* See LICENSE for the license information + +* -------------------------------------------------------------------------- */ + +/** +* @file EliminationTree.h +* @author Frank Dellaert +* @author Richard Roberts +* @date Oct 13, 2010 +*/ +#pragma once + +#include +#include + +#include + +class EliminationTreeTester; // for unit tests, see testEliminationTree + +namespace gtsam { + + class VariableIndex; + class Ordering; + + /** + * An elimination tree is a data structure used intermediately during + * elimination. In future versions it will be used to save work between + * multiple eliminations. + * + * When a variable is eliminated, a new factor is created by combining that + * variable's neighboring factors. The new combined factor involves the combined + * factors' involved variables. When the lowest-ordered one of those variables + * is eliminated, it consumes that combined factor. In the elimination tree, + * that lowest-ordered variable is the parent of the variable that was eliminated to + * produce the combined factor. This yields a tree in general, and not a chain + * because of the implicit sparse structure of the resulting Bayes net. + * + * This structure is examined even more closely in a JunctionTree, which + * additionally identifies cliques in the chordal Bayes net. + * \nosubgrouping + */ + template + class EliminationTree + { + protected: + typedef EliminationTree This; ///< This class + typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class + + public: + typedef GRAPH FactorGraphType; ///< The factor graph type + typedef typename GRAPH::FactorType FactorType; ///< The type of factors + typedef typename boost::shared_ptr sharedFactor; ///< Shared pointer to a factor + typedef BAYESNET BayesNetType; ///< The BayesNet corresponding to FACTOR + typedef typename BayesNetType::ConditionalType ConditionalType; ///< The type of conditionals + typedef typename boost::shared_ptr sharedConditional; ///< Shared pointer to a conditional + typedef typename GRAPH::Eliminate Eliminate; + + struct Node { + typedef std::vector Factors; + typedef std::vector > Children; + + Key key; ///< key associated with root + Factors factors; ///< factors associated with root + Children children; ///< sub-trees + + sharedFactor eliminate(const boost::shared_ptr& output, + const Eliminate& function, const std::vector& childrenFactors) const; + + void print(const std::string& str, const KeyFormatter& keyFormatter) const; + }; + + typedef boost::shared_ptr sharedNode; ///< Shared pointer to Node + + protected: + /** concept check */ + GTSAM_CONCEPT_TESTABLE_TYPE(FactorType); + + std::vector roots_; + std::vector remainingFactors_; + + /// @name Standard Constructors + /// @{ + + /** + * Build the elimination tree of a factor graph using pre-computed column structure. + * @param factorGraph The factor graph for which to build the elimination tree + * @param structure The set of factors involving each variable. If this is not + * precomputed, you can call the Create(const FactorGraph&) + * named constructor instead. + * @return The elimination tree + */ + EliminationTree(const FactorGraphType& factorGraph, + const VariableIndex& structure, const Ordering& order); + + /** Build the elimination tree of a factor graph. Note that this has to compute the column + * structure as a VariableIndex, so if you already have this precomputed, use the other + * constructor instead. + * @param factorGraph The factor graph for which to build the elimination tree + */ + EliminationTree(const FactorGraphType& factorGraph, const Ordering& order); + + /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are + * copied, factors are not cloned. */ + EliminationTree(const This& other) { *this = other; } + + /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors + * are copied, factors are not cloned. */ + This& operator=(const This& other); + + /// @} + + public: + /// @name Standard Interface + /// @{ + + /** Eliminate the factors to a Bayes net and remaining factor graph + * @param function The function to use to eliminate, see the namespace functions + * in GaussianFactorGraph.h + * @return The Bayes net and factor graph resulting from elimination + */ + std::pair, boost::shared_ptr > + eliminate(Eliminate function) const; + + /// @} + /// @name Testable + /// @{ + + /** Print the tree to cout */ + void print(const std::string& name = "EliminationTree: ", + const KeyFormatter& formatter = DefaultKeyFormatter) const; + + protected: + /** Test whether the tree is equal to another */ + bool equals(const This& other, double tol = 1e-9) const; + + /// @} + + public: + /// @name Advanced Interface + /// @{ + + /** Return the set of roots (one for a tree, multiple for a forest) */ + const std::vector& roots() const { return roots_; } + + /** Return the remaining factors that are not pulled into elimination */ + const std::vector& remainingFactors() const { return remainingFactors_; } + + /** Swap the data of this tree with another one, this operation is very fast. */ + void swap(This& other); + + protected: + /// Protected default constructor + EliminationTree() {} + + private: + /// Allow access to constructor and add methods for testing purposes + friend class ::EliminationTreeTester; + }; + +} diff --git a/gtsam/inference/EliminationTree-inl.h b/gtsam/inference/EliminationTreeOrdered-inl.h similarity index 82% rename from gtsam/inference/EliminationTree-inl.h rename to gtsam/inference/EliminationTreeOrdered-inl.h index d85e2e651..cfa01246e 100644 --- a/gtsam/inference/EliminationTree-inl.h +++ b/gtsam/inference/EliminationTreeOrdered-inl.h @@ -18,10 +18,10 @@ #include #include -#include +#include #include -#include -#include +#include +#include #include #include @@ -34,7 +34,7 @@ namespace gtsam { /* ************************************************************************* */ template -typename EliminationTree::sharedFactor EliminationTree::eliminate_( +typename EliminationTreeOrdered::sharedFactor EliminationTreeOrdered::eliminate_( Eliminate function, Conditionals& conditionals) const { static const bool debug = false; @@ -43,7 +43,7 @@ typename EliminationTree::sharedFactor EliminationTree::eliminat if(this->key_ < conditionals.size()) { // If it is requested to eliminate the current variable // Create the list of factors to be eliminated, initially empty, and reserve space - FactorGraph factors; + FactorGraphOrdered factors; factors.reserve(this->factors_.size() + this->subTrees_.size()); // Add all factors associated with the current node @@ -55,7 +55,7 @@ typename EliminationTree::sharedFactor EliminationTree::eliminat // TODO: wait for completion of all threads // Combine all factors (from this node and from subtrees) into a joint factor - typename FactorGraph::EliminationResult + typename FactorGraphOrdered::EliminationResult eliminated(function(factors, 1)); conditionals[this->key_] = eliminated.first; @@ -75,7 +75,7 @@ typename EliminationTree::sharedFactor EliminationTree::eliminat /* ************************************************************************* */ template -std::vector EliminationTree::ComputeParents(const VariableIndex& structure) { +std::vector EliminationTreeOrdered::ComputeParents(const VariableIndexOrdered& structure) { // Number of factors and variables const size_t m = structure.nFactors(); @@ -109,9 +109,9 @@ std::vector EliminationTree::ComputeParents(const VariableIndex& /* ************************************************************************* */ template template -typename EliminationTree::shared_ptr EliminationTree::Create( - const FactorGraph& factorGraph, - const VariableIndex& structure) { +typename EliminationTreeOrdered::shared_ptr EliminationTreeOrdered::Create( + const FactorGraphOrdered& factorGraph, + const VariableIndexOrdered& structure) { static const bool debug = false; gttic(ET_Create1); @@ -131,7 +131,7 @@ typename EliminationTree::shared_ptr EliminationTree::Create( std::vector trees(n); for (Index k = 1; k <= n; k++) { Index j = n - k; // Start at the last variable and loop down to 0 - trees[j].reset(new EliminationTree(j)); // Create a new node on this variable + trees[j].reset(new EliminationTreeOrdered(j)); // Create a new node on this variable if (parents[j] != none) // If this node has a parent, add it to the parent's children trees[parents[j]]->add(trees[j]); else if(!structure[j].empty() && j != n - 1) // If a node other than the last has no parents, this is a forest @@ -161,12 +161,12 @@ typename EliminationTree::shared_ptr EliminationTree::Create( /* ************************************************************************* */ template template -typename EliminationTree::shared_ptr -EliminationTree::Create(const FactorGraph& factorGraph) { +typename EliminationTreeOrdered::shared_ptr +EliminationTreeOrdered::Create(const FactorGraphOrdered& factorGraph) { gttic(ET_Create2); // Build variable index - const VariableIndex variableIndex(factorGraph); + const VariableIndexOrdered variableIndex(factorGraph); // Build elimination tree return Create(factorGraph, variableIndex); @@ -174,7 +174,7 @@ EliminationTree::Create(const FactorGraph& factorGraph) { /* ************************************************************************* */ template -void EliminationTree::print(const std::string& name, +void EliminationTreeOrdered::print(const std::string& name, const IndexFormatter& formatter) const { std::cout << name << " (" << formatter(key_) << ")" << std::endl; BOOST_FOREACH(const sharedFactor& factor, factors_) { @@ -185,7 +185,7 @@ void EliminationTree::print(const std::string& name, /* ************************************************************************* */ template -bool EliminationTree::equals(const EliminationTree& expected, double tol) const { +bool EliminationTreeOrdered::equals(const EliminationTreeOrdered& expected, double tol) const { if(this->key_ == expected.key_ && this->factors_ == expected.factors_ && this->subTrees_.size() == expected.subTrees_.size()) { typename SubTrees::const_iterator this_subtree = this->subTrees_.begin(); @@ -200,8 +200,8 @@ bool EliminationTree::equals(const EliminationTree& ex /* ************************************************************************* */ template -typename EliminationTree::BayesNet::shared_ptr - EliminationTree::eliminatePartial(typename EliminationTree::Eliminate function, size_t nrToEliminate) const { +typename EliminationTreeOrdered::BayesNet::shared_ptr + EliminationTreeOrdered::eliminatePartial(typename EliminationTreeOrdered::Eliminate function, size_t nrToEliminate) const { // call recursive routine gttic(ET_recursive_eliminate); @@ -225,8 +225,8 @@ typename EliminationTree::BayesNet::shared_ptr /* ************************************************************************* */ template -typename EliminationTree::BayesNet::shared_ptr -EliminationTree::eliminate(Eliminate function) const { +typename EliminationTreeOrdered::BayesNet::shared_ptr +EliminationTreeOrdered::eliminate(Eliminate function) const { size_t nrConditionals = this->key_ + 1; // root key has highest index return eliminatePartial(function, nrConditionals); } diff --git a/gtsam/inference/EliminationTreeOrdered.h b/gtsam/inference/EliminationTreeOrdered.h new file mode 100644 index 000000000..c11b2bc16 --- /dev/null +++ b/gtsam/inference/EliminationTreeOrdered.h @@ -0,0 +1,187 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file EliminationTree.h + * @author Frank Dellaert + * @date Oct 13, 2010 + */ +#pragma once + +#include + +#include +#include +#include +#include + +class EliminationTreeOrderedTester; // for unit tests, see testEliminationTree +namespace gtsam { template class BayesNetOrdered; } + +namespace gtsam { + +/** + * An elimination tree is a data structure used intermediately during + * elimination. In future versions it will be used to save work between + * multiple eliminations. + * + * When a variable is eliminated, a new factor is created by combining that + * variable's neighboring factors. The new combined factor involves the combined + * factors' involved variables. When the lowest-ordered one of those variables + * is eliminated, it consumes that combined factor. In the elimination tree, + * that lowest-ordered variable is the parent of the variable that was eliminated to + * produce the combined factor. This yields a tree in general, and not a chain + * because of the implicit sparse structure of the resulting Bayes net. + * + * This structure is examined even more closely in a JunctionTree, which + * additionally identifies cliques in the chordal Bayes net. + * \nosubgrouping + */ +template +class EliminationTreeOrdered { + +public: + + typedef EliminationTreeOrdered This; ///< This class + typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class + typedef typename boost::shared_ptr sharedFactor; ///< Shared pointer to a factor + typedef gtsam::BayesNetOrdered BayesNet; ///< The BayesNet corresponding to FACTOR + typedef FACTOR Factor; + typedef typename FACTOR::KeyType KeyType; + + /** Typedef for an eliminate subroutine */ + typedef typename FactorGraphOrdered::Eliminate Eliminate; + +private: + + /** concept check */ + GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR) + + typedef FastList Factors; + typedef FastList SubTrees; + typedef std::vector Conditionals; + + Index key_; ///< index associated with root // FIXME: doesn't this require that "Index" is the type of keys in the generic factor? + Factors factors_; ///< factors associated with root + SubTrees subTrees_; ///< sub-trees + +public: + + /// @name Standard Constructors + /// @{ + + /** + * Named constructor to build the elimination tree of a factor graph using + * pre-computed column structure. + * @param factorGraph The factor graph for which to build the elimination tree + * @param structure The set of factors involving each variable. If this is not + * precomputed, you can call the Create(const FactorGraph&) + * named constructor instead. + * @return The elimination tree + */ + template + static shared_ptr Create(const FactorGraphOrdered& factorGraph, const VariableIndexOrdered& structure); + + /** Named constructor to build the elimination tree of a factor graph. Note + * that this has to compute the column structure as a VariableIndex, so if you + * already have this precomputed, use the Create(const FactorGraph&, const VariableIndex&) + * named constructor instead. + * @param factorGraph The factor graph for which to build the elimination tree + */ + template + static shared_ptr Create(const FactorGraphOrdered& factorGraph); + + /// @} + /// @name Standard Interface + /// @{ + + /** Eliminate the factors to a Bayes Net + * @param function The function to use to eliminate, see the namespace functions + * in GaussianFactorGraph.h + * @return The BayesNet resulting from elimination + */ + typename BayesNet::shared_ptr eliminate(Eliminate function) const; + + /** Eliminate the factors to a Bayes Net and return the remaining factor + * @param function The function to use to eliminate, see the namespace functions + * in GaussianFactorGraph.h + * @return The BayesNet resulting from elimination and the remaining factor + */ + typename BayesNet::shared_ptr eliminatePartial(Eliminate function, size_t nrToEliminate) const; + + /// @} + /// @name Testable + /// @{ + + /** Print the tree to cout */ + void print(const std::string& name = "EliminationTree: ", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /** Test whether the tree is equal to another */ + bool equals(const EliminationTreeOrdered& other, double tol = 1e-9) const; + + /// @} + +private: + + /** default constructor, private, as you should use Create below */ + EliminationTreeOrdered(Index key = 0) : key_(key) {} + + /** + * Static internal function to build a vector of parent pointers using the + * algorithm of Gilbert et al., 2001, BIT. + */ + static std::vector ComputeParents(const VariableIndexOrdered& structure); + + /** add a factor, for Create use only */ + void add(const sharedFactor& factor) { factors_.push_back(factor); } + + /** add a subtree, for Create use only */ + void add(const shared_ptr& child) { subTrees_.push_back(child); } + + /** + * Recursive routine that eliminates the factors arranged in an elimination tree + * @param Conditionals is a vector of shared pointers that will be modified in place + */ + sharedFactor eliminate_(Eliminate function, Conditionals& conditionals) const; + + /// Allow access to constructor and add methods for testing purposes + friend class ::EliminationTreeOrderedTester; + +}; + + +/** + * An exception thrown when attempting to eliminate a disconnected factor + * graph, which is not currently possible in gtsam. If you need to work with + * disconnected graphs, a workaround is to create zero-information factors to + * bridge the disconnects. To do this, create any factor type (e.g. + * BetweenFactor or RangeFactor) with the noise model + * sharedPrecision(dim, 0.0), where \c dim is the appropriate + * dimensionality for that factor. + */ +struct DisconnectedGraphException : public std::exception { + DisconnectedGraphException() {} + virtual ~DisconnectedGraphException() throw() {} + + /// Returns the string "Attempting to eliminate a disconnected graph - this is not currently possible in gtsam." + virtual const char* what() const throw() { + return + "Attempting to eliminate a disconnected graph - this is not currently possible in\n" + "GTSAM. You may add \"empty\" BetweenFactor's to join disconnected graphs, these\n" + "will affect the symbolic structure and solving complexity of the graph but not\n" + "the solution. To do this, create BetweenFactor's with zero-precision noise\n" + "models, i.e. noiseModel::Isotropic::Precision(n, 0.0);\n"; } +}; + +} + +#include diff --git a/gtsam/inference/EliminationTreeUnordered.h b/gtsam/inference/EliminationTreeUnordered.h deleted file mode 100644 index 38f160fa5..000000000 --- a/gtsam/inference/EliminationTreeUnordered.h +++ /dev/null @@ -1,167 +0,0 @@ -/* ---------------------------------------------------------------------------- - -* GTSAM Copyright 2010, Georgia Tech Research Corporation, -* Atlanta, Georgia 30332-0415 -* All Rights Reserved -* Authors: Frank Dellaert, et al. (see THANKS for the full author list) - -* See LICENSE for the license information - -* -------------------------------------------------------------------------- */ - -/** -* @file EliminationTree.h -* @author Frank Dellaert -* @author Richard Roberts -* @date Oct 13, 2010 -*/ -#pragma once - -#include -#include - -#include - -class EliminationTreeUnorderedTester; // for unit tests, see testEliminationTree - -namespace gtsam { - - class VariableIndexUnordered; - class OrderingUnordered; - - /** - * An elimination tree is a data structure used intermediately during - * elimination. In future versions it will be used to save work between - * multiple eliminations. - * - * When a variable is eliminated, a new factor is created by combining that - * variable's neighboring factors. The new combined factor involves the combined - * factors' involved variables. When the lowest-ordered one of those variables - * is eliminated, it consumes that combined factor. In the elimination tree, - * that lowest-ordered variable is the parent of the variable that was eliminated to - * produce the combined factor. This yields a tree in general, and not a chain - * because of the implicit sparse structure of the resulting Bayes net. - * - * This structure is examined even more closely in a JunctionTree, which - * additionally identifies cliques in the chordal Bayes net. - * \nosubgrouping - */ - template - class EliminationTreeUnordered - { - protected: - typedef EliminationTreeUnordered This; ///< This class - typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class - - public: - typedef GRAPH FactorGraphType; ///< The factor graph type - typedef typename GRAPH::FactorType FactorType; ///< The type of factors - typedef typename boost::shared_ptr sharedFactor; ///< Shared pointer to a factor - typedef BAYESNET BayesNetType; ///< The BayesNet corresponding to FACTOR - typedef typename BayesNetType::ConditionalType ConditionalType; ///< The type of conditionals - typedef typename boost::shared_ptr sharedConditional; ///< Shared pointer to a conditional - typedef typename GRAPH::Eliminate Eliminate; - - struct Node { - typedef std::vector Factors; - typedef std::vector > Children; - - Key key; ///< key associated with root - Factors factors; ///< factors associated with root - Children children; ///< sub-trees - - sharedFactor eliminate(const boost::shared_ptr& output, - const Eliminate& function, const std::vector& childrenFactors) const; - - void print(const std::string& str, const KeyFormatter& keyFormatter) const; - }; - - typedef boost::shared_ptr sharedNode; ///< Shared pointer to Node - - protected: - /** concept check */ - GTSAM_CONCEPT_TESTABLE_TYPE(FactorType); - - std::vector roots_; - std::vector remainingFactors_; - - /// @name Standard Constructors - /// @{ - - /** - * Build the elimination tree of a factor graph using pre-computed column structure. - * @param factorGraph The factor graph for which to build the elimination tree - * @param structure The set of factors involving each variable. If this is not - * precomputed, you can call the Create(const FactorGraph&) - * named constructor instead. - * @return The elimination tree - */ - EliminationTreeUnordered(const FactorGraphType& factorGraph, - const VariableIndexUnordered& structure, const OrderingUnordered& order); - - /** Build the elimination tree of a factor graph. Note that this has to compute the column - * structure as a VariableIndex, so if you already have this precomputed, use the other - * constructor instead. - * @param factorGraph The factor graph for which to build the elimination tree - */ - EliminationTreeUnordered(const FactorGraphType& factorGraph, const OrderingUnordered& order); - - /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are - * copied, factors are not cloned. */ - EliminationTreeUnordered(const This& other) { *this = other; } - - /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors - * are copied, factors are not cloned. */ - This& operator=(const This& other); - - /// @} - - public: - /// @name Standard Interface - /// @{ - - /** Eliminate the factors to a Bayes net and remaining factor graph - * @param function The function to use to eliminate, see the namespace functions - * in GaussianFactorGraph.h - * @return The Bayes net and factor graph resulting from elimination - */ - std::pair, boost::shared_ptr > - eliminate(Eliminate function) const; - - /// @} - /// @name Testable - /// @{ - - /** Print the tree to cout */ - void print(const std::string& name = "EliminationTree: ", - const KeyFormatter& formatter = DefaultKeyFormatter) const; - - protected: - /** Test whether the tree is equal to another */ - bool equals(const This& other, double tol = 1e-9) const; - - /// @} - - public: - /// @name Advanced Interface - /// @{ - - /** Return the set of roots (one for a tree, multiple for a forest) */ - const std::vector& roots() const { return roots_; } - - /** Return the remaining factors that are not pulled into elimination */ - const std::vector& remainingFactors() const { return remainingFactors_; } - - /** Swap the data of this tree with another one, this operation is very fast. */ - void swap(This& other); - - protected: - /// Protected default constructor - EliminationTreeUnordered() {} - - private: - /// Allow access to constructor and add methods for testing purposes - friend class ::EliminationTreeUnorderedTester; - }; - -} diff --git a/gtsam/inference/FactorUnordered.cpp b/gtsam/inference/Factor.cpp similarity index 78% rename from gtsam/inference/FactorUnordered.cpp rename to gtsam/inference/Factor.cpp index 28b6594d1..707193a52 100644 --- a/gtsam/inference/FactorUnordered.cpp +++ b/gtsam/inference/Factor.cpp @@ -22,25 +22,25 @@ #include #include -#include +#include namespace gtsam { /* ************************************************************************* */ - void FactorUnordered::print(const std::string& s, const KeyFormatter& formatter) const + void Factor::print(const std::string& s, const KeyFormatter& formatter) const { return this->printKeys(s, formatter); } /* ************************************************************************* */ - void FactorUnordered::printKeys(const std::string& s, const KeyFormatter& formatter) const { + void Factor::printKeys(const std::string& s, const KeyFormatter& formatter) const { std::cout << s << " "; BOOST_FOREACH(Key key, keys_) std::cout << " " << formatter(key); std::cout << std::endl; } /* ************************************************************************* */ - bool FactorUnordered::equals(const This& other, double tol) const { + bool Factor::equals(const This& other, double tol) const { return keys_ == other.keys_; } diff --git a/gtsam/inference/Factor.h b/gtsam/inference/Factor.h index b8ff34788..c407c6507 100644 --- a/gtsam/inference/Factor.h +++ b/gtsam/inference/Factor.h @@ -21,212 +21,151 @@ #pragma once -#include #include #include -#include -#include -#include -#include -#include + +#include +#include namespace gtsam { -template class Conditional; - -/** - * This is the base class for all factor types. It is templated on a KEY type, - * which will be the type used to label variables. Key types currently in use - * in gtsam are Index with symbolic (IndexFactor, SymbolicFactorGraph) and - * Gaussian factors (GaussianFactor, JacobianFactor, HessianFactor, GaussianFactorGraph), - * and Key with nonlinear factors (NonlinearFactor, NonlinearFactorGraph). - * though currently only IndexFactor and IndexConditional derive from this - * class, using Index keys. This class does not store any data other than its - * keys. Derived classes store data such as matrices and probability tables. - * - * Note that derived classes *must* redefine the ConditionalType and shared_ptr - * typedefs to refer to the associated conditional and shared_ptr types of the - * derived class. See IndexFactor, JacobianFactor, etc. for examples. - * - * This class is \b not virtual for performance reasons - derived symbolic classes, - * IndexFactor and IndexConditional, need to be created and destroyed quickly - * during symbolic elimination. GaussianFactor and NonlinearFactor are virtual. - * \nosubgrouping - */ -template -class Factor { - -public: - - typedef KEY KeyType; ///< The KEY template parameter - typedef Factor This; ///< This class - /** - * Typedef to the conditional type obtained by eliminating this factor, - * derived classes must redefine this. + * This is the base class for all factor types. It is templated on a KEY type, + * which will be the type used to label variables. Key types currently in use + * in gtsam are Index with symbolic (IndexFactor, SymbolicFactorGraph) and + * Gaussian factors (GaussianFactor, JacobianFactor, HessianFactor, GaussianFactorGraph), + * and Key with nonlinear factors (NonlinearFactor, NonlinearFactorGraph). + * though currently only IndexFactor and IndexConditional derive from this + * class, using Index keys. This class does not store any data other than its + * keys. Derived classes store data such as matrices and probability tables. + * + * Note that derived classes *must* redefine the ConditionalType and shared_ptr + * typedefs to refer to the associated conditional and shared_ptr types of the + * derived class. See IndexFactor, JacobianFactor, etc. for examples. + * + * This class is \b not virtual for performance reasons - derived symbolic classes, + * IndexFactor and IndexConditional, need to be created and destroyed quickly + * during symbolic elimination. GaussianFactor and NonlinearFactor are virtual. + * \nosubgrouping */ - typedef Conditional ConditionalType; + class GTSAM_EXPORT Factor + { - /// A shared_ptr to this class, derived classes must redefine this. - typedef boost::shared_ptr shared_ptr; + private: + // These typedefs are private because they must be overridden in derived classes. + typedef Factor This; ///< This class + typedef boost::shared_ptr shared_ptr; ///< A shared_ptr to this class. - /// Iterator over keys - typedef typename std::vector::iterator iterator; + public: + /// Iterator over keys + typedef std::vector::iterator iterator; - /// Const iterator over keys - typedef typename std::vector::const_iterator const_iterator; + /// Const iterator over keys + typedef std::vector::const_iterator const_iterator; -protected: + protected: - /// The keys involved in this factor - std::vector keys_; + /// The keys involved in this factor + std::vector keys_; -public: + /// @name Standard Constructors + /// @{ - /// @name Standard Constructors - /// @{ + /** Default constructor for I/O */ + Factor() {} - /** Copy constructor */ - Factor(const This& f); + /** Construct factor from container of keys. This constructor is used internally from derived factor + * constructors, either from a container of keys or from a boost::assign::list_of. */ + template + Factor(const CONTAINER& keys) : keys_(keys.begin(), keys.end()) {} - /** Construct from conditional, calls ConditionalType::toFactor() */ - Factor(const ConditionalType& c); + /** Construct factor from iterator keys. This constructor may be used internally from derived + * factor constructors, although our code currently does not use this. */ + template + Factor(ITERATOR first, ITERATOR last) : keys_(first, last) {} - /** Default constructor for I/O */ - Factor() {} + /** Construct factor from container of keys. This is called internally from derived factor static + * factor methods, as a workaround for not being able to call the protected constructors above. */ + template + static Factor FromKeys(const CONTAINER& keys) { + return Factor(keys.begin(), keys.end()); } - /** Construct unary factor */ - Factor(KeyType key) : keys_(1) { - keys_[0] = key; assertInvariants(); } + /** Construct factor from iterator keys. This is called internally from derived factor static + * factor methods, as a workaround for not being able to call the protected constructors above. */ + template + static Factor FromIterators(ITERATOR first, ITERATOR last) { + return Factor(first, last); } - /** Construct binary factor */ - Factor(KeyType key1, KeyType key2) : keys_(2) { - keys_[0] = key1; keys_[1] = key2; assertInvariants(); } + /// @} - /** Construct ternary factor */ - Factor(KeyType key1, KeyType key2, KeyType key3) : keys_(3) { - keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; assertInvariants(); } + public: + /// @name Standard Interface + /// @{ - /** Construct 4-way factor */ - Factor(KeyType key1, KeyType key2, KeyType key3, KeyType key4) : keys_(4) { - keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; assertInvariants(); } + /// First key + Key front() const { return keys_.front(); } - /** Construct 5-way factor */ - Factor(KeyType key1, KeyType key2, KeyType key3, KeyType key4, KeyType key5) : keys_(5) { - keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; keys_[4] = key5; assertInvariants(); } + /// Last key + Key back() const { return keys_.back(); } - /** Construct 6-way factor */ - Factor(KeyType key1, KeyType key2, KeyType key3, KeyType key4, KeyType key5, KeyType key6) : keys_(6) { - keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; keys_[4] = key5; keys_[5] = key6; assertInvariants(); } + /// find + const_iterator find(Key key) const { return std::find(begin(), end(), key); } - /// @} - /// @name Advanced Constructors - /// @{ + /// Access the factor's involved variable keys + const std::vector& keys() const { return keys_; } - /** Construct n-way factor */ - Factor(const std::set& keys) { - BOOST_FOREACH(const KeyType& key, keys) keys_.push_back(key); - assertInvariants(); - } + /** Iterator at beginning of involved variable keys */ + const_iterator begin() const { return keys_.begin(); } - /** Construct n-way factor */ - Factor(const std::vector& keys) : keys_(keys) { - assertInvariants(); - } + /** Iterator at end of involved variable keys */ + const_iterator end() const { return keys_.end(); } - /** Constructor from a collection of keys */ - template Factor(KEYITERATOR beginKey, KEYITERATOR endKey) : - keys_(beginKey, endKey) { assertInvariants(); } + /** + * @return the number of variables involved in this factor + */ + size_t size() const { return keys_.size(); } - /// @} + /// @} -#ifdef TRACK_ELIMINATE - /** - * eliminate the first variable involved in this factor - * @return a conditional on the eliminated variable - */ - template - typename CONDITIONAL::shared_ptr eliminateFirst(); - /** - * eliminate the first nrFrontals frontal variables. - */ - template - typename BayesNet::shared_ptr eliminate(size_t nrFrontals = 1); -#endif + /// @name Testable + /// @{ - /// @name Standard Interface - /// @{ + /// print + void print(const std::string& s = "Factor", const KeyFormatter& formatter = DefaultKeyFormatter) const; - /// First key - KeyType front() const { return keys_.front(); } + /// print only keys + void printKeys(const std::string& s = "Factor", const KeyFormatter& formatter = DefaultKeyFormatter) const; - /// Last key - KeyType back() const { return keys_.back(); } + protected: + /// check equality + bool equals(const This& other, double tol = 1e-9) const; - /// find - const_iterator find(KeyType key) const { return std::find(begin(), end(), key); } + /// @} - /// Access the factor's involved variable keys - const std::vector& keys() const { return keys_; } + public: + /// @name Advanced Interface + /// @{ - /** iterators */ - const_iterator begin() const { return keys_.begin(); } ///TODO: comment - const_iterator end() const { return keys_.end(); } ///TODO: comment + /** @return keys involved in this factor */ + std::vector& keys() { return keys_; } - /** - * @return the number of variables involved in this factor - */ - size_t size() const { return keys_.size(); } + /** Iterator at beginning of involved variable keys */ + iterator begin() { return keys_.begin(); } - /// @} - /// @name Testable - /// @{ + /** Iterator at end of involved variable keys */ + iterator end() { return keys_.end(); } - /// print - void print(const std::string& s = "Factor", - const IndexFormatter& formatter = DefaultIndexFormatter) const; + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(keys_); + } - /// print only keys - void printKeys(const std::string& s = "Factor", - const IndexFormatter& formatter = DefaultIndexFormatter) const; + /// @} - /// check equality - bool equals(const This& other, double tol = 1e-9) const; - - /// @} - /// @name Advanced Interface - /// @{ - - /** - * @return keys involved in this factor - */ - std::vector& keys() { return keys_; } - - /** mutable iterators */ - iterator begin() { return keys_.begin(); } ///TODO: comment - iterator end() { return keys_.end(); } ///TODO: comment - -protected: - friend class JacobianFactor; - friend class HessianFactor; - - /// Internal consistency check that is run frequently when in debug mode. - /// If NDEBUG is defined, this is empty and optimized out. - void assertInvariants() const; - -private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(keys_); - } - - /// @} - -}; + }; } - -#include diff --git a/gtsam/inference/FactorGraphUnordered-inst.h b/gtsam/inference/FactorGraph-inst.h similarity index 84% rename from gtsam/inference/FactorGraphUnordered-inst.h rename to gtsam/inference/FactorGraph-inst.h index b31b80a8f..8fb5b5c2f 100644 --- a/gtsam/inference/FactorGraphUnordered-inst.h +++ b/gtsam/inference/FactorGraph-inst.h @@ -23,9 +23,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -37,7 +37,7 @@ namespace gtsam { /* ************************************************************************* */ template - void FactorGraphUnordered::print(const std::string& s, const KeyFormatter& formatter) const { + void FactorGraph::print(const std::string& s, const KeyFormatter& formatter) const { std::cout << s << std::endl; std::cout << "size: " << size() << std::endl; for (size_t i = 0; i < factors_.size(); i++) { @@ -50,7 +50,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool FactorGraphUnordered::equals(const This& fg, double tol) const { + bool FactorGraph::equals(const This& fg, double tol) const { /** check whether the two factor graphs have the same number of factors_ */ if (factors_.size() != fg.size()) return false; @@ -67,7 +67,7 @@ namespace gtsam { /* ************************************************************************* */ template - size_t FactorGraphUnordered::nrFactors() const { + size_t FactorGraph::nrFactors() const { size_t size_ = 0; BOOST_FOREACH(const sharedFactor& factor, factors_) if (factor) size_++; @@ -76,7 +76,7 @@ namespace gtsam { /* ************************************************************************* */ template - FastSet FactorGraphUnordered::keys() const { + FastSet FactorGraph::keys() const { FastSet allKeys; BOOST_FOREACH(const sharedFactor& factor, factors_) if (factor) diff --git a/gtsam/inference/FactorGraph.h b/gtsam/inference/FactorGraph.h index 0d3b10e31..cfc44bc78 100644 --- a/gtsam/inference/FactorGraph.h +++ b/gtsam/inference/FactorGraph.h @@ -15,25 +15,59 @@ * @author Carlos Nieto * @author Christian Potthast * @author Michael Kaess + * @author Richard Roberts */ // \callgraph #pragma once -#include -#include -#include - #include -#include -#include +#include +#include +#include +#include + +#include +#include namespace gtsam { -// Forward declarations -template class BayesTree; -class VariableIndex; + // Forward declarations + template class BayesTree; + + /** Helper */ + template + class CRefCallPushBack + { + C& obj; + public: + CRefCallPushBack(C& obj) : obj(obj) {} + template + void operator()(const A& a) { obj.push_back(a); } + }; + + /** Helper */ + template + class RefCallPushBack + { + C& obj; + public: + RefCallPushBack(C& obj) : obj(obj) {} + template + void operator()(A& a) { obj.push_back(a); } + }; + + /** Helper */ + template + class CRefCallAddCopy + { + C& obj; + public: + CRefCallAddCopy(C& obj) : obj(obj) {} + template + void operator()(const A& a) { obj.addCopy(a); } + }; /** * A factor graph is a bipartite graph with factor nodes connected to variable nodes. @@ -44,62 +78,64 @@ class VariableIndex; class FactorGraph { public: - typedef FACTOR FactorType; ///< factor type - typedef typename FACTOR::KeyType KeyType; ///< type of Keys we use to index variables with typedef boost::shared_ptr sharedFactor; ///< Shared pointer to a factor - typedef boost::shared_ptr sharedConditional; ///< Shared pointer to a conditional - - typedef FactorGraph This; ///< Typedef for this class - typedef boost::shared_ptr shared_ptr; ///< Shared pointer for this class + typedef sharedFactor value_type; typedef typename std::vector::iterator iterator; typedef typename std::vector::const_iterator const_iterator; - /** typedef for elimination result */ - typedef std::pair EliminationResult; - - /** typedef for an eliminate subroutine */ - typedef boost::function Eliminate; + private: + typedef FactorGraph This; ///< Typedef for this class + typedef boost::shared_ptr shared_ptr; ///< Shared pointer for this class protected: - /** concept check, makes sure FACTOR defines print and equals */ GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR) /** Collection of factors */ std::vector factors_; - public: - - /// @name Standard Constructor + /// @name Standard Constructors /// @{ /** Default constructor */ FactorGraph() {} + /** Constructor from iterator over factors (shared_ptr or plain objects) */ + template + FactorGraph(ITERATOR firstFactor, ITERATOR lastFactor) { push_back(firstFactor, lastFactor); } + + /** Construct from container of factors (shared_ptr or plain objects) */ + template + explicit FactorGraph(const CONTAINER& factors) { push_back(factors); } + /// @} /// @name Advanced Constructors /// @{ + + // TODO: are these needed? - /** - * @brief Constructor from a Bayes net - * @param bayesNet the Bayes net to convert, type CONDITIONAL must yield compatible factor - * @return a factor graph with all the conditionals, as factors - */ - template - FactorGraph(const BayesNet& bayesNet); + ///** + // * @brief Constructor from a Bayes net + // * @param bayesNet the Bayes net to convert, type CONDITIONAL must yield compatible factor + // * @return a factor graph with all the conditionals, as factors + // */ + //template + //FactorGraph(const BayesNet& bayesNet); - /** convert from Bayes tree */ - template - FactorGraph(const BayesTree& bayesTree); + ///** convert from Bayes tree */ + //template + //FactorGraph(const BayesTree& bayesTree); - /** convert from a derived type */ - template - FactorGraph(const FactorGraph& factors) { - factors_.assign(factors.begin(), factors.end()); - } + ///** convert from a derived type */ + //template + //FactorGraph(const FactorGraph& factors) { + // factors_.assign(factors.begin(), factors.end()); + //} /// @} + + public: /// @name Adding Factors /// @{ @@ -109,69 +145,159 @@ class VariableIndex; */ void reserve(size_t size) { factors_.reserve(size); } - /** Add a factor */ + // TODO: are these needed? + + /** Add a factor directly using a shared_ptr */ template - void push_back(const boost::shared_ptr& factor) { - factors_.push_back(boost::shared_ptr(factor)); - } + typename std::enable_if::value>::type + push_back(boost::shared_ptr& factor) { + factors_.push_back(boost::shared_ptr(factor)); } - /** push back many factors */ - void push_back(const This& factors) { - factors_.insert(end(), factors.begin(), factors.end()); - } + /** Add a factor directly using a shared_ptr */ + void push_back(const sharedFactor& factor) { + factors_.push_back(factor); } - /** push back many factors with an iterator */ + /** push back many factors with an iterator over shared_ptr (factors are not copied) */ template - void push_back(ITERATOR firstFactor, ITERATOR lastFactor) { - factors_.insert(end(), firstFactor, lastFactor); + typename std::enable_if::value>::type + push_back(ITERATOR firstFactor, ITERATOR lastFactor) { + factors_.insert(end(), firstFactor, lastFactor); } + + /** push back many factors as shared_ptr's in a container (factors are not copied) */ + template + typename std::enable_if::value>::type + push_back(const CONTAINER& container) { + push_back(container.begin(), container.end()); } - /** - * @brief Add a vector of derived factors - * @param factors to add - */ - template - void push_back(const std::vector >& factors) { - factors_.insert(end(), factors.begin(), factors.end()); + /** push back a BayesTree as a collection of factors. NOTE: This should be hidden in derived + * classes in favor of a type-specialized version that calls this templated function. */ + template + typename std::enable_if::value>::type + push_back(const BayesTree& bayesTree) { + bayesTree.addFactorsToGraph(*this); } + /** += syntax for push_back, e.g. graph += f1, f2, f3 */ + //template + //boost::assign::list_inserter > + // operator+=(const T& factorOrContainer) + //{ + // return boost::assign::make_list_inserter( + // boost::bind(&This::push_back, this, _1)); + //} + + /** Add a factor directly using a shared_ptr */ + template + typename std::enable_if::value, + boost::assign::list_inserter > >::type + operator+=(boost::shared_ptr& factor) { + return boost::assign::make_list_inserter(RefCallPushBack(*this))(factor); + } + + template + boost::assign::list_inserter > + operator+=(const FACTOR_OR_CONTAINER& factorOrContainer) { + return boost::assign::make_list_inserter(CRefCallPushBack(*this))(factorOrContainer); + } + + ///** Add a factor directly using a shared_ptr */ + //boost::assign::list_inserter > + // operator+=(const sharedFactor& factor) { + // return boost::assign::make_list_inserter(CRefCallPushBack(*this)); + //} + + ///** push back many factors as shared_ptr's in a container (factors are not copied) */ + //template + //typename std::enable_if::value, + // boost::assign::list_inserter > >::type + // operator+=(const CONTAINER& container) { + // return boost::assign::make_list_inserter(CRefCallPushBack(*this)); + //} + + ///** push back a BayesTree as a collection of factors. NOTE: This should be hidden in derived + // * classes in favor of a type-specialized version that calls this templated function. */ + //template + //boost::assign::list_inserter > + // operator+=(const BayesTree& bayesTree) { + // return boost::assign::make_list_inserter(CRefCallPushBack(*this)); + //} + + /** Add a factor by value, will be copy-constructed (use push_back with a shared_ptr to avoid + * the copy). */ + template + typename std::enable_if::value>::type + push_back(const DERIVEDFACTOR& factor) { + factors_.push_back(boost::make_shared(factor)); } + + /** push back many factors with an iterator over plain factors (factors are copied) */ + template + typename std::enable_if::value>::type + push_back(ITERATOR firstFactor, ITERATOR lastFactor) { + for(ITERATOR f = firstFactor; f != lastFactor; ++f) + push_back(*f); + } + + /** push back many factors as non-pointer objects in a container (factors are copied) */ + template + typename std::enable_if::value>::type + push_back(const CONTAINER& container) { + push_back(container.begin(), container.end()); + } + + //template + //boost::assign::list_inserter > + // operator*=(const FACTOR_OR_CONTAINER& factorOrContainer) { + // return boost::assign::make_list_inserter(CRefCallAddCopy(*this)); + //} + /// @} /// @name Testable /// @{ /** print out graph */ void print(const std::string& s = "FactorGraph", - const IndexFormatter& formatter = DefaultIndexFormatter) const; + const KeyFormatter& formatter = DefaultKeyFormatter) const; + protected: /** Check equality */ bool equals(const This& fg, double tol = 1e-9) const; - /// @} + + public: /// @name Standard Interface /// @{ - /** return the number of factors and NULLS */ - size_t size() const { return factors_.size();} + /** return the number of factors (including any null factors set by remove() ). */ + size_t size() const { return factors_.size(); } - /** Simple check for an empty graph - faster than comparing size() to zero */ + /** Check if the graph is empty (null factors set by remove() will cause this to return false). */ bool empty() const { return factors_.empty(); } - /** const cast to the underlying vector of factors */ - operator const std::vector&() const { return factors_; } + /** Get a specific factor by index (this checks array bounds and may throw an exception, as + * opposed to operator[] which does not). + */ + const sharedFactor at(size_t i) const { return factors_.at(i); } - /** Get a specific factor by index */ - const sharedFactor at(size_t i) const { assert(i > eliminateFrontals(size_t nFrontals, const Eliminate& eliminate) const; - - /** Factor the factor graph into a conditional and a remaining factor graph. - * Given the factor graph \f$ f(X) \f$, and \c variables to factorize out - * \f$ V \f$, this function factorizes into \f$ f(X) = f(V;Y)f(Y) \f$, where - * \f$ Y := X\V \f$ are the remaining variables. If \f$ f(X) = p(X) \f$ is - * a probability density or likelihood, the factorization produces a - * conditional probability density and a marginal \f$ p(X) = p(V|Y)p(Y) \f$. - * - * For efficiency, this function treats the variables to eliminate - * \c variables as fully-connected, so produces a dense (fully-connected) - * conditional on all of the variables in \c variables, instead of a sparse - * BayesNet. If the variables are not fully-connected, it is more efficient - * to sequentially factorize multiple times. - */ - std::pair > eliminate( - const std::vector& variables, const Eliminate& eliminateFcn, - boost::optional variableIndex = boost::none) const; - - /** Eliminate a single variable, by calling FactorGraph::eliminate. */ - std::pair > eliminateOne( - KeyType variable, const Eliminate& eliminateFcn, - boost::optional variableIndex = boost::none) const { - std::vector variables(1, variable); - return eliminate(variables, eliminateFcn, variableIndex); - } - /// @} /// @name Modifying Factor Graphs (imperative, discouraged) /// @{ @@ -222,24 +316,33 @@ class VariableIndex; /** non-const STL-style end() */ iterator end() { return factors_.end(); } - /** resize the factor graph. TODO: effects? */ + /** Directly resize the number of factors in the graph. If the new size is less than the + * original, factors at the end will be removed. If the new size is larger than the original, + * null factors will be appended. + */ void resize(size_t size) { factors_.resize(size); } /** delete factor without re-arranging indexes by inserting a NULL pointer */ - inline void remove(size_t i) { factors_[i].reset();} + void remove(size_t i) { factors_[i].reset();} /** replace a factor by index */ - void replace(size_t index, sharedFactor factor); + void replace(size_t index, sharedFactor factor) { at(index) = factor; } + + /** Erase factor and rearrange other factors to take up the empty space */ + void erase(const_iterator item) { factors_.erase(item); } + + /** Erase factors and rearrange other factors to take up the empty space */ + void erase(const_iterator first, const_iterator last) { factors_.erase(first, last); } /// @} /// @name Advanced Interface /// @{ - /** return the number valid factors */ + /** return the number of non-null factors */ size_t nrFactors() const; /** Potentially very slow function to return all keys involved */ - std::set keys() const; + FastSet keys() const; private: @@ -254,20 +357,4 @@ class VariableIndex; }; // FactorGraph - /** Create a combined joint factor (new style for EliminationTree). */ - template - typename DERIVEDFACTOR::shared_ptr Combine(const FactorGraph& factors, - const FastMap >& variableSlots); - - /** - * static function that combines two factor graphs - * @param fg1 Linear factor graph - * @param fg2 Linear factor graph - * @return a new combined factor graph - */ - template - FACTORGRAPH combine(const FACTORGRAPH& fg1, const FACTORGRAPH& fg2); - } // namespace gtsam - -#include diff --git a/gtsam/inference/FactorGraph-inl.h b/gtsam/inference/FactorGraphOrdered-inl.h similarity index 84% rename from gtsam/inference/FactorGraph-inl.h rename to gtsam/inference/FactorGraphOrdered-inl.h index 60fc2e767..b2e92e5d0 100644 --- a/gtsam/inference/FactorGraph-inl.h +++ b/gtsam/inference/FactorGraphOrdered-inl.h @@ -23,8 +23,8 @@ #pragma once #include -#include -#include +#include +#include #include #include @@ -41,7 +41,7 @@ namespace gtsam { /* ************************************************************************* */ template template - FactorGraph::FactorGraph(const BayesNet& bayesNet) { + FactorGraphOrdered::FactorGraphOrdered(const BayesNetOrdered& bayesNet) { factors_.reserve(bayesNet.size()); BOOST_FOREACH(const typename CONDITIONAL::shared_ptr& cond, bayesNet) { this->push_back(cond->toFactor()); @@ -50,7 +50,7 @@ namespace gtsam { /* ************************************************************************* */ template - void FactorGraph::print(const std::string& s, + void FactorGraphOrdered::print(const std::string& s, const IndexFormatter& formatter) const { std::cout << s << std::endl; std::cout << "size: " << size() << std::endl; @@ -63,7 +63,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool FactorGraph::equals(const This& fg, double tol) const { + bool FactorGraphOrdered::equals(const This& fg, double tol) const { /** check whether the two factor graphs have the same number of factors_ */ if (factors_.size() != fg.size()) return false; @@ -80,7 +80,7 @@ namespace gtsam { /* ************************************************************************* */ template - size_t FactorGraph::nrFactors() const { + size_t FactorGraphOrdered::nrFactors() const { size_t size_ = 0; BOOST_FOREACH(const sharedFactor& factor, factors_) if (factor) size_++; @@ -89,7 +89,7 @@ namespace gtsam { /* ************************************************************************* */ template - std::set FactorGraph::keys() const { + std::set FactorGraphOrdered::keys() const { std::set allKeys; BOOST_FOREACH(const sharedFactor& factor, factors_) if (factor) { @@ -101,11 +101,11 @@ namespace gtsam { /* ************************************************************************* */ template - std::pair::sharedConditional, FactorGraph > - FactorGraph::eliminateFrontals(size_t nFrontals, const Eliminate& eliminate) const + std::pair::sharedConditional, FactorGraphOrdered > + FactorGraphOrdered::eliminateFrontals(size_t nFrontals, const Eliminate& eliminate) const { // Build variable index - VariableIndex variableIndex(*this); + VariableIndexOrdered variableIndex(*this); // Find first variable Index firstIndex = 0; @@ -125,8 +125,8 @@ namespace gtsam { } // Separate factors into involved and remaining - FactorGraph involvedFactors; - FactorGraph remainingFactors; + FactorGraphOrdered involvedFactors; + FactorGraphOrdered remainingFactors; FastSet::const_iterator involvedFactorIsIt = involvedFactorIs.begin(); for(size_t i = 0; i < this->size(); ++i) { if(involvedFactorIsIt != involvedFactorIs.end() && *involvedFactorIsIt == i) { @@ -140,7 +140,7 @@ namespace gtsam { } // Do dense elimination on the involved factors - typename FactorGraph::EliminationResult eliminationResult = + typename FactorGraphOrdered::EliminationResult eliminationResult = eliminate(involvedFactors, nFrontals); // Add the remaining factor back into the factor graph @@ -152,15 +152,15 @@ namespace gtsam { /* ************************************************************************* */ template - std::pair::sharedConditional, FactorGraph > - FactorGraph::eliminate(const std::vector& variables, const Eliminate& eliminateFcn, - boost::optional variableIndex_) const + std::pair::sharedConditional, FactorGraphOrdered > + FactorGraphOrdered::eliminate(const std::vector& variables, const Eliminate& eliminateFcn, + boost::optional variableIndex_) const { - const VariableIndex& variableIndex = - variableIndex_ ? *variableIndex_ : VariableIndex(*this); + const VariableIndexOrdered& variableIndex = + variableIndex_ ? *variableIndex_ : VariableIndexOrdered(*this); // First find the involved factors - FactorGraph involvedFactors; + FactorGraphOrdered involvedFactors; Index highestInvolvedVariable = 0; // Largest index of the variables in the involved factors // First get the indices of the involved factors, but uniquely in a set @@ -205,7 +205,7 @@ namespace gtsam { } // Build the remaining graph, without the removed factors - FactorGraph remainingGraph; + FactorGraphOrdered remainingGraph; remainingGraph.reserve(this->size() - involvedFactors.size() + 1); FastSet::const_iterator involvedFactorIndexIt = involvedFactorIndices.begin(); for(size_t i = 0; i < this->size(); ++i) { @@ -224,7 +224,7 @@ namespace gtsam { } /* ************************************************************************* */ template - void FactorGraph::replace(size_t index, sharedFactor factor) { + void FactorGraphOrdered::replace(size_t index, sharedFactor factor) { if (index >= factors_.size()) throw std::invalid_argument(boost::str( boost::format("Factor graph does not contain a factor with index %d.") % index)); @@ -246,7 +246,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename DERIVEDFACTOR::shared_ptr Combine(const FactorGraph& factors, + typename DERIVEDFACTOR::shared_ptr Combine(const FactorGraphOrdered& factors, const FastMap >& variableSlots) { typedef const std::pair > KeySlotPair; @@ -263,14 +263,14 @@ namespace gtsam { template void _FactorGraph_BayesTree_adder( std::vector >& factors_io, - const typename BayesTree::sharedClique& clique) { + const typename BayesTreeOrdered::sharedClique& clique) { if(clique) { // Add factor from this clique factors_io.push_back((*clique)->toFactor()); // Traverse children - typedef typename BayesTree::sharedClique sharedClique; + typedef typename BayesTreeOrdered::sharedClique sharedClique; BOOST_FOREACH(const sharedClique& child, clique->children()) _FactorGraph_BayesTree_adder(factors_io, child); } @@ -279,7 +279,7 @@ namespace gtsam { /* ************************************************************************* */ template template - FactorGraph::FactorGraph(const BayesTree& bayesTree) { + FactorGraphOrdered::FactorGraphOrdered(const BayesTreeOrdered& bayesTree) { factors_.reserve(bayesTree.size()); _FactorGraph_BayesTree_adder(factors_, bayesTree.root()); } diff --git a/gtsam/inference/FactorGraphOrdered.h b/gtsam/inference/FactorGraphOrdered.h new file mode 100644 index 000000000..d75308c62 --- /dev/null +++ b/gtsam/inference/FactorGraphOrdered.h @@ -0,0 +1,273 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file FactorGraph.h + * @brief Factor Graph Base Class + * @author Carlos Nieto + * @author Christian Potthast + * @author Michael Kaess + */ + +// \callgraph + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace gtsam { + +// Forward declarations +template class BayesTreeOrdered; +class VariableIndexOrdered; + + /** + * A factor graph is a bipartite graph with factor nodes connected to variable nodes. + * In this class, however, only factor nodes are kept around. + * \nosubgrouping + */ + template + class FactorGraphOrdered { + + public: + + typedef FACTOR FactorType; ///< factor type + typedef typename FACTOR::KeyType KeyType; ///< type of Keys we use to index variables with + typedef boost::shared_ptr sharedFactor; ///< Shared pointer to a factor + typedef boost::shared_ptr sharedConditional; ///< Shared pointer to a conditional + + typedef FactorGraphOrdered This; ///< Typedef for this class + typedef boost::shared_ptr shared_ptr; ///< Shared pointer for this class + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + + /** typedef for elimination result */ + typedef std::pair EliminationResult; + + /** typedef for an eliminate subroutine */ + typedef boost::function Eliminate; + + protected: + + /** concept check, makes sure FACTOR defines print and equals */ + GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR) + + /** Collection of factors */ + std::vector factors_; + + public: + + /// @name Standard Constructor + /// @{ + + /** Default constructor */ + FactorGraphOrdered() {} + + /// @} + /// @name Advanced Constructors + /// @{ + + /** + * @brief Constructor from a Bayes net + * @param bayesNet the Bayes net to convert, type CONDITIONAL must yield compatible factor + * @return a factor graph with all the conditionals, as factors + */ + template + FactorGraphOrdered(const BayesNetOrdered& bayesNet); + + /** convert from Bayes tree */ + template + FactorGraphOrdered(const BayesTreeOrdered& bayesTree); + + /** convert from a derived type */ + template + FactorGraphOrdered(const FactorGraphOrdered& factors) { + factors_.assign(factors.begin(), factors.end()); + } + + /// @} + /// @name Adding Factors + /// @{ + + /** + * Reserve space for the specified number of factors if you know in + * advance how many there will be (works like std::vector::reserve). + */ + void reserve(size_t size) { factors_.reserve(size); } + + /** Add a factor */ + template + void push_back(const boost::shared_ptr& factor) { + factors_.push_back(boost::shared_ptr(factor)); + } + + /** push back many factors */ + void push_back(const This& factors) { + factors_.insert(end(), factors.begin(), factors.end()); + } + + /** push back many factors with an iterator */ + template + void push_back(ITERATOR firstFactor, ITERATOR lastFactor) { + factors_.insert(end(), firstFactor, lastFactor); + } + + /** + * @brief Add a vector of derived factors + * @param factors to add + */ + template + void push_back(const std::vector >& factors) { + factors_.insert(end(), factors.begin(), factors.end()); + } + + /// @} + /// @name Testable + /// @{ + + /** print out graph */ + void print(const std::string& s = "FactorGraph", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /** Check equality */ + bool equals(const This& fg, double tol = 1e-9) const; + + /// @} + /// @name Standard Interface + /// @{ + + /** return the number of factors and NULLS */ + size_t size() const { return factors_.size();} + + /** Simple check for an empty graph - faster than comparing size() to zero */ + bool empty() const { return factors_.empty(); } + + /** const cast to the underlying vector of factors */ + operator const std::vector&() const { return factors_; } + + /** Get a specific factor by index */ + const sharedFactor at(size_t i) const { assert(i > eliminateFrontals(size_t nFrontals, const Eliminate& eliminate) const; + + /** Factor the factor graph into a conditional and a remaining factor graph. + * Given the factor graph \f$ f(X) \f$, and \c variables to factorize out + * \f$ V \f$, this function factorizes into \f$ f(X) = f(V;Y)f(Y) \f$, where + * \f$ Y := X\V \f$ are the remaining variables. If \f$ f(X) = p(X) \f$ is + * a probability density or likelihood, the factorization produces a + * conditional probability density and a marginal \f$ p(X) = p(V|Y)p(Y) \f$. + * + * For efficiency, this function treats the variables to eliminate + * \c variables as fully-connected, so produces a dense (fully-connected) + * conditional on all of the variables in \c variables, instead of a sparse + * BayesNet. If the variables are not fully-connected, it is more efficient + * to sequentially factorize multiple times. + */ + std::pair > eliminate( + const std::vector& variables, const Eliminate& eliminateFcn, + boost::optional variableIndex = boost::none) const; + + /** Eliminate a single variable, by calling FactorGraph::eliminate. */ + std::pair > eliminateOne( + KeyType variable, const Eliminate& eliminateFcn, + boost::optional variableIndex = boost::none) const { + std::vector variables(1, variable); + return eliminate(variables, eliminateFcn, variableIndex); + } + + /// @} + /// @name Modifying Factor Graphs (imperative, discouraged) + /// @{ + + /** non-const STL-style begin() */ + iterator begin() { return factors_.begin();} + + /** non-const STL-style end() */ + iterator end() { return factors_.end(); } + + /** resize the factor graph. TODO: effects? */ + void resize(size_t size) { factors_.resize(size); } + + /** delete factor without re-arranging indexes by inserting a NULL pointer */ + inline void remove(size_t i) { factors_[i].reset();} + + /** replace a factor by index */ + void replace(size_t index, sharedFactor factor); + + /// @} + /// @name Advanced Interface + /// @{ + + /** return the number valid factors */ + size_t nrFactors() const; + + /** Potentially very slow function to return all keys involved */ + std::set keys() const; + + private: + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(factors_); + } + + /// @} + + }; // FactorGraph + + /** Create a combined joint factor (new style for EliminationTree). */ + template + typename DERIVEDFACTOR::shared_ptr Combine(const FactorGraphOrdered& factors, + const FastMap >& variableSlots); + + /** + * static function that combines two factor graphs + * @param fg1 Linear factor graph + * @param fg2 Linear factor graph + * @return a new combined factor graph + */ + template + FACTORGRAPH combine(const FACTORGRAPH& fg1, const FACTORGRAPH& fg2); + +} // namespace gtsam + +#include diff --git a/gtsam/inference/FactorGraphUnordered.h b/gtsam/inference/FactorGraphUnordered.h deleted file mode 100644 index 099f7adfd..000000000 --- a/gtsam/inference/FactorGraphUnordered.h +++ /dev/null @@ -1,360 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file FactorGraph.h - * @brief Factor Graph Base Class - * @author Carlos Nieto - * @author Christian Potthast - * @author Michael Kaess - * @author Richard Roberts - */ - -// \callgraph - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include - -namespace gtsam { - - // Forward declarations - template class BayesTreeUnordered; - - /** Helper */ - template - class CRefCallPushBack - { - C& obj; - public: - CRefCallPushBack(C& obj) : obj(obj) {} - template - void operator()(const A& a) { obj.push_back(a); } - }; - - /** Helper */ - template - class RefCallPushBack - { - C& obj; - public: - RefCallPushBack(C& obj) : obj(obj) {} - template - void operator()(A& a) { obj.push_back(a); } - }; - - /** Helper */ - template - class CRefCallAddCopy - { - C& obj; - public: - CRefCallAddCopy(C& obj) : obj(obj) {} - template - void operator()(const A& a) { obj.addCopy(a); } - }; - - /** - * A factor graph is a bipartite graph with factor nodes connected to variable nodes. - * In this class, however, only factor nodes are kept around. - * \nosubgrouping - */ - template - class FactorGraphUnordered { - - public: - typedef FACTOR FactorType; ///< factor type - typedef boost::shared_ptr sharedFactor; ///< Shared pointer to a factor - typedef sharedFactor value_type; - typedef typename std::vector::iterator iterator; - typedef typename std::vector::const_iterator const_iterator; - - private: - typedef FactorGraphUnordered This; ///< Typedef for this class - typedef boost::shared_ptr shared_ptr; ///< Shared pointer for this class - - protected: - /** concept check, makes sure FACTOR defines print and equals */ - GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR) - - /** Collection of factors */ - std::vector factors_; - - /// @name Standard Constructors - /// @{ - - /** Default constructor */ - FactorGraphUnordered() {} - - /** Constructor from iterator over factors (shared_ptr or plain objects) */ - template - FactorGraphUnordered(ITERATOR firstFactor, ITERATOR lastFactor) { push_back(firstFactor, lastFactor); } - - /** Construct from container of factors (shared_ptr or plain objects) */ - template - explicit FactorGraphUnordered(const CONTAINER& factors) { push_back(factors); } - - /// @} - /// @name Advanced Constructors - /// @{ - - // TODO: are these needed? - - ///** - // * @brief Constructor from a Bayes net - // * @param bayesNet the Bayes net to convert, type CONDITIONAL must yield compatible factor - // * @return a factor graph with all the conditionals, as factors - // */ - //template - //FactorGraph(const BayesNet& bayesNet); - - ///** convert from Bayes tree */ - //template - //FactorGraph(const BayesTree& bayesTree); - - ///** convert from a derived type */ - //template - //FactorGraph(const FactorGraph& factors) { - // factors_.assign(factors.begin(), factors.end()); - //} - - /// @} - - public: - /// @name Adding Factors - /// @{ - - /** - * Reserve space for the specified number of factors if you know in - * advance how many there will be (works like std::vector::reserve). - */ - void reserve(size_t size) { factors_.reserve(size); } - - // TODO: are these needed? - - /** Add a factor directly using a shared_ptr */ - template - typename std::enable_if::value>::type - push_back(boost::shared_ptr& factor) { - factors_.push_back(boost::shared_ptr(factor)); } - - /** Add a factor directly using a shared_ptr */ - void push_back(const sharedFactor& factor) { - factors_.push_back(factor); } - - /** push back many factors with an iterator over shared_ptr (factors are not copied) */ - template - typename std::enable_if::value>::type - push_back(ITERATOR firstFactor, ITERATOR lastFactor) { - factors_.insert(end(), firstFactor, lastFactor); } - - /** push back many factors as shared_ptr's in a container (factors are not copied) */ - template - typename std::enable_if::value>::type - push_back(const CONTAINER& container) { - push_back(container.begin(), container.end()); - } - - /** push back a BayesTree as a collection of factors. NOTE: This should be hidden in derived - * classes in favor of a type-specialized version that calls this templated function. */ - template - typename std::enable_if::value>::type - push_back(const BayesTreeUnordered& bayesTree) { - bayesTree.addFactorsToGraph(*this); - } - - /** += syntax for push_back, e.g. graph += f1, f2, f3 */ - //template - //boost::assign::list_inserter > - // operator+=(const T& factorOrContainer) - //{ - // return boost::assign::make_list_inserter( - // boost::bind(&This::push_back, this, _1)); - //} - - /** Add a factor directly using a shared_ptr */ - template - typename std::enable_if::value, - boost::assign::list_inserter > >::type - operator+=(boost::shared_ptr& factor) { - return boost::assign::make_list_inserter(RefCallPushBack(*this))(factor); - } - - template - boost::assign::list_inserter > - operator+=(const FACTOR_OR_CONTAINER& factorOrContainer) { - return boost::assign::make_list_inserter(CRefCallPushBack(*this))(factorOrContainer); - } - - ///** Add a factor directly using a shared_ptr */ - //boost::assign::list_inserter > - // operator+=(const sharedFactor& factor) { - // return boost::assign::make_list_inserter(CRefCallPushBack(*this)); - //} - - ///** push back many factors as shared_ptr's in a container (factors are not copied) */ - //template - //typename std::enable_if::value, - // boost::assign::list_inserter > >::type - // operator+=(const CONTAINER& container) { - // return boost::assign::make_list_inserter(CRefCallPushBack(*this)); - //} - - ///** push back a BayesTree as a collection of factors. NOTE: This should be hidden in derived - // * classes in favor of a type-specialized version that calls this templated function. */ - //template - //boost::assign::list_inserter > - // operator+=(const BayesTreeUnordered& bayesTree) { - // return boost::assign::make_list_inserter(CRefCallPushBack(*this)); - //} - - /** Add a factor by value, will be copy-constructed (use push_back with a shared_ptr to avoid - * the copy). */ - template - typename std::enable_if::value>::type - push_back(const DERIVEDFACTOR& factor) { - factors_.push_back(boost::make_shared(factor)); } - - /** push back many factors with an iterator over plain factors (factors are copied) */ - template - typename std::enable_if::value>::type - push_back(ITERATOR firstFactor, ITERATOR lastFactor) { - for(ITERATOR f = firstFactor; f != lastFactor; ++f) - push_back(*f); - } - - /** push back many factors as non-pointer objects in a container (factors are copied) */ - template - typename std::enable_if::value>::type - push_back(const CONTAINER& container) { - push_back(container.begin(), container.end()); - } - - //template - //boost::assign::list_inserter > - // operator*=(const FACTOR_OR_CONTAINER& factorOrContainer) { - // return boost::assign::make_list_inserter(CRefCallAddCopy(*this)); - //} - - /// @} - /// @name Testable - /// @{ - - /** print out graph */ - void print(const std::string& s = "FactorGraph", - const KeyFormatter& formatter = DefaultKeyFormatter) const; - - protected: - /** Check equality */ - bool equals(const This& fg, double tol = 1e-9) const; - /// @} - - public: - /// @name Standard Interface - /// @{ - - /** return the number of factors (including any null factors set by remove() ). */ - size_t size() const { return factors_.size(); } - - /** Check if the graph is empty (null factors set by remove() will cause this to return false). */ - bool empty() const { return factors_.empty(); } - - /** Get a specific factor by index (this checks array bounds and may throw an exception, as - * opposed to operator[] which does not). - */ - const sharedFactor at(size_t i) const { return factors_.at(i); } - - /** Get a specific factor by index (this checks array bounds and may throw an exception, as - * opposed to operator[] which does not). - */ - sharedFactor& at(size_t i) { return factors_.at(i); } - - /** Get a specific factor by index (this does not check array bounds, as opposed to at() which - * does). - */ - const sharedFactor operator[](size_t i) const { return at(i); } - - /** Get a specific factor by index (this does not check array bounds, as opposed to at() which - * does). - */ - sharedFactor& operator[](size_t i) { return at(i); } - - /** Iterator to beginning of factors. */ - const_iterator begin() const { return factors_.begin();} - - /** Iterator to end of factors. */ - const_iterator end() const { return factors_.end(); } - - /** Get the first factor */ - sharedFactor front() const { return factors_.front(); } - - /** Get the last factor */ - sharedFactor back() const { return factors_.back(); } - - /// @} - /// @name Modifying Factor Graphs (imperative, discouraged) - /// @{ - - /** non-const STL-style begin() */ - iterator begin() { return factors_.begin();} - - /** non-const STL-style end() */ - iterator end() { return factors_.end(); } - - /** Directly resize the number of factors in the graph. If the new size is less than the - * original, factors at the end will be removed. If the new size is larger than the original, - * null factors will be appended. - */ - void resize(size_t size) { factors_.resize(size); } - - /** delete factor without re-arranging indexes by inserting a NULL pointer */ - void remove(size_t i) { factors_[i].reset();} - - /** replace a factor by index */ - void replace(size_t index, sharedFactor factor) { at(index) = factor; } - - /** Erase factor and rearrange other factors to take up the empty space */ - void erase(const_iterator item) { factors_.erase(item); } - - /** Erase factors and rearrange other factors to take up the empty space */ - void erase(const_iterator first, const_iterator last) { factors_.erase(first, last); } - - /// @} - /// @name Advanced Interface - /// @{ - - /** return the number of non-null factors */ - size_t nrFactors() const; - - /** Potentially very slow function to return all keys involved */ - FastSet keys() const; - - private: - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(factors_); - } - - /// @} - - }; // FactorGraph - -} // namespace gtsam diff --git a/gtsam/inference/Factor-inl.h b/gtsam/inference/FactorOrdered-inl.h similarity index 80% rename from gtsam/inference/Factor-inl.h rename to gtsam/inference/FactorOrdered-inl.h index 7b22e083e..bf340f9c3 100644 --- a/gtsam/inference/Factor-inl.h +++ b/gtsam/inference/FactorOrdered-inl.h @@ -17,7 +17,7 @@ #pragma once -#include +#include #include #include #include @@ -27,14 +27,14 @@ namespace gtsam { /* ************************************************************************* */ template - Factor::Factor(const Factor& f) : + FactorOrdered::FactorOrdered(const FactorOrdered& f) : keys_(f.keys_) { assertInvariants(); } /* ************************************************************************* */ template - Factor::Factor(const ConditionalType& c) : + FactorOrdered::FactorOrdered(const ConditionalType& c) : keys_(c.keys()) { // assert(c.nrFrontals() == 1); assertInvariants(); @@ -42,7 +42,7 @@ namespace gtsam { /* ************************************************************************* */ template - void Factor::assertInvariants() const { + void FactorOrdered::assertInvariants() const { #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS // Check that keys are all unique std::multiset nonunique(keys_.begin(), keys_.end()); @@ -56,14 +56,14 @@ namespace gtsam { /* ************************************************************************* */ template - void Factor::print(const std::string& s, + void FactorOrdered::print(const std::string& s, const IndexFormatter& formatter) const { printKeys(s,formatter); } /* ************************************************************************* */ template - void Factor::printKeys(const std::string& s, const IndexFormatter& formatter) const { + void FactorOrdered::printKeys(const std::string& s, const IndexFormatter& formatter) const { std::cout << s << " "; BOOST_FOREACH(KEY key, keys_) std::cout << " " << formatter(key); std::cout << std::endl; @@ -71,7 +71,7 @@ namespace gtsam { /* ************************************************************************* */ template - bool Factor::equals(const This& other, double tol) const { + bool FactorOrdered::equals(const This& other, double tol) const { return keys_ == other.keys_; } @@ -79,7 +79,7 @@ namespace gtsam { #ifdef TRACK_ELIMINATE template template - typename COND::shared_ptr Factor::eliminateFirst() { + typename COND::shared_ptr FactorOrdered::eliminateFirst() { assert(!keys_.empty()); assertInvariants(); KEY eliminated = keys_.front(); @@ -91,10 +91,10 @@ namespace gtsam { /* ************************************************************************* */ template template - typename BayesNet::shared_ptr Factor::eliminate(size_t nrFrontals) { + typename BayesNetOrdered::shared_ptr FactorOrdered::eliminate(size_t nrFrontals) { assert(keys_.size() >= nrFrontals); assertInvariants(); - typename BayesNet::shared_ptr fragment(new BayesNet ()); + typename BayesNetOrdered::shared_ptr fragment(new BayesNetOrdered ()); const_iterator it = this->begin(); for (KEY n = 0; n < nrFrontals; ++n, ++it) fragment->push_back(COND::FromRange(it, const_iterator(this->end()), 1)); diff --git a/gtsam/inference/FactorOrdered.h b/gtsam/inference/FactorOrdered.h new file mode 100644 index 000000000..a4512a1bd --- /dev/null +++ b/gtsam/inference/FactorOrdered.h @@ -0,0 +1,232 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file Factor.h + * @brief The base class for all factors + * @author Kai Ni + * @author Frank Dellaert + * @author Richard Roberts + */ + +// \callgraph + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace gtsam { + +template class ConditionalOrdered; + +/** + * This is the base class for all factor types. It is templated on a KEY type, + * which will be the type used to label variables. Key types currently in use + * in gtsam are Index with symbolic (IndexFactor, SymbolicFactorGraph) and + * Gaussian factors (GaussianFactor, JacobianFactor, HessianFactor, GaussianFactorGraph), + * and Key with nonlinear factors (NonlinearFactor, NonlinearFactorGraph). + * though currently only IndexFactor and IndexConditional derive from this + * class, using Index keys. This class does not store any data other than its + * keys. Derived classes store data such as matrices and probability tables. + * + * Note that derived classes *must* redefine the ConditionalType and shared_ptr + * typedefs to refer to the associated conditional and shared_ptr types of the + * derived class. See IndexFactor, JacobianFactor, etc. for examples. + * + * This class is \b not virtual for performance reasons - derived symbolic classes, + * IndexFactor and IndexConditional, need to be created and destroyed quickly + * during symbolic elimination. GaussianFactor and NonlinearFactor are virtual. + * \nosubgrouping + */ +template +class FactorOrdered { + +public: + + typedef KEY KeyType; ///< The KEY template parameter + typedef FactorOrdered This; ///< This class + + /** + * Typedef to the conditional type obtained by eliminating this factor, + * derived classes must redefine this. + */ + typedef ConditionalOrdered ConditionalType; + + /// A shared_ptr to this class, derived classes must redefine this. + typedef boost::shared_ptr shared_ptr; + + /// Iterator over keys + typedef typename std::vector::iterator iterator; + + /// Const iterator over keys + typedef typename std::vector::const_iterator const_iterator; + +protected: + + /// The keys involved in this factor + std::vector keys_; + +public: + + /// @name Standard Constructors + /// @{ + + /** Copy constructor */ + FactorOrdered(const This& f); + + /** Construct from conditional, calls ConditionalType::toFactor() */ + FactorOrdered(const ConditionalType& c); + + /** Default constructor for I/O */ + FactorOrdered() {} + + /** Construct unary factor */ + FactorOrdered(KeyType key) : keys_(1) { + keys_[0] = key; assertInvariants(); } + + /** Construct binary factor */ + FactorOrdered(KeyType key1, KeyType key2) : keys_(2) { + keys_[0] = key1; keys_[1] = key2; assertInvariants(); } + + /** Construct ternary factor */ + FactorOrdered(KeyType key1, KeyType key2, KeyType key3) : keys_(3) { + keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; assertInvariants(); } + + /** Construct 4-way factor */ + FactorOrdered(KeyType key1, KeyType key2, KeyType key3, KeyType key4) : keys_(4) { + keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; assertInvariants(); } + + /** Construct 5-way factor */ + FactorOrdered(KeyType key1, KeyType key2, KeyType key3, KeyType key4, KeyType key5) : keys_(5) { + keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; keys_[4] = key5; assertInvariants(); } + + /** Construct 6-way factor */ + FactorOrdered(KeyType key1, KeyType key2, KeyType key3, KeyType key4, KeyType key5, KeyType key6) : keys_(6) { + keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; keys_[4] = key5; keys_[5] = key6; assertInvariants(); } + + /// @} + /// @name Advanced Constructors + /// @{ + + /** Construct n-way factor */ + FactorOrdered(const std::set& keys) { + BOOST_FOREACH(const KeyType& key, keys) keys_.push_back(key); + assertInvariants(); + } + + /** Construct n-way factor */ + FactorOrdered(const std::vector& keys) : keys_(keys) { + assertInvariants(); + } + + /** Constructor from a collection of keys */ + template FactorOrdered(KEYITERATOR beginKey, KEYITERATOR endKey) : + keys_(beginKey, endKey) { assertInvariants(); } + + /// @} + +#ifdef TRACK_ELIMINATE + /** + * eliminate the first variable involved in this factor + * @return a conditional on the eliminated variable + */ + template + typename CONDITIONAL::shared_ptr eliminateFirst(); + + /** + * eliminate the first nrFrontals frontal variables. + */ + template + typename BayesNetOrdered::shared_ptr eliminate(size_t nrFrontals = 1); +#endif + + /// @name Standard Interface + /// @{ + + /// First key + KeyType front() const { return keys_.front(); } + + /// Last key + KeyType back() const { return keys_.back(); } + + /// find + const_iterator find(KeyType key) const { return std::find(begin(), end(), key); } + + /// Access the factor's involved variable keys + const std::vector& keys() const { return keys_; } + + /** iterators */ + const_iterator begin() const { return keys_.begin(); } ///TODO: comment + const_iterator end() const { return keys_.end(); } ///TODO: comment + + /** + * @return the number of variables involved in this factor + */ + size_t size() const { return keys_.size(); } + + /// @} + /// @name Testable + /// @{ + + /// print + void print(const std::string& s = "Factor", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /// print only keys + void printKeys(const std::string& s = "Factor", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /// check equality + bool equals(const This& other, double tol = 1e-9) const; + + /// @} + /// @name Advanced Interface + /// @{ + + /** + * @return keys involved in this factor + */ + std::vector& keys() { return keys_; } + + /** mutable iterators */ + iterator begin() { return keys_.begin(); } ///TODO: comment + iterator end() { return keys_.end(); } ///TODO: comment + +protected: + friend class JacobianFactorOrdered; + friend class HessianFactorOrdered; + + /// Internal consistency check that is run frequently when in debug mode. + /// If NDEBUG is defined, this is empty and optimized out. + void assertInvariants() const; + +private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(keys_); + } + + /// @} + +}; + +} + +#include diff --git a/gtsam/inference/FactorUnordered.h b/gtsam/inference/FactorUnordered.h deleted file mode 100644 index 8425c81fd..000000000 --- a/gtsam/inference/FactorUnordered.h +++ /dev/null @@ -1,171 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file Factor.h - * @brief The base class for all factors - * @author Kai Ni - * @author Frank Dellaert - * @author Richard Roberts - */ - -// \callgraph - -#pragma once - -#include -#include - -#include -#include - -namespace gtsam { - - /** - * This is the base class for all factor types. It is templated on a KEY type, - * which will be the type used to label variables. Key types currently in use - * in gtsam are Index with symbolic (IndexFactor, SymbolicFactorGraph) and - * Gaussian factors (GaussianFactor, JacobianFactor, HessianFactor, GaussianFactorGraph), - * and Key with nonlinear factors (NonlinearFactor, NonlinearFactorGraph). - * though currently only IndexFactor and IndexConditional derive from this - * class, using Index keys. This class does not store any data other than its - * keys. Derived classes store data such as matrices and probability tables. - * - * Note that derived classes *must* redefine the ConditionalType and shared_ptr - * typedefs to refer to the associated conditional and shared_ptr types of the - * derived class. See IndexFactor, JacobianFactor, etc. for examples. - * - * This class is \b not virtual for performance reasons - derived symbolic classes, - * IndexFactor and IndexConditional, need to be created and destroyed quickly - * during symbolic elimination. GaussianFactor and NonlinearFactor are virtual. - * \nosubgrouping - */ - class GTSAM_EXPORT FactorUnordered - { - - private: - // These typedefs are private because they must be overridden in derived classes. - typedef FactorUnordered This; ///< This class - typedef boost::shared_ptr shared_ptr; ///< A shared_ptr to this class. - - public: - /// Iterator over keys - typedef std::vector::iterator iterator; - - /// Const iterator over keys - typedef std::vector::const_iterator const_iterator; - - protected: - - /// The keys involved in this factor - std::vector keys_; - - /// @name Standard Constructors - /// @{ - - /** Default constructor for I/O */ - FactorUnordered() {} - - /** Construct factor from container of keys. This constructor is used internally from derived factor - * constructors, either from a container of keys or from a boost::assign::list_of. */ - template - FactorUnordered(const CONTAINER& keys) : keys_(keys.begin(), keys.end()) {} - - /** Construct factor from iterator keys. This constructor may be used internally from derived - * factor constructors, although our code currently does not use this. */ - template - FactorUnordered(ITERATOR first, ITERATOR last) : keys_(first, last) {} - - /** Construct factor from container of keys. This is called internally from derived factor static - * factor methods, as a workaround for not being able to call the protected constructors above. */ - template - static FactorUnordered FromKeys(const CONTAINER& keys) { - return FactorUnordered(keys.begin(), keys.end()); } - - /** Construct factor from iterator keys. This is called internally from derived factor static - * factor methods, as a workaround for not being able to call the protected constructors above. */ - template - static FactorUnordered FromIterators(ITERATOR first, ITERATOR last) { - return FactorUnordered(first, last); } - - /// @} - - public: - /// @name Standard Interface - /// @{ - - /// First key - Key front() const { return keys_.front(); } - - /// Last key - Key back() const { return keys_.back(); } - - /// find - const_iterator find(Key key) const { return std::find(begin(), end(), key); } - - /// Access the factor's involved variable keys - const std::vector& keys() const { return keys_; } - - /** Iterator at beginning of involved variable keys */ - const_iterator begin() const { return keys_.begin(); } - - /** Iterator at end of involved variable keys */ - const_iterator end() const { return keys_.end(); } - - /** - * @return the number of variables involved in this factor - */ - size_t size() const { return keys_.size(); } - - /// @} - - - /// @name Testable - /// @{ - - /// print - void print(const std::string& s = "Factor", const KeyFormatter& formatter = DefaultKeyFormatter) const; - - /// print only keys - void printKeys(const std::string& s = "Factor", const KeyFormatter& formatter = DefaultKeyFormatter) const; - - protected: - /// check equality - bool equals(const This& other, double tol = 1e-9) const; - - /// @} - - public: - /// @name Advanced Interface - /// @{ - - /** @return keys involved in this factor */ - std::vector& keys() { return keys_; } - - /** Iterator at beginning of involved variable keys */ - iterator begin() { return keys_.begin(); } - - /** Iterator at end of involved variable keys */ - iterator end() { return keys_.end(); } - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(keys_); - } - - /// @} - - }; - -} diff --git a/gtsam/inference/GenericMultifrontalSolver-inl.h b/gtsam/inference/GenericMultifrontalSolver-inl.h index ff41d0627..9882a92dd 100644 --- a/gtsam/inference/GenericMultifrontalSolver-inl.h +++ b/gtsam/inference/GenericMultifrontalSolver-inl.h @@ -17,17 +17,17 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace gtsam { /* ************************************************************************* */ template GenericMultifrontalSolver::GenericMultifrontalSolver( - const FactorGraph& graph) : - structure_(new VariableIndex(graph)), junctionTree_( + const FactorGraphOrdered& graph) : + structure_(new VariableIndexOrdered(graph)), junctionTree_( new JT(graph, *structure_)) { } @@ -35,7 +35,7 @@ namespace gtsam { template GenericMultifrontalSolver::GenericMultifrontalSolver( const sharedGraph& graph, - const VariableIndex::shared_ptr& variableIndex) : + const VariableIndexOrdered::shared_ptr& variableIndex) : structure_(variableIndex), junctionTree_(new JT(*graph, *structure_)) { } @@ -63,16 +63,16 @@ namespace gtsam { /* ************************************************************************* */ template - typename BayesTree::shared_ptr + typename BayesTreeOrdered::shared_ptr GenericMultifrontalSolver::eliminate(Eliminate function) const { // eliminate junction tree, returns pointer to root - typename BayesTree::sharedClique + typename BayesTreeOrdered::sharedClique root = junctionTree_->eliminate(function); // create an empty Bayes tree and insert root clique - typename BayesTree::shared_ptr - bayesTree(new BayesTree); + typename BayesTreeOrdered::shared_ptr + bayesTree(new BayesTreeOrdered); bayesTree->insert(root); // return the Bayes tree @@ -81,7 +81,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename FactorGraph::shared_ptr GenericMultifrontalSolver::jointFactorGraph( + typename FactorGraphOrdered::shared_ptr GenericMultifrontalSolver::jointFactorGraph( const std::vector& js, Eliminate function) const { // FIXME: joint for arbitrary sets of variables not present diff --git a/gtsam/inference/GenericMultifrontalSolver.h b/gtsam/inference/GenericMultifrontalSolver.h index c06214122..0f379d024 100644 --- a/gtsam/inference/GenericMultifrontalSolver.h +++ b/gtsam/inference/GenericMultifrontalSolver.h @@ -19,8 +19,8 @@ #include -#include -#include +#include +#include namespace gtsam { @@ -44,15 +44,15 @@ namespace gtsam { protected: /// Column structure of the factor graph - VariableIndex::shared_ptr structure_; + VariableIndexOrdered::shared_ptr structure_; /// Junction tree that performs elimination. typename JUNCTIONTREE::shared_ptr junctionTree_; public: - typedef typename FactorGraph::shared_ptr sharedGraph; - typedef typename FactorGraph::Eliminate Eliminate; + typedef typename FactorGraphOrdered::shared_ptr sharedGraph; + typedef typename FactorGraphOrdered::Eliminate Eliminate; /// @name Standard Constructors /// @{ @@ -62,7 +62,7 @@ namespace gtsam { * tree, which does the symbolic elimination, identifies the cliques, * and distributes all the factors to the right cliques. */ - GenericMultifrontalSolver(const FactorGraph& factorGraph); + GenericMultifrontalSolver(const FactorGraphOrdered& factorGraph); /** * Construct the solver with a shared pointer to a factor graph and to a @@ -70,7 +70,7 @@ namespace gtsam { * is the fastest. */ GenericMultifrontalSolver(const sharedGraph& factorGraph, - const VariableIndex::shared_ptr& variableIndex); + const VariableIndexOrdered::shared_ptr& variableIndex); /// @} /// @name Testable @@ -97,7 +97,7 @@ namespace gtsam { * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. */ - typename BayesTree::shared_ptr + typename BayesTreeOrdered::shared_ptr eliminate(Eliminate function) const; /** @@ -105,7 +105,7 @@ namespace gtsam { * all of the other variables. This function returns the result as a factor * graph. */ - typename FactorGraph::shared_ptr jointFactorGraph( + typename FactorGraphOrdered::shared_ptr jointFactorGraph( const std::vector& js, Eliminate function) const; /** diff --git a/gtsam/inference/GenericSequentialSolver-inl.h b/gtsam/inference/GenericSequentialSolver-inl.h index 9dfe64fdc..455dcac80 100644 --- a/gtsam/inference/GenericSequentialSolver-inl.h +++ b/gtsam/inference/GenericSequentialSolver-inl.h @@ -18,11 +18,11 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include @@ -30,24 +30,24 @@ namespace gtsam { /* ************************************************************************* */ template - GenericSequentialSolver::GenericSequentialSolver(const FactorGraph& factorGraph) { + GenericSequentialSolver::GenericSequentialSolver(const FactorGraphOrdered& factorGraph) { gttic(GenericSequentialSolver_constructor1); assert(factorGraph.size()); - factors_.reset(new FactorGraph(factorGraph)); - structure_.reset(new VariableIndex(factorGraph)); - eliminationTree_ = EliminationTree::Create(*factors_, *structure_); + factors_.reset(new FactorGraphOrdered(factorGraph)); + structure_.reset(new VariableIndexOrdered(factorGraph)); + eliminationTree_ = EliminationTreeOrdered::Create(*factors_, *structure_); } /* ************************************************************************* */ template GenericSequentialSolver::GenericSequentialSolver( const sharedFactorGraph& factorGraph, - const boost::shared_ptr& variableIndex) + const boost::shared_ptr& variableIndex) { gttic(GenericSequentialSolver_constructor2); factors_ = factorGraph; structure_ = variableIndex; - eliminationTree_ = EliminationTree::Create(*factors_, *structure_); + eliminationTree_ = EliminationTreeOrdered::Create(*factors_, *structure_); } /* ************************************************************************* */ @@ -79,7 +79,7 @@ namespace gtsam { // problems there may not be enough memory to store two copies. eliminationTree_.reset(); factors_ = factorGraph; - eliminationTree_ = EliminationTree::Create(*factors_, *structure_); + eliminationTree_ = EliminationTreeOrdered::Create(*factors_, *structure_); } /* ************************************************************************* */ @@ -107,7 +107,7 @@ namespace gtsam { factor->permuteWithInverse(*permutationInverse); // Eliminate using elimination tree provided - typename EliminationTree::shared_ptr etree = EliminationTree::Create(*factors_); + typename EliminationTreeOrdered::shared_ptr etree = EliminationTreeOrdered::Create(*factors_); sharedBayesNet bayesNet; if(nrToEliminate) bayesNet = etree->eliminatePartial(function, *nrToEliminate); @@ -175,15 +175,15 @@ namespace gtsam { /* ************************************************************************* */ template - typename FactorGraph::shared_ptr // + typename FactorGraphOrdered::shared_ptr // GenericSequentialSolver::jointFactorGraph( const std::vector& js, Eliminate function) const { gttic(GenericSequentialSolver_jointFactorGraph); // Eliminate all variables - typename BayesNet::shared_ptr bayesNet = jointBayesNet(js, function); + typename BayesNetOrdered::shared_ptr bayesNet = jointBayesNet(js, function); - return boost::make_shared >(*bayesNet); + return boost::make_shared >(*bayesNet); } /* ************************************************************************* */ diff --git a/gtsam/inference/GenericSequentialSolver.h b/gtsam/inference/GenericSequentialSolver.h index 250ff0d73..2e157a4be 100644 --- a/gtsam/inference/GenericSequentialSolver.h +++ b/gtsam/inference/GenericSequentialSolver.h @@ -28,17 +28,17 @@ #include namespace gtsam { - class VariableIndex; + class VariableIndexOrdered; class Permutation; } namespace gtsam { - template class EliminationTree; + template class EliminationTreeOrdered; } namespace gtsam { - template class FactorGraph; + template class FactorGraphOrdered; } namespace gtsam { - template class BayesNet; + template class BayesNetOrdered; } namespace gtsam { @@ -62,13 +62,13 @@ namespace gtsam { protected: - typedef boost::shared_ptr > sharedFactorGraph; + typedef boost::shared_ptr > sharedFactorGraph; typedef typename FACTOR::ConditionalType Conditional; typedef typename boost::shared_ptr sharedConditional; - typedef typename boost::shared_ptr > sharedBayesNet; + typedef typename boost::shared_ptr > sharedBayesNet; typedef std::pair, boost::shared_ptr > EliminationResult; typedef boost::function< - EliminationResult(const FactorGraph&, size_t)> Eliminate; + EliminationResult(const FactorGraphOrdered&, size_t)> Eliminate; /** Store the original factors for computing marginals * TODO Frank says: really? Marginals should be computed from result. @@ -76,14 +76,14 @@ namespace gtsam { sharedFactorGraph factors_; /** Store column structure of the factor graph. Why? */ - boost::shared_ptr structure_; + boost::shared_ptr structure_; /** Elimination tree that performs elimination */ - boost::shared_ptr > eliminationTree_; + boost::shared_ptr > eliminationTree_; /** concept checks */ GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR) - // GTSAM_CONCEPT_TESTABLE_TYPE(EliminationTree) + // GTSAM_CONCEPT_TESTABLE_TYPE(EliminationTreeOrdered) /** * Eliminate in a different order, given a permutation @@ -101,7 +101,7 @@ namespace gtsam { * Construct the solver for a factor graph. This builds the elimination * tree, which already does some of the work of elimination. */ - GenericSequentialSolver(const FactorGraph& factorGraph); + GenericSequentialSolver(const FactorGraphOrdered& factorGraph); /** * Construct the solver with a shared pointer to a factor graph and to a @@ -109,7 +109,7 @@ namespace gtsam { * is the fastest. */ GenericSequentialSolver(const sharedFactorGraph& factorGraph, - const boost::shared_ptr& variableIndex); + const boost::shared_ptr& variableIndex); /// @} /// @name Testable @@ -158,7 +158,7 @@ namespace gtsam { * Compute the marginal joint over a set of variables, by integrating out * all of the other variables. Returns the result as a factor graph. */ - typename FactorGraph::shared_ptr + typename FactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector& js, Eliminate function) const; /** diff --git a/gtsam/inference/ISAM-inl.h b/gtsam/inference/ISAMOrdered-inl.h similarity index 82% rename from gtsam/inference/ISAM-inl.h rename to gtsam/inference/ISAMOrdered-inl.h index 4b5333f33..8183538a0 100644 --- a/gtsam/inference/ISAM-inl.h +++ b/gtsam/inference/ISAMOrdered-inl.h @@ -20,24 +20,24 @@ #include #include // for operator += -#include -#include +#include +#include #include namespace gtsam { /* ************************************************************************* */ template - ISAM::ISAM() : BayesTree() {} + ISAMOrdered::ISAMOrdered() : BayesTreeOrdered() {} /* ************************************************************************* */ template - template void ISAM::update_internal( + template void ISAMOrdered::update_internal( const FG& newFactors, Cliques& orphans, typename FG::Eliminate function) { // Remove the contaminated part of the Bayes tree // Throw exception if disconnected - BayesNet bn; + BayesNetOrdered bn; if (!this->empty()) { this->removeTop(newFactors.keys(), bn, orphans); if (bn.empty()) @@ -50,8 +50,8 @@ namespace gtsam { factors.push_back(newFactors); // eliminate into a Bayes net - GenericMultifrontalSolver > solver(factors); - boost::shared_ptr > bayesTree; + GenericMultifrontalSolver > solver(factors); + boost::shared_ptr > bayesTree; bayesTree = solver.eliminate(function); this->root_ = bayesTree->root(); this->nodes_ = bayesTree->nodes(); @@ -64,7 +64,7 @@ namespace gtsam { /* ************************************************************************* */ template template - void ISAM::update(const FG& newFactors, + void ISAMOrdered::update(const FG& newFactors, typename FG::Eliminate function) { Cliques orphans; this->update_internal(newFactors, orphans, function); diff --git a/gtsam/inference/ISAM.h b/gtsam/inference/ISAMOrdered.h similarity index 77% rename from gtsam/inference/ISAM.h rename to gtsam/inference/ISAMOrdered.h index e227ea57c..9ceb3f83e 100644 --- a/gtsam/inference/ISAM.h +++ b/gtsam/inference/ISAMOrdered.h @@ -18,7 +18,7 @@ // \callgraph #pragma once -#include +#include namespace gtsam { @@ -28,11 +28,11 @@ namespace gtsam { * \nosubgrouping */ template - class ISAM: public BayesTree { + class ISAMOrdered: public BayesTreeOrdered { private: - typedef BayesTree Base; + typedef BayesTreeOrdered Base; public: @@ -40,10 +40,10 @@ namespace gtsam { /// @{ /** Create an empty Bayes Tree */ - ISAM(); + ISAMOrdered(); /** Copy constructor */ - ISAM(const Base& bayesTree) : + ISAMOrdered(const Base& bayesTree) : Base(bayesTree) { } @@ -59,8 +59,8 @@ namespace gtsam { template void update(const FG& newFactors, typename FG::Eliminate function); - typedef typename BayesTree::sharedClique sharedClique; ///::Cliques Cliques; ///::sharedClique sharedClique; ///::Cliques Cliques; /// @@ -73,4 +73,4 @@ namespace gtsam { }/// namespace gtsam -#include +#include diff --git a/gtsam/inference/IndexConditional.cpp b/gtsam/inference/IndexConditionalOrdered.cpp similarity index 85% rename from gtsam/inference/IndexConditional.cpp rename to gtsam/inference/IndexConditionalOrdered.cpp index 20e978afe..5acaf4c9b 100644 --- a/gtsam/inference/IndexConditional.cpp +++ b/gtsam/inference/IndexConditionalOrdered.cpp @@ -16,7 +16,7 @@ */ #include -#include +#include #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-variable" @@ -32,13 +32,13 @@ namespace gtsam { using namespace boost::lambda; /* ************************************************************************* */ - void IndexConditional::assertInvariants() const { + void IndexConditionalOrdered::assertInvariants() const { // Checks for uniqueness of keys Base::assertInvariants(); } /* ************************************************************************* */ - bool IndexConditional::reduceSeparatorWithInverse(const internal::Reduction& inverseReduction) { + bool IndexConditionalOrdered::reduceSeparatorWithInverse(const internal::Reduction& inverseReduction) { #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS BOOST_FOREACH(KeyType key, frontals()) { assert(inverseReduction.find(key) == inverseReduction.end()); } #endif @@ -55,7 +55,7 @@ namespace gtsam { } /* ************************************************************************* */ - void IndexConditional::permuteWithInverse(const Permutation& inversePermutation) { + void IndexConditionalOrdered::permuteWithInverse(const Permutation& inversePermutation) { BOOST_FOREACH(Index& key, keys()) key = inversePermutation[key]; assertInvariants(); diff --git a/gtsam/inference/IndexConditional.h b/gtsam/inference/IndexConditionalOrdered.h similarity index 68% rename from gtsam/inference/IndexConditional.h rename to gtsam/inference/IndexConditionalOrdered.h index a4068f6c4..42b560da5 100644 --- a/gtsam/inference/IndexConditional.h +++ b/gtsam/inference/IndexConditionalOrdered.h @@ -18,9 +18,9 @@ #pragma once #include -#include -#include -#include +#include +#include +#include namespace gtsam { @@ -33,7 +33,7 @@ namespace gtsam { * unsigned integer. * \nosubgrouping */ - class IndexConditional : public Conditional { + class IndexConditionalOrdered : public ConditionalOrdered { protected: @@ -42,46 +42,46 @@ namespace gtsam { public: - typedef IndexConditional This; - typedef Conditional Base; - typedef IndexFactor FactorType; - typedef boost::shared_ptr shared_ptr; + typedef IndexConditionalOrdered This; + typedef ConditionalOrdered Base; + typedef IndexFactorOrdered FactorType; + typedef boost::shared_ptr shared_ptr; /// @name Standard Constructors /// @{ /** Empty Constructor to make serialization possible */ - IndexConditional() { assertInvariants(); } + IndexConditionalOrdered() { assertInvariants(); } /** No parents */ - IndexConditional(Index j) : Base(j) { assertInvariants(); } + IndexConditionalOrdered(Index j) : Base(j) { assertInvariants(); } /** Single parent */ - IndexConditional(Index j, Index parent) : Base(j, parent) { assertInvariants(); } + IndexConditionalOrdered(Index j, Index parent) : Base(j, parent) { assertInvariants(); } /** Two parents */ - IndexConditional(Index j, Index parent1, Index parent2) : Base(j, parent1, parent2) { assertInvariants(); } + IndexConditionalOrdered(Index j, Index parent1, Index parent2) : Base(j, parent1, parent2) { assertInvariants(); } /** Three parents */ - IndexConditional(Index j, Index parent1, Index parent2, Index parent3) : Base(j, parent1, parent2, parent3) { assertInvariants(); } + IndexConditionalOrdered(Index j, Index parent1, Index parent2, Index parent3) : Base(j, parent1, parent2, parent3) { assertInvariants(); } /// @} /// @name Advanced Constructors /// @{ /** Constructor from a frontal variable and a vector of parents */ - IndexConditional(Index j, const std::vector& parents) : Base(j, parents) { + IndexConditionalOrdered(Index j, const std::vector& parents) : Base(j, parents) { assertInvariants(); } /** Constructor from keys and nr of frontal variables */ - IndexConditional(const std::vector& keys, size_t nrFrontals) : + IndexConditionalOrdered(const std::vector& keys, size_t nrFrontals) : Base(keys, nrFrontals) { assertInvariants(); } /** Constructor from keys and nr of frontal variables */ - IndexConditional(const std::list& keys, size_t nrFrontals) : + IndexConditionalOrdered(const std::list& keys, size_t nrFrontals) : Base(keys, nrFrontals) { assertInvariants(); } @@ -93,15 +93,15 @@ namespace gtsam { /** Named constructor directly returning a shared pointer */ template static shared_ptr FromKeys(const KEYS& keys, size_t nrFrontals) { - shared_ptr conditional(new IndexConditional()); + shared_ptr conditional(new IndexConditionalOrdered()); conditional->keys_.assign(keys.begin(), keys.end()); conditional->nrFrontals_ = nrFrontals; return conditional; } /** Convert to a factor */ - IndexFactor::shared_ptr toFactor() const { - return IndexFactor::shared_ptr(new IndexFactor(*this)); + IndexFactorOrdered::shared_ptr toFactor() const { + return IndexFactorOrdered::shared_ptr(new IndexFactorOrdered(*this)); } /// @} diff --git a/gtsam/inference/IndexFactor.cpp b/gtsam/inference/IndexFactorOrdered.cpp similarity index 63% rename from gtsam/inference/IndexFactor.cpp rename to gtsam/inference/IndexFactorOrdered.cpp index 77b84074b..26159dd36 100644 --- a/gtsam/inference/IndexFactor.cpp +++ b/gtsam/inference/IndexFactorOrdered.cpp @@ -15,53 +15,53 @@ * @date Oct 17, 2010 */ -#include -#include -#include +#include +#include +#include using namespace std; namespace gtsam { /* ************************************************************************* */ - void IndexFactor::assertInvariants() const { + void IndexFactorOrdered::assertInvariants() const { Base::assertInvariants(); } /* ************************************************************************* */ - IndexFactor::IndexFactor(const IndexConditional& c) : + IndexFactorOrdered::IndexFactorOrdered(const IndexConditionalOrdered& c) : Base(c) { assertInvariants(); } /* ************************************************************************* */ #ifdef TRACK_ELIMINATE - boost::shared_ptr IndexFactor::eliminateFirst() { - boost::shared_ptr result(Base::eliminateFirst< - IndexConditional>()); + boost::shared_ptr IndexFactorOrdered::eliminateFirst() { + boost::shared_ptr result(Base::eliminateFirst< + IndexConditionalOrdered>()); assertInvariants(); return result; } /* ************************************************************************* */ - boost::shared_ptr > IndexFactor::eliminate( + boost::shared_ptr > IndexFactorOrdered::eliminate( size_t nrFrontals) { - boost::shared_ptr > result(Base::eliminate< - IndexConditional>(nrFrontals)); + boost::shared_ptr > result(Base::eliminate< + IndexConditionalOrdered>(nrFrontals)); assertInvariants(); return result; } #endif /* ************************************************************************* */ - void IndexFactor::permuteWithInverse(const Permutation& inversePermutation) { + void IndexFactorOrdered::permuteWithInverse(const Permutation& inversePermutation) { BOOST_FOREACH(Index& key, keys()) key = inversePermutation[key]; assertInvariants(); } /* ************************************************************************* */ - void IndexFactor::reduceWithInverse(const internal::Reduction& inverseReduction) { + void IndexFactorOrdered::reduceWithInverse(const internal::Reduction& inverseReduction) { BOOST_FOREACH(Index& key, keys()) key = inverseReduction[key]; assertInvariants(); diff --git a/gtsam/inference/IndexFactor.h b/gtsam/inference/IndexFactorOrdered.h similarity index 74% rename from gtsam/inference/IndexFactor.h rename to gtsam/inference/IndexFactorOrdered.h index d18c70086..ded98bf0a 100644 --- a/gtsam/inference/IndexFactor.h +++ b/gtsam/inference/IndexFactorOrdered.h @@ -17,13 +17,13 @@ #pragma once -#include -#include +#include +#include namespace gtsam { // Forward declaration of IndexConditional - class IndexConditional; + class IndexConditionalOrdered; /** * IndexFactor serves two purposes. It is the base class for all linear @@ -34,7 +34,7 @@ namespace gtsam { * It derives from Factor with a key type of Index, an unsigned integer. * \nosubgrouping */ - class IndexFactor: public Factor { + class IndexFactorOrdered: public FactorOrdered { protected: @@ -48,64 +48,64 @@ namespace gtsam { public: - typedef IndexFactor This; - typedef Factor Base; + typedef IndexFactorOrdered This; + typedef FactorOrdered Base; /** Elimination produces an IndexConditional */ - typedef IndexConditional ConditionalType; + typedef IndexConditionalOrdered ConditionalType; /** Overriding the shared_ptr typedef */ - typedef boost::shared_ptr shared_ptr; + typedef boost::shared_ptr shared_ptr; /// @name Standard Interface /// @{ /** Copy constructor */ - IndexFactor(const This& f) : + IndexFactorOrdered(const This& f) : Base(f) { assertInvariants(); } /** Construct from derived type */ - GTSAM_EXPORT IndexFactor(const IndexConditional& c); + GTSAM_EXPORT IndexFactorOrdered(const IndexConditionalOrdered& c); /** Default constructor for I/O */ - IndexFactor() { + IndexFactorOrdered() { assertInvariants(); } /** Construct unary factor */ - IndexFactor(Index j) : + IndexFactorOrdered(Index j) : Base(j) { assertInvariants(); } /** Construct binary factor */ - IndexFactor(Index j1, Index j2) : + IndexFactorOrdered(Index j1, Index j2) : Base(j1, j2) { assertInvariants(); } /** Construct ternary factor */ - IndexFactor(Index j1, Index j2, Index j3) : + IndexFactorOrdered(Index j1, Index j2, Index j3) : Base(j1, j2, j3) { assertInvariants(); } /** Construct 4-way factor */ - IndexFactor(Index j1, Index j2, Index j3, Index j4) : + IndexFactorOrdered(Index j1, Index j2, Index j3, Index j4) : Base(j1, j2, j3, j4) { assertInvariants(); } /** Construct 5-way factor */ - IndexFactor(Index j1, Index j2, Index j3, Index j4, Index j5) : + IndexFactorOrdered(Index j1, Index j2, Index j3, Index j4, Index j5) : Base(j1, j2, j3, j4, j5) { assertInvariants(); } /** Construct 6-way factor */ - IndexFactor(Index j1, Index j2, Index j3, Index j4, Index j5, Index j6) : + IndexFactorOrdered(Index j1, Index j2, Index j3, Index j4, Index j5, Index j6) : Base(j1, j2, j3, j4, j5, j6) { assertInvariants(); } @@ -115,19 +115,19 @@ namespace gtsam { /// @{ /** Construct n-way factor */ - IndexFactor(const std::set& js) : + IndexFactorOrdered(const std::set& js) : Base(js) { assertInvariants(); } /** Construct n-way factor */ - IndexFactor(const std::vector& js) : + IndexFactorOrdered(const std::vector& js) : Base(js) { assertInvariants(); } /** Constructor from a collection of keys */ - template IndexFactor(KeyIterator beginKey, + template IndexFactorOrdered(KeyIterator beginKey, KeyIterator endKey) : Base(beginKey, endKey) { assertInvariants(); @@ -143,7 +143,7 @@ namespace gtsam { GTSAM_EXPORT boost::shared_ptr eliminateFirst(); /** eliminate the first nrFrontals frontal variables.*/ - GTSAM_EXPORT boost::shared_ptr > eliminate(size_t nrFrontals = + GTSAM_EXPORT boost::shared_ptr > eliminate(size_t nrFrontals = 1); #endif @@ -161,7 +161,7 @@ namespace gtsam { */ GTSAM_EXPORT void reduceWithInverse(const internal::Reduction& inverseReduction); - virtual ~IndexFactor() { + virtual ~IndexFactorOrdered() { } private: diff --git a/gtsam/inference/JunctionTreeUnordered-inst.h b/gtsam/inference/JunctionTree-inst.h similarity index 90% rename from gtsam/inference/JunctionTreeUnordered-inst.h rename to gtsam/inference/JunctionTree-inst.h index 351aaf870..4e24aaac1 100644 --- a/gtsam/inference/JunctionTreeUnordered-inst.h +++ b/gtsam/inference/JunctionTree-inst.h @@ -22,9 +22,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -36,9 +36,9 @@ namespace gtsam { template struct ConstructorTraversalData { ConstructorTraversalData* const parentData; - typename JunctionTreeUnordered::sharedNode myJTNode; - std::vector childSymbolicConditionals; - std::vector childSymbolicFactors; + typename JunctionTree::sharedNode myJTNode; + std::vector childSymbolicConditionals; + std::vector childSymbolicFactors; ConstructorTraversalData(ConstructorTraversalData* _parentData) : parentData(_parentData) {} }; @@ -52,7 +52,7 @@ namespace gtsam { // On the pre-order pass, before children have been visited, we just set up a traversal data // structure with its own JT node, and create a child pointer in its parent. ConstructorTraversalData myData = ConstructorTraversalData(&parentData); - myData.myJTNode = boost::make_shared::Node>(); + myData.myJTNode = boost::make_shared::Node>(); myData.myJTNode->keys.push_back(node->key); myData.myJTNode->factors.insert(myData.myJTNode->factors.begin(), node->factors.begin(), node->factors.end()); parentData.myJTNode->children.push_back(myData.myJTNode); @@ -74,17 +74,17 @@ namespace gtsam { // current node did not introduce any parents beyond those already in the child. // Do symbolic elimination for this node - SymbolicFactorGraphUnordered symbolicFactors; + SymbolicFactorGraph symbolicFactors; symbolicFactors.reserve(ETreeNode->factors.size() + myData.childSymbolicFactors.size()); // Add symbolic versions of the ETree node factors BOOST_FOREACH(const typename GRAPH::sharedFactor& factor, ETreeNode->factors) { - symbolicFactors.push_back(boost::make_shared( - SymbolicFactorUnordered::FromKeys(*factor))); } + symbolicFactors.push_back(boost::make_shared( + SymbolicFactor::FromKeys(*factor))); } // Add symbolic factors passed up from children symbolicFactors.push_back(myData.childSymbolicFactors.begin(), myData.childSymbolicFactors.end()); - OrderingUnordered keyAsOrdering; keyAsOrdering.push_back(ETreeNode->key); - std::pair symbolicElimResult = - EliminateSymbolicUnordered(symbolicFactors, keyAsOrdering); + Ordering keyAsOrdering; keyAsOrdering.push_back(ETreeNode->key); + std::pair symbolicElimResult = + EliminateSymbolic(symbolicFactors, keyAsOrdering); // Store symbolic elimination results in the parent myData.parentData->childSymbolicConditionals.push_back(symbolicElimResult.first); @@ -102,7 +102,7 @@ namespace gtsam { if(myNrParents + 1 == myData.childSymbolicConditionals[child]->nrParents()) { // Get a reference to the child, adjusting the index to account for children previously // merged and removed from the child list. - const typename JunctionTreeUnordered::Node& childToMerge = + const typename JunctionTree::Node& childToMerge = *myData.myJTNode->children[child - nrMergedChildren]; // Merge keys, factors, and children. myData.myJTNode->keys.insert(myData.myJTNode->keys.begin(), childToMerge.keys.begin(), childToMerge.keys.end()); @@ -182,7 +182,7 @@ namespace gtsam { // Do dense elimination step std::pair, boost::shared_ptr > eliminationResult = - eliminationFunction(gatheredFactors, OrderingUnordered(node->keys)); + eliminationFunction(gatheredFactors, Ordering(node->keys)); // Store conditional in BayesTree clique myData.bayesTreeNode->conditional_ = eliminationResult.first; @@ -195,7 +195,7 @@ namespace gtsam { /* ************************************************************************* */ template - void JunctionTreeUnordered::Node::print( + void JunctionTree::Node::print( const std::string& s, const KeyFormatter& keyFormatter) const { std::cout << s; @@ -206,7 +206,7 @@ namespace gtsam { /* ************************************************************************* */ template - void JunctionTreeUnordered::print( + void JunctionTree::print( const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const { treeTraversal::PrintForest(*this, s, keyFormatter); @@ -215,8 +215,8 @@ namespace gtsam { /* ************************************************************************* */ template template - JunctionTreeUnordered - JunctionTreeUnordered::FromEliminationTree(const ETREE& eliminationTree) + JunctionTree + JunctionTree::FromEliminationTree(const ETREE& eliminationTree) { gttic(JunctionTree_FromEliminationTree); // Here we rely on the BayesNet having been produced by this elimination tree, such that the @@ -245,7 +245,7 @@ namespace gtsam { /* ************************************************************************* */ template - JunctionTreeUnordered& JunctionTreeUnordered::operator=(const This& other) + JunctionTree& JunctionTree::operator=(const This& other) { // Start by duplicating the tree. roots_ = treeTraversal::CloneForest(other); @@ -260,7 +260,7 @@ namespace gtsam { /* ************************************************************************* */ template std::pair, boost::shared_ptr > - JunctionTreeUnordered::eliminate(const Eliminate& function) const + JunctionTree::eliminate(const Eliminate& function) const { gttic(JunctionTree_eliminate); // Do elimination (depth-first traversal). The rootsContainer stores a 'dummy' BayesTree node diff --git a/gtsam/inference/JunctionTree.h b/gtsam/inference/JunctionTree.h index c8ecc0576..e7df4e32d 100644 --- a/gtsam/inference/JunctionTree.h +++ b/gtsam/inference/JunctionTree.h @@ -14,18 +14,14 @@ * @date Feb 4, 2010 * @author Kai Ni * @author Frank Dellaert - * @brief: The junction tree + * @author Richard Roberts + * @brief The junction tree */ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include +#include namespace gtsam { @@ -46,90 +42,103 @@ namespace gtsam { * The tree structure and elimination method are exactly analagous to the EliminationTree, * except that in the JunctionTree, at each node multiple variables are eliminated at a time. * - * * \addtogroup Multifrontal * \nosubgrouping */ - template::Clique> - class JunctionTree: public ClusterTree { + template + class JunctionTree { public: - /// In a junction tree each cluster is associated with a clique - typedef typename ClusterTree::Cluster Clique; - typedef typename Clique::shared_ptr sharedClique; ///< Shared pointer to a clique + typedef GRAPH FactorGraphType; ///< The factor graph type + typedef typename GRAPH::FactorType FactorType; ///< The type of factors + typedef JunctionTree This; ///< This class + typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class + typedef boost::shared_ptr sharedFactor; ///< Shared pointer to a factor + typedef BAYESTREE BayesTreeType; ///< The BayesTree type produced by elimination + typedef typename BayesTreeType::ConditionalType ConditionalType; ///< The type of conditionals + typedef boost::shared_ptr sharedConditional; ///< Shared pointer to a conditional + typedef typename FactorGraphType::Eliminate Eliminate; ///< Typedef for an eliminate subroutine - /// The BayesTree type produced by elimination - typedef BTCLIQUE BTClique; + struct Node { + typedef std::vector Keys; + typedef std::vector Factors; + typedef std::vector > Children; - /// Shared pointer to this class - typedef boost::shared_ptr > shared_ptr; + Keys keys; ///< Frontal keys of this node + Factors factors; ///< Factors associated with this node + Children children; ///< sub-trees + int problemSize_; - /// We will frequently refer to a symbolic Bayes tree, used to find the clique structure - typedef gtsam::BayesTree SymbolicBayesTree; + int problemSize() const { return problemSize_; } + + /** print this node */ + void print(const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; + }; + + typedef boost::shared_ptr sharedNode; ///< Shared pointer to Node private: - /// @name Advanced Interface - /// @{ + /** concept check */ + GTSAM_CONCEPT_TESTABLE_TYPE(FactorType); - /// distribute the factors along the cluster tree - sharedClique distributeFactors(const FG& fg, - const SymbolicBayesTree::sharedClique& clique); + std::vector roots_; + std::vector remainingFactors_; - /// distribute the factors along the cluster tree - sharedClique distributeFactors(const FG& fg, const std::vector >& targets, - const SymbolicBayesTree::sharedClique& clique); - - /// recursive elimination function - std::pair - eliminateOneClique(typename FG::Eliminate function, - const boost::shared_ptr& clique) const; - - /// internal constructor - void construct(const FG& fg, const VariableIndex& variableIndex); - - /// @} - - public: + protected: /// @name Standard Constructors /// @{ - /** Default constructor */ - JunctionTree() {} + /** Build the junction tree from an elimination tree. */ + template + static This FromEliminationTree(const ETREE& eliminationTree); + + /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are + * copied, factors are not cloned. */ + JunctionTree(const This& other) { *this = other; } - /** Named constructor to build the junction tree of a factor graph. Note - * that this has to compute the column structure as a VariableIndex, so if you - * already have this precomputed, use the JunctionTree(const FG&, const VariableIndex&) - * constructor instead. - * @param factorGraph The factor graph for which to build the elimination tree - */ - JunctionTree(const FG& factorGraph); - - /** Construct from a factor graph and pre-computed variable index. - * @param fg The factor graph for which to build the junction tree - * @param structure The set of factors involving each variable. If this is not - * precomputed, you can call the JunctionTree(const FG&) - * constructor instead. - */ - JunctionTree(const FG& fg, const VariableIndex& variableIndex); + /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors + * are copied, factors are not cloned. */ + This& operator=(const This& other); /// @} + + public: + /// @name Standard Interface /// @{ - /** Eliminate the factors in the subgraphs to produce a BayesTree. - * @param function The function used to eliminate, see the namespace functions - * in GaussianFactorGraph.h - * @return The BayesTree resulting from elimination - */ - typename BTClique::shared_ptr eliminate(typename FG::Eliminate function) const; + /** Eliminate the factors to a Bayes net and remaining factor graph + * @param function The function to use to eliminate, see the namespace functions + * in GaussianFactorGraph.h + * @return The Bayes net and factor graph resulting from elimination + */ + std::pair, boost::shared_ptr > + eliminate(const Eliminate& function) const; + + /** Print the junction tree */ + void print(const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; /// @} - }; // JunctionTree + /// @name Advanced Interface + /// @{ + + /** Return the set of roots (one for a tree, multiple for a forest) */ + const std::vector& roots() const { return roots_; } -} // namespace gtsam + /** Return the remaining factors that are not pulled into elimination */ + const std::vector& remainingFactors() const { return remainingFactors_; } -#include + /// @} + + private: + + // Private default constructor (used in static construction methods) + JunctionTree() {} + + }; + +} \ No newline at end of file diff --git a/gtsam/inference/JunctionTree-inl.h b/gtsam/inference/JunctionTreeOrdered-inl.h similarity index 85% rename from gtsam/inference/JunctionTree-inl.h rename to gtsam/inference/JunctionTreeOrdered-inl.h index 7a790875b..de648571c 100644 --- a/gtsam/inference/JunctionTree-inl.h +++ b/gtsam/inference/JunctionTreeOrdered-inl.h @@ -19,9 +19,9 @@ #pragma once -#include +#include #include -#include +#include #include #include @@ -30,15 +30,15 @@ namespace gtsam { /* ************************************************************************* */ template - void JunctionTree::construct(const FG& fg, const VariableIndex& variableIndex) { + void JunctionTreeOrdered::construct(const FG& fg, const VariableIndexOrdered& variableIndex) { gttic(JT_construct); gttic(JT_symbolic_ET); - const typename EliminationTree::shared_ptr symETree = - EliminationTree::Create(fg, variableIndex); + const typename EliminationTreeOrdered::shared_ptr symETree = + EliminationTreeOrdered::Create(fg, variableIndex); assert(symETree.get()); gttoc(JT_symbolic_ET); gttic(JT_symbolic_eliminate); - SymbolicBayesNet::shared_ptr sbn = symETree->eliminate(&EliminateSymbolic); + SymbolicBayesNetOrdered::shared_ptr sbn = symETree->eliminate(&EliminateSymbolic); assert(sbn.get()); gttoc(JT_symbolic_eliminate); gttic(symbolic_BayesTree); @@ -53,22 +53,22 @@ namespace gtsam { /* ************************************************************************* */ template - JunctionTree::JunctionTree(const FG& fg) { - gttic(VariableIndex); - VariableIndex varIndex(fg); - gttoc(VariableIndex); + JunctionTreeOrdered::JunctionTreeOrdered(const FG& fg) { + gttic(VariableIndexOrdered); + VariableIndexOrdered varIndex(fg); + gttoc(VariableIndexOrdered); construct(fg, varIndex); } /* ************************************************************************* */ template - JunctionTree::JunctionTree(const FG& fg, const VariableIndex& variableIndex) { + JunctionTreeOrdered::JunctionTreeOrdered(const FG& fg, const VariableIndexOrdered& variableIndex) { construct(fg, variableIndex); } /* ************************************************************************* */ template - typename JunctionTree::sharedClique JunctionTree::distributeFactors( + typename JunctionTreeOrdered::sharedClique JunctionTreeOrdered::distributeFactors( const FG& fg, const SymbolicBayesTree::sharedClique& bayesClique) { // Build "target" index. This is an index for each variable of the factors @@ -104,7 +104,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename JunctionTree::sharedClique JunctionTree::distributeFactors(const FG& fg, + typename JunctionTreeOrdered::sharedClique JunctionTreeOrdered::distributeFactors(const FG& fg, const std::vector >& targets, const SymbolicBayesTree::sharedClique& bayesClique) { @@ -142,8 +142,8 @@ namespace gtsam { /* ************************************************************************* */ template - std::pair::BTClique::shared_ptr, - typename FG::sharedFactor> JunctionTree::eliminateOneClique( + std::pair::BTClique::shared_ptr, + typename FG::sharedFactor> JunctionTreeOrdered::eliminateOneClique( typename FG::Eliminate function, const boost::shared_ptr& current) const { @@ -189,7 +189,7 @@ namespace gtsam { /* ************************************************************************* */ template - typename BTCLIQUE::shared_ptr JunctionTree::eliminate( + typename BTCLIQUE::shared_ptr JunctionTreeOrdered::eliminate( typename FG::Eliminate function) const { if (this->root()) { diff --git a/gtsam/inference/JunctionTreeOrdered.h b/gtsam/inference/JunctionTreeOrdered.h new file mode 100644 index 000000000..ae91ab661 --- /dev/null +++ b/gtsam/inference/JunctionTreeOrdered.h @@ -0,0 +1,135 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file JunctionTree.h + * @date Feb 4, 2010 + * @author Kai Ni + * @author Frank Dellaert + * @brief: The junction tree + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace gtsam { + + /** + * A ClusterTree, i.e., a set of variable clusters with factors, arranged in a tree, with + * the additional property that it represents the clique tree associated with a Bayes net. + * + * In GTSAM a junction tree is an intermediate data structure in multifrontal + * variable elimination. Each node is a cluster of factors, along with a + * clique of variables that are eliminated all at once. In detail, every node k represents + * a clique (maximal fully connected subset) of an associated chordal graph, such as a + * chordal Bayes net resulting from elimination. + * + * The difference with the BayesTree is that a JunctionTree stores factors, whereas a + * BayesTree stores conditionals, that are the product of eliminating the factors in the + * corresponding JunctionTree cliques. + * + * The tree structure and elimination method are exactly analagous to the EliminationTree, + * except that in the JunctionTree, at each node multiple variables are eliminated at a time. + * + * + * \addtogroup Multifrontal + * \nosubgrouping + */ + template::Clique> + class JunctionTreeOrdered: public ClusterTreeOrdered { + + public: + + /// In a junction tree each cluster is associated with a clique + typedef typename ClusterTreeOrdered::Cluster Clique; + typedef typename Clique::shared_ptr sharedClique; ///< Shared pointer to a clique + + /// The BayesTree type produced by elimination + typedef BTCLIQUE BTClique; + + /// Shared pointer to this class + typedef boost::shared_ptr > shared_ptr; + + /// We will frequently refer to a symbolic Bayes tree, used to find the clique structure + typedef gtsam::BayesTreeOrdered SymbolicBayesTree; + + private: + + /// @name Advanced Interface + /// @{ + + /// distribute the factors along the cluster tree + sharedClique distributeFactors(const FG& fg, + const SymbolicBayesTree::sharedClique& clique); + + /// distribute the factors along the cluster tree + sharedClique distributeFactors(const FG& fg, const std::vector >& targets, + const SymbolicBayesTree::sharedClique& clique); + + /// recursive elimination function + std::pair + eliminateOneClique(typename FG::Eliminate function, + const boost::shared_ptr& clique) const; + + /// internal constructor + void construct(const FG& fg, const VariableIndexOrdered& variableIndex); + + /// @} + + public: + + /// @name Standard Constructors + /// @{ + + /** Default constructor */ + JunctionTreeOrdered() {} + + /** Named constructor to build the junction tree of a factor graph. Note + * that this has to compute the column structure as a VariableIndex, so if you + * already have this precomputed, use the JunctionTree(const FG&, const VariableIndex&) + * constructor instead. + * @param factorGraph The factor graph for which to build the elimination tree + */ + JunctionTreeOrdered(const FG& factorGraph); + + /** Construct from a factor graph and pre-computed variable index. + * @param fg The factor graph for which to build the junction tree + * @param structure The set of factors involving each variable. If this is not + * precomputed, you can call the JunctionTree(const FG&) + * constructor instead. + */ + JunctionTreeOrdered(const FG& fg, const VariableIndexOrdered& variableIndex); + + /// @} + /// @name Standard Interface + /// @{ + + /** Eliminate the factors in the subgraphs to produce a BayesTree. + * @param function The function used to eliminate, see the namespace functions + * in GaussianFactorGraph.h + * @return The BayesTree resulting from elimination + */ + typename BTClique::shared_ptr eliminate(typename FG::Eliminate function) const; + + /// @} + + }; // JunctionTree + +} // namespace gtsam + +#include diff --git a/gtsam/inference/JunctionTreeUnordered.h b/gtsam/inference/JunctionTreeUnordered.h deleted file mode 100644 index ade95d335..000000000 --- a/gtsam/inference/JunctionTreeUnordered.h +++ /dev/null @@ -1,144 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file JunctionTree.h - * @date Feb 4, 2010 - * @author Kai Ni - * @author Frank Dellaert - * @author Richard Roberts - * @brief The junction tree - */ - -#pragma once - -#include -#include - -namespace gtsam { - - /** - * A ClusterTree, i.e., a set of variable clusters with factors, arranged in a tree, with - * the additional property that it represents the clique tree associated with a Bayes net. - * - * In GTSAM a junction tree is an intermediate data structure in multifrontal - * variable elimination. Each node is a cluster of factors, along with a - * clique of variables that are eliminated all at once. In detail, every node k represents - * a clique (maximal fully connected subset) of an associated chordal graph, such as a - * chordal Bayes net resulting from elimination. - * - * The difference with the BayesTree is that a JunctionTree stores factors, whereas a - * BayesTree stores conditionals, that are the product of eliminating the factors in the - * corresponding JunctionTree cliques. - * - * The tree structure and elimination method are exactly analagous to the EliminationTree, - * except that in the JunctionTree, at each node multiple variables are eliminated at a time. - * - * \addtogroup Multifrontal - * \nosubgrouping - */ - template - class JunctionTreeUnordered { - - public: - - typedef GRAPH FactorGraphType; ///< The factor graph type - typedef typename GRAPH::FactorType FactorType; ///< The type of factors - typedef JunctionTreeUnordered This; ///< This class - typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class - typedef boost::shared_ptr sharedFactor; ///< Shared pointer to a factor - typedef BAYESTREE BayesTreeType; ///< The BayesTree type produced by elimination - typedef typename BayesTreeType::ConditionalType ConditionalType; ///< The type of conditionals - typedef boost::shared_ptr sharedConditional; ///< Shared pointer to a conditional - typedef typename FactorGraphType::Eliminate Eliminate; ///< Typedef for an eliminate subroutine - - struct Node { - typedef std::vector Keys; - typedef std::vector Factors; - typedef std::vector > Children; - - Keys keys; ///< Frontal keys of this node - Factors factors; ///< Factors associated with this node - Children children; ///< sub-trees - int problemSize_; - - int problemSize() const { return problemSize_; } - - /** print this node */ - void print(const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; - }; - - typedef boost::shared_ptr sharedNode; ///< Shared pointer to Node - - private: - - /** concept check */ - GTSAM_CONCEPT_TESTABLE_TYPE(FactorType); - - std::vector roots_; - std::vector remainingFactors_; - - protected: - - /// @name Standard Constructors - /// @{ - - /** Build the junction tree from an elimination tree. */ - template - static This FromEliminationTree(const ETREE& eliminationTree); - - /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are - * copied, factors are not cloned. */ - JunctionTreeUnordered(const This& other) { *this = other; } - - /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors - * are copied, factors are not cloned. */ - This& operator=(const This& other); - - /// @} - - public: - - /// @name Standard Interface - /// @{ - - /** Eliminate the factors to a Bayes net and remaining factor graph - * @param function The function to use to eliminate, see the namespace functions - * in GaussianFactorGraph.h - * @return The Bayes net and factor graph resulting from elimination - */ - std::pair, boost::shared_ptr > - eliminate(const Eliminate& function) const; - - /** Print the junction tree */ - void print(const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; - - /// @} - - /// @name Advanced Interface - /// @{ - - /** Return the set of roots (one for a tree, multiple for a forest) */ - const std::vector& roots() const { return roots_; } - - /** Return the remaining factors that are not pulled into elimination */ - const std::vector& remainingFactors() const { return remainingFactors_; } - - /// @} - - private: - - // Private default constructor (used in static construction methods) - JunctionTreeUnordered() {} - - }; - -} \ No newline at end of file diff --git a/gtsam/inference/OrderingUnordered.cpp b/gtsam/inference/Ordering.cpp similarity index 79% rename from gtsam/inference/OrderingUnordered.cpp rename to gtsam/inference/Ordering.cpp index e790a9055..9fe5a6105 100644 --- a/gtsam/inference/OrderingUnordered.cpp +++ b/gtsam/inference/Ordering.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include using namespace std; @@ -28,7 +28,7 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ - FastMap OrderingUnordered::invert() const + FastMap Ordering::invert() const { FastMap inverted; for(size_t pos = 0; pos < this->size(); ++pos) @@ -37,17 +37,17 @@ namespace gtsam { } /* ************************************************************************* */ - OrderingUnordered OrderingUnordered::COLAMD(const VariableIndexUnordered& variableIndex) + Ordering Ordering::COLAMD(const VariableIndex& variableIndex) { // Call constrained version with all groups set to zero - return OrderingUnordered::COLAMDConstrained(variableIndex, vector(variableIndex.size(), 0)); + return Ordering::COLAMDConstrained(variableIndex, vector(variableIndex.size(), 0)); } /* ************************************************************************* */ - OrderingUnordered OrderingUnordered::COLAMDConstrained( - const VariableIndexUnordered& variableIndex, std::vector& cmember) + Ordering Ordering::COLAMDConstrained( + const VariableIndex& variableIndex, std::vector& cmember) { - gttic(OrderingUnordered_COLAMDConstrained); + gttic(Ordering_COLAMDConstrained); gttic(Prepare); size_t nEntries = variableIndex.nEntries(), nFactors = variableIndex.nFactors(), nVars = variableIndex.size(); @@ -61,9 +61,9 @@ namespace gtsam { int count = 0; vector keys(nVars); // Array to store the keys in the order we add them so we can retrieve them in permuted order size_t index = 0; - BOOST_FOREACH(const VariableIndexUnordered::value_type key_factors, variableIndex) { + BOOST_FOREACH(const VariableIndex::value_type key_factors, variableIndex) { // Arrange factor indices into COLAMD format - const VariableIndexUnordered::Factors& column = key_factors.second; + const VariableIndex::Factors& column = key_factors.second; size_t lastFactorId = numeric_limits::max(); BOOST_FOREACH(size_t factorIndex, column) { if(lastFactorId != numeric_limits::max()) @@ -101,7 +101,7 @@ namespace gtsam { gttic(Fill_Ordering); // Convert elimination ordering in p to an ordering - OrderingUnordered result; + Ordering result; result.resize(nVars); for(size_t j = 0; j < nVars; ++j) result[j] = keys[p[j]]; @@ -111,10 +111,10 @@ namespace gtsam { } /* ************************************************************************* */ - OrderingUnordered OrderingUnordered::COLAMDConstrainedLast( - const VariableIndexUnordered& variableIndex, const std::vector& constrainLast, bool forceOrder) + Ordering Ordering::COLAMDConstrainedLast( + const VariableIndex& variableIndex, const std::vector& constrainLast, bool forceOrder) { - gttic(OrderingUnordered_COLAMDConstrainedLast); + gttic(Ordering_COLAMDConstrainedLast); size_t n = variableIndex.size(); std::vector cmember(n, 0); @@ -122,7 +122,7 @@ namespace gtsam { // Build a mapping to look up sorted Key indices by Key FastMap keyIndices; size_t j = 0; - BOOST_FOREACH(const VariableIndexUnordered::value_type key_factors, variableIndex) + BOOST_FOREACH(const VariableIndex::value_type key_factors, variableIndex) keyIndices.insert(keyIndices.end(), make_pair(key_factors.first, j++)); // If at least some variables are not constrained to be last, constrain the @@ -134,7 +134,7 @@ namespace gtsam { ++ group; } - return OrderingUnordered::COLAMDConstrained(variableIndex, cmember); + return Ordering::COLAMDConstrained(variableIndex, cmember); } } diff --git a/gtsam/inference/OrderingUnordered.h b/gtsam/inference/Ordering.h similarity index 56% rename from gtsam/inference/OrderingUnordered.h rename to gtsam/inference/Ordering.h index 9874421be..c737c2743 100644 --- a/gtsam/inference/OrderingUnordered.h +++ b/gtsam/inference/Ordering.h @@ -20,45 +20,45 @@ #include #include -#include -#include +#include +#include namespace gtsam { - class OrderingUnordered : public std::vector { + class Ordering : public std::vector { protected: typedef std::vector Base; public: /// Create an empty ordering - GTSAM_EXPORT OrderingUnordered() {} + GTSAM_EXPORT Ordering() {} /// Create from a container template - explicit OrderingUnordered(const KEYS& keys) : Base(keys.begin(), keys.end()) {} + explicit Ordering(const KEYS& keys) : Base(keys.begin(), keys.end()) {} /// Create an ordering using iterators over keys template - OrderingUnordered(ITERATOR firstKey, ITERATOR lastKey) : Base(firstKey, lastKey) {} + Ordering(ITERATOR firstKey, ITERATOR lastKey) : Base(firstKey, lastKey) {} /// Invert (not reverse) the ordering - returns a map from key to order position FastMap invert() const; /// Compute an ordering using COLAMD directly from a factor graph - this internally builds a /// VariableIndex so if you already have a VariableIndex, it is faster to use COLAMD(const - /// VariableIndexUnordered&) + /// VariableIndex&) template - static OrderingUnordered COLAMD(const FactorGraphUnordered& graph) { - return COLAMD(VariableIndexUnordered(graph)); + static Ordering COLAMD(const FactorGraph& graph) { + return COLAMD(VariableIndex(graph)); } - static GTSAM_EXPORT OrderingUnordered COLAMD(const VariableIndexUnordered& variableIndex); + static GTSAM_EXPORT Ordering COLAMD(const VariableIndex& variableIndex); - static GTSAM_EXPORT OrderingUnordered COLAMDConstrainedLast( - const VariableIndexUnordered& variableIndex, const std::vector& constrainLast, bool forceOrder = false); + static GTSAM_EXPORT Ordering COLAMDConstrainedLast( + const VariableIndex& variableIndex, const std::vector& constrainLast, bool forceOrder = false); private: - static GTSAM_EXPORT OrderingUnordered COLAMDConstrained( - const VariableIndexUnordered& variableIndex, + static GTSAM_EXPORT Ordering COLAMDConstrained( + const VariableIndex& variableIndex, std::vector& cmember); }; } diff --git a/gtsam/inference/Permutation.cpp b/gtsam/inference/PermutationOrdered.cpp similarity index 99% rename from gtsam/inference/Permutation.cpp rename to gtsam/inference/PermutationOrdered.cpp index 94528f64f..e8e510568 100644 --- a/gtsam/inference/Permutation.cpp +++ b/gtsam/inference/PermutationOrdered.cpp @@ -15,7 +15,7 @@ * @date Oct 9, 2010 */ -#include +#include #include #include diff --git a/gtsam/inference/Permutation.h b/gtsam/inference/PermutationOrdered.h similarity index 100% rename from gtsam/inference/Permutation.h rename to gtsam/inference/PermutationOrdered.h diff --git a/gtsam/inference/SymbolicFactorGraph.cpp b/gtsam/inference/SymbolicFactorGraph.cpp deleted file mode 100644 index 7f71ab54a..000000000 --- a/gtsam/inference/SymbolicFactorGraph.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file SymbolicFactorGraph.cpp - * @date Oct 29, 2009 - * @author Frank Dellaert - */ - -#include -#include -#include -#include - -#include - -namespace gtsam { - - using namespace std; - - /* ************************************************************************* */ - SymbolicFactorGraph::SymbolicFactorGraph(const SymbolicBayesNet& bayesNet) : - FactorGraph(bayesNet) {} - - /* ************************************************************************* */ - SymbolicFactorGraph::SymbolicFactorGraph(const SymbolicBayesTree& bayesTree) : - FactorGraph(bayesTree) {} - - /* ************************************************************************* */ - void SymbolicFactorGraph::push_factor(Index key) { - push_back(boost::make_shared(key)); - } - - /** Push back binary factor */ - void SymbolicFactorGraph::push_factor(Index key1, Index key2) { - push_back(boost::make_shared(key1,key2)); - } - - /** Push back ternary factor */ - void SymbolicFactorGraph::push_factor(Index key1, Index key2, Index key3) { - push_back(boost::make_shared(key1,key2,key3)); - } - - /** Push back 4-way factor */ - void SymbolicFactorGraph::push_factor(Index key1, Index key2, Index key3, Index key4) { - push_back(boost::make_shared(key1,key2,key3,key4)); - } - - /* ************************************************************************* */ - FastSet - SymbolicFactorGraph::keys() const { - FastSet keys; - BOOST_FOREACH(const sharedFactor& factor, *this) { - if(factor) keys.insert(factor->begin(), factor->end()); } - return keys; - } - - /* ************************************************************************* */ - std::pair - SymbolicFactorGraph::eliminateFrontals(size_t nFrontals) const - { - return FactorGraph::eliminateFrontals(nFrontals, EliminateSymbolic); - } - - /* ************************************************************************* */ - std::pair - SymbolicFactorGraph::eliminate(const std::vector& variables) const - { - return FactorGraph::eliminate(variables, EliminateSymbolic); - } - - /* ************************************************************************* */ - std::pair - SymbolicFactorGraph::eliminateOne(Index variable) const - { - return FactorGraph::eliminateOne(variable, EliminateSymbolic); - } - - /* ************************************************************************* */ - void SymbolicFactorGraph::permuteWithInverse( - const Permutation& inversePermutation) { - BOOST_FOREACH(const sharedFactor& factor, factors_) { - if(factor) - factor->permuteWithInverse(inversePermutation); - } - } - - /* ************************************************************************* */ - void SymbolicFactorGraph::reduceWithInverse( - const internal::Reduction& inverseReduction) { - BOOST_FOREACH(const sharedFactor& factor, factors_) { - if(factor) - factor->reduceWithInverse(inverseReduction); - } - } - - /* ************************************************************************* */ - IndexFactor::shared_ptr CombineSymbolic( - const FactorGraph& factors, const FastMap >& variableSlots) { - IndexFactor::shared_ptr combined(Combine (factors, variableSlots)); -// combined->assertInvariants(); - return combined; - } - - /* ************************************************************************* */ - pair // - EliminateSymbolic(const FactorGraph& factors, size_t nrFrontals) { - - FastSet keys; - BOOST_FOREACH(const IndexFactor::shared_ptr& factor, factors) - BOOST_FOREACH(Index var, *factor) - keys.insert(var); - - if (keys.size() < nrFrontals) throw invalid_argument( - "EliminateSymbolic requested to eliminate more variables than exist in graph."); - - vector newKeys(keys.begin(), keys.end()); - return make_pair(boost::make_shared(newKeys, nrFrontals), - boost::make_shared(newKeys.begin() + nrFrontals, newKeys.end())); - } - - /* ************************************************************************* */ -} diff --git a/gtsam/inference/SymbolicFactorGraphOrdered.cpp b/gtsam/inference/SymbolicFactorGraphOrdered.cpp new file mode 100644 index 000000000..76c1e42fb --- /dev/null +++ b/gtsam/inference/SymbolicFactorGraphOrdered.cpp @@ -0,0 +1,132 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file SymbolicFactorGraph.cpp + * @date Oct 29, 2009 + * @author Frank Dellaert + */ + +#include +#include +#include +#include + +#include + +namespace gtsam { + + using namespace std; + + /* ************************************************************************* */ + SymbolicFactorGraphOrdered::SymbolicFactorGraphOrdered(const SymbolicBayesNetOrdered& bayesNet) : + FactorGraphOrdered(bayesNet) {} + + /* ************************************************************************* */ + SymbolicFactorGraphOrdered::SymbolicFactorGraphOrdered(const SymbolicBayesTreeOrdered& bayesTree) : + FactorGraphOrdered(bayesTree) {} + + /* ************************************************************************* */ + void SymbolicFactorGraphOrdered::push_factor(Index key) { + push_back(boost::make_shared(key)); + } + + /** Push back binary factor */ + void SymbolicFactorGraphOrdered::push_factor(Index key1, Index key2) { + push_back(boost::make_shared(key1,key2)); + } + + /** Push back ternary factor */ + void SymbolicFactorGraphOrdered::push_factor(Index key1, Index key2, Index key3) { + push_back(boost::make_shared(key1,key2,key3)); + } + + /** Push back 4-way factor */ + void SymbolicFactorGraphOrdered::push_factor(Index key1, Index key2, Index key3, Index key4) { + push_back(boost::make_shared(key1,key2,key3,key4)); + } + + /* ************************************************************************* */ + FastSet + SymbolicFactorGraphOrdered::keys() const { + FastSet keys; + BOOST_FOREACH(const sharedFactor& factor, *this) { + if(factor) keys.insert(factor->begin(), factor->end()); } + return keys; + } + + /* ************************************************************************* */ + std::pair + SymbolicFactorGraphOrdered::eliminateFrontals(size_t nFrontals) const + { + return FactorGraphOrdered::eliminateFrontals(nFrontals, EliminateSymbolic); + } + + /* ************************************************************************* */ + std::pair + SymbolicFactorGraphOrdered::eliminate(const std::vector& variables) const + { + return FactorGraphOrdered::eliminate(variables, EliminateSymbolic); + } + + /* ************************************************************************* */ + std::pair + SymbolicFactorGraphOrdered::eliminateOne(Index variable) const + { + return FactorGraphOrdered::eliminateOne(variable, EliminateSymbolic); + } + + /* ************************************************************************* */ + void SymbolicFactorGraphOrdered::permuteWithInverse( + const Permutation& inversePermutation) { + BOOST_FOREACH(const sharedFactor& factor, factors_) { + if(factor) + factor->permuteWithInverse(inversePermutation); + } + } + + /* ************************************************************************* */ + void SymbolicFactorGraphOrdered::reduceWithInverse( + const internal::Reduction& inverseReduction) { + BOOST_FOREACH(const sharedFactor& factor, factors_) { + if(factor) + factor->reduceWithInverse(inverseReduction); + } + } + + /* ************************************************************************* */ + IndexFactorOrdered::shared_ptr CombineSymbolic( + const FactorGraphOrdered& factors, const FastMap >& variableSlots) { + IndexFactorOrdered::shared_ptr combined(Combine (factors, variableSlots)); +// combined->assertInvariants(); + return combined; + } + + /* ************************************************************************* */ + pair // + EliminateSymbolic(const FactorGraphOrdered& factors, size_t nrFrontals) { + + FastSet keys; + BOOST_FOREACH(const IndexFactorOrdered::shared_ptr& factor, factors) + BOOST_FOREACH(Index var, *factor) + keys.insert(var); + + if (keys.size() < nrFrontals) throw invalid_argument( + "EliminateSymbolic requested to eliminate more variables than exist in graph."); + + vector newKeys(keys.begin(), keys.end()); + return make_pair(boost::make_shared(newKeys, nrFrontals), + boost::make_shared(newKeys.begin() + nrFrontals, newKeys.end())); + } + + /* ************************************************************************* */ +} diff --git a/gtsam/inference/SymbolicFactorGraph.h b/gtsam/inference/SymbolicFactorGraphOrdered.h similarity index 72% rename from gtsam/inference/SymbolicFactorGraph.h rename to gtsam/inference/SymbolicFactorGraphOrdered.h index 31e2b2b88..97ef21810 100644 --- a/gtsam/inference/SymbolicFactorGraph.h +++ b/gtsam/inference/SymbolicFactorGraphOrdered.h @@ -18,24 +18,24 @@ #pragma once #include -#include -#include +#include +#include -namespace gtsam { template class EliminationTree; } -namespace gtsam { template class BayesNet; } -namespace gtsam { template class BayesTree; } -namespace gtsam { class IndexConditional; } +namespace gtsam { template class EliminationTreeOrdered; } +namespace gtsam { template class BayesNetOrdered; } +namespace gtsam { template class BayesTreeOrdered; } +namespace gtsam { class IndexConditionalOrdered; } namespace gtsam { - typedef EliminationTree SymbolicEliminationTree; - typedef BayesNet SymbolicBayesNet; - typedef BayesTree SymbolicBayesTree; + typedef EliminationTreeOrdered SymbolicEliminationTreeOrdered; + typedef BayesNetOrdered SymbolicBayesNetOrdered; + typedef BayesTreeOrdered SymbolicBayesTreeOrdered; /** Symbolic IndexFactor Graph * \nosubgrouping */ - class SymbolicFactorGraph: public FactorGraph { + class SymbolicFactorGraphOrdered: public FactorGraphOrdered { public: @@ -43,29 +43,29 @@ namespace gtsam { /// @{ /** Construct empty factor graph */ - SymbolicFactorGraph() { + SymbolicFactorGraphOrdered() { } /** Construct from a BayesNet */ - GTSAM_EXPORT SymbolicFactorGraph(const SymbolicBayesNet& bayesNet); + GTSAM_EXPORT SymbolicFactorGraphOrdered(const SymbolicBayesNetOrdered& bayesNet); /** Construct from a BayesTree */ - GTSAM_EXPORT SymbolicFactorGraph(const SymbolicBayesTree& bayesTree); + GTSAM_EXPORT SymbolicFactorGraphOrdered(const SymbolicBayesTreeOrdered& bayesTree); /** * Construct from a factor graph of any type */ template - SymbolicFactorGraph(const FactorGraph& fg); - - /** Eliminate the first \c n frontal variables, returning the resulting - * conditional and remaining factor graph - this is very inefficient for - * eliminating all variables, to do that use EliminationTree or - * JunctionTree. Note that this version simply calls - * FactorGraph::eliminateFrontals with EliminateSymbolic - * as the eliminate function argument. - */ - GTSAM_EXPORT std::pair eliminateFrontals(size_t nFrontals) const; + SymbolicFactorGraphOrdered(const FactorGraphOrdered& fg); + + /** Eliminate the first \c n frontal variables, returning the resulting + * conditional and remaining factor graph - this is very inefficient for + * eliminating all variables, to do that use EliminationTree or + * JunctionTree. Note that this version simply calls + * FactorGraph::eliminateFrontals with EliminateSymbolic + * as the eliminate function argument. + */ + GTSAM_EXPORT std::pair eliminateFrontals(size_t nFrontals) const; /** Factor the factor graph into a conditional and a remaining factor graph. * Given the factor graph \f$ f(X) \f$, and \c variables to factorize out @@ -79,14 +79,14 @@ namespace gtsam { * conditional on all of the variables in \c variables, instead of a sparse * BayesNet. If the variables are not fully-connected, it is more efficient * to sequentially factorize multiple times. - * Note that this version simply calls + * Note that this version simply calls * FactorGraph::eliminate with EliminateSymbolic as the eliminate * function argument. */ - GTSAM_EXPORT std::pair eliminate(const std::vector& variables) const; + GTSAM_EXPORT std::pair eliminate(const std::vector& variables) const; /** Eliminate a single variable, by calling SymbolicFactorGraph::eliminate. */ - GTSAM_EXPORT std::pair eliminateOne(Index variable) const; + GTSAM_EXPORT std::pair eliminateOne(Index variable) const; /// @} /// @name Standard Interface @@ -113,17 +113,17 @@ namespace gtsam { /** Push back 4-way factor */ GTSAM_EXPORT void push_factor(Index key1, Index key2, Index key3, Index key4); - - /** Permute the variables in the factors */ - GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation); - + + /** Permute the variables in the factors */ + GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation); + /** Apply a reduction, which is a remapping of variable indices. */ GTSAM_EXPORT void reduceWithInverse(const internal::Reduction& inverseReduction); }; /** Create a combined joint factor (new style for EliminationTree). */ - GTSAM_EXPORT IndexFactor::shared_ptr CombineSymbolic(const FactorGraph& factors, + GTSAM_EXPORT IndexFactorOrdered::shared_ptr CombineSymbolic(const FactorGraphOrdered& factors, const FastMap >& variableSlots); /** @@ -131,20 +131,20 @@ namespace gtsam { * Combine and eliminate can also be called separately, but for this and * derived classes calling them separately generally does extra work. */ - GTSAM_EXPORT std::pair, boost::shared_ptr > - EliminateSymbolic(const FactorGraph&, size_t nrFrontals = 1); + GTSAM_EXPORT std::pair, boost::shared_ptr > + EliminateSymbolic(const FactorGraphOrdered&, size_t nrFrontals = 1); /// @} /** Template function implementation */ template - SymbolicFactorGraph::SymbolicFactorGraph(const FactorGraph& fg) { + SymbolicFactorGraphOrdered::SymbolicFactorGraphOrdered(const FactorGraphOrdered& fg) { for (size_t i = 0; i < fg.size(); i++) { if (fg[i]) { - IndexFactor::shared_ptr factor(new IndexFactor(*fg[i])); + IndexFactorOrdered::shared_ptr factor(new IndexFactorOrdered(*fg[i])); push_back(factor); } else - push_back(IndexFactor::shared_ptr()); + push_back(IndexFactorOrdered::shared_ptr()); } } diff --git a/gtsam/inference/SymbolicMultifrontalSolver.cpp b/gtsam/inference/SymbolicMultifrontalSolverOrdered.cpp similarity index 84% rename from gtsam/inference/SymbolicMultifrontalSolver.cpp rename to gtsam/inference/SymbolicMultifrontalSolverOrdered.cpp index 7072954a9..b1e142d4b 100644 --- a/gtsam/inference/SymbolicMultifrontalSolver.cpp +++ b/gtsam/inference/SymbolicMultifrontalSolverOrdered.cpp @@ -15,8 +15,8 @@ * @date Oct 22, 2010 */ -#include -#include +#include +#include namespace gtsam { diff --git a/gtsam/inference/SymbolicMultifrontalSolver.h b/gtsam/inference/SymbolicMultifrontalSolverOrdered.h similarity index 66% rename from gtsam/inference/SymbolicMultifrontalSolver.h rename to gtsam/inference/SymbolicMultifrontalSolverOrdered.h index 802b10d72..fc36c3388 100644 --- a/gtsam/inference/SymbolicMultifrontalSolver.h +++ b/gtsam/inference/SymbolicMultifrontalSolverOrdered.h @@ -18,14 +18,14 @@ #pragma once #include -#include +#include namespace gtsam { - class SymbolicMultifrontalSolver : GenericMultifrontalSolver > > { + class SymbolicMultifrontalSolver : GenericMultifrontalSolver > > { protected: - typedef GenericMultifrontalSolver > > Base; + typedef GenericMultifrontalSolver > > Base; public: /** @@ -33,15 +33,15 @@ namespace gtsam { * tree, which does the symbolic elimination, identifies the cliques, * and distributes all the factors to the right cliques. */ - SymbolicMultifrontalSolver(const SymbolicFactorGraph& factorGraph) : Base(factorGraph) {}; + SymbolicMultifrontalSolver(const SymbolicFactorGraphOrdered& factorGraph) : Base(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. */ - SymbolicMultifrontalSolver(const SymbolicFactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex) : Base(factorGraph, variableIndex) {}; + SymbolicMultifrontalSolver(const SymbolicFactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex) : Base(factorGraph, variableIndex) {}; /** Print to cout */ void print(const std::string& name = "SymbolicMultifrontalSolver: ") const { Base::print(name); }; @@ -53,19 +53,19 @@ namespace gtsam { * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. */ - SymbolicBayesTree::shared_ptr eliminate() const { return Base::eliminate(&EliminateSymbolic); }; + SymbolicBayesTreeOrdered::shared_ptr eliminate() const { return Base::eliminate(&EliminateSymbolic); }; /** * Compute the marginal joint over a set of variables, by integrating out * all of the other variables. Returns the result as a factor graph. */ - SymbolicFactorGraph::shared_ptr jointFactorGraph(const std::vector& js) const { return Base::jointFactorGraph(js, &EliminateSymbolic); }; + SymbolicFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector& js) const { return Base::jointFactorGraph(js, &EliminateSymbolic); }; /** * Compute the marginal Gaussian density over a variable, by integrating out * all of the other variables. This function returns the result as a factor. */ - IndexFactor::shared_ptr marginalFactor(Index j) const { return Base::marginalFactor(j, &EliminateSymbolic); }; + IndexFactorOrdered::shared_ptr marginalFactor(Index j) const { return Base::marginalFactor(j, &EliminateSymbolic); }; }; } diff --git a/gtsam/inference/SymbolicSequentialSolver.cpp b/gtsam/inference/SymbolicSequentialSolverOrdered.cpp similarity index 91% rename from gtsam/inference/SymbolicSequentialSolver.cpp rename to gtsam/inference/SymbolicSequentialSolverOrdered.cpp index 937623886..0c4fc8386 100644 --- a/gtsam/inference/SymbolicSequentialSolver.cpp +++ b/gtsam/inference/SymbolicSequentialSolverOrdered.cpp @@ -15,7 +15,7 @@ * @date Oct 21, 2010 */ -#include +#include #include namespace gtsam { diff --git a/gtsam/inference/SymbolicSequentialSolver.h b/gtsam/inference/SymbolicSequentialSolverOrdered.h similarity index 73% rename from gtsam/inference/SymbolicSequentialSolver.h rename to gtsam/inference/SymbolicSequentialSolverOrdered.h index 5bff88430..2bf245e81 100644 --- a/gtsam/inference/SymbolicSequentialSolver.h +++ b/gtsam/inference/SymbolicSequentialSolverOrdered.h @@ -17,14 +17,14 @@ #pragma once #include -#include +#include namespace gtsam { - class SymbolicSequentialSolver : GenericSequentialSolver { + class SymbolicSequentialSolver : GenericSequentialSolver { protected: - typedef GenericSequentialSolver Base; + typedef GenericSequentialSolver Base; public: /** @@ -32,15 +32,15 @@ namespace gtsam { * tree, which does the symbolic elimination, identifies the cliques, * and distributes all the factors to the right cliques. */ - SymbolicSequentialSolver(const SymbolicFactorGraph& factorGraph) : Base(factorGraph) {}; + SymbolicSequentialSolver(const SymbolicFactorGraphOrdered& factorGraph) : Base(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. */ - SymbolicSequentialSolver(const SymbolicFactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex) : Base(factorGraph, variableIndex) {}; + SymbolicSequentialSolver(const SymbolicFactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex) : Base(factorGraph, variableIndex) {}; /** Print to cout */ void print(const std::string& name = "SymbolicSequentialSolver: ") const { Base::print(name); }; @@ -52,7 +52,7 @@ namespace gtsam { * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. */ - SymbolicBayesNet::shared_ptr eliminate() const + SymbolicBayesNetOrdered::shared_ptr eliminate() const { return Base::eliminate(&EliminateSymbolic); }; /** @@ -60,28 +60,28 @@ namespace gtsam { * P(F|S) is obtained by P(J,F,S)=P(J|F,S)P(F|S)P(S) and dropping P(S) * Returns the result as a Bayes net. */ - SymbolicBayesNet::shared_ptr conditionalBayesNet(const std::vector& js, size_t nrFrontals) const + SymbolicBayesNetOrdered::shared_ptr conditionalBayesNet(const std::vector& js, size_t nrFrontals) const { return Base::conditionalBayesNet(js, nrFrontals, &EliminateSymbolic); }; /** * Compute the marginal joint over a set of variables, by integrating out * all of the other variables. Returns the result as a Bayes net. */ - SymbolicBayesNet::shared_ptr jointBayesNet(const std::vector& js) const + SymbolicBayesNetOrdered::shared_ptr jointBayesNet(const std::vector& js) const { return Base::jointBayesNet(js, &EliminateSymbolic); }; /** * Compute the marginal joint over a set of variables, by integrating out * all of the other variables. Returns the result as a factor graph. */ - SymbolicFactorGraph::shared_ptr jointFactorGraph(const std::vector& js) const + SymbolicFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector& js) const { return Base::jointFactorGraph(js, &EliminateSymbolic); }; /** * Compute the marginal Gaussian density over a variable, by integrating out * all of the other variables. This function returns the result as a factor. */ - IndexFactor::shared_ptr marginalFactor(Index j) const { return Base::marginalFactor(j, &EliminateSymbolic); }; + IndexFactorOrdered::shared_ptr marginalFactor(Index j) const { return Base::marginalFactor(j, &EliminateSymbolic); }; }; } diff --git a/gtsam/inference/VariableIndexUnordered-inl.h b/gtsam/inference/VariableIndex-inl.h similarity index 89% rename from gtsam/inference/VariableIndexUnordered-inl.h rename to gtsam/inference/VariableIndex-inl.h index 480e42fee..1ce108321 100644 --- a/gtsam/inference/VariableIndexUnordered-inl.h +++ b/gtsam/inference/VariableIndex-inl.h @@ -17,13 +17,13 @@ #pragma once -#include +#include namespace gtsam { /* ************************************************************************* */ template -void VariableIndexUnordered::augment(const FG& factors) +void VariableIndex::augment(const FG& factors) { gttic(VariableIndex_augment); @@ -45,7 +45,7 @@ void VariableIndexUnordered::augment(const FG& factors) /* ************************************************************************* */ template -void VariableIndexUnordered::remove(ITERATOR firstFactor, ITERATOR lastFactor, const FG& factors) +void VariableIndex::remove(ITERATOR firstFactor, ITERATOR lastFactor, const FG& factors) { gttic(VariableIndex_remove); @@ -73,7 +73,7 @@ void VariableIndexUnordered::remove(ITERATOR firstFactor, ITERATOR lastFactor, c /* ************************************************************************* */ template -void VariableIndexUnordered::removeUnusedVariables(ITERATOR firstKey, ITERATOR lastKey) { +void VariableIndex::removeUnusedVariables(ITERATOR firstKey, ITERATOR lastKey) { for(ITERATOR key = firstKey; key != lastKey; ++key) { assert(internalAt(*key).empty()); index_.erase(*key); diff --git a/gtsam/inference/VariableIndex.cpp b/gtsam/inference/VariableIndex.cpp index 91036e82a..26ba191dd 100644 --- a/gtsam/inference/VariableIndex.cpp +++ b/gtsam/inference/VariableIndex.cpp @@ -1,104 +1,58 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VariableIndex.cpp - * @author Richard Roberts - * @date Oct 22, 2010 - */ - -#include - -#include -#include - -namespace gtsam { - -using namespace std; - -/* ************************************************************************* */ -bool VariableIndex::equals(const VariableIndex& other, double tol) const { - if(this->nEntries_ == other.nEntries_ && this->nFactors_ == other.nFactors_) { - for(size_t var=0; var < max(this->index_.size(), other.index_.size()); ++var) - if(var >= this->index_.size() || var >= other.index_.size()) { - if(!((var >= this->index_.size() && other.index_[var].empty()) || - (var >= other.index_.size() && this->index_[var].empty()))) - return false; - } else if(this->index_[var] != other.index_[var]) - return false; - } else - return false; - return true; -} - -/* ************************************************************************* */ -void VariableIndex::print(const string& str) const { - cout << str; - cout << "nEntries = " << nEntries() << ", nFactors = " << nFactors() << "\n"; - for(Index var = 0; var < size(); ++var) { - cout << "var " << var << ":"; - BOOST_FOREACH(const size_t factor, index_[var]) - cout << " " << factor; - cout << "\n"; - } - cout << flush; -} - -/* ************************************************************************* */ -void VariableIndex::outputMetisFormat(ostream& os) const { - os << size() << " " << nFactors() << "\n"; - // run over variables, which will be hyper-edges. - BOOST_FOREACH(const Factors& variable, index_) { - // every variable is a hyper-edge covering its factors - BOOST_FOREACH(const size_t factor, variable) - os << (factor+1) << " "; // base 1 - os << "\n"; - } - os << flush; -} - -/* ************************************************************************* */ -void VariableIndex::permuteInPlace(const Permutation& permutation) { - // Create new index and move references to data into it in permuted order - vector newIndex(this->size()); - for(Index i = 0; i < newIndex.size(); ++i) - newIndex[i].swap(this->index_[permutation[i]]); - - // Move reference to entire index into the VariableIndex - index_.swap(newIndex); -} - -/* ************************************************************************* */ -void VariableIndex::permuteInPlace(const Permutation& selector, const Permutation& permutation) { - if(selector.size() != permutation.size()) - throw invalid_argument("VariableIndex::permuteInPlace (partial permutation version) called with selector and permutation of different sizes."); - // Create new index the size of the permuted entries - vector newIndex(selector.size()); - // Permute the affected entries into the new index - for(size_t dstSlot = 0; dstSlot < selector.size(); ++dstSlot) - newIndex[dstSlot].swap(this->index_[selector[permutation[dstSlot]]]); - // Put the affected entries back in the new order - for(size_t slot = 0; slot < selector.size(); ++slot) - this->index_[selector[slot]].swap(newIndex[slot]); -} - -/* ************************************************************************* */ -void VariableIndex::removeUnusedAtEnd(size_t nToRemove) { -#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS - for(size_t i = this->size() - nToRemove; i < this->size(); ++i) - if(!(*this)[i].empty()) - throw std::invalid_argument("Attempting to remove non-empty variables with VariableIndex::removeUnusedAtEnd()"); -#endif - - index_.resize(this->size() - nToRemove); -} - -} +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VariableIndex.cpp + * @author Richard Roberts + * @date March 26, 2013 + */ + +#include + +#include + +namespace gtsam { + +using namespace std; + +/* ************************************************************************* */ +bool VariableIndex::equals(const VariableIndex& other, double tol) const { + return this->nEntries_ == other.nEntries_ && this->nFactors_ == other.nFactors_ + && this->index_ == other.index_; +} + +/* ************************************************************************* */ +void VariableIndex::print(const string& str) const { + cout << str; + cout << "nEntries = " << nEntries() << ", nFactors = " << nFactors() << "\n"; + BOOST_FOREACH(KeyMap::value_type key_factors, index_) { + cout << "var " << key_factors.first << ":"; + BOOST_FOREACH(const size_t factor, key_factors.second) + cout << " " << factor; + cout << "\n"; + } + cout.flush(); +} + +/* ************************************************************************* */ +void VariableIndex::outputMetisFormat(ostream& os) const { + os << size() << " " << nFactors() << "\n"; + // run over variables, which will be hyper-edges. + BOOST_FOREACH(KeyMap::value_type key_factors, index_) { + // every variable is a hyper-edge covering its factors + BOOST_FOREACH(const size_t factor, key_factors.second) + os << (factor+1) << " "; // base 1 + os << "\n"; + } + os << flush; +} + +} diff --git a/gtsam/inference/VariableIndex.h b/gtsam/inference/VariableIndex.h index 570369e0a..4733ca59c 100644 --- a/gtsam/inference/VariableIndex.h +++ b/gtsam/inference/VariableIndex.h @@ -1,292 +1,182 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VariableIndex.h - * @author Richard Roberts - * @date Sep 12, 2010 - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace gtsam { - - class Permutation; - -/** - * The VariableIndex class computes and stores the block column structure of a - * factor graph. The factor graph stores a collection of factors, each of - * which involves a set of variables. In contrast, the VariableIndex is built - * from a factor graph prior to elimination, and stores the list of factors - * that involve each variable. This information is stored as a deque of - * lists of factor indices. - * \nosubgrouping - */ -class GTSAM_EXPORT VariableIndex { -public: - - typedef boost::shared_ptr shared_ptr; - typedef FastList Factors; - typedef Factors::iterator Factor_iterator; - typedef Factors::const_iterator Factor_const_iterator; - -protected: - std::vector index_; - size_t nFactors_; // Number of factors in the original factor graph. - size_t nEntries_; // Sum of involved variable counts of each factor. - -public: - - /// @name Standard Constructors - /// @{ - - /** Default constructor, creates an empty VariableIndex */ - VariableIndex() : nFactors_(0), nEntries_(0) {} - - /** - * Create a VariableIndex that computes and stores the block column structure - * of a factor graph. This constructor is used when the number of variables - * is known beforehand. - */ - template VariableIndex(const FG& factorGraph, Index nVariables); - - /** - * Create a VariableIndex that computes and stores the block column structure - * of a factor graph. - */ - template VariableIndex(const FG& factorGraph); - - /// @} - /// @name Standard Interface - /// @{ - - /** - * The number of variable entries. This is one greater than the variable - * with the highest index. - */ - Index size() const { return index_.size(); } - - /** The number of factors in the original factor graph */ - size_t nFactors() const { return nFactors_; } - - /** The number of nonzero blocks, i.e. the number of variable-factor entries */ - size_t nEntries() const { return nEntries_; } - - /** Access a list of factors by variable */ - const Factors& operator[](Index variable) const { checkVar(variable); return index_[variable]; } - - /// @} - /// @name Testable - /// @{ - - /** Test for equality (for unit tests and debug assertions). */ - bool equals(const VariableIndex& other, double tol=0.0) const; - - /** Print the variable index (for unit tests and debugging). */ - void print(const std::string& str = "VariableIndex: ") const; - - /** - * Output dual hypergraph to Metis file format for use with hmetis - * In the dual graph, variables are hyperedges, factors are nodes. - */ - void outputMetisFormat(std::ostream& os) const; - - - /// @} - /// @name Advanced Interface - /// @{ - - /** - * Augment the variable index with new factors. This can be used when - * solving problems incrementally. - */ - template void augment(const FG& factors); - - /** - * Remove entries corresponding to the specified factors. - * NOTE: We intentionally do not decrement nFactors_ because the factor - * indices need to remain consistent. Removing factors from a factor graph - * does not shift the indices of other factors. Also, we keep nFactors_ - * one greater than the highest-numbered factor referenced in a VariableIndex. - * - * @param indices The indices of the factors to remove, which must match \c factors - * @param factors The factors being removed, which must symbolically correspond - * exactly to the factors with the specified \c indices that were added. - */ - template void remove(const CONTAINER& indices, const FG& factors); - - /// Permute the variables in the VariableIndex according to the given permutation - void permuteInPlace(const Permutation& permutation); - - /// Permute the variables in the VariableIndex according to the given partial permutation - void permuteInPlace(const Permutation& selector, const Permutation& permutation); - - /** Remove unused empty variables at the end of the ordering (in debug mode - * verifies they are empty). - * @param nToRemove The number of unused variables at the end to remove - */ - void removeUnusedAtEnd(size_t nToRemove); - -protected: - Factor_iterator factorsBegin(Index variable) { checkVar(variable); return index_[variable].begin(); } - Factor_iterator factorsEnd(Index variable) { checkVar(variable); return index_[variable].end(); } - - Factor_const_iterator factorsBegin(Index variable) const { checkVar(variable); return index_[variable].begin(); } - Factor_const_iterator factorsEnd(Index variable) const { checkVar(variable); return index_[variable].end(); } - - /// Internal constructor to allocate a VariableIndex of the requested size - VariableIndex(size_t nVars) : index_(nVars), nFactors_(0), nEntries_(0) {} - - /// Internal check of the validity of a variable - void checkVar(Index variable) const { assert(variable < index_.size()); } - - /// Internal function to populate the variable index from a factor graph - template void fill(const FG& factorGraph); - - /// @} - -private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(index_); - ar & BOOST_SERIALIZATION_NVP(nFactors_); - ar & BOOST_SERIALIZATION_NVP(nEntries_); - } -}; - -/* ************************************************************************* */ -template -void VariableIndex::fill(const FG& factorGraph) { - gttic(VariableIndex_fill); - // Build index mapping from variable id to factor index - for(size_t fi=0; fikeys()) { - if(key < index_.size()) { - index_[key].push_back(fi); - ++ nEntries_; - } - } - } - ++ nFactors_; // Increment factor count even if factors are null, to keep indices consistent - } -} - -/* ************************************************************************* */ -template -VariableIndex::VariableIndex(const FG& factorGraph) : - nFactors_(0), nEntries_(0) -{ - gttic(VariableIndex_constructor); - // If the factor graph is empty, return an empty index because inside this - // if block we assume at least one factor. - if(factorGraph.size() > 0) { - gttic(VariableIndex_constructor_find_highest); - // Find highest-numbered variable - Index maxVar = 0; - BOOST_FOREACH(const typename FG::sharedFactor& factor, factorGraph) { - if(factor) { - BOOST_FOREACH(const Index key, factor->keys()) { - if(key > maxVar) - maxVar = key; - } - } - } - gttoc(VariableIndex_constructor_find_highest); - - // Allocate array - gttic(VariableIndex_constructor_allocate); - index_.resize(maxVar+1); - gttoc(VariableIndex_constructor_allocate); - - fill(factorGraph); - } -} - -/* ************************************************************************* */ -template -VariableIndex::VariableIndex(const FG& factorGraph, Index nVariables) : - nFactors_(0), nEntries_(0) -{ - gttic(VariableIndex_constructor_allocate); - index_.resize(nVariables); - gttoc(VariableIndex_constructor_allocate); - fill(factorGraph); -} - -/* ************************************************************************* */ -template -void VariableIndex::augment(const FG& factors) { - gttic(VariableIndex_augment); - // If the factor graph is empty, return an empty index because inside this - // if block we assume at least one factor. - if(factors.size() > 0) { - // Find highest-numbered variable - Index maxVar = 0; - BOOST_FOREACH(const typename FG::sharedFactor& factor, factors) { - if(factor) { - BOOST_FOREACH(const Index key, factor->keys()) { - if(key > maxVar) - maxVar = key; - } - } - } - - // Allocate index - index_.resize(std::max(index_.size(), maxVar+1)); - - // Augment index mapping from variable id to factor index - size_t orignFactors = nFactors_; - for(size_t fi=0; fikeys()) { - index_[key].push_back(orignFactors + fi); - ++ nEntries_; - } - } - ++ nFactors_; // Increment factor count even if factors are null, to keep indices consistent - } - } -} - -/* ************************************************************************* */ -template -void VariableIndex::remove(const CONTAINER& indices, const FG& factors) { - gttic(VariableIndex_remove); - // NOTE: We intentionally do not decrement nFactors_ because the factor - // indices need to remain consistent. Removing factors from a factor graph - // does not shift the indices of other factors. Also, we keep nFactors_ - // one greater than the highest-numbered factor referenced in a VariableIndex. - for(size_t fi=0; fikeys().size(); ++ji) { - Factors& factorEntries = index_[factors[fi]->keys()[ji]]; - Factors::iterator entry = std::find(factorEntries.begin(), factorEntries.end(), indices[fi]); - if(entry == factorEntries.end()) - throw std::invalid_argument("Internal error, indices and factors passed into VariableIndex::remove are not consistent with the existing variable index"); - factorEntries.erase(entry); - -- nEntries_; - } - } -} - -} +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VariableIndex.h + * @author Richard Roberts + * @date March 26, 2013 + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace gtsam { + +/** + * The VariableIndex class computes and stores the block column structure of a + * factor graph. The factor graph stores a collection of factors, each of + * which involves a set of variables. In contrast, the VariableIndex is built + * from a factor graph prior to elimination, and stores the list of factors + * that involve each variable. This information is stored as a deque of + * lists of factor indices. + * \nosubgrouping + */ +class GTSAM_EXPORT VariableIndex { +public: + + typedef boost::shared_ptr shared_ptr; + typedef FastList Factors; + typedef Factors::iterator Factor_iterator; + typedef Factors::const_iterator Factor_const_iterator; + +protected: + typedef FastMap KeyMap; + KeyMap index_; + size_t nFactors_; // Number of factors in the original factor graph. + size_t nEntries_; // Sum of involved variable counts of each factor. + +public: + typedef KeyMap::const_iterator const_iterator; + typedef KeyMap::const_iterator iterator; + typedef KeyMap::value_type value_type; + +public: + + /// @name Standard Constructors + /// @{ + + /** Default constructor, creates an empty VariableIndex */ + VariableIndex() : nFactors_(0), nEntries_(0) {} + + /** + * Create a VariableIndex that computes and stores the block column structure + * of a factor graph. + */ + template + VariableIndex(const FG& factorGraph) : nFactors_(0), nEntries_(0) { augment(factorGraph); } + + /// @} + /// @name Standard Interface + /// @{ + + /** + * The number of variable entries. This is one greater than the variable + * with the highest index. + */ + Index size() const { return index_.size(); } + + /** The number of factors in the original factor graph */ + size_t nFactors() const { return nFactors_; } + + /** The number of nonzero blocks, i.e. the number of variable-factor entries */ + size_t nEntries() const { return nEntries_; } + + /** Access a list of factors by variable */ + const Factors& operator[](Key variable) const { + KeyMap::const_iterator item = index_.find(variable); + if(item == index_.end()) + throw std::invalid_argument("Requested non-existent variable from VariableIndex"); + else + return item->second; + } + + /// @} + /// @name Testable + /// @{ + + /** Test for equality (for unit tests and debug assertions). */ + bool equals(const VariableIndex& other, double tol=0.0) const; + + /** Print the variable index (for unit tests and debugging). */ + void print(const std::string& str = "VariableIndex: ") const; + + /** + * Output dual hypergraph to Metis file format for use with hmetis + * In the dual graph, variables are hyperedges, factors are nodes. + */ + void outputMetisFormat(std::ostream& os) const; + + + /// @} + /// @name Advanced Interface + /// @{ + + /** + * Augment the variable index with new factors. This can be used when + * solving problems incrementally. + */ + template + void augment(const FG& factors); + + /** + * Remove entries corresponding to the specified factors. NOTE: We intentionally do not decrement + * nFactors_ because the factor indices need to remain consistent. Removing factors from a factor + * graph does not shift the indices of other factors. Also, we keep nFactors_ one greater than + * the highest-numbered factor referenced in a VariableIndex. + * + * @param indices The indices of the factors to remove, which must match \c factors + * @param factors The factors being removed, which must symbolically correspond exactly to the + * factors with the specified \c indices that were added. + */ + template + void remove(ITERATOR firstFactor, ITERATOR lastFactor, const FG& factors); + + /** Remove unused empty variables at the end of the ordering (in debug mode + * verifies they are empty). + * @param nToRemove The number of unused variables at the end to remove + */ + template + void removeUnusedVariables(ITERATOR firstKey, ITERATOR lastKey); + + /** Iterator to the first variable entry */ + const_iterator begin() const { return index_.begin(); } + + /** Iterator to the first variable entry */ + const_iterator end() const { return index_.end(); } + + /** Find the iterator for the requested variable entry */ + const_iterator find(Key key) const { return index_.find(key); } + +protected: + Factor_iterator factorsBegin(Index variable) { return internalAt(variable).begin(); } + Factor_iterator factorsEnd(Index variable) { return internalAt(variable).end(); } + + Factor_const_iterator factorsBegin(Index variable) const { return internalAt(variable).begin(); } + Factor_const_iterator factorsEnd(Index variable) const { return internalAt(variable).end(); } + + /// Internal version of 'at' that asserts existence + const Factors& internalAt(Key variable) const { + const KeyMap::const_iterator item = index_.find(variable); + assert(item != index_.end()); + return item->second; } + + /// Internal version of 'at' that asserts existence + Factors& internalAt(Key variable) { + const KeyMap::iterator item = index_.find(variable); + assert(item != index_.end()); + return item->second; } + + /// @} +}; + +} + +#include diff --git a/gtsam/inference/VariableIndexOrdered.cpp b/gtsam/inference/VariableIndexOrdered.cpp new file mode 100644 index 000000000..70b6afa70 --- /dev/null +++ b/gtsam/inference/VariableIndexOrdered.cpp @@ -0,0 +1,104 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VariableIndex.cpp + * @author Richard Roberts + * @date Oct 22, 2010 + */ + +#include + +#include +#include + +namespace gtsam { + +using namespace std; + +/* ************************************************************************* */ +bool VariableIndexOrdered::equals(const VariableIndexOrdered& other, double tol) const { + if(this->nEntries_ == other.nEntries_ && this->nFactors_ == other.nFactors_) { + for(size_t var=0; var < max(this->index_.size(), other.index_.size()); ++var) + if(var >= this->index_.size() || var >= other.index_.size()) { + if(!((var >= this->index_.size() && other.index_[var].empty()) || + (var >= other.index_.size() && this->index_[var].empty()))) + return false; + } else if(this->index_[var] != other.index_[var]) + return false; + } else + return false; + return true; +} + +/* ************************************************************************* */ +void VariableIndexOrdered::print(const string& str) const { + cout << str; + cout << "nEntries = " << nEntries() << ", nFactors = " << nFactors() << "\n"; + for(Index var = 0; var < size(); ++var) { + cout << "var " << var << ":"; + BOOST_FOREACH(const size_t factor, index_[var]) + cout << " " << factor; + cout << "\n"; + } + cout << flush; +} + +/* ************************************************************************* */ +void VariableIndexOrdered::outputMetisFormat(ostream& os) const { + os << size() << " " << nFactors() << "\n"; + // run over variables, which will be hyper-edges. + BOOST_FOREACH(const Factors& variable, index_) { + // every variable is a hyper-edge covering its factors + BOOST_FOREACH(const size_t factor, variable) + os << (factor+1) << " "; // base 1 + os << "\n"; + } + os << flush; +} + +/* ************************************************************************* */ +void VariableIndexOrdered::permuteInPlace(const Permutation& permutation) { + // Create new index and move references to data into it in permuted order + vector newIndex(this->size()); + for(Index i = 0; i < newIndex.size(); ++i) + newIndex[i].swap(this->index_[permutation[i]]); + + // Move reference to entire index into the VariableIndex + index_.swap(newIndex); +} + +/* ************************************************************************* */ +void VariableIndexOrdered::permuteInPlace(const Permutation& selector, const Permutation& permutation) { + if(selector.size() != permutation.size()) + throw invalid_argument("VariableIndex::permuteInPlace (partial permutation version) called with selector and permutation of different sizes."); + // Create new index the size of the permuted entries + vector newIndex(selector.size()); + // Permute the affected entries into the new index + for(size_t dstSlot = 0; dstSlot < selector.size(); ++dstSlot) + newIndex[dstSlot].swap(this->index_[selector[permutation[dstSlot]]]); + // Put the affected entries back in the new order + for(size_t slot = 0; slot < selector.size(); ++slot) + this->index_[selector[slot]].swap(newIndex[slot]); +} + +/* ************************************************************************* */ +void VariableIndexOrdered::removeUnusedAtEnd(size_t nToRemove) { +#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS + for(size_t i = this->size() - nToRemove; i < this->size(); ++i) + if(!(*this)[i].empty()) + throw std::invalid_argument("Attempting to remove non-empty variables with VariableIndex::removeUnusedAtEnd()"); +#endif + + index_.resize(this->size() - nToRemove); +} + +} diff --git a/gtsam/inference/VariableIndexOrdered.h b/gtsam/inference/VariableIndexOrdered.h new file mode 100644 index 000000000..cf6867dd2 --- /dev/null +++ b/gtsam/inference/VariableIndexOrdered.h @@ -0,0 +1,292 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VariableIndex.h + * @author Richard Roberts + * @date Sep 12, 2010 + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace gtsam { + + class Permutation; + +/** + * The VariableIndex class computes and stores the block column structure of a + * factor graph. The factor graph stores a collection of factors, each of + * which involves a set of variables. In contrast, the VariableIndex is built + * from a factor graph prior to elimination, and stores the list of factors + * that involve each variable. This information is stored as a deque of + * lists of factor indices. + * \nosubgrouping + */ +class GTSAM_EXPORT VariableIndexOrdered { +public: + + typedef boost::shared_ptr shared_ptr; + typedef FastList Factors; + typedef Factors::iterator Factor_iterator; + typedef Factors::const_iterator Factor_const_iterator; + +protected: + std::vector index_; + size_t nFactors_; // Number of factors in the original factor graph. + size_t nEntries_; // Sum of involved variable counts of each factor. + +public: + + /// @name Standard Constructors + /// @{ + + /** Default constructor, creates an empty VariableIndex */ + VariableIndexOrdered() : nFactors_(0), nEntries_(0) {} + + /** + * Create a VariableIndex that computes and stores the block column structure + * of a factor graph. This constructor is used when the number of variables + * is known beforehand. + */ + template VariableIndexOrdered(const FG& factorGraph, Index nVariables); + + /** + * Create a VariableIndex that computes and stores the block column structure + * of a factor graph. + */ + template VariableIndexOrdered(const FG& factorGraph); + + /// @} + /// @name Standard Interface + /// @{ + + /** + * The number of variable entries. This is one greater than the variable + * with the highest index. + */ + Index size() const { return index_.size(); } + + /** The number of factors in the original factor graph */ + size_t nFactors() const { return nFactors_; } + + /** The number of nonzero blocks, i.e. the number of variable-factor entries */ + size_t nEntries() const { return nEntries_; } + + /** Access a list of factors by variable */ + const Factors& operator[](Index variable) const { checkVar(variable); return index_[variable]; } + + /// @} + /// @name Testable + /// @{ + + /** Test for equality (for unit tests and debug assertions). */ + bool equals(const VariableIndexOrdered& other, double tol=0.0) const; + + /** Print the variable index (for unit tests and debugging). */ + void print(const std::string& str = "VariableIndex: ") const; + + /** + * Output dual hypergraph to Metis file format for use with hmetis + * In the dual graph, variables are hyperedges, factors are nodes. + */ + void outputMetisFormat(std::ostream& os) const; + + + /// @} + /// @name Advanced Interface + /// @{ + + /** + * Augment the variable index with new factors. This can be used when + * solving problems incrementally. + */ + template void augment(const FG& factors); + + /** + * Remove entries corresponding to the specified factors. + * NOTE: We intentionally do not decrement nFactors_ because the factor + * indices need to remain consistent. Removing factors from a factor graph + * does not shift the indices of other factors. Also, we keep nFactors_ + * one greater than the highest-numbered factor referenced in a VariableIndex. + * + * @param indices The indices of the factors to remove, which must match \c factors + * @param factors The factors being removed, which must symbolically correspond + * exactly to the factors with the specified \c indices that were added. + */ + template void remove(const CONTAINER& indices, const FG& factors); + + /// Permute the variables in the VariableIndex according to the given permutation + void permuteInPlace(const Permutation& permutation); + + /// Permute the variables in the VariableIndex according to the given partial permutation + void permuteInPlace(const Permutation& selector, const Permutation& permutation); + + /** Remove unused empty variables at the end of the ordering (in debug mode + * verifies they are empty). + * @param nToRemove The number of unused variables at the end to remove + */ + void removeUnusedAtEnd(size_t nToRemove); + +protected: + Factor_iterator factorsBegin(Index variable) { checkVar(variable); return index_[variable].begin(); } + Factor_iterator factorsEnd(Index variable) { checkVar(variable); return index_[variable].end(); } + + Factor_const_iterator factorsBegin(Index variable) const { checkVar(variable); return index_[variable].begin(); } + Factor_const_iterator factorsEnd(Index variable) const { checkVar(variable); return index_[variable].end(); } + + /// Internal constructor to allocate a VariableIndex of the requested size + VariableIndexOrdered(size_t nVars) : index_(nVars), nFactors_(0), nEntries_(0) {} + + /// Internal check of the validity of a variable + void checkVar(Index variable) const { assert(variable < index_.size()); } + + /// Internal function to populate the variable index from a factor graph + template void fill(const FG& factorGraph); + + /// @} + +private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(index_); + ar & BOOST_SERIALIZATION_NVP(nFactors_); + ar & BOOST_SERIALIZATION_NVP(nEntries_); + } +}; + +/* ************************************************************************* */ +template +void VariableIndexOrdered::fill(const FG& factorGraph) { + gttic(VariableIndex_fill); + // Build index mapping from variable id to factor index + for(size_t fi=0; fikeys()) { + if(key < index_.size()) { + index_[key].push_back(fi); + ++ nEntries_; + } + } + } + ++ nFactors_; // Increment factor count even if factors are null, to keep indices consistent + } +} + +/* ************************************************************************* */ +template +VariableIndexOrdered::VariableIndexOrdered(const FG& factorGraph) : + nFactors_(0), nEntries_(0) +{ + gttic(VariableIndex_constructor); + // If the factor graph is empty, return an empty index because inside this + // if block we assume at least one factor. + if(factorGraph.size() > 0) { + gttic(VariableIndex_constructor_find_highest); + // Find highest-numbered variable + Index maxVar = 0; + BOOST_FOREACH(const typename FG::sharedFactor& factor, factorGraph) { + if(factor) { + BOOST_FOREACH(const Index key, factor->keys()) { + if(key > maxVar) + maxVar = key; + } + } + } + gttoc(VariableIndex_constructor_find_highest); + + // Allocate array + gttic(VariableIndex_constructor_allocate); + index_.resize(maxVar+1); + gttoc(VariableIndex_constructor_allocate); + + fill(factorGraph); + } +} + +/* ************************************************************************* */ +template +VariableIndexOrdered::VariableIndexOrdered(const FG& factorGraph, Index nVariables) : + nFactors_(0), nEntries_(0) +{ + gttic(VariableIndex_constructor_allocate); + index_.resize(nVariables); + gttoc(VariableIndex_constructor_allocate); + fill(factorGraph); +} + +/* ************************************************************************* */ +template +void VariableIndexOrdered::augment(const FG& factors) { + gttic(VariableIndex_augment); + // If the factor graph is empty, return an empty index because inside this + // if block we assume at least one factor. + if(factors.size() > 0) { + // Find highest-numbered variable + Index maxVar = 0; + BOOST_FOREACH(const typename FG::sharedFactor& factor, factors) { + if(factor) { + BOOST_FOREACH(const Index key, factor->keys()) { + if(key > maxVar) + maxVar = key; + } + } + } + + // Allocate index + index_.resize(std::max(index_.size(), maxVar+1)); + + // Augment index mapping from variable id to factor index + size_t orignFactors = nFactors_; + for(size_t fi=0; fikeys()) { + index_[key].push_back(orignFactors + fi); + ++ nEntries_; + } + } + ++ nFactors_; // Increment factor count even if factors are null, to keep indices consistent + } + } +} + +/* ************************************************************************* */ +template +void VariableIndexOrdered::remove(const CONTAINER& indices, const FG& factors) { + gttic(VariableIndex_remove); + // NOTE: We intentionally do not decrement nFactors_ because the factor + // indices need to remain consistent. Removing factors from a factor graph + // does not shift the indices of other factors. Also, we keep nFactors_ + // one greater than the highest-numbered factor referenced in a VariableIndex. + for(size_t fi=0; fikeys().size(); ++ji) { + Factors& factorEntries = index_[factors[fi]->keys()[ji]]; + Factors::iterator entry = std::find(factorEntries.begin(), factorEntries.end(), indices[fi]); + if(entry == factorEntries.end()) + throw std::invalid_argument("Internal error, indices and factors passed into VariableIndex::remove are not consistent with the existing variable index"); + factorEntries.erase(entry); + -- nEntries_; + } + } +} + +} diff --git a/gtsam/inference/VariableIndexUnordered.cpp b/gtsam/inference/VariableIndexUnordered.cpp deleted file mode 100644 index 79eb196f6..000000000 --- a/gtsam/inference/VariableIndexUnordered.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VariableIndex.cpp - * @author Richard Roberts - * @date March 26, 2013 - */ - -#include - -#include - -namespace gtsam { - -using namespace std; - -/* ************************************************************************* */ -bool VariableIndexUnordered::equals(const VariableIndexUnordered& other, double tol) const { - return this->nEntries_ == other.nEntries_ && this->nFactors_ == other.nFactors_ - && this->index_ == other.index_; -} - -/* ************************************************************************* */ -void VariableIndexUnordered::print(const string& str) const { - cout << str; - cout << "nEntries = " << nEntries() << ", nFactors = " << nFactors() << "\n"; - BOOST_FOREACH(KeyMap::value_type key_factors, index_) { - cout << "var " << key_factors.first << ":"; - BOOST_FOREACH(const size_t factor, key_factors.second) - cout << " " << factor; - cout << "\n"; - } - cout.flush(); -} - -/* ************************************************************************* */ -void VariableIndexUnordered::outputMetisFormat(ostream& os) const { - os << size() << " " << nFactors() << "\n"; - // run over variables, which will be hyper-edges. - BOOST_FOREACH(KeyMap::value_type key_factors, index_) { - // every variable is a hyper-edge covering its factors - BOOST_FOREACH(const size_t factor, key_factors.second) - os << (factor+1) << " "; // base 1 - os << "\n"; - } - os << flush; -} - -} diff --git a/gtsam/inference/VariableIndexUnordered.h b/gtsam/inference/VariableIndexUnordered.h deleted file mode 100644 index 140f51d40..000000000 --- a/gtsam/inference/VariableIndexUnordered.h +++ /dev/null @@ -1,182 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VariableIndex.h - * @author Richard Roberts - * @date March 26, 2013 - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace gtsam { - -/** - * The VariableIndex class computes and stores the block column structure of a - * factor graph. The factor graph stores a collection of factors, each of - * which involves a set of variables. In contrast, the VariableIndex is built - * from a factor graph prior to elimination, and stores the list of factors - * that involve each variable. This information is stored as a deque of - * lists of factor indices. - * \nosubgrouping - */ -class GTSAM_EXPORT VariableIndexUnordered { -public: - - typedef boost::shared_ptr shared_ptr; - typedef FastList Factors; - typedef Factors::iterator Factor_iterator; - typedef Factors::const_iterator Factor_const_iterator; - -protected: - typedef FastMap KeyMap; - KeyMap index_; - size_t nFactors_; // Number of factors in the original factor graph. - size_t nEntries_; // Sum of involved variable counts of each factor. - -public: - typedef KeyMap::const_iterator const_iterator; - typedef KeyMap::const_iterator iterator; - typedef KeyMap::value_type value_type; - -public: - - /// @name Standard Constructors - /// @{ - - /** Default constructor, creates an empty VariableIndex */ - VariableIndexUnordered() : nFactors_(0), nEntries_(0) {} - - /** - * Create a VariableIndex that computes and stores the block column structure - * of a factor graph. - */ - template - VariableIndexUnordered(const FG& factorGraph) : nFactors_(0), nEntries_(0) { augment(factorGraph); } - - /// @} - /// @name Standard Interface - /// @{ - - /** - * The number of variable entries. This is one greater than the variable - * with the highest index. - */ - Index size() const { return index_.size(); } - - /** The number of factors in the original factor graph */ - size_t nFactors() const { return nFactors_; } - - /** The number of nonzero blocks, i.e. the number of variable-factor entries */ - size_t nEntries() const { return nEntries_; } - - /** Access a list of factors by variable */ - const Factors& operator[](Key variable) const { - KeyMap::const_iterator item = index_.find(variable); - if(item == index_.end()) - throw std::invalid_argument("Requested non-existent variable from VariableIndex"); - else - return item->second; - } - - /// @} - /// @name Testable - /// @{ - - /** Test for equality (for unit tests and debug assertions). */ - bool equals(const VariableIndexUnordered& other, double tol=0.0) const; - - /** Print the variable index (for unit tests and debugging). */ - void print(const std::string& str = "VariableIndex: ") const; - - /** - * Output dual hypergraph to Metis file format for use with hmetis - * In the dual graph, variables are hyperedges, factors are nodes. - */ - void outputMetisFormat(std::ostream& os) const; - - - /// @} - /// @name Advanced Interface - /// @{ - - /** - * Augment the variable index with new factors. This can be used when - * solving problems incrementally. - */ - template - void augment(const FG& factors); - - /** - * Remove entries corresponding to the specified factors. NOTE: We intentionally do not decrement - * nFactors_ because the factor indices need to remain consistent. Removing factors from a factor - * graph does not shift the indices of other factors. Also, we keep nFactors_ one greater than - * the highest-numbered factor referenced in a VariableIndex. - * - * @param indices The indices of the factors to remove, which must match \c factors - * @param factors The factors being removed, which must symbolically correspond exactly to the - * factors with the specified \c indices that were added. - */ - template - void remove(ITERATOR firstFactor, ITERATOR lastFactor, const FG& factors); - - /** Remove unused empty variables at the end of the ordering (in debug mode - * verifies they are empty). - * @param nToRemove The number of unused variables at the end to remove - */ - template - void removeUnusedVariables(ITERATOR firstKey, ITERATOR lastKey); - - /** Iterator to the first variable entry */ - const_iterator begin() const { return index_.begin(); } - - /** Iterator to the first variable entry */ - const_iterator end() const { return index_.end(); } - - /** Find the iterator for the requested variable entry */ - const_iterator find(Key key) const { return index_.find(key); } - -protected: - Factor_iterator factorsBegin(Index variable) { return internalAt(variable).begin(); } - Factor_iterator factorsEnd(Index variable) { return internalAt(variable).end(); } - - Factor_const_iterator factorsBegin(Index variable) const { return internalAt(variable).begin(); } - Factor_const_iterator factorsEnd(Index variable) const { return internalAt(variable).end(); } - - /// Internal version of 'at' that asserts existence - const Factors& internalAt(Key variable) const { - const KeyMap::const_iterator item = index_.find(variable); - assert(item != index_.end()); - return item->second; } - - /// Internal version of 'at' that asserts existence - Factors& internalAt(Key variable) { - const KeyMap::iterator item = index_.find(variable); - assert(item != index_.end()); - return item->second; } - - /// @} -}; - -} - -#include diff --git a/gtsam/inference/inference-inl.h b/gtsam/inference/inferenceOrdered-inl.h similarity index 90% rename from gtsam/inference/inference-inl.h rename to gtsam/inference/inferenceOrdered-inl.h index 5c5cedbc3..1a7612d92 100644 --- a/gtsam/inference/inference-inl.h +++ b/gtsam/inference/inferenceOrdered-inl.h @@ -21,7 +21,7 @@ #include // Only for Eclipse parser, inference-inl.h (this file) is included at the bottom of inference.h -#include +#include #include @@ -32,7 +32,7 @@ namespace inference { /* ************************************************************************* */ template Permutation::shared_ptr PermutationCOLAMD( - const VariableIndex& variableIndex, const CONSTRAINED& constrainLast, bool forceOrder) { + const VariableIndexOrdered& variableIndex, const CONSTRAINED& constrainLast, bool forceOrder) { gttic(PermutationCOLAMD_constrained); size_t n = variableIndex.size(); @@ -59,7 +59,7 @@ Permutation::shared_ptr PermutationCOLAMD( /* ************************************************************************* */ template Permutation::shared_ptr PermutationCOLAMDGrouped( - const VariableIndex& variableIndex, const CONSTRAINED_MAP& constraints) { + const VariableIndexOrdered& variableIndex, const CONSTRAINED_MAP& constraints) { gttic(PermutationCOLAMD_grouped); size_t n = variableIndex.size(); std::vector cmember(n, 0); @@ -75,7 +75,7 @@ Permutation::shared_ptr PermutationCOLAMDGrouped( } /* ************************************************************************* */ -inline Permutation::shared_ptr PermutationCOLAMD(const VariableIndex& variableIndex) { +inline Permutation::shared_ptr PermutationCOLAMD(const VariableIndexOrdered& variableIndex) { gttic(PermutationCOLAMD_unconstrained); size_t n = variableIndex.size(); std::vector cmember(n, 0); diff --git a/gtsam/inference/inference.cpp b/gtsam/inference/inferenceOrdered.cpp similarity index 92% rename from gtsam/inference/inference.cpp rename to gtsam/inference/inferenceOrdered.cpp index 8b8f98139..a5e546cb8 100644 --- a/gtsam/inference/inference.cpp +++ b/gtsam/inference/inferenceOrdered.cpp @@ -16,8 +16,8 @@ * @author Richard Roberts */ -#include -#include +#include +#include #include #include @@ -32,7 +32,7 @@ namespace gtsam { namespace inference { /* ************************************************************************* */ -Permutation::shared_ptr PermutationCOLAMD_(const VariableIndex& variableIndex, std::vector& cmember) { +Permutation::shared_ptr PermutationCOLAMD_(const VariableIndexOrdered& variableIndex, std::vector& cmember) { gttic(PermutationCOLAMD_internal); gttic(Prepare); @@ -47,7 +47,7 @@ Permutation::shared_ptr PermutationCOLAMD_(const VariableIndex& variableIndex, s p[0] = 0; int count = 0; for(Index var = 0; var < variableIndex.size(); ++var) { - const VariableIndex::Factors& column(variableIndex[var]); + const VariableIndexOrdered::Factors& column(variableIndex[var]); size_t lastFactorId = numeric_limits::max(); BOOST_FOREACH(size_t factorIndex, column) { if(lastFactorId != numeric_limits::max()) diff --git a/gtsam/inference/inference.h b/gtsam/inference/inferenceOrdered.h similarity index 84% rename from gtsam/inference/inference.h rename to gtsam/inference/inferenceOrdered.h index 099887ab6..ee3bcad85 100644 --- a/gtsam/inference/inference.h +++ b/gtsam/inference/inferenceOrdered.h @@ -19,8 +19,8 @@ #pragma once -#include -#include +#include +#include #include #include @@ -35,7 +35,7 @@ namespace gtsam { * Compute a permutation (variable ordering) using colamd */ GTSAM_EXPORT Permutation::shared_ptr PermutationCOLAMD( - const VariableIndex& variableIndex); + const VariableIndexOrdered& variableIndex); /** * Compute a permutation (variable ordering) using constrained colamd to move @@ -47,7 +47,7 @@ namespace gtsam { */ template Permutation::shared_ptr PermutationCOLAMD( - const VariableIndex& variableIndex, const CONSTRAINED& constrainLast, bool forceOrder=false); + const VariableIndexOrdered& variableIndex, const CONSTRAINED& constrainLast, bool forceOrder=false); /** * Compute a permutation of variable ordering using constrained colamd to @@ -59,7 +59,7 @@ namespace gtsam { */ template Permutation::shared_ptr PermutationCOLAMDGrouped( - const VariableIndex& variableIndex, const CONSTRAINED_MAP& constraints); + const VariableIndexOrdered& variableIndex, const CONSTRAINED_MAP& constraints); /** * Compute a CCOLAMD permutation using the constraint groups in cmember. @@ -73,10 +73,10 @@ namespace gtsam { * AGC: does cmember change? */ GTSAM_EXPORT Permutation::shared_ptr PermutationCOLAMD_( - const VariableIndex& variableIndex, std::vector& cmember); + const VariableIndexOrdered& variableIndex, std::vector& cmember); } // \namespace inference } // \namespace gtsam -#include +#include diff --git a/gtsam/inference/tests/testBayesTreeObsolete.cpp b/gtsam/inference/tests/testBayesTreeObsolete.cpp index 702c8682a..54bd2922f 100644 --- a/gtsam/inference/tests/testBayesTreeObsolete.cpp +++ b/gtsam/inference/tests/testBayesTreeObsolete.cpp @@ -26,10 +26,10 @@ using namespace boost::assign; #include #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace std; using namespace gtsam; @@ -38,18 +38,18 @@ using namespace gtsam; //// SLAM example from RSS sqrtSAM paper static const Index _x3_=0, _x2_=1; //static const Index _x1_=2, _l2_=3, _l1_=4; // unused -//IndexConditional::shared_ptr -// x3(new IndexConditional(_x3_)), -// x2(new IndexConditional(_x2_,_x3_)), -// x1(new IndexConditional(_x1_,_x2_,_x3_)), -// l1(new IndexConditional(_l1_,_x1_,_x2_)), -// l2(new IndexConditional(_l2_,_x1_,_x3_)); +//IndexConditionalOrdered::shared_ptr +// x3(new IndexConditionalOrdered(_x3_)), +// x2(new IndexConditionalOrdered(_x2_,_x3_)), +// x1(new IndexConditionalOrdered(_x1_,_x2_,_x3_)), +// l1(new IndexConditionalOrdered(_l1_,_x1_,_x2_)), +// l2(new IndexConditionalOrdered(_l2_,_x1_,_x3_)); // //// Bayes Tree for sqrtSAM example -//SymbolicBayesTree createSlamSymbolicBayesTree(){ +//SymbolicBayesTreeOrdered createSlamSymbolicBayesTree(){ // // Create using insert //// Ordering slamOrdering; slamOrdering += _x3_, _x2_, _x1_, _l2_, _l1_; -// SymbolicBayesTree bayesTree_slam; +// SymbolicBayesTreeOrdered bayesTree_slam; // bayesTree_slam.insert(x3); // bayesTree_slam.insert(x2); // bayesTree_slam.insert(x1); @@ -61,36 +61,36 @@ static const Index _x3_=0, _x2_=1; /* ************************************************************************* */ // Conditionals for ASIA example from the tutorial with A and D evidence static const Index _X_=0, _T_=1, _S_=2, _E_=3, _L_=4, _B_=5; -static IndexConditional::shared_ptr - B(new IndexConditional(_B_)), - L(new IndexConditional(_L_, _B_)), - E(new IndexConditional(_E_, _L_, _B_)), - S(new IndexConditional(_S_, _L_, _B_)), - T(new IndexConditional(_T_, _E_, _L_)), - X(new IndexConditional(_X_, _E_)); +static IndexConditionalOrdered::shared_ptr + B(new IndexConditionalOrdered(_B_)), + L(new IndexConditionalOrdered(_L_, _B_)), + E(new IndexConditionalOrdered(_E_, _L_, _B_)), + S(new IndexConditionalOrdered(_S_, _L_, _B_)), + T(new IndexConditionalOrdered(_T_, _E_, _L_)), + X(new IndexConditionalOrdered(_X_, _E_)); // Cliques -static IndexConditional::shared_ptr - ELB(IndexConditional::FromKeys(cref_list_of<3>(_E_)(_L_)(_B_), 3)); +static IndexConditionalOrdered::shared_ptr + ELB(IndexConditionalOrdered::FromKeys(cref_list_of<3>(_E_)(_L_)(_B_), 3)); // Bayes Tree for Asia example -static SymbolicBayesTree createAsiaSymbolicBayesTree() { - SymbolicBayesTree bayesTree; +static SymbolicBayesTreeOrdered createAsiaSymbolicBayesTree() { + SymbolicBayesTreeOrdered bayesTree; // Ordering asiaOrdering; asiaOrdering += _X_, _T_, _S_, _E_, _L_, _B_; - SymbolicBayesTree::insert(bayesTree, B); - SymbolicBayesTree::insert(bayesTree, L); - SymbolicBayesTree::insert(bayesTree, E); - SymbolicBayesTree::insert(bayesTree, S); - SymbolicBayesTree::insert(bayesTree, T); - SymbolicBayesTree::insert(bayesTree, X); + SymbolicBayesTreeOrdered::insert(bayesTree, B); + SymbolicBayesTreeOrdered::insert(bayesTree, L); + SymbolicBayesTreeOrdered::insert(bayesTree, E); + SymbolicBayesTreeOrdered::insert(bayesTree, S); + SymbolicBayesTreeOrdered::insert(bayesTree, T); + SymbolicBayesTreeOrdered::insert(bayesTree, X); return bayesTree; } /* ************************************************************************* */ -TEST( BayesTree, constructor ) +TEST( BayesTreeOrdered, constructor ) { // Create using insert - SymbolicBayesTree bayesTree = createAsiaSymbolicBayesTree(); + SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree(); bayesTree.print("bayesTree (ordered): "); @@ -99,18 +99,18 @@ TEST( BayesTree, constructor ) EXPECT(!bayesTree.empty()); // Check root - boost::shared_ptr actual_root = bayesTree.root()->conditional(); + boost::shared_ptr actual_root = bayesTree.root()->conditional(); CHECK(assert_equal(*ELB,*actual_root)); // Create from symbolic Bayes chain in which we want to discover cliques - BayesNet ASIA; + BayesNetOrdered ASIA; ASIA.push_back(X); ASIA.push_back(T); ASIA.push_back(S); ASIA.push_back(E); ASIA.push_back(L); ASIA.push_back(B); - SymbolicBayesTree bayesTree2(ASIA); + SymbolicBayesTreeOrdered bayesTree2(ASIA); // Check whether the same CHECK(assert_equal(bayesTree,bayesTree2)); @@ -130,14 +130,14 @@ TEST( BayesTree, constructor ) } /* ************************************************************************* */ -TEST(BayesTree, clear) +TEST(BayesTreeOrdered, clear) { -// SymbolicBayesTree bayesTree = createAsiaSymbolicBayesTree(); +// SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree(); // bayesTree.clear(); // -// SymbolicBayesTree expected; +// SymbolicBayesTreeOrdered expected; // -// // Check whether cleared BayesTree is equal to a new BayesTree +// // Check whether cleared BayesTreeOrdered is equal to a new BayesTreeOrdered // CHECK(assert_equal(expected, bayesTree)); } @@ -148,144 +148,144 @@ Bayes Tree for testing conversion to a forest of orphans needed for incremental. D|C F|E */ /* ************************************************************************* */ -TEST( BayesTree, removePath ) +TEST( BayesTreeOrdered, removePath ) { const Index _A_=5, _B_=4, _C_=3, _D_=2, _E_=1, _F_=0; - IndexConditional::shared_ptr - A(new IndexConditional(_A_)), - B(new IndexConditional(_B_, _A_)), - C(new IndexConditional(_C_, _A_)), - D(new IndexConditional(_D_, _C_)), - E(new IndexConditional(_E_, _B_)), - F(new IndexConditional(_F_, _E_)); - SymbolicBayesTree bayesTree; + IndexConditionalOrdered::shared_ptr + A(new IndexConditionalOrdered(_A_)), + B(new IndexConditionalOrdered(_B_, _A_)), + C(new IndexConditionalOrdered(_C_, _A_)), + D(new IndexConditionalOrdered(_D_, _C_)), + E(new IndexConditionalOrdered(_E_, _B_)), + F(new IndexConditionalOrdered(_F_, _E_)); + SymbolicBayesTreeOrdered bayesTree; EXPECT(bayesTree.empty()); // Ordering ord; ord += _A_,_B_,_C_,_D_,_E_,_F_; - SymbolicBayesTree::insert(bayesTree, A); - SymbolicBayesTree::insert(bayesTree, B); - SymbolicBayesTree::insert(bayesTree, C); - SymbolicBayesTree::insert(bayesTree, D); - SymbolicBayesTree::insert(bayesTree, E); - SymbolicBayesTree::insert(bayesTree, F); + SymbolicBayesTreeOrdered::insert(bayesTree, A); + SymbolicBayesTreeOrdered::insert(bayesTree, B); + SymbolicBayesTreeOrdered::insert(bayesTree, C); + SymbolicBayesTreeOrdered::insert(bayesTree, D); + SymbolicBayesTreeOrdered::insert(bayesTree, E); + SymbolicBayesTreeOrdered::insert(bayesTree, F); // remove C, expected outcome: factor graph with ABC, // Bayes Tree now contains two orphan trees: D|C and E|B,F|E - SymbolicFactorGraph expected; + SymbolicFactorGraphOrdered expected; expected.push_factor(_B_,_A_); // expected.push_factor(_A_); expected.push_factor(_C_,_A_); - SymbolicBayesTree::Cliques expectedOrphans; + SymbolicBayesTreeOrdered::Cliques expectedOrphans; expectedOrphans += bayesTree[_D_], bayesTree[_E_]; - BayesNet bn; - SymbolicBayesTree::Cliques orphans; + BayesNetOrdered bn; + SymbolicBayesTreeOrdered::Cliques orphans; bayesTree.removePath(bayesTree[_C_], bn, orphans); - SymbolicFactorGraph factors(bn); - CHECK(assert_equal((SymbolicFactorGraph)expected, factors)); + SymbolicFactorGraphOrdered factors(bn); + CHECK(assert_equal((SymbolicFactorGraphOrdered)expected, factors)); CHECK(assert_equal(expectedOrphans, orphans)); // remove E: factor graph with EB; E|B removed from second orphan tree - SymbolicFactorGraph expected2; + SymbolicFactorGraphOrdered expected2; expected2.push_factor(_E_,_B_); - SymbolicBayesTree::Cliques expectedOrphans2; + SymbolicBayesTreeOrdered::Cliques expectedOrphans2; expectedOrphans2 += bayesTree[_F_]; - BayesNet bn2; - SymbolicBayesTree::Cliques orphans2; + BayesNetOrdered bn2; + SymbolicBayesTreeOrdered::Cliques orphans2; bayesTree.removePath(bayesTree[_E_], bn2, orphans2); - SymbolicFactorGraph factors2(bn2); - CHECK(assert_equal((SymbolicFactorGraph)expected2, factors2)); + SymbolicFactorGraphOrdered factors2(bn2); + CHECK(assert_equal((SymbolicFactorGraphOrdered)expected2, factors2)); CHECK(assert_equal(expectedOrphans2, orphans2)); } /* ************************************************************************* */ -TEST( BayesTree, removePath2 ) +TEST( BayesTreeOrdered, removePath2 ) { - SymbolicBayesTree bayesTree = createAsiaSymbolicBayesTree(); + SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree(); // Call remove-path with clique B - BayesNet bn; - SymbolicBayesTree::Cliques orphans; + BayesNetOrdered bn; + SymbolicBayesTreeOrdered::Cliques orphans; bayesTree.removePath(bayesTree[_B_], bn, orphans); - SymbolicFactorGraph factors(bn); + SymbolicFactorGraphOrdered factors(bn); // Check expected outcome - SymbolicFactorGraph expected; + SymbolicFactorGraphOrdered expected; expected.push_factor(_E_,_L_,_B_); // expected.push_factor(_L_,_B_); // expected.push_factor(_B_); CHECK(assert_equal(expected, factors)); - SymbolicBayesTree::Cliques expectedOrphans; + SymbolicBayesTreeOrdered::Cliques expectedOrphans; expectedOrphans += bayesTree[_S_], bayesTree[_T_], bayesTree[_X_]; CHECK(assert_equal(expectedOrphans, orphans)); } /* ************************************************************************* */ -TEST( BayesTree, removePath3 ) +TEST( BayesTreeOrdered, removePath3 ) { - SymbolicBayesTree bayesTree = createAsiaSymbolicBayesTree(); + SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree(); // Call remove-path with clique S - BayesNet bn; - SymbolicBayesTree::Cliques orphans; + BayesNetOrdered bn; + SymbolicBayesTreeOrdered::Cliques orphans; bayesTree.removePath(bayesTree[_S_], bn, orphans); - SymbolicFactorGraph factors(bn); + SymbolicFactorGraphOrdered factors(bn); // Check expected outcome - SymbolicFactorGraph expected; + SymbolicFactorGraphOrdered expected; expected.push_factor(_E_,_L_,_B_); // expected.push_factor(_L_,_B_); // expected.push_factor(_B_); expected.push_factor(_S_,_L_,_B_); CHECK(assert_equal(expected, factors)); - SymbolicBayesTree::Cliques expectedOrphans; + SymbolicBayesTreeOrdered::Cliques expectedOrphans; expectedOrphans += bayesTree[_T_], bayesTree[_X_]; CHECK(assert_equal(expectedOrphans, orphans)); } -void getAllCliques(const SymbolicBayesTree::sharedClique& subtree, SymbolicBayesTree::Cliques& cliques) { +void getAllCliques(const SymbolicBayesTreeOrdered::sharedClique& subtree, SymbolicBayesTreeOrdered::Cliques& cliques) { // Check if subtree exists if (subtree) { cliques.push_back(subtree); // Recursive call over all child cliques - BOOST_FOREACH(SymbolicBayesTree::sharedClique& childClique, subtree->children()) { + BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& childClique, subtree->children()) { getAllCliques(childClique,cliques); } } } /* ************************************************************************* */ -TEST( BayesTree, shortcutCheck ) +TEST( BayesTreeOrdered, shortcutCheck ) { const Index _A_=6, _B_=5, _C_=4, _D_=3, _E_=2, _F_=1, _G_=0; - IndexConditional::shared_ptr - A(new IndexConditional(_A_)), - B(new IndexConditional(_B_, _A_)), - C(new IndexConditional(_C_, _A_)), - D(new IndexConditional(_D_, _C_)), - E(new IndexConditional(_E_, _B_)), - F(new IndexConditional(_F_, _E_)), - G(new IndexConditional(_G_, _F_)); - SymbolicBayesTree bayesTree; + IndexConditionalOrdered::shared_ptr + A(new IndexConditionalOrdered(_A_)), + B(new IndexConditionalOrdered(_B_, _A_)), + C(new IndexConditionalOrdered(_C_, _A_)), + D(new IndexConditionalOrdered(_D_, _C_)), + E(new IndexConditionalOrdered(_E_, _B_)), + F(new IndexConditionalOrdered(_F_, _E_)), + G(new IndexConditionalOrdered(_G_, _F_)); + SymbolicBayesTreeOrdered bayesTree; // Ordering ord; ord += _A_,_B_,_C_,_D_,_E_,_F_; - SymbolicBayesTree::insert(bayesTree, A); - SymbolicBayesTree::insert(bayesTree, B); - SymbolicBayesTree::insert(bayesTree, C); - SymbolicBayesTree::insert(bayesTree, D); - SymbolicBayesTree::insert(bayesTree, E); - SymbolicBayesTree::insert(bayesTree, F); - SymbolicBayesTree::insert(bayesTree, G); + SymbolicBayesTreeOrdered::insert(bayesTree, A); + SymbolicBayesTreeOrdered::insert(bayesTree, B); + SymbolicBayesTreeOrdered::insert(bayesTree, C); + SymbolicBayesTreeOrdered::insert(bayesTree, D); + SymbolicBayesTreeOrdered::insert(bayesTree, E); + SymbolicBayesTreeOrdered::insert(bayesTree, F); + SymbolicBayesTreeOrdered::insert(bayesTree, G); - //bayesTree.print("BayesTree"); + //bayesTree.print("BayesTreeOrdered"); //bayesTree.saveGraph("BT1.dot"); - SymbolicBayesTree::sharedClique rootClique= bayesTree.root(); + SymbolicBayesTreeOrdered::sharedClique rootClique= bayesTree.root(); //rootClique->printTree(); - SymbolicBayesTree::Cliques allCliques; + SymbolicBayesTreeOrdered::Cliques allCliques; getAllCliques(rootClique,allCliques); - BayesNet bn; - BOOST_FOREACH(SymbolicBayesTree::sharedClique& clique, allCliques) { + BayesNetOrdered bn; + BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& clique, allCliques) { //clique->print("Clique#"); bn = clique->shortcut(rootClique, &EliminateSymbolic); //bn.print("Shortcut:\n"); @@ -294,13 +294,13 @@ TEST( BayesTree, shortcutCheck ) // Check if all the cached shortcuts are cleared rootClique->deleteCachedShortcuts(); - BOOST_FOREACH(SymbolicBayesTree::sharedClique& clique, allCliques) { + BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& clique, allCliques) { bool notCleared = clique->cachedSeparatorMarginal(); CHECK( notCleared == false); } EXPECT_LONGS_EQUAL(0, rootClique->numCachedSeparatorMarginals()); -// BOOST_FOREACH(SymbolicBayesTree::sharedClique& clique, allCliques) { +// BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& clique, allCliques) { // clique->print("Clique#"); // if(clique->cachedShortcut()){ // bn = clique->cachedShortcut().get(); @@ -313,105 +313,105 @@ TEST( BayesTree, shortcutCheck ) } /* ************************************************************************* */ -TEST( BayesTree, removeTop ) +TEST( BayesTreeOrdered, removeTop ) { - SymbolicBayesTree bayesTree = createAsiaSymbolicBayesTree(); + SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree(); // create a new factor to be inserted - boost::shared_ptr newFactor(new IndexFactor(_S_,_B_)); + boost::shared_ptr newFactor(new IndexFactorOrdered(_S_,_B_)); // Remove the contaminated part of the Bayes tree - BayesNet bn; - SymbolicBayesTree::Cliques orphans; + BayesNetOrdered bn; + SymbolicBayesTreeOrdered::Cliques orphans; list keys; keys += _B_,_S_; bayesTree.removeTop(keys, bn, orphans); - SymbolicFactorGraph factors(bn); + SymbolicFactorGraphOrdered factors(bn); // Check expected outcome - SymbolicFactorGraph expected; + SymbolicFactorGraphOrdered expected; expected.push_factor(_E_,_L_,_B_); // expected.push_factor(_L_,_B_); // expected.push_factor(_B_); expected.push_factor(_S_,_L_,_B_); CHECK(assert_equal(expected, factors)); - SymbolicBayesTree::Cliques expectedOrphans; + SymbolicBayesTreeOrdered::Cliques expectedOrphans; expectedOrphans += bayesTree[_T_], bayesTree[_X_]; CHECK(assert_equal(expectedOrphans, orphans)); // Try removeTop again with a factor that should not change a thing - boost::shared_ptr newFactor2(new IndexFactor(_B_)); - BayesNet bn2; - SymbolicBayesTree::Cliques orphans2; + boost::shared_ptr newFactor2(new IndexFactorOrdered(_B_)); + BayesNetOrdered bn2; + SymbolicBayesTreeOrdered::Cliques orphans2; keys.clear(); keys += _B_; bayesTree.removeTop(keys, bn2, orphans2); - SymbolicFactorGraph factors2(bn2); - SymbolicFactorGraph expected2; + SymbolicFactorGraphOrdered factors2(bn2); + SymbolicFactorGraphOrdered expected2; CHECK(assert_equal(expected2, factors2)); - SymbolicBayesTree::Cliques expectedOrphans2; + SymbolicBayesTreeOrdered::Cliques expectedOrphans2; CHECK(assert_equal(expectedOrphans2, orphans2)); } /* ************************************************************************* */ -TEST( BayesTree, removeTop2 ) +TEST( BayesTreeOrdered, removeTop2 ) { - SymbolicBayesTree bayesTree = createAsiaSymbolicBayesTree(); + SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree(); // create two factors to be inserted - SymbolicFactorGraph newFactors; + SymbolicFactorGraphOrdered newFactors; newFactors.push_factor(_B_); newFactors.push_factor(_S_); // Remove the contaminated part of the Bayes tree - BayesNet bn; - SymbolicBayesTree::Cliques orphans; + BayesNetOrdered bn; + SymbolicBayesTreeOrdered::Cliques orphans; list keys; keys += _B_,_S_; bayesTree.removeTop(keys, bn, orphans); - SymbolicFactorGraph factors(bn); + SymbolicFactorGraphOrdered factors(bn); // Check expected outcome - SymbolicFactorGraph expected; + SymbolicFactorGraphOrdered expected; expected.push_factor(_E_,_L_,_B_); // expected.push_factor(_L_,_B_); // expected.push_factor(_B_); expected.push_factor(_S_,_L_,_B_); CHECK(assert_equal(expected, factors)); - SymbolicBayesTree::Cliques expectedOrphans; + SymbolicBayesTreeOrdered::Cliques expectedOrphans; expectedOrphans += bayesTree[_T_], bayesTree[_X_]; CHECK(assert_equal(expectedOrphans, orphans)); } /* ************************************************************************* */ -TEST( BayesTree, removeTop3 ) +TEST( BayesTreeOrdered, removeTop3 ) { const Index _x4_=5, _l5_=6; // simple test case that failed after COLAMD was fixed/activated - IndexConditional::shared_ptr - X(new IndexConditional(_l5_)), - A(new IndexConditional(_x4_, _l5_)), - B(new IndexConditional(_x2_, _x4_)), - C(new IndexConditional(_x3_, _x2_)); + IndexConditionalOrdered::shared_ptr + X(new IndexConditionalOrdered(_l5_)), + A(new IndexConditionalOrdered(_x4_, _l5_)), + B(new IndexConditionalOrdered(_x2_, _x4_)), + C(new IndexConditionalOrdered(_x3_, _x2_)); // Ordering newOrdering; // newOrdering += _x3_, _x2_, _x1_, _l2_, _l1_, _x4_, _l5_; - SymbolicBayesTree bayesTree; - SymbolicBayesTree::insert(bayesTree, X); - SymbolicBayesTree::insert(bayesTree, A); - SymbolicBayesTree::insert(bayesTree, B); - SymbolicBayesTree::insert(bayesTree, C); + SymbolicBayesTreeOrdered bayesTree; + SymbolicBayesTreeOrdered::insert(bayesTree, X); + SymbolicBayesTreeOrdered::insert(bayesTree, A); + SymbolicBayesTreeOrdered::insert(bayesTree, B); + SymbolicBayesTreeOrdered::insert(bayesTree, C); // remove all list keys; keys += _l5_, _x2_, _x3_, _x4_; - BayesNet bn; - SymbolicBayesTree::Cliques orphans; + BayesNetOrdered bn; + SymbolicBayesTreeOrdered::Cliques orphans; bayesTree.removeTop(keys, bn, orphans); - SymbolicFactorGraph factors(bn); + SymbolicFactorGraphOrdered factors(bn); CHECK(orphans.size() == 0); } /* ************************************************************************* */ -TEST( BayesTree, permute ) +TEST( BayesTreeOrdered, permute ) { // creates a permutation and ensures that the nodes listing is updated @@ -437,20 +437,20 @@ TEST( BayesTree, permute ) gtsam::internal::Reduction inv_reduction = gtsam::internal::Reduction::CreateAsInverse(expReducingPermutation); // Build a bayes tree around reduced keys as if just eliminated from subset of factors/variables - IndexConditional::shared_ptr - A(new IndexConditional(_A_)), - B(new IndexConditional(_B_, _A_)), - C(new IndexConditional(_C_, _A_)), - D(new IndexConditional(_D_, _C_)), - E(new IndexConditional(_E_, _B_)), - F(new IndexConditional(_F_, _E_)); - SymbolicBayesTree bayesTreeReduced; - SymbolicBayesTree::insert(bayesTreeReduced, A); - SymbolicBayesTree::insert(bayesTreeReduced, B); - SymbolicBayesTree::insert(bayesTreeReduced, C); - SymbolicBayesTree::insert(bayesTreeReduced, D); - SymbolicBayesTree::insert(bayesTreeReduced, E); - SymbolicBayesTree::insert(bayesTreeReduced, F); + IndexConditionalOrdered::shared_ptr + A(new IndexConditionalOrdered(_A_)), + B(new IndexConditionalOrdered(_B_, _A_)), + C(new IndexConditionalOrdered(_C_, _A_)), + D(new IndexConditionalOrdered(_D_, _C_)), + E(new IndexConditionalOrdered(_E_, _B_)), + F(new IndexConditionalOrdered(_F_, _E_)); + SymbolicBayesTreeOrdered bayesTreeReduced; + SymbolicBayesTreeOrdered::insert(bayesTreeReduced, A); + SymbolicBayesTreeOrdered::insert(bayesTreeReduced, B); + SymbolicBayesTreeOrdered::insert(bayesTreeReduced, C); + SymbolicBayesTreeOrdered::insert(bayesTreeReduced, D); + SymbolicBayesTreeOrdered::insert(bayesTreeReduced, E); + SymbolicBayesTreeOrdered::insert(bayesTreeReduced, F); // bayesTreeReduced.print("Reduced bayes tree"); // P( 4 5) @@ -460,7 +460,7 @@ TEST( BayesTree, permute ) // P( 0 | 1) // Apply the permutation - should add placeholders for variables not present in nodes - SymbolicBayesTree actBayesTree = *bayesTreeReduced.clone(); + SymbolicBayesTreeOrdered actBayesTree = *bayesTreeReduced.clone(); actBayesTree.permuteWithInverse(expReducingPermutation); // actBayesTree.print("Full bayes tree"); @@ -472,14 +472,14 @@ TEST( BayesTree, permute ) // check keys in cliques std::vector expRootIndices; expRootIndices += _B0_, _A0_; - IndexConditional::shared_ptr - expRoot(new IndexConditional(expRootIndices, 2)), // root - A0(new IndexConditional(_A0_)), - B0(new IndexConditional(_B0_, _A0_)), - C0(new IndexConditional(_C0_, _A0_)), // leaf level 1 - D0(new IndexConditional(_D0_, _C0_)), // leaf level 2 - E0(new IndexConditional(_E0_, _B0_)), // leaf level 2 - F0(new IndexConditional(_F0_, _E0_)); // leaf level 3 + IndexConditionalOrdered::shared_ptr + expRoot(new IndexConditionalOrdered(expRootIndices, 2)), // root + A0(new IndexConditionalOrdered(_A0_)), + B0(new IndexConditionalOrdered(_B0_, _A0_)), + C0(new IndexConditionalOrdered(_C0_, _A0_)), // leaf level 1 + D0(new IndexConditionalOrdered(_D0_, _C0_)), // leaf level 2 + E0(new IndexConditionalOrdered(_E0_, _B0_)), // leaf level 2 + F0(new IndexConditionalOrdered(_F0_, _E0_)); // leaf level 3 CHECK(actBayesTree.root()); EXPECT(assert_equal(*expRoot, *actBayesTree.root()->conditional())); @@ -491,13 +491,13 @@ TEST( BayesTree, permute ) // check nodes structure LONGS_EQUAL(9, actBayesTree.nodes().size()); - SymbolicBayesTree expFullTree; - SymbolicBayesTree::insert(expFullTree, A0); - SymbolicBayesTree::insert(expFullTree, B0); - SymbolicBayesTree::insert(expFullTree, C0); - SymbolicBayesTree::insert(expFullTree, D0); - SymbolicBayesTree::insert(expFullTree, E0); - SymbolicBayesTree::insert(expFullTree, F0); + SymbolicBayesTreeOrdered expFullTree; + SymbolicBayesTreeOrdered::insert(expFullTree, A0); + SymbolicBayesTreeOrdered::insert(expFullTree, B0); + SymbolicBayesTreeOrdered::insert(expFullTree, C0); + SymbolicBayesTreeOrdered::insert(expFullTree, D0); + SymbolicBayesTreeOrdered::insert(expFullTree, E0); + SymbolicBayesTreeOrdered::insert(expFullTree, F0); EXPECT(assert_equal(expFullTree, actBayesTree)); } @@ -508,11 +508,11 @@ TEST( BayesTree, permute ) // * | / \ | // * x1 / \ x6 // */ -//TEST( BayesTree, insert ) +//TEST( BayesTreeOrdered, insert ) //{ // // construct bayes tree by split the graph along the separator x3 - x4 // const Index _x1_=0, _x2_=1, _x6_=2, _x5_=3, _x3_=4, _x4_=5; -// SymbolicFactorGraph fg1, fg2, fg3; +// SymbolicFactorGraphOrdered fg1, fg2, fg3; // fg1.push_factor(_x3_, _x4_); // fg2.push_factor(_x1_, _x2_); // fg2.push_factor(_x2_, _x3_); @@ -525,16 +525,16 @@ TEST( BayesTree, permute ) //// Ordering ordering2; ordering2 += _x1_, _x2_; //// Ordering ordering3; ordering3 += _x6_, _x5_; // -// BayesNet bn1, bn2, bn3; +// BayesNetOrdered bn1, bn2, bn3; // bn1 = *SymbolicSequentialSolver::EliminateUntil(fg1, _x4_+1); // bn2 = *SymbolicSequentialSolver::EliminateUntil(fg2, _x2_+1); // bn3 = *SymbolicSequentialSolver::EliminateUntil(fg3, _x5_+1); // // // insert child cliques -// SymbolicBayesTree actual; -// list children; -// SymbolicBayesTree::sharedClique r1 = actual.insert(bn2, children); -// SymbolicBayesTree::sharedClique r2 = actual.insert(bn3, children); +// SymbolicBayesTreeOrdered actual; +// list children; +// SymbolicBayesTreeOrdered::sharedClique r1 = actual.insert(bn2, children); +// SymbolicBayesTreeOrdered::sharedClique r2 = actual.insert(bn3, children); // // // insert root clique // children.push_back(r1); @@ -542,7 +542,7 @@ TEST( BayesTree, permute ) // actual.insert(bn1, children, true); // // // traditional way -// SymbolicFactorGraph fg; +// SymbolicFactorGraphOrdered fg; // fg.push_factor(_x3_, _x4_); // fg.push_factor(_x1_, _x2_); // fg.push_factor(_x2_, _x3_); @@ -552,8 +552,8 @@ TEST( BayesTree, permute ) // fg.push_factor(_x6_, _x4_); // //// Ordering ordering; ordering += _x1_, _x2_, _x6_, _x5_, _x3_, _x4_; -// BayesNet bn(*SymbolicSequentialSolver(fg).eliminate()); -// SymbolicBayesTree expected(bn); +// BayesNetOrdered bn(*SymbolicSequentialSolver(fg).eliminate()); +// SymbolicBayesTreeOrdered expected(bn); // CHECK(assert_equal(expected, actual)); // //} diff --git a/gtsam/inference/tests/testClusterTreeObsolete.cpp b/gtsam/inference/tests/testClusterTreeObsolete.cpp index 0464aa546..1f0ef4d1f 100644 --- a/gtsam/inference/tests/testClusterTreeObsolete.cpp +++ b/gtsam/inference/tests/testClusterTreeObsolete.cpp @@ -21,17 +21,17 @@ using namespace boost::assign; #include -#include -#include +#include +#include using namespace gtsam; // explicit instantiation and typedef -namespace gtsam { template class ClusterTree; } -typedef ClusterTree SymbolicClusterTree; +namespace gtsam { template class ClusterTreeOrdered; } +typedef ClusterTreeOrdered SymbolicClusterTree; /* ************************************************************************* */ -TEST(ClusterTree, constructor) { +TEST(ClusterTreeOrdered, constructor) { SymbolicClusterTree tree; } diff --git a/gtsam/inference/tests/testConditionalObsolete.cpp b/gtsam/inference/tests/testConditionalObsolete.cpp index 5ee695bb5..b70f41ddd 100644 --- a/gtsam/inference/tests/testConditionalObsolete.cpp +++ b/gtsam/inference/tests/testConditionalObsolete.cpp @@ -20,76 +20,76 @@ using namespace boost::assign; #include -#include -#include +#include +#include using namespace std; using namespace gtsam; /* ************************************************************************* */ -TEST( IndexConditional, empty ) +TEST( IndexConditionalOrdered, empty ) { - IndexConditional c0; + IndexConditionalOrdered c0; LONGS_EQUAL(0,c0.nrFrontals()) LONGS_EQUAL(0,c0.nrParents()) } /* ************************************************************************* */ -TEST( IndexConditional, noParents ) +TEST( IndexConditionalOrdered, noParents ) { - IndexConditional c0(0); + IndexConditionalOrdered c0(0); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(0,c0.nrParents()) } /* ************************************************************************* */ -TEST( IndexConditional, oneParents ) +TEST( IndexConditionalOrdered, oneParents ) { - IndexConditional c0(0,1); + IndexConditionalOrdered c0(0,1); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(1,c0.nrParents()) } /* ************************************************************************* */ -TEST( IndexConditional, twoParents ) +TEST( IndexConditionalOrdered, twoParents ) { - IndexConditional c0(0,1,2); + IndexConditionalOrdered c0(0,1,2); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(2,c0.nrParents()) } /* ************************************************************************* */ -TEST( IndexConditional, threeParents ) +TEST( IndexConditionalOrdered, threeParents ) { - IndexConditional c0(0,1,2,3); + IndexConditionalOrdered c0(0,1,2,3); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(3,c0.nrParents()) } /* ************************************************************************* */ -TEST( IndexConditional, fourParents ) +TEST( IndexConditionalOrdered, fourParents ) { vector parents; parents += 1,2,3,4; - IndexConditional c0(0,parents); + IndexConditionalOrdered c0(0,parents); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(4,c0.nrParents()) } /* ************************************************************************* */ -TEST( IndexConditional, FromRange ) +TEST( IndexConditionalOrdered, FromRange ) { vector keys; keys += 1,2,3,4,5; - IndexConditional::shared_ptr c0(new IndexConditional(keys,2)); + IndexConditionalOrdered::shared_ptr c0(new IndexConditionalOrdered(keys,2)); LONGS_EQUAL(2,c0->nrFrontals()) LONGS_EQUAL(3,c0->nrParents()) } /* ************************************************************************* */ -TEST( IndexConditional, equals ) +TEST( IndexConditionalOrdered, equals ) { - IndexConditional c0(0, 1, 2), c1(0, 1, 2), c2(1, 2, 3), c3(3,4); + IndexConditionalOrdered c0(0, 1, 2), c1(0, 1, 2), c2(1, 2, 3), c3(3,4); CHECK(c0.equals(c1)); CHECK(c1.equals(c0)); CHECK(!c0.equals(c2)); diff --git a/gtsam/inference/tests/testEliminationTreeObsolete.cpp b/gtsam/inference/tests/testEliminationTreeObsolete.cpp index 00679083a..76c8c2172 100644 --- a/gtsam/inference/tests/testEliminationTreeObsolete.cpp +++ b/gtsam/inference/tests/testEliminationTreeObsolete.cpp @@ -19,33 +19,33 @@ #include #include -#include -#include +#include +#include using namespace gtsam; using namespace std; -class EliminationTreeTester { +class EliminationTreeOrderedTester { public: // build hardcoded tree - static SymbolicEliminationTree::shared_ptr buildHardcodedTree(const SymbolicFactorGraph& fg) { + static SymbolicEliminationTreeOrdered::shared_ptr buildHardcodedTree(const SymbolicFactorGraphOrdered& fg) { - SymbolicEliminationTree::shared_ptr leaf0(new SymbolicEliminationTree); + SymbolicEliminationTreeOrdered::shared_ptr leaf0(new SymbolicEliminationTreeOrdered); leaf0->add(fg[0]); leaf0->add(fg[1]); - SymbolicEliminationTree::shared_ptr node1(new SymbolicEliminationTree(1)); + SymbolicEliminationTreeOrdered::shared_ptr node1(new SymbolicEliminationTreeOrdered(1)); node1->add(fg[2]); node1->add(leaf0); - SymbolicEliminationTree::shared_ptr node2(new SymbolicEliminationTree(2)); + SymbolicEliminationTreeOrdered::shared_ptr node2(new SymbolicEliminationTreeOrdered(2)); node2->add(fg[3]); node2->add(node1); - SymbolicEliminationTree::shared_ptr leaf3(new SymbolicEliminationTree(3)); + SymbolicEliminationTreeOrdered::shared_ptr leaf3(new SymbolicEliminationTreeOrdered(3)); leaf3->add(fg[4]); - SymbolicEliminationTree::shared_ptr etree(new SymbolicEliminationTree(4)); + SymbolicEliminationTreeOrdered::shared_ptr etree(new SymbolicEliminationTreeOrdered(4)); etree->add(leaf3); etree->add(node2); @@ -53,20 +53,20 @@ public: } }; -TEST(EliminationTree, Create) +TEST(EliminationTreeOrdered, Create) { // create example factor graph - SymbolicFactorGraph fg; + SymbolicFactorGraphOrdered fg; fg.push_factor(0, 1); fg.push_factor(0, 2); fg.push_factor(1, 4); fg.push_factor(2, 4); fg.push_factor(3, 4); - SymbolicEliminationTree::shared_ptr expected = EliminationTreeTester::buildHardcodedTree(fg); + SymbolicEliminationTreeOrdered::shared_ptr expected = EliminationTreeOrderedTester::buildHardcodedTree(fg); // Build from factor graph - SymbolicEliminationTree::shared_ptr actual = SymbolicEliminationTree::Create(fg); + SymbolicEliminationTreeOrdered::shared_ptr actual = SymbolicEliminationTreeOrdered::Create(fg); CHECK(assert_equal(*expected,*actual)); } @@ -76,18 +76,18 @@ TEST(EliminationTree, Create) // graph: f(0,1) f(0,2) f(1,4) f(2,4) f(3,4) /* ************************************************************************* */ -TEST(EliminationTree, eliminate ) +TEST(EliminationTreeOrdered, eliminate ) { // create expected Chordal bayes Net - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(4)); - expected.push_front(boost::make_shared(3,4)); - expected.push_front(boost::make_shared(2,4)); - expected.push_front(boost::make_shared(1,2,4)); - expected.push_front(boost::make_shared(0,1,2)); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(4)); + expected.push_front(boost::make_shared(3,4)); + expected.push_front(boost::make_shared(2,4)); + expected.push_front(boost::make_shared(1,2,4)); + expected.push_front(boost::make_shared(0,1,2)); // Create factor graph - SymbolicFactorGraph fg; + SymbolicFactorGraphOrdered fg; fg.push_factor(0, 1); fg.push_factor(0, 2); fg.push_factor(1, 4); @@ -95,20 +95,20 @@ TEST(EliminationTree, eliminate ) fg.push_factor(3, 4); // eliminate - SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(); + SymbolicBayesNetOrdered actual = *SymbolicSequentialSolver(fg).eliminate(); CHECK(assert_equal(expected,actual)); } /* ************************************************************************* */ -TEST(EliminationTree, disconnected_graph) { - SymbolicFactorGraph fg; +TEST(EliminationTreeOrdered, disconnected_graph) { + SymbolicFactorGraphOrdered fg; fg.push_factor(0, 1); fg.push_factor(0, 2); fg.push_factor(1, 2); fg.push_factor(3, 4); - CHECK_EXCEPTION(SymbolicEliminationTree::Create(fg), DisconnectedGraphException); + CHECK_EXCEPTION(SymbolicEliminationTreeOrdered::Create(fg), DisconnectedGraphException); } /* ************************************************************************* */ diff --git a/gtsam/inference/tests/testFactorGraphObsolete.cpp b/gtsam/inference/tests/testFactorGraphObsolete.cpp index 43402d2cb..8dac0e3ec 100644 --- a/gtsam/inference/tests/testFactorGraphObsolete.cpp +++ b/gtsam/inference/tests/testFactorGraphObsolete.cpp @@ -26,16 +26,16 @@ using namespace boost::assign; #include -#include -#include +#include +#include using namespace std; using namespace gtsam; /* ************************************************************************* */ -TEST(FactorGraph, eliminateFrontals) { +TEST(FactorGraphOrdered, eliminateFrontals) { - SymbolicFactorGraph sfgOrig; + SymbolicFactorGraphOrdered sfgOrig; sfgOrig.push_factor(0,1); sfgOrig.push_factor(0,2); sfgOrig.push_factor(1,3); @@ -43,15 +43,15 @@ TEST(FactorGraph, eliminateFrontals) { sfgOrig.push_factor(2,3); sfgOrig.push_factor(4,5); - IndexConditional::shared_ptr actualCond; - SymbolicFactorGraph actualSfg; + IndexConditionalOrdered::shared_ptr actualCond; + SymbolicFactorGraphOrdered actualSfg; boost::tie(actualCond, actualSfg) = sfgOrig.eliminateFrontals(2); vector condIndices; condIndices += 0,1,2,3,4; - IndexConditional expectedCond(condIndices, 2); + IndexConditionalOrdered expectedCond(condIndices, 2); - SymbolicFactorGraph expectedSfg; + SymbolicFactorGraphOrdered expectedSfg; expectedSfg.push_factor(2,3); expectedSfg.push_factor(4,5); expectedSfg.push_factor(2,3,4); diff --git a/gtsam/inference/tests/testISAM.cpp b/gtsam/inference/tests/testISAM.cpp index 0e8f1a75d..c57a9be2f 100644 --- a/gtsam/inference/tests/testISAM.cpp +++ b/gtsam/inference/tests/testISAM.cpp @@ -21,15 +21,15 @@ using namespace boost::assign; #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace std; using namespace gtsam; -typedef ISAM SymbolicISAM; +typedef ISAMOrdered SymbolicISAM; /* ************************************************************************* */ // Some numbers that should be consistent among all smoother tests diff --git a/gtsam/inference/tests/testInference.cpp b/gtsam/inference/tests/testInference.cpp index b25703cb6..67f2d4833 100644 --- a/gtsam/inference/tests/testInference.cpp +++ b/gtsam/inference/tests/testInference.cpp @@ -18,22 +18,22 @@ #include -#include -#include -#include +#include +#include +#include using namespace gtsam; /* ************************************************************************* */ TEST(inference, UnobservedVariables) { - SymbolicFactorGraph sfg; + SymbolicFactorGraphOrdered sfg; // Create a factor graph that skips some variables sfg.push_factor(0,1); sfg.push_factor(1,3); sfg.push_factor(3,5); - VariableIndex variableIndex(sfg); + VariableIndexOrdered variableIndex(sfg); // Computes a permutation with known variables first, skipped variables last // Actual 0 1 3 5 2 4 @@ -50,7 +50,7 @@ TEST(inference, UnobservedVariables) { /* ************************************************************************* */ TEST(inference, constrained_ordering) { - SymbolicFactorGraph sfg; + SymbolicFactorGraphOrdered sfg; // create graph with wanted variable set = 2, 4 sfg.push_factor(0,1); @@ -59,7 +59,7 @@ TEST(inference, constrained_ordering) { sfg.push_factor(3,4); sfg.push_factor(4,5); - VariableIndex variableIndex(sfg); + VariableIndexOrdered variableIndex(sfg); // unconstrained version Permutation::shared_ptr actUnconstrained(inference::PermutationCOLAMD(variableIndex)); @@ -83,7 +83,7 @@ TEST(inference, constrained_ordering) { /* ************************************************************************* */ TEST(inference, grouped_constrained_ordering) { - SymbolicFactorGraph sfg; + SymbolicFactorGraphOrdered sfg; // create graph with constrained groups: // 1: 2, 4 @@ -94,7 +94,7 @@ TEST(inference, grouped_constrained_ordering) { sfg.push_factor(3,4); sfg.push_factor(4,5); - VariableIndex variableIndex(sfg); + VariableIndexOrdered variableIndex(sfg); // constrained version - push one set to the end FastMap constraints; diff --git a/gtsam/inference/tests/testJunctionTreeObsolete.cpp b/gtsam/inference/tests/testJunctionTreeObsolete.cpp index ba7175e24..b64d596f5 100644 --- a/gtsam/inference/tests/testJunctionTreeObsolete.cpp +++ b/gtsam/inference/tests/testJunctionTreeObsolete.cpp @@ -24,27 +24,27 @@ using namespace boost::assign; #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include using namespace gtsam; using namespace std; -typedef JunctionTree SymbolicJunctionTree; +typedef JunctionTreeOrdered SymbolicJunctionTree; /* ************************************************************************* * * x1 - x2 - x3 - x4 * x3 x4 * x2 x1 : x3 ****************************************************************************/ -TEST( JunctionTree, constructor ) +TEST( JunctionTreeOrdered, constructor ) { const Index x2=0, x1=1, x3=2, x4=3; - SymbolicFactorGraph fg; + SymbolicFactorGraphOrdered fg; fg.push_factor(x2,x1); fg.push_factor(x2,x3); fg.push_factor(x3,x4); @@ -71,19 +71,19 @@ TEST( JunctionTree, constructor ) * x3 x4 * x2 x1 : x3 ****************************************************************************/ -TEST( JunctionTree, eliminate) +TEST( JunctionTreeOrdered, eliminate) { const Index x2=0, x1=1, x3=2, x4=3; - SymbolicFactorGraph fg; + SymbolicFactorGraphOrdered fg; fg.push_factor(x2,x1); fg.push_factor(x2,x3); fg.push_factor(x3,x4); SymbolicJunctionTree jt(fg); - SymbolicBayesTree::sharedClique actual = jt.eliminate(&EliminateSymbolic); + SymbolicBayesTreeOrdered::sharedClique actual = jt.eliminate(&EliminateSymbolic); - BayesNet bn(*SymbolicSequentialSolver(fg).eliminate()); - SymbolicBayesTree expected(bn); + BayesNetOrdered bn(*SymbolicSequentialSolver(fg).eliminate()); + SymbolicBayesTreeOrdered expected(bn); // cout << "BT from JT:\n"; // actual->printTree(""); diff --git a/gtsam/inference/tests/testPermutationObsolete.cpp b/gtsam/inference/tests/testPermutationObsolete.cpp index 5aa83422f..a14fa7a43 100644 --- a/gtsam/inference/tests/testPermutationObsolete.cpp +++ b/gtsam/inference/tests/testPermutationObsolete.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include diff --git a/gtsam/inference/tests/testSerializationInference.cpp b/gtsam/inference/tests/testSerializationInference.cpp index b2b300440..a9a4de973 100644 --- a/gtsam/inference/tests/testSerializationInference.cpp +++ b/gtsam/inference/tests/testSerializationInference.cpp @@ -16,9 +16,9 @@ * @date Feb 7, 2012 */ -#include -#include -#include +#include +#include +#include #include #include @@ -30,7 +30,7 @@ using namespace gtsam::serializationTestHelpers; /* ************************************************************************* */ TEST (Serialization, symbolic_graph) { // construct expected symbolic graph - SymbolicFactorGraph sfg; + SymbolicFactorGraphOrdered sfg; sfg.push_factor(0); sfg.push_factor(0,1); sfg.push_factor(0,2); @@ -43,11 +43,11 @@ TEST (Serialization, symbolic_graph) { /* ************************************************************************* */ TEST (Serialization, symbolic_bn) { - IndexConditional::shared_ptr x2(new IndexConditional(1, 2, 0)); - IndexConditional::shared_ptr l1(new IndexConditional(2, 0)); - IndexConditional::shared_ptr x1(new IndexConditional(0)); + IndexConditionalOrdered::shared_ptr x2(new IndexConditionalOrdered(1, 2, 0)); + IndexConditionalOrdered::shared_ptr l1(new IndexConditionalOrdered(2, 0)); + IndexConditionalOrdered::shared_ptr x1(new IndexConditionalOrdered(0)); - SymbolicBayesNet sbn; + SymbolicBayesNetOrdered sbn; sbn.push_back(x2); sbn.push_back(l1); sbn.push_back(x1); @@ -59,15 +59,15 @@ TEST (Serialization, symbolic_bn) { /* ************************************************************************* */ TEST (Serialization, symbolic_bayes_tree ) { - typedef BayesTree SymbolicBayesTree; + typedef BayesTreeOrdered SymbolicBayesTree; static const Index _X_=0, _T_=1, _S_=2, _E_=3, _L_=4, _B_=5; - IndexConditional::shared_ptr - B(new IndexConditional(_B_)), - L(new IndexConditional(_L_, _B_)), - E(new IndexConditional(_E_, _L_, _B_)), - S(new IndexConditional(_S_, _L_, _B_)), - T(new IndexConditional(_T_, _E_, _L_)), - X(new IndexConditional(_X_, _E_)); + IndexConditionalOrdered::shared_ptr + B(new IndexConditionalOrdered(_B_)), + L(new IndexConditionalOrdered(_L_, _B_)), + E(new IndexConditionalOrdered(_E_, _L_, _B_)), + S(new IndexConditionalOrdered(_S_, _L_, _B_)), + T(new IndexConditionalOrdered(_T_, _E_, _L_)), + X(new IndexConditionalOrdered(_X_, _E_)); // Bayes Tree for Asia example SymbolicBayesTree bayesTree; diff --git a/gtsam/inference/tests/testSymbolicBayesNetObsolete.cpp b/gtsam/inference/tests/testSymbolicBayesNetObsolete.cpp index 44def4c24..0ce99c1b8 100644 --- a/gtsam/inference/tests/testSymbolicBayesNetObsolete.cpp +++ b/gtsam/inference/tests/testSymbolicBayesNetObsolete.cpp @@ -22,8 +22,8 @@ using namespace boost::assign; #include #include -#include -#include +#include +#include using namespace std; using namespace gtsam; @@ -35,17 +35,17 @@ static const Index _C_ = 3; static const Index _D_ = 4; static const Index _E_ = 5; -static IndexConditional::shared_ptr - B(new IndexConditional(_B_)), - L(new IndexConditional(_L_, _B_)); +static IndexConditionalOrdered::shared_ptr + B(new IndexConditionalOrdered(_B_)), + L(new IndexConditionalOrdered(_L_, _B_)); /* ************************************************************************* */ -TEST( SymbolicBayesNet, equals ) +TEST( SymbolicBayesNetOrdered, equals ) { - BayesNet f1; + BayesNetOrdered f1; f1.push_back(B); f1.push_back(L); - BayesNet f2; + BayesNetOrdered f2; f2.push_back(L); f2.push_back(B); CHECK(f1.equals(f1)); @@ -53,20 +53,20 @@ TEST( SymbolicBayesNet, equals ) } /* ************************************************************************* */ -TEST( SymbolicBayesNet, pop_front ) +TEST( SymbolicBayesNetOrdered, pop_front ) { - IndexConditional::shared_ptr - A(new IndexConditional(_A_,_B_,_C_)), - B(new IndexConditional(_B_,_C_)), - C(new IndexConditional(_C_)); + IndexConditionalOrdered::shared_ptr + A(new IndexConditionalOrdered(_A_,_B_,_C_)), + B(new IndexConditionalOrdered(_B_,_C_)), + C(new IndexConditionalOrdered(_C_)); // Expected after pop_front - BayesNet expected; + BayesNetOrdered expected; expected.push_back(B); expected.push_back(C); // Actual - BayesNet actual; + BayesNetOrdered actual; actual.push_back(A); actual.push_back(B); actual.push_back(C); @@ -76,26 +76,26 @@ TEST( SymbolicBayesNet, pop_front ) } /* ************************************************************************* */ -TEST( SymbolicBayesNet, combine ) +TEST( SymbolicBayesNetOrdered, combine ) { - IndexConditional::shared_ptr - A(new IndexConditional(_A_,_B_,_C_)), - B(new IndexConditional(_B_,_C_)), - C(new IndexConditional(_C_)); + IndexConditionalOrdered::shared_ptr + A(new IndexConditionalOrdered(_A_,_B_,_C_)), + B(new IndexConditionalOrdered(_B_,_C_)), + C(new IndexConditionalOrdered(_C_)); // p(A|BC) - BayesNet p_ABC; + BayesNetOrdered p_ABC; p_ABC.push_back(A); // P(BC)=P(B|C)P(C) - BayesNet p_BC; + BayesNetOrdered p_BC; p_BC.push_back(B); p_BC.push_back(C); // P(ABC) = P(A|BC) P(BC) p_ABC.push_back(p_BC); - BayesNet expected; + BayesNetOrdered expected; expected.push_back(A); expected.push_back(B); expected.push_back(C); @@ -104,65 +104,65 @@ TEST( SymbolicBayesNet, combine ) } /* ************************************************************************* */ -TEST(SymbolicBayesNet, find) { - SymbolicBayesNet bn; - bn += IndexConditional::shared_ptr(new IndexConditional(_A_, _B_)); +TEST(SymbolicBayesNetOrdered, find) { + SymbolicBayesNetOrdered bn; + bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_A_, _B_)); std::vector keys; keys.push_back(_B_); keys.push_back(_C_); keys.push_back(_D_); - bn += IndexConditional::shared_ptr(new IndexConditional(keys,2)); - bn += IndexConditional::shared_ptr(new IndexConditional(_D_)); + bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(keys,2)); + bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_D_)); - SymbolicBayesNet::iterator expected = bn.begin(); ++ expected; - SymbolicBayesNet::iterator actual = bn.find(_C_); + SymbolicBayesNetOrdered::iterator expected = bn.begin(); ++ expected; + SymbolicBayesNetOrdered::iterator actual = bn.find(_C_); EXPECT(assert_equal(**expected, **actual)); } /* ************************************************************************* */ -TEST_UNSAFE(SymbolicBayesNet, popLeaf) { - IndexConditional::shared_ptr - A(new IndexConditional(_A_,_E_)), - B(new IndexConditional(_B_,_E_)), - C(new IndexConditional(_C_,_D_)), - D(new IndexConditional(_D_,_E_)), - E(new IndexConditional(_E_)); +TEST_UNSAFE(SymbolicBayesNetOrdered, popLeaf) { + IndexConditionalOrdered::shared_ptr + A(new IndexConditionalOrdered(_A_,_E_)), + B(new IndexConditionalOrdered(_B_,_E_)), + C(new IndexConditionalOrdered(_C_,_D_)), + D(new IndexConditionalOrdered(_D_,_E_)), + E(new IndexConditionalOrdered(_E_)); // BayesNet after popping A - SymbolicBayesNet expected1; + SymbolicBayesNetOrdered expected1; expected1 += B, C, D, E; // BayesNet after popping C - SymbolicBayesNet expected2; + SymbolicBayesNetOrdered expected2; expected2 += A, B, D, E; // BayesNet after popping C and D - SymbolicBayesNet expected3; + SymbolicBayesNetOrdered expected3; expected3 += A, B, E; // BayesNet after popping C and A - SymbolicBayesNet expected4; + SymbolicBayesNetOrdered expected4; expected4 += B, D, E; // BayesNet after popping A - SymbolicBayesNet actual1; + SymbolicBayesNetOrdered actual1; actual1 += A, B, C, D, E; actual1.popLeaf(actual1.find(_A_)); // BayesNet after popping C - SymbolicBayesNet actual2; + SymbolicBayesNetOrdered actual2; actual2 += A, B, C, D, E; actual2.popLeaf(actual2.find(_C_)); // BayesNet after popping C and D - SymbolicBayesNet actual3; + SymbolicBayesNetOrdered actual3; actual3 += A, B, C, D, E; actual3.popLeaf(actual3.find(_C_)); actual3.popLeaf(actual3.find(_D_)); // BayesNet after popping C and A - SymbolicBayesNet actual4; + SymbolicBayesNetOrdered actual4; actual4 += A, B, C, D, E; actual4.popLeaf(actual4.find(_C_)); actual4.popLeaf(actual4.find(_A_)); @@ -179,7 +179,7 @@ TEST_UNSAFE(SymbolicBayesNet, popLeaf) { //#endif // //#undef NDEBUG -// SymbolicBayesNet actual5; +// SymbolicBayesNetOrdered actual5; // actual5 += A, B, C, D, E; // CHECK_EXCEPTION(actual5.popLeaf(actual5.find(_D_)), std::invalid_argument); // @@ -189,15 +189,15 @@ TEST_UNSAFE(SymbolicBayesNet, popLeaf) { } /* ************************************************************************* */ -TEST(SymbolicBayesNet, saveGraph) { - SymbolicBayesNet bn; - bn += IndexConditional::shared_ptr(new IndexConditional(_A_, _B_)); +TEST(SymbolicBayesNetOrdered, saveGraph) { + SymbolicBayesNetOrdered bn; + bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_A_, _B_)); std::vector keys; keys.push_back(_B_); keys.push_back(_C_); keys.push_back(_D_); - bn += IndexConditional::shared_ptr(new IndexConditional(keys,2)); - bn += IndexConditional::shared_ptr(new IndexConditional(_D_)); + bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(keys,2)); + bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_D_)); bn.saveGraph("SymbolicBayesNet.dot"); } diff --git a/gtsam/inference/tests/testSymbolicBayesTreeObsolete.cpp b/gtsam/inference/tests/testSymbolicBayesTreeObsolete.cpp index 68693817b..dcc877d9b 100644 --- a/gtsam/inference/tests/testSymbolicBayesTreeObsolete.cpp +++ b/gtsam/inference/tests/testSymbolicBayesTreeObsolete.cpp @@ -15,9 +15,9 @@ * @author Frank Dellaert */ -#include -#include -#include +#include +#include +#include #include #include @@ -32,29 +32,29 @@ static bool debug = false; /* ************************************************************************* */ -TEST_UNSAFE( SymbolicBayesTree, thinTree ) { +TEST_UNSAFE( SymbolicBayesTreeOrdered, thinTree ) { // create a thin-tree Bayesnet, a la Jean-Guillaume - SymbolicBayesNet bayesNet; - bayesNet.push_front(boost::make_shared(14)); + SymbolicBayesNetOrdered bayesNet; + bayesNet.push_front(boost::make_shared(14)); - bayesNet.push_front(boost::make_shared(13, 14)); - bayesNet.push_front(boost::make_shared(12, 14)); + bayesNet.push_front(boost::make_shared(13, 14)); + bayesNet.push_front(boost::make_shared(12, 14)); - bayesNet.push_front(boost::make_shared(11, 13, 14)); - bayesNet.push_front(boost::make_shared(10, 13, 14)); - bayesNet.push_front(boost::make_shared(9, 12, 14)); - bayesNet.push_front(boost::make_shared(8, 12, 14)); + bayesNet.push_front(boost::make_shared(11, 13, 14)); + bayesNet.push_front(boost::make_shared(10, 13, 14)); + bayesNet.push_front(boost::make_shared(9, 12, 14)); + bayesNet.push_front(boost::make_shared(8, 12, 14)); - bayesNet.push_front(boost::make_shared(7, 11, 13)); - bayesNet.push_front(boost::make_shared(6, 11, 13)); - bayesNet.push_front(boost::make_shared(5, 10, 13)); - bayesNet.push_front(boost::make_shared(4, 10, 13)); + bayesNet.push_front(boost::make_shared(7, 11, 13)); + bayesNet.push_front(boost::make_shared(6, 11, 13)); + bayesNet.push_front(boost::make_shared(5, 10, 13)); + bayesNet.push_front(boost::make_shared(4, 10, 13)); - bayesNet.push_front(boost::make_shared(3, 9, 12)); - bayesNet.push_front(boost::make_shared(2, 9, 12)); - bayesNet.push_front(boost::make_shared(1, 8, 12)); - bayesNet.push_front(boost::make_shared(0, 8, 12)); + bayesNet.push_front(boost::make_shared(3, 9, 12)); + bayesNet.push_front(boost::make_shared(2, 9, 12)); + bayesNet.push_front(boost::make_shared(1, 8, 12)); + bayesNet.push_front(boost::make_shared(0, 8, 12)); if (debug) { GTSAM_PRINT(bayesNet); @@ -62,95 +62,95 @@ TEST_UNSAFE( SymbolicBayesTree, thinTree ) { } // create a BayesTree out of a Bayes net - SymbolicBayesTree bayesTree(bayesNet); + SymbolicBayesTreeOrdered bayesTree(bayesNet); if (debug) { GTSAM_PRINT(bayesTree); bayesTree.saveGraph("/tmp/symbolicBayesTree.dot"); } - SymbolicBayesTree::Clique::shared_ptr R = bayesTree.root(); + SymbolicBayesTreeOrdered::Clique::shared_ptr R = bayesTree.root(); { // check shortcut P(S9||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[9]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[9]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S8||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[8]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(12, 14)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[8]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(12, 14)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S4||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[4]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(10, 13, 14)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[4]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(10, 13, 14)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S2||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[2]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(12, 14)); - expected.push_front(boost::make_shared(9, 12, 14)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[2]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(12, 14)); + expected.push_front(boost::make_shared(9, 12, 14)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S0||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[0]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(12, 14)); - expected.push_front(boost::make_shared(8, 12, 14)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[0]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(12, 14)); + expected.push_front(boost::make_shared(8, 12, 14)); EXPECT(assert_equal(expected, shortcut)); } - SymbolicBayesNet::shared_ptr actualJoint; + SymbolicBayesNetOrdered::shared_ptr actualJoint; // Check joint P(8,2) if (false) { // TODO, not disjoint actualJoint = bayesTree.jointBayesNet(8, 2, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(8)); - expected.push_front(boost::make_shared(2, 8)); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(8)); + expected.push_front(boost::make_shared(2, 8)); EXPECT(assert_equal(expected, *actualJoint)); } // Check joint P(1,2) if (false) { // TODO, not disjoint actualJoint = bayesTree.jointBayesNet(1, 2, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(2)); - expected.push_front(boost::make_shared(1, 2)); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(2)); + expected.push_front(boost::make_shared(1, 2)); EXPECT(assert_equal(expected, *actualJoint)); } // Check joint P(2,6) if (true) { actualJoint = bayesTree.jointBayesNet(2, 6, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(6)); - expected.push_front(boost::make_shared(2, 6)); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(6)); + expected.push_front(boost::make_shared(2, 6)); EXPECT(assert_equal(expected, *actualJoint)); } // Check joint P(4,6) if (false) { // TODO, not disjoint actualJoint = bayesTree.jointBayesNet(4, 6, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(6)); - expected.push_front(boost::make_shared(4, 6)); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(6)); + expected.push_front(boost::make_shared(4, 6)); EXPECT(assert_equal(expected, *actualJoint)); } } @@ -165,9 +165,9 @@ TEST_UNSAFE( SymbolicBayesTree, thinTree ) { C6 0 : 1 **************************************************************************** */ -TEST_UNSAFE( SymbolicBayesTree, linear_smoother_shortcuts ) { +TEST_UNSAFE( SymbolicBayesTreeOrdered, linear_smoother_shortcuts ) { // Create smoother with 7 nodes - SymbolicFactorGraph smoother; + SymbolicFactorGraphOrdered smoother; smoother.push_factor(0); smoother.push_factor(0, 1); smoother.push_factor(1, 2); @@ -176,7 +176,7 @@ TEST_UNSAFE( SymbolicBayesTree, linear_smoother_shortcuts ) { smoother.push_factor(4, 5); smoother.push_factor(5, 6); - BayesNet bayesNet = + BayesNetOrdered bayesNet = *SymbolicSequentialSolver(smoother).eliminate(); if (debug) { @@ -185,66 +185,66 @@ TEST_UNSAFE( SymbolicBayesTree, linear_smoother_shortcuts ) { } // create a BayesTree out of a Bayes net - SymbolicBayesTree bayesTree(bayesNet); + SymbolicBayesTreeOrdered bayesTree(bayesNet); if (debug) { GTSAM_PRINT(bayesTree); bayesTree.saveGraph("/tmp/symbolicBayesTree.dot"); } - SymbolicBayesTree::Clique::shared_ptr R = bayesTree.root(); + SymbolicBayesTreeOrdered::Clique::shared_ptr R = bayesTree.root(); { // check shortcut P(S2||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[4]; // 4 is frontal in C2 - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[4]; // 4 is frontal in C2 + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S3||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[3]; // 3 is frontal in C3 - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(4, 5)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[3]; // 3 is frontal in C3 + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(4, 5)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S4||R) to root - SymbolicBayesTree::Clique::shared_ptr c = bayesTree[2]; // 2 is frontal in C4 - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(3, 5)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[2]; // 2 is frontal in C4 + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(3, 5)); EXPECT(assert_equal(expected, shortcut)); } } /* ************************************************************************* */ // from testSymbolicJunctionTree, which failed at one point -TEST(SymbolicBayesTree, complicatedMarginal) { +TEST(SymbolicBayesTreeOrdered, complicatedMarginal) { // Create the conditionals to go in the BayesTree list L; L = list_of(1)(2)(5); - IndexConditional::shared_ptr R_1_2(new IndexConditional(L, 2)); + IndexConditionalOrdered::shared_ptr R_1_2(new IndexConditionalOrdered(L, 2)); L = list_of(3)(4)(6); - IndexConditional::shared_ptr R_3_4(new IndexConditional(L, 2)); + IndexConditionalOrdered::shared_ptr R_3_4(new IndexConditionalOrdered(L, 2)); L = list_of(5)(6)(7)(8); - IndexConditional::shared_ptr R_5_6(new IndexConditional(L, 2)); + IndexConditionalOrdered::shared_ptr R_5_6(new IndexConditionalOrdered(L, 2)); L = list_of(7)(8)(11); - IndexConditional::shared_ptr R_7_8(new IndexConditional(L, 2)); + IndexConditionalOrdered::shared_ptr R_7_8(new IndexConditionalOrdered(L, 2)); L = list_of(9)(10)(11)(12); - IndexConditional::shared_ptr R_9_10(new IndexConditional(L, 2)); + IndexConditionalOrdered::shared_ptr R_9_10(new IndexConditionalOrdered(L, 2)); L = list_of(11)(12); - IndexConditional::shared_ptr R_11_12(new IndexConditional(L, 2)); + IndexConditionalOrdered::shared_ptr R_11_12(new IndexConditionalOrdered(L, 2)); // Symbolic Bayes Tree - typedef SymbolicBayesTree::Clique Clique; - typedef SymbolicBayesTree::sharedClique sharedClique; + typedef SymbolicBayesTreeOrdered::Clique Clique; + typedef SymbolicBayesTreeOrdered::sharedClique sharedClique; // Create Bayes Tree - SymbolicBayesTree bt; + SymbolicBayesTreeOrdered bt; bt.insert(sharedClique(new Clique(R_11_12))); bt.insert(sharedClique(new Clique(R_9_10))); bt.insert(sharedClique(new Clique(R_7_8))); @@ -256,61 +256,61 @@ TEST(SymbolicBayesTree, complicatedMarginal) { bt.saveGraph("/tmp/symbolicBayesTree.dot"); } - SymbolicBayesTree::Clique::shared_ptr R = bt.root(); - SymbolicBayesNet empty; + SymbolicBayesTreeOrdered::Clique::shared_ptr R = bt.root(); + SymbolicBayesNetOrdered empty; // Shortcut on 9 { - SymbolicBayesTree::Clique::shared_ptr c = bt[9]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[9]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); EXPECT(assert_equal(empty, shortcut)); } // Shortcut on 7 { - SymbolicBayesTree::Clique::shared_ptr c = bt[7]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[7]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); EXPECT(assert_equal(empty, shortcut)); } // Shortcut on 5 { - SymbolicBayesTree::Clique::shared_ptr c = bt[5]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(8, 11)); - expected.push_front(boost::make_shared(7, 8, 11)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[5]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(8, 11)); + expected.push_front(boost::make_shared(7, 8, 11)); EXPECT(assert_equal(expected, shortcut)); } // Shortcut on 3 { - SymbolicBayesTree::Clique::shared_ptr c = bt[3]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(6, 11)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[3]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(6, 11)); EXPECT(assert_equal(expected, shortcut)); } // Shortcut on 1 { - SymbolicBayesTree::Clique::shared_ptr c = bt[1]; - SymbolicBayesNet shortcut = c->shortcut(R, EliminateSymbolic); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(5, 11)); + SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[1]; + SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(5, 11)); EXPECT(assert_equal(expected, shortcut)); } // Marginal on 5 { - IndexFactor::shared_ptr actual = bt.marginalFactor(5, EliminateSymbolic); - EXPECT(assert_equal(IndexFactor(5), *actual, 1e-1)); + IndexFactorOrdered::shared_ptr actual = bt.marginalFactor(5, EliminateSymbolic); + EXPECT(assert_equal(IndexFactorOrdered(5), *actual, 1e-1)); } // Shortcut on 6 { - IndexFactor::shared_ptr actual = bt.marginalFactor(6, EliminateSymbolic); - EXPECT(assert_equal(IndexFactor(6), *actual, 1e-1)); + IndexFactorOrdered::shared_ptr actual = bt.marginalFactor(6, EliminateSymbolic); + EXPECT(assert_equal(IndexFactorOrdered(6), *actual, 1e-1)); } } diff --git a/gtsam/inference/tests/testSymbolicFactorGraphObsolete.cpp b/gtsam/inference/tests/testSymbolicFactorGraphObsolete.cpp index 35c50eb9e..403cbf5f8 100644 --- a/gtsam/inference/tests/testSymbolicFactorGraphObsolete.cpp +++ b/gtsam/inference/tests/testSymbolicFactorGraphObsolete.cpp @@ -20,11 +20,11 @@ using namespace boost::assign; #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include using namespace std; using namespace gtsam; @@ -34,14 +34,14 @@ static const Index vx1 = 1; static const Index vl1 = 2; ///* ************************************************************************* */ -//TEST( SymbolicFactorGraph, EliminateOne ) +//TEST( SymbolicFactorGraphOrdered, EliminateOne ) //{ // // create a test graph -// SymbolicFactorGraph fg; +// SymbolicFactorGraphOrdered fg; // fg.push_factor(vx2, vx1); // // SymbolicSequentialSolver::EliminateUntil(fg, vx2+1); -// SymbolicFactorGraph expected; +// SymbolicFactorGraphOrdered expected; // expected.push_back(boost::shared_ptr()); // expected.push_factor(vx1); // @@ -49,35 +49,35 @@ static const Index vl1 = 2; //} /* ************************************************************************* */ -TEST( SymbolicFactorGraph, constructFromBayesNet ) +TEST( SymbolicFactorGraphOrdered, constructFromBayesNet ) { // create expected factor graph - SymbolicFactorGraph expected; + SymbolicFactorGraphOrdered expected; expected.push_factor(vx2, vx1, vl1); expected.push_factor(vx1, vl1); expected.push_factor(vx1); // create Bayes Net - IndexConditional::shared_ptr x2(new IndexConditional(vx2, vx1, vl1)); - IndexConditional::shared_ptr l1(new IndexConditional(vx1, vl1)); - IndexConditional::shared_ptr x1(new IndexConditional(vx1)); + IndexConditionalOrdered::shared_ptr x2(new IndexConditionalOrdered(vx2, vx1, vl1)); + IndexConditionalOrdered::shared_ptr l1(new IndexConditionalOrdered(vx1, vl1)); + IndexConditionalOrdered::shared_ptr x1(new IndexConditionalOrdered(vx1)); - BayesNet bayesNet; + BayesNetOrdered bayesNet; bayesNet.push_back(x2); bayesNet.push_back(l1); bayesNet.push_back(x1); // create actual factor graph from a Bayes Net - SymbolicFactorGraph actual(bayesNet); + SymbolicFactorGraphOrdered actual(bayesNet); - CHECK(assert_equal((SymbolicFactorGraph)expected,actual)); + CHECK(assert_equal((SymbolicFactorGraphOrdered)expected,actual)); } /* ************************************************************************* */ -TEST( SymbolicFactorGraph, push_back ) +TEST( SymbolicFactorGraphOrdered, push_back ) { // Create two factor graphs and expected combined graph - SymbolicFactorGraph fg1, fg2, expected; + SymbolicFactorGraphOrdered fg1, fg2, expected; fg1.push_factor(vx1); fg1.push_factor(vx2, vx1); @@ -91,7 +91,7 @@ TEST( SymbolicFactorGraph, push_back ) expected.push_factor(vx2, vl1); // combine - SymbolicFactorGraph actual = combine(fg1, fg2); + SymbolicFactorGraphOrdered actual = combine(fg1, fg2); CHECK(assert_equal(expected, actual)); // combine using push_back diff --git a/gtsam/inference/tests/testSymbolicFactorObsolete.cpp b/gtsam/inference/tests/testSymbolicFactorObsolete.cpp index a474c09a1..80e1eb83b 100644 --- a/gtsam/inference/tests/testSymbolicFactorObsolete.cpp +++ b/gtsam/inference/tests/testSymbolicFactorObsolete.cpp @@ -17,9 +17,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -33,32 +33,32 @@ TEST(SymbolicFactor, constructor) { // Frontals sorted, parents not sorted vector keys1; keys1 += 3, 4, 5, 9, 7, 8; - (void)IndexConditional(keys1, 3); + (void)IndexConditionalOrdered(keys1, 3); // // Frontals not sorted // vector keys2; keys2 += 3, 5, 4, 9, 7, 8; -// (void)IndexConditional::FromRange(keys2.begin(), keys2.end(), 3); +// (void)IndexConditionalOrdered::FromRange(keys2.begin(), keys2.end(), 3); // // Frontals not before parents // vector keys3; keys3 += 3, 4, 5, 1, 7, 8; -// (void)IndexConditional::FromRange(keys3.begin(), keys3.end(), 3); +// (void)IndexConditionalOrdered::FromRange(keys3.begin(), keys3.end(), 3); } /* ************************************************************************* */ #ifdef TRACK_ELIMINATE TEST(SymbolicFactor, eliminate) { vector keys; keys += 2, 3, 4, 6, 7, 9, 10, 11; - IndexFactor actual(keys.begin(), keys.end()); - BayesNet fragment = *actual.eliminate(3); + IndexFactorOrdered actual(keys.begin(), keys.end()); + BayesNetOrdered fragment = *actual.eliminate(3); - IndexFactor expected(keys.begin()+3, keys.end()); - IndexConditional::shared_ptr expected0 = IndexConditional::FromRange(keys.begin(), keys.end(), 1); - IndexConditional::shared_ptr expected1 = IndexConditional::FromRange(keys.begin()+1, keys.end(), 1); - IndexConditional::shared_ptr expected2 = IndexConditional::FromRange(keys.begin()+2, keys.end(), 1); + IndexFactorOrdered expected(keys.begin()+3, keys.end()); + IndexConditionalOrdered::shared_ptr expected0 = IndexConditionalOrdered::FromRange(keys.begin(), keys.end(), 1); + IndexConditionalOrdered::shared_ptr expected1 = IndexConditionalOrdered::FromRange(keys.begin()+1, keys.end(), 1); + IndexConditionalOrdered::shared_ptr expected2 = IndexConditionalOrdered::FromRange(keys.begin()+2, keys.end(), 1); CHECK(assert_equal(fragment.size(), size_t(3))); CHECK(assert_equal(expected, actual)); - BayesNet::const_iterator fragmentCond = fragment.begin(); + BayesNetOrdered::const_iterator fragmentCond = fragment.begin(); CHECK(assert_equal(**fragmentCond++, *expected0)); CHECK(assert_equal(**fragmentCond++, *expected1)); CHECK(assert_equal(**fragmentCond++, *expected2)); @@ -66,38 +66,38 @@ TEST(SymbolicFactor, eliminate) { #endif /* ************************************************************************* */ TEST(SymbolicFactor, EliminateSymbolic) { - SymbolicFactorGraph factors; + SymbolicFactorGraphOrdered factors; factors.push_factor(2,4,6); factors.push_factor(1,2,5); factors.push_factor(0,3); - IndexFactor expectedFactor(4,5,6); + IndexFactorOrdered expectedFactor(4,5,6); std::vector keys; keys += 0,1,2,3,4,5,6; - IndexConditional::shared_ptr expectedConditional(new IndexConditional(keys, 4)); + IndexConditionalOrdered::shared_ptr expectedConditional(new IndexConditionalOrdered(keys, 4)); - IndexFactor::shared_ptr actualFactor; - IndexConditional::shared_ptr actualConditional; + IndexFactorOrdered::shared_ptr actualFactor; + IndexConditionalOrdered::shared_ptr actualConditional; boost::tie(actualConditional, actualFactor) = EliminateSymbolic(factors, 4); CHECK(assert_equal(*expectedConditional, *actualConditional)); CHECK(assert_equal(expectedFactor, *actualFactor)); -// BayesNet expected_bn; +// BayesNetOrdered expected_bn; // vector parents; // // parents.clear(); parents += 1,2,3,4,5,6; -// expected_bn.push_back(IndexConditional::shared_ptr(new IndexConditional(0, parents))); +// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(0, parents))); // // parents.clear(); parents += 2,3,4,5,6; -// expected_bn.push_back(IndexConditional::shared_ptr(new IndexConditional(1, parents))); +// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(1, parents))); // // parents.clear(); parents += 3,4,5,6; -// expected_bn.push_back(IndexConditional::shared_ptr(new IndexConditional(2, parents))); +// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(2, parents))); // // parents.clear(); parents += 4,5,6; -// expected_bn.push_back(IndexConditional::shared_ptr(new IndexConditional(3, parents))); +// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(3, parents))); // -// BayesNet::shared_ptr actual_bn; +// BayesNetOrdered::shared_ptr actual_bn; // IndexFactor::shared_ptr actual_factor; // boost::tie(actual_bn, actual_factor) = EliminateSymbolic(factors, 4); // diff --git a/gtsam/inference/tests/testSymbolicSequentialSolverObsolete.cpp b/gtsam/inference/tests/testSymbolicSequentialSolverObsolete.cpp index c95bbdab5..abcad74cf 100644 --- a/gtsam/inference/tests/testSymbolicSequentialSolverObsolete.cpp +++ b/gtsam/inference/tests/testSymbolicSequentialSolverObsolete.cpp @@ -16,7 +16,7 @@ * @date Sept 16, 2012 */ -#include +#include #include @@ -30,7 +30,7 @@ using namespace gtsam; TEST( SymbolicSequentialSolver, SymbolicSequentialSolver ) { // create factor graph - SymbolicFactorGraph g; + SymbolicFactorGraphOrdered g; g.push_factor(2, 1, 0); g.push_factor(2, 0); g.push_factor(2); @@ -44,7 +44,7 @@ TEST( SymbolicSequentialSolver, SymbolicSequentialSolver ) { TEST( SymbolicSequentialSolver, inference ) { // Create factor graph - SymbolicFactorGraph fg; + SymbolicFactorGraphOrdered fg; fg.push_factor(0, 1); fg.push_factor(0, 2); fg.push_factor(1, 4); @@ -53,13 +53,13 @@ TEST( SymbolicSequentialSolver, inference ) { // eliminate SymbolicSequentialSolver solver(fg); - SymbolicBayesNet::shared_ptr actual = solver.eliminate(); - SymbolicBayesNet expected; - expected.push_front(boost::make_shared(4)); - expected.push_front(boost::make_shared(3, 4)); - expected.push_front(boost::make_shared(2, 4)); - expected.push_front(boost::make_shared(1, 2, 4)); - expected.push_front(boost::make_shared(0, 1, 2)); + SymbolicBayesNetOrdered::shared_ptr actual = solver.eliminate(); + SymbolicBayesNetOrdered expected; + expected.push_front(boost::make_shared(4)); + expected.push_front(boost::make_shared(3, 4)); + expected.push_front(boost::make_shared(2, 4)); + expected.push_front(boost::make_shared(1, 2, 4)); + expected.push_front(boost::make_shared(0, 1, 2)); EXPECT(assert_equal(expected,*actual)); { @@ -68,20 +68,20 @@ TEST( SymbolicSequentialSolver, inference ) { js.push_back(0); js.push_back(4); js.push_back(3); - SymbolicBayesNet::shared_ptr actualBN = solver.jointBayesNet(js); - SymbolicBayesNet expectedBN; - expectedBN.push_front(boost::make_shared(3)); - expectedBN.push_front(boost::make_shared(4, 3)); - expectedBN.push_front(boost::make_shared(0, 4)); + SymbolicBayesNetOrdered::shared_ptr actualBN = solver.jointBayesNet(js); + SymbolicBayesNetOrdered expectedBN; + expectedBN.push_front(boost::make_shared(3)); + expectedBN.push_front(boost::make_shared(4, 3)); + expectedBN.push_front(boost::make_shared(0, 4)); EXPECT( assert_equal(expectedBN,*actualBN)); // jointFactorGraph - SymbolicFactorGraph::shared_ptr actualFG = solver.jointFactorGraph(js); - SymbolicFactorGraph expectedFG; + SymbolicFactorGraphOrdered::shared_ptr actualFG = solver.jointFactorGraph(js); + SymbolicFactorGraphOrdered expectedFG; expectedFG.push_factor(0, 4); expectedFG.push_factor(4, 3); expectedFG.push_factor(3); - EXPECT( assert_equal(expectedFG,(SymbolicFactorGraph)(*actualFG))); + EXPECT( assert_equal(expectedFG,(SymbolicFactorGraphOrdered)(*actualFG))); } { @@ -90,20 +90,20 @@ TEST( SymbolicSequentialSolver, inference ) { js.push_back(0); js.push_back(2); js.push_back(3); - SymbolicBayesNet::shared_ptr actualBN = solver.jointBayesNet(js); - SymbolicBayesNet expectedBN; - expectedBN.push_front(boost::make_shared(2)); - expectedBN.push_front(boost::make_shared(3, 2)); - expectedBN.push_front(boost::make_shared(0, 3, 2)); + SymbolicBayesNetOrdered::shared_ptr actualBN = solver.jointBayesNet(js); + SymbolicBayesNetOrdered expectedBN; + expectedBN.push_front(boost::make_shared(2)); + expectedBN.push_front(boost::make_shared(3, 2)); + expectedBN.push_front(boost::make_shared(0, 3, 2)); EXPECT( assert_equal(expectedBN,*actualBN)); // jointFactorGraph - SymbolicFactorGraph::shared_ptr actualFG = solver.jointFactorGraph(js); - SymbolicFactorGraph expectedFG; + SymbolicFactorGraphOrdered::shared_ptr actualFG = solver.jointFactorGraph(js); + SymbolicFactorGraphOrdered expectedFG; expectedFG.push_factor(0, 3, 2); expectedFG.push_factor(3, 2); expectedFG.push_factor(2); - EXPECT( assert_equal(expectedFG,(SymbolicFactorGraph)(*actualFG))); + EXPECT( assert_equal(expectedFG,(SymbolicFactorGraphOrdered)(*actualFG))); } { @@ -113,11 +113,11 @@ TEST( SymbolicSequentialSolver, inference ) { js.push_back(2); js.push_back(3); size_t nrFrontals = 2; - SymbolicBayesNet::shared_ptr actualBN = // + SymbolicBayesNetOrdered::shared_ptr actualBN = // solver.conditionalBayesNet(js, nrFrontals); - SymbolicBayesNet expectedBN; - expectedBN.push_front(boost::make_shared(2, 3)); - expectedBN.push_front(boost::make_shared(0, 2, 3)); + SymbolicBayesNetOrdered expectedBN; + expectedBN.push_front(boost::make_shared(2, 3)); + expectedBN.push_front(boost::make_shared(0, 2, 3)); EXPECT( assert_equal(expectedBN,*actualBN)); } } diff --git a/gtsam/inference/tests/testVariableIndexObsolete.cpp b/gtsam/inference/tests/testVariableIndexObsolete.cpp index bc2af6565..a844879ad 100644 --- a/gtsam/inference/tests/testVariableIndexObsolete.cpp +++ b/gtsam/inference/tests/testVariableIndexObsolete.cpp @@ -19,16 +19,16 @@ #include #include -#include -#include +#include +#include using namespace std; using namespace gtsam; /* ************************************************************************* */ -TEST(VariableIndex, augment) { +TEST(VariableIndexOrdered, augment) { - SymbolicFactorGraph fg1, fg2; + SymbolicFactorGraphOrdered fg1, fg2; fg1.push_factor(0, 1); fg1.push_factor(0, 2); fg1.push_factor(5, 9); @@ -38,10 +38,10 @@ TEST(VariableIndex, augment) { fg2.push_factor(3, 5); fg2.push_factor(5, 6); - SymbolicFactorGraph fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); + SymbolicFactorGraphOrdered fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); - VariableIndex expected(fgCombined); - VariableIndex actual(fg1); + VariableIndexOrdered expected(fgCombined); + VariableIndexOrdered actual(fg1); actual.augment(fg2); LONGS_EQUAL(16, actual.nEntries()); @@ -50,9 +50,9 @@ TEST(VariableIndex, augment) { } /* ************************************************************************* */ -TEST(VariableIndex, remove) { +TEST(VariableIndexOrdered, remove) { - SymbolicFactorGraph fg1, fg2; + SymbolicFactorGraphOrdered fg1, fg2; fg1.push_factor(0, 1); fg1.push_factor(0, 2); fg1.push_factor(5, 9); @@ -62,17 +62,17 @@ TEST(VariableIndex, remove) { fg2.push_factor(3, 5); fg2.push_factor(5, 6); - SymbolicFactorGraph fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); + SymbolicFactorGraphOrdered fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); // Create a factor graph containing only the factors from fg2 and with null // factors in the place of those of fg1, so that the factor indices are correct. - SymbolicFactorGraph fg2removed(fgCombined); + SymbolicFactorGraphOrdered fg2removed(fgCombined); fg2removed.remove(0); fg2removed.remove(1); fg2removed.remove(2); fg2removed.remove(3); // The expected VariableIndex has the same factor indices as fgCombined but // with entries from fg1 removed, and still has all 10 variables. - VariableIndex expected(fg2removed, 10); - VariableIndex actual(fgCombined); + VariableIndexOrdered expected(fg2removed, 10); + VariableIndexOrdered actual(fgCombined); vector indices; indices.push_back(0); indices.push_back(1); indices.push_back(2); indices.push_back(3); actual.remove(indices, fg1); @@ -81,9 +81,9 @@ TEST(VariableIndex, remove) { } /* ************************************************************************* */ -TEST(VariableIndex, deep_copy) { +TEST(VariableIndexOrdered, deep_copy) { - SymbolicFactorGraph fg1, fg2; + SymbolicFactorGraphOrdered fg1, fg2; fg1.push_factor(0, 1); fg1.push_factor(0, 2); fg1.push_factor(5, 9); @@ -94,18 +94,18 @@ TEST(VariableIndex, deep_copy) { fg2.push_factor(5, 6); // Create original graph and VariableIndex - SymbolicFactorGraph fgOriginal; fgOriginal.push_back(fg1); fgOriginal.push_back(fg2); - VariableIndex original(fgOriginal); - VariableIndex expectedOriginal(fgOriginal); + SymbolicFactorGraphOrdered fgOriginal; fgOriginal.push_back(fg1); fgOriginal.push_back(fg2); + VariableIndexOrdered original(fgOriginal); + VariableIndexOrdered expectedOriginal(fgOriginal); // Create a factor graph containing only the factors from fg2 and with null // factors in the place of those of fg1, so that the factor indices are correct. - SymbolicFactorGraph fg2removed(fgOriginal); + SymbolicFactorGraphOrdered fg2removed(fgOriginal); fg2removed.remove(0); fg2removed.remove(1); fg2removed.remove(2); fg2removed.remove(3); - VariableIndex expectedRemoved(fg2removed); + VariableIndexOrdered expectedRemoved(fg2removed); // Create a clone and modify the clone - the original should not change - VariableIndex clone(original); + VariableIndexOrdered clone(original); vector indices; indices.push_back(0); indices.push_back(1); indices.push_back(2); indices.push_back(3); clone.remove(indices, fg1); diff --git a/gtsam/inference/tests/testVariableSlots.cpp b/gtsam/inference/tests/testVariableSlots.cpp index 1dd422908..5ef9c82df 100644 --- a/gtsam/inference/tests/testVariableSlots.cpp +++ b/gtsam/inference/tests/testVariableSlots.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include @@ -31,7 +31,7 @@ using namespace boost::assign; /* ************************************************************************* */ TEST(VariableSlots, constructor) { - SymbolicFactorGraph fg; + SymbolicFactorGraphOrdered fg; fg.push_factor(2, 3); fg.push_factor(0, 1); fg.push_factor(0, 2); @@ -40,7 +40,7 @@ TEST(VariableSlots, constructor) { VariableSlots actual(fg); static const size_t none = numeric_limits::max(); - VariableSlots expected((SymbolicFactorGraph())); + VariableSlots expected((SymbolicFactorGraphOrdered())); expected[0] += none, 0, 0, none; expected[1] += none, 1, none, none; expected[2] += 0, none, 1, none; diff --git a/gtsam/linear/Errors.cpp b/gtsam/linear/Errors.cpp index 1aae91869..839e2859b 100644 --- a/gtsam/linear/Errors.cpp +++ b/gtsam/linear/Errors.cpp @@ -28,7 +28,7 @@ namespace gtsam { Errors::Errors(){} /* ************************************************************************* */ -Errors::Errors(const VectorValues &V) { +Errors::Errors(const VectorValuesOrdered &V) { this->resize(V.size()) ; int i = 0 ; BOOST_FOREACH( Vector &e, *this) { diff --git a/gtsam/linear/Errors.h b/gtsam/linear/Errors.h index f3ccffb14..4233bc93f 100644 --- a/gtsam/linear/Errors.h +++ b/gtsam/linear/Errors.h @@ -19,7 +19,7 @@ #pragma once -#include +#include namespace gtsam { @@ -31,7 +31,7 @@ namespace gtsam { GTSAM_EXPORT Errors() ; /** break V into pieces according to its start indices */ - GTSAM_EXPORT Errors(const VectorValues &V) ; + GTSAM_EXPORT Errors(const VectorValuesOrdered &V) ; /** print */ GTSAM_EXPORT void print(const std::string& s = "Errors") const; diff --git a/gtsam/linear/GaussianBayesNet.cpp b/gtsam/linear/GaussianBayesNet.cpp index 8e1520235..b0027f770 100644 --- a/gtsam/linear/GaussianBayesNet.cpp +++ b/gtsam/linear/GaussianBayesNet.cpp @@ -17,239 +17,135 @@ #include #include -#include -#include +#include +#include #include -#include -#include - -#include using namespace std; using namespace gtsam; -// trick from some reading group #define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) #define REVERSE_FOREACH_PAIR( KEY, VAL, COL) BOOST_REVERSE_FOREACH (boost::tie(KEY,VAL),COL) namespace gtsam { -// Explicitly instantiate so we don't have to include everywhere -template class BayesNet; - -/* ************************************************************************* */ -GaussianBayesNet scalarGaussian(Index key, double mu, double sigma) { - GaussianBayesNet bn; - GaussianConditional::shared_ptr - conditional(new GaussianConditional(key, Vector_(1,mu)/sigma, eye(1)/sigma, ones(1))); - bn.push_back(conditional); - return bn; -} - -/* ************************************************************************* */ -GaussianBayesNet simpleGaussian(Index key, const Vector& mu, double sigma) { - GaussianBayesNet bn; - size_t n = mu.size(); - GaussianConditional::shared_ptr - conditional(new GaussianConditional(key, mu/sigma, eye(n)/sigma, ones(n))); - bn.push_back(conditional); - return bn; -} - -/* ************************************************************************* */ -void push_front(GaussianBayesNet& bn, Index key, Vector d, Matrix R, - Index name1, Matrix S, Vector sigmas) { - GaussianConditional::shared_ptr cg(new GaussianConditional(key, d, R, name1, S, sigmas)); - bn.push_front(cg); -} - -/* ************************************************************************* */ -void push_front(GaussianBayesNet& bn, Index key, Vector d, Matrix R, - Index name1, Matrix S, Index name2, Matrix T, Vector sigmas) { - GaussianConditional::shared_ptr cg(new GaussianConditional(key, d, R, name1, S, name2, T, sigmas)); - bn.push_front(cg); -} - -/* ************************************************************************* */ -boost::shared_ptr allocateVectorValues(const GaussianBayesNet& bn) { - vector dimensions(bn.size()); - Index var = 0; - BOOST_FOREACH(const boost::shared_ptr conditional, bn) { - dimensions[var++] = conditional->dim(); - } - return boost::shared_ptr(new VectorValues(dimensions)); -} - -/* ************************************************************************* */ -VectorValues optimize(const GaussianBayesNet& bn) { - VectorValues x = *allocateVectorValues(bn); - optimizeInPlace(bn, x); - return x; -} - -/* ************************************************************************* */ -// (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas) -void optimizeInPlace(const GaussianBayesNet& bn, VectorValues& x) { - /** solve each node in turn in topological sort order (parents first)*/ - BOOST_REVERSE_FOREACH(const boost::shared_ptr cg, bn) { - // 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:)) - cg->solveInPlace(x); - } -} - -/* ************************************************************************* */ -VectorValues backSubstitute(const GaussianBayesNet& bn, const VectorValues& input) { - VectorValues output = input; - BOOST_REVERSE_FOREACH(const boost::shared_ptr cg, bn) { - const Index key = *(cg->beginFrontals()); - Vector xS = internal::extractVectorValuesSlices(output, cg->beginParents(), cg->endParents()); - xS = input[key] - cg->get_S() * xS; - output[key] = cg->get_R().triangularView().solve(xS); + /* ************************************************************************* */ + bool GaussianBayesNet::equals(const This& bn, double tol) const + { + return Base::equals(bn, tol); } - BOOST_FOREACH(const boost::shared_ptr cg, bn) { - cg->scaleFrontalsBySigma(output); - } - - return output; -} - - -/* ************************************************************************* */ -// gy=inv(L)*gx by solving L*gy=gx. -// gy=inv(R'*inv(Sigma))*gx -// gz'*R'=gx', gy = gz.*sigmas -VectorValues backSubstituteTranspose(const GaussianBayesNet& bn, - const VectorValues& gx) { - - // Initialize gy from gx - // TODO: used to insert zeros if gx did not have an entry for a variable in bn - VectorValues gy = gx; - - // we loop from first-eliminated to last-eliminated - // i^th part of L*gy=gx is done block-column by block-column of L - BOOST_FOREACH(const boost::shared_ptr cg, bn) - cg->solveTransposeInPlace(gy); - - // Scale gy - BOOST_FOREACH(GaussianConditional::shared_ptr cg, bn) - cg->scaleFrontalsBySigma(gy); - - return gy; -} - -/* ************************************************************************* */ -VectorValues optimizeGradientSearch(const GaussianBayesNet& Rd) { - gttic(Allocate_VectorValues); - VectorValues grad = *allocateVectorValues(Rd); - gttoc(Allocate_VectorValues); - - optimizeGradientSearchInPlace(Rd, grad); - - return grad; -} - -/* ************************************************************************* */ -void optimizeGradientSearchInPlace(const GaussianBayesNet& Rd, VectorValues& grad) { - gttic(Compute_Gradient); - // Compute gradient (call gradientAtZero function, which is defined for various linear systems) - gradientAtZero(Rd, grad); - double gradientSqNorm = grad.dot(grad); - gttoc(Compute_Gradient); - - gttic(Compute_Rg); - // Compute R * g - FactorGraph Rd_jfg(Rd); - Errors Rg = Rd_jfg * grad; - gttoc(Compute_Rg); - - gttic(Compute_minimizing_step_size); - // Compute minimizing step size - double step = -gradientSqNorm / dot(Rg, Rg); - gttoc(Compute_minimizing_step_size); - - gttic(Compute_point); - // Compute steepest descent point - scal(step, grad); - gttoc(Compute_point); -} - -/* ************************************************************************* */ -pair matrix(const GaussianBayesNet& bn) { - - // add the dimensions of all variables to get matrix dimension - // and at the same time create a mapping from keys to indices - size_t N=0; map mapping; - BOOST_FOREACH(GaussianConditional::shared_ptr cg,bn) { - GaussianConditional::const_iterator it = cg->beginFrontals(); - for (; it != cg->endFrontals(); ++it) { - mapping.insert(make_pair(*it,N)); - N += cg->dim(it); + /* ************************************************************************* */ + VectorValues GaussianBayesNet::optimize() const + { + VectorValues soln; + // (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas) + /** solve each node in turn in topological sort order (parents first)*/ + BOOST_REVERSE_FOREACH(const sharedConditional& cg, *this) { + // 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:)) + soln.insert(cg->solve(soln)); } + return soln; } - // create matrix and copy in values - Matrix R = zeros(N,N); - Vector d(N); - Index key; size_t I; - FOREACH_PAIR(key,I,mapping) { - // find corresponding conditional - boost::shared_ptr cg = bn[key]; - - // get sigmas - Vector sigmas = cg->get_sigmas(); - - // get RHS and copy to d - GaussianConditional::const_d_type d_ = cg->get_d(); - const size_t n = d_.size(); - for (size_t i=0;iget_R(); - for (size_t i=0;ibeginParents(); - for (; keyS!=cg->endParents(); keyS++) { - Matrix S = cg->get_S(keyS); // get S matrix - const size_t m = S.rows(), n = S.cols(); // find S size - const size_t J = mapping[*keyS]; // find column index - for (size_t i=0;i cg, bayesNet){ - logDet += cg->get_R().diagonal().unaryExpr(ptr_fun(log)).sum(); + /* ************************************************************************* */ + VectorValues GaussianBayesNet::backSubstitute(const VectorValues& rhs) const + { + VectorValues result; + BOOST_REVERSE_FOREACH(const sharedConditional& cg, *this) { + result.insert(cg->solveOtherRHS(result, rhs)); + } + return result; } - return exp(logDet); -} -/* ************************************************************************* */ -VectorValues gradient(const GaussianBayesNet& bayesNet, const VectorValues& x0) { - return gradient(GaussianFactorGraph(bayesNet), x0); -} + /* ************************************************************************* */ + // gy=inv(L)*gx by solving L*gy=gx. + // gy=inv(R'*inv(Sigma))*gx + // gz'*R'=gx', gy = gz.*sigmas + VectorValues GaussianBayesNet::backSubstituteTranspose(const VectorValues& gx) const + { + // Initialize gy from gx + // TODO: used to insert zeros if gx did not have an entry for a variable in bn + VectorValues gy = gx; -/* ************************************************************************* */ -void gradientAtZero(const GaussianBayesNet& bayesNet, VectorValues& g) { - gradientAtZero(GaussianFactorGraph(bayesNet), g); -} + // we loop from first-eliminated to last-eliminated + // i^th part of L*gy=gx is done block-column by block-column of L + BOOST_FOREACH(const sharedConditional& cg, *this) + cg->solveTransposeInPlace(gy); -/* ************************************************************************* */ + return gy; + } + + ///* ************************************************************************* */ + //VectorValues GaussianBayesNet::optimizeGradientSearch() const + //{ + // gttic(Compute_Gradient); + // // Compute gradient (call gradientAtZero function, which is defined for various linear systems) + // VectorValues grad = gradientAtZero(); + // double gradientSqNorm = grad.dot(grad); + // gttoc(Compute_Gradient); + + // gttic(Compute_Rg); + // // Compute R * g + // Errors Rg = GaussianFactorGraph(*this) * grad; + // gttoc(Compute_Rg); + + // gttic(Compute_minimizing_step_size); + // // Compute minimizing step size + // double step = -gradientSqNorm / dot(Rg, Rg); + // gttoc(Compute_minimizing_step_size); + + // gttic(Compute_point); + // // Compute steepest descent point + // scal(step, grad); + // gttoc(Compute_point); + + // return grad; + //} + + /* ************************************************************************* */ + pair GaussianBayesNet::matrix() const + { + return GaussianFactorGraph(*this).jacobian(); + } + + ///* ************************************************************************* */ + //VectorValues GaussianBayesNet::gradient(const VectorValues& x0) const + //{ + // return GaussianFactorGraph(*this).gradient(x0); + //} + + ///* ************************************************************************* */ + //VectorValues GaussianBayesNet::gradientAtZero() const + //{ + // return GaussianFactorGraph(*this).gradientAtZero(); + //} + + /* ************************************************************************* */ + double GaussianBayesNet::determinant() const + { + return exp(logDeterminant()); + } + + /* ************************************************************************* */ + double GaussianBayesNet::logDeterminant() const + { + double logDet = 0.0; + BOOST_FOREACH(const sharedConditional& cg, *this) { + if(cg->get_model()) { + Vector diag = cg->get_R().diagonal(); + cg->get_model()->whitenInPlace(diag); + logDet += diag.unaryExpr(ptr_fun(log)).sum(); + } else { + logDet += cg->get_R().diagonal().unaryExpr(ptr_fun(log)).sum(); + } + } + return logDet; + } + + /* ************************************************************************* */ } // namespace gtsam diff --git a/gtsam/linear/GaussianBayesNet.h b/gtsam/linear/GaussianBayesNet.h index 3052e3926..ec5722c99 100644 --- a/gtsam/linear/GaussianBayesNet.h +++ b/gtsam/linear/GaussianBayesNet.h @@ -20,142 +20,156 @@ #pragma once -#include #include -#include +#include +#include namespace gtsam { /** A Bayes net made from linear-Gaussian densities */ - typedef BayesNet GaussianBayesNet; + class GTSAM_EXPORT GaussianBayesNet: public FactorGraph + { + public: - /** Create a scalar Gaussian */ - GTSAM_EXPORT GaussianBayesNet scalarGaussian(Index key, double mu=0.0, double sigma=1.0); + typedef FactorGraph Base; + typedef GaussianBayesNet This; + typedef GaussianConditional ConditionalType; + typedef boost::shared_ptr shared_ptr; + typedef boost::shared_ptr sharedConditional; - /** Create a simple Gaussian on a single multivariate variable */ - GTSAM_EXPORT GaussianBayesNet simpleGaussian(Index key, const Vector& mu, double sigma=1.0); + /// @name Standard Constructors + /// @{ - /** - * Add a conditional node with one parent - * |Rx+Sy-d| - */ - GTSAM_EXPORT void push_front(GaussianBayesNet& bn, Index key, Vector d, Matrix R, - Index name1, Matrix S, Vector sigmas); + /** Construct empty factor graph */ + GaussianBayesNet() {} - /** - * Add a conditional node with two parents - * |Rx+Sy+Tz-d| - */ - GTSAM_EXPORT void push_front(GaussianBayesNet& bn, Index key, Vector d, Matrix R, - Index name1, Matrix S, Index name2, Matrix T, Vector sigmas); + /** Construct from iterator over conditionals */ + template + GaussianBayesNet(ITERATOR firstConditional, ITERATOR lastConditional) : Base(firstConditional, lastConditional) {} - /** - * Allocate a VectorValues for the variables in a BayesNet - */ - GTSAM_EXPORT boost::shared_ptr allocateVectorValues(const GaussianBayesNet& bn); + /** Construct from container of factors (shared_ptr or plain objects) */ + template + explicit GaussianBayesNet(const CONTAINER& conditionals) : Base(conditionals) {} - /** - * Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by - * back-substitution. - */ - GTSAM_EXPORT VectorValues optimize(const GaussianBayesNet& bn); + /** Implicit copy/downcast constructor to override explicit template container constructor */ + template + GaussianBayesNet(const FactorGraph& graph) : Base(graph) {} - /** - * Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by - * back-substitution, writes the solution \f$ x \f$ into a pre-allocated - * VectorValues. You can use allocateVectorValues(const GaussianBayesNet&) - * allocate it. See also optimize(const GaussianBayesNet&), which does not - * require pre-allocation. - */ - GTSAM_EXPORT void optimizeInPlace(const GaussianBayesNet& bn, VectorValues& x); + /** - /** - * Optimize along the gradient direction, with a closed-form computation to - * perform the line search. The gradient is computed about \f$ \delta x=0 \f$. - * - * This function returns \f$ \delta x \f$ that minimizes a reparametrized - * problem. The error function of a GaussianBayesNet is - * - * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f] - * - * with gradient and Hessian - * - * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] - * - * This function performs the line search in the direction of the - * gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size - * \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$: - * - * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] - * - * Optimizing by setting the derivative to zero yields - * \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function - * evaluates the denominator without computing the Hessian \f$ G \f$, returning - * - * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] - * - * @param bn The GaussianBayesNet on which to perform this computation - * @return The resulting \f$ \delta x \f$ as described above - */ - GTSAM_EXPORT VectorValues optimizeGradientSearch(const GaussianBayesNet& bn); + /// @} - /** In-place version of optimizeGradientSearch(const GaussianBayesNet&) requiring pre-allocated VectorValues \c grad - * - * @param bn The GaussianBayesNet on which to perform this computation - * @param [out] grad The resulting \f$ \delta x \f$ as described in optimizeGradientSearch(const GaussianBayesNet&) - * */ - GTSAM_EXPORT void optimizeGradientSearchInPlace(const GaussianBayesNet& bn, VectorValues& grad); + /// @name Testable + /// @{ - /** - * Backsubstitute - * gy=inv(R*inv(Sigma))*gx - */ - GTSAM_EXPORT VectorValues backSubstitute(const GaussianBayesNet& bn, const VectorValues& gx); + /** Check equality */ + bool equals(const This& bn, double tol = 1e-9) const; - /** - * Transpose Backsubstitute - * gy=inv(L)*gx by solving L*gy=gx. - * gy=inv(R'*inv(Sigma))*gx - * gz'*R'=gx', gy = gz.*sigmas - */ - GTSAM_EXPORT VectorValues backSubstituteTranspose(const GaussianBayesNet& bn, const VectorValues& gx); + /// @} - /** - * Return (dense) upper-triangular matrix representation - */ - GTSAM_EXPORT std::pair matrix(const GaussianBayesNet&); + /// @name Standard Interface + /// @{ - /** - * Computes the determinant of a GassianBayesNet - * A GaussianBayesNet is an upper triangular matrix and for an upper triangular matrix - * determinant is the product of the diagonal elements. Instead of actually multiplying - * we add the logarithms of the diagonal elements and take the exponent at the end - * because this is more numerically stable. - * @param bayesNet The input GaussianBayesNet - * @return The determinant - */ - GTSAM_EXPORT double determinant(const GaussianBayesNet& bayesNet); + /** + * Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by + * back-substitution. + */ + VectorValues optimize() const; - /** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, - * centered around \f$ x = x_0 \f$. - * The gradient is \f$ R^T(Rx-d) \f$. - * @param bayesNet The Gaussian Bayes net $(R,d)$ - * @param x0 The center about which to compute the gradient - * @return The gradient as a VectorValues - */ - GTSAM_EXPORT VectorValues gradient(const GaussianBayesNet& bayesNet, const VectorValues& x0); + /** + * Optimize along the gradient direction, with a closed-form computation to + * perform the line search. The gradient is computed about \f$ \delta x=0 \f$. + * + * This function returns \f$ \delta x \f$ that minimizes a reparametrized + * problem. The error function of a GaussianBayesNet is + * + * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f] + * + * with gradient and Hessian + * + * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] + * + * This function performs the line search in the direction of the + * gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size + * \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$: + * + * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] + * + * Optimizing by setting the derivative to zero yields + * \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function + * evaluates the denominator without computing the Hessian \f$ G \f$, returning + * + * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] + * + * @param bn The GaussianBayesNet on which to perform this computation + * @return The resulting \f$ \delta x \f$ as described above + */ + //VectorValues optimizeGradientSearch() const; - /** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, - * centered around zero. - * The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&). - * @param bayesNet The Gaussian Bayes net $(R,d)$ - * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues - * @return The gradient as a VectorValues - */ - GTSAM_EXPORT void gradientAtZero(const GaussianBayesNet& bayesNet, VectorValues& g); + ///@} + + ///@name Linear Algebra + ///@{ + + /** + * Return (dense) upper-triangular matrix representation + */ + std::pair matrix() const; + + /** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, + * centered around \f$ x = x_0 \f$. + * The gradient is \f$ R^T(Rx-d) \f$. + * @param bayesNet The Gaussian Bayes net $(R,d)$ + * @param x0 The center about which to compute the gradient + * @return The gradient as a VectorValues + */ + //VectorValues gradient(const VectorValues& x0) const; + + /** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, + * centered around zero. + * The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&). + * @param bayesNet The Gaussian Bayes net $(R,d)$ + * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues + * @return The gradient as a VectorValues + */ + //VectorValues gradientAtZero() const; + + /** + * Computes the determinant of a GassianBayesNet. A GaussianBayesNet is an upper triangular + * matrix and for an upper triangular matrix determinant is the product of the diagonal + * elements. Instead of actually multiplying we add the logarithms of the diagonal elements and + * take the exponent at the end because this is more numerically stable. + * @param bayesNet The input GaussianBayesNet + * @return The determinant */ + double determinant() const; + + /** + * Computes the log of the determinant of a GassianBayesNet. A GaussianBayesNet is an upper + * triangular matrix and for an upper triangular matrix determinant is the product of the + * diagonal elements. + * @param bayesNet The input GaussianBayesNet + * @return The determinant */ + double logDeterminant() const; + + /** + * Backsubstitute with a different RHS vector than the one stored in this BayesNet. + * gy=inv(R*inv(Sigma))*gx + */ + VectorValues backSubstitute(const VectorValues& gx) const; + + /** + * Transpose backsubstitute with a different RHS vector than the one stored in this BayesNet. + * gy=inv(L)*gx by solving L*gy=gx. + * gy=inv(R'*inv(Sigma))*gx + * gz'*R'=gx', gy = gz.*sigmas + */ + VectorValues backSubstituteTranspose(const VectorValues& gx) const; + + /// @} + }; } /// namespace gtsam diff --git a/gtsam/linear/GaussianBayesNetOrdered.cpp b/gtsam/linear/GaussianBayesNetOrdered.cpp new file mode 100644 index 000000000..eaa7edb0f --- /dev/null +++ b/gtsam/linear/GaussianBayesNetOrdered.cpp @@ -0,0 +1,255 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianBayesNet.cpp + * @brief Chordal Bayes Net, the result of eliminating a factor graph + * @author Frank Dellaert + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace gtsam; + +// trick from some reading group +#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) +#define REVERSE_FOREACH_PAIR( KEY, VAL, COL) BOOST_REVERSE_FOREACH (boost::tie(KEY,VAL),COL) + +namespace gtsam { + +// Explicitly instantiate so we don't have to include everywhere +template class BayesNetOrdered; + +/* ************************************************************************* */ +GaussianBayesNetOrdered scalarGaussian(Index key, double mu, double sigma) { + GaussianBayesNetOrdered bn; + GaussianConditionalOrdered::shared_ptr + conditional(new GaussianConditionalOrdered(key, Vector_(1,mu)/sigma, eye(1)/sigma, ones(1))); + bn.push_back(conditional); + return bn; +} + +/* ************************************************************************* */ +GaussianBayesNetOrdered simpleGaussian(Index key, const Vector& mu, double sigma) { + GaussianBayesNetOrdered bn; + size_t n = mu.size(); + GaussianConditionalOrdered::shared_ptr + conditional(new GaussianConditionalOrdered(key, mu/sigma, eye(n)/sigma, ones(n))); + bn.push_back(conditional); + return bn; +} + +/* ************************************************************************* */ +void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R, + Index name1, Matrix S, Vector sigmas) { + GaussianConditionalOrdered::shared_ptr cg(new GaussianConditionalOrdered(key, d, R, name1, S, sigmas)); + bn.push_front(cg); +} + +/* ************************************************************************* */ +void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R, + Index name1, Matrix S, Index name2, Matrix T, Vector sigmas) { + GaussianConditionalOrdered::shared_ptr cg(new GaussianConditionalOrdered(key, d, R, name1, S, name2, T, sigmas)); + bn.push_front(cg); +} + +/* ************************************************************************* */ +boost::shared_ptr allocateVectorValues(const GaussianBayesNetOrdered& bn) { + vector dimensions(bn.size()); + Index var = 0; + BOOST_FOREACH(const boost::shared_ptr conditional, bn) { + dimensions[var++] = conditional->dim(); + } + return boost::shared_ptr(new VectorValuesOrdered(dimensions)); +} + +/* ************************************************************************* */ +VectorValuesOrdered optimize(const GaussianBayesNetOrdered& bn) { + VectorValuesOrdered x = *allocateVectorValues(bn); + optimizeInPlace(bn, x); + return x; +} + +/* ************************************************************************* */ +// (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas) +void optimizeInPlace(const GaussianBayesNetOrdered& bn, VectorValuesOrdered& x) { + /** solve each node in turn in topological sort order (parents first)*/ + BOOST_REVERSE_FOREACH(const boost::shared_ptr cg, bn) { + // 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:)) + cg->solveInPlace(x); + } +} + +/* ************************************************************************* */ +VectorValuesOrdered backSubstitute(const GaussianBayesNetOrdered& bn, const VectorValuesOrdered& input) { + VectorValuesOrdered output = input; + BOOST_REVERSE_FOREACH(const boost::shared_ptr cg, bn) { + const Index key = *(cg->beginFrontals()); + Vector xS = internal::extractVectorValuesSlices(output, cg->beginParents(), cg->endParents()); + xS = input[key] - cg->get_S() * xS; + output[key] = cg->get_R().triangularView().solve(xS); + } + + BOOST_FOREACH(const boost::shared_ptr cg, bn) { + cg->scaleFrontalsBySigma(output); + } + + return output; +} + + +/* ************************************************************************* */ +// gy=inv(L)*gx by solving L*gy=gx. +// gy=inv(R'*inv(Sigma))*gx +// gz'*R'=gx', gy = gz.*sigmas +VectorValuesOrdered backSubstituteTranspose(const GaussianBayesNetOrdered& bn, + const VectorValuesOrdered& gx) { + + // Initialize gy from gx + // TODO: used to insert zeros if gx did not have an entry for a variable in bn + VectorValuesOrdered gy = gx; + + // we loop from first-eliminated to last-eliminated + // i^th part of L*gy=gx is done block-column by block-column of L + BOOST_FOREACH(const boost::shared_ptr cg, bn) + cg->solveTransposeInPlace(gy); + + // Scale gy + BOOST_FOREACH(GaussianConditionalOrdered::shared_ptr cg, bn) + cg->scaleFrontalsBySigma(gy); + + return gy; +} + +/* ************************************************************************* */ +VectorValuesOrdered optimizeGradientSearch(const GaussianBayesNetOrdered& Rd) { + gttic(Allocate_VectorValues); + VectorValuesOrdered grad = *allocateVectorValues(Rd); + gttoc(Allocate_VectorValues); + + optimizeGradientSearchInPlace(Rd, grad); + + return grad; +} + +/* ************************************************************************* */ +void optimizeGradientSearchInPlace(const GaussianBayesNetOrdered& Rd, VectorValuesOrdered& grad) { + gttic(Compute_Gradient); + // Compute gradient (call gradientAtZero function, which is defined for various linear systems) + gradientAtZero(Rd, grad); + double gradientSqNorm = grad.dot(grad); + gttoc(Compute_Gradient); + + gttic(Compute_Rg); + // Compute R * g + FactorGraphOrdered Rd_jfg(Rd); + Errors Rg = Rd_jfg * grad; + gttoc(Compute_Rg); + + gttic(Compute_minimizing_step_size); + // Compute minimizing step size + double step = -gradientSqNorm / dot(Rg, Rg); + gttoc(Compute_minimizing_step_size); + + gttic(Compute_point); + // Compute steepest descent point + scal(step, grad); + gttoc(Compute_point); +} + +/* ************************************************************************* */ +pair matrix(const GaussianBayesNetOrdered& bn) { + + // add the dimensions of all variables to get matrix dimension + // and at the same time create a mapping from keys to indices + size_t N=0; map mapping; + BOOST_FOREACH(GaussianConditionalOrdered::shared_ptr cg,bn) { + GaussianConditionalOrdered::const_iterator it = cg->beginFrontals(); + for (; it != cg->endFrontals(); ++it) { + mapping.insert(make_pair(*it,N)); + N += cg->dim(it); + } + } + + // create matrix and copy in values + Matrix R = zeros(N,N); + Vector d(N); + Index key; size_t I; + FOREACH_PAIR(key,I,mapping) { + // find corresponding conditional + boost::shared_ptr cg = bn[key]; + + // get sigmas + Vector sigmas = cg->get_sigmas(); + + // get RHS and copy to d + GaussianConditionalOrdered::const_d_type d_ = cg->get_d(); + const size_t n = d_.size(); + for (size_t i=0;iget_R(); + for (size_t i=0;ibeginParents(); + for (; keyS!=cg->endParents(); keyS++) { + Matrix S = cg->get_S(keyS); // get S matrix + const size_t m = S.rows(), n = S.cols(); // find S size + const size_t J = mapping[*keyS]; // find column index + for (size_t i=0;i cg, bayesNet){ + logDet += cg->get_R().diagonal().unaryExpr(ptr_fun(log)).sum(); + } + + return exp(logDet); +} + +/* ************************************************************************* */ +VectorValuesOrdered gradient(const GaussianBayesNetOrdered& bayesNet, const VectorValuesOrdered& x0) { + return gradient(GaussianFactorGraphOrdered(bayesNet), x0); +} + +/* ************************************************************************* */ +void gradientAtZero(const GaussianBayesNetOrdered& bayesNet, VectorValuesOrdered& g) { + gradientAtZero(GaussianFactorGraphOrdered(bayesNet), g); +} + +/* ************************************************************************* */ + +} // namespace gtsam diff --git a/gtsam/linear/GaussianBayesNetOrdered.h b/gtsam/linear/GaussianBayesNetOrdered.h new file mode 100644 index 000000000..f95565da4 --- /dev/null +++ b/gtsam/linear/GaussianBayesNetOrdered.h @@ -0,0 +1,161 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianBayesNet.h + * @brief Chordal Bayes Net, the result of eliminating a factor graph + * @brief GaussianBayesNet + * @author Frank Dellaert + */ + +// \callgraph + +#pragma once + +#include +#include +#include + +namespace gtsam { + + /** A Bayes net made from linear-Gaussian densities */ + typedef BayesNetOrdered GaussianBayesNetOrdered; + + /** Create a scalar Gaussian */ + GTSAM_EXPORT GaussianBayesNetOrdered scalarGaussian(Index key, double mu=0.0, double sigma=1.0); + + /** Create a simple Gaussian on a single multivariate variable */ + GTSAM_EXPORT GaussianBayesNetOrdered simpleGaussian(Index key, const Vector& mu, double sigma=1.0); + + /** + * Add a conditional node with one parent + * |Rx+Sy-d| + */ + GTSAM_EXPORT void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R, + Index name1, Matrix S, Vector sigmas); + + /** + * Add a conditional node with two parents + * |Rx+Sy+Tz-d| + */ + GTSAM_EXPORT void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R, + Index name1, Matrix S, Index name2, Matrix T, Vector sigmas); + + /** + * Allocate a VectorValues for the variables in a BayesNet + */ + GTSAM_EXPORT boost::shared_ptr allocateVectorValues(const GaussianBayesNetOrdered& bn); + + /** + * Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by + * back-substitution. + */ + GTSAM_EXPORT VectorValuesOrdered optimize(const GaussianBayesNetOrdered& bn); + + /** + * Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by + * back-substitution, writes the solution \f$ x \f$ into a pre-allocated + * VectorValues. You can use allocateVectorValues(const GaussianBayesNet&) + * allocate it. See also optimize(const GaussianBayesNet&), which does not + * require pre-allocation. + */ + GTSAM_EXPORT void optimizeInPlace(const GaussianBayesNetOrdered& bn, VectorValuesOrdered& x); + + /** + * Optimize along the gradient direction, with a closed-form computation to + * perform the line search. The gradient is computed about \f$ \delta x=0 \f$. + * + * This function returns \f$ \delta x \f$ that minimizes a reparametrized + * problem. The error function of a GaussianBayesNet is + * + * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f] + * + * with gradient and Hessian + * + * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] + * + * This function performs the line search in the direction of the + * gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size + * \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$: + * + * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] + * + * Optimizing by setting the derivative to zero yields + * \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function + * evaluates the denominator without computing the Hessian \f$ G \f$, returning + * + * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] + * + * @param bn The GaussianBayesNet on which to perform this computation + * @return The resulting \f$ \delta x \f$ as described above + */ + GTSAM_EXPORT VectorValuesOrdered optimizeGradientSearch(const GaussianBayesNetOrdered& bn); + + /** In-place version of optimizeGradientSearch(const GaussianBayesNet&) requiring pre-allocated VectorValues \c grad + * + * @param bn The GaussianBayesNet on which to perform this computation + * @param [out] grad The resulting \f$ \delta x \f$ as described in optimizeGradientSearch(const GaussianBayesNet&) + * */ + GTSAM_EXPORT void optimizeGradientSearchInPlace(const GaussianBayesNetOrdered& bn, VectorValuesOrdered& grad); + + /** + * Backsubstitute + * gy=inv(R*inv(Sigma))*gx + */ + GTSAM_EXPORT VectorValuesOrdered backSubstitute(const GaussianBayesNetOrdered& bn, const VectorValuesOrdered& gx); + + /** + * Transpose Backsubstitute + * gy=inv(L)*gx by solving L*gy=gx. + * gy=inv(R'*inv(Sigma))*gx + * gz'*R'=gx', gy = gz.*sigmas + */ + GTSAM_EXPORT VectorValuesOrdered backSubstituteTranspose(const GaussianBayesNetOrdered& bn, const VectorValuesOrdered& gx); + + /** + * Return (dense) upper-triangular matrix representation + */ + GTSAM_EXPORT std::pair matrix(const GaussianBayesNetOrdered&); + + /** + * Computes the determinant of a GassianBayesNet + * A GaussianBayesNet is an upper triangular matrix and for an upper triangular matrix + * determinant is the product of the diagonal elements. Instead of actually multiplying + * we add the logarithms of the diagonal elements and take the exponent at the end + * because this is more numerically stable. + * @param bayesNet The input GaussianBayesNet + * @return The determinant + */ + GTSAM_EXPORT double determinant(const GaussianBayesNetOrdered& bayesNet); + + /** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, + * centered around \f$ x = x_0 \f$. + * The gradient is \f$ R^T(Rx-d) \f$. + * @param bayesNet The Gaussian Bayes net $(R,d)$ + * @param x0 The center about which to compute the gradient + * @return The gradient as a VectorValues + */ + GTSAM_EXPORT VectorValuesOrdered gradient(const GaussianBayesNetOrdered& bayesNet, const VectorValuesOrdered& x0); + + /** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, + * centered around zero. + * The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&). + * @param bayesNet The Gaussian Bayes net $(R,d)$ + * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues + * @return The gradient as a VectorValues + */ + GTSAM_EXPORT void gradientAtZero(const GaussianBayesNetOrdered& bayesNet, VectorValuesOrdered& g); + +} /// namespace gtsam diff --git a/gtsam/linear/GaussianBayesNetUnordered.cpp b/gtsam/linear/GaussianBayesNetUnordered.cpp deleted file mode 100644 index 39658a483..000000000 --- a/gtsam/linear/GaussianBayesNetUnordered.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianBayesNet.cpp - * @brief Chordal Bayes Net, the result of eliminating a factor graph - * @author Frank Dellaert - */ - -#include -#include -#include -#include - -#include - -using namespace std; -using namespace gtsam; - -#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) -#define REVERSE_FOREACH_PAIR( KEY, VAL, COL) BOOST_REVERSE_FOREACH (boost::tie(KEY,VAL),COL) - -namespace gtsam { - - /* ************************************************************************* */ - bool GaussianBayesNetUnordered::equals(const This& bn, double tol) const - { - return Base::equals(bn, tol); - } - - /* ************************************************************************* */ - VectorValuesUnordered GaussianBayesNetUnordered::optimize() const - { - VectorValuesUnordered soln; - // (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas) - /** solve each node in turn in topological sort order (parents first)*/ - BOOST_REVERSE_FOREACH(const sharedConditional& cg, *this) { - // 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:)) - soln.insert(cg->solve(soln)); - } - return soln; - } - - /* ************************************************************************* */ - VectorValuesUnordered GaussianBayesNetUnordered::backSubstitute(const VectorValuesUnordered& rhs) const - { - VectorValuesUnordered result; - BOOST_REVERSE_FOREACH(const sharedConditional& cg, *this) { - result.insert(cg->solveOtherRHS(result, rhs)); - } - return result; - } - - - /* ************************************************************************* */ - // gy=inv(L)*gx by solving L*gy=gx. - // gy=inv(R'*inv(Sigma))*gx - // gz'*R'=gx', gy = gz.*sigmas - VectorValuesUnordered GaussianBayesNetUnordered::backSubstituteTranspose(const VectorValuesUnordered& gx) const - { - // Initialize gy from gx - // TODO: used to insert zeros if gx did not have an entry for a variable in bn - VectorValuesUnordered gy = gx; - - // we loop from first-eliminated to last-eliminated - // i^th part of L*gy=gx is done block-column by block-column of L - BOOST_FOREACH(const sharedConditional& cg, *this) - cg->solveTransposeInPlace(gy); - - return gy; - } - - ///* ************************************************************************* */ - //VectorValuesUnordered GaussianBayesNetUnordered::optimizeGradientSearch() const - //{ - // gttic(Compute_Gradient); - // // Compute gradient (call gradientAtZero function, which is defined for various linear systems) - // VectorValuesUnordered grad = gradientAtZero(); - // double gradientSqNorm = grad.dot(grad); - // gttoc(Compute_Gradient); - - // gttic(Compute_Rg); - // // Compute R * g - // Errors Rg = GaussianFactorGraphUnordered(*this) * grad; - // gttoc(Compute_Rg); - - // gttic(Compute_minimizing_step_size); - // // Compute minimizing step size - // double step = -gradientSqNorm / dot(Rg, Rg); - // gttoc(Compute_minimizing_step_size); - - // gttic(Compute_point); - // // Compute steepest descent point - // scal(step, grad); - // gttoc(Compute_point); - - // return grad; - //} - - /* ************************************************************************* */ - pair GaussianBayesNetUnordered::matrix() const - { - return GaussianFactorGraphUnordered(*this).jacobian(); - } - - ///* ************************************************************************* */ - //VectorValuesUnordered GaussianBayesNetUnordered::gradient(const VectorValuesUnordered& x0) const - //{ - // return GaussianFactorGraphUnordered(*this).gradient(x0); - //} - - ///* ************************************************************************* */ - //VectorValuesUnordered GaussianBayesNetUnordered::gradientAtZero() const - //{ - // return GaussianFactorGraphUnordered(*this).gradientAtZero(); - //} - - /* ************************************************************************* */ - double GaussianBayesNetUnordered::determinant() const - { - return exp(logDeterminant()); - } - - /* ************************************************************************* */ - double GaussianBayesNetUnordered::logDeterminant() const - { - double logDet = 0.0; - BOOST_FOREACH(const sharedConditional& cg, *this) { - if(cg->get_model()) { - Vector diag = cg->get_R().diagonal(); - cg->get_model()->whitenInPlace(diag); - logDet += diag.unaryExpr(ptr_fun(log)).sum(); - } else { - logDet += cg->get_R().diagonal().unaryExpr(ptr_fun(log)).sum(); - } - } - return logDet; - } - - /* ************************************************************************* */ - -} // namespace gtsam diff --git a/gtsam/linear/GaussianBayesNetUnordered.h b/gtsam/linear/GaussianBayesNetUnordered.h deleted file mode 100644 index a29d8096c..000000000 --- a/gtsam/linear/GaussianBayesNetUnordered.h +++ /dev/null @@ -1,175 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianBayesNet.h - * @brief Chordal Bayes Net, the result of eliminating a factor graph - * @brief GaussianBayesNet - * @author Frank Dellaert - */ - -// \callgraph - -#pragma once - -#include -#include -#include - -namespace gtsam { - - /** A Bayes net made from linear-Gaussian densities */ - class GTSAM_EXPORT GaussianBayesNetUnordered: public FactorGraphUnordered - { - public: - - typedef FactorGraphUnordered Base; - typedef GaussianBayesNetUnordered This; - typedef GaussianConditionalUnordered ConditionalType; - typedef boost::shared_ptr shared_ptr; - typedef boost::shared_ptr sharedConditional; - - /// @name Standard Constructors - /// @{ - - /** Construct empty factor graph */ - GaussianBayesNetUnordered() {} - - /** Construct from iterator over conditionals */ - template - GaussianBayesNetUnordered(ITERATOR firstConditional, ITERATOR lastConditional) : Base(firstConditional, lastConditional) {} - - /** Construct from container of factors (shared_ptr or plain objects) */ - template - explicit GaussianBayesNetUnordered(const CONTAINER& conditionals) : Base(conditionals) {} - - /** Implicit copy/downcast constructor to override explicit template container constructor */ - template - GaussianBayesNetUnordered(const FactorGraphUnordered& graph) : Base(graph) {} - - /** - - /// @} - - /// @name Testable - /// @{ - - /** Check equality */ - bool equals(const This& bn, double tol = 1e-9) const; - - /// @} - - /// @name Standard Interface - /// @{ - - /** - * Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by - * back-substitution. - */ - VectorValuesUnordered optimize() const; - - /** - * Optimize along the gradient direction, with a closed-form computation to - * perform the line search. The gradient is computed about \f$ \delta x=0 \f$. - * - * This function returns \f$ \delta x \f$ that minimizes a reparametrized - * problem. The error function of a GaussianBayesNet is - * - * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f] - * - * with gradient and Hessian - * - * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] - * - * This function performs the line search in the direction of the - * gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size - * \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$: - * - * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] - * - * Optimizing by setting the derivative to zero yields - * \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function - * evaluates the denominator without computing the Hessian \f$ G \f$, returning - * - * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] - * - * @param bn The GaussianBayesNet on which to perform this computation - * @return The resulting \f$ \delta x \f$ as described above - */ - //VectorValuesUnordered optimizeGradientSearch() const; - - ///@} - - ///@name Linear Algebra - ///@{ - - /** - * Return (dense) upper-triangular matrix representation - */ - std::pair matrix() const; - - /** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, - * centered around \f$ x = x_0 \f$. - * The gradient is \f$ R^T(Rx-d) \f$. - * @param bayesNet The Gaussian Bayes net $(R,d)$ - * @param x0 The center about which to compute the gradient - * @return The gradient as a VectorValues - */ - //VectorValuesUnordered gradient(const VectorValuesUnordered& x0) const; - - /** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, - * centered around zero. - * The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&). - * @param bayesNet The Gaussian Bayes net $(R,d)$ - * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues - * @return The gradient as a VectorValues - */ - //VectorValuesUnordered gradientAtZero() const; - - /** - * Computes the determinant of a GassianBayesNet. A GaussianBayesNet is an upper triangular - * matrix and for an upper triangular matrix determinant is the product of the diagonal - * elements. Instead of actually multiplying we add the logarithms of the diagonal elements and - * take the exponent at the end because this is more numerically stable. - * @param bayesNet The input GaussianBayesNet - * @return The determinant */ - double determinant() const; - - /** - * Computes the log of the determinant of a GassianBayesNet. A GaussianBayesNet is an upper - * triangular matrix and for an upper triangular matrix determinant is the product of the - * diagonal elements. - * @param bayesNet The input GaussianBayesNet - * @return The determinant */ - double logDeterminant() const; - - /** - * Backsubstitute with a different RHS vector than the one stored in this BayesNet. - * gy=inv(R*inv(Sigma))*gx - */ - VectorValuesUnordered backSubstitute(const VectorValuesUnordered& gx) const; - - /** - * Transpose backsubstitute with a different RHS vector than the one stored in this BayesNet. - * gy=inv(L)*gx by solving L*gy=gx. - * gy=inv(R'*inv(Sigma))*gx - * gz'*R'=gx', gy = gz.*sigmas - */ - VectorValuesUnordered backSubstituteTranspose(const VectorValuesUnordered& gx) const; - - /// @} - }; - -} /// namespace gtsam diff --git a/gtsam/linear/GaussianBayesTree-inl.h b/gtsam/linear/GaussianBayesTree-inl.h index 1f6c8e9f5..7b4ac6858 100644 --- a/gtsam/linear/GaussianBayesTree-inl.h +++ b/gtsam/linear/GaussianBayesTree-inl.h @@ -21,7 +21,7 @@ #include -#include // Only to help Eclipse +#include // Only to help Eclipse #include @@ -30,7 +30,7 @@ namespace gtsam { /* ************************************************************************* */ namespace internal { template -void optimizeInPlace(const typename BAYESTREE::sharedClique& clique, VectorValues& result) { +void optimizeInPlace(const typename BAYESTREE::sharedClique& clique, VectorValuesOrdered& result) { // parents are assumed to already be solved and available in result clique->conditional()->solveInPlace(result); diff --git a/gtsam/linear/GaussianBayesTree.cpp b/gtsam/linear/GaussianBayesTree.cpp index 7011524e4..53b4ac6e5 100644 --- a/gtsam/linear/GaussianBayesTree.cpp +++ b/gtsam/linear/GaussianBayesTree.cpp @@ -17,77 +17,168 @@ * @author Richard Roberts */ +#include +#include +#include #include -#include +#include +#include namespace gtsam { -/* ************************************************************************* */ -VectorValues optimize(const GaussianBayesTree& bayesTree) { - VectorValues result = *allocateVectorValues(bayesTree); - optimizeInPlace(bayesTree, result); - return result; -} + /* ************************************************************************* */ + namespace internal + { + /* ************************************************************************* */ + struct OptimizeData { + boost::optional parentData; + VectorValues ancestorResults; + //VectorValues results; + }; -/* ************************************************************************* */ -void optimizeInPlace(const GaussianBayesTree& bayesTree, VectorValues& result) { - internal::optimizeInPlace(bayesTree.root(), result); -} + /* ************************************************************************* */ + /** Pre-order visitor for back-substitution in a Bayes tree. The visitor function operator()() + * optimizes the clique given the solution for the parents, and returns the solution for the + * clique's frontal variables. In addition, it adds the solution to a global collected + * solution that will finally be returned to the user. The reason we pass the individual + * clique solutions between nodes is to avoid log(n) lookups over all variables, they instead + * then are only over a node's parent variables. */ + struct OptimizeClique + { + VectorValues collectedResult; -/* ************************************************************************* */ -VectorValues optimizeGradientSearch(const GaussianBayesTree& bayesTree) { - gttic(Allocate_VectorValues); - VectorValues grad = *allocateVectorValues(bayesTree); - gttoc(Allocate_VectorValues); + OptimizeData operator()( + const GaussianBayesTreeClique::shared_ptr& clique, + OptimizeData& parentData) + { + OptimizeData myData; + myData.parentData = parentData; + // Take any ancestor results we'll need + //BOOST_FOREACH(Key parent, clique->conditional_->parents()) + // myData.ancestorResults.insert(parent, myData.parentData->ancestorResults[parent]); + // Solve and store in our results + VectorValues result = clique->conditional()->solve(collectedResult/*myData.ancestorResults*/); + collectedResult.insert(result); + //myData.ancestorResults.insert(result); + return myData; + } + }; - optimizeGradientSearchInPlace(bayesTree, grad); + /* ************************************************************************* */ + //OptimizeData OptimizePreVisitor(const GaussianBayesTreeClique::shared_ptr& clique, OptimizeData& parentData) + //{ + // // Create data - holds a pointer to our parent, a copy of parent solution, and our results + // OptimizeData myData; + // myData.parentData = parentData; + // // Take any ancestor results we'll need + // BOOST_FOREACH(Key parent, clique->conditional_->parents()) + // myData.ancestorResults.insert(parent, myData.parentData->ancestorResults[parent]); + // // Solve and store in our results + // myData.results.insert(clique->conditional()->solve(myData.ancestorResults)); + // myData.ancestorResults.insert(myData.results); + // return myData; + //} - return grad; -} + /* ************************************************************************* */ + //void OptimizePostVisitor(const GaussianBayesTreeClique::shared_ptr& clique, OptimizeData& myData) + //{ + // // Conglomerate our results to the parent + // myData.parentData->results.insert(myData.results); + //} -/* ************************************************************************* */ -void optimizeGradientSearchInPlace(const GaussianBayesTree& bayesTree, VectorValues& grad) { - gttic(Compute_Gradient); - // Compute gradient (call gradientAtZero function, which is defined for various linear systems) - gradientAtZero(bayesTree, grad); - double gradientSqNorm = grad.dot(grad); - gttoc(Compute_Gradient); + /* ************************************************************************* */ + double logDeterminant(const GaussianBayesTreeClique::shared_ptr& clique, double& parentSum) + { + parentSum += clique->conditional()->get_R().diagonal().unaryExpr(std::ptr_fun(log)).sum(); + assert(false); + return 0; + } + } - gttic(Compute_Rg); - // Compute R * g - FactorGraph Rd_jfg(bayesTree); - Errors Rg = Rd_jfg * grad; - gttoc(Compute_Rg); + /* ************************************************************************* */ + GaussianBayesTree::GaussianBayesTree(const GaussianBayesTree& other) : + Base(other) {} - gttic(Compute_minimizing_step_size); - // Compute minimizing step size - double step = -gradientSqNorm / dot(Rg, Rg); - gttoc(Compute_minimizing_step_size); + /* ************************************************************************* */ + GaussianBayesTree& GaussianBayesTree::operator=(const GaussianBayesTree& other) + { + (void) Base::operator=(other); + return *this; + } - gttic(Compute_point); - // Compute steepest descent point - scal(step, grad); - gttoc(Compute_point); -} + /* ************************************************************************* */ + bool GaussianBayesTree::equals(const This& other, double tol) const + { + return Base::equals(other, tol); + } -/* ************************************************************************* */ -VectorValues gradient(const GaussianBayesTree& bayesTree, const VectorValues& x0) { - return gradient(FactorGraph(bayesTree), x0); -} + /* ************************************************************************* */ + VectorValues GaussianBayesTree::optimize() const + { + gttic(GaussianBayesTree_optimize); + //internal::OptimizeData rootData; // Will hold final solution + //treeTraversal::DepthFirstForest(*this, rootData, internal::OptimizePreVisitor, internal::OptimizePostVisitor); + //return rootData.results; + internal::OptimizeData rootData; + internal::OptimizeClique preVisitor; + treeTraversal::DepthFirstForest(*this, rootData, preVisitor); + return preVisitor.collectedResult; + } -/* ************************************************************************* */ -void gradientAtZero(const GaussianBayesTree& bayesTree, VectorValues& g) { - gradientAtZero(FactorGraph(bayesTree), g); -} + ///* ************************************************************************* */ + //VectorValues GaussianBayesTree::optimizeGradientSearch() const + //{ + // gttic(Compute_Gradient); + // // Compute gradient (call gradientAtZero function, which is defined for various linear systems) + // VectorValues grad = gradientAtZero(); + // double gradientSqNorm = grad.dot(grad); + // gttoc(Compute_Gradient); -/* ************************************************************************* */ -double determinant(const GaussianBayesTree& bayesTree) { - if (!bayesTree.root()) - return 0.0; + // gttic(Compute_Rg); + // // Compute R * g + // Errors Rg = GaussianFactorGraph(*this) * grad; + // gttoc(Compute_Rg); - return exp(internal::logDeterminant(bayesTree.root())); -} -/* ************************************************************************* */ + // gttic(Compute_minimizing_step_size); + // // Compute minimizing step size + // double step = -gradientSqNorm / dot(Rg, Rg); + // gttoc(Compute_minimizing_step_size); + + // gttic(Compute_point); + // // Compute steepest descent point + // scal(step, grad); + // gttoc(Compute_point); + + // return grad; + //} + + ///* ************************************************************************* */ + //VectorValues GaussianBayesTree::gradient(const VectorValues& x0) const { + // return GaussianFactorGraph(*this).gradient(x0); + //} + + ///* ************************************************************************* */ + //VectorValues GaussianBayesTree::gradientAtZero() const { + // return GaussianFactorGraph(*this).gradientAtZero(); + //} + + /* ************************************************************************* */ + double GaussianBayesTree::logDeterminant() const + { + if(this->roots_.empty()) { + return 0.0; + } else { + double sum = 0.0; + treeTraversal::DepthFirstForest(*this, sum, internal::logDeterminant); + return sum; + } + } + + /* ************************************************************************* */ + double GaussianBayesTree::determinant() const + { + return exp(logDeterminant()); + } } // \namespace gtsam diff --git a/gtsam/linear/GaussianBayesTree.h b/gtsam/linear/GaussianBayesTree.h index 9df3d67b4..7ddfa545d 100644 --- a/gtsam/linear/GaussianBayesTree.h +++ b/gtsam/linear/GaussianBayesTree.h @@ -19,96 +19,116 @@ #pragma once +#include +#include #include -#include -#include +#include namespace gtsam { -/// A Bayes Tree representing a Gaussian density -GTSAM_EXPORT typedef BayesTree GaussianBayesTree; + // Forward declarations + class GaussianConditional; + class VectorValues; -/// optimize the BayesTree, starting from the root -GTSAM_EXPORT VectorValues optimize(const GaussianBayesTree& bayesTree); + /* ************************************************************************* */ + /** A clique in a GaussianBayesTree */ + class GTSAM_EXPORT GaussianBayesTreeClique : + public BayesTreeCliqueBase + { + public: + typedef GaussianBayesTreeClique This; + typedef BayesTreeCliqueBase Base; + typedef boost::shared_ptr shared_ptr; + typedef boost::weak_ptr weak_ptr; + GaussianBayesTreeClique() {} + GaussianBayesTreeClique(const boost::shared_ptr& conditional) : Base(conditional) {} + }; -/// recursively optimize this conditional and all subtrees -GTSAM_EXPORT void optimizeInPlace(const GaussianBayesTree& bayesTree, VectorValues& result); + /* ************************************************************************* */ + /** A Bayes tree representing a Gaussian density */ + class GTSAM_EXPORT GaussianBayesTree : + public BayesTree + { + private: + typedef BayesTree Base; -namespace internal { -template -void optimizeInPlace(const typename BAYESTREE::sharedClique& clique, VectorValues& result); -} + public: + typedef GaussianBayesTree This; + typedef boost::shared_ptr shared_ptr; -/** - * Optimize along the gradient direction, with a closed-form computation to - * perform the line search. The gradient is computed about \f$ \delta x=0 \f$. - * - * This function returns \f$ \delta x \f$ that minimizes a reparametrized - * problem. The error function of a GaussianBayesNet is - * - * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f] - * - * with gradient and Hessian - * - * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] - * - * This function performs the line search in the direction of the - * gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size - * \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$: - * - * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] - * - * Optimizing by setting the derivative to zero yields - * \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function - * evaluates the denominator without computing the Hessian \f$ G \f$, returning - * - * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] - */ -GTSAM_EXPORT VectorValues optimizeGradientSearch(const GaussianBayesTree& bayesTree); + /** Default constructor, creates an empty Bayes tree */ + GaussianBayesTree() {} -/** In-place version of optimizeGradientSearch requiring pre-allocated VectorValues \c x */ -GTSAM_EXPORT void optimizeGradientSearchInPlace(const GaussianBayesTree& bayesTree, VectorValues& grad); + /** Makes a deep copy of the tree structure, but only pointers to conditionals are + * copied, the conditionals and their matrices are not cloned. */ + GaussianBayesTree(const GaussianBayesTree& other); -/** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, - * centered around \f$ x = x_0 \f$. - * The gradient is \f$ R^T(Rx-d) \f$. - * @param bayesTree The Gaussian Bayes Tree $(R,d)$ - * @param x0 The center about which to compute the gradient - * @return The gradient as a VectorValues - */ -GTSAM_EXPORT VectorValues gradient(const GaussianBayesTree& bayesTree, const VectorValues& x0); + /** Makes a deep copy of the tree structure, but only pointers to conditionals are + * copied, the conditionals and their matrices are not cloned. */ + GaussianBayesTree& operator=(const GaussianBayesTree& other); -/** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, - * centered around zero. - * The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&). - * @param bayesTree The Gaussian Bayes Tree $(R,d)$ - * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues - * @return The gradient as a VectorValues - */ -GTSAM_EXPORT void gradientAtZero(const GaussianBayesTree& bayesTree, VectorValues& g); + /** Check equality */ + bool equals(const This& other, double tol = 1e-9) const; -/** - * Computes the determinant of a GassianBayesTree - * A GassianBayesTree is an upper triangular matrix and for an upper triangular matrix - * determinant is the product of the diagonal elements. Instead of actually multiplying - * we add the logarithms of the diagonal elements and take the exponent at the end - * because this is more numerically stable. - * @param bayesTree The input GassianBayesTree - * @return The determinant - */ -GTSAM_EXPORT double determinant(const GaussianBayesTree& bayesTree); + /** Recursively optimize the BayesTree to produce a vector solution. */ + VectorValues optimize() const; + /** + * Optimize along the gradient direction, with a closed-form computation to perform the line + * search. The gradient is computed about \f$ \delta x=0 \f$. + * + * This function returns \f$ \delta x \f$ that minimizes a reparametrized problem. The error + * function of a GaussianBayesNet is + * + * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + + * \frac{1}{2} \delta x^T R^T R \delta x \f] + * + * with gradient and Hessian + * + * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] + * + * This function performs the line search in the direction of the gradient evaluated at \f$ g = + * g(\delta x = 0) \f$ with step size \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) + * \f$: + * + * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] + * + * Optimizing by setting the derivative to zero yields \f$ \hat \alpha = (-g^T g) / (g^T G g) + * \f$. For efficiency, this function evaluates the denominator without computing the Hessian + * \f$ G \f$, returning + * + * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] */ + //VectorValues optimizeGradientSearch() const; -namespace internal { -template -double logDeterminant(const typename BAYESTREE::sharedClique& clique); -} + /** Compute the gradient of the energy function, \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - + * d \right\Vert^2 \f$, centered around \f$ x = x_0 \f$. The gradient is \f$ R^T(Rx-d) \f$. + * + * @param x0 The center about which to compute the gradient + * @return The gradient as a VectorValues */ + //VectorValues gradient(const VectorValues& x0) const; + + /** Compute the gradient of the energy function, \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d + * \right\Vert^2 \f$, centered around zero. The gradient about zero is \f$ -R^T d \f$. See also + * gradient(const GaussianBayesNet&, const VectorValues&). + * + * @param [output] g A VectorValues to store the gradient, which must be preallocated, see + * allocateVectorValues */ + //VectorValues gradientAtZero() const; + + /** Computes the determinant of a GassianBayesTree, as if the Bayes tree is reorganized into a + * matrix. A GassianBayesTree is equivalent to an upper triangular matrix, and for an upper + * triangular matrix determinant is the product of the diagonal elements. Instead of actually + * multiplying we add the logarithms of the diagonal elements and take the exponent at the end + * because this is more numerically stable. */ + double determinant() const; + + /** Computes the determinant of a GassianBayesTree, as if the Bayes tree is reorganized into a + * matrix. A GassianBayesTree is equivalent to an upper triangular matrix, and for an upper + * triangular matrix determinant is the product of the diagonal elements. Instead of actually + * multiplying we add the logarithms of the diagonal elements and take the exponent at the end + * because this is more numerically stable. */ + double logDeterminant() const; + + }; } - -#include - diff --git a/gtsam/linear/GaussianBayesTreeUnordered-inl.h b/gtsam/linear/GaussianBayesTreeOrdered-inl.h similarity index 94% rename from gtsam/linear/GaussianBayesTreeUnordered-inl.h rename to gtsam/linear/GaussianBayesTreeOrdered-inl.h index 1f6c8e9f5..7b4ac6858 100644 --- a/gtsam/linear/GaussianBayesTreeUnordered-inl.h +++ b/gtsam/linear/GaussianBayesTreeOrdered-inl.h @@ -21,7 +21,7 @@ #include -#include // Only to help Eclipse +#include // Only to help Eclipse #include @@ -30,7 +30,7 @@ namespace gtsam { /* ************************************************************************* */ namespace internal { template -void optimizeInPlace(const typename BAYESTREE::sharedClique& clique, VectorValues& result) { +void optimizeInPlace(const typename BAYESTREE::sharedClique& clique, VectorValuesOrdered& result) { // parents are assumed to already be solved and available in result clique->conditional()->solveInPlace(result); diff --git a/gtsam/linear/GaussianBayesTreeOrdered.cpp b/gtsam/linear/GaussianBayesTreeOrdered.cpp new file mode 100644 index 000000000..abaef4a76 --- /dev/null +++ b/gtsam/linear/GaussianBayesTreeOrdered.cpp @@ -0,0 +1,96 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianBayesTree.cpp + * @brief Gaussian Bayes Tree, the result of eliminating a GaussianJunctionTree + * @brief GaussianBayesTree + * @author Frank Dellaert + * @author Richard Roberts + */ + +#include +#include + +namespace gtsam { + +/* ************************************************************************* */ +VectorValuesOrdered optimize(const GaussianBayesTreeOrdered& bayesTree) { + VectorValuesOrdered result = *allocateVectorValues(bayesTree); + optimizeInPlace(bayesTree, result); + return result; +} + +/* ************************************************************************* */ +void optimizeInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& result) { + internal::optimizeInPlace(bayesTree.root(), result); +} + +/* ************************************************************************* */ +VectorValuesOrdered optimizeGradientSearch(const GaussianBayesTreeOrdered& bayesTree) { + gttic(Allocate_VectorValues); + VectorValuesOrdered grad = *allocateVectorValues(bayesTree); + gttoc(Allocate_VectorValues); + + optimizeGradientSearchInPlace(bayesTree, grad); + + return grad; +} + +/* ************************************************************************* */ +void optimizeGradientSearchInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& grad) { + gttic(Compute_Gradient); + // Compute gradient (call gradientAtZero function, which is defined for various linear systems) + gradientAtZero(bayesTree, grad); + double gradientSqNorm = grad.dot(grad); + gttoc(Compute_Gradient); + + gttic(Compute_Rg); + // Compute R * g + FactorGraphOrdered Rd_jfg(bayesTree); + Errors Rg = Rd_jfg * grad; + gttoc(Compute_Rg); + + gttic(Compute_minimizing_step_size); + // Compute minimizing step size + double step = -gradientSqNorm / dot(Rg, Rg); + gttoc(Compute_minimizing_step_size); + + gttic(Compute_point); + // Compute steepest descent point + scal(step, grad); + gttoc(Compute_point); +} + +/* ************************************************************************* */ +VectorValuesOrdered gradient(const GaussianBayesTreeOrdered& bayesTree, const VectorValuesOrdered& x0) { + return gradient(FactorGraphOrdered(bayesTree), x0); +} + +/* ************************************************************************* */ +void gradientAtZero(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& g) { + gradientAtZero(FactorGraphOrdered(bayesTree), g); +} + +/* ************************************************************************* */ +double determinant(const GaussianBayesTreeOrdered& bayesTree) { + if (!bayesTree.root()) + return 0.0; + + return exp(internal::logDeterminant(bayesTree.root())); +} +/* ************************************************************************* */ + +} // \namespace gtsam + + + + diff --git a/gtsam/linear/GaussianBayesTreeOrdered.h b/gtsam/linear/GaussianBayesTreeOrdered.h new file mode 100644 index 000000000..7df2d3d5a --- /dev/null +++ b/gtsam/linear/GaussianBayesTreeOrdered.h @@ -0,0 +1,114 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianBayesTree.h + * @brief Gaussian Bayes Tree, the result of eliminating a GaussianJunctionTree + * @brief GaussianBayesTree + * @author Frank Dellaert + * @author Richard Roberts + */ + +#pragma once + +#include +#include +#include + +namespace gtsam { + +/// A Bayes Tree representing a Gaussian density +GTSAM_EXPORT typedef BayesTreeOrdered GaussianBayesTreeOrdered; + +/// optimize the BayesTree, starting from the root +GTSAM_EXPORT VectorValuesOrdered optimize(const GaussianBayesTreeOrdered& bayesTree); + +/// recursively optimize this conditional and all subtrees +GTSAM_EXPORT void optimizeInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& result); + +namespace internal { +template +void optimizeInPlace(const typename BAYESTREE::sharedClique& clique, VectorValuesOrdered& result); +} + +/** + * Optimize along the gradient direction, with a closed-form computation to + * perform the line search. The gradient is computed about \f$ \delta x=0 \f$. + * + * This function returns \f$ \delta x \f$ that minimizes a reparametrized + * problem. The error function of a GaussianBayesNet is + * + * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f] + * + * with gradient and Hessian + * + * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] + * + * This function performs the line search in the direction of the + * gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size + * \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$: + * + * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] + * + * Optimizing by setting the derivative to zero yields + * \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function + * evaluates the denominator without computing the Hessian \f$ G \f$, returning + * + * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] + */ +GTSAM_EXPORT VectorValuesOrdered optimizeGradientSearch(const GaussianBayesTreeOrdered& bayesTree); + +/** In-place version of optimizeGradientSearch requiring pre-allocated VectorValues \c x */ +GTSAM_EXPORT void optimizeGradientSearchInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& grad); + +/** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, + * centered around \f$ x = x_0 \f$. + * The gradient is \f$ R^T(Rx-d) \f$. + * @param bayesTree The Gaussian Bayes Tree $(R,d)$ + * @param x0 The center about which to compute the gradient + * @return The gradient as a VectorValues + */ +GTSAM_EXPORT VectorValuesOrdered gradient(const GaussianBayesTreeOrdered& bayesTree, const VectorValuesOrdered& x0); + +/** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$, + * centered around zero. + * The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&). + * @param bayesTree The Gaussian Bayes Tree $(R,d)$ + * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues + * @return The gradient as a VectorValues + */ +GTSAM_EXPORT void gradientAtZero(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& g); + +/** + * Computes the determinant of a GassianBayesTree + * A GassianBayesTree is an upper triangular matrix and for an upper triangular matrix + * determinant is the product of the diagonal elements. Instead of actually multiplying + * we add the logarithms of the diagonal elements and take the exponent at the end + * because this is more numerically stable. + * @param bayesTree The input GassianBayesTree + * @return The determinant + */ +GTSAM_EXPORT double determinant(const GaussianBayesTreeOrdered& bayesTree); + + +namespace internal { +template +double logDeterminant(const typename BAYESTREE::sharedClique& clique); +} + +} + +#include + diff --git a/gtsam/linear/GaussianBayesTreeUnordered.cpp b/gtsam/linear/GaussianBayesTreeUnordered.cpp deleted file mode 100644 index e56645a77..000000000 --- a/gtsam/linear/GaussianBayesTreeUnordered.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianBayesTree.cpp - * @brief Gaussian Bayes Tree, the result of eliminating a GaussianJunctionTree - * @brief GaussianBayesTree - * @author Frank Dellaert - * @author Richard Roberts - */ - -#include -#include -#include -#include -#include -#include - -namespace gtsam { - - /* ************************************************************************* */ - namespace internal - { - /* ************************************************************************* */ - struct OptimizeData { - boost::optional parentData; - VectorValuesUnordered ancestorResults; - //VectorValuesUnordered results; - }; - - /* ************************************************************************* */ - /** Pre-order visitor for back-substitution in a Bayes tree. The visitor function operator()() - * optimizes the clique given the solution for the parents, and returns the solution for the - * clique's frontal variables. In addition, it adds the solution to a global collected - * solution that will finally be returned to the user. The reason we pass the individual - * clique solutions between nodes is to avoid log(n) lookups over all variables, they instead - * then are only over a node's parent variables. */ - struct OptimizeClique - { - VectorValuesUnordered collectedResult; - - OptimizeData operator()( - const GaussianBayesTreeCliqueUnordered::shared_ptr& clique, - OptimizeData& parentData) - { - OptimizeData myData; - myData.parentData = parentData; - // Take any ancestor results we'll need - //BOOST_FOREACH(Key parent, clique->conditional_->parents()) - // myData.ancestorResults.insert(parent, myData.parentData->ancestorResults[parent]); - // Solve and store in our results - VectorValuesUnordered result = clique->conditional()->solve(collectedResult/*myData.ancestorResults*/); - collectedResult.insert(result); - //myData.ancestorResults.insert(result); - return myData; - } - }; - - /* ************************************************************************* */ - //OptimizeData OptimizePreVisitor(const GaussianBayesTreeCliqueUnordered::shared_ptr& clique, OptimizeData& parentData) - //{ - // // Create data - holds a pointer to our parent, a copy of parent solution, and our results - // OptimizeData myData; - // myData.parentData = parentData; - // // Take any ancestor results we'll need - // BOOST_FOREACH(Key parent, clique->conditional_->parents()) - // myData.ancestorResults.insert(parent, myData.parentData->ancestorResults[parent]); - // // Solve and store in our results - // myData.results.insert(clique->conditional()->solve(myData.ancestorResults)); - // myData.ancestorResults.insert(myData.results); - // return myData; - //} - - /* ************************************************************************* */ - //void OptimizePostVisitor(const GaussianBayesTreeCliqueUnordered::shared_ptr& clique, OptimizeData& myData) - //{ - // // Conglomerate our results to the parent - // myData.parentData->results.insert(myData.results); - //} - - /* ************************************************************************* */ - double logDeterminant(const GaussianBayesTreeCliqueUnordered::shared_ptr& clique, double& parentSum) - { - parentSum += clique->conditional()->get_R().diagonal().unaryExpr(std::ptr_fun(log)).sum(); - assert(false); - return 0; - } - } - - /* ************************************************************************* */ - GaussianBayesTreeUnordered::GaussianBayesTreeUnordered(const GaussianBayesTreeUnordered& other) : - Base(other) {} - - /* ************************************************************************* */ - GaussianBayesTreeUnordered& GaussianBayesTreeUnordered::operator=(const GaussianBayesTreeUnordered& other) - { - (void) Base::operator=(other); - return *this; - } - - /* ************************************************************************* */ - bool GaussianBayesTreeUnordered::equals(const This& other, double tol) const - { - return Base::equals(other, tol); - } - - /* ************************************************************************* */ - VectorValuesUnordered GaussianBayesTreeUnordered::optimize() const - { - gttic(GaussianBayesTree_optimize); - //internal::OptimizeData rootData; // Will hold final solution - //treeTraversal::DepthFirstForest(*this, rootData, internal::OptimizePreVisitor, internal::OptimizePostVisitor); - //return rootData.results; - internal::OptimizeData rootData; - internal::OptimizeClique preVisitor; - treeTraversal::DepthFirstForest(*this, rootData, preVisitor); - return preVisitor.collectedResult; - } - - ///* ************************************************************************* */ - //VectorValuesUnordered GaussianBayesTreeUnordered::optimizeGradientSearch() const - //{ - // gttic(Compute_Gradient); - // // Compute gradient (call gradientAtZero function, which is defined for various linear systems) - // VectorValuesUnordered grad = gradientAtZero(); - // double gradientSqNorm = grad.dot(grad); - // gttoc(Compute_Gradient); - - // gttic(Compute_Rg); - // // Compute R * g - // Errors Rg = GaussianFactorGraphUnordered(*this) * grad; - // gttoc(Compute_Rg); - - // gttic(Compute_minimizing_step_size); - // // Compute minimizing step size - // double step = -gradientSqNorm / dot(Rg, Rg); - // gttoc(Compute_minimizing_step_size); - - // gttic(Compute_point); - // // Compute steepest descent point - // scal(step, grad); - // gttoc(Compute_point); - - // return grad; - //} - - ///* ************************************************************************* */ - //VectorValuesUnordered GaussianBayesTreeUnordered::gradient(const VectorValuesUnordered& x0) const { - // return GaussianFactorGraphUnordered(*this).gradient(x0); - //} - - ///* ************************************************************************* */ - //VectorValuesUnordered GaussianBayesTreeUnordered::gradientAtZero() const { - // return GaussianFactorGraphUnordered(*this).gradientAtZero(); - //} - - /* ************************************************************************* */ - double GaussianBayesTreeUnordered::logDeterminant() const - { - if(this->roots_.empty()) { - return 0.0; - } else { - double sum = 0.0; - treeTraversal::DepthFirstForest(*this, sum, internal::logDeterminant); - return sum; - } - } - - /* ************************************************************************* */ - double GaussianBayesTreeUnordered::determinant() const - { - return exp(logDeterminant()); - } - -} // \namespace gtsam - - - - diff --git a/gtsam/linear/GaussianBayesTreeUnordered.h b/gtsam/linear/GaussianBayesTreeUnordered.h deleted file mode 100644 index 4213b3289..000000000 --- a/gtsam/linear/GaussianBayesTreeUnordered.h +++ /dev/null @@ -1,134 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianBayesTree.h - * @brief Gaussian Bayes Tree, the result of eliminating a GaussianJunctionTree - * @brief GaussianBayesTree - * @author Frank Dellaert - * @author Richard Roberts - */ - -#pragma once - -#include -#include -#include -#include - -namespace gtsam { - - // Forward declarations - class GaussianConditionalUnordered; - class VectorValuesUnordered; - - /* ************************************************************************* */ - /** A clique in a GaussianBayesTree */ - class GTSAM_EXPORT GaussianBayesTreeCliqueUnordered : - public BayesTreeCliqueBaseUnordered - { - public: - typedef GaussianBayesTreeCliqueUnordered This; - typedef BayesTreeCliqueBaseUnordered Base; - typedef boost::shared_ptr shared_ptr; - typedef boost::weak_ptr weak_ptr; - GaussianBayesTreeCliqueUnordered() {} - GaussianBayesTreeCliqueUnordered(const boost::shared_ptr& conditional) : Base(conditional) {} - }; - - /* ************************************************************************* */ - /** A Bayes tree representing a Gaussian density */ - class GTSAM_EXPORT GaussianBayesTreeUnordered : - public BayesTreeUnordered - { - private: - typedef BayesTreeUnordered Base; - - public: - typedef GaussianBayesTreeUnordered This; - typedef boost::shared_ptr shared_ptr; - - /** Default constructor, creates an empty Bayes tree */ - GaussianBayesTreeUnordered() {} - - /** Makes a deep copy of the tree structure, but only pointers to conditionals are - * copied, the conditionals and their matrices are not cloned. */ - GaussianBayesTreeUnordered(const GaussianBayesTreeUnordered& other); - - /** Makes a deep copy of the tree structure, but only pointers to conditionals are - * copied, the conditionals and their matrices are not cloned. */ - GaussianBayesTreeUnordered& operator=(const GaussianBayesTreeUnordered& other); - - /** Check equality */ - bool equals(const This& other, double tol = 1e-9) const; - - /** Recursively optimize the BayesTree to produce a vector solution. */ - VectorValuesUnordered optimize() const; - - /** - * Optimize along the gradient direction, with a closed-form computation to perform the line - * search. The gradient is computed about \f$ \delta x=0 \f$. - * - * This function returns \f$ \delta x \f$ that minimizes a reparametrized problem. The error - * function of a GaussianBayesNet is - * - * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + - * \frac{1}{2} \delta x^T R^T R \delta x \f] - * - * with gradient and Hessian - * - * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] - * - * This function performs the line search in the direction of the gradient evaluated at \f$ g = - * g(\delta x = 0) \f$ with step size \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) - * \f$: - * - * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] - * - * Optimizing by setting the derivative to zero yields \f$ \hat \alpha = (-g^T g) / (g^T G g) - * \f$. For efficiency, this function evaluates the denominator without computing the Hessian - * \f$ G \f$, returning - * - * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] */ - //VectorValuesUnordered optimizeGradientSearch() const; - - /** Compute the gradient of the energy function, \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - - * d \right\Vert^2 \f$, centered around \f$ x = x_0 \f$. The gradient is \f$ R^T(Rx-d) \f$. - * - * @param x0 The center about which to compute the gradient - * @return The gradient as a VectorValues */ - //VectorValuesUnordered gradient(const VectorValuesUnordered& x0) const; - - /** Compute the gradient of the energy function, \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d - * \right\Vert^2 \f$, centered around zero. The gradient about zero is \f$ -R^T d \f$. See also - * gradient(const GaussianBayesNet&, const VectorValues&). - * - * @param [output] g A VectorValues to store the gradient, which must be preallocated, see - * allocateVectorValues */ - //VectorValuesUnordered gradientAtZero() const; - - /** Computes the determinant of a GassianBayesTree, as if the Bayes tree is reorganized into a - * matrix. A GassianBayesTree is equivalent to an upper triangular matrix, and for an upper - * triangular matrix determinant is the product of the diagonal elements. Instead of actually - * multiplying we add the logarithms of the diagonal elements and take the exponent at the end - * because this is more numerically stable. */ - double determinant() const; - - /** Computes the determinant of a GassianBayesTree, as if the Bayes tree is reorganized into a - * matrix. A GassianBayesTree is equivalent to an upper triangular matrix, and for an upper - * triangular matrix determinant is the product of the diagonal elements. Instead of actually - * multiplying we add the logarithms of the diagonal elements and take the exponent at the end - * because this is more numerically stable. */ - double logDeterminant() const; - - }; - -} diff --git a/gtsam/linear/GaussianConditionalUnordered-inl.h b/gtsam/linear/GaussianConditional-inl.h similarity index 88% rename from gtsam/linear/GaussianConditionalUnordered-inl.h rename to gtsam/linear/GaussianConditional-inl.h index 9050479ad..5c0eb63a8 100644 --- a/gtsam/linear/GaussianConditionalUnordered-inl.h +++ b/gtsam/linear/GaussianConditional-inl.h @@ -26,26 +26,26 @@ namespace gtsam { /* ************************************************************************* */ template - GaussianConditionalUnordered::GaussianConditionalUnordered(Index key, const Vector& d, + GaussianConditional::GaussianConditional(Index key, const Vector& d, const Matrix& R, const PARENTS& parents, const SharedDiagonal& sigmas, const typename PARENTS::value_type*) : BaseFactor(boost::join(boost::assign::cref_list_of<1,typename PARENTS::value_type>(std::make_pair(key, R)), parents), d, sigmas), BaseConditional(1) {} /* ************************************************************************* */ template - GaussianConditionalUnordered::GaussianConditionalUnordered(const TERMS& terms, + GaussianConditional::GaussianConditional(const TERMS& terms, size_t nrFrontals, const Vector& d, const SharedDiagonal& sigmas) : BaseFactor(terms, d, sigmas), BaseConditional(nrFrontals) {} /* ************************************************************************* */ template - GaussianConditionalUnordered::GaussianConditionalUnordered( + GaussianConditional::GaussianConditional( const KEYS& keys, size_t nrFrontals, const VerticalBlockMatrix& augmentedMatrix, const SharedDiagonal& sigmas) : BaseFactor(keys, augmentedMatrix, sigmas), BaseConditional(nrFrontals) {} /* ************************************************************************* */ template - GaussianConditionalUnordered::shared_ptr GaussianConditionalUnordered::Combine(ITERATOR firstConditional, ITERATOR lastConditional) + GaussianConditional::shared_ptr GaussianConditional::Combine(ITERATOR firstConditional, ITERATOR lastConditional) { // TODO: check for being a clique @@ -67,8 +67,8 @@ namespace gtsam { // Allocate combined conditional, has same keys as firstConditional Matrix tempCombined; VerticalBlockView tempBlockView(tempCombined, dims.begin(), dims.end(), 0); - GaussianConditional::shared_ptr combinedConditional = - boost::make_shared( + GaussianConditionalOrdered::shared_ptr combinedConditional = + boost::make_shared( (*firstConditional)->begin(), (*firstConditional)->end(), nFrontals, tempBlockView, Vector::Zero(nRows)); // Resize to correct number of rows diff --git a/gtsam/linear/GaussianConditional.cpp b/gtsam/linear/GaussianConditional.cpp index 16b04af14..de787cda1 100644 --- a/gtsam/linear/GaussianConditional.cpp +++ b/gtsam/linear/GaussianConditional.cpp @@ -29,210 +29,166 @@ #include #include -#include -#include +#include using namespace std; namespace gtsam { -/* ************************************************************************* */ -GaussianConditional::GaussianConditional() : rsd_(matrix_) {} + /* ************************************************************************* */ + GaussianConditional::GaussianConditional( + Key key, const Vector& d, const Matrix& R, const SharedDiagonal& sigmas) : + BaseFactor(key, R, d, sigmas), BaseConditional(1) {} -/* ************************************************************************* */ -GaussianConditional::GaussianConditional(Index key) : IndexConditional(key), rsd_(matrix_) {} + /* ************************************************************************* */ + GaussianConditional::GaussianConditional( + Key key, const Vector& d, const Matrix& R, + Key name1, const Matrix& S, const SharedDiagonal& sigmas) : + BaseFactor(key, R, name1, S, d, sigmas), BaseConditional(1) {} -/* ************************************************************************* */ -GaussianConditional::GaussianConditional(Index key,const Vector& d, const Matrix& R, const Vector& sigmas) : - IndexConditional(key), rsd_(matrix_), sigmas_(sigmas) { - assert(R.rows() <= R.cols()); - size_t dims[] = { R.cols(), 1 }; - rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+2, d.size())); - rsd_(0) = R.triangularView(); - get_d_() = d; -} + /* ************************************************************************* */ + GaussianConditional::GaussianConditional( + Key key, const Vector& d, const Matrix& R, + Key name1, const Matrix& S, Key name2, const Matrix& T, const SharedDiagonal& sigmas) : + BaseFactor(key, R, name1, S, name2, T, d, sigmas), BaseConditional(1) {} -/* ************************************************************************* */ -GaussianConditional::GaussianConditional(Index key, const Vector& d, const Matrix& R, - Index name1, const Matrix& S, const Vector& sigmas) : - IndexConditional(key,name1), rsd_(matrix_), sigmas_(sigmas) { - assert(R.rows() <= R.cols()); - size_t dims[] = { R.cols(), S.cols(), 1 }; - rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+3, d.size())); - rsd_(0) = R.triangularView(); - rsd_(1) = S; - get_d_() = d; -} + /* ************************************************************************* */ + void GaussianConditional::print(const string &s, const IndexFormatter& formatter) const + { + cout << s << " Conditional density "; + for(const_iterator it = beginFrontals(); it != endFrontals(); ++it) { + cout << (boost::format("[%1%]")%(formatter(*it))).str() << " "; + } + cout << endl; + cout << formatMatrixIndented(" R = ", get_R()) << endl; + for(const_iterator it = beginParents() ; it != endParents() ; ++it ) { + cout << formatMatrixIndented((boost::format(" S[%1%] = ")%(formatter(*it))).str(), getA(it)) + << endl; + } + cout << formatMatrixIndented(" d = ", getb(), true) << "\n"; + if(model_) + model_->print(" Noise model: "); + else + cout << " No noise model" << endl; + } -/* ************************************************************************* */ -GaussianConditional::GaussianConditional(Index key, const Vector& d, const Matrix& R, - Index name1, const Matrix& S, Index name2, const Matrix& T, const Vector& sigmas) : - IndexConditional(key,name1,name2), rsd_(matrix_), sigmas_(sigmas) { - assert(R.rows() <= R.cols()); - size_t dims[] = { R.cols(), S.cols(), T.cols(), 1 }; - rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+4, d.size())); - rsd_(0) = R.triangularView(); - rsd_(1) = S; - rsd_(2) = T; - get_d_() = d; -} + /* ************************************************************************* */ + bool GaussianConditional::equals(const GaussianConditional &c, double tol) const + { + // check if the size of the parents_ map is the same + if (parents().size() != c.parents().size()) + return false; -/* ************************************************************************* */ - GaussianConditional::GaussianConditional(Index key, const Vector& d, - const Matrix& R, const list >& parents, const Vector& sigmas) : - IndexConditional(key, GetKeys(parents.size(), parents.begin(), parents.end())), rsd_(matrix_), sigmas_(sigmas) { - assert(R.rows() <= R.cols()); - size_t* dims = (size_t*)alloca(sizeof(size_t)*(1+parents.size()+1)); // FIXME: alloca is bad, just ask Google. - dims[0] = R.cols(); - size_t j=1; - std::list >::const_iterator parent=parents.begin(); - for(; parent!=parents.end(); ++parent,++j) - dims[j] = parent->second.cols(); - dims[j] = 1; - rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+1+parents.size()+1, d.size())); - rsd_(0) = R.triangularView(); - j = 1; - for(std::list >::const_iterator parent=parents.begin(); parent!=parents.end(); ++parent) { - rsd_(j).noalias() = parent->second; - ++ j; - } - get_d_() = d; -} + // check if R_ and d_ are linear independent + for (DenseIndex i=0; i rows1; rows1.push_back(Vector(get_R().row(i))); + list rows2; rows2.push_back(Vector(c.get_R().row(i))); -/* ************************************************************************* */ -GaussianConditional::GaussianConditional(const std::list >& terms, - const size_t nrFrontals, const Vector& d, const Vector& sigmas) : - IndexConditional(GetKeys(terms.size(), terms.begin(), terms.end()), nrFrontals), - rsd_(matrix_), sigmas_(sigmas) { - size_t* dims = (size_t*)alloca(sizeof(size_t)*(terms.size()+1)); // FIXME: alloca is bad, just ask Google. - size_t j=0; - typedef pair Index_Matrix; - BOOST_FOREACH(const Index_Matrix& term, terms) { - dims[j] = term.second.cols(); - ++ j; - } - dims[j] = 1; - rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+terms.size()+1, d.size())); - j=0; - BOOST_FOREACH(const Index_Matrix& term, terms) { - rsd_(j) = term.second; - ++ j; - } - get_d_() = d; -} + // check if the matrices are the same + // iterate over the parents_ map + for (const_iterator it = beginParents(); it != endParents(); ++it) { + const_iterator it2 = c.beginParents() + (it-beginParents()); + if(*it != *(it2)) + return false; + rows1.push_back(row(getA(it), i)); + rows2.push_back(row(c.getA(it2), i)); + } -/* ************************************************************************* */ -GaussianConditional::GaussianConditional(const GaussianConditional& rhs) : - rsd_(matrix_) { - *this = rhs; -} - -/* ************************************************************************* */ -GaussianConditional& GaussianConditional::operator=(const GaussianConditional& rhs) { - if(this != &rhs) { - this->Base::operator=(rhs); // Copy keys - rsd_.assignNoalias(rhs.rsd_); // Copy matrix and block configuration - sigmas_ = rhs.sigmas_; // Copy sigmas - } - return *this; -} - -/* ************************************************************************* */ -void GaussianConditional::print(const string &s, const IndexFormatter& formatter) const -{ - cout << s << ": density on "; - for(const_iterator it = beginFrontals(); it != endFrontals(); ++it) { - cout << (boost::format("[%1%]")%(formatter(*it))).str() << " "; - } - cout << endl; - gtsam::print(Matrix(get_R()),"R"); - for(const_iterator it = beginParents() ; it != endParents() ; ++it ) { - gtsam::print(Matrix(get_S(it)), (boost::format("A[%1%]")%(formatter(*it))).str()); - } - gtsam::print(Vector(get_d()),"d"); - gtsam::print(sigmas_,"sigmas"); -} - -/* ************************************************************************* */ -bool GaussianConditional::equals(const GaussianConditional &c, double tol) const { - // check if the size of the parents_ map is the same - if (parents().size() != c.parents().size()) - return false; - - // check if R_ and d_ are linear independent - for (size_t i=0; i rows1; rows1.push_back(Vector(get_R().row(i))); - list rows2; rows2.push_back(Vector(c.get_R().row(i))); - - // check if the matrices are the same - // iterate over the parents_ map - for (const_iterator it = beginParents(); it != endParents(); ++it) { - const_iterator it2 = c.beginParents() + (it-beginParents()); - if(*it != *(it2)) + Vector row1 = concatVectors(rows1); + Vector row2 = concatVectors(rows2); + if (!linear_dependent(row1, row2, tol)) return false; - rows1.push_back(row(get_S(it), i)); - rows2.push_back(row(c.get_S(it2), i)); } - Vector row1 = concatVectors(rows1); - Vector row2 = concatVectors(rows2); - if (!linear_dependent(row1, row2, tol)) + // check if sigmas are equal + if ((model_ && !c.model_) || (!model_ && c.model_) + || (model_ && c.model_ && !model_->equals(*c.model_, tol))) return false; + + return true; } - // check if sigmas are equal - if (!(equal_with_abs_tol(sigmas_, c.sigmas_, tol))) return false; + /* ************************************************************************* */ + VectorValues GaussianConditional::solve(const VectorValues& x) const + { + // Solve matrix + Vector xS = x.vector(vector(beginParents(), endParents())); + xS = getb() - get_S() * xS; + Vector soln = get_R().triangularView().solve(xS); - return true; -} + // Check for indeterminant solution + if(soln.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) + throw IndeterminantLinearSystemException(keys().front()); -/* ************************************************************************* */ -JacobianFactor::shared_ptr GaussianConditional::toFactor() const { - return JacobianFactor::shared_ptr(new JacobianFactor(*this)); -} + // Insert solution into a VectorValues + VectorValues result; + DenseIndex vectorPosition = 0; + for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { + result.insert(*frontal, soln.segment(vectorPosition, getDim(frontal))); + vectorPosition += getDim(frontal); + } -/* ************************************************************************* */ -void GaussianConditional::solveInPlace(VectorValues& x) const { - static const bool debug = false; - if(debug) this->print("Solving conditional in place"); - Vector xS = internal::extractVectorValuesSlices(x, this->beginParents(), this->endParents()); - xS = this->get_d() - this->get_S() * xS; - Vector soln = this->get_R().triangularView().solve(xS); - - // Check for indeterminant solution - if(soln.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) - throw IndeterminantLinearSystemException(this->keys().front()); - - if(debug) { - gtsam::print(Matrix(this->get_R()), "Calling backSubstituteUpper on "); - gtsam::print(soln, "full back-substitution solution: "); + return result; } - internal::writeVectorValuesSlices(soln, x, this->beginFrontals(), this->endFrontals()); -} -/* ************************************************************************* */ -void GaussianConditional::solveTransposeInPlace(VectorValues& gy) const { - Vector frontalVec = internal::extractVectorValuesSlices(gy, beginFrontals(), endFrontals()); - frontalVec = gtsam::backSubstituteUpper(frontalVec,Matrix(get_R())); + /* ************************************************************************* */ + VectorValues GaussianConditional::solveOtherRHS( + const VectorValues& parents, const VectorValues& rhs) const + { + Vector xS = parents.vector(vector(beginParents(), endParents())); + const Vector rhsR = rhs.vector(vector(beginFrontals(), endFrontals())); + xS = rhsR - get_S() * xS; + Vector soln = get_R().triangularView().solve(xS); - // Check for indeterminant solution - if(frontalVec.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) - throw IndeterminantLinearSystemException(this->keys().front()); + // Scale by sigmas + if(model_) + soln.array() *= model_->sigmas().array(); - GaussianConditional::const_iterator it; - for (it = beginParents(); it!= endParents(); it++) { - const Index i = *it; - transposeMultiplyAdd(-1.0,get_S(it),frontalVec,gy[i]); + // Insert solution into a VectorValues + VectorValues result; + DenseIndex vectorPosition = 0; + for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { + result.insert(*frontal, soln.segment(vectorPosition, getDim(frontal))); + vectorPosition += getDim(frontal); + } + + return result; } - internal::writeVectorValuesSlices(frontalVec, gy, beginFrontals(), endFrontals()); -} -/* ************************************************************************* */ -void GaussianConditional::scaleFrontalsBySigma(VectorValues& gy) const { - Vector frontalVec = internal::extractVectorValuesSlices(gy, beginFrontals(), endFrontals()); - frontalVec = emul(frontalVec, get_sigmas()); - internal::writeVectorValuesSlices(frontalVec, gy, beginFrontals(), endFrontals()); -} + /* ************************************************************************* */ + void GaussianConditional::solveTransposeInPlace(VectorValues& gy) const + { + Vector frontalVec = gy.vector(vector(beginFrontals(), endFrontals())); + frontalVec = gtsam::backSubstituteUpper(frontalVec, Matrix(get_R())); + + // Check for indeterminant solution + if(frontalVec.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) + throw IndeterminantLinearSystemException(this->keys().front()); + + for (const_iterator it = beginParents(); it!= endParents(); it++) + gtsam::transposeMultiplyAdd(-1.0, Matrix(getA(it)), frontalVec, gy[*it]); + + // Scale by sigmas + if(model_) + frontalVec.array() *= model_->sigmas().array(); + + // Write frontal solution into a VectorValues + DenseIndex vectorPosition = 0; + for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { + gy[*frontal] = frontalVec.segment(vectorPosition, getDim(frontal)); + vectorPosition += getDim(frontal); + } + } + + /* ************************************************************************* */ + void GaussianConditional::scaleFrontalsBySigma(VectorValues& gy) const + { + DenseIndex vectorPosition = 0; + for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { + gy[*frontal].array() *= model_->sigmas().segment(vectorPosition, getDim(frontal)).array(); + vectorPosition += getDim(frontal); + } + } } diff --git a/gtsam/linear/GaussianConditional.h b/gtsam/linear/GaussianConditional.h index f20d10ef9..1717b62fa 100644 --- a/gtsam/linear/GaussianConditional.h +++ b/gtsam/linear/GaussianConditional.h @@ -22,279 +22,134 @@ #include #include -#include -#include +#include +#include #include -// Forward declaration to friend unit tests -class JacobianFactoreliminate2Test; -class GaussianConditionalconstructorTest; -class GaussianFactorGrapheliminationTest; -class GaussianJunctionTreecomplicatedMarginalTest; -class GaussianConditionalinformationTest; -class GaussianConditionalisGaussianFactorTest; - namespace gtsam { -// Forward declarations -class GaussianFactor; -class JacobianFactor; - -/** - * A conditional Gaussian functions as the node in a Bayes network - * It has a set of parents y,z, etc. and implements a probability density on x. - * The negative log-probability is given by \f$ \frac{1}{2} |Rx - (d - Sy - Tz - ...)|^2 \f$ - */ -class GTSAM_EXPORT GaussianConditional : public IndexConditional { - -public: - typedef GaussianFactor FactorType; - typedef boost::shared_ptr shared_ptr; - - /** Store the conditional matrix as upper-triangular column-major */ - typedef Matrix RdMatrix; - typedef VerticalBlockView rsd_type; - - typedef rsd_type::Block r_type; - typedef rsd_type::constBlock const_r_type; - typedef rsd_type::Column d_type; - typedef rsd_type::constColumn const_d_type; - -protected: - - /** Store the conditional as one big upper-triangular wide matrix, arranged - * as \f$ [ R S1 S2 ... d ] \f$. Access these blocks using a VerticalBlockView. - * */ - RdMatrix matrix_; - rsd_type rsd_; - - /** vector of standard deviations */ - Vector sigmas_; - - /** typedef to base class */ - typedef IndexConditional Base; - -public: - - /** default constructor needed for serialization */ - GaussianConditional(); - - /** constructor */ - explicit GaussianConditional(Index key); - - /** constructor with no parents - * |Rx-d| - */ - GaussianConditional(Index key, const Vector& d, const Matrix& R, const Vector& sigmas); - - /** constructor with only one parent - * |Rx+Sy-d| - */ - GaussianConditional(Index key, const Vector& d, const Matrix& R, - Index name1, const Matrix& S, const Vector& sigmas); - - /** constructor with two parents - * |Rx+Sy+Tz-d| - */ - GaussianConditional(Index key, const Vector& d, const Matrix& R, - Index name1, const Matrix& S, Index name2, const Matrix& T, const Vector& sigmas); - /** - * constructor with number of arbitrary parents (only used in unit tests, - * std::list is not efficient) - * \f$ |Rx+sum(Ai*xi)-d| \f$ - */ - GaussianConditional(Index key, const Vector& d, - const Matrix& R, const std::list >& parents, const Vector& sigmas); + * A conditional Gaussian functions as the node in a Bayes network + * It has a set of parents y,z, etc. and implements a probability density on x. + * The negative log-probability is given by \f$ \frac{1}{2} |Rx - (d - Sy - Tz - ...)|^2 \f$ + */ + class GTSAM_EXPORT GaussianConditional : + public JacobianFactor, + public Conditional + { + public: + typedef GaussianConditional This; ///< Typedef to this class + typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class + typedef JacobianFactor BaseFactor; ///< Typedef to our factor base class + typedef Conditional BaseConditional; ///< Typedef to our conditional base class - /** - * Constructor with arbitrary number of frontals and parents (only used in unit tests, - * std::list is not efficient) - */ - GaussianConditional(const std::list >& terms, - size_t nrFrontals, const Vector& d, const Vector& sigmas); + /** default constructor needed for serialization */ + GaussianConditional() {} - /** - * Constructor when matrices are already stored in a combined matrix, allows - * for multiple frontal variables. - */ - template - GaussianConditional(ITERATOR firstKey, ITERATOR lastKey, size_t nrFrontals, - const VerticalBlockView& matrices, const Vector& sigmas); + /** constructor with no parents |Rx-d| */ + GaussianConditional(Key key, const Vector& d, const Matrix& R, + const SharedDiagonal& sigmas = SharedDiagonal()); - /** Copy constructor */ - GaussianConditional(const GaussianConditional& rhs); + /** constructor with only one parent |Rx+Sy-d| */ + GaussianConditional(Key key, const Vector& d, const Matrix& R, + Key name1, const Matrix& S, const SharedDiagonal& sigmas = SharedDiagonal()); - /** Combine several GaussianConditional into a single dense GC. The - * conditionals enumerated by \c first and \c last must be in increasing - * order, meaning that the parents of any conditional may not include a - * conditional coming before it. - * @param firstConditional Iterator to the first conditional to combine, must dereference to a shared_ptr. - * @param lastConditional Iterator to after the last conditional to combine, must dereference to a shared_ptr. */ - template - static shared_ptr Combine(ITERATOR firstConditional, ITERATOR lastConditional); + /** constructor with two parents |Rx+Sy+Tz-d| */ + GaussianConditional(Key key, const Vector& d, const Matrix& R, + Key name1, const Matrix& S, Key name2, const Matrix& T, + const SharedDiagonal& sigmas = SharedDiagonal()); - /** Assignment operator */ - GaussianConditional& operator=(const GaussianConditional& rhs); + /** Constructor with number of arbitrary parents. \f$ |Rx+sum(Ai*xi)-d| \f$ + * @tparam PARENTS A container whose value type is std::pair, specifying the + * collection of parent keys and matrices. */ + template + GaussianConditional(Key key, const Vector& d, + const Matrix& R, const PARENTS& parents, + const SharedDiagonal& sigmas = SharedDiagonal(), + const typename PARENTS::value_type* = 0); - /** print */ - void print(const std::string& = "GaussianConditional", - const IndexFormatter& formatter = DefaultIndexFormatter) const; + /** Constructor with arbitrary number of frontals and parents. + * @tparam TERMS A container whose value type is std::pair, specifying the + * collection of keys and matrices making up the conditional. */ + template + GaussianConditional(const TERMS& terms, + size_t nrFrontals, const Vector& d, + const SharedDiagonal& sigmas = SharedDiagonal()); - /** equals function */ - bool equals(const GaussianConditional &cg, double tol = 1e-9) const; + /** Constructor with arbitrary number keys, and where the augmented matrix is given all together + * instead of in block terms. Note that only the active view of the provided augmented matrix + * is used, and that the matrix data is copied into a newly-allocated matrix in the constructed + * factor. */ + template + GaussianConditional( + const KEYS& keys, size_t nrFrontals, const VerticalBlockMatrix& augmentedMatrix, + const SharedDiagonal& sigmas = SharedDiagonal()); - /** dimension of multivariate variable (same as rows()) */ - size_t dim() const { return rsd_.rows(); } + /** Combine several GaussianConditional into a single dense GC. The conditionals enumerated by + * \c first and \c last must be in increasing order, meaning that the parents of any + * conditional may not include a conditional coming before it. + * @param firstConditional Iterator to the first conditional to combine, must dereference to a + * shared_ptr. + * @param lastConditional Iterator to after the last conditional to combine, must dereference + * to a shared_ptr. */ + template + static shared_ptr Combine(ITERATOR firstConditional, ITERATOR lastConditional); - /** dimension of multivariate variable (same as dim()) */ - size_t rows() const { return dim(); } + /** print */ + void print(const std::string& = "GaussianConditional", + const KeyFormatter& formatter = DefaultKeyFormatter) const; - /** Compute the augmented information matrix as - * \f$ [ R S d ]^T [ R S d ] \f$ - */ - Matrix augmentedInformation() const { - return rsd_.full().transpose() * rsd_.full().transpose(); - } + /** equals function */ + bool equals(const GaussianConditional&cg, double tol = 1e-9) const; - /** Compute the information matrix */ - Matrix information() const { - return get_R().transpose() * get_R(); - } + /** Return a view of the upper-triangular R block of the conditional */ + constABlock get_R() const { return Ab_.range(0, nrFrontals()); } - /** Return a view of the upper-triangular R block of the conditional */ - rsd_type::constBlock get_R() const { return rsd_.range(0, nrFrontals()); } + /** Get a view of the parent blocks. */ + constABlock get_S() const { return Ab_.range(nrFrontals(), size()); } - /** Return a view of the r.h.s. d vector */ - const_d_type get_d() const { return rsd_.column(nrFrontals()+nrParents(), 0); } + /** Get a view of the S matrix for the variable pointed to by the given key iterator */ + constABlock get_S(const_iterator variable) const { return BaseFactor::getA(variable); } - /** get the dimension of a variable */ - size_t dim(const_iterator variable) const { return rsd_(variable - this->begin()).cols(); } + /** Get a view of the r.h.s. vector d */ + const constBVector get_d() const { return BaseFactor::getb(); } - /** Get a view of the parent block corresponding to the variable pointed to by the given key iterator */ - rsd_type::constBlock get_S(const_iterator variable) const { return rsd_(variable - this->begin()); } - /** Get a view of the parent block corresponding to the variable pointed to by the given key iterator (non-const version) */ - rsd_type::constBlock get_S() const { return rsd_.range(nrFrontals(), size()); } - /** Get the Vector of sigmas */ - const Vector& get_sigmas() const {return sigmas_;} + /** + * Solves a conditional Gaussian and writes the solution into the entries of + * \c x for each frontal variable of the conditional. The parents are + * assumed to have already been solved in and their values are read from \c x. + * This function works for multiple frontal variables. + * + * Given the Gaussian conditional with log likelihood \f$ |R x_f - (d - S x_s)|^2, + * where \f$ f \f$ are the frontal variables and \f$ s \f$ are the separator + * variables of this conditional, this solve function computes + * \f$ x_f = R^{-1} (d - S x_s) \f$ using back-substitution. + * + * @param parents VectorValues containing solved parents \f$ x_s \f$. + */ + VectorValues solve(const VectorValues& parents) const; -protected: + VectorValues solveOtherRHS(const VectorValues& parents, const VectorValues& rhs) const; - const RdMatrix& matrix() const { return matrix_; } - const rsd_type& rsd() const { return rsd_; } + /** Performs transpose backsubstition in place on values */ + void solveTransposeInPlace(VectorValues& gy) const; -public: - /** - * Copy to a Factor (this creates a JacobianFactor and returns it as its - * base class GaussianFactor. - */ - boost::shared_ptr toFactor() const; + /** Scale the values in \c gy according to the sigmas for the frontal variables in this + * conditional. */ + __declspec(deprecated) void scaleFrontalsBySigma(VectorValues& gy) const; - /** - * Solves a conditional Gaussian and writes the solution into the entries of - * \c x for each frontal variable of the conditional. The parents are - * assumed to have already been solved in and their values are read from \c x. - * This function works for multiple frontal variables. - * - * Given the Gaussian conditional with log likelihood \f$ |R x_f - (d - S x_s)|^2, - * where \f$ f \f$ are the frontal variables and \f$ s \f$ are the separator - * variables of this conditional, this solve function computes - * \f$ x_f = R^{-1} (d - S x_s) \f$ using back-substitution. - * - * @param x VectorValues structure with solved parents \f$ x_s \f$, and into which the - * solution \f$ x_f \f$ will be written. - */ - void solveInPlace(VectorValues& x) const; + private: - // functions for transpose backsubstitution - - /** - * Performs backsubstition in place on values - */ - void solveTransposeInPlace(VectorValues& gy) const; - void scaleFrontalsBySigma(VectorValues& gy) const; - -protected: - rsd_type::Column get_d_() { return rsd_.column(nrFrontals()+nrParents(), 0); } - rsd_type::Block get_R_() { return rsd_.range(0, nrFrontals()); } - rsd_type::Block get_S_(iterator variable) { return rsd_(variable - this->begin()); } - -private: - - // Friends - friend class JacobianFactor; - friend class ::JacobianFactoreliminate2Test; - friend class ::GaussianConditionalconstructorTest; - friend class ::GaussianFactorGrapheliminationTest; - friend class ::GaussianJunctionTreecomplicatedMarginalTest; - friend class ::GaussianConditionalinformationTest; - friend class ::GaussianConditionalisGaussianFactorTest; - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(IndexConditional); - ar & BOOST_SERIALIZATION_NVP(matrix_); - ar & BOOST_SERIALIZATION_NVP(rsd_); - ar & BOOST_SERIALIZATION_NVP(sigmas_); - } -}; // GaussianConditional - -/* ************************************************************************* */ -template -GaussianConditional::GaussianConditional(ITERATOR firstKey, ITERATOR lastKey, - size_t nrFrontals, const VerticalBlockView& matrices, - const Vector& sigmas) : - IndexConditional(std::vector(firstKey, lastKey), nrFrontals), rsd_( - matrix_), sigmas_(sigmas) { - rsd_.assignNoalias(matrices); -} - -/* ************************************************************************* */ -template -GaussianConditional::shared_ptr GaussianConditional::Combine(ITERATOR firstConditional, ITERATOR lastConditional) { - - // TODO: check for being a clique - - // Get dimensions from first conditional - std::vector dims; dims.reserve((*firstConditional)->size() + 1); - for(const_iterator j = (*firstConditional)->begin(); j != (*firstConditional)->end(); ++j) - dims.push_back((*firstConditional)->dim(j)); - dims.push_back(1); - - // We assume the conditionals form clique, so the first n variables will be - // frontal variables in the new conditional. - size_t nFrontals = 0; - size_t nRows = 0; - for(ITERATOR c = firstConditional; c != lastConditional; ++c) { - nRows += dims[nFrontals]; - ++ nFrontals; - } - - // Allocate combined conditional, has same keys as firstConditional - Matrix tempCombined; - VerticalBlockView tempBlockView(tempCombined, dims.begin(), dims.end(), 0); - GaussianConditional::shared_ptr combinedConditional(new GaussianConditional((*firstConditional)->begin(), (*firstConditional)->end(), nFrontals, tempBlockView, zero(nRows))); - - // Resize to correct number of rows - combinedConditional->matrix_.resize(nRows, combinedConditional->matrix_.cols()); - combinedConditional->rsd_.rowEnd() = combinedConditional->matrix_.rows(); - - // Copy matrix and sigmas - const size_t totalDims = combinedConditional->matrix_.cols(); - size_t currentSlot = 0; - for(ITERATOR c = firstConditional; c != lastConditional; ++c) { - const size_t startRow = combinedConditional->rsd_.offset(currentSlot); // Start row is same as start column - combinedConditional->rsd_.range(0, currentSlot).block(startRow, 0, dims[currentSlot], combinedConditional->rsd_.offset(currentSlot)).operator=( - Matrix::Zero(dims[currentSlot], combinedConditional->rsd_.offset(currentSlot))); - combinedConditional->rsd_.range(currentSlot, dims.size()).block(startRow, 0, dims[currentSlot], totalDims - startRow).operator=( - (*c)->matrix_); - combinedConditional->sigmas_.segment(startRow, dims[currentSlot]) = (*c)->sigmas_; - ++ currentSlot; - } - - return combinedConditional; -} + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(BaseFactor); + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(BaseConditional); + } + }; // GaussianConditional } // gtsam + +#include + diff --git a/gtsam/linear/GaussianConditionalOrdered.cpp b/gtsam/linear/GaussianConditionalOrdered.cpp new file mode 100644 index 000000000..dca2d8aa7 --- /dev/null +++ b/gtsam/linear/GaussianConditionalOrdered.cpp @@ -0,0 +1,238 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianConditional.cpp + * @brief Conditional Gaussian Base class + * @author Christian Potthast + */ + +#include +#include +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif +#include +#include +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include +#include +#include +#include + +using namespace std; + +namespace gtsam { + +/* ************************************************************************* */ +GaussianConditionalOrdered::GaussianConditionalOrdered() : rsd_(matrix_) {} + +/* ************************************************************************* */ +GaussianConditionalOrdered::GaussianConditionalOrdered(Index key) : IndexConditionalOrdered(key), rsd_(matrix_) {} + +/* ************************************************************************* */ +GaussianConditionalOrdered::GaussianConditionalOrdered(Index key,const Vector& d, const Matrix& R, const Vector& sigmas) : + IndexConditionalOrdered(key), rsd_(matrix_), sigmas_(sigmas) { + assert(R.rows() <= R.cols()); + size_t dims[] = { R.cols(), 1 }; + rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+2, d.size())); + rsd_(0) = R.triangularView(); + get_d_() = d; +} + +/* ************************************************************************* */ +GaussianConditionalOrdered::GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R, + Index name1, const Matrix& S, const Vector& sigmas) : + IndexConditionalOrdered(key,name1), rsd_(matrix_), sigmas_(sigmas) { + assert(R.rows() <= R.cols()); + size_t dims[] = { R.cols(), S.cols(), 1 }; + rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+3, d.size())); + rsd_(0) = R.triangularView(); + rsd_(1) = S; + get_d_() = d; +} + +/* ************************************************************************* */ +GaussianConditionalOrdered::GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R, + Index name1, const Matrix& S, Index name2, const Matrix& T, const Vector& sigmas) : + IndexConditionalOrdered(key,name1,name2), rsd_(matrix_), sigmas_(sigmas) { + assert(R.rows() <= R.cols()); + size_t dims[] = { R.cols(), S.cols(), T.cols(), 1 }; + rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+4, d.size())); + rsd_(0) = R.triangularView(); + rsd_(1) = S; + rsd_(2) = T; + get_d_() = d; +} + +/* ************************************************************************* */ + GaussianConditionalOrdered::GaussianConditionalOrdered(Index key, const Vector& d, + const Matrix& R, const list >& parents, const Vector& sigmas) : + IndexConditionalOrdered(key, GetKeys(parents.size(), parents.begin(), parents.end())), rsd_(matrix_), sigmas_(sigmas) { + assert(R.rows() <= R.cols()); + size_t* dims = (size_t*)alloca(sizeof(size_t)*(1+parents.size()+1)); // FIXME: alloca is bad, just ask Google. + dims[0] = R.cols(); + size_t j=1; + std::list >::const_iterator parent=parents.begin(); + for(; parent!=parents.end(); ++parent,++j) + dims[j] = parent->second.cols(); + dims[j] = 1; + rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+1+parents.size()+1, d.size())); + rsd_(0) = R.triangularView(); + j = 1; + for(std::list >::const_iterator parent=parents.begin(); parent!=parents.end(); ++parent) { + rsd_(j).noalias() = parent->second; + ++ j; + } + get_d_() = d; +} + +/* ************************************************************************* */ +GaussianConditionalOrdered::GaussianConditionalOrdered(const std::list >& terms, + const size_t nrFrontals, const Vector& d, const Vector& sigmas) : + IndexConditionalOrdered(GetKeys(terms.size(), terms.begin(), terms.end()), nrFrontals), + rsd_(matrix_), sigmas_(sigmas) { + size_t* dims = (size_t*)alloca(sizeof(size_t)*(terms.size()+1)); // FIXME: alloca is bad, just ask Google. + size_t j=0; + typedef pair Index_Matrix; + BOOST_FOREACH(const Index_Matrix& term, terms) { + dims[j] = term.second.cols(); + ++ j; + } + dims[j] = 1; + rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+terms.size()+1, d.size())); + j=0; + BOOST_FOREACH(const Index_Matrix& term, terms) { + rsd_(j) = term.second; + ++ j; + } + get_d_() = d; +} + +/* ************************************************************************* */ +GaussianConditionalOrdered::GaussianConditionalOrdered(const GaussianConditionalOrdered& rhs) : + rsd_(matrix_) { + *this = rhs; +} + +/* ************************************************************************* */ +GaussianConditionalOrdered& GaussianConditionalOrdered::operator=(const GaussianConditionalOrdered& rhs) { + if(this != &rhs) { + this->Base::operator=(rhs); // Copy keys + rsd_.assignNoalias(rhs.rsd_); // Copy matrix and block configuration + sigmas_ = rhs.sigmas_; // Copy sigmas + } + return *this; +} + +/* ************************************************************************* */ +void GaussianConditionalOrdered::print(const string &s, const IndexFormatter& formatter) const +{ + cout << s << ": density on "; + for(const_iterator it = beginFrontals(); it != endFrontals(); ++it) { + cout << (boost::format("[%1%]")%(formatter(*it))).str() << " "; + } + cout << endl; + gtsam::print(Matrix(get_R()),"R"); + for(const_iterator it = beginParents() ; it != endParents() ; ++it ) { + gtsam::print(Matrix(get_S(it)), (boost::format("A[%1%]")%(formatter(*it))).str()); + } + gtsam::print(Vector(get_d()),"d"); + gtsam::print(sigmas_,"sigmas"); +} + +/* ************************************************************************* */ +bool GaussianConditionalOrdered::equals(const GaussianConditionalOrdered &c, double tol) const { + // check if the size of the parents_ map is the same + if (parents().size() != c.parents().size()) + return false; + + // check if R_ and d_ are linear independent + for (size_t i=0; i rows1; rows1.push_back(Vector(get_R().row(i))); + list rows2; rows2.push_back(Vector(c.get_R().row(i))); + + // check if the matrices are the same + // iterate over the parents_ map + for (const_iterator it = beginParents(); it != endParents(); ++it) { + const_iterator it2 = c.beginParents() + (it-beginParents()); + if(*it != *(it2)) + return false; + rows1.push_back(row(get_S(it), i)); + rows2.push_back(row(c.get_S(it2), i)); + } + + Vector row1 = concatVectors(rows1); + Vector row2 = concatVectors(rows2); + if (!linear_dependent(row1, row2, tol)) + return false; + } + + // check if sigmas are equal + if (!(equal_with_abs_tol(sigmas_, c.sigmas_, tol))) return false; + + return true; +} + +/* ************************************************************************* */ +JacobianFactorOrdered::shared_ptr GaussianConditionalOrdered::toFactor() const { + return JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(*this)); +} + +/* ************************************************************************* */ +void GaussianConditionalOrdered::solveInPlace(VectorValuesOrdered& x) const { + static const bool debug = false; + if(debug) this->print("Solving conditional in place"); + Vector xS = internal::extractVectorValuesSlices(x, this->beginParents(), this->endParents()); + xS = this->get_d() - this->get_S() * xS; + Vector soln = this->get_R().triangularView().solve(xS); + + // Check for indeterminant solution + if(soln.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) + throw IndeterminantLinearSystemException(this->keys().front()); + + if(debug) { + gtsam::print(Matrix(this->get_R()), "Calling backSubstituteUpper on "); + gtsam::print(soln, "full back-substitution solution: "); + } + internal::writeVectorValuesSlices(soln, x, this->beginFrontals(), this->endFrontals()); +} + +/* ************************************************************************* */ +void GaussianConditionalOrdered::solveTransposeInPlace(VectorValuesOrdered& gy) const { + Vector frontalVec = internal::extractVectorValuesSlices(gy, beginFrontals(), endFrontals()); + frontalVec = gtsam::backSubstituteUpper(frontalVec,Matrix(get_R())); + + // Check for indeterminant solution + if(frontalVec.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) + throw IndeterminantLinearSystemException(this->keys().front()); + + GaussianConditionalOrdered::const_iterator it; + for (it = beginParents(); it!= endParents(); it++) { + const Index i = *it; + transposeMultiplyAdd(-1.0,get_S(it),frontalVec,gy[i]); + } + internal::writeVectorValuesSlices(frontalVec, gy, beginFrontals(), endFrontals()); +} + +/* ************************************************************************* */ +void GaussianConditionalOrdered::scaleFrontalsBySigma(VectorValuesOrdered& gy) const { + Vector frontalVec = internal::extractVectorValuesSlices(gy, beginFrontals(), endFrontals()); + frontalVec = emul(frontalVec, get_sigmas()); + internal::writeVectorValuesSlices(frontalVec, gy, beginFrontals(), endFrontals()); +} + +} + diff --git a/gtsam/linear/GaussianConditionalOrdered.h b/gtsam/linear/GaussianConditionalOrdered.h new file mode 100644 index 000000000..0c9f17f80 --- /dev/null +++ b/gtsam/linear/GaussianConditionalOrdered.h @@ -0,0 +1,300 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianConditional.h + * @brief Conditional Gaussian Base class + * @author Christian Potthast + */ + +// \callgraph + +#pragma once + +#include + +#include +#include +#include +#include + +// Forward declaration to friend unit tests +class JacobianFactorOrderedeliminate2Test; +class GaussianConditionalOrderedconstructorTest; +class GaussianFactorGraphOrderedeliminationTest; +class GaussianJunctionTreeOrderedcomplicatedMarginalTest; +class GaussianConditionalOrderedinformationTest; +class GaussianConditionalOrderedisGaussianFactorTest; + +namespace gtsam { + +// Forward declarations +class GaussianFactorOrdered; +class JacobianFactorOrdered; + +/** + * A conditional Gaussian functions as the node in a Bayes network + * It has a set of parents y,z, etc. and implements a probability density on x. + * The negative log-probability is given by \f$ \frac{1}{2} |Rx - (d - Sy - Tz - ...)|^2 \f$ + */ +class GTSAM_EXPORT GaussianConditionalOrdered : public IndexConditionalOrdered { + +public: + typedef GaussianFactorOrdered FactorType; + typedef boost::shared_ptr shared_ptr; + + /** Store the conditional matrix as upper-triangular column-major */ + typedef Matrix RdMatrix; + typedef VerticalBlockView rsd_type; + + typedef rsd_type::Block r_type; + typedef rsd_type::constBlock const_r_type; + typedef rsd_type::Column d_type; + typedef rsd_type::constColumn const_d_type; + +protected: + + /** Store the conditional as one big upper-triangular wide matrix, arranged + * as \f$ [ R S1 S2 ... d ] \f$. Access these blocks using a VerticalBlockView. + * */ + RdMatrix matrix_; + rsd_type rsd_; + + /** vector of standard deviations */ + Vector sigmas_; + + /** typedef to base class */ + typedef IndexConditionalOrdered Base; + +public: + + /** default constructor needed for serialization */ + GaussianConditionalOrdered(); + + /** constructor */ + explicit GaussianConditionalOrdered(Index key); + + /** constructor with no parents + * |Rx-d| + */ + GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R, const Vector& sigmas); + + /** constructor with only one parent + * |Rx+Sy-d| + */ + GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R, + Index name1, const Matrix& S, const Vector& sigmas); + + /** constructor with two parents + * |Rx+Sy+Tz-d| + */ + GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R, + Index name1, const Matrix& S, Index name2, const Matrix& T, const Vector& sigmas); + + /** + * constructor with number of arbitrary parents (only used in unit tests, + * std::list is not efficient) + * \f$ |Rx+sum(Ai*xi)-d| \f$ + */ + GaussianConditionalOrdered(Index key, const Vector& d, + const Matrix& R, const std::list >& parents, const Vector& sigmas); + + /** + * Constructor with arbitrary number of frontals and parents (only used in unit tests, + * std::list is not efficient) + */ + GaussianConditionalOrdered(const std::list >& terms, + size_t nrFrontals, const Vector& d, const Vector& sigmas); + + /** + * Constructor when matrices are already stored in a combined matrix, allows + * for multiple frontal variables. + */ + template + GaussianConditionalOrdered(ITERATOR firstKey, ITERATOR lastKey, size_t nrFrontals, + const VerticalBlockView& matrices, const Vector& sigmas); + + /** Copy constructor */ + GaussianConditionalOrdered(const GaussianConditionalOrdered& rhs); + + /** Combine several GaussianConditional into a single dense GC. The + * conditionals enumerated by \c first and \c last must be in increasing + * order, meaning that the parents of any conditional may not include a + * conditional coming before it. + * @param firstConditional Iterator to the first conditional to combine, must dereference to a shared_ptr. + * @param lastConditional Iterator to after the last conditional to combine, must dereference to a shared_ptr. */ + template + static shared_ptr Combine(ITERATOR firstConditional, ITERATOR lastConditional); + + /** Assignment operator */ + GaussianConditionalOrdered& operator=(const GaussianConditionalOrdered& rhs); + + /** print */ + void print(const std::string& = "GaussianConditional", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /** equals function */ + bool equals(const GaussianConditionalOrdered &cg, double tol = 1e-9) const; + + /** dimension of multivariate variable (same as rows()) */ + size_t dim() const { return rsd_.rows(); } + + /** dimension of multivariate variable (same as dim()) */ + size_t rows() const { return dim(); } + + /** Compute the augmented information matrix as + * \f$ [ R S d ]^T [ R S d ] \f$ + */ + Matrix augmentedInformation() const { + return rsd_.full().transpose() * rsd_.full().transpose(); + } + + /** Compute the information matrix */ + Matrix information() const { + return get_R().transpose() * get_R(); + } + + /** Return a view of the upper-triangular R block of the conditional */ + rsd_type::constBlock get_R() const { return rsd_.range(0, nrFrontals()); } + + /** Return a view of the r.h.s. d vector */ + const_d_type get_d() const { return rsd_.column(nrFrontals()+nrParents(), 0); } + + /** get the dimension of a variable */ + size_t dim(const_iterator variable) const { return rsd_(variable - this->begin()).cols(); } + + /** Get a view of the parent block corresponding to the variable pointed to by the given key iterator */ + rsd_type::constBlock get_S(const_iterator variable) const { return rsd_(variable - this->begin()); } + /** Get a view of the parent block corresponding to the variable pointed to by the given key iterator (non-const version) */ + rsd_type::constBlock get_S() const { return rsd_.range(nrFrontals(), size()); } + /** Get the Vector of sigmas */ + const Vector& get_sigmas() const {return sigmas_;} + +protected: + + const RdMatrix& matrix() const { return matrix_; } + const rsd_type& rsd() const { return rsd_; } + +public: + /** + * Copy to a Factor (this creates a JacobianFactor and returns it as its + * base class GaussianFactor. + */ + boost::shared_ptr toFactor() const; + + /** + * Solves a conditional Gaussian and writes the solution into the entries of + * \c x for each frontal variable of the conditional. The parents are + * assumed to have already been solved in and their values are read from \c x. + * This function works for multiple frontal variables. + * + * Given the Gaussian conditional with log likelihood \f$ |R x_f - (d - S x_s)|^2, + * where \f$ f \f$ are the frontal variables and \f$ s \f$ are the separator + * variables of this conditional, this solve function computes + * \f$ x_f = R^{-1} (d - S x_s) \f$ using back-substitution. + * + * @param x VectorValues structure with solved parents \f$ x_s \f$, and into which the + * solution \f$ x_f \f$ will be written. + */ + void solveInPlace(VectorValuesOrdered& x) const; + + // functions for transpose backsubstitution + + /** + * Performs backsubstition in place on values + */ + void solveTransposeInPlace(VectorValuesOrdered& gy) const; + void scaleFrontalsBySigma(VectorValuesOrdered& gy) const; + +protected: + rsd_type::Column get_d_() { return rsd_.column(nrFrontals()+nrParents(), 0); } + rsd_type::Block get_R_() { return rsd_.range(0, nrFrontals()); } + rsd_type::Block get_S_(iterator variable) { return rsd_(variable - this->begin()); } + +private: + + // Friends + friend class JacobianFactorOrdered; + friend class ::JacobianFactorOrderedeliminate2Test; + friend class ::GaussianConditionalOrderedconstructorTest; + friend class ::GaussianFactorGraphOrderedeliminationTest; + friend class ::GaussianJunctionTreeOrderedcomplicatedMarginalTest; + friend class ::GaussianConditionalOrderedinformationTest; + friend class ::GaussianConditionalOrderedisGaussianFactorTest; + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(IndexConditionalOrdered); + ar & BOOST_SERIALIZATION_NVP(matrix_); + ar & BOOST_SERIALIZATION_NVP(rsd_); + ar & BOOST_SERIALIZATION_NVP(sigmas_); + } +}; // GaussianConditional + +/* ************************************************************************* */ +template +GaussianConditionalOrdered::GaussianConditionalOrdered(ITERATOR firstKey, ITERATOR lastKey, + size_t nrFrontals, const VerticalBlockView& matrices, + const Vector& sigmas) : + IndexConditionalOrdered(std::vector(firstKey, lastKey), nrFrontals), rsd_( + matrix_), sigmas_(sigmas) { + rsd_.assignNoalias(matrices); +} + +/* ************************************************************************* */ +template +GaussianConditionalOrdered::shared_ptr GaussianConditionalOrdered::Combine(ITERATOR firstConditional, ITERATOR lastConditional) { + + // TODO: check for being a clique + + // Get dimensions from first conditional + std::vector dims; dims.reserve((*firstConditional)->size() + 1); + for(const_iterator j = (*firstConditional)->begin(); j != (*firstConditional)->end(); ++j) + dims.push_back((*firstConditional)->dim(j)); + dims.push_back(1); + + // We assume the conditionals form clique, so the first n variables will be + // frontal variables in the new conditional. + size_t nFrontals = 0; + size_t nRows = 0; + for(ITERATOR c = firstConditional; c != lastConditional; ++c) { + nRows += dims[nFrontals]; + ++ nFrontals; + } + + // Allocate combined conditional, has same keys as firstConditional + Matrix tempCombined; + VerticalBlockView tempBlockView(tempCombined, dims.begin(), dims.end(), 0); + GaussianConditionalOrdered::shared_ptr combinedConditional(new GaussianConditionalOrdered((*firstConditional)->begin(), (*firstConditional)->end(), nFrontals, tempBlockView, zero(nRows))); + + // Resize to correct number of rows + combinedConditional->matrix_.resize(nRows, combinedConditional->matrix_.cols()); + combinedConditional->rsd_.rowEnd() = combinedConditional->matrix_.rows(); + + // Copy matrix and sigmas + const size_t totalDims = combinedConditional->matrix_.cols(); + size_t currentSlot = 0; + for(ITERATOR c = firstConditional; c != lastConditional; ++c) { + const size_t startRow = combinedConditional->rsd_.offset(currentSlot); // Start row is same as start column + combinedConditional->rsd_.range(0, currentSlot).block(startRow, 0, dims[currentSlot], combinedConditional->rsd_.offset(currentSlot)).operator=( + Matrix::Zero(dims[currentSlot], combinedConditional->rsd_.offset(currentSlot))); + combinedConditional->rsd_.range(currentSlot, dims.size()).block(startRow, 0, dims[currentSlot], totalDims - startRow).operator=( + (*c)->matrix_); + combinedConditional->sigmas_.segment(startRow, dims[currentSlot]) = (*c)->sigmas_; + ++ currentSlot; + } + + return combinedConditional; +} + +} // gtsam diff --git a/gtsam/linear/GaussianConditionalUnordered.cpp b/gtsam/linear/GaussianConditionalUnordered.cpp deleted file mode 100644 index 556d60e7f..000000000 --- a/gtsam/linear/GaussianConditionalUnordered.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianConditional.cpp - * @brief Conditional Gaussian Base class - * @author Christian Potthast - */ - -#include -#include -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif -#include -#include -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#include -#include -#include - -using namespace std; - -namespace gtsam { - - /* ************************************************************************* */ - GaussianConditionalUnordered::GaussianConditionalUnordered( - Key key, const Vector& d, const Matrix& R, const SharedDiagonal& sigmas) : - BaseFactor(key, R, d, sigmas), BaseConditional(1) {} - - /* ************************************************************************* */ - GaussianConditionalUnordered::GaussianConditionalUnordered( - Key key, const Vector& d, const Matrix& R, - Key name1, const Matrix& S, const SharedDiagonal& sigmas) : - BaseFactor(key, R, name1, S, d, sigmas), BaseConditional(1) {} - - /* ************************************************************************* */ - GaussianConditionalUnordered::GaussianConditionalUnordered( - Key key, const Vector& d, const Matrix& R, - Key name1, const Matrix& S, Key name2, const Matrix& T, const SharedDiagonal& sigmas) : - BaseFactor(key, R, name1, S, name2, T, d, sigmas), BaseConditional(1) {} - - /* ************************************************************************* */ - void GaussianConditionalUnordered::print(const string &s, const IndexFormatter& formatter) const - { - cout << s << " Conditional density "; - for(const_iterator it = beginFrontals(); it != endFrontals(); ++it) { - cout << (boost::format("[%1%]")%(formatter(*it))).str() << " "; - } - cout << endl; - cout << formatMatrixIndented(" R = ", get_R()) << endl; - for(const_iterator it = beginParents() ; it != endParents() ; ++it ) { - cout << formatMatrixIndented((boost::format(" S[%1%] = ")%(formatter(*it))).str(), getA(it)) - << endl; - } - cout << formatMatrixIndented(" d = ", getb(), true) << "\n"; - if(model_) - model_->print(" Noise model: "); - else - cout << " No noise model" << endl; - } - - /* ************************************************************************* */ - bool GaussianConditionalUnordered::equals(const GaussianConditionalUnordered &c, double tol) const - { - // check if the size of the parents_ map is the same - if (parents().size() != c.parents().size()) - return false; - - // check if R_ and d_ are linear independent - for (DenseIndex i=0; i rows1; rows1.push_back(Vector(get_R().row(i))); - list rows2; rows2.push_back(Vector(c.get_R().row(i))); - - // check if the matrices are the same - // iterate over the parents_ map - for (const_iterator it = beginParents(); it != endParents(); ++it) { - const_iterator it2 = c.beginParents() + (it-beginParents()); - if(*it != *(it2)) - return false; - rows1.push_back(row(getA(it), i)); - rows2.push_back(row(c.getA(it2), i)); - } - - Vector row1 = concatVectors(rows1); - Vector row2 = concatVectors(rows2); - if (!linear_dependent(row1, row2, tol)) - return false; - } - - // check if sigmas are equal - if ((model_ && !c.model_) || (!model_ && c.model_) - || (model_ && c.model_ && !model_->equals(*c.model_, tol))) - return false; - - return true; - } - - /* ************************************************************************* */ - VectorValuesUnordered GaussianConditionalUnordered::solve(const VectorValuesUnordered& x) const - { - // Solve matrix - Vector xS = x.vector(vector(beginParents(), endParents())); - xS = getb() - get_S() * xS; - Vector soln = get_R().triangularView().solve(xS); - - // Check for indeterminant solution - if(soln.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) - throw IndeterminantLinearSystemException(keys().front()); - - // Insert solution into a VectorValues - VectorValuesUnordered result; - DenseIndex vectorPosition = 0; - for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { - result.insert(*frontal, soln.segment(vectorPosition, getDim(frontal))); - vectorPosition += getDim(frontal); - } - - return result; - } - - /* ************************************************************************* */ - VectorValuesUnordered GaussianConditionalUnordered::solveOtherRHS( - const VectorValuesUnordered& parents, const VectorValuesUnordered& rhs) const - { - Vector xS = parents.vector(vector(beginParents(), endParents())); - const Vector rhsR = rhs.vector(vector(beginFrontals(), endFrontals())); - xS = rhsR - get_S() * xS; - Vector soln = get_R().triangularView().solve(xS); - - // Scale by sigmas - if(model_) - soln.array() *= model_->sigmas().array(); - - // Insert solution into a VectorValues - VectorValuesUnordered result; - DenseIndex vectorPosition = 0; - for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { - result.insert(*frontal, soln.segment(vectorPosition, getDim(frontal))); - vectorPosition += getDim(frontal); - } - - return result; - } - - /* ************************************************************************* */ - void GaussianConditionalUnordered::solveTransposeInPlace(VectorValuesUnordered& gy) const - { - Vector frontalVec = gy.vector(vector(beginFrontals(), endFrontals())); - frontalVec = gtsam::backSubstituteUpper(frontalVec, Matrix(get_R())); - - // Check for indeterminant solution - if(frontalVec.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite), boost::lambda::_1)).any()) - throw IndeterminantLinearSystemException(this->keys().front()); - - for (const_iterator it = beginParents(); it!= endParents(); it++) - gtsam::transposeMultiplyAdd(-1.0, Matrix(getA(it)), frontalVec, gy[*it]); - - // Scale by sigmas - if(model_) - frontalVec.array() *= model_->sigmas().array(); - - // Write frontal solution into a VectorValues - DenseIndex vectorPosition = 0; - for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { - gy[*frontal] = frontalVec.segment(vectorPosition, getDim(frontal)); - vectorPosition += getDim(frontal); - } - } - - /* ************************************************************************* */ - void GaussianConditionalUnordered::scaleFrontalsBySigma(VectorValuesUnordered& gy) const - { - DenseIndex vectorPosition = 0; - for(const_iterator frontal = beginFrontals(); frontal != endFrontals(); ++frontal) { - gy[*frontal].array() *= model_->sigmas().segment(vectorPosition, getDim(frontal)).array(); - vectorPosition += getDim(frontal); - } - } - -} - diff --git a/gtsam/linear/GaussianConditionalUnordered.h b/gtsam/linear/GaussianConditionalUnordered.h deleted file mode 100644 index 3bfc2fccd..000000000 --- a/gtsam/linear/GaussianConditionalUnordered.h +++ /dev/null @@ -1,155 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianConditional.h - * @brief Conditional Gaussian Base class - * @author Christian Potthast - */ - -// \callgraph - -#pragma once - -#include - -#include -#include -#include -#include - -namespace gtsam { - - /** - * A conditional Gaussian functions as the node in a Bayes network - * It has a set of parents y,z, etc. and implements a probability density on x. - * The negative log-probability is given by \f$ \frac{1}{2} |Rx - (d - Sy - Tz - ...)|^2 \f$ - */ - class GTSAM_EXPORT GaussianConditionalUnordered : - public JacobianFactorUnordered, - public ConditionalUnordered - { - public: - typedef GaussianConditionalUnordered This; ///< Typedef to this class - typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class - typedef JacobianFactorUnordered BaseFactor; ///< Typedef to our factor base class - typedef ConditionalUnordered BaseConditional; ///< Typedef to our conditional base class - - /** default constructor needed for serialization */ - GaussianConditionalUnordered() {} - - /** constructor with no parents |Rx-d| */ - GaussianConditionalUnordered(Key key, const Vector& d, const Matrix& R, - const SharedDiagonal& sigmas = SharedDiagonal()); - - /** constructor with only one parent |Rx+Sy-d| */ - GaussianConditionalUnordered(Key key, const Vector& d, const Matrix& R, - Key name1, const Matrix& S, const SharedDiagonal& sigmas = SharedDiagonal()); - - /** constructor with two parents |Rx+Sy+Tz-d| */ - GaussianConditionalUnordered(Key key, const Vector& d, const Matrix& R, - Key name1, const Matrix& S, Key name2, const Matrix& T, - const SharedDiagonal& sigmas = SharedDiagonal()); - - /** Constructor with number of arbitrary parents. \f$ |Rx+sum(Ai*xi)-d| \f$ - * @tparam PARENTS A container whose value type is std::pair, specifying the - * collection of parent keys and matrices. */ - template - GaussianConditionalUnordered(Key key, const Vector& d, - const Matrix& R, const PARENTS& parents, - const SharedDiagonal& sigmas = SharedDiagonal(), - const typename PARENTS::value_type* = 0); - - /** Constructor with arbitrary number of frontals and parents. - * @tparam TERMS A container whose value type is std::pair, specifying the - * collection of keys and matrices making up the conditional. */ - template - GaussianConditionalUnordered(const TERMS& terms, - size_t nrFrontals, const Vector& d, - const SharedDiagonal& sigmas = SharedDiagonal()); - - /** Constructor with arbitrary number keys, and where the augmented matrix is given all together - * instead of in block terms. Note that only the active view of the provided augmented matrix - * is used, and that the matrix data is copied into a newly-allocated matrix in the constructed - * factor. */ - template - GaussianConditionalUnordered( - const KEYS& keys, size_t nrFrontals, const VerticalBlockMatrix& augmentedMatrix, - const SharedDiagonal& sigmas = SharedDiagonal()); - - /** Combine several GaussianConditional into a single dense GC. The conditionals enumerated by - * \c first and \c last must be in increasing order, meaning that the parents of any - * conditional may not include a conditional coming before it. - * @param firstConditional Iterator to the first conditional to combine, must dereference to a - * shared_ptr. - * @param lastConditional Iterator to after the last conditional to combine, must dereference - * to a shared_ptr. */ - template - static shared_ptr Combine(ITERATOR firstConditional, ITERATOR lastConditional); - - /** print */ - void print(const std::string& = "GaussianConditional", - const KeyFormatter& formatter = DefaultKeyFormatter) const; - - /** equals function */ - bool equals(const GaussianConditionalUnordered&cg, double tol = 1e-9) const; - - /** Return a view of the upper-triangular R block of the conditional */ - constABlock get_R() const { return Ab_.range(0, nrFrontals()); } - - /** Get a view of the parent blocks. */ - constABlock get_S() const { return Ab_.range(nrFrontals(), size()); } - - /** Get a view of the S matrix for the variable pointed to by the given key iterator */ - constABlock get_S(const_iterator variable) const { return BaseFactor::getA(variable); } - - /** Get a view of the r.h.s. vector d */ - const constBVector get_d() const { return BaseFactor::getb(); } - - /** - * Solves a conditional Gaussian and writes the solution into the entries of - * \c x for each frontal variable of the conditional. The parents are - * assumed to have already been solved in and their values are read from \c x. - * This function works for multiple frontal variables. - * - * Given the Gaussian conditional with log likelihood \f$ |R x_f - (d - S x_s)|^2, - * where \f$ f \f$ are the frontal variables and \f$ s \f$ are the separator - * variables of this conditional, this solve function computes - * \f$ x_f = R^{-1} (d - S x_s) \f$ using back-substitution. - * - * @param parents VectorValues containing solved parents \f$ x_s \f$. - */ - VectorValuesUnordered solve(const VectorValuesUnordered& parents) const; - - VectorValuesUnordered solveOtherRHS(const VectorValuesUnordered& parents, const VectorValuesUnordered& rhs) const; - - /** Performs transpose backsubstition in place on values */ - void solveTransposeInPlace(VectorValuesUnordered& gy) const; - - /** Scale the values in \c gy according to the sigmas for the frontal variables in this - * conditional. */ - __declspec(deprecated) void scaleFrontalsBySigma(VectorValuesUnordered& gy) const; - - private: - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(BaseFactor); - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(BaseConditional); - } - }; // GaussianConditionalUnordered - -} // gtsam - -#include - diff --git a/gtsam/linear/GaussianDensity.cpp b/gtsam/linear/GaussianDensity.cpp index a8f2fc895..b546c7448 100644 --- a/gtsam/linear/GaussianDensity.cpp +++ b/gtsam/linear/GaussianDensity.cpp @@ -37,7 +37,7 @@ namespace gtsam { /* ************************************************************************* */ Vector GaussianDensity::mean() const { // Solve for mean - VectorValues x; + VectorValuesOrdered x; Index k = firstFrontalKey(); // a VectorValues that only has a value for k: cannot be printed if k<>0 x.insert(k, Vector(sigmas_.size())); diff --git a/gtsam/linear/GaussianDensity.h b/gtsam/linear/GaussianDensity.h index e7bc51f74..d88f02f85 100644 --- a/gtsam/linear/GaussianDensity.h +++ b/gtsam/linear/GaussianDensity.h @@ -19,7 +19,7 @@ // \callgraph #pragma once -#include +#include namespace gtsam { @@ -30,7 +30,7 @@ namespace gtsam { * The negative log-probability is given by \f$ |Rx - d|^2 \f$ * with \f$ \Lambda = \Sigma^{-1} = R^T R \f$ and \f$ \mu = R^{-1} d \f$ */ - class GTSAM_EXPORT GaussianDensity: public GaussianConditional { + class GTSAM_EXPORT GaussianDensity: public GaussianConditionalOrdered { public: @@ -38,19 +38,19 @@ namespace gtsam { /// default constructor needed for serialization GaussianDensity() : - GaussianConditional() { + GaussianConditionalOrdered() { } /// Copy constructor from GaussianConditional - GaussianDensity(const GaussianConditional& conditional) : - GaussianConditional(conditional) { + GaussianDensity(const GaussianConditionalOrdered& conditional) : + GaussianConditionalOrdered(conditional) { assert(conditional.nrParents() == 0); } /// constructor using d, R GaussianDensity(Index key, const Vector& d, const Matrix& R, const Vector& sigmas) : - GaussianConditional(key, d, R, sigmas) { + GaussianConditionalOrdered(key, d, R, sigmas) { } /// print diff --git a/gtsam/linear/GaussianEliminationTreeUnordered.cpp b/gtsam/linear/GaussianEliminationTree.cpp similarity index 59% rename from gtsam/linear/GaussianEliminationTreeUnordered.cpp rename to gtsam/linear/GaussianEliminationTree.cpp index 49c2cbe9d..3979b7e6e 100644 --- a/gtsam/linear/GaussianEliminationTreeUnordered.cpp +++ b/gtsam/linear/GaussianEliminationTree.cpp @@ -10,42 +10,42 @@ * -------------------------------------------------------------------------- */ /** - * @file GaussianEliminationTreeUnordered.cpp + * @file GaussianEliminationTree.cpp * @date Mar 29, 2013 * @author Frank Dellaert * @author Richard Roberts */ -#include -#include +#include +#include namespace gtsam { /* ************************************************************************* */ - GaussianEliminationTreeUnordered::GaussianEliminationTreeUnordered( - const GaussianFactorGraphUnordered& factorGraph, const VariableIndexUnordered& structure, - const OrderingUnordered& order) : + GaussianEliminationTree::GaussianEliminationTree( + const GaussianFactorGraph& factorGraph, const VariableIndex& structure, + const Ordering& order) : Base(factorGraph, structure, order) {} /* ************************************************************************* */ - GaussianEliminationTreeUnordered::GaussianEliminationTreeUnordered( - const GaussianFactorGraphUnordered& factorGraph, const OrderingUnordered& order) : + GaussianEliminationTree::GaussianEliminationTree( + const GaussianFactorGraph& factorGraph, const Ordering& order) : Base(factorGraph, order) {} /* ************************************************************************* */ - GaussianEliminationTreeUnordered::GaussianEliminationTreeUnordered( + GaussianEliminationTree::GaussianEliminationTree( const This& other) : Base(other) {} /* ************************************************************************* */ - GaussianEliminationTreeUnordered& GaussianEliminationTreeUnordered::operator=(const This& other) + GaussianEliminationTree& GaussianEliminationTree::operator=(const This& other) { (void) Base::operator=(other); return *this; } /* ************************************************************************* */ - bool GaussianEliminationTreeUnordered::equals(const This& other, double tol) const + bool GaussianEliminationTree::equals(const This& other, double tol) const { return Base::equals(other, tol); } diff --git a/gtsam/linear/GaussianEliminationTreeUnordered.h b/gtsam/linear/GaussianEliminationTree.h similarity index 65% rename from gtsam/linear/GaussianEliminationTreeUnordered.h rename to gtsam/linear/GaussianEliminationTree.h index e33488422..a3d989416 100644 --- a/gtsam/linear/GaussianEliminationTreeUnordered.h +++ b/gtsam/linear/GaussianEliminationTree.h @@ -10,7 +10,7 @@ * -------------------------------------------------------------------------- */ /** - * @file GaussianEliminationTreeUnordered.h + * @file GaussianEliminationTree.h * @date Mar 29, 2013 * @author Frank Dellaert * @author Richard Roberts @@ -18,18 +18,18 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace gtsam { - class GTSAM_EXPORT GaussianEliminationTreeUnordered : - public EliminationTreeUnordered + class GTSAM_EXPORT GaussianEliminationTree : + public EliminationTree { public: - typedef EliminationTreeUnordered Base; ///< Base class - typedef GaussianEliminationTreeUnordered This; ///< This class + typedef EliminationTree Base; ///< Base class + typedef GaussianEliminationTree This; ///< This class typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class /** @@ -40,20 +40,20 @@ namespace gtsam { * named constructor instead. * @return The elimination tree */ - GaussianEliminationTreeUnordered(const GaussianFactorGraphUnordered& factorGraph, - const VariableIndexUnordered& structure, const OrderingUnordered& order); + GaussianEliminationTree(const GaussianFactorGraph& factorGraph, + const VariableIndex& structure, const Ordering& order); /** Build the elimination tree of a factor graph. Note that this has to compute the column * structure as a VariableIndex, so if you already have this precomputed, use the other * constructor instead. * @param factorGraph The factor graph for which to build the elimination tree */ - GaussianEliminationTreeUnordered(const GaussianFactorGraphUnordered& factorGraph, - const OrderingUnordered& order); + GaussianEliminationTree(const GaussianFactorGraph& factorGraph, + const Ordering& order); /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are * copied, factors are not cloned. */ - GaussianEliminationTreeUnordered(const This& other); + GaussianEliminationTree(const This& other); /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors are * copied, factors are not cloned. */ @@ -64,7 +64,7 @@ namespace gtsam { private: - friend class ::EliminationTreeUnorderedTester; + friend class ::EliminationTreeTester; }; diff --git a/gtsam/linear/GaussianFactor.h b/gtsam/linear/GaussianFactor.h index 3363880ef..9c87682e3 100644 --- a/gtsam/linear/GaussianFactor.h +++ b/gtsam/linear/GaussianFactor.h @@ -21,78 +21,63 @@ #pragma once #include -#include - -#include - -#include -#include +#include namespace gtsam { // Forward declarations class VectorValues; - class Permutation; - class GaussianConditional; - template class BayesNet; /** - * An abstract virtual base class for JacobianFactor and HessianFactor. - * A GaussianFactor has a quadratic error function. - * GaussianFactor is non-mutable (all methods const!). - * The factor value is exp(-0.5*||Ax-b||^2) - */ - class GTSAM_EXPORT GaussianFactor: public IndexFactor { - - protected: - - /** Copy constructor */ - GaussianFactor(const This& f) : IndexFactor(f) {} - - /** Construct from derived type */ - GaussianFactor(const GaussianConditional& c); - - /** Constructor from a collection of keys */ - template GaussianFactor(KeyIterator beginKey, KeyIterator endKey) : - Base(beginKey, endKey) {} - - /** Default constructor for I/O */ - GaussianFactor() {} - - /** Construct unary factor */ - GaussianFactor(Index j) : IndexFactor(j) {} - - /** Construct binary factor */ - GaussianFactor(Index j1, Index j2) : IndexFactor(j1, j2) {} - - /** Construct ternary factor */ - GaussianFactor(Index j1, Index j2, Index j3) : IndexFactor(j1, j2, j3) {} - - /** Construct 4-way factor */ - GaussianFactor(Index j1, Index j2, Index j3, Index j4) : IndexFactor(j1, j2, j3, j4) {} - - /** Construct n-way factor */ - GaussianFactor(const std::set& js) : IndexFactor(js) {} - - /** Construct n-way factor */ - GaussianFactor(const std::vector& js) : IndexFactor(js) {} - + * An abstract virtual base class for JacobianFactor and HessianFactor. A GaussianFactor has a + * quadratic error function. GaussianFactor is non-mutable (all methods const!). The factor value + * is exp(-0.5*||Ax-b||^2) */ + class GTSAM_EXPORT GaussianFactor : public Factor + { public: + typedef GaussianFactor This; ///< This class + typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class + typedef Factor Base; ///< Our base class - typedef GaussianConditional ConditionalType; - typedef boost::shared_ptr shared_ptr; + /** Default constructor creates empty factor */ + GaussianFactor() {} + + /** Construct from container of keys. This constructor is used internally from derived factor + * constructors, either from a container of keys or from a boost::assign::list_of. */ + template + GaussianFactor(const CONTAINER& keys) : Base(keys) {} // Implementing Testable interface virtual void print(const std::string& s = "", const IndexFormatter& formatter = DefaultIndexFormatter) const = 0; + /** Equals for testable */ virtual bool equals(const GaussianFactor& lf, double tol = 1e-9) const = 0; + /** Print for testable */ virtual double error(const VectorValues& c) const = 0; /** 0.5*(A*x-b)'*D*(A*x-b) */ /** Return the dimension of the variable pointed to by the given key iterator */ virtual size_t getDim(const_iterator variable) const = 0; + /** + * Return a dense \f$ [ \;A\;b\; ] \in \mathbb{R}^{m \times n+1} \f$ + * Jacobian matrix, augmented with b with the noise models baked + * into A and b. The negative log-likelihood is + * \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also + * GaussianFactorGraph::jacobian and GaussianFactorGraph::sparseJacobian. + */ + virtual Matrix augmentedJacobian(bool weight = true) const = 0; + + /** + * Return the dense Jacobian \f$ A \f$ and right-hand-side \f$ b \f$, + * with the noise models baked into A and b. The negative log-likelihood + * is \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also + * GaussianFactorGraph::augmentedJacobian and + * GaussianFactorGraph::sparseJacobian. + */ + virtual std::pair jacobian(bool weight = true) const = 0; + /** Return the augmented information matrix represented by this GaussianFactor. * The augmented information matrix contains the information matrix with an * additional column holding the information vector, and an additional row @@ -111,46 +96,24 @@ namespace gtsam { /** Clone a factor (make a deep copy) */ virtual GaussianFactor::shared_ptr clone() const = 0; - /** - * Permutes the GaussianFactor, but for efficiency requires the permutation - * to already be inverted. This acts just as a change-of-name for each - * variable. The order of the variables within the factor is not changed. - */ - virtual void permuteWithInverse(const Permutation& inversePermutation) { - IndexFactor::permuteWithInverse(inversePermutation); - } - - /** - * Apply a reduction, which is a remapping of variable indices. - */ - virtual void reduceWithInverse(const internal::Reduction& inverseReduction) { - IndexFactor::reduceWithInverse(inverseReduction); - } + /** Test whether the factor is empty */ + virtual bool empty() const = 0; /** * Construct the corresponding anti-factor to negate information * stored stored in this factor. * @return a HessianFactor with negated Hessian matrices */ - virtual GaussianFactor::shared_ptr negate() const = 0; + //virtual GaussianFactor::shared_ptr negate() const = 0; private: /** Serialization function */ friend class boost::serialization::access; template void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(IndexFactor); + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); } }; // GaussianFactor - - /** make keys from list, vector, or map of matrices */ - template - static std::vector GetKeys(size_t n, ITERATOR begin, ITERATOR end) { - std::vector keys; - keys.reserve(n); - for (ITERATOR it=begin;it!=end;++it) keys.push_back(it->first); - return keys; - } - + } // namespace gtsam diff --git a/gtsam/linear/GaussianFactorGraph.cpp b/gtsam/linear/GaussianFactorGraph.cpp index 3f648042d..c67008ba1 100644 --- a/gtsam/linear/GaussianFactorGraph.cpp +++ b/gtsam/linear/GaussianFactorGraph.cpp @@ -18,15 +18,13 @@ * @author Frank Dellaert */ -#include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -37,57 +35,20 @@ using namespace gtsam; namespace gtsam { /* ************************************************************************* */ - GaussianFactorGraph::GaussianFactorGraph(const GaussianBayesNet& CBN) : Base(CBN) {} + bool GaussianFactorGraph::equals(const This& fg, double tol) const + { + return Base::equals(fg, tol); + } /* ************************************************************************* */ GaussianFactorGraph::Keys GaussianFactorGraph::keys() const { - FastSet keys; + FastSet keys; BOOST_FOREACH(const sharedFactor& factor, *this) - if (factor) keys.insert(factor->begin(), factor->end()); + if (factor) + keys.insert(factor->begin(), factor->end()); return keys; } - /* ************************************************************************* */ - void GaussianFactorGraph::permuteWithInverse( - const Permutation& inversePermutation) { - BOOST_FOREACH(const sharedFactor& factor, factors_) { - if(factor) - factor->permuteWithInverse(inversePermutation); - } - } - - /* ************************************************************************* */ - void GaussianFactorGraph::reduceWithInverse( - const internal::Reduction& inverseReduction) { - BOOST_FOREACH(const sharedFactor& factor, factors_) { - if(factor) - factor->reduceWithInverse(inverseReduction); - } - } - - /* ************************************************************************* */ - void GaussianFactorGraph::combine(const GaussianFactorGraph &lfg) { - for (const_iterator factor = lfg.factors_.begin(); factor - != lfg.factors_.end(); factor++) { - push_back(*factor); - } - } - - /* ************************************************************************* */ - GaussianFactorGraph GaussianFactorGraph::combine2( - const GaussianFactorGraph& lfg1, const GaussianFactorGraph& lfg2) { - - // create new linear factor graph equal to the first one - GaussianFactorGraph fg = lfg1; - - // add the second factors_ in the graph - for (const_iterator factor = lfg2.factors_.begin(); factor - != lfg2.factors_.end(); factor++) { - fg.push_back(*factor); - } - return fg; - } - /* ************************************************************************* */ std::vector > GaussianFactorGraph::sparseJacobian() const { // First find dimensions of each variable @@ -114,10 +75,11 @@ namespace gtsam { JacobianFactor::shared_ptr jacobianFactor( boost::dynamic_pointer_cast(factor)); if (!jacobianFactor) { - HessianFactor::shared_ptr hessian(boost::dynamic_pointer_cast(factor)); - if (hessian) - jacobianFactor.reset(new JacobianFactor(*hessian)); - else + //TODO : re-enable + //HessianFactor::shared_ptr hessian(boost::dynamic_pointer_cast(factor)); + //if (hessian) + // jacobianFactor.reset(new JacobianFactor(*hessian)); + //else throw invalid_argument( "GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor."); } @@ -169,19 +131,9 @@ namespace gtsam { /* ************************************************************************* */ Matrix GaussianFactorGraph::augmentedJacobian() const { - // Convert to Jacobians - FactorGraph jfg; - jfg.reserve(this->size()); - BOOST_FOREACH(const sharedFactor& factor, *this) { - if(boost::shared_ptr jf = - boost::dynamic_pointer_cast(factor)) - jfg.push_back(jf); - else - jfg.push_back(boost::make_shared(*factor)); - } // combine all factors - JacobianFactor combined(*CombineJacobians(jfg, VariableSlots(*this))); - return combined.matrix_augmented(); + JacobianFactor combined(*this); + return combined.augmentedJacobian(); } /* ************************************************************************* */ @@ -192,249 +144,100 @@ namespace gtsam { augmented.col(augmented.cols()-1)); } - // Helper functions for Combine - static boost::tuple, size_t, size_t> countDims(const FactorGraph& factors, const VariableSlots& variableSlots) { -#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS - vector varDims(variableSlots.size(), numeric_limits::max()); -#else - vector varDims(variableSlots.size()); -#endif - size_t m = 0; - size_t n = 0; - { - Index jointVarpos = 0; - BOOST_FOREACH(const VariableSlots::value_type& slots, variableSlots) { + /* ************************************************************************* */ + //Matrix GaussianFactorGraph::augmentedHessian() const { + // // combine all factors and get upper-triangular part of Hessian + // HessianFactor combined(*this); + // Matrix result = combined.info(); + // // Fill in lower-triangular part of Hessian + // result.triangularView() = result.transpose(); + // return result; + //} - assert(slots.second.size() == factors.size()); + /* ************************************************************************* */ + //std::pair GaussianFactorGraph::hessian() const { + // Matrix augmented = augmentedHessian(); + // return make_pair( + // augmented.topLeftCorner(augmented.rows()-1, augmented.rows()-1), + // augmented.col(augmented.rows()-1).head(augmented.rows()-1)); + //} - Index sourceFactorI = 0; - BOOST_FOREACH(const Index sourceVarpos, slots.second) { - if(sourceVarpos < numeric_limits::max()) { - const JacobianFactor& sourceFactor = *factors[sourceFactorI]; - size_t vardim = sourceFactor.getDim(sourceFactor.begin() + sourceVarpos); -#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS - if(varDims[jointVarpos] == numeric_limits::max()) { - varDims[jointVarpos] = vardim; - n += vardim; - } else - assert(varDims[jointVarpos] == vardim); -#else - varDims[jointVarpos] = vardim; - n += vardim; - break; -#endif - } - ++ sourceFactorI; - } - ++ jointVarpos; - } - BOOST_FOREACH(const JacobianFactor::shared_ptr& factor, factors) { - m += factor->rows(); + /* ************************************************************************* */ + //GaussianFactorGraph::EliminationResult EliminateCholesky(const FactorGraph< + // GaussianFactor>& factors, size_t nrFrontals) { + + // const bool debug = ISDEBUG("EliminateCholesky"); + + // // Form Ab' * Ab + // gttic(combine); + // HessianFactor::shared_ptr combinedFactor(new HessianFactor(factors)); + // gttoc(combine); + + // // 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. + // gttic(partial_Cholesky); + // combinedFactor->partialCholesky(nrFrontals); + + // gttoc(partial_Cholesky); + + // // Extract conditional and fill in details of the remaining factor + // gttic(split); + // GaussianConditional::shared_ptr conditional = + // combinedFactor->splitEliminatedFactor(nrFrontals); + // if (debug) { + // conditional->print("Extracted conditional: "); + // combinedFactor->print("Eliminated factor (L piece): "); + // } + // gttoc(split); + + // combinedFactor->assertInvariants(); + // return make_pair(conditional, combinedFactor); + //} + + /* ************************************************************************* */ + VectorValues GaussianFactorGraph::optimize(const Eliminate& function) const + { + gttic(GaussianFactorGraph_optimize); + return BaseEliminateable::eliminateMultifrontal(boost::none, function)->optimize(); + } + + /* ************************************************************************* */ + VectorValues GaussianFactorGraph::gradient(const VectorValues& x0) const + { + VectorValues g = VectorValues::Zero(x0); + Errors e = gaussianErrors(x0); + transposeMultiplyAdd(1.0, e, g); + return g; + } + + /* ************************************************************************* */ + namespace { + JacobianFactor::shared_ptr convertToJacobianFactorPtr(const GaussianFactor::shared_ptr &gf) { + JacobianFactor::shared_ptr result = boost::dynamic_pointer_cast(gf); + if( !result ) { + result = boost::make_shared(*gf); // Convert any non-Jacobian factors to Jacobians (e.g. Hessian -> Jacobian with Cholesky) } + return result; } - return boost::make_tuple(varDims, m, n); } /* ************************************************************************* */ - JacobianFactor::shared_ptr CombineJacobians( - const FactorGraph& factors, - const VariableSlots& variableSlots) { - - const bool debug = ISDEBUG("CombineJacobians"); - if (debug) factors.print("Combining factors: "); - if (debug) variableSlots.print(); - - if (debug) cout << "Determine dimensions" << endl; - gttic(countDims); - vector varDims; - size_t m, n; - boost::tie(varDims, m, n) = countDims(factors, variableSlots); - if (debug) { - cout << "Dims: " << m << " x " << n << "\n"; - BOOST_FOREACH(const size_t dim, varDims) cout << dim << " "; - cout << endl; + VectorValues GaussianFactorGraph::gradientAtZero() const + { + // Zero-out the gradient + VectorValues g; + Errors e; + BOOST_FOREACH(const sharedFactor& Ai_G, *this) { + JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + e.push_back(-Ai->getb()); } - gttoc(countDims); - - if (debug) cout << "Allocate new factor" << endl; - gttic(allocate); - JacobianFactor::shared_ptr combined(new JacobianFactor()); - combined->allocate(variableSlots, varDims, m); - Vector sigmas(m); - gttoc(allocate); - - if (debug) cout << "Copy blocks" << endl; - gttic(copy_blocks); - // Loop over slots in combined factor - Index combinedSlot = 0; - BOOST_FOREACH(const VariableSlots::value_type& varslot, variableSlots) { - JacobianFactor::ABlock destSlot(combined->getA(combined->begin()+combinedSlot)); - // Loop over source factors - size_t nextRow = 0; - for(size_t factorI = 0; factorI < factors.size(); ++factorI) { - // Slot in source factor - const Index sourceSlot = varslot.second[factorI]; - const size_t sourceRows = factors[factorI]->rows(); - JacobianFactor::ABlock::RowsBlockXpr destBlock(destSlot.middleRows(nextRow, sourceRows)); - // Copy if exists in source factor, otherwise set zero - if(sourceSlot != numeric_limits::max()) - destBlock = factors[factorI]->getA(factors[factorI]->begin()+sourceSlot); - else - destBlock.setZero(); - nextRow += sourceRows; - } - ++combinedSlot; - } - gttoc(copy_blocks); - - if (debug) cout << "Copy rhs (b) and sigma" << endl; - gttic(copy_vectors); - bool anyConstrained = false; - // Loop over source factors - size_t nextRow = 0; - for(size_t factorI = 0; factorI < factors.size(); ++factorI) { - const size_t sourceRows = factors[factorI]->rows(); - combined->getb().segment(nextRow, sourceRows) = factors[factorI]->getb(); - sigmas.segment(nextRow, sourceRows) = factors[factorI]->get_model()->sigmas(); - if (factors[factorI]->isConstrained()) anyConstrained = true; - nextRow += sourceRows; - } - gttoc(copy_vectors); - - if (debug) cout << "Create noise model from sigmas" << endl; - gttic(noise_model); - combined->setModel(anyConstrained, sigmas); - gttoc(noise_model); - - if (debug) cout << "Assert Invariants" << endl; - combined->assertInvariants(); - - return combined; + transposeMultiplyAdd(1.0, e, g); + return g; } /* ************************************************************************* */ - GaussianFactorGraph::EliminationResult EliminateJacobians(const FactorGraph< - JacobianFactor>& factors, size_t nrFrontals) { - gttic(Combine); - JacobianFactor::shared_ptr jointFactor = - CombineJacobians(factors, VariableSlots(factors)); - gttoc(Combine); - gttic(eliminate); - GaussianConditional::shared_ptr gbn = jointFactor->eliminate(nrFrontals); - gttoc(eliminate); - return make_pair(gbn, jointFactor); - } - - /* ************************************************************************* */ - Matrix GaussianFactorGraph::augmentedHessian() const { - // combine all factors and get upper-triangular part of Hessian - HessianFactor combined(*this); - Matrix result = combined.info(); - // Fill in lower-triangular part of Hessian - result.triangularView() = result.transpose(); - return result; - } - - /* ************************************************************************* */ - std::pair GaussianFactorGraph::hessian() const { - Matrix augmented = augmentedHessian(); - return make_pair( - augmented.topLeftCorner(augmented.rows()-1, augmented.rows()-1), - augmented.col(augmented.rows()-1).head(augmented.rows()-1)); - } - - /* ************************************************************************* */ - GaussianFactorGraph::EliminationResult EliminateCholesky(const FactorGraph< - GaussianFactor>& factors, size_t nrFrontals) { - - const bool debug = ISDEBUG("EliminateCholesky"); - - // Form Ab' * Ab - gttic(combine); - HessianFactor::shared_ptr combinedFactor(new HessianFactor(factors)); - gttoc(combine); - - // 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. - gttic(partial_Cholesky); - combinedFactor->partialCholesky(nrFrontals); - - gttoc(partial_Cholesky); - - // Extract conditional and fill in details of the remaining factor - gttic(split); - GaussianConditional::shared_ptr conditional = - combinedFactor->splitEliminatedFactor(nrFrontals); - if (debug) { - conditional->print("Extracted conditional: "); - combinedFactor->print("Eliminated factor (L piece): "); - } - gttoc(split); - - combinedFactor->assertInvariants(); - return make_pair(conditional, combinedFactor); - } - - /* ************************************************************************* */ - static FactorGraph convertToJacobians(const FactorGraph< - GaussianFactor>& factors) { - - typedef JacobianFactor J; - typedef HessianFactor H; - - const bool debug = ISDEBUG("convertToJacobians"); - - FactorGraph jacobians; - jacobians.reserve(factors.size()); - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) - if (factor) { - J::shared_ptr jacobian(boost::dynamic_pointer_cast(factor)); - if (jacobian) { - jacobians.push_back(jacobian); - if (debug) jacobian->print("Existing JacobianFactor: "); - } else { - H::shared_ptr hessian(boost::dynamic_pointer_cast(factor)); - if (!hessian) throw std::invalid_argument( - "convertToJacobians: factor is neither a JacobianFactor nor a HessianFactor."); - J::shared_ptr converted(new J(*hessian)); - if (debug) { - cout << "Converted HessianFactor to JacobianFactor:\n"; - hessian->print("HessianFactor: "); - converted->print("JacobianFactor: "); - if (!assert_equal(*hessian, HessianFactor(*converted), 1e-3)) throw runtime_error( - "convertToJacobians: Conversion between Jacobian and Hessian incorrect"); - } - jacobians.push_back(converted); - } - } - return jacobians; - } - - /* ************************************************************************* */ - GaussianFactorGraph::EliminationResult EliminateQR(const FactorGraph< - GaussianFactor>& factors, size_t nrFrontals) { - - const bool debug = ISDEBUG("EliminateQR"); - - // Convert all factors to the appropriate type and call the type-specific EliminateGaussian. - if (debug) cout << "Using QR" << endl; - - gttic(convert_to_Jacobian); - FactorGraph jacobians = convertToJacobians(factors); - gttoc(convert_to_Jacobian); - - gttic(Jacobian_EliminateGaussian); - GaussianConditional::shared_ptr conditional; - GaussianFactor::shared_ptr factor; - boost::tie(conditional, factor) = EliminateJacobians(jacobians, nrFrontals); - gttoc(Jacobian_EliminateGaussian); - - return make_pair(conditional, factor); - } // \EliminateQR - - /* ************************************************************************* */ - bool hasConstraints(const FactorGraph& factors) { + bool hasConstraints(const GaussianFactorGraph& factors) { typedef JacobianFactor J; BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) { J::shared_ptr jacobian(boost::dynamic_pointer_cast(factor)); @@ -446,143 +249,117 @@ namespace gtsam { } /* ************************************************************************* */ - GaussianFactorGraph::EliminationResult EliminatePreferCholesky( - const FactorGraph& factors, size_t nrFrontals) { + //GaussianFactorGraph::EliminationResult EliminatePreferCholesky( + // const FactorGraph& factors, size_t nrFrontals) { - // If any JacobianFactors have constrained noise models, we have to convert - // all factors to JacobianFactors. Otherwise, we can convert all factors - // to HessianFactors. This is because QR can handle constrained noise - // models but Cholesky cannot. - if (hasConstraints(factors)) - return EliminateQR(factors, nrFrontals); - else { - GaussianFactorGraph::EliminationResult ret; - gttic(EliminateCholesky); - ret = EliminateCholesky(factors, nrFrontals); - gttoc(EliminateCholesky); - return ret; - } + // // If any JacobianFactors have constrained noise models, we have to convert + // // all factors to JacobianFactors. Otherwise, we can convert all factors + // // to HessianFactors. This is because QR can handle constrained noise + // // models but Cholesky cannot. + // if (hasConstraints(factors)) + // return EliminateQR(factors, nrFrontals); + // else { + // GaussianFactorGraph::EliminationResult ret; + // gttic(EliminateCholesky); + // ret = EliminateCholesky(factors, nrFrontals); + // gttoc(EliminateCholesky); + // return ret; + // } - } // \EliminatePreferCholesky + //} // \EliminatePreferCholesky - /* ************************************************************************* */ - static JacobianFactor::shared_ptr convertToJacobianFactorPtr(const GaussianFactor::shared_ptr &gf) { - JacobianFactor::shared_ptr result = boost::dynamic_pointer_cast(gf); - if( !result ) { - result = boost::make_shared(*gf); // Convert any non-Jacobian factors to Jacobians (e.g. Hessian -> Jacobian with Cholesky) - } - return result; - } + ///* ************************************************************************* */ + //Errors operator*(const GaussianFactorGraph& fg, const VectorValues& x) { + // Errors e; + // BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { + // JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + // e.push_back((*Ai)*x); + // } + // return e; + //} - /* ************************************************************************* */ - Errors operator*(const GaussianFactorGraph& fg, const VectorValues& x) { - Errors e; - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { - JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - e.push_back((*Ai)*x); - } - return e; - } + ///* ************************************************************************* */ + //void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, Errors& e) { + // multiplyInPlace(fg,x,e.begin()); + //} - /* ************************************************************************* */ - void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, Errors& e) { - multiplyInPlace(fg,x,e.begin()); - } - - /* ************************************************************************* */ - void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, const Errors::iterator& e) { - Errors::iterator ei = e; - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { - JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - *ei = (*Ai)*x; - ei++; - } - } + ///* ************************************************************************* */ + //void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, const Errors::iterator& e) { + // Errors::iterator ei = e; + // BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { + // JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + // *ei = (*Ai)*x; + // ei++; + // } + //} /* ************************************************************************* */ // x += alpha*A'*e - void transposeMultiplyAdd(const GaussianFactorGraph& fg, double alpha, const Errors& e, VectorValues& x) { + void GaussianFactorGraph::transposeMultiplyAdd(double alpha, const Errors& e, VectorValues& x) const + { // For each factor add the gradient contribution Errors::const_iterator ei = e.begin(); - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { + BOOST_FOREACH(const sharedFactor& Ai_G, *this) { JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - Ai->transposeMultiplyAdd(alpha,*(ei++),x); + Ai->transposeMultiplyAdd(alpha, *(ei++), x); } } - /* ************************************************************************* */ - VectorValues gradient(const GaussianFactorGraph& fg, const VectorValues& x0) { - // It is crucial for performance to make a zero-valued clone of x - VectorValues g = VectorValues::Zero(x0); - Errors e; - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { - JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - e.push_back(Ai->error_vector(x0)); - } - transposeMultiplyAdd(fg, 1.0, e, g); - return g; - } + ///* ************************************************************************* */ + //void residual(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r) { + // Key i = 0 ; + // BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { + // JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + // r[i] = Ai->getb(); + // i++; + // } + // VectorValues Ax = VectorValues::SameStructure(r); + // multiply(fg,x,Ax); + // axpy(-1.0,Ax,r); + //} + + ///* ************************************************************************* */ + //void multiply(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r) { + // r.setZero(); + // Key i = 0; + // BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { + // JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + // Vector &y = r[i]; + // for(JacobianFactor::const_iterator j = Ai->begin(); j != Ai->end(); ++j) { + // y += Ai->getA(j) * x[*j]; + // } + // ++i; + // } + //} /* ************************************************************************* */ - void gradientAtZero(const GaussianFactorGraph& fg, VectorValues& g) { - // Zero-out the gradient - g.setZero(); - Errors e; - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { - JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - e.push_back(-Ai->getb()); - } - transposeMultiplyAdd(fg, 1.0, e, g); - } - - /* ************************************************************************* */ - void residual(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r) { - Index i = 0 ; - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { - JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - r[i] = Ai->getb(); - i++; - } - VectorValues Ax = VectorValues::SameStructure(r); - multiply(fg,x,Ax); - axpy(-1.0,Ax,r); - } - - /* ************************************************************************* */ - void multiply(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r) { - r.setZero(); - Index i = 0; - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { - JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - Vector &y = r[i]; - for(JacobianFactor::const_iterator j = Ai->begin(); j != Ai->end(); ++j) { - y += Ai->getA(j) * x[*j]; - } - ++i; - } - } - - /* ************************************************************************* */ - void transposeMultiply(const GaussianFactorGraph& fg, const VectorValues &r, VectorValues &x) { - x.setZero(); - Index i = 0; - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { + VectorValues GaussianFactorGraph::transposeMultiply(const Errors& e) const + { + VectorValues x; + Errors::const_iterator ei = e.begin(); + BOOST_FOREACH(const sharedFactor& Ai_G, *this) { JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); for(JacobianFactor::const_iterator j = Ai->begin(); j != Ai->end(); ++j) { - x[*j] += Ai->getA(j).transpose() * r[i]; + // Create the value as a zero vector if it does not exist. + pair xi = x.tryInsert(*j, Vector()); + if(xi.second) + xi.first->second = Vector::Zero(Ai->getDim(j)); + xi.first->second += Ai->getA(j).transpose() * *ei; } - ++i; + ++ ei; } + return x; } /* ************************************************************************* */ - boost::shared_ptr gaussianErrors_(const GaussianFactorGraph& fg, const VectorValues& x) { - boost::shared_ptr e(new Errors); - BOOST_FOREACH(const GaussianFactor::shared_ptr& Ai_G, fg) { + Errors GaussianFactorGraph::gaussianErrors(const VectorValues& x) const + { + Errors e; + BOOST_FOREACH(const sharedFactor& Ai_G, *this) { JacobianFactor::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - e->push_back(Ai->error_vector(x)); + e.push_back(Ai->error_vector(x)); } return e; } diff --git a/gtsam/linear/GaussianFactorGraph.h b/gtsam/linear/GaussianFactorGraph.h index 03fd04215..78004299d 100644 --- a/gtsam/linear/GaussianFactorGraph.h +++ b/gtsam/linear/GaussianFactorGraph.h @@ -21,142 +21,118 @@ #pragma once -#include - -#include -#include -#include +#include +#include +#include #include -#include +#include // Included here instead of fw-declared so we can use Errors::iterator namespace gtsam { - // Forward declaration to use as default argument, documented declaration below. - GTSAM_EXPORT FactorGraph::EliminationResult - EliminateQR(const FactorGraph& factors, size_t nrFrontals); + // Forward declarations + class GaussianFactorGraph; + class GaussianFactor; + class GaussianConditional; + class GaussianBayesNet; + class GaussianEliminationTree; + class GaussianBayesTree; + class GaussianJunctionTree; + /* ************************************************************************* */ + template<> struct EliminationTraits + { + typedef GaussianFactor FactorType; ///< Type of factors in factor graph + typedef GaussianFactorGraph FactorGraphType; ///< Type of the factor graph (e.g. GaussianFactorGraph) + typedef GaussianConditional ConditionalType; ///< Type of conditionals from elimination + typedef GaussianBayesNet BayesNetType; ///< Type of Bayes net from sequential elimination + typedef GaussianEliminationTree EliminationTreeType; ///< Type of elimination tree + typedef GaussianBayesTree BayesTreeType; ///< Type of Bayes tree + typedef GaussianJunctionTree JunctionTreeType; ///< Type of Junction tree + /// The default dense elimination function + static std::pair, boost::shared_ptr > + DefaultEliminate(const FactorGraphType& factors, const Ordering& keys) { + return EliminateQR(factors, keys); } + }; + + /* ************************************************************************* */ /** * A Linear Factor Graph is a factor graph where all factors are Gaussian, i.e. * Factor == GaussianFactor * VectorValues = A values structure of vectors * Most of the time, linear factor graphs arise by linearizing a non-linear factor graph. */ - class GaussianFactorGraph : public FactorGraph { + class GTSAM_EXPORT GaussianFactorGraph : + public FactorGraph, + public EliminateableFactorGraph + { public: - typedef boost::shared_ptr shared_ptr; - typedef FactorGraph Base; + typedef GaussianFactorGraph This; ///< Typedef to this class + typedef FactorGraph Base; ///< Typedef to base factor graph type + typedef EliminateableFactorGraph BaseEliminateable; ///< Typedef to base elimination class + typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class - /** - * Default constructor - */ + /** Default constructor */ GaussianFactorGraph() {} - /** - * Constructor that receives a Chordal Bayes Net and returns a GaussianFactorGraph - */ - GTSAM_EXPORT GaussianFactorGraph(const GaussianBayesNet& CBN); + /** Construct from iterator over factors */ + template + GaussianFactorGraph(ITERATOR firstFactor, ITERATOR lastFactor) : Base(firstFactor, lastFactor) {} - /** - * Constructor that receives a BayesTree and returns a GaussianFactorGraph - */ - template - GaussianFactorGraph(const BayesTree& gbt) : Base(gbt) {} + /** Construct from container of factors (shared_ptr or plain objects) */ + template + explicit GaussianFactorGraph(const CONTAINER& factors) : Base(factors) {} - /** Constructor from a factor graph of GaussianFactor or a derived type */ + /** Implicit copy/downcast constructor to override explicit template container constructor */ template - GaussianFactorGraph(const FactorGraph& fg) { - push_back(fg); - } + GaussianFactorGraph(const FactorGraph& graph) : Base(graph) {} + + /// @name Testable + /// @{ + + bool equals(const This& fg, double tol = 1e-9) const; + + /// @} /** Add a factor by value - makes a copy */ - void add(const GaussianFactor& factor) { - factors_.push_back(factor.clone()); - } + void add(const GaussianFactor& factor) { factors_.push_back(factor.clone()); } /** Add a factor by pointer - stores pointer without copying the factor */ - void add(const sharedFactor& factor) { - factors_.push_back(factor); - } + void add(const sharedFactor& factor) { factors_.push_back(factor); } /** Add a null factor */ void add(const Vector& b) { - add(JacobianFactor(b)); - } + add(JacobianFactor(b)); } /** Add a unary factor */ - void add(Index key1, const Matrix& A1, + void add(Key key1, const Matrix& A1, const Vector& b, const SharedDiagonal& model) { - add(JacobianFactor(key1,A1,b,model)); - } + add(JacobianFactor(key1,A1,b,model)); } /** Add a binary factor */ - void add(Index key1, const Matrix& A1, - Index key2, const Matrix& A2, + void add(Key key1, const Matrix& A1, + Key key2, const Matrix& A2, const Vector& b, const SharedDiagonal& model) { - add(JacobianFactor(key1,A1,key2,A2,b,model)); - } + add(JacobianFactor(key1,A1,key2,A2,b,model)); } /** Add a ternary factor */ - void add(Index key1, const Matrix& A1, - Index key2, const Matrix& A2, - Index key3, const Matrix& A3, + void add(Key key1, const Matrix& A1, + Key key2, const Matrix& A2, + Key key3, const Matrix& A3, const Vector& b, const SharedDiagonal& model) { - add(JacobianFactor(key1,A1,key2,A2,key3,A3,b,model)); - } + add(JacobianFactor(key1,A1,key2,A2,key3,A3,b,model)); } /** Add an n-ary factor */ - void add(const std::vector > &terms, - const Vector &b, const SharedDiagonal& model) { - add(JacobianFactor(terms,b,model)); - } + template + void add(const TERMS& terms, const Vector &b, const SharedDiagonal& model) { + add(JacobianFactor(terms,b,model)); } /** * Return the set of variables involved in the factors (computes a set * union). */ - typedef FastSet Keys; - GTSAM_EXPORT Keys keys() const; - - - /** Eliminate the first \c n frontal variables, returning the resulting - * conditional and remaining factor graph - this is very inefficient for - * eliminating all variables, to do that use EliminationTree or - * JunctionTree. Note that this version simply calls - * FactorGraph::eliminateFrontals with EliminateQR as the - * eliminate function argument. - */ - std::pair eliminateFrontals(size_t nFrontals, const Eliminate& function = EliminateQR) const { - return Base::eliminateFrontals(nFrontals, function); } - - /** Factor the factor graph into a conditional and a remaining factor graph. - * Given the factor graph \f$ f(X) \f$, and \c variables to factorize out - * \f$ V \f$, this function factorizes into \f$ f(X) = f(V;Y)f(Y) \f$, where - * \f$ Y := X\V \f$ are the remaining variables. If \f$ f(X) = p(X) \f$ is - * a probability density or likelihood, the factorization produces a - * conditional probability density and a marginal \f$ p(X) = p(V|Y)p(Y) \f$. - * - * For efficiency, this function treats the variables to eliminate - * \c variables as fully-connected, so produces a dense (fully-connected) - * conditional on all of the variables in \c variables, instead of a sparse - * BayesNet. If the variables are not fully-connected, it is more efficient - * to sequentially factorize multiple times. - * Note that this version simply calls - * FactorGraph::eliminate with EliminateQR as the eliminate - * function argument. - */ - std::pair eliminate(const std::vector& variables, const Eliminate& function = EliminateQR) const { - return Base::eliminate(variables, function); } - - /** Eliminate a single variable, by calling GaussianFactorGraph::eliminate. */ - std::pair eliminateOne(Index variable, const Eliminate& function = EliminateQR) const { - return Base::eliminateOne(variable, function); } - - /** Permute the variables in the factors */ - GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation); - - /** Apply a reduction, which is a remapping of variable indices. */ - GTSAM_EXPORT void reduceWithInverse(const internal::Reduction& inverseReduction); + typedef FastSet Keys; + Keys keys() const; /** unnormalized error */ double error(const VectorValues& x) const { @@ -171,34 +147,22 @@ namespace gtsam { return exp(-0.5 * error(c)); } - /** - * Static function that combines two factor graphs. - * @param lfg1 Linear factor graph - * @param lfg2 Linear factor graph - * @return a new combined factor graph - */ - GTSAM_EXPORT static GaussianFactorGraph combine2(const GaussianFactorGraph& lfg1, - const GaussianFactorGraph& lfg2); - - /** - * combine two factor graphs - * @param *lfg Linear factor graph - */ - GTSAM_EXPORT void combine(const GaussianFactorGraph &lfg); + ///@name Linear Algebra + ///@{ /** * Return vector of i, j, and s to generate an m-by-n sparse Jacobian matrix, * where i(k) and j(k) are the base 0 row and column indices, s(k) a double. * The standard deviations are baked into A and b */ - GTSAM_EXPORT std::vector > sparseJacobian() const; + std::vector > sparseJacobian() const; /** * Matrix version of sparseJacobian: generates a 3*m matrix with [i,j,s] entries * such that S(i(k),j(k)) = s(k), which can be given to MATLAB's sparse. * The standard deviations are baked into A and b */ - GTSAM_EXPORT Matrix sparseJacobian_() const; + Matrix sparseJacobian_() const; /** * Return a dense \f$ [ \;A\;b\; ] \in \mathbb{R}^{m \times n+1} \f$ @@ -207,7 +171,7 @@ namespace gtsam { * \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also * GaussianFactorGraph::jacobian and GaussianFactorGraph::sparseJacobian. */ - GTSAM_EXPORT Matrix augmentedJacobian() const; + Matrix augmentedJacobian() const; /** * Return the dense Jacobian \f$ A \f$ and right-hand-side \f$ b \f$, @@ -216,7 +180,7 @@ namespace gtsam { * GaussianFactorGraph::augmentedJacobian and * GaussianFactorGraph::sparseJacobian. */ - GTSAM_EXPORT std::pair jacobian() const; + std::pair jacobian() const; /** * Return a dense \f$ \Lambda \in \mathbb{R}^{n+1 \times n+1} \f$ Hessian @@ -229,7 +193,7 @@ namespace gtsam { and the negative log-likelihood is \f$ \frac{1}{2} x^T \Lambda x + \eta^T x + c \f$. */ - GTSAM_EXPORT Matrix augmentedHessian() const; + //Matrix augmentedHessian() const; /** * Return the dense Hessian \f$ \Lambda \f$ and information vector @@ -237,7 +201,70 @@ namespace gtsam { * is \frac{1}{2} x^T \Lambda x + \eta^T x + c. See also * GaussianFactorGraph::augmentedHessian. */ - GTSAM_EXPORT std::pair hessian() const; + //std::pair hessian() const; + + /** Solve the factor graph by performing multifrontal variable elimination in COLAMD order using + * the dense elimination function specified in \c function (default EliminatePreferCholesky), + * followed by back-substitution in the Bayes tree resulting from elimination. Is equivalent + * to calling graph.eliminateMultifrontal()->optimize(). */ + VectorValues optimize(const Eliminate& function = EliminationTraits::DefaultEliminate) const; + + /** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$, + * centered around \f$ x = x_0 \f$. + * The gradient is \f$ A^T(Ax-b) \f$. + * @param fg The Jacobian factor graph $(A,b)$ + * @param x0 The center about which to compute the gradient + * @return The gradient as a VectorValues + */ + VectorValues gradient(const VectorValues& x0) const; + + /** + * Compute the gradient of the energy function, \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} A x - b + * \right\Vert^2 \f$, centered around zero. The gradient is \f$ A^T(Ax-b) \f$. + * @param fg The Jacobian factor graph $(A,b)$ + * @param [output] g A VectorValues to store the gradient, which must be preallocated, + * see allocateVectorValues + * @return The gradient as a VectorValues */ + VectorValues gradientAtZero() const; + + /** Optimize along the gradient direction, with a closed-form computation to perform the line + * search. The gradient is computed about \f$ \delta x=0 \f$. + * + * This function returns \f$ \delta x \f$ that minimizes a reparametrized problem. The error + * function of a GaussianBayesNet is + * + * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + + * \frac{1}{2} \delta x^T R^T R \delta x \f] + * + * with gradient and Hessian + * + * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] + * + * This function performs the line search in the direction of the gradient evaluated at \f$ g = + * g(\delta x = 0) \f$ with step size \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) + * \f$: + * + * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] + * + * Optimizing by setting the derivative to zero yields \f$ \hat \alpha = (-g^T g) / (g^T G g) + * \f$. For efficiency, this function evaluates the denominator without computing the Hessian + * \f$ G \f$, returning + * + * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] */ + //VectorValues optimizeGradientSearch() const; + + /** x = A'*e */ + VectorValues transposeMultiply(const Errors& e) const; + + /** x += alpha*A'*e */ + void transposeMultiplyAdd(double alpha, const Errors& e, VectorValues& x) const; + + /** return A*x-b */ + Errors gaussianErrors(const VectorValues& x) const; + + /// @} private: /** Serialization function */ @@ -249,48 +276,11 @@ namespace gtsam { }; - /** - * Combine and eliminate several factors. - * \addtogroup LinearSolving - */ - GTSAM_EXPORT JacobianFactor::shared_ptr CombineJacobians( - const FactorGraph& factors, - const VariableSlots& variableSlots); - /** * Evaluates whether linear factors have any constrained noise models * @return true if any factor is constrained. */ - GTSAM_EXPORT bool hasConstraints(const FactorGraph& factors); - - /** - * Densely combine and partially eliminate JacobianFactors to produce a - * single conditional with nrFrontals frontal variables and a remaining - * factor. - * Variables are eliminated in the natural order of the variable indices of in the factors. - * @param factors Factors to combine and eliminate - * @param nrFrontals Number of frontal variables to eliminate. - * @return The conditional and remaining factor - - * \addtogroup LinearSolving - */ - GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminateJacobians(const FactorGraph< - JacobianFactor>& factors, size_t nrFrontals = 1); - - /** - * Densely partially eliminate with QR factorization. HessianFactors are - * first factored with Cholesky decomposition to produce JacobianFactors, - * by calling the conversion constructor JacobianFactor(const HessianFactor&). - * Variables are eliminated in the natural order of the variable indices of in - * the factors. - * @param factors Factors to combine and eliminate - * @param nrFrontals Number of frontal variables to eliminate. - * @return The conditional and remaining factor - - * \addtogroup LinearSolving - */ - GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminateQR(const FactorGraph< - GaussianFactor>& factors, size_t nrFrontals = 1); + GTSAM_EXPORT bool hasConstraints(const GaussianFactorGraph& factors); /** * Densely partially eliminate with Cholesky factorization. JacobianFactors @@ -311,8 +301,8 @@ namespace gtsam { * \addtogroup LinearSolving */ - GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminatePreferCholesky(const FactorGraph< - GaussianFactor>& factors, size_t nrFrontals = 1); + //GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminatePreferCholesky(const FactorGraph< + // GaussianFactor>& factors, size_t nrFrontals = 1); /** * Densely partially eliminate with Cholesky factorization. JacobianFactors @@ -332,57 +322,22 @@ namespace gtsam { * \addtogroup LinearSolving */ - GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminateCholesky(const FactorGraph< - GaussianFactor>& factors, size_t nrFrontals = 1); + //GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminateCholesky(const FactorGraph< + // GaussianFactor>& factors, size_t nrFrontals = 1); /****** Linear Algebra Opeations ******/ - /** return A*x */ - GTSAM_EXPORT Errors operator*(const GaussianFactorGraph& fg, const VectorValues& x); + ///** return A*x */ + //GTSAM_EXPORT Errors operator*(const GaussianFactorGraph& fg, const VectorValues& x); - /** In-place version e <- A*x that overwrites e. */ - GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, Errors& e); + ///** In-place version e <- A*x that overwrites e. */ + //GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, Errors& e); - /** In-place version e <- A*x that takes an iterator. */ - GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, const Errors::iterator& e); + ///** In-place version e <- A*x that takes an iterator. */ + //GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraph& fg, const VectorValues& x, const Errors::iterator& e); - /** x += alpha*A'*e */ - GTSAM_EXPORT void transposeMultiplyAdd(const GaussianFactorGraph& fg, double alpha, const Errors& e, VectorValues& x); - - /** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$, - * centered around \f$ x = x_0 \f$. - * The gradient is \f$ A^T(Ax-b) \f$. - * @param fg The Jacobian factor graph $(A,b)$ - * @param x0 The center about which to compute the gradient - * @return The gradient as a VectorValues - */ - GTSAM_EXPORT VectorValues gradient(const GaussianFactorGraph& fg, const VectorValues& x0); - - /** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$, - * centered around zero. - * The gradient is \f$ A^T(Ax-b) \f$. - * @param fg The Jacobian factor graph $(A,b)$ - * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues - * @return The gradient as a VectorValues - */ - GTSAM_EXPORT void gradientAtZero(const GaussianFactorGraph& fg, VectorValues& g); - - /* matrix-vector operations */ - GTSAM_EXPORT void residual(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r); - GTSAM_EXPORT void multiply(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r); - GTSAM_EXPORT void transposeMultiply(const GaussianFactorGraph& fg, const VectorValues &r, VectorValues &x); - - /** shared pointer version - * \todo Make this a member function - affects SubgraphPreconditioner */ - GTSAM_EXPORT boost::shared_ptr gaussianErrors_(const GaussianFactorGraph& fg, const VectorValues& x); - - /** return A*x-b - * \todo Make this a member function - affects SubgraphPreconditioner */ - inline Errors gaussianErrors(const GaussianFactorGraph& fg, const VectorValues& x) { - return *gaussianErrors_(fg, x); } + ///* matrix-vector operations */ + //GTSAM_EXPORT void residual(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r); + //GTSAM_EXPORT void multiply(const GaussianFactorGraph& fg, const VectorValues &x, VectorValues &r); } // namespace gtsam diff --git a/gtsam/linear/GaussianFactorGraphOrdered.cpp b/gtsam/linear/GaussianFactorGraphOrdered.cpp new file mode 100644 index 000000000..c64994fca --- /dev/null +++ b/gtsam/linear/GaussianFactorGraphOrdered.cpp @@ -0,0 +1,590 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianFactorGraph.cpp + * @brief Linear Factor Graph where all factors are Gaussians + * @author Kai Ni + * @author Christian Potthast + * @author Richard Roberts + * @author Frank Dellaert + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace gtsam; + +namespace gtsam { + + /* ************************************************************************* */ + GaussianFactorGraphOrdered::GaussianFactorGraphOrdered(const GaussianBayesNetOrdered& CBN) : Base(CBN) {} + + /* ************************************************************************* */ + GaussianFactorGraphOrdered::Keys GaussianFactorGraphOrdered::keys() const { + FastSet keys; + BOOST_FOREACH(const sharedFactor& factor, *this) + if (factor) keys.insert(factor->begin(), factor->end()); + return keys; + } + + /* ************************************************************************* */ + void GaussianFactorGraphOrdered::permuteWithInverse( + const Permutation& inversePermutation) { + BOOST_FOREACH(const sharedFactor& factor, factors_) { + if(factor) + factor->permuteWithInverse(inversePermutation); + } + } + + /* ************************************************************************* */ + void GaussianFactorGraphOrdered::reduceWithInverse( + const internal::Reduction& inverseReduction) { + BOOST_FOREACH(const sharedFactor& factor, factors_) { + if(factor) + factor->reduceWithInverse(inverseReduction); + } + } + + /* ************************************************************************* */ + void GaussianFactorGraphOrdered::combine(const GaussianFactorGraphOrdered &lfg) { + for (const_iterator factor = lfg.factors_.begin(); factor + != lfg.factors_.end(); factor++) { + push_back(*factor); + } + } + + /* ************************************************************************* */ + GaussianFactorGraphOrdered GaussianFactorGraphOrdered::combine2( + const GaussianFactorGraphOrdered& lfg1, const GaussianFactorGraphOrdered& lfg2) { + + // create new linear factor graph equal to the first one + GaussianFactorGraphOrdered fg = lfg1; + + // add the second factors_ in the graph + for (const_iterator factor = lfg2.factors_.begin(); factor + != lfg2.factors_.end(); factor++) { + fg.push_back(*factor); + } + return fg; + } + + /* ************************************************************************* */ + std::vector > GaussianFactorGraphOrdered::sparseJacobian() const { + // First find dimensions of each variable + FastVector dims; + BOOST_FOREACH(const sharedFactor& factor, *this) { + for(GaussianFactorOrdered::const_iterator pos = factor->begin(); pos != factor->end(); ++pos) { + if(dims.size() <= *pos) + dims.resize(*pos + 1, 0); + dims[*pos] = factor->getDim(pos); + } + } + + // Compute first scalar column of each variable + vector columnIndices(dims.size()+1, 0); + for(size_t j=1; j triplet; + FastVector entries; + size_t row = 0; + BOOST_FOREACH(const sharedFactor& factor, *this) { + // Convert to JacobianFactor if necessary + JacobianFactorOrdered::shared_ptr jacobianFactor( + boost::dynamic_pointer_cast(factor)); + if (!jacobianFactor) { + HessianFactorOrdered::shared_ptr hessian(boost::dynamic_pointer_cast(factor)); + if (hessian) + jacobianFactor.reset(new JacobianFactorOrdered(*hessian)); + else + throw invalid_argument( + "GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor."); + } + + // Whiten the factor and add entries for it + // iterate over all variables in the factor + const JacobianFactorOrdered whitened(jacobianFactor->whiten()); + for(JacobianFactorOrdered::const_iterator pos=whitened.begin(); pos 1e-12) entries.push_back( + boost::make_tuple(row+i, column_start+j, s)); + } + } + + JacobianFactorOrdered::constBVector whitenedb(whitened.getb()); + size_t bcolumn = columnIndices.back(); + for (size_t i = 0; i < (size_t) whitenedb.size(); i++) + entries.push_back(boost::make_tuple(row+i, bcolumn, whitenedb(i))); + + // Increment row index + row += jacobianFactor->rows(); + } + return vector(entries.begin(), entries.end()); + } + + /* ************************************************************************* */ + Matrix GaussianFactorGraphOrdered::sparseJacobian_() const { + + // call sparseJacobian + typedef boost::tuple triplet; + std::vector result = sparseJacobian(); + + // translate to base 1 matrix + size_t nzmax = result.size(); + Matrix IJS(3,nzmax); + for (size_t k = 0; k < result.size(); k++) { + const triplet& entry = result[k]; + IJS(0,k) = double(entry.get<0>() + 1); + IJS(1,k) = double(entry.get<1>() + 1); + IJS(2,k) = entry.get<2>(); + } + return IJS; + } + + /* ************************************************************************* */ + Matrix GaussianFactorGraphOrdered::augmentedJacobian() const { + // Convert to Jacobians + FactorGraphOrdered jfg; + jfg.reserve(this->size()); + BOOST_FOREACH(const sharedFactor& factor, *this) { + if(boost::shared_ptr jf = + boost::dynamic_pointer_cast(factor)) + jfg.push_back(jf); + else + jfg.push_back(boost::make_shared(*factor)); + } + // combine all factors + JacobianFactorOrdered combined(*CombineJacobians(jfg, VariableSlots(*this))); + return combined.matrix_augmented(); + } + + /* ************************************************************************* */ + std::pair GaussianFactorGraphOrdered::jacobian() const { + Matrix augmented = augmentedJacobian(); + return make_pair( + augmented.leftCols(augmented.cols()-1), + augmented.col(augmented.cols()-1)); + } + + // Helper functions for Combine + static boost::tuple, size_t, size_t> countDims(const FactorGraphOrdered& factors, const VariableSlots& variableSlots) { +#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS + vector varDims(variableSlots.size(), numeric_limits::max()); +#else + vector varDims(variableSlots.size()); +#endif + size_t m = 0; + size_t n = 0; + { + Index jointVarpos = 0; + BOOST_FOREACH(const VariableSlots::value_type& slots, variableSlots) { + + assert(slots.second.size() == factors.size()); + + Index sourceFactorI = 0; + BOOST_FOREACH(const Index sourceVarpos, slots.second) { + if(sourceVarpos < numeric_limits::max()) { + const JacobianFactorOrdered& sourceFactor = *factors[sourceFactorI]; + size_t vardim = sourceFactor.getDim(sourceFactor.begin() + sourceVarpos); +#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS + if(varDims[jointVarpos] == numeric_limits::max()) { + varDims[jointVarpos] = vardim; + n += vardim; + } else + assert(varDims[jointVarpos] == vardim); +#else + varDims[jointVarpos] = vardim; + n += vardim; + break; +#endif + } + ++ sourceFactorI; + } + ++ jointVarpos; + } + BOOST_FOREACH(const JacobianFactorOrdered::shared_ptr& factor, factors) { + m += factor->rows(); + } + } + return boost::make_tuple(varDims, m, n); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::shared_ptr CombineJacobians( + const FactorGraphOrdered& factors, + const VariableSlots& variableSlots) { + + const bool debug = ISDEBUG("CombineJacobians"); + if (debug) factors.print("Combining factors: "); + if (debug) variableSlots.print(); + + if (debug) cout << "Determine dimensions" << endl; + gttic(countDims); + vector varDims; + size_t m, n; + boost::tie(varDims, m, n) = countDims(factors, variableSlots); + if (debug) { + cout << "Dims: " << m << " x " << n << "\n"; + BOOST_FOREACH(const size_t dim, varDims) cout << dim << " "; + cout << endl; + } + gttoc(countDims); + + if (debug) cout << "Allocate new factor" << endl; + gttic(allocate); + JacobianFactorOrdered::shared_ptr combined(new JacobianFactorOrdered()); + combined->allocate(variableSlots, varDims, m); + Vector sigmas(m); + gttoc(allocate); + + if (debug) cout << "Copy blocks" << endl; + gttic(copy_blocks); + // Loop over slots in combined factor + Index combinedSlot = 0; + BOOST_FOREACH(const VariableSlots::value_type& varslot, variableSlots) { + JacobianFactorOrdered::ABlock destSlot(combined->getA(combined->begin()+combinedSlot)); + // Loop over source factors + size_t nextRow = 0; + for(size_t factorI = 0; factorI < factors.size(); ++factorI) { + // Slot in source factor + const Index sourceSlot = varslot.second[factorI]; + const size_t sourceRows = factors[factorI]->rows(); + JacobianFactorOrdered::ABlock::RowsBlockXpr destBlock(destSlot.middleRows(nextRow, sourceRows)); + // Copy if exists in source factor, otherwise set zero + if(sourceSlot != numeric_limits::max()) + destBlock = factors[factorI]->getA(factors[factorI]->begin()+sourceSlot); + else + destBlock.setZero(); + nextRow += sourceRows; + } + ++combinedSlot; + } + gttoc(copy_blocks); + + if (debug) cout << "Copy rhs (b) and sigma" << endl; + gttic(copy_vectors); + bool anyConstrained = false; + // Loop over source factors + size_t nextRow = 0; + for(size_t factorI = 0; factorI < factors.size(); ++factorI) { + const size_t sourceRows = factors[factorI]->rows(); + combined->getb().segment(nextRow, sourceRows) = factors[factorI]->getb(); + sigmas.segment(nextRow, sourceRows) = factors[factorI]->get_model()->sigmas(); + if (factors[factorI]->isConstrained()) anyConstrained = true; + nextRow += sourceRows; + } + gttoc(copy_vectors); + + if (debug) cout << "Create noise model from sigmas" << endl; + gttic(noise_model); + combined->setModel(anyConstrained, sigmas); + gttoc(noise_model); + + if (debug) cout << "Assert Invariants" << endl; + combined->assertInvariants(); + + return combined; + } + + /* ************************************************************************* */ + GaussianFactorGraphOrdered::EliminationResult EliminateJacobians(const FactorGraphOrdered< + JacobianFactorOrdered>& factors, size_t nrFrontals) { + gttic(Combine); + JacobianFactorOrdered::shared_ptr jointFactor = + CombineJacobians(factors, VariableSlots(factors)); + gttoc(Combine); + gttic(eliminate); + GaussianConditionalOrdered::shared_ptr gbn = jointFactor->eliminate(nrFrontals); + gttoc(eliminate); + return make_pair(gbn, jointFactor); + } + + /* ************************************************************************* */ + Matrix GaussianFactorGraphOrdered::augmentedHessian() const { + // combine all factors and get upper-triangular part of Hessian + HessianFactorOrdered combined(*this); + Matrix result = combined.info(); + // Fill in lower-triangular part of Hessian + result.triangularView() = result.transpose(); + return result; + } + + /* ************************************************************************* */ + std::pair GaussianFactorGraphOrdered::hessian() const { + Matrix augmented = augmentedHessian(); + return make_pair( + augmented.topLeftCorner(augmented.rows()-1, augmented.rows()-1), + augmented.col(augmented.rows()-1).head(augmented.rows()-1)); + } + + /* ************************************************************************* */ + GaussianFactorGraphOrdered::EliminationResult EliminateCholeskyOrdered(const FactorGraphOrdered< + GaussianFactorOrdered>& factors, size_t nrFrontals) { + + const bool debug = ISDEBUG("EliminateCholesky"); + + // Form Ab' * Ab + gttic(combine); + HessianFactorOrdered::shared_ptr combinedFactor(new HessianFactorOrdered(factors)); + gttoc(combine); + + // 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. + gttic(partial_Cholesky); + combinedFactor->partialCholesky(nrFrontals); + + gttoc(partial_Cholesky); + + // Extract conditional and fill in details of the remaining factor + gttic(split); + GaussianConditionalOrdered::shared_ptr conditional = + combinedFactor->splitEliminatedFactor(nrFrontals); + if (debug) { + conditional->print("Extracted conditional: "); + combinedFactor->print("Eliminated factor (L piece): "); + } + gttoc(split); + + combinedFactor->assertInvariants(); + return make_pair(conditional, combinedFactor); + } + + /* ************************************************************************* */ + static FactorGraphOrdered convertToJacobians(const FactorGraphOrdered< + GaussianFactorOrdered>& factors) { + + typedef JacobianFactorOrdered J; + typedef HessianFactorOrdered H; + + const bool debug = ISDEBUG("convertToJacobians"); + + FactorGraphOrdered jacobians; + jacobians.reserve(factors.size()); + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factors) + if (factor) { + J::shared_ptr jacobian(boost::dynamic_pointer_cast(factor)); + if (jacobian) { + jacobians.push_back(jacobian); + if (debug) jacobian->print("Existing JacobianFactor: "); + } else { + H::shared_ptr hessian(boost::dynamic_pointer_cast(factor)); + if (!hessian) throw std::invalid_argument( + "convertToJacobians: factor is neither a JacobianFactor nor a HessianFactor."); + J::shared_ptr converted(new J(*hessian)); + if (debug) { + cout << "Converted HessianFactor to JacobianFactor:\n"; + hessian->print("HessianFactor: "); + converted->print("JacobianFactor: "); + if (!assert_equal(*hessian, HessianFactorOrdered(*converted), 1e-3)) throw runtime_error( + "convertToJacobians: Conversion between Jacobian and Hessian incorrect"); + } + jacobians.push_back(converted); + } + } + return jacobians; + } + + /* ************************************************************************* */ + GaussianFactorGraphOrdered::EliminationResult EliminateQROrdered(const FactorGraphOrdered< + GaussianFactorOrdered>& factors, size_t nrFrontals) { + + const bool debug = ISDEBUG("EliminateQR"); + + // Convert all factors to the appropriate type and call the type-specific EliminateGaussian. + if (debug) cout << "Using QR" << endl; + + gttic(convert_to_Jacobian); + FactorGraphOrdered jacobians = convertToJacobians(factors); + gttoc(convert_to_Jacobian); + + gttic(Jacobian_EliminateGaussian); + GaussianConditionalOrdered::shared_ptr conditional; + GaussianFactorOrdered::shared_ptr factor; + boost::tie(conditional, factor) = EliminateJacobians(jacobians, nrFrontals); + gttoc(Jacobian_EliminateGaussian); + + return make_pair(conditional, factor); + } // \EliminateQR + + /* ************************************************************************* */ + bool hasConstraints(const FactorGraphOrdered& factors) { + typedef JacobianFactorOrdered J; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factors) { + J::shared_ptr jacobian(boost::dynamic_pointer_cast(factor)); + if (jacobian && jacobian->get_model()->isConstrained()) { + return true; + } + } + return false; + } + + /* ************************************************************************* */ + GaussianFactorGraphOrdered::EliminationResult EliminatePreferCholeskyOrdered( + const FactorGraphOrdered& factors, size_t nrFrontals) { + + // If any JacobianFactors have constrained noise models, we have to convert + // all factors to JacobianFactors. Otherwise, we can convert all factors + // to HessianFactors. This is because QR can handle constrained noise + // models but Cholesky cannot. + if (hasConstraints(factors)) + return EliminateQROrdered(factors, nrFrontals); + else { + GaussianFactorGraphOrdered::EliminationResult ret; + gttic(EliminateCholeskyOrdered); + ret = EliminateCholeskyOrdered(factors, nrFrontals); + gttoc(EliminateCholeskyOrdered); + return ret; + } + + } // \EliminatePreferCholesky + + + + /* ************************************************************************* */ + static JacobianFactorOrdered::shared_ptr convertToJacobianFactorPtr(const GaussianFactorOrdered::shared_ptr &gf) { + JacobianFactorOrdered::shared_ptr result = boost::dynamic_pointer_cast(gf); + if( !result ) { + result = boost::make_shared(*gf); // Convert any non-Jacobian factors to Jacobians (e.g. Hessian -> Jacobian with Cholesky) + } + return result; + } + + /* ************************************************************************* */ + Errors operator*(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) { + Errors e; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + e.push_back((*Ai)*x); + } + return e; + } + + /* ************************************************************************* */ + void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, Errors& e) { + multiplyInPlace(fg,x,e.begin()); + } + + /* ************************************************************************* */ + void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, const Errors::iterator& e) { + Errors::iterator ei = e; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + *ei = (*Ai)*x; + ei++; + } + } + + /* ************************************************************************* */ + // x += alpha*A'*e + void transposeMultiplyAdd(const GaussianFactorGraphOrdered& fg, double alpha, const Errors& e, VectorValuesOrdered& x) { + // For each factor add the gradient contribution + Errors::const_iterator ei = e.begin(); + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + Ai->transposeMultiplyAdd(alpha,*(ei++),x); + } + } + + /* ************************************************************************* */ + VectorValuesOrdered gradient(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x0) { + // It is crucial for performance to make a zero-valued clone of x + VectorValuesOrdered g = VectorValuesOrdered::Zero(x0); + Errors e; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + e.push_back(Ai->error_vector(x0)); + } + transposeMultiplyAdd(fg, 1.0, e, g); + return g; + } + + /* ************************************************************************* */ + void gradientAtZero(const GaussianFactorGraphOrdered& fg, VectorValuesOrdered& g) { + // Zero-out the gradient + g.setZero(); + Errors e; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + e.push_back(-Ai->getb()); + } + transposeMultiplyAdd(fg, 1.0, e, g); + } + + /* ************************************************************************* */ + void residual(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r) { + Index i = 0 ; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + r[i] = Ai->getb(); + i++; + } + VectorValuesOrdered Ax = VectorValuesOrdered::SameStructure(r); + multiply(fg,x,Ax); + axpy(-1.0,Ax,r); + } + + /* ************************************************************************* */ + void multiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r) { + r.setZero(); + Index i = 0; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + Vector &y = r[i]; + for(JacobianFactorOrdered::const_iterator j = Ai->begin(); j != Ai->end(); ++j) { + y += Ai->getA(j) * x[*j]; + } + ++i; + } + } + + /* ************************************************************************* */ + void transposeMultiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &r, VectorValuesOrdered &x) { + x.setZero(); + Index i = 0; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + for(JacobianFactorOrdered::const_iterator j = Ai->begin(); j != Ai->end(); ++j) { + x[*j] += Ai->getA(j).transpose() * r[i]; + } + ++i; + } + } + + /* ************************************************************************* */ + boost::shared_ptr gaussianErrors_(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) { + boost::shared_ptr e(new Errors); + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) { + JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); + e->push_back(Ai->error_vector(x)); + } + return e; + } + +} // namespace gtsam diff --git a/gtsam/linear/GaussianFactorGraphOrdered.h b/gtsam/linear/GaussianFactorGraphOrdered.h new file mode 100644 index 000000000..0db7f9fae --- /dev/null +++ b/gtsam/linear/GaussianFactorGraphOrdered.h @@ -0,0 +1,388 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianFactorGraph.h + * @brief Linear Factor Graph where all factors are Gaussians + * @author Kai Ni + * @author Christian Potthast + * @author Alireza Fathi + * @author Richard Roberts + * @author Frank Dellaert + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace gtsam { + + // Forward declaration to use as default argument, documented declaration below. + GTSAM_EXPORT FactorGraphOrdered::EliminationResult + EliminateQROrdered(const FactorGraphOrdered& factors, size_t nrFrontals); + + /** + * A Linear Factor Graph is a factor graph where all factors are Gaussian, i.e. + * Factor == GaussianFactor + * VectorValues = A values structure of vectors + * Most of the time, linear factor graphs arise by linearizing a non-linear factor graph. + */ + class GaussianFactorGraphOrdered : public FactorGraphOrdered { + public: + + typedef boost::shared_ptr shared_ptr; + typedef FactorGraphOrdered Base; + + /** + * Default constructor + */ + GaussianFactorGraphOrdered() {} + + /** + * Constructor that receives a Chordal Bayes Net and returns a GaussianFactorGraph + */ + GTSAM_EXPORT GaussianFactorGraphOrdered(const GaussianBayesNetOrdered& CBN); + + /** + * Constructor that receives a BayesTree and returns a GaussianFactorGraph + */ + template + GaussianFactorGraphOrdered(const BayesTreeOrdered& gbt) : Base(gbt) {} + + /** Constructor from a factor graph of GaussianFactor or a derived type */ + template + GaussianFactorGraphOrdered(const FactorGraphOrdered& fg) { + push_back(fg); + } + + /** Add a factor by value - makes a copy */ + void add(const GaussianFactorOrdered& factor) { + factors_.push_back(factor.clone()); + } + + /** Add a factor by pointer - stores pointer without copying the factor */ + void add(const sharedFactor& factor) { + factors_.push_back(factor); + } + + /** Add a null factor */ + void add(const Vector& b) { + add(JacobianFactorOrdered(b)); + } + + /** Add a unary factor */ + void add(Index key1, const Matrix& A1, + const Vector& b, const SharedDiagonal& model) { + add(JacobianFactorOrdered(key1,A1,b,model)); + } + + /** Add a binary factor */ + void add(Index key1, const Matrix& A1, + Index key2, const Matrix& A2, + const Vector& b, const SharedDiagonal& model) { + add(JacobianFactorOrdered(key1,A1,key2,A2,b,model)); + } + + /** Add a ternary factor */ + void add(Index key1, const Matrix& A1, + Index key2, const Matrix& A2, + Index key3, const Matrix& A3, + const Vector& b, const SharedDiagonal& model) { + add(JacobianFactorOrdered(key1,A1,key2,A2,key3,A3,b,model)); + } + + /** Add an n-ary factor */ + void add(const std::vector > &terms, + const Vector &b, const SharedDiagonal& model) { + add(JacobianFactorOrdered(terms,b,model)); + } + + /** + * Return the set of variables involved in the factors (computes a set + * union). + */ + typedef FastSet Keys; + GTSAM_EXPORT Keys keys() const; + + + /** Eliminate the first \c n frontal variables, returning the resulting + * conditional and remaining factor graph - this is very inefficient for + * eliminating all variables, to do that use EliminationTree or + * JunctionTree. Note that this version simply calls + * FactorGraph::eliminateFrontals with EliminateQR as the + * eliminate function argument. + */ + std::pair eliminateFrontals(size_t nFrontals, const Eliminate& function = EliminateQROrdered) const { + return Base::eliminateFrontals(nFrontals, function); } + + /** Factor the factor graph into a conditional and a remaining factor graph. + * Given the factor graph \f$ f(X) \f$, and \c variables to factorize out + * \f$ V \f$, this function factorizes into \f$ f(X) = f(V;Y)f(Y) \f$, where + * \f$ Y := X\V \f$ are the remaining variables. If \f$ f(X) = p(X) \f$ is + * a probability density or likelihood, the factorization produces a + * conditional probability density and a marginal \f$ p(X) = p(V|Y)p(Y) \f$. + * + * For efficiency, this function treats the variables to eliminate + * \c variables as fully-connected, so produces a dense (fully-connected) + * conditional on all of the variables in \c variables, instead of a sparse + * BayesNet. If the variables are not fully-connected, it is more efficient + * to sequentially factorize multiple times. + * Note that this version simply calls + * FactorGraph::eliminate with EliminateQR as the eliminate + * function argument. + */ + std::pair eliminate(const std::vector& variables, const Eliminate& function = EliminateQROrdered) const { + return Base::eliminate(variables, function); } + + /** Eliminate a single variable, by calling GaussianFactorGraph::eliminate. */ + std::pair eliminateOne(Index variable, const Eliminate& function = EliminateQROrdered) const { + return Base::eliminateOne(variable, function); } + + /** Permute the variables in the factors */ + GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation); + + /** Apply a reduction, which is a remapping of variable indices. */ + GTSAM_EXPORT void reduceWithInverse(const internal::Reduction& inverseReduction); + + /** unnormalized error */ + double error(const VectorValuesOrdered& x) const { + double total_error = 0.; + BOOST_FOREACH(const sharedFactor& factor, *this) + total_error += factor->error(x); + return total_error; + } + + /** Unnormalized probability. O(n) */ + double probPrime(const VectorValuesOrdered& c) const { + return exp(-0.5 * error(c)); + } + + /** + * Static function that combines two factor graphs. + * @param lfg1 Linear factor graph + * @param lfg2 Linear factor graph + * @return a new combined factor graph + */ + GTSAM_EXPORT static GaussianFactorGraphOrdered combine2(const GaussianFactorGraphOrdered& lfg1, + const GaussianFactorGraphOrdered& lfg2); + + /** + * combine two factor graphs + * @param *lfg Linear factor graph + */ + GTSAM_EXPORT void combine(const GaussianFactorGraphOrdered &lfg); + + /** + * Return vector of i, j, and s to generate an m-by-n sparse Jacobian matrix, + * where i(k) and j(k) are the base 0 row and column indices, s(k) a double. + * The standard deviations are baked into A and b + */ + GTSAM_EXPORT std::vector > sparseJacobian() const; + + /** + * Matrix version of sparseJacobian: generates a 3*m matrix with [i,j,s] entries + * such that S(i(k),j(k)) = s(k), which can be given to MATLAB's sparse. + * The standard deviations are baked into A and b + */ + GTSAM_EXPORT Matrix sparseJacobian_() const; + + /** + * Return a dense \f$ [ \;A\;b\; ] \in \mathbb{R}^{m \times n+1} \f$ + * Jacobian matrix, augmented with b with the noise models baked + * into A and b. The negative log-likelihood is + * \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also + * GaussianFactorGraph::jacobian and GaussianFactorGraph::sparseJacobian. + */ + GTSAM_EXPORT Matrix augmentedJacobian() const; + + /** + * Return the dense Jacobian \f$ A \f$ and right-hand-side \f$ b \f$, + * with the noise models baked into A and b. The negative log-likelihood + * is \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also + * GaussianFactorGraph::augmentedJacobian and + * GaussianFactorGraph::sparseJacobian. + */ + GTSAM_EXPORT std::pair jacobian() const; + + /** + * Return a dense \f$ \Lambda \in \mathbb{R}^{n+1 \times n+1} \f$ Hessian + * matrix, augmented with the information vector \f$ \eta \f$. The + * augmented Hessian is + \f[ \left[ \begin{array}{ccc} + \Lambda & \eta \\ + \eta^T & c + \end{array} \right] \f] + and the negative log-likelihood is + \f$ \frac{1}{2} x^T \Lambda x + \eta^T x + c \f$. + */ + GTSAM_EXPORT Matrix augmentedHessian() const; + + /** + * Return the dense Hessian \f$ \Lambda \f$ and information vector + * \f$ \eta \f$, with the noise models baked in. The negative log-likelihood + * is \frac{1}{2} x^T \Lambda x + \eta^T x + c. See also + * GaussianFactorGraph::augmentedHessian. + */ + GTSAM_EXPORT std::pair hessian() const; + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); + } + + }; + + /** + * Combine and eliminate several factors. + * \addtogroup LinearSolving + */ + GTSAM_EXPORT JacobianFactorOrdered::shared_ptr CombineJacobians( + const FactorGraphOrdered& factors, + const VariableSlots& variableSlots); + + /** + * Evaluates whether linear factors have any constrained noise models + * @return true if any factor is constrained. + */ + GTSAM_EXPORT bool hasConstraints(const FactorGraphOrdered& factors); + + /** + * Densely combine and partially eliminate JacobianFactors to produce a + * single conditional with nrFrontals frontal variables and a remaining + * factor. + * Variables are eliminated in the natural order of the variable indices of in the factors. + * @param factors Factors to combine and eliminate + * @param nrFrontals Number of frontal variables to eliminate. + * @return The conditional and remaining factor + + * \addtogroup LinearSolving + */ + GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminateJacobians(const FactorGraphOrdered< + JacobianFactorOrdered>& factors, size_t nrFrontals = 1); + + /** + * Densely partially eliminate with QR factorization. HessianFactors are + * first factored with Cholesky decomposition to produce JacobianFactors, + * by calling the conversion constructor JacobianFactor(const HessianFactor&). + * Variables are eliminated in the natural order of the variable indices of in + * the factors. + * @param factors Factors to combine and eliminate + * @param nrFrontals Number of frontal variables to eliminate. + * @return The conditional and remaining factor + + * \addtogroup LinearSolving + */ + GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminateQROrdered(const FactorGraphOrdered< + GaussianFactorOrdered>& factors, size_t nrFrontals = 1); + + /** + * Densely partially eliminate with Cholesky factorization. JacobianFactors + * are left-multiplied with their transpose to form the Hessian using the + * conversion constructor HessianFactor(const JacobianFactor&). + * + * If any factors contain constrained noise models (any sigmas equal to + * zero), QR factorization will be performed instead, because our current + * implementation cannot handle constrained noise models in Cholesky + * factorization. EliminateCholesky(), on the other hand, will fail if any + * factors contain constrained noise models. + * + * Variables are eliminated in the natural order of the variable indices of in + * the factors. + * @param factors Factors to combine and eliminate + * @param nrFrontals Number of frontal variables to eliminate. + * @return The conditional and remaining factor + + * \addtogroup LinearSolving + */ + GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminatePreferCholeskyOrdered(const FactorGraphOrdered< + GaussianFactorOrdered>& factors, size_t nrFrontals = 1); + + /** + * Densely partially eliminate with Cholesky factorization. JacobianFactors + * are left-multiplied with their transpose to form the Hessian using the + * conversion constructor HessianFactor(const JacobianFactor&). + * + * If any factors contain constrained noise models, this function will fail + * because our current implementation cannot handle constrained noise models + * in Cholesky factorization. The function EliminatePreferCholesky() + * automatically does QR instead when this is the case. + * + * Variables are eliminated in the natural order of the variable indices of in + * the factors. + * @param factors Factors to combine and eliminate + * @param nrFrontals Number of frontal variables to eliminate. + * @return The conditional and remaining factor + + * \addtogroup LinearSolving + */ + GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminateCholeskyOrdered(const FactorGraphOrdered< + GaussianFactorOrdered>& factors, size_t nrFrontals = 1); + + /****** Linear Algebra Opeations ******/ + + /** return A*x */ + GTSAM_EXPORT Errors operator*(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x); + + /** In-place version e <- A*x that overwrites e. */ + GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, Errors& e); + + /** In-place version e <- A*x that takes an iterator. */ + GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, const Errors::iterator& e); + + /** x += alpha*A'*e */ + GTSAM_EXPORT void transposeMultiplyAdd(const GaussianFactorGraphOrdered& fg, double alpha, const Errors& e, VectorValuesOrdered& x); + + /** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$, + * centered around \f$ x = x_0 \f$. + * The gradient is \f$ A^T(Ax-b) \f$. + * @param fg The Jacobian factor graph $(A,b)$ + * @param x0 The center about which to compute the gradient + * @return The gradient as a VectorValues + */ + GTSAM_EXPORT VectorValuesOrdered gradient(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x0); + + /** + * Compute the gradient of the energy function, + * \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$, + * centered around zero. + * The gradient is \f$ A^T(Ax-b) \f$. + * @param fg The Jacobian factor graph $(A,b)$ + * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues + * @return The gradient as a VectorValues + */ + GTSAM_EXPORT void gradientAtZero(const GaussianFactorGraphOrdered& fg, VectorValuesOrdered& g); + + /* matrix-vector operations */ + GTSAM_EXPORT void residual(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r); + GTSAM_EXPORT void multiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r); + GTSAM_EXPORT void transposeMultiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &r, VectorValuesOrdered &x); + + /** shared pointer version + * \todo Make this a member function - affects SubgraphPreconditioner */ + GTSAM_EXPORT boost::shared_ptr gaussianErrors_(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x); + + /** return A*x-b + * \todo Make this a member function - affects SubgraphPreconditioner */ + inline Errors gaussianErrors(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) { + return *gaussianErrors_(fg, x); } + +} // namespace gtsam diff --git a/gtsam/linear/GaussianFactorGraphUnordered.cpp b/gtsam/linear/GaussianFactorGraphUnordered.cpp deleted file mode 100644 index 902b6cf28..000000000 --- a/gtsam/linear/GaussianFactorGraphUnordered.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianFactorGraph.cpp - * @brief Linear Factor Graph where all factors are Gaussians - * @author Kai Ni - * @author Christian Potthast - * @author Richard Roberts - * @author Frank Dellaert - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -using namespace gtsam; - -namespace gtsam { - - /* ************************************************************************* */ - bool GaussianFactorGraphUnordered::equals(const This& fg, double tol) const - { - return Base::equals(fg, tol); - } - - /* ************************************************************************* */ - GaussianFactorGraphUnordered::Keys GaussianFactorGraphUnordered::keys() const { - FastSet keys; - BOOST_FOREACH(const sharedFactor& factor, *this) - if (factor) - keys.insert(factor->begin(), factor->end()); - return keys; - } - - /* ************************************************************************* */ - std::vector > GaussianFactorGraphUnordered::sparseJacobian() const { - // First find dimensions of each variable - FastVector dims; - BOOST_FOREACH(const sharedFactor& factor, *this) { - for(GaussianFactorUnordered::const_iterator pos = factor->begin(); pos != factor->end(); ++pos) { - if(dims.size() <= *pos) - dims.resize(*pos + 1, 0); - dims[*pos] = factor->getDim(pos); - } - } - - // Compute first scalar column of each variable - vector columnIndices(dims.size()+1, 0); - for(size_t j=1; j triplet; - FastVector entries; - size_t row = 0; - BOOST_FOREACH(const sharedFactor& factor, *this) { - // Convert to JacobianFactor if necessary - JacobianFactorUnordered::shared_ptr jacobianFactor( - boost::dynamic_pointer_cast(factor)); - if (!jacobianFactor) { - //TODO Unordered: re-enable - //HessianFactorUnordered::shared_ptr hessian(boost::dynamic_pointer_cast(factor)); - //if (hessian) - // jacobianFactor.reset(new JacobianFactorUnordered(*hessian)); - //else - throw invalid_argument( - "GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor."); - } - - // Whiten the factor and add entries for it - // iterate over all variables in the factor - const JacobianFactorUnordered whitened(jacobianFactor->whiten()); - for(JacobianFactorUnordered::const_iterator pos=whitened.begin(); pos 1e-12) entries.push_back( - boost::make_tuple(row+i, column_start+j, s)); - } - } - - JacobianFactorUnordered::constBVector whitenedb(whitened.getb()); - size_t bcolumn = columnIndices.back(); - for (size_t i = 0; i < (size_t) whitenedb.size(); i++) - entries.push_back(boost::make_tuple(row+i, bcolumn, whitenedb(i))); - - // Increment row index - row += jacobianFactor->rows(); - } - return vector(entries.begin(), entries.end()); - } - - /* ************************************************************************* */ - Matrix GaussianFactorGraphUnordered::sparseJacobian_() const { - - // call sparseJacobian - typedef boost::tuple triplet; - std::vector result = sparseJacobian(); - - // translate to base 1 matrix - size_t nzmax = result.size(); - Matrix IJS(3,nzmax); - for (size_t k = 0; k < result.size(); k++) { - const triplet& entry = result[k]; - IJS(0,k) = double(entry.get<0>() + 1); - IJS(1,k) = double(entry.get<1>() + 1); - IJS(2,k) = entry.get<2>(); - } - return IJS; - } - - /* ************************************************************************* */ - Matrix GaussianFactorGraphUnordered::augmentedJacobian() const { - // combine all factors - JacobianFactorUnordered combined(*this); - return combined.augmentedJacobian(); - } - - /* ************************************************************************* */ - std::pair GaussianFactorGraphUnordered::jacobian() const { - Matrix augmented = augmentedJacobian(); - return make_pair( - augmented.leftCols(augmented.cols()-1), - augmented.col(augmented.cols()-1)); - } - - /* ************************************************************************* */ - //Matrix GaussianFactorGraphUnordered::augmentedHessian() const { - // // combine all factors and get upper-triangular part of Hessian - // HessianFactorUnordered combined(*this); - // Matrix result = combined.info(); - // // Fill in lower-triangular part of Hessian - // result.triangularView() = result.transpose(); - // return result; - //} - - /* ************************************************************************* */ - //std::pair GaussianFactorGraphUnordered::hessian() const { - // Matrix augmented = augmentedHessian(); - // return make_pair( - // augmented.topLeftCorner(augmented.rows()-1, augmented.rows()-1), - // augmented.col(augmented.rows()-1).head(augmented.rows()-1)); - //} - - /* ************************************************************************* */ - //GaussianFactorGraphUnordered::EliminationResult EliminateCholesky(const FactorGraph< - // GaussianFactorUnordered>& factors, size_t nrFrontals) { - - // const bool debug = ISDEBUG("EliminateCholesky"); - - // // Form Ab' * Ab - // gttic(combine); - // HessianFactorUnordered::shared_ptr combinedFactor(new HessianFactorUnordered(factors)); - // gttoc(combine); - - // // 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. - // gttic(partial_Cholesky); - // combinedFactor->partialCholesky(nrFrontals); - - // gttoc(partial_Cholesky); - - // // Extract conditional and fill in details of the remaining factor - // gttic(split); - // GaussianConditional::shared_ptr conditional = - // combinedFactor->splitEliminatedFactor(nrFrontals); - // if (debug) { - // conditional->print("Extracted conditional: "); - // combinedFactor->print("Eliminated factor (L piece): "); - // } - // gttoc(split); - - // combinedFactor->assertInvariants(); - // return make_pair(conditional, combinedFactor); - //} - - /* ************************************************************************* */ - VectorValuesUnordered GaussianFactorGraphUnordered::optimize(const Eliminate& function) const - { - gttic(GaussianFactorGraph_optimize); - return BaseEliminateable::eliminateMultifrontal(boost::none, function)->optimize(); - } - - /* ************************************************************************* */ - VectorValuesUnordered GaussianFactorGraphUnordered::gradient(const VectorValuesUnordered& x0) const - { - VectorValuesUnordered g = VectorValuesUnordered::Zero(x0); - Errors e = gaussianErrors(x0); - transposeMultiplyAdd(1.0, e, g); - return g; - } - - /* ************************************************************************* */ - namespace { - JacobianFactorUnordered::shared_ptr convertToJacobianFactorPtr(const GaussianFactorUnordered::shared_ptr &gf) { - JacobianFactorUnordered::shared_ptr result = boost::dynamic_pointer_cast(gf); - if( !result ) { - result = boost::make_shared(*gf); // Convert any non-Jacobian factors to Jacobians (e.g. Hessian -> Jacobian with Cholesky) - } - return result; - } - } - - /* ************************************************************************* */ - VectorValuesUnordered GaussianFactorGraphUnordered::gradientAtZero() const - { - // Zero-out the gradient - VectorValuesUnordered g; - Errors e; - BOOST_FOREACH(const sharedFactor& Ai_G, *this) { - JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - e.push_back(-Ai->getb()); - } - transposeMultiplyAdd(1.0, e, g); - return g; - } - - /* ************************************************************************* */ - bool hasConstraints(const GaussianFactorGraphUnordered& factors) { - typedef JacobianFactorUnordered J; - BOOST_FOREACH(const GaussianFactorUnordered::shared_ptr& factor, factors) { - J::shared_ptr jacobian(boost::dynamic_pointer_cast(factor)); - if (jacobian && jacobian->get_model()->isConstrained()) { - return true; - } - } - return false; - } - - /* ************************************************************************* */ - //GaussianFactorGraphUnordered::EliminationResult EliminatePreferCholesky( - // const FactorGraph& factors, size_t nrFrontals) { - - // // If any JacobianFactors have constrained noise models, we have to convert - // // all factors to JacobianFactors. Otherwise, we can convert all factors - // // to HessianFactors. This is because QR can handle constrained noise - // // models but Cholesky cannot. - // if (hasConstraints(factors)) - // return EliminateQR(factors, nrFrontals); - // else { - // GaussianFactorGraphUnordered::EliminationResult ret; - // gttic(EliminateCholesky); - // ret = EliminateCholesky(factors, nrFrontals); - // gttoc(EliminateCholesky); - // return ret; - // } - - //} // \EliminatePreferCholesky - - - - ///* ************************************************************************* */ - //Errors operator*(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered& x) { - // Errors e; - // BOOST_FOREACH(const GaussianFactorUnordered::shared_ptr& Ai_G, fg) { - // JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - // e.push_back((*Ai)*x); - // } - // return e; - //} - - ///* ************************************************************************* */ - //void multiplyInPlace(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered& x, Errors& e) { - // multiplyInPlace(fg,x,e.begin()); - //} - - ///* ************************************************************************* */ - //void multiplyInPlace(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered& x, const Errors::iterator& e) { - // Errors::iterator ei = e; - // BOOST_FOREACH(const GaussianFactorUnordered::shared_ptr& Ai_G, fg) { - // JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - // *ei = (*Ai)*x; - // ei++; - // } - //} - - /* ************************************************************************* */ - // x += alpha*A'*e - void GaussianFactorGraphUnordered::transposeMultiplyAdd(double alpha, const Errors& e, VectorValuesUnordered& x) const - { - // For each factor add the gradient contribution - Errors::const_iterator ei = e.begin(); - BOOST_FOREACH(const sharedFactor& Ai_G, *this) { - JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - Ai->transposeMultiplyAdd(alpha, *(ei++), x); - } - } - - ///* ************************************************************************* */ - //void residual(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered &x, VectorValuesUnordered &r) { - // Key i = 0 ; - // BOOST_FOREACH(const GaussianFactorUnordered::shared_ptr& Ai_G, fg) { - // JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - // r[i] = Ai->getb(); - // i++; - // } - // VectorValuesUnordered Ax = VectorValuesUnordered::SameStructure(r); - // multiply(fg,x,Ax); - // axpy(-1.0,Ax,r); - //} - - ///* ************************************************************************* */ - //void multiply(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered &x, VectorValuesUnordered &r) { - // r.setZero(); - // Key i = 0; - // BOOST_FOREACH(const GaussianFactorUnordered::shared_ptr& Ai_G, fg) { - // JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - // Vector &y = r[i]; - // for(JacobianFactorUnordered::const_iterator j = Ai->begin(); j != Ai->end(); ++j) { - // y += Ai->getA(j) * x[*j]; - // } - // ++i; - // } - //} - - /* ************************************************************************* */ - VectorValuesUnordered GaussianFactorGraphUnordered::transposeMultiply(const Errors& e) const - { - VectorValuesUnordered x; - Errors::const_iterator ei = e.begin(); - BOOST_FOREACH(const sharedFactor& Ai_G, *this) { - JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - for(JacobianFactorUnordered::const_iterator j = Ai->begin(); j != Ai->end(); ++j) { - // Create the value as a zero vector if it does not exist. - pair xi = x.tryInsert(*j, Vector()); - if(xi.second) - xi.first->second = Vector::Zero(Ai->getDim(j)); - xi.first->second += Ai->getA(j).transpose() * *ei; - } - ++ ei; - } - return x; - } - - /* ************************************************************************* */ - Errors GaussianFactorGraphUnordered::gaussianErrors(const VectorValuesUnordered& x) const - { - Errors e; - BOOST_FOREACH(const sharedFactor& Ai_G, *this) { - JacobianFactorUnordered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G); - e.push_back(Ai->error_vector(x)); - } - return e; - } - -} // namespace gtsam diff --git a/gtsam/linear/GaussianFactorGraphUnordered.h b/gtsam/linear/GaussianFactorGraphUnordered.h deleted file mode 100644 index 09d57f95a..000000000 --- a/gtsam/linear/GaussianFactorGraphUnordered.h +++ /dev/null @@ -1,343 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianFactorGraph.h - * @brief Linear Factor Graph where all factors are Gaussians - * @author Kai Ni - * @author Christian Potthast - * @author Alireza Fathi - * @author Richard Roberts - * @author Frank Dellaert - */ - -#pragma once - -#include -#include -#include -#include -#include // Included here instead of fw-declared so we can use Errors::iterator - -namespace gtsam { - - // Forward declarations - class GaussianFactorGraphUnordered; - class GaussianFactorUnordered; - class GaussianConditionalUnordered; - class GaussianBayesNetUnordered; - class GaussianEliminationTreeUnordered; - class GaussianBayesTreeUnordered; - class GaussianJunctionTreeUnordered; - - /* ************************************************************************* */ - template<> struct EliminationTraits - { - typedef GaussianFactorUnordered FactorType; ///< Type of factors in factor graph - typedef GaussianFactorGraphUnordered FactorGraphType; ///< Type of the factor graph (e.g. GaussianFactorGraph) - typedef GaussianConditionalUnordered ConditionalType; ///< Type of conditionals from elimination - typedef GaussianBayesNetUnordered BayesNetType; ///< Type of Bayes net from sequential elimination - typedef GaussianEliminationTreeUnordered EliminationTreeType; ///< Type of elimination tree - typedef GaussianBayesTreeUnordered BayesTreeType; ///< Type of Bayes tree - typedef GaussianJunctionTreeUnordered JunctionTreeType; ///< Type of Junction tree - /// The default dense elimination function - static std::pair, boost::shared_ptr > - DefaultEliminate(const FactorGraphType& factors, const OrderingUnordered& keys) { - return EliminateQRUnordered(factors, keys); } - }; - - /* ************************************************************************* */ - /** - * A Linear Factor Graph is a factor graph where all factors are Gaussian, i.e. - * Factor == GaussianFactor - * VectorValues = A values structure of vectors - * Most of the time, linear factor graphs arise by linearizing a non-linear factor graph. - */ - class GTSAM_EXPORT GaussianFactorGraphUnordered : - public FactorGraphUnordered, - public EliminateableFactorGraph - { - public: - - typedef GaussianFactorGraphUnordered This; ///< Typedef to this class - typedef FactorGraphUnordered Base; ///< Typedef to base factor graph type - typedef EliminateableFactorGraph BaseEliminateable; ///< Typedef to base elimination class - typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class - - /** Default constructor */ - GaussianFactorGraphUnordered() {} - - /** Construct from iterator over factors */ - template - GaussianFactorGraphUnordered(ITERATOR firstFactor, ITERATOR lastFactor) : Base(firstFactor, lastFactor) {} - - /** Construct from container of factors (shared_ptr or plain objects) */ - template - explicit GaussianFactorGraphUnordered(const CONTAINER& factors) : Base(factors) {} - - /** Implicit copy/downcast constructor to override explicit template container constructor */ - template - GaussianFactorGraphUnordered(const FactorGraphUnordered& graph) : Base(graph) {} - - /// @name Testable - /// @{ - - bool equals(const This& fg, double tol = 1e-9) const; - - /// @} - - /** Add a factor by value - makes a copy */ - void add(const GaussianFactorUnordered& factor) { factors_.push_back(factor.clone()); } - - /** Add a factor by pointer - stores pointer without copying the factor */ - void add(const sharedFactor& factor) { factors_.push_back(factor); } - - /** Add a null factor */ - void add(const Vector& b) { - add(JacobianFactorUnordered(b)); } - - /** Add a unary factor */ - void add(Key key1, const Matrix& A1, - const Vector& b, const SharedDiagonal& model) { - add(JacobianFactorUnordered(key1,A1,b,model)); } - - /** Add a binary factor */ - void add(Key key1, const Matrix& A1, - Key key2, const Matrix& A2, - const Vector& b, const SharedDiagonal& model) { - add(JacobianFactorUnordered(key1,A1,key2,A2,b,model)); } - - /** Add a ternary factor */ - void add(Key key1, const Matrix& A1, - Key key2, const Matrix& A2, - Key key3, const Matrix& A3, - const Vector& b, const SharedDiagonal& model) { - add(JacobianFactorUnordered(key1,A1,key2,A2,key3,A3,b,model)); } - - /** Add an n-ary factor */ - template - void add(const TERMS& terms, const Vector &b, const SharedDiagonal& model) { - add(JacobianFactorUnordered(terms,b,model)); } - - /** - * Return the set of variables involved in the factors (computes a set - * union). - */ - typedef FastSet Keys; - Keys keys() const; - - /** unnormalized error */ - double error(const VectorValuesUnordered& x) const { - double total_error = 0.; - BOOST_FOREACH(const sharedFactor& factor, *this) - total_error += factor->error(x); - return total_error; - } - - /** Unnormalized probability. O(n) */ - double probPrime(const VectorValuesUnordered& c) const { - return exp(-0.5 * error(c)); - } - - ///@name Linear Algebra - ///@{ - - /** - * Return vector of i, j, and s to generate an m-by-n sparse Jacobian matrix, - * where i(k) and j(k) are the base 0 row and column indices, s(k) a double. - * The standard deviations are baked into A and b - */ - std::vector > sparseJacobian() const; - - /** - * Matrix version of sparseJacobian: generates a 3*m matrix with [i,j,s] entries - * such that S(i(k),j(k)) = s(k), which can be given to MATLAB's sparse. - * The standard deviations are baked into A and b - */ - Matrix sparseJacobian_() const; - - /** - * Return a dense \f$ [ \;A\;b\; ] \in \mathbb{R}^{m \times n+1} \f$ - * Jacobian matrix, augmented with b with the noise models baked - * into A and b. The negative log-likelihood is - * \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also - * GaussianFactorGraph::jacobian and GaussianFactorGraph::sparseJacobian. - */ - Matrix augmentedJacobian() const; - - /** - * Return the dense Jacobian \f$ A \f$ and right-hand-side \f$ b \f$, - * with the noise models baked into A and b. The negative log-likelihood - * is \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also - * GaussianFactorGraph::augmentedJacobian and - * GaussianFactorGraph::sparseJacobian. - */ - std::pair jacobian() const; - - /** - * Return a dense \f$ \Lambda \in \mathbb{R}^{n+1 \times n+1} \f$ Hessian - * matrix, augmented with the information vector \f$ \eta \f$. The - * augmented Hessian is - \f[ \left[ \begin{array}{ccc} - \Lambda & \eta \\ - \eta^T & c - \end{array} \right] \f] - and the negative log-likelihood is - \f$ \frac{1}{2} x^T \Lambda x + \eta^T x + c \f$. - */ - //Matrix augmentedHessian() const; - - /** - * Return the dense Hessian \f$ \Lambda \f$ and information vector - * \f$ \eta \f$, with the noise models baked in. The negative log-likelihood - * is \frac{1}{2} x^T \Lambda x + \eta^T x + c. See also - * GaussianFactorGraph::augmentedHessian. - */ - //std::pair hessian() const; - - /** Solve the factor graph by performing multifrontal variable elimination in COLAMD order using - * the dense elimination function specified in \c function (default EliminatePreferCholesky), - * followed by back-substitution in the Bayes tree resulting from elimination. Is equivalent - * to calling graph.eliminateMultifrontal()->optimize(). */ - VectorValuesUnordered optimize(const Eliminate& function = EliminationTraits::DefaultEliminate) const; - - /** - * Compute the gradient of the energy function, - * \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$, - * centered around \f$ x = x_0 \f$. - * The gradient is \f$ A^T(Ax-b) \f$. - * @param fg The Jacobian factor graph $(A,b)$ - * @param x0 The center about which to compute the gradient - * @return The gradient as a VectorValuesUnordered - */ - VectorValuesUnordered gradient(const VectorValuesUnordered& x0) const; - - /** - * Compute the gradient of the energy function, \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} A x - b - * \right\Vert^2 \f$, centered around zero. The gradient is \f$ A^T(Ax-b) \f$. - * @param fg The Jacobian factor graph $(A,b)$ - * @param [output] g A VectorValuesUnordered to store the gradient, which must be preallocated, - * see allocateVectorValues - * @return The gradient as a VectorValuesUnordered */ - VectorValuesUnordered gradientAtZero() const; - - /** Optimize along the gradient direction, with a closed-form computation to perform the line - * search. The gradient is computed about \f$ \delta x=0 \f$. - * - * This function returns \f$ \delta x \f$ that minimizes a reparametrized problem. The error - * function of a GaussianBayesNet is - * - * \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + - * \frac{1}{2} \delta x^T R^T R \delta x \f] - * - * with gradient and Hessian - * - * \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f] - * - * This function performs the line search in the direction of the gradient evaluated at \f$ g = - * g(\delta x = 0) \f$ with step size \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) - * \f$: - * - * \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f] - * - * Optimizing by setting the derivative to zero yields \f$ \hat \alpha = (-g^T g) / (g^T G g) - * \f$. For efficiency, this function evaluates the denominator without computing the Hessian - * \f$ G \f$, returning - * - * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] */ - //VectorValuesUnordered optimizeGradientSearch() const; - - /** x = A'*e */ - VectorValuesUnordered transposeMultiply(const Errors& e) const; - - /** x += alpha*A'*e */ - void transposeMultiplyAdd(double alpha, const Errors& e, VectorValuesUnordered& x) const; - - /** return A*x-b */ - Errors gaussianErrors(const VectorValuesUnordered& x) const; - - /// @} - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); - } - - }; - - /** - * Evaluates whether linear factors have any constrained noise models - * @return true if any factor is constrained. - */ - GTSAM_EXPORT bool hasConstraints(const GaussianFactorGraphUnordered& factors); - - /** - * Densely partially eliminate with Cholesky factorization. JacobianFactors - * are left-multiplied with their transpose to form the Hessian using the - * conversion constructor HessianFactor(const JacobianFactor&). - * - * If any factors contain constrained noise models (any sigmas equal to - * zero), QR factorization will be performed instead, because our current - * implementation cannot handle constrained noise models in Cholesky - * factorization. EliminateCholesky(), on the other hand, will fail if any - * factors contain constrained noise models. - * - * Variables are eliminated in the natural order of the variable indices of in - * the factors. - * @param factors Factors to combine and eliminate - * @param nrFrontals Number of frontal variables to eliminate. - * @return The conditional and remaining factor - - * \addtogroup LinearSolving - */ - //GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminatePreferCholesky(const FactorGraph< - // GaussianFactor>& factors, size_t nrFrontals = 1); - - /** - * Densely partially eliminate with Cholesky factorization. JacobianFactors - * are left-multiplied with their transpose to form the Hessian using the - * conversion constructor HessianFactor(const JacobianFactor&). - * - * If any factors contain constrained noise models, this function will fail - * because our current implementation cannot handle constrained noise models - * in Cholesky factorization. The function EliminatePreferCholesky() - * automatically does QR instead when this is the case. - * - * Variables are eliminated in the natural order of the variable indices of in - * the factors. - * @param factors Factors to combine and eliminate - * @param nrFrontals Number of frontal variables to eliminate. - * @return The conditional and remaining factor - - * \addtogroup LinearSolving - */ - //GTSAM_EXPORT GaussianFactorGraph::EliminationResult EliminateCholesky(const FactorGraph< - // GaussianFactor>& factors, size_t nrFrontals = 1); - - /****** Linear Algebra Opeations ******/ - - ///** return A*x */ - //GTSAM_EXPORT Errors operator*(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered& x); - - ///** In-place version e <- A*x that overwrites e. */ - //GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered& x, Errors& e); - - ///** In-place version e <- A*x that takes an iterator. */ - //GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered& x, const Errors::iterator& e); - - ///* matrix-vector operations */ - //GTSAM_EXPORT void residual(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered &x, VectorValuesUnordered &r); - //GTSAM_EXPORT void multiply(const GaussianFactorGraphUnordered& fg, const VectorValuesUnordered &x, VectorValuesUnordered &r); - -} // namespace gtsam diff --git a/gtsam/linear/GaussianFactor.cpp b/gtsam/linear/GaussianFactorOrdered.cpp similarity index 75% rename from gtsam/linear/GaussianFactor.cpp rename to gtsam/linear/GaussianFactorOrdered.cpp index 1bf47ec51..d65410428 100644 --- a/gtsam/linear/GaussianFactor.cpp +++ b/gtsam/linear/GaussianFactorOrdered.cpp @@ -16,15 +16,15 @@ * @author Richard Roberts, Christian Potthast */ -#include -#include +#include +#include namespace gtsam { using namespace std; /* ************************************************************************* */ - GaussianFactor::GaussianFactor(const GaussianConditional& c) : - IndexFactor(c) {} + GaussianFactorOrdered::GaussianFactorOrdered(const GaussianConditionalOrdered& c) : + IndexFactorOrdered(c) {} } diff --git a/gtsam/linear/GaussianFactorOrdered.h b/gtsam/linear/GaussianFactorOrdered.h new file mode 100644 index 000000000..76f027281 --- /dev/null +++ b/gtsam/linear/GaussianFactorOrdered.h @@ -0,0 +1,156 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianFactor.h + * @brief A factor with a quadratic error function - a Gaussian + * @brief GaussianFactor + * @author Richard Roberts, Christian Potthast + */ + +// \callgraph + +#pragma once + +#include +#include + +#include + +#include +#include + +namespace gtsam { + + // Forward declarations + class VectorValuesOrdered; + class Permutation; + class GaussianConditionalOrdered; + template class BayesNetOrdered; + + /** + * An abstract virtual base class for JacobianFactor and HessianFactor. + * A GaussianFactor has a quadratic error function. + * GaussianFactor is non-mutable (all methods const!). + * The factor value is exp(-0.5*||Ax-b||^2) + */ + class GTSAM_EXPORT GaussianFactorOrdered: public IndexFactorOrdered { + + protected: + + /** Copy constructor */ + GaussianFactorOrdered(const This& f) : IndexFactorOrdered(f) {} + + /** Construct from derived type */ + GaussianFactorOrdered(const GaussianConditionalOrdered& c); + + /** Constructor from a collection of keys */ + template GaussianFactorOrdered(KeyIterator beginKey, KeyIterator endKey) : + Base(beginKey, endKey) {} + + /** Default constructor for I/O */ + GaussianFactorOrdered() {} + + /** Construct unary factor */ + GaussianFactorOrdered(Index j) : IndexFactorOrdered(j) {} + + /** Construct binary factor */ + GaussianFactorOrdered(Index j1, Index j2) : IndexFactorOrdered(j1, j2) {} + + /** Construct ternary factor */ + GaussianFactorOrdered(Index j1, Index j2, Index j3) : IndexFactorOrdered(j1, j2, j3) {} + + /** Construct 4-way factor */ + GaussianFactorOrdered(Index j1, Index j2, Index j3, Index j4) : IndexFactorOrdered(j1, j2, j3, j4) {} + + /** Construct n-way factor */ + GaussianFactorOrdered(const std::set& js) : IndexFactorOrdered(js) {} + + /** Construct n-way factor */ + GaussianFactorOrdered(const std::vector& js) : IndexFactorOrdered(js) {} + + public: + + typedef GaussianConditionalOrdered ConditionalType; + typedef boost::shared_ptr shared_ptr; + + // Implementing Testable interface + virtual void print(const std::string& s = "", + const IndexFormatter& formatter = DefaultIndexFormatter) const = 0; + + virtual bool equals(const GaussianFactorOrdered& lf, double tol = 1e-9) const = 0; + + virtual double error(const VectorValuesOrdered& c) const = 0; /** 0.5*(A*x-b)'*D*(A*x-b) */ + + /** Return the dimension of the variable pointed to by the given key iterator */ + virtual size_t getDim(const_iterator variable) const = 0; + + /** Return the augmented information matrix represented by this GaussianFactor. + * The augmented information matrix contains the information matrix with an + * additional column holding the information vector, and an additional row + * holding the transpose of the information vector. The lower-right entry + * contains the constant error term (when \f$ \delta x = 0 \f$). The + * augmented information matrix is described in more detail in HessianFactor, + * which in fact stores an augmented information matrix. + */ + virtual Matrix augmentedInformation() const = 0; + + /** Return the non-augmented information matrix represented by this + * GaussianFactor. + */ + virtual Matrix information() const = 0; + + /** Clone a factor (make a deep copy) */ + virtual GaussianFactorOrdered::shared_ptr clone() const = 0; + + /** + * Permutes the GaussianFactor, but for efficiency requires the permutation + * to already be inverted. This acts just as a change-of-name for each + * variable. The order of the variables within the factor is not changed. + */ + virtual void permuteWithInverse(const Permutation& inversePermutation) { + IndexFactorOrdered::permuteWithInverse(inversePermutation); + } + + /** + * Apply a reduction, which is a remapping of variable indices. + */ + virtual void reduceWithInverse(const internal::Reduction& inverseReduction) { + IndexFactorOrdered::reduceWithInverse(inverseReduction); + } + + /** + * Construct the corresponding anti-factor to negate information + * stored stored in this factor. + * @return a HessianFactor with negated Hessian matrices + */ + virtual GaussianFactorOrdered::shared_ptr negate() const = 0; + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(IndexFactorOrdered); + } + + }; // GaussianFactor + + /** make keys from list, vector, or map of matrices */ + template + static std::vector GetKeys(size_t n, ITERATOR begin, ITERATOR end) { + std::vector keys; + keys.reserve(n); + for (ITERATOR it=begin;it!=end;++it) keys.push_back(it->first); + return keys; + } + +} // namespace gtsam diff --git a/gtsam/linear/GaussianFactorUnordered.h b/gtsam/linear/GaussianFactorUnordered.h deleted file mode 100644 index 33de77054..000000000 --- a/gtsam/linear/GaussianFactorUnordered.h +++ /dev/null @@ -1,119 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file GaussianFactor.h - * @brief A factor with a quadratic error function - a Gaussian - * @brief GaussianFactor - * @author Richard Roberts, Christian Potthast - */ - -// \callgraph - -#pragma once - -#include -#include - -namespace gtsam { - - // Forward declarations - class VectorValuesUnordered; - - /** - * An abstract virtual base class for JacobianFactor and HessianFactor. A GaussianFactor has a - * quadratic error function. GaussianFactor is non-mutable (all methods const!). The factor value - * is exp(-0.5*||Ax-b||^2) */ - class GTSAM_EXPORT GaussianFactorUnordered : public FactorUnordered - { - public: - typedef GaussianFactorUnordered This; ///< This class - typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class - typedef FactorUnordered Base; ///< Our base class - - /** Default constructor creates empty factor */ - GaussianFactorUnordered() {} - - /** Construct from container of keys. This constructor is used internally from derived factor - * constructors, either from a container of keys or from a boost::assign::list_of. */ - template - GaussianFactorUnordered(const CONTAINER& keys) : Base(keys) {} - - // Implementing Testable interface - virtual void print(const std::string& s = "", - const IndexFormatter& formatter = DefaultIndexFormatter) const = 0; - - /** Equals for testable */ - virtual bool equals(const GaussianFactorUnordered& lf, double tol = 1e-9) const = 0; - - /** Print for testable */ - virtual double error(const VectorValuesUnordered& c) const = 0; /** 0.5*(A*x-b)'*D*(A*x-b) */ - - /** Return the dimension of the variable pointed to by the given key iterator */ - virtual size_t getDim(const_iterator variable) const = 0; - - /** - * Return a dense \f$ [ \;A\;b\; ] \in \mathbb{R}^{m \times n+1} \f$ - * Jacobian matrix, augmented with b with the noise models baked - * into A and b. The negative log-likelihood is - * \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also - * GaussianFactorGraph::jacobian and GaussianFactorGraph::sparseJacobian. - */ - virtual Matrix augmentedJacobian(bool weight = true) const = 0; - - /** - * Return the dense Jacobian \f$ A \f$ and right-hand-side \f$ b \f$, - * with the noise models baked into A and b. The negative log-likelihood - * is \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also - * GaussianFactorGraph::augmentedJacobian and - * GaussianFactorGraph::sparseJacobian. - */ - virtual std::pair jacobian(bool weight = true) const = 0; - - /** Return the augmented information matrix represented by this GaussianFactorUnordered. - * The augmented information matrix contains the information matrix with an - * additional column holding the information vector, and an additional row - * holding the transpose of the information vector. The lower-right entry - * contains the constant error term (when \f$ \delta x = 0 \f$). The - * augmented information matrix is described in more detail in HessianFactor, - * which in fact stores an augmented information matrix. - */ - virtual Matrix augmentedInformation() const = 0; - - /** Return the non-augmented information matrix represented by this - * GaussianFactorUnordered. - */ - virtual Matrix information() const = 0; - - /** Clone a factor (make a deep copy) */ - virtual GaussianFactorUnordered::shared_ptr clone() const = 0; - - /** Test whether the factor is empty */ - virtual bool empty() const = 0; - - /** - * Construct the corresponding anti-factor to negate information - * stored stored in this factor. - * @return a HessianFactor with negated Hessian matrices - */ - //virtual GaussianFactorUnordered::shared_ptr negate() const = 0; - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); - } - - }; // GaussianFactorUnordered - -} // namespace gtsam diff --git a/gtsam/linear/GaussianISAM.cpp b/gtsam/linear/GaussianISAMOrdered.cpp similarity index 55% rename from gtsam/linear/GaussianISAM.cpp rename to gtsam/linear/GaussianISAMOrdered.cpp index a358e5cab..0b8f3e1ef 100644 --- a/gtsam/linear/GaussianISAM.cpp +++ b/gtsam/linear/GaussianISAMOrdered.cpp @@ -15,10 +15,10 @@ * @author Michael Kaess */ -#include -#include +#include +#include -#include +#include using namespace std; using namespace gtsam; @@ -26,41 +26,41 @@ using namespace gtsam; namespace gtsam { // Explicitly instantiate so we don't have to include everywhere -template class ISAM; +template class ISAMOrdered; /* ************************************************************************* */ -GaussianFactor::shared_ptr GaussianISAM::marginalFactor(Index j) const { - return Super::marginalFactor(j, &EliminateQR); +GaussianFactorOrdered::shared_ptr GaussianISAMOrdered::marginalFactor(Index j) const { + return Super::marginalFactor(j, &EliminateQROrdered); } /* ************************************************************************* */ -BayesNet::shared_ptr GaussianISAM::marginalBayesNet(Index j) const { - return Super::marginalBayesNet(j, &EliminateQR); +BayesNetOrdered::shared_ptr GaussianISAMOrdered::marginalBayesNet(Index j) const { + return Super::marginalBayesNet(j, &EliminateQROrdered); } /* ************************************************************************* */ -Matrix GaussianISAM::marginalCovariance(Index j) const { - GaussianConditional::shared_ptr conditional = marginalBayesNet(j)->front(); +Matrix GaussianISAMOrdered::marginalCovariance(Index j) const { + GaussianConditionalOrdered::shared_ptr conditional = marginalBayesNet(j)->front(); return conditional->information().inverse(); } /* ************************************************************************* */ - BayesNet::shared_ptr GaussianISAM::jointBayesNet( + BayesNetOrdered::shared_ptr GaussianISAMOrdered::jointBayesNet( Index key1, Index key2) const { - return Super::jointBayesNet(key1, key2, &EliminateQR); + return Super::jointBayesNet(key1, key2, &EliminateQROrdered); } /* ************************************************************************* */ -VectorValues optimize(const GaussianISAM& isam) { - VectorValues result(isam.dims_); +VectorValuesOrdered optimize(const GaussianISAMOrdered& isam) { + VectorValuesOrdered result(isam.dims_); // Call optimize for BayesTree - optimizeInPlace((const BayesTree&)isam, result); + optimizeInPlace((const BayesTreeOrdered&)isam, result); return result; } /* ************************************************************************* */ -BayesNet GaussianISAM::shortcut(sharedClique clique, sharedClique root) { - return clique->shortcut(root,&EliminateQR); +BayesNetOrdered GaussianISAMOrdered::shortcut(sharedClique clique, sharedClique root) { + return clique->shortcut(root,&EliminateQROrdered); } /* ************************************************************************* */ diff --git a/gtsam/linear/GaussianISAM.h b/gtsam/linear/GaussianISAMOrdered.h similarity index 66% rename from gtsam/linear/GaussianISAM.h rename to gtsam/linear/GaussianISAMOrdered.h index fcee326e4..1434b6503 100644 --- a/gtsam/linear/GaussianISAM.h +++ b/gtsam/linear/GaussianISAMOrdered.h @@ -21,15 +21,15 @@ #include -#include -#include -#include +#include +#include +#include namespace gtsam { -class GaussianISAM : public ISAM { +class GaussianISAMOrdered : public ISAMOrdered { - typedef ISAM Super; + typedef ISAMOrdered Super; std::vector dims_; public: @@ -37,18 +37,18 @@ public: typedef std::vector Dims; /** Create an empty Bayes Tree */ - GaussianISAM() : Super() {} + GaussianISAMOrdered() : Super() {} /** Create a Bayes Tree from a Bayes Net */ // GaussianISAM(const GaussianBayesNet& bayesNet) : Super(bayesNet) {} - GaussianISAM(const BayesTree& bayesTree) : Super(bayesTree) { - GaussianJunctionTree::countDims(bayesTree, dims_); + GaussianISAMOrdered(const BayesTreeOrdered& bayesTree) : Super(bayesTree) { + GaussianJunctionTreeOrdered::countDims(bayesTree, dims_); } /** Override update_internal to also keep track of variable dimensions. */ template void update_internal(const FACTORGRAPH& newFactors, Cliques& orphans) { - Super::update_internal(newFactors, orphans, &EliminateQR); // TODO: why does this force QR? + Super::update_internal(newFactors, orphans, &EliminateQROrdered); // TODO: why does this force QR? update_dimensions(newFactors); } @@ -81,22 +81,22 @@ public: const Dims& dims() const { return dims_; } ///< Const access to dimensions structure Dims& dims() { return dims_; } ///< non-const access to dimensions structure (advanced interface) - GTSAM_EXPORT friend VectorValues optimize(const GaussianISAM&); + GTSAM_EXPORT friend VectorValuesOrdered optimize(const GaussianISAMOrdered&); /** return marginal on any variable as a factor, Bayes net, or mean/cov */ - GTSAM_EXPORT GaussianFactor::shared_ptr marginalFactor(Index j) const; - GTSAM_EXPORT BayesNet::shared_ptr marginalBayesNet(Index key) const; + GTSAM_EXPORT GaussianFactorOrdered::shared_ptr marginalFactor(Index j) const; + GTSAM_EXPORT BayesNetOrdered::shared_ptr marginalBayesNet(Index key) const; GTSAM_EXPORT Matrix marginalCovariance(Index key) const; /** return joint between two variables, as a Bayes net */ - GTSAM_EXPORT BayesNet::shared_ptr jointBayesNet(Index key1, Index key2) const; + GTSAM_EXPORT BayesNetOrdered::shared_ptr jointBayesNet(Index key1, Index key2) const; /** return the conditional P(S|Root) on the separator given the root */ - GTSAM_EXPORT static BayesNet shortcut(sharedClique clique, sharedClique root); + GTSAM_EXPORT static BayesNetOrdered shortcut(sharedClique clique, sharedClique root); }; // \class GaussianISAM // optimize the BayesTree, starting from the root -GTSAM_EXPORT VectorValues optimize(const GaussianISAM& isam); +GTSAM_EXPORT VectorValuesOrdered optimize(const GaussianISAMOrdered& isam); } // \namespace gtsam diff --git a/gtsam/linear/GaussianJunctionTree.cpp b/gtsam/linear/GaussianJunctionTree.cpp index 381c35e3f..10cf8e11f 100644 --- a/gtsam/linear/GaussianJunctionTree.cpp +++ b/gtsam/linear/GaussianJunctionTree.cpp @@ -11,49 +11,31 @@ /** * @file GaussianJunctionTree.cpp - * @date Jul 12, 2010 - * @author Kai Ni + * @date Mar 29, 2013 * @author Frank Dellaert - * @brief: the Gaussian junction tree + * @author Richard Roberts */ -#include -#include +#include #include -#include - -#include - -#include +#include namespace gtsam { - // explicit template instantiation - template class JunctionTree; - template class ClusterTree; - - using namespace std; + /* ************************************************************************* */ + GaussianJunctionTree::GaussianJunctionTree( + const GaussianEliminationTree& eliminationTree) : + Base(Base::FromEliminationTree(eliminationTree)) {} /* ************************************************************************* */ - VectorValues GaussianJunctionTree::optimize(Eliminate function) const { - gttic(GJT_eliminate); - // eliminate from leaves to the root - BTClique::shared_ptr rootClique(this->eliminate(function)); - gttoc(GJT_eliminate); + GaussianJunctionTree::GaussianJunctionTree(const This& other) : + Base(other) {} - // Allocate solution vector and copy RHS - gttic(allocate_VectorValues); - vector dims(rootClique->conditional()->back()+1, 0); - countDims(rootClique, dims); - VectorValues result(dims); - gttoc(allocate_VectorValues); - - // back-substitution - gttic(backsubstitute); - internal::optimizeInPlace(rootClique, result); - gttoc(backsubstitute); - return result; + /* ************************************************************************* */ + GaussianJunctionTree& GaussianJunctionTree::operator=(const This& other) + { + (void) Base::operator=(other); + return *this; } - /* ************************************************************************* */ -} //namespace gtsam +} diff --git a/gtsam/linear/GaussianJunctionTree.h b/gtsam/linear/GaussianJunctionTree.h index ba67e6002..8ccb07f42 100644 --- a/gtsam/linear/GaussianJunctionTree.h +++ b/gtsam/linear/GaussianJunctionTree.h @@ -11,78 +11,64 @@ /** * @file GaussianJunctionTree.h - * @date Jul 12, 2010 - * @author Kai Ni + * @date Mar 29, 2013 * @author Frank Dellaert - * @brief: the Gaussian junction tree + * @author Richard Roberts */ -#pragma once - -#include -#include -#include -#include #include +#include +#include namespace gtsam { + // Forward declarations + class GaussianEliminationTree; + /** - * A JunctionTree where all the factors are of type GaussianFactor. + * A ClusterTree, i.e., a set of variable clusters with factors, arranged in a tree, with + * the additional property that it represents the clique tree associated with a Bayes net. * - * In GTSAM, typically, a GaussianJunctionTree is created directly from a GaussianFactorGraph, - * after which you call optimize() to solve for the mean, or JunctionTree::eliminate() to - * create a BayesTree. In both cases, you need to provide a basic - * GaussianFactorGraph::Eliminate function that will be used to + * In GTSAM a junction tree is an intermediate data structure in multifrontal + * variable elimination. Each node is a cluster of factors, along with a + * clique of variables that are eliminated all at once. In detail, every node k represents + * a clique (maximal fully connected subset) of an associated chordal graph, such as a + * chordal Bayes net resulting from elimination. + * + * The difference with the BayesTree is that a JunctionTree stores factors, whereas a + * BayesTree stores conditionals, that are the product of eliminating the factors in the + * corresponding JunctionTree cliques. + * + * The tree structure and elimination method are exactly analagous to the EliminationTree, + * except that in the JunctionTree, at each node multiple variables are eliminated at a time. * * \addtogroup Multifrontal + * \nosubgrouping */ - class GaussianJunctionTree: public JunctionTree { - + class GTSAM_EXPORT GaussianJunctionTree : + public JunctionTree { public: - typedef boost::shared_ptr shared_ptr; - typedef JunctionTree Base; - typedef Base::sharedClique sharedClique; - typedef GaussianFactorGraph::Eliminate Eliminate; - - public : - - /** Default constructor */ - GaussianJunctionTree() : Base() {} - - /** 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) {} - + typedef JunctionTree Base; ///< Base class + typedef GaussianJunctionTree This; ///< This class + typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class + /** - * optimize the linear graph - */ - GTSAM_EXPORT VectorValues optimize(Eliminate function) const; + * Build the elimination tree of a factor graph using pre-computed column structure. + * @param factorGraph The factor graph for which to build the elimination tree + * @param structure The set of factors involving each variable. If this is not + * precomputed, you can call the Create(const FactorGraph&) + * named constructor instead. + * @return The elimination tree + */ + GaussianJunctionTree(const GaussianEliminationTree& eliminationTree); - // convenient function to return dimensions of all variables in the BayesTree - template - static void countDims(const BayesTree& bayesTree, DIM_CONTAINER& dims) { - dims = DIM_CONTAINER(bayesTree.root()->conditional()->back()+1, 0); - countDims(bayesTree.root(), dims); - } + /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are + * copied, factors are not cloned. */ + GaussianJunctionTree(const This& other); - private: - template - static void countDims(const boost::shared_ptr& clique, DIM_CONTAINER& dims) { - GaussianConditional::const_iterator it = clique->conditional()->beginFrontals(); - for (; it != clique->conditional()->endFrontals(); ++it) { - assert(dims.at(*it) == 0); - dims.at(*it) = clique->conditional()->dim(it); - } + /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors are + * copied, factors are not cloned. */ + This& operator=(const This& other); + }; - BOOST_FOREACH(const typename CLIQUE::shared_ptr& child, clique->children()) { - countDims(child, dims); - } - } - - }; // GaussianJunctionTree - -} // namespace gtsam +} diff --git a/gtsam/linear/GaussianJunctionTreeOrdered.cpp b/gtsam/linear/GaussianJunctionTreeOrdered.cpp new file mode 100644 index 000000000..ed928462c --- /dev/null +++ b/gtsam/linear/GaussianJunctionTreeOrdered.cpp @@ -0,0 +1,59 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianJunctionTree.cpp + * @date Jul 12, 2010 + * @author Kai Ni + * @author Frank Dellaert + * @brief: the Gaussian junction tree + */ + +#include +#include +#include +#include + +#include + +#include + +namespace gtsam { + + // explicit template instantiation + template class JunctionTreeOrdered; + template class ClusterTreeOrdered; + + using namespace std; + + /* ************************************************************************* */ + VectorValuesOrdered GaussianJunctionTreeOrdered::optimize(Eliminate function) const { + gttic(GJT_eliminate); + // eliminate from leaves to the root + BTClique::shared_ptr rootClique(this->eliminate(function)); + gttoc(GJT_eliminate); + + // Allocate solution vector and copy RHS + gttic(allocate_VectorValues); + vector dims(rootClique->conditional()->back()+1, 0); + countDims(rootClique, dims); + VectorValuesOrdered result(dims); + gttoc(allocate_VectorValues); + + // back-substitution + gttic(backsubstitute); + internal::optimizeInPlace(rootClique, result); + gttoc(backsubstitute); + return result; + } + + /* ************************************************************************* */ +} //namespace gtsam diff --git a/gtsam/linear/GaussianJunctionTreeOrdered.h b/gtsam/linear/GaussianJunctionTreeOrdered.h new file mode 100644 index 000000000..0360513e3 --- /dev/null +++ b/gtsam/linear/GaussianJunctionTreeOrdered.h @@ -0,0 +1,88 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GaussianJunctionTree.h + * @date Jul 12, 2010 + * @author Kai Ni + * @author Frank Dellaert + * @brief: the Gaussian junction tree + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace gtsam { + + /** + * A JunctionTree where all the factors are of type GaussianFactor. + * + * In GTSAM, typically, a GaussianJunctionTree is created directly from a GaussianFactorGraph, + * after which you call optimize() to solve for the mean, or JunctionTree::eliminate() to + * create a BayesTree. In both cases, you need to provide a basic + * GaussianFactorGraph::Eliminate function that will be used to + * + * \addtogroup Multifrontal + */ + class GaussianJunctionTreeOrdered: public JunctionTreeOrdered { + + public: + typedef boost::shared_ptr shared_ptr; + typedef JunctionTreeOrdered Base; + typedef Base::sharedClique sharedClique; + typedef GaussianFactorGraphOrdered::Eliminate Eliminate; + + public : + + /** Default constructor */ + GaussianJunctionTreeOrdered() : Base() {} + + /** Constructor from a factor graph. Builds a VariableIndex. */ + GaussianJunctionTreeOrdered(const GaussianFactorGraphOrdered& fg) : Base(fg) {} + + /** Construct from a factor graph and a pre-computed variable index. */ + GaussianJunctionTreeOrdered(const GaussianFactorGraphOrdered& fg, const VariableIndexOrdered& variableIndex) + : Base(fg, variableIndex) {} + + /** + * optimize the linear graph + */ + GTSAM_EXPORT VectorValuesOrdered optimize(Eliminate function) const; + + // convenient function to return dimensions of all variables in the BayesTree + template + static void countDims(const BayesTreeOrdered& bayesTree, DIM_CONTAINER& dims) { + dims = DIM_CONTAINER(bayesTree.root()->conditional()->back()+1, 0); + countDims(bayesTree.root(), dims); + } + + private: + template + static void countDims(const boost::shared_ptr& clique, DIM_CONTAINER& dims) { + GaussianConditionalOrdered::const_iterator it = clique->conditional()->beginFrontals(); + for (; it != clique->conditional()->endFrontals(); ++it) { + assert(dims.at(*it) == 0); + dims.at(*it) = clique->conditional()->dim(it); + } + + BOOST_FOREACH(const typename CLIQUE::shared_ptr& child, clique->children()) { + countDims(child, dims); + } + } + + }; // GaussianJunctionTree + +} // namespace gtsam diff --git a/gtsam/linear/GaussianMultifrontalSolver.cpp b/gtsam/linear/GaussianMultifrontalSolver.cpp index 22d352f2c..26da08ecd 100644 --- a/gtsam/linear/GaussianMultifrontalSolver.cpp +++ b/gtsam/linear/GaussianMultifrontalSolver.cpp @@ -20,71 +20,71 @@ namespace gtsam { /* ************************************************************************* */ -GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraph& factorGraph, bool useQR) : +GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraphOrdered& factorGraph, bool useQR) : Base(factorGraph), useQR_(useQR) {} /* ************************************************************************* */ -GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR) : +GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) : Base(factorGraph, variableIndex), useQR_(useQR) {} /* ************************************************************************* */ GaussianMultifrontalSolver::shared_ptr -GaussianMultifrontalSolver::Create(const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR) { +GaussianMultifrontalSolver::Create(const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) { return shared_ptr(new GaussianMultifrontalSolver(factorGraph, variableIndex, useQR)); } /* ************************************************************************* */ -void GaussianMultifrontalSolver::replaceFactors(const FactorGraph::shared_ptr& factorGraph) { +void GaussianMultifrontalSolver::replaceFactors(const FactorGraphOrdered::shared_ptr& factorGraph) { Base::replaceFactors(factorGraph); } /* ************************************************************************* */ -GaussianBayesTree::shared_ptr GaussianMultifrontalSolver::eliminate() const { +GaussianBayesTreeOrdered::shared_ptr GaussianMultifrontalSolver::eliminate() const { if (useQR_) - return Base::eliminate(&EliminateQR); + return Base::eliminate(&EliminateQROrdered); else - return Base::eliminate(&EliminatePreferCholesky); + return Base::eliminate(&EliminatePreferCholeskyOrdered); } /* ************************************************************************* */ -VectorValues::shared_ptr GaussianMultifrontalSolver::optimize() const { +VectorValuesOrdered::shared_ptr GaussianMultifrontalSolver::optimize() const { gttic(GaussianMultifrontalSolver_optimize); - VectorValues::shared_ptr values; + VectorValuesOrdered::shared_ptr values; if (useQR_) - values = VectorValues::shared_ptr(new VectorValues(junctionTree_->optimize(&EliminateQR))); + values = VectorValuesOrdered::shared_ptr(new VectorValuesOrdered(junctionTree_->optimize(&EliminateQROrdered))); else - values= VectorValues::shared_ptr(new VectorValues(junctionTree_->optimize(&EliminatePreferCholesky))); + values= VectorValuesOrdered::shared_ptr(new VectorValuesOrdered(junctionTree_->optimize(&EliminatePreferCholeskyOrdered))); return values; } /* ************************************************************************* */ -GaussianFactorGraph::shared_ptr GaussianMultifrontalSolver::jointFactorGraph(const std::vector& js) const { +GaussianFactorGraphOrdered::shared_ptr GaussianMultifrontalSolver::jointFactorGraph(const std::vector& js) const { if (useQR_) - return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph(*Base::jointFactorGraph(js,&EliminateQR))); + return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered(*Base::jointFactorGraph(js,&EliminateQROrdered))); else - return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph(*Base::jointFactorGraph(js,&EliminatePreferCholesky))); + return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered(*Base::jointFactorGraph(js,&EliminatePreferCholeskyOrdered))); } /* ************************************************************************* */ -GaussianFactor::shared_ptr GaussianMultifrontalSolver::marginalFactor(Index j) const { +GaussianFactorOrdered::shared_ptr GaussianMultifrontalSolver::marginalFactor(Index j) const { if (useQR_) - return Base::marginalFactor(j,&EliminateQR); + return Base::marginalFactor(j,&EliminateQROrdered); else - return Base::marginalFactor(j,&EliminatePreferCholesky); + return Base::marginalFactor(j,&EliminatePreferCholeskyOrdered); } /* ************************************************************************* */ Matrix GaussianMultifrontalSolver::marginalCovariance(Index j) const { - FactorGraph fg; - GaussianConditional::shared_ptr conditional; + FactorGraphOrdered fg; + GaussianConditionalOrdered::shared_ptr conditional; if (useQR_) { - fg.push_back(Base::marginalFactor(j,&EliminateQR)); - conditional = EliminateQR(fg,1).first; + fg.push_back(Base::marginalFactor(j,&EliminateQROrdered)); + conditional = EliminateQROrdered(fg,1).first; } else { - fg.push_back(Base::marginalFactor(j,&EliminatePreferCholesky)); - conditional = EliminatePreferCholesky(fg,1).first; + fg.push_back(Base::marginalFactor(j,&EliminatePreferCholeskyOrdered)); + conditional = EliminatePreferCholeskyOrdered(fg,1).first; } return conditional->information().inverse(); } diff --git a/gtsam/linear/GaussianMultifrontalSolver.h b/gtsam/linear/GaussianMultifrontalSolver.h index 97f3de67c..4b7460773 100644 --- a/gtsam/linear/GaussianMultifrontalSolver.h +++ b/gtsam/linear/GaussianMultifrontalSolver.h @@ -18,9 +18,9 @@ #pragma once #include -#include -#include -#include +#include +#include +#include #include @@ -41,11 +41,11 @@ namespace gtsam { * The JunctionTree recursively produces a BayesTree, * on which this class calls optimize(...) to perform back-substitution. */ -class GaussianMultifrontalSolver : GenericMultifrontalSolver { +class GaussianMultifrontalSolver : GenericMultifrontalSolver { protected: - typedef GenericMultifrontalSolver Base; + typedef GenericMultifrontalSolver Base; typedef boost::shared_ptr shared_ptr; /** flag to determine whether to use Cholesky or QR */ @@ -57,22 +57,22 @@ public: * Construct the solver for a factor graph. This builds the junction * tree, which already does some of the work of elimination. */ - GTSAM_EXPORT GaussianMultifrontalSolver(const FactorGraph& factorGraph, bool useQR = false); + GTSAM_EXPORT GaussianMultifrontalSolver(const FactorGraphOrdered& factorGraph, bool useQR = false); /** * 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. */ - GTSAM_EXPORT GaussianMultifrontalSolver(const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR = false); + GTSAM_EXPORT GaussianMultifrontalSolver(const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false); /** * Named constructor to return a shared_ptr. This builds the elimination * tree, which already does some of the symbolic work of elimination. */ - GTSAM_EXPORT static shared_ptr Create(const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR = false); + GTSAM_EXPORT static shared_ptr Create(const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false); /** * Return a new solver that solves the given factor graph, which must have @@ -81,20 +81,20 @@ public: * used in cases where the numerical values of the linear problem change, * e.g. during iterative nonlinear optimization. */ - GTSAM_EXPORT void replaceFactors(const FactorGraph::shared_ptr& factorGraph); + GTSAM_EXPORT void replaceFactors(const FactorGraphOrdered::shared_ptr& factorGraph); /** * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. */ - GTSAM_EXPORT GaussianBayesTree::shared_ptr eliminate() const; + GTSAM_EXPORT GaussianBayesTreeOrdered::shared_ptr eliminate() const; /** * Compute the least-squares solution of the GaussianFactorGraph. This * eliminates to create a BayesNet and then back-substitutes this BayesNet to * obtain the solution. */ - GTSAM_EXPORT VectorValues::shared_ptr optimize() const; + GTSAM_EXPORT VectorValuesOrdered::shared_ptr optimize() const; /** * Compute the marginal joint over a set of variables, by integrating out @@ -103,7 +103,7 @@ public: * * NOTE: This function is limited to computing a joint on 2 variables */ - GTSAM_EXPORT GaussianFactorGraph::shared_ptr jointFactorGraph(const std::vector& js) const; + GTSAM_EXPORT GaussianFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector& js) const; /** * Compute the marginal Gaussian density over a variable, by integrating out @@ -111,7 +111,7 @@ public: * triangular R factor and right-hand-side, i.e. a GaussianConditional with * R*x = d. To get a mean and covariance matrix, use marginalStandard(...) */ - GTSAM_EXPORT GaussianFactor::shared_ptr marginalFactor(Index j) const; + GTSAM_EXPORT GaussianFactorOrdered::shared_ptr marginalFactor(Index j) const; /** * Compute the marginal Gaussian density over a variable, by integrating out diff --git a/gtsam/linear/GaussianSequentialSolver.cpp b/gtsam/linear/GaussianSequentialSolver.cpp index 75a8c3871..85012d62f 100644 --- a/gtsam/linear/GaussianSequentialSolver.cpp +++ b/gtsam/linear/GaussianSequentialSolver.cpp @@ -22,41 +22,41 @@ namespace gtsam { /* ************************************************************************* */ GaussianSequentialSolver::GaussianSequentialSolver( - const FactorGraph& factorGraph, bool useQR) : + const FactorGraphOrdered& factorGraph, bool useQR) : Base(factorGraph), useQR_(useQR) { } /* ************************************************************************* */ GaussianSequentialSolver::GaussianSequentialSolver( - const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR) : + const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) : Base(factorGraph, variableIndex), useQR_(useQR) { } /* ************************************************************************* */ GaussianSequentialSolver::shared_ptr GaussianSequentialSolver::Create( - const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR) { + const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) { return shared_ptr( new GaussianSequentialSolver(factorGraph, variableIndex, useQR)); } /* ************************************************************************* */ void GaussianSequentialSolver::replaceFactors( - const FactorGraph::shared_ptr& factorGraph) { + const FactorGraphOrdered::shared_ptr& factorGraph) { Base::replaceFactors(factorGraph); } /* ************************************************************************* */ -GaussianBayesNet::shared_ptr GaussianSequentialSolver::eliminate() const { +GaussianBayesNetOrdered::shared_ptr GaussianSequentialSolver::eliminate() const { if (useQR_) - return Base::eliminate(&EliminateQR); + return Base::eliminate(&EliminateQROrdered); else - return Base::eliminate(&EliminatePreferCholesky); + return Base::eliminate(&EliminatePreferCholeskyOrdered); } /* ************************************************************************* */ -VectorValues::shared_ptr GaussianSequentialSolver::optimize() const { +VectorValuesOrdered::shared_ptr GaussianSequentialSolver::optimize() const { static const bool debug = false; @@ -65,18 +65,18 @@ VectorValues::shared_ptr GaussianSequentialSolver::optimize() const { gttic(eliminate); // Eliminate using the elimination tree - GaussianBayesNet::shared_ptr bayesNet(this->eliminate()); + GaussianBayesNetOrdered::shared_ptr bayesNet(this->eliminate()); gttoc(eliminate); if(debug) bayesNet->print("GaussianSequentialSolver, Bayes net "); // Allocate the solution vector if it is not already allocated -// VectorValues::shared_ptr solution = allocateVectorValues(*bayesNet); +// VectorValuesOrdered::shared_ptr solution = allocateVectorValues(*bayesNet); gttic(optimize); // Back-substitute - VectorValues::shared_ptr solution( - new VectorValues(gtsam::optimize(*bayesNet))); + VectorValuesOrdered::shared_ptr solution( + new VectorValuesOrdered(gtsam::optimize(*bayesNet))); gttoc(optimize); if(debug) solution->print("GaussianSequentialSolver, solution "); @@ -85,36 +85,36 @@ VectorValues::shared_ptr GaussianSequentialSolver::optimize() const { } /* ************************************************************************* */ -GaussianFactor::shared_ptr GaussianSequentialSolver::marginalFactor(Index j) const { +GaussianFactorOrdered::shared_ptr GaussianSequentialSolver::marginalFactor(Index j) const { if (useQR_) - return Base::marginalFactor(j,&EliminateQR); + return Base::marginalFactor(j,&EliminateQROrdered); else - return Base::marginalFactor(j,&EliminatePreferCholesky); + return Base::marginalFactor(j,&EliminatePreferCholeskyOrdered); } /* ************************************************************************* */ Matrix GaussianSequentialSolver::marginalCovariance(Index j) const { - FactorGraph fg; - GaussianConditional::shared_ptr conditional; + FactorGraphOrdered fg; + GaussianConditionalOrdered::shared_ptr conditional; if (useQR_) { - fg.push_back(Base::marginalFactor(j, &EliminateQR)); - conditional = EliminateQR(fg, 1).first; + fg.push_back(Base::marginalFactor(j, &EliminateQROrdered)); + conditional = EliminateQROrdered(fg, 1).first; } else { - fg.push_back(Base::marginalFactor(j, &EliminatePreferCholesky)); - conditional = EliminatePreferCholesky(fg, 1).first; + fg.push_back(Base::marginalFactor(j, &EliminatePreferCholeskyOrdered)); + conditional = EliminatePreferCholeskyOrdered(fg, 1).first; } return conditional->information().inverse(); } /* ************************************************************************* */ -GaussianFactorGraph::shared_ptr +GaussianFactorGraphOrdered::shared_ptr GaussianSequentialSolver::jointFactorGraph(const std::vector& js) const { if (useQR_) - return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph( - *Base::jointFactorGraph(js, &EliminateQR))); + return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered( + *Base::jointFactorGraph(js, &EliminateQROrdered))); else - return GaussianFactorGraph::shared_ptr(new GaussianFactorGraph( - *Base::jointFactorGraph(js, &EliminatePreferCholesky))); + return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered( + *Base::jointFactorGraph(js, &EliminatePreferCholeskyOrdered))); } } /// namespace gtsam diff --git a/gtsam/linear/GaussianSequentialSolver.h b/gtsam/linear/GaussianSequentialSolver.h index c3c54154e..ec236c49c 100644 --- a/gtsam/linear/GaussianSequentialSolver.h +++ b/gtsam/linear/GaussianSequentialSolver.h @@ -19,8 +19,8 @@ #pragma once #include -#include -#include +#include +#include #include @@ -47,11 +47,11 @@ namespace gtsam { * typedef'ed in linear/GaussianBayesNet, on which this class calls * optimize(...) to perform back-substitution. */ -class GaussianSequentialSolver : GenericSequentialSolver { +class GaussianSequentialSolver : GenericSequentialSolver { protected: - typedef GenericSequentialSolver Base; + typedef GenericSequentialSolver Base; typedef boost::shared_ptr shared_ptr; /** flag to determine whether to use Cholesky or QR */ @@ -63,22 +63,22 @@ public: * Construct the solver for a factor graph. This builds the elimination * tree, which already does some of the work of elimination. */ - GTSAM_EXPORT GaussianSequentialSolver(const FactorGraph& factorGraph, bool useQR = false); + GTSAM_EXPORT GaussianSequentialSolver(const FactorGraphOrdered& factorGraph, bool useQR = false); /** * 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. */ - GTSAM_EXPORT GaussianSequentialSolver(const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR = false); + GTSAM_EXPORT GaussianSequentialSolver(const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false); /** * Named constructor to return a shared_ptr. This builds the elimination * tree, which already does some of the symbolic work of elimination. */ - GTSAM_EXPORT static shared_ptr Create(const FactorGraph::shared_ptr& factorGraph, - const VariableIndex::shared_ptr& variableIndex, bool useQR = false); + GTSAM_EXPORT static shared_ptr Create(const FactorGraphOrdered::shared_ptr& factorGraph, + const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false); /** * Return a new solver that solves the given factor graph, which must have @@ -87,20 +87,20 @@ public: * used in cases where the numerical values of the linear problem change, * e.g. during iterative nonlinear optimization. */ - GTSAM_EXPORT void replaceFactors(const FactorGraph::shared_ptr& factorGraph); + GTSAM_EXPORT void replaceFactors(const FactorGraphOrdered::shared_ptr& factorGraph); /** * Eliminate the factor graph sequentially. Uses a column elimination tree * to recursively eliminate. */ - GTSAM_EXPORT GaussianBayesNet::shared_ptr eliminate() const; + GTSAM_EXPORT GaussianBayesNetOrdered::shared_ptr eliminate() const; /** * Compute the least-squares solution of the GaussianFactorGraph. This * eliminates to create a BayesNet and then back-substitutes this BayesNet to * obtain the solution. */ - GTSAM_EXPORT VectorValues::shared_ptr optimize() const; + GTSAM_EXPORT VectorValuesOrdered::shared_ptr optimize() const; /** * Compute the marginal Gaussian density over a variable, by integrating out @@ -108,7 +108,7 @@ public: * triangular R factor and right-hand-side, i.e. a GaussianConditional with * R*x = d. To get a mean and covariance matrix, use marginalStandard(...) */ - GTSAM_EXPORT GaussianFactor::shared_ptr marginalFactor(Index j) const; + GTSAM_EXPORT GaussianFactorOrdered::shared_ptr marginalFactor(Index j) const; /** * Compute the marginal Gaussian density over a variable, by integrating out @@ -125,7 +125,7 @@ public: * triangular R factor and right-hand-side, i.e. a GaussianBayesNet with * R*x = d. To get a mean and covariance matrix, use jointStandard(...) */ - GTSAM_EXPORT GaussianFactorGraph::shared_ptr jointFactorGraph(const std::vector& js) const; + GTSAM_EXPORT GaussianFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector& js) const; }; diff --git a/gtsam/linear/HessianFactor.cpp b/gtsam/linear/HessianFactorOrdered.cpp similarity index 84% rename from gtsam/linear/HessianFactor.cpp rename to gtsam/linear/HessianFactorOrdered.cpp index 385ed2394..1929e2a53 100644 --- a/gtsam/linear/HessianFactor.cpp +++ b/gtsam/linear/HessianFactorOrdered.cpp @@ -36,11 +36,11 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include using namespace std; @@ -54,38 +54,38 @@ string SlotEntry::toString() const { } /* ************************************************************************* */ -Scatter::Scatter(const FactorGraph& gfg) { - // First do the set union. - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, gfg) { - if(factor) { - for(GaussianFactor::const_iterator variable = factor->begin(); variable != factor->end(); ++variable) { - this->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(value_type& var_slot, *this) { - var_slot.second.slot = (slot ++); - } +Scatter::Scatter(const FactorGraphOrdered& gfg) { + // First do the set union. + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, gfg) { + if(factor) { + for(GaussianFactorOrdered::const_iterator variable = factor->begin(); variable != factor->end(); ++variable) { + this->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(value_type& var_slot, *this) { + var_slot.second.slot = (slot ++); + } } /* ************************************************************************* */ -void HessianFactor::assertInvariants() const { - GaussianFactor::assertInvariants(); // The base class checks for unique keys +void HessianFactorOrdered::assertInvariants() const { + GaussianFactorOrdered::assertInvariants(); // The base class checks for unique keys } /* ************************************************************************* */ -HessianFactor::HessianFactor(const HessianFactor& gf) : - GaussianFactor(gf), info_(matrix_) { +HessianFactorOrdered::HessianFactorOrdered(const HessianFactorOrdered& gf) : + GaussianFactorOrdered(gf), info_(matrix_) { info_.assignNoalias(gf.info_); assertInvariants(); } /* ************************************************************************* */ -HessianFactor::HessianFactor() : info_(matrix_) { +HessianFactorOrdered::HessianFactorOrdered() : info_(matrix_) { // The empty HessianFactor has only a constant error term of zero FastVector dims; dims.push_back(1); @@ -95,8 +95,8 @@ HessianFactor::HessianFactor() : info_(matrix_) { } /* ************************************************************************* */ -HessianFactor::HessianFactor(Index j, const Matrix& G, const Vector& g, double f) : - GaussianFactor(j), info_(matrix_) { +HessianFactorOrdered::HessianFactorOrdered(Index j, const Matrix& G, const Vector& g, double f) : + GaussianFactorOrdered(j), info_(matrix_) { if(G.rows() != G.cols() || G.rows() != g.size()) throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor"); size_t dims[] = { G.rows(), 1 }; @@ -112,8 +112,8 @@ HessianFactor::HessianFactor(Index j, const Matrix& G, const Vector& g, double f /* ************************************************************************* */ // error is 0.5*(x-mu)'*inv(Sigma)*(x-mu) = 0.5*(x'*G*x - 2*x'*G*mu + mu'*G*mu) // where G = inv(Sigma), g = G*mu, f = mu'*G*mu = mu'*g -HessianFactor::HessianFactor(Index j, const Vector& mu, const Matrix& Sigma) : - GaussianFactor(j), info_(matrix_) { +HessianFactorOrdered::HessianFactorOrdered(Index j, const Vector& mu, const Matrix& Sigma) : + GaussianFactorOrdered(j), info_(matrix_) { if (Sigma.rows() != Sigma.cols() || Sigma.rows() != mu.size()) throw invalid_argument( "Inconsistent matrix and/or vector dimensions in HessianFactor constructor"); Matrix G = inverse(Sigma); @@ -130,10 +130,10 @@ HessianFactor::HessianFactor(Index j, const Vector& mu, const Matrix& Sigma) : } /* ************************************************************************* */ -HessianFactor::HessianFactor(Index j1, Index j2, +HessianFactorOrdered::HessianFactorOrdered(Index j1, Index j2, const Matrix& G11, const Matrix& G12, const Vector& g1, const Matrix& G22, const Vector& g2, double f) : - GaussianFactor(j1, j2), info_(matrix_) { + GaussianFactorOrdered(j1, j2), info_(matrix_) { if(G11.rows() != G11.cols() || G11.rows() != G12.rows() || G11.rows() != g1.size() || G22.cols() != G12.cols() || G22.cols() != g2.size()) throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor"); @@ -151,11 +151,11 @@ HessianFactor::HessianFactor(Index j1, Index j2, } /* ************************************************************************* */ -HessianFactor::HessianFactor(Index j1, Index j2, Index j3, +HessianFactorOrdered::HessianFactorOrdered(Index j1, Index j2, Index j3, const Matrix& G11, const Matrix& G12, const Matrix& G13, const Vector& g1, const Matrix& G22, const Matrix& G23, const Vector& g2, const Matrix& G33, const Vector& g3, double f) : - GaussianFactor(j1, j2, j3), info_(matrix_) { + GaussianFactorOrdered(j1, j2, j3), info_(matrix_) { if(G11.rows() != G11.cols() || G11.rows() != G12.rows() || G11.rows() != G13.rows() || G11.rows() != g1.size() || G22.cols() != G12.cols() || G33.cols() != G13.cols() || G22.cols() != g2.size() || G33.cols() != g3.size()) throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor"); @@ -177,8 +177,8 @@ HessianFactor::HessianFactor(Index j1, Index j2, Index j3, } /* ************************************************************************* */ -HessianFactor::HessianFactor(const std::vector& js, const std::vector& Gs, - const std::vector& gs, double f) : GaussianFactor(js), info_(matrix_) { +HessianFactorOrdered::HessianFactorOrdered(const std::vector& js, const std::vector& Gs, + const std::vector& gs, double f) : GaussianFactorOrdered(js), info_(matrix_) { // Get the number of variables size_t variable_count = js.size(); @@ -237,20 +237,20 @@ HessianFactor::HessianFactor(const std::vector& js, const std::vector(&gf)) { - const JacobianFactor& jf(static_cast(gf)); + if(dynamic_cast(&gf)) { + const JacobianFactorOrdered& jf(static_cast(gf)); if(jf.model_->isConstrained()) throw invalid_argument("Cannot construct HessianFactor from JacobianFactor with constrained noise model"); else { @@ -259,8 +259,8 @@ HessianFactor::HessianFactor(const GaussianFactor& gf) : info_(matrix_) { BlockInfo::constBlock A = jf.Ab_.full(); matrix_.noalias() = A.transpose() * invsigmas.asDiagonal() * A; } - } else if(dynamic_cast(&gf)) { - const HessianFactor& hf(static_cast(gf)); + } else if(dynamic_cast(&gf)) { + const HessianFactorOrdered& hf(static_cast(gf)); info_.assignNoalias(hf.info_); } else throw std::invalid_argument("In HessianFactor(const GaussianFactor& gf), gf is neither a JacobianFactor nor a HessianFactor"); @@ -268,19 +268,19 @@ HessianFactor::HessianFactor(const GaussianFactor& gf) : info_(matrix_) { } /* ************************************************************************* */ -HessianFactor::HessianFactor(const FactorGraph& factors) : info_(matrix_) +HessianFactorOrdered::HessianFactorOrdered(const FactorGraphOrdered& factors) : info_(matrix_) { Scatter scatter(factors); - // Pull out keys and dimensions - gttic(keys); - vector dimensions(scatter.size() + 1); - BOOST_FOREACH(const Scatter::value_type& var_slot, scatter) { - dimensions[var_slot.second.slot] = var_slot.second.dimension; - } - // This is for the r.h.s. vector - dimensions.back() = 1; - gttoc(keys); + // Pull out keys and dimensions + gttic(keys); + vector dimensions(scatter.size() + 1); + BOOST_FOREACH(const Scatter::value_type& var_slot, scatter) { + dimensions[var_slot.second.slot] = var_slot.second.dimension; + } + // This is for the r.h.s. vector + dimensions.back() = 1; + gttoc(keys); const bool debug = ISDEBUG("EliminateCholesky"); // Form Ab' * Ab @@ -295,12 +295,12 @@ HessianFactor::HessianFactor(const FactorGraph& factors) : info_ gttoc(zero); gttic(update); if (debug) cout << "Combining " << factors.size() << " factors" << endl; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factors) { if(factor) { - if(shared_ptr hessian = boost::dynamic_pointer_cast(factor)) + if(shared_ptr hessian = boost::dynamic_pointer_cast(factor)) updateATA(*hessian, scatter); - else if(JacobianFactor::shared_ptr jacobianFactor = boost::dynamic_pointer_cast(factor)) + else if(JacobianFactorOrdered::shared_ptr jacobianFactor = boost::dynamic_pointer_cast(factor)) updateATA(*jacobianFactor, scatter); else throw invalid_argument("GaussianFactor is neither Hessian nor Jacobian"); @@ -314,14 +314,14 @@ HessianFactor::HessianFactor(const FactorGraph& factors) : info_ } /* ************************************************************************* */ -HessianFactor& HessianFactor::operator=(const HessianFactor& rhs) { +HessianFactorOrdered& HessianFactorOrdered::operator=(const HessianFactorOrdered& rhs) { this->Base::operator=(rhs); // Copy keys info_.assignNoalias(rhs.info_); // Copy matrix and block structure return *this; } /* ************************************************************************* */ -void HessianFactor::print(const std::string& s, const IndexFormatter& formatter) const { +void HessianFactorOrdered::print(const std::string& s, const IndexFormatter& formatter) const { cout << s << "\n"; cout << " keys: "; for(const_iterator key=this->begin(); key!=this->end(); ++key) @@ -331,30 +331,30 @@ void HessianFactor::print(const std::string& s, const IndexFormatter& formatter) } /* ************************************************************************* */ -bool HessianFactor::equals(const GaussianFactor& lf, double tol) const { - if(!dynamic_cast(&lf)) +bool HessianFactorOrdered::equals(const GaussianFactorOrdered& lf, double tol) const { + if(!dynamic_cast(&lf)) return false; else { Matrix thisMatrix = this->info_.full().selfadjointView(); thisMatrix(thisMatrix.rows()-1, thisMatrix.cols()-1) = 0.0; - Matrix rhsMatrix = static_cast(lf).info_.full().selfadjointView(); + Matrix rhsMatrix = static_cast(lf).info_.full().selfadjointView(); rhsMatrix(rhsMatrix.rows()-1, rhsMatrix.cols()-1) = 0.0; return equal_with_abs_tol(thisMatrix, rhsMatrix, tol); } } /* ************************************************************************* */ -Matrix HessianFactor::augmentedInformation() const { +Matrix HessianFactorOrdered::augmentedInformation() const { return info_.full().selfadjointView(); } /* ************************************************************************* */ -Matrix HessianFactor::information() const { +Matrix HessianFactorOrdered::information() const { return info_.range(0, this->size(), 0, this->size()).selfadjointView(); } /* ************************************************************************* */ -double HessianFactor::error(const VectorValues& c) const { +double HessianFactorOrdered::error(const VectorValuesOrdered& c) const { // error 0.5*(f - 2*x'*g + x'*G*x) const double f = constantTerm(); double xtg = 0, xGx = 0; @@ -367,7 +367,7 @@ double HessianFactor::error(const VectorValues& c) const { } /* ************************************************************************* */ -void HessianFactor::updateATA(const HessianFactor& update, const Scatter& scatter) { +void HessianFactorOrdered::updateATA(const HessianFactorOrdered& update, const Scatter& scatter) { // This function updates 'combined' with the information in 'update'. // 'scatter' maps variables in the update factor to slots in the combined @@ -420,7 +420,7 @@ void HessianFactor::updateATA(const HessianFactor& update, const Scatter& scatte } /* ************************************************************************* */ -void HessianFactor::updateATA(const JacobianFactor& update, const Scatter& scatter) { +void HessianFactorOrdered::updateATA(const JacobianFactorOrdered& update, const Scatter& scatter) { // This function updates 'combined' with the information in 'update'. // 'scatter' maps variables in the update factor to slots in the combined @@ -447,7 +447,7 @@ void HessianFactor::updateATA(const JacobianFactor& update, const Scatter& scatt update.print("with (Jacobian): "); } - typedef Eigen::Block BlockUpdateMatrix; + typedef Eigen::Block BlockUpdateMatrix; BlockUpdateMatrix updateA(update.matrix_.block( update.Ab_.rowStart(),update.Ab_.offset(0), update.Ab_.full().rows(), update.Ab_.full().cols())); if (debug) cout << "updateA: \n" << updateA << endl; @@ -497,19 +497,19 @@ void HessianFactor::updateATA(const JacobianFactor& update, const Scatter& scatt } /* ************************************************************************* */ -void HessianFactor::partialCholesky(size_t nrFrontals) { +void HessianFactorOrdered::partialCholesky(size_t nrFrontals) { if(!choleskyPartial(matrix_, info_.offset(nrFrontals))) throw IndeterminantLinearSystemException(this->keys().front()); } /* ************************************************************************* */ -GaussianConditional::shared_ptr HessianFactor::splitEliminatedFactor(size_t nrFrontals) { +GaussianConditionalOrdered::shared_ptr HessianFactorOrdered::splitEliminatedFactor(size_t nrFrontals) { static const bool debug = false; // Extract conditionals gttic(extract_conditionals); - GaussianConditional::shared_ptr conditional(new GaussianConditional()); + GaussianConditionalOrdered::shared_ptr conditional(new GaussianConditionalOrdered()); typedef VerticalBlockView BlockAb; BlockAb Ab(matrix_, info_); @@ -538,7 +538,7 @@ GaussianConditional::shared_ptr HessianFactor::splitEliminatedFactor(size_t nrFr } /* ************************************************************************* */ -GaussianFactor::shared_ptr HessianFactor::negate() const { +GaussianFactorOrdered::shared_ptr HessianFactorOrdered::negate() const { // Copy Hessian Blocks from Hessian factor and invert std::vector js; std::vector Gs; @@ -554,7 +554,7 @@ GaussianFactor::shared_ptr HessianFactor::negate() const { f = -constantTerm(); // Create the Anti-Hessian Factor from the negated blocks - return HessianFactor::shared_ptr(new HessianFactor(js, Gs, gs, f)); + return HessianFactorOrdered::shared_ptr(new HessianFactorOrdered(js, Gs, gs, f)); } } // gtsam diff --git a/gtsam/linear/HessianFactor.h b/gtsam/linear/HessianFactorOrdered.h similarity index 85% rename from gtsam/linear/HessianFactor.h rename to gtsam/linear/HessianFactorOrdered.h index 9f44a0964..9adaf0221 100644 --- a/gtsam/linear/HessianFactor.h +++ b/gtsam/linear/HessianFactorOrdered.h @@ -1,377 +1,377 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file HessianFactor.h - * @brief Contains the HessianFactor class, a general quadratic factor - * @author Richard Roberts - * @date Dec 8, 2010 - */ - -#pragma once - -#include -#include -#include - -// Forward declarations for friend unit tests -class HessianFactorConversionConstructorTest; -class HessianFactorConstructor1Test; -class HessianFactorConstructor1bTest; -class HessianFactorcombineTest; - - -namespace gtsam { - - // Forward declarations - class JacobianFactor; - class GaussianConditional; - template class BayesNet; - - // Definition of Scatter, which is an intermediate data structure used when - // building a HessianFactor incrementally, to get the keys in the right - // order. - // 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. - struct GTSAM_EXPORT SlotEntry { - size_t slot; - size_t dimension; - SlotEntry(size_t _slot, size_t _dimension) - : slot(_slot), dimension(_dimension) {} - std::string toString() const; - }; - class Scatter : public FastMap { - public: - Scatter() {} - Scatter(const FactorGraph& gfg); - }; - - /** - * @brief A Gaussian factor using the canonical parameters (information form) - * - * HessianFactor implements a general quadratic factor of the form - * \f[ E(x) = 0.5 x^T G x - x^T g + 0.5 f \f] - * that stores the matrix \f$ G \f$, the vector \f$ g \f$, and the constant term \f$ f \f$. - * - * When \f$ G \f$ is positive semidefinite, this factor represents a Gaussian, - * in which case \f$ G \f$ is the information matrix \f$ \Lambda \f$, - * \f$ g \f$ is the information vector \f$ \eta \f$, and \f$ f \f$ is the residual - * sum-square-error at the mean, when \f$ x = \mu \f$. - * - * Indeed, the negative log-likelihood of a Gaussian is (up to a constant) - * @f$ E(x) = 0.5(x-\mu)^T P^{-1} (x-\mu) @f$ - * with @f$ \mu @f$ the mean and @f$ P @f$ the covariance matrix. Expanding the product we get - * @f[ - * E(x) = 0.5 x^T P^{-1} x - x^T P^{-1} \mu + 0.5 \mu^T P^{-1} \mu - * @f] - * We define the Information matrix (or Hessian) @f$ \Lambda = P^{-1} @f$ - * and the information vector @f$ \eta = P^{-1} \mu = \Lambda \mu @f$ - * to arrive at the canonical form of the Gaussian: - * @f[ - * E(x) = 0.5 x^T \Lambda x - x^T \eta + 0.5 \mu^T \Lambda \mu - * @f] - * - * This factor is one of the factors that can be in a GaussianFactorGraph. - * It may be returned from NonlinearFactor::linearize(), but is also - * used internally to store the Hessian during Cholesky elimination. - * - * This can represent a quadratic factor with characteristics that cannot be - * represented using a JacobianFactor (which has the form - * \f$ E(x) = \Vert Ax - b \Vert^2 \f$ and stores the Jacobian \f$ A \f$ - * and error vector \f$ b \f$, i.e. is a sum-of-squares factor). For example, - * a HessianFactor need not be positive semidefinite, it can be indefinite or - * even negative semidefinite. - * - * If a HessianFactor is indefinite or negative semi-definite, then in order - * for solving the linear system to be possible, - * the Hessian of the full system must be positive definite (i.e. when all - * small Hessians are combined, the result must be positive definite). If - * this is not the case, an error will occur during elimination. - * - * This class stores G, g, and f as an augmented matrix HessianFactor::matrix_. - * The upper-left n x n blocks of HessianFactor::matrix_ store the upper-right - * triangle of G, the upper-right-most column of length n of HessianFactor::matrix_ - * stores g, and the lower-right entry of HessianFactor::matrix_ stores f, i.e. - * \code - HessianFactor::matrix_ = [ G11 G12 G13 ... g1 - 0 G22 G23 ... g2 - 0 0 G33 ... g3 - : : : : - 0 0 0 ... f ] - \endcode - Blocks can be accessed as follows: - \code - G11 = info(begin(), begin()); - G12 = info(begin(), begin()+1); - G23 = info(begin()+1, begin()+2); - g2 = linearTerm(begin()+1); - f = constantTerm(); - ....... - \endcode - */ - class GTSAM_EXPORT HessianFactor : public GaussianFactor { - protected: - typedef Matrix InfoMatrix; ///< The full augmented Hessian - typedef SymmetricBlockView BlockInfo; ///< A blockwise view of the Hessian - typedef GaussianFactor Base; ///< Typedef to base class - - InfoMatrix matrix_; ///< The full augmented information matrix, s.t. the quadratic error is 0.5*[x -1]'*H*[x -1] - BlockInfo info_; ///< The block view of the full information matrix. - - public: - - typedef boost::shared_ptr shared_ptr; ///< A shared_ptr to this - typedef BlockInfo::Block Block; ///< A block from the Hessian matrix - typedef BlockInfo::constBlock constBlock; ///< A block from the Hessian matrix (const version) - typedef BlockInfo::Column Column; ///< A column containing the linear term h - typedef BlockInfo::constColumn constColumn; ///< A column containing the linear term h (const version) - - /** Copy constructor */ - HessianFactor(const HessianFactor& gf); - - /** default constructor for I/O */ - HessianFactor(); - - /** Construct a unary factor. G is the quadratic term (Hessian matrix), g - * the linear term (a vector), and f the constant term. The quadratic - * error is: - * 0.5*(f - 2*x'*g + x'*G*x) - */ - HessianFactor(Index j, const Matrix& G, const Vector& g, double f); - - /** Construct a unary factor, given a mean and covariance matrix. - * error is 0.5*(x-mu)'*inv(Sigma)*(x-mu) - */ - HessianFactor(Index j, const Vector& mu, const Matrix& Sigma); - - /** Construct a binary factor. Gxx are the upper-triangle blocks of the - * quadratic term (the Hessian matrix), gx the pieces of the linear vector - * term, and f the constant term. - * JacobianFactor error is \f[ 0.5* (Ax-b)' M (Ax-b) = 0.5*x'A'MAx - x'A'Mb + 0.5*b'Mb \f] - * HessianFactor error is \f[ 0.5*(x'Gx - 2x'g + f) = 0.5*x'Gx - x'*g + 0.5*f \f] - * So, with \f$ A = [A1 A2] \f$ and \f$ G=A*'M*A = [A1';A2']*M*[A1 A2] \f$ we have - \code - n1*n1 G11 = A1'*M*A1 - n1*n2 G12 = A1'*M*A2 - n2*n2 G22 = A2'*M*A2 - n1*1 g1 = A1'*M*b - n2*1 g2 = A2'*M*b - 1*1 f = b'*M*b - \endcode - */ - HessianFactor(Index j1, Index j2, - const Matrix& G11, const Matrix& G12, const Vector& g1, - const Matrix& G22, const Vector& g2, double f); - - /** Construct a ternary factor. Gxx are the upper-triangle blocks of the - * quadratic term (the Hessian matrix), gx the pieces of the linear vector - * term, and f the constant term. - */ - HessianFactor(Index j1, Index j2, Index j3, - const Matrix& G11, const Matrix& G12, const Matrix& G13, const Vector& g1, - const Matrix& G22, const Matrix& G23, const Vector& g2, - const Matrix& G33, const Vector& g3, double f); - - /** Construct an n-way factor. Gs contains the upper-triangle blocks of the - * quadratic term (the Hessian matrix) provided in row-order, gs the pieces - * of the linear vector term, and f the constant term. - */ - HessianFactor(const std::vector& js, const std::vector& Gs, - const std::vector& gs, double f); - - /** Construct from Conditional Gaussian */ - explicit HessianFactor(const GaussianConditional& cg); - - /** Convert from a JacobianFactor (computes A^T * A) or HessianFactor */ - explicit HessianFactor(const GaussianFactor& factor); - - /** Combine a set of factors into a single dense HessianFactor */ - HessianFactor(const FactorGraph& factors); - - /** Destructor */ - virtual ~HessianFactor() {} - - /** Aassignment operator */ - HessianFactor& operator=(const HessianFactor& rhs); - - /** Clone this JacobianFactor */ - virtual GaussianFactor::shared_ptr clone() const { - return boost::static_pointer_cast( - shared_ptr(new HessianFactor(*this))); - } - - /** Print the factor for debugging and testing (implementing Testable) */ - virtual void print(const std::string& s = "", - const IndexFormatter& formatter = DefaultIndexFormatter) const; - - /** Compare to another factor for testing (implementing Testable) */ - virtual bool equals(const GaussianFactor& lf, double tol = 1e-9) const; - - /** Evaluate the factor error f(x), see above. */ - virtual double error(const VectorValues& c) const; /** 0.5*[x -1]'*H*[x -1] (also see constructor documentation) */ - - /** Return the dimension of the variable pointed to by the given key iterator - * todo: Remove this in favor of keeping track of dimensions with variables? - * @param variable An iterator pointing to the slot in this factor. You can - * use, for example, begin() + 2 to get the 3rd variable in this factor. - */ - virtual size_t getDim(const_iterator variable) const { return info_(variable-this->begin(), 0).rows(); } - - /** Return the number of columns and rows of the Hessian matrix */ - size_t rows() const { return info_.rows(); } - - /** - * Construct the corresponding anti-factor to negate information - * stored stored in this factor. - * @return a HessianFactor with negated Hessian matrices - */ - virtual GaussianFactor::shared_ptr negate() const; - - /** Return a view of the block at (j1,j2) of the upper-triangular part of the - * information matrix \f$ H \f$, no data is copied. See HessianFactor class documentation - * above to explain that only the upper-triangular part of the information matrix is stored - * and returned by this function. - * @param j1 Which block row to get, as an iterator pointing to the slot in this factor. You can - * use, for example, begin() + 2 to get the 3rd variable in this factor. - * @param j2 Which block column to get, as an iterator pointing to the slot in this factor. You can - * use, for example, begin() + 2 to get the 3rd variable in this factor. - * @return A view of the requested block, not a copy. - */ - constBlock info(const_iterator j1, const_iterator j2) const { return info_(j1-begin(), j2-begin()); } - - /** Return a view of the block at (j1,j2) of the upper-triangular part of the - * information matrix \f$ H \f$, no data is copied. See HessianFactor class documentation - * above to explain that only the upper-triangular part of the information matrix is stored - * and returned by this function. - * @param j1 Which block row to get, as an iterator pointing to the slot in this factor. You can - * use, for example, begin() + 2 to get the 3rd variable in this factor. - * @param j2 Which block column to get, as an iterator pointing to the slot in this factor. You can - * use, for example, begin() + 2 to get the 3rd variable in this factor. - * @return A view of the requested block, not a copy. - */ - Block info(iterator j1, iterator j2) { return info_(j1-begin(), j2-begin()); } - - /** Return the upper-triangular part of the full *augmented* information matrix, - * as described above. See HessianFactor class documentation above to explain that only the - * upper-triangular part of the information matrix is stored and returned by this function. - */ - constBlock info() const { return info_.full(); } - - /** Return the upper-triangular part of the full *augmented* information matrix, - * as described above. See HessianFactor class documentation above to explain that only the - * upper-triangular part of the information matrix is stored and returned by this function. - */ - Block info() { return info_.full(); } - - /** Return the constant term \f$ f \f$ as described above - * @return The constant term \f$ f \f$ - */ - double constantTerm() const { return info_(this->size(), this->size())(0,0); } - - /** Return the constant term \f$ f \f$ as described above - * @return The constant term \f$ f \f$ - */ - double& constantTerm() { return info_(this->size(), this->size())(0,0); } - - /** Return the part of linear term \f$ g \f$ as described above corresponding to the requested variable. - * @param j Which block row to get, as an iterator pointing to the slot in this factor. You can - * use, for example, begin() + 2 to get the 3rd variable in this factor. - * @return The linear term \f$ g \f$ */ - constColumn linearTerm(const_iterator j) const { return info_.column(j-begin(), size(), 0); } - - /** Return the part of linear term \f$ g \f$ as described above corresponding to the requested variable. - * @param j Which block row to get, as an iterator pointing to the slot in this factor. You can - * use, for example, begin() + 2 to get the 3rd variable in this factor. - * @return The linear term \f$ g \f$ */ - Column linearTerm(iterator j) { return info_.column(j-begin(), size(), 0); } - - /** Return the complete linear term \f$ g \f$ as described above. - * @return The linear term \f$ g \f$ */ - constColumn linearTerm() const { return info_.rangeColumn(0, this->size(), this->size(), 0); } - - /** Return the complete linear term \f$ g \f$ as described above. - * @return The linear term \f$ g \f$ */ - Column linearTerm() { return info_.rangeColumn(0, this->size(), this->size(), 0); } - - /** Return the augmented information matrix represented by this GaussianFactor. - * The augmented information matrix contains the information matrix with an - * additional column holding the information vector, and an additional row - * holding the transpose of the information vector. The lower-right entry - * contains the constant error term (when \f$ \delta x = 0 \f$). The - * augmented information matrix is described in more detail in HessianFactor, - * which in fact stores an augmented information matrix. - * - * For HessianFactor, this is the same as info() except that this function - * returns a complete symmetric matrix whereas info() returns a matrix where - * only the upper triangle is valid, but should be interpreted as symmetric. - * This is because info() returns only a reference to the internal - * representation of the augmented information matrix, which stores only the - * upper triangle. - */ - virtual Matrix augmentedInformation() const; - - /** Return the non-augmented information matrix represented by this - * GaussianFactor. - */ - virtual Matrix information() const; - - // Friend unit test classes - friend class ::HessianFactorConversionConstructorTest; - friend class ::HessianFactorConstructor1Test; - friend class ::HessianFactorConstructor1bTest; - friend class ::HessianFactorcombineTest; - - // Friend JacobianFactor for conversion - friend class JacobianFactor; - - // used in eliminateCholesky: - - /** - * 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 in splitEliminatedFactor. Frank says :-( - */ - void partialCholesky(size_t nrFrontals); - - /** split partially eliminated factor */ - boost::shared_ptr splitEliminatedFactor(size_t nrFrontals); - - /** Update the factor by adding the information from the JacobianFactor - * (used internally during elimination). - * @param update The JacobianFactor containing the new information to add - * @param scatter A mapping from variable index to slot index in this HessianFactor - */ - void updateATA(const JacobianFactor& update, const Scatter& scatter); - - /** Update the factor by adding the information from the HessianFactor - * (used internally during elimination). - * @param update The HessianFactor containing the new information to add - * @param scatter A mapping from variable index to slot index in this HessianFactor - */ - void updateATA(const HessianFactor& update, const Scatter& scatter); - - /** assert invariants */ - void assertInvariants() const; - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(GaussianFactor); - ar & BOOST_SERIALIZATION_NVP(info_); - ar & BOOST_SERIALIZATION_NVP(matrix_); - } - }; - -} - +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file HessianFactor.h + * @brief Contains the HessianFactor class, a general quadratic factor + * @author Richard Roberts + * @date Dec 8, 2010 + */ + +#pragma once + +#include +#include +#include + +// Forward declarations for friend unit tests +class HessianFactorOrderedConversionConstructorTest; +class HessianFactorOrderedConstructor1Test; +class HessianFactorOrderedConstructor1bTest; +class HessianFactorOrderedcombineTest; + + +namespace gtsam { + + // Forward declarations + class JacobianFactorOrdered; + class GaussianConditionalOrdered; + template class BayesNetOrdered; + + // Definition of Scatter, which is an intermediate data structure used when + // building a HessianFactor incrementally, to get the keys in the right + // order. + // 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. + struct GTSAM_EXPORT SlotEntry { + size_t slot; + size_t dimension; + SlotEntry(size_t _slot, size_t _dimension) + : slot(_slot), dimension(_dimension) {} + std::string toString() const; + }; + class Scatter : public FastMap { + public: + Scatter() {} + Scatter(const FactorGraphOrdered& gfg); + }; + + /** + * @brief A Gaussian factor using the canonical parameters (information form) + * + * HessianFactor implements a general quadratic factor of the form + * \f[ E(x) = 0.5 x^T G x - x^T g + 0.5 f \f] + * that stores the matrix \f$ G \f$, the vector \f$ g \f$, and the constant term \f$ f \f$. + * + * When \f$ G \f$ is positive semidefinite, this factor represents a Gaussian, + * in which case \f$ G \f$ is the information matrix \f$ \Lambda \f$, + * \f$ g \f$ is the information vector \f$ \eta \f$, and \f$ f \f$ is the residual + * sum-square-error at the mean, when \f$ x = \mu \f$. + * + * Indeed, the negative log-likelihood of a Gaussian is (up to a constant) + * @f$ E(x) = 0.5(x-\mu)^T P^{-1} (x-\mu) @f$ + * with @f$ \mu @f$ the mean and @f$ P @f$ the covariance matrix. Expanding the product we get + * @f[ + * E(x) = 0.5 x^T P^{-1} x - x^T P^{-1} \mu + 0.5 \mu^T P^{-1} \mu + * @f] + * We define the Information matrix (or Hessian) @f$ \Lambda = P^{-1} @f$ + * and the information vector @f$ \eta = P^{-1} \mu = \Lambda \mu @f$ + * to arrive at the canonical form of the Gaussian: + * @f[ + * E(x) = 0.5 x^T \Lambda x - x^T \eta + 0.5 \mu^T \Lambda \mu + * @f] + * + * This factor is one of the factors that can be in a GaussianFactorGraph. + * It may be returned from NonlinearFactor::linearize(), but is also + * used internally to store the Hessian during Cholesky elimination. + * + * This can represent a quadratic factor with characteristics that cannot be + * represented using a JacobianFactor (which has the form + * \f$ E(x) = \Vert Ax - b \Vert^2 \f$ and stores the Jacobian \f$ A \f$ + * and error vector \f$ b \f$, i.e. is a sum-of-squares factor). For example, + * a HessianFactor need not be positive semidefinite, it can be indefinite or + * even negative semidefinite. + * + * If a HessianFactor is indefinite or negative semi-definite, then in order + * for solving the linear system to be possible, + * the Hessian of the full system must be positive definite (i.e. when all + * small Hessians are combined, the result must be positive definite). If + * this is not the case, an error will occur during elimination. + * + * This class stores G, g, and f as an augmented matrix HessianFactor::matrix_. + * The upper-left n x n blocks of HessianFactor::matrix_ store the upper-right + * triangle of G, the upper-right-most column of length n of HessianFactor::matrix_ + * stores g, and the lower-right entry of HessianFactor::matrix_ stores f, i.e. + * \code + HessianFactor::matrix_ = [ G11 G12 G13 ... g1 + 0 G22 G23 ... g2 + 0 0 G33 ... g3 + : : : : + 0 0 0 ... f ] + \endcode + Blocks can be accessed as follows: + \code + G11 = info(begin(), begin()); + G12 = info(begin(), begin()+1); + G23 = info(begin()+1, begin()+2); + g2 = linearTerm(begin()+1); + f = constantTerm(); + ....... + \endcode + */ + class GTSAM_EXPORT HessianFactorOrdered : public GaussianFactorOrdered { + protected: + typedef Matrix InfoMatrix; ///< The full augmented Hessian + typedef SymmetricBlockView BlockInfo; ///< A blockwise view of the Hessian + typedef GaussianFactorOrdered Base; ///< Typedef to base class + + InfoMatrix matrix_; ///< The full augmented information matrix, s.t. the quadratic error is 0.5*[x -1]'*H*[x -1] + BlockInfo info_; ///< The block view of the full information matrix. + + public: + + typedef boost::shared_ptr shared_ptr; ///< A shared_ptr to this + typedef BlockInfo::Block Block; ///< A block from the Hessian matrix + typedef BlockInfo::constBlock constBlock; ///< A block from the Hessian matrix (const version) + typedef BlockInfo::Column Column; ///< A column containing the linear term h + typedef BlockInfo::constColumn constColumn; ///< A column containing the linear term h (const version) + + /** Copy constructor */ + HessianFactorOrdered(const HessianFactorOrdered& gf); + + /** default constructor for I/O */ + HessianFactorOrdered(); + + /** Construct a unary factor. G is the quadratic term (Hessian matrix), g + * the linear term (a vector), and f the constant term. The quadratic + * error is: + * 0.5*(f - 2*x'*g + x'*G*x) + */ + HessianFactorOrdered(Index j, const Matrix& G, const Vector& g, double f); + + /** Construct a unary factor, given a mean and covariance matrix. + * error is 0.5*(x-mu)'*inv(Sigma)*(x-mu) + */ + HessianFactorOrdered(Index j, const Vector& mu, const Matrix& Sigma); + + /** Construct a binary factor. Gxx are the upper-triangle blocks of the + * quadratic term (the Hessian matrix), gx the pieces of the linear vector + * term, and f the constant term. + * JacobianFactor error is \f[ 0.5* (Ax-b)' M (Ax-b) = 0.5*x'A'MAx - x'A'Mb + 0.5*b'Mb \f] + * HessianFactor error is \f[ 0.5*(x'Gx - 2x'g + f) = 0.5*x'Gx - x'*g + 0.5*f \f] + * So, with \f$ A = [A1 A2] \f$ and \f$ G=A*'M*A = [A1';A2']*M*[A1 A2] \f$ we have + \code + n1*n1 G11 = A1'*M*A1 + n1*n2 G12 = A1'*M*A2 + n2*n2 G22 = A2'*M*A2 + n1*1 g1 = A1'*M*b + n2*1 g2 = A2'*M*b + 1*1 f = b'*M*b + \endcode + */ + HessianFactorOrdered(Index j1, Index j2, + const Matrix& G11, const Matrix& G12, const Vector& g1, + const Matrix& G22, const Vector& g2, double f); + + /** Construct a ternary factor. Gxx are the upper-triangle blocks of the + * quadratic term (the Hessian matrix), gx the pieces of the linear vector + * term, and f the constant term. + */ + HessianFactorOrdered(Index j1, Index j2, Index j3, + const Matrix& G11, const Matrix& G12, const Matrix& G13, const Vector& g1, + const Matrix& G22, const Matrix& G23, const Vector& g2, + const Matrix& G33, const Vector& g3, double f); + + /** Construct an n-way factor. Gs contains the upper-triangle blocks of the + * quadratic term (the Hessian matrix) provided in row-order, gs the pieces + * of the linear vector term, and f the constant term. + */ + HessianFactorOrdered(const std::vector& js, const std::vector& Gs, + const std::vector& gs, double f); + + /** Construct from Conditional Gaussian */ + explicit HessianFactorOrdered(const GaussianConditionalOrdered& cg); + + /** Convert from a JacobianFactor (computes A^T * A) or HessianFactor */ + explicit HessianFactorOrdered(const GaussianFactorOrdered& factor); + + /** Combine a set of factors into a single dense HessianFactor */ + HessianFactorOrdered(const FactorGraphOrdered& factors); + + /** Destructor */ + virtual ~HessianFactorOrdered() {} + + /** Aassignment operator */ + HessianFactorOrdered& operator=(const HessianFactorOrdered& rhs); + + /** Clone this JacobianFactor */ + virtual GaussianFactorOrdered::shared_ptr clone() const { + return boost::static_pointer_cast( + shared_ptr(new HessianFactorOrdered(*this))); + } + + /** Print the factor for debugging and testing (implementing Testable) */ + virtual void print(const std::string& s = "", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /** Compare to another factor for testing (implementing Testable) */ + virtual bool equals(const GaussianFactorOrdered& lf, double tol = 1e-9) const; + + /** Evaluate the factor error f(x), see above. */ + virtual double error(const VectorValuesOrdered& c) const; /** 0.5*[x -1]'*H*[x -1] (also see constructor documentation) */ + + /** Return the dimension of the variable pointed to by the given key iterator + * todo: Remove this in favor of keeping track of dimensions with variables? + * @param variable An iterator pointing to the slot in this factor. You can + * use, for example, begin() + 2 to get the 3rd variable in this factor. + */ + virtual size_t getDim(const_iterator variable) const { return info_(variable-this->begin(), 0).rows(); } + + /** Return the number of columns and rows of the Hessian matrix */ + size_t rows() const { return info_.rows(); } + + /** + * Construct the corresponding anti-factor to negate information + * stored stored in this factor. + * @return a HessianFactor with negated Hessian matrices + */ + virtual GaussianFactorOrdered::shared_ptr negate() const; + + /** Return a view of the block at (j1,j2) of the upper-triangular part of the + * information matrix \f$ H \f$, no data is copied. See HessianFactor class documentation + * above to explain that only the upper-triangular part of the information matrix is stored + * and returned by this function. + * @param j1 Which block row to get, as an iterator pointing to the slot in this factor. You can + * use, for example, begin() + 2 to get the 3rd variable in this factor. + * @param j2 Which block column to get, as an iterator pointing to the slot in this factor. You can + * use, for example, begin() + 2 to get the 3rd variable in this factor. + * @return A view of the requested block, not a copy. + */ + constBlock info(const_iterator j1, const_iterator j2) const { return info_(j1-begin(), j2-begin()); } + + /** Return a view of the block at (j1,j2) of the upper-triangular part of the + * information matrix \f$ H \f$, no data is copied. See HessianFactor class documentation + * above to explain that only the upper-triangular part of the information matrix is stored + * and returned by this function. + * @param j1 Which block row to get, as an iterator pointing to the slot in this factor. You can + * use, for example, begin() + 2 to get the 3rd variable in this factor. + * @param j2 Which block column to get, as an iterator pointing to the slot in this factor. You can + * use, for example, begin() + 2 to get the 3rd variable in this factor. + * @return A view of the requested block, not a copy. + */ + Block info(iterator j1, iterator j2) { return info_(j1-begin(), j2-begin()); } + + /** Return the upper-triangular part of the full *augmented* information matrix, + * as described above. See HessianFactor class documentation above to explain that only the + * upper-triangular part of the information matrix is stored and returned by this function. + */ + constBlock info() const { return info_.full(); } + + /** Return the upper-triangular part of the full *augmented* information matrix, + * as described above. See HessianFactor class documentation above to explain that only the + * upper-triangular part of the information matrix is stored and returned by this function. + */ + Block info() { return info_.full(); } + + /** Return the constant term \f$ f \f$ as described above + * @return The constant term \f$ f \f$ + */ + double constantTerm() const { return info_(this->size(), this->size())(0,0); } + + /** Return the constant term \f$ f \f$ as described above + * @return The constant term \f$ f \f$ + */ + double& constantTerm() { return info_(this->size(), this->size())(0,0); } + + /** Return the part of linear term \f$ g \f$ as described above corresponding to the requested variable. + * @param j Which block row to get, as an iterator pointing to the slot in this factor. You can + * use, for example, begin() + 2 to get the 3rd variable in this factor. + * @return The linear term \f$ g \f$ */ + constColumn linearTerm(const_iterator j) const { return info_.column(j-begin(), size(), 0); } + + /** Return the part of linear term \f$ g \f$ as described above corresponding to the requested variable. + * @param j Which block row to get, as an iterator pointing to the slot in this factor. You can + * use, for example, begin() + 2 to get the 3rd variable in this factor. + * @return The linear term \f$ g \f$ */ + Column linearTerm(iterator j) { return info_.column(j-begin(), size(), 0); } + + /** Return the complete linear term \f$ g \f$ as described above. + * @return The linear term \f$ g \f$ */ + constColumn linearTerm() const { return info_.rangeColumn(0, this->size(), this->size(), 0); } + + /** Return the complete linear term \f$ g \f$ as described above. + * @return The linear term \f$ g \f$ */ + Column linearTerm() { return info_.rangeColumn(0, this->size(), this->size(), 0); } + + /** Return the augmented information matrix represented by this GaussianFactor. + * The augmented information matrix contains the information matrix with an + * additional column holding the information vector, and an additional row + * holding the transpose of the information vector. The lower-right entry + * contains the constant error term (when \f$ \delta x = 0 \f$). The + * augmented information matrix is described in more detail in HessianFactor, + * which in fact stores an augmented information matrix. + * + * For HessianFactor, this is the same as info() except that this function + * returns a complete symmetric matrix whereas info() returns a matrix where + * only the upper triangle is valid, but should be interpreted as symmetric. + * This is because info() returns only a reference to the internal + * representation of the augmented information matrix, which stores only the + * upper triangle. + */ + virtual Matrix augmentedInformation() const; + + /** Return the non-augmented information matrix represented by this + * GaussianFactor. + */ + virtual Matrix information() const; + + // Friend unit test classes + friend class ::HessianFactorOrderedConversionConstructorTest; + friend class ::HessianFactorOrderedConstructor1Test; + friend class ::HessianFactorOrderedConstructor1bTest; + friend class ::HessianFactorOrderedcombineTest; + + // Friend JacobianFactor for conversion + friend class JacobianFactorOrdered; + + // used in eliminateCholesky: + + /** + * 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 in splitEliminatedFactor. Frank says :-( + */ + void partialCholesky(size_t nrFrontals); + + /** split partially eliminated factor */ + boost::shared_ptr splitEliminatedFactor(size_t nrFrontals); + + /** Update the factor by adding the information from the JacobianFactor + * (used internally during elimination). + * @param update The JacobianFactor containing the new information to add + * @param scatter A mapping from variable index to slot index in this HessianFactor + */ + void updateATA(const JacobianFactorOrdered& update, const Scatter& scatter); + + /** Update the factor by adding the information from the HessianFactor + * (used internally during elimination). + * @param update The HessianFactor containing the new information to add + * @param scatter A mapping from variable index to slot index in this HessianFactor + */ + void updateATA(const HessianFactorOrdered& update, const Scatter& scatter); + + /** assert invariants */ + void assertInvariants() const; + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(GaussianFactorOrdered); + ar & BOOST_SERIALIZATION_NVP(info_); + ar & BOOST_SERIALIZATION_NVP(matrix_); + } + }; + +} + diff --git a/gtsam/linear/IterativeSolver.h b/gtsam/linear/IterativeSolver.h index 38515952e..4ecf88af3 100644 --- a/gtsam/linear/IterativeSolver.h +++ b/gtsam/linear/IterativeSolver.h @@ -11,8 +11,8 @@ #pragma once -#include -#include +#include +#include #include namespace gtsam { @@ -67,13 +67,13 @@ namespace gtsam { virtual ~IterativeSolver() {} /* interface to the nonlinear optimizer */ - virtual VectorValues optimize () = 0; + virtual VectorValuesOrdered optimize () = 0; /* interface to the nonlinear optimizer */ - virtual VectorValues optimize (const VectorValues &initial) = 0; + virtual VectorValuesOrdered optimize (const VectorValuesOrdered &initial) = 0; /* update interface to the nonlinear optimizer */ - virtual void replaceFactors(const GaussianFactorGraph::shared_ptr &factorGraph, const double lambda) {} + virtual void replaceFactors(const GaussianFactorGraphOrdered::shared_ptr &factorGraph, const double lambda) {} }; } diff --git a/gtsam/linear/JacobianFactorUnordered-inl.h b/gtsam/linear/JacobianFactor-inl.h similarity index 92% rename from gtsam/linear/JacobianFactorUnordered-inl.h rename to gtsam/linear/JacobianFactor-inl.h index 9168207c1..ef75cd884 100644 --- a/gtsam/linear/JacobianFactorUnordered-inl.h +++ b/gtsam/linear/JacobianFactor-inl.h @@ -28,14 +28,14 @@ namespace gtsam { /* ************************************************************************* */ template - JacobianFactorUnordered::JacobianFactorUnordered(const TERMS&terms, const Vector &b, const SharedDiagonal& model) + JacobianFactor::JacobianFactor(const TERMS&terms, const Vector &b, const SharedDiagonal& model) { fillTerms(terms, b, model); } /* ************************************************************************* */ template - JacobianFactorUnordered::JacobianFactorUnordered( + JacobianFactor::JacobianFactor( const KEYS& keys, const VerticalBlockMatrix& augmentedMatrix, const SharedDiagonal& model) : Base(keys) { @@ -72,7 +72,7 @@ namespace gtsam { /* ************************************************************************* */ template - void JacobianFactorUnordered::fillTerms(const TERMS& terms, const Vector& b, const SharedDiagonal& noiseModel) + void JacobianFactor::fillTerms(const TERMS& terms, const Vector& b, const SharedDiagonal& noiseModel) { // Check noise model dimension if(noiseModel && noiseModel->dim() != b.size()) diff --git a/gtsam/linear/JacobianFactor.cpp b/gtsam/linear/JacobianFactor.cpp index 4493d2b00..aa6c4609d 100644 --- a/gtsam/linear/JacobianFactor.cpp +++ b/gtsam/linear/JacobianFactor.cpp @@ -1,533 +1,574 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file JacobianFactor.cpp - * @author Richard Roberts - * @date Dec 8, 2010 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif -#include -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#include -#include -#include - -using namespace std; - -namespace gtsam { - - /* ************************************************************************* */ - void JacobianFactor::assertInvariants() const { -#ifndef NDEBUG - GaussianFactor::assertInvariants(); // The base class checks for unique keys - assert((size() == 0 && Ab_.rows() == 0 && Ab_.nBlocks() == 0) || size()+1 == Ab_.nBlocks()); -#endif - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(const JacobianFactor& gf) : - GaussianFactor(gf), model_(gf.model_), Ab_(matrix_) { - Ab_.assignNoalias(gf.Ab_); - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(const GaussianFactor& gf) : Ab_(matrix_) { - // Copy the matrix data depending on what type of factor we're copying from - if(const JacobianFactor* rhs = dynamic_cast(&gf)) - *this = JacobianFactor(*rhs); - else if(const HessianFactor* rhs = dynamic_cast(&gf)) - *this = JacobianFactor(*rhs); - else - throw std::invalid_argument("In JacobianFactor(const GaussianFactor& rhs), rhs is neither a JacobianFactor nor a HessianFactor"); - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor() : Ab_(matrix_) { assertInvariants(); } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(const Vector& b_in) : Ab_(matrix_) { - size_t dims[] = { 1 }; - Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+1, b_in.size())); - getb() = b_in; - model_ = noiseModel::Unit::Create(this->rows()); - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(Index i1, const Matrix& A1, - const Vector& b, const SharedDiagonal& model) : - GaussianFactor(i1), model_(model), Ab_(matrix_) { - - if(model->dim() != (size_t) b.size()) - throw InvalidNoiseModel(b.size(), model->dim()); - - size_t dims[] = { A1.cols(), 1}; - Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+2, b.size())); - Ab_(0) = A1; - getb() = b; - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(Index i1, const Matrix& A1, Index i2, const Matrix& A2, - const Vector& b, const SharedDiagonal& model) : - GaussianFactor(i1,i2), model_(model), Ab_(matrix_) { - - if(model->dim() != (size_t) b.size()) - throw InvalidNoiseModel(b.size(), model->dim()); - - size_t dims[] = { A1.cols(), A2.cols(), 1}; - Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+3, b.size())); - Ab_(0) = A1; - Ab_(1) = A2; - getb() = b; - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(Index i1, const Matrix& A1, Index i2, const Matrix& A2, - Index i3, const Matrix& A3, const Vector& b, const SharedDiagonal& model) : - GaussianFactor(i1,i2,i3), model_(model), Ab_(matrix_) { - - if(model->dim() != (size_t) b.size()) - throw InvalidNoiseModel(b.size(), model->dim()); - - size_t dims[] = { A1.cols(), A2.cols(), A3.cols(), 1}; - Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+4, b.size())); - Ab_(0) = A1; - Ab_(1) = A2; - Ab_(2) = A3; - getb() = b; - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(const std::vector > &terms, - const Vector &b, const SharedDiagonal& model) : - GaussianFactor(GetKeys(terms.size(), terms.begin(), terms.end())), - model_(model), Ab_(matrix_) - { - // get number of measurements and variables involved in this factor - size_t m = b.size(), n = terms.size(); - - if(model->dim() != (size_t) m) - throw InvalidNoiseModel(b.size(), model->dim()); - - // Get the dimensions of each variable and copy to "dims" array, add 1 for RHS - size_t* dims = (size_t*)alloca(sizeof(size_t)*(n+1)); // FIXME: alloca is bad, just ask Google. - for(size_t j=0; j > &terms, - const Vector &b, const SharedDiagonal& model) : - GaussianFactor(GetKeys(terms.size(), terms.begin(), terms.end())), - model_(model), Ab_(matrix_) - { - - if(model->dim() != (size_t) b.size()) - throw InvalidNoiseModel(b.size(), model->dim()); - - size_t* dims=(size_t*)alloca(sizeof(size_t)*(terms.size()+1)); // FIXME: alloca is bad, just ask Google. - size_t j=0; - std::list >::const_iterator term=terms.begin(); - for(; term!=terms.end(); ++term,++j) - dims[j] = term->second.cols(); - dims[j] = 1; - Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+terms.size()+1, b.size())); - j = 0; - for(term=terms.begin(); term!=terms.end(); ++term,++j) - Ab_(j) = term->second; - getb() = b; - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(const GaussianConditional& cg) : - GaussianFactor(cg), - model_(noiseModel::Diagonal::Sigmas(cg.get_sigmas(), true)), - Ab_(matrix_) { - Ab_.assignNoalias(cg.rsd_); - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(const HessianFactor& factor) : Ab_(matrix_) { - keys_ = factor.keys_; - Ab_.assignNoalias(factor.info_); - - // Do Cholesky to get a Jacobian - size_t maxrank; - bool success; - boost::tie(maxrank, success) = choleskyCareful(matrix_); - - // Check for indefinite system - if(!success) - throw IndeterminantLinearSystemException(factor.keys().front()); - - // Zero out lower triangle - matrix_.topRows(maxrank).triangularView() = - Matrix::Zero(maxrank, matrix_.cols()); - // FIXME: replace with triangular system - Ab_.rowEnd() = maxrank; - model_ = noiseModel::Unit::Create(maxrank); - - assertInvariants(); - } - - /* ************************************************************************* */ - JacobianFactor::JacobianFactor(const GaussianFactorGraph& gfg) : Ab_(matrix_) { - // Cast or convert to Jacobians - FactorGraph jacobians; - BOOST_FOREACH(const GaussianFactorGraph::sharedFactor& factor, gfg) { - if(factor) { - if(JacobianFactor::shared_ptr jf = boost::dynamic_pointer_cast(factor)) - jacobians.push_back(jf); - else - jacobians.push_back(boost::make_shared(*factor)); - } - } - - *this = *CombineJacobians(jacobians, VariableSlots(jacobians)); - } - - /* ************************************************************************* */ - JacobianFactor& JacobianFactor::operator=(const JacobianFactor& rhs) { - this->Base::operator=(rhs); // Copy keys - model_ = rhs.model_; // Copy noise model - Ab_.assignNoalias(rhs.Ab_); // Copy matrix and block structure - assertInvariants(); - return *this; - } - - /* ************************************************************************* */ - void JacobianFactor::print(const string& s, const IndexFormatter& formatter) const { - cout << s << "\n"; - if (empty()) { - cout << " empty, keys: "; - BOOST_FOREACH(const Index& key, keys()) { cout << formatter(key) << " "; } - cout << endl; - } else { - for(const_iterator key=begin(); key!=end(); ++key) - cout << boost::format("A[%1%]=\n")%formatter(*key) << getA(key) << endl; - cout << "b=" << getb() << endl; - model_->print("model"); - } - } - - /* ************************************************************************* */ - // Check if two linear factors are equal - bool JacobianFactor::equals(const GaussianFactor& f_, double tol) const { - if(!dynamic_cast(&f_)) - return false; - else { - const JacobianFactor& f(static_cast(f_)); - if (empty()) return (f.empty()); - if(keys()!=f.keys() /*|| !model_->equals(lf->model_, tol)*/) - return false; - - if (!(Ab_.rows() == f.Ab_.rows() && Ab_.cols() == f.Ab_.cols())) - return false; - - constABlock Ab1(Ab_.range(0, Ab_.nBlocks())); - constABlock Ab2(f.Ab_.range(0, f.Ab_.nBlocks())); - for(size_t row=0; row< (size_t) Ab1.rows(); ++row) - if(!equal_with_abs_tol(Ab1.row(row), Ab2.row(row), tol) && - !equal_with_abs_tol(-Ab1.row(row), Ab2.row(row), tol)) - return false; - - return true; - } - } - - /* ************************************************************************* */ - Vector JacobianFactor::unweighted_error(const VectorValues& c) const { - Vector e = -getb(); - if (empty()) return e; - for(size_t pos=0; poswhiten(-getb()); - return model_->whiten(unweighted_error(c)); - } - - /* ************************************************************************* */ - double JacobianFactor::error(const VectorValues& c) const { - if (empty()) return 0; - Vector weighted = error_vector(c); - return 0.5 * weighted.dot(weighted); - } - - /* ************************************************************************* */ - Matrix JacobianFactor::augmentedInformation() const { - Matrix AbWhitened = Ab_.full(); - model_->WhitenInPlace(AbWhitened); - return AbWhitened.transpose() * AbWhitened; - } - - /* ************************************************************************* */ - Matrix JacobianFactor::information() const { - Matrix AWhitened = this->getA(); - model_->WhitenInPlace(AWhitened); - return AWhitened.transpose() * AWhitened; - } - - /* ************************************************************************* */ - Vector JacobianFactor::operator*(const VectorValues& x) const { - Vector Ax = zero(Ab_.rows()); - if (empty()) return Ax; - - // Just iterate over all A matrices and multiply in correct config part - for(size_t pos=0; poswhiten(Ax); - } - - /* ************************************************************************* */ - void JacobianFactor::transposeMultiplyAdd(double alpha, const Vector& e, - VectorValues& x) const { - Vector E = alpha * model_->whiten(e); - // Just iterate over all A matrices and insert Ai^e into VectorValues - for(size_t pos=0; pos JacobianFactor::matrix(bool weight) const { - Matrix A(Ab_.range(0, size())); - Vector b(getb()); - // divide in sigma so error is indeed 0.5*|Ax-b| - if (weight) model_->WhitenSystem(A,b); - return make_pair(A, b); - } - - /* ************************************************************************* */ - Matrix JacobianFactor::matrix_augmented(bool weight) const { - if (weight) { Matrix Ab(Ab_.range(0,Ab_.nBlocks())); model_->WhitenInPlace(Ab); return Ab; } - else return Ab_.range(0, Ab_.nBlocks()); - } - - /* ************************************************************************* */ - std::vector > - JacobianFactor::sparse(const std::vector& columnIndices) const { - - std::vector > entries; - - // iterate over all variables in the factor - for(const_iterator var=begin(); varWhiten(getA(var))); - // find first column index for this key - size_t column_start = columnIndices[*var]; - for (size_t i = 0; i < (size_t) whitenedA.rows(); i++) - for (size_t j = 0; j < (size_t) whitenedA.cols(); j++) { - double s = whitenedA(i,j); - if (std::abs(s) > 1e-12) entries.push_back( - boost::make_tuple(i, column_start + j, s)); - } - } - - Vector whitenedb(model_->whiten(getb())); - size_t bcolumn = columnIndices.back(); - for (size_t i = 0; i < (size_t) whitenedb.size(); i++) - entries.push_back(boost::make_tuple(i, bcolumn, whitenedb(i))); - - // return the result - return entries; - } - - /* ************************************************************************* */ - JacobianFactor JacobianFactor::whiten() const { - JacobianFactor result(*this); - result.model_->WhitenInPlace(result.matrix_); - result.model_ = noiseModel::Unit::Create(result.model_->dim()); - return result; - } - - /* ************************************************************************* */ - GaussianFactor::shared_ptr JacobianFactor::negate() const { - HessianFactor hessian(*this); - return hessian.negate(); - } - - /* ************************************************************************* */ - GaussianConditional::shared_ptr JacobianFactor::eliminateFirst() { - return this->eliminate(1); - } - - /* ************************************************************************* */ - GaussianConditional::shared_ptr JacobianFactor::splitConditional(size_t nrFrontals) { - assert(Ab_.rowStart() == 0 && Ab_.rowEnd() == (size_t) matrix_.rows() && Ab_.firstBlock() == 0); - assert(size() >= nrFrontals); - assertInvariants(); - - const bool debug = ISDEBUG("JacobianFactor::splitConditional"); - - if(debug) cout << "Eliminating " << nrFrontals << " frontal variables" << endl; - if(debug) this->print("Splitting JacobianFactor: "); - - size_t frontalDim = Ab_.range(0,nrFrontals).cols(); - - // Check for singular factor - if(model_->dim() < frontalDim) - throw IndeterminantLinearSystemException(this->keys().front()); - - // Extract conditional - gttic(cond_Rd); - - // Restrict the matrix to be in the first nrFrontals variables - Ab_.rowEnd() = Ab_.rowStart() + frontalDim; - const Eigen::VectorBlock sigmas = model_->sigmas().segment(Ab_.rowStart(), Ab_.rowEnd()-Ab_.rowStart()); - GaussianConditional::shared_ptr conditional(new GaussianConditional(begin(), end(), nrFrontals, Ab_, sigmas)); - if(debug) conditional->print("Extracted conditional: "); - Ab_.rowStart() += frontalDim; - Ab_.firstBlock() += nrFrontals; - gttoc(cond_Rd); - - if(debug) conditional->print("Extracted conditional: "); - - gttic(remaining_factor); - // Take lower-right block of Ab to get the new factor - Ab_.rowEnd() = model_->dim(); - keys_.erase(begin(), begin() + nrFrontals); - // Set sigmas with the right model - if (model_->isConstrained()) - model_ = noiseModel::Constrained::MixedSigmas(sub(model_->sigmas(), frontalDim, model_->dim())); - else - model_ = noiseModel::Diagonal::Sigmas(sub(model_->sigmas(), frontalDim, model_->dim())); - if(debug) this->print("Eliminated factor: "); - assert(Ab_.rows() <= Ab_.cols()-1); - gttoc(remaining_factor); - - if(debug) print("Eliminated factor: "); - - assertInvariants(); - - return conditional; - } - - /* ************************************************************************* */ - GaussianConditional::shared_ptr JacobianFactor::eliminate(size_t nrFrontals) { - - assert(Ab_.rowStart() == 0 && Ab_.rowEnd() == (size_t) matrix_.rows() && Ab_.firstBlock() == 0); - assert(size() >= nrFrontals); - assertInvariants(); - - const bool debug = ISDEBUG("JacobianFactor::eliminate"); - - if(debug) cout << "Eliminating " << nrFrontals << " frontal variables" << endl; - if(debug) this->print("Eliminating JacobianFactor: "); - if(debug) gtsam::print(matrix_, "Augmented Ab: "); - - size_t frontalDim = Ab_.range(0,nrFrontals).cols(); - - if(debug) cout << "frontalDim = " << frontalDim << endl; - - // Use in-place QR dense Ab appropriate to NoiseModel - gttic(QR); - SharedDiagonal noiseModel = model_->QR(matrix_); - // In the new unordered code, empty noise model indicates unit noise model, and I already - // modified QR to return an empty noise model. This just creates a unit noise model in that - // case because this old code does not handle empty noise models. - if(!noiseModel) - noiseModel = noiseModel::Unit::Create(std::min(matrix_.rows(), matrix_.cols() - 1)); - gttoc(QR); - - // Zero the lower-left triangle. todo: not all of these entries actually - // need to be zeroed if we are careful to start copying rows after the last - // structural zero. - if(matrix_.rows() > 0) - for(size_t j=0; j<(size_t) matrix_.cols(); ++j) - for(size_t i=j+1; idim(); ++i) - matrix_(i,j) = 0.0; - - if(debug) gtsam::print(matrix_, "QR result: "); - if(debug) noiseModel->print("QR result noise model: "); - - // Start of next part - model_ = noiseModel; - return splitConditional(nrFrontals); - } - - /* ************************************************************************* */ - void JacobianFactor::allocate(const VariableSlots& variableSlots, vector< - size_t>& varDims, size_t m) { - keys_.resize(variableSlots.size()); - std::transform(variableSlots.begin(), variableSlots.end(), begin(), - boost::bind(&VariableSlots::const_iterator::value_type::first, _1)); - varDims.push_back(1); - Ab_.copyStructureFrom(BlockAb(matrix_, varDims.begin(), varDims.end(), m)); - } - - /* ************************************************************************* */ - void JacobianFactor::setModel(bool anyConstrained, const Vector& sigmas) { - if((size_t) sigmas.size() != this->rows()) - throw InvalidNoiseModel(this->rows(), sigmas.size()); - if (anyConstrained) - model_ = noiseModel::Constrained::MixedSigmas(sigmas); - else - model_ = noiseModel::Diagonal::Sigmas(sigmas); - } - - /* ************************************************************************* */ - const char* JacobianFactor::InvalidNoiseModel::what() const throw() { - if(description_.empty()) - description_ = (boost::format( - "A JacobianFactor was attempted to be constructed or modified to use a\n" - "noise model of incompatible dimension. The JacobianFactor has\n" - "dimensionality (i.e. length of error vector) %d but the provided noise\n" - "model has dimensionality %d.") % factorDims % noiseModelDims).str(); - return description_.c_str(); - } - -} +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file JacobianFactor.cpp + * @author Richard Roberts + * @author Christian Potthast + * @author Frank Dellaert + * @date Dec 8, 2010 + */ + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif +#include +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace boost::assign; + +namespace gtsam { + + /* ************************************************************************* */ + JacobianFactor::JacobianFactor() : + Ab_(cref_list_of<1>(1), 0) + {} + + /* ************************************************************************* */ + JacobianFactor::JacobianFactor(const GaussianFactor& gf) { + // Copy the matrix data depending on what type of factor we're copying from + if(const JacobianFactor* rhs = dynamic_cast(&gf)) + *this = JacobianFactor(*rhs); + //else if(const HessianFactor* rhs = dynamic_cast(&gf)) + // *this = JacobianFactor(*rhs); + else + throw std::invalid_argument("In JacobianFactor(const GaussianFactor& rhs), rhs is neither a JacobianFactor nor a HessianFactor"); + } + + /* ************************************************************************* */ + JacobianFactor::JacobianFactor(const Vector& b_in) : + Ab_(cref_list_of<1>(1), b_in.size()) + { + getb() = b_in; + } + + /* ************************************************************************* */ + JacobianFactor::JacobianFactor(Key i1, const Matrix& A1, + const Vector& b, const SharedDiagonal& model) + { + fillTerms(cref_list_of<1>(make_pair(i1, A1)), b, model); + } + + /* ************************************************************************* */ + JacobianFactor::JacobianFactor( + const Key i1, const Matrix& A1, Key i2, const Matrix& A2, + const Vector& b, const SharedDiagonal& model) + { + fillTerms(cref_list_of<2> + (make_pair(i1,A1)) + (make_pair(i2,A2)), b, model); + } + + /* ************************************************************************* */ + JacobianFactor::JacobianFactor( + const Key i1, const Matrix& A1, Key i2, const Matrix& A2, + Key i3, const Matrix& A3, const Vector& b, const SharedDiagonal& model) + { + fillTerms(cref_list_of<3> + (make_pair(i1,A1)) + (make_pair(i2,A2)) + (make_pair(i3,A3)), b, model); + } + + /* ************************************************************************* */ + //JacobianFactor::JacobianFactor(const HessianFactor& factor) { + // keys_ = factor.keys_; + // Ab_.assignNoalias(factor.info_); + + // // Do Cholesky to get a Jacobian + // size_t maxrank; + // bool success; + // boost::tie(maxrank, success) = choleskyCareful(matrix_); + + // // Check for indefinite system + // if(!success) + // throw IndeterminantLinearSystemException(factor.keys().front()); + + // // Zero out lower triangle + // matrix_.topRows(maxrank).triangularView() = + // Matrix::Zero(maxrank, matrix_.cols()); + // // FIXME: replace with triangular system + // Ab_.rowEnd() = maxrank; + // model_ = noiseModel::Unit::Create(maxrank); + + // assertInvariants(); + //} + + /* ************************************************************************* */ + // Helper functions for combine constructor + namespace { + boost::tuple, DenseIndex, DenseIndex> _countDims( + const std::vector& factors, const vector& variableSlots) + { + gttic(countDims); +#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS + vector varDims(variableSlots.size(), numeric_limits::max()); +#else + vector varDims(variableSlots.size()); +#endif + DenseIndex m = 0; + DenseIndex n = 0; + { + size_t jointVarpos = 0; + BOOST_FOREACH(VariableSlots::const_iterator slots, variableSlots) + { + assert(slots->second.size() == factors.size()); + + size_t sourceFactorI = 0; + BOOST_FOREACH(const size_t sourceVarpos, slots->second) { + if(sourceVarpos < numeric_limits::max()) { + const JacobianFactor& sourceFactor = *factors[sourceFactorI]; + DenseIndex vardim = sourceFactor.getDim(sourceFactor.begin() + sourceVarpos); +#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS + if(varDims[jointVarpos] == numeric_limits::max()) { + varDims[jointVarpos] = vardim; + n += vardim; + } else + assert(varDims[jointVarpos] == vardim); +#else + varDims[jointVarpos] = vardim; + n += vardim; + break; +#endif + } + ++ sourceFactorI; + } + ++ jointVarpos; + } + BOOST_FOREACH(const JacobianFactor::shared_ptr& factor, factors) { + m += factor->rows(); + } + } + return boost::make_tuple(varDims, m, n); + } + + /* ************************************************************************* */ + std::vector + _convertOrCastToJacobians(const GaussianFactorGraph& factors) + { + gttic(Convert_to_Jacobians); + std::vector jacobians; + jacobians.reserve(factors.size()); + BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) { + if(factor) { + if(JacobianFactor::shared_ptr jf = boost::dynamic_pointer_cast(factor)) + jacobians.push_back(jf); + else + jacobians.push_back(boost::make_shared(*factor)); + } + } + return jacobians; + } + } + + /* ************************************************************************* */ + JacobianFactor::JacobianFactor( + const GaussianFactorGraph& graph, + boost::optional ordering, + boost::optional variableSlots) + { + gttic(JacobianFactor_combine_constructor); + + // Compute VariableSlots if one was not provided + gttic(Compute_VariableSlots); + boost::optional computedVariableSlots; + if(!variableSlots) { + computedVariableSlots = VariableSlots(graph); + variableSlots = computedVariableSlots; // Binds reference, does not copy VariableSlots + } + gttoc(Compute_VariableSlots); + + // Cast or convert to Jacobians + std::vector jacobians = _convertOrCastToJacobians(graph); + + gttic(Order_slots); + // Order variable slots - we maintain the vector of ordered slots, as well as keep a list + // 'unorderedSlots' of any variables discovered that are not in the ordering. Those will then + // be added after all of the ordered variables. + vector orderedSlots; + orderedSlots.reserve(variableSlots->size()); + if(ordering) { + // If an ordering is provided, arrange the slots first that ordering + FastList unorderedSlots; + size_t nOrderingSlotsUsed = 0; + orderedSlots.resize(ordering->size()); + FastMap inverseOrdering = ordering->invert(); + for(VariableSlots::const_iterator item = variableSlots->begin(); item != variableSlots->end(); ++item) { + FastMap::const_iterator orderingPosition = inverseOrdering.find(item->first); + if(orderingPosition == inverseOrdering.end()) { + unorderedSlots.push_back(item); + } else { + orderedSlots[orderingPosition->second] = item; + ++ nOrderingSlotsUsed; + } + } + if(nOrderingSlotsUsed != ordering->size()) + throw std::invalid_argument( + "The ordering provided to the JacobianFactor combine constructor\n" + "contained extra variables that did not appear in the factors to combine."); + // Add the remaining slots + BOOST_FOREACH(VariableSlots::const_iterator item, unorderedSlots) { + orderedSlots.push_back(item); + } + } else { + // If no ordering is provided, arrange the slots as they were, which will be sorted + // numerically since VariableSlots uses a map sorting on Key. + for(VariableSlots::const_iterator item = variableSlots->begin(); item != variableSlots->end(); ++item) + orderedSlots.push_back(item); + } + gttoc(Order_slots); + + // Count dimensions + vector varDims; + DenseIndex m, n; + boost::tie(varDims, m, n) = _countDims(jacobians, orderedSlots); + + // Allocate matrix and copy keys in order + gttic(allocate); + Ab_ = VerticalBlockMatrix(boost::join(varDims, cref_list_of<1,DenseIndex>(1)), m); // Allocate augmented matrix + Base::keys_.resize(orderedSlots.size()); + boost::range::copy( // Get variable keys + orderedSlots | boost::adaptors::indirected | boost::adaptors::map_keys, Base::keys_.begin()); + gttoc(allocate); + + // Loop over slots in combined factor and copy blocks from source factors + gttic(copy_blocks); + size_t combinedSlot = 0; + BOOST_FOREACH(VariableSlots::const_iterator varslot, orderedSlots) { + JacobianFactor::ABlock destSlot(this->getA(this->begin()+combinedSlot)); + // Loop over source jacobians + DenseIndex nextRow = 0; + for(size_t factorI = 0; factorI < jacobians.size(); ++factorI) { + // Slot in source factor + const size_t sourceSlot = varslot->second[factorI]; + const DenseIndex sourceRows = jacobians[factorI]->rows(); + JacobianFactor::ABlock::RowsBlockXpr destBlock(destSlot.middleRows(nextRow, sourceRows)); + // Copy if exists in source factor, otherwise set zero + if(sourceSlot != numeric_limits::max()) + destBlock = jacobians[factorI]->getA(jacobians[factorI]->begin()+sourceSlot); + else + destBlock.setZero(); + nextRow += sourceRows; + } + ++combinedSlot; + } + gttoc(copy_blocks); + + // Copy the RHS vectors and sigmas + gttic(copy_vectors); + bool anyConstrained = false; + boost::optional sigmas; + // Loop over source jacobians + DenseIndex nextRow = 0; + for(size_t factorI = 0; factorI < jacobians.size(); ++factorI) { + const DenseIndex sourceRows = jacobians[factorI]->rows(); + this->getb().segment(nextRow, sourceRows) = jacobians[factorI]->getb(); + if(jacobians[factorI]->get_model()) { + // If the factor has a noise model and we haven't yet allocated sigmas, allocate it. + if(!sigmas) + sigmas = Vector::Constant(m, 1.0); + sigmas->segment(nextRow, sourceRows) = jacobians[factorI]->get_model()->sigmas(); + if (jacobians[factorI]->isConstrained()) + anyConstrained = true; + } + nextRow += sourceRows; + } + gttoc(copy_vectors); + + if(sigmas) + this->setModel(anyConstrained, *sigmas); + } + + /* ************************************************************************* */ + void JacobianFactor::print(const string& s, const KeyFormatter& formatter) const + { + if(!s.empty()) + cout << s << "\n"; + for(const_iterator key = begin(); key != end(); ++key) { + cout << + formatMatrixIndented((boost::format(" A[%1%] = ") % formatter(*key)).str(), getA(key)) + << endl; + } + cout << formatMatrixIndented(" b = ", getb(), true) << "\n"; + if(model_) + model_->print(" Noise model: "); + else + cout << " No noise model" << endl; + } + + /* ************************************************************************* */ + // Check if two linear factors are equal + bool JacobianFactor::equals(const GaussianFactor& f_, double tol) const + { + if(!dynamic_cast(&f_)) + return false; + else { + const JacobianFactor& f(static_cast(f_)); + + // Check keys + if(keys() != f.keys()) + return false; + + // Check noise model + if(model_ && !f.model_ || !model_ && f.model_) + return false; + if(model_ && f.model_ && !model_->equals(*f.model_, tol)) + return false; + + // Check matrix sizes + if (!(Ab_.rows() == f.Ab_.rows() && Ab_.cols() == f.Ab_.cols())) + return false; + + // Check matrix contents + constABlock Ab1(Ab_.range(0, Ab_.nBlocks())); + constABlock Ab2(f.Ab_.range(0, f.Ab_.nBlocks())); + for(size_t row=0; row< (size_t) Ab1.rows(); ++row) + if(!equal_with_abs_tol(Ab1.row(row), Ab2.row(row), tol) && + !equal_with_abs_tol(-Ab1.row(row), Ab2.row(row), tol)) + return false; + + return true; + } + } + + /* ************************************************************************* */ + Vector JacobianFactor::unweighted_error(const VectorValues& c) const { + Vector e = -getb(); + for(size_t pos=0; poswhiten(-getb()); + return model_->whiten(unweighted_error(c)); + } + + /* ************************************************************************* */ + double JacobianFactor::error(const VectorValues& c) const { + if (empty()) return 0; + Vector weighted = error_vector(c); + return 0.5 * weighted.dot(weighted); + } + + /* ************************************************************************* */ + Matrix JacobianFactor::augmentedInformation() const { + if(model_) { + Matrix AbWhitened = Ab_.full(); + model_->WhitenInPlace(AbWhitened); + return AbWhitened.transpose() * AbWhitened; + } else { + return Ab_.full().transpose() * Ab_.full(); + } + } + + /* ************************************************************************* */ + Matrix JacobianFactor::information() const { + if(model_) { + Matrix AWhitened = this->getA(); + model_->WhitenInPlace(AWhitened); + return AWhitened.transpose() * AWhitened; + } else { + return this->getA().transpose() * this->getA(); + } + } + + /* ************************************************************************* */ + Vector JacobianFactor::operator*(const VectorValues& x) const { + Vector Ax = zero(Ab_.rows()); + if (empty()) return Ax; + + // Just iterate over all A matrices and multiply in correct config part + for(size_t pos=0; poswhiten(Ax); + } + + /* ************************************************************************* */ + void JacobianFactor::transposeMultiplyAdd(double alpha, const Vector& e, + VectorValues& x) const + { + Vector E = alpha * model_->whiten(e); + // Just iterate over all A matrices and insert Ai^e into VectorValues + for(size_t pos=0; pos xi = x.tryInsert(keys_[pos], Vector()); + if(xi.second) + xi.first->second = Vector::Zero(getDim(begin() + pos)); + gtsam::transposeMultiplyAdd(1.0, Ab_(pos), E, xi.first->second); + } + } + + /* ************************************************************************* */ + pair JacobianFactor::jacobian(bool weight) const { + Matrix A(Ab_.range(0, size())); + Vector b(getb()); + // divide in sigma so error is indeed 0.5*|Ax-b| + if (weight && model_) + model_->WhitenSystem(A,b); + return make_pair(A, b); + } + + /* ************************************************************************* */ + Matrix JacobianFactor::augmentedJacobian(bool weight) const { + if (weight && model_) { + Matrix Ab(Ab_.range(0,Ab_.nBlocks())); + model_->WhitenInPlace(Ab); + return Ab; + } else { + return Ab_.range(0, Ab_.nBlocks()); + } + } + + /* ************************************************************************* */ + JacobianFactor JacobianFactor::whiten() const { + JacobianFactor result(*this); + if(model_) { + result.model_->WhitenInPlace(result.Ab_.matrix()); + result.model_ = noiseModel::Unit::Create(result.model_->dim()); + } + return result; + } + + /* ************************************************************************* */ + //GaussianFactor::shared_ptr JacobianFactor::negate() const { + // HessianFactor hessian(*this); + // return hessian.negate(); + //} + + /* ************************************************************************* */ + std::pair, boost::shared_ptr > + JacobianFactor::eliminate(const Ordering& keys) + { + GaussianFactorGraph graph; + graph.add(*this); + return EliminateQR(graph, keys); + } + + /* ************************************************************************* */ + void JacobianFactor::setModel(bool anyConstrained, const Vector& sigmas) { + if((size_t) sigmas.size() != this->rows()) + throw InvalidNoiseModel(this->rows(), sigmas.size()); + if (anyConstrained) + model_ = noiseModel::Constrained::MixedSigmas(sigmas); + else + model_ = noiseModel::Diagonal::Sigmas(sigmas); + } + + /* ************************************************************************* */ + std::pair, boost::shared_ptr > + EliminateQR(const GaussianFactorGraph& factors, const Ordering& keys) + { + gttic(EliminateQR); + // Combine and sort variable blocks in elimination order + JacobianFactor::shared_ptr jointFactor; + try { + jointFactor = boost::make_shared(factors, keys); + } catch(std::invalid_argument& e) { + (void) e; // Avoid unused variable warning + throw InvalidDenseElimination( + "EliminateQR was called with a request to eliminate variables that are not\n" + "involved in the provided factors."); + } + + // Do dense elimination + SharedDiagonal noiseModel; + if(jointFactor->model_) + jointFactor->model_ = jointFactor->model_->QR(jointFactor->Ab_.matrix()); + else + inplace_QR(jointFactor->Ab_.matrix()); + + // Zero below the diagonal + jointFactor->Ab_.matrix().triangularView().setZero(); + + // Split elimination result into conditional and remaining factor + GaussianConditional::shared_ptr conditional = jointFactor->splitConditional(keys.size()); + + return make_pair(conditional, jointFactor); + } + + /* ************************************************************************* */ + GaussianConditional::shared_ptr JacobianFactor::splitConditional(size_t nrFrontals) + { + if(nrFrontals > size()) + throw std::invalid_argument("Requesting to split more variables than exist using JacobianFactor::splitConditional"); + + size_t frontalDim = Ab_.range(0, nrFrontals).cols(); + + // Check for singular factor + // TODO: fix this check + //if(model_->dim() < frontalDim) + // throw IndeterminantLinearSystemException(this->keys().front()); + + // Restrict the matrix to be in the first nrFrontals variables and create the conditional + gttic(cond_Rd); + const DenseIndex originalRowEnd = Ab_.rowEnd(); + Ab_.rowEnd() = Ab_.rowStart() + frontalDim; + SharedDiagonal conditionalNoiseModel; + if(model_) + conditionalNoiseModel = + noiseModel::Diagonal::Sigmas(model_->sigmas().segment(Ab_.rowStart(), Ab_.rowEnd()-Ab_.rowStart())); + GaussianConditional::shared_ptr conditional = boost::make_shared( + Base::keys_, nrFrontals, Ab_, conditionalNoiseModel); + Ab_.rowStart() += frontalDim; + Ab_.rowEnd() = std::min(Ab_.cols() - 1, originalRowEnd); + Ab_.firstBlock() += nrFrontals; + gttoc(cond_Rd); + + // Take lower-right block of Ab to get the new factor + gttic(remaining_factor); + keys_.erase(begin(), begin() + nrFrontals); + // Set sigmas with the right model + if(model_) { + if (model_->isConstrained()) + model_ = noiseModel::Constrained::MixedSigmas(model_->sigmas().tail(model_->sigmas().size() - frontalDim)); + else + model_ = noiseModel::Diagonal::Sigmas(model_->sigmas().tail(model_->sigmas().size() - frontalDim)); + } + gttoc(remaining_factor); + + return conditional; + } + +} diff --git a/gtsam/linear/JacobianFactor.h b/gtsam/linear/JacobianFactor.h index 01de4953a..960c8e976 100644 --- a/gtsam/linear/JacobianFactor.h +++ b/gtsam/linear/JacobianFactor.h @@ -1,335 +1,303 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file JacobianFactor.h - * @author Richard Roberts - * @date Dec 8, 2010 - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -// Forward declarations of friend unit tests -class JacobianFactorCombine2Test; -class JacobianFactoreliminateFrontalsTest; -class JacobianFactorconstructor2Test; - -namespace gtsam { - - // Forward declarations - class HessianFactor; - class VariableSlots; - template class BayesNet; - class GaussianFactorGraph; - - /** - * A Gaussian factor in the squared-error form. - * - * JacobianFactor implements a - * Gaussian, which has quadratic negative log-likelihood - * \f[ E(x) = \frac{1}{2} (Ax-b)^T \Sigma^{-1} (Ax-b) \f] - * where \f$ \Sigma \f$ is a \a diagonal covariance matrix. The - * matrix \f$ A \f$, r.h.s. vector \f$ b \f$, and diagonal noise model - * \f$ \Sigma \f$ are stored in this class. - * - * This factor represents the sum-of-squares error of a \a linear - * measurement function, and is created upon linearization of a NoiseModelFactor, - * which in turn is a sum-of-squares factor with a nonlinear measurement function. - * - * Here is an example of how this factor represents a sum-of-squares error: - * - * Letting \f$ h(x) \f$ be a \a linear measurement prediction function, \f$ z \f$ be - * the actual observed measurement, the residual is - * \f[ f(x) = h(x) - z . \f] - * If we expect noise with diagonal covariance matrix \f$ \Sigma \f$ on this - * measurement, then the negative log-likelihood of the Gaussian induced by this - * measurement model is - * \f[ E(x) = \frac{1}{2} (h(x) - z)^T \Sigma^{-1} (h(x) - z) . \f] - * Because \f$ h(x) \f$ is linear, we can write it as - * \f[ h(x) = Ax + e \f] - * and thus we have - * \f[ E(x) = \frac{1}{2} (Ax-b)^T \Sigma^{-1} (Ax-b) \f] - * where \f$ b = z - e \f$. - * - * This factor can involve an arbitrary number of variables, and in the - * above example \f$ x \f$ would almost always be only be a subset of the variables - * in the entire factor graph. There are special constructors for 1-, 2-, and 3- - * way JacobianFactors, and additional constructors for creating n-way JacobianFactors. - * The Jacobian matrix \f$ A \f$ is passed to these constructors in blocks, - * for example, for a 2-way factor, the constructor would accept \f$ A1 \f$ and \f$ A2 \f$, - * as well as the variable indices \f$ j1 \f$ and \f$ j2 \f$ - * and the negative log-likelihood represented by this factor would be - * \f[ E(x) = \frac{1}{2} (A_1 x_{j1} + A_2 x_{j2} - b)^T \Sigma^{-1} (A_1 x_{j1} + A_2 x_{j2} - b) . \f] - */ - class GTSAM_EXPORT JacobianFactor : public GaussianFactor { - protected: - typedef Matrix AbMatrix; - typedef VerticalBlockView BlockAb; - - noiseModel::Diagonal::shared_ptr model_; // Gaussian noise model with diagonal covariance matrix - AbMatrix matrix_; // the full matrix corresponding to the factor - BlockAb Ab_; // the block view of the full matrix - typedef GaussianFactor Base; // typedef to base - - public: - typedef boost::shared_ptr shared_ptr; - typedef BlockAb::Block ABlock; - typedef BlockAb::constBlock constABlock; - typedef BlockAb::Column BVector; - typedef BlockAb::constColumn constBVector; - - /** Copy constructor */ - JacobianFactor(const JacobianFactor& gf); - - /** Convert from other GaussianFactor */ - JacobianFactor(const GaussianFactor& gf); - - /** default constructor for I/O */ - JacobianFactor(); - - /** Construct Null factor */ - JacobianFactor(const Vector& b_in); - - /** Construct unary factor */ - JacobianFactor(Index i1, const Matrix& A1, - const Vector& b, const SharedDiagonal& model); - - /** Construct binary factor */ - JacobianFactor(Index i1, const Matrix& A1, - Index i2, const Matrix& A2, - const Vector& b, const SharedDiagonal& model); - - /** Construct ternary factor */ - JacobianFactor(Index i1, const Matrix& A1, Index i2, - const Matrix& A2, Index i3, const Matrix& A3, - const Vector& b, const SharedDiagonal& model); - - /** Construct an n-ary factor */ - JacobianFactor(const std::vector > &terms, - const Vector &b, const SharedDiagonal& model); - - JacobianFactor(const std::list > &terms, - const Vector &b, const SharedDiagonal& model); - - /** Construct from Conditional Gaussian */ - JacobianFactor(const GaussianConditional& cg); - - /** Convert from a HessianFactor (does Cholesky) */ - JacobianFactor(const HessianFactor& factor); - - /** Build a dense joint factor from all the factors in a factor graph. */ - JacobianFactor(const GaussianFactorGraph& gfg); - - /** Virtual destructor */ - virtual ~JacobianFactor() {} - - /** Aassignment operator */ - JacobianFactor& operator=(const JacobianFactor& rhs); - - /** Clone this JacobianFactor */ - virtual GaussianFactor::shared_ptr clone() const { - return boost::static_pointer_cast( - shared_ptr(new JacobianFactor(*this))); - } - - // Implementing Testable interface - virtual void print(const std::string& s = "", - const IndexFormatter& formatter = DefaultIndexFormatter) const; - virtual bool equals(const GaussianFactor& lf, double tol = 1e-9) const; - - Vector unweighted_error(const VectorValues& c) const; /** (A*x-b) */ - Vector error_vector(const VectorValues& c) const; /** (A*x-b)/sigma */ - virtual double error(const VectorValues& c) const; /** 0.5*(A*x-b)'*D*(A*x-b) */ - - /** Return the augmented information matrix represented by this GaussianFactor. - * The augmented information matrix contains the information matrix with an - * additional column holding the information vector, and an additional row - * holding the transpose of the information vector. The lower-right entry - * contains the constant error term (when \f$ \delta x = 0 \f$). The - * augmented information matrix is described in more detail in HessianFactor, - * which in fact stores an augmented information matrix. - */ - virtual Matrix augmentedInformation() const; +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file JacobianFactor.h + * @author Richard Roberts + * @author Christian Potthast + * @author Frank Dellaert + * @date Dec 8, 2010 + */ +#pragma once + +#include +#include +#include +#include + +#include + +namespace gtsam { + + // Forward declarations + //class HessianFactor; + class VariableSlots; + class GaussianFactorGraph; + class GaussianConditional; + class VectorValues; + class Ordering; + + /** + * A Gaussian factor in the squared-error form. + * + * JacobianFactor implements a + * Gaussian, which has quadratic negative log-likelihood + * \f[ E(x) = \frac{1}{2} (Ax-b)^T \Sigma^{-1} (Ax-b) \f] + * where \f$ \Sigma \f$ is a \a diagonal covariance matrix. The + * matrix \f$ A \f$, r.h.s. vector \f$ b \f$, and diagonal noise model + * \f$ \Sigma \f$ are stored in this class. + * + * This factor represents the sum-of-squares error of a \a linear + * measurement function, and is created upon linearization of a NoiseModelFactor, + * which in turn is a sum-of-squares factor with a nonlinear measurement function. + * + * Here is an example of how this factor represents a sum-of-squares error: + * + * Letting \f$ h(x) \f$ be a \a linear measurement prediction function, \f$ z \f$ be + * the actual observed measurement, the residual is + * \f[ f(x) = h(x) - z . \f] + * If we expect noise with diagonal covariance matrix \f$ \Sigma \f$ on this + * measurement, then the negative log-likelihood of the Gaussian induced by this + * measurement model is + * \f[ E(x) = \frac{1}{2} (h(x) - z)^T \Sigma^{-1} (h(x) - z) . \f] + * Because \f$ h(x) \f$ is linear, we can write it as + * \f[ h(x) = Ax + e \f] + * and thus we have + * \f[ E(x) = \frac{1}{2} (Ax-b)^T \Sigma^{-1} (Ax-b) \f] + * where \f$ b = z - e \f$. + * + * This factor can involve an arbitrary number of variables, and in the + * above example \f$ x \f$ would almost always be only be a subset of the variables + * in the entire factor graph. There are special constructors for 1-, 2-, and 3- + * way JacobianFactors, and additional constructors for creating n-way JacobianFactors. + * The Jacobian matrix \f$ A \f$ is passed to these constructors in blocks, + * for example, for a 2-way factor, the constructor would accept \f$ A1 \f$ and \f$ A2 \f$, + * as well as the variable indices \f$ j1 \f$ and \f$ j2 \f$ + * and the negative log-likelihood represented by this factor would be + * \f[ E(x) = \frac{1}{2} (A_1 x_{j1} + A_2 x_{j2} - b)^T \Sigma^{-1} (A_1 x_{j1} + A_2 x_{j2} - b) . \f] + */ + class GTSAM_EXPORT JacobianFactor : public GaussianFactor + { + public: + typedef JacobianFactor This; ///< Typedef to this class + typedef GaussianFactor Base; ///< Typedef to base class + typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class + + protected: + VerticalBlockMatrix Ab_; // the block view of the full matrix + noiseModel::Diagonal::shared_ptr model_; // Gaussian noise model with diagonal covariance matrix + + public: + typedef VerticalBlockMatrix::Block ABlock; + typedef VerticalBlockMatrix::constBlock constABlock; + typedef VerticalBlockMatrix::Column BVector; + typedef VerticalBlockMatrix::constColumn constBVector; + + /** Convert from other GaussianFactor */ + explicit JacobianFactor(const GaussianFactor& gf); + + /** default constructor for I/O */ + JacobianFactor(); + + /** Construct Null factor */ + explicit JacobianFactor(const Vector& b_in); + + /** Construct unary factor */ + JacobianFactor(Key i1, const Matrix& A1, + const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + + /** Construct binary factor */ + JacobianFactor(Key i1, const Matrix& A1, + Key i2, const Matrix& A2, + const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + + /** Construct ternary factor */ + JacobianFactor(Key i1, const Matrix& A1, Key i2, + const Matrix& A2, Key i3, const Matrix& A3, + const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + + /** Construct an n-ary factor + * @tparam TERMS A container whose value type is std::pair, specifying the + * collection of keys and matrices making up the factor. */ + template + JacobianFactor(const TERMS& terms, const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + + /** Constructor with arbitrary number keys, and where the augmented matrix is given all together + * instead of in block terms. Note that only the active view of the provided augmented matrix + * is used, and that the matrix data is copied into a newly-allocated matrix in the constructed + * factor. */ + template + JacobianFactor( + const KEYS& keys, const VerticalBlockMatrix& augmentedMatrix, const SharedDiagonal& sigmas = SharedDiagonal()); + + /** Convert from a HessianFactor (does Cholesky) */ + //JacobianFactor(const HessianFactor& factor); + + /** + * Build a dense joint factor from all the factors in a factor graph. If a VariableSlots + * structure computed for \c graph is already available, providing it will reduce the amount of + * computation performed. */ + explicit JacobianFactor( + const GaussianFactorGraph& graph, + boost::optional ordering = boost::none, + boost::optional variableSlots = boost::none); + + /** Virtual destructor */ + virtual ~JacobianFactor() {} + + /** Clone this JacobianFactor */ + virtual GaussianFactor::shared_ptr clone() const { + return boost::static_pointer_cast( + boost::make_shared(*this)); + } + + // Implementing Testable interface + virtual void print(const std::string& s = "", + const KeyFormatter& formatter = DefaultKeyFormatter) const; + virtual bool equals(const GaussianFactor& lf, double tol = 1e-9) const; + + Vector unweighted_error(const VectorValues& c) const; /** (A*x-b) */ + Vector error_vector(const VectorValues& c) const; /** (A*x-b)/sigma */ + virtual double error(const VectorValues& c) const; /** 0.5*(A*x-b)'*D*(A*x-b) */ + + /** Return the augmented information matrix represented by this GaussianFactor. + * The augmented information matrix contains the information matrix with an + * additional column holding the information vector, and an additional row + * holding the transpose of the information vector. The lower-right entry + * contains the constant error term (when \f$ \delta x = 0 \f$). The + * augmented information matrix is described in more detail in HessianFactor, + * which in fact stores an augmented information matrix. + */ + virtual Matrix augmentedInformation() const; /** Return the non-augmented information matrix represented by this * GaussianFactor. */ virtual Matrix information() const; - - /** - * Construct the corresponding anti-factor to negate information - * stored stored in this factor. - * @return a HessianFactor with negated Hessian matrices - */ - virtual GaussianFactor::shared_ptr negate() const; - - /** Check if the factor contains no information, i.e. zero rows. This does - * not necessarily mean that the factor involves no variables (to check for - * involving no variables use keys().empty()). - */ - bool empty() const { return Ab_.rows() == 0;} - - /** is noise model constrained ? */ - bool isConstrained() const { return model_->isConstrained();} - - /** Return the dimension of the variable pointed to by the given key iterator - * todo: Remove this in favor of keeping track of dimensions with variables? - */ - virtual size_t getDim(const_iterator variable) const { return Ab_(variable - begin()).cols(); } - - /** - * return the number of rows in the corresponding linear system - */ - size_t rows() const { return Ab_.rows(); } - - /** - * return the number of rows in the corresponding linear system - */ - size_t numberOfRows() const { return rows(); } - - /** - * return the number of columns in the corresponding linear system - */ - size_t cols() const { return Ab_.cols(); } - - /** get a copy of model */ - const SharedDiagonal& get_model() const { return model_; } - - /** get a copy of model (non-const version) */ - SharedDiagonal& get_model() { return model_; } - - /** Get a view of the r.h.s. vector b */ - const constBVector getb() const { return Ab_.column(size(), 0); } - - /** Get a view of the A matrix for the variable pointed to by the given key iterator */ - constABlock getA(const_iterator variable) const { return Ab_(variable - begin()); } - - /** Get a view of the A matrix */ - constABlock getA() const { return Ab_.range(0, size()); } - - /** Get a view of the r.h.s. vector b (non-const version) */ - BVector getb() { return Ab_.column(size(), 0); } - - /** Get a view of the A matrix for the variable pointed to by the given key iterator (non-const version) */ - ABlock getA(iterator variable) { return Ab_(variable - begin()); } - - /** Get a view of the A matrix */ - ABlock getA() { return Ab_.range(0, size()); } - - /** Return A*x */ - Vector operator*(const VectorValues& x) const; - - /** x += A'*e */ - void transposeMultiplyAdd(double alpha, const Vector& e, VectorValues& x) const; - - /** - * Return (dense) matrix associated with factor - * @param ordering of variables needed for matrix column order - * @param set weight to true to bake in the weights - */ - std::pair matrix(bool weight = true) const; - - /** - * Return (dense) matrix associated with factor - * The returned system is an augmented matrix: [A b] - * @param set weight to use whitening to bake in weights - */ - Matrix matrix_augmented(bool weight = true) const; - - /** - * Return vector of i, j, and s to generate an m-by-n sparse matrix - * such that S(i(k),j(k)) = s(k), which can be given to MATLAB's sparse. - * As above, the standard deviations are baked into A and b - * @param columnIndices First column index for each variable. - */ - std::vector > - sparse(const std::vector& columnIndices) const; - - /** - * Return a whitened version of the factor, i.e. with unit diagonal noise - * model. */ - JacobianFactor whiten() const; - - /** Eliminate the first variable, modifying the factor in place to contain the remaining marginal. */ - boost::shared_ptr eliminateFirst(); - - /** Eliminate the requested number of frontal variables, modifying the factor in place to contain the remaining marginal. */ - boost::shared_ptr eliminate(size_t nrFrontals = 1); - - /** - * splits a pre-factorized factor into a conditional, and changes the current - * factor to be the remaining component. Performs same operation as eliminate(), - * but without running QR. - */ - boost::shared_ptr splitConditional(size_t nrFrontals = 1); - - // following methods all used in CombineJacobians: - // Many imperative, perhaps all need to be combined in constructor - - /** allocate space */ - void allocate(const VariableSlots& variableSlots, - std::vector& varDims, size_t m); - - /** set noiseModel correctly */ - void setModel(bool anyConstrained, const Vector& sigmas); - - /** Assert invariants after elimination */ - void assertInvariants() const; - - /** An exception indicating that the noise model dimension passed into the - * JacobianFactor has a different dimensionality than the factor. */ - class InvalidNoiseModel : public std::exception { - public: - const size_t factorDims; ///< The dimensionality of the factor - const size_t noiseModelDims; ///< The dimensionality of the noise model - - InvalidNoiseModel(size_t factorDims, size_t noiseModelDims) : - factorDims(factorDims), noiseModelDims(noiseModelDims) {} - virtual ~InvalidNoiseModel() throw() {} - - virtual const char* what() const throw(); - - private: - mutable std::string description_; - }; - - private: - - // Friend HessianFactor to facilitate conversion constructors - friend class HessianFactor; - - // Friend unit tests (see also forward declarations above) - friend class ::JacobianFactorCombine2Test; - friend class ::JacobianFactoreliminateFrontalsTest; - friend class ::JacobianFactorconstructor2Test; - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(GaussianFactor); - ar & BOOST_SERIALIZATION_NVP(Ab_); - ar & BOOST_SERIALIZATION_NVP(model_); - ar & BOOST_SERIALIZATION_NVP(matrix_); - } - }; // JacobianFactor - -} // gtsam - + + /** + * Return (dense) matrix associated with factor + * @param ordering of variables needed for matrix column order + * @param set weight to true to bake in the weights + */ + virtual std::pair jacobian(bool weight = true) const; + + /** + * Return (dense) matrix associated with factor + * The returned system is an augmented matrix: [A b] + * @param set weight to use whitening to bake in weights + */ + virtual Matrix augmentedJacobian(bool weight = true) const; + + /** + * Construct the corresponding anti-factor to negate information + * stored stored in this factor. + * @return a HessianFactor with negated Hessian matrices + */ + //virtual GaussianFactor::shared_ptr negate() const; + + /** Check if the factor contains no information, i.e. zero rows. This does + * not necessarily mean that the factor involves no variables (to check for + * involving no variables use keys().empty()). + */ + virtual bool empty() const { return size() == 0 /*|| rows() == 0*/; } + + /** is noise model constrained ? */ + bool isConstrained() const { return model_->isConstrained(); } + + /** Return the dimension of the variable pointed to by the given key iterator + * todo: Remove this in favor of keeping track of dimensions with variables? + */ + virtual size_t getDim(const_iterator variable) const { return Ab_(variable - begin()).cols(); } + + /** + * return the number of rows in the corresponding linear system + */ + size_t rows() const { return Ab_.rows(); } + + /** + * return the number of columns in the corresponding linear system + */ + size_t cols() const { return Ab_.cols(); } + + /** get a copy of model */ + const SharedDiagonal& get_model() const { return model_; } + + /** get a copy of model (non-const version) */ + SharedDiagonal& get_model() { return model_; } + + /** Get a view of the r.h.s. vector b */ + const constBVector getb() const { return Ab_(size()).col(0); } + + /** Get a view of the A matrix for the variable pointed to by the given key iterator */ + constABlock getA(const_iterator variable) const { return Ab_(variable - begin()); } + + /** Get a view of the A matrix */ + constABlock getA() const { return Ab_.range(0, size()); } + + /** Get a view of the r.h.s. vector b (non-const version) */ + BVector getb() { return Ab_(size()).col(0); } + + /** Get a view of the A matrix for the variable pointed to by the given key iterator (non-const version) */ + ABlock getA(iterator variable) { return Ab_(variable - begin()); } + + /** Get a view of the A matrix */ + ABlock getA() { return Ab_.range(0, size()); } + + /** Return A*x */ + Vector operator*(const VectorValues& x) const; + + /** x += A'*e. If x is initially missing any values, they are created and assumed to start as + * zero vectors. */ + void transposeMultiplyAdd(double alpha, const Vector& e, VectorValues& x) const; + + /** Return a whitened version of the factor, i.e. with unit diagonal noise model. */ + JacobianFactor whiten() const; + + /** Eliminate the requested variables. */ + std::pair, boost::shared_ptr > + eliminate(const Ordering& keys); + + /** set noiseModel correctly */ + void setModel(bool anyConstrained, const Vector& sigmas); + + /** + * Densely partially eliminate with QR factorization, this is usually provided as an argument to + * one of the factor graph elimination functions (see EliminateableFactorGraph). HessianFactors + * are first factored with Cholesky decomposition to produce JacobianFactors, by calling the + * conversion constructor JacobianFactor(const HessianFactor&). Variables are eliminated in the + * order specified in \c keys. + * @param factors Factors to combine and eliminate + * @param keys The variables to eliminate in the order as specified here in \c keys + * @return The conditional and remaining factor + * + * \addtogroup LinearSolving */ + friend GTSAM_EXPORT std::pair, boost::shared_ptr > + EliminateQR(const GaussianFactorGraph& factors, const Ordering& keys); + + private: + + /// Internal function to fill blocks and set dimensions + template + void fillTerms(const TERMS& terms, const Vector& b, const SharedDiagonal& noiseModel); + + /** + * splits a pre-factorized factor into a conditional, and changes the current + * factor to be the remaining component. Performs same operation as eliminate(), + * but without running QR. + */ + boost::shared_ptr splitConditional(size_t nrFrontals = 1); + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); + ar & BOOST_SERIALIZATION_NVP(Ab_); + ar & BOOST_SERIALIZATION_NVP(model_); + } + }; // JacobianFactor + +} // gtsam + +#include + + diff --git a/gtsam/linear/JacobianFactorOrdered.cpp b/gtsam/linear/JacobianFactorOrdered.cpp new file mode 100644 index 000000000..ced8881ba --- /dev/null +++ b/gtsam/linear/JacobianFactorOrdered.cpp @@ -0,0 +1,533 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file JacobianFactor.cpp + * @author Richard Roberts + * @date Dec 8, 2010 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif +#include +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#include +#include +#include + +using namespace std; + +namespace gtsam { + + /* ************************************************************************* */ + void JacobianFactorOrdered::assertInvariants() const { +#ifndef NDEBUG + GaussianFactorOrdered::assertInvariants(); // The base class checks for unique keys + assert((size() == 0 && Ab_.rows() == 0 && Ab_.nBlocks() == 0) || size()+1 == Ab_.nBlocks()); +#endif + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(const JacobianFactorOrdered& gf) : + GaussianFactorOrdered(gf), model_(gf.model_), Ab_(matrix_) { + Ab_.assignNoalias(gf.Ab_); + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(const GaussianFactorOrdered& gf) : Ab_(matrix_) { + // Copy the matrix data depending on what type of factor we're copying from + if(const JacobianFactorOrdered* rhs = dynamic_cast(&gf)) + *this = JacobianFactorOrdered(*rhs); + else if(const HessianFactorOrdered* rhs = dynamic_cast(&gf)) + *this = JacobianFactorOrdered(*rhs); + else + throw std::invalid_argument("In JacobianFactor(const GaussianFactor& rhs), rhs is neither a JacobianFactor nor a HessianFactor"); + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered() : Ab_(matrix_) { assertInvariants(); } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(const Vector& b_in) : Ab_(matrix_) { + size_t dims[] = { 1 }; + Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+1, b_in.size())); + getb() = b_in; + model_ = noiseModel::Unit::Create(this->rows()); + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(Index i1, const Matrix& A1, + const Vector& b, const SharedDiagonal& model) : + GaussianFactorOrdered(i1), model_(model), Ab_(matrix_) { + + if(model->dim() != (size_t) b.size()) + throw InvalidNoiseModel(b.size(), model->dim()); + + size_t dims[] = { A1.cols(), 1}; + Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+2, b.size())); + Ab_(0) = A1; + getb() = b; + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(Index i1, const Matrix& A1, Index i2, const Matrix& A2, + const Vector& b, const SharedDiagonal& model) : + GaussianFactorOrdered(i1,i2), model_(model), Ab_(matrix_) { + + if(model->dim() != (size_t) b.size()) + throw InvalidNoiseModel(b.size(), model->dim()); + + size_t dims[] = { A1.cols(), A2.cols(), 1}; + Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+3, b.size())); + Ab_(0) = A1; + Ab_(1) = A2; + getb() = b; + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(Index i1, const Matrix& A1, Index i2, const Matrix& A2, + Index i3, const Matrix& A3, const Vector& b, const SharedDiagonal& model) : + GaussianFactorOrdered(i1,i2,i3), model_(model), Ab_(matrix_) { + + if(model->dim() != (size_t) b.size()) + throw InvalidNoiseModel(b.size(), model->dim()); + + size_t dims[] = { A1.cols(), A2.cols(), A3.cols(), 1}; + Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+4, b.size())); + Ab_(0) = A1; + Ab_(1) = A2; + Ab_(2) = A3; + getb() = b; + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(const std::vector > &terms, + const Vector &b, const SharedDiagonal& model) : + GaussianFactorOrdered(GetKeys(terms.size(), terms.begin(), terms.end())), + model_(model), Ab_(matrix_) + { + // get number of measurements and variables involved in this factor + size_t m = b.size(), n = terms.size(); + + if(model->dim() != (size_t) m) + throw InvalidNoiseModel(b.size(), model->dim()); + + // Get the dimensions of each variable and copy to "dims" array, add 1 for RHS + size_t* dims = (size_t*)alloca(sizeof(size_t)*(n+1)); // FIXME: alloca is bad, just ask Google. + for(size_t j=0; j > &terms, + const Vector &b, const SharedDiagonal& model) : + GaussianFactorOrdered(GetKeys(terms.size(), terms.begin(), terms.end())), + model_(model), Ab_(matrix_) + { + + if(model->dim() != (size_t) b.size()) + throw InvalidNoiseModel(b.size(), model->dim()); + + size_t* dims=(size_t*)alloca(sizeof(size_t)*(terms.size()+1)); // FIXME: alloca is bad, just ask Google. + size_t j=0; + std::list >::const_iterator term=terms.begin(); + for(; term!=terms.end(); ++term,++j) + dims[j] = term->second.cols(); + dims[j] = 1; + Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+terms.size()+1, b.size())); + j = 0; + for(term=terms.begin(); term!=terms.end(); ++term,++j) + Ab_(j) = term->second; + getb() = b; + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(const GaussianConditionalOrdered& cg) : + GaussianFactorOrdered(cg), + model_(noiseModel::Diagonal::Sigmas(cg.get_sigmas(), true)), + Ab_(matrix_) { + Ab_.assignNoalias(cg.rsd_); + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(const HessianFactorOrdered& factor) : Ab_(matrix_) { + keys_ = factor.keys_; + Ab_.assignNoalias(factor.info_); + + // Do Cholesky to get a Jacobian + size_t maxrank; + bool success; + boost::tie(maxrank, success) = choleskyCareful(matrix_); + + // Check for indefinite system + if(!success) + throw IndeterminantLinearSystemException(factor.keys().front()); + + // Zero out lower triangle + matrix_.topRows(maxrank).triangularView() = + Matrix::Zero(maxrank, matrix_.cols()); + // FIXME: replace with triangular system + Ab_.rowEnd() = maxrank; + model_ = noiseModel::Unit::Create(maxrank); + + assertInvariants(); + } + + /* ************************************************************************* */ + JacobianFactorOrdered::JacobianFactorOrdered(const GaussianFactorGraphOrdered& gfg) : Ab_(matrix_) { + // Cast or convert to Jacobians + FactorGraphOrdered jacobians; + BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, gfg) { + if(factor) { + if(JacobianFactorOrdered::shared_ptr jf = boost::dynamic_pointer_cast(factor)) + jacobians.push_back(jf); + else + jacobians.push_back(boost::make_shared(*factor)); + } + } + + *this = *CombineJacobians(jacobians, VariableSlots(jacobians)); + } + + /* ************************************************************************* */ + JacobianFactorOrdered& JacobianFactorOrdered::operator=(const JacobianFactorOrdered& rhs) { + this->Base::operator=(rhs); // Copy keys + model_ = rhs.model_; // Copy noise model + Ab_.assignNoalias(rhs.Ab_); // Copy matrix and block structure + assertInvariants(); + return *this; + } + + /* ************************************************************************* */ + void JacobianFactorOrdered::print(const string& s, const IndexFormatter& formatter) const { + cout << s << "\n"; + if (empty()) { + cout << " empty, keys: "; + BOOST_FOREACH(const Index& key, keys()) { cout << formatter(key) << " "; } + cout << endl; + } else { + for(const_iterator key=begin(); key!=end(); ++key) + cout << boost::format("A[%1%]=\n")%formatter(*key) << getA(key) << endl; + cout << "b=" << getb() << endl; + model_->print("model"); + } + } + + /* ************************************************************************* */ + // Check if two linear factors are equal + bool JacobianFactorOrdered::equals(const GaussianFactorOrdered& f_, double tol) const { + if(!dynamic_cast(&f_)) + return false; + else { + const JacobianFactorOrdered& f(static_cast(f_)); + if (empty()) return (f.empty()); + if(keys()!=f.keys() /*|| !model_->equals(lf->model_, tol)*/) + return false; + + if (!(Ab_.rows() == f.Ab_.rows() && Ab_.cols() == f.Ab_.cols())) + return false; + + constABlock Ab1(Ab_.range(0, Ab_.nBlocks())); + constABlock Ab2(f.Ab_.range(0, f.Ab_.nBlocks())); + for(size_t row=0; row< (size_t) Ab1.rows(); ++row) + if(!equal_with_abs_tol(Ab1.row(row), Ab2.row(row), tol) && + !equal_with_abs_tol(-Ab1.row(row), Ab2.row(row), tol)) + return false; + + return true; + } + } + + /* ************************************************************************* */ + Vector JacobianFactorOrdered::unweighted_error(const VectorValuesOrdered& c) const { + Vector e = -getb(); + if (empty()) return e; + for(size_t pos=0; poswhiten(-getb()); + return model_->whiten(unweighted_error(c)); + } + + /* ************************************************************************* */ + double JacobianFactorOrdered::error(const VectorValuesOrdered& c) const { + if (empty()) return 0; + Vector weighted = error_vector(c); + return 0.5 * weighted.dot(weighted); + } + + /* ************************************************************************* */ + Matrix JacobianFactorOrdered::augmentedInformation() const { + Matrix AbWhitened = Ab_.full(); + model_->WhitenInPlace(AbWhitened); + return AbWhitened.transpose() * AbWhitened; + } + + /* ************************************************************************* */ + Matrix JacobianFactorOrdered::information() const { + Matrix AWhitened = this->getA(); + model_->WhitenInPlace(AWhitened); + return AWhitened.transpose() * AWhitened; + } + + /* ************************************************************************* */ + Vector JacobianFactorOrdered::operator*(const VectorValuesOrdered& x) const { + Vector Ax = zero(Ab_.rows()); + if (empty()) return Ax; + + // Just iterate over all A matrices and multiply in correct config part + for(size_t pos=0; poswhiten(Ax); + } + + /* ************************************************************************* */ + void JacobianFactorOrdered::transposeMultiplyAdd(double alpha, const Vector& e, + VectorValuesOrdered& x) const { + Vector E = alpha * model_->whiten(e); + // Just iterate over all A matrices and insert Ai^e into VectorValues + for(size_t pos=0; pos JacobianFactorOrdered::matrix(bool weight) const { + Matrix A(Ab_.range(0, size())); + Vector b(getb()); + // divide in sigma so error is indeed 0.5*|Ax-b| + if (weight) model_->WhitenSystem(A,b); + return make_pair(A, b); + } + + /* ************************************************************************* */ + Matrix JacobianFactorOrdered::matrix_augmented(bool weight) const { + if (weight) { Matrix Ab(Ab_.range(0,Ab_.nBlocks())); model_->WhitenInPlace(Ab); return Ab; } + else return Ab_.range(0, Ab_.nBlocks()); + } + + /* ************************************************************************* */ + std::vector > + JacobianFactorOrdered::sparse(const std::vector& columnIndices) const { + + std::vector > entries; + + // iterate over all variables in the factor + for(const_iterator var=begin(); varWhiten(getA(var))); + // find first column index for this key + size_t column_start = columnIndices[*var]; + for (size_t i = 0; i < (size_t) whitenedA.rows(); i++) + for (size_t j = 0; j < (size_t) whitenedA.cols(); j++) { + double s = whitenedA(i,j); + if (std::abs(s) > 1e-12) entries.push_back( + boost::make_tuple(i, column_start + j, s)); + } + } + + Vector whitenedb(model_->whiten(getb())); + size_t bcolumn = columnIndices.back(); + for (size_t i = 0; i < (size_t) whitenedb.size(); i++) + entries.push_back(boost::make_tuple(i, bcolumn, whitenedb(i))); + + // return the result + return entries; + } + + /* ************************************************************************* */ + JacobianFactorOrdered JacobianFactorOrdered::whiten() const { + JacobianFactorOrdered result(*this); + result.model_->WhitenInPlace(result.matrix_); + result.model_ = noiseModel::Unit::Create(result.model_->dim()); + return result; + } + + /* ************************************************************************* */ + GaussianFactorOrdered::shared_ptr JacobianFactorOrdered::negate() const { + HessianFactorOrdered hessian(*this); + return hessian.negate(); + } + + /* ************************************************************************* */ + GaussianConditionalOrdered::shared_ptr JacobianFactorOrdered::eliminateFirst() { + return this->eliminate(1); + } + + /* ************************************************************************* */ + GaussianConditionalOrdered::shared_ptr JacobianFactorOrdered::splitConditional(size_t nrFrontals) { + assert(Ab_.rowStart() == 0 && Ab_.rowEnd() == (size_t) matrix_.rows() && Ab_.firstBlock() == 0); + assert(size() >= nrFrontals); + assertInvariants(); + + const bool debug = ISDEBUG("JacobianFactor::splitConditional"); + + if(debug) cout << "Eliminating " << nrFrontals << " frontal variables" << endl; + if(debug) this->print("Splitting JacobianFactor: "); + + size_t frontalDim = Ab_.range(0,nrFrontals).cols(); + + // Check for singular factor + if(model_->dim() < frontalDim) + throw IndeterminantLinearSystemException(this->keys().front()); + + // Extract conditional + gttic(cond_Rd); + + // Restrict the matrix to be in the first nrFrontals variables + Ab_.rowEnd() = Ab_.rowStart() + frontalDim; + const Eigen::VectorBlock sigmas = model_->sigmas().segment(Ab_.rowStart(), Ab_.rowEnd()-Ab_.rowStart()); + GaussianConditionalOrdered::shared_ptr conditional(new GaussianConditionalOrdered(begin(), end(), nrFrontals, Ab_, sigmas)); + if(debug) conditional->print("Extracted conditional: "); + Ab_.rowStart() += frontalDim; + Ab_.firstBlock() += nrFrontals; + gttoc(cond_Rd); + + if(debug) conditional->print("Extracted conditional: "); + + gttic(remaining_factor); + // Take lower-right block of Ab to get the new factor + Ab_.rowEnd() = model_->dim(); + keys_.erase(begin(), begin() + nrFrontals); + // Set sigmas with the right model + if (model_->isConstrained()) + model_ = noiseModel::Constrained::MixedSigmas(sub(model_->sigmas(), frontalDim, model_->dim())); + else + model_ = noiseModel::Diagonal::Sigmas(sub(model_->sigmas(), frontalDim, model_->dim())); + if(debug) this->print("Eliminated factor: "); + assert(Ab_.rows() <= Ab_.cols()-1); + gttoc(remaining_factor); + + if(debug) print("Eliminated factor: "); + + assertInvariants(); + + return conditional; + } + + /* ************************************************************************* */ + GaussianConditionalOrdered::shared_ptr JacobianFactorOrdered::eliminate(size_t nrFrontals) { + + assert(Ab_.rowStart() == 0 && Ab_.rowEnd() == (size_t) matrix_.rows() && Ab_.firstBlock() == 0); + assert(size() >= nrFrontals); + assertInvariants(); + + const bool debug = ISDEBUG("JacobianFactor::eliminate"); + + if(debug) cout << "Eliminating " << nrFrontals << " frontal variables" << endl; + if(debug) this->print("Eliminating JacobianFactor: "); + if(debug) gtsam::print(matrix_, "Augmented Ab: "); + + size_t frontalDim = Ab_.range(0,nrFrontals).cols(); + + if(debug) cout << "frontalDim = " << frontalDim << endl; + + // Use in-place QR dense Ab appropriate to NoiseModel + gttic(QR); + SharedDiagonal noiseModel = model_->QR(matrix_); + // In the new unordered code, empty noise model indicates unit noise model, and I already + // modified QR to return an empty noise model. This just creates a unit noise model in that + // case because this old code does not handle empty noise models. + if(!noiseModel) + noiseModel = noiseModel::Unit::Create(std::min(matrix_.rows(), matrix_.cols() - 1)); + gttoc(QR); + + // Zero the lower-left triangle. todo: not all of these entries actually + // need to be zeroed if we are careful to start copying rows after the last + // structural zero. + if(matrix_.rows() > 0) + for(size_t j=0; j<(size_t) matrix_.cols(); ++j) + for(size_t i=j+1; idim(); ++i) + matrix_(i,j) = 0.0; + + if(debug) gtsam::print(matrix_, "QR result: "); + if(debug) noiseModel->print("QR result noise model: "); + + // Start of next part + model_ = noiseModel; + return splitConditional(nrFrontals); + } + + /* ************************************************************************* */ + void JacobianFactorOrdered::allocate(const VariableSlots& variableSlots, vector< + size_t>& varDims, size_t m) { + keys_.resize(variableSlots.size()); + std::transform(variableSlots.begin(), variableSlots.end(), begin(), + boost::bind(&VariableSlots::const_iterator::value_type::first, _1)); + varDims.push_back(1); + Ab_.copyStructureFrom(BlockAb(matrix_, varDims.begin(), varDims.end(), m)); + } + + /* ************************************************************************* */ + void JacobianFactorOrdered::setModel(bool anyConstrained, const Vector& sigmas) { + if((size_t) sigmas.size() != this->rows()) + throw InvalidNoiseModel(this->rows(), sigmas.size()); + if (anyConstrained) + model_ = noiseModel::Constrained::MixedSigmas(sigmas); + else + model_ = noiseModel::Diagonal::Sigmas(sigmas); + } + + /* ************************************************************************* */ + const char* JacobianFactorOrdered::InvalidNoiseModel::what() const throw() { + if(description_.empty()) + description_ = (boost::format( + "A JacobianFactor was attempted to be constructed or modified to use a\n" + "noise model of incompatible dimension. The JacobianFactor has\n" + "dimensionality (i.e. length of error vector) %d but the provided noise\n" + "model has dimensionality %d.") % factorDims % noiseModelDims).str(); + return description_.c_str(); + } + +} diff --git a/gtsam/linear/JacobianFactorUnordered.h b/gtsam/linear/JacobianFactorOrdered.h similarity index 53% rename from gtsam/linear/JacobianFactorUnordered.h rename to gtsam/linear/JacobianFactorOrdered.h index 56b0922b7..cab39f7fa 100644 --- a/gtsam/linear/JacobianFactorUnordered.h +++ b/gtsam/linear/JacobianFactorOrdered.h @@ -12,28 +12,32 @@ /** * @file JacobianFactor.h * @author Richard Roberts - * @author Christian Potthast - * @author Frank Dellaert * @date Dec 8, 2010 */ #pragma once -#include +#include +#include +#include #include -#include +#include +#include #include -#include +#include + +// Forward declarations of friend unit tests +class JacobianFactorOrderedCombine2Test; +class JacobianFactorOrderedeliminateFrontalsTest; +class JacobianFactorOrderedconstructor2Test; namespace gtsam { // Forward declarations - //class HessianFactor; + class HessianFactorOrdered; class VariableSlots; - class GaussianFactorGraphUnordered; - class GaussianConditionalUnordered; - class VectorValuesUnordered; - class OrderingUnordered; + template class BayesNetOrdered; + class GaussianFactorGraphOrdered; /** * A Gaussian factor in the squared-error form. @@ -74,89 +78,85 @@ namespace gtsam { * and the negative log-likelihood represented by this factor would be * \f[ E(x) = \frac{1}{2} (A_1 x_{j1} + A_2 x_{j2} - b)^T \Sigma^{-1} (A_1 x_{j1} + A_2 x_{j2} - b) . \f] */ - class GTSAM_EXPORT JacobianFactorUnordered : public GaussianFactorUnordered - { - public: - typedef JacobianFactorUnordered This; ///< Typedef to this class - typedef GaussianFactorUnordered Base; ///< Typedef to base class - typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class - + class GTSAM_EXPORT JacobianFactorOrdered : public GaussianFactorOrdered { protected: - VerticalBlockMatrix Ab_; // the block view of the full matrix + typedef Matrix AbMatrix; + typedef VerticalBlockView BlockAb; + noiseModel::Diagonal::shared_ptr model_; // Gaussian noise model with diagonal covariance matrix + AbMatrix matrix_; // the full matrix corresponding to the factor + BlockAb Ab_; // the block view of the full matrix + typedef GaussianFactorOrdered Base; // typedef to base public: - typedef VerticalBlockMatrix::Block ABlock; - typedef VerticalBlockMatrix::constBlock constABlock; - typedef VerticalBlockMatrix::Column BVector; - typedef VerticalBlockMatrix::constColumn constBVector; + typedef boost::shared_ptr shared_ptr; + typedef BlockAb::Block ABlock; + typedef BlockAb::constBlock constABlock; + typedef BlockAb::Column BVector; + typedef BlockAb::constColumn constBVector; + + /** Copy constructor */ + JacobianFactorOrdered(const JacobianFactorOrdered& gf); /** Convert from other GaussianFactor */ - explicit JacobianFactorUnordered(const GaussianFactorUnordered& gf); + JacobianFactorOrdered(const GaussianFactorOrdered& gf); /** default constructor for I/O */ - JacobianFactorUnordered(); + JacobianFactorOrdered(); /** Construct Null factor */ - explicit JacobianFactorUnordered(const Vector& b_in); + JacobianFactorOrdered(const Vector& b_in); /** Construct unary factor */ - JacobianFactorUnordered(Key i1, const Matrix& A1, - const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + JacobianFactorOrdered(Index i1, const Matrix& A1, + const Vector& b, const SharedDiagonal& model); /** Construct binary factor */ - JacobianFactorUnordered(Key i1, const Matrix& A1, - Key i2, const Matrix& A2, - const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + JacobianFactorOrdered(Index i1, const Matrix& A1, + Index i2, const Matrix& A2, + const Vector& b, const SharedDiagonal& model); /** Construct ternary factor */ - JacobianFactorUnordered(Key i1, const Matrix& A1, Key i2, - const Matrix& A2, Key i3, const Matrix& A3, - const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + JacobianFactorOrdered(Index i1, const Matrix& A1, Index i2, + const Matrix& A2, Index i3, const Matrix& A3, + const Vector& b, const SharedDiagonal& model); - /** Construct an n-ary factor - * @tparam TERMS A container whose value type is std::pair, specifying the - * collection of keys and matrices making up the factor. */ - template - JacobianFactorUnordered(const TERMS& terms, const Vector& b, const SharedDiagonal& model = SharedDiagonal()); + /** Construct an n-ary factor */ + JacobianFactorOrdered(const std::vector > &terms, + const Vector &b, const SharedDiagonal& model); + + JacobianFactorOrdered(const std::list > &terms, + const Vector &b, const SharedDiagonal& model); + + /** Construct from Conditional Gaussian */ + JacobianFactorOrdered(const GaussianConditionalOrdered& cg); - /** Constructor with arbitrary number keys, and where the augmented matrix is given all together - * instead of in block terms. Note that only the active view of the provided augmented matrix - * is used, and that the matrix data is copied into a newly-allocated matrix in the constructed - * factor. */ - template - JacobianFactorUnordered( - const KEYS& keys, const VerticalBlockMatrix& augmentedMatrix, const SharedDiagonal& sigmas = SharedDiagonal()); - /** Convert from a HessianFactor (does Cholesky) */ - //JacobianFactorUnordered(const HessianFactor& factor); + JacobianFactorOrdered(const HessianFactorOrdered& factor); - /** - * Build a dense joint factor from all the factors in a factor graph. If a VariableSlots - * structure computed for \c graph is already available, providing it will reduce the amount of - * computation performed. */ - explicit JacobianFactorUnordered( - const GaussianFactorGraphUnordered& graph, - boost::optional ordering = boost::none, - boost::optional variableSlots = boost::none); + /** Build a dense joint factor from all the factors in a factor graph. */ + JacobianFactorOrdered(const GaussianFactorGraphOrdered& gfg); /** Virtual destructor */ - virtual ~JacobianFactorUnordered() {} + virtual ~JacobianFactorOrdered() {} - /** Clone this JacobianFactorUnordered */ - virtual GaussianFactorUnordered::shared_ptr clone() const { - return boost::static_pointer_cast( - boost::make_shared(*this)); + /** Aassignment operator */ + JacobianFactorOrdered& operator=(const JacobianFactorOrdered& rhs); + + /** Clone this JacobianFactor */ + virtual GaussianFactorOrdered::shared_ptr clone() const { + return boost::static_pointer_cast( + shared_ptr(new JacobianFactorOrdered(*this))); } // Implementing Testable interface virtual void print(const std::string& s = "", - const KeyFormatter& formatter = DefaultKeyFormatter) const; - virtual bool equals(const GaussianFactorUnordered& lf, double tol = 1e-9) const; + const IndexFormatter& formatter = DefaultIndexFormatter) const; + virtual bool equals(const GaussianFactorOrdered& lf, double tol = 1e-9) const; - Vector unweighted_error(const VectorValuesUnordered& c) const; /** (A*x-b) */ - Vector error_vector(const VectorValuesUnordered& c) const; /** (A*x-b)/sigma */ - virtual double error(const VectorValuesUnordered& c) const; /** 0.5*(A*x-b)'*D*(A*x-b) */ + Vector unweighted_error(const VectorValuesOrdered& c) const; /** (A*x-b) */ + Vector error_vector(const VectorValuesOrdered& c) const; /** (A*x-b)/sigma */ + virtual double error(const VectorValuesOrdered& c) const; /** 0.5*(A*x-b)'*D*(A*x-b) */ /** Return the augmented information matrix represented by this GaussianFactor. * The augmented information matrix contains the information matrix with an @@ -172,36 +172,22 @@ namespace gtsam { * GaussianFactor. */ virtual Matrix information() const; - - /** - * Return (dense) matrix associated with factor - * @param ordering of variables needed for matrix column order - * @param set weight to true to bake in the weights - */ - virtual std::pair jacobian(bool weight = true) const; - - /** - * Return (dense) matrix associated with factor - * The returned system is an augmented matrix: [A b] - * @param set weight to use whitening to bake in weights - */ - virtual Matrix augmentedJacobian(bool weight = true) const; /** * Construct the corresponding anti-factor to negate information * stored stored in this factor. * @return a HessianFactor with negated Hessian matrices */ - //virtual GaussianFactorUnordered::shared_ptr negate() const; + virtual GaussianFactorOrdered::shared_ptr negate() const; /** Check if the factor contains no information, i.e. zero rows. This does * not necessarily mean that the factor involves no variables (to check for * involving no variables use keys().empty()). */ - virtual bool empty() const { return size() == 0 /*|| rows() == 0*/; } + bool empty() const { return Ab_.rows() == 0;} /** is noise model constrained ? */ - bool isConstrained() const { return model_->isConstrained(); } + bool isConstrained() const { return model_->isConstrained();} /** Return the dimension of the variable pointed to by the given key iterator * todo: Remove this in favor of keeping track of dimensions with variables? @@ -213,6 +199,11 @@ namespace gtsam { */ size_t rows() const { return Ab_.rows(); } + /** + * return the number of rows in the corresponding linear system + */ + size_t numberOfRows() const { return rows(); } + /** * return the number of columns in the corresponding linear system */ @@ -225,7 +216,7 @@ namespace gtsam { SharedDiagonal& get_model() { return model_; } /** Get a view of the r.h.s. vector b */ - const constBVector getb() const { return Ab_(size()).col(0); } + const constBVector getb() const { return Ab_.column(size(), 0); } /** Get a view of the A matrix for the variable pointed to by the given key iterator */ constABlock getA(const_iterator variable) const { return Ab_(variable - begin()); } @@ -234,7 +225,7 @@ namespace gtsam { constABlock getA() const { return Ab_.range(0, size()); } /** Get a view of the r.h.s. vector b (non-const version) */ - BVector getb() { return Ab_(size()).col(0); } + BVector getb() { return Ab_.column(size(), 0); } /** Get a view of the A matrix for the variable pointed to by the given key iterator (non-const version) */ ABlock getA(iterator variable) { return Ab_(variable - begin()); } @@ -243,61 +234,102 @@ namespace gtsam { ABlock getA() { return Ab_.range(0, size()); } /** Return A*x */ - Vector operator*(const VectorValuesUnordered& x) const; + Vector operator*(const VectorValuesOrdered& x) const; - /** x += A'*e. If x is initially missing any values, they are created and assumed to start as - * zero vectors. */ - void transposeMultiplyAdd(double alpha, const Vector& e, VectorValuesUnordered& x) const; + /** x += A'*e */ + void transposeMultiplyAdd(double alpha, const Vector& e, VectorValuesOrdered& x) const; - /** Return a whitened version of the factor, i.e. with unit diagonal noise model. */ - JacobianFactorUnordered whiten() const; - - /** Eliminate the requested variables. */ - std::pair, boost::shared_ptr > - eliminate(const OrderingUnordered& keys); - - /** set noiseModel correctly */ - void setModel(bool anyConstrained, const Vector& sigmas); - /** - * Densely partially eliminate with QR factorization, this is usually provided as an argument to - * one of the factor graph elimination functions (see EliminateableFactorGraph). HessianFactors - * are first factored with Cholesky decomposition to produce JacobianFactors, by calling the - * conversion constructor JacobianFactor(const HessianFactor&). Variables are eliminated in the - * order specified in \c keys. - * @param factors Factors to combine and eliminate - * @param keys The variables to eliminate in the order as specified here in \c keys - * @return The conditional and remaining factor - * - * \addtogroup LinearSolving */ - friend GTSAM_EXPORT std::pair, boost::shared_ptr > - EliminateQRUnordered(const GaussianFactorGraphUnordered& factors, const OrderingUnordered& keys); + * Return (dense) matrix associated with factor + * @param ordering of variables needed for matrix column order + * @param set weight to true to bake in the weights + */ + std::pair matrix(bool weight = true) const; - private: + /** + * Return (dense) matrix associated with factor + * The returned system is an augmented matrix: [A b] + * @param set weight to use whitening to bake in weights + */ + Matrix matrix_augmented(bool weight = true) const; + + /** + * Return vector of i, j, and s to generate an m-by-n sparse matrix + * such that S(i(k),j(k)) = s(k), which can be given to MATLAB's sparse. + * As above, the standard deviations are baked into A and b + * @param columnIndices First column index for each variable. + */ + std::vector > + sparse(const std::vector& columnIndices) const; + + /** + * Return a whitened version of the factor, i.e. with unit diagonal noise + * model. */ + JacobianFactorOrdered whiten() const; + + /** Eliminate the first variable, modifying the factor in place to contain the remaining marginal. */ + boost::shared_ptr eliminateFirst(); + + /** Eliminate the requested number of frontal variables, modifying the factor in place to contain the remaining marginal. */ + boost::shared_ptr eliminate(size_t nrFrontals = 1); - /// Internal function to fill blocks and set dimensions - template - void fillTerms(const TERMS& terms, const Vector& b, const SharedDiagonal& noiseModel); - /** * splits a pre-factorized factor into a conditional, and changes the current * factor to be the remaining component. Performs same operation as eliminate(), * but without running QR. */ - boost::shared_ptr splitConditional(size_t nrFrontals = 1); + boost::shared_ptr splitConditional(size_t nrFrontals = 1); + + // following methods all used in CombineJacobians: + // Many imperative, perhaps all need to be combined in constructor + + /** allocate space */ + void allocate(const VariableSlots& variableSlots, + std::vector& varDims, size_t m); + + /** set noiseModel correctly */ + void setModel(bool anyConstrained, const Vector& sigmas); + + /** Assert invariants after elimination */ + void assertInvariants() const; + + /** An exception indicating that the noise model dimension passed into the + * JacobianFactor has a different dimensionality than the factor. */ + class InvalidNoiseModel : public std::exception { + public: + const size_t factorDims; ///< The dimensionality of the factor + const size_t noiseModelDims; ///< The dimensionality of the noise model + + InvalidNoiseModel(size_t factorDims, size_t noiseModelDims) : + factorDims(factorDims), noiseModelDims(noiseModelDims) {} + virtual ~InvalidNoiseModel() throw() {} + + virtual const char* what() const throw(); + + private: + mutable std::string description_; + }; + + private: + + // Friend HessianFactor to facilitate conversion constructors + friend class HessianFactorOrdered; + + // Friend unit tests (see also forward declarations above) + friend class ::JacobianFactorOrderedCombine2Test; + friend class ::JacobianFactorOrderedeliminateFrontalsTest; + friend class ::JacobianFactorOrderedconstructor2Test; /** Serialization function */ friend class boost::serialization::access; template void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); + ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(GaussianFactorOrdered); ar & BOOST_SERIALIZATION_NVP(Ab_); ar & BOOST_SERIALIZATION_NVP(model_); + ar & BOOST_SERIALIZATION_NVP(matrix_); } }; // JacobianFactor } // gtsam -#include - - diff --git a/gtsam/linear/JacobianFactorUnordered.cpp b/gtsam/linear/JacobianFactorUnordered.cpp deleted file mode 100644 index f395cc1a7..000000000 --- a/gtsam/linear/JacobianFactorUnordered.cpp +++ /dev/null @@ -1,574 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file JacobianFactor.cpp - * @author Richard Roberts - * @author Christian Potthast - * @author Frank Dellaert - * @date Dec 8, 2010 - */ - -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif -#include -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -#include -#include -#include - -#include -#include -#include - -using namespace std; -using namespace boost::assign; - -namespace gtsam { - - /* ************************************************************************* */ - JacobianFactorUnordered::JacobianFactorUnordered() : - Ab_(cref_list_of<1>(1), 0) - {} - - /* ************************************************************************* */ - JacobianFactorUnordered::JacobianFactorUnordered(const GaussianFactorUnordered& gf) { - // Copy the matrix data depending on what type of factor we're copying from - if(const JacobianFactorUnordered* rhs = dynamic_cast(&gf)) - *this = JacobianFactorUnordered(*rhs); - //else if(const HessianFactor* rhs = dynamic_cast(&gf)) - // *this = JacobianFactorUnordered(*rhs); - else - throw std::invalid_argument("In JacobianFactor(const GaussianFactor& rhs), rhs is neither a JacobianFactor nor a HessianFactor"); - } - - /* ************************************************************************* */ - JacobianFactorUnordered::JacobianFactorUnordered(const Vector& b_in) : - Ab_(cref_list_of<1>(1), b_in.size()) - { - getb() = b_in; - } - - /* ************************************************************************* */ - JacobianFactorUnordered::JacobianFactorUnordered(Key i1, const Matrix& A1, - const Vector& b, const SharedDiagonal& model) - { - fillTerms(cref_list_of<1>(make_pair(i1, A1)), b, model); - } - - /* ************************************************************************* */ - JacobianFactorUnordered::JacobianFactorUnordered( - const Key i1, const Matrix& A1, Key i2, const Matrix& A2, - const Vector& b, const SharedDiagonal& model) - { - fillTerms(cref_list_of<2> - (make_pair(i1,A1)) - (make_pair(i2,A2)), b, model); - } - - /* ************************************************************************* */ - JacobianFactorUnordered::JacobianFactorUnordered( - const Key i1, const Matrix& A1, Key i2, const Matrix& A2, - Key i3, const Matrix& A3, const Vector& b, const SharedDiagonal& model) - { - fillTerms(cref_list_of<3> - (make_pair(i1,A1)) - (make_pair(i2,A2)) - (make_pair(i3,A3)), b, model); - } - - /* ************************************************************************* */ - //JacobianFactorUnordered::JacobianFactorUnordered(const HessianFactorUnordered& factor) { - // keys_ = factor.keys_; - // Ab_.assignNoalias(factor.info_); - - // // Do Cholesky to get a Jacobian - // size_t maxrank; - // bool success; - // boost::tie(maxrank, success) = choleskyCareful(matrix_); - - // // Check for indefinite system - // if(!success) - // throw IndeterminantLinearSystemException(factor.keys().front()); - - // // Zero out lower triangle - // matrix_.topRows(maxrank).triangularView() = - // Matrix::Zero(maxrank, matrix_.cols()); - // // FIXME: replace with triangular system - // Ab_.rowEnd() = maxrank; - // model_ = noiseModel::Unit::Create(maxrank); - - // assertInvariants(); - //} - - /* ************************************************************************* */ - // Helper functions for combine constructor - namespace { - boost::tuple, DenseIndex, DenseIndex> _countDims( - const std::vector& factors, const vector& variableSlots) - { - gttic(countDims); -#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS - vector varDims(variableSlots.size(), numeric_limits::max()); -#else - vector varDims(variableSlots.size()); -#endif - DenseIndex m = 0; - DenseIndex n = 0; - { - size_t jointVarpos = 0; - BOOST_FOREACH(VariableSlots::const_iterator slots, variableSlots) - { - assert(slots->second.size() == factors.size()); - - size_t sourceFactorI = 0; - BOOST_FOREACH(const size_t sourceVarpos, slots->second) { - if(sourceVarpos < numeric_limits::max()) { - const JacobianFactorUnordered& sourceFactor = *factors[sourceFactorI]; - DenseIndex vardim = sourceFactor.getDim(sourceFactor.begin() + sourceVarpos); -#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS - if(varDims[jointVarpos] == numeric_limits::max()) { - varDims[jointVarpos] = vardim; - n += vardim; - } else - assert(varDims[jointVarpos] == vardim); -#else - varDims[jointVarpos] = vardim; - n += vardim; - break; -#endif - } - ++ sourceFactorI; - } - ++ jointVarpos; - } - BOOST_FOREACH(const JacobianFactorUnordered::shared_ptr& factor, factors) { - m += factor->rows(); - } - } - return boost::make_tuple(varDims, m, n); - } - - /* ************************************************************************* */ - std::vector - _convertOrCastToJacobians(const GaussianFactorGraphUnordered& factors) - { - gttic(Convert_to_Jacobians); - std::vector jacobians; - jacobians.reserve(factors.size()); - BOOST_FOREACH(const GaussianFactorUnordered::shared_ptr& factor, factors) { - if(factor) { - if(JacobianFactorUnordered::shared_ptr jf = boost::dynamic_pointer_cast(factor)) - jacobians.push_back(jf); - else - jacobians.push_back(boost::make_shared(*factor)); - } - } - return jacobians; - } - } - - /* ************************************************************************* */ - JacobianFactorUnordered::JacobianFactorUnordered( - const GaussianFactorGraphUnordered& graph, - boost::optional ordering, - boost::optional variableSlots) - { - gttic(JacobianFactorUnordered_combine_constructor); - - // Compute VariableSlots if one was not provided - gttic(Compute_VariableSlots); - boost::optional computedVariableSlots; - if(!variableSlots) { - computedVariableSlots = VariableSlots(graph); - variableSlots = computedVariableSlots; // Binds reference, does not copy VariableSlots - } - gttoc(Compute_VariableSlots); - - // Cast or convert to Jacobians - std::vector jacobians = _convertOrCastToJacobians(graph); - - gttic(Order_slots); - // Order variable slots - we maintain the vector of ordered slots, as well as keep a list - // 'unorderedSlots' of any variables discovered that are not in the ordering. Those will then - // be added after all of the ordered variables. - vector orderedSlots; - orderedSlots.reserve(variableSlots->size()); - if(ordering) { - // If an ordering is provided, arrange the slots first that ordering - FastList unorderedSlots; - size_t nOrderingSlotsUsed = 0; - orderedSlots.resize(ordering->size()); - FastMap inverseOrdering = ordering->invert(); - for(VariableSlots::const_iterator item = variableSlots->begin(); item != variableSlots->end(); ++item) { - FastMap::const_iterator orderingPosition = inverseOrdering.find(item->first); - if(orderingPosition == inverseOrdering.end()) { - unorderedSlots.push_back(item); - } else { - orderedSlots[orderingPosition->second] = item; - ++ nOrderingSlotsUsed; - } - } - if(nOrderingSlotsUsed != ordering->size()) - throw std::invalid_argument( - "The ordering provided to the JacobianFactor combine constructor\n" - "contained extra variables that did not appear in the factors to combine."); - // Add the remaining slots - BOOST_FOREACH(VariableSlots::const_iterator item, unorderedSlots) { - orderedSlots.push_back(item); - } - } else { - // If no ordering is provided, arrange the slots as they were, which will be sorted - // numerically since VariableSlots uses a map sorting on Key. - for(VariableSlots::const_iterator item = variableSlots->begin(); item != variableSlots->end(); ++item) - orderedSlots.push_back(item); - } - gttoc(Order_slots); - - // Count dimensions - vector varDims; - DenseIndex m, n; - boost::tie(varDims, m, n) = _countDims(jacobians, orderedSlots); - - // Allocate matrix and copy keys in order - gttic(allocate); - Ab_ = VerticalBlockMatrix(boost::join(varDims, cref_list_of<1,DenseIndex>(1)), m); // Allocate augmented matrix - Base::keys_.resize(orderedSlots.size()); - boost::range::copy( // Get variable keys - orderedSlots | boost::adaptors::indirected | boost::adaptors::map_keys, Base::keys_.begin()); - gttoc(allocate); - - // Loop over slots in combined factor and copy blocks from source factors - gttic(copy_blocks); - size_t combinedSlot = 0; - BOOST_FOREACH(VariableSlots::const_iterator varslot, orderedSlots) { - JacobianFactorUnordered::ABlock destSlot(this->getA(this->begin()+combinedSlot)); - // Loop over source jacobians - DenseIndex nextRow = 0; - for(size_t factorI = 0; factorI < jacobians.size(); ++factorI) { - // Slot in source factor - const size_t sourceSlot = varslot->second[factorI]; - const DenseIndex sourceRows = jacobians[factorI]->rows(); - JacobianFactorUnordered::ABlock::RowsBlockXpr destBlock(destSlot.middleRows(nextRow, sourceRows)); - // Copy if exists in source factor, otherwise set zero - if(sourceSlot != numeric_limits::max()) - destBlock = jacobians[factorI]->getA(jacobians[factorI]->begin()+sourceSlot); - else - destBlock.setZero(); - nextRow += sourceRows; - } - ++combinedSlot; - } - gttoc(copy_blocks); - - // Copy the RHS vectors and sigmas - gttic(copy_vectors); - bool anyConstrained = false; - boost::optional sigmas; - // Loop over source jacobians - DenseIndex nextRow = 0; - for(size_t factorI = 0; factorI < jacobians.size(); ++factorI) { - const DenseIndex sourceRows = jacobians[factorI]->rows(); - this->getb().segment(nextRow, sourceRows) = jacobians[factorI]->getb(); - if(jacobians[factorI]->get_model()) { - // If the factor has a noise model and we haven't yet allocated sigmas, allocate it. - if(!sigmas) - sigmas = Vector::Constant(m, 1.0); - sigmas->segment(nextRow, sourceRows) = jacobians[factorI]->get_model()->sigmas(); - if (jacobians[factorI]->isConstrained()) - anyConstrained = true; - } - nextRow += sourceRows; - } - gttoc(copy_vectors); - - if(sigmas) - this->setModel(anyConstrained, *sigmas); - } - - /* ************************************************************************* */ - void JacobianFactorUnordered::print(const string& s, const KeyFormatter& formatter) const - { - if(!s.empty()) - cout << s << "\n"; - for(const_iterator key = begin(); key != end(); ++key) { - cout << - formatMatrixIndented((boost::format(" A[%1%] = ") % formatter(*key)).str(), getA(key)) - << endl; - } - cout << formatMatrixIndented(" b = ", getb(), true) << "\n"; - if(model_) - model_->print(" Noise model: "); - else - cout << " No noise model" << endl; - } - - /* ************************************************************************* */ - // Check if two linear factors are equal - bool JacobianFactorUnordered::equals(const GaussianFactorUnordered& f_, double tol) const - { - if(!dynamic_cast(&f_)) - return false; - else { - const JacobianFactorUnordered& f(static_cast(f_)); - - // Check keys - if(keys() != f.keys()) - return false; - - // Check noise model - if(model_ && !f.model_ || !model_ && f.model_) - return false; - if(model_ && f.model_ && !model_->equals(*f.model_, tol)) - return false; - - // Check matrix sizes - if (!(Ab_.rows() == f.Ab_.rows() && Ab_.cols() == f.Ab_.cols())) - return false; - - // Check matrix contents - constABlock Ab1(Ab_.range(0, Ab_.nBlocks())); - constABlock Ab2(f.Ab_.range(0, f.Ab_.nBlocks())); - for(size_t row=0; row< (size_t) Ab1.rows(); ++row) - if(!equal_with_abs_tol(Ab1.row(row), Ab2.row(row), tol) && - !equal_with_abs_tol(-Ab1.row(row), Ab2.row(row), tol)) - return false; - - return true; - } - } - - /* ************************************************************************* */ - Vector JacobianFactorUnordered::unweighted_error(const VectorValuesUnordered& c) const { - Vector e = -getb(); - for(size_t pos=0; poswhiten(-getb()); - return model_->whiten(unweighted_error(c)); - } - - /* ************************************************************************* */ - double JacobianFactorUnordered::error(const VectorValuesUnordered& c) const { - if (empty()) return 0; - Vector weighted = error_vector(c); - return 0.5 * weighted.dot(weighted); - } - - /* ************************************************************************* */ - Matrix JacobianFactorUnordered::augmentedInformation() const { - if(model_) { - Matrix AbWhitened = Ab_.full(); - model_->WhitenInPlace(AbWhitened); - return AbWhitened.transpose() * AbWhitened; - } else { - return Ab_.full().transpose() * Ab_.full(); - } - } - - /* ************************************************************************* */ - Matrix JacobianFactorUnordered::information() const { - if(model_) { - Matrix AWhitened = this->getA(); - model_->WhitenInPlace(AWhitened); - return AWhitened.transpose() * AWhitened; - } else { - return this->getA().transpose() * this->getA(); - } - } - - /* ************************************************************************* */ - Vector JacobianFactorUnordered::operator*(const VectorValuesUnordered& x) const { - Vector Ax = zero(Ab_.rows()); - if (empty()) return Ax; - - // Just iterate over all A matrices and multiply in correct config part - for(size_t pos=0; poswhiten(Ax); - } - - /* ************************************************************************* */ - void JacobianFactorUnordered::transposeMultiplyAdd(double alpha, const Vector& e, - VectorValuesUnordered& x) const - { - Vector E = alpha * model_->whiten(e); - // Just iterate over all A matrices and insert Ai^e into VectorValues - for(size_t pos=0; pos xi = x.tryInsert(keys_[pos], Vector()); - if(xi.second) - xi.first->second = Vector::Zero(getDim(begin() + pos)); - gtsam::transposeMultiplyAdd(1.0, Ab_(pos), E, xi.first->second); - } - } - - /* ************************************************************************* */ - pair JacobianFactorUnordered::jacobian(bool weight) const { - Matrix A(Ab_.range(0, size())); - Vector b(getb()); - // divide in sigma so error is indeed 0.5*|Ax-b| - if (weight && model_) - model_->WhitenSystem(A,b); - return make_pair(A, b); - } - - /* ************************************************************************* */ - Matrix JacobianFactorUnordered::augmentedJacobian(bool weight) const { - if (weight && model_) { - Matrix Ab(Ab_.range(0,Ab_.nBlocks())); - model_->WhitenInPlace(Ab); - return Ab; - } else { - return Ab_.range(0, Ab_.nBlocks()); - } - } - - /* ************************************************************************* */ - JacobianFactorUnordered JacobianFactorUnordered::whiten() const { - JacobianFactorUnordered result(*this); - if(model_) { - result.model_->WhitenInPlace(result.Ab_.matrix()); - result.model_ = noiseModel::Unit::Create(result.model_->dim()); - } - return result; - } - - /* ************************************************************************* */ - //GaussianFactorUnordered::shared_ptr JacobianFactorUnordered::negate() const { - // HessianFactor hessian(*this); - // return hessian.negate(); - //} - - /* ************************************************************************* */ - std::pair, boost::shared_ptr > - JacobianFactorUnordered::eliminate(const OrderingUnordered& keys) - { - GaussianFactorGraphUnordered graph; - graph.add(*this); - return EliminateQRUnordered(graph, keys); - } - - /* ************************************************************************* */ - void JacobianFactorUnordered::setModel(bool anyConstrained, const Vector& sigmas) { - if((size_t) sigmas.size() != this->rows()) - throw InvalidNoiseModel(this->rows(), sigmas.size()); - if (anyConstrained) - model_ = noiseModel::Constrained::MixedSigmas(sigmas); - else - model_ = noiseModel::Diagonal::Sigmas(sigmas); - } - - /* ************************************************************************* */ - std::pair, boost::shared_ptr > - EliminateQRUnordered(const GaussianFactorGraphUnordered& factors, const OrderingUnordered& keys) - { - gttic(EliminateQRUnordered); - // Combine and sort variable blocks in elimination order - JacobianFactorUnordered::shared_ptr jointFactor; - try { - jointFactor = boost::make_shared(factors, keys); - } catch(std::invalid_argument& e) { - (void) e; // Avoid unused variable warning - throw InvalidDenseElimination( - "EliminateQRUnordered was called with a request to eliminate variables that are not\n" - "involved in the provided factors."); - } - - // Do dense elimination - SharedDiagonal noiseModel; - if(jointFactor->model_) - jointFactor->model_ = jointFactor->model_->QR(jointFactor->Ab_.matrix()); - else - inplace_QR(jointFactor->Ab_.matrix()); - - // Zero below the diagonal - jointFactor->Ab_.matrix().triangularView().setZero(); - - // Split elimination result into conditional and remaining factor - GaussianConditionalUnordered::shared_ptr conditional = jointFactor->splitConditional(keys.size()); - - return make_pair(conditional, jointFactor); - } - - /* ************************************************************************* */ - GaussianConditionalUnordered::shared_ptr JacobianFactorUnordered::splitConditional(size_t nrFrontals) - { - if(nrFrontals > size()) - throw std::invalid_argument("Requesting to split more variables than exist using JacobianFactor::splitConditional"); - - size_t frontalDim = Ab_.range(0, nrFrontals).cols(); - - // Check for singular factor - // TODO: fix this check - //if(model_->dim() < frontalDim) - // throw IndeterminantLinearSystemException(this->keys().front()); - - // Restrict the matrix to be in the first nrFrontals variables and create the conditional - gttic(cond_Rd); - const DenseIndex originalRowEnd = Ab_.rowEnd(); - Ab_.rowEnd() = Ab_.rowStart() + frontalDim; - SharedDiagonal conditionalNoiseModel; - if(model_) - conditionalNoiseModel = - noiseModel::Diagonal::Sigmas(model_->sigmas().segment(Ab_.rowStart(), Ab_.rowEnd()-Ab_.rowStart())); - GaussianConditionalUnordered::shared_ptr conditional = boost::make_shared( - Base::keys_, nrFrontals, Ab_, conditionalNoiseModel); - Ab_.rowStart() += frontalDim; - Ab_.rowEnd() = std::min(Ab_.cols() - 1, originalRowEnd); - Ab_.firstBlock() += nrFrontals; - gttoc(cond_Rd); - - // Take lower-right block of Ab to get the new factor - gttic(remaining_factor); - keys_.erase(begin(), begin() + nrFrontals); - // Set sigmas with the right model - if(model_) { - if (model_->isConstrained()) - model_ = noiseModel::Constrained::MixedSigmas(model_->sigmas().tail(model_->sigmas().size() - frontalDim)); - else - model_ = noiseModel::Diagonal::Sigmas(model_->sigmas().tail(model_->sigmas().size() - frontalDim)); - } - gttoc(remaining_factor); - - return conditional; - } - -} diff --git a/gtsam/linear/KalmanFilter.cpp b/gtsam/linear/KalmanFilter.cpp index 4a4730e60..7576d0955 100644 --- a/gtsam/linear/KalmanFilter.cpp +++ b/gtsam/linear/KalmanFilter.cpp @@ -21,10 +21,10 @@ */ #include -#include +#include #include -#include -#include +#include +#include #include #include @@ -34,26 +34,26 @@ namespace gtsam { using namespace std; /// Auxiliary function to solve factor graph and return pointer to root conditional - KalmanFilter::State solve(const GaussianFactorGraph& factorGraph, bool useQR) + KalmanFilter::State solve(const GaussianFactorGraphOrdered& factorGraph, bool useQR) { // Start indices at zero Index nVars = 0; internal::Reduction remapping; - BOOST_FOREACH(const GaussianFactorGraph::sharedFactor& factor, factorGraph) + BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, factorGraph) BOOST_FOREACH(Index j, *factor) if(remapping.insert(make_pair(j, nVars)).second) ++ nVars; Permutation inverseRemapping = remapping.inverse(); - GaussianFactorGraph factorGraphOrdered(factorGraph); // NOTE this shares the factors with the original!! + GaussianFactorGraphOrdered factorGraphOrdered(factorGraph); // NOTE this shares the factors with the original!! factorGraphOrdered.reduceWithInverse(remapping); // Solve the factor graph GaussianSequentialSolver solver(factorGraphOrdered, useQR); - GaussianBayesNet::shared_ptr bayesNet = solver.eliminate(); + GaussianBayesNetOrdered::shared_ptr bayesNet = solver.eliminate(); // As this is a filter, all we need is the posterior P(x_t), // so we just keep the root of the Bayes net - GaussianConditional::shared_ptr conditional = bayesNet->back(); + GaussianConditionalOrdered::shared_ptr conditional = bayesNet->back(); // Undo the remapping factorGraphOrdered.permuteWithInverse(inverseRemapping); @@ -65,14 +65,14 @@ namespace gtsam { /* ************************************************************************* */ KalmanFilter::State fuse(const KalmanFilter::State& p, - GaussianFactor* newFactor, bool useQR) { + GaussianFactorOrdered* newFactor, bool useQR) { // Create a factor graph - GaussianFactorGraph factorGraph; + GaussianFactorGraphOrdered factorGraph; // push back previous solution and new factor factorGraph.push_back(p->toFactor()); - factorGraph.push_back(GaussianFactor::shared_ptr(newFactor)); + factorGraph.push_back(GaussianFactorOrdered::shared_ptr(newFactor)); // Eliminate graph in order x0, x1, to get Bayes net P(x0|x1)P(x1) return solve(factorGraph, useQR); @@ -83,7 +83,7 @@ namespace gtsam { const SharedDiagonal& P0) { // Create a factor graph f(x0), eliminate it into P(x0) - GaussianFactorGraph factorGraph; + GaussianFactorGraphOrdered factorGraph; factorGraph.add(0, I_, x0, P0); // |x-x0|^2_diagSigma return solve(factorGraph, useQR()); } @@ -92,9 +92,9 @@ namespace gtsam { KalmanFilter::State KalmanFilter::init(const Vector& x, const Matrix& P0) { // Create a factor graph f(x0), eliminate it into P(x0) - GaussianFactorGraph factorGraph; + GaussianFactorGraphOrdered factorGraph; // 0.5*(x-x0)'*inv(Sigma)*(x-x0) - HessianFactor::shared_ptr factor(new HessianFactor(0, x, P0)); + HessianFactorOrdered::shared_ptr factor(new HessianFactorOrdered(0, x, P0)); factorGraph.push_back(factor); return solve(factorGraph, useQR()); } @@ -111,7 +111,7 @@ namespace gtsam { // The factor related to the motion model is defined as // f2(x_{t},x_{t+1}) = (F*x_{t} + B*u - x_{t+1}) * Q^-1 * (F*x_{t} + B*u - x_{t+1})^T Index k = step(p); - return fuse(p, new JacobianFactor(k, -F, k + 1, I_, B * u, model), useQR()); + return fuse(p, new JacobianFactorOrdered(k, -F, k + 1, I_, B * u, model), useQR()); } /* ************************************************************************* */ @@ -136,7 +136,7 @@ namespace gtsam { Vector b = B * u, g2 = M * b, g1 = -Ft * g2; double f = dot(b, g2); Index k = step(p); - return fuse(p, new HessianFactor(k, k + 1, G11, G12, g1, G22, g2, f), + return fuse(p, new HessianFactorOrdered(k, k + 1, G11, G12, g1, G22, g2, f), useQR()); } @@ -146,7 +146,7 @@ namespace gtsam { // Nhe factor related to the motion model is defined as // f2(x_{t},x_{t+1}) = |A0*x_{t} + A1*x_{t+1} - b|^2 Index k = step(p); - return fuse(p, new JacobianFactor(k, A0, k + 1, A1, b, model), useQR()); + return fuse(p, new JacobianFactorOrdered(k, A0, k + 1, A1, b, model), useQR()); } /* ************************************************************************* */ @@ -156,7 +156,7 @@ namespace gtsam { // f2 = (h(x_{t}) - z_{t}) * R^-1 * (h(x_{t}) - z_{t})^T // = (x_{t} - z_{t}) * R^-1 * (x_{t} - z_{t})^T Index k = step(p); - return fuse(p, new JacobianFactor(k, H, z, model), useQR()); + return fuse(p, new JacobianFactorOrdered(k, H, z, model), useQR()); } /* ************************************************************************* */ @@ -167,7 +167,7 @@ namespace gtsam { Matrix G = Ht * M * H; Vector g = Ht * M * z; double f = dot(z, M * z); - return fuse(p, new HessianFactor(k, G, g, f), useQR()); + return fuse(p, new HessianFactorOrdered(k, G, g, f), useQR()); } /* ************************************************************************* */ diff --git a/gtsam/linear/SubgraphPreconditioner.cpp b/gtsam/linear/SubgraphPreconditioner.cpp index c12838fbd..f4cfce096 100644 --- a/gtsam/linear/SubgraphPreconditioner.cpp +++ b/gtsam/linear/SubgraphPreconditioner.cpp @@ -16,7 +16,7 @@ */ #include -#include +#include #include using namespace std; @@ -24,12 +24,12 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ - static GaussianFactorGraph::shared_ptr convertToJacobianFactors(const GaussianFactorGraph &gfg) { - GaussianFactorGraph::shared_ptr result(new GaussianFactorGraph()); - BOOST_FOREACH(const GaussianFactor::shared_ptr &gf, gfg) { - JacobianFactor::shared_ptr jf = boost::dynamic_pointer_cast(gf); + static GaussianFactorGraphOrdered::shared_ptr convertToJacobianFactors(const GaussianFactorGraphOrdered &gfg) { + GaussianFactorGraphOrdered::shared_ptr result(new GaussianFactorGraphOrdered()); + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr &gf, gfg) { + JacobianFactorOrdered::shared_ptr jf = boost::dynamic_pointer_cast(gf); if( !jf ) { - jf = boost::make_shared(*gf); // Convert any non-Jacobian factors to Jacobians (e.g. Hessian -> Jacobian with Cholesky) + jf = boost::make_shared(*gf); // Convert any non-Jacobian factors to Jacobians (e.g. Hessian -> Jacobian with Cholesky) } result->push_back(jf); } @@ -44,34 +44,34 @@ namespace gtsam { /* ************************************************************************* */ // x = xbar + inv(R1)*y - VectorValues SubgraphPreconditioner::x(const VectorValues& y) const { + VectorValuesOrdered SubgraphPreconditioner::x(const VectorValuesOrdered& y) const { return *xbar_ + gtsam::backSubstitute(*Rc1_, y); } /* ************************************************************************* */ - double error(const SubgraphPreconditioner& sp, const VectorValues& y) { + double error(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y) { Errors e(y); - VectorValues x = sp.x(y); + VectorValuesOrdered x = sp.x(y); Errors e2 = gaussianErrors(*sp.Ab2(),x); return 0.5 * (dot(e, e) + dot(e2,e2)); } /* ************************************************************************* */ // gradient is y + inv(R1')*A2'*(A2*inv(R1)*y-b2bar), - VectorValues gradient(const SubgraphPreconditioner& sp, const VectorValues& y) { - VectorValues x = gtsam::backSubstitute(*sp.Rc1(), y); /* inv(R1)*y */ + VectorValuesOrdered gradient(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y) { + VectorValuesOrdered x = gtsam::backSubstitute(*sp.Rc1(), y); /* inv(R1)*y */ Errors e = (*sp.Ab2()*x - *sp.b2bar()); /* (A2*inv(R1)*y-b2bar) */ - VectorValues v = VectorValues::Zero(x); + VectorValuesOrdered v = VectorValuesOrdered::Zero(x); transposeMultiplyAdd(*sp.Ab2(), 1.0, e, v); /* A2'*(A2*inv(R1)*y-b2bar) */ return y + gtsam::backSubstituteTranspose(*sp.Rc1(), v); } /* ************************************************************************* */ // Apply operator A, A*y = [I;A2*inv(R1)]*y = [y; A2*inv(R1)*y] - Errors operator*(const SubgraphPreconditioner& sp, const VectorValues& y) { + Errors operator*(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y) { Errors e(y); - VectorValues x = gtsam::backSubstitute(*sp.Rc1(), y); /* x=inv(R1)*y */ + VectorValuesOrdered x = gtsam::backSubstitute(*sp.Rc1(), y); /* x=inv(R1)*y */ Errors e2 = *sp.Ab2() * x; /* A2*x */ e.splice(e.end(), e2); return e; @@ -79,7 +79,7 @@ namespace gtsam { /* ************************************************************************* */ // In-place version that overwrites e - void multiplyInPlace(const SubgraphPreconditioner& sp, const VectorValues& y, Errors& e) { + void multiplyInPlace(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y, Errors& e) { Errors::iterator ei = e.begin(); for ( Index i = 0 ; i < y.size() ; ++i, ++ei ) { @@ -87,16 +87,16 @@ namespace gtsam { } // Add A2 contribution - VectorValues x = gtsam::backSubstitute(*sp.Rc1(), y); // x=inv(R1)*y + VectorValuesOrdered x = gtsam::backSubstitute(*sp.Rc1(), y); // x=inv(R1)*y gtsam::multiplyInPlace(*sp.Ab2(), x, ei); // use iterator version } /* ************************************************************************* */ // Apply operator A', A'*e = [I inv(R1')*A2']*e = e1 + inv(R1')*A2'*e2 - VectorValues operator^(const SubgraphPreconditioner& sp, const Errors& e) { + VectorValuesOrdered operator^(const SubgraphPreconditioner& sp, const Errors& e) { Errors::const_iterator it = e.begin(); - VectorValues y = sp.zero(); + VectorValuesOrdered y = sp.zero(); for ( Index i = 0 ; i < y.size() ; ++i, ++it ) y[i] = *it ; sp.transposeMultiplyAdd2(1.0,it,e.end(),y); @@ -106,7 +106,7 @@ namespace gtsam { /* ************************************************************************* */ // y += alpha*A'*e void transposeMultiplyAdd - (const SubgraphPreconditioner& sp, double alpha, const Errors& e, VectorValues& y) { + (const SubgraphPreconditioner& sp, double alpha, const Errors& e, VectorValuesOrdered& y) { Errors::const_iterator it = e.begin(); for ( Index i = 0 ; i < y.size() ; ++i, ++it ) { @@ -119,14 +119,14 @@ namespace gtsam { /* ************************************************************************* */ // y += alpha*inv(R1')*A2'*e2 void SubgraphPreconditioner::transposeMultiplyAdd2 (double alpha, - Errors::const_iterator it, Errors::const_iterator end, VectorValues& y) const { + Errors::const_iterator it, Errors::const_iterator end, VectorValuesOrdered& y) const { // create e2 with what's left of e // TODO can we avoid creating e2 by passing iterator to transposeMultiplyAdd ? Errors e2; while (it != end) e2.push_back(*(it++)); - VectorValues x = VectorValues::Zero(y); // x = 0 + VectorValuesOrdered x = VectorValuesOrdered::Zero(y); // x = 0 gtsam::transposeMultiplyAdd(*Ab2_,1.0,e2,x); // x += A2'*e2 axpy(alpha, gtsam::backSubstituteTranspose(*Rc1_, x), y); // y += alpha*inv(R1')*x } diff --git a/gtsam/linear/SubgraphPreconditioner.h b/gtsam/linear/SubgraphPreconditioner.h index 4396a59dc..eadc0e596 100644 --- a/gtsam/linear/SubgraphPreconditioner.h +++ b/gtsam/linear/SubgraphPreconditioner.h @@ -17,9 +17,9 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace gtsam { @@ -34,9 +34,9 @@ namespace gtsam { public: typedef boost::shared_ptr shared_ptr; - typedef boost::shared_ptr sharedBayesNet; - typedef boost::shared_ptr sharedFG; - typedef boost::shared_ptr sharedValues; + typedef boost::shared_ptr sharedBayesNet; + typedef boost::shared_ptr sharedFG; + typedef boost::shared_ptr sharedValues; typedef boost::shared_ptr sharedErrors; private: @@ -73,11 +73,11 @@ namespace gtsam { // SubgraphPreconditioner add_priors(double sigma) const; /* x = xbar + inv(R1)*y */ - VectorValues x(const VectorValues& y) const; + VectorValuesOrdered x(const VectorValuesOrdered& y) const; /* A zero VectorValues with the structure of xbar */ - VectorValues zero() const { - VectorValues V(VectorValues::Zero(*xbar_)); + VectorValuesOrdered zero() const { + VectorValuesOrdered V(VectorValuesOrdered::Zero(*xbar_)); return V ; } @@ -87,31 +87,31 @@ namespace gtsam { * Takes a range indicating e2 !!!! */ void transposeMultiplyAdd2(double alpha, Errors::const_iterator begin, - Errors::const_iterator end, VectorValues& y) const; + Errors::const_iterator end, VectorValuesOrdered& y) const; /** print the object */ void print(const std::string& s = "SubgraphPreconditioner") const; }; /* error, given y */ - GTSAM_EXPORT double error(const SubgraphPreconditioner& sp, const VectorValues& y); + GTSAM_EXPORT double error(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y); /** gradient = y + inv(R1')*A2'*(A2*inv(R1)*y-b2bar) */ - GTSAM_EXPORT VectorValues gradient(const SubgraphPreconditioner& sp, const VectorValues& y); + GTSAM_EXPORT VectorValuesOrdered gradient(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y); /** Apply operator A */ - GTSAM_EXPORT Errors operator*(const SubgraphPreconditioner& sp, const VectorValues& y); + GTSAM_EXPORT Errors operator*(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y); /** Apply operator A in place: needs e allocated already */ - GTSAM_EXPORT void multiplyInPlace(const SubgraphPreconditioner& sp, const VectorValues& y, Errors& e); + GTSAM_EXPORT void multiplyInPlace(const SubgraphPreconditioner& sp, const VectorValuesOrdered& y, Errors& e); /** Apply operator A' */ - GTSAM_EXPORT VectorValues operator^(const SubgraphPreconditioner& sp, const Errors& e); + GTSAM_EXPORT VectorValuesOrdered operator^(const SubgraphPreconditioner& sp, const Errors& e); /** * Add A'*e to y * y += alpha*A'*[e1;e2] = [alpha*e1; alpha*inv(R1')*A2'*e2] */ - GTSAM_EXPORT void transposeMultiplyAdd(const SubgraphPreconditioner& sp, double alpha, const Errors& e, VectorValues& y); + GTSAM_EXPORT void transposeMultiplyAdd(const SubgraphPreconditioner& sp, double alpha, const Errors& e, VectorValuesOrdered& y); } // namespace gtsam diff --git a/gtsam/linear/SubgraphSolver.cpp b/gtsam/linear/SubgraphSolver.cpp index 519192144..599c1b494 100644 --- a/gtsam/linear/SubgraphSolver.cpp +++ b/gtsam/linear/SubgraphSolver.cpp @@ -10,15 +10,15 @@ * -------------------------------------------------------------------------- */ #include -#include -#include -#include +#include +#include +#include #include -#include +#include #include -#include +#include #include -#include +#include #include #include #include @@ -29,92 +29,92 @@ using namespace std; namespace gtsam { /**************************************************************************************************/ -SubgraphSolver::SubgraphSolver(const GaussianFactorGraph &gfg, const Parameters ¶meters) +SubgraphSolver::SubgraphSolver(const GaussianFactorGraphOrdered &gfg, const Parameters ¶meters) : parameters_(parameters) { initialize(gfg); } /**************************************************************************************************/ -SubgraphSolver::SubgraphSolver(const GaussianFactorGraph::shared_ptr &jfg, const Parameters ¶meters) +SubgraphSolver::SubgraphSolver(const GaussianFactorGraphOrdered::shared_ptr &jfg, const Parameters ¶meters) : parameters_(parameters) { initialize(*jfg); } /**************************************************************************************************/ -SubgraphSolver::SubgraphSolver(const GaussianFactorGraph &Ab1, const GaussianFactorGraph &Ab2, const Parameters ¶meters) +SubgraphSolver::SubgraphSolver(const GaussianFactorGraphOrdered &Ab1, const GaussianFactorGraphOrdered &Ab2, const Parameters ¶meters) : parameters_(parameters) { - GaussianBayesNet::shared_ptr Rc1 = EliminationTree::Create(Ab1)->eliminate(&EliminateQR); - initialize(Rc1, boost::make_shared(Ab2)); + GaussianBayesNetOrdered::shared_ptr Rc1 = EliminationTreeOrdered::Create(Ab1)->eliminate(&EliminateQROrdered); + initialize(Rc1, boost::make_shared(Ab2)); } /**************************************************************************************************/ -SubgraphSolver::SubgraphSolver(const GaussianFactorGraph::shared_ptr &Ab1, - const GaussianFactorGraph::shared_ptr &Ab2, const Parameters ¶meters) +SubgraphSolver::SubgraphSolver(const GaussianFactorGraphOrdered::shared_ptr &Ab1, + const GaussianFactorGraphOrdered::shared_ptr &Ab2, const Parameters ¶meters) : parameters_(parameters) { - GaussianBayesNet::shared_ptr Rc1 = EliminationTree::Create(*Ab1)->eliminate(&EliminateQR); + GaussianBayesNetOrdered::shared_ptr Rc1 = EliminationTreeOrdered::Create(*Ab1)->eliminate(&EliminateQROrdered); initialize(Rc1, Ab2); } /**************************************************************************************************/ -SubgraphSolver::SubgraphSolver(const GaussianBayesNet::shared_ptr &Rc1, const GaussianFactorGraph &Ab2, +SubgraphSolver::SubgraphSolver(const GaussianBayesNetOrdered::shared_ptr &Rc1, const GaussianFactorGraphOrdered &Ab2, const Parameters ¶meters) : parameters_(parameters) { - initialize(Rc1, boost::make_shared(Ab2)); + initialize(Rc1, boost::make_shared(Ab2)); } /**************************************************************************************************/ -SubgraphSolver::SubgraphSolver(const GaussianBayesNet::shared_ptr &Rc1, - const GaussianFactorGraph::shared_ptr &Ab2, const Parameters ¶meters) : parameters_(parameters) +SubgraphSolver::SubgraphSolver(const GaussianBayesNetOrdered::shared_ptr &Rc1, + const GaussianFactorGraphOrdered::shared_ptr &Ab2, const Parameters ¶meters) : parameters_(parameters) { initialize(Rc1, Ab2); } -VectorValues SubgraphSolver::optimize() { - VectorValues ybar = conjugateGradients(*pc_, pc_->zero(), parameters_); +VectorValuesOrdered SubgraphSolver::optimize() { + VectorValuesOrdered ybar = conjugateGradients(*pc_, pc_->zero(), parameters_); return pc_->x(ybar); } -VectorValues SubgraphSolver::optimize(const VectorValues &initial) { +VectorValuesOrdered SubgraphSolver::optimize(const VectorValuesOrdered &initial) { // the initial is ignored in this case ... return optimize(); } -void SubgraphSolver::initialize(const GaussianFactorGraph &jfg) +void SubgraphSolver::initialize(const GaussianFactorGraphOrdered &jfg) { - GaussianFactorGraph::shared_ptr Ab1 = boost::make_shared(), - Ab2 = boost::make_shared(); + GaussianFactorGraphOrdered::shared_ptr Ab1 = boost::make_shared(), + Ab2 = boost::make_shared(); boost::tie(Ab1, Ab2) = splitGraph(jfg) ; if (parameters_.verbosity()) cout << "Split A into (A1) " << Ab1->size() << " and (A2) " << Ab2->size() << " factors" << endl; - GaussianBayesNet::shared_ptr Rc1 = EliminationTree::Create(*Ab1)->eliminate(&EliminateQR); - VectorValues::shared_ptr xbar(new VectorValues(gtsam::optimize(*Rc1))); + GaussianBayesNetOrdered::shared_ptr Rc1 = EliminationTreeOrdered::Create(*Ab1)->eliminate(&EliminateQROrdered); + VectorValuesOrdered::shared_ptr xbar(new VectorValuesOrdered(gtsam::optimize(*Rc1))); pc_ = boost::make_shared(Ab2, Rc1, xbar); } -void SubgraphSolver::initialize(const GaussianBayesNet::shared_ptr &Rc1, const GaussianFactorGraph::shared_ptr &Ab2) +void SubgraphSolver::initialize(const GaussianBayesNetOrdered::shared_ptr &Rc1, const GaussianFactorGraphOrdered::shared_ptr &Ab2) { - VectorValues::shared_ptr xbar(new VectorValues(gtsam::optimize(*Rc1))); + VectorValuesOrdered::shared_ptr xbar(new VectorValuesOrdered(gtsam::optimize(*Rc1))); pc_ = boost::make_shared(Ab2, Rc1, xbar); } -boost::tuple -SubgraphSolver::splitGraph(const GaussianFactorGraph &jfg) { +boost::tuple +SubgraphSolver::splitGraph(const GaussianFactorGraphOrdered &jfg) { - const VariableIndex index(jfg); + const VariableIndexOrdered index(jfg); const size_t n = index.size(); DSFVector D(n); - GaussianFactorGraph::shared_ptr At(new GaussianFactorGraph()); - GaussianFactorGraph::shared_ptr Ac( new GaussianFactorGraph()); + GaussianFactorGraphOrdered::shared_ptr At(new GaussianFactorGraphOrdered()); + GaussianFactorGraphOrdered::shared_ptr Ac( new GaussianFactorGraphOrdered()); size_t t = 0; - BOOST_FOREACH ( const GaussianFactor::shared_ptr &gf, jfg ) { + BOOST_FOREACH ( const GaussianFactorOrdered::shared_ptr &gf, jfg ) { if ( gf->keys().size() > 2 ) { throw runtime_error("SubgraphSolver::splitGraph the graph is not simple, sanity check failed "); diff --git a/gtsam/linear/SubgraphSolver.h b/gtsam/linear/SubgraphSolver.h index 1f071fcdd..a8a6492fb 100644 --- a/gtsam/linear/SubgraphSolver.h +++ b/gtsam/linear/SubgraphSolver.h @@ -12,10 +12,10 @@ #pragma once #include -#include -#include +#include +#include #include -#include +#include namespace gtsam { @@ -59,28 +59,28 @@ protected: public: /* Given a gaussian factor graph, split it into a spanning tree (A1) + others (A2) for SPCG */ - SubgraphSolver(const GaussianFactorGraph &A, const Parameters ¶meters); - SubgraphSolver(const GaussianFactorGraph::shared_ptr &A, const Parameters ¶meters); + SubgraphSolver(const GaussianFactorGraphOrdered &A, const Parameters ¶meters); + SubgraphSolver(const GaussianFactorGraphOrdered::shared_ptr &A, const Parameters ¶meters); /* The user specify the subgraph part and the constraint part, may throw exception if A1 is underdetermined */ - SubgraphSolver(const GaussianFactorGraph &Ab1, const GaussianFactorGraph &Ab2, const Parameters ¶meters); - SubgraphSolver(const GaussianFactorGraph::shared_ptr &Ab1, const GaussianFactorGraph::shared_ptr &Ab2, const Parameters ¶meters); + SubgraphSolver(const GaussianFactorGraphOrdered &Ab1, const GaussianFactorGraphOrdered &Ab2, const Parameters ¶meters); + SubgraphSolver(const GaussianFactorGraphOrdered::shared_ptr &Ab1, const GaussianFactorGraphOrdered::shared_ptr &Ab2, const Parameters ¶meters); /* The same as above, but the A1 is solved before */ - SubgraphSolver(const GaussianBayesNet::shared_ptr &Rc1, const GaussianFactorGraph &Ab2, const Parameters ¶meters); - SubgraphSolver(const GaussianBayesNet::shared_ptr &Rc1, const GaussianFactorGraph::shared_ptr &Ab2, const Parameters ¶meters); + SubgraphSolver(const GaussianBayesNetOrdered::shared_ptr &Rc1, const GaussianFactorGraphOrdered &Ab2, const Parameters ¶meters); + SubgraphSolver(const GaussianBayesNetOrdered::shared_ptr &Rc1, const GaussianFactorGraphOrdered::shared_ptr &Ab2, const Parameters ¶meters); virtual ~SubgraphSolver() {} - virtual VectorValues optimize () ; - virtual VectorValues optimize (const VectorValues &initial) ; + virtual VectorValuesOrdered optimize () ; + virtual VectorValuesOrdered optimize (const VectorValuesOrdered &initial) ; protected: - void initialize(const GaussianFactorGraph &jfg); - void initialize(const GaussianBayesNet::shared_ptr &Rc1, const GaussianFactorGraph::shared_ptr &Ab2); + void initialize(const GaussianFactorGraphOrdered &jfg); + void initialize(const GaussianBayesNetOrdered::shared_ptr &Rc1, const GaussianFactorGraphOrdered::shared_ptr &Ab2); - boost::tuple - splitGraph(const GaussianFactorGraph &gfg) ; + boost::tuple + splitGraph(const GaussianFactorGraphOrdered &gfg) ; }; } // namespace gtsam diff --git a/gtsam/linear/VectorValues.cpp b/gtsam/linear/VectorValues.cpp index 586b33312..ad08a14b2 100644 --- a/gtsam/linear/VectorValues.cpp +++ b/gtsam/linear/VectorValues.cpp @@ -1,237 +1,265 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VectorValues.cpp - * @brief Implementations for VectorValues - * @author Richard Roberts - * @author Alex Cunningham - */ - -#include -#include -#include - -#include - -using namespace std; - -namespace gtsam { - -/* ************************************************************************* */ -VectorValues VectorValues::Zero(const VectorValues& x) { - VectorValues result; - result.values_.resize(x.size()); - for(size_t j=0; j VectorValues::dims() const { - std::vector result(this->size()); - for(Index j = 0; j < this->size(); ++j) - result[j] = this->dim(j); - return result; -} - -/* ************************************************************************* */ -void VectorValues::insert(Index j, const Vector& value) { - // Make sure j does not already exist - if(exists(j)) - throw invalid_argument("VectorValues: requested variable index to insert already exists."); - - // If this adds variables at the end, insert zero-length entries up to j - if(j >= size()) - values_.resize(j+1); - - // Assign value - values_[j] = value; -} - -/* ************************************************************************* */ -void VectorValues::print(const std::string& str, const IndexFormatter& formatter) const { - std::cout << str << ": " << size() << " elements\n"; - for (Index var = 0; var < size(); ++var) - std::cout << " " << formatter(var) << ": " << (*this)[var].transpose() << "\n"; - std::cout.flush(); -} - -/* ************************************************************************* */ -bool VectorValues::equals(const VectorValues& x, double tol) const { - if(this->size() != x.size()) - return false; - for(Index j=0; j < size(); ++j) - if(!equal_with_abs_tol(values_[j], x.values_[j], tol)) - return false; - return true; -} - -/* ************************************************************************* */ -void VectorValues::resize(Index nVars, size_t varDim) { - values_.resize(nVars); - for(Index j = 0; j < nVars; ++j) - values_[j] = Vector(varDim); -} - -/* ************************************************************************* */ -void VectorValues::resizeLike(const VectorValues& other) { - values_.resize(other.size()); - for(Index j = 0; j < other.size(); ++j) - values_[j].resize(other.values_[j].size()); -} - -/* ************************************************************************* */ -VectorValues VectorValues::SameStructure(const VectorValues& other) { - VectorValues ret; - ret.resizeLike(other); - return ret; -} - -/* ************************************************************************* */ -VectorValues VectorValues::Zero(Index nVars, size_t varDim) { - VectorValues ret(nVars, varDim); - ret.setZero(); - return ret; -} - -/* ************************************************************************* */ -void VectorValues::setZero() { - BOOST_FOREACH(Vector& v, *this) { - v.setZero(); - } -} - -/* ************************************************************************* */ -const Vector VectorValues::asVector() const { - return internal::extractVectorValuesSlices(*this, - boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(this->size()), true); -} - -/* ************************************************************************* */ -const Vector VectorValues::vector(const std::vector& indices) const { - return internal::extractVectorValuesSlices(*this, indices.begin(), indices.end()); -} - -/* ************************************************************************* */ -bool VectorValues::hasSameStructure(const VectorValues& other) const { - if(this->size() != other.size()) - return false; - for(size_t j = 0; j < size(); ++j) - // Directly accessing maps instead of using VV::dim in case some values are empty - if(this->values_[j].rows() != other.values_[j].rows()) - return false; - return true; -} - -/* ************************************************************************* */ -void VectorValues::permuteInPlace(const Permutation& permutation) { - // Allocate new values - Values newValues(this->size()); - - // Swap values from this VectorValues to the permuted VectorValues - for(size_t i = 0; i < this->size(); ++i) - newValues[i].swap(this->at(permutation[i])); - - // Swap the values into this VectorValues - values_.swap(newValues); -} - -/* ************************************************************************* */ -void VectorValues::permuteInPlace(const Permutation& selector, const Permutation& permutation) { - if(selector.size() != permutation.size()) - throw invalid_argument("VariableIndex::permuteInPlace (partial permutation version) called with selector and permutation of different sizes."); - // Create new index the size of the permuted entries - Values reorderedEntries(selector.size()); - // Permute the affected entries into the new index - for(size_t dstSlot = 0; dstSlot < selector.size(); ++dstSlot) - reorderedEntries[dstSlot].swap(values_[selector[permutation[dstSlot]]]); - // Put the affected entries back in the new order - for(size_t slot = 0; slot < selector.size(); ++slot) - values_[selector[slot]].swap(reorderedEntries[slot]); -} - -/* ************************************************************************* */ -void VectorValues::swap(VectorValues& other) { - this->values_.swap(other.values_); -} - -/* ************************************************************************* */ -double VectorValues::dot(const VectorValues& v) const { - double result = 0.0; - if(this->size() != v.size()) - throw invalid_argument("VectorValues::dot called with different vector sizes"); - for(Index j = 0; j < this->size(); ++j) - // Directly accessing maps instead of using VV::dim in case some values are empty - if(this->values_[j].size() == v.values_[j].size()) - result += this->values_[j].dot(v.values_[j]); - else - throw invalid_argument("VectorValues::dot called with different vector sizes"); - return result; -} - -/* ************************************************************************* */ -double VectorValues::norm() const { - return std::sqrt(this->squaredNorm()); -} - -/* ************************************************************************* */ -double VectorValues::squaredNorm() const { - double sumSquares = 0.0; - for(Index j = 0; j < this->size(); ++j) - // Directly accessing maps instead of using VV::dim in case some values are empty - sumSquares += this->values_[j].squaredNorm(); - return sumSquares; -} - -/* ************************************************************************* */ -VectorValues VectorValues::operator+(const VectorValues& c) const { - VectorValues result = SameStructure(*this); - if(this->size() != c.size()) - throw invalid_argument("VectorValues::operator+ called with different vector sizes"); - for(Index j = 0; j < this->size(); ++j) - // Directly accessing maps instead of using VV::dim in case some values are empty - if(this->values_[j].size() == c.values_[j].size()) - result.values_[j] = this->values_[j] + c.values_[j]; - else - throw invalid_argument("VectorValues::operator- called with different vector sizes"); - return result; -} - -/* ************************************************************************* */ -VectorValues VectorValues::operator-(const VectorValues& c) const { - VectorValues result = SameStructure(*this); - if(this->size() != c.size()) - throw invalid_argument("VectorValues::operator- called with different vector sizes"); - for(Index j = 0; j < this->size(); ++j) - // Directly accessing maps instead of using VV::dim in case some values are empty - if(this->values_[j].size() == c.values_[j].size()) - result.values_[j] = this->values_[j] - c.values_[j]; - else - throw invalid_argument("VectorValues::operator- called with different vector sizes"); - return result; -} - -/* ************************************************************************* */ -void VectorValues::operator+=(const VectorValues& c) { - if(this->size() != c.size()) - throw invalid_argument("VectorValues::operator+= called with different vector sizes"); - for(Index j = 0; j < this->size(); ++j) - // Directly accessing maps instead of using VV::dim in case some values are empty - if(this->values_[j].size() == c.values_[j].size()) - this->values_[j] += c.values_[j]; - else - throw invalid_argument("VectorValues::operator+= called with different vector sizes"); -} - -/* ************************************************************************* */ - -} // \namespace gtsam +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VectorValues.cpp + * @brief Implementations for VectorValues + * @author Richard Roberts + * @author Alex Cunningham + */ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace gtsam { + + using boost::combine; + using boost::adaptors::transformed; + using boost::adaptors::map_values; + using boost::accumulate; + + /* ************************************************************************* */ + VectorValues::VectorValues(const VectorValues& first, const VectorValues& second) + { + // Merge using predicate for comparing first of pair + std::merge(first.begin(), first.end(), second.begin(), second.end(), std::inserter(values_, values_.end()), + boost::bind(&std::less::operator(), std::less(), boost::bind(&KeyValuePair::first, _1), boost::bind(&KeyValuePair::first, _2))); + if(size() != first.size() + second.size()) + throw std::invalid_argument("Requested to merge two VectorValues that have one or more variables in common."); + } + + /* ************************************************************************* */ + VectorValues VectorValues::Zero(const VectorValues& other) + { + VectorValues result; + BOOST_FOREACH(const KeyValuePair& v, other) + result.values_.insert(make_pair(v.first, Vector::Zero(v.second.size()))); + return result; + } + + /* ************************************************************************* */ + void VectorValues::insert(const VectorValues& values) + { + size_t originalSize = size(); + values_.insert(values.begin(), values.end()); + if(size() != originalSize + values.size()) + throw std::invalid_argument("Requested to insert a VectorValues into another VectorValues that already contains one or more of its keys."); + } + + /* ************************************************************************* */ + void VectorValues::print(const std::string& str, const KeyFormatter& formatter) const { + std::cout << str << ": " << size() << " elements\n"; + BOOST_FOREACH(const value_type& key_value, *this) + std::cout << " " << formatter(key_value.first) << ": " << key_value.second.transpose() << "\n"; + std::cout.flush(); + } + + /* ************************************************************************* */ + bool VectorValues::equals(const VectorValues& x, double tol) const { + if(this->size() != x.size()) + return false; + typedef boost::tuple ValuePair; + BOOST_FOREACH(const ValuePair& values, boost::combine(*this, x)) { + if(values.get<0>().first != values.get<1>().first || + !equal_with_abs_tol(values.get<0>().second, values.get<1>().second, tol)) + return false; + } + return true; + } + + /* ************************************************************************* */ + const Vector VectorValues::vector() const + { + // Count dimensions + DenseIndex totalDim = 0; + BOOST_FOREACH(const value_type& v, *this) + totalDim += v.second.size(); + + // Copy vectors + Vector result(totalDim); + DenseIndex pos = 0; + BOOST_FOREACH(const Vector& v, *this | map_values) { + result.segment(pos, v.size()) = v; + pos += v.size(); + } + + return result; + } + + /* ************************************************************************* */ + const Vector VectorValues::vector(const std::vector& keys) const + { + // Count dimensions and collect pointers to avoid double lookups + DenseIndex totalDim = 0; + std::vector items(keys.size()); + for(size_t i = 0; i < keys.size(); ++i) { + items[i] = &at(keys[i]); + totalDim += items[i]->size(); + } + + // Copy vectors + Vector result(totalDim); + DenseIndex pos = 0; + BOOST_FOREACH(const Vector *v, items) { + result.segment(pos, v->size()) = *v; + pos += v->size(); + } + + return result; + } + + /* ************************************************************************* */ + void VectorValues::swap(VectorValues& other) { + this->values_.swap(other.values_); + } + + /* ************************************************************************* */ + namespace internal + { + bool structureCompareOp(const boost::tuple& vv) + { + return vv.get<0>().first == vv.get<1>().first + && vv.get<0>().second.size() == vv.get<1>().second.size(); + } + } + + /* ************************************************************************* */ + bool VectorValues::hasSameStructure(const VectorValues other) const + { + return accumulate(combine(*this, other) + | transformed(internal::structureCompareOp), true, std::logical_and()); + } + + /* ************************************************************************* */ + double VectorValues::dot(const VectorValues& v) const + { + if(this->size() != v.size()) + throw invalid_argument("VectorValues::dot called with a VectorValues of different structure"); + double result = 0.0; + typedef boost::tuple ValuePair; + using boost::adaptors::map_values; + BOOST_FOREACH(const ValuePair& values, boost::combine(*this, v)) { + assert_throw(values.get<0>().first == values.get<1>().first, + std::invalid_argument("VectorValues::dot called with a VectorValues of different structure")); + assert_throw(values.get<0>().second.size() == values.get<1>().second.size(), + std::invalid_argument("VectorValues::dot called with a VectorValues of different structure")); + result += values.get<0>().second.dot(values.get<1>().second); + } + return result; + } + + /* ************************************************************************* */ + double VectorValues::norm() const { + return std::sqrt(this->squaredNorm()); + } + + /* ************************************************************************* */ + double VectorValues::squaredNorm() const { + double sumSquares = 0.0; + using boost::adaptors::map_values; + BOOST_FOREACH(const Vector& v, *this | map_values) + sumSquares += v.squaredNorm(); + return sumSquares; + } + + /* ************************************************************************* */ + VectorValues VectorValues::operator+(const VectorValues& c) const + { + if(this->size() != c.size()) + throw invalid_argument("VectorValues::operator+ called with different vector sizes"); + assert_throw(hasSameStructure(c), + invalid_argument("VectorValues::operator+ called with different vector sizes")); + + VectorValues result; + // The result.end() hint here should result in constant-time inserts + for(const_iterator j1 = begin(), j2 = c.begin(); j1 != end(); ++j1, ++j2) + result.values_.insert(result.end(), make_pair(j1->first, j1->second + j2->second)); + + return result; + } + + /* ************************************************************************* */ + VectorValues VectorValues::add(const VectorValues& c) const + { + return *this + c; + } + + /* ************************************************************************* */ + VectorValues& VectorValues::operator+=(const VectorValues& c) + { + if(this->size() != c.size()) + throw invalid_argument("VectorValues::operator+= called with different vector sizes"); + assert_throw(hasSameStructure(c), + invalid_argument("VectorValues::operator+= called with different vector sizes")); + + iterator j1 = begin(); + const_iterator j2 = c.begin(); + // The result.end() hint here should result in constant-time inserts + for(; j1 != end(); ++j1, ++j2) + j1->second += j2->second; + + return *this; + } + + /* ************************************************************************* */ + VectorValues& VectorValues::addInPlace(const VectorValues& c) + { + return *this += c; + } + + /* ************************************************************************* */ + VectorValues VectorValues::operator-(const VectorValues& c) const + { + if(this->size() != c.size()) + throw invalid_argument("VectorValues::operator- called with different vector sizes"); + assert_throw(hasSameStructure(c), + invalid_argument("VectorValues::operator- called with different vector sizes")); + + VectorValues result; + // The result.end() hint here should result in constant-time inserts + for(const_iterator j1 = begin(), j2 = c.begin(); j1 != end(); ++j1, ++j2) + result.values_.insert(result.end(), make_pair(j1->first, j1->second - j2->second)); + + return result; + } + + /* ************************************************************************* */ + VectorValues VectorValues::subtract(const VectorValues& c) const + { + return *this - c; + } + + /* ************************************************************************* */ + VectorValues& VectorValues::operator*=(double alpha) + { + BOOST_FOREACH(Vector& v, *this | map_values) + v *= alpha; + return *this; + } + + /* ************************************************************************* */ + VectorValues& VectorValues::scaleInPlace(double alpha) + { + return *this *= alpha; + } + + /* ************************************************************************* */ + +} // \namespace gtsam diff --git a/gtsam/linear/VectorValues.h b/gtsam/linear/VectorValues.h index bcd106a0e..e63de77af 100644 --- a/gtsam/linear/VectorValues.h +++ b/gtsam/linear/VectorValues.h @@ -1,468 +1,348 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VectorValues.h - * @brief Factor Graph Values - * @author Richard Roberts - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace gtsam { - - // Forward declarations - class Permutation; - - /** - * This class represents a collection of vector-valued variables associated - * each with a unique integer index. It is typically used to store the variables - * of a GaussianFactorGraph. Optimizing a GaussianFactorGraph or GaussianBayesNet - * returns this class. - * - * For basic usage, such as receiving a linear solution from gtsam solving functions, - * or creating this class in unit tests and examples where speed is not important, - * you can use a simple interface: - * - The default constructor VectorValues() to create this class - * - insert(Index, const Vector&) to add vector variables - * - operator[](Index) for read and write access to stored variables - * - \ref exists (Index) to check if a variable is present - * - Other facilities like iterators, size(), dim(), etc. - * - * Indices can be non-consecutive and inserted out-of-order, but you should not - * use indices that are larger than a reasonable array size because the indices - * correspond to positions in an internal array. - * - * Example: - * \code - VectorValues values; - values.insert(3, Vector_(3, 1.0, 2.0, 3.0)); - values.insert(4, Vector_(2, 4.0, 5.0)); - values.insert(0, Vector_(4, 6.0, 7.0, 8.0, 9.0)); - - // Prints [ 3.0 4.0 ] - gtsam::print(values[1]); - - // Prints [ 8.0 9.0 ] - values[1] = Vector_(2, 8.0, 9.0); - gtsam::print(values[1]); - \endcode - * - *

Advanced Interface and Performance Information

- * - * Internally, all vector values are stored as part of one large vector. In - * gtsam this vector is always pre-allocated for efficiency, using the - * advanced interface described below. Accessing and modifying already-allocated - * values is \f$ O(1) \f$. Using the insert() function of the standard interface - * is slow because it requires re-allocating the internal vector. - * - * For advanced usage, or where speed is important: - * - Allocate space ahead of time using a pre-allocating constructor - * (\ref AdvancedConstructors "Advanced Constructors"), Zero(), - * SameStructure(), resize(), or append(). Do not use - * insert(Index, const Vector&), which always has to re-allocate the - * internal vector. - * - The vector() function permits access to the underlying Vector, for - * doing mathematical or other operations that require all values. - * - operator[]() returns a SubVector view of the underlying Vector, - * without copying any data. - * - * Access is through the variable index j, and returns a SubVector, - * which is a view on the underlying data structure. - * - * This class is additionally used in gradient descent and dog leg to store the gradient. - * \nosubgrouping - */ - class GTSAM_EXPORT VectorValues { - protected: - typedef std::vector Values; ///< Typedef for the collection of Vectors making up a VectorValues - Values values_; ///< Collection of Vectors making up this VectorValues - - public: - typedef Values::iterator iterator; ///< Iterator over vector values - typedef Values::const_iterator const_iterator; ///< Const iterator over vector values - typedef Values::reverse_iterator reverse_iterator; ///< Reverse iterator over vector values - typedef Values::const_reverse_iterator const_reverse_iterator; ///< Const reverse iterator over vector values - typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class - - /// @name Standard Constructors - /// @{ - - /** - * Default constructor creates an empty VectorValues. - */ - VectorValues() {} - - /** Named constructor to create a VectorValues of the same structure of the - * specified one, but filled with zeros. - * @return - */ - static VectorValues Zero(const VectorValues& model); - - /// @} - /// @name Standard Interface - /// @{ - - /** Number of variables stored, always 1 more than the highest variable index, - * even if some variables with lower indices are not present. */ - Index size() const { return values_.size(); } - - /** Return the dimension of variable \c j. */ - size_t dim(Index j) const { checkExists(j); return (*this)[j].rows(); } - - /** Return the dimension of each vector in this container */ - std::vector dims() const; - - /** Check whether a variable with index \c j exists. */ - bool exists(Index j) const { return j < size() && values_[j].rows() > 0; } - - /** Read/write access to the vector value with index \c j, throws std::out_of_range if \c j does not exist, identical to operator[](Index). */ - Vector& at(Index j) { checkExists(j); return values_[j]; } - - /** Access the vector value with index \c j (const version), throws std::out_of_range if \c j does not exist, identical to operator[](Index). */ - const Vector& at(Index j) const { checkExists(j); return values_[j]; } - - /** Read/write access to the vector value with index \c j, throws std::out_of_range if \c j does not exist, identical to at(Index). */ - Vector& operator[](Index j) { return at(j); } - - /** Access the vector value with index \c j (const version), throws std::out_of_range if \c j does not exist, identical to at(Index). */ - const Vector& operator[](Index j) const { return at(j); } - - /** Insert a vector \c value with index \c j. - * Causes reallocation, but can insert values in any order. - * Throws an invalid_argument exception if the index \c j is already used. - * @param value The vector to be inserted. - * @param j The index with which the value will be associated. - */ - void insert(Index j, const Vector& value); - - iterator begin() { return values_.begin(); } ///< Iterator over variables - const_iterator begin() const { return values_.begin(); } ///< Iterator over variables - iterator end() { return values_.end(); } ///< Iterator over variables - const_iterator end() const { return values_.end(); } ///< Iterator over variables - reverse_iterator rbegin() { return values_.rbegin(); } ///< Reverse iterator over variables - const_reverse_iterator rbegin() const { return values_.rbegin(); } ///< Reverse iterator over variables - reverse_iterator rend() { return values_.rend(); } ///< Reverse iterator over variables - const_reverse_iterator rend() const { return values_.rend(); } ///< Reverse iterator over variables - - /** print required by Testable for unit testing */ - void print(const std::string& str = "VectorValues: ", - const IndexFormatter& formatter = DefaultIndexFormatter) const; - - /** equals required by Testable for unit testing */ - bool equals(const VectorValues& x, double tol = 1e-9) const; - - /// @{ - /// \anchor AdvancedConstructors - /// @name Advanced Constructors - /// @} - - /** Construct from a container of variable dimensions (in variable order), without initializing any values. */ - template - explicit VectorValues(const CONTAINER& dimensions) { this->append(dimensions); } - - /** Construct to hold nVars vectors of varDim dimension each. */ - VectorValues(Index nVars, size_t varDim) { this->resize(nVars, varDim); } - - /** Named constructor to create a VectorValues that matches the structure of - * the specified VectorValues, but do not initialize the new values. */ - static VectorValues SameStructure(const VectorValues& other); - - /** Named constructor to create a VectorValues from a container of variable - * dimensions that is filled with zeros. - * @param dimensions A container of the dimension of each variable to create. - */ - template - static VectorValues Zero(const CONTAINER& dimensions); - - /** Named constructor to create a VectorValues filled with zeros that has - * \c nVars variables, each of dimension \c varDim - * @param nVars The number of variables to create - * @param varDim The dimension of each variable - * @return The new VectorValues - */ - static VectorValues Zero(Index nVars, size_t varDim); - - /// @} - /// @name Advanced Interface - /// @{ - - /** Resize this VectorValues to have identical structure to other, leaving - * this VectorValues with uninitialized values. - * @param other The VectorValues whose structure to copy - */ - void resizeLike(const VectorValues& other); - - /** Resize the VectorValues to hold \c nVars variables, each of dimension - * \c varDim. Any individual vectors that do not change size will keep - * their values, but any new or resized vectors will be uninitialized. - * @param nVars The number of variables to create - * @param varDim The dimension of each variable - */ - void resize(Index nVars, size_t varDim); - - /** Resize the VectorValues to contain variables of the dimensions stored - * in \c dimensions. Any individual vectors that do not change size will keep - * their values, but any new or resized vectors will be uninitialized. - * @param dimensions A container of the dimension of each variable to create. - */ - template - void resize(const CONTAINER& dimensions); - - /** Append to the VectorValues to additionally contain variables of the - * dimensions stored in \c dimensions. The new variables are uninitialized, - * but this function is used to pre-allocate space for performance. This - * function preserves the original data, so all previously-existing variables - * are left unchanged. - * @param dimensions A container of the dimension of each variable to create. - */ - template - void append(const CONTAINER& dimensions); - - /** Removes the last subvector from the VectorValues */ - void pop_back() { values_.pop_back(); }; - - /** Set all entries to zero, does not modify the size. */ - void setZero(); - - /** Retrieve the entire solution as a single vector */ - const Vector asVector() const; - - /** Access a vector that is a subset of relevant indices */ - const Vector vector(const std::vector& indices) const; - - /** Check whether this VectorValues has the same structure, meaning has the - * same number of variables and that all variables are of the same dimension, - * as another VectorValues - * @param other The other VectorValues with which to compare structure - * @return \c true if the structure is the same, \c false if not. - */ - bool hasSameStructure(const VectorValues& other) const; - - /** - * Permute the variables in the VariableIndex according to the given partial permutation - */ - void permuteInPlace(const Permutation& selector, const Permutation& permutation); - - /** - * Permute the entries of this VectorValues in place - */ - void permuteInPlace(const Permutation& permutation); - - /** - * Swap the data in this VectorValues with another. - */ - void swap(VectorValues& other); - - /// @} - /// @name Linear algebra operations - /// @{ - - /** Dot product with another VectorValues, interpreting both as vectors of - * their concatenated values. */ - double dot(const VectorValues& v) const; - - /** Vector L2 norm */ - double norm() const; - - /** Squared vector L2 norm */ - double squaredNorm() const; - - /** - * + operator does element-wise addition. Both VectorValues must have the - * same structure (checked when NDEBUG is not defined). - */ - VectorValues operator+(const VectorValues& c) const; - - /** - * + operator does element-wise subtraction. Both VectorValues must have the - * same structure (checked when NDEBUG is not defined). - */ - VectorValues operator-(const VectorValues& c) const; - - /** - * += operator does element-wise addition. Both VectorValues must have the - * same structure (checked when NDEBUG is not defined). - */ - void operator+=(const VectorValues& c); - - /// @} - - /// @} - /// @name Matlab syntactic sugar for linear algebra operations - /// @{ - - inline VectorValues add(const VectorValues& c) const { return *this + c; } - inline VectorValues scale(const double a, const VectorValues& c) const { return a * (*this); } - - /// @} - - private: - // Throw an exception if j does not exist - void checkExists(Index j) const { - if(!exists(j)) { - const std::string msg = - (boost::format("VectorValues: requested variable index j=%1% is not in this VectorValues.") % j).str(); - throw std::out_of_range(msg); - } - } - - public: - - /** - * scale a vector by a scalar - */ - friend VectorValues operator*(const double a, const VectorValues &v) { - VectorValues result = VectorValues::SameStructure(v); - for(Index j = 0; j < v.size(); ++j) - result.values_[j] = a * v.values_[j]; - return result; - } - - /// TODO: linear algebra interface seems to have been added for SPCG. - friend void scal(double alpha, VectorValues& x) { - for(Index j = 0; j < x.size(); ++j) - x.values_[j] *= alpha; - } - /// TODO: linear algebra interface seems to have been added for SPCG. - friend void axpy(double alpha, const VectorValues& x, VectorValues& y) { - if(x.size() != y.size()) - throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); - for(Index j = 0; j < x.size(); ++j) - if(x.values_[j].size() == y.values_[j].size()) - y.values_[j] += alpha * x.values_[j]; - else - throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); - } - /// TODO: linear algebra interface seems to have been added for SPCG. - friend void sqrt(VectorValues &x) { - for(Index j = 0; j < x.size(); ++j) - x.values_[j] = x.values_[j].cwiseSqrt(); - } - - /// TODO: linear algebra interface seems to have been added for SPCG. - friend void ediv(const VectorValues& numerator, const VectorValues& denominator, VectorValues &result) { - if(numerator.size() != denominator.size() || numerator.size() != result.size()) - throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); - for(Index j = 0; j < numerator.size(); ++j) - if(numerator.values_[j].size() == denominator.values_[j].size() && numerator.values_[j].size() == result.values_[j].size()) - result.values_[j] = numerator.values_[j].cwiseQuotient(denominator.values_[j]); - else - throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); - } - - /// TODO: linear algebra interface seems to have been added for SPCG. - friend void edivInPlace(VectorValues& x, const VectorValues& y) { - if(x.size() != y.size()) - throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); - for(Index j = 0; j < x.size(); ++j) - if(x.values_[j].size() == y.values_[j].size()) - x.values_[j].array() /= y.values_[j].array(); - else - throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); - } - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(values_); - } - }; // VectorValues definition - - // Implementations of template and inline functions - - /* ************************************************************************* */ - template - void VectorValues::resize(const CONTAINER& dimensions) { - values_.clear(); - append(dimensions); - } - - /* ************************************************************************* */ - template - void VectorValues::append(const CONTAINER& dimensions) { - size_t i = size(); - values_.resize(size() + dimensions.size()); - BOOST_FOREACH(size_t dim, dimensions) { - values_[i] = Vector(dim); - ++ i; - } - } - - /* ************************************************************************* */ - template - VectorValues VectorValues::Zero(const CONTAINER& dimensions) { - VectorValues ret; - ret.values_.resize(dimensions.size()); - size_t i = 0; - BOOST_FOREACH(size_t dim, dimensions) { - ret.values_[i] = Vector::Zero(dim); - ++ i; - } - return ret; - } - - namespace internal { - /* ************************************************************************* */ - // Helper function, extracts vectors with variable indices - // in the first and last iterators, and concatenates them in that order into the - // output. - template - const Vector extractVectorValuesSlices(const VectorValues& values, ITERATOR first, ITERATOR last, bool allowNonexistant = false) { - // Find total dimensionality - size_t dim = 0; - for(ITERATOR j = first; j != last; ++j) - // If allowNonexistant is true, skip nonexistent indices (otherwise dim will throw an error on nonexistent) - if(!allowNonexistant || values.exists(*j)) - dim += values.dim(*j); - - // Copy vectors - Vector ret(dim); - size_t varStart = 0; - for(ITERATOR j = first; j != last; ++j) { - // If allowNonexistant is true, skip nonexistent indices (otherwise dim will throw an error on nonexistent) - if(!allowNonexistant || values.exists(*j)) { - ret.segment(varStart, values.dim(*j)) = values[*j]; - varStart += values.dim(*j); - } - } - return ret; - } - - /* ************************************************************************* */ - // Helper function, writes to the variables in values - // with indices iterated over by first and last, interpreting vector as the - // concatenated vectors to write. - template - void writeVectorValuesSlices(const VECTOR& vector, VectorValues& values, ITERATOR first, ITERATOR last) { - // Copy vectors - size_t varStart = 0; - for(ITERATOR j = first; j != last; ++j) { - values[*j] = vector.segment(varStart, values[*j].rows()); - varStart += values[*j].rows(); - } - assert(varStart == vector.rows()); - } - } - -} // \namespace gtsam +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VectorValues.h + * @brief Factor Graph Values + * @author Richard Roberts + */ + +#pragma once + +#include +#include +#include + +#include + +namespace gtsam { + + /** + * This class represents a collection of vector-valued variables associated + * each with a unique integer index. It is typically used to store the variables + * of a GaussianFactorGraph. Optimizing a GaussianFactorGraph or GaussianBayesNet + * returns this class. + * + * For basic usage, such as receiving a linear solution from gtsam solving functions, + * or creating this class in unit tests and examples where speed is not important, + * you can use a simple interface: + * - The default constructor VectorValues() to create this class + * - insert(Key, const Vector&) to add vector variables + * - operator[](Key) for read and write access to stored variables + * - \ref exists (Key) to check if a variable is present + * - Other facilities like iterators, size(), dim(), etc. + * + * Indices can be non-consecutive and inserted out-of-order, but you should not + * use indices that are larger than a reasonable array size because the indices + * correspond to positions in an internal array. + * + * Example: + * \code + VectorValues values; + values.insert(3, Vector_(3, 1.0, 2.0, 3.0)); + values.insert(4, Vector_(2, 4.0, 5.0)); + values.insert(0, Vector_(4, 6.0, 7.0, 8.0, 9.0)); + + // Prints [ 3.0 4.0 ] + gtsam::print(values[1]); + + // Prints [ 8.0 9.0 ] + values[1] = Vector_(2, 8.0, 9.0); + gtsam::print(values[1]); + \endcode + * + *

Advanced Interface and Performance Information

+ * + * Internally, all vector values are stored as part of one large vector. In + * gtsam this vector is always pre-allocated for efficiency, using the + * advanced interface described below. Accessing and modifying already-allocated + * values is \f$ O(1) \f$. Using the insert() function of the standard interface + * is slow because it requires re-allocating the internal vector. + * + * For advanced usage, or where speed is important: + * - Allocate space ahead of time using a pre-allocating constructor + * (\ref AdvancedConstructors "Advanced Constructors"), Zero(), + * SameStructure(), resize(), or append(). Do not use + * insert(Key, const Vector&), which always has to re-allocate the + * internal vector. + * - The vector() function permits access to the underlying Vector, for + * doing mathematical or other operations that require all values. + * - operator[]() returns a SubVector view of the underlying Vector, + * without copying any data. + * + * Access is through the variable index j, and returns a SubVector, + * which is a view on the underlying data structure. + * + * This class is additionally used in gradient descent and dog leg to store the gradient. + * \nosubgrouping + */ + class GTSAM_EXPORT VectorValues { + protected: + typedef VectorValues This; + typedef FastMap Values; ///< Typedef for the collection of Vectors making up a VectorValues + Values values_; ///< Collection of Vectors making up this VectorValues + + public: + typedef Values::iterator iterator; ///< Iterator over vector values + typedef Values::const_iterator const_iterator; ///< Const iterator over vector values + typedef Values::reverse_iterator reverse_iterator; ///< Reverse iterator over vector values + typedef Values::const_reverse_iterator const_reverse_iterator; ///< Const reverse iterator over vector values + typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class + typedef Values::value_type value_type; ///< Typedef to pair, a key-value pair + typedef value_type KeyValuePair; ///< Typedef to pair, a key-value pair + + /// @name Standard Constructors + /// @{ + + /** + * Default constructor creates an empty VectorValues. + */ + VectorValues() {} + + /** Merge two VectorValues into one, this is more efficient than inserting elements one by one. */ + VectorValues(const VectorValues& first, const VectorValues& second); + + /** Create from another container holding pair. */ + template + explicit VectorValues(const CONTAINER& c) : values_(c.begin(), c.end()) {} + + /** Implicit copy constructor to specialize the explicit constructor from any container. */ + VectorValues(const VectorValues& c) : values_(c.values_) {} + + /** Create from a pair of iterators over pair. */ + template + VectorValues(ITERATOR first, ITERATOR last) : values_(first, last) {} + + /** Create a VectorValues with the same structure as \c other, but filled with zeros. */ + static VectorValues Zero(const VectorValues& other); + + /// @} + /// @name Standard Interface + /// @{ + + /** Number of variables stored. */ + Key size() const { return values_.size(); } + + /** Return the dimension of variable \c j. */ + size_t dim(Key j) const { return at(j).rows(); } + + /** Check whether a variable with key \c j exists. */ + bool exists(Key j) const { return find(j) != end(); } + + /** Read/write access to the vector value with key \c j, throws std::out_of_range if \c j does not exist, identical to operator[](Key). */ + Vector& at(Key j) { + iterator item = find(j); + if(item == end()) + throw std::out_of_range( + "Requested variable '" + DefaultKeyFormatter(j) + "' is not in this VectorValues."); + else + return item->second; + } + + /** Access the vector value with key \c j (const version), throws std::out_of_range if \c j does not exist, identical to operator[](Key). */ + const Vector& at(Key j) const { + const_iterator item = find(j); + if(item == end()) + throw std::out_of_range( + "Requested variable '" + DefaultKeyFormatter(j) + "' is not in this VectorValues."); + else + return item->second; + } + + /** Read/write access to the vector value with key \c j, throws std::out_of_range if \c j does not exist, identical to at(Key). */ + Vector& operator[](Key j) { return at(j); } + + /** Access the vector value with key \c j (const version), throws std::out_of_range if \c j does not exist, identical to at(Key). */ + const Vector& operator[](Key j) const { return at(j); } + + /** Insert a vector \c value with key \c j. Throws an invalid_argument exception if the key \c j is already used. + * @param value The vector to be inserted. + * @param j The index with which the value will be associated. + */ + void insert(Key j, const Vector& value) { + insert(std::pair(j, value)); // Note only passing a reference to the Vector + } + + /** Insert a vector \c value with key \c j. Throws an invalid_argument exception if the key \c j is already used. + * @param value The vector to be inserted. + * @param j The index with which the value will be associated. + */ + void insert(std::pair key_value) { + // Note that here we accept a pair with a reference to the Vector, but the Vector is copied as + // it is inserted into the values_ map. + if(!values_.insert(key_value).second) + throw std::invalid_argument( + "Requested to insert variable '" + DefaultKeyFormatter(key_value.first) + + "' already in this VectorValues."); + } + + /** Insert all values from \c values. Throws an invalid_argument exception if any keys to be + * inserted are already used. */ + void insert(const VectorValues& values); + + /** insert that mimics the STL map insert - if the value already exists, the map is not modified + * and an iterator to the existing value is returned, along with 'false'. If the value did not + * exist, it is inserted and an iterator pointing to the new element, along with 'true', is + * returned. */ + std::pair tryInsert(Key j, const Vector& value) { + return values_.insert(std::make_pair(j, value)); } + + iterator begin() { return values_.begin(); } ///< Iterator over variables + const_iterator begin() const { return values_.begin(); } ///< Iterator over variables + iterator end() { return values_.end(); } ///< Iterator over variables + const_iterator end() const { return values_.end(); } ///< Iterator over variables + reverse_iterator rbegin() { return values_.rbegin(); } ///< Reverse iterator over variables + const_reverse_iterator rbegin() const { return values_.rbegin(); } ///< Reverse iterator over variables + reverse_iterator rend() { return values_.rend(); } ///< Reverse iterator over variables + const_reverse_iterator rend() const { return values_.rend(); } ///< Reverse iterator over variables + + /** Return the iterator corresponding to the requested key, or end() if no variable is present with this key. */ + iterator find(Key j) { return values_.find(j); } + + /** Return the iterator corresponding to the requested key, or end() if no variable is present with this key. */ + const_iterator find(Key j) const { return values_.find(j); } + + /** print required by Testable for unit testing */ + void print(const std::string& str = "VectorValues: ", + const KeyFormatter& formatter = DefaultKeyFormatter) const; + + /** equals required by Testable for unit testing */ + bool equals(const VectorValues& x, double tol = 1e-9) const; + + /// @{ + /// @name Advanced Interface + /// @{ + + /** Retrieve the entire solution as a single vector */ + const Vector vector() const; + + /** Access a vector that is a subset of relevant keys. */ + const Vector vector(const std::vector& keys) const; + + /** Swap the data in this VectorValues with another. */ + void swap(VectorValues& other); + + /** Check if this VectorValues has the same structure (keys and dimensions) as another */ + bool hasSameStructure(const VectorValues other) const; + + /// @} + /// @name Linear algebra operations + /// @{ + + /** Dot product with another VectorValues, interpreting both as vectors of + * their concatenated values. Both VectorValues must have the + * same structure (checked when NDEBUG is not defined). */ + double dot(const VectorValues& v) const; + + /** Vector L2 norm */ + double norm() const; + + /** Squared vector L2 norm */ + double squaredNorm() const; + + /** Element-wise addition, synonym for add(). Both VectorValues must have the same structure + * (checked when NDEBUG is not defined). */ + VectorValues operator+(const VectorValues& c) const; + + /** Element-wise addition, synonym for operator+(). Both VectorValues must have the same + * structure (checked when NDEBUG is not defined). */ + VectorValues add(const VectorValues& c) const; + + /** Element-wise addition in-place, synonym for operator+=(). Both VectorValues must have the + * same structure (checked when NDEBUG is not defined). */ + VectorValues& operator+=(const VectorValues& c); + + /** Element-wise addition in-place, synonym for operator+=(). Both VectorValues must have the + * same structure (checked when NDEBUG is not defined). */ + VectorValues& addInPlace(const VectorValues& c); + + /** Element-wise subtraction, synonym for subtract(). Both VectorValues must have the same + * structure (checked when NDEBUG is not defined). */ + VectorValues operator-(const VectorValues& c) const; + + /** Element-wise subtraction, synonym for operator-(). Both VectorValues must have the same + * structure (checked when NDEBUG is not defined). */ + VectorValues subtract(const VectorValues& c) const; + + /** Element-wise scaling by a constant in-place. */ + VectorValues& operator*=(double alpha); + + /** Element-wise scaling by a constant in-place. */ + VectorValues& scaleInPlace(double alpha); + + /// @} + + /// @} + /// @name Matlab syntactic sugar for linear algebra operations + /// @{ + + //inline VectorValues scale(const double a, const VectorValues& c) const { return a * (*this); } + + /// @} + + /** + * scale a vector by a scalar + */ + //friend VectorValues operator*(const double a, const VectorValues &v) { + // VectorValues result = VectorValues::SameStructure(v); + // for(Key j = 0; j < v.size(); ++j) + // result.values_[j] = a * v.values_[j]; + // return result; + //} + + //// TODO: linear algebra interface seems to have been added for SPCG. + //friend void axpy(double alpha, const VectorValues& x, VectorValues& y) { + // if(x.size() != y.size()) + // throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); + // for(Key j = 0; j < x.size(); ++j) + // if(x.values_[j].size() == y.values_[j].size()) + // y.values_[j] += alpha * x.values_[j]; + // else + // throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); + //} + //// TODO: linear algebra interface seems to have been added for SPCG. + //friend void sqrt(VectorValues &x) { + // for(Key j = 0; j < x.size(); ++j) + // x.values_[j] = x.values_[j].cwiseSqrt(); + //} + + //// TODO: linear algebra interface seems to have been added for SPCG. + //friend void ediv(const VectorValues& numerator, const VectorValues& denominator, VectorValues &result) { + // if(numerator.size() != denominator.size() || numerator.size() != result.size()) + // throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); + // for(Key j = 0; j < numerator.size(); ++j) + // if(numerator.values_[j].size() == denominator.values_[j].size() && numerator.values_[j].size() == result.values_[j].size()) + // result.values_[j] = numerator.values_[j].cwiseQuotient(denominator.values_[j]); + // else + // throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); + //} + + //// TODO: linear algebra interface seems to have been added for SPCG. + //friend void edivInPlace(VectorValues& x, const VectorValues& y) { + // if(x.size() != y.size()) + // throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); + // for(Key j = 0; j < x.size(); ++j) + // if(x.values_[j].size() == y.values_[j].size()) + // x.values_[j].array() /= y.values_[j].array(); + // else + // throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); + //} + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(values_); + } + }; // VectorValues definition + +} // \namespace gtsam diff --git a/gtsam/linear/VectorValuesOrdered.cpp b/gtsam/linear/VectorValuesOrdered.cpp new file mode 100644 index 000000000..24367d82d --- /dev/null +++ b/gtsam/linear/VectorValuesOrdered.cpp @@ -0,0 +1,237 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VectorValues.cpp + * @brief Implementations for VectorValues + * @author Richard Roberts + * @author Alex Cunningham + */ + +#include +#include +#include + +#include + +using namespace std; + +namespace gtsam { + +/* ************************************************************************* */ +VectorValuesOrdered VectorValuesOrdered::Zero(const VectorValuesOrdered& x) { + VectorValuesOrdered result; + result.values_.resize(x.size()); + for(size_t j=0; j VectorValuesOrdered::dims() const { + std::vector result(this->size()); + for(Index j = 0; j < this->size(); ++j) + result[j] = this->dim(j); + return result; +} + +/* ************************************************************************* */ +void VectorValuesOrdered::insert(Index j, const Vector& value) { + // Make sure j does not already exist + if(exists(j)) + throw invalid_argument("VectorValues: requested variable index to insert already exists."); + + // If this adds variables at the end, insert zero-length entries up to j + if(j >= size()) + values_.resize(j+1); + + // Assign value + values_[j] = value; +} + +/* ************************************************************************* */ +void VectorValuesOrdered::print(const std::string& str, const IndexFormatter& formatter) const { + std::cout << str << ": " << size() << " elements\n"; + for (Index var = 0; var < size(); ++var) + std::cout << " " << formatter(var) << ": " << (*this)[var].transpose() << "\n"; + std::cout.flush(); +} + +/* ************************************************************************* */ +bool VectorValuesOrdered::equals(const VectorValuesOrdered& x, double tol) const { + if(this->size() != x.size()) + return false; + for(Index j=0; j < size(); ++j) + if(!equal_with_abs_tol(values_[j], x.values_[j], tol)) + return false; + return true; +} + +/* ************************************************************************* */ +void VectorValuesOrdered::resize(Index nVars, size_t varDim) { + values_.resize(nVars); + for(Index j = 0; j < nVars; ++j) + values_[j] = Vector(varDim); +} + +/* ************************************************************************* */ +void VectorValuesOrdered::resizeLike(const VectorValuesOrdered& other) { + values_.resize(other.size()); + for(Index j = 0; j < other.size(); ++j) + values_[j].resize(other.values_[j].size()); +} + +/* ************************************************************************* */ +VectorValuesOrdered VectorValuesOrdered::SameStructure(const VectorValuesOrdered& other) { + VectorValuesOrdered ret; + ret.resizeLike(other); + return ret; +} + +/* ************************************************************************* */ +VectorValuesOrdered VectorValuesOrdered::Zero(Index nVars, size_t varDim) { + VectorValuesOrdered ret(nVars, varDim); + ret.setZero(); + return ret; +} + +/* ************************************************************************* */ +void VectorValuesOrdered::setZero() { + BOOST_FOREACH(Vector& v, *this) { + v.setZero(); + } +} + +/* ************************************************************************* */ +const Vector VectorValuesOrdered::asVector() const { + return internal::extractVectorValuesSlices(*this, + boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(this->size()), true); +} + +/* ************************************************************************* */ +const Vector VectorValuesOrdered::vector(const std::vector& indices) const { + return internal::extractVectorValuesSlices(*this, indices.begin(), indices.end()); +} + +/* ************************************************************************* */ +bool VectorValuesOrdered::hasSameStructure(const VectorValuesOrdered& other) const { + if(this->size() != other.size()) + return false; + for(size_t j = 0; j < size(); ++j) + // Directly accessing maps instead of using VV::dim in case some values are empty + if(this->values_[j].rows() != other.values_[j].rows()) + return false; + return true; +} + +/* ************************************************************************* */ +void VectorValuesOrdered::permuteInPlace(const Permutation& permutation) { + // Allocate new values + Values newValues(this->size()); + + // Swap values from this VectorValues to the permuted VectorValues + for(size_t i = 0; i < this->size(); ++i) + newValues[i].swap(this->at(permutation[i])); + + // Swap the values into this VectorValues + values_.swap(newValues); +} + +/* ************************************************************************* */ +void VectorValuesOrdered::permuteInPlace(const Permutation& selector, const Permutation& permutation) { + if(selector.size() != permutation.size()) + throw invalid_argument("VariableIndex::permuteInPlace (partial permutation version) called with selector and permutation of different sizes."); + // Create new index the size of the permuted entries + Values reorderedEntries(selector.size()); + // Permute the affected entries into the new index + for(size_t dstSlot = 0; dstSlot < selector.size(); ++dstSlot) + reorderedEntries[dstSlot].swap(values_[selector[permutation[dstSlot]]]); + // Put the affected entries back in the new order + for(size_t slot = 0; slot < selector.size(); ++slot) + values_[selector[slot]].swap(reorderedEntries[slot]); +} + +/* ************************************************************************* */ +void VectorValuesOrdered::swap(VectorValuesOrdered& other) { + this->values_.swap(other.values_); +} + +/* ************************************************************************* */ +double VectorValuesOrdered::dot(const VectorValuesOrdered& v) const { + double result = 0.0; + if(this->size() != v.size()) + throw invalid_argument("VectorValues::dot called with different vector sizes"); + for(Index j = 0; j < this->size(); ++j) + // Directly accessing maps instead of using VV::dim in case some values are empty + if(this->values_[j].size() == v.values_[j].size()) + result += this->values_[j].dot(v.values_[j]); + else + throw invalid_argument("VectorValues::dot called with different vector sizes"); + return result; +} + +/* ************************************************************************* */ +double VectorValuesOrdered::norm() const { + return std::sqrt(this->squaredNorm()); +} + +/* ************************************************************************* */ +double VectorValuesOrdered::squaredNorm() const { + double sumSquares = 0.0; + for(Index j = 0; j < this->size(); ++j) + // Directly accessing maps instead of using VV::dim in case some values are empty + sumSquares += this->values_[j].squaredNorm(); + return sumSquares; +} + +/* ************************************************************************* */ +VectorValuesOrdered VectorValuesOrdered::operator+(const VectorValuesOrdered& c) const { + VectorValuesOrdered result = SameStructure(*this); + if(this->size() != c.size()) + throw invalid_argument("VectorValues::operator+ called with different vector sizes"); + for(Index j = 0; j < this->size(); ++j) + // Directly accessing maps instead of using VV::dim in case some values are empty + if(this->values_[j].size() == c.values_[j].size()) + result.values_[j] = this->values_[j] + c.values_[j]; + else + throw invalid_argument("VectorValues::operator- called with different vector sizes"); + return result; +} + +/* ************************************************************************* */ +VectorValuesOrdered VectorValuesOrdered::operator-(const VectorValuesOrdered& c) const { + VectorValuesOrdered result = SameStructure(*this); + if(this->size() != c.size()) + throw invalid_argument("VectorValues::operator- called with different vector sizes"); + for(Index j = 0; j < this->size(); ++j) + // Directly accessing maps instead of using VV::dim in case some values are empty + if(this->values_[j].size() == c.values_[j].size()) + result.values_[j] = this->values_[j] - c.values_[j]; + else + throw invalid_argument("VectorValues::operator- called with different vector sizes"); + return result; +} + +/* ************************************************************************* */ +void VectorValuesOrdered::operator+=(const VectorValuesOrdered& c) { + if(this->size() != c.size()) + throw invalid_argument("VectorValues::operator+= called with different vector sizes"); + for(Index j = 0; j < this->size(); ++j) + // Directly accessing maps instead of using VV::dim in case some values are empty + if(this->values_[j].size() == c.values_[j].size()) + this->values_[j] += c.values_[j]; + else + throw invalid_argument("VectorValues::operator+= called with different vector sizes"); +} + +/* ************************************************************************* */ + +} // \namespace gtsam diff --git a/gtsam/linear/VectorValuesOrdered.h b/gtsam/linear/VectorValuesOrdered.h new file mode 100644 index 000000000..081014284 --- /dev/null +++ b/gtsam/linear/VectorValuesOrdered.h @@ -0,0 +1,468 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file VectorValues.h + * @brief Factor Graph Values + * @author Richard Roberts + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace gtsam { + + // Forward declarations + class Permutation; + + /** + * This class represents a collection of vector-valued variables associated + * each with a unique integer index. It is typically used to store the variables + * of a GaussianFactorGraph. Optimizing a GaussianFactorGraph or GaussianBayesNet + * returns this class. + * + * For basic usage, such as receiving a linear solution from gtsam solving functions, + * or creating this class in unit tests and examples where speed is not important, + * you can use a simple interface: + * - The default constructor VectorValues() to create this class + * - insert(Index, const Vector&) to add vector variables + * - operator[](Index) for read and write access to stored variables + * - \ref exists (Index) to check if a variable is present + * - Other facilities like iterators, size(), dim(), etc. + * + * Indices can be non-consecutive and inserted out-of-order, but you should not + * use indices that are larger than a reasonable array size because the indices + * correspond to positions in an internal array. + * + * Example: + * \code + VectorValues values; + values.insert(3, Vector_(3, 1.0, 2.0, 3.0)); + values.insert(4, Vector_(2, 4.0, 5.0)); + values.insert(0, Vector_(4, 6.0, 7.0, 8.0, 9.0)); + + // Prints [ 3.0 4.0 ] + gtsam::print(values[1]); + + // Prints [ 8.0 9.0 ] + values[1] = Vector_(2, 8.0, 9.0); + gtsam::print(values[1]); + \endcode + * + *

Advanced Interface and Performance Information

+ * + * Internally, all vector values are stored as part of one large vector. In + * gtsam this vector is always pre-allocated for efficiency, using the + * advanced interface described below. Accessing and modifying already-allocated + * values is \f$ O(1) \f$. Using the insert() function of the standard interface + * is slow because it requires re-allocating the internal vector. + * + * For advanced usage, or where speed is important: + * - Allocate space ahead of time using a pre-allocating constructor + * (\ref AdvancedConstructors "Advanced Constructors"), Zero(), + * SameStructure(), resize(), or append(). Do not use + * insert(Index, const Vector&), which always has to re-allocate the + * internal vector. + * - The vector() function permits access to the underlying Vector, for + * doing mathematical or other operations that require all values. + * - operator[]() returns a SubVector view of the underlying Vector, + * without copying any data. + * + * Access is through the variable index j, and returns a SubVector, + * which is a view on the underlying data structure. + * + * This class is additionally used in gradient descent and dog leg to store the gradient. + * \nosubgrouping + */ + class GTSAM_EXPORT VectorValuesOrdered { + protected: + typedef std::vector Values; ///< Typedef for the collection of Vectors making up a VectorValues + Values values_; ///< Collection of Vectors making up this VectorValues + + public: + typedef Values::iterator iterator; ///< Iterator over vector values + typedef Values::const_iterator const_iterator; ///< Const iterator over vector values + typedef Values::reverse_iterator reverse_iterator; ///< Reverse iterator over vector values + typedef Values::const_reverse_iterator const_reverse_iterator; ///< Const reverse iterator over vector values + typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class + + /// @name Standard Constructors + /// @{ + + /** + * Default constructor creates an empty VectorValues. + */ + VectorValuesOrdered() {} + + /** Named constructor to create a VectorValues of the same structure of the + * specified one, but filled with zeros. + * @return + */ + static VectorValuesOrdered Zero(const VectorValuesOrdered& model); + + /// @} + /// @name Standard Interface + /// @{ + + /** Number of variables stored, always 1 more than the highest variable index, + * even if some variables with lower indices are not present. */ + Index size() const { return values_.size(); } + + /** Return the dimension of variable \c j. */ + size_t dim(Index j) const { checkExists(j); return (*this)[j].rows(); } + + /** Return the dimension of each vector in this container */ + std::vector dims() const; + + /** Check whether a variable with index \c j exists. */ + bool exists(Index j) const { return j < size() && values_[j].rows() > 0; } + + /** Read/write access to the vector value with index \c j, throws std::out_of_range if \c j does not exist, identical to operator[](Index). */ + Vector& at(Index j) { checkExists(j); return values_[j]; } + + /** Access the vector value with index \c j (const version), throws std::out_of_range if \c j does not exist, identical to operator[](Index). */ + const Vector& at(Index j) const { checkExists(j); return values_[j]; } + + /** Read/write access to the vector value with index \c j, throws std::out_of_range if \c j does not exist, identical to at(Index). */ + Vector& operator[](Index j) { return at(j); } + + /** Access the vector value with index \c j (const version), throws std::out_of_range if \c j does not exist, identical to at(Index). */ + const Vector& operator[](Index j) const { return at(j); } + + /** Insert a vector \c value with index \c j. + * Causes reallocation, but can insert values in any order. + * Throws an invalid_argument exception if the index \c j is already used. + * @param value The vector to be inserted. + * @param j The index with which the value will be associated. + */ + void insert(Index j, const Vector& value); + + iterator begin() { return values_.begin(); } ///< Iterator over variables + const_iterator begin() const { return values_.begin(); } ///< Iterator over variables + iterator end() { return values_.end(); } ///< Iterator over variables + const_iterator end() const { return values_.end(); } ///< Iterator over variables + reverse_iterator rbegin() { return values_.rbegin(); } ///< Reverse iterator over variables + const_reverse_iterator rbegin() const { return values_.rbegin(); } ///< Reverse iterator over variables + reverse_iterator rend() { return values_.rend(); } ///< Reverse iterator over variables + const_reverse_iterator rend() const { return values_.rend(); } ///< Reverse iterator over variables + + /** print required by Testable for unit testing */ + void print(const std::string& str = "VectorValues: ", + const IndexFormatter& formatter = DefaultIndexFormatter) const; + + /** equals required by Testable for unit testing */ + bool equals(const VectorValuesOrdered& x, double tol = 1e-9) const; + + /// @{ + /// \anchor AdvancedConstructors + /// @name Advanced Constructors + /// @} + + /** Construct from a container of variable dimensions (in variable order), without initializing any values. */ + template + explicit VectorValuesOrdered(const CONTAINER& dimensions) { this->append(dimensions); } + + /** Construct to hold nVars vectors of varDim dimension each. */ + VectorValuesOrdered(Index nVars, size_t varDim) { this->resize(nVars, varDim); } + + /** Named constructor to create a VectorValues that matches the structure of + * the specified VectorValues, but do not initialize the new values. */ + static VectorValuesOrdered SameStructure(const VectorValuesOrdered& other); + + /** Named constructor to create a VectorValues from a container of variable + * dimensions that is filled with zeros. + * @param dimensions A container of the dimension of each variable to create. + */ + template + static VectorValuesOrdered Zero(const CONTAINER& dimensions); + + /** Named constructor to create a VectorValues filled with zeros that has + * \c nVars variables, each of dimension \c varDim + * @param nVars The number of variables to create + * @param varDim The dimension of each variable + * @return The new VectorValues + */ + static VectorValuesOrdered Zero(Index nVars, size_t varDim); + + /// @} + /// @name Advanced Interface + /// @{ + + /** Resize this VectorValues to have identical structure to other, leaving + * this VectorValues with uninitialized values. + * @param other The VectorValues whose structure to copy + */ + void resizeLike(const VectorValuesOrdered& other); + + /** Resize the VectorValues to hold \c nVars variables, each of dimension + * \c varDim. Any individual vectors that do not change size will keep + * their values, but any new or resized vectors will be uninitialized. + * @param nVars The number of variables to create + * @param varDim The dimension of each variable + */ + void resize(Index nVars, size_t varDim); + + /** Resize the VectorValues to contain variables of the dimensions stored + * in \c dimensions. Any individual vectors that do not change size will keep + * their values, but any new or resized vectors will be uninitialized. + * @param dimensions A container of the dimension of each variable to create. + */ + template + void resize(const CONTAINER& dimensions); + + /** Append to the VectorValues to additionally contain variables of the + * dimensions stored in \c dimensions. The new variables are uninitialized, + * but this function is used to pre-allocate space for performance. This + * function preserves the original data, so all previously-existing variables + * are left unchanged. + * @param dimensions A container of the dimension of each variable to create. + */ + template + void append(const CONTAINER& dimensions); + + /** Removes the last subvector from the VectorValues */ + void pop_back() { values_.pop_back(); }; + + /** Set all entries to zero, does not modify the size. */ + void setZero(); + + /** Retrieve the entire solution as a single vector */ + const Vector asVector() const; + + /** Access a vector that is a subset of relevant indices */ + const Vector vector(const std::vector& indices) const; + + /** Check whether this VectorValues has the same structure, meaning has the + * same number of variables and that all variables are of the same dimension, + * as another VectorValues + * @param other The other VectorValues with which to compare structure + * @return \c true if the structure is the same, \c false if not. + */ + bool hasSameStructure(const VectorValuesOrdered& other) const; + + /** + * Permute the variables in the VariableIndex according to the given partial permutation + */ + void permuteInPlace(const Permutation& selector, const Permutation& permutation); + + /** + * Permute the entries of this VectorValues in place + */ + void permuteInPlace(const Permutation& permutation); + + /** + * Swap the data in this VectorValues with another. + */ + void swap(VectorValuesOrdered& other); + + /// @} + /// @name Linear algebra operations + /// @{ + + /** Dot product with another VectorValues, interpreting both as vectors of + * their concatenated values. */ + double dot(const VectorValuesOrdered& v) const; + + /** Vector L2 norm */ + double norm() const; + + /** Squared vector L2 norm */ + double squaredNorm() const; + + /** + * + operator does element-wise addition. Both VectorValues must have the + * same structure (checked when NDEBUG is not defined). + */ + VectorValuesOrdered operator+(const VectorValuesOrdered& c) const; + + /** + * + operator does element-wise subtraction. Both VectorValues must have the + * same structure (checked when NDEBUG is not defined). + */ + VectorValuesOrdered operator-(const VectorValuesOrdered& c) const; + + /** + * += operator does element-wise addition. Both VectorValues must have the + * same structure (checked when NDEBUG is not defined). + */ + void operator+=(const VectorValuesOrdered& c); + + /// @} + + /// @} + /// @name Matlab syntactic sugar for linear algebra operations + /// @{ + + inline VectorValuesOrdered add(const VectorValuesOrdered& c) const { return *this + c; } + inline VectorValuesOrdered scale(const double a, const VectorValuesOrdered& c) const { return a * (*this); } + + /// @} + + private: + // Throw an exception if j does not exist + void checkExists(Index j) const { + if(!exists(j)) { + const std::string msg = + (boost::format("VectorValues: requested variable index j=%1% is not in this VectorValues.") % j).str(); + throw std::out_of_range(msg); + } + } + + public: + + /** + * scale a vector by a scalar + */ + friend VectorValuesOrdered operator*(const double a, const VectorValuesOrdered &v) { + VectorValuesOrdered result = VectorValuesOrdered::SameStructure(v); + for(Index j = 0; j < v.size(); ++j) + result.values_[j] = a * v.values_[j]; + return result; + } + + /// TODO: linear algebra interface seems to have been added for SPCG. + friend void scal(double alpha, VectorValuesOrdered& x) { + for(Index j = 0; j < x.size(); ++j) + x.values_[j] *= alpha; + } + /// TODO: linear algebra interface seems to have been added for SPCG. + friend void axpy(double alpha, const VectorValuesOrdered& x, VectorValuesOrdered& y) { + if(x.size() != y.size()) + throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); + for(Index j = 0; j < x.size(); ++j) + if(x.values_[j].size() == y.values_[j].size()) + y.values_[j] += alpha * x.values_[j]; + else + throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); + } + /// TODO: linear algebra interface seems to have been added for SPCG. + friend void sqrt(VectorValuesOrdered &x) { + for(Index j = 0; j < x.size(); ++j) + x.values_[j] = x.values_[j].cwiseSqrt(); + } + + /// TODO: linear algebra interface seems to have been added for SPCG. + friend void ediv(const VectorValuesOrdered& numerator, const VectorValuesOrdered& denominator, VectorValuesOrdered &result) { + if(numerator.size() != denominator.size() || numerator.size() != result.size()) + throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); + for(Index j = 0; j < numerator.size(); ++j) + if(numerator.values_[j].size() == denominator.values_[j].size() && numerator.values_[j].size() == result.values_[j].size()) + result.values_[j] = numerator.values_[j].cwiseQuotient(denominator.values_[j]); + else + throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); + } + + /// TODO: linear algebra interface seems to have been added for SPCG. + friend void edivInPlace(VectorValuesOrdered& x, const VectorValuesOrdered& y) { + if(x.size() != y.size()) + throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); + for(Index j = 0; j < x.size(); ++j) + if(x.values_[j].size() == y.values_[j].size()) + x.values_[j].array() /= y.values_[j].array(); + else + throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); + } + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(values_); + } + }; // VectorValues definition + + // Implementations of template and inline functions + + /* ************************************************************************* */ + template + void VectorValuesOrdered::resize(const CONTAINER& dimensions) { + values_.clear(); + append(dimensions); + } + + /* ************************************************************************* */ + template + void VectorValuesOrdered::append(const CONTAINER& dimensions) { + size_t i = size(); + values_.resize(size() + dimensions.size()); + BOOST_FOREACH(size_t dim, dimensions) { + values_[i] = Vector(dim); + ++ i; + } + } + + /* ************************************************************************* */ + template + VectorValuesOrdered VectorValuesOrdered::Zero(const CONTAINER& dimensions) { + VectorValuesOrdered ret; + ret.values_.resize(dimensions.size()); + size_t i = 0; + BOOST_FOREACH(size_t dim, dimensions) { + ret.values_[i] = Vector::Zero(dim); + ++ i; + } + return ret; + } + + namespace internal { + /* ************************************************************************* */ + // Helper function, extracts vectors with variable indices + // in the first and last iterators, and concatenates them in that order into the + // output. + template + const Vector extractVectorValuesSlices(const VectorValuesOrdered& values, ITERATOR first, ITERATOR last, bool allowNonexistant = false) { + // Find total dimensionality + size_t dim = 0; + for(ITERATOR j = first; j != last; ++j) + // If allowNonexistant is true, skip nonexistent indices (otherwise dim will throw an error on nonexistent) + if(!allowNonexistant || values.exists(*j)) + dim += values.dim(*j); + + // Copy vectors + Vector ret(dim); + size_t varStart = 0; + for(ITERATOR j = first; j != last; ++j) { + // If allowNonexistant is true, skip nonexistent indices (otherwise dim will throw an error on nonexistent) + if(!allowNonexistant || values.exists(*j)) { + ret.segment(varStart, values.dim(*j)) = values[*j]; + varStart += values.dim(*j); + } + } + return ret; + } + + /* ************************************************************************* */ + // Helper function, writes to the variables in values + // with indices iterated over by first and last, interpreting vector as the + // concatenated vectors to write. + template + void writeVectorValuesSlices(const VECTOR& vector, VectorValuesOrdered& values, ITERATOR first, ITERATOR last) { + // Copy vectors + size_t varStart = 0; + for(ITERATOR j = first; j != last; ++j) { + values[*j] = vector.segment(varStart, values[*j].rows()); + varStart += values[*j].rows(); + } + assert(varStart == vector.rows()); + } + } + +} // \namespace gtsam diff --git a/gtsam/linear/VectorValuesUnordered.cpp b/gtsam/linear/VectorValuesUnordered.cpp deleted file mode 100644 index ea805ebe5..000000000 --- a/gtsam/linear/VectorValuesUnordered.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VectorValues.cpp - * @brief Implementations for VectorValues - * @author Richard Roberts - * @author Alex Cunningham - */ - -#include - -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace gtsam { - - using boost::combine; - using boost::adaptors::transformed; - using boost::adaptors::map_values; - using boost::accumulate; - - /* ************************************************************************* */ - VectorValuesUnordered::VectorValuesUnordered(const VectorValuesUnordered& first, const VectorValuesUnordered& second) - { - // Merge using predicate for comparing first of pair - std::merge(first.begin(), first.end(), second.begin(), second.end(), std::inserter(values_, values_.end()), - boost::bind(&std::less::operator(), std::less(), boost::bind(&KeyValuePair::first, _1), boost::bind(&KeyValuePair::first, _2))); - if(size() != first.size() + second.size()) - throw std::invalid_argument("Requested to merge two VectorValues that have one or more variables in common."); - } - - /* ************************************************************************* */ - VectorValuesUnordered VectorValuesUnordered::Zero(const VectorValuesUnordered& other) - { - VectorValuesUnordered result; - BOOST_FOREACH(const KeyValuePair& v, other) - result.values_.insert(make_pair(v.first, Vector::Zero(v.second.size()))); - return result; - } - - /* ************************************************************************* */ - void VectorValuesUnordered::insert(const VectorValuesUnordered& values) - { - size_t originalSize = size(); - values_.insert(values.begin(), values.end()); - if(size() != originalSize + values.size()) - throw std::invalid_argument("Requested to insert a VectorValues into another VectorValues that already contains one or more of its keys."); - } - - /* ************************************************************************* */ - void VectorValuesUnordered::print(const std::string& str, const KeyFormatter& formatter) const { - std::cout << str << ": " << size() << " elements\n"; - BOOST_FOREACH(const value_type& key_value, *this) - std::cout << " " << formatter(key_value.first) << ": " << key_value.second.transpose() << "\n"; - std::cout.flush(); - } - - /* ************************************************************************* */ - bool VectorValuesUnordered::equals(const VectorValuesUnordered& x, double tol) const { - if(this->size() != x.size()) - return false; - typedef boost::tuple ValuePair; - BOOST_FOREACH(const ValuePair& values, boost::combine(*this, x)) { - if(values.get<0>().first != values.get<1>().first || - !equal_with_abs_tol(values.get<0>().second, values.get<1>().second, tol)) - return false; - } - return true; - } - - /* ************************************************************************* */ - const Vector VectorValuesUnordered::vector() const - { - // Count dimensions - DenseIndex totalDim = 0; - BOOST_FOREACH(const value_type& v, *this) - totalDim += v.second.size(); - - // Copy vectors - Vector result(totalDim); - DenseIndex pos = 0; - BOOST_FOREACH(const Vector& v, *this | map_values) { - result.segment(pos, v.size()) = v; - pos += v.size(); - } - - return result; - } - - /* ************************************************************************* */ - const Vector VectorValuesUnordered::vector(const std::vector& keys) const - { - // Count dimensions and collect pointers to avoid double lookups - DenseIndex totalDim = 0; - std::vector items(keys.size()); - for(size_t i = 0; i < keys.size(); ++i) { - items[i] = &at(keys[i]); - totalDim += items[i]->size(); - } - - // Copy vectors - Vector result(totalDim); - DenseIndex pos = 0; - BOOST_FOREACH(const Vector *v, items) { - result.segment(pos, v->size()) = *v; - pos += v->size(); - } - - return result; - } - - /* ************************************************************************* */ - void VectorValuesUnordered::swap(VectorValuesUnordered& other) { - this->values_.swap(other.values_); - } - - /* ************************************************************************* */ - namespace internal - { - bool structureCompareOp(const boost::tuple& vv) - { - return vv.get<0>().first == vv.get<1>().first - && vv.get<0>().second.size() == vv.get<1>().second.size(); - } - } - - /* ************************************************************************* */ - bool VectorValuesUnordered::hasSameStructure(const VectorValuesUnordered other) const - { - return accumulate(combine(*this, other) - | transformed(internal::structureCompareOp), true, std::logical_and()); - } - - /* ************************************************************************* */ - double VectorValuesUnordered::dot(const VectorValuesUnordered& v) const - { - if(this->size() != v.size()) - throw invalid_argument("VectorValues::dot called with a VectorValues of different structure"); - double result = 0.0; - typedef boost::tuple ValuePair; - using boost::adaptors::map_values; - BOOST_FOREACH(const ValuePair& values, boost::combine(*this, v)) { - assert_throw(values.get<0>().first == values.get<1>().first, - std::invalid_argument("VectorValues::dot called with a VectorValues of different structure")); - assert_throw(values.get<0>().second.size() == values.get<1>().second.size(), - std::invalid_argument("VectorValues::dot called with a VectorValues of different structure")); - result += values.get<0>().second.dot(values.get<1>().second); - } - return result; - } - - /* ************************************************************************* */ - double VectorValuesUnordered::norm() const { - return std::sqrt(this->squaredNorm()); - } - - /* ************************************************************************* */ - double VectorValuesUnordered::squaredNorm() const { - double sumSquares = 0.0; - using boost::adaptors::map_values; - BOOST_FOREACH(const Vector& v, *this | map_values) - sumSquares += v.squaredNorm(); - return sumSquares; - } - - /* ************************************************************************* */ - VectorValuesUnordered VectorValuesUnordered::operator+(const VectorValuesUnordered& c) const - { - if(this->size() != c.size()) - throw invalid_argument("VectorValues::operator+ called with different vector sizes"); - assert_throw(hasSameStructure(c), - invalid_argument("VectorValues::operator+ called with different vector sizes")); - - VectorValuesUnordered result; - // The result.end() hint here should result in constant-time inserts - for(const_iterator j1 = begin(), j2 = c.begin(); j1 != end(); ++j1, ++j2) - result.values_.insert(result.end(), make_pair(j1->first, j1->second + j2->second)); - - return result; - } - - /* ************************************************************************* */ - VectorValuesUnordered VectorValuesUnordered::add(const VectorValuesUnordered& c) const - { - return *this + c; - } - - /* ************************************************************************* */ - VectorValuesUnordered& VectorValuesUnordered::operator+=(const VectorValuesUnordered& c) - { - if(this->size() != c.size()) - throw invalid_argument("VectorValues::operator+= called with different vector sizes"); - assert_throw(hasSameStructure(c), - invalid_argument("VectorValues::operator+= called with different vector sizes")); - - iterator j1 = begin(); - const_iterator j2 = c.begin(); - // The result.end() hint here should result in constant-time inserts - for(; j1 != end(); ++j1, ++j2) - j1->second += j2->second; - - return *this; - } - - /* ************************************************************************* */ - VectorValuesUnordered& VectorValuesUnordered::addInPlace(const VectorValuesUnordered& c) - { - return *this += c; - } - - /* ************************************************************************* */ - VectorValuesUnordered VectorValuesUnordered::operator-(const VectorValuesUnordered& c) const - { - if(this->size() != c.size()) - throw invalid_argument("VectorValues::operator- called with different vector sizes"); - assert_throw(hasSameStructure(c), - invalid_argument("VectorValues::operator- called with different vector sizes")); - - VectorValuesUnordered result; - // The result.end() hint here should result in constant-time inserts - for(const_iterator j1 = begin(), j2 = c.begin(); j1 != end(); ++j1, ++j2) - result.values_.insert(result.end(), make_pair(j1->first, j1->second - j2->second)); - - return result; - } - - /* ************************************************************************* */ - VectorValuesUnordered VectorValuesUnordered::subtract(const VectorValuesUnordered& c) const - { - return *this - c; - } - - /* ************************************************************************* */ - VectorValuesUnordered& VectorValuesUnordered::operator*=(double alpha) - { - BOOST_FOREACH(Vector& v, *this | map_values) - v *= alpha; - return *this; - } - - /* ************************************************************************* */ - VectorValuesUnordered& VectorValuesUnordered::scaleInPlace(double alpha) - { - return *this *= alpha; - } - - /* ************************************************************************* */ - -} // \namespace gtsam diff --git a/gtsam/linear/VectorValuesUnordered.h b/gtsam/linear/VectorValuesUnordered.h deleted file mode 100644 index ad633c100..000000000 --- a/gtsam/linear/VectorValuesUnordered.h +++ /dev/null @@ -1,348 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file VectorValues.h - * @brief Factor Graph Values - * @author Richard Roberts - */ - -#pragma once - -#include -#include -#include - -#include - -namespace gtsam { - - /** - * This class represents a collection of vector-valued variables associated - * each with a unique integer index. It is typically used to store the variables - * of a GaussianFactorGraph. Optimizing a GaussianFactorGraph or GaussianBayesNet - * returns this class. - * - * For basic usage, such as receiving a linear solution from gtsam solving functions, - * or creating this class in unit tests and examples where speed is not important, - * you can use a simple interface: - * - The default constructor VectorValues() to create this class - * - insert(Key, const Vector&) to add vector variables - * - operator[](Key) for read and write access to stored variables - * - \ref exists (Key) to check if a variable is present - * - Other facilities like iterators, size(), dim(), etc. - * - * Indices can be non-consecutive and inserted out-of-order, but you should not - * use indices that are larger than a reasonable array size because the indices - * correspond to positions in an internal array. - * - * Example: - * \code - VectorValues values; - values.insert(3, Vector_(3, 1.0, 2.0, 3.0)); - values.insert(4, Vector_(2, 4.0, 5.0)); - values.insert(0, Vector_(4, 6.0, 7.0, 8.0, 9.0)); - - // Prints [ 3.0 4.0 ] - gtsam::print(values[1]); - - // Prints [ 8.0 9.0 ] - values[1] = Vector_(2, 8.0, 9.0); - gtsam::print(values[1]); - \endcode - * - *

Advanced Interface and Performance Information

- * - * Internally, all vector values are stored as part of one large vector. In - * gtsam this vector is always pre-allocated for efficiency, using the - * advanced interface described below. Accessing and modifying already-allocated - * values is \f$ O(1) \f$. Using the insert() function of the standard interface - * is slow because it requires re-allocating the internal vector. - * - * For advanced usage, or where speed is important: - * - Allocate space ahead of time using a pre-allocating constructor - * (\ref AdvancedConstructors "Advanced Constructors"), Zero(), - * SameStructure(), resize(), or append(). Do not use - * insert(Key, const Vector&), which always has to re-allocate the - * internal vector. - * - The vector() function permits access to the underlying Vector, for - * doing mathematical or other operations that require all values. - * - operator[]() returns a SubVector view of the underlying Vector, - * without copying any data. - * - * Access is through the variable index j, and returns a SubVector, - * which is a view on the underlying data structure. - * - * This class is additionally used in gradient descent and dog leg to store the gradient. - * \nosubgrouping - */ - class GTSAM_EXPORT VectorValuesUnordered { - protected: - typedef VectorValuesUnordered This; - typedef FastMap Values; ///< Typedef for the collection of Vectors making up a VectorValues - Values values_; ///< Collection of Vectors making up this VectorValues - - public: - typedef Values::iterator iterator; ///< Iterator over vector values - typedef Values::const_iterator const_iterator; ///< Const iterator over vector values - typedef Values::reverse_iterator reverse_iterator; ///< Reverse iterator over vector values - typedef Values::const_reverse_iterator const_reverse_iterator; ///< Const reverse iterator over vector values - typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class - typedef Values::value_type value_type; ///< Typedef to pair, a key-value pair - typedef value_type KeyValuePair; ///< Typedef to pair, a key-value pair - - /// @name Standard Constructors - /// @{ - - /** - * Default constructor creates an empty VectorValues. - */ - VectorValuesUnordered() {} - - /** Merge two VectorValues into one, this is more efficient than inserting elements one by one. */ - VectorValuesUnordered(const VectorValuesUnordered& first, const VectorValuesUnordered& second); - - /** Create from another container holding pair. */ - template - explicit VectorValuesUnordered(const CONTAINER& c) : values_(c.begin(), c.end()) {} - - /** Implicit copy constructor to specialize the explicit constructor from any container. */ - VectorValuesUnordered(const VectorValuesUnordered& c) : values_(c.values_) {} - - /** Create from a pair of iterators over pair. */ - template - VectorValuesUnordered(ITERATOR first, ITERATOR last) : values_(first, last) {} - - /** Create a VectorValues with the same structure as \c other, but filled with zeros. */ - static VectorValuesUnordered Zero(const VectorValuesUnordered& other); - - /// @} - /// @name Standard Interface - /// @{ - - /** Number of variables stored. */ - Key size() const { return values_.size(); } - - /** Return the dimension of variable \c j. */ - size_t dim(Key j) const { return at(j).rows(); } - - /** Check whether a variable with key \c j exists. */ - bool exists(Key j) const { return find(j) != end(); } - - /** Read/write access to the vector value with key \c j, throws std::out_of_range if \c j does not exist, identical to operator[](Key). */ - Vector& at(Key j) { - iterator item = find(j); - if(item == end()) - throw std::out_of_range( - "Requested variable '" + DefaultKeyFormatter(j) + "' is not in this VectorValues."); - else - return item->second; - } - - /** Access the vector value with key \c j (const version), throws std::out_of_range if \c j does not exist, identical to operator[](Key). */ - const Vector& at(Key j) const { - const_iterator item = find(j); - if(item == end()) - throw std::out_of_range( - "Requested variable '" + DefaultKeyFormatter(j) + "' is not in this VectorValues."); - else - return item->second; - } - - /** Read/write access to the vector value with key \c j, throws std::out_of_range if \c j does not exist, identical to at(Key). */ - Vector& operator[](Key j) { return at(j); } - - /** Access the vector value with key \c j (const version), throws std::out_of_range if \c j does not exist, identical to at(Key). */ - const Vector& operator[](Key j) const { return at(j); } - - /** Insert a vector \c value with key \c j. Throws an invalid_argument exception if the key \c j is already used. - * @param value The vector to be inserted. - * @param j The index with which the value will be associated. - */ - void insert(Key j, const Vector& value) { - insert(std::pair(j, value)); // Note only passing a reference to the Vector - } - - /** Insert a vector \c value with key \c j. Throws an invalid_argument exception if the key \c j is already used. - * @param value The vector to be inserted. - * @param j The index with which the value will be associated. - */ - void insert(std::pair key_value) { - // Note that here we accept a pair with a reference to the Vector, but the Vector is copied as - // it is inserted into the values_ map. - if(!values_.insert(key_value).second) - throw std::invalid_argument( - "Requested to insert variable '" + DefaultKeyFormatter(key_value.first) - + "' already in this VectorValues."); - } - - /** Insert all values from \c values. Throws an invalid_argument exception if any keys to be - * inserted are already used. */ - void insert(const VectorValuesUnordered& values); - - /** insert that mimics the STL map insert - if the value already exists, the map is not modified - * and an iterator to the existing value is returned, along with 'false'. If the value did not - * exist, it is inserted and an iterator pointing to the new element, along with 'true', is - * returned. */ - std::pair tryInsert(Key j, const Vector& value) { - return values_.insert(std::make_pair(j, value)); } - - iterator begin() { return values_.begin(); } ///< Iterator over variables - const_iterator begin() const { return values_.begin(); } ///< Iterator over variables - iterator end() { return values_.end(); } ///< Iterator over variables - const_iterator end() const { return values_.end(); } ///< Iterator over variables - reverse_iterator rbegin() { return values_.rbegin(); } ///< Reverse iterator over variables - const_reverse_iterator rbegin() const { return values_.rbegin(); } ///< Reverse iterator over variables - reverse_iterator rend() { return values_.rend(); } ///< Reverse iterator over variables - const_reverse_iterator rend() const { return values_.rend(); } ///< Reverse iterator over variables - - /** Return the iterator corresponding to the requested key, or end() if no variable is present with this key. */ - iterator find(Key j) { return values_.find(j); } - - /** Return the iterator corresponding to the requested key, or end() if no variable is present with this key. */ - const_iterator find(Key j) const { return values_.find(j); } - - /** print required by Testable for unit testing */ - void print(const std::string& str = "VectorValues: ", - const KeyFormatter& formatter = DefaultKeyFormatter) const; - - /** equals required by Testable for unit testing */ - bool equals(const VectorValuesUnordered& x, double tol = 1e-9) const; - - /// @{ - /// @name Advanced Interface - /// @{ - - /** Retrieve the entire solution as a single vector */ - const Vector vector() const; - - /** Access a vector that is a subset of relevant keys. */ - const Vector vector(const std::vector& keys) const; - - /** Swap the data in this VectorValues with another. */ - void swap(VectorValuesUnordered& other); - - /** Check if this VectorValues has the same structure (keys and dimensions) as another */ - bool hasSameStructure(const VectorValuesUnordered other) const; - - /// @} - /// @name Linear algebra operations - /// @{ - - /** Dot product with another VectorValues, interpreting both as vectors of - * their concatenated values. Both VectorValues must have the - * same structure (checked when NDEBUG is not defined). */ - double dot(const VectorValuesUnordered& v) const; - - /** Vector L2 norm */ - double norm() const; - - /** Squared vector L2 norm */ - double squaredNorm() const; - - /** Element-wise addition, synonym for add(). Both VectorValues must have the same structure - * (checked when NDEBUG is not defined). */ - VectorValuesUnordered operator+(const VectorValuesUnordered& c) const; - - /** Element-wise addition, synonym for operator+(). Both VectorValues must have the same - * structure (checked when NDEBUG is not defined). */ - VectorValuesUnordered add(const VectorValuesUnordered& c) const; - - /** Element-wise addition in-place, synonym for operator+=(). Both VectorValues must have the - * same structure (checked when NDEBUG is not defined). */ - VectorValuesUnordered& operator+=(const VectorValuesUnordered& c); - - /** Element-wise addition in-place, synonym for operator+=(). Both VectorValues must have the - * same structure (checked when NDEBUG is not defined). */ - VectorValuesUnordered& addInPlace(const VectorValuesUnordered& c); - - /** Element-wise subtraction, synonym for subtract(). Both VectorValues must have the same - * structure (checked when NDEBUG is not defined). */ - VectorValuesUnordered operator-(const VectorValuesUnordered& c) const; - - /** Element-wise subtraction, synonym for operator-(). Both VectorValues must have the same - * structure (checked when NDEBUG is not defined). */ - VectorValuesUnordered subtract(const VectorValuesUnordered& c) const; - - /** Element-wise scaling by a constant in-place. */ - VectorValuesUnordered& operator*=(double alpha); - - /** Element-wise scaling by a constant in-place. */ - VectorValuesUnordered& scaleInPlace(double alpha); - - /// @} - - /// @} - /// @name Matlab syntactic sugar for linear algebra operations - /// @{ - - //inline VectorValuesUnordered scale(const double a, const VectorValuesUnordered& c) const { return a * (*this); } - - /// @} - - /** - * scale a vector by a scalar - */ - //friend VectorValuesUnordered operator*(const double a, const VectorValuesUnordered &v) { - // VectorValuesUnordered result = VectorValuesUnordered::SameStructure(v); - // for(Key j = 0; j < v.size(); ++j) - // result.values_[j] = a * v.values_[j]; - // return result; - //} - - //// TODO: linear algebra interface seems to have been added for SPCG. - //friend void axpy(double alpha, const VectorValuesUnordered& x, VectorValuesUnordered& y) { - // if(x.size() != y.size()) - // throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); - // for(Key j = 0; j < x.size(); ++j) - // if(x.values_[j].size() == y.values_[j].size()) - // y.values_[j] += alpha * x.values_[j]; - // else - // throw std::invalid_argument("axpy(VectorValues) called with different vector sizes"); - //} - //// TODO: linear algebra interface seems to have been added for SPCG. - //friend void sqrt(VectorValuesUnordered &x) { - // for(Key j = 0; j < x.size(); ++j) - // x.values_[j] = x.values_[j].cwiseSqrt(); - //} - - //// TODO: linear algebra interface seems to have been added for SPCG. - //friend void ediv(const VectorValuesUnordered& numerator, const VectorValuesUnordered& denominator, VectorValuesUnordered &result) { - // if(numerator.size() != denominator.size() || numerator.size() != result.size()) - // throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); - // for(Key j = 0; j < numerator.size(); ++j) - // if(numerator.values_[j].size() == denominator.values_[j].size() && numerator.values_[j].size() == result.values_[j].size()) - // result.values_[j] = numerator.values_[j].cwiseQuotient(denominator.values_[j]); - // else - // throw std::invalid_argument("ediv(VectorValues) called with different vector sizes"); - //} - - //// TODO: linear algebra interface seems to have been added for SPCG. - //friend void edivInPlace(VectorValuesUnordered& x, const VectorValuesUnordered& y) { - // if(x.size() != y.size()) - // throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); - // for(Key j = 0; j < x.size(); ++j) - // if(x.values_[j].size() == y.values_[j].size()) - // x.values_[j].array() /= y.values_[j].array(); - // else - // throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes"); - //} - - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(values_); - } - }; // VectorValues definition - -} // \namespace gtsam diff --git a/gtsam/linear/iterative.cpp b/gtsam/linear/iterative.cpp index 07d4de865..52652fd79 100644 --- a/gtsam/linear/iterative.cpp +++ b/gtsam/linear/iterative.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -61,15 +61,15 @@ namespace gtsam { } /* ************************************************************************* */ - VectorValues steepestDescent(const GaussianFactorGraph& fg, - const VectorValues& x, const ConjugateGradientParameters & parameters) { - return conjugateGradients( + VectorValuesOrdered steepestDescent(const GaussianFactorGraphOrdered& fg, + const VectorValuesOrdered& x, const ConjugateGradientParameters & parameters) { + return conjugateGradients( fg, x, parameters, true); } - VectorValues conjugateGradientDescent(const GaussianFactorGraph& fg, - const VectorValues& x, const ConjugateGradientParameters & parameters) { - return conjugateGradients( + VectorValuesOrdered conjugateGradientDescent(const GaussianFactorGraphOrdered& fg, + const VectorValuesOrdered& x, const ConjugateGradientParameters & parameters) { + return conjugateGradients( fg, x, parameters); } diff --git a/gtsam/linear/iterative.h b/gtsam/linear/iterative.h index 7e0609f37..cffe856de 100644 --- a/gtsam/linear/iterative.h +++ b/gtsam/linear/iterative.h @@ -19,7 +19,7 @@ #pragma once #include -#include +#include #include namespace gtsam { @@ -129,17 +129,17 @@ namespace gtsam { /** * Method of steepest gradients, Gaussian Factor Graph version */ - GTSAM_EXPORT VectorValues steepestDescent( - const GaussianFactorGraph& fg, - const VectorValues& x, + GTSAM_EXPORT VectorValuesOrdered steepestDescent( + const GaussianFactorGraphOrdered& fg, + const VectorValuesOrdered& x, const ConjugateGradientParameters & parameters); /** * Method of conjugate gradients (CG), Gaussian Factor Graph version */ - GTSAM_EXPORT VectorValues conjugateGradientDescent( - const GaussianFactorGraph& fg, - const VectorValues& x, + GTSAM_EXPORT VectorValuesOrdered conjugateGradientDescent( + const GaussianFactorGraphOrdered& fg, + const VectorValuesOrdered& x, const ConjugateGradientParameters & parameters); diff --git a/gtsam/linear/tests/testGaussianBayesNetUnordered.cpp b/gtsam/linear/tests/testGaussianBayesNetUnordered.cpp index c35a670b0..60cd181aa 100644 --- a/gtsam/linear/tests/testGaussianBayesNetUnordered.cpp +++ b/gtsam/linear/tests/testGaussianBayesNetUnordered.cpp @@ -26,21 +26,21 @@ using namespace boost::assign; #include -#include -#include -#include +#include +#include +#include using namespace std; using namespace gtsam; static const Key _x_=0, _y_=1, _z_=2; -static GaussianBayesNetUnordered smallBayesNet = list_of - (GaussianConditionalUnordered(_x_, Vector_(1, 9.0), Matrix_(1, 1, 1.0), _y_, Matrix_(1, 1, 1.0))) - (GaussianConditionalUnordered(_y_, Vector_(1, 5.0), Matrix_(1, 1, 1.0))); +static GaussianBayesNet smallBayesNet = list_of + (GaussianConditional(_x_, Vector_(1, 9.0), Matrix_(1, 1, 1.0), _y_, Matrix_(1, 1, 1.0))) + (GaussianConditional(_y_, Vector_(1, 5.0), Matrix_(1, 1, 1.0))); /* ************************************************************************* */ -TEST( GaussianBayesNet, matrix ) +TEST( GaussianBayesNetOrdered, matrix ) { Matrix R; Vector d; boost::tie(R,d) = smallBayesNet.matrix(); // find matrix and RHS @@ -56,11 +56,11 @@ TEST( GaussianBayesNet, matrix ) } /* ************************************************************************* */ -TEST( GaussianBayesNet, optimize ) +TEST( GaussianBayesNetOrdered, optimize ) { - VectorValuesUnordered actual = smallBayesNet.optimize(); + VectorValues actual = smallBayesNet.optimize(); - VectorValuesUnordered expected = map_list_of + VectorValues expected = map_list_of (_x_, Vector_(1, 4.0)) (_y_, Vector_(1, 5.0)); @@ -68,32 +68,32 @@ TEST( GaussianBayesNet, optimize ) } /* ************************************************************************* */ -TEST( GaussianBayesNet, optimize3 ) +TEST( GaussianBayesNetOrdered, optimize3 ) { // y = R*x, x=inv(R)*y // 4 = 1 1 -1 // 5 1 5 // NOTE: we are supplying a new RHS here - VectorValuesUnordered expected = map_list_of + VectorValues expected = map_list_of (_x_, Vector_(1, -1.0)) (_y_, Vector_(1, 5.0)); // Test different RHS version - VectorValuesUnordered gx = map_list_of + VectorValues gx = map_list_of (_x_, Vector_(1, 4.0)) (_y_, Vector_(1, 5.0)); - VectorValuesUnordered actual = smallBayesNet.backSubstitute(gx); + VectorValues actual = smallBayesNet.backSubstitute(gx); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST( GaussianBayesNet, backSubstituteTranspose ) +TEST( GaussianBayesNetOrdered, backSubstituteTranspose ) { // x=R'*y, expected=inv(R')*x // 2 = 1 2 // 5 1 1 3 - VectorValuesUnordered + VectorValues x = map_list_of (_x_, Vector_(1, 2.0)) (_y_, Vector_(1, 5.0)), @@ -101,24 +101,24 @@ TEST( GaussianBayesNet, backSubstituteTranspose ) (_x_, Vector_(1, 2.0)) (_y_, Vector_(1, 3.0)); - VectorValuesUnordered actual = smallBayesNet.backSubstituteTranspose(x); + VectorValues actual = smallBayesNet.backSubstituteTranspose(x); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ // Tests computing Determinant -TEST( GaussianBayesNet, DeterminantTest ) +TEST( GaussianBayesNetOrdered, DeterminantTest ) { - GaussianBayesNetUnordered cbn; - cbn += GaussianConditionalUnordered( + GaussianBayesNet cbn; + cbn += GaussianConditional( 0, Vector_( 2, 3.0, 4.0 ), Matrix_(2, 2, 1.0, 3.0, 0.0, 4.0 ), 1, Matrix_(2, 2, 2.0, 1.0, 2.0, 3.0), noiseModel::Isotropic::Sigma(2, 2.0)); - cbn += GaussianConditionalUnordered( + cbn += GaussianConditional( 1, Vector_( 2, 5.0, 6.0 ), Matrix_(2, 2, 1.0, 1.0, 0.0, 3.0 ), 2, Matrix_(2, 2, 1.0, 0.0, 5.0, 2.0), noiseModel::Isotropic::Sigma(2, 2.0)); - cbn += GaussianConditionalUnordered( + cbn += GaussianConditional( 3, Vector_( 2, 7.0, 8.0 ), Matrix_(2, 2, 1.0, 1.0, 0.0, 5.0 ), noiseModel::Isotropic::Sigma(2, 2.0)); double expectedDeterminant = 60.0 / 64.0; diff --git a/gtsam/linear/tests/testGaussianBayesTreeUnordered.cpp b/gtsam/linear/tests/testGaussianBayesTreeUnordered.cpp index 864f35456..ec03f9e75 100644 --- a/gtsam/linear/tests/testGaussianBayesTreeUnordered.cpp +++ b/gtsam/linear/tests/testGaussianBayesTreeUnordered.cpp @@ -25,9 +25,9 @@ using namespace boost::assign; #include #include -#include -#include -#include +#include +#include +#include using namespace std; using namespace gtsam; @@ -37,30 +37,30 @@ using namespace gtsam; namespace { const Key x1=1, x2=2, x3=3, x4=4; const SharedDiagonal chainNoise = noiseModel::Isotropic::Sigma(1, 0.5); - const GaussianFactorGraphUnordered chain = list_of - (JacobianFactorUnordered(x2, Matrix_(1,1,1.), x1, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)) - (JacobianFactorUnordered(x2, Matrix_(1,1,1.), x3, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)) - (JacobianFactorUnordered(x3, Matrix_(1,1,1.), x4, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)) - (JacobianFactorUnordered(x4, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)); - const OrderingUnordered chainOrdering = OrderingUnordered(list_of(x2)(x1)(x3)(x4)); + const GaussianFactorGraph chain = list_of + (JacobianFactor(x2, Matrix_(1,1,1.), x1, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)) + (JacobianFactor(x2, Matrix_(1,1,1.), x3, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)) + (JacobianFactor(x3, Matrix_(1,1,1.), x4, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)) + (JacobianFactor(x4, Matrix_(1,1,1.), Vector_(1,1.), chainNoise)); + const Ordering chainOrdering = Ordering(list_of(x2)(x1)(x3)(x4)); /* ************************************************************************* */ // Helper functions for below - GaussianBayesTreeCliqueUnordered::shared_ptr MakeClique(const GaussianConditionalUnordered& conditional) + GaussianBayesTreeClique::shared_ptr MakeClique(const GaussianConditional& conditional) { - return boost::make_shared( - boost::make_shared(conditional)); + return boost::make_shared( + boost::make_shared(conditional)); } template - GaussianBayesTreeCliqueUnordered::shared_ptr MakeClique( - const GaussianConditionalUnordered& conditional, const CHILDREN& children) + GaussianBayesTreeClique::shared_ptr MakeClique( + const GaussianConditional& conditional, const CHILDREN& children) { - GaussianBayesTreeCliqueUnordered::shared_ptr clique = - boost::make_shared( - boost::make_shared(conditional)); + GaussianBayesTreeClique::shared_ptr clique = + boost::make_shared( + boost::make_shared(conditional)); clique->children = children; - BOOST_FOREACH(const GaussianBayesTreeCliqueUnordered::shared_ptr& child, children) + BOOST_FOREACH(const GaussianBayesTreeClique::shared_ptr& child, children) child->parent_ = clique; return clique; } @@ -80,53 +80,53 @@ namespace { * * 1 0 0 1 */ -TEST( GaussianBayesTree, eliminate ) +TEST( GaussianBayesTreeOrdered, eliminate ) { - GaussianBayesTreeUnordered bt = *chain.eliminateMultifrontal(chainOrdering); + GaussianBayesTree bt = *chain.eliminateMultifrontal(chainOrdering); Matrix two = Matrix_(1,1,2.); Matrix one = Matrix_(1,1,1.); - GaussianBayesTreeUnordered bayesTree_expected; + GaussianBayesTree bayesTree_expected; bayesTree_expected.insertRoot( - MakeClique(GaussianConditionalUnordered(pair_list_of (x3, Matrix_(2,1, 2., 0.)) (x4, Matrix_(2,1, 2., 2.)), 2, Vector_(2, 2., 2.)), list_of - (MakeClique(GaussianConditionalUnordered(pair_list_of (x2, Matrix_(2,1, -2.*sqrt(2.), 0.)) (x1, Matrix_(2,1, -sqrt(2.), -sqrt(2.))) (x3, Matrix_(2,1, -sqrt(2.), sqrt(2.))), 2, Vector_(2, -2.*sqrt(2.), 0.)))))); + MakeClique(GaussianConditional(pair_list_of (x3, Matrix_(2,1, 2., 0.)) (x4, Matrix_(2,1, 2., 2.)), 2, Vector_(2, 2., 2.)), list_of + (MakeClique(GaussianConditional(pair_list_of (x2, Matrix_(2,1, -2.*sqrt(2.), 0.)) (x1, Matrix_(2,1, -sqrt(2.), -sqrt(2.))) (x3, Matrix_(2,1, -sqrt(2.), sqrt(2.))), 2, Vector_(2, -2.*sqrt(2.), 0.)))))); EXPECT(assert_equal(bayesTree_expected, bt)); } /* ************************************************************************* */ -TEST( GaussianBayesTree, optimizeMultiFrontal ) +TEST( GaussianBayesTreeOrdered, optimizeMultiFrontal ) { - VectorValuesUnordered expected = pair_list_of + VectorValues expected = pair_list_of (x1, Vector_(1, 0.)) (x2, Vector_(1, 1.)) (x3, Vector_(1, 0.)) (x4, Vector_(1, 1.)); - VectorValuesUnordered actual = chain.eliminateMultifrontal(chainOrdering)->optimize(); + VectorValues actual = chain.eliminateMultifrontal(chainOrdering)->optimize(); EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ -TEST(GaussianBayesTree, complicatedMarginal) { +TEST(GaussianBayesTreeOrdered, complicatedMarginal) { // Create the conditionals to go in the BayesTree - GaussianBayesTreeUnordered bt; + GaussianBayesTree bt; bt.insertRoot( - MakeClique(GaussianConditionalUnordered(pair_list_of (11, (Matrix(3,1) << 0.0971, 0, 0).finished()) + MakeClique(GaussianConditional(pair_list_of (11, (Matrix(3,1) << 0.0971, 0, 0).finished()) (12, (Matrix(3,2) << 0.3171, 0.4387, 0.9502, 0.3816, 0, 0.7655).finished()), 2, (Vector(3) << 0.2638, 0.1455, 0.1361).finished()), list_of - (MakeClique(GaussianConditionalUnordered(pair_list_of (9, (Matrix(3,1) << 0.7952, 0, 0).finished()) + (MakeClique(GaussianConditional(pair_list_of (9, (Matrix(3,1) << 0.7952, 0, 0).finished()) (10, (Matrix(3,2) << 0.4456, 0.7547, 0.6463, 0.2760, 0, 0.6797).finished()) (11, (Matrix(3,1) << 0.6551, 0.1626, 0.1190).finished()) (12, (Matrix(3,2) << 0.4984, 0.5853, 0.9597, 0.2238, 0.3404, 0.7513).finished()), 2, (Vector(3) << 0.4314, 0.9106, 0.1818).finished()))) - (MakeClique(GaussianConditionalUnordered(pair_list_of (7, (Matrix(3,1) << 0.2551, 0, 0).finished()) + (MakeClique(GaussianConditional(pair_list_of (7, (Matrix(3,1) << 0.2551, 0, 0).finished()) (8, (Matrix(3,2) << 0.8909, 0.1386, 0.9593, 0.1493, 0, 0.2575).finished()) (11, (Matrix(3,1) << 0.8407, 0.2543, 0.8143).finished()), 2, (Vector(3) << 0.3998, 0.2599, 0.8001).finished()), list_of - (MakeClique(GaussianConditionalUnordered(pair_list_of (5, (Matrix(3,1) << 0.2435, 0, 0).finished()) + (MakeClique(GaussianConditional(pair_list_of (5, (Matrix(3,1) << 0.2435, 0, 0).finished()) (6, (Matrix(3,2) << 0.4733, 0.1966, 0.3517, 0.2511, 0.8308, 0.0).finished()) // NOTE the non-upper-triangular form // here since this test was written when we had column permutations @@ -136,19 +136,19 @@ TEST(GaussianBayesTree, complicatedMarginal) { (7, (Matrix(3,1) << 0.5853, 0.5497, 0.9172).finished()) (8, (Matrix(3,2) << 0.2858, 0.3804, 0.7572, 0.5678, 0.7537, 0.0759).finished()), 2, (Vector(3) << 0.8173, 0.8687, 0.0844).finished()), list_of - (MakeClique(GaussianConditionalUnordered(pair_list_of (3, (Matrix(3,1) << 0.0540, 0, 0).finished()) + (MakeClique(GaussianConditional(pair_list_of (3, (Matrix(3,1) << 0.0540, 0, 0).finished()) (4, (Matrix(3,2) << 0.9340, 0.4694, 0.1299, 0.0119, 0, 0.3371).finished()) (6, (Matrix(3,2) << 0.1622, 0.5285, 0.7943, 0.1656, 0.3112, 0.6020).finished()), 2, (Vector(3) << 0.9619, 0.0046, 0.7749).finished()))) - (MakeClique(GaussianConditionalUnordered(pair_list_of (1, (Matrix(3,1) << 0.2630, 0, 0).finished()) + (MakeClique(GaussianConditional(pair_list_of (1, (Matrix(3,1) << 0.2630, 0, 0).finished()) (2, (Matrix(3,2) << 0.7482, 0.2290, 0.4505, 0.9133, 0, 0.1524).finished()) (5, (Matrix(3,1) << 0.8258, 0.5383, 0.9961).finished()), 2, (Vector(3) << 0.0782, 0.4427, 0.1067).finished()))))))))); // Marginal on 5 Matrix expectedCov = (Matrix(1,1) << 236.5166).finished(); - //GaussianConditionalUnordered actualJacobianChol = *bt.marginalFactor(5, EliminateCholesky); - GaussianConditionalUnordered actualJacobianQR = *bt.marginalFactor(5, EliminateQRUnordered); + //GaussianConditional actualJacobianChol = *bt.marginalFactor(5, EliminateCholesky); + GaussianConditional actualJacobianQR = *bt.marginalFactor(5, EliminateQR); //EXPECT(assert_equal(actualJacobianChol, actualJacobianQR)); // Check that Chol and QR obtained marginals are the same LONGS_EQUAL(1, (long)actualJacobianQR.rows()); LONGS_EQUAL(1, (long)actualJacobianQR.size()); @@ -165,7 +165,7 @@ TEST(GaussianBayesTree, complicatedMarginal) { 1015.8, 2886.2, 2886.2, 8471.2).finished(); //actualJacobianChol = bt.marginalFactor(6, EliminateCholesky); - actualJacobianQR = *bt.marginalFactor(6, EliminateQRUnordered); + actualJacobianQR = *bt.marginalFactor(6, EliminateQR); //EXPECT(assert_equal(actualJacobianChol, actualJacobianQR)); // Check that Chol and QR obtained marginals are the same LONGS_EQUAL(2, (long)actualJacobianQR.rows()); LONGS_EQUAL(1, (long)actualJacobianQR.size()); diff --git a/gtsam/linear/tests/testGaussianConditionalObsolete.cpp b/gtsam/linear/tests/testGaussianConditionalObsolete.cpp index 86d4b28b4..2622b71a5 100644 --- a/gtsam/linear/tests/testGaussianConditionalObsolete.cpp +++ b/gtsam/linear/tests/testGaussianConditionalObsolete.cpp @@ -19,9 +19,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -41,7 +41,7 @@ Matrix R = Matrix_(2,2, 0., 4.6904); /* ************************************************************************* */ -TEST(GaussianConditional, constructor) +TEST(GaussianConditionalOrdered, constructor) { Matrix S1 = Matrix_(2,2, -5.2786, -8.6603, @@ -62,9 +62,9 @@ TEST(GaussianConditional, constructor) make_pair(5, S2), make_pair(7, S3); - GaussianConditional actual(1, d, R, terms, s); + GaussianConditionalOrdered actual(1, d, R, terms, s); - GaussianConditional::const_iterator it = actual.beginFrontals(); + GaussianConditionalOrdered::const_iterator it = actual.beginFrontals(); EXPECT(assert_equal(Index(1), *it)); EXPECT(assert_equal(R, actual.get_R())); ++ it; @@ -89,7 +89,7 @@ TEST(GaussianConditional, constructor) EXPECT(assert_equal(s, actual.get_sigmas())); // test copy constructor - GaussianConditional copied(actual); + GaussianConditionalOrdered copied(actual); EXPECT(assert_equal(d, copied.get_d())); EXPECT(assert_equal(s, copied.get_sigmas())); EXPECT(assert_equal(R, copied.get_R())); @@ -97,25 +97,25 @@ TEST(GaussianConditional, constructor) /* ************************************************************************* */ -GaussianConditional construct() { +GaussianConditionalOrdered construct() { Vector d = Vector_(2, 1.0, 2.0); Vector s = Vector_(2, 3.0, 4.0); - GaussianConditional::shared_ptr shared(new GaussianConditional(1, d, R, s)); + GaussianConditionalOrdered::shared_ptr shared(new GaussianConditionalOrdered(1, d, R, s)); return *shared; } -TEST(GaussianConditional, return_value) +TEST(GaussianConditionalOrdered, return_value) { Vector d = Vector_(2, 1.0, 2.0); Vector s = Vector_(2, 3.0, 4.0); - GaussianConditional copied = construct(); + GaussianConditionalOrdered copied = construct(); EXPECT(assert_equal(d, copied.get_d())); EXPECT(assert_equal(s, copied.get_sigmas())); EXPECT(assert_equal(R, copied.get_R())); } /* ************************************************************************* */ -TEST( GaussianConditional, equals ) +TEST( GaussianConditionalOrdered, equals ) { // create a conditional gaussian node Matrix A1(2,2); @@ -137,7 +137,7 @@ TEST( GaussianConditional, equals ) Vector d(2); d(0) = 0.2; d(1) = 0.5; - GaussianConditional + GaussianConditionalOrdered expected(_x_,d, R, _x1_, A1, _l1_, A2, tau), actual(_x_,d, R, _x1_, A1, _l1_, A2, tau); @@ -145,7 +145,7 @@ TEST( GaussianConditional, equals ) } /* ************************************************************************* */ -TEST( GaussianConditional, solve ) +TEST( GaussianConditionalOrdered, solve ) { //expected solution Vector expectedX(2); @@ -166,7 +166,7 @@ TEST( GaussianConditional, solve ) Vector tau = ones(2); - GaussianConditional cg(_x_, d, R, _x1_, A1, _l1_, A2, tau); + GaussianConditionalOrdered cg(_x_, d, R, _x1_, A1, _l1_, A2, tau); Vector sx1(2); sx1(0) = 1.0; sx1(1) = 1.0; @@ -174,12 +174,12 @@ TEST( GaussianConditional, solve ) Vector sl1(2); sl1(0) = 1.0; sl1(1) = 1.0; - VectorValues solution(vector(3, 2)); + VectorValuesOrdered solution(vector(3, 2)); solution[_x_] = d; solution[_x1_] = sx1; // parents solution[_l1_] = sl1; - VectorValues expected(vector(3, 2)); + VectorValuesOrdered expected(vector(3, 2)); expected[_x_] = expectedX; expected[_x1_] = sx1; expected[_l1_] = sl1; @@ -189,7 +189,7 @@ TEST( GaussianConditional, solve ) } /* ************************************************************************* */ -TEST( GaussianConditional, solve_simple ) +TEST( GaussianConditionalOrdered, solve_simple ) { Matrix full_matrix = Matrix_(4, 7, 1.0, 0.0, 2.0, 0.0, 3.0, 0.0, 0.1, @@ -200,20 +200,20 @@ TEST( GaussianConditional, solve_simple ) // solve system as a non-multifrontal version first // 2 variables, frontal has dim=4 vector dims; dims += 4, 2, 1; - GaussianConditional::rsd_type matrices(full_matrix, dims.begin(), dims.end()); + GaussianConditionalOrdered::rsd_type matrices(full_matrix, dims.begin(), dims.end()); Vector sigmas = ones(4); vector cgdims; cgdims += _x_, _x1_; - GaussianConditional cg(cgdims.begin(), cgdims.end(), 1, matrices, sigmas); + GaussianConditionalOrdered cg(cgdims.begin(), cgdims.end(), 1, matrices, sigmas); // partial solution Vector sx1 = Vector_(2, 9.0, 10.0); // elimination order; _x_, _x1_ vector vdim; vdim += 4, 2; - VectorValues actual(vdim); + VectorValuesOrdered actual(vdim); actual[_x1_] = sx1; // parent - VectorValues expected(vdim); + VectorValuesOrdered expected(vdim); expected[_x1_] = sx1; expected[_x_] = Vector_(4, -3.1,-3.4,-11.9,-13.2); @@ -227,7 +227,7 @@ TEST( GaussianConditional, solve_simple ) } /* ************************************************************************* */ -TEST( GaussianConditional, solve_multifrontal ) +TEST( GaussianConditionalOrdered, solve_multifrontal ) { // create full system, 3 variables, 2 frontals, all 2 dim Matrix full_matrix = Matrix_(4, 7, @@ -238,10 +238,10 @@ TEST( GaussianConditional, solve_multifrontal ) // 3 variables, all dim=2 vector dims; dims += 2, 2, 2, 1; - GaussianConditional::rsd_type matrices(full_matrix, dims.begin(), dims.end()); + GaussianConditionalOrdered::rsd_type matrices(full_matrix, dims.begin(), dims.end()); Vector sigmas = ones(4); vector cgdims; cgdims += _x_, _x1_, _l1_; - GaussianConditional cg(cgdims.begin(), cgdims.end(), 2, matrices, sigmas); + GaussianConditionalOrdered cg(cgdims.begin(), cgdims.end(), 2, matrices, sigmas); EXPECT(assert_equal(Vector_(4, 0.1, 0.2, 0.3, 0.4), cg.get_d())); @@ -249,10 +249,10 @@ TEST( GaussianConditional, solve_multifrontal ) Vector sl1 = Vector_(2, 9.0, 10.0); // elimination order; _x_, _x1_, _l1_ - VectorValues actual(vector(3, 2)); + VectorValuesOrdered actual(vector(3, 2)); actual[_l1_] = sl1; // parent - VectorValues expected(vector(3, 2)); + VectorValuesOrdered expected(vector(3, 2)); expected[_x_] = Vector_(2, -3.1,-3.4); expected[_x1_] = Vector_(2, -11.9,-13.2); expected[_l1_] = sl1; @@ -268,7 +268,7 @@ TEST( GaussianConditional, solve_multifrontal ) } /* ************************************************************************* */ -TEST( GaussianConditional, solveTranspose ) { +TEST( GaussianConditionalOrdered, solveTranspose ) { static const Index _y_=1; /** create small Chordal Bayes Net x <- y * x y d @@ -284,9 +284,9 @@ TEST( GaussianConditional, solveTranspose ) { tau(0) = 1.0; // define nodes and specify in reverse topological sort (i.e. parents last) - GaussianConditional::shared_ptr Px_y(new GaussianConditional(_x_, d1, R11, _y_, S12, tau)); - GaussianConditional::shared_ptr Py(new GaussianConditional(_y_, d2, R22, tau)); - GaussianBayesNet cbn; + GaussianConditionalOrdered::shared_ptr Px_y(new GaussianConditionalOrdered(_x_, d1, R11, _y_, S12, tau)); + GaussianConditionalOrdered::shared_ptr Py(new GaussianConditionalOrdered(_y_, d2, R22, tau)); + GaussianBayesNetOrdered cbn; cbn.push_back(Px_y); cbn.push_back(Py); @@ -294,19 +294,19 @@ TEST( GaussianConditional, solveTranspose ) { // 2 = 1 2 // 5 1 1 3 - VectorValues y(vector(2,1)), x(vector(2,1)); + VectorValuesOrdered y(vector(2,1)), x(vector(2,1)); x[_x_] = Vector_(1,2.); x[_y_] = Vector_(1,5.); y[_x_] = Vector_(1,2.); y[_y_] = Vector_(1,3.); // test functional version - VectorValues actual = backSubstituteTranspose(cbn,x); + VectorValuesOrdered actual = backSubstituteTranspose(cbn,x); CHECK(assert_equal(y,actual)); } /* ************************************************************************* */ -TEST( GaussianConditional, information ) { +TEST( GaussianConditionalOrdered, information ) { // Create R matrix Matrix R = (Matrix(4,4) << @@ -316,7 +316,7 @@ TEST( GaussianConditional, information ) { 0, 0, 0, 10).finished(); // Create conditional - GaussianConditional conditional(0, Vector::Zero(4), R, Vector::Constant(4, 1.0)); + GaussianConditionalOrdered conditional(0, Vector::Zero(4), R, Vector::Constant(4, 1.0)); // Expected information matrix (using permuted R) Matrix IExpected = R.transpose() * R; @@ -327,7 +327,7 @@ TEST( GaussianConditional, information ) { } /* ************************************************************************* */ -TEST( GaussianConditional, isGaussianFactor ) { +TEST( GaussianConditionalOrdered, isGaussianFactor ) { // Create R matrix Matrix R = (Matrix(4,4) << @@ -337,13 +337,13 @@ TEST( GaussianConditional, isGaussianFactor ) { 0, 0, 0, 10).finished(); // Create a conditional - GaussianConditional conditional(0, Vector::Zero(4), R, Vector::Constant(4, 1.0)); + GaussianConditionalOrdered conditional(0, Vector::Zero(4), R, Vector::Constant(4, 1.0)); // Expected information matrix computed by conditional Matrix IExpected = conditional.information(); // Expected information matrix computed by a factor - JacobianFactor jf = *conditional.toFactor(); + JacobianFactorOrdered jf = *conditional.toFactor(); Matrix IActual = jf.getA(jf.begin()).transpose() * jf.getA(jf.begin()); EXPECT(assert_equal(IExpected, IActual)); diff --git a/gtsam/linear/tests/testGaussianConditionalUnordered.cpp b/gtsam/linear/tests/testGaussianConditionalUnordered.cpp index a53d8c308..45e9d29d2 100644 --- a/gtsam/linear/tests/testGaussianConditionalUnordered.cpp +++ b/gtsam/linear/tests/testGaussianConditionalUnordered.cpp @@ -21,9 +21,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -44,7 +44,7 @@ static Matrix R = Matrix_(2,2, 0., 4.6904); /* ************************************************************************* */ -TEST(GaussianConditionalUnordered, constructor) +TEST(GaussianConditional, constructor) { Matrix S1 = Matrix_(2,2, -5.2786, -8.6603, @@ -64,9 +64,9 @@ TEST(GaussianConditionalUnordered, constructor) (5, S2) (7, S3); - GaussianConditionalUnordered actual(1, d, R, terms, s); + GaussianConditional actual(1, d, R, terms, s); - GaussianConditionalUnordered::const_iterator it = actual.beginFrontals(); + GaussianConditional::const_iterator it = actual.beginFrontals(); EXPECT(assert_equal(Key(1), *it)); EXPECT(assert_equal(R, actual.get_R())); ++ it; @@ -91,14 +91,14 @@ TEST(GaussianConditionalUnordered, constructor) EXPECT(assert_equal(*s, *actual.get_model())); // test copy constructor - GaussianConditionalUnordered copied(actual); + GaussianConditional copied(actual); EXPECT(assert_equal(d, copied.get_d())); EXPECT(assert_equal(*s, *copied.get_model())); EXPECT(assert_equal(R, copied.get_R())); } /* ************************************************************************* */ -TEST( GaussianConditionalUnordered, equals ) +TEST( GaussianConditional, equals ) { // create a conditional gaussian node Matrix A1(2,2); @@ -117,7 +117,7 @@ TEST( GaussianConditionalUnordered, equals ) Vector d = Vector_(2, 0.2, 0.5); - GaussianConditionalUnordered + GaussianConditional expected(1, d, R, 2, A1, 10, A2, model), actual(1, d, R, 2, A1, 10, A2, model); @@ -125,7 +125,7 @@ TEST( GaussianConditionalUnordered, equals ) } /* ************************************************************************* */ -TEST( GaussianConditionalUnordered, solve ) +TEST( GaussianConditional, solve ) { //expected solution Vector expectedX(2); @@ -143,17 +143,17 @@ TEST( GaussianConditionalUnordered, solve ) Vector d(2); d << 20.0, 40.0; - GaussianConditionalUnordered cg(1, d, R, 2, A1, 10, A2); + GaussianConditional cg(1, d, R, 2, A1, 10, A2); Vector sx1(2); sx1 << 1.0, 1.0; Vector sl1(2); sl1 << 1.0, 1.0; - VectorValuesUnordered expected = map_list_of + VectorValues expected = map_list_of (1, expectedX) (2, sx1) (10, sl1); - VectorValuesUnordered solution = map_list_of + VectorValues solution = map_list_of (2, sx1) // parents (10, sl1); solution.insert(cg.solve(solution)); @@ -162,7 +162,7 @@ TEST( GaussianConditionalUnordered, solve ) } /* ************************************************************************* */ -TEST( GaussianConditionalUnordered, solve_simple ) +TEST( GaussianConditional, solve_simple ) { // 2 variables, frontal has dim=4 VerticalBlockMatrix blockMatrix(list_of(4)(2)(1), 4); @@ -173,16 +173,16 @@ TEST( GaussianConditionalUnordered, solve_simple ) 0.0, 0.0, 0.0, 3.0, 0.0, 4.0, 0.4; // solve system as a non-multifrontal version first - GaussianConditionalUnordered cg(list_of(1)(2), 1, blockMatrix); + GaussianConditional cg(list_of(1)(2), 1, blockMatrix); // partial solution Vector sx1 = Vector_(2, 9.0, 10.0); // elimination order: 1, 2 - VectorValuesUnordered actual = map_list_of + VectorValues actual = map_list_of (2, sx1); // parent - VectorValuesUnordered expected = map_list_of + VectorValues expected = map_list_of (2, sx1) (1, Vector_(4, -3.1,-3.4,-11.9,-13.2)); @@ -196,7 +196,7 @@ TEST( GaussianConditionalUnordered, solve_simple ) } /* ************************************************************************* */ -TEST( GaussianConditionalUnordered, solve_multifrontal ) +TEST( GaussianConditional, solve_multifrontal ) { // create full system, 3 variables, 2 frontals, all 2 dim VerticalBlockMatrix blockMatrix(list_of(2)(2)(2)(1), 4); @@ -207,7 +207,7 @@ TEST( GaussianConditionalUnordered, solve_multifrontal ) 0.0, 0.0, 0.0, 3.0, 0.0, 4.0, 0.4; // 3 variables, all dim=2 - GaussianConditionalUnordered cg(list_of(1)(2)(10), 2, blockMatrix); + GaussianConditional cg(list_of(1)(2)(10), 2, blockMatrix); EXPECT(assert_equal(Vector(blockMatrix.full().rightCols(1)), cg.get_d())); @@ -215,10 +215,10 @@ TEST( GaussianConditionalUnordered, solve_multifrontal ) Vector sl1 = Vector_(2, 9.0, 10.0); // elimination order; _x_, _x1_, _l1_ - VectorValuesUnordered actual = map_list_of + VectorValues actual = map_list_of (10, sl1); // parent - VectorValuesUnordered expected = map_list_of + VectorValues expected = map_list_of (1, Vector_(2, -3.1,-3.4)) (2, Vector_(2, -11.9,-13.2)) (10, sl1); @@ -234,7 +234,7 @@ TEST( GaussianConditionalUnordered, solve_multifrontal ) } /* ************************************************************************* */ -TEST( GaussianConditionalUnordered, solveTranspose ) { +TEST( GaussianConditional, solveTranspose ) { /** create small Chordal Bayes Net x <- y * x y d * 1 1 9 @@ -247,15 +247,15 @@ TEST( GaussianConditionalUnordered, solveTranspose ) { d2(0) = 5; // define nodes and specify in reverse topological sort (i.e. parents last) - GaussianBayesNetUnordered cbn = list_of - (GaussianConditionalUnordered(1, d1, R11, 2, S12)) - (GaussianConditionalUnordered(1, d2, R22)); + GaussianBayesNet cbn = list_of + (GaussianConditional(1, d1, R11, 2, S12)) + (GaussianConditional(1, d2, R22)); // x=R'*y, y=inv(R')*x // 2 = 1 2 // 5 1 1 3 - VectorValuesUnordered + VectorValues x = map_list_of (1, Vector_(1,2.)) (2, Vector_(1,5.)), @@ -264,12 +264,12 @@ TEST( GaussianConditionalUnordered, solveTranspose ) { (2, Vector_(1,3.)); // test functional version - VectorValuesUnordered actual = cbn.backSubstituteTranspose(x); + VectorValues actual = cbn.backSubstituteTranspose(x); CHECK(assert_equal(y, actual)); } /* ************************************************************************* */ -TEST( GaussianConditionalUnordered, information ) { +TEST( GaussianConditional, information ) { // Create R matrix Matrix R(4,4); R << @@ -279,7 +279,7 @@ TEST( GaussianConditionalUnordered, information ) { 0, 0, 0, 10; // Create conditional - GaussianConditionalUnordered conditional(0, Vector::Zero(4), R); + GaussianConditional conditional(0, Vector::Zero(4), R); // Expected information matrix (using permuted R) Matrix IExpected = R.transpose() * R; @@ -290,7 +290,7 @@ TEST( GaussianConditionalUnordered, information ) { } /* ************************************************************************* */ -TEST( GaussianConditionalUnordered, isGaussianFactor ) { +TEST( GaussianConditional, isGaussianFactor ) { // Create R matrix Matrix R(4,4); R << @@ -300,13 +300,13 @@ TEST( GaussianConditionalUnordered, isGaussianFactor ) { 0, 0, 0, 10; // Create a conditional - GaussianConditionalUnordered conditional(0, Vector::Zero(4), R); + GaussianConditional conditional(0, Vector::Zero(4), R); // Expected information matrix computed by conditional Matrix IExpected = conditional.information(); // Expected information matrix computed by a factor - JacobianFactorUnordered jf = conditional; + JacobianFactor jf = conditional; Matrix IActual = jf.information(); EXPECT(assert_equal(IExpected, IActual)); diff --git a/gtsam/linear/tests/testGaussianDensity.cpp b/gtsam/linear/tests/testGaussianDensity.cpp index 7e7ecf5f8..0bdbb55f3 100644 --- a/gtsam/linear/tests/testGaussianDensity.cpp +++ b/gtsam/linear/tests/testGaussianDensity.cpp @@ -30,7 +30,7 @@ TEST(GaussianDensity, constructor) 0., 4.6904); Vector d = Vector_(2, 1.0, 2.0), s = Vector_(2, 3.0, 4.0); - GaussianConditional conditional(1, d, R, s); + GaussianConditionalOrdered conditional(1, d, R, s); GaussianDensity copied(conditional); EXPECT(assert_equal(d, copied.get_d())); diff --git a/gtsam/linear/tests/testGaussianFactorGraphObsolete.cpp b/gtsam/linear/tests/testGaussianFactorGraphObsolete.cpp index 827672631..63e537d59 100644 --- a/gtsam/linear/tests/testGaussianFactorGraphObsolete.cpp +++ b/gtsam/linear/tests/testGaussianFactorGraphObsolete.cpp @@ -24,8 +24,8 @@ using namespace boost::assign; #include #include -#include -#include +#include +#include #include using namespace std; @@ -36,8 +36,8 @@ static SharedDiagonal sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1), sigma_02 = noiseModel::Isotropic::Sigma(2,0.2), constraintModel = noiseModel::Constrained::All(2); -static GaussianFactorGraph createSimpleGaussianFactorGraph() { - GaussianFactorGraph fg; +static GaussianFactorGraphOrdered createSimpleGaussianFactorGraph() { + GaussianFactorGraphOrdered fg; SharedDiagonal unit2 = noiseModel::Unit::Create(2); // linearized prior on x1: c[_x1_]+x1=0 i.e. x1=-c[_x1_] fg.add(2, 10*eye(2), -1.0*ones(2), unit2); @@ -52,9 +52,9 @@ static GaussianFactorGraph createSimpleGaussianFactorGraph() { /* ************************************************************************* */ -TEST(GaussianFactorGraph, initialization) { +TEST(GaussianFactorGraphOrdered, initialization) { // Create empty graph - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; SharedDiagonal unit2 = noiseModel::Unit::Create(2); fg.add(0, 10*eye(2), -1.0*ones(2), unit2); @@ -63,7 +63,7 @@ TEST(GaussianFactorGraph, initialization) { fg.add(1, -5*eye(2), 2, 5*eye(2), Vector_(2, -1.0, 1.5), unit2); EXPECT_LONGS_EQUAL(4, fg.size()); - JacobianFactor factor = *boost::dynamic_pointer_cast(fg[0]); + JacobianFactorOrdered factor = *boost::dynamic_pointer_cast(fg[0]); // Test sparse, which takes a vector and returns a matrix, used in MATLAB // Note that this the augmented vector and the RHS is in column 7 @@ -77,7 +77,7 @@ TEST(GaussianFactorGraph, initialization) { } /* ************************************************************************* */ -TEST(GaussianFactorGraph, CombineJacobians) +TEST(GaussianFactorGraphOrdered, CombineJacobians) { Matrix A01 = Matrix_(3,3, 1.0, 0.0, 0.0, @@ -104,19 +104,19 @@ TEST(GaussianFactorGraph, CombineJacobians) Vector b2 = Vector_(3, 3.5, 3.5, 3.5); Vector s2 = Vector_(3, 3.6, 3.6, 3.6); - GaussianFactorGraph gfg; + GaussianFactorGraphOrdered 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)); // Convert to Jacobians (inefficient copy of all factors instead of selectively converting only Hessians) - FactorGraph jacobians; - BOOST_FOREACH(const GaussianFactorGraph::sharedFactor& factor, gfg) { - jacobians.push_back(boost::make_shared(*factor)); + FactorGraphOrdered jacobians; + BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, gfg) { + jacobians.push_back(boost::make_shared(*factor)); } // Combine Jacobians into a single dense factor - JacobianFactor actual = *CombineJacobians(jacobians, VariableSlots(gfg)); + JacobianFactorOrdered actual = *CombineJacobians(jacobians, VariableSlots(gfg)); Matrix zero3x3 = zeros(3,3); Matrix A0 = gtsam::stack(3, &zero3x3, &A10, &zero3x3); @@ -124,13 +124,13 @@ TEST(GaussianFactorGraph, CombineJacobians) Vector b = gtsam::concatVectors(3, &b0, &b1, &b2); Vector sigmas = gtsam::concatVectors(3, &s0, &s1, &s2); - JacobianFactor expected(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); + JacobianFactorOrdered expected(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST(GaussianFactor, CombineAndEliminate) +TEST(GaussianFactorOrdered, CombineAndEliminate) { Matrix A01 = Matrix_(3,3, 1.0, 0.0, 0.0, @@ -157,7 +157,7 @@ TEST(GaussianFactor, CombineAndEliminate) Vector b2 = Vector_(3, 3.5, 3.5, 3.5); Vector s2 = Vector_(3, 3.6, 3.6, 3.6); - GaussianFactorGraph gfg; + GaussianFactorGraphOrdered 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)); @@ -168,21 +168,21 @@ TEST(GaussianFactor, CombineAndEliminate) Vector b = gtsam::concatVectors(3, &b1, &b0, &b2); Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2); - JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); - GaussianConditional::shared_ptr expectedBN = expectedFactor.eliminate(1); + JacobianFactorOrdered expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); + GaussianConditionalOrdered::shared_ptr expectedBN = expectedFactor.eliminate(1); - GaussianConditional::shared_ptr actualBN; - GaussianFactor::shared_ptr actualFactor; - boost::tie(actualBN, actualFactor) = EliminateQR(gfg, 1); - JacobianFactor::shared_ptr actualJacobian = boost::dynamic_pointer_cast< - JacobianFactor>(actualFactor); + GaussianConditionalOrdered::shared_ptr actualBN; + GaussianFactorOrdered::shared_ptr actualFactor; + boost::tie(actualBN, actualFactor) = EliminateQROrdered(gfg, 1); + JacobianFactorOrdered::shared_ptr actualJacobian = boost::dynamic_pointer_cast< + JacobianFactorOrdered>(actualFactor); EXPECT(assert_equal(*expectedBN, *actualBN)); EXPECT(assert_equal(expectedFactor, *actualJacobian)); } /* ************************************************************************* */ -TEST(GaussianFactor, eliminateFrontals) +TEST(GaussianFactorOrdered, eliminateFrontals) { // Augmented Ab test case for whole factor graph Matrix Ab = Matrix_(14,11, @@ -211,7 +211,7 @@ TEST(GaussianFactor, eliminateFrontals) make_pair( 9, Matrix(Ab.block(0, 6, 4, 2))), make_pair(11, Matrix(Ab.block(0, 8, 4, 2))); Vector b1 = Ab.col(10).segment(0, 4); - JacobianFactor::shared_ptr factor1(new JacobianFactor(terms1, b1, noiseModel::Isotropic::Sigma(4, 0.5))); + JacobianFactorOrdered::shared_ptr factor1(new JacobianFactorOrdered(terms1, b1, noiseModel::Isotropic::Sigma(4, 0.5))); // Create second factor list > terms2; @@ -221,7 +221,7 @@ TEST(GaussianFactor, eliminateFrontals) make_pair(9, Matrix(Ab.block(4, 6, 4, 2))), make_pair(11,Matrix(Ab.block(4, 8, 4, 2))); Vector b2 = Ab.col(10).segment(4, 4); - JacobianFactor::shared_ptr factor2(new JacobianFactor(terms2, b2, noiseModel::Isotropic::Sigma(4, 0.5))); + JacobianFactorOrdered::shared_ptr factor2(new JacobianFactorOrdered(terms2, b2, noiseModel::Isotropic::Sigma(4, 0.5))); // Create third factor list > terms3; @@ -230,17 +230,17 @@ TEST(GaussianFactor, eliminateFrontals) make_pair(9, Matrix(Ab.block(8, 6, 4, 2))), make_pair(11,Matrix(Ab.block(8, 8, 4, 2))); Vector b3 = Ab.col(10).segment(8, 4); - JacobianFactor::shared_ptr factor3(new JacobianFactor(terms3, b3, noiseModel::Isotropic::Sigma(4, 0.5))); + JacobianFactorOrdered::shared_ptr factor3(new JacobianFactorOrdered(terms3, b3, noiseModel::Isotropic::Sigma(4, 0.5))); // Create fourth factor list > terms4; terms4 += make_pair(11, Matrix(Ab.block(12, 8, 2, 2))); Vector b4 = Ab.col(10).segment(12, 2); - JacobianFactor::shared_ptr factor4(new JacobianFactor(terms4, b4, noiseModel::Isotropic::Sigma(2, 0.5))); + JacobianFactorOrdered::shared_ptr factor4(new JacobianFactorOrdered(terms4, b4, noiseModel::Isotropic::Sigma(2, 0.5))); // Create factor graph - GaussianFactorGraph factors; + GaussianFactorGraphOrdered factors; factors.push_back(factor1); factors.push_back(factor2); factors.push_back(factor3); @@ -251,17 +251,17 @@ TEST(GaussianFactor, eliminateFrontals) EXPECT(assert_equal(2.0 * Ab, actualDense)); // Convert to Jacobians, inefficient copy of all factors instead of selectively converting only Hessians - FactorGraph jacobians; - BOOST_FOREACH(const GaussianFactorGraph::sharedFactor& factor, factors) { - jacobians.push_back(boost::make_shared(*factor)); + FactorGraphOrdered jacobians; + BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, factors) { + jacobians.push_back(boost::make_shared(*factor)); } // Create combined factor - JacobianFactor combined(*CombineJacobians(jacobians, VariableSlots(factors))); + JacobianFactorOrdered combined(*CombineJacobians(jacobians, VariableSlots(factors))); // Copies factors as they will be eliminated in place - JacobianFactor actualFactor_QR = combined; - JacobianFactor actualFactor_Chol = combined; + JacobianFactorOrdered actualFactor_QR = combined; + JacobianFactorOrdered actualFactor_Chol = combined; // Expected augmented matrix, both GaussianConditional (first 6 rows) and remaining factor (next 4 rows) Matrix R = 2.0*Matrix_(11,11, @@ -286,7 +286,7 @@ TEST(GaussianFactor, eliminateFrontals) make_pair(9, sub(R, 0,2, 6,8 )), make_pair(11,sub(R, 0,2, 8,10)); Vector d1 = R.col(10).segment(0,2); - GaussianConditional::shared_ptr cond1(new GaussianConditional(3, d1, R1, cterms1, ones(2))); + GaussianConditionalOrdered::shared_ptr cond1(new GaussianConditionalOrdered(3, d1, R1, cterms1, ones(2))); // Expected conditional on second variable from next 2 rows of R Matrix R2 = sub(R, 2,4, 2,4); @@ -296,7 +296,7 @@ TEST(GaussianFactor, eliminateFrontals) make_pair(9, sub(R, 2,4, 6,8)), make_pair(11,sub(R, 2,4, 8,10)); Vector d2 = R.col(10).segment(2,2); - GaussianConditional::shared_ptr cond2(new GaussianConditional(5, d2, R2, cterms2, ones(2))); + GaussianConditionalOrdered::shared_ptr cond2(new GaussianConditionalOrdered(5, d2, R2, cterms2, ones(2))); // Expected conditional on third variable from next 2 rows of R Matrix R3 = sub(R, 4,6, 4,6); @@ -305,10 +305,10 @@ TEST(GaussianFactor, eliminateFrontals) make_pair(9, sub(R, 4,6, 6,8)), make_pair(11, sub(R, 4,6, 8,10)); Vector d3 = R.col(10).segment(4,2); - GaussianConditional::shared_ptr cond3(new GaussianConditional(7, d3, R3, cterms3, ones(2))); + GaussianConditionalOrdered::shared_ptr cond3(new GaussianConditionalOrdered(7, d3, R3, cterms3, ones(2))); // Create expected Bayes net fragment from three conditionals above -// GaussianBayesNet expectedFragment; +// GaussianBayesNetOrdered expectedFragment; // expectedFragment.push_back(cond1); // expectedFragment.push_back(cond2); // expectedFragment.push_back(cond3); @@ -317,7 +317,7 @@ TEST(GaussianFactor, eliminateFrontals) size_t dims[] = { 2,2,2,2,2,1 }; size_t height = 11; VerticalBlockView Rblock(R, dims, dims+6, height); - GaussianConditional::shared_ptr expectedFragment( new GaussianConditional(keys.begin(), keys.end(), 3, + GaussianConditionalOrdered::shared_ptr expectedFragment( new GaussianConditionalOrdered(keys.begin(), keys.end(), 3, Rblock, ones(6)) ); // Get expected matrices for remaining factor @@ -326,7 +326,7 @@ TEST(GaussianFactor, eliminateFrontals) Vector be = R.col(10).segment(6, 4); // Eliminate (3 frontal variables, 6 scalar columns) using QR !!!! - GaussianConditional::shared_ptr actualFragment_QR = actualFactor_QR.eliminate(3); + GaussianConditionalOrdered::shared_ptr actualFragment_QR = actualFactor_QR.eliminate(3); EXPECT(assert_equal(*expectedFragment, *actualFragment_QR, 0.001)); EXPECT(assert_equal(size_t(2), actualFactor_QR.keys().size())); @@ -339,7 +339,7 @@ TEST(GaussianFactor, eliminateFrontals) // Eliminate (3 frontal variables, 6 scalar columns) using Cholesky !!!! #ifdef BROKEN - GaussianBayesNet actualFragment_Chol = *actualFactor_Chol.eliminate(3, JacobianFactor::SOLVE_CHOLESKY); + GaussianBayesNetOrdered actualFragment_Chol = *actualFactor_Chol.eliminate(3, JacobianFactorOrdered::SOLVE_CHOLESKY); EXPECT(assert_equal(expectedFragment, actualFragment_Chol, 0.001)); EXPECT(assert_equal(size_t(2), actualFactor_Chol.keys().size())); EXPECT(assert_equal(Index(9), actualFactor_Chol.keys()[0])); @@ -352,7 +352,7 @@ TEST(GaussianFactor, eliminateFrontals) } /* ************************************************************************* */ -TEST(GaussianFactor, permuteWithInverse) +TEST(GaussianFactorOrdered, permuteWithInverse) { Matrix A1 = Matrix_(2,2, 1.0, 2.0, @@ -373,21 +373,21 @@ TEST(GaussianFactor, permuteWithInverse) inversePermutation[4] = 1; inversePermutation[5] = 0; - JacobianFactor actual(1, A1, 3, A2, 5, A3, b, noiseModel::Isotropic::Sigma(2, 1.0)); - GaussianFactorGraph actualFG; actualFG.push_back(JacobianFactor::shared_ptr(new JacobianFactor(actual))); - VariableIndex actualIndex(actualFG); + JacobianFactorOrdered actual(1, A1, 3, A2, 5, A3, b, noiseModel::Isotropic::Sigma(2, 1.0)); + GaussianFactorGraphOrdered actualFG; actualFG.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(actual))); + VariableIndexOrdered actualIndex(actualFG); actual.permuteWithInverse(inversePermutation); // actualIndex.permute(*inversePermutation.inverse()); - JacobianFactor expected(4, A1, 2, A2, 0, A3, b, noiseModel::Isotropic::Sigma(2, 1.0)); - GaussianFactorGraph expectedFG; expectedFG.push_back(JacobianFactor::shared_ptr(new JacobianFactor(expected))); + JacobianFactorOrdered expected(4, A1, 2, A2, 0, A3, b, noiseModel::Isotropic::Sigma(2, 1.0)); + GaussianFactorGraphOrdered expectedFG; expectedFG.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(expected))); // GaussianVariableIndex expectedIndex(expectedFG); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST(GaussianFactorGraph, sparseJacobian) { +TEST(GaussianFactorGraphOrdered, sparseJacobian) { // Create factor graph: // x1 x2 x3 x4 x5 b // 1 2 3 0 0 4 @@ -414,7 +414,7 @@ TEST(GaussianFactorGraph, sparseJacobian) { 3., 6.,26., 4., 6.,32.).transpose(); - GaussianFactorGraph gfg; + GaussianFactorGraphOrdered gfg; SharedDiagonal model = noiseModel::Isotropic::Sigma(2, 0.5); gfg.add(0, Matrix_(2,3, 1., 2., 3., 5., 6., 7.), Vector_(2, 4., 8.), model); gfg.add(0, Matrix_(2,3, 9.,10., 0., 0., 0., 0.), 1, Matrix_(2,2, 11., 12., 14., 15.), Vector_(2, 13.,16.), model); @@ -425,7 +425,7 @@ TEST(GaussianFactorGraph, sparseJacobian) { } /* ************************************************************************* */ -TEST(GaussianFactorGraph, matrices) { +TEST(GaussianFactorGraphOrdered, matrices) { // Create factor graph: // x1 x2 x3 x4 x5 b // 1 2 3 0 0 4 @@ -433,7 +433,7 @@ TEST(GaussianFactorGraph, matrices) { // 9 10 0 11 12 13 // 0 0 0 14 15 16 - GaussianFactorGraph gfg; + GaussianFactorGraphOrdered gfg; SharedDiagonal model = noiseModel::Unit::Create(2); gfg.add(0, Matrix_(2,3, 1., 2., 3., 5., 6., 7.), Vector_(2, 4., 8.), model); gfg.add(0, Matrix_(2,3, 9.,10., 0., 0., 0., 0.), 1, Matrix_(2,2, 11., 12., 14., 15.), Vector_(2, 13.,16.), model); @@ -466,12 +466,12 @@ TEST(GaussianFactorGraph, matrices) { } /* ************************************************************************* */ -TEST( GaussianFactorGraph, gradient ) +TEST( GaussianFactorGraphOrdered, gradient ) { - GaussianFactorGraph fg = createSimpleGaussianFactorGraph(); + GaussianFactorGraphOrdered fg = createSimpleGaussianFactorGraph(); // Construct expected gradient - VectorValues expected; + VectorValuesOrdered expected; // 2*f(x) = 100*(x1+c[X(1)])^2 + 100*(x2-x1-[0.2;-0.1])^2 + 25*(l1-x1-[0.0;0.2])^2 + 25*(l1-x2-[-0.2;0.3])^2 // worked out: df/dx1 = 100*[0.1;0.1] + 100*[0.2;-0.1]) + 25*[0.0;0.2] = [10+20;10-10+5] = [30;5] @@ -480,52 +480,52 @@ TEST( GaussianFactorGraph, gradient ) expected.insert(0,Vector_(2,-25.0, 17.5)); // Check the gradient at delta=0 - VectorValues zero = VectorValues::Zero(expected); - VectorValues actual = gradient(fg, zero); + VectorValuesOrdered zero = VectorValuesOrdered::Zero(expected); + VectorValuesOrdered actual = gradient(fg, zero); EXPECT(assert_equal(expected,actual)); // Check the gradient at the solution (should be zero) - VectorValues solution = *GaussianSequentialSolver(fg).optimize(); - VectorValues actual2 = gradient(fg, solution); - EXPECT(assert_equal(VectorValues::Zero(solution), actual2)); + VectorValuesOrdered solution = *GaussianSequentialSolver(fg).optimize(); + VectorValuesOrdered actual2 = gradient(fg, solution); + EXPECT(assert_equal(VectorValuesOrdered::Zero(solution), actual2)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, transposeMultiplication ) +TEST( GaussianFactorGraphOrdered, transposeMultiplication ) { - GaussianFactorGraph A = createSimpleGaussianFactorGraph(); + GaussianFactorGraphOrdered A = createSimpleGaussianFactorGraph(); - VectorValues e; + VectorValuesOrdered e; e.insert(0, Vector_(2, 0.0, 0.0)); e.insert(1, Vector_(2,15.0, 0.0)); e.insert(2, Vector_(2, 0.0,-5.0)); e.insert(3, Vector_(2,-7.5,-5.0)); - VectorValues expected; + VectorValuesOrdered expected; expected.insert(1, Vector_(2, -37.5,-50.0)); expected.insert(2, Vector_(2,-150.0, 25.0)); expected.insert(0, Vector_(2, 187.5, 25.0)); - VectorValues actual = VectorValues::SameStructure(expected); + VectorValuesOrdered actual = VectorValuesOrdered::SameStructure(expected); transposeMultiply(A, e, actual); EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ -TEST(GaussianFactorGraph, eliminate_empty ) +TEST(GaussianFactorGraphOrdered, eliminate_empty ) { // eliminate an empty factor - GaussianFactorGraph gfg; - gfg.push_back(boost::make_shared()); - GaussianConditional::shared_ptr actualCG; - GaussianFactorGraph remainingGFG; + GaussianFactorGraphOrdered gfg; + gfg.push_back(boost::make_shared()); + GaussianConditionalOrdered::shared_ptr actualCG; + GaussianFactorGraphOrdered remainingGFG; boost::tie(actualCG, remainingGFG) = gfg.eliminateOne(0); // expected Conditional Gaussian is just a parent-less node with P(x)=1 - GaussianConditional expectedCG(0, Vector(), Matrix(), Vector()); + GaussianConditionalOrdered expectedCG(0, Vector(), Matrix(), Vector()); // expected remaining graph should be the same as the original, still empty :-) - GaussianFactorGraph expectedLF = gfg; + GaussianFactorGraphOrdered expectedLF = gfg; // check if the result matches EXPECT(actualCG->equals(expectedCG)); diff --git a/gtsam/linear/tests/testGaussianFactorGraphUnordered.cpp b/gtsam/linear/tests/testGaussianFactorGraphUnordered.cpp index b42b49646..bc0a0d1ba 100644 --- a/gtsam/linear/tests/testGaussianFactorGraphUnordered.cpp +++ b/gtsam/linear/tests/testGaussianFactorGraphUnordered.cpp @@ -25,10 +25,10 @@ using namespace boost::assign; #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace std; using namespace gtsam; @@ -37,31 +37,31 @@ static SharedDiagonal sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1), sigma_02 = noiseModel::Isotropic::Sigma(2,0.2), constraintModel = noiseModel::Constrained::All(2); -static GaussianFactorGraphUnordered createSimpleGaussianFactorGraph() { - GaussianFactorGraphUnordered fg; +static GaussianFactorGraph createSimpleGaussianFactorGraph() { + GaussianFactorGraph fg; SharedDiagonal unit2 = noiseModel::Unit::Create(2); // linearized prior on x1: c[_x1_]+x1=0 i.e. x1=-c[_x1_] - fg += JacobianFactorUnordered(2, 10*eye(2), -1.0*ones(2), unit2); + fg += JacobianFactor(2, 10*eye(2), -1.0*ones(2), unit2); // odometry between x1 and x2: x2-x1=[0.2;-0.1] - fg += JacobianFactorUnordered(2, -10*eye(2), 0, 10*eye(2), Vector_(2, 2.0, -1.0), unit2); + fg += JacobianFactor(2, -10*eye(2), 0, 10*eye(2), Vector_(2, 2.0, -1.0), unit2); // measurement between x1 and l1: l1-x1=[0.0;0.2] - fg += JacobianFactorUnordered(2, -5*eye(2), 1, 5*eye(2), Vector_(2, 0.0, 1.0), unit2); + fg += JacobianFactor(2, -5*eye(2), 1, 5*eye(2), Vector_(2, 0.0, 1.0), unit2); // measurement between x2 and l1: l1-x2=[-0.2;0.3] - fg += JacobianFactorUnordered(0, -5*eye(2), 1, 5*eye(2), Vector_(2, -1.0, 1.5), unit2); + fg += JacobianFactor(0, -5*eye(2), 1, 5*eye(2), Vector_(2, -1.0, 1.5), unit2); return fg; } /* ************************************************************************* */ -TEST(GaussianFactorGraphUnordered, initialization) { +TEST(GaussianFactorGraph, initialization) { // Create empty graph - GaussianFactorGraphUnordered fg; + GaussianFactorGraph fg; SharedDiagonal unit2 = noiseModel::Unit::Create(2); fg += - JacobianFactorUnordered(0, 10*eye(2), -1.0*ones(2), unit2), - JacobianFactorUnordered(0, -10*eye(2),1, 10*eye(2), Vector_(2, 2.0, -1.0), unit2), - JacobianFactorUnordered(0, -5*eye(2), 2, 5*eye(2), Vector_(2, 0.0, 1.0), unit2), - JacobianFactorUnordered(1, -5*eye(2), 2, 5*eye(2), Vector_(2, -1.0, 1.5), unit2); + JacobianFactor(0, 10*eye(2), -1.0*ones(2), unit2), + JacobianFactor(0, -10*eye(2),1, 10*eye(2), Vector_(2, 2.0, -1.0), unit2), + JacobianFactor(0, -5*eye(2), 2, 5*eye(2), Vector_(2, 0.0, 1.0), unit2), + JacobianFactor(1, -5*eye(2), 2, 5*eye(2), Vector_(2, -1.0, 1.5), unit2); EXPECT_LONGS_EQUAL(4, (long)fg.size()); @@ -77,7 +77,7 @@ TEST(GaussianFactorGraphUnordered, initialization) { } /* ************************************************************************* */ -TEST(GaussianFactorGraphUnordered, sparseJacobian) { +TEST(GaussianFactorGraph, sparseJacobian) { // Create factor graph: // x1 x2 x3 x4 x5 b // 1 2 3 0 0 4 @@ -104,7 +104,7 @@ TEST(GaussianFactorGraphUnordered, sparseJacobian) { 3., 6.,26., 4., 6.,32.).transpose(); - GaussianFactorGraphUnordered gfg; + GaussianFactorGraph gfg; SharedDiagonal model = noiseModel::Isotropic::Sigma(2, 0.5); gfg.add(0, Matrix_(2,3, 1., 2., 3., 5., 6., 7.), Vector_(2, 4., 8.), model); gfg.add(0, Matrix_(2,3, 9.,10., 0., 0., 0., 0.), 1, Matrix_(2,2, 11., 12., 14., 15.), Vector_(2, 13.,16.), model); @@ -115,7 +115,7 @@ TEST(GaussianFactorGraphUnordered, sparseJacobian) { } /* ************************************************************************* */ -TEST(GaussianFactorGraphUnordered, matrices) { +TEST(GaussianFactorGraph, matrices) { // Create factor graph: // x1 x2 x3 x4 x5 b // 1 2 3 0 0 4 @@ -123,7 +123,7 @@ TEST(GaussianFactorGraphUnordered, matrices) { // 9 10 0 11 12 13 // 0 0 0 14 15 16 - GaussianFactorGraphUnordered gfg; + GaussianFactorGraph gfg; SharedDiagonal model = noiseModel::Unit::Create(2); gfg.add(0, Matrix_(2,3, 1., 2., 3., 5., 6., 7.), Vector_(2, 4., 8.), model); gfg.add(0, Matrix_(2,3, 9.,10., 0., 0., 0., 0.), 1, Matrix_(2,2, 11., 12., 14., 15.), Vector_(2, 13.,16.), model); @@ -156,33 +156,33 @@ TEST(GaussianFactorGraphUnordered, matrices) { } /* ************************************************************************* */ -TEST( GaussianFactorGraphUnordered, gradient ) +TEST( GaussianFactorGraph, gradient ) { - GaussianFactorGraphUnordered fg = createSimpleGaussianFactorGraph(); + GaussianFactorGraph fg = createSimpleGaussianFactorGraph(); // Construct expected gradient // 2*f(x) = 100*(x1+c[X(1)])^2 + 100*(x2-x1-[0.2;-0.1])^2 + 25*(l1-x1-[0.0;0.2])^2 + 25*(l1-x2-[-0.2;0.3])^2 // worked out: df/dx1 = 100*[0.1;0.1] + 100*[0.2;-0.1]) + 25*[0.0;0.2] = [10+20;10-10+5] = [30;5] - VectorValuesUnordered expected = map_list_of + VectorValues expected = map_list_of (1, Vector_(2, 5.0,-12.5)) (2, Vector_(2, 30.0, 5.0)) (0, Vector_(2,-25.0, 17.5)); // Check the gradient at delta=0 - VectorValuesUnordered zero = VectorValuesUnordered::Zero(expected); - VectorValuesUnordered actual = fg.gradient(zero); + VectorValues zero = VectorValues::Zero(expected); + VectorValues actual = fg.gradient(zero); EXPECT(assert_equal(expected, actual)); // Check the gradient at the solution (should be zero) - VectorValuesUnordered solution = fg.optimize(); - VectorValuesUnordered actual2 = fg.gradient(solution); - EXPECT(assert_equal(VectorValuesUnordered::Zero(solution), actual2)); + VectorValues solution = fg.optimize(); + VectorValues actual2 = fg.gradient(solution); + EXPECT(assert_equal(VectorValues::Zero(solution), actual2)); } /* ************************************************************************* */ -TEST( GaussianFactorGraphUnordered, transposeMultiplication ) +TEST( GaussianFactorGraph, transposeMultiplication ) { - GaussianFactorGraphUnordered A = createSimpleGaussianFactorGraph(); + GaussianFactorGraph A = createSimpleGaussianFactorGraph(); Errors e; e += Vector_(2, 0.0, 0.0), @@ -190,30 +190,30 @@ TEST( GaussianFactorGraphUnordered, transposeMultiplication ) Vector_(2, 0.0,-5.0), Vector_(2,-7.5,-5.0); - VectorValuesUnordered expected; + VectorValues expected; expected.insert(1, Vector_(2, -37.5,-50.0)); expected.insert(2, Vector_(2,-150.0, 25.0)); expected.insert(0, Vector_(2, 187.5, 25.0)); - VectorValuesUnordered actual = A.transposeMultiply(e); + VectorValues actual = A.transposeMultiply(e); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST(GaussianFactorGraphUnordered, eliminate_empty ) +TEST(GaussianFactorGraph, eliminate_empty ) { // eliminate an empty factor - GaussianFactorGraphUnordered gfg; - gfg.add(JacobianFactorUnordered()); - GaussianBayesNetUnordered::shared_ptr actualBN; - GaussianFactorGraphUnordered::shared_ptr remainingGFG; - boost::tie(actualBN, remainingGFG) = gfg.eliminatePartialSequential(OrderingUnordered()); + GaussianFactorGraph gfg; + gfg.add(JacobianFactor()); + GaussianBayesNet::shared_ptr actualBN; + GaussianFactorGraph::shared_ptr remainingGFG; + boost::tie(actualBN, remainingGFG) = gfg.eliminatePartialSequential(Ordering()); // expected Bayes net is empty - GaussianBayesNetUnordered expectedBN; + GaussianBayesNet expectedBN; // expected remaining graph should be the same as the original, still containing the empty factor - GaussianFactorGraphUnordered expectedLF = gfg; + GaussianFactorGraph expectedLF = gfg; // check if the result matches EXPECT(assert_equal(*actualBN, expectedBN)); diff --git a/gtsam/linear/tests/testGaussianJunctionTreeObsolete.cpp b/gtsam/linear/tests/testGaussianJunctionTreeObsolete.cpp index 71d32cb1e..53630b717 100644 --- a/gtsam/linear/tests/testGaussianJunctionTreeObsolete.cpp +++ b/gtsam/linear/tests/testGaussianJunctionTreeObsolete.cpp @@ -25,26 +25,26 @@ using namespace boost::assign; #include #include -#include +#include #include #include -#include +#include using namespace std; using namespace gtsam; static const Index x2=0, x1=1, x3=2, x4=3; -static GaussianFactorGraph createChain() { +static GaussianFactorGraphOrdered createChain() { - typedef GaussianFactorGraph::sharedFactor Factor; + typedef GaussianFactorGraphOrdered::sharedFactor Factor; SharedDiagonal model = noiseModel::Isotropic::Sigma(1, 0.5); - Factor factor1(new JacobianFactor(x2, Matrix_(1,1,1.), x1, Matrix_(1,1,1.), Vector_(1,1.), model)); - Factor factor2(new JacobianFactor(x2, Matrix_(1,1,1.), x3, Matrix_(1,1,1.), Vector_(1,1.), model)); - Factor factor3(new JacobianFactor(x3, Matrix_(1,1,1.), x4, Matrix_(1,1,1.), Vector_(1,1.), model)); - Factor factor4(new JacobianFactor(x4, Matrix_(1,1,1.), Vector_(1,1.), model)); + Factor factor1(new JacobianFactorOrdered(x2, Matrix_(1,1,1.), x1, Matrix_(1,1,1.), Vector_(1,1.), model)); + Factor factor2(new JacobianFactorOrdered(x2, Matrix_(1,1,1.), x3, Matrix_(1,1,1.), Vector_(1,1.), model)); + Factor factor3(new JacobianFactorOrdered(x3, Matrix_(1,1,1.), x4, Matrix_(1,1,1.), Vector_(1,1.), model)); + Factor factor4(new JacobianFactorOrdered(x4, Matrix_(1,1,1.), Vector_(1,1.), model)); - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; fg.push_back(factor1); fg.push_back(factor2); fg.push_back(factor3); @@ -67,65 +67,65 @@ static GaussianFactorGraph createChain() { * * 1 0 0 1 */ -TEST( GaussianJunctionTree, eliminate ) +TEST( GaussianJunctionTreeOrdered, eliminate ) { - GaussianFactorGraph fg = createChain(); - GaussianJunctionTree junctionTree(fg); - BayesTree::sharedClique rootClique = junctionTree.eliminate(&EliminateQR); + GaussianFactorGraphOrdered fg = createChain(); + GaussianJunctionTreeOrdered junctionTree(fg); + BayesTreeOrdered::sharedClique rootClique = junctionTree.eliminate(&EliminateQROrdered); - typedef BayesTree::sharedConditional sharedConditional; + typedef BayesTreeOrdered::sharedConditional sharedConditional; Matrix two = Matrix_(1,1,2.); Matrix one = Matrix_(1,1,1.); - BayesTree bayesTree_expected; + BayesTreeOrdered bayesTree_expected; Index keys_root[] = {x3,x4}; Matrix rsd_root = Matrix_(2,3, 2., 2., 2., 0., 2., 2.); size_t dim_root[] = {1, 1, 1}; - sharedConditional root_expected(new GaussianConditional(keys_root, keys_root+2, 2, + sharedConditional root_expected(new GaussianConditionalOrdered(keys_root, keys_root+2, 2, VerticalBlockView(rsd_root, dim_root, dim_root+3, 2), ones(2))); - BayesTree::sharedClique rootClique_expected(new BayesTree::Clique(root_expected)); + BayesTreeOrdered::sharedClique rootClique_expected(new BayesTreeOrdered::Clique(root_expected)); Index keys_child[] = {x2,x1,x3}; Matrix rsd_child = Matrix_(2,4, 2., 1., 1., 2., 0., -1., 1., 0.); size_t dim_child[] = {1, 1, 1, 1}; - sharedConditional child_expected(new GaussianConditional(keys_child, keys_child+3, 2, + sharedConditional child_expected(new GaussianConditionalOrdered(keys_child, keys_child+3, 2, VerticalBlockView(rsd_child, dim_child, dim_child+4, 2), ones(2))); - BayesTree::sharedClique childClique_expected(new BayesTree::Clique(child_expected)); + BayesTreeOrdered::sharedClique childClique_expected(new BayesTreeOrdered::Clique(child_expected)); bayesTree_expected.insert(rootClique_expected); bayesTree_expected.insert(childClique_expected); -// bayesTree_expected.insert(sharedConditional(new GaussianConditional(x4, Vector_(1,2.), two, Vector_(1,1.)))); -// bayesTree_expected.insert(sharedConditional(new GaussianConditional(x3, Vector_(1,2.), two, x4, two, Vector_(1,1.)))); -// bayesTree_expected.insert(sharedConditional(new GaussianConditional(x1, Vector_(1,0.), one*(-1), x3, one, Vector_(1,1.)))); -// bayesTree_expected.insert(sharedConditional(new GaussianConditional(x2, Vector_(1,2.), two, x1, one, x3, one, Vector_(1,1.)))); +// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x4, Vector_(1,2.), two, Vector_(1,1.)))); +// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x3, Vector_(1,2.), two, x4, two, Vector_(1,1.)))); +// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x1, Vector_(1,0.), one*(-1), x3, one, Vector_(1,1.)))); +// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x2, Vector_(1,2.), two, x1, one, x3, one, Vector_(1,1.)))); CHECK(assert_equal(*bayesTree_expected.root(), *rootClique)); EXPECT(assert_equal(*(bayesTree_expected.root()->children().front()), *(rootClique->children().front()))); } /* ************************************************************************* */ -TEST( GaussianJunctionTree, GBNConstructor ) +TEST( GaussianJunctionTreeOrdered, GBNConstructor ) { - GaussianFactorGraph fg = createChain(); - GaussianJunctionTree jt(fg); - BayesTree::sharedClique root = jt.eliminate(&EliminateQR); - BayesTree expected; + GaussianFactorGraphOrdered fg = createChain(); + GaussianJunctionTreeOrdered jt(fg); + BayesTreeOrdered::sharedClique root = jt.eliminate(&EliminateQROrdered); + BayesTreeOrdered expected; expected.insert(root); - GaussianBayesNet bn(*GaussianSequentialSolver(fg).eliminate()); - BayesTree actual(bn); + GaussianBayesNetOrdered bn(*GaussianSequentialSolver(fg).eliminate()); + BayesTreeOrdered actual(bn); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST( GaussianJunctionTree, optimizeMultiFrontal ) +TEST( GaussianJunctionTreeOrdered, optimizeMultiFrontal ) { - GaussianFactorGraph fg = createChain(); - GaussianJunctionTree tree(fg); + GaussianFactorGraphOrdered fg = createChain(); + GaussianJunctionTreeOrdered tree(fg); - VectorValues actual = tree.optimize(&EliminateQR); - VectorValues expected(vector(4,1)); + VectorValuesOrdered actual = tree.optimize(&EliminateQROrdered); + VectorValuesOrdered expected(vector(4,1)); expected[x1] = Vector_(1, 0.); expected[x2] = Vector_(1, 1.); expected[x3] = Vector_(1, 0.); @@ -134,10 +134,10 @@ TEST( GaussianJunctionTree, optimizeMultiFrontal ) } /* ************************************************************************* */ -TEST(GaussianJunctionTree, complicatedMarginal) { +TEST(GaussianJunctionTreeOrdered, complicatedMarginal) { // Create the conditionals to go in the BayesTree - GaussianConditional::shared_ptr R_1_2(new GaussianConditional( + GaussianConditionalOrdered::shared_ptr R_1_2(new GaussianConditionalOrdered( pair_list_of (1, (Matrix(3,1) << 0.2630, @@ -152,7 +152,7 @@ TEST(GaussianJunctionTree, complicatedMarginal) { 0.5383, 0.9961).finished()), 2, (Vector(3) << 0.0782, 0.4427, 0.1067).finished(), ones(3))); - GaussianConditional::shared_ptr R_3_4(new GaussianConditional( + GaussianConditionalOrdered::shared_ptr R_3_4(new GaussianConditionalOrdered( pair_list_of (3, (Matrix(3,1) << 0.0540, @@ -167,7 +167,7 @@ TEST(GaussianJunctionTree, complicatedMarginal) { 0.7943, 0.1656, 0.3112, 0.6020).finished()), 2, (Vector(3) << 0.9619, 0.0046, 0.7749).finished(), ones(3))); -// GaussianConditional::shared_ptr R_5_6(new GaussianConditional( +// GaussianConditionalOrdered::shared_ptr R_5_6(new GaussianConditionalOrdered( // pair_list_of // (5, (Matrix(3,1) << // 0.2435, @@ -186,7 +186,7 @@ TEST(GaussianJunctionTree, complicatedMarginal) { // 0.9893, 0.2912, // 0.4035, 0.4933).finished()), // 2, (Vector(3) << 0.8173, 0.4164, 0.7671).finished(), ones(3))); - GaussianConditional::shared_ptr R_5_6(new GaussianConditional( + GaussianConditionalOrdered::shared_ptr R_5_6(new GaussianConditionalOrdered( pair_list_of (5, (Matrix(3,1) << 0.2435, @@ -209,7 +209,7 @@ TEST(GaussianJunctionTree, complicatedMarginal) { 0.7572, 0.5678, 0.7537, 0.0759).finished()), 2, (Vector(3) << 0.8173, 0.8687, 0.0844).finished(), ones(3))); - GaussianConditional::shared_ptr R_7_8(new GaussianConditional( + GaussianConditionalOrdered::shared_ptr R_7_8(new GaussianConditionalOrdered( pair_list_of (7, (Matrix(3,1) << 0.2551, @@ -224,7 +224,7 @@ TEST(GaussianJunctionTree, complicatedMarginal) { 0.2543, 0.8143).finished()), 2, (Vector(3) << 0.3998, 0.2599, 0.8001).finished(), ones(3))); - GaussianConditional::shared_ptr R_9_10(new GaussianConditional( + GaussianConditionalOrdered::shared_ptr R_9_10(new GaussianConditionalOrdered( pair_list_of (9, (Matrix(3,1) << 0.7952, @@ -243,7 +243,7 @@ TEST(GaussianJunctionTree, complicatedMarginal) { 0.9597, 0.2238, 0.3404, 0.7513).finished()), 2, (Vector(3) << 0.4314, 0.9106, 0.1818).finished(), ones(3))); - GaussianConditional::shared_ptr R_11_12(new GaussianConditional( + GaussianConditionalOrdered::shared_ptr R_11_12(new GaussianConditionalOrdered( pair_list_of (11, (Matrix(3,1) << 0.0971, @@ -256,7 +256,7 @@ TEST(GaussianJunctionTree, complicatedMarginal) { 2, (Vector(3) << 0.2638, 0.1455, 0.1361).finished(), ones(3))); // Gaussian Bayes Tree - typedef BayesTree GaussianBayesTree; + typedef BayesTreeOrdered GaussianBayesTree; typedef GaussianBayesTree::Clique Clique; typedef GaussianBayesTree::sharedClique sharedClique; @@ -271,10 +271,10 @@ TEST(GaussianJunctionTree, complicatedMarginal) { // Marginal on 5 Matrix expectedCov = (Matrix(1,1) << 236.5166).finished(); - JacobianFactor::shared_ptr actualJacobianChol= boost::dynamic_pointer_cast( - bt.marginalFactor(5, EliminateCholesky)); - JacobianFactor::shared_ptr actualJacobianQR = boost::dynamic_pointer_cast( - bt.marginalFactor(5, EliminateQR)); + JacobianFactorOrdered::shared_ptr actualJacobianChol= boost::dynamic_pointer_cast( + bt.marginalFactor(5, EliminateCholeskyOrdered)); + JacobianFactorOrdered::shared_ptr actualJacobianQR = boost::dynamic_pointer_cast( + bt.marginalFactor(5, EliminateQROrdered)); CHECK(assert_equal(*actualJacobianChol, *actualJacobianQR)); // Check that Chol and QR obtained marginals are the same LONGS_EQUAL(1, actualJacobianChol->rows()); LONGS_EQUAL(1, actualJacobianChol->size()); @@ -290,10 +290,10 @@ TEST(GaussianJunctionTree, complicatedMarginal) { expectedCov = (Matrix(2,2) << 1015.8, 2886.2, 2886.2, 8471.2).finished(); - actualJacobianChol = boost::dynamic_pointer_cast( - bt.marginalFactor(6, EliminateCholesky)); - actualJacobianQR = boost::dynamic_pointer_cast( - bt.marginalFactor(6, EliminateQR)); + actualJacobianChol = boost::dynamic_pointer_cast( + bt.marginalFactor(6, EliminateCholeskyOrdered)); + actualJacobianQR = boost::dynamic_pointer_cast( + bt.marginalFactor(6, EliminateQROrdered)); CHECK(assert_equal(*actualJacobianChol, *actualJacobianQR)); // Check that Chol and QR obtained marginals are the same LONGS_EQUAL(2, actualJacobianChol->rows()); LONGS_EQUAL(1, actualJacobianChol->size()); diff --git a/gtsam/linear/tests/testHessianFactor.cpp b/gtsam/linear/tests/testHessianFactor.cpp index dccbd17da..09c3b6a64 100644 --- a/gtsam/linear/tests/testHessianFactor.cpp +++ b/gtsam/linear/tests/testHessianFactor.cpp @@ -22,9 +22,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -36,18 +36,18 @@ using namespace gtsam; const double tol = 1e-5; /* ************************************************************************* */ -TEST(HessianFactor, emptyConstructor) { - HessianFactor f; +TEST(HessianFactorOrdered, emptyConstructor) { + HessianFactorOrdered f; DOUBLES_EQUAL(0.0, f.constantTerm(), 1e-9); // Constant term should be zero EXPECT(assert_equal(Vector(), f.linearTerm())); // Linear term should be empty EXPECT(assert_equal(zeros(1,1), f.info())); // Full matrix should be 1-by-1 zero matrix - DOUBLES_EQUAL(0.0, f.error(VectorValues()), 1e-9); // Should have zero error + DOUBLES_EQUAL(0.0, f.error(VectorValuesOrdered()), 1e-9); // Should have zero error } /* ************************************************************************* */ -TEST(HessianFactor, ConversionConstructor) { +TEST(HessianFactorOrdered, ConversionConstructor) { - HessianFactor expected; + HessianFactorOrdered expected; expected.keys_.push_back(0); expected.keys_.push_back(1); size_t dims[] = { 2, 4, 1 }; @@ -93,11 +93,11 @@ TEST(HessianFactor, ConversionConstructor) { vector > meas; meas.push_back(make_pair(0, Ax2)); meas.push_back(make_pair(1, Al1x1)); - JacobianFactor combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactorOrdered combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); - HessianFactor actual(combined); + HessianFactorOrdered actual(combined); - VectorValues values(std::vector(dims, dims+2)); + VectorValuesOrdered values(std::vector(dims, dims+2)); values[0] = Vector_(2, 1.0, 2.0); values[1] = Vector_(4, 3.0, 4.0, 5.0, 6.0); @@ -110,7 +110,7 @@ TEST(HessianFactor, ConversionConstructor) { } /* ************************************************************************* */ -TEST(HessianFactor, Constructor1) +TEST(HessianFactorOrdered, Constructor1) { Matrix G = Matrix_(2,2, 3.0, 5.0, 0.0, 6.0); Vector g = Vector_(2, -8.0, -9.0); @@ -120,11 +120,11 @@ TEST(HessianFactor, Constructor1) vector dims; dims.push_back(2); - VectorValues dx(dims); + VectorValuesOrdered dx(dims); dx[0] = dxv; - HessianFactor factor(0, G, g, f); + HessianFactorOrdered factor(0, G, g, f); // extract underlying parts Matrix info_matrix = factor.info_.range(0, 1, 0, 1); @@ -142,12 +142,12 @@ TEST(HessianFactor, Constructor1) } /* ************************************************************************* */ -TEST(HessianFactor, Constructor1b) +TEST(HessianFactorOrdered, Constructor1b) { Vector mu = Vector_(2,1.0,2.0); Matrix Sigma = eye(2,2); - HessianFactor factor(0, mu, Sigma); + HessianFactorOrdered factor(0, mu, Sigma); Matrix G = eye(2,2); Vector g = G*mu; @@ -162,7 +162,7 @@ TEST(HessianFactor, Constructor1b) } /* ************************************************************************* */ -TEST(HessianFactor, Constructor2) +TEST(HessianFactorOrdered, Constructor2) { Matrix G11 = Matrix_(1,1, 1.0); Matrix G12 = Matrix_(1,2, 2.0, 4.0); @@ -177,12 +177,12 @@ TEST(HessianFactor, Constructor2) vector dims; dims.push_back(1); dims.push_back(2); - VectorValues dx(dims); + VectorValuesOrdered dx(dims); dx[0] = dx0; dx[1] = dx1; - HessianFactor factor(0, 1, G11, G12, g1, G22, g2, f); + HessianFactorOrdered factor(0, 1, G11, G12, g1, G22, g2, f); double expected = 90.5; double actual = factor.error(dx); @@ -200,7 +200,7 @@ TEST(HessianFactor, Constructor2) // Check case when vector values is larger than factor dims.push_back(2); - VectorValues dxLarge(dims); + VectorValuesOrdered dxLarge(dims); dxLarge[0] = dx0; dxLarge[1] = dx1; dxLarge[2] = Vector_(2, 0.1, 0.2); @@ -208,7 +208,7 @@ TEST(HessianFactor, Constructor2) } /* ************************************************************************* */ -TEST(HessianFactor, Constructor3) +TEST(HessianFactorOrdered, Constructor3) { Matrix G11 = Matrix_(1,1, 1.0); Matrix G12 = Matrix_(1,2, 2.0, 4.0); @@ -233,13 +233,13 @@ TEST(HessianFactor, Constructor3) dims.push_back(1); dims.push_back(2); dims.push_back(3); - VectorValues dx(dims); + VectorValuesOrdered dx(dims); dx[0] = dx0; dx[1] = dx1; dx[2] = dx2; - HessianFactor factor(0, 1, 2, G11, G12, G13, g1, G22, G23, g2, G33, g3, f); + HessianFactorOrdered factor(0, 1, 2, G11, G12, G13, g1, G22, G23, g2, G33, g3, f); double expected = 371.3750; double actual = factor.error(dx); @@ -260,7 +260,7 @@ TEST(HessianFactor, Constructor3) } /* ************************************************************************* */ -TEST(HessianFactor, ConstructorNWay) +TEST(HessianFactorOrdered, ConstructorNWay) { Matrix G11 = Matrix_(1,1, 1.0); Matrix G12 = Matrix_(1,2, 2.0, 4.0); @@ -285,7 +285,7 @@ TEST(HessianFactor, ConstructorNWay) dims.push_back(1); dims.push_back(2); dims.push_back(3); - VectorValues dx(dims); + VectorValuesOrdered dx(dims); dx[0] = dx0; dx[1] = dx1; @@ -298,7 +298,7 @@ TEST(HessianFactor, ConstructorNWay) Gs.push_back(G11); Gs.push_back(G12); Gs.push_back(G13); Gs.push_back(G22); Gs.push_back(G23); Gs.push_back(G33); std::vector gs; gs.push_back(g1); gs.push_back(g2); gs.push_back(g3); - HessianFactor factor(js, Gs, gs, f); + HessianFactorOrdered factor(js, Gs, gs, f); double expected = 371.3750; double actual = factor.error(dx); @@ -319,7 +319,7 @@ TEST(HessianFactor, ConstructorNWay) } /* ************************************************************************* */ -TEST_UNSAFE(HessianFactor, CopyConstructor_and_assignment) +TEST_UNSAFE(HessianFactorOrdered, CopyConstructor_and_assignment) { Matrix G11 = Matrix_(1,1, 1.0); Matrix G12 = Matrix_(1,2, 2.0, 4.0); @@ -334,15 +334,15 @@ TEST_UNSAFE(HessianFactor, CopyConstructor_and_assignment) vector dims; dims.push_back(1); dims.push_back(2); - VectorValues dx(dims); + VectorValuesOrdered dx(dims); dx[0] = dx0; dx[1] = dx1; - HessianFactor originalFactor(0, 1, G11, G12, g1, G22, g2, f); + HessianFactorOrdered originalFactor(0, 1, G11, G12, g1, G22, g2, f); // Make a copy - HessianFactor copy1(originalFactor); + HessianFactorOrdered copy1(originalFactor); double expected = 90.5; double actual = copy1.error(dx); @@ -359,8 +359,8 @@ TEST_UNSAFE(HessianFactor, CopyConstructor_and_assignment) EXPECT(assert_equal(G22, copy1.info(copy1.begin()+1, copy1.begin()+1))); // Make a copy using the assignment operator - HessianFactor copy2; - copy2 = HessianFactor(originalFactor); // Make a temporary to make sure copying does not shared references + HessianFactorOrdered copy2; + copy2 = HessianFactorOrdered(originalFactor); // Make a temporary to make sure copying does not shared references actual = copy2.error(dx); DOUBLES_EQUAL(expected, actual, 1e-10); @@ -375,7 +375,7 @@ TEST_UNSAFE(HessianFactor, CopyConstructor_and_assignment) } /* ************************************************************************* */ -TEST_UNSAFE(HessianFactor, CombineAndEliminate) +TEST_UNSAFE(HessianFactorOrdered, CombineAndEliminate) { Matrix A01 = Matrix_(3,3, 1.0, 0.0, 0.0, @@ -402,7 +402,7 @@ TEST_UNSAFE(HessianFactor, CombineAndEliminate) Vector b2 = Vector_(3, 3.5, 3.5, 3.5); Vector s2 = Vector_(3, 3.6, 3.6, 3.6); - GaussianFactorGraph gfg; + GaussianFactorGraphOrdered 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)); @@ -414,35 +414,35 @@ TEST_UNSAFE(HessianFactor, CombineAndEliminate) Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2); // create a full, uneliminated version of the factor - JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); + JacobianFactorOrdered expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); // perform elimination - GaussianConditional::shared_ptr expectedBN = expectedFactor.eliminate(1); + GaussianConditionalOrdered::shared_ptr expectedBN = expectedFactor.eliminate(1); // create expected Hessian after elimination - HessianFactor expectedCholeskyFactor(expectedFactor); + HessianFactorOrdered expectedCholeskyFactor(expectedFactor); // Convert all factors to hessians - FactorGraph hessians; - BOOST_FOREACH(const GaussianFactorGraph::sharedFactor& factor, gfg) { - if(boost::shared_ptr hf = boost::dynamic_pointer_cast(factor)) + FactorGraphOrdered hessians; + BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, gfg) { + if(boost::shared_ptr hf = boost::dynamic_pointer_cast(factor)) hessians.push_back(hf); - else if(boost::shared_ptr jf = boost::dynamic_pointer_cast(factor)) - hessians.push_back(boost::make_shared(*jf)); + else if(boost::shared_ptr jf = boost::dynamic_pointer_cast(factor)) + hessians.push_back(boost::make_shared(*jf)); else CHECK(false); } // Eliminate - GaussianFactorGraph::EliminationResult actualCholesky = EliminateCholesky(gfg, 1); - HessianFactor::shared_ptr actualFactor = boost::dynamic_pointer_cast(actualCholesky.second); + GaussianFactorGraphOrdered::EliminationResult actualCholesky = EliminateCholeskyOrdered(gfg, 1); + HessianFactorOrdered::shared_ptr actualFactor = boost::dynamic_pointer_cast(actualCholesky.second); EXPECT(assert_equal(*expectedBN, *actualCholesky.first, 1e-6)); EXPECT(assert_equal(expectedCholeskyFactor, *actualFactor, 1e-6)); } /* ************************************************************************* */ -TEST(HessianFactor, eliminate2 ) +TEST(HessianFactorOrdered, eliminate2 ) { // sigmas double sigma1 = 0.2; @@ -476,17 +476,17 @@ TEST(HessianFactor, eliminate2 ) vector > meas; meas.push_back(make_pair(0, Ax2)); meas.push_back(make_pair(1, Al1x1)); - JacobianFactor combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactorOrdered combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); // eliminate the combined factor - HessianFactor::shared_ptr combinedLF_Chol(new HessianFactor(combined)); - FactorGraph combinedLFG_Chol; + HessianFactorOrdered::shared_ptr combinedLF_Chol(new HessianFactorOrdered(combined)); + FactorGraphOrdered combinedLFG_Chol; combinedLFG_Chol.push_back(combinedLF_Chol); - GaussianFactorGraph::EliminationResult actual_Chol = EliminateCholesky( + GaussianFactorGraphOrdered::EliminationResult actual_Chol = EliminateCholeskyOrdered( combinedLFG_Chol, 1); - HessianFactor::shared_ptr actualFactor = boost::dynamic_pointer_cast< - HessianFactor>(actual_Chol.second); + HessianFactorOrdered::shared_ptr actualFactor = boost::dynamic_pointer_cast< + HessianFactorOrdered>(actual_Chol.second); // create expected Conditional Gaussian double oldSigma = 0.0894427; // from when R was made unit @@ -499,7 +499,7 @@ TEST(HessianFactor, eliminate2 ) +0.00,-0.20,+0.00,-0.80 )/oldSigma; Vector d = Vector_(2,0.2,-0.14)/oldSigma; - GaussianConditional expectedCG(0,d,R11,1,S12,ones(2)); + GaussianConditionalOrdered expectedCG(0,d,R11,1,S12,ones(2)); EXPECT(assert_equal(expectedCG,*actual_Chol.first,1e-4)); // the expected linear factor @@ -510,15 +510,15 @@ TEST(HessianFactor, eliminate2 ) 0.00, 1.00, +0.00, -1.00 )/sigma; Vector b1 = Vector_(2,0.0,0.894427); - JacobianFactor expectedLF(1, Bl1x1, b1, noiseModel::Isotropic::Sigma(2,1.0)); - EXPECT(assert_equal(HessianFactor(expectedLF), *actualFactor, 1.5e-3)); + JacobianFactorOrdered expectedLF(1, Bl1x1, b1, noiseModel::Isotropic::Sigma(2,1.0)); + EXPECT(assert_equal(HessianFactorOrdered(expectedLF), *actualFactor, 1.5e-3)); } /* ************************************************************************* */ -TEST(HessianFactor, eliminateUnsorted) { +TEST(HessianFactorOrdered, eliminateUnsorted) { - JacobianFactor::shared_ptr factor1( - new JacobianFactor(0, + JacobianFactorOrdered::shared_ptr factor1( + new JacobianFactorOrdered(0, Matrix_(3,3, 44.7214, 0.0, 0.0, 0.0, 44.7214, 0.0, @@ -530,8 +530,8 @@ TEST(HessianFactor, eliminateUnsorted) { 0.0, 0.0, -44.7214), Vector_(3, 1.98916e-17, -4.96503e-15, -7.75792e-17), noiseModel::Unit::Create(3))); - HessianFactor::shared_ptr unsorted_factor2( - new HessianFactor(JacobianFactor(0, + HessianFactorOrdered::shared_ptr unsorted_factor2( + new HessianFactorOrdered(JacobianFactorOrdered(0, Matrix_(6,3, 25.8367, 0.1211, 0.0593, 0.0, 23.4099, 30.8733, @@ -554,8 +554,8 @@ TEST(HessianFactor, eliminateUnsorted) { permutation[1] = 0; unsorted_factor2->permuteWithInverse(permutation); - HessianFactor::shared_ptr sorted_factor2( - new HessianFactor(JacobianFactor(0, + HessianFactorOrdered::shared_ptr sorted_factor2( + new HessianFactorOrdered(JacobianFactorOrdered(0, Matrix_(6,3, 25.7429, -1.6897, 0.4587, 1.6400, 23.3095, -8.4816, @@ -574,30 +574,30 @@ TEST(HessianFactor, eliminateUnsorted) { Vector_(6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), noiseModel::Unit::Create(6)))); - GaussianFactorGraph sortedGraph; + GaussianFactorGraphOrdered sortedGraph; // sortedGraph.push_back(factor1); sortedGraph.push_back(sorted_factor2); - GaussianFactorGraph unsortedGraph; + GaussianFactorGraphOrdered unsortedGraph; // unsortedGraph.push_back(factor1); unsortedGraph.push_back(unsorted_factor2); - GaussianConditional::shared_ptr expected_bn; - GaussianFactor::shared_ptr expected_factor; + GaussianConditionalOrdered::shared_ptr expected_bn; + GaussianFactorOrdered::shared_ptr expected_factor; boost::tie(expected_bn, expected_factor) = - EliminatePreferCholesky(sortedGraph, 1); + EliminatePreferCholeskyOrdered(sortedGraph, 1); - GaussianConditional::shared_ptr actual_bn; - GaussianFactor::shared_ptr actual_factor; + GaussianConditionalOrdered::shared_ptr actual_bn; + GaussianFactorOrdered::shared_ptr actual_factor; boost::tie(actual_bn, actual_factor) = - EliminatePreferCholesky(unsortedGraph, 1); + EliminatePreferCholeskyOrdered(unsortedGraph, 1); EXPECT(assert_equal(*expected_bn, *actual_bn, 1e-10)); EXPECT(assert_equal(*expected_factor, *actual_factor, 1e-10)); } /* ************************************************************************* */ -TEST(HessianFactor, combine) { +TEST(HessianFactorOrdered, combine) { // update the information matrix with a single jacobian factor Matrix A0 = Matrix_(2, 2, @@ -611,12 +611,12 @@ TEST(HessianFactor, combine) { 0.0, -8.94427191); Vector b = Vector_(2, 2.23606798,-1.56524758); SharedDiagonal model = noiseModel::Diagonal::Sigmas(ones(2)); - GaussianFactor::shared_ptr f(new JacobianFactor(0, A0, 1, A1, 2, A2, b, model)); - FactorGraph factors; + GaussianFactorOrdered::shared_ptr f(new JacobianFactorOrdered(0, A0, 1, A1, 2, A2, b, model)); + FactorGraphOrdered factors; factors.push_back(f); // Form Ab' * Ab - HessianFactor actual(factors); + HessianFactorOrdered actual(factors); Matrix expected = Matrix_(7, 7, 125.0000, 0.0, -25.0000, 0.0, -100.0000, 0.0, 25.0000, diff --git a/gtsam/linear/tests/testJacobianFactorObsolete.cpp b/gtsam/linear/tests/testJacobianFactorObsolete.cpp index fe13fdeac..8e94d6f09 100644 --- a/gtsam/linear/tests/testJacobianFactorObsolete.cpp +++ b/gtsam/linear/tests/testJacobianFactorObsolete.cpp @@ -19,10 +19,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace std; using namespace gtsam; @@ -32,30 +32,30 @@ static const Index _x0_=0, _x1_=1, _x2_=2, _x_=5, _y_=6, _l11_=8; static SharedDiagonal constraintModel = noiseModel::Constrained::All(2); /* ************************************************************************* */ -TEST(JacobianFactor, constructor) +TEST(JacobianFactorOrdered, constructor) { Vector b = Vector_(3, 1., 2., 3.); SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector_(3,1.,1.,1.)); std::list > terms; terms.push_back(make_pair(_x0_, eye(3))); terms.push_back(make_pair(_x1_, 2.*eye(3))); - JacobianFactor actual(terms, b, noise); - JacobianFactor expected(_x0_, eye(3), _x1_, 2.*eye(3), b, noise); + JacobianFactorOrdered actual(terms, b, noise); + JacobianFactorOrdered expected(_x0_, eye(3), _x1_, 2.*eye(3), b, noise); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST(JacobianFactor, constructor2) +TEST(JacobianFactorOrdered, constructor2) { Vector b = Vector_(3, 1., 2., 3.); SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector_(3,1.,1.,1.)); std::list > terms; terms.push_back(make_pair(_x0_, eye(3))); terms.push_back(make_pair(_x1_, 2.*eye(3))); - const JacobianFactor actual(terms, b, noise); + const JacobianFactorOrdered actual(terms, b, noise); - JacobianFactor::const_iterator key0 = actual.begin(); - JacobianFactor::const_iterator key1 = key0 + 1; + JacobianFactorOrdered::const_iterator key0 = actual.begin(); + JacobianFactorOrdered::const_iterator key1 = key0 + 1; EXPECT(assert_equal(*key0, _x0_)); EXPECT(assert_equal(*key1, _x1_)); EXPECT(!actual.empty()); @@ -72,21 +72,21 @@ TEST(JacobianFactor, constructor2) /* ************************************************************************* */ -JacobianFactor construct() { +JacobianFactorOrdered construct() { Matrix A = Matrix_(2,2, 1.,2.,3.,4.); Vector b = Vector_(2, 1.0, 2.0); SharedDiagonal s = noiseModel::Diagonal::Sigmas(Vector_(2, 3.0, 4.0)); - JacobianFactor::shared_ptr shared( - new JacobianFactor(0, A, b, s)); + JacobianFactorOrdered::shared_ptr shared( + new JacobianFactorOrdered(0, A, b, s)); return *shared; } -TEST(JacobianFactor, return_value) +TEST(JacobianFactorOrdered, return_value) { Matrix A = Matrix_(2,2, 1.,2.,3.,4.); Vector b = Vector_(2, 1.0, 2.0); SharedDiagonal s = noiseModel::Diagonal::Sigmas(Vector_(2, 3.0, 4.0)); - JacobianFactor copied = construct(); + JacobianFactorOrdered copied = construct(); EXPECT(assert_equal(b, copied.getb())); EXPECT(assert_equal(*s, *copied.get_model())); EXPECT(assert_equal(A, copied.getA(copied.begin()))); @@ -94,7 +94,7 @@ TEST(JacobianFactor, return_value) /* ************************************************************************* */ TEST(JabobianFactor, Hessian_conversion) { - HessianFactor hessian(0, (Matrix(4,4) << + HessianFactorOrdered hessian(0, (Matrix(4,4) << 1.57, 2.695, -1.1, -2.35, 2.695, 11.3125, -0.65, -10.225, -1.1, -0.65, 1, 0.5, @@ -102,52 +102,52 @@ TEST(JabobianFactor, Hessian_conversion) { (Vector(4) << -7.885, -28.5175, 2.75, 25.675).finished(), 73.1725); - JacobianFactor expected(0, (Matrix(2,4) << + JacobianFactorOrdered expected(0, (Matrix(2,4) << 1.2530, 2.1508, -0.8779, -1.8755, 0, 2.5858, 0.4789, -2.3943).finished(), (Vector(2) << -6.2929, -5.7941).finished(), noiseModel::Unit::Create(2)); - JacobianFactor actual(hessian); + JacobianFactorOrdered actual(hessian); EXPECT(assert_equal(expected, actual, 1e-3)); } /* ************************************************************************* */ -TEST( JacobianFactor, constructor_combined){ +TEST( JacobianFactorOrdered, constructor_combined){ double sigma1 = 0.0957; Matrix A11(2,2); A11(0,0) = 1; A11(0,1) = 0; A11(1,0) = 0; A11(1,1) = 1; Vector b(2); b(0) = 2; b(1) = -1; - JacobianFactor::shared_ptr f1(new JacobianFactor(0, A11, b*sigma1, noiseModel::Isotropic::Sigma(2,sigma1))); + JacobianFactorOrdered::shared_ptr f1(new JacobianFactorOrdered(0, A11, b*sigma1, noiseModel::Isotropic::Sigma(2,sigma1))); double sigma2 = 0.5; A11(0,0) = 1; A11(0,1) = 0; A11(1,0) = 0; A11(1,1) = -1; b(0) = 4 ; b(1) = -5; - JacobianFactor::shared_ptr f2(new JacobianFactor(0, A11, b*sigma2, noiseModel::Isotropic::Sigma(2,sigma2))); + JacobianFactorOrdered::shared_ptr f2(new JacobianFactorOrdered(0, A11, b*sigma2, noiseModel::Isotropic::Sigma(2,sigma2))); double sigma3 = 0.25; A11(0,0) = 1; A11(0,1) = 0; A11(1,0) = 0; A11(1,1) = -1; b(0) = 3 ; b(1) = -88; - JacobianFactor::shared_ptr f3(new JacobianFactor(0, A11, b*sigma3, noiseModel::Isotropic::Sigma(2,sigma3))); + JacobianFactorOrdered::shared_ptr f3(new JacobianFactorOrdered(0, A11, b*sigma3, noiseModel::Isotropic::Sigma(2,sigma3))); // TODO: find a real sigma value for this example double sigma4 = 0.1; A11(0,0) = 6; A11(0,1) = 0; A11(1,0) = 0; A11(1,1) = 7; b(0) = 5 ; b(1) = -6; - JacobianFactor::shared_ptr f4(new JacobianFactor(0, A11*sigma4, b*sigma4, noiseModel::Isotropic::Sigma(2,sigma4))); + JacobianFactorOrdered::shared_ptr f4(new JacobianFactorOrdered(0, A11*sigma4, b*sigma4, noiseModel::Isotropic::Sigma(2,sigma4))); - GaussianFactorGraph lfg; + GaussianFactorGraphOrdered lfg; lfg.push_back(f1); lfg.push_back(f2); lfg.push_back(f3); lfg.push_back(f4); - JacobianFactor combined(lfg); + JacobianFactorOrdered combined(lfg); Vector sigmas = Vector_(8, sigma1, sigma1, sigma2, sigma2, sigma3, sigma3, sigma4, sigma4); Matrix A22(8,2); @@ -165,21 +165,21 @@ TEST( JacobianFactor, constructor_combined){ vector > meas; meas.push_back(make_pair(0, A22)); - JacobianFactor expected(meas, exb, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactorOrdered expected(meas, exb, noiseModel::Diagonal::Sigmas(sigmas)); EXPECT(assert_equal(expected,combined)); } /* ************************************************************************* */ -TEST(JacobianFactor, linearFactorN){ +TEST(JacobianFactorOrdered, linearFactorN){ Matrix I = eye(2); - GaussianFactorGraph f; + GaussianFactorGraphOrdered f; SharedDiagonal model = noiseModel::Isotropic::Sigma(2,1.0); - f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(0, I, Vector_(2, 10.0, 5.0), model))); - f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(0, -10 * I, 1, 10 * I, Vector_(2, 1.0, -2.0), model))); - f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(1, -10 * I, 2, 10 * I, Vector_(2, 1.5, -1.5), model))); - f.push_back(JacobianFactor::shared_ptr(new JacobianFactor(2, -10 * I, 3, 10 * I, Vector_(2, 2.0, -1.0), model))); + f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(0, I, Vector_(2, 10.0, 5.0), model))); + f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(0, -10 * I, 1, 10 * I, Vector_(2, 1.0, -2.0), model))); + f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(1, -10 * I, 2, 10 * I, Vector_(2, 1.5, -1.5), model))); + f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(2, -10 * I, 3, 10 * I, Vector_(2, 2.0, -1.0), model))); - JacobianFactor combinedFactor(f); + JacobianFactorOrdered combinedFactor(f); vector > combinedMeasurement; combinedMeasurement.push_back(make_pair(0, Matrix_(8,2, @@ -222,20 +222,20 @@ TEST(JacobianFactor, linearFactorN){ 10.0, 5.0, 1.0, -2.0, 1.5, -1.5, 2.0, -1.0); Vector sigmas = repeat(8,1.0); - JacobianFactor expected(combinedMeasurement, b, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactorOrdered expected(combinedMeasurement, b, noiseModel::Diagonal::Sigmas(sigmas)); EXPECT(assert_equal(expected,combinedFactor)); } /* ************************************************************************* */ -TEST(JacobianFactor, error) { +TEST(JacobianFactorOrdered, error) { Vector b = Vector_(3, 1., 2., 3.); SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector_(3,2.,2.,2.)); std::list > terms; terms.push_back(make_pair(_x0_, eye(3))); terms.push_back(make_pair(_x1_, 2.*eye(3))); - const JacobianFactor jf(terms, b, noise); + const JacobianFactorOrdered jf(terms, b, noise); - VectorValues values(2, 3); + VectorValuesOrdered values(2, 3); values[0] = Vector_(3, 1.,2.,3.); values[1] = Vector_(3, 4.,5.,6.); @@ -248,7 +248,7 @@ TEST(JacobianFactor, error) { EXPECT(assert_equal(expected_whitened, actual_whitened)); // check behavior when there are more values than in this factor - VectorValues largeValues(3, 3); + VectorValuesOrdered largeValues(3, 3); largeValues[0] = Vector_(3, 1.,2.,3.); largeValues[1] = Vector_(3, 4.,5.,6.); largeValues[2] = Vector_(3, 7.,8.,9.); @@ -258,15 +258,15 @@ TEST(JacobianFactor, error) { } /* ************************************************************************* */ -TEST(JacobianFactor, operators ) +TEST(JacobianFactorOrdered, operators ) { SharedDiagonal sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1); Matrix I = eye(2); Vector b = Vector_(2,0.2,-0.1); - JacobianFactor lf(_x1_, -I, _x2_, I, b, sigma0_1); + JacobianFactorOrdered lf(_x1_, -I, _x2_, I, b, sigma0_1); - VectorValues c; + VectorValuesOrdered c; c.insert(_x1_, Vector_(2,10.,20.)); c.insert(_x2_, Vector_(2,30.,60.)); @@ -275,16 +275,16 @@ TEST(JacobianFactor, operators ) EXPECT(assert_equal(expectedE,e)); // test A^e - VectorValues expectedX; + VectorValuesOrdered expectedX; expectedX.insert(_x1_, Vector_(2,-2000.,-4000.)); expectedX.insert(_x2_, Vector_(2, 2000., 4000.)); - VectorValues actualX = VectorValues::Zero(expectedX); + VectorValuesOrdered actualX = VectorValuesOrdered::Zero(expectedX); lf.transposeMultiplyAdd(1.0, e, actualX); EXPECT(assert_equal(expectedX, actualX)); } /* ************************************************************************* */ -TEST(JacobianFactor, eliminate2 ) +TEST(JacobianFactorOrdered, eliminate2 ) { // sigmas double sigma1 = 0.2; @@ -318,11 +318,11 @@ TEST(JacobianFactor, eliminate2 ) vector > meas; meas.push_back(make_pair(_x2_, Ax2)); meas.push_back(make_pair(_l11_, Al1x1)); - JacobianFactor combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactorOrdered combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); // eliminate the combined factor - GaussianConditional::shared_ptr actualCG_QR; - JacobianFactor::shared_ptr actualLF_QR(new JacobianFactor(combined)); + GaussianConditionalOrdered::shared_ptr actualCG_QR; + JacobianFactorOrdered::shared_ptr actualLF_QR(new JacobianFactorOrdered(combined)); actualCG_QR = actualLF_QR->eliminateFirst(); // create expected Conditional Gaussian @@ -336,7 +336,7 @@ TEST(JacobianFactor, eliminate2 ) +0.00,-0.20,+0.00,-0.80 )/oldSigma; Vector d = Vector_(2,0.2,-0.14)/oldSigma; - GaussianConditional expectedCG(_x2_,d,R11,_l11_,S12,ones(2)); + GaussianConditionalOrdered expectedCG(_x2_,d,R11,_l11_,S12,ones(2)); EXPECT_LONGS_EQUAL(0, actualCG_QR->rsd().firstBlock()); EXPECT_LONGS_EQUAL(0, actualCG_QR->rsd().rowStart()); @@ -352,25 +352,25 @@ TEST(JacobianFactor, eliminate2 ) 0.00, 1.00, +0.00, -1.00 )/sigma; Vector b1 = Vector_(2,0.0,0.894427); - JacobianFactor expectedLF(_l11_, Bl1x1, b1, noiseModel::Isotropic::Sigma(2,1.0)); + JacobianFactorOrdered expectedLF(_l11_, Bl1x1, b1, noiseModel::Isotropic::Sigma(2,1.0)); EXPECT(assert_equal(expectedLF,*actualLF_QR,1e-3)); } /* ************************************************************************* */ -TEST(JacobianFactor, default_error ) +TEST(JacobianFactorOrdered, default_error ) { - JacobianFactor f; + JacobianFactorOrdered f; vector dims; - VectorValues c(dims); + VectorValuesOrdered c(dims); double actual = f.error(c); EXPECT(actual==0.0); } //* ************************************************************************* */ -TEST(JacobianFactor, empty ) +TEST(JacobianFactorOrdered, empty ) { // create an empty factor - JacobianFactor f; + JacobianFactorOrdered f; EXPECT(f.empty()==true); } @@ -383,7 +383,7 @@ void print(const list& i) { } /* ************************************************************************* */ -TEST(JacobianFactor, CONSTRUCTOR_GaussianConditional ) +TEST(JacobianFactorOrdered, CONSTRUCTOR_GaussianConditional ) { Matrix R11 = eye(2); Matrix S12 = Matrix_(2,2, @@ -392,26 +392,26 @@ TEST(JacobianFactor, CONSTRUCTOR_GaussianConditional ) ); Vector d(2); d(0) = 2.23607; d(1) = -1.56525; Vector sigmas =repeat(2,0.29907); - GaussianConditional::shared_ptr CG(new GaussianConditional(_x2_,d,R11,_l11_,S12,sigmas)); + GaussianConditionalOrdered::shared_ptr CG(new GaussianConditionalOrdered(_x2_,d,R11,_l11_,S12,sigmas)); // Call the constructor we are testing ! - JacobianFactor actualLF(*CG); + JacobianFactorOrdered actualLF(*CG); - JacobianFactor expectedLF(_x2_,R11,_l11_,S12,d, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactorOrdered expectedLF(_x2_,R11,_l11_,S12,d, noiseModel::Diagonal::Sigmas(sigmas)); EXPECT(assert_equal(expectedLF,actualLF,1e-5)); } /* ************************************************************************* */ -TEST ( JacobianFactor, constraint_eliminate1 ) +TEST ( JacobianFactorOrdered, constraint_eliminate1 ) { // construct a linear constraint Vector v(2); v(0)=1.2; v(1)=3.4; Index key = _x0_; - JacobianFactor lc(key, eye(2), v, constraintModel); + JacobianFactorOrdered lc(key, eye(2), v, constraintModel); // eliminate it - GaussianConditional::shared_ptr actualCG; - JacobianFactor::shared_ptr actualLF(new JacobianFactor(lc)); + GaussianConditionalOrdered::shared_ptr actualCG; + JacobianFactorOrdered::shared_ptr actualLF(new JacobianFactorOrdered(lc)); actualCG = actualLF->eliminateFirst(); // verify linear factor @@ -419,12 +419,12 @@ TEST ( JacobianFactor, constraint_eliminate1 ) // verify conditional Gaussian Vector sigmas = Vector_(2, 0.0, 0.0); - GaussianConditional expCG(_x0_, v, eye(2), sigmas); + GaussianConditionalOrdered expCG(_x0_, v, eye(2), sigmas); EXPECT(assert_equal(expCG, *actualCG)); } /* ************************************************************************* */ -TEST ( JacobianFactor, constraint_eliminate2 ) +TEST ( JacobianFactorOrdered, constraint_eliminate2 ) { // Construct a linear constraint // RHS @@ -440,15 +440,15 @@ TEST ( JacobianFactor, constraint_eliminate2 ) A2(0,0) = 1.0 ; A2(0,1) = 2.0; A2(1,0) = 2.0 ; A2(1,1) = 4.0; - JacobianFactor lc(_x_, A1, _y_, A2, b, constraintModel); + JacobianFactorOrdered lc(_x_, A1, _y_, A2, b, constraintModel); // eliminate x and verify results - GaussianConditional::shared_ptr actualCG; - JacobianFactor::shared_ptr actualLF(new JacobianFactor(lc)); + GaussianConditionalOrdered::shared_ptr actualCG; + JacobianFactorOrdered::shared_ptr actualLF(new JacobianFactorOrdered(lc)); actualCG = actualLF->eliminateFirst(); // LF should be null - JacobianFactor expectedLF; + JacobianFactorOrdered expectedLF; EXPECT(assert_equal(*actualLF, expectedLF)); // verify CG @@ -459,7 +459,7 @@ TEST ( JacobianFactor, constraint_eliminate2 ) 1.0, 2.0, 0.0, 0.0); Vector d = Vector_(2, 3.0, 0.6666); - GaussianConditional expectedCG(_x_, d, R, _y_, S, zero(2)); + GaussianConditionalOrdered expectedCG(_x_, d, R, _y_, S, zero(2)); EXPECT(assert_equal(expectedCG, *actualCG, 1e-4)); } diff --git a/gtsam/linear/tests/testJacobianFactorUnordered.cpp b/gtsam/linear/tests/testJacobianFactorUnordered.cpp index a2972e6b8..0f02c5529 100644 --- a/gtsam/linear/tests/testJacobianFactorUnordered.cpp +++ b/gtsam/linear/tests/testJacobianFactorUnordered.cpp @@ -19,10 +19,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -47,16 +47,16 @@ namespace { } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, constructors_and_accessors) +TEST(JacobianFactor, constructors_and_accessors) { using namespace simple; // Test for using different numbers of terms { // b vector only constructor - JacobianFactorUnordered expected( + JacobianFactor expected( boost::make_iterator_range(terms.begin(), terms.begin()), b); - JacobianFactorUnordered actual(b); + JacobianFactor actual(b); EXPECT(assert_equal(expected, actual)); EXPECT(assert_equal(b, expected.getb())); EXPECT(assert_equal(b, actual.getb())); @@ -65,9 +65,9 @@ TEST(JacobianFactorUnordered, constructors_and_accessors) } { // One term constructor - JacobianFactorUnordered expected( + JacobianFactor expected( boost::make_iterator_range(terms.begin(), terms.begin() + 1), b, noise); - JacobianFactorUnordered actual(terms[0].first, terms[0].second, b, noise); + JacobianFactor actual(terms[0].first, terms[0].second, b, noise); EXPECT(assert_equal(expected, actual)); LONGS_EQUAL((long)terms[0].first, (long)actual.keys().back()); EXPECT(assert_equal(terms[0].second, actual.getA(actual.end() - 1))); @@ -78,9 +78,9 @@ TEST(JacobianFactorUnordered, constructors_and_accessors) } { // Two term constructor - JacobianFactorUnordered expected( + JacobianFactor expected( boost::make_iterator_range(terms.begin(), terms.begin() + 2), b, noise); - JacobianFactorUnordered actual(terms[0].first, terms[0].second, + JacobianFactor actual(terms[0].first, terms[0].second, terms[1].first, terms[1].second, b, noise); EXPECT(assert_equal(expected, actual)); LONGS_EQUAL((long)terms[1].first, (long)actual.keys().back()); @@ -92,9 +92,9 @@ TEST(JacobianFactorUnordered, constructors_and_accessors) } { // Three term constructor - JacobianFactorUnordered expected( + JacobianFactor expected( boost::make_iterator_range(terms.begin(), terms.begin() + 3), b, noise); - JacobianFactorUnordered actual(terms[0].first, terms[0].second, + JacobianFactor actual(terms[0].first, terms[0].second, terms[1].first, terms[1].second, terms[2].first, terms[2].second, b, noise); EXPECT(assert_equal(expected, actual)); LONGS_EQUAL((long)terms[2].first, (long)actual.keys().back()); @@ -106,14 +106,14 @@ TEST(JacobianFactorUnordered, constructors_and_accessors) } { // VerticalBlockMatrix constructor - JacobianFactorUnordered expected( + JacobianFactor expected( boost::make_iterator_range(terms.begin(), terms.begin() + 3), b, noise); VerticalBlockMatrix blockMatrix(list_of(3)(3)(3)(1), 3); blockMatrix(0) = terms[0].second; blockMatrix(1) = terms[1].second; blockMatrix(2) = terms[2].second; blockMatrix(3) = b; - JacobianFactorUnordered actual(terms | boost::adaptors::map_keys, blockMatrix, noise); + JacobianFactor actual(terms | boost::adaptors::map_keys, blockMatrix, noise); EXPECT(assert_equal(expected, actual)); LONGS_EQUAL((long)terms[2].first, (long)actual.keys().back()); EXPECT(assert_equal(terms[2].second, actual.getA(actual.end() - 1))); @@ -146,46 +146,46 @@ TEST(JacobianFactorUnordered, constructors_and_accessors) //} /* ************************************************************************* */ -TEST( JacobianFactorUnordered, construct_from_graph) +TEST( JacobianFactor, construct_from_graph) { - GaussianFactorGraphUnordered factors; + GaussianFactorGraph factors; double sigma1 = 0.1; Matrix A11 = Matrix::Identity(2,2); Vector b1(2); b1 << 2, -1; - factors.add(JacobianFactorUnordered(10, A11, b1, noiseModel::Isotropic::Sigma(2, sigma1))); + factors.add(JacobianFactor(10, A11, b1, noiseModel::Isotropic::Sigma(2, sigma1))); double sigma2 = 0.5; Matrix A21 = -2 * Matrix::Identity(2,2); Matrix A22 = 3 * Matrix::Identity(2,2); Vector b2(2); b2 << 4, -5; - factors.add(JacobianFactorUnordered(10, A21, 8, A22, b2, noiseModel::Isotropic::Sigma(2, sigma2))); + factors.add(JacobianFactor(10, A21, 8, A22, b2, noiseModel::Isotropic::Sigma(2, sigma2))); double sigma3 = 1.0; Matrix A32 = -4 * Matrix::Identity(2,2); Matrix A33 = 5 * Matrix::Identity(2,2); Vector b3(2); b3 << 3, -6; - factors.add(JacobianFactorUnordered(8, A32, 12, A33, b3, noiseModel::Isotropic::Sigma(2, sigma3))); + factors.add(JacobianFactor(8, A32, 12, A33, b3, noiseModel::Isotropic::Sigma(2, sigma3))); Matrix A1(6,2); A1 << A11, A21, Matrix::Zero(2,2); Matrix A2(6,2); A2 << Matrix::Zero(2,2), A22, A32; Matrix A3(6,2); A3 << Matrix::Zero(4,2), A33; Vector b(6); b << b1, b2, b3; Vector sigmas(6); sigmas << sigma1, sigma1, sigma2, sigma2, sigma3, sigma3; - JacobianFactorUnordered expected(10, A1, 8, A2, 12, A3, b, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactor expected(10, A1, 8, A2, 12, A3, b, noiseModel::Diagonal::Sigmas(sigmas)); // The ordering here specifies the order in which the variables will appear in the combined factor - JacobianFactorUnordered actual(factors, OrderingUnordered(list_of(10)(8)(12))); + JacobianFactor actual(factors, Ordering(list_of(10)(8)(12))); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, error) +TEST(JacobianFactor, error) { - JacobianFactorUnordered factor(simple::terms, simple::b, simple::noise); + JacobianFactor factor(simple::terms, simple::b, simple::noise); - VectorValuesUnordered values; + VectorValues values; values.insert(5, Vector::Constant(3, 1.0)); values.insert(10, Vector::Constant(3, 0.5)); values.insert(15, Vector::Constant(3, 1.0/3.0)); @@ -204,9 +204,9 @@ TEST(JacobianFactorUnordered, error) } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, matrices) +TEST(JacobianFactor, matrices) { - JacobianFactorUnordered factor(simple::terms, simple::b, simple::noise); + JacobianFactor factor(simple::terms, simple::b, simple::noise); Matrix jacobianExpected(3, 9); jacobianExpected << simple::terms[0].second, simple::terms[1].second, simple::terms[2].second; @@ -234,15 +234,15 @@ TEST(JacobianFactorUnordered, matrices) } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, operators ) +TEST(JacobianFactor, operators ) { SharedDiagonal sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1); Matrix I = eye(2); Vector b = Vector_(2,0.2,-0.1); - JacobianFactorUnordered lf(1, -I, 2, I, b, sigma0_1); + JacobianFactor lf(1, -I, 2, I, b, sigma0_1); - VectorValuesUnordered c; + VectorValues c; c.insert(1, Vector_(2,10.,20.)); c.insert(2, Vector_(2,30.,60.)); @@ -252,32 +252,32 @@ TEST(JacobianFactorUnordered, operators ) EXPECT(assert_equal(expectedE, actualE)); // test A^e - VectorValuesUnordered expectedX; + VectorValues expectedX; expectedX.insert(1, Vector_(2,-2000.,-4000.)); expectedX.insert(2, Vector_(2, 2000., 4000.)); - VectorValuesUnordered actualX = VectorValuesUnordered::Zero(expectedX); + VectorValues actualX = VectorValues::Zero(expectedX); lf.transposeMultiplyAdd(1.0, actualE, actualX); EXPECT(assert_equal(expectedX, actualX)); } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, default_error ) +TEST(JacobianFactor, default_error ) { - JacobianFactorUnordered f; - double actual = f.error(VectorValuesUnordered()); + JacobianFactor f; + double actual = f.error(VectorValues()); DOUBLES_EQUAL(0.0, actual, 1e-15); } //* ************************************************************************* */ -TEST(JacobianFactorUnordered, empty ) +TEST(JacobianFactor, empty ) { // create an empty factor - JacobianFactorUnordered f; + JacobianFactor f; EXPECT(f.empty()); } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, eliminate) +TEST(JacobianFactor, eliminate) { Matrix A01 = Matrix_(3,3, 1.0, 0.0, 0.0, @@ -304,7 +304,7 @@ TEST(JacobianFactorUnordered, eliminate) Vector b2 = Vector_(3, 3.5, 3.5, 3.5); Vector s2 = Vector_(3, 3.6, 3.6, 3.6); - GaussianFactorGraphUnordered gfg; + 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)); @@ -315,21 +315,21 @@ TEST(JacobianFactorUnordered, eliminate) Vector b = gtsam::concatVectors(3, &b1, &b0, &b2); Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2); - JacobianFactorUnordered combinedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); - GaussianFactorGraphUnordered::EliminationResult expected = combinedFactor.eliminate(list_of(0)); - JacobianFactorUnordered::shared_ptr expectedJacobian = boost::dynamic_pointer_cast< - JacobianFactorUnordered>(expected.second); + JacobianFactor combinedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true)); + GaussianFactorGraph::EliminationResult expected = combinedFactor.eliminate(list_of(0)); + JacobianFactor::shared_ptr expectedJacobian = boost::dynamic_pointer_cast< + JacobianFactor>(expected.second); - GaussianFactorGraphUnordered::EliminationResult actual = EliminateQRUnordered(gfg, list_of(0)); - JacobianFactorUnordered::shared_ptr actualJacobian = boost::dynamic_pointer_cast< - JacobianFactorUnordered>(actual.second); + GaussianFactorGraph::EliminationResult actual = EliminateQR(gfg, list_of(0)); + JacobianFactor::shared_ptr actualJacobian = boost::dynamic_pointer_cast< + JacobianFactor>(actual.second); EXPECT(assert_equal(*expected.first, *actual.first)); EXPECT(assert_equal(*expectedJacobian, *actualJacobian)); } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, eliminate2 ) +TEST(JacobianFactor, eliminate2 ) { // sigmas double sigma1 = 0.2; @@ -363,11 +363,11 @@ TEST(JacobianFactorUnordered, eliminate2 ) vector > meas; meas.push_back(make_pair(2, Ax2)); meas.push_back(make_pair(11, Al1x1)); - JacobianFactorUnordered combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); + JacobianFactor combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas)); // eliminate the combined factor - pair - actual = combined.eliminate(OrderingUnordered(list_of(2))); + pair + actual = combined.eliminate(Ordering(list_of(2))); // create expected Conditional Gaussian double oldSigma = 0.0894427; // from when R was made unit @@ -380,7 +380,7 @@ TEST(JacobianFactorUnordered, eliminate2 ) +0.00,-0.20,+0.00,-0.80 )/oldSigma; Vector d = Vector_(2,0.2,-0.14)/oldSigma; - GaussianConditionalUnordered expectedCG(2, d, R11, 11, S12); + GaussianConditional expectedCG(2, d, R11, 11, S12); EXPECT(assert_equal(expectedCG, *actual.first, 1e-4)); @@ -392,12 +392,12 @@ TEST(JacobianFactorUnordered, eliminate2 ) 0.00, 1.00, +0.00, -1.00 )/sigma; Vector b1 = Vector_(2, 0.0, 0.894427); - JacobianFactorUnordered expectedLF(11, Bl1x1, b1); + JacobianFactor expectedLF(11, Bl1x1, b1); EXPECT(assert_equal(expectedLF, *actual.second,1e-3)); } /* ************************************************************************* */ -TEST(JacobianFactorUnordered, EliminateQR) +TEST(JacobianFactor, EliminateQROrdered) { // Augmented Ab test case for whole factor graph Matrix Ab = Matrix_(14,11, @@ -419,11 +419,11 @@ TEST(JacobianFactorUnordered, EliminateQR) // Create factor graph const SharedDiagonal sig_4D = noiseModel::Isotropic::Sigma(4, 0.5); const SharedDiagonal sig_2D = noiseModel::Isotropic::Sigma(2, 0.5); - GaussianFactorGraphUnordered factors = list_of - (JacobianFactorUnordered(list_of(3)(5)(7)(9)(11), VerticalBlockMatrix(list_of(2)(2)(2)(2)(2)(1), Ab.block(0, 0, 4, 11)), sig_4D)) - (JacobianFactorUnordered(list_of(5)(7)(9)(11), VerticalBlockMatrix(list_of(2)(2)(2)(2)(1), Ab.block(4, 2, 4, 9)), sig_4D)) - (JacobianFactorUnordered(list_of(7)(9)(11), VerticalBlockMatrix(list_of(2)(2)(2)(1), Ab.block(8, 4, 4, 7)), sig_4D)) - (JacobianFactorUnordered(list_of(11), VerticalBlockMatrix(list_of(2)(1), Ab.block(12, 8, 2, 3)), sig_2D)); + GaussianFactorGraph factors = list_of + (JacobianFactor(list_of(3)(5)(7)(9)(11), VerticalBlockMatrix(list_of(2)(2)(2)(2)(2)(1), Ab.block(0, 0, 4, 11)), sig_4D)) + (JacobianFactor(list_of(5)(7)(9)(11), VerticalBlockMatrix(list_of(2)(2)(2)(2)(1), Ab.block(4, 2, 4, 9)), sig_4D)) + (JacobianFactor(list_of(7)(9)(11), VerticalBlockMatrix(list_of(2)(2)(2)(1), Ab.block(8, 4, 4, 7)), sig_4D)) + (JacobianFactor(list_of(11), VerticalBlockMatrix(list_of(2)(1), Ab.block(12, 8, 2, 3)), sig_2D)); // extract the dense matrix for the graph Matrix actualDense = factors.augmentedJacobian(); @@ -443,12 +443,12 @@ TEST(JacobianFactorUnordered, EliminateQR) 0., 0., 0., 0., 0., 0., 0., 0., 0., -5.7095, -0.0090, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., -7.1635); - GaussianConditionalUnordered expectedFragment( + GaussianConditional expectedFragment( list_of(3)(5)(7)(9)(11), 3, VerticalBlockMatrix(list_of(2)(2)(2)(2)(2)(1), R)); // Eliminate (3 frontal variables, 6 scalar columns) using QR !!!! - GaussianFactorGraphUnordered::EliminationResult actual = EliminateQRUnordered(factors, list_of(3)(5)(7)); - const JacobianFactorUnordered &actualJF = dynamic_cast(*actual.second); + GaussianFactorGraph::EliminationResult actual = EliminateQR(factors, list_of(3)(5)(7)); + const JacobianFactor &actualJF = dynamic_cast(*actual.second); EXPECT(assert_equal(expectedFragment, *actual.first, 0.001)); EXPECT(assert_equal(size_t(2), actualJF.keys().size())); @@ -473,14 +473,14 @@ TEST(JacobianFactorUnordered, EliminateQR) } /* ************************************************************************* */ -TEST ( JacobianFactorUnordered, constraint_eliminate1 ) +TEST ( JacobianFactor, constraint_eliminate1 ) { // construct a linear constraint Vector v(2); v(0)=1.2; v(1)=3.4; - JacobianFactorUnordered lc(1, eye(2), v, noiseModel::Constrained::All(2)); + JacobianFactor lc(1, eye(2), v, noiseModel::Constrained::All(2)); // eliminate it - pair + pair actual = lc.eliminate(list_of(1)); // verify linear factor @@ -488,12 +488,12 @@ TEST ( JacobianFactorUnordered, constraint_eliminate1 ) // verify conditional Gaussian Vector sigmas = Vector_(2, 0.0, 0.0); - GaussianConditionalUnordered expCG(1, v, eye(2), noiseModel::Diagonal::Sigmas(sigmas)); + GaussianConditional expCG(1, v, eye(2), noiseModel::Diagonal::Sigmas(sigmas)); EXPECT(assert_equal(expCG, *actual.first)); } /* ************************************************************************* */ -TEST ( JacobianFactorUnordered, constraint_eliminate2 ) +TEST ( JacobianFactor, constraint_eliminate2 ) { // Construct a linear constraint // RHS @@ -509,10 +509,10 @@ TEST ( JacobianFactorUnordered, constraint_eliminate2 ) A2(0,0) = 1.0 ; A2(0,1) = 2.0; A2(1,0) = 2.0 ; A2(1,1) = 4.0; - JacobianFactorUnordered lc(1, A1, 2, A2, b, noiseModel::Constrained::All(2)); + JacobianFactor lc(1, A1, 2, A2, b, noiseModel::Constrained::All(2)); // eliminate x and verify results - pair + pair actual = lc.eliminate(list_of(1)); // LF should be empty @@ -520,7 +520,7 @@ TEST ( JacobianFactorUnordered, constraint_eliminate2 ) Matrix m(1,2); Matrix Aempty = m.topRows(0); Vector bempty = m.block(0,0,0,1); - JacobianFactorUnordered expectedLF(2, Aempty, bempty, noiseModel::Constrained::All(0)); + JacobianFactor expectedLF(2, Aempty, bempty, noiseModel::Constrained::All(0)); EXPECT(assert_equal(expectedLF, *actual.second)); // verify CG @@ -532,7 +532,7 @@ TEST ( JacobianFactorUnordered, constraint_eliminate2 ) 0.0, 0.0); Vector d = Vector_(2, 3.0, 0.6666); Vector sigmas = Vector_(2, 0.0, 0.0); - GaussianConditionalUnordered expectedCG(1, d, R, 2, S, noiseModel::Diagonal::Sigmas(sigmas)); + GaussianConditional expectedCG(1, d, R, 2, S, noiseModel::Diagonal::Sigmas(sigmas)); EXPECT(assert_equal(expectedCG, *actual.first, 1e-4)); } diff --git a/gtsam/linear/tests/testSerializationLinear.cpp b/gtsam/linear/tests/testSerializationLinear.cpp index b258fb52e..a708137ef 100644 --- a/gtsam/linear/tests/testSerializationLinear.cpp +++ b/gtsam/linear/tests/testSerializationLinear.cpp @@ -16,11 +16,11 @@ * @date Feb 7, 2012 */ -#include -#include -#include +#include +#include +#include #include -#include +#include #include #include @@ -130,29 +130,29 @@ TEST (Serialization, SharedDiagonal_noiseModels) { /* Create GUIDs for factors */ /* ************************************************************************* */ -BOOST_CLASS_EXPORT_GUID(gtsam::JacobianFactor, "gtsam::JacobianFactor"); -BOOST_CLASS_EXPORT_GUID(gtsam::HessianFactor , "gtsam::HessianFactor"); +BOOST_CLASS_EXPORT_GUID(gtsam::JacobianFactorOrdered, "gtsam::JacobianFactor"); +BOOST_CLASS_EXPORT_GUID(gtsam::HessianFactorOrdered , "gtsam::HessianFactor"); /* ************************************************************************* */ TEST (Serialization, linear_factors) { - VectorValues values; + VectorValuesOrdered values; values.insert(0, Vector_(1, 1.0)); values.insert(1, Vector_(2, 2.0,3.0)); values.insert(2, Vector_(2, 4.0,5.0)); - EXPECT(equalsObj(values)); - EXPECT(equalsXML(values)); - EXPECT(equalsBinary(values)); + EXPECT(equalsObj(values)); + EXPECT(equalsXML(values)); + EXPECT(equalsBinary(values)); Index i1 = 4, i2 = 7; Matrix A1 = eye(3), A2 = -1.0 * eye(3); Vector b = ones(3); SharedDiagonal model = noiseModel::Diagonal::Sigmas(Vector_(3, 1.0, 2.0, 3.0)); - JacobianFactor jacobianfactor(i1, A1, i2, A2, b, model); + JacobianFactorOrdered jacobianfactor(i1, A1, i2, A2, b, model); EXPECT(equalsObj(jacobianfactor)); EXPECT(equalsXML(jacobianfactor)); EXPECT(equalsBinary(jacobianfactor)); - HessianFactor hessianfactor(jacobianfactor); + HessianFactorOrdered hessianfactor(jacobianfactor); EXPECT(equalsObj(hessianfactor)); EXPECT(equalsXML(hessianfactor)); EXPECT(equalsBinary(hessianfactor)); @@ -164,7 +164,7 @@ TEST (Serialization, gaussian_conditional) { Matrix A2 = Matrix_(2,2, 6., 0.2, 8., 0.4); Matrix R = Matrix_(2,2, 0.1, 0.3, 0.0, 0.34); Vector d(2); d << 0.2, 0.5; - GaussianConditional cg(0, d, R, 1, A1, 2, A2, ones(2)); + GaussianConditionalOrdered cg(0, d, R, 1, A1, 2, A2, ones(2)); EXPECT(equalsObj(cg)); EXPECT(equalsXML(cg)); diff --git a/gtsam/linear/tests/testVectorValuesObsolete.cpp b/gtsam/linear/tests/testVectorValuesObsolete.cpp index 8bfd42781..264c4543b 100644 --- a/gtsam/linear/tests/testVectorValuesObsolete.cpp +++ b/gtsam/linear/tests/testVectorValuesObsolete.cpp @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include @@ -28,10 +28,10 @@ using namespace boost::assign; using namespace gtsam; /* ************************************************************************* */ -TEST(VectorValues, insert) { +TEST(VectorValuesOrdered, insert) { // insert, with out-of-order indices - VectorValues actual; + VectorValuesOrdered actual; actual.insert(0, Vector_(1, 1.0)); actual.insert(1, Vector_(2, 2.0, 3.0)); actual.insert(5, Vector_(2, 6.0, 7.0)); @@ -66,13 +66,13 @@ TEST(VectorValues, insert) { } /* ************************************************************************* */ -TEST(VectorValues, dimsConstructor) { +TEST(VectorValuesOrdered, dimsConstructor) { vector dims; dims.push_back(1); dims.push_back(2); dims.push_back(2); - VectorValues actual(dims); + VectorValuesOrdered actual(dims); actual[0] = Vector_(1, 1.0); actual[1] = Vector_(2, 2.0, 3.0); actual[2] = Vector_(2, 4.0, 5.0); @@ -91,16 +91,16 @@ TEST(VectorValues, dimsConstructor) { } /* ************************************************************************* */ -TEST(VectorValues, copyConstructor) { +TEST(VectorValuesOrdered, copyConstructor) { // insert, with out-of-order indices - VectorValues original; + VectorValuesOrdered original; original.insert(0, Vector_(1, 1.0)); original.insert(1, Vector_(2, 2.0, 3.0)); original.insert(5, Vector_(2, 6.0, 7.0)); original.insert(2, Vector_(2, 4.0, 5.0)); - VectorValues actual(original); + VectorValuesOrdered actual(original); // Check dimensions LONGS_EQUAL(6, actual.size()); @@ -130,13 +130,13 @@ TEST(VectorValues, copyConstructor) { } /* ************************************************************************* */ -TEST(VectorValues, assignment) { +TEST(VectorValuesOrdered, assignment) { - VectorValues actual; + VectorValuesOrdered actual; { // insert, with out-of-order indices - VectorValues original; + VectorValuesOrdered original; original.insert(0, Vector_(1, 1.0)); original.insert(1, Vector_(2, 2.0, 3.0)); original.insert(5, Vector_(2, 6.0, 7.0)); @@ -172,15 +172,15 @@ TEST(VectorValues, assignment) { } /* ************************************************************************* */ -TEST(VectorValues, SameStructure) { +TEST(VectorValuesOrdered, SameStructure) { // insert, with out-of-order indices - VectorValues original; + VectorValuesOrdered original; original.insert(0, Vector_(1, 1.0)); original.insert(1, Vector_(2, 2.0, 3.0)); original.insert(5, Vector_(2, 6.0, 7.0)); original.insert(2, Vector_(2, 4.0, 5.0)); - VectorValues actual(VectorValues::SameStructure(original)); + VectorValuesOrdered actual(VectorValuesOrdered::SameStructure(original)); // Check dimensions LONGS_EQUAL(6, actual.size()); @@ -203,15 +203,15 @@ TEST(VectorValues, SameStructure) { } /* ************************************************************************* */ -TEST(VectorValues, Zero_fromModel) { +TEST(VectorValuesOrdered, Zero_fromModel) { // insert, with out-of-order indices - VectorValues original; + VectorValuesOrdered original; original.insert(0, Vector_(1, 1.0)); original.insert(1, Vector_(2, 2.0, 3.0)); original.insert(5, Vector_(2, 6.0, 7.0)); original.insert(2, Vector_(2, 4.0, 5.0)); - VectorValues actual(VectorValues::Zero(original)); + VectorValuesOrdered actual(VectorValuesOrdered::Zero(original)); // Check dimensions LONGS_EQUAL(6, actual.size()); @@ -240,13 +240,13 @@ TEST(VectorValues, Zero_fromModel) { } /* ************************************************************************* */ -TEST(VectorValues, Zero_fromDims) { +TEST(VectorValuesOrdered, Zero_fromDims) { vector dims; dims.push_back(1); dims.push_back(2); dims.push_back(2); - VectorValues actual(VectorValues::Zero(dims)); + VectorValuesOrdered actual(VectorValuesOrdered::Zero(dims)); // Check dimensions LONGS_EQUAL(3, actual.size()); @@ -261,8 +261,8 @@ TEST(VectorValues, Zero_fromDims) { } /* ************************************************************************* */ -TEST(VectorValues, Zero_fromUniform) { - VectorValues actual(VectorValues::Zero(3, 2)); +TEST(VectorValuesOrdered, Zero_fromUniform) { + VectorValuesOrdered actual(VectorValuesOrdered::Zero(3, 2)); // Check dimensions LONGS_EQUAL(3, actual.size()); @@ -277,15 +277,15 @@ TEST(VectorValues, Zero_fromUniform) { } /* ************************************************************************* */ -TEST(VectorValues, resizeLike) { +TEST(VectorValuesOrdered, resizeLike) { // insert, with out-of-order indices - VectorValues original; + VectorValuesOrdered original; original.insert(0, Vector_(1, 1.0)); original.insert(1, Vector_(2, 2.0, 3.0)); original.insert(5, Vector_(2, 6.0, 7.0)); original.insert(2, Vector_(2, 4.0, 5.0)); - VectorValues actual(10, 3); + VectorValuesOrdered actual(10, 3); actual.resizeLike(original); // Check dimensions @@ -309,8 +309,8 @@ TEST(VectorValues, resizeLike) { } /* ************************************************************************* */ -TEST(VectorValues, resize_fromUniform) { - VectorValues actual(4, 10); +TEST(VectorValuesOrdered, resize_fromUniform) { + VectorValuesOrdered actual(4, 10); actual.resize(3, 2); actual[0] = Vector_(2, 1.0, 2.0); @@ -331,13 +331,13 @@ TEST(VectorValues, resize_fromUniform) { } /* ************************************************************************* */ -TEST(VectorValues, resize_fromDims) { +TEST(VectorValuesOrdered, resize_fromDims) { vector dims; dims.push_back(1); dims.push_back(2); dims.push_back(2); - VectorValues actual(4, 10); + VectorValuesOrdered actual(4, 10); actual.resize(dims); actual[0] = Vector_(1, 1.0); actual[1] = Vector_(2, 2.0, 3.0); @@ -357,9 +357,9 @@ TEST(VectorValues, resize_fromDims) { } /* ************************************************************************* */ -TEST(VectorValues, append) { +TEST(VectorValuesOrdered, append) { // insert - VectorValues actual; + VectorValuesOrdered actual; actual.insert(0, Vector_(1, 1.0)); actual.insert(1, Vector_(2, 2.0, 3.0)); actual.insert(2, Vector_(2, 4.0, 5.0)); @@ -396,30 +396,30 @@ TEST(VectorValues, append) { } /* ************************************************************************* */ -TEST(VectorValues, hasSameStructure) { - VectorValues v1(2, 3); - VectorValues v2(3, 2); - VectorValues v3(4, 2); - VectorValues v4(4, 2); +TEST(VectorValuesOrdered, hasSameStructure) { + VectorValuesOrdered v1(2, 3); + VectorValuesOrdered v2(3, 2); + VectorValuesOrdered v3(4, 2); + VectorValuesOrdered v4(4, 2); EXPECT(!v1.hasSameStructure(v2)); EXPECT(!v2.hasSameStructure(v3)); EXPECT(v3.hasSameStructure(v4)); - EXPECT(VectorValues().hasSameStructure(VectorValues())); - EXPECT(!v1.hasSameStructure(VectorValues())); + EXPECT(VectorValuesOrdered().hasSameStructure(VectorValuesOrdered())); + EXPECT(!v1.hasSameStructure(VectorValuesOrdered())); } /* ************************************************************************* */ -TEST(VectorValues, permute) { +TEST(VectorValuesOrdered, permute) { - VectorValues original; + VectorValuesOrdered original; original.insert(0, Vector_(1, 1.0)); original.insert(1, Vector_(2, 2.0, 3.0)); original.insert(2, Vector_(2, 4.0, 5.0)); original.insert(3, Vector_(2, 6.0, 7.0)); - VectorValues expected; + VectorValuesOrdered expected; expected.insert(0, Vector_(2, 4.0, 5.0)); // from 2 expected.insert(1, Vector_(1, 1.0)); // from 0 expected.insert(2, Vector_(2, 6.0, 7.0)); // from 3 @@ -431,15 +431,15 @@ TEST(VectorValues, permute) { permutation[2] = 3; permutation[3] = 1; - VectorValues actual = original; + VectorValuesOrdered actual = original; actual.permuteInPlace(permutation); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST(VectorValues, subvector) { - VectorValues init; +TEST(VectorValuesOrdered, subvector) { + VectorValuesOrdered init; init.insert(0, Vector_(1, 1.0)); init.insert(1, Vector_(2, 2.0, 3.0)); init.insert(2, Vector_(2, 4.0, 5.0)); diff --git a/gtsam/linear/tests/testVectorValuesUnordered.cpp b/gtsam/linear/tests/testVectorValuesUnordered.cpp index dd988217c..393985651 100644 --- a/gtsam/linear/tests/testVectorValuesUnordered.cpp +++ b/gtsam/linear/tests/testVectorValuesUnordered.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include @@ -27,12 +27,12 @@ using namespace boost::assign; using namespace gtsam; /* ************************************************************************* */ -TEST(VectorValuesUnordered, basics) +TEST(VectorValues, basics) { // Tests insert(), size(), dim(), exists(), vector() // insert - VectorValuesUnordered actual; + VectorValues actual; actual.insert(0, Vector_(1, 1.0)); actual.insert(1, Vector_(2, 2.0, 3.0)); actual.insert(5, Vector_(2, 6.0, 7.0)); @@ -67,31 +67,31 @@ TEST(VectorValuesUnordered, basics) } /* ************************************************************************* */ -TEST(VectorValuesUnordered, combine) +TEST(VectorValues, combine) { - VectorValuesUnordered expected; + VectorValues expected; expected.insert(0, Vector_(1, 1.0)); expected.insert(1, Vector_(2, 2.0, 3.0)); expected.insert(5, Vector_(2, 6.0, 7.0)); expected.insert(2, Vector_(2, 4.0, 5.0)); - VectorValuesUnordered first; + VectorValues first; first.insert(0, Vector_(1, 1.0)); first.insert(1, Vector_(2, 2.0, 3.0)); - VectorValuesUnordered second; + VectorValues second; second.insert(5, Vector_(2, 6.0, 7.0)); second.insert(2, Vector_(2, 4.0, 5.0)); - VectorValuesUnordered actual(first, second); + VectorValues actual(first, second); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST(VectorValuesUnordered, subvector) +TEST(VectorValues, subvector) { - VectorValuesUnordered init; + VectorValues init; init.insert(10, Vector_(1, 1.0)); init.insert(11, Vector_(2, 2.0, 3.0)); init.insert(12, Vector_(2, 4.0, 5.0)); @@ -104,15 +104,15 @@ TEST(VectorValuesUnordered, subvector) } /* ************************************************************************* */ -TEST(VectorValuesUnordered, LinearAlgebra) +TEST(VectorValues, LinearAlgebra) { - VectorValuesUnordered test1; + VectorValues test1; test1.insert(0, Vector_(1, 1.0)); test1.insert(1, Vector_(2, 2.0, 3.0)); test1.insert(5, Vector_(2, 6.0, 7.0)); test1.insert(2, Vector_(2, 4.0, 5.0)); - VectorValuesUnordered test2; + VectorValues test2; test2.insert(0, Vector_(1, 6.0)); test2.insert(1, Vector_(2, 1.0, 6.0)); test2.insert(5, Vector_(2, 4.0, 3.0)); @@ -135,23 +135,23 @@ TEST(VectorValuesUnordered, LinearAlgebra) // Addition Vector sumExpected = test1.vector() + test2.vector(); - VectorValuesUnordered sumActual = test1 + test2; + VectorValues sumActual = test1 + test2; EXPECT(sumActual.hasSameStructure(test1)); EXPECT(assert_equal(sumExpected, sumActual.vector())); Vector sum2Expected = sumActual.vector() + test1.vector(); - VectorValuesUnordered sum2Actual = sumActual; + VectorValues sum2Actual = sumActual; sum2Actual += test1; EXPECT(assert_equal(sum2Expected, sum2Actual.vector())); // Subtraction Vector difExpected = test1.vector() - test2.vector(); - VectorValuesUnordered difActual = test1 - test2; + VectorValues difActual = test1 - test2; EXPECT(difActual.hasSameStructure(test1)); EXPECT(assert_equal(difExpected, difActual.vector())); // Scaling Vector scalExpected = test1.vector() * 5.0; - VectorValuesUnordered scalActual = test1; + VectorValues scalActual = test1; scalActual *= 5.0; EXPECT(assert_equal(scalExpected, scalActual.vector())); } diff --git a/gtsam/linear/tests/timeFactorOverhead.cpp b/gtsam/linear/tests/timeFactorOverhead.cpp index 6e5d6b9ad..dc7f17917 100644 --- a/gtsam/linear/tests/timeFactorOverhead.cpp +++ b/gtsam/linear/tests/timeFactorOverhead.cpp @@ -16,9 +16,9 @@ * @date Aug 20, 2010 */ -#include +#include #include -#include +#include #include #include @@ -27,7 +27,7 @@ using namespace gtsam; using namespace std; -typedef EliminationTree GaussianEliminationTree; +typedef EliminationTreeOrdered GaussianEliminationTree; static boost::variate_generator > rg(boost::mt19937(), boost::uniform_real<>(0.0, 1.0)); @@ -56,10 +56,10 @@ int main(int argc, char *argv[]) { cout.flush(); boost::timer timer; timer.restart(); - vector blockGfgs; + vector blockGfgs; blockGfgs.reserve(nTrials); for(size_t trial=0; trialeliminate(&EliminateQR)); - VectorValues soln(optimize(*gbn)); + GaussianBayesNetOrdered::shared_ptr gbn(GaussianEliminationTree::Create(blockGfgs[trial])->eliminate(&EliminateQROrdered)); + VectorValuesOrdered soln(optimize(*gbn)); } blocksolve = timer.elapsed(); cout << blocksolve << " s" << endl; @@ -99,9 +99,9 @@ int main(int argc, char *argv[]) { cout.flush(); boost::timer timer; timer.restart(); - vector combGfgs; + vector combGfgs; for(size_t trial=0; trialeliminate(&EliminateQR)); - VectorValues soln(optimize(*gbn)); + GaussianBayesNetOrdered::shared_ptr gbn(GaussianEliminationTree::Create(combGfgs[trial])->eliminate(&EliminateQROrdered)); + VectorValuesOrdered soln(optimize(*gbn)); } combsolve = timer.elapsed(); cout << combsolve << " s" << endl; diff --git a/gtsam/linear/tests/timeGaussianFactor.cpp b/gtsam/linear/tests/timeGaussianFactor.cpp index 3938abc8b..8f6f440a4 100644 --- a/gtsam/linear/tests/timeGaussianFactor.cpp +++ b/gtsam/linear/tests/timeGaussianFactor.cpp @@ -25,9 +25,9 @@ using namespace std; #include // for operator += in Ordering #include -#include -#include -#include +#include +#include +#include #include using namespace gtsam; @@ -101,14 +101,14 @@ int main() b2(7) = -1; // time eliminate - JacobianFactor combined(_x2_, Ax2, _l1_, Al1, _x1_, Ax1, b2, noiseModel::Isotropic::Sigma(8,1)); + JacobianFactorOrdered combined(_x2_, Ax2, _l1_, Al1, _x1_, Ax1, b2, noiseModel::Isotropic::Sigma(8,1)); long timeLog = clock(); int n = 1000000; - GaussianConditional::shared_ptr conditional; - JacobianFactor::shared_ptr factor; + GaussianConditionalOrdered::shared_ptr conditional; + JacobianFactorOrdered::shared_ptr factor; for(int i = 0; i < n; i++) - conditional = JacobianFactor(combined).eliminateFirst(); + conditional = JacobianFactorOrdered(combined).eliminateFirst(); long timeLog2 = clock(); double seconds = (double)(timeLog2-timeLog)/CLOCKS_PER_SEC; diff --git a/gtsam/linear/tests/timeSLAMlike.cpp b/gtsam/linear/tests/timeSLAMlike.cpp index 340e16a79..820282d25 100644 --- a/gtsam/linear/tests/timeSLAMlike.cpp +++ b/gtsam/linear/tests/timeSLAMlike.cpp @@ -16,7 +16,7 @@ * @date Aug 30, 2010 */ -#include +#include #include #include #include @@ -31,7 +31,7 @@ using namespace gtsam; using namespace std; using namespace boost::lambda; -typedef EliminationTree GaussianEliminationTree; +typedef EliminationTreeOrdered GaussianEliminationTree; static boost::variate_generator > rg(boost::mt19937(), boost::uniform_real<>(0.0, 1.0)); @@ -65,10 +65,10 @@ int main(int argc, char *argv[]) { cout.flush(); boost::timer timer; timer.restart(); - vector blockGfgs; + vector blockGfgs; blockGfgs.reserve(nTrials); for(size_t trial=0; trial -#include -#include +#include +#include #include #include @@ -53,8 +53,8 @@ std::string DoglegParams::verbosityDLTranslator(VerbosityDL verbosityDL) const { void DoglegOptimizer::iterate(void) { // Linearize graph - const Ordering& ordering = *params_.ordering; - GaussianFactorGraph::shared_ptr linear = graph_.linearize(state_.values, ordering); + const OrderingOrdered& ordering = *params_.ordering; + GaussianFactorGraphOrdered::shared_ptr linear = graph_.linearize(state_.values, ordering); // Pull out parameters we'll use const bool dlVerbose = (params_.verbosityDL > DoglegParams::SILENT); @@ -63,12 +63,12 @@ void DoglegOptimizer::iterate(void) { DoglegOptimizerImpl::IterationResult result; if ( params_.isMultifrontal() ) { - GaussianBayesTree bt; - bt.insert(GaussianJunctionTree(*linear).eliminate(params_.getEliminationFunction())); + GaussianBayesTreeOrdered bt; + bt.insert(GaussianJunctionTreeOrdered(*linear).eliminate(params_.getEliminationFunction())); result = DoglegOptimizerImpl::Iterate(state_.Delta, DoglegOptimizerImpl::ONE_STEP_PER_ITERATION, bt, graph_, state_.values, ordering, state_.error, dlVerbose); } else if ( params_.isSequential() ) { - GaussianBayesNet::shared_ptr bn = EliminationTree::Create(*linear)->eliminate(params_.getEliminationFunction()); + GaussianBayesNetOrdered::shared_ptr bn = EliminationTreeOrdered::Create(*linear)->eliminate(params_.getEliminationFunction()); result = DoglegOptimizerImpl::Iterate(state_.Delta, DoglegOptimizerImpl::ONE_STEP_PER_ITERATION, *bn, graph_, state_.values, ordering, state_.error, dlVerbose); } else if ( params_.isCG() ) { diff --git a/gtsam/nonlinear/DoglegOptimizer.h b/gtsam/nonlinear/DoglegOptimizer.h index 86a8b5570..ffd0b0d8a 100644 --- a/gtsam/nonlinear/DoglegOptimizer.h +++ b/gtsam/nonlinear/DoglegOptimizer.h @@ -114,7 +114,7 @@ public: * @param graph The nonlinear factor graph to optimize * @param initialValues The initial variable assignments */ - DoglegOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const Ordering& ordering) : + DoglegOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const OrderingOrdered& ordering) : NonlinearOptimizer(graph) { params_.ordering = ordering; state_ = DoglegState(graph, initialValues, params_); } diff --git a/gtsam/nonlinear/DoglegOptimizerImpl.cpp b/gtsam/nonlinear/DoglegOptimizerImpl.cpp index 671dfe8f8..894c41ffa 100644 --- a/gtsam/nonlinear/DoglegOptimizerImpl.cpp +++ b/gtsam/nonlinear/DoglegOptimizerImpl.cpp @@ -22,8 +22,8 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ -VectorValues DoglegOptimizerImpl::ComputeDoglegPoint( - double Delta, const VectorValues& dx_u, const VectorValues& dx_n, const bool verbose) { +VectorValuesOrdered DoglegOptimizerImpl::ComputeDoglegPoint( + double Delta, const VectorValuesOrdered& dx_u, const VectorValuesOrdered& dx_n, const bool verbose) { // Get magnitude of each update and find out which segment Delta falls in assert(Delta >= 0.0); @@ -33,7 +33,7 @@ VectorValues DoglegOptimizerImpl::ComputeDoglegPoint( if(verbose) cout << "Steepest descent magnitude " << std::sqrt(x_u_norm_sq) << ", Newton's method magnitude " << std::sqrt(x_n_norm_sq) << endl; if(DeltaSq < x_u_norm_sq) { // Trust region is smaller than steepest descent update - VectorValues x_d = std::sqrt(DeltaSq / x_u_norm_sq) * dx_u; + VectorValuesOrdered x_d = std::sqrt(DeltaSq / x_u_norm_sq) * dx_u; if(verbose) cout << "In steepest descent region with fraction " << std::sqrt(DeltaSq / x_u_norm_sq) << " of steepest descent magnitude" << endl; return x_d; } else if(DeltaSq < x_n_norm_sq) { @@ -48,7 +48,7 @@ VectorValues DoglegOptimizerImpl::ComputeDoglegPoint( } /* ************************************************************************* */ -VectorValues DoglegOptimizerImpl::ComputeBlend(double Delta, const VectorValues& x_u, const VectorValues& x_n, const bool verbose) { +VectorValuesOrdered DoglegOptimizerImpl::ComputeBlend(double Delta, const VectorValuesOrdered& x_u, const VectorValuesOrdered& x_n, const bool verbose) { // See doc/trustregion.lyx or doc/trustregion.pdf @@ -78,7 +78,7 @@ VectorValues DoglegOptimizerImpl::ComputeBlend(double Delta, const VectorValues& // Compute blended point if(verbose) cout << "In blend region with fraction " << tau << " of Newton's method point" << endl; - VectorValues blend = (1. - tau) * x_u; axpy(tau, x_n, blend); + VectorValuesOrdered blend = (1. - tau) * x_u; axpy(tau, x_n, blend); return blend; } diff --git a/gtsam/nonlinear/DoglegOptimizerImpl.h b/gtsam/nonlinear/DoglegOptimizerImpl.h index ae659f092..e992776a1 100644 --- a/gtsam/nonlinear/DoglegOptimizerImpl.h +++ b/gtsam/nonlinear/DoglegOptimizerImpl.h @@ -18,10 +18,10 @@ #include -#include -#include // To get optimize(BayesTree) +#include +#include // To get optimize(BayesTree) //#include -#include +#include namespace gtsam { @@ -42,7 +42,7 @@ struct GTSAM_EXPORT DoglegOptimizerImpl { struct GTSAM_EXPORT IterationResult { double Delta; - VectorValues dx_d; + VectorValuesOrdered dx_d; double f_error; }; @@ -103,7 +103,7 @@ struct GTSAM_EXPORT DoglegOptimizerImpl { template static IterationResult Iterate( double Delta, TrustRegionAdaptationMode mode, const M& Rd, - const F& f, const VALUES& x0, const Ordering& ordering, const double f_error, const bool verbose=false); + const F& f, const VALUES& x0, const OrderingOrdered& ordering, const double f_error, const bool verbose=false); /** * Compute the dogleg point given a trust region radius \f$ \Delta \f$. The @@ -127,7 +127,7 @@ struct GTSAM_EXPORT DoglegOptimizerImpl { * @param dx_n The Gauss-Newton point * @return The dogleg point \f$ \delta x_d \f$ */ - static VectorValues ComputeDoglegPoint(double Delta, const VectorValues& dx_u, const VectorValues& dx_n, const bool verbose=false); + static VectorValuesOrdered ComputeDoglegPoint(double Delta, const VectorValuesOrdered& dx_u, const VectorValuesOrdered& dx_n, const bool verbose=false); /** Compute the point on the line between the steepest descent point and the * Newton's method point intersecting the trust region boundary. @@ -138,7 +138,7 @@ struct GTSAM_EXPORT DoglegOptimizerImpl { * @param x_u Steepest descent minimizer * @param x_n Newton's method minimizer */ - static VectorValues ComputeBlend(double Delta, const VectorValues& x_u, const VectorValues& x_n, const bool verbose=false); + static VectorValuesOrdered ComputeBlend(double Delta, const VectorValuesOrdered& x_u, const VectorValuesOrdered& x_n, const bool verbose=false); }; @@ -146,24 +146,24 @@ struct GTSAM_EXPORT DoglegOptimizerImpl { template typename DoglegOptimizerImpl::IterationResult DoglegOptimizerImpl::Iterate( double Delta, TrustRegionAdaptationMode mode, const M& Rd, - const F& f, const VALUES& x0, const Ordering& ordering, const double f_error, const bool verbose) { + const F& f, const VALUES& x0, const OrderingOrdered& ordering, const double f_error, const bool verbose) { // Compute steepest descent and Newton's method points gttic(optimizeGradientSearch); gttic(allocateVectorValues); - VectorValues dx_u = *allocateVectorValues(Rd); + VectorValuesOrdered dx_u = *allocateVectorValues(Rd); gttoc(allocateVectorValues); gttic(optimizeGradientSearchInPlace); optimizeGradientSearchInPlace(Rd, dx_u); gttoc(optimizeGradientSearchInPlace); gttoc(optimizeGradientSearch); gttic(optimizeInPlace); - VectorValues dx_n(VectorValues::SameStructure(dx_u)); + VectorValuesOrdered dx_n(VectorValuesOrdered::SameStructure(dx_u)); optimizeInPlace(Rd, dx_n); gttoc(optimizeInPlace); gttic(jfg_error); - const GaussianFactorGraph jfg(Rd); - const double M_error = jfg.error(VectorValues::Zero(dx_u)); + const GaussianFactorGraphOrdered jfg(Rd); + const double M_error = jfg.error(VectorValuesOrdered::Zero(dx_u)); gttoc(jfg_error); // Result to return diff --git a/gtsam/nonlinear/ExtendedKalmanFilter-inl.h b/gtsam/nonlinear/ExtendedKalmanFilter-inl.h index e56bc3cda..ba659914c 100644 --- a/gtsam/nonlinear/ExtendedKalmanFilter-inl.h +++ b/gtsam/nonlinear/ExtendedKalmanFilter-inl.h @@ -21,17 +21,17 @@ #include #include #include -#include -#include +#include +#include namespace gtsam { /* ************************************************************************* */ template typename ExtendedKalmanFilter::T ExtendedKalmanFilter::solve_( - const GaussianFactorGraph& linearFactorGraph, const Ordering& ordering, + const GaussianFactorGraphOrdered& linearFactorGraph, const OrderingOrdered& ordering, const Values& linearizationPoints, Key lastKey, - JacobianFactor::shared_ptr& newPrior) const { + JacobianFactorOrdered::shared_ptr& newPrior) const { // Extract the Index of the provided last key gtsam::Index lastIndex = ordering.at(lastKey); @@ -39,23 +39,23 @@ namespace gtsam { // Solve the linear factor graph, converting it into a linear Bayes Network // P(x0,x1) = P(x0|x1)*P(x1) GaussianSequentialSolver solver(linearFactorGraph); - GaussianBayesNet::shared_ptr linearBayesNet = solver.eliminate(); + GaussianBayesNetOrdered::shared_ptr linearBayesNet = solver.eliminate(); // Extract the current estimate of x1,P1 from the Bayes Network - VectorValues result = optimize(*linearBayesNet); + VectorValuesOrdered result = optimize(*linearBayesNet); T x = linearizationPoints.at(lastKey).retract(result[lastIndex]); // Create a Jacobian Factor from the root node of the produced Bayes Net. // This will act as a prior for the next iteration. // The linearization point of this prior must be moved to the new estimate of x, // and the key/index needs to be reset to 0, the first key in the next iteration. - const GaussianConditional::shared_ptr& cg = linearBayesNet->back(); + const GaussianConditionalOrdered::shared_ptr& cg = linearBayesNet->back(); assert(cg->nrFrontals() == 1); assert(cg->nrParents() == 0); // TODO: Find a way to create the correct Jacobian Factor in a single pass - JacobianFactor tmpPrior = JacobianFactor(*cg); - newPrior = JacobianFactor::shared_ptr( - new JacobianFactor( + JacobianFactorOrdered tmpPrior = JacobianFactorOrdered(*cg); + newPrior = JacobianFactorOrdered::shared_ptr( + new JacobianFactorOrdered( 0, tmpPrior.getA(tmpPrior.begin()), tmpPrior.getb() @@ -76,8 +76,8 @@ namespace gtsam { // Create a Jacobian Prior Factor directly P_initial. // Since x0 is set to the provided mean, the b vector in the prior will be zero // TODO Frank asks: is there a reason why noiseModel is not simply P_initial ? - priorFactor_ = JacobianFactor::shared_ptr( - new JacobianFactor(0, P_initial->R(), Vector::Zero(x_initial.dim()), + priorFactor_ = JacobianFactorOrdered::shared_ptr( + new JacobianFactorOrdered(0, P_initial->R(), Vector::Zero(x_initial.dim()), noiseModel::Unit::Create(P_initial->dim()))); } @@ -95,7 +95,7 @@ namespace gtsam { Key x1 = motionFactor.key2(); // Create an elimination ordering - Ordering ordering; + OrderingOrdered ordering; ordering.insert(x0, 0); ordering.insert(x1, 1); @@ -105,7 +105,7 @@ namespace gtsam { linearizationPoints.insert(x1, x_); // TODO should this really be x_ ? // Create a Gaussian Factor Graph - GaussianFactorGraph linearFactorGraph; + GaussianFactorGraphOrdered linearFactorGraph; // Add in previous posterior as prior on the first state linearFactorGraph.push_back(priorFactor_); @@ -134,7 +134,7 @@ namespace gtsam { Key x0 = measurementFactor.key(); // Create an elimination ordering - Ordering ordering; + OrderingOrdered ordering; ordering.insert(x0, 0); // Create a set of linearization points @@ -142,7 +142,7 @@ namespace gtsam { linearizationPoints.insert(x0, x_); // Create a Gaussian Factor Graph - GaussianFactorGraph linearFactorGraph; + GaussianFactorGraphOrdered linearFactorGraph; // Add in the prior on the first state linearFactorGraph.push_back(priorFactor_); diff --git a/gtsam/nonlinear/ExtendedKalmanFilter.h b/gtsam/nonlinear/ExtendedKalmanFilter.h index a71a5332a..a0ab1a327 100644 --- a/gtsam/nonlinear/ExtendedKalmanFilter.h +++ b/gtsam/nonlinear/ExtendedKalmanFilter.h @@ -51,11 +51,11 @@ namespace gtsam { protected: T x_; // linearization point - JacobianFactor::shared_ptr priorFactor_; // density + JacobianFactorOrdered::shared_ptr priorFactor_; // density - T solve_(const GaussianFactorGraph& linearFactorGraph, - const Ordering& ordering, const Values& linearizationPoints, - Key x, JacobianFactor::shared_ptr& newPrior) const; + T solve_(const GaussianFactorGraphOrdered& linearFactorGraph, + const OrderingOrdered& ordering, const Values& linearizationPoints, + Key x, JacobianFactorOrdered::shared_ptr& newPrior) const; public: diff --git a/gtsam/nonlinear/GaussNewtonOptimizer.cpp b/gtsam/nonlinear/GaussNewtonOptimizer.cpp index 06e9ab148..e33e0b8be 100644 --- a/gtsam/nonlinear/GaussNewtonOptimizer.cpp +++ b/gtsam/nonlinear/GaussNewtonOptimizer.cpp @@ -28,10 +28,10 @@ void GaussNewtonOptimizer::iterate() { const NonlinearOptimizerState& current = state_; // Linearize graph - GaussianFactorGraph::shared_ptr linear = graph_.linearize(current.values, *params_.ordering); + GaussianFactorGraphOrdered::shared_ptr linear = graph_.linearize(current.values, *params_.ordering); // Solve Factor Graph - const VectorValues delta = solveGaussianFactorGraph(*linear, params_); + const VectorValuesOrdered delta = solveGaussianFactorGraph(*linear, params_); // Maybe show output if(params_.verbosity >= NonlinearOptimizerParams::DELTA) delta.print("delta"); diff --git a/gtsam/nonlinear/GaussNewtonOptimizer.h b/gtsam/nonlinear/GaussNewtonOptimizer.h index 67daf7305..091a4be89 100644 --- a/gtsam/nonlinear/GaussNewtonOptimizer.h +++ b/gtsam/nonlinear/GaussNewtonOptimizer.h @@ -70,7 +70,7 @@ public: * @param graph The nonlinear factor graph to optimize * @param initialValues The initial variable assignments */ - GaussNewtonOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const Ordering& ordering) : + GaussNewtonOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const OrderingOrdered& ordering) : NonlinearOptimizer(graph), state_(graph, initialValues) { params_.ordering = ordering; } diff --git a/gtsam/nonlinear/ISAM2-impl.cpp b/gtsam/nonlinear/ISAM2-impl.cpp index 9abd62016..25210063b 100644 --- a/gtsam/nonlinear/ISAM2-impl.cpp +++ b/gtsam/nonlinear/ISAM2-impl.cpp @@ -29,9 +29,9 @@ namespace gtsam { /* ************************************************************************* */ void ISAM2::Impl::AddVariables( - const Values& newTheta, Values& theta, VectorValues& delta, - VectorValues& deltaNewton, VectorValues& RgProd, vector& replacedKeys, - Ordering& ordering, const KeyFormatter& keyFormatter) { + const Values& newTheta, Values& theta, VectorValuesOrdered& delta, + VectorValuesOrdered& deltaNewton, VectorValuesOrdered& RgProd, vector& replacedKeys, + OrderingOrdered& ordering, const KeyFormatter& keyFormatter) { const bool debug = ISDEBUG("ISAM2 AddVariables"); theta.insert(newTheta); @@ -62,10 +62,10 @@ void ISAM2::Impl::AddVariables( /* ************************************************************************* */ void ISAM2::Impl::RemoveVariables(const FastSet& unusedKeys, const ISAM2Clique::shared_ptr& root, - Values& theta, VariableIndex& variableIndex, - VectorValues& delta, VectorValues& deltaNewton, VectorValues& RgProd, - std::vector& replacedKeys, Ordering& ordering, Base::Nodes& nodes, - GaussianFactorGraph& linearFactors, FastSet& fixedVariables) { + Values& theta, VariableIndexOrdered& variableIndex, + VectorValuesOrdered& delta, VectorValuesOrdered& deltaNewton, VectorValuesOrdered& RgProd, + std::vector& replacedKeys, OrderingOrdered& ordering, Base::Nodes& nodes, + GaussianFactorGraphOrdered& linearFactors, FastSet& fixedVariables) { // Get indices of unused keys vector unusedIndices; unusedIndices.reserve(unusedKeys.size()); @@ -91,9 +91,9 @@ void ISAM2::Impl::RemoveVariables(const FastSet& unusedKeys, const ISAM2Cli // Copy from the old data structures to new ones, only iterating up to // the number of used variables, and applying the unusedToEnd permutation // in order to remove the unused variables. - VectorValues newDelta(dims); - VectorValues newDeltaNewton(dims); - VectorValues newDeltaGradSearch(dims); + VectorValuesOrdered newDelta(dims); + VectorValuesOrdered newDeltaNewton(dims); + VectorValuesOrdered newDeltaGradSearch(dims); std::vector newReplacedKeys(replacedKeys.size() - unusedIndices.size()); Base::Nodes newNodes(replacedKeys.size() - unusedIndices.size()); @@ -116,7 +116,7 @@ void ISAM2::Impl::RemoveVariables(const FastSet& unusedKeys, const ISAM2Cli // Reorder and remove from ordering, solution, and fixed keys ordering.permuteInPlace(unusedToEnd); BOOST_REVERSE_FOREACH(Key key, unusedKeys) { - Ordering::value_type removed = ordering.pop_back(); + OrderingOrdered::value_type removed = ordering.pop_back(); assert(removed.first == key); theta.erase(key); fixedVariables.erase(key); @@ -129,7 +129,7 @@ void ISAM2::Impl::RemoveVariables(const FastSet& unusedKeys, const ISAM2Cli } /* ************************************************************************* */ -FastSet ISAM2::Impl::IndicesFromFactors(const Ordering& ordering, const NonlinearFactorGraph& factors) { +FastSet ISAM2::Impl::IndicesFromFactors(const OrderingOrdered& ordering, const NonlinearFactorGraph& factors) { FastSet indices; BOOST_FOREACH(const NonlinearFactor::shared_ptr& factor, factors) { BOOST_FOREACH(Key key, factor->keys()) { @@ -140,7 +140,7 @@ FastSet ISAM2::Impl::IndicesFromFactors(const Ordering& ordering, const N } /* ************************************************************************* */ -FastSet ISAM2::Impl::CheckRelinearizationFull(const VectorValues& delta, const Ordering& ordering, +FastSet ISAM2::Impl::CheckRelinearizationFull(const VectorValuesOrdered& delta, const OrderingOrdered& ordering, const ISAM2Params::RelinearizationThreshold& relinearizeThreshold, const KeyFormatter& keyFormatter) { FastSet relinKeys; @@ -154,7 +154,7 @@ FastSet ISAM2::Impl::CheckRelinearizationFull(const VectorValues& delta, } } else if(relinearizeThreshold.type() == typeid(FastMap)) { const FastMap& thresholds = boost::get >(relinearizeThreshold); - BOOST_FOREACH(const Ordering::value_type& key_index, ordering) { + BOOST_FOREACH(const OrderingOrdered::value_type& key_index, ordering) { const Vector& threshold = thresholds.find(Symbol(key_index.first).chr())->second; Index j = key_index.second; if(threshold.rows() != delta[j].rows()) @@ -168,7 +168,7 @@ FastSet ISAM2::Impl::CheckRelinearizationFull(const VectorValues& delta, } /* ************************************************************************* */ -void CheckRelinearizationRecursiveDouble(FastSet& relinKeys, double threshold, const VectorValues& delta, const ISAM2Clique::shared_ptr& clique) { +void CheckRelinearizationRecursiveDouble(FastSet& relinKeys, double threshold, const VectorValuesOrdered& delta, const ISAM2Clique::shared_ptr& clique) { // Check the current clique for relinearization bool relinearize = false; @@ -189,7 +189,7 @@ void CheckRelinearizationRecursiveDouble(FastSet& relinKeys, double thres } /* ************************************************************************* */ -void CheckRelinearizationRecursiveMap(FastSet& relinKeys, const FastMap& thresholds, const VectorValues& delta, const Ordering& ordering, const ISAM2Clique::shared_ptr& clique) { +void CheckRelinearizationRecursiveMap(FastSet& relinKeys, const FastMap& thresholds, const VectorValuesOrdered& delta, const OrderingOrdered& ordering, const ISAM2Clique::shared_ptr& clique) { // Check the current clique for relinearization bool relinearize = false; @@ -221,7 +221,7 @@ void CheckRelinearizationRecursiveMap(FastSet& relinKeys, const FastMap ISAM2::Impl::CheckRelinearizationPartial(const ISAM2Clique::shared_ptr& root, const VectorValues& delta, const Ordering& ordering, +FastSet ISAM2::Impl::CheckRelinearizationPartial(const ISAM2Clique::shared_ptr& root, const VectorValuesOrdered& delta, const OrderingOrdered& ordering, const ISAM2Params::RelinearizationThreshold& relinearizeThreshold, const KeyFormatter& keyFormatter) { FastSet relinKeys; @@ -258,8 +258,8 @@ void ISAM2::Impl::FindAll(ISAM2Clique::shared_ptr clique, FastSet& keys, } /* ************************************************************************* */ -void ISAM2::Impl::ExpmapMasked(Values& values, const VectorValues& delta, const Ordering& ordering, - const vector& mask, boost::optional invalidateIfDebug, const KeyFormatter& keyFormatter) { +void ISAM2::Impl::ExpmapMasked(Values& values, const VectorValuesOrdered& delta, const OrderingOrdered& ordering, + const vector& mask, boost::optional invalidateIfDebug, const KeyFormatter& keyFormatter) { // If debugging, invalidate if requested, otherwise do not invalidate. // Invalidating means setting expmapped entries to Inf, to trigger assertions // if we try to re-use them. @@ -270,7 +270,7 @@ void ISAM2::Impl::ExpmapMasked(Values& values, const VectorValues& delta, const assert(values.size() == ordering.size()); assert(delta.size() == ordering.size()); Values::iterator key_value; - Ordering::const_iterator key_index; + OrderingOrdered::const_iterator key_index; for(key_value = values.begin(), key_index = ordering.begin(); key_value != values.end() && key_index != ordering.end(); ++key_value, ++key_index) { assert(key_value->key == key_index->first); @@ -295,7 +295,7 @@ void ISAM2::Impl::ExpmapMasked(Values& values, const VectorValues& delta, const /* ************************************************************************* */ ISAM2::Impl::PartialSolveResult -ISAM2::Impl::PartialSolve(GaussianFactorGraph& factors, +ISAM2::Impl::PartialSolve(GaussianFactorGraphOrdered& factors, const FastSet& keys, const ReorderingMode& reorderingMode, bool useQR) { const bool debug = ISDEBUG("ISAM2 recalculate"); @@ -306,7 +306,7 @@ ISAM2::Impl::PartialSolve(GaussianFactorGraph& factors, #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS // Debug check that all variables involved in the factors to be re-eliminated // are in affectedKeys, since we will use it to select a subset of variables. - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors) { + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factors) { BOOST_FOREACH(Index key, factor->keys()) { assert(find(keys.begin(), keys.end(), key) != keys.end()); } @@ -328,7 +328,7 @@ ISAM2::Impl::PartialSolve(GaussianFactorGraph& factors, if(debug) factors.print("Factors to reorder/re-eliminate: "); gttoc(select_affected_variables); gttic(variable_index); - VariableIndex affectedFactorsIndex(factors); // Create a variable index for the factors to be re-eliminated + VariableIndexOrdered affectedFactorsIndex(factors); // Create a variable index for the factors to be re-eliminated if(debug) affectedFactorsIndex.print("affectedFactorsIndex: "); gttoc(variable_index); gttic(ccolamd); @@ -369,17 +369,17 @@ ISAM2::Impl::PartialSolve(GaussianFactorGraph& factors, if(debug) factors.print("Colamd-ordered affected factors: "); #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS - VariableIndex fromScratchIndex(factors); + VariableIndexOrdered fromScratchIndex(factors); assert(assert_equal(fromScratchIndex, affectedFactorsIndex)); #endif // eliminate into a Bayes net gttic(eliminate); - JunctionTree jt(factors, affectedFactorsIndex); + JunctionTreeOrdered jt(factors, affectedFactorsIndex); if(!useQR) - result.bayesTree = jt.eliminate(EliminatePreferCholesky); + result.bayesTree = jt.eliminate(EliminatePreferCholeskyOrdered); else - result.bayesTree = jt.eliminate(EliminateQR); + result.bayesTree = jt.eliminate(EliminateQROrdered); gttoc(eliminate); gttic(permute_eliminated); @@ -398,7 +398,7 @@ ISAM2::Impl::PartialSolve(GaussianFactorGraph& factors, /* ************************************************************************* */ namespace internal { -inline static void optimizeInPlace(const boost::shared_ptr& clique, VectorValues& result) { +inline static void optimizeInPlace(const boost::shared_ptr& clique, VectorValuesOrdered& result) { // parents are assumed to already be solved and available in result clique->conditional()->solveInPlace(result); @@ -409,7 +409,7 @@ inline static void optimizeInPlace(const boost::shared_ptr& clique, } /* ************************************************************************* */ -size_t ISAM2::Impl::UpdateDelta(const boost::shared_ptr& root, std::vector& replacedKeys, VectorValues& delta, double wildfireThreshold) { +size_t ISAM2::Impl::UpdateDelta(const boost::shared_ptr& root, std::vector& replacedKeys, VectorValuesOrdered& delta, double wildfireThreshold) { size_t lastBacksubVariableCount; @@ -437,7 +437,7 @@ size_t ISAM2::Impl::UpdateDelta(const boost::shared_ptr& root, std: /* ************************************************************************* */ namespace internal { void updateDoglegDeltas(const boost::shared_ptr& clique, const std::vector& replacedKeys, - const VectorValues& grad, VectorValues& deltaNewton, VectorValues& RgProd, size_t& varsUpdated) { + const VectorValuesOrdered& grad, VectorValuesOrdered& deltaNewton, VectorValuesOrdered& RgProd, size_t& varsUpdated) { // Check if any frontal or separator keys were recalculated, if so, we need // update deltas and recurse to children, but if not, we do not need to @@ -476,10 +476,10 @@ void updateDoglegDeltas(const boost::shared_ptr& clique, const std: /* ************************************************************************* */ size_t ISAM2::Impl::UpdateDoglegDeltas(const ISAM2& isam, double wildfireThreshold, std::vector& replacedKeys, - VectorValues& deltaNewton, VectorValues& RgProd) { + VectorValuesOrdered& deltaNewton, VectorValuesOrdered& RgProd) { // Get gradient - VectorValues grad = *allocateVectorValues(isam); + VectorValuesOrdered grad = *allocateVectorValues(isam); gradientAtZero(isam, grad); // Update variables diff --git a/gtsam/nonlinear/ISAM2-impl.h b/gtsam/nonlinear/ISAM2-impl.h index 07c27c896..406b22374 100644 --- a/gtsam/nonlinear/ISAM2-impl.h +++ b/gtsam/nonlinear/ISAM2-impl.h @@ -17,7 +17,7 @@ #pragma once -#include +#include #include namespace gtsam { @@ -47,17 +47,17 @@ struct GTSAM_EXPORT ISAM2::Impl { * @param nodes Current BayesTree::Nodes index to be augmented with slots for new variables * @param keyFormatter Formatter for printing nonlinear keys during debugging */ - static void AddVariables(const Values& newTheta, Values& theta, VectorValues& delta, - VectorValues& deltaNewton, VectorValues& RgProd, std::vector& replacedKeys, - Ordering& ordering, const KeyFormatter& keyFormatter = DefaultKeyFormatter); + static void AddVariables(const Values& newTheta, Values& theta, VectorValuesOrdered& delta, + VectorValuesOrdered& deltaNewton, VectorValuesOrdered& RgProd, std::vector& replacedKeys, + OrderingOrdered& ordering, const KeyFormatter& keyFormatter = DefaultKeyFormatter); /** * Remove variables from the ISAM2 system. */ static void RemoveVariables(const FastSet& unusedKeys, const ISAM2Clique::shared_ptr& root, - Values& theta, VariableIndex& variableIndex, VectorValues& delta, VectorValues& deltaNewton, - VectorValues& RgProd, std::vector& replacedKeys, Ordering& ordering, Base::Nodes& nodes, - GaussianFactorGraph& linearFactors, FastSet& fixedVariables); + Values& theta, VariableIndexOrdered& variableIndex, VectorValuesOrdered& delta, VectorValuesOrdered& deltaNewton, + VectorValuesOrdered& RgProd, std::vector& replacedKeys, OrderingOrdered& ordering, Base::Nodes& nodes, + GaussianFactorGraphOrdered& linearFactors, FastSet& fixedVariables); /** * Extract the set of variable indices from a NonlinearFactorGraph. For each Symbol @@ -66,7 +66,7 @@ struct GTSAM_EXPORT ISAM2::Impl { * @param factors The factors from which to extract the variables * @return The set of variables indices from the factors */ - static FastSet IndicesFromFactors(const Ordering& ordering, const NonlinearFactorGraph& factors); + static FastSet IndicesFromFactors(const OrderingOrdered& ordering, const NonlinearFactorGraph& factors); /** * Find the set of variables to be relinearized according to relinearizeThreshold. @@ -77,7 +77,7 @@ struct GTSAM_EXPORT ISAM2::Impl { * @return The set of variable indices in delta whose magnitude is greater than or * equal to relinearizeThreshold */ - static FastSet CheckRelinearizationFull(const VectorValues& delta, const Ordering& ordering, + static FastSet CheckRelinearizationFull(const VectorValuesOrdered& delta, const OrderingOrdered& ordering, const ISAM2Params::RelinearizationThreshold& relinearizeThreshold, const KeyFormatter& keyFormatter = DefaultKeyFormatter); /** @@ -91,7 +91,7 @@ struct GTSAM_EXPORT ISAM2::Impl { * @return The set of variable indices in delta whose magnitude is greater than or * equal to relinearizeThreshold */ - static FastSet CheckRelinearizationPartial(const ISAM2Clique::shared_ptr& root, const VectorValues& delta, const Ordering& ordering, + static FastSet CheckRelinearizationPartial(const ISAM2Clique::shared_ptr& root, const VectorValuesOrdered& delta, const OrderingOrdered& ordering, const ISAM2Params::RelinearizationThreshold& relinearizeThreshold, const KeyFormatter& keyFormatter = DefaultKeyFormatter); /** @@ -124,9 +124,9 @@ struct GTSAM_EXPORT ISAM2::Impl { * recalculate its delta. * @param keyFormatter Formatter for printing nonlinear keys during debugging */ - static void ExpmapMasked(Values& values, const VectorValues& delta, - const Ordering& ordering, const std::vector& mask, - boost::optional invalidateIfDebug = boost::none, + static void ExpmapMasked(Values& values, const VectorValuesOrdered& delta, + const OrderingOrdered& ordering, const std::vector& mask, + boost::optional invalidateIfDebug = boost::none, const KeyFormatter& keyFormatter = DefaultKeyFormatter); /** @@ -143,13 +143,13 @@ struct GTSAM_EXPORT ISAM2::Impl { * \return The eliminated BayesTree and the permutation to be applied to the * rest of the ISAM2 data. */ - static PartialSolveResult PartialSolve(GaussianFactorGraph& factors, const FastSet& keys, + static PartialSolveResult PartialSolve(GaussianFactorGraphOrdered& factors, const FastSet& keys, const ReorderingMode& reorderingMode, bool useQR); - static size_t UpdateDelta(const boost::shared_ptr& root, std::vector& replacedKeys, VectorValues& delta, double wildfireThreshold); + static size_t UpdateDelta(const boost::shared_ptr& root, std::vector& replacedKeys, VectorValuesOrdered& delta, double wildfireThreshold); static size_t UpdateDoglegDeltas(const ISAM2& isam, double wildfireThreshold, std::vector& replacedKeys, - VectorValues& deltaNewton, VectorValues& RgProd); + VectorValuesOrdered& deltaNewton, VectorValuesOrdered& RgProd); }; diff --git a/gtsam/nonlinear/ISAM2-inl.h b/gtsam/nonlinear/ISAM2-inl.h index 4a9cf105a..a00ca5737 100644 --- a/gtsam/nonlinear/ISAM2-inl.h +++ b/gtsam/nonlinear/ISAM2-inl.h @@ -20,8 +20,8 @@ #pragma once #include -#include -#include +#include +#include namespace gtsam { @@ -37,7 +37,7 @@ VALUE ISAM2::calculateEstimate(Key key) const { namespace internal { template void optimizeWildfire(const boost::shared_ptr& clique, double threshold, - std::vector& changed, const std::vector& replaced, VectorValues& delta, int& count) { + std::vector& changed, const std::vector& replaced, VectorValuesOrdered& delta, int& count) { // if none of the variables in this clique (frontal and separator!) changed // significantly, then by the running intersection property, none of the // cliques in the children need to be processed @@ -67,7 +67,7 @@ void optimizeWildfire(const boost::shared_ptr& clique, double threshold, // Temporary copy of the original values, to check how much they change std::vector originalValues((*clique)->nrFrontals()); - GaussianConditional::const_iterator it; + GaussianConditionalOrdered::const_iterator it; for(it = (*clique)->beginFrontals(); it!=(*clique)->endFrontals(); it++) { originalValues[it - (*clique)->beginFrontals()] = delta[*it]; } @@ -113,7 +113,7 @@ void optimizeWildfire(const boost::shared_ptr& clique, double threshold, template bool optimizeWildfireNode(const boost::shared_ptr& clique, double threshold, - std::vector& changed, const std::vector& replaced, VectorValues& delta, int& count) { + std::vector& changed, const std::vector& replaced, VectorValuesOrdered& delta, int& count) { // if none of the variables in this clique (frontal and separator!) changed // significantly, then by the running intersection property, none of the // cliques in the children need to be processed @@ -143,7 +143,7 @@ bool optimizeWildfireNode(const boost::shared_ptr& clique, double thresh // Temporary copy of the original values, to check how much they change std::vector originalValues((*clique)->nrFrontals()); - GaussianConditional::const_iterator it; + GaussianConditionalOrdered::const_iterator it; for(it = (*clique)->beginFrontals(); it!=(*clique)->endFrontals(); it++) { originalValues[it - (*clique)->beginFrontals()] = delta[*it]; } @@ -189,7 +189,7 @@ bool optimizeWildfireNode(const boost::shared_ptr& clique, double thresh /* ************************************************************************* */ template -int optimizeWildfire(const boost::shared_ptr& root, double threshold, const std::vector& keys, VectorValues& delta) { +int optimizeWildfire(const boost::shared_ptr& root, double threshold, const std::vector& keys, VectorValuesOrdered& delta) { std::vector changed(keys.size(), false); int count = 0; // starting from the root, call optimize on each conditional @@ -200,7 +200,7 @@ int optimizeWildfire(const boost::shared_ptr& root, double threshold, co /* ************************************************************************* */ template -int optimizeWildfireNonRecursive(const boost::shared_ptr& root, double threshold, const std::vector& keys, VectorValues& delta) { +int optimizeWildfireNonRecursive(const boost::shared_ptr& root, double threshold, const std::vector& keys, VectorValuesOrdered& delta) { std::vector changed(keys.size(), false); int count = 0; diff --git a/gtsam/nonlinear/ISAM2.cpp b/gtsam/nonlinear/ISAM2.cpp index dc764c164..4ea251ed0 100644 --- a/gtsam/nonlinear/ISAM2.cpp +++ b/gtsam/nonlinear/ISAM2.cpp @@ -24,11 +24,11 @@ using namespace boost::assign; #include #include -#include -#include +#include +#include #include -#include -#include +#include +#include #include #include @@ -122,10 +122,10 @@ ISAM2& ISAM2::operator=(const ISAM2& rhs) { deltaReplacedMask_ = rhs.deltaReplacedMask_; nonlinearFactors_ = rhs.nonlinearFactors_; - linearFactors_ = GaussianFactorGraph(); + linearFactors_ = GaussianFactorGraphOrdered(); linearFactors_.reserve(rhs.linearFactors_.size()); - BOOST_FOREACH(const GaussianFactor::shared_ptr& linearFactor, rhs.linearFactors_) { - linearFactors_.push_back(linearFactor ? linearFactor->clone() : GaussianFactor::shared_ptr()); } + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& linearFactor, rhs.linearFactors_) { + linearFactors_.push_back(linearFactor ? linearFactor->clone() : GaussianFactorOrdered::shared_ptr()); } ordering_ = rhs.ordering_; params_ = rhs.params_; @@ -148,12 +148,12 @@ FastList ISAM2::getAffectedFactors(const FastList& keys) const { if(debug) { BOOST_FOREACH(const Index key, keys) { cout << key << " "; } } if(debug) cout << endl; - FactorGraph allAffected; + FactorGraphOrdered allAffected; FastList indices; BOOST_FOREACH(const Index key, keys) { // const list l = nonlinearFactors_.factors(key); // indices.insert(indices.begin(), l.begin(), l.end()); - const VariableIndex::Factors& factors(variableIndex_[key]); + const VariableIndexOrdered::Factors& factors(variableIndex_[key]); BOOST_FOREACH(size_t factor, factors) { if(debug) cout << "Variable " << key << " affects factor " << factor << endl; indices.push_back(factor); @@ -170,7 +170,7 @@ FastList ISAM2::getAffectedFactors(const FastList& keys) const { /* ************************************************************************* */ // retrieve all factors that ONLY contain the affected variables // (note that the remaining stuff is summarized in the cached factors) -FactorGraph::shared_ptr +FactorGraphOrdered::shared_ptr ISAM2::relinearizeAffectedFactors(const FastList& affectedKeys, const FastSet& relinKeys) const { gttic(getAffectedFactors); @@ -186,7 +186,7 @@ ISAM2::relinearizeAffectedFactors(const FastList& affectedKeys, const Fas gttoc(affectedKeysSet); gttic(check_candidates_and_linearize); - FactorGraph::shared_ptr linearized = boost::make_shared >(); + FactorGraphOrdered::shared_ptr linearized = boost::make_shared >(); BOOST_FOREACH(size_t idx, candidates) { bool inside = true; bool useCachedLinear = params_.cacheLinearizedFactors; @@ -207,7 +207,7 @@ ISAM2::relinearizeAffectedFactors(const FastList& affectedKeys, const Fas #endif linearized->push_back(linearFactors_[idx]); } else { - GaussianFactor::shared_ptr linearFactor = nonlinearFactors_[idx]->linearize(theta_, ordering_); + GaussianFactorOrdered::shared_ptr linearFactor = nonlinearFactors_[idx]->linearize(theta_, ordering_); linearized->push_back(linearFactor); if(params_.cacheLinearizedFactors) { #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS @@ -225,11 +225,11 @@ ISAM2::relinearizeAffectedFactors(const FastList& affectedKeys, const Fas /* ************************************************************************* */ // find intermediate (linearized) factors from cache that are passed into the affected area -GaussianFactorGraph ISAM2::getCachedBoundaryFactors(Cliques& orphans) { +GaussianFactorGraphOrdered ISAM2::getCachedBoundaryFactors(Cliques& orphans) { static const bool debug = false; - GaussianFactorGraph cachedBoundary; + GaussianFactorGraphOrdered cachedBoundary; BOOST_FOREACH(sharedClique orphan, orphans) { // find the last variable that was eliminated @@ -284,14 +284,14 @@ boost::shared_ptr > ISAM2::recalculate(const FastSet& mark // (b) Store orphaned sub-trees \BayesTree_{O} of removed cliques. gttic(removetop); Cliques orphans; - BayesNet affectedBayesNet; + BayesNetOrdered affectedBayesNet; this->removeTop(markedKeys, affectedBayesNet, orphans); gttoc(removetop); if(debug) affectedBayesNet.print("Removed top: "); if(debug) orphans.print("Orphans: "); - // FactorGraph factors(affectedBayesNet); + // FactorGraph factors(affectedBayesNet); // bug was here: we cannot reuse the original factors, because then the cached factors get messed up // [all the necessary data is actually contained in the affectedBayesNet, including what was passed in from the boundaries, // so this would be correct; however, in the process we also generate new cached_ entries that will be wrong (ie. they don't @@ -314,7 +314,7 @@ boost::shared_ptr > ISAM2::recalculate(const FastSet& mark gttic(batch); gttic(add_keys); - BOOST_FOREACH(const Ordering::value_type& key_index, ordering_) { affectedKeysSet->insert(key_index.second); } + BOOST_FOREACH(const OrderingOrdered::value_type& key_index, ordering_) { affectedKeysSet->insert(key_index.second); } gttoc(add_keys); gttic(reorder); @@ -357,18 +357,18 @@ boost::shared_ptr > ISAM2::recalculate(const FastSet& mark gttoc(reorder); gttic(linearize); - GaussianFactorGraph linearized = *nonlinearFactors_.linearize(theta_, ordering_); + GaussianFactorGraphOrdered linearized = *nonlinearFactors_.linearize(theta_, ordering_); if(params_.cacheLinearizedFactors) linearFactors_ = linearized; gttoc(linearize); gttic(eliminate); - JunctionTree jt(linearized, variableIndex_); + JunctionTreeOrdered jt(linearized, variableIndex_); sharedClique newRoot; if(params_.factorization == ISAM2Params::CHOLESKY) - newRoot = jt.eliminate(EliminatePreferCholesky); + newRoot = jt.eliminate(EliminatePreferCholeskyOrdered); else if(params_.factorization == ISAM2Params::QR) - newRoot = jt.eliminate(EliminateQR); + newRoot = jt.eliminate(EliminateQROrdered); else assert(false); if(debug) newRoot->print("Eliminated: "); gttoc(eliminate); @@ -403,7 +403,7 @@ boost::shared_ptr > ISAM2::recalculate(const FastSet& mark affectedAndNewKeys.insert(affectedAndNewKeys.end(), affectedKeys.begin(), affectedKeys.end()); affectedAndNewKeys.insert(affectedAndNewKeys.end(), observedKeys.begin(), observedKeys.end()); gttic(relinearizeAffected); - GaussianFactorGraph factors(*relinearizeAffectedFactors(affectedAndNewKeys, relinKeys)); + GaussianFactorGraphOrdered factors(*relinearizeAffectedFactors(affectedAndNewKeys, relinKeys)); if(debug) factors.print("Relinearized factors: "); gttoc(relinearizeAffected); @@ -431,7 +431,7 @@ boost::shared_ptr > ISAM2::recalculate(const FastSet& mark gttic(cached); // add the cached intermediate results from the boundary of the orphans ... - GaussianFactorGraph cachedBoundary = getCachedBoundaryFactors(orphans); + GaussianFactorGraphOrdered cachedBoundary = getCachedBoundaryFactors(orphans); if(debug) cachedBoundary.print("Boundary factors: "); factors.push_back(cachedBoundary); gttoc(cached); @@ -735,7 +735,7 @@ ISAM2Result ISAM2::update( // 7. Linearize new factors if(params_.cacheLinearizedFactors) { gttic(linearize); - FactorGraph::shared_ptr linearFactors = newFactors.linearize(theta_, ordering_); + FactorGraphOrdered::shared_ptr linearFactors = newFactors.linearize(theta_, ordering_); linearFactors_.push_back(*linearFactors); assert(nonlinearFactors_.size() == linearFactors_.size()); gttoc(linearize); @@ -802,7 +802,7 @@ void ISAM2::marginalizeLeaves(const FastList& leafKeys) // Keep track of marginal factors - map from clique to the marginal factors // that should be incorporated into it, passed up from it's children. - multimap marginalFactors; + multimap marginalFactors; // Remove each variable and its subtrees BOOST_REVERSE_FOREACH(Index j, indices) { @@ -819,7 +819,7 @@ void ISAM2::marginalizeLeaves(const FastList& leafKeys) // Remove either the whole clique or part of it if(marginalizeEntireClique) { // Remove the whole clique and its subtree, and keep the marginal factor. - GaussianFactor::shared_ptr marginalFactor = clique->cachedFactor(); + GaussianFactorOrdered::shared_ptr marginalFactor = clique->cachedFactor(); // We do not need the marginal factors associated with this clique // because their information is already incorporated in the new // marginal factor. So, now associate this marginal factor with the @@ -843,7 +843,7 @@ void ISAM2::marginalizeLeaves(const FastList& leafKeys) // subtrees already marginalized out. // Add child marginals and remove marginalized subtrees - GaussianFactorGraph graph; + GaussianFactorGraphOrdered graph; FastSet factorsInSubtreeRoot; Cliques subtreesToRemove; BOOST_FOREACH(const sharedClique& child, clique->children()) { @@ -895,30 +895,30 @@ void ISAM2::marginalizeLeaves(const FastList& leafKeys) std::set_intersection(cliqueFrontals.begin(), cliqueFrontals.end(), indices.begin(), indices.end(), std::inserter(cliqueFrontalsToEliminate, cliqueFrontalsToEliminate.end())); vector cliqueFrontalsToEliminateV(cliqueFrontalsToEliminate.begin(), cliqueFrontalsToEliminate.end()); - pair eliminationResult1 = + pair eliminationResult1 = graph.eliminate(cliqueFrontalsToEliminateV, - params_.factorization==ISAM2Params::QR ? EliminateQR : EliminatePreferCholesky); + params_.factorization==ISAM2Params::QR ? EliminateQROrdered : EliminatePreferCholeskyOrdered); // Add the resulting marginal - BOOST_FOREACH(const GaussianFactor::shared_ptr& marginal, eliminationResult1.second) { + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& marginal, eliminationResult1.second) { if(marginal) marginalFactors.insert(make_pair(clique, marginal)); } // Recover the conditional on the remaining subset of frontal variables // of this clique being martially marginalized. size_t nToEliminate = std::find(clique->conditional()->beginFrontals(), clique->conditional()->endFrontals(), j) - clique->conditional()->begin() + 1; - GaussianFactorGraph graph2; + GaussianFactorGraphOrdered graph2; graph2.push_back(clique->conditional()->toFactor()); - GaussianFactorGraph::EliminationResult eliminationResult2 = + GaussianFactorGraphOrdered::EliminationResult eliminationResult2 = params_.factorization == ISAM2Params::QR ? - EliminateQR(graph2, nToEliminate) : - EliminatePreferCholesky(graph2, nToEliminate); - GaussianFactorGraph graph3; + EliminateQROrdered(graph2, nToEliminate) : + EliminatePreferCholeskyOrdered(graph2, nToEliminate); + GaussianFactorGraphOrdered graph3; graph3.push_back(eliminationResult2.second); - GaussianFactorGraph::EliminationResult eliminationResult3 = + GaussianFactorGraphOrdered::EliminationResult eliminationResult3 = params_.factorization == ISAM2Params::QR ? - EliminateQR(graph3, clique->conditional()->nrFrontals() - nToEliminate) : - EliminatePreferCholesky(graph3, clique->conditional()->nrFrontals() - nToEliminate); + EliminateQROrdered(graph3, clique->conditional()->nrFrontals() - nToEliminate) : + EliminatePreferCholeskyOrdered(graph3, clique->conditional()->nrFrontals() - nToEliminate); sharedClique newClique = boost::make_shared(make_pair(eliminationResult3.first, clique->cachedFactor())); // Add the marginalized clique to the BayesTree @@ -934,8 +934,8 @@ void ISAM2::marginalizeLeaves(const FastList& leafKeys) // At this point we have updated the BayesTree, now update the remaining iSAM2 data structures // Gather factors to add - the new marginal factors - GaussianFactorGraph factorsToAdd; - typedef pair Clique_Factor; + GaussianFactorGraphOrdered factorsToAdd; + typedef pair Clique_Factor; BOOST_FOREACH(const Clique_Factor& clique_factor, marginalFactors) { if(clique_factor.second) factorsToAdd.push_back(clique_factor.second); @@ -953,7 +953,7 @@ void ISAM2::marginalizeLeaves(const FastList& leafKeys) BOOST_FOREACH(Index j, indices) { factorIndicesToRemove.insert(variableIndex_[j].begin(), variableIndex_[j].end()); } vector removedFactorIndices; - SymbolicFactorGraph removedFactors; + SymbolicFactorGraphOrdered removedFactors; BOOST_FOREACH(size_t i, factorIndicesToRemove) { removedFactorIndices.push_back(i); removedFactors.push_back(nonlinearFactors_[i]->symbolic(ordering_)); @@ -1009,7 +1009,7 @@ Values ISAM2::calculateEstimate() const { Values ret(theta_); gttoc(Copy_Values); gttic(getDelta); - const VectorValues& delta(getDelta()); + const VectorValuesOrdered& delta(getDelta()); gttoc(getDelta); gttic(Expmap); vector mask(ordering_.size(), true); @@ -1021,35 +1021,35 @@ Values ISAM2::calculateEstimate() const { /* ************************************************************************* */ Matrix ISAM2::marginalCovariance(Index key) const { return marginalFactor(ordering_[key], - params_.factorization == ISAM2Params::QR ? EliminateQR : EliminatePreferCholesky) + params_.factorization == ISAM2Params::QR ? EliminateQROrdered : EliminatePreferCholeskyOrdered) ->information().inverse(); } /* ************************************************************************* */ Values ISAM2::calculateBestEstimate() const { - VectorValues delta(theta_.dims(ordering_)); + VectorValuesOrdered delta(theta_.dims(ordering_)); internal::optimizeInPlace(this->root(), delta); return theta_.retract(delta, ordering_); } /* ************************************************************************* */ -const VectorValues& ISAM2::getDelta() const { +const VectorValuesOrdered& ISAM2::getDelta() const { if(!deltaUptodate_) updateDelta(); return delta_; } /* ************************************************************************* */ -VectorValues optimize(const ISAM2& isam) { +VectorValuesOrdered optimize(const ISAM2& isam) { gttic(allocateVectorValues); - VectorValues delta = *allocateVectorValues(isam); + VectorValuesOrdered delta = *allocateVectorValues(isam); gttoc(allocateVectorValues); optimizeInPlace(isam, delta); return delta; } /* ************************************************************************* */ -void optimizeInPlace(const ISAM2& isam, VectorValues& delta) { +void optimizeInPlace(const ISAM2& isam, VectorValuesOrdered& delta) { // We may need to update the solution calculations if(!isam.deltaDoglegUptodate_) { gttic(UpdateDoglegDeltas); @@ -1071,9 +1071,9 @@ void optimizeInPlace(const ISAM2& isam, VectorValues& delta) { } /* ************************************************************************* */ -VectorValues optimizeGradientSearch(const ISAM2& isam) { +VectorValuesOrdered optimizeGradientSearch(const ISAM2& isam) { gttic(Allocate_VectorValues); - VectorValues grad = *allocateVectorValues(isam); + VectorValuesOrdered grad = *allocateVectorValues(isam); gttoc(Allocate_VectorValues); optimizeGradientSearchInPlace(isam, grad); @@ -1082,7 +1082,7 @@ VectorValues optimizeGradientSearch(const ISAM2& isam) { } /* ************************************************************************* */ -void optimizeGradientSearchInPlace(const ISAM2& isam, VectorValues& grad) { +void optimizeGradientSearchInPlace(const ISAM2& isam, VectorValuesOrdered& grad) { // We may need to update the solution calcaulations if(!isam.deltaDoglegUptodate_) { gttic(UpdateDoglegDeltas); @@ -1117,15 +1117,15 @@ void optimizeGradientSearchInPlace(const ISAM2& isam, VectorValues& grad) { } /* ************************************************************************* */ -VectorValues gradient(const ISAM2& bayesTree, const VectorValues& x0) { - return gradient(FactorGraph(bayesTree), x0); +VectorValuesOrdered gradient(const ISAM2& bayesTree, const VectorValuesOrdered& x0) { + return gradient(FactorGraphOrdered(bayesTree), x0); } /* ************************************************************************* */ -static void gradientAtZeroTreeAdder(const boost::shared_ptr& root, VectorValues& g) { +static void gradientAtZeroTreeAdder(const boost::shared_ptr& root, VectorValuesOrdered& g) { // Loop through variables in each clique, adding contributions int variablePosition = 0; - for(GaussianConditional::const_iterator jit = root->conditional()->begin(); jit != root->conditional()->end(); ++jit) { + for(GaussianConditionalOrdered::const_iterator jit = root->conditional()->begin(); jit != root->conditional()->end(); ++jit) { const int dim = root->conditional()->dim(jit); g[*jit] += root->gradientContribution().segment(variablePosition, dim); variablePosition += dim; @@ -1139,7 +1139,7 @@ static void gradientAtZeroTreeAdder(const boost::shared_ptr& root, } /* ************************************************************************* */ -void gradientAtZero(const ISAM2& bayesTree, VectorValues& g) { +void gradientAtZero(const ISAM2& bayesTree, VectorValuesOrdered& g) { // Zero-out gradient g.setZero(); diff --git a/gtsam/nonlinear/ISAM2.h b/gtsam/nonlinear/ISAM2.h index 687723392..481dd3ff6 100644 --- a/gtsam/nonlinear/ISAM2.h +++ b/gtsam/nonlinear/ISAM2.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include @@ -342,13 +342,13 @@ struct GTSAM_EXPORT ISAM2Result { * Specialized Clique structure for ISAM2, incorporating caching and gradient contribution * TODO: more documentation */ -class GTSAM_EXPORT ISAM2Clique : public BayesTreeCliqueBase { +class GTSAM_EXPORT ISAM2Clique : public BayesTreeCliqueBaseOrdered { public: typedef ISAM2Clique This; - typedef BayesTreeCliqueBase Base; + typedef BayesTreeCliqueBaseOrdered Base; typedef boost::shared_ptr shared_ptr; typedef boost::weak_ptr weak_ptr; - typedef GaussianConditional ConditionalType; + typedef GaussianConditionalOrdered ConditionalType; typedef ConditionalType::shared_ptr sharedConditional; Base::FactorType::shared_ptr cachedFactor_; @@ -436,7 +436,7 @@ private: * estimate of all variables. * */ -class ISAM2: public BayesTree { +class ISAM2: public BayesTreeOrdered { protected: @@ -444,7 +444,7 @@ protected: Values theta_; /** VariableIndex lets us look up factors by involved variable and keeps track of dimensions */ - VariableIndex variableIndex_; + VariableIndexOrdered variableIndex_; /** The linear delta from the last linear solution, an update to the estimate in theta * @@ -452,10 +452,10 @@ protected: * until either requested with getDelta() or calculateEstimate(), or needed * during update() to evaluate whether to relinearize variables. */ - mutable VectorValues delta_; + mutable VectorValuesOrdered delta_; - mutable VectorValues deltaNewton_; - mutable VectorValues RgProd_; + mutable VectorValuesOrdered deltaNewton_; + mutable VectorValuesOrdered RgProd_; mutable bool deltaDoglegUptodate_; /** Indicates whether the current delta is up-to-date, only used @@ -485,11 +485,11 @@ protected: NonlinearFactorGraph nonlinearFactors_; /** The current linear factors, which are only updated as needed */ - mutable GaussianFactorGraph linearFactors_; + mutable GaussianFactorGraphOrdered linearFactors_; /** The current elimination ordering Symbols to Index (integer) keys. * We keep it up to date as we add and reorder variables. */ - Ordering ordering_; + OrderingOrdered ordering_; /** The current parameters */ ISAM2Params params_; @@ -504,7 +504,7 @@ protected: public: typedef ISAM2 This; ///< This class - typedef BayesTree Base; ///< The BayesTree base class + typedef BayesTreeOrdered Base; ///< The BayesTree base class /** Create an empty ISAM2 instance */ GTSAM_EXPORT ISAM2(const ISAM2Params& params); @@ -599,16 +599,16 @@ public: GTSAM_EXPORT Values calculateBestEstimate() const; /** Access the current delta, computed during the last call to update */ - GTSAM_EXPORT const VectorValues& getDelta() const; + GTSAM_EXPORT const VectorValuesOrdered& getDelta() const; /** Access the set of nonlinear factors */ GTSAM_EXPORT const NonlinearFactorGraph& getFactorsUnsafe() const { return nonlinearFactors_; } /** Access the current ordering */ - GTSAM_EXPORT const Ordering& getOrdering() const { return ordering_; } + GTSAM_EXPORT const OrderingOrdered& getOrdering() const { return ordering_; } /** Access the nonlinear variable index */ - GTSAM_EXPORT const VariableIndex& getVariableIndex() const { return variableIndex_; } + GTSAM_EXPORT const VariableIndexOrdered& getVariableIndex() const { return variableIndex_; } size_t lastAffectedVariableCount; size_t lastAffectedFactorCount; @@ -627,24 +627,24 @@ public: private: GTSAM_EXPORT FastList getAffectedFactors(const FastList& keys) const; - GTSAM_EXPORT FactorGraph::shared_ptr relinearizeAffectedFactors(const FastList& affectedKeys, const FastSet& relinKeys) const; - GTSAM_EXPORT GaussianFactorGraph getCachedBoundaryFactors(Cliques& orphans); + GTSAM_EXPORT FactorGraphOrdered::shared_ptr relinearizeAffectedFactors(const FastList& affectedKeys, const FastSet& relinKeys) const; + GTSAM_EXPORT GaussianFactorGraphOrdered getCachedBoundaryFactors(Cliques& orphans); GTSAM_EXPORT boost::shared_ptr > recalculate(const FastSet& markedKeys, const FastSet& relinKeys, const FastVector& observedKeys, const FastSet& unusedIndices, const boost::optional >& constrainKeys, ISAM2Result& result); // void linear_update(const GaussianFactorGraph& newFactors); GTSAM_EXPORT void updateDelta(bool forceFullSolve = false) const; - GTSAM_EXPORT friend void optimizeInPlace(const ISAM2&, VectorValues&); - GTSAM_EXPORT friend void optimizeGradientSearchInPlace(const ISAM2&, VectorValues&); + GTSAM_EXPORT friend void optimizeInPlace(const ISAM2&, VectorValuesOrdered&); + GTSAM_EXPORT friend void optimizeGradientSearchInPlace(const ISAM2&, VectorValuesOrdered&); }; // ISAM2 /** Get the linear delta for the ISAM2 object, unpermuted the delta returned by ISAM2::getDelta() */ -GTSAM_EXPORT VectorValues optimize(const ISAM2& isam); +GTSAM_EXPORT VectorValuesOrdered optimize(const ISAM2& isam); /** Get the linear delta for the ISAM2 object, unpermuted the delta returned by ISAM2::getDelta() */ -GTSAM_EXPORT void optimizeInPlace(const ISAM2& isam, VectorValues& delta); +GTSAM_EXPORT void optimizeInPlace(const ISAM2& isam, VectorValuesOrdered& delta); /// Optimize the BayesTree, starting from the root. /// @param replaced Needs to contain @@ -659,11 +659,11 @@ GTSAM_EXPORT void optimizeInPlace(const ISAM2& isam, VectorValues& delta); /// @return The number of variables that were solved for template int optimizeWildfire(const boost::shared_ptr& root, - double threshold, const std::vector& replaced, VectorValues& delta); + double threshold, const std::vector& replaced, VectorValuesOrdered& delta); template int optimizeWildfireNonRecursive(const boost::shared_ptr& root, - double threshold, const std::vector& replaced, VectorValues& delta); + double threshold, const std::vector& replaced, VectorValuesOrdered& delta); /** * Optimize along the gradient direction, with a closed-form computation to @@ -690,10 +690,10 @@ int optimizeWildfireNonRecursive(const boost::shared_ptr& root, * * \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f] */ -GTSAM_EXPORT VectorValues optimizeGradientSearch(const ISAM2& isam); +GTSAM_EXPORT VectorValuesOrdered optimizeGradientSearch(const ISAM2& isam); /** In-place version of optimizeGradientSearch requiring pre-allocated VectorValues \c x */ -GTSAM_EXPORT void optimizeGradientSearchInPlace(const ISAM2& isam, VectorValues& grad); +GTSAM_EXPORT void optimizeGradientSearchInPlace(const ISAM2& isam, VectorValuesOrdered& grad); /// calculate the number of non-zero entries for the tree starting at clique (use root for complete matrix) template @@ -710,7 +710,7 @@ int calculate_nnz(const boost::shared_ptr& clique); * @param x0 The center about which to compute the gradient * @return The gradient as a VectorValues */ -GTSAM_EXPORT VectorValues gradient(const ISAM2& bayesTree, const VectorValues& x0); +GTSAM_EXPORT VectorValuesOrdered gradient(const ISAM2& bayesTree, const VectorValuesOrdered& x0); /** * Compute the gradient of the energy function, @@ -723,7 +723,7 @@ GTSAM_EXPORT VectorValues gradient(const ISAM2& bayesTree, const VectorValues& x * @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues * @return The gradient as a VectorValues */ -GTSAM_EXPORT void gradientAtZero(const ISAM2& bayesTree, VectorValues& g); +GTSAM_EXPORT void gradientAtZero(const ISAM2& bayesTree, VectorValuesOrdered& g); } /// namespace gtsam diff --git a/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp b/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp index 48ed5d1c9..a502b694d 100644 --- a/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp +++ b/gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp @@ -74,7 +74,7 @@ void LevenbergMarquardtOptimizer::iterate() { gttic(LM_iterate); // Linearize graph - GaussianFactorGraph::shared_ptr linear = graph_.linearize(state_.values, *params_.ordering); + GaussianFactorGraphOrdered::shared_ptr linear = graph_.linearize(state_.values, *params_.ordering); // Pull out parameters we'll use const NonlinearOptimizerParams::Verbosity nloVerbosity = params_.verbosity; @@ -88,7 +88,7 @@ void LevenbergMarquardtOptimizer::iterate() { // Add prior-factors // TODO: replace this dampening with a backsubstitution approach gttic(damp); - GaussianFactorGraph dampedSystem(*linear); + GaussianFactorGraphOrdered dampedSystem(*linear); { double sigma = 1.0 / std::sqrt(state_.lambda); dampedSystem.reserve(dampedSystem.size() + dimensions_.size()); @@ -98,7 +98,7 @@ void LevenbergMarquardtOptimizer::iterate() { Matrix A = eye(dim); Vector b = zero(dim); SharedDiagonal model = noiseModel::Isotropic::Sigma(dim,sigma); - GaussianFactor::shared_ptr prior(new JacobianFactor(j, A, b, model)); + GaussianFactorOrdered::shared_ptr prior(new JacobianFactorOrdered(j, A, b, model)); dampedSystem.push_back(prior); } } @@ -108,7 +108,7 @@ void LevenbergMarquardtOptimizer::iterate() { // Try solving try { // Solve Damped Gaussian Factor Graph - const VectorValues delta = solveGaussianFactorGraph(dampedSystem, params_); + const VectorValuesOrdered delta = solveGaussianFactorGraph(dampedSystem, params_); if (lmVerbosity >= LevenbergMarquardtParams::TRYLAMBDA) cout << "linear delta norm = " << delta.norm() << endl; if (lmVerbosity >= LevenbergMarquardtParams::TRYDELTA) delta.print("delta"); diff --git a/gtsam/nonlinear/LevenbergMarquardtOptimizer.h b/gtsam/nonlinear/LevenbergMarquardtOptimizer.h index 5c769ea7b..9bbc9f1d3 100644 --- a/gtsam/nonlinear/LevenbergMarquardtOptimizer.h +++ b/gtsam/nonlinear/LevenbergMarquardtOptimizer.h @@ -122,7 +122,7 @@ public: * @param graph The nonlinear factor graph to optimize * @param initialValues The initial variable assignments */ - LevenbergMarquardtOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const Ordering& ordering) : + LevenbergMarquardtOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const OrderingOrdered& ordering) : NonlinearOptimizer(graph), dimensions_(initialValues.dims(ordering)) { params_.ordering = ordering; state_ = LevenbergMarquardtState(graph, initialValues, params_); } diff --git a/gtsam/nonlinear/LinearContainerFactor.cpp b/gtsam/nonlinear/LinearContainerFactor.cpp index afbc4cfc7..9748049b6 100644 --- a/gtsam/nonlinear/LinearContainerFactor.cpp +++ b/gtsam/nonlinear/LinearContainerFactor.cpp @@ -12,7 +12,7 @@ namespace gtsam { /* ************************************************************************* */ -void LinearContainerFactor::rekeyFactor(const Ordering& ordering) { +void LinearContainerFactor::rekeyFactor(const OrderingOrdered& ordering) { BOOST_FOREACH(Index& idx, factor_->keys()) { Key fullKey = ordering.key(idx); idx = fullKey; @@ -33,7 +33,7 @@ void LinearContainerFactor::initializeLinearizationPoint(const Values& lineariza } /* ************************************************************************* */ -LinearContainerFactor::LinearContainerFactor(const GaussianFactor::shared_ptr& factor, +LinearContainerFactor::LinearContainerFactor(const GaussianFactorOrdered::shared_ptr& factor, const boost::optional& linearizationPoint) : factor_(factor), linearizationPoint_(linearizationPoint) { // Extract keys stashed in linear factor @@ -43,7 +43,7 @@ LinearContainerFactor::LinearContainerFactor(const GaussianFactor::shared_ptr& f /* ************************************************************************* */ LinearContainerFactor::LinearContainerFactor( - const JacobianFactor& factor, const Ordering& ordering, + const JacobianFactorOrdered& factor, const OrderingOrdered& ordering, const Values& linearizationPoint) : factor_(factor.clone()) { rekeyFactor(ordering); @@ -52,7 +52,7 @@ LinearContainerFactor::LinearContainerFactor( /* ************************************************************************* */ LinearContainerFactor::LinearContainerFactor( - const HessianFactor& factor, const Ordering& ordering, + const HessianFactorOrdered& factor, const OrderingOrdered& ordering, const Values& linearizationPoint) : factor_(factor.clone()) { rekeyFactor(ordering); @@ -61,7 +61,7 @@ LinearContainerFactor::LinearContainerFactor( /* ************************************************************************* */ LinearContainerFactor::LinearContainerFactor( - const GaussianFactor::shared_ptr& factor, const Ordering& ordering, + const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering, const Values& linearizationPoint) : factor_(factor->clone()) { rekeyFactor(ordering); @@ -70,7 +70,7 @@ LinearContainerFactor::LinearContainerFactor( /* ************************************************************************* */ LinearContainerFactor::LinearContainerFactor( - const GaussianFactor::shared_ptr& factor, + const GaussianFactorOrdered::shared_ptr& factor, const Values& linearizationPoint) : factor_(factor->clone()) { @@ -112,8 +112,8 @@ double LinearContainerFactor::error(const Values& c) const { csub.insert(key, c.at(key)); // create dummy ordering for evaluation - Ordering ordering = *csub.orderingArbitrary(); - VectorValues delta = linearizationPoint_->localCoordinates(csub, ordering); + OrderingOrdered ordering = *csub.orderingArbitrary(); + VectorValuesOrdered delta = linearizationPoint_->localCoordinates(csub, ordering); // Change keys on stored factor BOOST_FOREACH(gtsam::Index& index, factor_->keys()) @@ -137,9 +137,9 @@ size_t LinearContainerFactor::dim() const { } /* ************************************************************************* */ -GaussianFactor::shared_ptr LinearContainerFactor::order(const Ordering& ordering) const { +GaussianFactorOrdered::shared_ptr LinearContainerFactor::order(const OrderingOrdered& ordering) const { // clone factor - boost::shared_ptr result = factor_->clone(); + boost::shared_ptr result = factor_->clone(); // rekey BOOST_FOREACH(Index& key, result->keys()) @@ -149,8 +149,8 @@ GaussianFactor::shared_ptr LinearContainerFactor::order(const Ordering& ordering } /* ************************************************************************* */ -GaussianFactor::shared_ptr LinearContainerFactor::linearize( - const Values& c, const Ordering& ordering) const { +GaussianFactorOrdered::shared_ptr LinearContainerFactor::linearize( + const Values& c, const OrderingOrdered& ordering) const { if (!hasLinearizationPoint()) return order(ordering); @@ -160,20 +160,20 @@ GaussianFactor::shared_ptr LinearContainerFactor::linearize( subsetC.insert(key, c.at(key)); // Create a temp ordering for this factor - Ordering localOrdering = *subsetC.orderingArbitrary(); + OrderingOrdered localOrdering = *subsetC.orderingArbitrary(); // Determine delta between linearization points using new ordering - VectorValues delta = linearizationPoint_->localCoordinates(subsetC, localOrdering); + VectorValuesOrdered delta = linearizationPoint_->localCoordinates(subsetC, localOrdering); // clone and reorder linear factor to final ordering - GaussianFactor::shared_ptr linFactor = order(localOrdering); + GaussianFactorOrdered::shared_ptr linFactor = order(localOrdering); if (isJacobian()) { - JacobianFactor::shared_ptr jacFactor = boost::dynamic_pointer_cast(linFactor); + JacobianFactorOrdered::shared_ptr jacFactor = boost::dynamic_pointer_cast(linFactor); jacFactor->getb() = -jacFactor->unweighted_error(delta); } else { - HessianFactor::shared_ptr hesFactor = boost::dynamic_pointer_cast(linFactor); + HessianFactorOrdered::shared_ptr hesFactor = boost::dynamic_pointer_cast(linFactor); size_t dim = hesFactor->linearTerm().size(); - Eigen::Block Gview = hesFactor->info().block(0, 0, dim, dim); + Eigen::Block Gview = hesFactor->info().block(0, 0, dim, dim); Vector deltaVector = delta.asVector(); Vector G_delta = Gview.selfadjointView() * deltaVector; hesFactor->constantTerm() += deltaVector.dot(G_delta) - 2.0 * deltaVector.dot(hesFactor->linearTerm()); @@ -188,27 +188,27 @@ GaussianFactor::shared_ptr LinearContainerFactor::linearize( /* ************************************************************************* */ bool LinearContainerFactor::isJacobian() const { - return boost::dynamic_pointer_cast(factor_); + return boost::dynamic_pointer_cast(factor_); } /* ************************************************************************* */ bool LinearContainerFactor::isHessian() const { - return boost::dynamic_pointer_cast(factor_); + return boost::dynamic_pointer_cast(factor_); } /* ************************************************************************* */ -JacobianFactor::shared_ptr LinearContainerFactor::toJacobian() const { - return boost::dynamic_pointer_cast(factor_); +JacobianFactorOrdered::shared_ptr LinearContainerFactor::toJacobian() const { + return boost::dynamic_pointer_cast(factor_); } /* ************************************************************************* */ -HessianFactor::shared_ptr LinearContainerFactor::toHessian() const { - return boost::dynamic_pointer_cast(factor_); +HessianFactorOrdered::shared_ptr LinearContainerFactor::toHessian() const { + return boost::dynamic_pointer_cast(factor_); } /* ************************************************************************* */ -GaussianFactor::shared_ptr LinearContainerFactor::negate(const Ordering& ordering) const { - GaussianFactor::shared_ptr result = factor_->negate(); +GaussianFactorOrdered::shared_ptr LinearContainerFactor::negate(const OrderingOrdered& ordering) const { + GaussianFactorOrdered::shared_ptr result = factor_->negate(); BOOST_FOREACH(Key& key, result->keys()) key = ordering[key]; return result; @@ -216,16 +216,16 @@ GaussianFactor::shared_ptr LinearContainerFactor::negate(const Ordering& orderin /* ************************************************************************* */ NonlinearFactor::shared_ptr LinearContainerFactor::negate() const { - GaussianFactor::shared_ptr antifactor = factor_->negate(); // already has keys in place + GaussianFactorOrdered::shared_ptr antifactor = factor_->negate(); // already has keys in place return NonlinearFactor::shared_ptr(new LinearContainerFactor(antifactor,linearizationPoint_)); } /* ************************************************************************* */ NonlinearFactorGraph LinearContainerFactor::convertLinearGraph( - const GaussianFactorGraph& linear_graph, const Ordering& ordering, + const GaussianFactorGraphOrdered& linear_graph, const OrderingOrdered& ordering, const Values& linearizationPoint) { NonlinearFactorGraph result; - BOOST_FOREACH(const GaussianFactor::shared_ptr& f, linear_graph) + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& f, linear_graph) if (f) result.push_back(NonlinearFactorGraph::sharedFactor( new LinearContainerFactor(f, ordering, linearizationPoint))); diff --git a/gtsam/nonlinear/LinearContainerFactor.h b/gtsam/nonlinear/LinearContainerFactor.h index cc87e278a..a3ab53cec 100644 --- a/gtsam/nonlinear/LinearContainerFactor.h +++ b/gtsam/nonlinear/LinearContainerFactor.h @@ -9,7 +9,7 @@ #pragma once -#include +#include #include namespace gtsam { @@ -23,37 +23,37 @@ namespace gtsam { class GTSAM_EXPORT LinearContainerFactor : public NonlinearFactor { protected: - GaussianFactor::shared_ptr factor_; + GaussianFactorOrdered::shared_ptr factor_; boost::optional linearizationPoint_; /** Default constructor - necessary for serialization */ LinearContainerFactor() {} /** direct copy constructor */ - LinearContainerFactor(const GaussianFactor::shared_ptr& factor, + LinearContainerFactor(const GaussianFactorOrdered::shared_ptr& factor, const boost::optional& linearizationPoint); public: /** Primary constructor: store a linear factor and decode the ordering */ - LinearContainerFactor(const JacobianFactor& factor, const Ordering& ordering, + LinearContainerFactor(const JacobianFactorOrdered& factor, const OrderingOrdered& ordering, const Values& linearizationPoint = Values()); /** Primary constructor: store a linear factor and decode the ordering */ - LinearContainerFactor(const HessianFactor& factor, const Ordering& ordering, + LinearContainerFactor(const HessianFactorOrdered& factor, const OrderingOrdered& ordering, const Values& linearizationPoint = Values()); /** Constructor from shared_ptr */ - LinearContainerFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering, + LinearContainerFactor(const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering, const Values& linearizationPoint = Values()); /** Constructor from re-keyed factor: all indices assumed replaced with Key */ - LinearContainerFactor(const GaussianFactor::shared_ptr& factor, + LinearContainerFactor(const GaussianFactorOrdered::shared_ptr& factor, const Values& linearizationPoint = Values()); // Access - const GaussianFactor::shared_ptr& factor() const { return factor_; } + const GaussianFactorOrdered::shared_ptr& factor() const { return factor_; } // Testable @@ -82,7 +82,7 @@ public: const boost::optional& linearizationPoint() const { return linearizationPoint_; } /** Apply the ordering to a graph - same as linearize(), but without needing a linearization point */ - GaussianFactor::shared_ptr order(const Ordering& ordering) const; + GaussianFactorOrdered::shared_ptr order(const OrderingOrdered& ordering) const; /** * Linearize to a GaussianFactor, with method depending on the presence of a linearizationPoint @@ -101,12 +101,12 @@ public: * TODO: better approximation of relinearization * TODO: switchable modes for approximation technique */ - GaussianFactor::shared_ptr linearize(const Values& c, const Ordering& ordering) const; + GaussianFactorOrdered::shared_ptr linearize(const Values& c, const OrderingOrdered& ordering) const; /** * Creates an anti-factor directly and performs rekeying due to ordering */ - GaussianFactor::shared_ptr negate(const Ordering& ordering) const; + GaussianFactorOrdered::shared_ptr negate(const OrderingOrdered& ordering) const; /** * Creates the equivalent anti-factor as another LinearContainerFactor, @@ -135,20 +135,20 @@ public: bool isHessian() const; /** Casts to JacobianFactor */ - JacobianFactor::shared_ptr toJacobian() const; + JacobianFactorOrdered::shared_ptr toJacobian() const; /** Casts to HessianFactor */ - HessianFactor::shared_ptr toHessian() const; + HessianFactorOrdered::shared_ptr toHessian() const; /** * Utility function for converting linear graphs to nonlinear graphs * consisting of LinearContainerFactors. */ - static NonlinearFactorGraph convertLinearGraph(const GaussianFactorGraph& linear_graph, - const Ordering& ordering, const Values& linearizationPoint = Values()); + static NonlinearFactorGraph convertLinearGraph(const GaussianFactorGraphOrdered& linear_graph, + const OrderingOrdered& ordering, const Values& linearizationPoint = Values()); protected: - void rekeyFactor(const Ordering& ordering); + void rekeyFactor(const OrderingOrdered& ordering); void initializeLinearizationPoint(const Values& linearizationPoint); private: diff --git a/gtsam/nonlinear/Marginals.cpp b/gtsam/nonlinear/Marginals.cpp index 466a20a84..64e450dec 100644 --- a/gtsam/nonlinear/Marginals.cpp +++ b/gtsam/nonlinear/Marginals.cpp @@ -66,11 +66,11 @@ Matrix Marginals::marginalInformation(Key variable) const { Index index = ordering_[variable]; // Compute marginal - GaussianFactor::shared_ptr marginalFactor; + GaussianFactorOrdered::shared_ptr marginalFactor; if(factorization_ == CHOLESKY) - marginalFactor = bayesTree_.marginalFactor(index, EliminatePreferCholesky); + marginalFactor = bayesTree_.marginalFactor(index, EliminatePreferCholeskyOrdered); else if(factorization_ == QR) - marginalFactor = bayesTree_.marginalFactor(index, EliminateQR); + marginalFactor = bayesTree_.marginalFactor(index, EliminateQROrdered); // Get information matrix (only store upper-right triangle) gttic(AsMatrix); @@ -106,7 +106,7 @@ JointMarginal Marginals::jointMarginalInformation(const std::vector& variab Matrix info = marginalInformation(variables.front()); std::vector dims; dims.push_back(info.rows()); - Ordering indices; + OrderingOrdered indices; indices.insert(variables.front(), 0); return JointMarginal(info, dims, indices); @@ -116,12 +116,12 @@ JointMarginal Marginals::jointMarginalInformation(const std::vector& variab for(size_t i=0; i& variab // Build map from variable keys to position in factor graph variables, // which are sorted in index order. - Ordering variableConversion; + OrderingOrdered variableConversion; { // First build map from index to key FastMap usedIndices; @@ -164,7 +164,7 @@ JointMarginal Marginals::jointMarginalInformation(const std::vector& variab void JointMarginal::print(const std::string& s, const KeyFormatter& formatter) const { cout << s << "Joint marginal on keys "; bool first = true; - BOOST_FOREACH(const Ordering::value_type& key_index, indices_) { + BOOST_FOREACH(const OrderingOrdered::value_type& key_index, indices_) { if(!first) cout << ", "; else diff --git a/gtsam/nonlinear/Marginals.h b/gtsam/nonlinear/Marginals.h index 94876dcf9..0a60cf7f9 100644 --- a/gtsam/nonlinear/Marginals.h +++ b/gtsam/nonlinear/Marginals.h @@ -19,7 +19,7 @@ #pragma once #include -#include +#include #include #include @@ -42,11 +42,11 @@ public: protected: - GaussianFactorGraph graph_; - Ordering ordering_; + GaussianFactorGraphOrdered graph_; + OrderingOrdered ordering_; Values values_; Factorization factorization_; - GaussianBayesTree bayesTree_; + GaussianBayesTreeOrdered bayesTree_; public: @@ -86,7 +86,7 @@ protected: Matrix fullMatrix_; BlockView blockView_; - Ordering indices_; + OrderingOrdered indices_; public: /** A block view of the joint marginal - this stores a reference to the @@ -133,7 +133,7 @@ public: void print(const std::string& s = "", const KeyFormatter& formatter = DefaultKeyFormatter) const; protected: - JointMarginal(const Matrix& fullMatrix, const std::vector& dims, const Ordering& indices) : + JointMarginal(const Matrix& fullMatrix, const std::vector& dims, const OrderingOrdered& indices) : fullMatrix_(fullMatrix), blockView_(fullMatrix_, dims.begin(), dims.end()), indices_(indices) {} friend class Marginals; diff --git a/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.cpp b/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.cpp index 90f663639..9a34f1b6d 100644 --- a/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.cpp +++ b/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.cpp @@ -6,10 +6,10 @@ */ #include -#include +#include #include -#include -#include +#include +#include #include @@ -19,15 +19,15 @@ namespace gtsam { /* Return the gradient vector of a nonlinear factor given a linearization point and a variable ordering * Can be moved to NonlinearFactorGraph.h if desired */ -void gradientInPlace(const NonlinearFactorGraph &nfg, const Values &values, const Ordering &ordering, VectorValues &g) { +void gradientInPlace(const NonlinearFactorGraph &nfg, const Values &values, const OrderingOrdered &ordering, VectorValuesOrdered &g) { // Linearize graph - GaussianFactorGraph::shared_ptr linear = nfg.linearize(values, ordering); - FactorGraph jfg; jfg.reserve(linear->size()); - BOOST_FOREACH(const GaussianFactorGraph::sharedFactor& factor, *linear) { - if(boost::shared_ptr jf = boost::dynamic_pointer_cast(factor)) + GaussianFactorGraphOrdered::shared_ptr linear = nfg.linearize(values, ordering); + FactorGraphOrdered jfg; jfg.reserve(linear->size()); + BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, *linear) { + if(boost::shared_ptr jf = boost::dynamic_pointer_cast(factor)) jfg.push_back((jf)); else - jfg.push_back(boost::make_shared(*factor)); + jfg.push_back(boost::make_shared(*factor)); } // compute the gradient direction gradientAtZero(jfg, g); diff --git a/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h b/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h index 4cb5be573..767d6b999 100644 --- a/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h +++ b/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h @@ -26,15 +26,15 @@ class GTSAM_EXPORT NonlinearConjugateGradientOptimizer : public NonlinearOptimiz class System { public: typedef Values State; - typedef VectorValues Gradient; + typedef VectorValuesOrdered Gradient; typedef NonlinearOptimizerParams Parameters; protected: const NonlinearFactorGraph &graph_; - const Ordering &ordering_; + const OrderingOrdered &ordering_; public: - System(const NonlinearFactorGraph &graph, const Ordering &ordering): graph_(graph), ordering_(ordering) {} + System(const NonlinearFactorGraph &graph, const OrderingOrdered &ordering): graph_(graph), ordering_(ordering) {} double error(const State &state) const ; Gradient gradient(const State &state) const ; State advance(const State ¤t, const double alpha, const Gradient &g) const ; @@ -49,15 +49,15 @@ public: protected: States state_; Parameters params_; - Ordering::shared_ptr ordering_; - VectorValues::shared_ptr gradient_; + OrderingOrdered::shared_ptr ordering_; + VectorValuesOrdered::shared_ptr gradient_; public: NonlinearConjugateGradientOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const Parameters& params = Parameters()) : Base(graph), state_(graph, initialValues), params_(params), ordering_(initialValues.orderingArbitrary()), - gradient_(new VectorValues(initialValues.zeroVectors(*ordering_))){} + gradient_(new VectorValuesOrdered(initialValues.zeroVectors(*ordering_))){} virtual ~NonlinearConjugateGradientOptimizer() {} virtual void iterate(); diff --git a/gtsam/nonlinear/NonlinearEquality.h b/gtsam/nonlinear/NonlinearEquality.h index faee280b1..3bd7df529 100644 --- a/gtsam/nonlinear/NonlinearEquality.h +++ b/gtsam/nonlinear/NonlinearEquality.h @@ -153,12 +153,12 @@ namespace gtsam { } // Linearize is over-written, because base linearization tries to whiten - virtual GaussianFactor::shared_ptr linearize(const Values& x, const Ordering& ordering) const { + virtual GaussianFactorOrdered::shared_ptr linearize(const Values& x, const OrderingOrdered& ordering) const { const T& xj = x.at(this->key()); Matrix A; Vector b = evaluateError(xj, A); SharedDiagonal model = noiseModel::Constrained::All(b.size()); - return GaussianFactor::shared_ptr(new JacobianFactor(ordering[this->key()], A, b, model)); + return GaussianFactorOrdered::shared_ptr(new JacobianFactorOrdered(ordering[this->key()], A, b, model)); } /// @return a deep copy of this factor diff --git a/gtsam/nonlinear/NonlinearFactor.h b/gtsam/nonlinear/NonlinearFactor.h index 8b9b2a5da..1f181a5a9 100644 --- a/gtsam/nonlinear/NonlinearFactor.h +++ b/gtsam/nonlinear/NonlinearFactor.h @@ -26,13 +26,13 @@ #include #include -#include -#include +#include +#include #include -#include +#include #include -#include +#include /** * Macro to add a standard clone function to a derived factor @@ -54,12 +54,12 @@ namespace gtsam { * which are objects in non-linear manifolds (Lie groups). * \nosubgrouping */ -class NonlinearFactor: public Factor { +class NonlinearFactor: public FactorOrdered { protected: // Some handy typedefs - typedef Factor Base; + typedef FactorOrdered Base; typedef NonlinearFactor This; public: @@ -140,18 +140,18 @@ public: virtual bool active(const Values& c) const { return true; } /** linearize to a GaussianFactor */ - virtual boost::shared_ptr - linearize(const Values& c, const Ordering& ordering) const = 0; + virtual boost::shared_ptr + linearize(const Values& c, const OrderingOrdered& ordering) const = 0; /** * Create a symbolic factor using the given ordering to determine the * variable indices. */ - virtual IndexFactor::shared_ptr symbolic(const Ordering& ordering) const { + virtual IndexFactorOrdered::shared_ptr symbolic(const OrderingOrdered& ordering) const { std::vector indices(this->size()); for(size_t j=0; jsize(); ++j) indices[j] = ordering[this->keys()[j]]; - return IndexFactor::shared_ptr(new IndexFactor(indices)); + return IndexFactorOrdered::shared_ptr(new IndexFactorOrdered(indices)); } /** @@ -314,10 +314,10 @@ public: * \f$ Ax-b \approx h(x+\delta x)-z = h(x) + A \delta x - z \f$ * Hence \f$ b = z - h(x) = - \mathtt{error\_vector}(x) \f$ */ - boost::shared_ptr linearize(const Values& x, const Ordering& ordering) const { + boost::shared_ptr linearize(const Values& x, const OrderingOrdered& ordering) const { // Only linearize if the factor is active if (!this->active(x)) - return boost::shared_ptr(); + return boost::shared_ptr(); // Create the set of terms - Jacobians for each index Vector b; @@ -340,11 +340,11 @@ public: noiseModel::Constrained::shared_ptr constrained = boost::dynamic_pointer_cast(this->noiseModel_); if(constrained) - return GaussianFactor::shared_ptr( - new JacobianFactor(terms, b, constrained->unit())); + return GaussianFactorOrdered::shared_ptr( + new JacobianFactorOrdered(terms, b, constrained->unit())); else - return GaussianFactor::shared_ptr( - new JacobianFactor(terms, b, noiseModel::Unit::Create(b.size()))); + return GaussianFactorOrdered::shared_ptr( + new JacobianFactorOrdered(terms, b, noiseModel::Unit::Create(b.size()))); } private: diff --git a/gtsam/nonlinear/NonlinearFactorGraph.cpp b/gtsam/nonlinear/NonlinearFactorGraph.cpp index 66a658f25..b85ebe5f6 100644 --- a/gtsam/nonlinear/NonlinearFactorGraph.cpp +++ b/gtsam/nonlinear/NonlinearFactorGraph.cpp @@ -20,8 +20,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -207,18 +207,18 @@ FastSet NonlinearFactorGraph::keys() const { } /* ************************************************************************* */ -Ordering::shared_ptr NonlinearFactorGraph::orderingCOLAMD( +OrderingOrdered::shared_ptr NonlinearFactorGraph::orderingCOLAMD( const Values& config) const { gttic(NonlinearFactorGraph_orderingCOLAMD); // Create symbolic graph and initial (iterator) ordering - SymbolicFactorGraph::shared_ptr symbolic; - Ordering::shared_ptr ordering; + SymbolicFactorGraphOrdered::shared_ptr symbolic; + OrderingOrdered::shared_ptr ordering; boost::tie(symbolic, ordering) = this->symbolic(config); // Compute the VariableIndex (column-wise index) - VariableIndex variableIndex(*symbolic, ordering->size()); + VariableIndexOrdered variableIndex(*symbolic, ordering->size()); if (config.size() != variableIndex.size()) throw std::runtime_error( "orderingCOLAMD: some variables in the graph are not constrained!"); @@ -232,18 +232,18 @@ Ordering::shared_ptr NonlinearFactorGraph::orderingCOLAMD( } /* ************************************************************************* */ -Ordering::shared_ptr NonlinearFactorGraph::orderingCOLAMDConstrained(const Values& config, +OrderingOrdered::shared_ptr NonlinearFactorGraph::orderingCOLAMDConstrained(const Values& config, const std::map& constraints) const { gttic(NonlinearFactorGraph_orderingCOLAMDConstrained); // Create symbolic graph and initial (iterator) ordering - SymbolicFactorGraph::shared_ptr symbolic; - Ordering::shared_ptr ordering; + SymbolicFactorGraphOrdered::shared_ptr symbolic; + OrderingOrdered::shared_ptr ordering; boost::tie(symbolic, ordering) = this->symbolic(config); // Compute the VariableIndex (column-wise index) - VariableIndex variableIndex(*symbolic, ordering->size()); + VariableIndexOrdered variableIndex(*symbolic, ordering->size()); if (config.size() != variableIndex.size()) throw std::runtime_error( "orderingCOLAMD: some variables in the graph are not constrained!"); @@ -263,51 +263,51 @@ Ordering::shared_ptr NonlinearFactorGraph::orderingCOLAMDConstrained(const Value } /* ************************************************************************* */ -SymbolicFactorGraph::shared_ptr NonlinearFactorGraph::symbolic(const Ordering& ordering) const { +SymbolicFactorGraphOrdered::shared_ptr NonlinearFactorGraph::symbolic(const OrderingOrdered& ordering) const { gttic(NonlinearFactorGraph_symbolic_from_Ordering); // Generate the symbolic factor graph - SymbolicFactorGraph::shared_ptr symbolicfg(new SymbolicFactorGraph); + SymbolicFactorGraphOrdered::shared_ptr symbolicfg(new SymbolicFactorGraphOrdered); symbolicfg->reserve(this->size()); BOOST_FOREACH(const sharedFactor& factor, this->factors_) { if(factor) symbolicfg->push_back(factor->symbolic(ordering)); else - symbolicfg->push_back(SymbolicFactorGraph::sharedFactor()); + symbolicfg->push_back(SymbolicFactorGraphOrdered::sharedFactor()); } return symbolicfg; } /* ************************************************************************* */ -pair NonlinearFactorGraph::symbolic( +pair NonlinearFactorGraph::symbolic( const Values& config) const { gttic(NonlinearFactorGraph_symbolic_from_Values); // Generate an initial key ordering in iterator order - Ordering::shared_ptr ordering(config.orderingArbitrary()); + OrderingOrdered::shared_ptr ordering(config.orderingArbitrary()); return make_pair(symbolic(*ordering), ordering); } /* ************************************************************************* */ -GaussianFactorGraph::shared_ptr NonlinearFactorGraph::linearize( - const Values& config, const Ordering& ordering) const +GaussianFactorGraphOrdered::shared_ptr NonlinearFactorGraph::linearize( + const Values& config, const OrderingOrdered& ordering) const { gttic(NonlinearFactorGraph_linearize); // create an empty linear FG - GaussianFactorGraph::shared_ptr linearFG(new GaussianFactorGraph); + GaussianFactorGraphOrdered::shared_ptr linearFG(new GaussianFactorGraphOrdered); linearFG->reserve(this->size()); // linearize all factors BOOST_FOREACH(const sharedFactor& factor, this->factors_) { if(factor) { - GaussianFactor::shared_ptr lf = factor->linearize(config, ordering); + GaussianFactorOrdered::shared_ptr lf = factor->linearize(config, ordering); if (lf) linearFG->push_back(lf); } else - linearFG->push_back(GaussianFactor::shared_ptr()); + linearFG->push_back(GaussianFactorOrdered::shared_ptr()); } return linearFG; diff --git a/gtsam/nonlinear/NonlinearFactorGraph.h b/gtsam/nonlinear/NonlinearFactorGraph.h index 0bb9e4bde..8af5ff91b 100644 --- a/gtsam/nonlinear/NonlinearFactorGraph.h +++ b/gtsam/nonlinear/NonlinearFactorGraph.h @@ -22,8 +22,8 @@ #pragma once #include -#include -#include +#include +#include #include namespace gtsam { @@ -58,11 +58,11 @@ namespace gtsam { * tangent vector space at the linearization point. Because the tangent space is a true * vector space, the config type will be an VectorValues in that linearized factor graph. */ - class NonlinearFactorGraph: public FactorGraph { + class NonlinearFactorGraph: public FactorGraphOrdered { public: - typedef FactorGraph Base; + typedef FactorGraphOrdered Base; typedef boost::shared_ptr shared_ptr; typedef boost::shared_ptr sharedFactor; @@ -96,7 +96,7 @@ namespace gtsam { /** * Create a symbolic factor graph using an existing ordering */ - GTSAM_EXPORT SymbolicFactorGraph::shared_ptr symbolic(const Ordering& ordering) const; + GTSAM_EXPORT SymbolicFactorGraphOrdered::shared_ptr symbolic(const OrderingOrdered& ordering) const; /** * Create a symbolic factor graph and initial variable ordering that can @@ -104,13 +104,13 @@ namespace gtsam { * The graph and ordering should be permuted after such a fill-reducing * ordering is found. */ - GTSAM_EXPORT std::pair + GTSAM_EXPORT std::pair symbolic(const Values& config) const; /** * Compute a fill-reducing ordering using COLAMD. */ - GTSAM_EXPORT Ordering::shared_ptr orderingCOLAMD(const Values& config) const; + GTSAM_EXPORT OrderingOrdered::shared_ptr orderingCOLAMD(const Values& config) const; /** * Compute a fill-reducing ordering with constraints using CCOLAMD @@ -120,14 +120,14 @@ namespace gtsam { * indices need to appear in the constraints, unconstrained is assumed for all * other variables */ - GTSAM_EXPORT Ordering::shared_ptr orderingCOLAMDConstrained(const Values& config, + GTSAM_EXPORT OrderingOrdered::shared_ptr orderingCOLAMDConstrained(const Values& config, const std::map& constraints) const; /** * linearize a nonlinear factor graph */ - GTSAM_EXPORT boost::shared_ptr - linearize(const Values& config, const Ordering& ordering) const; + GTSAM_EXPORT boost::shared_ptr + linearize(const Values& config, const OrderingOrdered& ordering) const; /** * Clone() performs a deep-copy of the graph, including all of the factors diff --git a/gtsam/nonlinear/NonlinearISAM.cpp b/gtsam/nonlinear/NonlinearISAM.cpp index 214c1c887..413d554eb 100644 --- a/gtsam/nonlinear/NonlinearISAM.cpp +++ b/gtsam/nonlinear/NonlinearISAM.cpp @@ -17,9 +17,9 @@ #include -#include -#include -#include +#include +#include +#include #include @@ -58,7 +58,7 @@ void NonlinearISAM::update(const NonlinearFactorGraph& newFactors, BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, initialValues) ordering_.insert(key_value.key, ordering_.size()); - boost::shared_ptr linearizedNewFactors = newFactors.linearize(linPoint_, ordering_); + boost::shared_ptr linearizedNewFactors = newFactors.linearize(linPoint_, ordering_); // Update ISAM isam_.update(*linearizedNewFactors); @@ -82,7 +82,7 @@ void NonlinearISAM::reorder_relinearize() { // Create a linear factor graph at the new linearization point // TODO: decouple relinearization and reordering to avoid - boost::shared_ptr gfg = factors_.linearize(newLinPoint, ordering_); + boost::shared_ptr gfg = factors_.linearize(newLinPoint, ordering_); // Just recreate the whole BayesTree isam_.update(*gfg); diff --git a/gtsam/nonlinear/NonlinearISAM.h b/gtsam/nonlinear/NonlinearISAM.h index ba7393d81..02afcd3d4 100644 --- a/gtsam/nonlinear/NonlinearISAM.h +++ b/gtsam/nonlinear/NonlinearISAM.h @@ -18,7 +18,7 @@ #pragma once #include -#include +#include namespace gtsam { /** @@ -28,13 +28,13 @@ class GTSAM_EXPORT NonlinearISAM { protected: /** The internal iSAM object */ - gtsam::GaussianISAM isam_; + gtsam::GaussianISAMOrdered isam_; /** The current linearization point */ Values linPoint_; /** The ordering */ - gtsam::Ordering ordering_; + gtsam::OrderingOrdered ordering_; /** The original factors, used when relinearizing */ NonlinearFactorGraph factors_; @@ -70,13 +70,13 @@ public: // access /** access the underlying bayes tree */ - const GaussianISAM& bayesTree() const { return isam_; } + const GaussianISAMOrdered& bayesTree() const { return isam_; } /** Return the current linearization point */ const Values& getLinearizationPoint() const { return linPoint_; } /** Get the ordering */ - const gtsam::Ordering& getOrdering() const { return ordering_; } + const gtsam::OrderingOrdered& getOrdering() const { return ordering_; } /** get underlying nonlinear graph */ const NonlinearFactorGraph& getFactorsUnsafe() const { return factors_; } @@ -108,7 +108,7 @@ public: void addKey(Key key) { ordering_.push_back(key); } /** replace the current ordering */ - void setOrdering(const Ordering& new_ordering) { ordering_ = new_ordering; } + void setOrdering(const OrderingOrdered& new_ordering) { ordering_ = new_ordering; } /// @} diff --git a/gtsam/nonlinear/Ordering.cpp b/gtsam/nonlinear/OrderingOrdered.cpp similarity index 85% rename from gtsam/nonlinear/Ordering.cpp rename to gtsam/nonlinear/OrderingOrdered.cpp index 4ab3a2b75..8bece926f 100644 --- a/gtsam/nonlinear/Ordering.cpp +++ b/gtsam/nonlinear/OrderingOrdered.cpp @@ -15,7 +15,7 @@ * @date Sep 2, 2010 */ -#include "Ordering.h" +#include #include #include @@ -26,20 +26,20 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ -Ordering::Ordering(const std::list & L) { +OrderingOrdered::OrderingOrdered(const std::list & L) { int i = 0; BOOST_FOREACH( Key s, L ) insert(s, i++) ; } /* ************************************************************************* */ -Ordering::Ordering(const Ordering& other) : order_(other.order_), orderingIndex_(other.size()) { +OrderingOrdered::OrderingOrdered(const OrderingOrdered& other) : order_(other.order_), orderingIndex_(other.size()) { for(iterator item = order_.begin(); item != order_.end(); ++item) orderingIndex_[item->second] = item; } /* ************************************************************************* */ -Ordering& Ordering::operator=(const Ordering& rhs) { +OrderingOrdered& OrderingOrdered::operator=(const OrderingOrdered& rhs) { order_ = rhs.order_; orderingIndex_.resize(rhs.size()); for(iterator item = order_.begin(); item != order_.end(); ++item) @@ -48,7 +48,7 @@ Ordering& Ordering::operator=(const Ordering& rhs) { } /* ************************************************************************* */ -void Ordering::permuteInPlace(const Permutation& permutation) { +void OrderingOrdered::permuteInPlace(const Permutation& permutation) { gttic(Ordering_permuteInPlace); // Allocate new index and permute in map iterators OrderingIndex newIndex(permutation.size()); @@ -61,7 +61,7 @@ void Ordering::permuteInPlace(const Permutation& permutation) { } /* ************************************************************************* */ -void Ordering::permuteInPlace(const Permutation& selector, const Permutation& permutation) { +void OrderingOrdered::permuteInPlace(const Permutation& selector, const Permutation& permutation) { if(selector.size() != permutation.size()) throw invalid_argument("Ordering::permuteInPlace (partial permutation version) called with selector and permutation of different sizes."); // Create new index the size of the permuted entries @@ -77,7 +77,7 @@ void Ordering::permuteInPlace(const Permutation& selector, const Permutation& pe } /* ************************************************************************* */ -void Ordering::print(const string& str, const KeyFormatter& keyFormatter) const { +void OrderingOrdered::print(const string& str, const KeyFormatter& keyFormatter) const { cout << str; // Print ordering in index order // Print the ordering with varsPerLine ordering entries printed on each line, @@ -101,12 +101,12 @@ void Ordering::print(const string& str, const KeyFormatter& keyFormatter) const } /* ************************************************************************* */ -bool Ordering::equals(const Ordering& rhs, double tol) const { +bool OrderingOrdered::equals(const OrderingOrdered& rhs, double tol) const { return order_ == rhs.order_; } /* ************************************************************************* */ -Ordering::value_type Ordering::pop_back() { +OrderingOrdered::value_type OrderingOrdered::pop_back() { iterator lastItem = orderingIndex_.back(); // Get the map iterator to the highest-index entry value_type removed = *lastItem; // Save the key-index pair to return order_.erase(lastItem); // Erase the entry from the map diff --git a/gtsam/nonlinear/Ordering.h b/gtsam/nonlinear/OrderingOrdered.h similarity index 93% rename from gtsam/nonlinear/Ordering.h rename to gtsam/nonlinear/OrderingOrdered.h index 0c3d276ad..f47077975 100644 --- a/gtsam/nonlinear/Ordering.h +++ b/gtsam/nonlinear/OrderingOrdered.h @@ -18,7 +18,7 @@ #pragma once #include -#include +#include #include #include @@ -32,7 +32,7 @@ namespace gtsam { * An ordering is a map from symbols (non-typed keys) to integer indices * \nosubgrouping */ -class GTSAM_EXPORT Ordering { +class GTSAM_EXPORT OrderingOrdered { protected: typedef FastMap Map; typedef std::vector OrderingIndex; @@ -41,7 +41,7 @@ protected: public: - typedef boost::shared_ptr shared_ptr; + typedef boost::shared_ptr shared_ptr; typedef std::pair value_type; typedef Map::iterator iterator; @@ -51,16 +51,16 @@ public: /// @{ /// Default constructor for empty ordering - Ordering() {} + OrderingOrdered() {} /// Copy constructor - Ordering(const Ordering& other); + OrderingOrdered(const OrderingOrdered& other); /// Construct from list, assigns order indices sequentially to list items. - Ordering(const std::list & L); + OrderingOrdered(const std::list & L); /// Assignment operator - Ordering& operator=(const Ordering& rhs); + OrderingOrdered& operator=(const OrderingOrdered& rhs); /// @} /// @name Standard Interface @@ -179,9 +179,9 @@ public: * very useful for unit tests. This functionality is courtesy of * boost::assign. */ - inline boost::assign::list_inserter, Key> + inline boost::assign::list_inserter, Key> operator+=(Key key) { - return boost::assign::make_list_inserter(boost::assign_detail::call_push_back(*this))(key); } + return boost::assign::make_list_inserter(boost::assign_detail::call_push_back(*this))(key); } /** * Reorder the variables with a permutation. This is typically used @@ -203,7 +203,7 @@ public: void print(const std::string& str = "Ordering:\n", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; /** equals (from Testable) for testing and debugging */ - bool equals(const Ordering& rhs, double tol = 0.0) const; + bool equals(const OrderingOrdered& rhs, double tol = 0.0) const; /// @} @@ -211,24 +211,24 @@ private: /** Serialization function */ friend class boost::serialization::access; - template - void save(ARCHIVE & ar, const unsigned int version) const - { + template + void save(ARCHIVE & ar, const unsigned int version) const + { ar & BOOST_SERIALIZATION_NVP(order_); size_t size_ = orderingIndex_.size(); // Save only the size but not the iterators ar & BOOST_SERIALIZATION_NVP(size_); - } - template - void load(ARCHIVE & ar, const unsigned int version) - { + } + template + void load(ARCHIVE & ar, const unsigned int version) + { ar & BOOST_SERIALIZATION_NVP(order_); size_t size_; ar & BOOST_SERIALIZATION_NVP(size_); orderingIndex_.resize(size_); for(iterator item = order_.begin(); item != order_.end(); ++item) orderingIndex_[item->second] = item; // Assign the iterators - } - BOOST_SERIALIZATION_SPLIT_MEMBER() + } + BOOST_SERIALIZATION_SPLIT_MEMBER() }; // \class Ordering /** @@ -258,10 +258,10 @@ public: // formats the key using the provided key formatter, used in saveGraph. class GTSAM_EXPORT OrderingIndexFormatter { private: - Ordering ordering_; + OrderingOrdered ordering_; KeyFormatter keyFormatter_; public: - OrderingIndexFormatter(const Ordering& ordering, const KeyFormatter& keyFormatter) : + OrderingIndexFormatter(const OrderingOrdered& ordering, const KeyFormatter& keyFormatter) : ordering_(ordering), keyFormatter_(keyFormatter) {} std::string operator()(Index index) { return keyFormatter_(ordering_.key(index)); } @@ -269,7 +269,7 @@ public: /// Version of orderingIndexFormatter using multi-robot formatter struct GTSAM_EXPORT MultiRobotLinearFormatter : gtsam::OrderingIndexFormatter { - MultiRobotLinearFormatter(const gtsam::Ordering& ordering) + MultiRobotLinearFormatter(const gtsam::OrderingOrdered& ordering) : gtsam::OrderingIndexFormatter(ordering, MultiRobotKeyFormatter) {} }; diff --git a/gtsam/nonlinear/SuccessiveLinearizationOptimizer.cpp b/gtsam/nonlinear/SuccessiveLinearizationOptimizer.cpp index 0e8e4d748..1a08068f3 100644 --- a/gtsam/nonlinear/SuccessiveLinearizationOptimizer.cpp +++ b/gtsam/nonlinear/SuccessiveLinearizationOptimizer.cpp @@ -6,10 +6,10 @@ */ #include -#include -#include +#include +#include #include -#include +#include #include #include @@ -53,14 +53,14 @@ void SuccessiveLinearizationParams::print(const std::string& str) const { std::cout.flush(); } -VectorValues solveGaussianFactorGraph(const GaussianFactorGraph &gfg, const SuccessiveLinearizationParams ¶ms) { +VectorValuesOrdered solveGaussianFactorGraph(const GaussianFactorGraphOrdered &gfg, const SuccessiveLinearizationParams ¶ms) { gttic(solveGaussianFactorGraph); - VectorValues delta; + VectorValuesOrdered delta; if (params.isMultifrontal()) { - delta = GaussianJunctionTree(gfg).optimize(params.getEliminationFunction()); + delta = GaussianJunctionTreeOrdered(gfg).optimize(params.getEliminationFunction()); } else if(params.isSequential()) { - const boost::shared_ptr gbn = - EliminationTree::Create(gfg)->eliminate(params.getEliminationFunction()); + const boost::shared_ptr gbn = + EliminationTreeOrdered::Create(gfg)->eliminate(params.getEliminationFunction()); delta = gtsam::optimize(*gbn); } else if ( params.isCG() ) { diff --git a/gtsam/nonlinear/SuccessiveLinearizationOptimizer.h b/gtsam/nonlinear/SuccessiveLinearizationOptimizer.h index bdedd1987..a4e5c2e72 100644 --- a/gtsam/nonlinear/SuccessiveLinearizationOptimizer.h +++ b/gtsam/nonlinear/SuccessiveLinearizationOptimizer.h @@ -36,7 +36,7 @@ public: }; LinearSolverType linearSolverType; ///< The type of linear solver to use in the nonlinear optimizer - boost::optional ordering; ///< The variable elimination ordering, or empty to use COLAMD (default: empty) + boost::optional ordering; ///< The variable elimination ordering, or empty to use COLAMD (default: empty) IterativeOptimizationParameters::shared_ptr iterativeParams; ///< The container for iterativeOptimization parameters. used in CG Solvers. SuccessiveLinearizationParams() : linearSolverType(MULTIFRONTAL_CHOLESKY) {} @@ -54,19 +54,19 @@ public: virtual void print(const std::string& str) const; - GaussianFactorGraph::Eliminate getEliminationFunction() const { + GaussianFactorGraphOrdered::Eliminate getEliminationFunction() const { switch (linearSolverType) { case MULTIFRONTAL_CHOLESKY: case SEQUENTIAL_CHOLESKY: - return EliminatePreferCholesky; + return EliminatePreferCholeskyOrdered; case MULTIFRONTAL_QR: case SEQUENTIAL_QR: - return EliminateQR; + return EliminateQROrdered; default: throw std::runtime_error("Nonlinear optimization parameter \"factorization\" is invalid"); - return EliminateQR; + return EliminateQROrdered; break; } } @@ -75,7 +75,7 @@ public: void setLinearSolverType(const std::string& solver) { linearSolverType = linearSolverTranslator(solver); } void setIterativeParams(const SubgraphSolverParameters ¶ms); - void setOrdering(const Ordering& ordering) { this->ordering = ordering; } + void setOrdering(const OrderingOrdered& ordering) { this->ordering = ordering; } private: std::string linearSolverTranslator(LinearSolverType linearSolverType) const { @@ -101,6 +101,6 @@ private: }; /* a wrapper for solving a GaussianFactorGraph according to the parameters */ -GTSAM_EXPORT VectorValues solveGaussianFactorGraph(const GaussianFactorGraph &gfg, const SuccessiveLinearizationParams ¶ms) ; +GTSAM_EXPORT VectorValuesOrdered solveGaussianFactorGraph(const GaussianFactorGraphOrdered &gfg, const SuccessiveLinearizationParams ¶ms) ; } /* namespace gtsam */ diff --git a/gtsam/nonlinear/Values.cpp b/gtsam/nonlinear/Values.cpp index b95e8932a..f962d24bb 100644 --- a/gtsam/nonlinear/Values.cpp +++ b/gtsam/nonlinear/Values.cpp @@ -76,12 +76,12 @@ namespace gtsam { } /* ************************************************************************* */ - VectorValues Values::zeroVectors(const Ordering& ordering) const { - return VectorValues::Zero(this->dims(ordering)); + VectorValuesOrdered Values::zeroVectors(const OrderingOrdered& ordering) const { + return VectorValuesOrdered::Zero(this->dims(ordering)); } /* ************************************************************************* */ - Values Values::retract(const VectorValues& delta, const Ordering& ordering) const { + Values Values::retract(const VectorValuesOrdered& delta, const OrderingOrdered& ordering) const { Values result; for(const_iterator key_value = begin(); key_value != end(); ++key_value) { @@ -95,8 +95,8 @@ namespace gtsam { } /* ************************************************************************* */ - VectorValues Values::localCoordinates(const Values& cp, const Ordering& ordering) const { - VectorValues result(this->dims(ordering)); + VectorValuesOrdered Values::localCoordinates(const Values& cp, const OrderingOrdered& ordering) const { + VectorValuesOrdered result(this->dims(ordering)); if(this->size() != cp.size()) throw DynamicValuesMismatched(); for(const_iterator it1=this->begin(), it2=cp.begin(); it1!=this->end(); ++it1, ++it2) { @@ -110,7 +110,7 @@ namespace gtsam { } /* ************************************************************************* */ - void Values::localCoordinates(const Values& cp, const Ordering& ordering, VectorValues& result) const { + void Values::localCoordinates(const Values& cp, const OrderingOrdered& ordering, VectorValuesOrdered& result) const { if(this->size() != cp.size()) throw DynamicValuesMismatched(); for(const_iterator it1=this->begin(), it2=cp.begin(); it1!=this->end(); ++it1, ++it2) { @@ -193,7 +193,7 @@ namespace gtsam { } /* ************************************************************************* */ - vector Values::dims(const Ordering& ordering) const { + vector Values::dims(const OrderingOrdered& ordering) const { assert(ordering.size() == this->size()); // reads off of end of array if difference in size vector result(values_.size()); BOOST_FOREACH(const ConstKeyValuePair& key_value, *this) { @@ -212,8 +212,8 @@ namespace gtsam { } /* ************************************************************************* */ - Ordering::shared_ptr Values::orderingArbitrary(Index firstVar) const { - Ordering::shared_ptr ordering(new Ordering); + OrderingOrdered::shared_ptr Values::orderingArbitrary(Index firstVar) const { + OrderingOrdered::shared_ptr ordering(new OrderingOrdered); for(const_iterator key_value = begin(); key_value != end(); ++key_value) { ordering->insert(key_value->key, firstVar++); } diff --git a/gtsam/nonlinear/Values.h b/gtsam/nonlinear/Values.h index c8cd10d20..af8c8b9d6 100644 --- a/gtsam/nonlinear/Values.h +++ b/gtsam/nonlinear/Values.h @@ -45,9 +45,9 @@ #include #include -#include +#include #include -#include +#include namespace gtsam { @@ -207,7 +207,7 @@ namespace gtsam { bool empty() const { return values_.empty(); } /** Get a zero VectorValues of the correct structure */ - VectorValues zeroVectors(const Ordering& ordering) const; + VectorValuesOrdered zeroVectors(const OrderingOrdered& ordering) const; const_iterator begin() const { return boost::make_transform_iterator(values_.begin(), &make_const_deref_pair); } const_iterator end() const { return boost::make_transform_iterator(values_.end(), &make_const_deref_pair); } @@ -222,13 +222,13 @@ namespace gtsam { /// @{ /** Add a delta config to current config and returns a new config */ - Values retract(const VectorValues& delta, const Ordering& ordering) const; + Values retract(const VectorValuesOrdered& delta, const OrderingOrdered& ordering) const; /** Get a delta config about a linearization point c0 (*this) */ - VectorValues localCoordinates(const Values& cp, const Ordering& ordering) const; + VectorValuesOrdered localCoordinates(const Values& cp, const OrderingOrdered& ordering) const; /** Get a delta config about a linearization point c0 (*this) - assumes uninitialized delta */ - void localCoordinates(const Values& cp, const Ordering& ordering, VectorValues& delta) const; + void localCoordinates(const Values& cp, const OrderingOrdered& ordering, VectorValuesOrdered& delta) const; ///@} @@ -263,7 +263,7 @@ namespace gtsam { void clear() { values_.clear(); } /** Create an array of variable dimensions using the given ordering (\f$ O(n) \f$) */ - std::vector dims(const Ordering& ordering) const; + std::vector dims(const OrderingOrdered& ordering) const; /** Compute the total dimensionality of all values (\f$ O(n) \f$) */ size_t dim() const; @@ -274,7 +274,7 @@ namespace gtsam { * NonlinearFactorGraph::orderingCOLAMD(). Alternatively, you may permute * this ordering yourself (as orderingCOLAMD() does internally). */ - Ordering::shared_ptr orderingArbitrary(Index firstVar = 0) const; + OrderingOrdered::shared_ptr orderingArbitrary(Index firstVar = 0) const; /** * Return a filtered view of this Values class, without copying any data. diff --git a/gtsam/nonlinear/WhiteNoiseFactor.h b/gtsam/nonlinear/WhiteNoiseFactor.h index 910444cf8..ad55abe52 100644 --- a/gtsam/nonlinear/WhiteNoiseFactor.h +++ b/gtsam/nonlinear/WhiteNoiseFactor.h @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include @@ -71,7 +71,7 @@ namespace gtsam { * @f] * So f = 2 f(x), g = -df(x), G = ddf(x) */ - static HessianFactor::shared_ptr linearize(double z, double u, double p, + static HessianFactorOrdered::shared_ptr linearize(double z, double u, double p, Index j1, Index j2) { double e = u - z, e2 = e * e; double c = 2 * logSqrt2PI - log(p) + e2 * p; @@ -80,8 +80,8 @@ namespace gtsam { Matrix G11 = Matrix_(1, 1, p); Matrix G12 = Matrix_(1, 1, e); Matrix G22 = Matrix_(1, 1, 0.5 / (p * p)); - return HessianFactor::shared_ptr( - new HessianFactor(j1, j2, G11, G12, g1, G22, g2, c)); + return HessianFactorOrdered::shared_ptr( + new HessianFactorOrdered(j1, j2, G11, G12, g1, G22, g2, c)); } /// @name Standard Constructors @@ -144,9 +144,9 @@ namespace gtsam { * Create a symbolic factor using the given ordering to determine the * variable indices. */ - virtual IndexFactor::shared_ptr symbolic(const Ordering& ordering) const { + virtual IndexFactorOrdered::shared_ptr symbolic(const OrderingOrdered& ordering) const { const Index j1 = ordering[meanKey_], j2 = ordering[precisionKey_]; - return IndexFactor::shared_ptr(new IndexFactor(j1, j2)); + return IndexFactorOrdered::shared_ptr(new IndexFactorOrdered(j1, j2)); } /// @} @@ -154,8 +154,8 @@ namespace gtsam { /// @{ /// linearize returns a Hessianfactor that is an approximation of error(p) - virtual boost::shared_ptr linearize(const Values& x, - const Ordering& ordering) const { + virtual boost::shared_ptr linearize(const Values& x, + const OrderingOrdered& ordering) const { double u = x.at(meanKey_); double p = x.at(precisionKey_); Index j1 = ordering[meanKey_]; diff --git a/gtsam/nonlinear/summarization.cpp b/gtsam/nonlinear/summarization.cpp index acd222d43..b47e559ca 100644 --- a/gtsam/nonlinear/summarization.cpp +++ b/gtsam/nonlinear/summarization.cpp @@ -14,15 +14,15 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ -std::pair +std::pair summarize(const NonlinearFactorGraph& graph, const Values& values, const KeySet& saved_keys, SummarizationMode mode) { const size_t nrEliminatedKeys = values.size() - saved_keys.size(); // If we aren't eliminating anything, linearize and return if (!nrEliminatedKeys || saved_keys.empty()) { - Ordering ordering = *values.orderingArbitrary(); - GaussianFactorGraph linear_graph = *graph.linearize(values, ordering); + OrderingOrdered ordering = *values.orderingArbitrary(); + GaussianFactorGraphOrdered linear_graph = *graph.linearize(values, ordering); return make_pair(linear_graph, ordering); } @@ -33,11 +33,11 @@ summarize(const NonlinearFactorGraph& graph, const Values& values, BOOST_FOREACH(const gtsam::Key& key, saved_keys) ordering_constraints.insert(make_pair(key, 1)); - Ordering ordering = *graph.orderingCOLAMDConstrained(values, ordering_constraints); + OrderingOrdered ordering = *graph.orderingCOLAMDConstrained(values, ordering_constraints); // Linearize the system - GaussianFactorGraph full_graph = *graph.linearize(values, ordering); - GaussianFactorGraph summarized_system; + GaussianFactorGraphOrdered full_graph = *graph.linearize(values, ordering); + GaussianFactorGraphOrdered summarized_system; std::vector indices; BOOST_FOREACH(const Key& k, saved_keys) @@ -50,11 +50,11 @@ summarize(const NonlinearFactorGraph& graph, const Values& values, switch (mode) { case PARTIAL_QR: { - summarized_system.push_back(EliminateQR(full_graph, nrEliminatedKeys).second); + summarized_system.push_back(EliminateQROrdered(full_graph, nrEliminatedKeys).second); break; } case PARTIAL_CHOLESKY: { - summarized_system.push_back(EliminateCholesky(full_graph, nrEliminatedKeys).second); + summarized_system.push_back(EliminateCholeskyOrdered(full_graph, nrEliminatedKeys).second); break; } case SEQUENTIAL_QR: { @@ -75,8 +75,8 @@ summarize(const NonlinearFactorGraph& graph, const Values& values, NonlinearFactorGraph summarizeAsNonlinearContainer( const NonlinearFactorGraph& graph, const Values& values, const KeySet& saved_keys, SummarizationMode mode) { - GaussianFactorGraph summarized_graph; - Ordering ordering; + GaussianFactorGraphOrdered summarized_graph; + OrderingOrdered ordering; boost::tie(summarized_graph, ordering) = summarize(graph, values, saved_keys, mode); return LinearContainerFactor::convertLinearGraph(summarized_graph, ordering); } diff --git a/gtsam/nonlinear/summarization.h b/gtsam/nonlinear/summarization.h index c25d5d934..0b55cc820 100644 --- a/gtsam/nonlinear/summarization.h +++ b/gtsam/nonlinear/summarization.h @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include namespace gtsam { @@ -38,7 +38,7 @@ typedef enum { * @param mode controls what elimination technique and requirements to use * @return a pair of the remaining graph and the ordering used for linearization */ -std::pair GTSAM_EXPORT +std::pair GTSAM_EXPORT summarize(const NonlinearFactorGraph& graph, const Values& values, const KeySet& saved_keys, SummarizationMode mode = PARTIAL_QR); diff --git a/gtsam/nonlinear/tests/testLinearContainerFactor.cpp b/gtsam/nonlinear/tests/testLinearContainerFactor.cpp index 6c4617171..9c00da149 100644 --- a/gtsam/nonlinear/tests/testLinearContainerFactor.cpp +++ b/gtsam/nonlinear/tests/testLinearContainerFactor.cpp @@ -28,7 +28,7 @@ Pose2 poseA1(0.0, 0.0, 0.0), poseA2(2.0, 0.0, 0.0); /* ************************************************************************* */ TEST( testLinearContainerFactor, generic_jacobian_factor ) { - Ordering initOrdering; initOrdering += x1, x2, l1, l2; + OrderingOrdered initOrdering; initOrdering += x1, x2, l1, l2; Matrix A1 = Matrix_(2,2, 2.74222, -0.0067457, @@ -39,7 +39,7 @@ TEST( testLinearContainerFactor, generic_jacobian_factor ) { Vector b = Vector_(2, 0.0277052, -0.0533393); - JacobianFactor expLinFactor(initOrdering[l1], A1, initOrdering[l2], A2, b, diag_model2); + JacobianFactorOrdered expLinFactor(initOrdering[l1], A1, initOrdering[l2], A2, b, diag_model2); LinearContainerFactor actFactor(expLinFactor, initOrdering); EXPECT_LONGS_EQUAL(2, actFactor.size()); @@ -57,20 +57,20 @@ TEST( testLinearContainerFactor, generic_jacobian_factor ) { values.insert(x2, poseA2); // Check reconstruction from same ordering - GaussianFactor::shared_ptr actLinearizationA = actFactor.linearize(values, initOrdering); + GaussianFactorOrdered::shared_ptr actLinearizationA = actFactor.linearize(values, initOrdering); EXPECT(assert_equal(*expLinFactor.clone(), *actLinearizationA, tol)); // Check reconstruction from new ordering - Ordering newOrdering; newOrdering += x1, l1, x2, l2; - GaussianFactor::shared_ptr actLinearizationB = actFactor.linearize(values, newOrdering); - JacobianFactor expLinFactor2(newOrdering[l1], A1, newOrdering[l2], A2, b, diag_model2); + OrderingOrdered newOrdering; newOrdering += x1, l1, x2, l2; + GaussianFactorOrdered::shared_ptr actLinearizationB = actFactor.linearize(values, newOrdering); + JacobianFactorOrdered expLinFactor2(newOrdering[l1], A1, newOrdering[l2], A2, b, diag_model2); EXPECT(assert_equal(*expLinFactor2.clone(), *actLinearizationB, tol)); } /* ************************************************************************* */ TEST( testLinearContainerFactor, jacobian_factor_withlinpoints ) { - Ordering ordering; ordering += x1, x2, l1, l2; + OrderingOrdered ordering; ordering += x1, x2, l1, l2; Matrix A1 = Matrix_(2,2, 2.74222, -0.0067457, @@ -81,7 +81,7 @@ TEST( testLinearContainerFactor, jacobian_factor_withlinpoints ) { Vector b = Vector_(2, 0.0277052, -0.0533393); - JacobianFactor expLinFactor(ordering[l1], A1, ordering[l2], A2, b, diag_model2); + JacobianFactorOrdered expLinFactor(ordering[l1], A1, ordering[l2], A2, b, diag_model2); Values values; values.insert(l1, landmark1); @@ -108,7 +108,7 @@ TEST( testLinearContainerFactor, jacobian_factor_withlinpoints ) { Vector delta_l1 = Vector_(2, 1.0, 2.0); Vector delta_l2 = Vector_(2, 3.0, 4.0); - VectorValues delta = values.zeroVectors(ordering); + VectorValuesOrdered delta = values.zeroVectors(ordering); delta.at(ordering[l1]) = delta_l1; delta.at(ordering[l2]) = delta_l2; Values noisyValues = values.retract(delta, ordering); @@ -117,10 +117,10 @@ TEST( testLinearContainerFactor, jacobian_factor_withlinpoints ) { EXPECT_DOUBLES_EQUAL(expLinFactor.error(values.zeroVectors(ordering)), actFactor.error(values), tol); // Check linearization with corrections for updated linearization point - Ordering newOrdering; newOrdering += x1, l1, x2, l2; - GaussianFactor::shared_ptr actLinearizationB = actFactor.linearize(noisyValues, newOrdering); + OrderingOrdered newOrdering; newOrdering += x1, l1, x2, l2; + GaussianFactorOrdered::shared_ptr actLinearizationB = actFactor.linearize(noisyValues, newOrdering); Vector bprime = b - A1 * delta_l1 - A2 * delta_l2; - JacobianFactor expLinFactor2(newOrdering[l1], A1, newOrdering[l2], A2, bprime, diag_model2); + JacobianFactorOrdered expLinFactor2(newOrdering[l1], A1, newOrdering[l2], A2, bprime, diag_model2); EXPECT(assert_equal(*expLinFactor2.clone(), *actLinearizationB, tol)); } @@ -145,8 +145,8 @@ TEST( testLinearContainerFactor, generic_hessian_factor ) { double f = 10.0; - Ordering initOrdering; initOrdering += x1, x2, l1, l2; - HessianFactor initFactor(initOrdering[x1], initOrdering[x2], initOrdering[l1], + OrderingOrdered initOrdering; initOrdering += x1, x2, l1, l2; + HessianFactorOrdered initFactor(initOrdering[x1], initOrdering[x2], initOrdering[l1], G11, G12, G13, g1, G22, G23, g2, G33, g3, f); Values values; @@ -159,13 +159,13 @@ TEST( testLinearContainerFactor, generic_hessian_factor ) { EXPECT(!actFactor.isJacobian()); EXPECT(actFactor.isHessian()); - GaussianFactor::shared_ptr actLinearization1 = actFactor.linearize(values, initOrdering); + GaussianFactorOrdered::shared_ptr actLinearization1 = actFactor.linearize(values, initOrdering); EXPECT(assert_equal(*initFactor.clone(), *actLinearization1, tol)); - Ordering newOrdering; newOrdering += l1, x1, x2, l2; - HessianFactor expLinFactor(newOrdering[x1], newOrdering[x2], newOrdering[l1], + OrderingOrdered newOrdering; newOrdering += l1, x1, x2, l2; + HessianFactorOrdered expLinFactor(newOrdering[x1], newOrdering[x2], newOrdering[l1], G11, G12, G13, g1, G22, G23, g2, G33, g3, f); - GaussianFactor::shared_ptr actLinearization2 = actFactor.linearize(values, newOrdering); + GaussianFactorOrdered::shared_ptr actLinearization2 = actFactor.linearize(values, newOrdering); EXPECT(assert_equal(*expLinFactor.clone(), *actLinearization2, tol)); } @@ -196,8 +196,8 @@ TEST( testLinearContainerFactor, hessian_factor_withlinpoints ) { Matrix G(5,5); G << G11, G12, Matrix::Zero(2,3), G22; - Ordering ordering; ordering += x1, x2, l1; - HessianFactor initFactor(ordering[x1], ordering[l1], G11, G12, g1, G22, g2, f); + OrderingOrdered ordering; ordering += x1, x2, l1; + HessianFactorOrdered initFactor(ordering[x1], ordering[l1], G11, G12, g1, G22, g2, f); Values linearizationPoint, expLinPoints; linearizationPoint.insert(l1, landmark1); @@ -219,7 +219,7 @@ TEST( testLinearContainerFactor, hessian_factor_withlinpoints ) { Vector delta_x2 = Vector_(3, 6.0, 7.0, 0.3); // Check error calculation - VectorValues delta = linearizationPoint.zeroVectors(ordering); + VectorValuesOrdered delta = linearizationPoint.zeroVectors(ordering); delta.at(ordering[l1]) = delta_l1; delta.at(ordering[x1]) = delta_x1; delta.at(ordering[x2]) = delta_x2; @@ -239,7 +239,7 @@ TEST( testLinearContainerFactor, hessian_factor_withlinpoints ) { Vector g1_prime = g_prime.head(3); Vector g2_prime = g_prime.tail(2); double f_prime = f + dv.transpose() * G.selfadjointView() * dv - 2.0 * dv.transpose() * g; - HessianFactor expNewFactor(ordering[x1], ordering[l1], G11, G12, g1_prime, G22, g2_prime, f_prime); + HessianFactorOrdered expNewFactor(ordering[x1], ordering[l1], G11, G12, g1_prime, G22, g2_prime, f_prime); EXPECT(assert_equal(*expNewFactor.clone(), *actFactor.linearize(noisyValues, ordering), tol)); } @@ -252,12 +252,12 @@ TEST( testLinearContainerFactor, creation ) { l7 = 17, l8 = 18; // creating an ordering to decode the linearized factor - Ordering ordering; + OrderingOrdered ordering; ordering += l1,l2,l3,l4,l5,l6,l7,l8; // create a linear factor SharedDiagonal model = noiseModel::Unit::Create(2); - JacobianFactor::shared_ptr linear_factor(new JacobianFactor( + JacobianFactorOrdered::shared_ptr linear_factor(new JacobianFactorOrdered( ordering[l3], eye(2,2), ordering[l5], 2.0 * eye(2,2), zero(2), model)); // create a set of values - build with full set of values @@ -284,7 +284,7 @@ TEST( testLinearContainerFactor, jacobian_relinearize ) // Create a Between Factor from a Point3. This is actually a linear factor. gtsam::Key key1(1); gtsam::Key key2(2); - gtsam::Ordering ordering; + gtsam::OrderingOrdered ordering; ordering.push_back(key1); ordering.push_back(key2); gtsam::Values linpoint1; @@ -296,7 +296,7 @@ TEST( testLinearContainerFactor, jacobian_relinearize ) gtsam::BetweenFactor betweenFactor(key1, key2, measured, model); // Create a jacobian container factor at linpoint 1 - gtsam::JacobianFactor::shared_ptr jacobian(new gtsam::JacobianFactor(*betweenFactor.linearize(linpoint1, ordering))); + gtsam::JacobianFactorOrdered::shared_ptr jacobian(new gtsam::JacobianFactorOrdered(*betweenFactor.linearize(linpoint1, ordering))); gtsam::LinearContainerFactor jacobianContainer(jacobian, ordering, linpoint1); // Create a second linearization point @@ -310,8 +310,8 @@ TEST( testLinearContainerFactor, jacobian_relinearize ) EXPECT_DOUBLES_EQUAL(expected_error, actual_error, 1e-9 ); // Re-linearize around the new point and check the factors - gtsam::GaussianFactor::shared_ptr expected_factor = betweenFactor.linearize(linpoint2, ordering); - gtsam::GaussianFactor::shared_ptr actual_factor = jacobianContainer.linearize(linpoint2, ordering); + gtsam::GaussianFactorOrdered::shared_ptr expected_factor = betweenFactor.linearize(linpoint2, ordering); + gtsam::GaussianFactorOrdered::shared_ptr actual_factor = jacobianContainer.linearize(linpoint2, ordering); CHECK(gtsam::assert_equal(*expected_factor, *actual_factor)); } @@ -321,7 +321,7 @@ TEST( testLinearContainerFactor, hessian_relinearize ) // Create a Between Factor from a Point3. This is actually a linear factor. gtsam::Key key1(1); gtsam::Key key2(2); - gtsam::Ordering ordering; + gtsam::OrderingOrdered ordering; ordering.push_back(key1); ordering.push_back(key2); gtsam::Values linpoint1; @@ -333,7 +333,7 @@ TEST( testLinearContainerFactor, hessian_relinearize ) gtsam::BetweenFactor betweenFactor(key1, key2, measured, model); // Create a hessian container factor at linpoint 1 - gtsam::HessianFactor::shared_ptr hessian(new gtsam::HessianFactor(*betweenFactor.linearize(linpoint1, ordering))); + gtsam::HessianFactorOrdered::shared_ptr hessian(new gtsam::HessianFactorOrdered(*betweenFactor.linearize(linpoint1, ordering))); gtsam::LinearContainerFactor hessianContainer(hessian, ordering, linpoint1); // Create a second linearization point @@ -347,8 +347,8 @@ TEST( testLinearContainerFactor, hessian_relinearize ) EXPECT_DOUBLES_EQUAL(expected_error, actual_error, 1e-9 ); // Re-linearize around the new point and check the factors - gtsam::GaussianFactor::shared_ptr expected_factor = gtsam::HessianFactor::shared_ptr(new gtsam::HessianFactor(*betweenFactor.linearize(linpoint2, ordering))); - gtsam::GaussianFactor::shared_ptr actual_factor = hessianContainer.linearize(linpoint2, ordering); + gtsam::GaussianFactorOrdered::shared_ptr expected_factor = gtsam::HessianFactorOrdered::shared_ptr(new gtsam::HessianFactorOrdered(*betweenFactor.linearize(linpoint2, ordering))); + gtsam::GaussianFactorOrdered::shared_ptr actual_factor = hessianContainer.linearize(linpoint2, ordering); CHECK(gtsam::assert_equal(*expected_factor, *actual_factor)); } diff --git a/gtsam/nonlinear/tests/testOrdering.cpp b/gtsam/nonlinear/tests/testOrdering.cpp index a62278d1e..5ee5507db 100644 --- a/gtsam/nonlinear/tests/testOrdering.cpp +++ b/gtsam/nonlinear/tests/testOrdering.cpp @@ -14,7 +14,7 @@ * @author Alex Cunningham */ -#include +#include #include #include #include @@ -23,8 +23,8 @@ using namespace std; using namespace gtsam; /* ************************************************************************* */ -TEST( Ordering, simple_modifications ) { - Ordering ordering; +TEST( OrderingOrdered, simple_modifications ) { + OrderingOrdered ordering; // create an ordering Symbol x1('x', 1), x2('x', 2), x3('x', 3), x4('x', 4); @@ -40,7 +40,7 @@ TEST( Ordering, simple_modifications ) { EXPECT_LONGS_EQUAL(Key(x4), ordering.key(3)); // pop the last two elements - Ordering::value_type x4p = ordering.pop_back(); + OrderingOrdered::value_type x4p = ordering.pop_back(); EXPECT_LONGS_EQUAL(3, ordering.size()); EXPECT(assert_equal(x4, x4p.first)); @@ -59,17 +59,17 @@ TEST( Ordering, simple_modifications ) { EXPECT_LONGS_EQUAL(Key(x3), ordering.key(3)); // verify - Ordering expectedFinal; + OrderingOrdered expectedFinal; expectedFinal += x1, x2, x4, x3; EXPECT(assert_equal(expectedFinal, ordering)); } /* ************************************************************************* */ -TEST(Ordering, permute) { - Ordering ordering; +TEST(OrderingOrdered, permute) { + OrderingOrdered ordering; ordering += 2, 4, 6, 8; - Ordering expected; + OrderingOrdered expected; expected += 2, 8, 6, 4; Permutation permutation(4); @@ -78,7 +78,7 @@ TEST(Ordering, permute) { permutation[2] = 2; permutation[3] = 1; - Ordering actual = ordering; + OrderingOrdered actual = ordering; actual.permuteInPlace(permutation); EXPECT(assert_equal(expected, actual)); @@ -94,9 +94,9 @@ TEST(Ordering, permute) { } /* ************************************************************************* */ -TEST( Ordering, invert ) { +TEST( OrderingOrdered, invert ) { // creates a map with the opposite mapping: Index->Key - Ordering ordering; + OrderingOrdered ordering; // create an ordering Symbol x1('x', 1), x2('x', 2), x3('x', 3), x4('x', 4); diff --git a/gtsam/nonlinear/tests/testValues.cpp b/gtsam/nonlinear/tests/testValues.cpp index 227f20834..de92103a3 100644 --- a/gtsam/nonlinear/tests/testValues.cpp +++ b/gtsam/nonlinear/tests/testValues.cpp @@ -155,7 +155,7 @@ TEST( Values, update_element ) // config0.insert(key2, LieVector(3, 5.0, 6.0, 7.0)); // LONGS_EQUAL(5, config0.dim()); // -// VectorValues expected; +// VectorValuesOrdered expected; // expected.insert(key1, zero(2)); // expected.insert(key2, zero(3)); // CHECK(assert_equal(expected, config0.zero())); @@ -168,8 +168,8 @@ TEST(Values, expmap_a) config0.insert(key1, LieVector(3, 1.0, 2.0, 3.0)); config0.insert(key2, LieVector(3, 5.0, 6.0, 7.0)); - Ordering ordering(*config0.orderingArbitrary()); - VectorValues increment(config0.dims(ordering)); + OrderingOrdered ordering(*config0.orderingArbitrary()); + VectorValuesOrdered increment(config0.dims(ordering)); increment[ordering[key1]] = Vector_(3, 1.0, 1.1, 1.2); increment[ordering[key2]] = Vector_(3, 1.3, 1.4, 1.5); @@ -187,8 +187,8 @@ TEST(Values, expmap_b) config0.insert(key1, LieVector(3, 1.0, 2.0, 3.0)); config0.insert(key2, LieVector(3, 5.0, 6.0, 7.0)); - Ordering ordering(*config0.orderingArbitrary()); - VectorValues increment(VectorValues::Zero(config0.dims(ordering))); + OrderingOrdered ordering(*config0.orderingArbitrary()); + VectorValuesOrdered increment(VectorValuesOrdered::Zero(config0.dims(ordering))); increment[ordering[key2]] = LieVector(3, 1.3, 1.4, 1.5); Values expected; @@ -241,9 +241,9 @@ TEST(Values, localCoordinates) valuesA.insert(key1, LieVector(3, 1.0, 2.0, 3.0)); valuesA.insert(key2, LieVector(3, 5.0, 6.0, 7.0)); - Ordering ordering = *valuesA.orderingArbitrary(); + OrderingOrdered ordering = *valuesA.orderingArbitrary(); - VectorValues expDelta = valuesA.zeroVectors(ordering); + VectorValuesOrdered expDelta = valuesA.zeroVectors(ordering); // expDelta.at(ordering[key1]) = Vector_(3, 0.1, 0.2, 0.3); // expDelta.at(ordering[key2]) = Vector_(3, 0.4, 0.5, 0.6); diff --git a/gtsam/slam/AntiFactor.h b/gtsam/slam/AntiFactor.h index fe1b93bde..cb11d5af9 100644 --- a/gtsam/slam/AntiFactor.h +++ b/gtsam/slam/AntiFactor.h @@ -18,7 +18,7 @@ #include #include -#include +#include namespace gtsam { @@ -94,11 +94,11 @@ namespace gtsam { * returns a Jacobian instead of a full Hessian), but with the opposite sign. This * effectively cancels the effect of the original factor on the factor graph. */ - boost::shared_ptr - linearize(const Values& c, const Ordering& ordering) const { + boost::shared_ptr + linearize(const Values& c, const OrderingOrdered& ordering) const { // Generate the linearized factor from the contained nonlinear factor - GaussianFactor::shared_ptr gaussianFactor = factor_->linearize(c, ordering); + GaussianFactorOrdered::shared_ptr gaussianFactor = factor_->linearize(c, ordering); // return the negated version of the factor return gaussianFactor->negate(); diff --git a/gtsam/slam/BetweenFactor.h b/gtsam/slam/BetweenFactor.h index fd53ab1c7..1b194d8dd 100644 --- a/gtsam/slam/BetweenFactor.h +++ b/gtsam/slam/BetweenFactor.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include namespace gtsam { diff --git a/gtsam/slam/tests/testAntiFactor.cpp b/gtsam/slam/tests/testAntiFactor.cpp index d918dbd99..fb3b65059 100644 --- a/gtsam/slam/tests/testAntiFactor.cpp +++ b/gtsam/slam/tests/testAntiFactor.cpp @@ -46,7 +46,7 @@ TEST( AntiFactor, NegativeHessian) values->insert(2, pose2); // Define an elimination ordering - Ordering::shared_ptr ordering(new Ordering()); + OrderingOrdered::shared_ptr ordering(new OrderingOrdered()); ordering->insert(1, 0); ordering->insert(2, 1); @@ -55,17 +55,17 @@ TEST( AntiFactor, NegativeHessian) BetweenFactor::shared_ptr originalFactor(new BetweenFactor(1, 2, z, sigma)); // Linearize it into a Jacobian Factor - GaussianFactor::shared_ptr originalJacobian = originalFactor->linearize(*values, *ordering); + GaussianFactorOrdered::shared_ptr originalJacobian = originalFactor->linearize(*values, *ordering); // Convert it to a Hessian Factor - HessianFactor::shared_ptr originalHessian = HessianFactor::shared_ptr(new HessianFactor(*originalJacobian)); + HessianFactorOrdered::shared_ptr originalHessian = HessianFactorOrdered::shared_ptr(new HessianFactorOrdered(*originalJacobian)); // Create the AntiFactor version of the original nonlinear factor AntiFactor::shared_ptr antiFactor(new AntiFactor(originalFactor)); // Linearize the AntiFactor into a Hessian Factor - GaussianFactor::shared_ptr antiGaussian = antiFactor->linearize(*values, *ordering); - HessianFactor::shared_ptr antiHessian = boost::dynamic_pointer_cast(antiGaussian); + GaussianFactorOrdered::shared_ptr antiGaussian = antiFactor->linearize(*values, *ordering); + HessianFactorOrdered::shared_ptr antiHessian = boost::dynamic_pointer_cast(antiGaussian); // Compare Hessian blocks @@ -107,14 +107,14 @@ TEST( AntiFactor, EquivalentBayesNet) values->insert(2, pose2); // Define an elimination ordering - Ordering::shared_ptr ordering = graph->orderingCOLAMD(*values); + OrderingOrdered::shared_ptr ordering = graph->orderingCOLAMD(*values); // Eliminate into a BayesNet GaussianSequentialSolver solver1(*graph->linearize(*values, *ordering)); - GaussianBayesNet::shared_ptr expectedBayesNet = solver1.eliminate(); + GaussianBayesNetOrdered::shared_ptr expectedBayesNet = solver1.eliminate(); // Back-substitute to find the optimal deltas - VectorValues expectedDeltas = optimize(*expectedBayesNet); + VectorValuesOrdered expectedDeltas = optimize(*expectedBayesNet); // Add an additional factor between Pose1 and Pose2 BetweenFactor::shared_ptr f1(new BetweenFactor(1, 2, z, sigma)); @@ -126,10 +126,10 @@ TEST( AntiFactor, EquivalentBayesNet) // Again, Eliminate into a BayesNet GaussianSequentialSolver solver2(*graph->linearize(*values, *ordering)); - GaussianBayesNet::shared_ptr actualBayesNet = solver2.eliminate(); + GaussianBayesNetOrdered::shared_ptr actualBayesNet = solver2.eliminate(); // Back-substitute to find the optimal deltas - VectorValues actualDeltas = optimize(*actualBayesNet); + VectorValuesOrdered actualDeltas = optimize(*actualBayesNet); // Verify the BayesNets are identical CHECK(assert_equal(*expectedBayesNet, *actualBayesNet, 1e-5)); diff --git a/gtsam/slam/tests/testGeneralSFMFactor.cpp b/gtsam/slam/tests/testGeneralSFMFactor.cpp index 0aeadfa6a..414d0ba62 100644 --- a/gtsam/slam/tests/testGeneralSFMFactor.cpp +++ b/gtsam/slam/tests/testGeneralSFMFactor.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -149,8 +149,8 @@ static vector genCameraVariableCalibration() { return X ; } -static boost::shared_ptr getOrdering(const vector& cameras, const vector& landmarks) { - boost::shared_ptr ordering(new Ordering); +static boost::shared_ptr getOrdering(const vector& cameras, const vector& landmarks) { + boost::shared_ptr ordering(new OrderingOrdered); for ( size_t i = 0 ; i < landmarks.size() ; ++i ) ordering->push_back(L(i)) ; for ( size_t i = 0 ; i < cameras.size() ; ++i ) ordering->push_back(X(i)) ; return ordering ; @@ -190,7 +190,7 @@ TEST( GeneralSFMFactor, optimize_defaultK ) { graph.addCameraConstraint(0, cameras[0]); // Create an ordering of the variables - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * 1e-5 * nMeasurements); @@ -233,7 +233,7 @@ TEST( GeneralSFMFactor, optimize_varK_SingleMeasurementError ) { graph.addCameraConstraint(0, cameras[0]); const double reproj_error = 1e-5; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); @@ -274,7 +274,7 @@ TEST( GeneralSFMFactor, optimize_varK_FixCameras ) { const double reproj_error = 1e-5 ; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); @@ -331,7 +331,7 @@ TEST( GeneralSFMFactor, optimize_varK_FixLandmarks ) { const double reproj_error = 1e-5 ; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); @@ -375,7 +375,7 @@ TEST( GeneralSFMFactor, optimize_varK_BA ) { const double reproj_error = 1e-5 ; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); diff --git a/gtsam/slam/tests/testGeneralSFMFactor_Cal3Bundler.cpp b/gtsam/slam/tests/testGeneralSFMFactor_Cal3Bundler.cpp index 6d8f36634..96deddde5 100644 --- a/gtsam/slam/tests/testGeneralSFMFactor_Cal3Bundler.cpp +++ b/gtsam/slam/tests/testGeneralSFMFactor_Cal3Bundler.cpp @@ -20,10 +20,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include #include #include @@ -152,8 +152,8 @@ static vector genCameraVariableCalibration() { return cameras ; } -static boost::shared_ptr getOrdering(const std::vector& cameras, const std::vector& landmarks) { - boost::shared_ptr ordering(new Ordering); +static boost::shared_ptr getOrdering(const std::vector& cameras, const std::vector& landmarks) { + boost::shared_ptr ordering(new OrderingOrdered); for ( size_t i = 0 ; i < landmarks.size() ; ++i ) ordering->push_back(L(i)) ; for ( size_t i = 0 ; i < cameras.size() ; ++i ) ordering->push_back(X(i)) ; return ordering ; @@ -192,7 +192,7 @@ TEST( GeneralSFMFactor_Cal3Bundler, optimize_defaultK ) { graph.addCameraConstraint(0, cameras[0]); // Create an ordering of the variables - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * 1e-5 * nMeasurements); @@ -235,7 +235,7 @@ TEST( GeneralSFMFactor_Cal3Bundler, optimize_varK_SingleMeasurementError ) { graph.addCameraConstraint(0, cameras[0]); const double reproj_error = 1e-5; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); @@ -276,7 +276,7 @@ TEST( GeneralSFMFactor_Cal3Bundler, optimize_varK_FixCameras ) { const double reproj_error = 1e-5 ; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); @@ -329,7 +329,7 @@ TEST( GeneralSFMFactor_Cal3Bundler, optimize_varK_FixLandmarks ) { const double reproj_error = 1e-5 ; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); @@ -373,7 +373,7 @@ TEST( GeneralSFMFactor_Cal3Bundler, optimize_varK_BA ) { const double reproj_error = 1e-5 ; - Ordering ordering = *getOrdering(cameras,landmarks); + OrderingOrdered ordering = *getOrdering(cameras,landmarks); LevenbergMarquardtOptimizer optimizer(graph, values, ordering); Values final = optimizer.optimize(); EXPECT(optimizer.error() < 0.5 * reproj_error * nMeasurements); diff --git a/gtsam/symbolic/SymbolicBayesNetUnordered.cpp b/gtsam/symbolic/SymbolicBayesNet.cpp similarity index 67% rename from gtsam/symbolic/SymbolicBayesNetUnordered.cpp rename to gtsam/symbolic/SymbolicBayesNet.cpp index f1563532f..179e99c0c 100644 --- a/gtsam/symbolic/SymbolicBayesNetUnordered.cpp +++ b/gtsam/symbolic/SymbolicBayesNet.cpp @@ -16,30 +16,30 @@ * @author Richard Roberts */ -#include -#include -#include +#include +#include +#include #include namespace gtsam { /* ************************************************************************* */ - bool SymbolicBayesNetUnordered::equals(const This& bn, double tol) const + bool SymbolicBayesNet::equals(const This& bn, double tol) const { return Base::equals(bn, tol); } /* ************************************************************************* */ - void SymbolicBayesNetUnordered::saveGraph(const std::string &s, const KeyFormatter& keyFormatter) const + void SymbolicBayesNet::saveGraph(const std::string &s, const KeyFormatter& keyFormatter) const { std::ofstream of(s.c_str()); of << "digraph G{\n"; BOOST_REVERSE_FOREACH(const sharedConditional& conditional, *this) { - SymbolicConditionalUnordered::Frontals frontals = conditional->frontals(); + SymbolicConditional::Frontals frontals = conditional->frontals(); Key me = frontals.front(); - SymbolicConditionalUnordered::Parents parents = conditional->parents(); + SymbolicConditional::Parents parents = conditional->parents(); BOOST_FOREACH(Key p, parents) of << p << "->" << me << std::endl; } diff --git a/gtsam/symbolic/SymbolicBayesNetUnordered.h b/gtsam/symbolic/SymbolicBayesNet.h similarity index 67% rename from gtsam/symbolic/SymbolicBayesNetUnordered.h rename to gtsam/symbolic/SymbolicBayesNet.h index d2c3ea724..07dedf919 100644 --- a/gtsam/symbolic/SymbolicBayesNetUnordered.h +++ b/gtsam/symbolic/SymbolicBayesNet.h @@ -18,8 +18,8 @@ #pragma once -#include -#include +#include +#include #include namespace gtsam { @@ -27,13 +27,13 @@ namespace gtsam { /** Symbolic Bayes Net * \nosubgrouping */ - class GTSAM_EXPORT SymbolicBayesNetUnordered : public FactorGraphUnordered { + class GTSAM_EXPORT SymbolicBayesNet : public FactorGraph { public: - typedef FactorGraphUnordered Base; - typedef SymbolicBayesNetUnordered This; - typedef SymbolicConditionalUnordered ConditionalType; + typedef FactorGraph Base; + typedef SymbolicBayesNet This; + typedef SymbolicConditional ConditionalType; typedef boost::shared_ptr shared_ptr; typedef boost::shared_ptr sharedConditional; @@ -41,19 +41,19 @@ namespace gtsam { /// @{ /** Construct empty factor graph */ - SymbolicBayesNetUnordered() {} + SymbolicBayesNet() {} /** Construct from iterator over conditionals */ template - SymbolicBayesNetUnordered(ITERATOR firstConditional, ITERATOR lastConditional) : Base(firstConditional, lastConditional) {} + SymbolicBayesNet(ITERATOR firstConditional, ITERATOR lastConditional) : Base(firstConditional, lastConditional) {} /** Construct from container of factors (shared_ptr or plain objects) */ template - explicit SymbolicBayesNetUnordered(const CONTAINER& conditionals) : Base(conditionals) {} + explicit SymbolicBayesNet(const CONTAINER& conditionals) : Base(conditionals) {} /** Implicit copy/downcast constructor to override explicit template container constructor */ template - SymbolicBayesNetUnordered(const FactorGraphUnordered& graph) : Base(graph) {} + SymbolicBayesNet(const FactorGraph& graph) : Base(graph) {} /// @} diff --git a/gtsam/symbolic/SymbolicBayesTreeUnordered.cpp b/gtsam/symbolic/SymbolicBayesTree.cpp similarity index 59% rename from gtsam/symbolic/SymbolicBayesTreeUnordered.cpp rename to gtsam/symbolic/SymbolicBayesTree.cpp index 1146b7cfc..1779964ad 100644 --- a/gtsam/symbolic/SymbolicBayesTreeUnordered.cpp +++ b/gtsam/symbolic/SymbolicBayesTree.cpp @@ -18,28 +18,28 @@ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace gtsam { /* ************************************************************************* */ - SymbolicBayesTreeUnordered::SymbolicBayesTreeUnordered(const SymbolicBayesTreeUnordered& other) : + SymbolicBayesTree::SymbolicBayesTree(const SymbolicBayesTree& other) : Base(other) {} /* ************************************************************************* */ - SymbolicBayesTreeUnordered& SymbolicBayesTreeUnordered::operator=(const SymbolicBayesTreeUnordered& other) + SymbolicBayesTree& SymbolicBayesTree::operator=(const SymbolicBayesTree& other) { (void) Base::operator=(other); return *this; } /* ************************************************************************* */\ - bool SymbolicBayesTreeUnordered::equals(const This& other, double tol /* = 1e-9 */) const + bool SymbolicBayesTree::equals(const This& other, double tol /* = 1e-9 */) const { return Base::equals(other, tol); } diff --git a/gtsam/symbolic/SymbolicBayesTreeUnordered.h b/gtsam/symbolic/SymbolicBayesTree.h similarity index 57% rename from gtsam/symbolic/SymbolicBayesTreeUnordered.h rename to gtsam/symbolic/SymbolicBayesTree.h index 99a2b4ec3..e7ae6fbc9 100644 --- a/gtsam/symbolic/SymbolicBayesTreeUnordered.h +++ b/gtsam/symbolic/SymbolicBayesTree.h @@ -18,53 +18,53 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace gtsam { // Forward declarations - class SymbolicConditionalUnordered; + class SymbolicConditional; /* ************************************************************************* */ /// A clique in a SymbolicBayesTree - class GTSAM_EXPORT SymbolicBayesTreeCliqueUnordered : - public BayesTreeCliqueBaseUnordered + class GTSAM_EXPORT SymbolicBayesTreeClique : + public BayesTreeCliqueBase { public: - typedef SymbolicBayesTreeCliqueUnordered This; - typedef BayesTreeCliqueBaseUnordered Base; + typedef SymbolicBayesTreeClique This; + typedef BayesTreeCliqueBase Base; typedef boost::shared_ptr shared_ptr; typedef boost::weak_ptr weak_ptr; - SymbolicBayesTreeCliqueUnordered() {} - SymbolicBayesTreeCliqueUnordered(const boost::shared_ptr& conditional) : Base(conditional) {} + SymbolicBayesTreeClique() {} + SymbolicBayesTreeClique(const boost::shared_ptr& conditional) : Base(conditional) {} }; /* ************************************************************************* */ /// A Bayes tree that represents the connectivity between variables but is not associated with any /// probability functions. - class GTSAM_EXPORT SymbolicBayesTreeUnordered : - public BayesTreeUnordered + class GTSAM_EXPORT SymbolicBayesTree : + public BayesTree { private: - typedef BayesTreeUnordered Base; + typedef BayesTree Base; public: - typedef SymbolicBayesTreeUnordered This; + typedef SymbolicBayesTree This; typedef boost::shared_ptr shared_ptr; /** Default constructor, creates an empty Bayes tree */ - SymbolicBayesTreeUnordered() {} + SymbolicBayesTree() {} /** Makes a deep copy of the tree structure, but only pointers to conditionals are * copied, the conditionals and their matrices are not cloned. */ - SymbolicBayesTreeUnordered(const SymbolicBayesTreeUnordered& other); + SymbolicBayesTree(const SymbolicBayesTree& other); /** Makes a deep copy of the tree structure, but only pointers to conditionals are * copied, the conditionals and their matrices are not cloned. */ - SymbolicBayesTreeUnordered& operator=(const SymbolicBayesTreeUnordered& other); + SymbolicBayesTree& operator=(const SymbolicBayesTree& other); /** check equality */ bool equals(const This& other, double tol = 1e-9) const; diff --git a/gtsam/symbolic/SymbolicConditionalUnordered.cpp b/gtsam/symbolic/SymbolicConditional.cpp similarity index 73% rename from gtsam/symbolic/SymbolicConditionalUnordered.cpp rename to gtsam/symbolic/SymbolicConditional.cpp index fb85d42cf..d733c0937 100644 --- a/gtsam/symbolic/SymbolicConditionalUnordered.cpp +++ b/gtsam/symbolic/SymbolicConditional.cpp @@ -15,21 +15,21 @@ * @date Oct 17, 2010 */ -#include -#include +#include +#include namespace gtsam { using namespace std; /* ************************************************************************* */ - void SymbolicConditionalUnordered::print(const std::string& str, const KeyFormatter& keyFormatter) const + void SymbolicConditional::print(const std::string& str, const KeyFormatter& keyFormatter) const { BaseConditional::print(str, keyFormatter); } /* ************************************************************************* */ - bool SymbolicConditionalUnordered::equals(const This& c, double tol) const + bool SymbolicConditional::equals(const This& c, double tol) const { return BaseFactor::equals(c) && BaseConditional::equals(c); } diff --git a/gtsam/symbolic/SymbolicConditionalUnordered.h b/gtsam/symbolic/SymbolicConditional.h similarity index 55% rename from gtsam/symbolic/SymbolicConditionalUnordered.h rename to gtsam/symbolic/SymbolicConditional.h index b4227f14b..410784684 100644 --- a/gtsam/symbolic/SymbolicConditionalUnordered.h +++ b/gtsam/symbolic/SymbolicConditional.h @@ -18,28 +18,28 @@ #pragma once #include -#include -#include +#include +#include namespace gtsam { /** - * SymbolicConditionalUnordered is a conditional with keys but no probability - * data, produced by symbolic elimination of SymbolicFactorUnordered. + * SymbolicConditional is a conditional with keys but no probability + * data, produced by symbolic elimination of SymbolicFactor. * - * It is also a SymbolicFactorUnordered, and thus derives from it. It - * derives also from ConditionalUnordered, which is a generic interface + * It is also a SymbolicFactor, and thus derives from it. It + * derives also from Conditional, which is a generic interface * class for conditionals. * \nosubgrouping */ - class GTSAM_EXPORT SymbolicConditionalUnordered : - public SymbolicFactorUnordered, - public ConditionalUnordered { + class GTSAM_EXPORT SymbolicConditional : + public SymbolicFactor, + public Conditional { public: - typedef SymbolicConditionalUnordered This; /// Typedef to this class - typedef SymbolicFactorUnordered BaseFactor; /// Typedef to the factor base class - typedef ConditionalUnordered BaseConditional; /// Typedef to the conditional base class + typedef SymbolicConditional This; /// Typedef to this class + typedef SymbolicFactor BaseFactor; /// Typedef to the factor base class + typedef Conditional BaseConditional; /// Typedef to the conditional base class typedef boost::shared_ptr shared_ptr; /// Boost shared_ptr to this class typedef BaseFactor::iterator iterator; /// iterator to keys typedef BaseFactor::const_iterator const_iterator; /// const_iterator to keys @@ -48,35 +48,35 @@ namespace gtsam { /// @{ /** Empty Constructor to make serialization possible */ - SymbolicConditionalUnordered() {} + SymbolicConditional() {} /** No parents */ - SymbolicConditionalUnordered(Index j) : BaseFactor(j), BaseConditional(1) {} + SymbolicConditional(Index j) : BaseFactor(j), BaseConditional(1) {} /** Single parent */ - SymbolicConditionalUnordered(Index j, Index parent) : BaseFactor(j, parent), BaseConditional(1) {} + SymbolicConditional(Index j, Index parent) : BaseFactor(j, parent), BaseConditional(1) {} /** Two parents */ - SymbolicConditionalUnordered(Index j, Index parent1, Index parent2) : BaseFactor(j, parent1, parent2), BaseConditional(1) {} + SymbolicConditional(Index j, Index parent1, Index parent2) : BaseFactor(j, parent1, parent2), BaseConditional(1) {} /** Three parents */ - SymbolicConditionalUnordered(Index j, Index parent1, Index parent2, Index parent3) : BaseFactor(j, parent1, parent2, parent3), BaseConditional(1) {} + SymbolicConditional(Index j, Index parent1, Index parent2, Index parent3) : BaseFactor(j, parent1, parent2, parent3), BaseConditional(1) {} /** Named constructor from an arbitrary number of keys and frontals */ template - static SymbolicConditionalUnordered FromIterators(ITERATOR firstKey, ITERATOR lastKey, size_t nrFrontals) + static SymbolicConditional FromIterators(ITERATOR firstKey, ITERATOR lastKey, size_t nrFrontals) { - SymbolicConditionalUnordered result; + SymbolicConditional result; (BaseFactor&)result = BaseFactor::FromIterators(firstKey, lastKey); result.nrFrontals_ = nrFrontals; return result; } /** Named constructor from an arbitrary number of keys and frontals */ template - static SymbolicConditionalUnordered FromKeys(const CONTAINER& keys, size_t nrFrontals) { + static SymbolicConditional FromKeys(const CONTAINER& keys, size_t nrFrontals) { return FromIterators(keys.begin(), keys.end(), nrFrontals); } - virtual ~SymbolicConditionalUnordered() {} + virtual ~SymbolicConditional() {} /// @} diff --git a/gtsam/symbolic/SymbolicEliminationTreeUnordered.cpp b/gtsam/symbolic/SymbolicEliminationTree.cpp similarity index 59% rename from gtsam/symbolic/SymbolicEliminationTreeUnordered.cpp rename to gtsam/symbolic/SymbolicEliminationTree.cpp index ad1c909dc..e01d04bd6 100644 --- a/gtsam/symbolic/SymbolicEliminationTreeUnordered.cpp +++ b/gtsam/symbolic/SymbolicEliminationTree.cpp @@ -10,42 +10,42 @@ * -------------------------------------------------------------------------- */ /** - * @file SymbolicEliminationTreeUnordered.cpp + * @file SymbolicEliminationTree.cpp * @date Mar 29, 2013 * @author Frank Dellaert * @author Richard Roberts */ -#include -#include +#include +#include namespace gtsam { /* ************************************************************************* */ - SymbolicEliminationTreeUnordered::SymbolicEliminationTreeUnordered( - const SymbolicFactorGraphUnordered& factorGraph, const VariableIndexUnordered& structure, - const OrderingUnordered& order) : + SymbolicEliminationTree::SymbolicEliminationTree( + const SymbolicFactorGraph& factorGraph, const VariableIndex& structure, + const Ordering& order) : Base(factorGraph, structure, order) {} /* ************************************************************************* */ - SymbolicEliminationTreeUnordered::SymbolicEliminationTreeUnordered( - const SymbolicFactorGraphUnordered& factorGraph, const OrderingUnordered& order) : + SymbolicEliminationTree::SymbolicEliminationTree( + const SymbolicFactorGraph& factorGraph, const Ordering& order) : Base(factorGraph, order) {} /* ************************************************************************* */ - SymbolicEliminationTreeUnordered::SymbolicEliminationTreeUnordered( + SymbolicEliminationTree::SymbolicEliminationTree( const This& other) : Base(other) {} /* ************************************************************************* */ - SymbolicEliminationTreeUnordered& SymbolicEliminationTreeUnordered::operator=(const This& other) + SymbolicEliminationTree& SymbolicEliminationTree::operator=(const This& other) { (void) Base::operator=(other); return *this; } /* ************************************************************************* */ - bool SymbolicEliminationTreeUnordered::equals(const This& other, double tol) const + bool SymbolicEliminationTree::equals(const This& other, double tol) const { return Base::equals(other, tol); } diff --git a/gtsam/symbolic/SymbolicEliminationTreeUnordered.h b/gtsam/symbolic/SymbolicEliminationTree.h similarity index 65% rename from gtsam/symbolic/SymbolicEliminationTreeUnordered.h rename to gtsam/symbolic/SymbolicEliminationTree.h index 57836dbfc..a00bfde3d 100644 --- a/gtsam/symbolic/SymbolicEliminationTreeUnordered.h +++ b/gtsam/symbolic/SymbolicEliminationTree.h @@ -10,7 +10,7 @@ * -------------------------------------------------------------------------- */ /** - * @file SymbolicEliminationTreeUnordered.h + * @file SymbolicEliminationTree.h * @date Mar 29, 2013 * @author Frank Dellaert * @author Richard Roberts @@ -18,18 +18,18 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace gtsam { - class GTSAM_EXPORT SymbolicEliminationTreeUnordered : - public EliminationTreeUnordered + class GTSAM_EXPORT SymbolicEliminationTree : + public EliminationTree { public: - typedef EliminationTreeUnordered Base; ///< Base class - typedef SymbolicEliminationTreeUnordered This; ///< This class + typedef EliminationTree Base; ///< Base class + typedef SymbolicEliminationTree This; ///< This class typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class /** Build the elimination tree of a factor graph using pre-computed column structure. @@ -37,19 +37,19 @@ namespace gtsam { * @param structure The set of factors involving each variable. If this is not precomputed, * you can call the Create(const FactorGraph&) named constructor instead. * @return The elimination tree */ - SymbolicEliminationTreeUnordered(const SymbolicFactorGraphUnordered& factorGraph, - const VariableIndexUnordered& structure, const OrderingUnordered& order); + SymbolicEliminationTree(const SymbolicFactorGraph& factorGraph, + const VariableIndex& structure, const Ordering& order); /** Build the elimination tree of a factor graph. Note that this has to compute the column * structure as a VariableIndex, so if you already have this precomputed, use the other * constructor instead. * @param factorGraph The factor graph for which to build the elimination tree */ - SymbolicEliminationTreeUnordered(const SymbolicFactorGraphUnordered& factorGraph, - const OrderingUnordered& order); + SymbolicEliminationTree(const SymbolicFactorGraph& factorGraph, + const Ordering& order); /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are * copied, factors are not cloned. */ - SymbolicEliminationTreeUnordered(const This& other); + SymbolicEliminationTree(const This& other); /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors are * copied, factors are not cloned. */ @@ -61,9 +61,9 @@ namespace gtsam { private: /** Private default constructor for testing */ - SymbolicEliminationTreeUnordered() {} + SymbolicEliminationTree() {} - friend class ::EliminationTreeUnorderedTester; + friend class ::EliminationTreeTester; }; diff --git a/gtsam/symbolic/SymbolicFactorUnordered.cpp b/gtsam/symbolic/SymbolicFactor.cpp similarity index 60% rename from gtsam/symbolic/SymbolicFactorUnordered.cpp rename to gtsam/symbolic/SymbolicFactor.cpp index 5b24b34c2..4b475a26a 100644 --- a/gtsam/symbolic/SymbolicFactorUnordered.cpp +++ b/gtsam/symbolic/SymbolicFactor.cpp @@ -18,22 +18,22 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace std; namespace gtsam { /* ************************************************************************* */ - std::pair, boost::shared_ptr > - EliminateSymbolicUnordered(const SymbolicFactorGraphUnordered& factors, const OrderingUnordered& keys) + std::pair, boost::shared_ptr > + EliminateSymbolic(const SymbolicFactorGraph& factors, const Ordering& keys) { // Gather all keys FastSet allKeys; - BOOST_FOREACH(const SymbolicFactorUnordered::shared_ptr& factor, factors) { + BOOST_FOREACH(const SymbolicFactor::shared_ptr& factor, factors) { allKeys.insert(factor->begin(), factor->end()); } // Check keys @@ -53,25 +53,25 @@ namespace gtsam { // Return resulting conditional and factor return make_pair( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(orderedKeys, nFrontals)), - boost::make_shared( - SymbolicFactorUnordered::FromIterators(orderedKeys.begin() + nFrontals, orderedKeys.end()))); + boost::make_shared( + SymbolicConditional::FromKeys(orderedKeys, nFrontals)), + boost::make_shared( + SymbolicFactor::FromIterators(orderedKeys.begin() + nFrontals, orderedKeys.end()))); } /* ************************************************************************* */ - bool SymbolicFactorUnordered::equals(const This& other, double tol) const + bool SymbolicFactor::equals(const This& other, double tol) const { return Base::equals(other, tol); } /* ************************************************************************* */ - std::pair, boost::shared_ptr > - SymbolicFactorUnordered::eliminate(const OrderingUnordered& keys) const + std::pair, boost::shared_ptr > + SymbolicFactor::eliminate(const Ordering& keys) const { - SymbolicFactorGraphUnordered graph; + SymbolicFactorGraph graph; graph += *this; // TODO: Is there a way to avoid copying this factor? - return EliminateSymbolicUnordered(graph, keys); + return EliminateSymbolic(graph, keys); } } // gtsam diff --git a/gtsam/symbolic/SymbolicFactorUnordered.h b/gtsam/symbolic/SymbolicFactor.h similarity index 63% rename from gtsam/symbolic/SymbolicFactorUnordered.h rename to gtsam/symbolic/SymbolicFactor.h index 2f18ed567..36a96f9c0 100644 --- a/gtsam/symbolic/SymbolicFactorUnordered.h +++ b/gtsam/symbolic/SymbolicFactor.h @@ -21,25 +21,25 @@ #include #include -#include +#include #include namespace gtsam { // Forward declarations - class SymbolicConditionalUnordered; - class OrderingUnordered; + class SymbolicConditional; + class Ordering; - /** SymbolicFactorUnordered represents a symbolic factor that specifies graph topology but is not + /** SymbolicFactor represents a symbolic factor that specifies graph topology but is not * associated with any numerical function. * \nosubgrouping */ - class GTSAM_EXPORT SymbolicFactorUnordered : public FactorUnordered { + class GTSAM_EXPORT SymbolicFactor : public Factor { public: - typedef SymbolicFactorUnordered This; - typedef FactorUnordered Base; - typedef SymbolicConditionalUnordered ConditionalType; + typedef SymbolicFactor This; + typedef Factor Base; + typedef SymbolicConditional ConditionalType; /** Overriding the shared_ptr typedef */ typedef boost::shared_ptr shared_ptr; @@ -48,33 +48,33 @@ namespace gtsam { /// @{ /** Default constructor for I/O */ - SymbolicFactorUnordered() {} + SymbolicFactor() {} /** Construct unary factor */ - SymbolicFactorUnordered(Key j) : + SymbolicFactor(Key j) : Base(boost::assign::cref_list_of<1>(j)) {} /** Construct binary factor */ - SymbolicFactorUnordered(Key j1, Key j2) : + SymbolicFactor(Key j1, Key j2) : Base(boost::assign::cref_list_of<2>(j1)(j2)) {} /** Construct ternary factor */ - SymbolicFactorUnordered(Key j1, Key j2, Key j3) : + SymbolicFactor(Key j1, Key j2, Key j3) : Base(boost::assign::cref_list_of<3>(j1)(j2)(j3)) {} /** Construct 4-way factor */ - SymbolicFactorUnordered(Key j1, Key j2, Key j3, Key j4) : + SymbolicFactor(Key j1, Key j2, Key j3, Key j4) : Base(boost::assign::cref_list_of<4>(j1)(j2)(j3)(j4)) {} /** Construct 5-way factor */ - SymbolicFactorUnordered(Key j1, Key j2, Key j3, Key j4, Key j5) : + SymbolicFactor(Key j1, Key j2, Key j3, Key j4, Key j5) : Base(boost::assign::cref_list_of<5>(j1)(j2)(j3)(j4)(j5)) {} /** Construct 6-way factor */ - SymbolicFactorUnordered(Key j1, Key j2, Key j3, Key j4, Key j5, Key j6) : + SymbolicFactor(Key j1, Key j2, Key j3, Key j4, Key j5, Key j6) : Base(boost::assign::cref_list_of<6>(j1)(j2)(j3)(j4)(j5)(j6)) {} - virtual ~SymbolicFactorUnordered() {} + virtual ~SymbolicFactor() {} /// @} @@ -88,20 +88,20 @@ namespace gtsam { /// @name Advanced Constructors /// @{ private: - explicit SymbolicFactorUnordered(const Base& base) : + explicit SymbolicFactor(const Base& base) : Base(base) {} public: /** Constructor from a collection of keys */ template - static SymbolicFactorUnordered FromIterators(KEYITERATOR beginKey, KEYITERATOR endKey) { - return SymbolicFactorUnordered(Base::FromIterators(beginKey, endKey)); } + static SymbolicFactor FromIterators(KEYITERATOR beginKey, KEYITERATOR endKey) { + return SymbolicFactor(Base::FromIterators(beginKey, endKey)); } /** Constructor from a collection of keys - compatible with boost::assign::list_of and * boost::assign::cref_list_of */ template - static SymbolicFactorUnordered FromKeys(const CONTAINER& keys) { - return SymbolicFactorUnordered(Base::FromKeys(keys)); } + static SymbolicFactor FromKeys(const CONTAINER& keys) { + return SymbolicFactor(Base::FromKeys(keys)); } /// @} @@ -113,8 +113,8 @@ namespace gtsam { /** Eliminate the variables in \c keys, in the order specified in \c keys, returning a * conditional and marginal. */ - std::pair, boost::shared_ptr > - eliminate(const OrderingUnordered& keys) const; + std::pair, boost::shared_ptr > + eliminate(const Ordering& keys) const; /// @} @@ -128,14 +128,14 @@ namespace gtsam { }; // IndexFactor // Forward declarations - class SymbolicFactorGraphUnordered; - class OrderingUnordered; + class SymbolicFactorGraph; + class Ordering; /** Dense elimination function for symbolic factors. This is usually provided as an argument to * one of the factor graph elimination functions (see EliminateableFactorGraph). The factor * graph elimination functions do sparse variable elimination, and use this function to eliminate * single variables or variable cliques. */ - GTSAM_EXPORT std::pair, boost::shared_ptr > - EliminateSymbolicUnordered(const SymbolicFactorGraphUnordered& factors, const OrderingUnordered& keys); + GTSAM_EXPORT std::pair, boost::shared_ptr > + EliminateSymbolic(const SymbolicFactorGraph& factors, const Ordering& keys); } diff --git a/gtsam/symbolic/SymbolicFactorGraphUnordered.cpp b/gtsam/symbolic/SymbolicFactorGraph.cpp similarity index 76% rename from gtsam/symbolic/SymbolicFactorGraphUnordered.cpp rename to gtsam/symbolic/SymbolicFactorGraph.cpp index b4c1466e5..ff34b27e0 100644 --- a/gtsam/symbolic/SymbolicFactorGraphUnordered.cpp +++ b/gtsam/symbolic/SymbolicFactorGraph.cpp @@ -17,42 +17,42 @@ #include -#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace gtsam { using namespace std; /* ************************************************************************* */ - bool SymbolicFactorGraphUnordered::equals(const This& fg, double tol) const + bool SymbolicFactorGraph::equals(const This& fg, double tol) const { return Base::equals(fg, tol); } /* ************************************************************************* */ - void SymbolicFactorGraphUnordered::push_factor(Key key) { - push_back(boost::make_shared(key)); + void SymbolicFactorGraph::push_factor(Key key) { + push_back(boost::make_shared(key)); } /* ************************************************************************* */ - void SymbolicFactorGraphUnordered::push_factor(Key key1, Key key2) { - push_back(boost::make_shared(key1,key2)); + void SymbolicFactorGraph::push_factor(Key key1, Key key2) { + push_back(boost::make_shared(key1,key2)); } /* ************************************************************************* */ - void SymbolicFactorGraphUnordered::push_factor(Key key1, Key key2, Key key3) { - push_back(boost::make_shared(key1,key2,key3)); + void SymbolicFactorGraph::push_factor(Key key1, Key key2, Key key3) { + push_back(boost::make_shared(key1,key2,key3)); } /* ************************************************************************* */ - void SymbolicFactorGraphUnordered::push_factor(Key key1, Key key2, Key key3, Key key4) { - push_back(boost::make_shared(key1,key2,key3,key4)); + void SymbolicFactorGraph::push_factor(Key key1, Key key2, Key key3, Key key4) { + push_back(boost::make_shared(key1,key2,key3,key4)); } // /* ************************************************************************* */ diff --git a/gtsam/symbolic/SymbolicFactorGraphUnordered.h b/gtsam/symbolic/SymbolicFactorGraph.h similarity index 53% rename from gtsam/symbolic/SymbolicFactorGraphUnordered.h rename to gtsam/symbolic/SymbolicFactorGraph.h index 53eb2af65..b37fc7db1 100644 --- a/gtsam/symbolic/SymbolicFactorGraphUnordered.h +++ b/gtsam/symbolic/SymbolicFactorGraph.h @@ -18,48 +18,48 @@ #pragma once -#include -#include +#include +#include #include #include namespace gtsam { - class SymbolicFactorGraphUnordered; - class SymbolicConditionalUnordered; - class SymbolicBayesNetUnordered; - class SymbolicEliminationTreeUnordered; - class SymbolicBayesTreeUnordered; - class SymbolicJunctionTreeUnordered; + class SymbolicFactorGraph; + class SymbolicConditional; + class SymbolicBayesNet; + class SymbolicEliminationTree; + class SymbolicBayesTree; + class SymbolicJunctionTree; /* ************************************************************************* */ - template<> struct EliminationTraits + template<> struct EliminationTraits { - typedef SymbolicFactorUnordered FactorType; ///< Type of factors in factor graph - typedef SymbolicFactorGraphUnordered FactorGraphType; ///< Type of the factor graph (e.g. GaussianFactorGraph) - typedef SymbolicConditionalUnordered ConditionalType; ///< Type of conditionals from elimination - typedef SymbolicBayesNetUnordered BayesNetType; ///< Type of Bayes net from sequential elimination - typedef SymbolicEliminationTreeUnordered EliminationTreeType; ///< Type of elimination tree - typedef SymbolicBayesTreeUnordered BayesTreeType; ///< Type of Bayes tree - typedef SymbolicJunctionTreeUnordered JunctionTreeType; ///< Type of Junction tree + typedef SymbolicFactor FactorType; ///< Type of factors in factor graph + typedef SymbolicFactorGraph FactorGraphType; ///< Type of the factor graph (e.g. GaussianFactorGraph) + typedef SymbolicConditional ConditionalType; ///< Type of conditionals from elimination + typedef SymbolicBayesNet BayesNetType; ///< Type of Bayes net from sequential elimination + typedef SymbolicEliminationTree EliminationTreeType; ///< Type of elimination tree + typedef SymbolicBayesTree BayesTreeType; ///< Type of Bayes tree + typedef SymbolicJunctionTree JunctionTreeType; ///< Type of Junction tree /// The default dense elimination function static std::pair, boost::shared_ptr > - DefaultEliminate(const FactorGraphType& factors, const OrderingUnordered& keys) { - return EliminateSymbolicUnordered(factors, keys); } + DefaultEliminate(const FactorGraphType& factors, const Ordering& keys) { + return EliminateSymbolic(factors, keys); } }; /* ************************************************************************* */ /** Symbolic Factor Graph * \nosubgrouping */ - class GTSAM_EXPORT SymbolicFactorGraphUnordered : - public FactorGraphUnordered, - public EliminateableFactorGraph + class GTSAM_EXPORT SymbolicFactorGraph : + public FactorGraph, + public EliminateableFactorGraph { public: - typedef SymbolicFactorGraphUnordered This; ///< Typedef to this class - typedef FactorGraphUnordered Base; ///< Typedef to base factor graph type + typedef SymbolicFactorGraph This; ///< Typedef to this class + typedef FactorGraph Base; ///< Typedef to base factor graph type typedef EliminateableFactorGraph BaseEliminateable; ///< Typedef to base elimination class typedef boost::shared_ptr shared_ptr; ///< shared_ptr to this class @@ -67,19 +67,19 @@ namespace gtsam { /// @{ /** Construct empty factor graph */ - SymbolicFactorGraphUnordered() {} + SymbolicFactorGraph() {} /** Construct from iterator over factors */ template - SymbolicFactorGraphUnordered(ITERATOR firstFactor, ITERATOR lastFactor) : Base(firstFactor, lastFactor) {} + SymbolicFactorGraph(ITERATOR firstFactor, ITERATOR lastFactor) : Base(firstFactor, lastFactor) {} /** Construct from container of factors (shared_ptr or plain objects) */ template - explicit SymbolicFactorGraphUnordered(const CONTAINER& factors) : Base(factors) {} + explicit SymbolicFactorGraph(const CONTAINER& factors) : Base(factors) {} /** Implicit copy/downcast constructor to override explicit template container constructor */ template - SymbolicFactorGraphUnordered(const FactorGraphUnordered& graph) : Base(graph) {} + SymbolicFactorGraph(const FactorGraph& graph) : Base(graph) {} /// @} diff --git a/gtsam/linear/GaussianJunctionTreeUnordered.cpp b/gtsam/symbolic/SymbolicJunctionTree.cpp similarity index 63% rename from gtsam/linear/GaussianJunctionTreeUnordered.cpp rename to gtsam/symbolic/SymbolicJunctionTree.cpp index e876b1fe5..ca4f82deb 100644 --- a/gtsam/linear/GaussianJunctionTreeUnordered.cpp +++ b/gtsam/symbolic/SymbolicJunctionTree.cpp @@ -10,29 +10,29 @@ * -------------------------------------------------------------------------- */ /** - * @file GaussianJunctionTreeUnordered.cpp + * @file SymbolicJunctionTree.cpp * @date Mar 29, 2013 * @author Frank Dellaert * @author Richard Roberts */ -#include -#include -#include +#include +#include +#include namespace gtsam { /* ************************************************************************* */ - GaussianJunctionTreeUnordered::GaussianJunctionTreeUnordered( - const GaussianEliminationTreeUnordered& eliminationTree) : + SymbolicJunctionTree::SymbolicJunctionTree( + const SymbolicEliminationTree& eliminationTree) : Base(Base::FromEliminationTree(eliminationTree)) {} /* ************************************************************************* */ - GaussianJunctionTreeUnordered::GaussianJunctionTreeUnordered(const This& other) : + SymbolicJunctionTree::SymbolicJunctionTree(const This& other) : Base(other) {} /* ************************************************************************* */ - GaussianJunctionTreeUnordered& GaussianJunctionTreeUnordered::operator=(const This& other) + SymbolicJunctionTree& SymbolicJunctionTree::operator=(const This& other) { (void) Base::operator=(other); return *this; diff --git a/gtsam/linear/GaussianJunctionTreeUnordered.h b/gtsam/symbolic/SymbolicJunctionTree.h similarity index 77% rename from gtsam/linear/GaussianJunctionTreeUnordered.h rename to gtsam/symbolic/SymbolicJunctionTree.h index 20cc3a2a8..3396c8698 100644 --- a/gtsam/linear/GaussianJunctionTreeUnordered.h +++ b/gtsam/symbolic/SymbolicJunctionTree.h @@ -10,20 +10,20 @@ * -------------------------------------------------------------------------- */ /** - * @file GaussianJunctionTreeUnordered.h + * @file SymbolicJunctionTree.h * @date Mar 29, 2013 * @author Frank Dellaert * @author Richard Roberts */ -#include -#include -#include +#include +#include +#include namespace gtsam { // Forward declarations - class GaussianEliminationTreeUnordered; + class SymbolicEliminationTree; /** * A ClusterTree, i.e., a set of variable clusters with factors, arranged in a tree, with @@ -45,11 +45,11 @@ namespace gtsam { * \addtogroup Multifrontal * \nosubgrouping */ - class GTSAM_EXPORT GaussianJunctionTreeUnordered : - public JunctionTreeUnordered { + class GTSAM_EXPORT SymbolicJunctionTree : + public JunctionTree { public: - typedef JunctionTreeUnordered Base; ///< Base class - typedef GaussianJunctionTreeUnordered This; ///< This class + typedef JunctionTree Base; ///< Base class + typedef SymbolicJunctionTree This; ///< This class typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class /** @@ -60,11 +60,11 @@ namespace gtsam { * named constructor instead. * @return The elimination tree */ - GaussianJunctionTreeUnordered(const GaussianEliminationTreeUnordered& eliminationTree); + SymbolicJunctionTree(const SymbolicEliminationTree& eliminationTree); /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are * copied, factors are not cloned. */ - GaussianJunctionTreeUnordered(const This& other); + SymbolicJunctionTree(const This& other); /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors are * copied, factors are not cloned. */ diff --git a/gtsam/symbolic/SymbolicJunctionTreeUnordered.cpp b/gtsam/symbolic/SymbolicJunctionTreeUnordered.cpp deleted file mode 100644 index 5acee9b75..000000000 --- a/gtsam/symbolic/SymbolicJunctionTreeUnordered.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file SymbolicJunctionTreeUnordered.cpp - * @date Mar 29, 2013 - * @author Frank Dellaert - * @author Richard Roberts - */ - -#include -#include -#include - -namespace gtsam { - - /* ************************************************************************* */ - SymbolicJunctionTreeUnordered::SymbolicJunctionTreeUnordered( - const SymbolicEliminationTreeUnordered& eliminationTree) : - Base(Base::FromEliminationTree(eliminationTree)) {} - - /* ************************************************************************* */ - SymbolicJunctionTreeUnordered::SymbolicJunctionTreeUnordered(const This& other) : - Base(other) {} - - /* ************************************************************************* */ - SymbolicJunctionTreeUnordered& SymbolicJunctionTreeUnordered::operator=(const This& other) - { - (void) Base::operator=(other); - return *this; - } - -} diff --git a/gtsam/symbolic/SymbolicJunctionTreeUnordered.h b/gtsam/symbolic/SymbolicJunctionTreeUnordered.h deleted file mode 100644 index 81c7b23d8..000000000 --- a/gtsam/symbolic/SymbolicJunctionTreeUnordered.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file SymbolicJunctionTreeUnordered.h - * @date Mar 29, 2013 - * @author Frank Dellaert - * @author Richard Roberts - */ - -#include -#include -#include - -namespace gtsam { - - // Forward declarations - class SymbolicEliminationTreeUnordered; - - /** - * A ClusterTree, i.e., a set of variable clusters with factors, arranged in a tree, with - * the additional property that it represents the clique tree associated with a Bayes net. - * - * In GTSAM a junction tree is an intermediate data structure in multifrontal - * variable elimination. Each node is a cluster of factors, along with a - * clique of variables that are eliminated all at once. In detail, every node k represents - * a clique (maximal fully connected subset) of an associated chordal graph, such as a - * chordal Bayes net resulting from elimination. - * - * The difference with the BayesTree is that a JunctionTree stores factors, whereas a - * BayesTree stores conditionals, that are the product of eliminating the factors in the - * corresponding JunctionTree cliques. - * - * The tree structure and elimination method are exactly analagous to the EliminationTree, - * except that in the JunctionTree, at each node multiple variables are eliminated at a time. - * - * \addtogroup Multifrontal - * \nosubgrouping - */ - class GTSAM_EXPORT SymbolicJunctionTreeUnordered : - public JunctionTreeUnordered { - public: - typedef JunctionTreeUnordered Base; ///< Base class - typedef SymbolicJunctionTreeUnordered This; ///< This class - typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class - - /** - * Build the elimination tree of a factor graph using pre-computed column structure. - * @param factorGraph The factor graph for which to build the elimination tree - * @param structure The set of factors involving each variable. If this is not - * precomputed, you can call the Create(const FactorGraph&) - * named constructor instead. - * @return The elimination tree - */ - SymbolicJunctionTreeUnordered(const SymbolicEliminationTreeUnordered& eliminationTree); - - /** Copy constructor - makes a deep copy of the tree structure, but only pointers to factors are - * copied, factors are not cloned. */ - SymbolicJunctionTreeUnordered(const This& other); - - /** Assignment operator - makes a deep copy of the tree structure, but only pointers to factors are - * copied, factors are not cloned. */ - This& operator=(const This& other); - }; - -} diff --git a/gtsam/symbolic/tests/symbolicExampleGraphs.h b/gtsam/symbolic/tests/symbolicExampleGraphs.h index e66f3d501..5052eb04c 100644 --- a/gtsam/symbolic/tests/symbolicExampleGraphs.h +++ b/gtsam/symbolic/tests/symbolicExampleGraphs.h @@ -20,62 +20,62 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include namespace gtsam { namespace { - const SymbolicFactorGraphUnordered simpleTestGraph1 = boost::assign::list_of - (boost::make_shared(0,1)) - (boost::make_shared(0,2)) - (boost::make_shared(1,4)) - (boost::make_shared(2,4)) - (boost::make_shared(3,4)); + const SymbolicFactorGraph simpleTestGraph1 = boost::assign::list_of + (boost::make_shared(0,1)) + (boost::make_shared(0,2)) + (boost::make_shared(1,4)) + (boost::make_shared(2,4)) + (boost::make_shared(3,4)); - const SymbolicBayesNetUnordered simpleTestGraph1BayesNet = boost::assign::list_of - (boost::make_shared(0,1,2)) - (boost::make_shared(1,2,4)) - (boost::make_shared(2,4)) - (boost::make_shared(3,4)) - (boost::make_shared(4)); + const SymbolicBayesNet simpleTestGraph1BayesNet = boost::assign::list_of + (boost::make_shared(0,1,2)) + (boost::make_shared(1,2,4)) + (boost::make_shared(2,4)) + (boost::make_shared(3,4)) + (boost::make_shared(4)); - const SymbolicFactorGraphUnordered simpleTestGraph2 = boost::assign::list_of - (boost::make_shared(0,1)) - (boost::make_shared(0,2)) - (boost::make_shared(1,3)) - (boost::make_shared(1,4)) - (boost::make_shared(2,3)) - (boost::make_shared(4,5)); + const SymbolicFactorGraph simpleTestGraph2 = boost::assign::list_of + (boost::make_shared(0,1)) + (boost::make_shared(0,2)) + (boost::make_shared(1,3)) + (boost::make_shared(1,4)) + (boost::make_shared(2,3)) + (boost::make_shared(4,5)); /** 1 - 0 - 2 - 3 */ - const SymbolicFactorGraphUnordered simpleChain = boost::assign::list_of - (boost::make_shared(1,0)) - (boost::make_shared(0,2)) - (boost::make_shared(2,3)); + const SymbolicFactorGraph simpleChain = boost::assign::list_of + (boost::make_shared(1,0)) + (boost::make_shared(0,2)) + (boost::make_shared(2,3)); /* ************************************************************************* * * 2 3 * 0 1 : 2 ****************************************************************************/ - SymbolicBayesTreeUnordered __simpleChainBayesTree() { - SymbolicBayesTreeUnordered result; - result.insertRoot(boost::make_shared( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(boost::assign::list_of(3)(2), 2)))); - result.addClique(boost::make_shared( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(boost::assign::list_of(1)(0)(2), 2))), + SymbolicBayesTree __simpleChainBayesTree() { + SymbolicBayesTree result; + result.insertRoot(boost::make_shared( + boost::make_shared( + SymbolicConditional::FromKeys(boost::assign::list_of(3)(2), 2)))); + result.addClique(boost::make_shared( + boost::make_shared( + SymbolicConditional::FromKeys(boost::assign::list_of(1)(0)(2), 2))), result.roots().front()); return result; } - const SymbolicBayesTreeUnordered simpleChainBayesTree = __simpleChainBayesTree(); + const SymbolicBayesTree simpleChainBayesTree = __simpleChainBayesTree(); /* ************************************************************************* */ // Keys for ASIA example from the tutorial with A and D evidence @@ -84,43 +84,43 @@ namespace gtsam { _L_=gtsam::symbol_shorthand::L(0), _B_=gtsam::symbol_shorthand::B(0); // Factor graph for Asia example - const SymbolicFactorGraphUnordered asiaGraph = boost::assign::list_of - (boost::make_shared(_T_)) - (boost::make_shared(_S_)) - (boost::make_shared(_T_, _E_, _L_)) - (boost::make_shared(_L_, _S_)) - (boost::make_shared(_S_, _B_)) - (boost::make_shared(_E_, _B_)) - (boost::make_shared(_E_, _X_)); + const SymbolicFactorGraph asiaGraph = boost::assign::list_of + (boost::make_shared(_T_)) + (boost::make_shared(_S_)) + (boost::make_shared(_T_, _E_, _L_)) + (boost::make_shared(_L_, _S_)) + (boost::make_shared(_S_, _B_)) + (boost::make_shared(_E_, _B_)) + (boost::make_shared(_E_, _X_)); - const SymbolicBayesNetUnordered asiaBayesNet = boost::assign::list_of - (boost::make_shared(_T_, _E_, _L_)) - (boost::make_shared(_X_, _E_)) - (boost::make_shared(_E_, _B_, _L_)) - (boost::make_shared(_S_, _B_, _L_)) - (boost::make_shared(_L_, _B_)) - (boost::make_shared(_B_)); + const SymbolicBayesNet asiaBayesNet = boost::assign::list_of + (boost::make_shared(_T_, _E_, _L_)) + (boost::make_shared(_X_, _E_)) + (boost::make_shared(_E_, _B_, _L_)) + (boost::make_shared(_S_, _B_, _L_)) + (boost::make_shared(_L_, _B_)) + (boost::make_shared(_B_)); - SymbolicBayesTreeUnordered __asiaBayesTree() { - SymbolicBayesTreeUnordered result; - result.insertRoot(boost::make_shared( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(boost::assign::list_of(_B_)(_L_)(_E_)(_S_), 4)))); - result.addClique(boost::make_shared( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(boost::assign::list_of(_T_)(_E_)(_L_), 1))), + SymbolicBayesTree __asiaBayesTree() { + SymbolicBayesTree result; + result.insertRoot(boost::make_shared( + boost::make_shared( + SymbolicConditional::FromKeys(boost::assign::list_of(_B_)(_L_)(_E_)(_S_), 4)))); + result.addClique(boost::make_shared( + boost::make_shared( + SymbolicConditional::FromKeys(boost::assign::list_of(_T_)(_E_)(_L_), 1))), result.roots().front()); - result.addClique(boost::make_shared( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(boost::assign::list_of(_X_)(_E_), 1))), + result.addClique(boost::make_shared( + boost::make_shared( + SymbolicConditional::FromKeys(boost::assign::list_of(_X_)(_E_), 1))), result.roots().front()); return result; } - const SymbolicBayesTreeUnordered asiaBayesTree = __asiaBayesTree(); + const SymbolicBayesTree asiaBayesTree = __asiaBayesTree(); /* ************************************************************************* */ - const OrderingUnordered asiaOrdering = boost::assign::list_of(_X_)(_T_)(_S_)(_E_)(_L_)(_B_); + const Ordering asiaOrdering = boost::assign::list_of(_X_)(_T_)(_S_)(_E_)(_L_)(_B_); } } diff --git a/gtsam/symbolic/tests/testSymbolicBayesNet.cpp b/gtsam/symbolic/tests/testSymbolicBayesNet.cpp index c63234e77..e71076f77 100644 --- a/gtsam/symbolic/tests/testSymbolicBayesNet.cpp +++ b/gtsam/symbolic/tests/testSymbolicBayesNet.cpp @@ -20,8 +20,8 @@ #include #include -#include -#include +#include +#include using namespace std; using namespace gtsam; @@ -33,17 +33,17 @@ static const Key _C_ = 3; static const Key _D_ = 4; static const Key _E_ = 5; -static SymbolicConditionalUnordered::shared_ptr - B(new SymbolicConditionalUnordered(_B_)), - L(new SymbolicConditionalUnordered(_L_, _B_)); +static SymbolicConditional::shared_ptr + B(new SymbolicConditional(_B_)), + L(new SymbolicConditional(_L_, _B_)); /* ************************************************************************* */ -TEST( SymbolicBayesNet, equals ) +TEST( SymbolicBayesNetOrdered, equals ) { - SymbolicBayesNetUnordered f1; + SymbolicBayesNet f1; f1.push_back(B); f1.push_back(L); - SymbolicBayesNetUnordered f2; + SymbolicBayesNet f2; f2.push_back(L); f2.push_back(B); CHECK(f1.equals(f1)); @@ -51,26 +51,26 @@ TEST( SymbolicBayesNet, equals ) } /* ************************************************************************* */ -TEST( SymbolicBayesNet, combine ) +TEST( SymbolicBayesNetOrdered, combine ) { - SymbolicConditionalUnordered::shared_ptr - A(new SymbolicConditionalUnordered(_A_,_B_,_C_)), - B(new SymbolicConditionalUnordered(_B_,_C_)), - C(new SymbolicConditionalUnordered(_C_)); + SymbolicConditional::shared_ptr + A(new SymbolicConditional(_A_,_B_,_C_)), + B(new SymbolicConditional(_B_,_C_)), + C(new SymbolicConditional(_C_)); // p(A|BC) - SymbolicBayesNetUnordered p_ABC; + SymbolicBayesNet p_ABC; p_ABC.push_back(A); // P(BC)=P(B|C)P(C) - SymbolicBayesNetUnordered p_BC; + SymbolicBayesNet p_BC; p_BC.push_back(B); p_BC.push_back(C); // P(ABC) = P(A|BC) P(BC) p_ABC.push_back(p_BC); - SymbolicBayesNetUnordered expected; + SymbolicBayesNet expected; expected.push_back(A); expected.push_back(B); expected.push_back(C); @@ -79,15 +79,15 @@ TEST( SymbolicBayesNet, combine ) } /* ************************************************************************* */ -TEST(SymbolicBayesNet, saveGraph) { - SymbolicBayesNetUnordered bn; - bn += SymbolicConditionalUnordered(_A_, _B_); +TEST(SymbolicBayesNetOrdered, saveGraph) { + SymbolicBayesNet bn; + bn += SymbolicConditional(_A_, _B_); std::vector keys; keys.push_back(_B_); keys.push_back(_C_); keys.push_back(_D_); - bn += SymbolicConditionalUnordered::FromKeys(keys,2); - bn += SymbolicConditionalUnordered(_D_); + bn += SymbolicConditional::FromKeys(keys,2); + bn += SymbolicConditional(_D_); bn.saveGraph("SymbolicBayesNet.dot"); } diff --git a/gtsam/symbolic/tests/testSymbolicBayesTree.cpp b/gtsam/symbolic/tests/testSymbolicBayesTree.cpp index 673ce2dc4..2104a364b 100644 --- a/gtsam/symbolic/tests/testSymbolicBayesTree.cpp +++ b/gtsam/symbolic/tests/testSymbolicBayesTree.cpp @@ -10,15 +10,15 @@ * -------------------------------------------------------------------------- */ /* - * @file testSymbolicBayesTreeUnordered.cpp + * @file testSymbolicBayesTree.cpp * @date sept 15, 2012 * @author Frank Dellaert * @author Michael Kaess * @author Viorela Ila */ -#include -#include +#include +#include #include #include @@ -43,23 +43,23 @@ namespace { /* ************************************************************************* */ // Helper functions for below template - SymbolicBayesTreeCliqueUnordered::shared_ptr MakeClique(const KEYS& keys, DenseIndex nrFrontals) + SymbolicBayesTreeClique::shared_ptr MakeClique(const KEYS& keys, DenseIndex nrFrontals) { - return boost::make_shared( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(keys, nrFrontals))); + return boost::make_shared( + boost::make_shared( + SymbolicConditional::FromKeys(keys, nrFrontals))); } template - SymbolicBayesTreeCliqueUnordered::shared_ptr MakeClique( + SymbolicBayesTreeClique::shared_ptr MakeClique( const KEYS& keys, DenseIndex nrFrontals, const CHILDREN& children) { - SymbolicBayesTreeCliqueUnordered::shared_ptr clique = - boost::make_shared( - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(keys, nrFrontals))); + SymbolicBayesTreeClique::shared_ptr clique = + boost::make_shared( + boost::make_shared( + SymbolicConditional::FromKeys(keys, nrFrontals))); clique->children = children; - BOOST_FOREACH(const SymbolicBayesTreeCliqueUnordered::shared_ptr& child, children) + BOOST_FOREACH(const SymbolicBayesTreeClique::shared_ptr& child, children) child->parent_ = clique; return clique; } @@ -67,12 +67,12 @@ namespace { } /* ************************************************************************* */ -TEST(SymbolicBayesTree, clear) +TEST(SymbolicBayesTreeOrdered, clear) { - SymbolicBayesTreeUnordered bayesTree = asiaBayesTree; + SymbolicBayesTree bayesTree = asiaBayesTree; bayesTree.clear(); - SymbolicBayesTreeUnordered expected; + SymbolicBayesTree expected; // Check whether cleared BayesTree is equal to a new BayesTree CHECK(assert_equal(expected, bayesTree)); @@ -85,11 +85,11 @@ Bayes Tree for testing conversion to a forest of orphans needed for incremental. D|C F|E */ /* ************************************************************************* */ -TEST( BayesTree, removePath ) +TEST( BayesTreeOrdered, removePath ) { const Key _A_=A(0), _B_=B(0), _C_=C(0), _D_=D(0), _E_=E(0), _F_=F(0); - SymbolicBayesTreeUnordered bayesTreeOrig; + SymbolicBayesTree bayesTreeOrig; bayesTreeOrig.insertRoot( MakeClique(list_of(_A_)(_B_), 2, list_of (MakeClique(list_of(_C_)(_A_), 1, list_of @@ -97,131 +97,131 @@ TEST( BayesTree, removePath ) (MakeClique(list_of(_E_)(_B_), 1, list_of (MakeClique(list_of(_F_)(_E_), 1)))))); - SymbolicBayesTreeUnordered bayesTree = bayesTreeOrig; + SymbolicBayesTree bayesTree = bayesTreeOrig; // remove C, expected outcome: factor graph with ABC, // Bayes Tree now contains two orphan trees: D|C and E|B,F|E - SymbolicFactorGraphUnordered expected; - expected += SymbolicFactorUnordered(_A_,_B_); - expected += SymbolicFactorUnordered(_C_,_A_); - SymbolicBayesTreeUnordered::Cliques expectedOrphans; + SymbolicFactorGraph expected; + expected += SymbolicFactor(_A_,_B_); + expected += SymbolicFactor(_C_,_A_); + SymbolicBayesTree::Cliques expectedOrphans; expectedOrphans += bayesTree[_D_], bayesTree[_E_]; - SymbolicBayesNetUnordered bn; - SymbolicBayesTreeUnordered::Cliques orphans; + SymbolicBayesNet bn; + SymbolicBayesTree::Cliques orphans; bayesTree.removePath(bayesTree[_C_], bn, orphans); - SymbolicFactorGraphUnordered factors(bn); + SymbolicFactorGraph factors(bn); CHECK(assert_equal(expected, factors)); CHECK(assert_container_equal(expectedOrphans|indirected, orphans|indirected)); bayesTree = bayesTreeOrig; // remove E: factor graph with EB; E|B removed from second orphan tree - SymbolicFactorGraphUnordered expected2; - expected2 += SymbolicFactorUnordered(_A_,_B_); - expected2 += SymbolicFactorUnordered(_E_,_B_); - SymbolicBayesTreeUnordered::Cliques expectedOrphans2; + SymbolicFactorGraph expected2; + expected2 += SymbolicFactor(_A_,_B_); + expected2 += SymbolicFactor(_E_,_B_); + SymbolicBayesTree::Cliques expectedOrphans2; expectedOrphans2 += bayesTree[_F_]; expectedOrphans2 += bayesTree[_C_]; - SymbolicBayesNetUnordered bn2; - SymbolicBayesTreeUnordered::Cliques orphans2; + SymbolicBayesNet bn2; + SymbolicBayesTree::Cliques orphans2; bayesTree.removePath(bayesTree[_E_], bn2, orphans2); - SymbolicFactorGraphUnordered factors2(bn2); + SymbolicFactorGraph factors2(bn2); CHECK(assert_equal(expected2, factors2)); CHECK(assert_container_equal(expectedOrphans2|indirected, orphans2|indirected)); } /* ************************************************************************* */ -TEST( BayesTree, removePath2 ) +TEST( BayesTreeOrdered, removePath2 ) { - SymbolicBayesTreeUnordered bayesTree = asiaBayesTree; + SymbolicBayesTree bayesTree = asiaBayesTree; // Call remove-path with clique B - SymbolicBayesNetUnordered bn; - SymbolicBayesTreeUnordered::Cliques orphans; + SymbolicBayesNet bn; + SymbolicBayesTree::Cliques orphans; bayesTree.removePath(bayesTree[_B_], bn, orphans); - SymbolicFactorGraphUnordered factors(bn); + SymbolicFactorGraph factors(bn); // Check expected outcome - SymbolicFactorGraphUnordered expected; - expected += SymbolicFactorUnordered(_B_,_L_,_E_,_S_); + SymbolicFactorGraph expected; + expected += SymbolicFactor(_B_,_L_,_E_,_S_); CHECK(assert_equal(expected, factors)); - SymbolicBayesTreeUnordered::Cliques expectedOrphans; + SymbolicBayesTree::Cliques expectedOrphans; expectedOrphans += bayesTree[_T_], bayesTree[_X_]; CHECK(assert_container_equal(expectedOrphans|indirected, orphans|indirected)); } /* ************************************************************************* */ -TEST( BayesTree, removePath3 ) +TEST( BayesTreeOrdered, removePath3 ) { - SymbolicBayesTreeUnordered bayesTree = asiaBayesTree; + SymbolicBayesTree bayesTree = asiaBayesTree; // Call remove-path with clique S - SymbolicBayesNetUnordered bn; - SymbolicBayesTreeUnordered::Cliques orphans; + SymbolicBayesNet bn; + SymbolicBayesTree::Cliques orphans; bayesTree.removePath(bayesTree[_T_], bn, orphans); - SymbolicFactorGraphUnordered factors(bn); + SymbolicFactorGraph factors(bn); // Check expected outcome - SymbolicFactorGraphUnordered expected; - expected += SymbolicFactorUnordered(_B_,_L_,_E_,_S_); - expected += SymbolicFactorUnordered(_T_,_E_,_L_); + SymbolicFactorGraph expected; + expected += SymbolicFactor(_B_,_L_,_E_,_S_); + expected += SymbolicFactor(_T_,_E_,_L_); CHECK(assert_equal(expected, factors)); - SymbolicBayesTreeUnordered::Cliques expectedOrphans; + SymbolicBayesTree::Cliques expectedOrphans; expectedOrphans += bayesTree[_X_]; CHECK(assert_container_equal(expectedOrphans|indirected, orphans|indirected)); } -void getAllCliques(const SymbolicBayesTreeUnordered::sharedClique& subtree, SymbolicBayesTreeUnordered::Cliques& cliques) { +void getAllCliques(const SymbolicBayesTree::sharedClique& subtree, SymbolicBayesTree::Cliques& cliques) { // Check if subtree exists if (subtree) { cliques.push_back(subtree); // Recursive call over all child cliques - BOOST_FOREACH(SymbolicBayesTreeUnordered::sharedClique& childClique, subtree->children) { + BOOST_FOREACH(SymbolicBayesTree::sharedClique& childClique, subtree->children) { getAllCliques(childClique,cliques); } } } /* ************************************************************************* */ -TEST( BayesTree, shortcutCheck ) +TEST( BayesTreeOrdered, shortcutCheck ) { const Key _A_=6, _B_=5, _C_=4, _D_=3, _E_=2, _F_=1, _G_=0; - SymbolicFactorGraphUnordered chain = list_of - (SymbolicFactorUnordered(_A_)) - (SymbolicFactorUnordered(_B_, _A_)) - (SymbolicFactorUnordered(_C_, _A_)) - (SymbolicFactorUnordered(_D_, _C_)) - (SymbolicFactorUnordered(_E_, _B_)) - (SymbolicFactorUnordered(_F_, _E_)) - (SymbolicFactorUnordered(_G_, _F_)); - SymbolicBayesTreeUnordered bayesTree = *chain.eliminateMultifrontal( - OrderingUnordered(list_of(_G_)(_F_)(_E_)(_D_)(_C_)(_B_)(_A_))); + SymbolicFactorGraph chain = list_of + (SymbolicFactor(_A_)) + (SymbolicFactor(_B_, _A_)) + (SymbolicFactor(_C_, _A_)) + (SymbolicFactor(_D_, _C_)) + (SymbolicFactor(_E_, _B_)) + (SymbolicFactor(_F_, _E_)) + (SymbolicFactor(_G_, _F_)); + SymbolicBayesTree bayesTree = *chain.eliminateMultifrontal( + Ordering(list_of(_G_)(_F_)(_E_)(_D_)(_C_)(_B_)(_A_))); //bayesTree.saveGraph("BT1.dot"); - SymbolicBayesTreeUnordered::sharedClique rootClique = bayesTree.roots().front(); + SymbolicBayesTree::sharedClique rootClique = bayesTree.roots().front(); //rootClique->printTree(); - SymbolicBayesTreeUnordered::Cliques allCliques; + SymbolicBayesTree::Cliques allCliques; getAllCliques(rootClique,allCliques); - BOOST_FOREACH(SymbolicBayesTreeUnordered::sharedClique& clique, allCliques) { + BOOST_FOREACH(SymbolicBayesTree::sharedClique& clique, allCliques) { //clique->print("Clique#"); - SymbolicBayesNetUnordered bn = clique->shortcut(rootClique); + SymbolicBayesNet bn = clique->shortcut(rootClique); //bn.print("Shortcut:\n"); //cout << endl; } // Check if all the cached shortcuts are cleared rootClique->deleteCachedShortcuts(); - BOOST_FOREACH(SymbolicBayesTreeUnordered::sharedClique& clique, allCliques) { + BOOST_FOREACH(SymbolicBayesTree::sharedClique& clique, allCliques) { bool notCleared = clique->cachedSeparatorMarginal(); CHECK( notCleared == false); } EXPECT_LONGS_EQUAL(0, (long)rootClique->numCachedSeparatorMarginals()); -// BOOST_FOREACH(SymbolicBayesTreeUnordered::sharedClique& clique, allCliques) { +// BOOST_FOREACH(SymbolicBayesTree::sharedClique& clique, allCliques) { // clique->print("Clique#"); // if(clique->cachedShortcut()){ // bn = clique->cachedShortcut().get(); @@ -234,43 +234,43 @@ TEST( BayesTree, shortcutCheck ) } /* ************************************************************************* */ -TEST( BayesTree, removeTop ) +TEST( BayesTreeOrdered, removeTop ) { - SymbolicBayesTreeUnordered bayesTree = asiaBayesTree; + SymbolicBayesTree bayesTree = asiaBayesTree; // create a new factor to be inserted //boost::shared_ptr newFactor(new IndexFactor(_S_,_B_)); // Remove the contaminated part of the Bayes tree - SymbolicBayesNetUnordered bn; - SymbolicBayesTreeUnordered::Cliques orphans; + SymbolicBayesNet bn; + SymbolicBayesTree::Cliques orphans; bayesTree.removeTop(list_of(_B_)(_S_), bn, orphans); // Check expected outcome - SymbolicBayesNetUnordered expected; - expected += SymbolicConditionalUnordered::FromKeys(list_of(_B_)(_L_)(_E_)(_S_), 4); + SymbolicBayesNet expected; + expected += SymbolicConditional::FromKeys(list_of(_B_)(_L_)(_E_)(_S_), 4); CHECK(assert_equal(expected, bn)); - SymbolicBayesTreeUnordered::Cliques expectedOrphans; + SymbolicBayesTree::Cliques expectedOrphans; expectedOrphans += bayesTree[_T_], bayesTree[_X_]; CHECK(assert_container_equal(expectedOrphans|indirected, orphans|indirected)); // Try removeTop again with a factor that should not change a thing //boost::shared_ptr newFactor2(new IndexFactor(_B_)); - SymbolicBayesNetUnordered bn2; - SymbolicBayesTreeUnordered::Cliques orphans2; + SymbolicBayesNet bn2; + SymbolicBayesTree::Cliques orphans2; bayesTree.removeTop(list_of(_B_), bn2, orphans2); - SymbolicFactorGraphUnordered factors2(bn2); - SymbolicFactorGraphUnordered expected2; + SymbolicFactorGraph factors2(bn2); + SymbolicFactorGraph expected2; CHECK(assert_equal(expected2, factors2)); - SymbolicBayesTreeUnordered::Cliques expectedOrphans2; + SymbolicBayesTree::Cliques expectedOrphans2; CHECK(assert_container_equal(expectedOrphans2|indirected, orphans2|indirected)); } /* ************************************************************************* */ -TEST( BayesTree, removeTop2 ) +TEST( BayesTreeOrdered, removeTop2 ) { - SymbolicBayesTreeUnordered bayesTree = asiaBayesTree; + SymbolicBayesTree bayesTree = asiaBayesTree; // create two factors to be inserted //SymbolicFactorGraph newFactors; @@ -278,93 +278,93 @@ TEST( BayesTree, removeTop2 ) //newFactors.push_factor(_S_); // Remove the contaminated part of the Bayes tree - SymbolicBayesNetUnordered bn; - SymbolicBayesTreeUnordered::Cliques orphans; + SymbolicBayesNet bn; + SymbolicBayesTree::Cliques orphans; bayesTree.removeTop(list_of(_T_), bn, orphans); // Check expected outcome - SymbolicBayesNetUnordered expected = list_of - (SymbolicConditionalUnordered::FromKeys(list_of(_B_)(_L_)(_E_)(_S_), 4)) - (SymbolicConditionalUnordered::FromKeys(list_of(_T_)(_E_)(_L_), 1)); + SymbolicBayesNet expected = list_of + (SymbolicConditional::FromKeys(list_of(_B_)(_L_)(_E_)(_S_), 4)) + (SymbolicConditional::FromKeys(list_of(_T_)(_E_)(_L_), 1)); CHECK(assert_equal(expected, bn)); - SymbolicBayesTreeUnordered::Cliques expectedOrphans; + SymbolicBayesTree::Cliques expectedOrphans; expectedOrphans += bayesTree[_X_]; CHECK(assert_container_equal(expectedOrphans|indirected, orphans|indirected)); } /* ************************************************************************* */ -TEST( BayesTree, removeTop3 ) +TEST( BayesTreeOrdered, removeTop3 ) { - SymbolicFactorGraphUnordered graph = list_of - (SymbolicFactorUnordered(L(5))) - (SymbolicFactorUnordered(X(4), L(5))) - (SymbolicFactorUnordered(X(2), X(4))) - (SymbolicFactorUnordered(X(3), X(2))); - SymbolicBayesTreeUnordered bayesTree = *graph.eliminateMultifrontal( - OrderingUnordered(list_of (X(3)) (X(2)) (X(4)) (L(5)) )); + SymbolicFactorGraph graph = list_of + (SymbolicFactor(L(5))) + (SymbolicFactor(X(4), L(5))) + (SymbolicFactor(X(2), X(4))) + (SymbolicFactor(X(3), X(2))); + SymbolicBayesTree bayesTree = *graph.eliminateMultifrontal( + Ordering(list_of (X(3)) (X(2)) (X(4)) (L(5)) )); // remove all - SymbolicBayesNetUnordered bn; - SymbolicBayesTreeUnordered::Cliques orphans; + SymbolicBayesNet bn; + SymbolicBayesTree::Cliques orphans; bayesTree.removeTop(list_of(L(5))(X(4))(X(2))(X(3)), bn, orphans); - SymbolicBayesNetUnordered expectedBn = list_of - (SymbolicConditionalUnordered::FromKeys(list_of(L(5))(X(4)), 2)) - (SymbolicConditionalUnordered(X(2), X(4))) - (SymbolicConditionalUnordered(X(3), X(2))); + SymbolicBayesNet expectedBn = list_of + (SymbolicConditional::FromKeys(list_of(L(5))(X(4)), 2)) + (SymbolicConditional(X(2), X(4))) + (SymbolicConditional(X(3), X(2))); EXPECT(assert_equal(expectedBn, bn)); EXPECT(orphans.empty()); } /* ************************************************************************* */ -TEST( BayesTree, removeTop4 ) +TEST( BayesTreeOrdered, removeTop4 ) { - SymbolicFactorGraphUnordered graph = list_of - (SymbolicFactorUnordered(L(5))) - (SymbolicFactorUnordered(X(4), L(5))) - (SymbolicFactorUnordered(X(2), X(4))) - (SymbolicFactorUnordered(X(3), X(2))); - SymbolicBayesTreeUnordered bayesTree = *graph.eliminateMultifrontal( - OrderingUnordered(list_of (X(3)) (X(2)) (X(4)) (L(5)) )); + SymbolicFactorGraph graph = list_of + (SymbolicFactor(L(5))) + (SymbolicFactor(X(4), L(5))) + (SymbolicFactor(X(2), X(4))) + (SymbolicFactor(X(3), X(2))); + SymbolicBayesTree bayesTree = *graph.eliminateMultifrontal( + Ordering(list_of (X(3)) (X(2)) (X(4)) (L(5)) )); // remove all - SymbolicBayesNetUnordered bn; - SymbolicBayesTreeUnordered::Cliques orphans; + SymbolicBayesNet bn; + SymbolicBayesTree::Cliques orphans; bayesTree.removeTop(list_of(X(2))(L(5))(X(4))(X(3)), bn, orphans); - SymbolicBayesNetUnordered expectedBn = list_of - (SymbolicConditionalUnordered::FromKeys(list_of(L(5))(X(4)), 2)) - (SymbolicConditionalUnordered(X(2), X(4))) - (SymbolicConditionalUnordered(X(3), X(2))); + SymbolicBayesNet expectedBn = list_of + (SymbolicConditional::FromKeys(list_of(L(5))(X(4)), 2)) + (SymbolicConditional(X(2), X(4))) + (SymbolicConditional(X(3), X(2))); EXPECT(assert_equal(expectedBn, bn)); EXPECT(orphans.empty()); } /* ************************************************************************* */ -TEST( SymbolicBayesTreeUnordered, thinTree ) { +TEST( SymbolicBayesTree, thinTree ) { // create a thin-tree Bayesnet, a la Jean-Guillaume - SymbolicBayesNetUnordered bayesNet; - bayesNet.push_back(boost::make_shared(14)); + SymbolicBayesNet bayesNet; + bayesNet.push_back(boost::make_shared(14)); - bayesNet.push_back(boost::make_shared(13, 14)); - bayesNet.push_back(boost::make_shared(12, 14)); + bayesNet.push_back(boost::make_shared(13, 14)); + bayesNet.push_back(boost::make_shared(12, 14)); - bayesNet.push_back(boost::make_shared(11, 13, 14)); - bayesNet.push_back(boost::make_shared(10, 13, 14)); - bayesNet.push_back(boost::make_shared(9, 12, 14)); - bayesNet.push_back(boost::make_shared(8, 12, 14)); + bayesNet.push_back(boost::make_shared(11, 13, 14)); + bayesNet.push_back(boost::make_shared(10, 13, 14)); + bayesNet.push_back(boost::make_shared(9, 12, 14)); + bayesNet.push_back(boost::make_shared(8, 12, 14)); - bayesNet.push_back(boost::make_shared(7, 11, 13)); - bayesNet.push_back(boost::make_shared(6, 11, 13)); - bayesNet.push_back(boost::make_shared(5, 10, 13)); - bayesNet.push_back(boost::make_shared(4, 10, 13)); + bayesNet.push_back(boost::make_shared(7, 11, 13)); + bayesNet.push_back(boost::make_shared(6, 11, 13)); + bayesNet.push_back(boost::make_shared(5, 10, 13)); + bayesNet.push_back(boost::make_shared(4, 10, 13)); - bayesNet.push_back(boost::make_shared(3, 9, 12)); - bayesNet.push_back(boost::make_shared(2, 9, 12)); - bayesNet.push_back(boost::make_shared(1, 8, 12)); - bayesNet.push_back(boost::make_shared(0, 8, 12)); + bayesNet.push_back(boost::make_shared(3, 9, 12)); + bayesNet.push_back(boost::make_shared(2, 9, 12)); + bayesNet.push_back(boost::make_shared(1, 8, 12)); + bayesNet.push_back(boost::make_shared(0, 8, 12)); if (debug) { GTSAM_PRINT(bayesNet); @@ -372,114 +372,114 @@ TEST( SymbolicBayesTreeUnordered, thinTree ) { } // create a BayesTree out of a Bayes net - OrderingUnordered ordering(bayesNet.keys()); - SymbolicBayesTreeUnordered bayesTree = *SymbolicFactorGraphUnordered(bayesNet).eliminateMultifrontal(ordering); + Ordering ordering(bayesNet.keys()); + SymbolicBayesTree bayesTree = *SymbolicFactorGraph(bayesNet).eliminateMultifrontal(ordering); if (debug) { GTSAM_PRINT(bayesTree); - bayesTree.saveGraph("/tmp/SymbolicBayesTreeUnordered.dot"); + bayesTree.saveGraph("/tmp/SymbolicBayesTree.dot"); } - SymbolicBayesTreeUnordered::Clique::shared_ptr R = bayesTree.roots().front(); + SymbolicBayesTree::Clique::shared_ptr R = bayesTree.roots().front(); { // check shortcut P(S9||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[9]; - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected; + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[9]; + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected; EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S8||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[8]; - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected = list_of(SymbolicConditionalUnordered(12, 14)); + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[8]; + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected = list_of(SymbolicConditional(12, 14)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S4||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[4]; - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(10, 13, 14)); + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[4]; + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(10, 13, 14)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S2||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[2]; - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(12, 14)); - expected.push_back(boost::make_shared(9, 12, 14)); + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[2]; + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(12, 14)); + expected.push_back(boost::make_shared(9, 12, 14)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S0||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[0]; - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(12, 14)); - expected.push_back(boost::make_shared(8, 12, 14)); + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[0]; + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(12, 14)); + expected.push_back(boost::make_shared(8, 12, 14)); EXPECT(assert_equal(expected, shortcut)); } - SymbolicBayesNetUnordered::shared_ptr actualJoint; + SymbolicBayesNet::shared_ptr actualJoint; // Check joint P(8,2) if (false) { // TODO, not disjoint actualJoint = bayesTree.jointBayesNet(8, 2); - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(8)); - expected.push_back(boost::make_shared(2, 8)); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(8)); + expected.push_back(boost::make_shared(2, 8)); EXPECT(assert_equal(expected, *actualJoint)); } // Check joint P(1,2) if (false) { // TODO, not disjoint actualJoint = bayesTree.jointBayesNet(1, 2); - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(2)); - expected.push_back(boost::make_shared(1, 2)); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(2)); + expected.push_back(boost::make_shared(1, 2)); EXPECT(assert_equal(expected, *actualJoint)); } // Check joint P(2,6) if (true) { actualJoint = bayesTree.jointBayesNet(2, 6); - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(2, 6)); - expected.push_back(boost::make_shared(6)); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(2, 6)); + expected.push_back(boost::make_shared(6)); EXPECT(assert_equal(expected, *actualJoint)); } // Check joint P(4,6) if (false) { // TODO, not disjoint actualJoint = bayesTree.jointBayesNet(4, 6); - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(6)); - expected.push_back(boost::make_shared(4, 6)); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(6)); + expected.push_back(boost::make_shared(4, 6)); EXPECT(assert_equal(expected, *actualJoint)); } } /* ************************************************************************* */ -TEST(SymbolicBayesTreeUnordered, forest_joint) +TEST(SymbolicBayesTree, forest_joint) { // Create forest - SymbolicBayesTreeCliqueUnordered::shared_ptr root1 = MakeClique(list_of(1), 1); - SymbolicBayesTreeCliqueUnordered::shared_ptr root2 = MakeClique(list_of(2), 1); - SymbolicBayesTreeUnordered bayesTree; + SymbolicBayesTreeClique::shared_ptr root1 = MakeClique(list_of(1), 1); + SymbolicBayesTreeClique::shared_ptr root2 = MakeClique(list_of(2), 1); + SymbolicBayesTree bayesTree; bayesTree.insertRoot(root1); bayesTree.insertRoot(root2); // Check joint - SymbolicBayesNetUnordered expected = list_of - (SymbolicConditionalUnordered(1)) - (SymbolicConditionalUnordered(2)); - SymbolicBayesNetUnordered actual = *bayesTree.jointBayesNet(1, 2); + SymbolicBayesNet expected = list_of + (SymbolicConditional(1)) + (SymbolicConditional(2)); + SymbolicBayesNet actual = *bayesTree.jointBayesNet(1, 2); EXPECT(assert_equal(expected, actual)); } @@ -494,9 +494,9 @@ TEST(SymbolicBayesTreeUnordered, forest_joint) C6 0 : 1 **************************************************************************** */ -TEST( SymbolicBayesTreeUnordered, linear_smoother_shortcuts ) { +TEST( SymbolicBayesTree, linear_smoother_shortcuts ) { // Create smoother with 7 nodes - SymbolicFactorGraphUnordered smoother; + SymbolicFactorGraph smoother; smoother.push_factor(0); smoother.push_factor(0, 1); smoother.push_factor(1, 2); @@ -506,8 +506,8 @@ TEST( SymbolicBayesTreeUnordered, linear_smoother_shortcuts ) { smoother.push_factor(5, 6); // Eliminate in numerical order 0..6 - OrderingUnordered ordering(smoother.keys()); - SymbolicBayesNetUnordered bayesNet = *smoother.eliminateSequential(ordering); + Ordering ordering(smoother.keys()); + SymbolicBayesNet bayesNet = *smoother.eliminateSequential(ordering); if (debug) { GTSAM_PRINT(bayesNet); @@ -515,46 +515,46 @@ TEST( SymbolicBayesTreeUnordered, linear_smoother_shortcuts ) { } // create a BayesTree - SymbolicBayesTreeUnordered bayesTree = *smoother.eliminateMultifrontal(ordering); + SymbolicBayesTree bayesTree = *smoother.eliminateMultifrontal(ordering); if (debug) { GTSAM_PRINT(bayesTree); - bayesTree.saveGraph("/tmp/SymbolicBayesTreeUnordered.dot"); + bayesTree.saveGraph("/tmp/SymbolicBayesTree.dot"); } - SymbolicBayesTreeUnordered::Clique::shared_ptr R = bayesTree.roots().front(); + SymbolicBayesTree::Clique::shared_ptr R = bayesTree.roots().front(); { // check shortcut P(S2||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[4]; // 4 is frontal in C2 - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected; + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[4]; // 4 is frontal in C2 + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected; EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S3||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[3]; // 3 is frontal in C3 - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected = list_of(SymbolicConditionalUnordered(4, 5)); + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[3]; // 3 is frontal in C3 + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected = list_of(SymbolicConditional(4, 5)); EXPECT(assert_equal(expected, shortcut)); } { // check shortcut P(S4||R) to root - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bayesTree[2]; // 2 is frontal in C4 - SymbolicBayesNetUnordered shortcut = c->shortcut(R); - SymbolicBayesNetUnordered expected = list_of(SymbolicConditionalUnordered(3, 5)); + SymbolicBayesTree::Clique::shared_ptr c = bayesTree[2]; // 2 is frontal in C4 + SymbolicBayesNet shortcut = c->shortcut(R); + SymbolicBayesNet expected = list_of(SymbolicConditional(3, 5)); EXPECT(assert_equal(expected, shortcut)); } } /* ************************************************************************* */ // from testSymbolicJunctionTree, which failed at one point -TEST(SymbolicBayesTreeUnordered, complicatedMarginal) +TEST(SymbolicBayesTree, complicatedMarginal) { // Create the conditionals to go in the BayesTree - SymbolicBayesTreeCliqueUnordered::shared_ptr cur; - SymbolicBayesTreeCliqueUnordered::shared_ptr root = MakeClique(list_of(11)(12), 2); + SymbolicBayesTreeClique::shared_ptr cur; + SymbolicBayesTreeClique::shared_ptr root = MakeClique(list_of(11)(12), 2); cur = root; root->children += MakeClique(list_of(9)(10)(11)(12), 2); @@ -575,63 +575,63 @@ TEST(SymbolicBayesTreeUnordered, complicatedMarginal) cur->children.back()->parent_ = cur; // Create Bayes Tree - SymbolicBayesTreeUnordered bt; + SymbolicBayesTree bt; bt.insertRoot(root); if (debug) { GTSAM_PRINT(bt); - bt.saveGraph("/tmp/SymbolicBayesTreeUnordered.dot"); + bt.saveGraph("/tmp/SymbolicBayesTree.dot"); } // Shortcut on 9 { - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bt[9]; - SymbolicBayesNetUnordered shortcut = c->shortcut(root); - EXPECT(assert_equal(SymbolicBayesNetUnordered(), shortcut)); + SymbolicBayesTree::Clique::shared_ptr c = bt[9]; + SymbolicBayesNet shortcut = c->shortcut(root); + EXPECT(assert_equal(SymbolicBayesNet(), shortcut)); } // Shortcut on 7 { - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bt[7]; - SymbolicBayesNetUnordered shortcut = c->shortcut(root); - EXPECT(assert_equal(SymbolicBayesNetUnordered(), shortcut)); + SymbolicBayesTree::Clique::shared_ptr c = bt[7]; + SymbolicBayesNet shortcut = c->shortcut(root); + EXPECT(assert_equal(SymbolicBayesNet(), shortcut)); } // Shortcut on 5 { - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bt[5]; - SymbolicBayesNetUnordered shortcut = c->shortcut(root); - SymbolicBayesNetUnordered expected = list_of - (SymbolicConditionalUnordered(7, 8, 11)) - (SymbolicConditionalUnordered(8, 11)); + SymbolicBayesTree::Clique::shared_ptr c = bt[5]; + SymbolicBayesNet shortcut = c->shortcut(root); + SymbolicBayesNet expected = list_of + (SymbolicConditional(7, 8, 11)) + (SymbolicConditional(8, 11)); EXPECT(assert_equal(expected, shortcut)); } // Shortcut on 3 { - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bt[3]; - SymbolicBayesNetUnordered shortcut = c->shortcut(root); - SymbolicBayesNetUnordered expected = list_of(SymbolicConditionalUnordered(6, 11)); + SymbolicBayesTree::Clique::shared_ptr c = bt[3]; + SymbolicBayesNet shortcut = c->shortcut(root); + SymbolicBayesNet expected = list_of(SymbolicConditional(6, 11)); EXPECT(assert_equal(expected, shortcut)); } // Shortcut on 1 { - SymbolicBayesTreeUnordered::Clique::shared_ptr c = bt[1]; - SymbolicBayesNetUnordered shortcut = c->shortcut(root); - SymbolicBayesNetUnordered expected = list_of(SymbolicConditionalUnordered(5, 11)); + SymbolicBayesTree::Clique::shared_ptr c = bt[1]; + SymbolicBayesNet shortcut = c->shortcut(root); + SymbolicBayesNet expected = list_of(SymbolicConditional(5, 11)); EXPECT(assert_equal(expected, shortcut)); } // Marginal on 5 { - SymbolicFactorUnordered::shared_ptr actual = bt.marginalFactor(5); - EXPECT(assert_equal(SymbolicFactorUnordered(5), *actual, 1e-1)); + SymbolicFactor::shared_ptr actual = bt.marginalFactor(5); + EXPECT(assert_equal(SymbolicFactor(5), *actual, 1e-1)); } // Shortcut on 6 { - SymbolicFactorUnordered::shared_ptr actual = bt.marginalFactor(6); - EXPECT(assert_equal(SymbolicFactorUnordered(6), *actual, 1e-1)); + SymbolicFactor::shared_ptr actual = bt.marginalFactor(6); + EXPECT(assert_equal(SymbolicFactor(6), *actual, 1e-1)); } } diff --git a/gtsam/symbolic/tests/testSymbolicConditional.cpp b/gtsam/symbolic/tests/testSymbolicConditional.cpp index 9a8e3daec..c173f4a74 100644 --- a/gtsam/symbolic/tests/testSymbolicConditional.cpp +++ b/gtsam/symbolic/tests/testSymbolicConditional.cpp @@ -20,7 +20,7 @@ using namespace boost::assign; #include #include -#include +#include using namespace std; using namespace gtsam; @@ -28,7 +28,7 @@ using namespace gtsam; /* ************************************************************************* */ TEST( SymbolicConditional, empty ) { - SymbolicConditionalUnordered c0; + SymbolicConditional c0; LONGS_EQUAL(0,c0.nrFrontals()) LONGS_EQUAL(0,c0.nrParents()) } @@ -36,7 +36,7 @@ TEST( SymbolicConditional, empty ) /* ************************************************************************* */ TEST( SymbolicConditional, noParents ) { - SymbolicConditionalUnordered c0(0); + SymbolicConditional c0(0); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(0,c0.nrParents()) } @@ -44,7 +44,7 @@ TEST( SymbolicConditional, noParents ) /* ************************************************************************* */ TEST( SymbolicConditional, oneParents ) { - SymbolicConditionalUnordered c0(0,1); + SymbolicConditional c0(0,1); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(1,c0.nrParents()) } @@ -52,7 +52,7 @@ TEST( SymbolicConditional, oneParents ) /* ************************************************************************* */ TEST( SymbolicConditional, twoParents ) { - SymbolicConditionalUnordered c0(0,1,2); + SymbolicConditional c0(0,1,2); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(2,c0.nrParents()) } @@ -60,7 +60,7 @@ TEST( SymbolicConditional, twoParents ) /* ************************************************************************* */ TEST( SymbolicConditional, threeParents ) { - SymbolicConditionalUnordered c0(0,1,2,3); + SymbolicConditional c0(0,1,2,3); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(3,c0.nrParents()) } @@ -68,7 +68,7 @@ TEST( SymbolicConditional, threeParents ) /* ************************************************************************* */ TEST( SymbolicConditional, fourParents ) { - SymbolicConditionalUnordered c0 = SymbolicConditionalUnordered::FromKeys( + SymbolicConditional c0 = SymbolicConditional::FromKeys( list_of(0)(1)(2)(3)(4), 1); LONGS_EQUAL(1,c0.nrFrontals()) LONGS_EQUAL(4,c0.nrParents()) @@ -77,9 +77,9 @@ TEST( SymbolicConditional, fourParents ) /* ************************************************************************* */ TEST( SymbolicConditional, FromRange ) { - SymbolicConditionalUnordered::shared_ptr c0 = - boost::make_shared( - SymbolicConditionalUnordered::FromKeys(list_of(1)(2)(3)(4)(5), 2)); + SymbolicConditional::shared_ptr c0 = + boost::make_shared( + SymbolicConditional::FromKeys(list_of(1)(2)(3)(4)(5), 2)); LONGS_EQUAL(2,c0->nrFrontals()) LONGS_EQUAL(3,c0->nrParents()) } @@ -87,7 +87,7 @@ TEST( SymbolicConditional, FromRange ) /* ************************************************************************* */ TEST( SymbolicConditional, equals ) { - SymbolicConditionalUnordered c0(0, 1, 2), c1(0, 1, 2), c2(1, 2, 3), c3(3,4); + SymbolicConditional c0(0, 1, 2), c1(0, 1, 2), c2(1, 2, 3), c3(3,4); CHECK(c0.equals(c1)); CHECK(c1.equals(c0)); CHECK(!c0.equals(c2)); diff --git a/gtsam/symbolic/tests/testSymbolicEliminationTree.cpp b/gtsam/symbolic/tests/testSymbolicEliminationTree.cpp index 11b92f138..b6340e93c 100644 --- a/gtsam/symbolic/tests/testSymbolicEliminationTree.cpp +++ b/gtsam/symbolic/tests/testSymbolicEliminationTree.cpp @@ -25,7 +25,7 @@ using namespace boost::assign; #include #include -#include +#include #include #include "symbolicExampleGraphs.h" @@ -34,36 +34,36 @@ using namespace gtsam; using namespace gtsam::symbol_shorthand; using namespace std; -class EliminationTreeUnorderedTester { +class EliminationTreeTester { public: // build hardcoded tree - static SymbolicEliminationTreeUnordered buildHardcodedTree(const SymbolicFactorGraphUnordered& fg) { + static SymbolicEliminationTree buildHardcodedTree(const SymbolicFactorGraph& fg) { - SymbolicEliminationTreeUnordered::sharedNode leaf0(new SymbolicEliminationTreeUnordered::Node); + SymbolicEliminationTree::sharedNode leaf0(new SymbolicEliminationTree::Node); leaf0->key = 0; leaf0->factors.push_back(fg[0]); leaf0->factors.push_back(fg[1]); - SymbolicEliminationTreeUnordered::sharedNode node1(new SymbolicEliminationTreeUnordered::Node); + SymbolicEliminationTree::sharedNode node1(new SymbolicEliminationTree::Node); node1->key = 1; node1->factors.push_back(fg[2]); node1->children.push_back(leaf0); - SymbolicEliminationTreeUnordered::sharedNode node2(new SymbolicEliminationTreeUnordered::Node); + SymbolicEliminationTree::sharedNode node2(new SymbolicEliminationTree::Node); node2->key = 2; node2->factors.push_back(fg[3]); node2->children.push_back(node1); - SymbolicEliminationTreeUnordered::sharedNode leaf3(new SymbolicEliminationTreeUnordered::Node); + SymbolicEliminationTree::sharedNode leaf3(new SymbolicEliminationTree::Node); leaf3->key = 3; leaf3->factors.push_back(fg[4]); - SymbolicEliminationTreeUnordered::sharedNode root(new SymbolicEliminationTreeUnordered::Node); + SymbolicEliminationTree::sharedNode root(new SymbolicEliminationTree::Node); root->key = 4; root->children.push_back(leaf3); root->children.push_back(node2); - SymbolicEliminationTreeUnordered tree; + SymbolicEliminationTree tree; tree.roots_.push_back(root); return tree; } @@ -71,15 +71,15 @@ public: /* ************************************************************************* */ -TEST(EliminationTree, Create) +TEST(EliminationTreeOrdered, Create) { - SymbolicEliminationTreeUnordered expected = - EliminationTreeUnorderedTester::buildHardcodedTree(simpleTestGraph1); + SymbolicEliminationTree expected = + EliminationTreeTester::buildHardcodedTree(simpleTestGraph1); // Build from factor graph - OrderingUnordered order; + Ordering order; order += 0,1,2,3,4; - SymbolicEliminationTreeUnordered actual(simpleTestGraph1, order); + SymbolicEliminationTree actual(simpleTestGraph1, order); CHECK(assert_equal(expected, actual)); } diff --git a/gtsam/symbolic/tests/testSymbolicFactor.cpp b/gtsam/symbolic/tests/testSymbolicFactor.cpp index 525e25bed..7596f9017 100644 --- a/gtsam/symbolic/tests/testSymbolicFactor.cpp +++ b/gtsam/symbolic/tests/testSymbolicFactor.cpp @@ -17,9 +17,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -34,17 +34,17 @@ using namespace boost::assign; #ifdef TRACK_ELIMINATE TEST(SymbolicFactor, eliminate) { vector keys; keys += 2, 3, 4, 6, 7, 9, 10, 11; - IndexFactor actual(keys.begin(), keys.end()); - BayesNet fragment = *actual.eliminate(3); + IndexFactorOrdered actual(keys.begin(), keys.end()); + BayesNetOrdered fragment = *actual.eliminate(3); - IndexFactor expected(keys.begin()+3, keys.end()); - IndexConditional::shared_ptr expected0 = IndexConditional::FromRange(keys.begin(), keys.end(), 1); - IndexConditional::shared_ptr expected1 = IndexConditional::FromRange(keys.begin()+1, keys.end(), 1); - IndexConditional::shared_ptr expected2 = IndexConditional::FromRange(keys.begin()+2, keys.end(), 1); + IndexFactorOrdered expected(keys.begin()+3, keys.end()); + IndexConditionalOrdered::shared_ptr expected0 = IndexConditionalOrdered::FromRange(keys.begin(), keys.end(), 1); + IndexConditionalOrdered::shared_ptr expected1 = IndexConditionalOrdered::FromRange(keys.begin()+1, keys.end(), 1); + IndexConditionalOrdered::shared_ptr expected2 = IndexConditionalOrdered::FromRange(keys.begin()+2, keys.end(), 1); CHECK(assert_equal(fragment.size(), size_t(3))); CHECK(assert_equal(expected, actual)); - BayesNet::const_iterator fragmentCond = fragment.begin(); + BayesNetOrdered::const_iterator fragmentCond = fragment.begin(); CHECK(assert_equal(**fragmentCond++, *expected0)); CHECK(assert_equal(**fragmentCond++, *expected1)); CHECK(assert_equal(**fragmentCond++, *expected2)); @@ -53,19 +53,19 @@ TEST(SymbolicFactor, eliminate) { /* ************************************************************************* */ TEST(SymbolicFactor, EliminateSymbolic) { - const SymbolicFactorGraphUnordered factors = list_of - (SymbolicFactorUnordered(2,4,6)) - (SymbolicFactorUnordered(1,2,5)) - (SymbolicFactorUnordered(0,3)); + const SymbolicFactorGraph factors = list_of + (SymbolicFactor(2,4,6)) + (SymbolicFactor(1,2,5)) + (SymbolicFactor(0,3)); - const SymbolicFactorUnordered expectedFactor(4,5,6); - const SymbolicConditionalUnordered expectedConditional = - SymbolicConditionalUnordered::FromKeys(list_of(0)(1)(2)(3)(4)(5)(6), 4); + const SymbolicFactor expectedFactor(4,5,6); + const SymbolicConditional expectedConditional = + SymbolicConditional::FromKeys(list_of(0)(1)(2)(3)(4)(5)(6), 4); - SymbolicFactorUnordered::shared_ptr actualFactor; - SymbolicConditionalUnordered::shared_ptr actualConditional; + SymbolicFactor::shared_ptr actualFactor; + SymbolicConditional::shared_ptr actualConditional; boost::tie(actualConditional, actualFactor) = - EliminateSymbolicUnordered(factors, list_of(0)(1)(2)(3)); + EliminateSymbolic(factors, list_of(0)(1)(2)(3)); CHECK(assert_equal(expectedConditional, *actualConditional)); CHECK(assert_equal(expectedFactor, *actualFactor)); diff --git a/gtsam/symbolic/tests/testSymbolicFactorGraph.cpp b/gtsam/symbolic/tests/testSymbolicFactorGraph.cpp index 01f09ca14..10c75529d 100644 --- a/gtsam/symbolic/tests/testSymbolicFactorGraph.cpp +++ b/gtsam/symbolic/tests/testSymbolicFactorGraph.cpp @@ -17,10 +17,10 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -29,122 +29,122 @@ using namespace gtsam; using namespace boost::assign; /* ************************************************************************* */ -TEST(SymbolicFactorGraph, eliminateFullSequential) +TEST(SymbolicFactorGraphOrdered, eliminateFullSequential) { // Test with simpleTestGraph1 - OrderingUnordered order; + Ordering order; order += 0,1,2,3,4; - SymbolicBayesNetUnordered actual1 = *simpleTestGraph1.eliminateSequential(order); + SymbolicBayesNet actual1 = *simpleTestGraph1.eliminateSequential(order); EXPECT(assert_equal(simpleTestGraph1BayesNet, actual1)); // Test with Asia graph - SymbolicBayesNetUnordered actual2 = *asiaGraph.eliminateSequential(asiaOrdering); + SymbolicBayesNet actual2 = *asiaGraph.eliminateSequential(asiaOrdering); EXPECT(assert_equal(asiaBayesNet, actual2)); } /* ************************************************************************* */ -TEST(SymbolicFactorGraph, eliminatePartialSequential) +TEST(SymbolicFactorGraphOrdered, eliminatePartialSequential) { // Eliminate 0 and 1 - const OrderingUnordered order = list_of(0)(1); + const Ordering order = list_of(0)(1); - const SymbolicBayesNetUnordered expectedBayesNet = list_of - (SymbolicConditionalUnordered(0,1,2)) - (SymbolicConditionalUnordered(1,2,3,4)); + const SymbolicBayesNet expectedBayesNet = list_of + (SymbolicConditional(0,1,2)) + (SymbolicConditional(1,2,3,4)); - const SymbolicFactorGraphUnordered expectedSfg = list_of - (SymbolicFactorUnordered(2,3)) - (SymbolicFactorUnordered(4,5)) - (SymbolicFactorUnordered(2,3,4)); + const SymbolicFactorGraph expectedSfg = list_of + (SymbolicFactor(2,3)) + (SymbolicFactor(4,5)) + (SymbolicFactor(2,3,4)); - SymbolicBayesNetUnordered::shared_ptr actualBayesNet; - SymbolicFactorGraphUnordered::shared_ptr actualSfg; + SymbolicBayesNet::shared_ptr actualBayesNet; + SymbolicFactorGraph::shared_ptr actualSfg; boost::tie(actualBayesNet, actualSfg) = - simpleTestGraph2.eliminatePartialSequential(OrderingUnordered(list_of(0)(1))); + simpleTestGraph2.eliminatePartialSequential(Ordering(list_of(0)(1))); EXPECT(assert_equal(expectedSfg, *actualSfg)); EXPECT(assert_equal(expectedBayesNet, *actualBayesNet)); } /* ************************************************************************* */ -TEST(SymbolicFactorGraph, eliminateFullMultifrontal) +TEST(SymbolicFactorGraphOrdered, eliminateFullMultifrontal) { - OrderingUnordered ordering; ordering += 0,1,2,3; - SymbolicBayesTreeUnordered actual1 = + Ordering ordering; ordering += 0,1,2,3; + SymbolicBayesTree actual1 = *simpleChain.eliminateMultifrontal(ordering); EXPECT(assert_equal(simpleChainBayesTree, actual1)); - SymbolicBayesTreeUnordered actual2 = + SymbolicBayesTree actual2 = *asiaGraph.eliminateMultifrontal(asiaOrdering); EXPECT(assert_equal(asiaBayesTree, actual2)); } /* ************************************************************************* */ -TEST(SymbolicFactorGraph, eliminatePartialMultifrontal) +TEST(SymbolicFactorGraphOrdered, eliminatePartialMultifrontal) { - SymbolicBayesTreeUnordered expectedBayesTree; - SymbolicConditionalUnordered::shared_ptr root = boost::make_shared( - SymbolicConditionalUnordered::FromKeys(list_of(5)(4)(1), 2)); - expectedBayesTree.insertRoot(boost::make_shared(root)); + SymbolicBayesTree expectedBayesTree; + SymbolicConditional::shared_ptr root = boost::make_shared( + SymbolicConditional::FromKeys(list_of(5)(4)(1), 2)); + expectedBayesTree.insertRoot(boost::make_shared(root)); - SymbolicFactorGraphUnordered expectedFactorGraph = list_of - (SymbolicFactorUnordered(0,1)) - (SymbolicFactorUnordered(0,2)) - (SymbolicFactorUnordered(1,3)) - (SymbolicFactorUnordered(2,3)) - (SymbolicFactorUnordered(1)); + SymbolicFactorGraph expectedFactorGraph = list_of + (SymbolicFactor(0,1)) + (SymbolicFactor(0,2)) + (SymbolicFactor(1,3)) + (SymbolicFactor(2,3)) + (SymbolicFactor(1)); - SymbolicBayesTreeUnordered::shared_ptr actualBayesTree; - SymbolicFactorGraphUnordered::shared_ptr actualFactorGraph; + SymbolicBayesTree::shared_ptr actualBayesTree; + SymbolicFactorGraph::shared_ptr actualFactorGraph; boost::tie(actualBayesTree, actualFactorGraph) = - simpleTestGraph2.eliminatePartialMultifrontal(OrderingUnordered(list_of(4)(5))); + simpleTestGraph2.eliminatePartialMultifrontal(Ordering(list_of(4)(5))); EXPECT(assert_equal(expectedFactorGraph, *actualFactorGraph)); EXPECT(assert_equal(expectedBayesTree, *actualBayesTree)); } /* ************************************************************************* */ -TEST(SymbolicFactorGraph, marginalMultifrontalBayesNet) +TEST(SymbolicFactorGraphOrdered, marginalMultifrontalBayesNet) { - SymbolicBayesNetUnordered expectedBayesNet = list_of - (SymbolicConditionalUnordered(0, 1, 2)) - (SymbolicConditionalUnordered(1, 2, 3)) - (SymbolicConditionalUnordered(2, 3)) - (SymbolicConditionalUnordered(3)); + SymbolicBayesNet expectedBayesNet = list_of + (SymbolicConditional(0, 1, 2)) + (SymbolicConditional(1, 2, 3)) + (SymbolicConditional(2, 3)) + (SymbolicConditional(3)); - SymbolicBayesNetUnordered actual1 = *simpleTestGraph2.marginalMultifrontalBayesNet( - OrderingUnordered(list_of(0)(1)(2)(3))); + SymbolicBayesNet actual1 = *simpleTestGraph2.marginalMultifrontalBayesNet( + Ordering(list_of(0)(1)(2)(3))); EXPECT(assert_equal(expectedBayesNet, actual1)); } /* ************************************************************************* */ -TEST(SymbolicFactorGraph, eliminate_disconnected_graph) { - SymbolicFactorGraphUnordered fg; +TEST(SymbolicFactorGraphOrdered, eliminate_disconnected_graph) { + SymbolicFactorGraph fg; fg.push_factor(0, 1); fg.push_factor(0, 2); fg.push_factor(1, 2); fg.push_factor(3, 4); // create expected Chordal bayes Net - SymbolicBayesNetUnordered expected; - expected.push_back(boost::make_shared(0,1,2)); - expected.push_back(boost::make_shared(1,2)); - expected.push_back(boost::make_shared(2)); - expected.push_back(boost::make_shared(3,4)); - expected.push_back(boost::make_shared(4)); + SymbolicBayesNet expected; + expected.push_back(boost::make_shared(0,1,2)); + expected.push_back(boost::make_shared(1,2)); + expected.push_back(boost::make_shared(2)); + expected.push_back(boost::make_shared(3,4)); + expected.push_back(boost::make_shared(4)); - OrderingUnordered order; + Ordering order; order += 0,1,2,3,4; - SymbolicBayesNetUnordered actual = *fg.eliminateSequential(order); + SymbolicBayesNet actual = *fg.eliminateSequential(order); EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ -//TEST(SymbolicFactorGraph, marginals) +//TEST(SymbolicFactorGraphOrdered, marginals) //{ // // Create factor graph -// SymbolicFactorGraph fg; +// SymbolicFactorGraphOrdered fg; // fg.push_factor(0, 1); // fg.push_factor(0, 2); // fg.push_factor(1, 4); @@ -176,12 +176,12 @@ TEST(SymbolicFactorGraph, eliminate_disconnected_graph) { // EXPECT( assert_equal(expectedBN,*actualBN)); // // // jointFactorGraph -// SymbolicFactorGraph::shared_ptr actualFG = solver.jointFactorGraph(js); -// SymbolicFactorGraph expectedFG; +// SymbolicFactorGraphOrdered::shared_ptr actualFG = solver.jointFactorGraph(js); +// SymbolicFactorGraphOrdered expectedFG; // expectedFG.push_factor(0, 4); // expectedFG.push_factor(4, 3); // expectedFG.push_factor(3); -// EXPECT( assert_equal(expectedFG,(SymbolicFactorGraph)(*actualFG))); +// EXPECT( assert_equal(expectedFG,(SymbolicFactorGraphOrdered)(*actualFG))); // } // // { @@ -198,12 +198,12 @@ TEST(SymbolicFactorGraph, eliminate_disconnected_graph) { // EXPECT( assert_equal(expectedBN,*actualBN)); // // // jointFactorGraph -// SymbolicFactorGraph::shared_ptr actualFG = solver.jointFactorGraph(js); -// SymbolicFactorGraph expectedFG; +// SymbolicFactorGraphOrdered::shared_ptr actualFG = solver.jointFactorGraph(js); +// SymbolicFactorGraphOrdered expectedFG; // expectedFG.push_factor(0, 3, 2); // expectedFG.push_factor(3, 2); // expectedFG.push_factor(2); -// EXPECT( assert_equal(expectedFG,(SymbolicFactorGraph)(*actualFG))); +// EXPECT( assert_equal(expectedFG,(SymbolicFactorGraphOrdered)(*actualFG))); // } // // { @@ -223,46 +223,46 @@ TEST(SymbolicFactorGraph, eliminate_disconnected_graph) { //} /* ************************************************************************* */ -TEST( SymbolicFactorGraph, constructFromBayesNet ) +TEST( SymbolicFactorGraphOrdered, constructFromBayesNet ) { // create expected factor graph - SymbolicFactorGraphUnordered expected; + SymbolicFactorGraph expected; expected.push_factor(0, 1, 2); expected.push_factor(1, 2); expected.push_factor(1); // create Bayes Net - SymbolicBayesNetUnordered bayesNet; - bayesNet += SymbolicConditionalUnordered(0, 1, 2); - bayesNet += SymbolicConditionalUnordered(1, 2); - bayesNet += SymbolicConditionalUnordered(1); + SymbolicBayesNet bayesNet; + bayesNet += SymbolicConditional(0, 1, 2); + bayesNet += SymbolicConditional(1, 2); + bayesNet += SymbolicConditional(1); // create actual factor graph from a Bayes Net - SymbolicFactorGraphUnordered actual(bayesNet); + SymbolicFactorGraph actual(bayesNet); CHECK(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST( SymbolicFactorGraph, constructFromBayesTree ) +TEST( SymbolicFactorGraphOrdered, constructFromBayesTree ) { // create expected factor graph - SymbolicFactorGraphUnordered expected; + SymbolicFactorGraph expected; expected.push_factor(_B_, _L_, _E_, _S_); expected.push_factor(_T_, _E_, _L_); expected.push_factor(_X_, _E_); // create actual factor graph - SymbolicFactorGraphUnordered actual(asiaBayesTree); + SymbolicFactorGraph actual(asiaBayesTree); CHECK(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST( SymbolicFactorGraph, push_back ) +TEST( SymbolicFactorGraphOrdered, push_back ) { // Create two factor graphs and expected combined graph - SymbolicFactorGraphUnordered fg1, fg2, expected; + SymbolicFactorGraph fg1, fg2, expected; fg1.push_factor(1); fg1.push_factor(0, 1); @@ -276,7 +276,7 @@ TEST( SymbolicFactorGraph, push_back ) expected.push_factor(0, 2); // combine - SymbolicFactorGraphUnordered actual; + SymbolicFactorGraph actual; actual.push_back(fg1); actual.push_back(fg2); CHECK(assert_equal(expected, actual)); diff --git a/gtsam/symbolic/tests/testSymbolicJunctionTree.cpp b/gtsam/symbolic/tests/testSymbolicJunctionTree.cpp index 4babbecdc..f9dd344a3 100644 --- a/gtsam/symbolic/tests/testSymbolicJunctionTree.cpp +++ b/gtsam/symbolic/tests/testSymbolicJunctionTree.cpp @@ -24,9 +24,9 @@ using namespace boost::assign; #include #include -#include -#include -#include +#include +#include +#include #include "symbolicExampleGraphs.h" @@ -38,11 +38,11 @@ using namespace std; * 2 3 * 0 1 : 2 ****************************************************************************/ -TEST( JunctionTree, constructor ) +TEST( JunctionTreeOrdered, constructor ) { - OrderingUnordered order; order += 0, 1, 2, 3; + Ordering order; order += 0, 1, 2, 3; - SymbolicJunctionTreeUnordered actual(SymbolicEliminationTreeUnordered(simpleChain, order)); + SymbolicJunctionTree actual(SymbolicEliminationTree(simpleChain, order)); vector frontal1; frontal1 += 3, 2; vector frontal2; frontal2 += 1, 0; diff --git a/gtsam/symbolic/tests/testVariableIndexUnordered.cpp b/gtsam/symbolic/tests/testVariableIndexUnordered.cpp index 6af012b56..5cb0f68b7 100644 --- a/gtsam/symbolic/tests/testVariableIndexUnordered.cpp +++ b/gtsam/symbolic/tests/testVariableIndexUnordered.cpp @@ -22,16 +22,16 @@ using namespace boost::assign; #include #include -#include -#include +#include +#include using namespace std; using namespace gtsam; /* ************************************************************************* */ -TEST(VariableIndexUnordered, augment) { +TEST(VariableIndex, augment) { - SymbolicFactorGraphUnordered fg1, fg2; + SymbolicFactorGraph fg1, fg2; fg1.push_factor(0, 1); fg1.push_factor(0, 2); fg1.push_factor(5, 9); @@ -41,10 +41,10 @@ TEST(VariableIndexUnordered, augment) { fg2.push_factor(3, 5); fg2.push_factor(5, 6); - SymbolicFactorGraphUnordered fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); + SymbolicFactorGraph fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); - VariableIndexUnordered expected(fgCombined); - VariableIndexUnordered actual(fg1); + VariableIndex expected(fgCombined); + VariableIndex actual(fg1); actual.augment(fg2); LONGS_EQUAL(16, (long)actual.nEntries()); @@ -53,9 +53,9 @@ TEST(VariableIndexUnordered, augment) { } /* ************************************************************************* */ -TEST(VariableIndexUnordered, remove) { +TEST(VariableIndex, remove) { - SymbolicFactorGraphUnordered fg1, fg2; + SymbolicFactorGraph fg1, fg2; fg1.push_factor(0, 1); fg1.push_factor(0, 2); fg1.push_factor(5, 9); @@ -65,17 +65,17 @@ TEST(VariableIndexUnordered, remove) { fg2.push_factor(3, 5); fg2.push_factor(5, 6); - SymbolicFactorGraphUnordered fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); + SymbolicFactorGraph fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2); // Create a factor graph containing only the factors from fg2 and with null // factors in the place of those of fg1, so that the factor indices are correct. - SymbolicFactorGraphUnordered fg2removed(fgCombined); + SymbolicFactorGraph fg2removed(fgCombined); fg2removed.remove(0); fg2removed.remove(1); fg2removed.remove(2); fg2removed.remove(3); - // The expected VariableIndexUnordered has the same factor indices as fgCombined but + // The expected VariableIndex has the same factor indices as fgCombined but // with entries from fg1 removed, and still has all 10 variables. - VariableIndexUnordered expected(fg2removed); - VariableIndexUnordered actual(fgCombined); + VariableIndex expected(fg2removed); + VariableIndex actual(fgCombined); vector indices; indices.push_back(0); indices.push_back(1); indices.push_back(2); indices.push_back(3); actual.remove(indices.begin(), indices.end(), fg1); @@ -86,9 +86,9 @@ TEST(VariableIndexUnordered, remove) { } /* ************************************************************************* */ -TEST(VariableIndexUnordered, deep_copy) { +TEST(VariableIndex, deep_copy) { - SymbolicFactorGraphUnordered fg1, fg2; + SymbolicFactorGraph fg1, fg2; fg1.push_factor(0, 1); fg1.push_factor(0, 2); fg1.push_factor(5, 9); @@ -98,19 +98,19 @@ TEST(VariableIndexUnordered, deep_copy) { fg2.push_factor(3, 5); fg2.push_factor(5, 6); - // Create original graph and VariableIndexUnordered - SymbolicFactorGraphUnordered fgOriginal; fgOriginal.push_back(fg1); fgOriginal.push_back(fg2); - VariableIndexUnordered original(fgOriginal); - VariableIndexUnordered expectedOriginal(fgOriginal); + // Create original graph and VariableIndex + SymbolicFactorGraph fgOriginal; fgOriginal.push_back(fg1); fgOriginal.push_back(fg2); + VariableIndex original(fgOriginal); + VariableIndex expectedOriginal(fgOriginal); // Create a factor graph containing only the factors from fg2 and with null // factors in the place of those of fg1, so that the factor indices are correct. - SymbolicFactorGraphUnordered fg2removed(fgOriginal); + SymbolicFactorGraph fg2removed(fgOriginal); fg2removed.remove(0); fg2removed.remove(1); fg2removed.remove(2); fg2removed.remove(3); - VariableIndexUnordered expectedRemoved(fg2removed); + VariableIndex expectedRemoved(fg2removed); // Create a clone and modify the clone - the original should not change - VariableIndexUnordered clone(original); + VariableIndex clone(original); vector indices; indices.push_back(0); indices.push_back(1); indices.push_back(2); indices.push_back(3); clone.remove(indices.begin(), indices.end(), fg1); diff --git a/gtsam_unstable/discrete/CSP.cpp b/gtsam_unstable/discrete/CSP.cpp index 7b27fb866..93fef162c 100644 --- a/gtsam_unstable/discrete/CSP.cpp +++ b/gtsam_unstable/discrete/CSP.cpp @@ -25,7 +25,7 @@ namespace gtsam { void CSP::runArcConsistency(size_t cardinality, size_t nrIterations, bool print) const { // Create VariableIndex - VariableIndex index(*this); + VariableIndexOrdered index(*this); // index.print(); size_t n = index.size(); @@ -46,7 +46,7 @@ namespace gtsam { // keep track of which domains changed changed[v] = false; // loop over all factors/constraints for variable v - const VariableIndex::Factors& factors = index[v]; + const VariableIndexOrdered::Factors& factors = index[v]; BOOST_FOREACH(size_t f,factors) { // if not already a singleton if (!domains[v].isSingleton()) { diff --git a/gtsam_unstable/discrete/tests/testCSP.cpp b/gtsam_unstable/discrete/tests/testCSP.cpp index dd155e817..29cea692c 100644 --- a/gtsam_unstable/discrete/tests/testCSP.cpp +++ b/gtsam_unstable/discrete/tests/testCSP.cpp @@ -128,7 +128,7 @@ TEST_UNSAFE( CSP, WesternUS) // Write out the dual graph for hmetis #ifdef DUAL - VariableIndex index(csp); + VariableIndexOrdered index(csp); index.print("index"); ofstream os("/Users/dellaert/src/hmetis-1.5-osx-i686/US-West-dual.txt"); index.outputMetisFormat(os); diff --git a/gtsam_unstable/discrete/tests/testSudoku.cpp b/gtsam_unstable/discrete/tests/testSudoku.cpp index d2ce16a12..415a73dc1 100644 --- a/gtsam_unstable/discrete/tests/testSudoku.cpp +++ b/gtsam_unstable/discrete/tests/testSudoku.cpp @@ -179,7 +179,7 @@ TEST_UNSAFE( Sudoku, extreme) sudoku.runArcConsistency(9,10,PRINT); #ifdef METIS - VariableIndex index(sudoku); + VariableIndexOrdered index(sudoku); index.print("index"); ofstream os("/Users/dellaert/src/hmetis-1.5-osx-i686/extreme-dual.txt"); index.outputMetisFormat(os); diff --git a/gtsam_unstable/linear/bayesTreeOperations.cpp b/gtsam_unstable/linear/bayesTreeOperations.cpp index c2e84dec3..42808c318 100644 --- a/gtsam_unstable/linear/bayesTreeOperations.cpp +++ b/gtsam_unstable/linear/bayesTreeOperations.cpp @@ -14,7 +14,7 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ -std::set keysToIndices(const KeySet& keys, const Ordering& ordering) { +std::set keysToIndices(const KeySet& keys, const OrderingOrdered& ordering) { std::set result; BOOST_FOREACH(const Key& key, keys) result.insert(ordering[key]); @@ -22,22 +22,22 @@ std::set keysToIndices(const KeySet& keys, const Ordering& ordering) { } /* ************************************************************************* */ -GaussianFactorGraph splitFactors(const GaussianFactorGraph& fullgraph) { - GaussianFactorGraph result; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, fullgraph) { - GaussianFactorGraph split = splitFactor(factor); +GaussianFactorGraphOrdered splitFactors(const GaussianFactorGraphOrdered& fullgraph) { + GaussianFactorGraphOrdered result; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, fullgraph) { + GaussianFactorGraphOrdered split = splitFactor(factor); result.push_back(split); } return result; } /* ************************************************************************* */ -GaussianFactorGraph splitFactor(const GaussianFactor::shared_ptr& factor) { - GaussianFactorGraph result; +GaussianFactorGraphOrdered splitFactor(const GaussianFactorOrdered::shared_ptr& factor) { + GaussianFactorGraphOrdered result; if (!factor) return result; // Needs to be a jacobian factor - just pass along hessians - JacobianFactor::shared_ptr jf = boost::dynamic_pointer_cast(factor); + JacobianFactorOrdered::shared_ptr jf = boost::dynamic_pointer_cast(factor); if (!jf) { result.push_back(factor); return result; @@ -45,7 +45,7 @@ GaussianFactorGraph splitFactor(const GaussianFactor::shared_ptr& factor) { // Loop over variables and strip off factors using split conditionals // Assumes upper triangular structure - JacobianFactor::const_iterator rowIt, colIt; + JacobianFactorOrdered::const_iterator rowIt, colIt; const size_t totalRows = jf->rows(); size_t rowsRemaining = totalRows; for (rowIt = jf->begin(); rowIt != jf->end() && rowsRemaining > 0; ++rowIt) { @@ -80,10 +80,10 @@ GaussianFactorGraph splitFactor(const GaussianFactor::shared_ptr& factor) { } /* ************************************************************************* */ -GaussianFactorGraph removePriors(const GaussianFactorGraph& fullgraph) { - GaussianFactorGraph result; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, fullgraph) { - JacobianFactor::shared_ptr jf = boost::dynamic_pointer_cast(factor); +GaussianFactorGraphOrdered removePriors(const GaussianFactorGraphOrdered& fullgraph) { + GaussianFactorGraphOrdered result; + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, fullgraph) { + JacobianFactorOrdered::shared_ptr jf = boost::dynamic_pointer_cast(factor); if (factor && (!jf || jf->size() > 1)) result.push_back(factor); } @@ -91,8 +91,8 @@ GaussianFactorGraph removePriors(const GaussianFactorGraph& fullgraph) { } /* ************************************************************************* */ -void findCliques(const GaussianBayesTree::sharedClique& current_clique, - std::set& result) { +void findCliques(const GaussianBayesTreeOrdered::sharedClique& current_clique, + std::set& result) { // Add the current clique result.insert(current_clique->conditional()); @@ -102,12 +102,12 @@ void findCliques(const GaussianBayesTree::sharedClique& current_clique, } /* ************************************************************************* */ -std::set findAffectedCliqueConditionals( - const GaussianBayesTree& bayesTree, const std::set& savedIndices) { - std::set affected_cliques; +std::set findAffectedCliqueConditionals( + const GaussianBayesTreeOrdered& bayesTree, const std::set& savedIndices) { + std::set affected_cliques; // FIXME: track previously found keys more efficiently BOOST_FOREACH(const Index& index, savedIndices) { - GaussianBayesTree::sharedClique clique = bayesTree.nodes()[index]; + GaussianBayesTreeOrdered::sharedClique clique = bayesTree.nodes()[index]; // add path back to root to affected set findCliques(clique, affected_cliques); @@ -116,9 +116,9 @@ std::set findAffectedCliqueConditionals( } /* ************************************************************************* */ -std::deque -findPathCliques(const GaussianBayesTree::sharedClique& initial) { - std::deque result, parents; +std::deque +findPathCliques(const GaussianBayesTreeOrdered::sharedClique& initial) { + std::deque result, parents; if (initial->isRoot()) return result; result.push_back(initial->parent()); diff --git a/gtsam_unstable/linear/bayesTreeOperations.h b/gtsam_unstable/linear/bayesTreeOperations.h index 3f85dc12c..d28404731 100644 --- a/gtsam_unstable/linear/bayesTreeOperations.h +++ b/gtsam_unstable/linear/bayesTreeOperations.h @@ -10,16 +10,16 @@ #pragma once #include -#include -#include -#include +#include +#include +#include namespace gtsam { // Managing orderings /** Converts sets of keys to indices by way of orderings */ -GTSAM_UNSTABLE_EXPORT std::set keysToIndices(const KeySet& keys, const Ordering& ordering); +GTSAM_UNSTABLE_EXPORT std::set keysToIndices(const KeySet& keys, const OrderingOrdered& ordering); // Linear Graph Operations @@ -27,16 +27,16 @@ GTSAM_UNSTABLE_EXPORT std::set keysToIndices(const KeySet& keys, const Or * Given a graph, splits each factor into factors where the dimension is * that of the first variable. */ -GTSAM_UNSTABLE_EXPORT GaussianFactorGraph splitFactors(const GaussianFactorGraph& fullgraph); +GTSAM_UNSTABLE_EXPORT GaussianFactorGraphOrdered splitFactors(const GaussianFactorGraphOrdered& fullgraph); /** * Splits a factor into factors where the dimension is * that of the first variable. */ -GTSAM_UNSTABLE_EXPORT GaussianFactorGraph splitFactor(const GaussianFactor::shared_ptr& factor); +GTSAM_UNSTABLE_EXPORT GaussianFactorGraphOrdered splitFactor(const GaussianFactorOrdered::shared_ptr& factor); /** Removes prior jacobian factors from the graph */ -GTSAM_UNSTABLE_EXPORT GaussianFactorGraph removePriors(const GaussianFactorGraph& fullgraph); +GTSAM_UNSTABLE_EXPORT GaussianFactorGraphOrdered removePriors(const GaussianFactorGraphOrdered& fullgraph); // Bayes Tree / Conditional operations @@ -46,8 +46,8 @@ GTSAM_UNSTABLE_EXPORT GaussianFactorGraph removePriors(const GaussianFactorGraph * * @return the set of conditionals extracted from cliques. */ -GTSAM_UNSTABLE_EXPORT std::set findAffectedCliqueConditionals( - const GaussianBayesTree& bayesTree, const std::set& savedIndices); +GTSAM_UNSTABLE_EXPORT std::set findAffectedCliqueConditionals( + const GaussianBayesTreeOrdered& bayesTree, const std::set& savedIndices); /** * Recursively traverses from a given clique in a Bayes Tree and collects all of the conditionals @@ -56,15 +56,15 @@ GTSAM_UNSTABLE_EXPORT std::set findAffectedCliq * Note the use of a set of shared_ptr: this will sort/filter on unique *pointer* locations, * which ensures unique cliques, but the order of the cliques is meaningless */ -GTSAM_UNSTABLE_EXPORT void findCliqueConditionals(const GaussianBayesTree::sharedClique& current_clique, - std::set& result); +GTSAM_UNSTABLE_EXPORT void findCliqueConditionals(const GaussianBayesTreeOrdered::sharedClique& current_clique, + std::set& result); /** * Given a clique, returns a sequence of clique parents to the root, not including the * given clique. */ -GTSAM_UNSTABLE_EXPORT std::deque -findPathCliques(const GaussianBayesTree::sharedClique& initial); +GTSAM_UNSTABLE_EXPORT std::deque +findPathCliques(const GaussianBayesTreeOrdered::sharedClique& initial); /** * Liquefies a BayesTree into a GaussianFactorGraph recursively, given a @@ -73,10 +73,10 @@ findPathCliques(const GaussianBayesTree::sharedClique& initial); * @param splitConditionals flag enables spliting multi-frontal conditionals into separate factors */ template -GaussianFactorGraph liquefy(const typename BAYESTREE::sharedClique& root, bool splitConditionals = false) { - GaussianFactorGraph result; +GaussianFactorGraphOrdered liquefy(const typename BAYESTREE::sharedClique& root, bool splitConditionals = false) { + GaussianFactorGraphOrdered result; if (root && root->conditional()) { - GaussianConditional::shared_ptr conditional = root->conditional(); + GaussianConditionalOrdered::shared_ptr conditional = root->conditional(); if (!splitConditionals) result.push_back(conditional->toFactor()); else @@ -93,7 +93,7 @@ GaussianFactorGraph liquefy(const typename BAYESTREE::sharedClique& root, bool s * @param splitConditionals flag enables spliting multi-frontal conditionals into separate factors */ template -GaussianFactorGraph liquefy(const BAYESTREE& bayesTree, bool splitConditionals = false) { +GaussianFactorGraphOrdered liquefy(const BAYESTREE& bayesTree, bool splitConditionals = false) { return liquefy(bayesTree.root(), splitConditionals); } diff --git a/gtsam_unstable/linear/conditioning.cpp b/gtsam_unstable/linear/conditioning.cpp index c02f4d48c..b346729c2 100644 --- a/gtsam_unstable/linear/conditioning.cpp +++ b/gtsam_unstable/linear/conditioning.cpp @@ -13,8 +13,8 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ -GaussianConditional::shared_ptr conditionDensity(const GaussianConditional::shared_ptr& initConditional, - const std::set& saved_indices, const VectorValues& solution) { +GaussianConditionalOrdered::shared_ptr conditionDensity(const GaussianConditionalOrdered::shared_ptr& initConditional, + const std::set& saved_indices, const VectorValuesOrdered& solution) { const bool verbose = false; if (!initConditional) @@ -41,7 +41,7 @@ GaussianConditional::shared_ptr conditionDensity(const GaussianConditional::shar // If none of the frontal variables are to be saved, return empty pointer if (frontalsToRemove.size() == initConditional->nrFrontals()) - return GaussianConditional::shared_ptr(); + return GaussianConditionalOrdered::shared_ptr(); // Collect dimensions of the new conditional if (verbose) cout << " Collecting dimensions" << endl; @@ -54,7 +54,7 @@ GaussianConditional::shared_ptr conditionDensity(const GaussianConditional::shar vector newIdxToOldIdx; // Access to arrays, maps from new var to old var const vector& oldIndices = initConditional->keys(); const size_t oldNrFrontals = initConditional->nrFrontals(); - GaussianConditional::const_iterator varIt = initConditional->beginFrontals(); + GaussianConditionalOrdered::const_iterator varIt = initConditional->beginFrontals(); size_t oldIdx = 0; for (; varIt != initConditional->endFrontals(); ++varIt) { size_t varDim = initConditional->dim(varIt); @@ -99,7 +99,7 @@ GaussianConditional::shared_ptr conditionDensity(const GaussianConditional::shar size_t oldColOffset = oldColOffsets.at(newfrontalIdx); // get R block, sliced by row - Eigen::Block rblock = + Eigen::Block rblock = initConditional->get_R().block(oldColOffset, oldColOffset, dim, oldRNrCols-oldColOffset); if (verbose) cout << " rblock\n" << rblock << endl; @@ -142,7 +142,7 @@ GaussianConditional::shared_ptr conditionDensity(const GaussianConditional::shar } // add parents (looping over original block structure), while updating rhs - GaussianConditional::const_iterator oldParent = initConditional->beginParents(); + GaussianConditionalOrdered::const_iterator oldParent = initConditional->beginParents(); for (; oldParent != initConditional->endParents(); ++oldParent) { Index parentKey = *oldParent; size_t parentDim = initConditional->dim(oldParent); @@ -169,26 +169,26 @@ GaussianConditional::shared_ptr conditionDensity(const GaussianConditional::shar // Construct a new conditional if (verbose) cout << "backsubSummarize() Complete!" << endl; - GaussianConditional::rsd_type matrices(full_matrix, newDims.begin(), newDims.end()); - return GaussianConditional::shared_ptr(new - GaussianConditional(newIndices.begin(), newIndices.end(), newNrFrontals, matrices, sigmas)); + GaussianConditionalOrdered::rsd_type matrices(full_matrix, newDims.begin(), newDims.end()); + return GaussianConditionalOrdered::shared_ptr(new + GaussianConditionalOrdered(newIndices.begin(), newIndices.end(), newNrFrontals, matrices, sigmas)); } /* ************************************************************************* */ -GaussianFactorGraph conditionDensity(const GaussianBayesTree& bayesTree, +GaussianFactorGraphOrdered conditionDensity(const GaussianBayesTreeOrdered& bayesTree, const std::set& saved_indices) { const bool verbose = false; - VectorValues solution = optimize(bayesTree); + VectorValuesOrdered solution = optimize(bayesTree); // FIXME: set of conditionals does not manage possibility of solving out whole separators - std::set affected_cliques = findAffectedCliqueConditionals(bayesTree, saved_indices); + std::set affected_cliques = findAffectedCliqueConditionals(bayesTree, saved_indices); // Summarize conditionals separately - GaussianFactorGraph summarized_graph; - BOOST_FOREACH(const GaussianConditional::shared_ptr& conditional, affected_cliques) { + GaussianFactorGraphOrdered summarized_graph; + BOOST_FOREACH(const GaussianConditionalOrdered::shared_ptr& conditional, affected_cliques) { if (verbose) conditional->print("Initial conditional"); - GaussianConditional::shared_ptr reducedConditional = conditionDensity(conditional, saved_indices, solution); + GaussianConditionalOrdered::shared_ptr reducedConditional = conditionDensity(conditional, saved_indices, solution); if (reducedConditional) { if (verbose) reducedConditional->print("Final conditional"); summarized_graph.push_back(reducedConditional->toFactor()); diff --git a/gtsam_unstable/linear/conditioning.h b/gtsam_unstable/linear/conditioning.h index fbd5d6918..259eadf16 100644 --- a/gtsam_unstable/linear/conditioning.h +++ b/gtsam_unstable/linear/conditioning.h @@ -10,9 +10,9 @@ #pragma once #include -#include -#include -#include +#include +#include +#include namespace gtsam { @@ -27,15 +27,15 @@ namespace gtsam { * @param saved_indices is the set of indices that should appear in the result * @param solution is a full solution for the system */ -GTSAM_UNSTABLE_EXPORT gtsam::GaussianConditional::shared_ptr conditionDensity(const gtsam::GaussianConditional::shared_ptr& initConditional, - const std::set& saved_indices, const gtsam::VectorValues& solution); +GTSAM_UNSTABLE_EXPORT gtsam::GaussianConditionalOrdered::shared_ptr conditionDensity(const gtsam::GaussianConditionalOrdered::shared_ptr& initConditional, + const std::set& saved_indices, const gtsam::VectorValuesOrdered& solution); /** * Backsubstitution-based conditioning for a complete Bayes Tree - reduces * conditionals by solving out variables to eliminate. Traverses the tree to * add the correct dummy factors whenever a separator is eliminated. */ -GTSAM_UNSTABLE_EXPORT gtsam::GaussianFactorGraph conditionDensity(const gtsam::GaussianBayesTree& bayesTree, +GTSAM_UNSTABLE_EXPORT gtsam::GaussianFactorGraphOrdered conditionDensity(const gtsam::GaussianBayesTreeOrdered& bayesTree, const std::set& saved_indices); diff --git a/gtsam_unstable/linear/tests/testBayesTreeOperations.cpp b/gtsam_unstable/linear/tests/testBayesTreeOperations.cpp index efc5bba55..ac13d2374 100644 --- a/gtsam_unstable/linear/tests/testBayesTreeOperations.cpp +++ b/gtsam_unstable/linear/tests/testBayesTreeOperations.cpp @@ -31,7 +31,7 @@ static const double tol = 1e-4; TEST( testBayesTreeOperations, splitFactor1 ) { // Build upper-triangular system - JacobianFactor initFactor( + JacobianFactorOrdered initFactor( 0,Matrix_(4, 2, 1.0, 2.0, 0.0, 3.0, @@ -45,8 +45,8 @@ TEST( testBayesTreeOperations, splitFactor1 ) { Vector_(4, 0.1, 0.2, 0.3, 0.4), model4); - GaussianFactorGraph actSplit = splitFactor(initFactor.clone()); - GaussianFactorGraph expSplit; + GaussianFactorGraphOrdered actSplit = splitFactor(initFactor.clone()); + GaussianFactorGraphOrdered expSplit; expSplit.add( 0,Matrix_(2, 2, @@ -71,7 +71,7 @@ TEST( testBayesTreeOperations, splitFactor1 ) { TEST( testBayesTreeOperations, splitFactor2 ) { // Build upper-triangular system - JacobianFactor initFactor( + JacobianFactorOrdered initFactor( 0,Matrix_(6, 2, 1.0, 2.0, 0.0, 3.0, @@ -96,8 +96,8 @@ TEST( testBayesTreeOperations, splitFactor2 ) { Vector_(6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6), model6); - GaussianFactorGraph actSplit = splitFactor(initFactor.clone()); - GaussianFactorGraph expSplit; + GaussianFactorGraphOrdered actSplit = splitFactor(initFactor.clone()); + GaussianFactorGraphOrdered expSplit; expSplit.add( 0,Matrix_(2, 2, @@ -134,7 +134,7 @@ TEST( testBayesTreeOperations, splitFactor2 ) { TEST( testBayesTreeOperations, splitFactor3 ) { // Build upper-triangular system - JacobianFactor initFactor( + JacobianFactorOrdered initFactor( 0,Matrix_(4, 2, 1.0, 2.0, 0.0, 3.0, @@ -153,8 +153,8 @@ TEST( testBayesTreeOperations, splitFactor3 ) { Vector_(4, 0.1, 0.2, 0.3, 0.4), model4); - GaussianFactorGraph actSplit = splitFactor(initFactor.clone()); - GaussianFactorGraph expSplit; + GaussianFactorGraphOrdered actSplit = splitFactor(initFactor.clone()); + GaussianFactorGraphOrdered expSplit; expSplit.add( 0,Matrix_(2, 2, @@ -192,12 +192,12 @@ TEST( testBayesTreeOperations, liquefy ) { using namespace example; // Create smoother with 7 nodes - Ordering ordering; + OrderingOrdered ordering; ordering += X(1),X(3),X(5),X(7),X(2),X(6),X(4); - GaussianFactorGraph smoother = createSmoother(7, ordering).first; + GaussianFactorGraphOrdered smoother = createSmoother(7, ordering).first; // Create the Bayes tree - GaussianBayesTree bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); + GaussianBayesTreeOrdered bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); // bayesTree.print("Full tree"); SharedDiagonal unit6 = noiseModel::Diagonal::Sigmas(Vector_(ones(6))); @@ -206,8 +206,8 @@ TEST( testBayesTreeOperations, liquefy ) { // Liquefy the tree back into a graph { - GaussianFactorGraph actGraph = liquefy(bayesTree, false); // Doesn't split conditionals - GaussianFactorGraph expGraph; + GaussianFactorGraphOrdered actGraph = liquefy(bayesTree, false); // Doesn't split conditionals + GaussianFactorGraphOrdered expGraph; Matrix A12 = Matrix_(6, 2, 1.73205081, 0.0, @@ -278,8 +278,8 @@ TEST( testBayesTreeOperations, liquefy ) { // Liquefy the tree back into a graph, splitting factors { - GaussianFactorGraph actGraph = liquefy(bayesTree, true); - GaussianFactorGraph expGraph; + GaussianFactorGraphOrdered actGraph = liquefy(bayesTree, true); + GaussianFactorGraphOrdered expGraph; // Conditional 1 { diff --git a/gtsam_unstable/linear/tests/testConditioning.cpp b/gtsam_unstable/linear/tests/testConditioning.cpp index 69646fbdc..d01e4ff4d 100644 --- a/gtsam_unstable/linear/tests/testConditioning.cpp +++ b/gtsam_unstable/linear/tests/testConditioning.cpp @@ -65,10 +65,10 @@ TEST( testConditioning, directed_elimination_singlefrontal ) { Index root_key = 0, removed_key = 1, remaining_parent = 2; Matrix R11 = Matrix_(1,1, 1.0), R22 = Matrix_(1,1, 3.0), S = Matrix_(1,1,-2.0), T = Matrix_(1,1,-3.0); Vector d0 = d.segment(0,1), d1 = d.segment(1,1), sigmas = Vector_(1, 1.0); - GaussianConditional::shared_ptr initConditional(new - GaussianConditional(root_key, d0, R11, removed_key, S, remaining_parent, T, sigmas)); + GaussianConditionalOrdered::shared_ptr initConditional(new + GaussianConditionalOrdered(root_key, d0, R11, removed_key, S, remaining_parent, T, sigmas)); - VectorValues solution; + VectorValuesOrdered solution; solution.insert(0, x.segment(0,1)); solution.insert(1, x.segment(1,1)); solution.insert(2, x.segment(2,1)); @@ -76,22 +76,22 @@ TEST( testConditioning, directed_elimination_singlefrontal ) { std::set saved_indices; saved_indices += root_key, remaining_parent; - GaussianConditional::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); - GaussianConditional::shared_ptr expSummarized(new - GaussianConditional(root_key, d0 - S*x(1), R11, remaining_parent, T, sigmas)); + GaussianConditionalOrdered::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); + GaussianConditionalOrdered::shared_ptr expSummarized(new + GaussianConditionalOrdered(root_key, d0 - S*x(1), R11, remaining_parent, T, sigmas)); CHECK(actSummarized); EXPECT(assert_equal(*expSummarized, *actSummarized, tol)); // Simple test of base case: if target index isn't present, return clone - GaussianConditional::shared_ptr actSummarizedSimple = conditionDensity(expSummarized, saved_indices, solution); + GaussianConditionalOrdered::shared_ptr actSummarizedSimple = conditionDensity(expSummarized, saved_indices, solution); CHECK(actSummarizedSimple); EXPECT(assert_equal(*expSummarized, *actSummarizedSimple, tol)); // case where frontal variable is to be eliminated - return null - GaussianConditional::shared_ptr removeFrontalInit(new - GaussianConditional(removed_key, d1, R22, remaining_parent, T, sigmas)); - GaussianConditional::shared_ptr actRemoveFrontal = conditionDensity(removeFrontalInit, saved_indices, solution); + GaussianConditionalOrdered::shared_ptr removeFrontalInit(new + GaussianConditionalOrdered(removed_key, d1, R22, remaining_parent, T, sigmas)); + GaussianConditionalOrdered::shared_ptr actRemoveFrontal = conditionDensity(removeFrontalInit, saved_indices, solution); EXPECT(!actRemoveFrontal); } @@ -108,9 +108,9 @@ TEST( testConditioning, directed_elimination_multifrontal ) { terms += make_pair(root_key, Matrix(R11.col(0))); terms += make_pair(removed_key, Matrix(R11.col(1))); terms += make_pair(remaining_parent, S); - GaussianConditional::shared_ptr initConditional(new GaussianConditional(terms, 2, d1, sigmas2)); + GaussianConditionalOrdered::shared_ptr initConditional(new GaussianConditionalOrdered(terms, 2, d1, sigmas2)); - VectorValues solution; + VectorValuesOrdered solution; solution.insert(0, x.segment(0,1)); solution.insert(1, x.segment(1,1)); solution.insert(2, x.segment(2,1)); @@ -118,9 +118,9 @@ TEST( testConditioning, directed_elimination_multifrontal ) { std::set saved_indices; saved_indices += root_key, remaining_parent; - GaussianConditional::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); - GaussianConditional::shared_ptr expSummarized(new - GaussianConditional(root_key, d.segment(0,1) - Sprime*x(1), R11prime, remaining_parent, R.block(0,2,1,1), sigmas1)); + GaussianConditionalOrdered::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); + GaussianConditionalOrdered::shared_ptr expSummarized(new + GaussianConditionalOrdered(root_key, d.segment(0,1) - Sprime*x(1), R11prime, remaining_parent, R.block(0,2,1,1), sigmas1)); CHECK(actSummarized); EXPECT(assert_equal(*expSummarized, *actSummarized, tol)); @@ -140,14 +140,14 @@ TEST( testConditioning, directed_elimination_multifrontal_multidim ) { 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 0.0, 8.0, 0.0, 6.0, 0.6); vector init_dims; init_dims += 2, 2, 2, 2, 2, 1; - GaussianConditional::rsd_type init_matrices(Rinit, init_dims.begin(), init_dims.end()); + GaussianConditionalOrdered::rsd_type init_matrices(Rinit, init_dims.begin(), init_dims.end()); Vector sigmas = ones(6); vector init_keys; init_keys += 0, 1, 2, 3, 4; - GaussianConditional::shared_ptr initConditional(new - GaussianConditional(init_keys.begin(), init_keys.end(), 3, init_matrices, sigmas)); + GaussianConditionalOrdered::shared_ptr initConditional(new + GaussianConditionalOrdered(init_keys.begin(), init_keys.end(), 3, init_matrices, sigmas)); // Construct a solution vector - VectorValues solution; + VectorValuesOrdered solution; solution.insert(0, zero(2)); solution.insert(1, zero(2)); solution.insert(2, zero(2)); @@ -159,7 +159,7 @@ TEST( testConditioning, directed_elimination_multifrontal_multidim ) { std::set saved_indices; saved_indices += 0, 2, 4; - GaussianConditional::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); + GaussianConditionalOrdered::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); CHECK(actSummarized); Matrix Rexp = Matrix_(4, 7, @@ -173,10 +173,10 @@ TEST( testConditioning, directed_elimination_multifrontal_multidim ) { Rexp.block(2, 6, 2, 1) -= Rinit.block(4, 6, 2, 2) * solution.at(3); vector exp_dims; exp_dims += 2, 2, 2, 1; - GaussianConditional::rsd_type exp_matrices(Rexp, exp_dims.begin(), exp_dims.end()); + GaussianConditionalOrdered::rsd_type exp_matrices(Rexp, exp_dims.begin(), exp_dims.end()); Vector exp_sigmas = ones(4); vector exp_keys; exp_keys += 0, 2, 4; - GaussianConditional expSummarized(exp_keys.begin(), exp_keys.end(), 2, exp_matrices, exp_sigmas); + GaussianConditionalOrdered expSummarized(exp_keys.begin(), exp_keys.end(), 2, exp_matrices, exp_sigmas); EXPECT(assert_equal(expSummarized, *actSummarized, tol)); } @@ -205,13 +205,13 @@ TEST( testConditioning, directed_elimination_multifrontal_multidim2 ) { Rinit.rightCols(1) = dinit; Vector sigmas = ones(10); - GaussianConditional::rsd_type init_matrices(Rinit, init_dims.begin(), init_dims.end()); + GaussianConditionalOrdered::rsd_type init_matrices(Rinit, init_dims.begin(), init_dims.end()); vector init_keys; init_keys += 3, 4, 5, 6; - GaussianConditional::shared_ptr initConditional(new - GaussianConditional(init_keys.begin(), init_keys.end(), 4, init_matrices, sigmas)); + GaussianConditionalOrdered::shared_ptr initConditional(new + GaussianConditionalOrdered(init_keys.begin(), init_keys.end(), 4, init_matrices, sigmas)); // Calculate a solution - VectorValues solution; + VectorValuesOrdered solution; solution.insert(0, zero(3)); solution.insert(1, zero(3)); solution.insert(2, zero(3)); @@ -226,7 +226,7 @@ TEST( testConditioning, directed_elimination_multifrontal_multidim2 ) { std::set saved_indices; saved_indices += 5, 6; - GaussianConditional::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); + GaussianConditionalOrdered::shared_ptr actSummarized = conditionDensity(initConditional, saved_indices, solution); CHECK(actSummarized); // Create expected value on [5], [6] @@ -238,9 +238,9 @@ TEST( testConditioning, directed_elimination_multifrontal_multidim2 ) { Vector expsigmas = ones(4); vector exp_dims; exp_dims += 2, 2, 1; - GaussianConditional::rsd_type exp_matrices(Rexp, exp_dims.begin(), exp_dims.end()); + GaussianConditionalOrdered::rsd_type exp_matrices(Rexp, exp_dims.begin(), exp_dims.end()); vector exp_keys; exp_keys += 5, 6; - GaussianConditional expConditional(exp_keys.begin(), exp_keys.end(), 2, exp_matrices, expsigmas); + GaussianConditionalOrdered expConditional(exp_keys.begin(), exp_keys.end(), 2, exp_matrices, expsigmas); EXPECT(assert_equal(expConditional, *actSummarized, tol)); } diff --git a/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp b/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp index 0a84d307a..ec54dbc20 100644 --- a/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp +++ b/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp @@ -19,10 +19,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include namespace gtsam { @@ -189,7 +189,7 @@ void BatchFixedLagSmoother::eraseKeys(const std::set& keys) { void BatchFixedLagSmoother::reorder(const std::set& marginalizeKeys) { // Calculate a variable index - VariableIndex variableIndex(*factors_.symbolic(ordering_), ordering_.size()); + VariableIndexOrdered variableIndex(*factors_.symbolic(ordering_), ordering_.size()); // COLAMD groups will be used to place marginalize keys in Group 0, and everything else in Group 1 int group0 = 0; @@ -236,7 +236,7 @@ FixedLagSmoother::Result BatchFixedLagSmoother::optimize() { // Use a custom optimization loop so the linearization points can be controlled double previousError; - VectorValues newDelta; + VectorValuesOrdered newDelta; do { previousError = result.error; @@ -244,13 +244,13 @@ FixedLagSmoother::Result BatchFixedLagSmoother::optimize() { gttic(optimizer_iteration); { // Linearize graph around the linearization point - GaussianFactorGraph linearFactorGraph = *factors_.linearize(theta_, ordering_); + GaussianFactorGraphOrdered linearFactorGraph = *factors_.linearize(theta_, ordering_); // Keep increasing lambda until we make make progress while(true) { // Add prior factors at the current solution gttic(damp); - GaussianFactorGraph dampedFactorGraph(linearFactorGraph); + GaussianFactorGraphOrdered dampedFactorGraph(linearFactorGraph); dampedFactorGraph.reserve(linearFactorGraph.size() + delta_.size()); { // for each of the variables, add a prior at the current solution @@ -260,7 +260,7 @@ FixedLagSmoother::Result BatchFixedLagSmoother::optimize() { Matrix A = eye(dim); Vector b = delta_[j]; SharedDiagonal model = noiseModel::Isotropic::Sigma(dim, sigma); - GaussianFactor::shared_ptr prior(new JacobianFactor(j, A, b, model)); + GaussianFactorOrdered::shared_ptr prior(new JacobianFactorOrdered(j, A, b, model)); dampedFactorGraph.push_back(prior); } } @@ -269,7 +269,7 @@ FixedLagSmoother::Result BatchFixedLagSmoother::optimize() { gttic(solve); // Solve Damped Gaussian Factor Graph - newDelta = GaussianJunctionTree(dampedFactorGraph).optimize(parameters_.getEliminationFunction()); + newDelta = GaussianJunctionTreeOrdered(dampedFactorGraph).optimize(parameters_.getEliminationFunction()); // update the evalpoint with the new delta evalpoint = theta_.retract(newDelta, ordering_); gttoc(solve); @@ -334,10 +334,10 @@ void BatchFixedLagSmoother::marginalize(const std::set& marginalizeKeys) { // Calculate marginal factors on the remaining variables (after marginalizing 'marginalizeKeys') // Note: It is assumed the ordering already has these keys first // Create the linear factor graph - GaussianFactorGraph linearFactorGraph = *factors_.linearize(theta_, ordering_); + GaussianFactorGraphOrdered linearFactorGraph = *factors_.linearize(theta_, ordering_); // Create a variable index - VariableIndex variableIndex(linearFactorGraph, ordering_.size()); + VariableIndexOrdered variableIndex(linearFactorGraph, ordering_.size()); // Use the variable Index to mark the factors that will be marginalized std::set removedFactorSlots; @@ -364,7 +364,7 @@ void BatchFixedLagSmoother::marginalize(const std::set& marginalizeKeys) { // Add the marginal factor variables to the separator NonlinearFactorGraph marginalFactors; BOOST_FOREACH(Index index, indicesToEliminate) { - GaussianFactor::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(parameters_.getEliminationFunction()); + GaussianFactorOrdered::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(parameters_.getEliminationFunction()); if(gaussianFactor->size() > 0) { LinearContainerFactor::shared_ptr marginalFactor(new LinearContainerFactor(gaussianFactor, ordering_, theta_)); marginalFactors.push_back(marginalFactor); @@ -409,7 +409,7 @@ void BatchFixedLagSmoother::PrintSymbolicFactor(const NonlinearFactor::shared_pt } /* ************************************************************************* */ -void BatchFixedLagSmoother::PrintSymbolicFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering) { +void BatchFixedLagSmoother::PrintSymbolicFactor(const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering) { std::cout << "f("; BOOST_FOREACH(Index index, factor->keys()) { std::cout << " " << index << "[" << gtsam::DefaultKeyFormatter(ordering.key(index)) << "]"; @@ -426,15 +426,15 @@ void BatchFixedLagSmoother::PrintSymbolicGraph(const NonlinearFactorGraph& graph } /* ************************************************************************* */ -void BatchFixedLagSmoother::PrintSymbolicGraph(const GaussianFactorGraph& graph, const Ordering& ordering, const std::string& label) { +void BatchFixedLagSmoother::PrintSymbolicGraph(const GaussianFactorGraphOrdered& graph, const OrderingOrdered& ordering, const std::string& label) { std::cout << label << std::endl; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, graph) { + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, graph) { PrintSymbolicFactor(factor, ordering); } } /* ************************************************************************* */ -std::vector BatchFixedLagSmoother::EliminationForest::ComputeParents(const VariableIndex& structure) { +std::vector BatchFixedLagSmoother::EliminationForest::ComputeParents(const VariableIndexOrdered& structure) { // Number of factors and variables const size_t m = structure.nFactors(); const size_t n = structure.size(); @@ -465,7 +465,7 @@ std::vector BatchFixedLagSmoother::EliminationForest::ComputeParents(cons } /* ************************************************************************* */ -std::vector BatchFixedLagSmoother::EliminationForest::Create(const GaussianFactorGraph& factorGraph, const VariableIndex& structure) { +std::vector BatchFixedLagSmoother::EliminationForest::Create(const GaussianFactorGraphOrdered& factorGraph, const VariableIndexOrdered& structure) { // Compute the tree structure std::vector parents(ComputeParents(structure)); @@ -484,7 +484,7 @@ std::vector BatchFixedLagS } // Hang factors in right places - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factorGraph) { + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factorGraph) { if(factor && factor->size() > 0) { Index j = *std::min_element(factor->begin(), factor->end()); if(j < structure.size()) @@ -496,10 +496,10 @@ std::vector BatchFixedLagS } /* ************************************************************************* */ -GaussianFactor::shared_ptr BatchFixedLagSmoother::EliminationForest::eliminateRecursive(GaussianFactorGraph::Eliminate function) { +GaussianFactorOrdered::shared_ptr BatchFixedLagSmoother::EliminationForest::eliminateRecursive(GaussianFactorGraphOrdered::Eliminate function) { // Create the list of factors to be eliminated, initially empty, and reserve space - GaussianFactorGraph factors; + GaussianFactorGraphOrdered factors; factors.reserve(this->factors_.size() + this->subTrees_.size()); // Add all factors associated with the current node @@ -510,7 +510,7 @@ GaussianFactor::shared_ptr BatchFixedLagSmoother::EliminationForest::eliminateRe factors.push_back(child->eliminateRecursive(function)); // Combine all factors (from this node and from subtrees) into a joint factor - GaussianFactorGraph::EliminationResult eliminated(function(factors, 1)); + GaussianFactorGraphOrdered::EliminationResult eliminated(function(factors, 1)); return eliminated.second; } diff --git a/gtsam_unstable/nonlinear/BatchFixedLagSmoother.h b/gtsam_unstable/nonlinear/BatchFixedLagSmoother.h index dd22939bf..4c832f85b 100644 --- a/gtsam_unstable/nonlinear/BatchFixedLagSmoother.h +++ b/gtsam_unstable/nonlinear/BatchFixedLagSmoother.h @@ -92,12 +92,12 @@ public: } /** Access the current ordering */ - const Ordering& getOrdering() const { + const OrderingOrdered& getOrdering() const { return ordering_; } /** Access the current set of deltas to the linearization point */ - const VectorValues& getDelta() const { + const VectorValuesOrdered& getDelta() const { return delta_; } @@ -124,10 +124,10 @@ protected: Values linearKeys_; /** The current ordering */ - Ordering ordering_; + OrderingOrdered ordering_; /** The current set of linear deltas */ - VectorValues delta_; + VectorValuesOrdered delta_; /** The set of available factor graph slots. These occur because we are constantly deleting factors, leaving holes. **/ std::queue availableSlots_; @@ -162,9 +162,9 @@ protected: typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class private: - typedef FastList Factors; + typedef FastList Factors; typedef FastList SubTrees; - typedef std::vector Conditionals; + typedef std::vector Conditionals; Index key_; ///< index associated with root Factors factors_; ///< factors associated with root @@ -177,10 +177,10 @@ protected: * Static internal function to build a vector of parent pointers using the * algorithm of Gilbert et al., 2001, BIT. */ - static std::vector ComputeParents(const VariableIndex& structure); + static std::vector ComputeParents(const VariableIndexOrdered& structure); /** add a factor, for Create use only */ - void add(const GaussianFactor::shared_ptr& factor) { factors_.push_back(factor); } + void add(const GaussianFactorOrdered::shared_ptr& factor) { factors_.push_back(factor); } /** add a subtree, for Create use only */ void add(const shared_ptr& child) { subTrees_.push_back(child); } @@ -197,10 +197,10 @@ protected: const Factors& factors() const { return factors_; } /** Create an elimination tree from a factor graph */ - static std::vector Create(const GaussianFactorGraph& factorGraph, const VariableIndex& structure); + static std::vector Create(const GaussianFactorGraphOrdered& factorGraph, const VariableIndexOrdered& structure); /** Recursive routine that eliminates the factors arranged in an elimination tree */ - GaussianFactor::shared_ptr eliminateRecursive(GaussianFactorGraph::Eliminate function); + GaussianFactorOrdered::shared_ptr eliminateRecursive(GaussianFactorGraphOrdered::Eliminate function); /** Recursive function that helps find the top of each tree */ static void removeChildrenIndices(std::set& indices, const EliminationForest::shared_ptr& tree); @@ -210,9 +210,9 @@ private: /** Private methods for printing debug information */ static void PrintKeySet(const std::set& keys, const std::string& label); static void PrintSymbolicFactor(const NonlinearFactor::shared_ptr& factor); - static void PrintSymbolicFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering); + static void PrintSymbolicFactor(const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering); static void PrintSymbolicGraph(const NonlinearFactorGraph& graph, const std::string& label); - static void PrintSymbolicGraph(const GaussianFactorGraph& graph, const Ordering& ordering, const std::string& label); + static void PrintSymbolicGraph(const GaussianFactorGraphOrdered& graph, const OrderingOrdered& ordering, const std::string& label); }; // BatchFixedLagSmoother } /// namespace gtsam diff --git a/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp b/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp index 1e1e39e10..cfddc6e0b 100644 --- a/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp +++ b/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -128,8 +128,8 @@ void ConcurrentBatchFilter::synchronize(const NonlinearFactorGraph& summarizedFa // Perform an optional optimization on the to-be-sent-to-the-smoother factors if(relin_) { // Create ordering and delta - Ordering ordering = *graph.orderingCOLAMD(values); - VectorValues delta = values.zeroVectors(ordering); + OrderingOrdered ordering = *graph.orderingCOLAMD(values); + VectorValuesOrdered delta = values.zeroVectors(ordering); // Optimize this graph using a modified version of L-M optimize(graph, values, ordering, delta, separatorValues, parameters_); // Update filter theta and delta @@ -162,8 +162,8 @@ void ConcurrentBatchFilter::synchronize(const NonlinearFactorGraph& summarizedFa // Generate separate orderings that place the filter keys or the smoother keys first // TODO: This is convenient, but it recalculates the variable index each time - Ordering filterOrdering = *graph.orderingCOLAMDConstrained(values, filterConstraints); - Ordering smootherOrdering = *graph.orderingCOLAMDConstrained(values, smootherConstraints); + OrderingOrdered filterOrdering = *graph.orderingCOLAMDConstrained(values, filterConstraints); + OrderingOrdered smootherOrdering = *graph.orderingCOLAMDConstrained(values, smootherConstraints); // Extract the set of filter keys and smoother keys std::set filterKeys; @@ -276,7 +276,7 @@ void ConcurrentBatchFilter::removeFactors(const std::vector& slots) { gttic(remove_factors); // For each factor slot to delete... - SymbolicFactorGraph factors; + SymbolicFactorGraphOrdered factors; BOOST_FOREACH(size_t slot, slots) { // Create a symbolic version for the variable index factors.push_back(factors_.at(slot)->symbolic(ordering_)); @@ -295,7 +295,7 @@ void ConcurrentBatchFilter::removeFactors(const std::vector& slots) { void ConcurrentBatchFilter::reorder(const boost::optional >& keysToMove) { // Calculate the variable index - VariableIndex variableIndex(*factors_.symbolic(ordering_), ordering_.size()); + VariableIndexOrdered variableIndex(*factors_.symbolic(ordering_), ordering_.size()); // COLAMD groups will be used to place marginalize keys in Group 0, and everything else in Group 1 int group0 = 0; @@ -320,8 +320,8 @@ void ConcurrentBatchFilter::reorder(const boost::optional >& keysT } /* ************************************************************************* */ -ConcurrentBatchFilter::Result ConcurrentBatchFilter::optimize(const NonlinearFactorGraph& factors, Values& theta, const Ordering& ordering, - VectorValues& delta, const Values& linearValues, const LevenbergMarquardtParams& parameters) { +ConcurrentBatchFilter::Result ConcurrentBatchFilter::optimize(const NonlinearFactorGraph& factors, Values& theta, const OrderingOrdered& ordering, + VectorValuesOrdered& delta, const Values& linearValues, const LevenbergMarquardtParams& parameters) { // Create output result structure Result result; @@ -344,7 +344,7 @@ ConcurrentBatchFilter::Result ConcurrentBatchFilter::optimize(const NonlinearFac // Use a custom optimization loop so the linearization points can be controlled double previousError; - VectorValues newDelta; + VectorValuesOrdered newDelta; do { previousError = result.error; @@ -352,13 +352,13 @@ ConcurrentBatchFilter::Result ConcurrentBatchFilter::optimize(const NonlinearFac gttic(optimizer_iteration); { // Linearize graph around the linearization point - GaussianFactorGraph linearFactorGraph = *factors.linearize(theta, ordering); + GaussianFactorGraphOrdered linearFactorGraph = *factors.linearize(theta, ordering); // Keep increasing lambda until we make make progress while(true) { // Add prior factors at the current solution gttic(damp); - GaussianFactorGraph dampedFactorGraph(linearFactorGraph); + GaussianFactorGraphOrdered dampedFactorGraph(linearFactorGraph); dampedFactorGraph.reserve(linearFactorGraph.size() + delta.size()); { // for each of the variables, add a prior at the current solution @@ -366,7 +366,7 @@ ConcurrentBatchFilter::Result ConcurrentBatchFilter::optimize(const NonlinearFac Matrix A = lambda * eye(delta[j].size()); Vector b = lambda * delta[j]; SharedDiagonal model = noiseModel::Unit::Create(delta[j].size()); - GaussianFactor::shared_ptr prior(new JacobianFactor(j, A, b, model)); + GaussianFactorOrdered::shared_ptr prior(new JacobianFactorOrdered(j, A, b, model)); dampedFactorGraph.push_back(prior); } } @@ -375,7 +375,7 @@ ConcurrentBatchFilter::Result ConcurrentBatchFilter::optimize(const NonlinearFac gttic(solve); // Solve Damped Gaussian Factor Graph - newDelta = GaussianJunctionTree(dampedFactorGraph).optimize(parameters.getEliminationFunction()); + newDelta = GaussianJunctionTreeOrdered(dampedFactorGraph).optimize(parameters.getEliminationFunction()); // update the evalpoint with the new delta evalpoint = theta.retract(newDelta, ordering); gttoc(solve); @@ -442,10 +442,10 @@ void ConcurrentBatchFilter::marginalize(const FastList& keysToMove) { // Note: It is assumed the ordering already has these keys first // Create the linear factor graph - GaussianFactorGraph linearFactorGraph = *factors_.linearize(theta_, ordering_); + GaussianFactorGraphOrdered linearFactorGraph = *factors_.linearize(theta_, ordering_); // Calculate the variable index - VariableIndex variableIndex(linearFactorGraph, ordering_.size()); + VariableIndexOrdered variableIndex(linearFactorGraph, ordering_.size()); // Use the variable Index to mark the factors that will be marginalized std::set removedFactorSlots; @@ -472,7 +472,7 @@ void ConcurrentBatchFilter::marginalize(const FastList& keysToMove) { // Add the marginal factor variables to the separator NonlinearFactorGraph marginalFactors; BOOST_FOREACH(Index index, indicesToEliminate) { - GaussianFactor::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(parameters_.getEliminationFunction()); + GaussianFactorOrdered::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(parameters_.getEliminationFunction()); if(gaussianFactor->size() > 0) { LinearContainerFactor::shared_ptr marginalFactor(new LinearContainerFactor(gaussianFactor, ordering_, theta_)); marginalFactors.push_back(marginalFactor); @@ -545,16 +545,16 @@ void ConcurrentBatchFilter::marginalize(const FastList& keysToMove) { /* ************************************************************************* */ NonlinearFactorGraph ConcurrentBatchFilter::marginalize(const NonlinearFactorGraph& graph, const Values& values, - const Ordering& ordering, const std::set& marginalizeKeys, const GaussianFactorGraph::Eliminate& function) { + const OrderingOrdered& ordering, const std::set& marginalizeKeys, const GaussianFactorGraphOrdered::Eliminate& function) { // Calculate marginal factors on the remaining variables (after marginalizing 'marginalizeKeys') // Note: It is assumed the ordering already has these keys first // Create the linear factor graph - GaussianFactorGraph linearFactorGraph = *graph.linearize(values, ordering); + GaussianFactorGraphOrdered linearFactorGraph = *graph.linearize(values, ordering); // Construct a variable index - VariableIndex variableIndex(linearFactorGraph, ordering.size()); + VariableIndexOrdered variableIndex(linearFactorGraph, ordering.size()); // Construct an elimination tree to perform sparse elimination std::vector forest( EliminationForest::Create(linearFactorGraph, variableIndex) ); @@ -574,7 +574,7 @@ NonlinearFactorGraph ConcurrentBatchFilter::marginalize(const NonlinearFactorGra // Add the marginal factor variables to the separator NonlinearFactorGraph marginalFactors; BOOST_FOREACH(Index index, indicesToEliminate) { - GaussianFactor::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(function); + GaussianFactorOrdered::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(function); if(gaussianFactor->size() > 0) { LinearContainerFactor::shared_ptr marginalFactor(new LinearContainerFactor(gaussianFactor, ordering, values)); marginalFactors.push_back(marginalFactor); @@ -604,7 +604,7 @@ void ConcurrentBatchFilter::PrintNonlinearFactor(const NonlinearFactor::shared_p } /* ************************************************************************* */ -void ConcurrentBatchFilter::PrintLinearFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering, +void ConcurrentBatchFilter::PrintLinearFactor(const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering, const std::string& indent, const KeyFormatter& keyFormatter) { std::cout << indent; if(factor) { @@ -619,7 +619,7 @@ void ConcurrentBatchFilter::PrintLinearFactor(const GaussianFactor::shared_ptr& } /* ************************************************************************* */ -std::vector ConcurrentBatchFilter::EliminationForest::ComputeParents(const VariableIndex& structure) { +std::vector ConcurrentBatchFilter::EliminationForest::ComputeParents(const VariableIndexOrdered& structure) { // Number of factors and variables const size_t m = structure.nFactors(); const size_t n = structure.size(); @@ -650,7 +650,7 @@ std::vector ConcurrentBatchFilter::EliminationForest::ComputeParents(cons } /* ************************************************************************* */ -std::vector ConcurrentBatchFilter::EliminationForest::Create(const GaussianFactorGraph& factorGraph, const VariableIndex& structure) { +std::vector ConcurrentBatchFilter::EliminationForest::Create(const GaussianFactorGraphOrdered& factorGraph, const VariableIndexOrdered& structure) { // Compute the tree structure std::vector parents(ComputeParents(structure)); @@ -669,7 +669,7 @@ std::vector ConcurrentBatc } // Hang factors in right places - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factorGraph) { + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factorGraph) { if(factor && factor->size() > 0) { Index j = *std::min_element(factor->begin(), factor->end()); if(j < structure.size()) @@ -681,10 +681,10 @@ std::vector ConcurrentBatc } /* ************************************************************************* */ -GaussianFactor::shared_ptr ConcurrentBatchFilter::EliminationForest::eliminateRecursive(GaussianFactorGraph::Eliminate function) { +GaussianFactorOrdered::shared_ptr ConcurrentBatchFilter::EliminationForest::eliminateRecursive(GaussianFactorGraphOrdered::Eliminate function) { // Create the list of factors to be eliminated, initially empty, and reserve space - GaussianFactorGraph factors; + GaussianFactorGraphOrdered factors; factors.reserve(this->factors_.size() + this->subTrees_.size()); // Add all factors associated with the current node @@ -695,7 +695,7 @@ GaussianFactor::shared_ptr ConcurrentBatchFilter::EliminationForest::eliminateRe factors.push_back(child->eliminateRecursive(function)); // Combine all factors (from this node and from subtrees) into a joint factor - GaussianFactorGraph::EliminationResult eliminated(function(factors, 1)); + GaussianFactorGraphOrdered::EliminationResult eliminated(function(factors, 1)); return eliminated.second; } diff --git a/gtsam_unstable/nonlinear/ConcurrentBatchFilter.h b/gtsam_unstable/nonlinear/ConcurrentBatchFilter.h index 9a7690786..31122f2e7 100644 --- a/gtsam_unstable/nonlinear/ConcurrentBatchFilter.h +++ b/gtsam_unstable/nonlinear/ConcurrentBatchFilter.h @@ -76,12 +76,12 @@ public: } /** Access the current ordering */ - const Ordering& getOrdering() const { + const OrderingOrdered& getOrdering() const { return ordering_; } /** Access the current set of deltas to the linearization point */ - const VectorValues& getDelta() const { + const VectorValuesOrdered& getDelta() const { return delta_; } @@ -125,8 +125,8 @@ protected: bool relin_; NonlinearFactorGraph factors_; ///< The set of all factors currently in the filter Values theta_; ///< Current linearization point of all variables in the filter - Ordering ordering_; ///< The current ordering used to calculate the linear deltas - VectorValues delta_; ///< The current set of linear deltas from the linearization point + OrderingOrdered ordering_; ///< The current ordering used to calculate the linear deltas + VectorValuesOrdered delta_; ///< The current set of linear deltas from the linearization point std::queue availableSlots_; ///< The set of available factor graph slots caused by deleting factors Values separatorValues_; ///< The linearization points of the separator variables. These should not be updated during optimization. std::vector smootherSummarizationSlots_; ///< The slots in factor graph that correspond to the current smoother summarization factors @@ -194,8 +194,8 @@ private: void reorder(const boost::optional >& keysToMove = boost::none); /** Use a modified version of L-M to update the linearization point and delta */ - static Result optimize(const NonlinearFactorGraph& factors, Values& theta, const Ordering& ordering, - VectorValues& delta, const Values& linearValues, const LevenbergMarquardtParams& parameters); + static Result optimize(const NonlinearFactorGraph& factors, Values& theta, const OrderingOrdered& ordering, + VectorValuesOrdered& delta, const Values& linearValues, const LevenbergMarquardtParams& parameters); /** Marginalize out the set of requested variables from the filter, caching them for the smoother * This effectively moves the separator. @@ -206,14 +206,14 @@ private: * This effectively moves the separator. */ static NonlinearFactorGraph marginalize(const NonlinearFactorGraph& graph, const Values& values, - const Ordering& ordering, const std::set& marginalizeKeys, const GaussianFactorGraph::Eliminate& function = EliminateQR); + const OrderingOrdered& ordering, const std::set& marginalizeKeys, const GaussianFactorGraphOrdered::Eliminate& function = EliminateQROrdered); /** Print just the nonlinear keys in a nonlinear factor */ static void PrintNonlinearFactor(const NonlinearFactor::shared_ptr& factor, const std::string& indent = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter); /** Print just the nonlinear keys in a linear factor */ - static void PrintLinearFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering, + static void PrintLinearFactor(const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering, const std::string& indent = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter); // A custom elimination tree that supports forests and partial elimination @@ -222,9 +222,9 @@ private: typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class private: - typedef FastList Factors; + typedef FastList Factors; typedef FastList SubTrees; - typedef std::vector Conditionals; + typedef std::vector Conditionals; Index key_; ///< index associated with root Factors factors_; ///< factors associated with root @@ -237,10 +237,10 @@ private: * Static internal function to build a vector of parent pointers using the * algorithm of Gilbert et al., 2001, BIT. */ - static std::vector ComputeParents(const VariableIndex& structure); + static std::vector ComputeParents(const VariableIndexOrdered& structure); /** add a factor, for Create use only */ - void add(const GaussianFactor::shared_ptr& factor) { factors_.push_back(factor); } + void add(const GaussianFactorOrdered::shared_ptr& factor) { factors_.push_back(factor); } /** add a subtree, for Create use only */ void add(const shared_ptr& child) { subTrees_.push_back(child); } @@ -257,10 +257,10 @@ private: const Factors& factors() const { return factors_; } /** Create an elimination tree from a factor graph */ - static std::vector Create(const GaussianFactorGraph& factorGraph, const VariableIndex& structure); + static std::vector Create(const GaussianFactorGraphOrdered& factorGraph, const VariableIndexOrdered& structure); /** Recursive routine that eliminates the factors arranged in an elimination tree */ - GaussianFactor::shared_ptr eliminateRecursive(GaussianFactorGraph::Eliminate function); + GaussianFactorOrdered::shared_ptr eliminateRecursive(GaussianFactorGraphOrdered::Eliminate function); /** Recursive function that helps find the top of each tree */ static void removeChildrenIndices(std::set& indices, const EliminationForest::shared_ptr& tree); diff --git a/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp b/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp index 1e9d4a2a9..4a56a29a6 100644 --- a/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp +++ b/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -217,7 +217,7 @@ void ConcurrentBatchSmoother::removeFactors(const std::vector& slots) { gttic(remove_factors); // For each factor slot to delete... - SymbolicFactorGraph factors; + SymbolicFactorGraphOrdered factors; BOOST_FOREACH(size_t slot, slots) { // Create a symbolic version for the variable index factors.push_back(factors_.at(slot)->symbolic(ordering_)); @@ -236,7 +236,7 @@ void ConcurrentBatchSmoother::removeFactors(const std::vector& slots) { void ConcurrentBatchSmoother::reorder() { // Recalculate the variable index - variableIndex_ = VariableIndex(*factors_.symbolic(ordering_)); + variableIndex_ = VariableIndexOrdered(*factors_.symbolic(ordering_)); // Initialize all variables to group0 std::vector cmember(variableIndex_.size(), 0); @@ -281,7 +281,7 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::optimize() { // Use a custom optimization loop so the linearization points can be controlled double previousError; - VectorValues newDelta; + VectorValuesOrdered newDelta; do { previousError = result.error; @@ -289,13 +289,13 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::optimize() { gttic(optimizer_iteration); { // Linearize graph around the linearization point - GaussianFactorGraph linearFactorGraph = *factors_.linearize(theta_, ordering_); + GaussianFactorGraphOrdered linearFactorGraph = *factors_.linearize(theta_, ordering_); // Keep increasing lambda until we make make progress while(true) { // Add prior factors at the current solution gttic(damp); - GaussianFactorGraph dampedFactorGraph(linearFactorGraph); + GaussianFactorGraphOrdered dampedFactorGraph(linearFactorGraph); dampedFactorGraph.reserve(linearFactorGraph.size() + delta_.size()); { // for each of the variables, add a prior at the current solution @@ -303,7 +303,7 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::optimize() { Matrix A = lambda * eye(delta_[j].size()); Vector b = lambda * delta_[j]; SharedDiagonal model = noiseModel::Unit::Create(delta_[j].size()); - GaussianFactor::shared_ptr prior(new JacobianFactor(j, A, b, model)); + GaussianFactorOrdered::shared_ptr prior(new JacobianFactorOrdered(j, A, b, model)); dampedFactorGraph.push_back(prior); } } @@ -312,7 +312,7 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::optimize() { gttic(solve); // Solve Damped Gaussian Factor Graph - newDelta = GaussianJunctionTree(dampedFactorGraph).optimize(parameters_.getEliminationFunction()); + newDelta = GaussianJunctionTreeOrdered(dampedFactorGraph).optimize(parameters_.getEliminationFunction()); // update the evalpoint with the new delta evalpoint = theta_.retract(newDelta, ordering_); gttoc(solve); @@ -382,7 +382,7 @@ void ConcurrentBatchSmoother::updateSmootherSummarization() { reorder(); // Create the linear factor graph - GaussianFactorGraph linearFactorGraph = *factors_.linearize(theta_, ordering_); + GaussianFactorGraphOrdered linearFactorGraph = *factors_.linearize(theta_, ordering_); // Construct an elimination tree to perform sparse elimination std::vector forest( EliminationForest::Create(linearFactorGraph, variableIndex_) ); @@ -404,7 +404,7 @@ void ConcurrentBatchSmoother::updateSmootherSummarization() { // Eliminate each top-most key, returning a Gaussian Factor on some of the remaining variables // Convert the marginal factors into Linear Container Factors and store BOOST_FOREACH(Index index, indicesToEliminate) { - GaussianFactor::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(parameters_.getEliminationFunction()); + GaussianFactorOrdered::shared_ptr gaussianFactor = forest.at(index)->eliminateRecursive(parameters_.getEliminationFunction()); if(gaussianFactor->size() > 0) { LinearContainerFactor::shared_ptr marginalFactor(new LinearContainerFactor(gaussianFactor, ordering_, theta_)); smootherSummarization_.push_back(marginalFactor); @@ -432,7 +432,7 @@ void ConcurrentBatchSmoother::PrintNonlinearFactor(const NonlinearFactor::shared } /* ************************************************************************* */ -void ConcurrentBatchSmoother::PrintLinearFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering, const std::string& indent, const KeyFormatter& keyFormatter) { +void ConcurrentBatchSmoother::PrintLinearFactor(const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering, const std::string& indent, const KeyFormatter& keyFormatter) { std::cout << indent; if(factor) { std::cout << "g( "; @@ -446,7 +446,7 @@ void ConcurrentBatchSmoother::PrintLinearFactor(const GaussianFactor::shared_ptr } /* ************************************************************************* */ -std::vector ConcurrentBatchSmoother::EliminationForest::ComputeParents(const VariableIndex& structure) { +std::vector ConcurrentBatchSmoother::EliminationForest::ComputeParents(const VariableIndexOrdered& structure) { // Number of factors and variables const size_t m = structure.nFactors(); const size_t n = structure.size(); @@ -477,7 +477,7 @@ std::vector ConcurrentBatchSmoother::EliminationForest::ComputeParents(co } /* ************************************************************************* */ -std::vector ConcurrentBatchSmoother::EliminationForest::Create(const GaussianFactorGraph& factorGraph, const VariableIndex& structure) { +std::vector ConcurrentBatchSmoother::EliminationForest::Create(const GaussianFactorGraphOrdered& factorGraph, const VariableIndexOrdered& structure) { // Compute the tree structure std::vector parents(ComputeParents(structure)); @@ -496,7 +496,7 @@ std::vector ConcurrentBa } // Hang factors in right places - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factorGraph) { + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factorGraph) { if(factor && factor->size() > 0) { Index j = *std::min_element(factor->begin(), factor->end()); if(j < structure.size()) @@ -508,10 +508,10 @@ std::vector ConcurrentBa } /* ************************************************************************* */ -GaussianFactor::shared_ptr ConcurrentBatchSmoother::EliminationForest::eliminateRecursive(GaussianFactorGraph::Eliminate function) { +GaussianFactorOrdered::shared_ptr ConcurrentBatchSmoother::EliminationForest::eliminateRecursive(GaussianFactorGraphOrdered::Eliminate function) { // Create the list of factors to be eliminated, initially empty, and reserve space - GaussianFactorGraph factors; + GaussianFactorGraphOrdered factors; factors.reserve(this->factors_.size() + this->subTrees_.size()); // Add all factors associated with the current node @@ -522,7 +522,7 @@ GaussianFactor::shared_ptr ConcurrentBatchSmoother::EliminationForest::eliminate factors.push_back(child->eliminateRecursive(function)); // Combine all factors (from this node and from subtrees) into a joint factor - GaussianFactorGraph::EliminationResult eliminated(function(factors, 1)); + GaussianFactorGraphOrdered::EliminationResult eliminated(function(factors, 1)); return eliminated.second; } diff --git a/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.h b/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.h index f54c1f60d..80ce9724b 100644 --- a/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.h +++ b/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.h @@ -76,12 +76,12 @@ public: } /** Access the current ordering */ - const Ordering& getOrdering() const { + const OrderingOrdered& getOrdering() const { return ordering_; } /** Access the current set of deltas to the linearization point */ - const VectorValues& getDelta() const { + const VectorValuesOrdered& getDelta() const { return delta_; } @@ -126,9 +126,9 @@ protected: LevenbergMarquardtParams parameters_; ///< LM parameters NonlinearFactorGraph factors_; ///< The set of all factors currently in the smoother Values theta_; ///< Current linearization point of all variables in the smoother - Ordering ordering_; ///< The current ordering used to calculate the linear deltas - VectorValues delta_; ///< The current set of linear deltas from the linearization point - VariableIndex variableIndex_; ///< The current variable index, which allows efficient factor lookup by variable + OrderingOrdered ordering_; ///< The current ordering used to calculate the linear deltas + VectorValuesOrdered delta_; ///< The current set of linear deltas from the linearization point + VariableIndexOrdered variableIndex_; ///< The current variable index, which allows efficient factor lookup by variable std::queue availableSlots_; ///< The set of available factor graph slots caused by deleting factors Values separatorValues_; ///< The linearization points of the separator variables. These should not be updated during optimization. std::vector filterSummarizationSlots_; ///< The slots in factor graph that correspond to the current filter summarization factors @@ -197,7 +197,7 @@ private: const std::string& indent = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter); /** Print just the nonlinear keys in a linear factor */ - static void PrintLinearFactor(const GaussianFactor::shared_ptr& factor, const Ordering& ordering, + static void PrintLinearFactor(const GaussianFactorOrdered::shared_ptr& factor, const OrderingOrdered& ordering, const std::string& indent = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter); // A custom elimination tree that supports forests and partial elimination @@ -206,9 +206,9 @@ private: typedef boost::shared_ptr shared_ptr; ///< Shared pointer to this class private: - typedef FastList Factors; + typedef FastList Factors; typedef FastList SubTrees; - typedef std::vector Conditionals; + typedef std::vector Conditionals; Index key_; ///< index associated with root Factors factors_; ///< factors associated with root @@ -221,10 +221,10 @@ private: * Static internal function to build a vector of parent pointers using the * algorithm of Gilbert et al., 2001, BIT. */ - static std::vector ComputeParents(const VariableIndex& structure); + static std::vector ComputeParents(const VariableIndexOrdered& structure); /** add a factor, for Create use only */ - void add(const GaussianFactor::shared_ptr& factor) { factors_.push_back(factor); } + void add(const GaussianFactorOrdered::shared_ptr& factor) { factors_.push_back(factor); } /** add a subtree, for Create use only */ void add(const shared_ptr& child) { subTrees_.push_back(child); } @@ -241,10 +241,10 @@ private: const Factors& factors() const { return factors_; } /** Create an elimination tree from a factor graph */ - static std::vector Create(const GaussianFactorGraph& factorGraph, const VariableIndex& structure); + static std::vector Create(const GaussianFactorGraphOrdered& factorGraph, const VariableIndexOrdered& structure); /** Recursive routine that eliminates the factors arranged in an elimination tree */ - GaussianFactor::shared_ptr eliminateRecursive(GaussianFactorGraph::Eliminate function); + GaussianFactorOrdered::shared_ptr eliminateRecursive(GaussianFactorGraphOrdered::Eliminate function); /** Recursive function that helps find the top of each tree */ static void removeChildrenIndices(std::set& indices, const EliminationForest::shared_ptr& tree); diff --git a/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.cpp b/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.cpp index 2341fc449..8b8927661 100644 --- a/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.cpp +++ b/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.cpp @@ -25,7 +25,7 @@ namespace gtsam { /* ************************************************************************* */ -void recursiveMarkAffectedKeys(const Index& index, const ISAM2Clique::shared_ptr& clique, const Ordering& ordering, std::set& additionalKeys) { +void recursiveMarkAffectedKeys(const Index& index, const ISAM2Clique::shared_ptr& clique, const OrderingOrdered& ordering, std::set& additionalKeys) { // Check if the separator keys of the current clique contain the specified key if(std::find(clique->conditional()->beginParents(), clique->conditional()->endParents(), index) != clique->conditional()->endParents()) { @@ -184,7 +184,7 @@ void IncrementalFixedLagSmoother::PrintKeySet(const std::set& keys, const s } /* ************************************************************************* */ -void IncrementalFixedLagSmoother::PrintSymbolicFactor(const GaussianFactor::shared_ptr& factor, const gtsam::Ordering& ordering) { +void IncrementalFixedLagSmoother::PrintSymbolicFactor(const GaussianFactorOrdered::shared_ptr& factor, const gtsam::OrderingOrdered& ordering) { std::cout << "f("; BOOST_FOREACH(Index index, factor->keys()) { std::cout << " " << index << "[" << gtsam::DefaultKeyFormatter(ordering.key(index)) << "]"; @@ -193,9 +193,9 @@ void IncrementalFixedLagSmoother::PrintSymbolicFactor(const GaussianFactor::shar } /* ************************************************************************* */ -void IncrementalFixedLagSmoother::PrintSymbolicGraph(const GaussianFactorGraph& graph, const gtsam::Ordering& ordering, const std::string& label) { +void IncrementalFixedLagSmoother::PrintSymbolicGraph(const GaussianFactorGraphOrdered& graph, const gtsam::OrderingOrdered& ordering, const std::string& label) { std::cout << label << std::endl; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, graph) { + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, graph) { PrintSymbolicFactor(factor, ordering); } } @@ -210,7 +210,7 @@ void IncrementalFixedLagSmoother::PrintSymbolicTree(const gtsam::ISAM2& isam, co } /* ************************************************************************* */ -void IncrementalFixedLagSmoother::PrintSymbolicTreeHelper(const gtsam::ISAM2Clique::shared_ptr& clique, const gtsam::Ordering& ordering, const std::string indent) { +void IncrementalFixedLagSmoother::PrintSymbolicTreeHelper(const gtsam::ISAM2Clique::shared_ptr& clique, const gtsam::OrderingOrdered& ordering, const std::string indent) { // Print the current clique std::cout << indent << "P( "; diff --git a/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.h b/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.h index b46a08074..4c108c81f 100644 --- a/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.h +++ b/gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.h @@ -93,10 +93,10 @@ protected: private: /** Private methods for printing debug information */ static void PrintKeySet(const std::set& keys, const std::string& label = "Keys:"); - static void PrintSymbolicFactor(const GaussianFactor::shared_ptr& factor, const gtsam::Ordering& ordering); - static void PrintSymbolicGraph(const GaussianFactorGraph& graph, const gtsam::Ordering& ordering, const std::string& label = "Factor Graph:"); + static void PrintSymbolicFactor(const GaussianFactorOrdered::shared_ptr& factor, const gtsam::OrderingOrdered& ordering); + static void PrintSymbolicGraph(const GaussianFactorGraphOrdered& graph, const gtsam::OrderingOrdered& ordering, const std::string& label = "Factor Graph:"); static void PrintSymbolicTree(const gtsam::ISAM2& isam, const std::string& label = "Bayes Tree:"); - static void PrintSymbolicTreeHelper(const gtsam::ISAM2Clique::shared_ptr& clique, const gtsam::Ordering& ordering, const std::string indent = ""); + static void PrintSymbolicTreeHelper(const gtsam::ISAM2Clique::shared_ptr& clique, const gtsam::OrderingOrdered& ordering, const std::string indent = ""); }; // IncrementalFixedLagSmoother diff --git a/gtsam_unstable/nonlinear/LinearizedFactor.cpp b/gtsam_unstable/nonlinear/LinearizedFactor.cpp index eb5a83c79..fe0eb9328 100644 --- a/gtsam_unstable/nonlinear/LinearizedFactor.cpp +++ b/gtsam_unstable/nonlinear/LinearizedFactor.cpp @@ -22,7 +22,7 @@ namespace gtsam { /* ************************************************************************* */ -LinearizedGaussianFactor::LinearizedGaussianFactor(const GaussianFactor::shared_ptr& gaussian, const Ordering& ordering, const Values& lin_points) { +LinearizedGaussianFactor::LinearizedGaussianFactor(const GaussianFactorOrdered::shared_ptr& gaussian, const OrderingOrdered& ordering, const Values& lin_points) { // Extract the keys and linearization points BOOST_FOREACH(const Index& idx, gaussian->keys()) { // find full symbol @@ -48,8 +48,8 @@ LinearizedJacobianFactor::LinearizedJacobianFactor() : Ab_(matrix_) { } /* ************************************************************************* */ -LinearizedJacobianFactor::LinearizedJacobianFactor(const JacobianFactor::shared_ptr& jacobian, - const Ordering& ordering, const Values& lin_points) +LinearizedJacobianFactor::LinearizedJacobianFactor(const JacobianFactorOrdered::shared_ptr& jacobian, + const OrderingOrdered& ordering, const Values& lin_points) : Base(jacobian, ordering, lin_points), Ab_(matrix_) { // Get the Ab matrix from the Jacobian factor, with any covariance baked in @@ -58,7 +58,7 @@ LinearizedJacobianFactor::LinearizedJacobianFactor(const JacobianFactor::shared_ // Create the dims array size_t *dims = (size_t *)alloca(sizeof(size_t) * (jacobian->size() + 1)); size_t index = 0; - for(JacobianFactor::const_iterator iter = jacobian->begin(); iter != jacobian->end(); ++iter) { + for(JacobianFactorOrdered::const_iterator iter = jacobian->begin(); iter != jacobian->end(); ++iter) { dims[index++] = jacobian->getDim(iter); } dims[index] = 1; @@ -109,8 +109,8 @@ double LinearizedJacobianFactor::error(const Values& c) const { } /* ************************************************************************* */ -boost::shared_ptr -LinearizedJacobianFactor::linearize(const Values& c, const Ordering& ordering) const { +boost::shared_ptr +LinearizedJacobianFactor::linearize(const Values& c, const OrderingOrdered& ordering) const { // Create the 'terms' data structure for the Jacobian constructor std::vector > terms; @@ -121,7 +121,7 @@ LinearizedJacobianFactor::linearize(const Values& c, const Ordering& ordering) c // compute rhs Vector b = -error_vector(c); - return boost::shared_ptr(new JacobianFactor(terms, b, noiseModel::Unit::Create(dim()))); + return boost::shared_ptr(new JacobianFactorOrdered(terms, b, noiseModel::Unit::Create(dim()))); } /* ************************************************************************* */ @@ -150,8 +150,8 @@ LinearizedHessianFactor::LinearizedHessianFactor() : info_(matrix_) { } /* ************************************************************************* */ -LinearizedHessianFactor::LinearizedHessianFactor(const HessianFactor::shared_ptr& hessian, - const Ordering& ordering, const Values& lin_points) +LinearizedHessianFactor::LinearizedHessianFactor(const HessianFactorOrdered::shared_ptr& hessian, + const OrderingOrdered& ordering, const Values& lin_points) : Base(hessian, ordering, lin_points), info_(matrix_) { // Copy the augmented matrix holding G, g, and f @@ -160,7 +160,7 @@ LinearizedHessianFactor::LinearizedHessianFactor(const HessianFactor::shared_ptr // Create the dims array size_t *dims = (size_t*)alloca(sizeof(size_t)*(hessian->size() + 1)); size_t index = 0; - for(HessianFactor::const_iterator iter = hessian->begin(); iter != hessian->end(); ++iter) { + for(HessianFactorOrdered::const_iterator iter = hessian->begin(); iter != hessian->end(); ++iter) { dims[index++] = hessian->getDim(iter); } dims[index] = 1; @@ -227,8 +227,8 @@ double LinearizedHessianFactor::error(const Values& c) const { } /* ************************************************************************* */ -boost::shared_ptr -LinearizedHessianFactor::linearize(const Values& c, const Ordering& ordering) const { +boost::shared_ptr +LinearizedHessianFactor::linearize(const Values& c, const OrderingOrdered& ordering) const { // Use the ordering to convert the keys into indices; std::vector js; @@ -274,8 +274,8 @@ LinearizedHessianFactor::linearize(const Values& c, const Ordering& ordering) co } // Create a Hessian Factor from the modified info matrix - //return boost::shared_ptr(new HessianFactor(js, newInfo)); - return boost::shared_ptr(new HessianFactor(js, Gs, gs, f)); + //return boost::shared_ptr(new HessianFactorOrdered(js, newInfo)); + return boost::shared_ptr(new HessianFactorOrdered(js, Gs, gs, f)); } } // \namespace aspn diff --git a/gtsam_unstable/nonlinear/LinearizedFactor.h b/gtsam_unstable/nonlinear/LinearizedFactor.h index 330df0c6a..2fcab9207 100644 --- a/gtsam_unstable/nonlinear/LinearizedFactor.h +++ b/gtsam_unstable/nonlinear/LinearizedFactor.h @@ -19,10 +19,10 @@ #include #include -#include +#include #include -#include -#include +#include +#include #include namespace gtsam { @@ -54,7 +54,7 @@ public: * @param ordering: The full ordering used to linearize this factor * @param lin_points: The linearization points for, at least, the variables used by this factor */ - LinearizedGaussianFactor(const GaussianFactor::shared_ptr& gaussian, const Ordering& ordering, const Values& lin_points); + LinearizedGaussianFactor(const GaussianFactorOrdered::shared_ptr& gaussian, const OrderingOrdered& ordering, const Values& lin_points); virtual ~LinearizedGaussianFactor() {}; @@ -114,8 +114,8 @@ public: * @param ordering: The ordering used to linearize this factor * @param lin_points: The linearization points for, at least, the variables used by this factor */ - LinearizedJacobianFactor(const JacobianFactor::shared_ptr& jacobian, - const Ordering& ordering, const Values& lin_points); + LinearizedJacobianFactor(const JacobianFactorOrdered::shared_ptr& jacobian, + const OrderingOrdered& ordering, const Values& lin_points); virtual ~LinearizedJacobianFactor() {} @@ -148,8 +148,8 @@ public: * Reimplemented from NoiseModelFactor to directly copy out the * matrices and only update the RHS b with an updated residual */ - boost::shared_ptr linearize( - const Values& c, const Ordering& ordering) const; + boost::shared_ptr linearize( + const Values& c, const OrderingOrdered& ordering) const; /** (A*x-b) */ Vector error_vector(const Values& c) const; @@ -207,8 +207,8 @@ public: * @param ordering: The ordering used to linearize this factor * @param lin_points: The linearization points for, at least, the variables used by this factor */ - LinearizedHessianFactor(const HessianFactor::shared_ptr& hessian, - const Ordering& ordering, const Values& lin_points); + LinearizedHessianFactor(const HessianFactorOrdered::shared_ptr& hessian, + const OrderingOrdered& ordering, const Values& lin_points); virtual ~LinearizedHessianFactor() {} @@ -270,8 +270,8 @@ public: * Reimplemented from NoiseModelFactor to directly copy out the * matrices and only update the RHS b with an updated residual */ - boost::shared_ptr linearize( - const Values& c, const Ordering& ordering) const; + boost::shared_ptr linearize( + const Values& c, const OrderingOrdered& ordering) const; private: /** Serialization function */ diff --git a/gtsam_unstable/nonlinear/summarization.cpp b/gtsam_unstable/nonlinear/summarization.cpp index d691574b0..d5630488e 100644 --- a/gtsam_unstable/nonlinear/summarization.cpp +++ b/gtsam_unstable/nonlinear/summarization.cpp @@ -15,15 +15,15 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ -GaussianFactorGraph::shared_ptr summarizeGraphSequential( - const GaussianFactorGraph& full_graph, const std::vector& indices, bool useQR) { +GaussianFactorGraphOrdered::shared_ptr summarizeGraphSequential( + const GaussianFactorGraphOrdered& full_graph, const std::vector& indices, bool useQR) { GaussianSequentialSolver solver(full_graph, useQR); return solver.jointFactorGraph(indices); } /* ************************************************************************* */ -GaussianFactorGraph::shared_ptr summarizeGraphSequential( - const GaussianFactorGraph& full_graph, const Ordering& ordering, const KeySet& saved_keys, bool useQR) { +GaussianFactorGraphOrdered::shared_ptr summarizeGraphSequential( + const GaussianFactorGraphOrdered& full_graph, const OrderingOrdered& ordering, const KeySet& saved_keys, bool useQR) { std::vector indices; BOOST_FOREACH(const Key& k, saved_keys) indices.push_back(ordering[k]); diff --git a/gtsam_unstable/nonlinear/summarization.h b/gtsam_unstable/nonlinear/summarization.h index 4d783ebe1..79e2c49b2 100644 --- a/gtsam_unstable/nonlinear/summarization.h +++ b/gtsam_unstable/nonlinear/summarization.h @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include namespace gtsam { @@ -21,12 +21,12 @@ namespace gtsam { * Summarization function that eliminates a set of variables (does not convert to Jacobians) * NOTE: uses sequential solver - requires fully constrained system */ -GaussianFactorGraph::shared_ptr GTSAM_UNSTABLE_EXPORT summarizeGraphSequential( - const GaussianFactorGraph& full_graph, const std::vector& indices, bool useQR = false); +GaussianFactorGraphOrdered::shared_ptr GTSAM_UNSTABLE_EXPORT summarizeGraphSequential( + const GaussianFactorGraphOrdered& full_graph, const std::vector& indices, bool useQR = false); /** Summarization that also converts keys to indices */ -GaussianFactorGraph::shared_ptr GTSAM_UNSTABLE_EXPORT summarizeGraphSequential( - const GaussianFactorGraph& full_graph, const Ordering& ordering, +GaussianFactorGraphOrdered::shared_ptr GTSAM_UNSTABLE_EXPORT summarizeGraphSequential( + const GaussianFactorGraphOrdered& full_graph, const OrderingOrdered& ordering, const KeySet& saved_keys, bool useQR = false); } // \namespace gtsam diff --git a/gtsam_unstable/nonlinear/tests/testBatchFixedLagSmoother.cpp b/gtsam_unstable/nonlinear/tests/testBatchFixedLagSmoother.cpp index d2f17e9f3..53828d6b4 100644 --- a/gtsam_unstable/nonlinear/tests/testBatchFixedLagSmoother.cpp +++ b/gtsam_unstable/nonlinear/tests/testBatchFixedLagSmoother.cpp @@ -21,9 +21,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include #include @@ -35,10 +35,10 @@ using namespace gtsam; /* ************************************************************************* */ bool check_smoother(const NonlinearFactorGraph& fullgraph, const Values& fullinit, const BatchFixedLagSmoother& smoother, const Key& key) { - Ordering ordering = *fullgraph.orderingCOLAMD(fullinit); - GaussianFactorGraph linearized = *fullgraph.linearize(fullinit, ordering); - GaussianBayesNet gbn = *GaussianSequentialSolver(linearized).eliminate(); - VectorValues delta = optimize(gbn); + OrderingOrdered ordering = *fullgraph.orderingCOLAMD(fullinit); + GaussianFactorGraphOrdered linearized = *fullgraph.linearize(fullinit, ordering); + GaussianBayesNetOrdered gbn = *GaussianSequentialSolver(linearized).eliminate(); + VectorValuesOrdered delta = optimize(gbn); Values fullfinal = fullinit.retract(delta, ordering); Point2 expected = fullfinal.at(key); diff --git a/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp b/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp index 2a99ce31a..ac4a6a390 100644 --- a/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp +++ b/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp @@ -23,12 +23,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include #include #include @@ -87,18 +87,18 @@ bool hessian_equal(const NonlinearFactorGraph& expected, const NonlinearFactorGr } // Create an ordering - Ordering ordering; + OrderingOrdered ordering; BOOST_FOREACH(Key key, expectedKeys) { ordering.push_back(key); } // Linearize each factor graph - GaussianFactorGraph expectedGaussian; + GaussianFactorGraphOrdered expectedGaussian; BOOST_FOREACH(const NonlinearFactor::shared_ptr& factor, expected) { if(factor) expectedGaussian.push_back( factor->linearize(theta, ordering) ); } - GaussianFactorGraph actualGaussian; + GaussianFactorGraphOrdered actualGaussian; BOOST_FOREACH(const NonlinearFactor::shared_ptr& factor, actual) { if(factor) actualGaussian.push_back( factor->linearize(theta, ordering) ); @@ -384,7 +384,7 @@ NonlinearFactorGraph MarginalFactors(const NonlinearFactorGraph& factors, const BOOST_FOREACH(Key key, remainingKeys) { constraints[key] = 1; } - Ordering ordering = *factors.orderingCOLAMDConstrained(values, constraints); + OrderingOrdered ordering = *factors.orderingCOLAMDConstrained(values, constraints); // Convert the remaining keys into indices std::vector remainingIndices; @@ -394,7 +394,7 @@ NonlinearFactorGraph MarginalFactors(const NonlinearFactorGraph& factors, const // Solve for the Gaussian marginal factors GaussianSequentialSolver gss(*factors.linearize(values, ordering), true); - GaussianFactorGraph linearMarginals = *gss.jointFactorGraph(remainingIndices); + GaussianFactorGraphOrdered linearMarginals = *gss.jointFactorGraph(remainingIndices); // Convert to LinearContainFactors return LinearContainerFactor::convertLinearGraph(linearMarginals, ordering, values); diff --git a/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp b/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp index 550d8971d..99f7e6adb 100644 --- a/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp +++ b/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp @@ -23,11 +23,11 @@ #include #include #include -#include +#include #include #include #include -#include +#include #include #include @@ -78,18 +78,18 @@ bool hessian_equal(const NonlinearFactorGraph& expected, const NonlinearFactorGr return false; // Create an ordering - Ordering ordering; + OrderingOrdered ordering; BOOST_FOREACH(Key key, expectedKeys) { ordering.push_back(key); } // Linearize each factor graph - GaussianFactorGraph expectedGaussian; + GaussianFactorGraphOrdered expectedGaussian; BOOST_FOREACH(const NonlinearFactor::shared_ptr& factor, expected) { if(factor) expectedGaussian.push_back( factor->linearize(theta, ordering) ); } - GaussianFactorGraph actualGaussian; + GaussianFactorGraphOrdered actualGaussian; BOOST_FOREACH(const NonlinearFactor::shared_ptr& factor, actual) { if(factor) actualGaussian.push_back( factor->linearize(theta, ordering) ); @@ -511,7 +511,7 @@ TEST_UNSAFE( ConcurrentBatchSmoother, synchronize ) Values optimalTheta = BatchOptimize(fullGraph, fullTheta); // Re-eliminate to create the Bayes Tree - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(Symbol('X', 2)); ordering.push_back(Symbol('X', 0)); ordering.push_back(Symbol('X', 1)); @@ -527,10 +527,10 @@ TEST_UNSAFE( ConcurrentBatchSmoother, synchronize ) ordering.push_back(Symbol('X', 12)); Values linpoint; linpoint.insert(optimalTheta); - GaussianFactorGraph linearGraph = *fullGraph.linearize(linpoint, ordering); - JunctionTree jt(linearGraph); - ISAM2Clique::shared_ptr root = jt.eliminate(EliminateQR); - BayesTree bayesTree; + GaussianFactorGraphOrdered linearGraph = *fullGraph.linearize(linpoint, ordering); + JunctionTreeOrdered jt(linearGraph); + ISAM2Clique::shared_ptr root = jt.eliminate(EliminateQROrdered); + BayesTreeOrdered bayesTree; bayesTree.insert(root); // Extract the values for the smoother keys. This consists of the branches: X4 and X6 @@ -637,9 +637,9 @@ TEST_UNSAFE( ConcurrentBatchSmoother, synchronize ) linpoint.insert(optimalTheta); linpoint.update(rootValues); linearGraph = *fullGraph.linearize(linpoint, ordering); - jt = JunctionTree(linearGraph); - root = jt.eliminate(EliminateQR); - bayesTree = BayesTree(); + jt = JunctionTreeOrdered(linearGraph); + root = jt.eliminate(EliminateQROrdered); + bayesTree = BayesTreeOrdered(); bayesTree.insert(root); // Add the loop closure to the smoother diff --git a/gtsam_unstable/nonlinear/tests/testIncrementalFixedLagSmoother.cpp b/gtsam_unstable/nonlinear/tests/testIncrementalFixedLagSmoother.cpp index 2111f45ab..19aecc7f2 100644 --- a/gtsam_unstable/nonlinear/tests/testIncrementalFixedLagSmoother.cpp +++ b/gtsam_unstable/nonlinear/tests/testIncrementalFixedLagSmoother.cpp @@ -22,11 +22,11 @@ #include #include #include -#include +#include #include #include #include -#include +#include #include #include #include @@ -39,10 +39,10 @@ Key MakeKey(size_t index) { return Symbol('x', index); } /* ************************************************************************* */ bool check_smoother(const NonlinearFactorGraph& fullgraph, const Values& fullinit, const IncrementalFixedLagSmoother& smoother, const Key& key) { - Ordering ordering = *fullgraph.orderingCOLAMD(fullinit); - GaussianFactorGraph linearized = *fullgraph.linearize(fullinit, ordering); - GaussianBayesNet gbn = *GaussianSequentialSolver(linearized).eliminate(); - VectorValues delta = optimize(gbn); + OrderingOrdered ordering = *fullgraph.orderingCOLAMD(fullinit); + GaussianFactorGraphOrdered linearized = *fullgraph.linearize(fullinit, ordering); + GaussianBayesNetOrdered gbn = *GaussianSequentialSolver(linearized).eliminate(); + VectorValuesOrdered delta = optimize(gbn); Values fullfinal = fullinit.retract(delta, ordering); Point2 expected = fullfinal.at(key); diff --git a/gtsam_unstable/nonlinear/tests/testLinearizedFactor.cpp b/gtsam_unstable/nonlinear/tests/testLinearizedFactor.cpp index 66ed5f5c1..a1c70c4e5 100644 --- a/gtsam_unstable/nonlinear/tests/testLinearizedFactor.cpp +++ b/gtsam_unstable/nonlinear/tests/testLinearizedFactor.cpp @@ -33,7 +33,7 @@ TEST( LinearizedFactor, equals_jacobian ) // Create a Between Factor from a Point3. This is actually a linear factor. Key x1(1); Key x2(2); - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(x1); ordering.push_back(x2); Values values; @@ -46,7 +46,7 @@ TEST( LinearizedFactor, equals_jacobian ) // Create two identical factors and make sure they're equal - JacobianFactor::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); + JacobianFactorOrdered::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); LinearizedJacobianFactor jacobian1(jf, ordering, values); LinearizedJacobianFactor jacobian2(jf, ordering, values); @@ -59,7 +59,7 @@ TEST( LinearizedFactor, clone_jacobian ) // Create a Between Factor from a Point3. This is actually a linear factor. Key x1(1); Key x2(2); - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(x1); ordering.push_back(x2); Values values; @@ -71,13 +71,13 @@ TEST( LinearizedFactor, clone_jacobian ) BetweenFactor betweenFactor(x1, x2, measured, model); // Create one factor that is a clone of the other and make sure they're equal - JacobianFactor::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); + JacobianFactorOrdered::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); LinearizedJacobianFactor jacobian1(jf, ordering, values); LinearizedJacobianFactor::shared_ptr jacobian2 = boost::static_pointer_cast(jacobian1.clone()); CHECK(assert_equal(jacobian1, *jacobian2)); - JacobianFactor::shared_ptr jf1 = boost::static_pointer_cast(jacobian1.linearize(values, ordering)); - JacobianFactor::shared_ptr jf2 = boost::static_pointer_cast(jacobian2->linearize(values, ordering)); + JacobianFactorOrdered::shared_ptr jf1 = boost::static_pointer_cast(jacobian1.linearize(values, ordering)); + JacobianFactorOrdered::shared_ptr jf2 = boost::static_pointer_cast(jacobian2->linearize(values, ordering)); CHECK(assert_equal(*jf1, *jf2)); Matrix information1 = jf1->augmentedInformation(); @@ -91,7 +91,7 @@ TEST( LinearizedFactor, add_jacobian ) // Create a Between Factor from a Point3. This is actually a linear factor. Key x1(1); Key x2(2); - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(x1); ordering.push_back(x2); Values values; @@ -103,7 +103,7 @@ TEST( LinearizedFactor, add_jacobian ) BetweenFactor betweenFactor(x1, x2, measured, model); // Create two factor graphs, one using 'push_back' and one using 'add' and make sure they're equal - JacobianFactor::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); + JacobianFactorOrdered::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); LinearizedJacobianFactor::shared_ptr jacobian(new LinearizedJacobianFactor(jf, ordering, values)); NonlinearFactorGraph graph1; graph1.push_back(jacobian); NonlinearFactorGraph graph2; graph2.add(*jacobian); @@ -120,7 +120,7 @@ TEST( LinearizedFactor, add_jacobian ) // // Create a Between Factor from a Point3. This is actually a linear factor. // Key key1(1); // Key key2(2); -// Ordering ordering; +// OrderingOrdered ordering; // ordering.push_back(key1); // ordering.push_back(key2); // Values values; @@ -175,7 +175,7 @@ TEST( LinearizedFactor, equals_hessian ) // Create a Between Factor from a Point3. This is actually a linear factor. Key x1(1); Key x2(2); - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(x1); ordering.push_back(x2); Values values; @@ -188,8 +188,8 @@ TEST( LinearizedFactor, equals_hessian ) // Create two identical factors and make sure they're equal - JacobianFactor::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); - HessianFactor::shared_ptr hf(new HessianFactor(*jf)); + JacobianFactorOrdered::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); + HessianFactorOrdered::shared_ptr hf(new HessianFactorOrdered(*jf)); LinearizedHessianFactor hessian1(hf, ordering, values); LinearizedHessianFactor hessian2(hf, ordering, values); @@ -202,7 +202,7 @@ TEST( LinearizedFactor, clone_hessian ) // Create a Between Factor from a Point3. This is actually a linear factor. Key x1(1); Key x2(2); - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(x1); ordering.push_back(x2); Values values; @@ -215,8 +215,8 @@ TEST( LinearizedFactor, clone_hessian ) // Create two identical factors and make sure they're equal - JacobianFactor::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); - HessianFactor::shared_ptr hf(new HessianFactor(*jf)); + JacobianFactorOrdered::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); + HessianFactorOrdered::shared_ptr hf(new HessianFactorOrdered(*jf)); LinearizedHessianFactor hessian1(hf, ordering, values); LinearizedHessianFactor::shared_ptr hessian2 = boost::static_pointer_cast(hessian1.clone()); @@ -229,7 +229,7 @@ TEST( LinearizedFactor, add_hessian ) // Create a Between Factor from a Point3. This is actually a linear factor. Key x1(1); Key x2(2); - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(x1); ordering.push_back(x2); Values values; @@ -242,8 +242,8 @@ TEST( LinearizedFactor, add_hessian ) // Create two identical factors and make sure they're equal - JacobianFactor::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); - HessianFactor::shared_ptr hf(new HessianFactor(*jf)); + JacobianFactorOrdered::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); + HessianFactorOrdered::shared_ptr hf(new HessianFactorOrdered(*jf)); LinearizedHessianFactor::shared_ptr hessian(new LinearizedHessianFactor(hf, ordering, values)); NonlinearFactorGraph graph1; graph1.push_back(hessian); NonlinearFactorGraph graph2; graph2.add(*hessian); @@ -257,7 +257,7 @@ TEST( LinearizedFactor, add_hessian ) // // Create a Between Factor from a Point3. This is actually a linear factor. // Key key1(1); // Key key2(2); -// Ordering ordering; +// OrderingOrdered ordering; // ordering.push_back(key1); // ordering.push_back(key2); // Values values; @@ -271,7 +271,7 @@ TEST( LinearizedFactor, add_hessian ) // // // Create a linearized hessian factor // JacobianFactor::shared_ptr jf = boost::static_pointer_cast(betweenFactor.linearize(values, ordering)); -// HessianFactor::shared_ptr hf(new HessianFactor(*jf)); +// HessianFactorOrdered::shared_ptr hf(new HessianFactorOrdered(*jf)); // LinearizedHessianFactor hessian(hf, ordering, values); // // @@ -294,7 +294,7 @@ TEST( LinearizedFactor, add_hessian ) // EXPECT_DOUBLES_EQUAL(expected_error, actual_error, 1e-9 ); // // // Check that the linearized factors are identical -// GaussianFactor::shared_ptr expected_factor = HessianFactor::shared_ptr(new HessianFactor(*betweenFactor.linearize(linpoint, ordering))); +// GaussianFactor::shared_ptr expected_factor = HessianFactorOrdered::shared_ptr(new HessianFactorOrdered(*betweenFactor.linearize(linpoint, ordering))); // GaussianFactor::shared_ptr actual_factor = hessian.linearize(linpoint, ordering); // CHECK(assert_equal(*expected_factor, *actual_factor)); // } diff --git a/gtsam_unstable/slam/DummyFactor.cpp b/gtsam_unstable/slam/DummyFactor.cpp index 6f4b3b109..1f76fcb73 100644 --- a/gtsam_unstable/slam/DummyFactor.cpp +++ b/gtsam_unstable/slam/DummyFactor.cpp @@ -37,11 +37,11 @@ bool DummyFactor::equals(const NonlinearFactor& f, double tol) const { } /* ************************************************************************* */ -boost::shared_ptr -DummyFactor::linearize(const Values& c, const Ordering& ordering) const { +boost::shared_ptr +DummyFactor::linearize(const Values& c, const OrderingOrdered& ordering) const { // Only linearize if the factor is active if (!this->active(c)) - return boost::shared_ptr(); + return boost::shared_ptr(); // Fill in terms with zero matrices std::vector > terms(this->size()); @@ -51,8 +51,8 @@ DummyFactor::linearize(const Values& c, const Ordering& ordering) const { } noiseModel::Diagonal::shared_ptr model = noiseModel::Unit::Create(rowDim_); - return GaussianFactor::shared_ptr( - new JacobianFactor(terms, zero(rowDim_), model)); + return GaussianFactorOrdered::shared_ptr( + new JacobianFactorOrdered(terms, zero(rowDim_), model)); } /* ************************************************************************* */ diff --git a/gtsam_unstable/slam/DummyFactor.h b/gtsam_unstable/slam/DummyFactor.h index d2ea2567f..bed3819ba 100644 --- a/gtsam_unstable/slam/DummyFactor.h +++ b/gtsam_unstable/slam/DummyFactor.h @@ -54,8 +54,8 @@ public: virtual size_t dim() const { return rowDim_; } /** linearize to a GaussianFactor */ - virtual boost::shared_ptr - linearize(const Values& c, const Ordering& ordering) const; + virtual boost::shared_ptr + linearize(const Values& c, const OrderingOrdered& ordering) const; /** * Creates a shared_ptr clone of the factor - needs to be specialized to allow diff --git a/gtsam_unstable/slam/SmartRangeFactor.h b/gtsam_unstable/slam/SmartRangeFactor.h index c2a43b019..9f5d9413a 100644 --- a/gtsam_unstable/slam/SmartRangeFactor.h +++ b/gtsam_unstable/slam/SmartRangeFactor.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/gtsam_unstable/slam/tests/testDummyFactor.cpp b/gtsam_unstable/slam/tests/testDummyFactor.cpp index c6a1c8bd3..407d5c469 100644 --- a/gtsam_unstable/slam/tests/testDummyFactor.cpp +++ b/gtsam_unstable/slam/tests/testDummyFactor.cpp @@ -41,14 +41,14 @@ TEST( testDummyFactor, basics ) { // errors - all zeros DOUBLES_EQUAL(0.0, dummyfactor.error(c), tol); - Ordering ordering; + OrderingOrdered ordering; ordering += key1, key2; // linearization: all zeros - GaussianFactor::shared_ptr actLinearization = dummyfactor.linearize(c, ordering); + GaussianFactorOrdered::shared_ptr actLinearization = dummyfactor.linearize(c, ordering); CHECK(actLinearization); noiseModel::Diagonal::shared_ptr model3 = noiseModel::Unit::Create(3); - GaussianFactor::shared_ptr expLinearization(new JacobianFactor( + GaussianFactorOrdered::shared_ptr expLinearization(new JacobianFactorOrdered( ordering[key1], zeros(3,3), ordering[key2], zeros(3,3), zero(3), model3)); EXPECT(assert_equal(*expLinearization, *actLinearization, tol)); } diff --git a/tests/simulated3D.h b/tests/simulated3D.h index 46945558a..462873ea1 100644 --- a/tests/simulated3D.h +++ b/tests/simulated3D.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include // \namespace diff --git a/tests/smallExample.h b/tests/smallExample.h index eb87e84e2..1a1c17fce 100644 --- a/tests/smallExample.h +++ b/tests/smallExample.h @@ -45,7 +45,7 @@ Graph createNonlinearFactorGraph(); Values createValues(); /** Vector Values equivalent */ -VectorValues createVectorValues(); +VectorValuesOrdered createVectorValues(); /** * create a noisy values structure for a nonlinear factor graph @@ -56,23 +56,23 @@ Values createNoisyValues(); /** * Zero delta config */ -VectorValues createZeroDelta(const Ordering& ordering); +VectorValuesOrdered createZeroDelta(const OrderingOrdered& ordering); /** * Delta config that, when added to noisyValues, returns the ground truth */ -VectorValues createCorrectDelta(const Ordering& ordering); +VectorValuesOrdered createCorrectDelta(const OrderingOrdered& ordering); /** * create a linear factor graph * The non-linear graph above evaluated at NoisyValues */ -GaussianFactorGraph createGaussianFactorGraph(const Ordering& ordering); +GaussianFactorGraphOrdered createGaussianFactorGraph(const OrderingOrdered& ordering); /** * create small Chordal Bayes Net x <- y */ -GaussianBayesNet createSmallGaussianBayesNet(); +GaussianBayesNetOrdered createSmallGaussianBayesNet(); /** * Create really non-linear factor graph (cos/sin) @@ -91,7 +91,7 @@ std::pair createNonlinearSmoother(int T); * Create a Kalman smoother by linearizing a non-linear factor graph * @param T number of time-steps */ -std::pair, Ordering> createSmoother(int T, boost::optional ordering = boost::none); +std::pair, OrderingOrdered> createSmoother(int T, boost::optional ordering = boost::none); /* ******************************************************* */ // Linear Constrained Examples @@ -101,22 +101,22 @@ std::pair, Ordering> createSmoother(int T, boost::op * Creates a simple constrained graph with one linear factor and * one binary equality constraint that sets x = y */ -GaussianFactorGraph createSimpleConstraintGraph(); -VectorValues createSimpleConstraintValues(); +GaussianFactorGraphOrdered createSimpleConstraintGraph(); +VectorValuesOrdered createSimpleConstraintValues(); /** * Creates a simple constrained graph with one linear factor and * one binary constraint. */ -GaussianFactorGraph createSingleConstraintGraph(); -VectorValues createSingleConstraintValues(); +GaussianFactorGraphOrdered createSingleConstraintGraph(); +VectorValuesOrdered createSingleConstraintValues(); /** * Creates a constrained graph with a linear factor and two * binary constraints that share a node */ -GaussianFactorGraph createMultiConstraintGraph(); -VectorValues createMultiConstraintValues(); +GaussianFactorGraphOrdered createMultiConstraintGraph(); +VectorValuesOrdered createMultiConstraintValues(); /* ******************************************************* */ // Planar graph with easy subtree for SubgraphPreconditioner @@ -131,14 +131,14 @@ VectorValues createMultiConstraintValues(); * -x11-x21-x31 * with x11 clamped at (1,1), and others related by 2D odometry. */ -boost::tuple planarGraph(size_t N); +boost::tuple planarGraph(size_t N); /* * Create canonical ordering for planar graph that also works for tree * With x11 the root, e.g. for N=3 * x33 x23 x13 x32 x22 x12 x31 x21 x11 */ -Ordering planarOrdering(size_t N); +OrderingOrdered planarOrdering(size_t N); /* * Split graph into tree and loop closing constraints, e.g., with N=3 @@ -148,8 +148,8 @@ Ordering planarOrdering(size_t N); * | * -x11-x21-x31 */ -std::pair splitOffPlanarTree( - size_t N, const GaussianFactorGraph& original); +std::pair splitOffPlanarTree( + size_t N, const GaussianFactorGraphOrdered& original); @@ -219,9 +219,9 @@ Values createValues() { } /* ************************************************************************* */ -VectorValues createVectorValues() { +VectorValuesOrdered createVectorValues() { using namespace impl; - VectorValues c(std::vector(3, 2)); + VectorValuesOrdered c(std::vector(3, 2)); c[_l1_] = Vector_(2, 0.0, -1.0); c[_x1_] = Vector_(2, 0.0, 0.0); c[_x2_] = Vector_(2, 1.5, 0.0); @@ -245,10 +245,10 @@ Values createNoisyValues() { } /* ************************************************************************* */ -VectorValues createCorrectDelta(const Ordering& ordering) { +VectorValuesOrdered createCorrectDelta(const OrderingOrdered& ordering) { using symbol_shorthand::X; using symbol_shorthand::L; - VectorValues c(std::vector(3,2)); + VectorValuesOrdered c(std::vector(3,2)); c[ordering[L(1)]] = Vector_(2, -0.1, 0.1); c[ordering[X(1)]] = Vector_(2, -0.1, -0.1); c[ordering[X(2)]] = Vector_(2, 0.1, -0.2); @@ -256,10 +256,10 @@ VectorValues createCorrectDelta(const Ordering& ordering) { } /* ************************************************************************* */ -VectorValues createZeroDelta(const Ordering& ordering) { +VectorValuesOrdered createZeroDelta(const OrderingOrdered& ordering) { using symbol_shorthand::X; using symbol_shorthand::L; - VectorValues c(std::vector(3,2)); + VectorValuesOrdered c(std::vector(3,2)); c[ordering[L(1)]] = zero(2); c[ordering[X(1)]] = zero(2); c[ordering[X(2)]] = zero(2); @@ -267,25 +267,25 @@ VectorValues createZeroDelta(const Ordering& ordering) { } /* ************************************************************************* */ -GaussianFactorGraph createGaussianFactorGraph(const Ordering& ordering) { +GaussianFactorGraphOrdered createGaussianFactorGraph(const OrderingOrdered& ordering) { using symbol_shorthand::X; using symbol_shorthand::L; // Create empty graph - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; SharedDiagonal unit2 = noiseModel::Unit::Create(2); // linearized prior on x1: c[_x1_]+x1=0 i.e. x1=-c[_x1_] - fg.push_back(boost::make_shared(ordering[X(1)], 10*eye(2), -1.0*ones(2), unit2)); + fg.push_back(boost::make_shared(ordering[X(1)], 10*eye(2), -1.0*ones(2), unit2)); // odometry between x1 and x2: x2-x1=[0.2;-0.1] - fg.push_back(boost::make_shared(ordering[X(1)], -10*eye(2),ordering[X(2)], 10*eye(2), Vector_(2, 2.0, -1.0), unit2)); + fg.push_back(boost::make_shared(ordering[X(1)], -10*eye(2),ordering[X(2)], 10*eye(2), Vector_(2, 2.0, -1.0), unit2)); // measurement between x1 and l1: l1-x1=[0.0;0.2] - fg.push_back(boost::make_shared(ordering[X(1)], -5*eye(2), ordering[L(1)], 5*eye(2), Vector_(2, 0.0, 1.0), unit2)); + fg.push_back(boost::make_shared(ordering[X(1)], -5*eye(2), ordering[L(1)], 5*eye(2), Vector_(2, 0.0, 1.0), unit2)); // measurement between x2 and l1: l1-x2=[-0.2;0.3] - fg.push_back(boost::make_shared(ordering[X(2)], -5*eye(2), ordering[L(1)], 5*eye(2), Vector_(2, -1.0, 1.5), unit2)); + fg.push_back(boost::make_shared(ordering[X(2)], -5*eye(2), ordering[L(1)], 5*eye(2), Vector_(2, -1.0, 1.5), unit2)); return fg; } @@ -296,7 +296,7 @@ GaussianFactorGraph createGaussianFactorGraph(const Ordering& ordering) { * 1 1 9 * 1 5 */ -GaussianBayesNet createSmallGaussianBayesNet() { +GaussianBayesNetOrdered createSmallGaussianBayesNet() { using namespace impl; Matrix R11 = Matrix_(1, 1, 1.0), S12 = Matrix_(1, 1, 1.0); Matrix R22 = Matrix_(1, 1, 1.0); @@ -307,9 +307,9 @@ GaussianBayesNet createSmallGaussianBayesNet() { tau(0) = 1.0; // define nodes and specify in reverse topological sort (i.e. parents last) - GaussianConditional::shared_ptr Px_y(new GaussianConditional(_x_, d1, R11, _y_, S12, tau)); - GaussianConditional::shared_ptr Py(new GaussianConditional(_y_, d2, R22, tau)); - GaussianBayesNet cbn; + GaussianConditionalOrdered::shared_ptr Px_y(new GaussianConditionalOrdered(_x_, d1, R11, _y_, S12, tau)); + GaussianConditionalOrdered::shared_ptr Py(new GaussianConditionalOrdered(_y_, d2, R22, tau)); + GaussianBayesNetOrdered cbn; cbn.push_back(Px_y); cbn.push_back(Py); @@ -400,7 +400,7 @@ std::pair createNonlinearSmoother(int T) { } /* ************************************************************************* */ -std::pair, Ordering> createSmoother(int T, boost::optional ordering) { +std::pair, OrderingOrdered> createSmoother(int T, boost::optional ordering) { Graph nlfg; Values poses; boost::tie(nlfg, poses) = createNonlinearSmoother(T); @@ -410,7 +410,7 @@ std::pair, Ordering> createSmoother(int T, boost::op } /* ************************************************************************* */ -GaussianFactorGraph createSimpleConstraintGraph() { +GaussianFactorGraphOrdered createSimpleConstraintGraph() { using namespace impl; // create unary factor // prior on _x_, mean = [1,-1], sigma=0.1 @@ -418,7 +418,7 @@ GaussianFactorGraph createSimpleConstraintGraph() { Vector b1(2); b1(0) = 1.0; b1(1) = -1.0; - JacobianFactor::shared_ptr f1(new JacobianFactor(_x_, Ax, b1, sigma0_1)); + JacobianFactorOrdered::shared_ptr f1(new JacobianFactorOrdered(_x_, Ax, b1, sigma0_1)); // create binary constraint factor // between _x_ and _y_, that is going to be the only factor on _y_ @@ -427,11 +427,11 @@ GaussianFactorGraph createSimpleConstraintGraph() { Matrix Ax1 = eye(2); Matrix Ay1 = eye(2) * -1; Vector b2 = Vector_(2, 0.0, 0.0); - JacobianFactor::shared_ptr f2(new JacobianFactor(_x_, Ax1, _y_, Ay1, b2, + JacobianFactorOrdered::shared_ptr f2(new JacobianFactorOrdered(_x_, Ax1, _y_, Ay1, b2, constraintModel)); // construct the graph - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; fg.push_back(f1); fg.push_back(f2); @@ -439,11 +439,11 @@ GaussianFactorGraph createSimpleConstraintGraph() { } /* ************************************************************************* */ -VectorValues createSimpleConstraintValues() { +VectorValuesOrdered createSimpleConstraintValues() { using namespace impl; using symbol_shorthand::X; using symbol_shorthand::L; - VectorValues config(std::vector(2,2)); + VectorValuesOrdered config(std::vector(2,2)); Vector v = Vector_(2, 1.0, -1.0); config[_x_] = v; config[_y_] = v; @@ -451,7 +451,7 @@ VectorValues createSimpleConstraintValues() { } /* ************************************************************************* */ -GaussianFactorGraph createSingleConstraintGraph() { +GaussianFactorGraphOrdered createSingleConstraintGraph() { using namespace impl; // create unary factor // prior on _x_, mean = [1,-1], sigma=0.1 @@ -459,8 +459,8 @@ GaussianFactorGraph createSingleConstraintGraph() { Vector b1(2); b1(0) = 1.0; b1(1) = -1.0; - //GaussianFactor::shared_ptr f1(new JacobianFactor(_x_, sigma0_1->Whiten(Ax), sigma0_1->whiten(b1), sigma0_1)); - JacobianFactor::shared_ptr f1(new JacobianFactor(_x_, Ax, b1, sigma0_1)); + //GaussianFactorOrdered::shared_ptr f1(new JacobianFactor(_x_, sigma0_1->Whiten(Ax), sigma0_1->whiten(b1), sigma0_1)); + JacobianFactorOrdered::shared_ptr f1(new JacobianFactorOrdered(_x_, Ax, b1, sigma0_1)); // create binary constraint factor // between _x_ and _y_, that is going to be the only factor on _y_ @@ -473,11 +473,11 @@ GaussianFactorGraph createSingleConstraintGraph() { Ax1(1, 1) = 1.0; Matrix Ay1 = eye(2) * 10; Vector b2 = Vector_(2, 1.0, 2.0); - JacobianFactor::shared_ptr f2(new JacobianFactor(_x_, Ax1, _y_, Ay1, b2, + JacobianFactorOrdered::shared_ptr f2(new JacobianFactorOrdered(_x_, Ax1, _y_, Ay1, b2, constraintModel)); // construct the graph - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; fg.push_back(f1); fg.push_back(f2); @@ -485,21 +485,21 @@ GaussianFactorGraph createSingleConstraintGraph() { } /* ************************************************************************* */ -VectorValues createSingleConstraintValues() { +VectorValuesOrdered createSingleConstraintValues() { using namespace impl; - VectorValues config(std::vector(2,2)); + VectorValuesOrdered config(std::vector(2,2)); config[_x_] = Vector_(2, 1.0, -1.0); config[_y_] = Vector_(2, 0.2, 0.1); return config; } /* ************************************************************************* */ -GaussianFactorGraph createMultiConstraintGraph() { +GaussianFactorGraphOrdered createMultiConstraintGraph() { using namespace impl; // unary factor 1 Matrix A = eye(2); Vector b = Vector_(2, -2.0, 2.0); - JacobianFactor::shared_ptr lf1(new JacobianFactor(_x_, A, b, sigma0_1)); + JacobianFactorOrdered::shared_ptr lf1(new JacobianFactorOrdered(_x_, A, b, sigma0_1)); // constraint 1 Matrix A11(2, 2); @@ -517,7 +517,7 @@ GaussianFactorGraph createMultiConstraintGraph() { Vector b1(2); b1(0) = 1.0; b1(1) = 2.0; - JacobianFactor::shared_ptr lc1(new JacobianFactor(_x_, A11, _y_, A12, b1, + JacobianFactorOrdered::shared_ptr lc1(new JacobianFactorOrdered(_x_, A11, _y_, A12, b1, constraintModel)); // constraint 2 @@ -536,11 +536,11 @@ GaussianFactorGraph createMultiConstraintGraph() { Vector b2(2); b2(0) = 3.0; b2(1) = 4.0; - JacobianFactor::shared_ptr lc2(new JacobianFactor(_x_, A21, _z_, A22, b2, + JacobianFactorOrdered::shared_ptr lc2(new JacobianFactorOrdered(_x_, A21, _z_, A22, b2, constraintModel)); // construct the graph - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; fg.push_back(lf1); fg.push_back(lc1); fg.push_back(lc2); @@ -549,9 +549,9 @@ GaussianFactorGraph createMultiConstraintGraph() { } /* ************************************************************************* */ -VectorValues createMultiConstraintValues() { +VectorValuesOrdered createMultiConstraintValues() { using namespace impl; - VectorValues config(std::vector(3,2)); + VectorValuesOrdered config(std::vector(3,2)); config[_x_] = Vector_(2, -2.0, 2.0); config[_y_] = Vector_(2, -0.1, 0.4); config[_z_] = Vector_(2, -4.0, 5.0); @@ -568,7 +568,7 @@ Symbol key(int x, int y) { } // \namespace impl /* ************************************************************************* */ -boost::tuple planarGraph(size_t N) { +boost::tuple planarGraph(size_t N) { using namespace impl; // create empty graph @@ -599,20 +599,20 @@ boost::tuple planarGraph(size_t N) { for (size_t x = 1; x <= N; x++) for (size_t y = 1; y <= N; y++) zeros.insert(key(x, y), Point2()); - Ordering ordering(planarOrdering(N)); - VectorValues xtrue(zeros.dims(ordering)); + OrderingOrdered ordering(planarOrdering(N)); + VectorValuesOrdered xtrue(zeros.dims(ordering)); for (size_t x = 1; x <= N; x++) for (size_t y = 1; y <= N; y++) xtrue[ordering[key(x, y)]] = Point2(x,y).vector(); // linearize around zero - boost::shared_ptr gfg = nlfg.linearize(zeros, ordering); + boost::shared_ptr gfg = nlfg.linearize(zeros, ordering); return boost::make_tuple(*gfg, xtrue); } /* ************************************************************************* */ -Ordering planarOrdering(size_t N) { - Ordering ordering; +OrderingOrdered planarOrdering(size_t N) { + OrderingOrdered ordering; for (size_t y = N; y >= 1; y--) for (size_t x = N; x >= 1; x--) ordering.push_back(impl::key(x, y)); @@ -620,9 +620,9 @@ Ordering planarOrdering(size_t N) { } /* ************************************************************************* */ -std::pair splitOffPlanarTree(size_t N, - const GaussianFactorGraph& original) { - GaussianFactorGraph T, C; +std::pair splitOffPlanarTree(size_t N, + const GaussianFactorGraphOrdered& original) { + GaussianFactorGraphOrdered T, C; // Add the x11 constraint to the tree T.push_back(original[0]); diff --git a/tests/testBoundingConstraint.cpp b/tests/testBoundingConstraint.cpp index 516b7e070..06d343e6e 100644 --- a/tests/testBoundingConstraint.cpp +++ b/tests/testBoundingConstraint.cpp @@ -116,10 +116,10 @@ TEST( testBoundingConstraint, unary_linearization_inactive) { Point2 pt1(2.0, 3.0); Values config1; config1.insert(key, pt1); - Ordering ordering; + OrderingOrdered ordering; ordering += key; - GaussianFactor::shared_ptr actual1 = constraint1.linearize(config1, ordering); - GaussianFactor::shared_ptr actual2 = constraint2.linearize(config1, ordering); + GaussianFactorOrdered::shared_ptr actual1 = constraint1.linearize(config1, ordering); + GaussianFactorOrdered::shared_ptr actual2 = constraint2.linearize(config1, ordering); EXPECT(!actual1); EXPECT(!actual2); } @@ -129,14 +129,14 @@ TEST( testBoundingConstraint, unary_linearization_active) { Point2 pt2(-2.0, -3.0); Values config2; config2.insert(key, pt2); - Ordering ordering; + OrderingOrdered ordering; ordering += key; - GaussianFactor::shared_ptr actual1 = constraint1.linearize(config2, ordering); - GaussianFactor::shared_ptr actual2 = constraint2.linearize(config2, ordering); - JacobianFactor expected1(ordering[key], Matrix_(1, 2, 1.0, 0.0), repeat(1, 3.0), hard_model1); - JacobianFactor expected2(ordering[key], Matrix_(1, 2, 0.0, 1.0), repeat(1, 5.0), hard_model1); - EXPECT(assert_equal((const GaussianFactor&)expected1, *actual1, tol)); - EXPECT(assert_equal((const GaussianFactor&)expected2, *actual2, tol)); + GaussianFactorOrdered::shared_ptr actual1 = constraint1.linearize(config2, ordering); + GaussianFactorOrdered::shared_ptr actual2 = constraint2.linearize(config2, ordering); + JacobianFactorOrdered expected1(ordering[key], Matrix_(1, 2, 1.0, 0.0), repeat(1, 3.0), hard_model1); + JacobianFactorOrdered expected2(ordering[key], Matrix_(1, 2, 0.0, 1.0), repeat(1, 5.0), hard_model1); + EXPECT(assert_equal((const GaussianFactorOrdered&)expected1, *actual1, tol)); + EXPECT(assert_equal((const GaussianFactorOrdered&)expected2, *actual2, tol)); } /* ************************************************************************* */ @@ -199,7 +199,7 @@ TEST( testBoundingConstraint, MaxDistance_basics) { Values config1; config1.insert(key1, pt1); config1.insert(key2, pt1); - Ordering ordering; ordering += key1, key2; + OrderingOrdered ordering; ordering += key1, key2; EXPECT(!rangeBound.active(config1)); EXPECT(assert_equal(zero(1), rangeBound.unwhitenedError(config1))); EXPECT(!rangeBound.linearize(config1, ordering)); diff --git a/tests/testDoglegOptimizer.cpp b/tests/testDoglegOptimizer.cpp index 008ea443a..1a5fb77e6 100644 --- a/tests/testDoglegOptimizer.cpp +++ b/tests/testDoglegOptimizer.cpp @@ -18,10 +18,10 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include #include #include @@ -46,28 +46,28 @@ using symbol_shorthand::X; using symbol_shorthand::L; /* ************************************************************************* */ -double computeError(const GaussianBayesNet& gbn, const LieVector& values) { +double computeError(const GaussianBayesNetOrdered& gbn, const LieVector& values) { // Convert Vector to VectorValues - VectorValues vv = *allocateVectorValues(gbn); + VectorValuesOrdered vv = *allocateVectorValues(gbn); internal::writeVectorValuesSlices(values, vv, boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(vv.size())); // Convert to factor graph - GaussianFactorGraph gfg(gbn); + GaussianFactorGraphOrdered gfg(gbn); return gfg.error(vv); } /* ************************************************************************* */ -double computeErrorBt(const BayesTree& gbt, const LieVector& values) { +double computeErrorBt(const BayesTreeOrdered& gbt, const LieVector& values) { // Convert Vector to VectorValues - VectorValues vv = *allocateVectorValues(gbt); + VectorValuesOrdered vv = *allocateVectorValues(gbt); internal::writeVectorValuesSlices(values, vv, boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(vv.size())); // Convert to factor graph - GaussianFactorGraph gfg(gbt); + GaussianFactorGraphOrdered gfg(gbt); return gfg.error(vv); } @@ -75,58 +75,58 @@ double computeErrorBt(const BayesTree& gbt, const LieVector TEST(DoglegOptimizer, ComputeSteepestDescentPoint) { // Create an arbitrary Bayes Net - GaussianBayesNet gbn; - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + GaussianBayesNetOrdered gbn; + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 0, Vector_(2, 1.0,2.0), Matrix_(2,2, 3.0,4.0,0.0,6.0), 3, Matrix_(2,2, 7.0,8.0,9.0,10.0), 4, Matrix_(2,2, 11.0,12.0,13.0,14.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 1, Vector_(2, 15.0,16.0), Matrix_(2,2, 17.0,18.0,0.0,20.0), 2, Matrix_(2,2, 21.0,22.0,23.0,24.0), 4, Matrix_(2,2, 25.0,26.0,27.0,28.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 2, Vector_(2, 29.0,30.0), Matrix_(2,2, 31.0,32.0,0.0,34.0), 3, Matrix_(2,2, 35.0,36.0,37.0,38.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 3, Vector_(2, 39.0,40.0), Matrix_(2,2, 41.0,42.0,0.0,44.0), 4, Matrix_(2,2, 45.0,46.0,47.0,48.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 4, Vector_(2, 49.0,50.0), Matrix_(2,2, 51.0,52.0,0.0,54.0), ones(2))); // Compute the Hessian numerically Matrix hessian = numericalHessian( boost::function(boost::bind(&computeError, gbn, _1)), - LieVector(VectorValues::Zero(*allocateVectorValues(gbn)).asVector())); + LieVector(VectorValuesOrdered::Zero(*allocateVectorValues(gbn)).asVector())); // Compute the gradient numerically - VectorValues gradientValues = *allocateVectorValues(gbn); + VectorValuesOrdered gradientValues = *allocateVectorValues(gbn); Vector gradient = numericalGradient( boost::function(boost::bind(&computeError, gbn, _1)), - LieVector(VectorValues::Zero(gradientValues).asVector())); + LieVector(VectorValuesOrdered::Zero(gradientValues).asVector())); internal::writeVectorValuesSlices(gradient, gradientValues, boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(gradientValues.size())); // Compute the gradient using dense matrices - Matrix augmentedHessian = GaussianFactorGraph(gbn).augmentedHessian(); + Matrix augmentedHessian = GaussianFactorGraphOrdered(gbn).augmentedHessian(); LONGS_EQUAL(11, augmentedHessian.cols()); - VectorValues denseMatrixGradient = *allocateVectorValues(gbn); + VectorValuesOrdered denseMatrixGradient = *allocateVectorValues(gbn); internal::writeVectorValuesSlices(-augmentedHessian.col(10).segment(0,10), denseMatrixGradient, boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(gradientValues.size())); EXPECT(assert_equal(gradientValues, denseMatrixGradient, 1e-5)); // Compute the steepest descent point double step = -gradient.squaredNorm() / (gradient.transpose() * hessian * gradient)(0); - VectorValues expected = gradientValues; scal(step, expected); + VectorValuesOrdered expected = gradientValues; scal(step, expected); // Compute the steepest descent point with the dogleg function - VectorValues actual = optimizeGradientSearch(gbn); + VectorValuesOrdered actual = optimizeGradientSearch(gbn); // Check that points agree EXPECT(assert_equal(expected, actual, 1e-5)); // Check that point causes a decrease in error - double origError = GaussianFactorGraph(gbn).error(VectorValues::Zero(*allocateVectorValues(gbn))); - double newError = GaussianFactorGraph(gbn).error(actual); + double origError = GaussianFactorGraphOrdered(gbn).error(VectorValuesOrdered::Zero(*allocateVectorValues(gbn))); + double newError = GaussianFactorGraphOrdered(gbn).error(actual); EXPECT(newError < origError); } @@ -134,9 +134,9 @@ TEST(DoglegOptimizer, ComputeSteepestDescentPoint) { TEST(DoglegOptimizer, BT_BN_equivalency) { // Create an arbitrary Bayes Tree - BayesTree bt; - bt.insert(BayesTree::sharedClique(new BayesTree::Clique( - GaussianConditional::shared_ptr(new GaussianConditional( + BayesTreeOrdered bt; + bt.insert(BayesTreeOrdered::sharedClique(new BayesTreeOrdered::Clique( + GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( boost::assign::pair_list_of (2, Matrix_(6,2, 31.0,32.0, @@ -160,8 +160,8 @@ TEST(DoglegOptimizer, BT_BN_equivalency) { 51.0,52.0, 0.0,54.0)), 3, Vector_(6, 29.0,30.0,39.0,40.0,49.0,50.0), ones(6)))))); - bt.insert(BayesTree::sharedClique(new BayesTree::Clique( - GaussianConditional::shared_ptr(new GaussianConditional( + bt.insert(BayesTreeOrdered::sharedClique(new BayesTreeOrdered::Clique( + GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( boost::assign::pair_list_of (0, Matrix_(4,2, 3.0,4.0, @@ -191,26 +191,26 @@ TEST(DoglegOptimizer, BT_BN_equivalency) { 2, Vector_(4, 1.0,2.0,15.0,16.0), ones(4)))))); // Create an arbitrary Bayes Net - GaussianBayesNet gbn; - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + GaussianBayesNetOrdered gbn; + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 0, Vector_(2, 1.0,2.0), Matrix_(2,2, 3.0,4.0,0.0,6.0), 3, Matrix_(2,2, 7.0,8.0,9.0,10.0), 4, Matrix_(2,2, 11.0,12.0,13.0,14.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 1, Vector_(2, 15.0,16.0), Matrix_(2,2, 17.0,18.0,0.0,20.0), 2, Matrix_(2,2, 21.0,22.0,23.0,24.0), 4, Matrix_(2,2, 25.0,26.0,27.0,28.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 2, Vector_(2, 29.0,30.0), Matrix_(2,2, 31.0,32.0,0.0,34.0), 3, Matrix_(2,2, 35.0,36.0,37.0,38.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 3, Vector_(2, 39.0,40.0), Matrix_(2,2, 41.0,42.0,0.0,44.0), 4, Matrix_(2,2, 45.0,46.0,47.0,48.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 4, Vector_(2, 49.0,50.0), Matrix_(2,2, 51.0,52.0,0.0,54.0), ones(2))); - GaussianFactorGraph expected(gbn); - GaussianFactorGraph actual(bt); + GaussianFactorGraphOrdered expected(gbn); + GaussianFactorGraphOrdered actual(bt); EXPECT(assert_equal(expected.augmentedHessian(), actual.augmentedHessian())); } @@ -219,9 +219,9 @@ TEST(DoglegOptimizer, BT_BN_equivalency) { TEST(DoglegOptimizer, ComputeSteepestDescentPointBT) { // Create an arbitrary Bayes Tree - BayesTree bt; - bt.insert(BayesTree::sharedClique(new BayesTree::Clique( - GaussianConditional::shared_ptr(new GaussianConditional( + BayesTreeOrdered bt; + bt.insert(BayesTreeOrdered::sharedClique(new BayesTreeOrdered::Clique( + GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( boost::assign::pair_list_of (2, Matrix_(6,2, 31.0,32.0, @@ -245,8 +245,8 @@ TEST(DoglegOptimizer, ComputeSteepestDescentPointBT) { 51.0,52.0, 0.0,54.0)), 3, Vector_(6, 29.0,30.0,39.0,40.0,49.0,50.0), ones(6)))))); - bt.insert(BayesTree::sharedClique(new BayesTree::Clique( - GaussianConditional::shared_ptr(new GaussianConditional( + bt.insert(BayesTreeOrdered::sharedClique(new BayesTreeOrdered::Clique( + GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( boost::assign::pair_list_of (0, Matrix_(4,2, 3.0,4.0, @@ -278,30 +278,30 @@ TEST(DoglegOptimizer, ComputeSteepestDescentPointBT) { // Compute the Hessian numerically Matrix hessian = numericalHessian( boost::function(boost::bind(&computeErrorBt, bt, _1)), - LieVector(VectorValues::Zero(*allocateVectorValues(bt)).asVector())); + LieVector(VectorValuesOrdered::Zero(*allocateVectorValues(bt)).asVector())); // Compute the gradient numerically - VectorValues gradientValues = *allocateVectorValues(bt); + VectorValuesOrdered gradientValues = *allocateVectorValues(bt); Vector gradient = numericalGradient( boost::function(boost::bind(&computeErrorBt, bt, _1)), - LieVector(VectorValues::Zero(gradientValues).asVector())); + LieVector(VectorValuesOrdered::Zero(gradientValues).asVector())); internal::writeVectorValuesSlices(gradient, gradientValues, boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(gradientValues.size())); // Compute the gradient using dense matrices - Matrix augmentedHessian = GaussianFactorGraph(bt).augmentedHessian(); + Matrix augmentedHessian = GaussianFactorGraphOrdered(bt).augmentedHessian(); LONGS_EQUAL(11, augmentedHessian.cols()); - VectorValues denseMatrixGradient = *allocateVectorValues(bt); + VectorValuesOrdered denseMatrixGradient = *allocateVectorValues(bt); internal::writeVectorValuesSlices(-augmentedHessian.col(10).segment(0,10), denseMatrixGradient, boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(gradientValues.size())); EXPECT(assert_equal(gradientValues, denseMatrixGradient, 1e-5)); // Compute the steepest descent point double step = -gradient.squaredNorm() / (gradient.transpose() * hessian * gradient)(0); - VectorValues expected = gradientValues; scal(step, expected); + VectorValuesOrdered expected = gradientValues; scal(step, expected); // Known steepest descent point from Bayes' net version - VectorValues expectedFromBN(5,2); + VectorValuesOrdered expectedFromBN(5,2); expectedFromBN[0] = Vector_(2, 0.000129034, 0.000688183); expectedFromBN[1] = Vector_(2, 0.0109679, 0.0253767); expectedFromBN[2] = Vector_(2, 0.0680441, 0.114496); @@ -309,90 +309,90 @@ TEST(DoglegOptimizer, ComputeSteepestDescentPointBT) { expectedFromBN[4] = Vector_(2, 0.300134, 0.423233); // Compute the steepest descent point with the dogleg function - VectorValues actual = optimizeGradientSearch(bt); + VectorValuesOrdered actual = optimizeGradientSearch(bt); // Check that points agree EXPECT(assert_equal(expected, actual, 1e-5)); EXPECT(assert_equal(expectedFromBN, actual, 1e-5)); // Check that point causes a decrease in error - double origError = GaussianFactorGraph(bt).error(VectorValues::Zero(*allocateVectorValues(bt))); - double newError = GaussianFactorGraph(bt).error(actual); + double origError = GaussianFactorGraphOrdered(bt).error(VectorValuesOrdered::Zero(*allocateVectorValues(bt))); + double newError = GaussianFactorGraphOrdered(bt).error(actual); EXPECT(newError < origError); } /* ************************************************************************* */ TEST(DoglegOptimizer, ComputeBlend) { // Create an arbitrary Bayes Net - GaussianBayesNet gbn; - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + GaussianBayesNetOrdered gbn; + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 0, Vector_(2, 1.0,2.0), Matrix_(2,2, 3.0,4.0,0.0,6.0), 3, Matrix_(2,2, 7.0,8.0,9.0,10.0), 4, Matrix_(2,2, 11.0,12.0,13.0,14.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 1, Vector_(2, 15.0,16.0), Matrix_(2,2, 17.0,18.0,0.0,20.0), 2, Matrix_(2,2, 21.0,22.0,23.0,24.0), 4, Matrix_(2,2, 25.0,26.0,27.0,28.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 2, Vector_(2, 29.0,30.0), Matrix_(2,2, 31.0,32.0,0.0,34.0), 3, Matrix_(2,2, 35.0,36.0,37.0,38.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 3, Vector_(2, 39.0,40.0), Matrix_(2,2, 41.0,42.0,0.0,44.0), 4, Matrix_(2,2, 45.0,46.0,47.0,48.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 4, Vector_(2, 49.0,50.0), Matrix_(2,2, 51.0,52.0,0.0,54.0), ones(2))); // Compute steepest descent point - VectorValues xu = optimizeGradientSearch(gbn); + VectorValuesOrdered xu = optimizeGradientSearch(gbn); // Compute Newton's method point - VectorValues xn = optimize(gbn); + VectorValuesOrdered xn = optimize(gbn); // The Newton's method point should be more "adventurous", i.e. larger, than the steepest descent point EXPECT(xu.asVector().norm() < xn.asVector().norm()); // Compute blend double Delta = 1.5; - VectorValues xb = DoglegOptimizerImpl::ComputeBlend(Delta, xu, xn); + VectorValuesOrdered xb = DoglegOptimizerImpl::ComputeBlend(Delta, xu, xn); DOUBLES_EQUAL(Delta, xb.asVector().norm(), 1e-10); } /* ************************************************************************* */ TEST(DoglegOptimizer, ComputeDoglegPoint) { // Create an arbitrary Bayes Net - GaussianBayesNet gbn; - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + GaussianBayesNetOrdered gbn; + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 0, Vector_(2, 1.0,2.0), Matrix_(2,2, 3.0,4.0,0.0,6.0), 3, Matrix_(2,2, 7.0,8.0,9.0,10.0), 4, Matrix_(2,2, 11.0,12.0,13.0,14.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 1, Vector_(2, 15.0,16.0), Matrix_(2,2, 17.0,18.0,0.0,20.0), 2, Matrix_(2,2, 21.0,22.0,23.0,24.0), 4, Matrix_(2,2, 25.0,26.0,27.0,28.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 2, Vector_(2, 29.0,30.0), Matrix_(2,2, 31.0,32.0,0.0,34.0), 3, Matrix_(2,2, 35.0,36.0,37.0,38.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 3, Vector_(2, 39.0,40.0), Matrix_(2,2, 41.0,42.0,0.0,44.0), 4, Matrix_(2,2, 45.0,46.0,47.0,48.0), ones(2))); - gbn += GaussianConditional::shared_ptr(new GaussianConditional( + gbn += GaussianConditionalOrdered::shared_ptr(new GaussianConditionalOrdered( 4, Vector_(2, 49.0,50.0), Matrix_(2,2, 51.0,52.0,0.0,54.0), ones(2))); // Compute dogleg point for different deltas double Delta1 = 0.5; // Less than steepest descent - VectorValues actual1 = DoglegOptimizerImpl::ComputeDoglegPoint(Delta1, optimizeGradientSearch(gbn), optimize(gbn)); + VectorValuesOrdered actual1 = DoglegOptimizerImpl::ComputeDoglegPoint(Delta1, optimizeGradientSearch(gbn), optimize(gbn)); DOUBLES_EQUAL(Delta1, actual1.asVector().norm(), 1e-5); double Delta2 = 1.5; // Between steepest descent and Newton's method - VectorValues expected2 = DoglegOptimizerImpl::ComputeBlend(Delta2, optimizeGradientSearch(gbn), optimize(gbn)); - VectorValues actual2 = DoglegOptimizerImpl::ComputeDoglegPoint(Delta2, optimizeGradientSearch(gbn), optimize(gbn)); + VectorValuesOrdered expected2 = DoglegOptimizerImpl::ComputeBlend(Delta2, optimizeGradientSearch(gbn), optimize(gbn)); + VectorValuesOrdered actual2 = DoglegOptimizerImpl::ComputeDoglegPoint(Delta2, optimizeGradientSearch(gbn), optimize(gbn)); DOUBLES_EQUAL(Delta2, actual2.asVector().norm(), 1e-5); EXPECT(assert_equal(expected2, actual2)); double Delta3 = 5.0; // Larger than Newton's method point - VectorValues expected3 = optimize(gbn); - VectorValues actual3 = DoglegOptimizerImpl::ComputeDoglegPoint(Delta3, optimizeGradientSearch(gbn), optimize(gbn)); + VectorValuesOrdered expected3 = optimize(gbn); + VectorValuesOrdered actual3 = DoglegOptimizerImpl::ComputeDoglegPoint(Delta3, optimizeGradientSearch(gbn), optimize(gbn)); EXPECT(assert_equal(expected3, actual3)); } @@ -408,16 +408,16 @@ TEST(DoglegOptimizer, Iterate) { config->insert(X(1), x0); // ordering - boost::shared_ptr ord(new Ordering()); + boost::shared_ptr ord(new OrderingOrdered()); ord->push_back(X(1)); double Delta = 1.0; for(size_t it=0; it<10; ++it) { GaussianSequentialSolver solver(*fg->linearize(*config, *ord)); - GaussianBayesNet gbn = *solver.eliminate(); + GaussianBayesNetOrdered gbn = *solver.eliminate(); // Iterate assumes that linear error = nonlinear error at the linearization point, and this should be true double nonlinearError = fg->error(*config); - double linearError = GaussianFactorGraph(gbn).error(VectorValues::Zero(*allocateVectorValues(gbn))); + double linearError = GaussianFactorGraphOrdered(gbn).error(VectorValuesOrdered::Zero(*allocateVectorValues(gbn))); DOUBLES_EQUAL(nonlinearError, linearError, 1e-5); // cout << "it " << it << ", Delta = " << Delta << ", error = " << fg->error(*config) << endl; DoglegOptimizerImpl::IterationResult result = DoglegOptimizerImpl::Iterate(Delta, DoglegOptimizerImpl::SEARCH_EACH_ITERATION, gbn, *fg, *config, *ord, fg->error(*config)); diff --git a/tests/testExtendedKalmanFilter.cpp b/tests/testExtendedKalmanFilter.cpp index 6bdfa7eee..bb79cbdea 100644 --- a/tests/testExtendedKalmanFilter.cpp +++ b/tests/testExtendedKalmanFilter.cpp @@ -192,7 +192,7 @@ public: * Ax-b \approx h(x1+dx1,x2+dx2)-z = h(x1,x2) + A2*dx1 + A2*dx2 - z * Hence b = z - h(x1,x2) = - error_vector(x) */ - boost::shared_ptr linearize(const Values& c, const Ordering& ordering) const { + boost::shared_ptr linearize(const Values& c, const OrderingOrdered& ordering) const { const X1& x1 = c.at(key1()); const X2& x2 = c.at(key2()); Matrix A1, A2; @@ -201,7 +201,7 @@ public: SharedDiagonal constrained = boost::dynamic_pointer_cast(this->noiseModel_); if (constrained.get() != NULL) { - return JacobianFactor::shared_ptr(new JacobianFactor(var1, A1, var2, + return JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(var1, A1, var2, A2, b, constrained)); } // "Whiten" the system before converting to a Gaussian Factor @@ -209,7 +209,7 @@ public: A1 = Qinvsqrt*A1; A2 = Qinvsqrt*A2; b = Qinvsqrt*b; - return GaussianFactor::shared_ptr(new JacobianFactor(var1, A1, var2, + return GaussianFactorOrdered::shared_ptr(new JacobianFactorOrdered(var1, A1, var2, A2, b, noiseModel::Unit::Create(b.size()))); } @@ -329,7 +329,7 @@ public: * Ax-b \approx h(x1+dx1)-z = h(x1) + A1*dx1 - z * Hence b = z - h(x1) = - error_vector(x) */ - boost::shared_ptr linearize(const Values& c, const Ordering& ordering) const { + boost::shared_ptr linearize(const Values& c, const OrderingOrdered& ordering) const { const X& x1 = c.at(key()); Matrix A1; Vector b = -evaluateError(x1, A1); @@ -337,13 +337,13 @@ public: SharedDiagonal constrained = boost::dynamic_pointer_cast(this->noiseModel_); if (constrained.get() != NULL) { - return JacobianFactor::shared_ptr(new JacobianFactor(var1, A1, b, constrained)); + return JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(var1, A1, b, constrained)); } // "Whiten" the system before converting to a Gaussian Factor Matrix Rinvsqrt = RInvSqrt(x1); A1 = Rinvsqrt*A1; b = Rinvsqrt*b; - return GaussianFactor::shared_ptr(new JacobianFactor(var1, A1, b, noiseModel::Unit::Create(b.size()))); + return GaussianFactorOrdered::shared_ptr(new JacobianFactorOrdered(var1, A1, b, noiseModel::Unit::Create(b.size()))); } /** vector of errors */ diff --git a/tests/testGaussianBayesNetObsolete.cpp b/tests/testGaussianBayesNetObsolete.cpp index 1cef17341..53483dd47 100644 --- a/tests/testGaussianBayesNetObsolete.cpp +++ b/tests/testGaussianBayesNetObsolete.cpp @@ -26,8 +26,8 @@ using namespace boost::assign; #include -#include -#include +#include +#include #include #include @@ -38,7 +38,7 @@ using namespace example; static const Index _x_=0, _y_=1, _z_=2; /* ************************************************************************* */ -TEST( GaussianBayesNet, constructor ) +TEST( GaussianBayesNetOrdered, constructor ) { // small Bayes Net x <- y // x y d @@ -52,19 +52,19 @@ TEST( GaussianBayesNet, constructor ) sigmas(0) = 1.; // define nodes and specify in reverse topological sort (i.e. parents last) - GaussianConditional x(_x_,d1,R11,_y_,S12, sigmas), y(_y_,d2,R22, sigmas); + GaussianConditionalOrdered x(_x_,d1,R11,_y_,S12, sigmas), y(_y_,d2,R22, sigmas); // check small example which uses constructor - GaussianBayesNet cbn = createSmallGaussianBayesNet(); + GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet(); EXPECT( x.equals(*cbn[_x_]) ); EXPECT( y.equals(*cbn[_y_]) ); } /* ************************************************************************* */ -TEST( GaussianBayesNet, matrix ) +TEST( GaussianBayesNetOrdered, matrix ) { // Create a test graph - GaussianBayesNet cbn = createSmallGaussianBayesNet(); + GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet(); Matrix R; Vector d; boost::tie(R,d) = matrix(cbn); // find matrix and RHS @@ -80,12 +80,12 @@ TEST( GaussianBayesNet, matrix ) } /* ************************************************************************* */ -TEST( GaussianBayesNet, optimize ) +TEST( GaussianBayesNetOrdered, optimize ) { - GaussianBayesNet cbn = createSmallGaussianBayesNet(); - VectorValues actual = optimize(cbn); + GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet(); + VectorValuesOrdered actual = optimize(cbn); - VectorValues expected(vector(2,1)); + VectorValuesOrdered expected(vector(2,1)); expected[_x_] = Vector_(1,4.); expected[_y_] = Vector_(1,5.); @@ -93,11 +93,11 @@ TEST( GaussianBayesNet, optimize ) } /* ************************************************************************* */ -TEST( GaussianBayesNet, optimize2 ) +TEST( GaussianBayesNetOrdered, optimize2 ) { // Create empty graph - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; SharedDiagonal noise = noiseModel::Unit::Create(1); fg.add(_y_, eye(1), 2*ones(1), noise); @@ -108,9 +108,9 @@ TEST( GaussianBayesNet, optimize2 ) fg.add(_x_, -eye(1), _z_, eye(1), 2*ones(1), noise); - VectorValues actual = *GaussianSequentialSolver(fg).optimize(); + VectorValuesOrdered actual = *GaussianSequentialSolver(fg).optimize(); - VectorValues expected(vector(3,1)); + VectorValuesOrdered expected(vector(3,1)); expected[_x_] = Vector_(1,1.); expected[_y_] = Vector_(1,2.); expected[_z_] = Vector_(1,3.); @@ -119,20 +119,20 @@ TEST( GaussianBayesNet, optimize2 ) } /* ************************************************************************* */ -TEST( GaussianBayesNet, optimize3 ) +TEST( GaussianBayesNetOrdered, optimize3 ) { // y=R*x, x=inv(R)*y // 9 = 1 1 4 // 5 1 5 // NOTE: we are supplying a new RHS here - GaussianBayesNet cbn = createSmallGaussianBayesNet(); + GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet(); - VectorValues expected(vector(2,1)), x(vector(2,1)); + VectorValuesOrdered expected(vector(2,1)), x(vector(2,1)); expected[_x_] = Vector_(1, 4.); expected[_y_] = Vector_(1, 5.); // test functional version - VectorValues actual = optimize(cbn); + VectorValuesOrdered actual = optimize(cbn); EXPECT(assert_equal(expected,actual)); // test imperative version @@ -141,40 +141,40 @@ TEST( GaussianBayesNet, optimize3 ) } /* ************************************************************************* */ -TEST( GaussianBayesNet, backSubstituteTranspose ) +TEST( GaussianBayesNetOrdered, backSubstituteTranspose ) { // x=R'*y, y=inv(R')*x // 2 = 1 2 // 5 1 1 3 - GaussianBayesNet cbn = createSmallGaussianBayesNet(); + GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet(); - VectorValues y(vector(2,1)), x(vector(2,1)); + VectorValuesOrdered y(vector(2,1)), x(vector(2,1)); x[_x_] = Vector_(1,2.); x[_y_] = Vector_(1,5.); y[_x_] = Vector_(1,2.); y[_y_] = Vector_(1,3.); // test functional version - VectorValues actual = backSubstituteTranspose(cbn,x); + VectorValuesOrdered actual = backSubstituteTranspose(cbn,x); EXPECT(assert_equal(y,actual)); } /* ************************************************************************* */ // Tests computing Determinant -TEST( GaussianBayesNet, DeterminantTest ) +TEST( GaussianBayesNetOrdered, DeterminantTest ) { - GaussianBayesNet cbn; - cbn += boost::shared_ptr(new GaussianConditional( + GaussianBayesNetOrdered cbn; + cbn += boost::shared_ptr(new GaussianConditionalOrdered( 0, Vector_( 2, 3.0, 4.0 ), Matrix_(2, 2, 1.0, 3.0, 0.0, 4.0 ), 1, Matrix_(2, 2, 2.0, 1.0, 2.0, 3.0), ones(2))); - cbn += boost::shared_ptr(new GaussianConditional( + cbn += boost::shared_ptr(new GaussianConditionalOrdered( 1, Vector_( 2, 5.0, 6.0 ), Matrix_(2, 2, 1.0, 1.0, 0.0, 3.0 ), 2, Matrix_(2, 2, 1.0, 0.0, 5.0, 2.0), ones(2))); - cbn += boost::shared_ptr(new GaussianConditional( + cbn += boost::shared_ptr(new GaussianConditionalOrdered( 3, Vector_( 2, 7.0, 8.0 ), Matrix_(2, 2, 1.0, 1.0, 0.0, 5.0 ), ones(2))); diff --git a/tests/testGaussianBayesTree.cpp b/tests/testGaussianBayesTree.cpp index 85ea792fe..71bc4b2f7 100644 --- a/tests/testGaussianBayesTree.cpp +++ b/tests/testGaussianBayesTree.cpp @@ -16,7 +16,7 @@ */ #include -#include +#include #include #include #include @@ -52,45 +52,45 @@ C4 x3 : x4 C5 x2 : x3 C6 x1 : x2 **************************************************************************** */ -TEST( GaussianBayesTree, linear_smoother_shortcuts ) +TEST( GaussianBayesTreeOrdered, linear_smoother_shortcuts ) { // Create smoother with 7 nodes - Ordering ordering; - GaussianFactorGraph smoother; + OrderingOrdered ordering; + GaussianFactorGraphOrdered smoother; boost::tie(smoother, ordering) = createSmoother(7); - GaussianBayesTree bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); + GaussianBayesTreeOrdered bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); // Create the Bayes tree LONGS_EQUAL(6, bayesTree.size()); // Check the conditional P(Root|Root) - GaussianBayesNet empty; - GaussianBayesTree::sharedClique R = bayesTree.root(); - GaussianBayesNet actual1 = R->shortcut(R, EliminateCholesky); + GaussianBayesNetOrdered empty; + GaussianBayesTreeOrdered::sharedClique R = bayesTree.root(); + GaussianBayesNetOrdered actual1 = R->shortcut(R, EliminateCholeskyOrdered); EXPECT(assert_equal(empty,actual1,tol)); // Check the conditional P(C2|Root) - GaussianBayesTree::sharedClique C2 = bayesTree[ordering[X(5)]]; - GaussianBayesNet actual2 = C2->shortcut(R, EliminateCholesky); + GaussianBayesTreeOrdered::sharedClique C2 = bayesTree[ordering[X(5)]]; + GaussianBayesNetOrdered actual2 = C2->shortcut(R, EliminateCholeskyOrdered); EXPECT(assert_equal(empty,actual2,tol)); // Check the conditional P(C3|Root) double sigma3 = 0.61808; Matrix A56 = Matrix_(2,2,-0.382022,0.,0.,-0.382022); - GaussianBayesNet expected3; + GaussianBayesNetOrdered expected3; push_front(expected3,ordering[X(5)], zero(2), eye(2)/sigma3, ordering[X(6)], A56/sigma3, ones(2)); - GaussianBayesTree::sharedClique C3 = bayesTree[ordering[X(4)]]; - GaussianBayesNet actual3 = C3->shortcut(R, EliminateCholesky); + GaussianBayesTreeOrdered::sharedClique C3 = bayesTree[ordering[X(4)]]; + GaussianBayesNetOrdered actual3 = C3->shortcut(R, EliminateCholeskyOrdered); EXPECT(assert_equal(expected3,actual3,tol)); // Check the conditional P(C4|Root) double sigma4 = 0.661968; Matrix A46 = Matrix_(2,2,-0.146067,0.,0.,-0.146067); - GaussianBayesNet expected4; + GaussianBayesNetOrdered expected4; push_front(expected4, ordering[X(4)], zero(2), eye(2)/sigma4, ordering[X(6)], A46/sigma4, ones(2)); - GaussianBayesTree::sharedClique C4 = bayesTree[ordering[X(3)]]; - GaussianBayesNet actual4 = C4->shortcut(R, EliminateCholesky); + GaussianBayesTreeOrdered::sharedClique C4 = bayesTree[ordering[X(3)]]; + GaussianBayesNetOrdered actual4 = C4->shortcut(R, EliminateCholeskyOrdered); EXPECT(assert_equal(expected4,actual4,tol)); } @@ -113,18 +113,18 @@ TEST( GaussianBayesTree, linear_smoother_shortcuts ) C4 x7 : x6 ************************************************************************* */ -TEST( GaussianBayesTree, balanced_smoother_marginals ) +TEST( GaussianBayesTreeOrdered, balanced_smoother_marginals ) { // Create smoother with 7 nodes - Ordering ordering; + OrderingOrdered ordering; ordering += X(1),X(3),X(5),X(7),X(2),X(6),X(4); - GaussianFactorGraph smoother = createSmoother(7, ordering).first; + GaussianFactorGraphOrdered smoother = createSmoother(7, ordering).first; // Create the Bayes tree - GaussianBayesTree bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); + GaussianBayesTreeOrdered bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); - VectorValues expectedSolution(VectorValues::Zero(7,2)); - VectorValues actualSolution = optimize(bayesTree); + VectorValuesOrdered expectedSolution(VectorValuesOrdered::Zero(7,2)); + VectorValuesOrdered actualSolution = optimize(bayesTree); EXPECT(assert_equal(expectedSolution,actualSolution,tol)); LONGS_EQUAL(4,bayesTree.size()); @@ -132,73 +132,73 @@ TEST( GaussianBayesTree, balanced_smoother_marginals ) double tol=1e-5; // Check marginal on x1 - GaussianBayesNet expected1 = simpleGaussian(ordering[X(1)], zero(2), sigmax1); - GaussianBayesNet actual1 = *bayesTree.marginalBayesNet(ordering[X(1)], EliminateCholesky); + GaussianBayesNetOrdered expected1 = simpleGaussian(ordering[X(1)], zero(2), sigmax1); + GaussianBayesNetOrdered actual1 = *bayesTree.marginalBayesNet(ordering[X(1)], EliminateCholeskyOrdered); Matrix expectedCovarianceX1 = eye(2,2) * (sigmax1 * sigmax1); Matrix actualCovarianceX1; - GaussianFactor::shared_ptr m = bayesTree.marginalFactor(ordering[X(1)], EliminateCholesky); - actualCovarianceX1 = bayesTree.marginalFactor(ordering[X(1)], EliminateCholesky)->information().inverse(); + GaussianFactorOrdered::shared_ptr m = bayesTree.marginalFactor(ordering[X(1)], EliminateCholeskyOrdered); + actualCovarianceX1 = bayesTree.marginalFactor(ordering[X(1)], EliminateCholeskyOrdered)->information().inverse(); EXPECT(assert_equal(expectedCovarianceX1, actualCovarianceX1, tol)); EXPECT(assert_equal(expected1,actual1,tol)); // Check marginal on x2 double sigx2 = 0.68712938; // FIXME: this should be corrected analytically - GaussianBayesNet expected2 = simpleGaussian(ordering[X(2)], zero(2), sigx2); - GaussianBayesNet actual2 = *bayesTree.marginalBayesNet(ordering[X(2)], EliminateCholesky); + GaussianBayesNetOrdered expected2 = simpleGaussian(ordering[X(2)], zero(2), sigx2); + GaussianBayesNetOrdered actual2 = *bayesTree.marginalBayesNet(ordering[X(2)], EliminateCholeskyOrdered); Matrix expectedCovarianceX2 = eye(2,2) * (sigx2 * sigx2); Matrix actualCovarianceX2; - actualCovarianceX2 = bayesTree.marginalFactor(ordering[X(2)], EliminateCholesky)->information().inverse(); + actualCovarianceX2 = bayesTree.marginalFactor(ordering[X(2)], EliminateCholeskyOrdered)->information().inverse(); EXPECT(assert_equal(expectedCovarianceX2, actualCovarianceX2, tol)); EXPECT(assert_equal(expected2,actual2,tol)); // Check marginal on x3 - GaussianBayesNet expected3 = simpleGaussian(ordering[X(3)], zero(2), sigmax3); - GaussianBayesNet actual3 = *bayesTree.marginalBayesNet(ordering[X(3)], EliminateCholesky); + GaussianBayesNetOrdered expected3 = simpleGaussian(ordering[X(3)], zero(2), sigmax3); + GaussianBayesNetOrdered actual3 = *bayesTree.marginalBayesNet(ordering[X(3)], EliminateCholeskyOrdered); Matrix expectedCovarianceX3 = eye(2,2) * (sigmax3 * sigmax3); Matrix actualCovarianceX3; - actualCovarianceX3 = bayesTree.marginalFactor(ordering[X(3)], EliminateCholesky)->information().inverse(); + actualCovarianceX3 = bayesTree.marginalFactor(ordering[X(3)], EliminateCholeskyOrdered)->information().inverse(); EXPECT(assert_equal(expectedCovarianceX3, actualCovarianceX3, tol)); EXPECT(assert_equal(expected3,actual3,tol)); // Check marginal on x4 - GaussianBayesNet expected4 = simpleGaussian(ordering[X(4)], zero(2), sigmax4); - GaussianBayesNet actual4 = *bayesTree.marginalBayesNet(ordering[X(4)], EliminateCholesky); + GaussianBayesNetOrdered expected4 = simpleGaussian(ordering[X(4)], zero(2), sigmax4); + GaussianBayesNetOrdered actual4 = *bayesTree.marginalBayesNet(ordering[X(4)], EliminateCholeskyOrdered); Matrix expectedCovarianceX4 = eye(2,2) * (sigmax4 * sigmax4); Matrix actualCovarianceX4; - actualCovarianceX4 = bayesTree.marginalFactor(ordering[X(4)], EliminateCholesky)->information().inverse(); + actualCovarianceX4 = bayesTree.marginalFactor(ordering[X(4)], EliminateCholeskyOrdered)->information().inverse(); EXPECT(assert_equal(expectedCovarianceX4, actualCovarianceX4, tol)); EXPECT(assert_equal(expected4,actual4,tol)); // Check marginal on x7 (should be equal to x1) - GaussianBayesNet expected7 = simpleGaussian(ordering[X(7)], zero(2), sigmax7); - GaussianBayesNet actual7 = *bayesTree.marginalBayesNet(ordering[X(7)], EliminateCholesky); + GaussianBayesNetOrdered expected7 = simpleGaussian(ordering[X(7)], zero(2), sigmax7); + GaussianBayesNetOrdered actual7 = *bayesTree.marginalBayesNet(ordering[X(7)], EliminateCholeskyOrdered); Matrix expectedCovarianceX7 = eye(2,2) * (sigmax7 * sigmax7); Matrix actualCovarianceX7; - actualCovarianceX7 = bayesTree.marginalFactor(ordering[X(7)], EliminateCholesky)->information().inverse(); + actualCovarianceX7 = bayesTree.marginalFactor(ordering[X(7)], EliminateCholeskyOrdered)->information().inverse(); EXPECT(assert_equal(expectedCovarianceX7, actualCovarianceX7, tol)); EXPECT(assert_equal(expected7,actual7,tol)); } /* ************************************************************************* */ -TEST( GaussianBayesTree, balanced_smoother_shortcuts ) +TEST( GaussianBayesTreeOrdered, balanced_smoother_shortcuts ) { // Create smoother with 7 nodes - Ordering ordering; + OrderingOrdered ordering; ordering += X(1),X(3),X(5),X(7),X(2),X(6),X(4); - GaussianFactorGraph smoother = createSmoother(7, ordering).first; + GaussianFactorGraphOrdered smoother = createSmoother(7, ordering).first; // Create the Bayes tree - GaussianBayesTree bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); + GaussianBayesTreeOrdered bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); // Check the conditional P(Root|Root) - GaussianBayesNet empty; - GaussianBayesTree::sharedClique R = bayesTree.root(); - GaussianBayesNet actual1 = R->shortcut(R, EliminateCholesky); + GaussianBayesNetOrdered empty; + GaussianBayesTreeOrdered::sharedClique R = bayesTree.root(); + GaussianBayesNetOrdered actual1 = R->shortcut(R, EliminateCholeskyOrdered); EXPECT(assert_equal(empty,actual1,tol)); // Check the conditional P(C2|Root) - GaussianBayesTree::sharedClique C2 = bayesTree[ordering[X(3)]]; - GaussianBayesNet actual2 = C2->shortcut(R, EliminateCholesky); + GaussianBayesTreeOrdered::sharedClique C2 = bayesTree[ordering[X(3)]]; + GaussianBayesNetOrdered actual2 = C2->shortcut(R, EliminateCholeskyOrdered); EXPECT(assert_equal(empty,actual2,tol)); // Check the conditional P(C3|Root), which should be equal to P(x2|x4) @@ -206,11 +206,11 @@ TEST( GaussianBayesTree, balanced_smoother_shortcuts ) * p_x2_x4 is now an element conditional of the multifrontal conditional bayesTree[ordering[X(2)]]->conditional() * We don't know yet how to take it out. */ -// GaussianConditional::shared_ptr p_x2_x4 = bayesTree[ordering[X(2)]]->conditional(); +// GaussianConditionalOrdered::shared_ptr p_x2_x4 = bayesTree[ordering[X(2)]]->conditional(); // p_x2_x4->print("Conditional p_x2_x4: "); -// GaussianBayesNet expected3(p_x2_x4); +// GaussianBayesNetOrdered expected3(p_x2_x4); // GaussianISAM::sharedClique C3 = isamTree[ordering[X(1)]]; -// GaussianBayesNet actual3 = GaussianISAM::shortcut(C3,R); +// GaussianBayesNetOrdered actual3 = GaussianISAM::shortcut(C3,R); // EXPECT(assert_equal(expected3,actual3,tol)); } @@ -218,96 +218,96 @@ TEST( GaussianBayesTree, balanced_smoother_shortcuts ) //TEST( BayesTree, balanced_smoother_clique_marginals ) //{ // // Create smoother with 7 nodes -// Ordering ordering; +// OrderingOrdered ordering; // ordering += X(1),X(3),X(5),X(7),X(2),X(6),X(4); -// GaussianFactorGraph smoother = createSmoother(7, ordering).first; +// GaussianFactorGraphOrdered smoother = createSmoother(7, ordering).first; // // // Create the Bayes tree -// GaussianBayesNet chordalBayesNet = *GaussianSequentialSolver(smoother).eliminate(); +// GaussianBayesNetOrdered chordalBayesNet = *GaussianSequentialSolver(smoother).eliminate(); // GaussianISAM bayesTree(chordalBayesNet); // // // Check the clique marginal P(C3) // double sigmax2_alt = 1/1.45533; // THIS NEEDS TO BE CHECKED! -// GaussianBayesNet expected = simpleGaussian(ordering[X(2)],zero(2),sigmax2_alt); +// GaussianBayesNetOrdered expected = simpleGaussian(ordering[X(2)],zero(2),sigmax2_alt); // push_front(expected,ordering[X(1)], zero(2), eye(2)*sqrt(2), ordering[X(2)], -eye(2)*sqrt(2)/2, ones(2)); // GaussianISAM::sharedClique R = bayesTree.root(), C3 = bayesTree[ordering[X(1)]]; -// GaussianFactorGraph marginal = C3->marginal(R); +// GaussianFactorGraphOrdered marginal = C3->marginal(R); // GaussianVariableIndex varIndex(marginal); // Permutation toFront(Permutation::PullToFront(C3->keys(), varIndex.size())); // Permutation toFrontInverse(*toFront.inverse()); // varIndex.permute(toFront); -// BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, marginal) { +// BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, marginal) { // factor->permuteWithInverse(toFrontInverse); } -// GaussianBayesNet actual = *inference::EliminateUntil(marginal, C3->keys().size(), varIndex); +// GaussianBayesNetOrdered actual = *inference::EliminateUntil(marginal, C3->keys().size(), varIndex); // actual.permuteWithInverse(toFront); // EXPECT(assert_equal(expected,actual,tol)); //} /* ************************************************************************* */ -TEST( GaussianBayesTree, balanced_smoother_joint ) +TEST( GaussianBayesTreeOrdered, balanced_smoother_joint ) { // Create smoother with 7 nodes - Ordering ordering; + OrderingOrdered ordering; ordering += X(1),X(3),X(5),X(7),X(2),X(6),X(4); - GaussianFactorGraph smoother = createSmoother(7, ordering).first; + GaussianFactorGraphOrdered smoother = createSmoother(7, ordering).first; // Create the Bayes tree, expected to look like: // x5 x6 x4 // x3 x2 : x4 // x1 : x2 // x7 : x6 - GaussianBayesTree bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); + GaussianBayesTreeOrdered bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); // Conditional density elements reused by both tests const Vector sigma = ones(2); const Matrix I = eye(2), A = -0.00429185*I; // Check the joint density P(x1,x7) factored as P(x1|x7)P(x7) - GaussianBayesNet expected1; + GaussianBayesNetOrdered expected1; // Why does the sign get flipped on the prior? - GaussianConditional::shared_ptr - parent1(new GaussianConditional(ordering[X(7)], zero(2), -1*I/sigmax7, ones(2))); + GaussianConditionalOrdered::shared_ptr + parent1(new GaussianConditionalOrdered(ordering[X(7)], zero(2), -1*I/sigmax7, ones(2))); expected1.push_front(parent1); push_front(expected1,ordering[X(1)], zero(2), I/sigmax7, ordering[X(7)], A/sigmax7, sigma); - GaussianBayesNet actual1 = *bayesTree.jointBayesNet(ordering[X(1)],ordering[X(7)], EliminateCholesky); + GaussianBayesNetOrdered actual1 = *bayesTree.jointBayesNet(ordering[X(1)],ordering[X(7)], EliminateCholeskyOrdered); EXPECT(assert_equal(expected1,actual1,tol)); // // Check the joint density P(x7,x1) factored as P(x7|x1)P(x1) - // GaussianBayesNet expected2; - // GaussianConditional::shared_ptr - // parent2(new GaussianConditional(ordering[X(1)], zero(2), -1*I/sigmax1, ones(2))); + // GaussianBayesNetOrdered expected2; + // GaussianConditionalOrdered::shared_ptr + // parent2(new GaussianConditionalOrdered(ordering[X(1)], zero(2), -1*I/sigmax1, ones(2))); // expected2.push_front(parent2); // push_front(expected2,ordering[X(7)], zero(2), I/sigmax1, ordering[X(1)], A/sigmax1, sigma); - // GaussianBayesNet actual2 = *bayesTree.jointBayesNet(ordering[X(7)],ordering[X(1)]); + // GaussianBayesNetOrdered actual2 = *bayesTree.jointBayesNet(ordering[X(7)],ordering[X(1)]); // EXPECT(assert_equal(expected2,actual2,tol)); // Check the joint density P(x1,x4), i.e. with a root variable - GaussianBayesNet expected3; - GaussianConditional::shared_ptr - parent3(new GaussianConditional(ordering[X(4)], zero(2), I/sigmax4, ones(2))); + GaussianBayesNetOrdered expected3; + GaussianConditionalOrdered::shared_ptr + parent3(new GaussianConditionalOrdered(ordering[X(4)], zero(2), I/sigmax4, ones(2))); expected3.push_front(parent3); double sig14 = 0.784465; Matrix A14 = -0.0769231*I; push_front(expected3,ordering[X(1)], zero(2), I/sig14, ordering[X(4)], A14/sig14, sigma); - GaussianBayesNet actual3 = *bayesTree.jointBayesNet(ordering[X(1)],ordering[X(4)], EliminateCholesky); + GaussianBayesNetOrdered actual3 = *bayesTree.jointBayesNet(ordering[X(1)],ordering[X(4)], EliminateCholeskyOrdered); EXPECT(assert_equal(expected3,actual3,tol)); // // Check the joint density P(x4,x1), i.e. with a root variable, factored the other way - // GaussianBayesNet expected4; - // GaussianConditional::shared_ptr - // parent4(new GaussianConditional(ordering[X(1)], zero(2), -1.0*I/sigmax1, ones(2))); + // GaussianBayesNetOrdered expected4; + // GaussianConditionalOrdered::shared_ptr + // parent4(new GaussianConditionalOrdered(ordering[X(1)], zero(2), -1.0*I/sigmax1, ones(2))); // expected4.push_front(parent4); // double sig41 = 0.668096; // Matrix A41 = -0.055794*I; // push_front(expected4,ordering[X(4)], zero(2), I/sig41, ordering[X(1)], A41/sig41, sigma); - // GaussianBayesNet actual4 = *bayesTree.jointBayesNet(ordering[X(4)],ordering[X(1)]); + // GaussianBayesNetOrdered actual4 = *bayesTree.jointBayesNet(ordering[X(4)],ordering[X(1)]); // EXPECT(assert_equal(expected4,actual4,tol)); } /* ************************************************************************* */ -TEST(GaussianBayesTree, simpleMarginal) +TEST(GaussianBayesTreeOrdered, simpleMarginal) { - GaussianFactorGraph gfg; + GaussianFactorGraphOrdered gfg; Matrix A12 = Rot2::fromDegrees(45.0).matrix(); @@ -322,7 +322,7 @@ TEST(GaussianBayesTree, simpleMarginal) } /* ************************************************************************* */ -TEST(GaussianBayesTree, shortcut_overlapping_separator) +TEST(GaussianBayesTreeOrdered, shortcut_overlapping_separator) { // Test computing shortcuts when the separator overlaps. This previously // would have highlighted a problem where information was duplicated. @@ -332,7 +332,7 @@ TEST(GaussianBayesTree, shortcut_overlapping_separator) // f(3,4,5) // f(5,6) // f(6,7) - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; noiseModel::Diagonal::shared_ptr model = noiseModel::Unit::Create(1); fg.add(1, Matrix_(1,1, 1.0), 3, Matrix_(1,1, 2.0), 5, Matrix_(1,1, 3.0), Vector_(1, 4.0), model); fg.add(1, Matrix_(1,1, 5.0), Vector_(1, 6.0), model); @@ -347,9 +347,9 @@ TEST(GaussianBayesTree, shortcut_overlapping_separator) // c(5|6) // c(1,2|5) // c(3,4|5) - GaussianBayesTree bt = *GaussianMultifrontalSolver(fg).eliminate(); + GaussianBayesTreeOrdered bt = *GaussianMultifrontalSolver(fg).eliminate(); - GaussianFactorGraph joint = *bt.joint(1,2, EliminateQR); + GaussianFactorGraphOrdered joint = *bt.joint(1,2, EliminateQROrdered); Matrix expectedJointJ = (Matrix(2,3) << 0, 11, 12, diff --git a/tests/testGaussianFactorGraphB.cpp b/tests/testGaussianFactorGraphB.cpp index b8bea8c6e..157d57cf3 100644 --- a/tests/testGaussianFactorGraphB.cpp +++ b/tests/testGaussianFactorGraphB.cpp @@ -17,10 +17,10 @@ #include #include -#include +#include #include -#include -#include +#include +#include #include #include #include @@ -47,19 +47,19 @@ using symbol_shorthand::X; using symbol_shorthand::L; /* ************************************************************************* */ -TEST( GaussianFactorGraph, equals ) { +TEST( GaussianFactorGraphOrdered, equals ) { - Ordering ordering; ordering += X(1),X(2),L(1); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - GaussianFactorGraph fg2 = createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += X(1),X(2),L(1); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); + GaussianFactorGraphOrdered fg2 = createGaussianFactorGraph(ordering); EXPECT(fg.equals(fg2)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, error ) { - Ordering ordering; ordering += X(1),X(2),L(1); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - VectorValues cfg = createZeroDelta(ordering); +TEST( GaussianFactorGraphOrdered, error ) { + OrderingOrdered ordering; ordering += X(1),X(2),L(1); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); + VectorValuesOrdered cfg = createZeroDelta(ordering); // note the error is the same as in testNonlinearFactorGraph as a // zero delta config in the linear graph is equivalent to noisy in @@ -69,71 +69,71 @@ TEST( GaussianFactorGraph, error ) { } /* ************************************************************************* */ -TEST( GaussianFactorGraph, eliminateOne_x1 ) +TEST( GaussianFactorGraphOrdered, eliminateOne_x1 ) { - Ordering ordering; ordering += X(1),L(1),X(2); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += X(1),L(1),X(2); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); - GaussianConditional::shared_ptr conditional; - GaussianFactorGraph remaining; - boost::tie(conditional,remaining) = fg.eliminateOne(0, EliminateQR); + GaussianConditionalOrdered::shared_ptr conditional; + GaussianFactorGraphOrdered remaining; + boost::tie(conditional,remaining) = fg.eliminateOne(0, EliminateQROrdered); // create expected Conditional Gaussian Matrix I = 15*eye(2), R11 = I, S12 = -0.111111*I, S13 = -0.444444*I; Vector d = Vector_(2, -0.133333, -0.0222222), sigma = ones(2); - GaussianConditional expected(ordering[X(1)],15*d,R11,ordering[L(1)],S12,ordering[X(2)],S13,sigma); + GaussianConditionalOrdered expected(ordering[X(1)],15*d,R11,ordering[L(1)],S12,ordering[X(2)],S13,sigma); EXPECT(assert_equal(expected,*conditional,tol)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, eliminateOne_x2 ) +TEST( GaussianFactorGraphOrdered, eliminateOne_x2 ) { - Ordering ordering; ordering += X(2),L(1),X(1); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - GaussianConditional::shared_ptr actual = fg.eliminateOne(0, EliminateQR).first; + OrderingOrdered ordering; ordering += X(2),L(1),X(1); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); + GaussianConditionalOrdered::shared_ptr actual = fg.eliminateOne(0, EliminateQROrdered).first; // create expected Conditional Gaussian double sig = 0.0894427; Matrix I = eye(2)/sig, R11 = I, S12 = -0.2*I, S13 = -0.8*I; Vector d = Vector_(2, 0.2, -0.14)/sig, sigma = ones(2); - GaussianConditional expected(ordering[X(2)],d,R11,ordering[L(1)],S12,ordering[X(1)],S13,sigma); + GaussianConditionalOrdered expected(ordering[X(2)],d,R11,ordering[L(1)],S12,ordering[X(1)],S13,sigma); EXPECT(assert_equal(expected,*actual,tol)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, eliminateOne_l1 ) +TEST( GaussianFactorGraphOrdered, eliminateOne_l1 ) { - Ordering ordering; ordering += L(1),X(1),X(2); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - GaussianConditional::shared_ptr actual = fg.eliminateOne(0, EliminateQR).first; + OrderingOrdered ordering; ordering += L(1),X(1),X(2); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); + GaussianConditionalOrdered::shared_ptr actual = fg.eliminateOne(0, EliminateQROrdered).first; // create expected Conditional Gaussian double sig = sqrt(2.0)/10.; Matrix I = eye(2)/sig, R11 = I, S12 = -0.5*I, S13 = -0.5*I; Vector d = Vector_(2, -0.1, 0.25)/sig, sigma = ones(2); - GaussianConditional expected(ordering[L(1)],d,R11,ordering[X(1)],S12,ordering[X(2)],S13,sigma); + GaussianConditionalOrdered expected(ordering[L(1)],d,R11,ordering[X(1)],S12,ordering[X(2)],S13,sigma); EXPECT(assert_equal(expected,*actual,tol)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, eliminateOne_x1_fast ) +TEST( GaussianFactorGraphOrdered, eliminateOne_x1_fast ) { - Ordering ordering; ordering += X(1),L(1),X(2); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - GaussianConditional::shared_ptr conditional; - GaussianFactorGraph remaining; - boost::tie(conditional,remaining) = fg.eliminateOne(ordering[X(1)], EliminateQR); + OrderingOrdered ordering; ordering += X(1),L(1),X(2); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); + GaussianConditionalOrdered::shared_ptr conditional; + GaussianFactorGraphOrdered remaining; + boost::tie(conditional,remaining) = fg.eliminateOne(ordering[X(1)], EliminateQROrdered); // create expected Conditional Gaussian Matrix I = 15*eye(2), R11 = I, S12 = -0.111111*I, S13 = -0.444444*I; Vector d = Vector_(2, -0.133333, -0.0222222), sigma = ones(2); - GaussianConditional expected(ordering[X(1)],15*d,R11,ordering[L(1)],S12,ordering[X(2)],S13,sigma); + GaussianConditionalOrdered expected(ordering[X(1)],15*d,R11,ordering[L(1)],S12,ordering[X(2)],S13,sigma); // Create expected remaining new factor - JacobianFactor expectedFactor(1, Matrix_(4,2, + JacobianFactorOrdered expectedFactor(1, Matrix_(4,2, 4.714045207910318, 0., 0., 4.714045207910318, 0., 0., @@ -146,52 +146,52 @@ TEST( GaussianFactorGraph, eliminateOne_x1_fast ) Vector_(4, -0.707106781186547, 0.942809041582063, 0.707106781186547, -1.414213562373094), noiseModel::Unit::Create(4)); EXPECT(assert_equal(expected,*conditional,tol)); - EXPECT(assert_equal((const GaussianFactor&)expectedFactor,*remaining.back(),tol)); + EXPECT(assert_equal((const GaussianFactorOrdered&)expectedFactor,*remaining.back(),tol)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, eliminateOne_x2_fast ) +TEST( GaussianFactorGraphOrdered, eliminateOne_x2_fast ) { - Ordering ordering; ordering += X(1),L(1),X(2); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - GaussianConditional::shared_ptr actual = fg.eliminateOne(ordering[X(2)], EliminateQR).first; + OrderingOrdered ordering; ordering += X(1),L(1),X(2); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); + GaussianConditionalOrdered::shared_ptr actual = fg.eliminateOne(ordering[X(2)], EliminateQROrdered).first; // create expected Conditional Gaussian double sig = 0.0894427; Matrix I = eye(2)/sig, R11 = I, S12 = -0.2*I, S13 = -0.8*I; Vector d = Vector_(2, 0.2, -0.14)/sig, sigma = ones(2); - GaussianConditional expected(ordering[X(2)],d,R11,ordering[X(1)],S13,ordering[L(1)],S12,sigma); + GaussianConditionalOrdered expected(ordering[X(2)],d,R11,ordering[X(1)],S13,ordering[L(1)],S12,sigma); EXPECT(assert_equal(expected,*actual,tol)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, eliminateOne_l1_fast ) +TEST( GaussianFactorGraphOrdered, eliminateOne_l1_fast ) { - Ordering ordering; ordering += X(1),L(1),X(2); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); - GaussianConditional::shared_ptr actual = fg.eliminateOne(ordering[L(1)], EliminateQR).first; + OrderingOrdered ordering; ordering += X(1),L(1),X(2); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); + GaussianConditionalOrdered::shared_ptr actual = fg.eliminateOne(ordering[L(1)], EliminateQROrdered).first; // create expected Conditional Gaussian double sig = sqrt(2.0)/10.; Matrix I = eye(2)/sig, R11 = I, S12 = -0.5*I, S13 = -0.5*I; Vector d = Vector_(2, -0.1, 0.25)/sig, sigma = ones(2); - GaussianConditional expected(ordering[L(1)],d,R11,ordering[X(1)],S12,ordering[X(2)],S13,sigma); + GaussianConditionalOrdered expected(ordering[L(1)],d,R11,ordering[X(1)],S12,ordering[X(2)],S13,sigma); EXPECT(assert_equal(expected,*actual,tol)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, eliminateAll ) +TEST( GaussianFactorGraphOrdered, eliminateAll ) { // create expected Chordal bayes Net Matrix I = eye(2); - Ordering ordering; + OrderingOrdered ordering; ordering += X(2),L(1),X(1); Vector d1 = Vector_(2, -0.1,-0.1); - GaussianBayesNet expected = simpleGaussian(ordering[X(1)],d1,0.1); + GaussianBayesNetOrdered expected = simpleGaussian(ordering[X(1)],d1,0.1); double sig1 = 0.149071; Vector d2 = Vector_(2, 0.0, 0.2)/sig1, sigma2 = ones(2); @@ -202,108 +202,108 @@ TEST( GaussianFactorGraph, eliminateAll ) push_front(expected,ordering[X(2)],d3, I/sig2,ordering[L(1)], (-0.2)*I/sig2, ordering[X(1)], (-0.8)*I/sig2, sigma3); // Check one ordering - GaussianFactorGraph fg1 = createGaussianFactorGraph(ordering); - GaussianBayesNet actual = *GaussianSequentialSolver(fg1).eliminate(); + GaussianFactorGraphOrdered fg1 = createGaussianFactorGraph(ordering); + GaussianBayesNetOrdered actual = *GaussianSequentialSolver(fg1).eliminate(); EXPECT(assert_equal(expected,actual,tol)); - GaussianBayesNet actualQR = *GaussianSequentialSolver(fg1, true).eliminate(); + GaussianBayesNetOrdered actualQR = *GaussianSequentialSolver(fg1, true).eliminate(); EXPECT(assert_equal(expected,actualQR,tol)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, copying ) +TEST( GaussianFactorGraphOrdered, copying ) { // Create a graph - Ordering ordering; ordering += X(2),L(1),X(1); - GaussianFactorGraph actual = createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += X(2),L(1),X(1); + GaussianFactorGraphOrdered actual = createGaussianFactorGraph(ordering); // Copy the graph ! - GaussianFactorGraph copy = actual; + GaussianFactorGraphOrdered copy = actual; // now eliminate the copy - GaussianBayesNet actual1 = *GaussianSequentialSolver(copy).eliminate(); + GaussianBayesNetOrdered actual1 = *GaussianSequentialSolver(copy).eliminate(); // Create the same graph, but not by copying - GaussianFactorGraph expected = createGaussianFactorGraph(ordering); + GaussianFactorGraphOrdered expected = createGaussianFactorGraph(ordering); // and check that original is still the same graph EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, CONSTRUCTOR_GaussianBayesNet ) +TEST( GaussianFactorGraphOrdered, CONSTRUCTOR_GaussianBayesNet ) { - Ordering ord; + OrderingOrdered ord; ord += X(2),L(1),X(1); - GaussianFactorGraph fg = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ord); // render with a given ordering - GaussianBayesNet CBN = *GaussianSequentialSolver(fg).eliminate(); + GaussianBayesNetOrdered CBN = *GaussianSequentialSolver(fg).eliminate(); // True GaussianFactorGraph - GaussianFactorGraph fg2(CBN); - GaussianBayesNet CBN2 = *GaussianSequentialSolver(fg2).eliminate(); + GaussianFactorGraphOrdered fg2(CBN); + GaussianBayesNetOrdered CBN2 = *GaussianSequentialSolver(fg2).eliminate(); EXPECT(assert_equal(CBN,CBN2)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, getOrdering) +TEST( GaussianFactorGraphOrdered, getOrdering) { - Ordering original; original += L(1),X(1),X(2); - FactorGraph symbolic(createGaussianFactorGraph(original)); - Permutation perm(*inference::PermutationCOLAMD(VariableIndex(symbolic))); - Ordering actual = original; actual.permuteInPlace(perm); - Ordering expected; expected += L(1),X(2),X(1); + OrderingOrdered original; original += L(1),X(1),X(2); + FactorGraphOrdered symbolic(createGaussianFactorGraph(original)); + Permutation perm(*inference::PermutationCOLAMD(VariableIndexOrdered(symbolic))); + OrderingOrdered actual = original; actual.permuteInPlace(perm); + OrderingOrdered expected; expected += L(1),X(2),X(1); EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, optimize_Cholesky ) +TEST( GaussianFactorGraphOrdered, optimize_Cholesky ) { // create an ordering - Ordering ord; ord += X(2),L(1),X(1); + OrderingOrdered ord; ord += X(2),L(1),X(1); // create a graph - GaussianFactorGraph fg = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ord); // optimize the graph - VectorValues actual = *GaussianSequentialSolver(fg, false).optimize(); + VectorValuesOrdered actual = *GaussianSequentialSolver(fg, false).optimize(); // verify - VectorValues expected = createCorrectDelta(ord); + VectorValuesOrdered expected = createCorrectDelta(ord); EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, optimize_QR ) +TEST( GaussianFactorGraphOrdered, optimize_QR ) { // create an ordering - Ordering ord; ord += X(2),L(1),X(1); + OrderingOrdered ord; ord += X(2),L(1),X(1); // create a graph - GaussianFactorGraph fg = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ord); // optimize the graph - VectorValues actual = *GaussianSequentialSolver(fg, true).optimize(); + VectorValuesOrdered actual = *GaussianSequentialSolver(fg, true).optimize(); // verify - VectorValues expected = createCorrectDelta(ord); + VectorValuesOrdered expected = createCorrectDelta(ord); EXPECT(assert_equal(expected,actual)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, combine) +TEST( GaussianFactorGraphOrdered, combine) { // create an ordering - Ordering ord; ord += X(2),L(1),X(1); + OrderingOrdered ord; ord += X(2),L(1),X(1); // create a test graph - GaussianFactorGraph fg1 = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg1 = createGaussianFactorGraph(ord); // create another factor graph - GaussianFactorGraph fg2 = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg2 = createGaussianFactorGraph(ord); // get sizes size_t size1 = fg1.size(); @@ -316,23 +316,23 @@ TEST( GaussianFactorGraph, combine) } /* ************************************************************************* */ -TEST( GaussianFactorGraph, combine2) +TEST( GaussianFactorGraphOrdered, combine2) { // create an ordering - Ordering ord; ord += X(2),L(1),X(1); + OrderingOrdered ord; ord += X(2),L(1),X(1); // create a test graph - GaussianFactorGraph fg1 = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg1 = createGaussianFactorGraph(ord); // create another factor graph - GaussianFactorGraph fg2 = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg2 = createGaussianFactorGraph(ord); // get sizes size_t size1 = fg1.size(); size_t size2 = fg2.size(); // combine them - GaussianFactorGraph fg3 = GaussianFactorGraph::combine2(fg1, fg2); + GaussianFactorGraphOrdered fg3 = GaussianFactorGraphOrdered::combine2(fg1, fg2); EXPECT(size1+size2 == fg3.size()); } @@ -346,31 +346,31 @@ void print(vector v) { } /* ************************************************************************* */ -TEST(GaussianFactorGraph, createSmoother) +TEST(GaussianFactorGraphOrdered, createSmoother) { - GaussianFactorGraph fg1 = createSmoother(2).first; + GaussianFactorGraphOrdered fg1 = createSmoother(2).first; LONGS_EQUAL(3,fg1.size()); - GaussianFactorGraph fg2 = createSmoother(3).first; + GaussianFactorGraphOrdered fg2 = createSmoother(3).first; LONGS_EQUAL(5,fg2.size()); } /* ************************************************************************* */ -double error(const VectorValues& x) { +double error(const VectorValuesOrdered& x) { // create an ordering - Ordering ord; ord += X(2),L(1),X(1); + OrderingOrdered ord; ord += X(2),L(1),X(1); - GaussianFactorGraph fg = createGaussianFactorGraph(ord); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ord); return fg.error(x); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, multiplication ) +TEST( GaussianFactorGraphOrdered, multiplication ) { // create an ordering - Ordering ord; ord += X(2),L(1),X(1); + OrderingOrdered ord; ord += X(2),L(1),X(1); - GaussianFactorGraph A = createGaussianFactorGraph(ord); - VectorValues x = createCorrectDelta(ord); + GaussianFactorGraphOrdered A = createGaussianFactorGraph(ord); + VectorValuesOrdered x = createCorrectDelta(ord); Errors actual = A * x; Errors expected; expected += Vector_(2,-1.0,-1.0); @@ -382,12 +382,12 @@ TEST( GaussianFactorGraph, multiplication ) /* ************************************************************************* */ // Extra test on elimination prompted by Michael's email to Frank 1/4/2010 -TEST( GaussianFactorGraph, elimination ) +TEST( GaussianFactorGraphOrdered, elimination ) { - Ordering ord; + OrderingOrdered ord; ord += X(1), X(2); // Create Gaussian Factor Graph - GaussianFactorGraph fg; + GaussianFactorGraphOrdered fg; Matrix Ap = eye(1), An = eye(1) * -1; Vector b = Vector_(1, 0.0); SharedDiagonal sigma = noiseModel::Isotropic::Sigma(1,2.0); @@ -396,7 +396,7 @@ TEST( GaussianFactorGraph, elimination ) fg.add(ord[X(2)], Ap, b, sigma); // Eliminate - GaussianBayesNet bayesNet = *GaussianSequentialSolver(fg).eliminate(); + GaussianBayesNetOrdered bayesNet = *GaussianSequentialSolver(fg).eliminate(); // Check sigma EXPECT_DOUBLES_EQUAL(1.0,bayesNet[ord[X(2)]]->get_sigmas()(0),1e-5); @@ -416,48 +416,48 @@ TEST( GaussianFactorGraph, elimination ) /* ************************************************************************* */ // Tests ported from ConstrainedGaussianFactorGraph /* ************************************************************************* */ -TEST( GaussianFactorGraph, constrained_simple ) +TEST( GaussianFactorGraphOrdered, constrained_simple ) { // get a graph with a constraint in it - GaussianFactorGraph fg = createSimpleConstraintGraph(); + GaussianFactorGraphOrdered fg = createSimpleConstraintGraph(); EXPECT(hasConstraints(fg)); // eliminate and solve - VectorValues actual = *GaussianSequentialSolver(fg).optimize(); + VectorValuesOrdered actual = *GaussianSequentialSolver(fg).optimize(); // verify - VectorValues expected = createSimpleConstraintValues(); + VectorValuesOrdered expected = createSimpleConstraintValues(); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, constrained_single ) +TEST( GaussianFactorGraphOrdered, constrained_single ) { // get a graph with a constraint in it - GaussianFactorGraph fg = createSingleConstraintGraph(); + GaussianFactorGraphOrdered fg = createSingleConstraintGraph(); EXPECT(hasConstraints(fg)); // eliminate and solve - VectorValues actual = *GaussianSequentialSolver(fg).optimize(); + VectorValuesOrdered actual = *GaussianSequentialSolver(fg).optimize(); // verify - VectorValues expected = createSingleConstraintValues(); + VectorValuesOrdered expected = createSingleConstraintValues(); EXPECT(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST( GaussianFactorGraph, constrained_multi1 ) +TEST( GaussianFactorGraphOrdered, constrained_multi1 ) { // get a graph with a constraint in it - GaussianFactorGraph fg = createMultiConstraintGraph(); + GaussianFactorGraphOrdered fg = createMultiConstraintGraph(); EXPECT(hasConstraints(fg)); // eliminate and solve - VectorValues actual = *GaussianSequentialSolver(fg).optimize(); + VectorValuesOrdered actual = *GaussianSequentialSolver(fg).optimize(); // verify - VectorValues expected = createMultiConstraintValues(); + VectorValuesOrdered expected = createMultiConstraintValues(); EXPECT(assert_equal(expected, actual)); } @@ -466,27 +466,27 @@ TEST( GaussianFactorGraph, constrained_multi1 ) static SharedDiagonal model = noiseModel::Isotropic::Sigma(2,1); /* ************************************************************************* */ -TEST(GaussianFactorGraph, replace) +TEST(GaussianFactorGraphOrdered, replace) { - Ordering ord; ord += X(1),X(2),X(3),X(4),X(5),X(6); + OrderingOrdered ord; ord += X(1),X(2),X(3),X(4),X(5),X(6); SharedDiagonal noise(noiseModel::Isotropic::Sigma(3, 1.0)); - GaussianFactorGraph::sharedFactor f1(new JacobianFactor( + GaussianFactorGraphOrdered::sharedFactor f1(new JacobianFactorOrdered( ord[X(1)], eye(3,3), ord[X(2)], eye(3,3), zero(3), noise)); - GaussianFactorGraph::sharedFactor f2(new JacobianFactor( + GaussianFactorGraphOrdered::sharedFactor f2(new JacobianFactorOrdered( ord[X(2)], eye(3,3), ord[X(3)], eye(3,3), zero(3), noise)); - GaussianFactorGraph::sharedFactor f3(new JacobianFactor( + GaussianFactorGraphOrdered::sharedFactor f3(new JacobianFactorOrdered( ord[X(3)], eye(3,3), ord[X(4)], eye(3,3), zero(3), noise)); - GaussianFactorGraph::sharedFactor f4(new JacobianFactor( + GaussianFactorGraphOrdered::sharedFactor f4(new JacobianFactorOrdered( ord[X(5)], eye(3,3), ord[X(6)], eye(3,3), zero(3), noise)); - GaussianFactorGraph actual; + GaussianFactorGraphOrdered actual; actual.push_back(f1); actual.push_back(f2); actual.push_back(f3); actual.replace(0, f4); - GaussianFactorGraph expected; + GaussianFactorGraphOrdered expected; expected.push_back(f4); expected.push_back(f2); expected.push_back(f3); @@ -495,35 +495,35 @@ TEST(GaussianFactorGraph, replace) } /* ************************************************************************* */ -TEST(GaussianFactorGraph, createSmoother2) +TEST(GaussianFactorGraphOrdered, createSmoother2) { using namespace example; - GaussianFactorGraph fg2; - Ordering ordering; + GaussianFactorGraphOrdered fg2; + OrderingOrdered ordering; boost::tie(fg2,ordering) = createSmoother(3); LONGS_EQUAL(5,fg2.size()); // eliminate vector x3var; x3var.push_back(ordering[X(3)]); vector x1var; x1var.push_back(ordering[X(1)]); - GaussianBayesNet p_x3 = *GaussianSequentialSolver( + GaussianBayesNetOrdered p_x3 = *GaussianSequentialSolver( *GaussianSequentialSolver(fg2).jointFactorGraph(x3var)).eliminate(); - GaussianBayesNet p_x1 = *GaussianSequentialSolver( + GaussianBayesNetOrdered p_x1 = *GaussianSequentialSolver( *GaussianSequentialSolver(fg2).jointFactorGraph(x1var)).eliminate(); CHECK(assert_equal(*p_x1.back(),*p_x3.front())); // should be the same because of symmetry } /* ************************************************************************* */ -TEST(GaussianFactorGraph, hasConstraints) +TEST(GaussianFactorGraphOrdered, hasConstraints) { - FactorGraph fgc1 = createMultiConstraintGraph(); + FactorGraphOrdered fgc1 = createMultiConstraintGraph(); EXPECT(hasConstraints(fgc1)); - FactorGraph fgc2 = createSimpleConstraintGraph() ; + FactorGraphOrdered fgc2 = createSimpleConstraintGraph() ; EXPECT(hasConstraints(fgc2)); - Ordering ordering; ordering += X(1), X(2), L(1); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += X(1), X(2), L(1); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); EXPECT(!hasConstraints(fg)); } @@ -534,7 +534,7 @@ TEST(GaussianFactorGraph, hasConstraints) #include /* ************************************************************************* */ -TEST( GaussianFactorGraph, conditional_sigma_failure) { +TEST( GaussianFactorGraphOrdered, conditional_sigma_failure) { // This system derives from a failure case in DDF in which a Bayes Tree // has non-unit sigmas for conditionals in the Bayes Tree, which // should never happen by construction @@ -578,17 +578,17 @@ TEST( GaussianFactorGraph, conditional_sigma_failure) { factors.add(RangeFactor(xC1, l32, relElevation, elevationModel)); factors.add(RangeFactor(xC1, l41, relElevation, elevationModel)); - Ordering orderingC; orderingC += xC1, l32, l41; + OrderingOrdered orderingC; orderingC += xC1, l32, l41; // Check that sigmas are correct (i.e., unit) - GaussianFactorGraph lfg = *factors.linearize(initValues, orderingC); + GaussianFactorGraphOrdered lfg = *factors.linearize(initValues, orderingC); GaussianMultifrontalSolver solver(lfg, false); - GaussianBayesTree actBT = *solver.eliminate(); + GaussianBayesTreeOrdered actBT = *solver.eliminate(); // Check that all sigmas in an unconstrained bayes tree are set to one - BOOST_FOREACH(const GaussianBayesTree::sharedClique& clique, actBT.nodes()) { - GaussianConditional::shared_ptr conditional = clique->conditional(); + BOOST_FOREACH(const GaussianBayesTreeOrdered::sharedClique& clique, actBT.nodes()) { + GaussianConditionalOrdered::shared_ptr conditional = clique->conditional(); size_t dim = conditional->dim(); EXPECT(assert_equal(gtsam::ones(dim), conditional->get_sigmas(), tol)); } diff --git a/tests/testGaussianFactorObsolete.cpp b/tests/testGaussianFactorObsolete.cpp index 62cad80ca..9dd7f27ba 100644 --- a/tests/testGaussianFactorObsolete.cpp +++ b/tests/testGaussianFactorObsolete.cpp @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -47,34 +47,34 @@ static SharedDiagonal //const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); // FIXME: throws exception /* ************************************************************************* */ -TEST( GaussianFactor, linearFactor ) +TEST( GaussianFactorOrdered, linearFactor ) { const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); - Ordering ordering; ordering += kx1,kx2,kl1; + OrderingOrdered ordering; ordering += kx1,kx2,kl1; Matrix I = eye(2); Vector b = Vector_(2, 2.0, -1.0); - JacobianFactor expected(ordering[kx1], -10*I,ordering[kx2], 10*I, b, noiseModel::Unit::Create(2)); + JacobianFactorOrdered expected(ordering[kx1], -10*I,ordering[kx2], 10*I, b, noiseModel::Unit::Create(2)); // create a small linear factor graph - GaussianFactorGraph fg = example::createGaussianFactorGraph(ordering); + GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering); // get the factor kf2 from the factor graph - JacobianFactor::shared_ptr lf = - boost::dynamic_pointer_cast(fg[1]); + JacobianFactorOrdered::shared_ptr lf = + boost::dynamic_pointer_cast(fg[1]); // check if the two factors are the same EXPECT(assert_equal(expected,*lf)); } /* ************************************************************************* */ -TEST( GaussianFactor, getDim ) +TEST( GaussianFactorOrdered, getDim ) { const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); // get a factor - Ordering ordering; ordering += kx1,kx2,kl1; - GaussianFactorGraph fg = example::createGaussianFactorGraph(ordering); - GaussianFactor::shared_ptr factor = fg[0]; + OrderingOrdered ordering; ordering += kx1,kx2,kl1; + GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering); + GaussianFactorOrdered::shared_ptr factor = fg[0]; // get the size of a variable size_t actual = factor->getDim(factor->find(ordering[kx1])); @@ -85,18 +85,18 @@ TEST( GaussianFactor, getDim ) } /* ************************************************************************* */ -TEST( GaussianFactor, error ) +TEST( GaussianFactorOrdered, error ) { const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); // create a small linear factor graph - Ordering ordering; ordering += kx1,kx2,kl1; - GaussianFactorGraph fg = example::createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += kx1,kx2,kl1; + GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering); // get the first factor from the factor graph - GaussianFactor::shared_ptr lf = fg[0]; + GaussianFactorOrdered::shared_ptr lf = fg[0]; // check the error of the first factor with noisy config - VectorValues cfg = example::createZeroDelta(ordering); + VectorValuesOrdered cfg = example::createZeroDelta(ordering); // calculate the error from the factor kf1 // note the error is the same as in testNonlinearFactor @@ -105,21 +105,21 @@ TEST( GaussianFactor, error ) } /* ************************************************************************* */ -TEST( GaussianFactor, matrix ) +TEST( GaussianFactorOrdered, matrix ) { const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); // create a small linear factor graph - Ordering ordering; ordering += kx1,kx2,kl1; - GaussianFactorGraph fg = example::createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += kx1,kx2,kl1; + GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering); // get the factor kf2 from the factor graph - //GaussianFactor::shared_ptr lf = fg[1]; // NOTE: using the older version + //GaussianFactorOrdered::shared_ptr lf = fg[1]; // NOTE: using the older version Vector b2 = Vector_(2, 0.2, -0.1); Matrix I = eye(2); // render with a given ordering - Ordering ord; + OrderingOrdered ord; ord += kx1,kx2; - JacobianFactor::shared_ptr lf(new JacobianFactor(ord[kx1], -I, ord[kx2], I, b2, sigma0_1)); + JacobianFactorOrdered::shared_ptr lf(new JacobianFactorOrdered(ord[kx1], -I, ord[kx2], I, b2, sigma0_1)); // Test whitened version Matrix A_act1; Vector b_act1; @@ -154,21 +154,21 @@ TEST( GaussianFactor, matrix ) } /* ************************************************************************* */ -TEST( GaussianFactor, matrix_aug ) +TEST( GaussianFactorOrdered, matrix_aug ) { const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); // create a small linear factor graph - Ordering ordering; ordering += kx1,kx2,kl1; - GaussianFactorGraph fg = example::createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += kx1,kx2,kl1; + GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering); // get the factor kf2 from the factor graph - //GaussianFactor::shared_ptr lf = fg[1]; + //GaussianFactorOrdered::shared_ptr lf = fg[1]; Vector b2 = Vector_(2, 0.2, -0.1); Matrix I = eye(2); // render with a given ordering - Ordering ord; + OrderingOrdered ord; ord += kx1,kx2; - JacobianFactor::shared_ptr lf(new JacobianFactor(ord[kx1], -I, ord[kx2], I, b2, sigma0_1)); + JacobianFactorOrdered::shared_ptr lf(new JacobianFactorOrdered(ord[kx1], -I, ord[kx2], I, b2, sigma0_1)); // Test unwhitened version @@ -206,17 +206,17 @@ void print(const list& i) { } /* ************************************************************************* */ -TEST( GaussianFactor, size ) +TEST( GaussianFactorOrdered, size ) { // create a linear factor graph const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); - Ordering ordering; ordering += kx1,kx2,kl1; - GaussianFactorGraph fg = example::createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += kx1,kx2,kl1; + GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering); // get some factors from the graph - boost::shared_ptr factor1 = fg[0]; - boost::shared_ptr factor2 = fg[1]; - boost::shared_ptr factor3 = fg[2]; + boost::shared_ptr factor1 = fg[0]; + boost::shared_ptr factor2 = fg[1]; + boost::shared_ptr factor3 = fg[2]; EXPECT_LONGS_EQUAL(1, factor1->size()); EXPECT_LONGS_EQUAL(2, factor2->size()); diff --git a/tests/testGaussianISAM.cpp b/tests/testGaussianISAM.cpp index 60d5db672..e6aad0864 100644 --- a/tests/testGaussianISAM.cpp +++ b/tests/testGaussianISAM.cpp @@ -16,13 +16,13 @@ */ #include -#include +#include #include -#include -#include +#include +#include #include #include -#include +#include #include #include @@ -44,29 +44,29 @@ using symbol_shorthand::L; static const double tol = 1e-4; /* ************************************************************************* */ -TEST( ISAM, iSAM_smoother ) +TEST( ISAMOrdered, iSAM_smoother ) { - Ordering ordering; + OrderingOrdered ordering; for (int t = 1; t <= 7; t++) ordering += X(t); // Create smoother with 7 nodes - GaussianFactorGraph smoother = createSmoother(7, ordering).first; + GaussianFactorGraphOrdered smoother = createSmoother(7, ordering).first; // run iSAM for every factor - GaussianISAM actual; - BOOST_FOREACH(boost::shared_ptr factor, smoother) { - GaussianFactorGraph factorGraph; + GaussianISAMOrdered actual; + BOOST_FOREACH(boost::shared_ptr factor, smoother) { + GaussianFactorGraphOrdered factorGraph; factorGraph.push_back(factor); actual.update(factorGraph); } // Create expected Bayes Tree by solving smoother with "natural" ordering - BayesTree::shared_ptr bayesTree = GaussianMultifrontalSolver(smoother).eliminate(); - GaussianISAM expected(*bayesTree); + BayesTreeOrdered::shared_ptr bayesTree = GaussianMultifrontalSolver(smoother).eliminate(); + GaussianISAMOrdered expected(*bayesTree); // Verify sigmas in the bayes tree - BOOST_FOREACH(const GaussianBayesTree::sharedClique& clique, bayesTree->nodes()) { - GaussianConditional::shared_ptr conditional = clique->conditional(); + BOOST_FOREACH(const GaussianBayesTreeOrdered::sharedClique& clique, bayesTree->nodes()) { + GaussianConditionalOrdered::shared_ptr conditional = clique->conditional(); size_t dim = conditional->dim(); EXPECT(assert_equal(gtsam::ones(dim), conditional->get_sigmas(), tol)); } @@ -75,8 +75,8 @@ TEST( ISAM, iSAM_smoother ) EXPECT(assert_equal(expected, actual)); // obtain solution - VectorValues e(VectorValues::Zero(7,2)); // expected solution - VectorValues optimized = optimize(actual); // actual solution + VectorValuesOrdered e(VectorValuesOrdered::Zero(7,2)); // expected solution + VectorValuesOrdered optimized = optimize(actual); // actual solution EXPECT(assert_equal(e, optimized)); } diff --git a/tests/testGaussianISAM2.cpp b/tests/testGaussianISAM2.cpp index aa169c3a0..fd4b31348 100644 --- a/tests/testGaussianISAM2.cpp +++ b/tests/testGaussianISAM2.cpp @@ -9,12 +9,12 @@ #include #include #include -#include -#include +#include +#include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -152,21 +152,21 @@ TEST_UNSAFE(ISAM2, ImplAddVariables) { Values newTheta; newTheta.insert(1, Pose2(.6, .7, .8)); - VectorValues delta; + VectorValuesOrdered delta; delta.insert(0, Vector_(3, .1, .2, .3)); delta.insert(1, Vector_(2, .4, .5)); - VectorValues deltaNewton; + VectorValuesOrdered deltaNewton; deltaNewton.insert(0, Vector_(3, .1, .2, .3)); deltaNewton.insert(1, Vector_(2, .4, .5)); - VectorValues deltaRg; + VectorValuesOrdered deltaRg; deltaRg.insert(0, Vector_(3, .1, .2, .3)); deltaRg.insert(1, Vector_(2, .4, .5)); vector replacedKeys(2, false); - Ordering ordering; ordering += 100, 0; + OrderingOrdered ordering; ordering += 100, 0; // Verify initial state LONGS_EQUAL(0, ordering[100]); @@ -180,24 +180,24 @@ TEST_UNSAFE(ISAM2, ImplAddVariables) { thetaExpected.insert(100, Point2(.4, .5)); thetaExpected.insert(1, Pose2(.6, .7, .8)); - VectorValues deltaExpected; + VectorValuesOrdered deltaExpected; deltaExpected.insert(0, Vector_(3, .1, .2, .3)); deltaExpected.insert(1, Vector_(2, .4, .5)); deltaExpected.insert(2, Vector_(3, 0.0, 0.0, 0.0)); - VectorValues deltaNewtonExpected; + VectorValuesOrdered deltaNewtonExpected; deltaNewtonExpected.insert(0, Vector_(3, .1, .2, .3)); deltaNewtonExpected.insert(1, Vector_(2, .4, .5)); deltaNewtonExpected.insert(2, Vector_(3, 0.0, 0.0, 0.0)); - VectorValues deltaRgExpected; + VectorValuesOrdered deltaRgExpected; deltaRgExpected.insert(0, Vector_(3, .1, .2, .3)); deltaRgExpected.insert(1, Vector_(2, .4, .5)); deltaRgExpected.insert(2, Vector_(3, 0.0, 0.0, 0.0)); vector replacedKeysExpected(3, false); - Ordering orderingExpected; orderingExpected += 100, 0, 1; + OrderingOrdered orderingExpected; orderingExpected += 100, 0, 1; // Expand initial state ISAM2::Impl::AddVariables(newTheta, theta, delta, deltaNewton, deltaRg, replacedKeys, ordering); @@ -219,22 +219,22 @@ TEST_UNSAFE(ISAM2, ImplRemoveVariables) { theta.insert(1, Pose2(.6, .7, .8)); theta.insert(100, Point2(.4, .5)); - SymbolicFactorGraph sfg; - sfg.push_back(boost::make_shared(Index(0), Index(2))); - sfg.push_back(boost::make_shared(Index(0), Index(1))); - VariableIndex variableIndex(sfg); + SymbolicFactorGraphOrdered sfg; + sfg.push_back(boost::make_shared(Index(0), Index(2))); + sfg.push_back(boost::make_shared(Index(0), Index(1))); + VariableIndexOrdered variableIndex(sfg); - VectorValues delta; + VectorValuesOrdered delta; delta.insert(0, Vector_(3, .1, .2, .3)); delta.insert(1, Vector_(3, .4, .5, .6)); delta.insert(2, Vector_(2, .7, .8)); - VectorValues deltaNewton; + VectorValuesOrdered deltaNewton; deltaNewton.insert(0, Vector_(3, .1, .2, .3)); deltaNewton.insert(1, Vector_(3, .4, .5, .6)); deltaNewton.insert(2, Vector_(2, .7, .8)); - VectorValues deltaRg; + VectorValuesOrdered deltaRg; deltaRg.insert(0, Vector_(3, .1, .2, .3)); deltaRg.insert(1, Vector_(3, .4, .5, .6)); deltaRg.insert(2, Vector_(2, .7, .8)); @@ -244,7 +244,7 @@ TEST_UNSAFE(ISAM2, ImplRemoveVariables) { replacedKeys[1] = false; replacedKeys[2] = true; - Ordering ordering; ordering += 100, 1, 0; + OrderingOrdered ordering; ordering += 100, 1, 0; ISAM2::Nodes nodes(3); @@ -258,26 +258,26 @@ TEST_UNSAFE(ISAM2, ImplRemoveVariables) { thetaExpected.insert(0, Pose2(.1, .2, .3)); thetaExpected.insert(100, Point2(.4, .5)); - SymbolicFactorGraph sfgRemoved; - sfgRemoved.push_back(boost::make_shared(Index(0), Index(1))); - sfgRemoved.push_back(SymbolicFactorGraph::sharedFactor()); // Add empty factor to keep factor indices consistent - VariableIndex variableIndexExpected(sfgRemoved); + SymbolicFactorGraphOrdered sfgRemoved; + sfgRemoved.push_back(boost::make_shared(Index(0), Index(1))); + sfgRemoved.push_back(SymbolicFactorGraphOrdered::sharedFactor()); // Add empty factor to keep factor indices consistent + VariableIndexOrdered variableIndexExpected(sfgRemoved); - VectorValues deltaExpected; + VectorValuesOrdered deltaExpected; deltaExpected.insert(0, Vector_(3, .1, .2, .3)); deltaExpected.insert(1, Vector_(2, .7, .8)); - VectorValues deltaNewtonExpected; + VectorValuesOrdered deltaNewtonExpected; deltaNewtonExpected.insert(0, Vector_(3, .1, .2, .3)); deltaNewtonExpected.insert(1, Vector_(2, .7, .8)); - VectorValues deltaRgExpected; + VectorValuesOrdered deltaRgExpected; deltaRgExpected.insert(0, Vector_(3, .1, .2, .3)); deltaRgExpected.insert(1, Vector_(2, .7, .8)); vector replacedKeysExpected(2, true); - Ordering orderingExpected; orderingExpected += 100, 0; + OrderingOrdered orderingExpected; orderingExpected += 100, 0; ISAM2::Nodes nodesExpected(2); @@ -285,9 +285,9 @@ TEST_UNSAFE(ISAM2, ImplRemoveVariables) { FastSet unusedKeys; unusedKeys.insert(1); vector removedFactorsI; removedFactorsI.push_back(1); - SymbolicFactorGraph removedFactors; removedFactors.push_back(sfg[1]); + SymbolicFactorGraphOrdered removedFactors; removedFactors.push_back(sfg[1]); variableIndex.remove(removedFactorsI, removedFactors); - GaussianFactorGraph linearFactors; + GaussianFactorGraphOrdered linearFactors; FastSet fixedVariables; ISAM2::Impl::RemoveVariables(unusedKeys, ISAM2::sharedClique(), theta, variableIndex, delta, deltaNewton, deltaRg, replacedKeys, ordering, nodes, linearFactors, fixedVariables); @@ -307,7 +307,7 @@ TEST_UNSAFE(ISAM2, ImplRemoveVariables) { // using namespace gtsam::planarSLAM; // typedef GaussianISAM2::Impl Impl; // -// Ordering ordering; ordering += (0), (0), (1); +// OrderingOrdered ordering; ordering += (0), (0), (1); // NonlinearFactorGraph graph; // graph.add(PriorFactor((0), Pose2(), noiseModel::Unit::Create(Pose2::dimension)); // graph.addRange((0), (0), 1.0, noiseModel::Unit::Create(1)); @@ -327,7 +327,7 @@ TEST_UNSAFE(ISAM2, ImplRemoveVariables) { // typedef GaussianISAM2::Impl Impl; // // // Create values where indices 1 and 3 are above the threshold of 0.1 -// VectorValues values; +// VectorValuesOrdered values; // values.reserve(4, 10); // values.push_back_preallocated(Vector_(2, 0.09, 0.09)); // values.push_back_preallocated(Vector_(3, 0.11, 0.11, 0.09)); @@ -341,7 +341,7 @@ TEST_UNSAFE(ISAM2, ImplRemoveVariables) { // permutation[2] = 1; // permutation[3] = 3; // -// Permuted permuted(permutation, values); +// Permuted permuted(permutation, values); // // // After permutation, the indices above the threshold are 2 and 2 // FastSet expected; @@ -367,19 +367,19 @@ TEST(ISAM2, optimize2) { 10, 0.0, 0.0, 0.0, 10, 0.0, 0.0, 0.0, 31.8309886; - GaussianConditional::shared_ptr conditional(new GaussianConditional(0, d, R, Vector::Ones(3))); + GaussianConditionalOrdered::shared_ptr conditional(new GaussianConditionalOrdered(0, d, R, Vector::Ones(3))); // Create ordering - Ordering ordering; ordering += (0); + OrderingOrdered ordering; ordering += (0); // Expected vector - VectorValues expected(1, 3); + VectorValuesOrdered expected(1, 3); conditional->solveInPlace(expected); // Clique ISAM2::sharedClique clique( - ISAM2::Clique::Create(make_pair(conditional,GaussianFactor::shared_ptr()))); - VectorValues actual(theta.dims(ordering)); + ISAM2::Clique::Create(make_pair(conditional,GaussianFactorOrdered::shared_ptr()))); + VectorValuesOrdered actual(theta.dims(ordering)); internal::optimizeInPlace(clique, actual); // expected.print("expected: "); @@ -394,12 +394,12 @@ bool isam_check(const NonlinearFactorGraph& fullgraph, const Values& fullinit, c const std::string name_ = test.getName(); Values actual = isam.calculateEstimate(); - Ordering ordering = isam.getOrdering(); // *fullgraph.orderingCOLAMD(fullinit).first; - GaussianFactorGraph linearized = *fullgraph.linearize(fullinit, ordering); + OrderingOrdered ordering = isam.getOrdering(); // *fullgraph.orderingCOLAMD(fullinit).first; + GaussianFactorGraphOrdered linearized = *fullgraph.linearize(fullinit, ordering); // linearized.print("Expected linearized: "); - GaussianBayesNet gbn = *GaussianSequentialSolver(linearized).eliminate(); + GaussianBayesNetOrdered gbn = *GaussianSequentialSolver(linearized).eliminate(); // gbn.print("Expected bayesnet: "); - VectorValues delta = optimize(gbn); + VectorValuesOrdered delta = optimize(gbn); Values expected = fullinit.retract(delta, ordering); bool isamEqual = assert_equal(expected, actual); @@ -411,13 +411,13 @@ bool isam_check(const NonlinearFactorGraph& fullgraph, const Values& fullinit, c typedef ISAM2::sharedClique sharedClique; BOOST_FOREACH(const sharedClique& clique, isam.nodes()) { // Compute expected gradient - FactorGraph jfg; - jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional()))); - VectorValues expectedGradient(*allocateVectorValues(isam)); + FactorGraphOrdered jfg; + jfg.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(*clique->conditional()))); + VectorValuesOrdered expectedGradient(*allocateVectorValues(isam)); gradientAtZero(jfg, expectedGradient); // Compare with actual gradients int variablePosition = 0; - for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) { + for(GaussianConditionalOrdered::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) { const int dim = clique->conditional()->dim(jit); Vector actual = clique->gradientContribution().segment(variablePosition, dim); bool gradOk = assert_equal(expectedGradient[*jit], actual); @@ -431,10 +431,10 @@ bool isam_check(const NonlinearFactorGraph& fullgraph, const Values& fullinit, c } // Check gradient - VectorValues expectedGradient(*allocateVectorValues(isam)); - gradientAtZero(FactorGraph(isam), expectedGradient); - VectorValues expectedGradient2(gradient(FactorGraph(isam), VectorValues::Zero(expectedGradient))); - VectorValues actualGradient(*allocateVectorValues(isam)); + VectorValuesOrdered expectedGradient(*allocateVectorValues(isam)); + gradientAtZero(FactorGraphOrdered(isam), expectedGradient); + VectorValuesOrdered expectedGradient2(gradient(FactorGraphOrdered(isam), VectorValuesOrdered::Zero(expectedGradient))); + VectorValuesOrdered actualGradient(*allocateVectorValues(isam)); gradientAtZero(isam, actualGradient); bool expectedGradOk = assert_equal(expectedGradient2, expectedGradient); EXPECT(expectedGradOk); @@ -531,49 +531,49 @@ TEST(ISAM2, permute_cached) { typedef boost::shared_ptr sharedISAM2Clique; // Construct expected permuted BayesTree (variable 2 has been changed to 1) - BayesTree expected; + BayesTreeOrdered expected; expected.insert(sharedISAM2Clique(new ISAM2Clique(make_pair( - boost::make_shared(pair_list_of + boost::make_shared(pair_list_of (3, Matrix_(1,1,1.0)) (4, Matrix_(1,1,2.0)), 2, Vector_(1,1.0), Vector_(1,1.0)), // p(3,4) - HessianFactor::shared_ptr())))); // Cached: empty + HessianFactorOrdered::shared_ptr())))); // Cached: empty expected.insert(sharedISAM2Clique(new ISAM2Clique(make_pair( - boost::make_shared(pair_list_of + boost::make_shared(pair_list_of (2, Matrix_(1,1,1.0)) (3, Matrix_(1,1,2.0)), 1, Vector_(1,1.0), Vector_(1,1.0)), // p(2|3) - boost::make_shared(3, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(3) + boost::make_shared(3, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(3) expected.insert(sharedISAM2Clique(new ISAM2Clique(make_pair( - boost::make_shared(pair_list_of + boost::make_shared(pair_list_of (0, Matrix_(1,1,1.0)) (2, Matrix_(1,1,2.0)), 1, Vector_(1,1.0), Vector_(1,1.0)), // p(0|2) - boost::make_shared(1, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(1) + boost::make_shared(1, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(1) // Change variable 2 to 1 expected.root()->children().front()->conditional()->keys()[0] = 1; expected.root()->children().front()->children().front()->conditional()->keys()[1] = 1; // Construct unpermuted BayesTree - BayesTree actual; + BayesTreeOrdered actual; actual.insert(sharedISAM2Clique(new ISAM2Clique(make_pair( - boost::make_shared(pair_list_of + boost::make_shared(pair_list_of (3, Matrix_(1,1,1.0)) (4, Matrix_(1,1,2.0)), 2, Vector_(1,1.0), Vector_(1,1.0)), // p(3,4) - HessianFactor::shared_ptr())))); // Cached: empty + HessianFactorOrdered::shared_ptr())))); // Cached: empty actual.insert(sharedISAM2Clique(new ISAM2Clique(make_pair( - boost::make_shared(pair_list_of + boost::make_shared(pair_list_of (2, Matrix_(1,1,1.0)) (3, Matrix_(1,1,2.0)), 1, Vector_(1,1.0), Vector_(1,1.0)), // p(2|3) - boost::make_shared(3, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(3) + boost::make_shared(3, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(3) actual.insert(sharedISAM2Clique(new ISAM2Clique(make_pair( - boost::make_shared(pair_list_of + boost::make_shared(pair_list_of (0, Matrix_(1,1,1.0)) (2, Matrix_(1,1,2.0)), 1, Vector_(1,1.0), Vector_(1,1.0)), // p(0|2) - boost::make_shared(2, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(2) + boost::make_shared(2, Matrix_(1,1,1.0), Vector_(1,1.0), 0.0))))); // Cached: p(2) // Create permutation that changes variable 2 -> 0 Permutation permutation = Permutation::Identity(5); @@ -664,13 +664,13 @@ TEST_UNSAFE(ISAM2, swapFactors) typedef ISAM2::sharedClique sharedClique; BOOST_FOREACH(const sharedClique& clique, isam.nodes()) { // Compute expected gradient - FactorGraph jfg; - jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional()))); - VectorValues expectedGradient(*allocateVectorValues(isam)); + FactorGraphOrdered jfg; + jfg.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(*clique->conditional()))); + VectorValuesOrdered expectedGradient(*allocateVectorValues(isam)); gradientAtZero(jfg, expectedGradient); // Compare with actual gradients int variablePosition = 0; - for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) { + for(GaussianConditionalOrdered::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) { const int dim = clique->conditional()->dim(jit); Vector actual = clique->gradientContribution().segment(variablePosition, dim); EXPECT(assert_equal(expectedGradient[*jit], actual)); @@ -680,10 +680,10 @@ TEST_UNSAFE(ISAM2, swapFactors) } // Check gradient - VectorValues expectedGradient(*allocateVectorValues(isam)); - gradientAtZero(FactorGraph(isam), expectedGradient); - VectorValues expectedGradient2(gradient(FactorGraph(isam), VectorValues::Zero(expectedGradient))); - VectorValues actualGradient(*allocateVectorValues(isam)); + VectorValuesOrdered expectedGradient(*allocateVectorValues(isam)); + gradientAtZero(FactorGraphOrdered(isam), expectedGradient); + VectorValuesOrdered expectedGradient2(gradient(FactorGraphOrdered(isam), VectorValuesOrdered::Zero(expectedGradient))); + VectorValuesOrdered actualGradient(*allocateVectorValues(isam)); gradientAtZero(isam, actualGradient); EXPECT(assert_equal(expectedGradient2, expectedGradient)); EXPECT(assert_equal(expectedGradient, actualGradient)); @@ -795,13 +795,13 @@ TEST(ISAM2, constrained_ordering) typedef ISAM2::sharedClique sharedClique; BOOST_FOREACH(const sharedClique& clique, isam.nodes()) { // Compute expected gradient - FactorGraph jfg; - jfg.push_back(JacobianFactor::shared_ptr(new JacobianFactor(*clique->conditional()))); - VectorValues expectedGradient(*allocateVectorValues(isam)); + FactorGraphOrdered jfg; + jfg.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(*clique->conditional()))); + VectorValuesOrdered expectedGradient(*allocateVectorValues(isam)); gradientAtZero(jfg, expectedGradient); // Compare with actual gradients int variablePosition = 0; - for(GaussianConditional::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) { + for(GaussianConditionalOrdered::const_iterator jit = clique->conditional()->begin(); jit != clique->conditional()->end(); ++jit) { const int dim = clique->conditional()->dim(jit); Vector actual = clique->gradientContribution().segment(variablePosition, dim); EXPECT(assert_equal(expectedGradient[*jit], actual)); @@ -811,10 +811,10 @@ TEST(ISAM2, constrained_ordering) } // Check gradient - VectorValues expectedGradient(*allocateVectorValues(isam)); - gradientAtZero(FactorGraph(isam), expectedGradient); - VectorValues expectedGradient2(gradient(FactorGraph(isam), VectorValues::Zero(expectedGradient))); - VectorValues actualGradient(*allocateVectorValues(isam)); + VectorValuesOrdered expectedGradient(*allocateVectorValues(isam)); + gradientAtZero(FactorGraphOrdered(isam), expectedGradient); + VectorValuesOrdered expectedGradient2(gradient(FactorGraphOrdered(isam), VectorValuesOrdered::Zero(expectedGradient))); + VectorValuesOrdered actualGradient(*allocateVectorValues(isam)); gradientAtZero(isam, actualGradient); EXPECT(assert_equal(expectedGradient2, expectedGradient)); EXPECT(assert_equal(expectedGradient, actualGradient)); @@ -844,9 +844,9 @@ namespace { toKeep.push_back(i); // Calculate expected marginal from iSAM2 tree - GaussianFactorGraph isamAsGraph(isam); + GaussianFactorGraphOrdered isamAsGraph(isam); GaussianSequentialSolver solver(isamAsGraph); - GaussianFactorGraph marginalgfg = *solver.jointFactorGraph(toKeep); + GaussianFactorGraphOrdered marginalgfg = *solver.jointFactorGraph(toKeep); expectedAugmentedHessian = marginalgfg.augmentedHessian(); //// Calculate expected marginal from cached linear factors @@ -864,7 +864,7 @@ namespace { isam.marginalizeLeaves(leafKeys); // Check - GaussianFactorGraph actualMarginalGraph(isam); + GaussianFactorGraphOrdered actualMarginalGraph(isam); Matrix actualAugmentedHessian = actualMarginalGraph.augmentedHessian(); //Matrix actual2AugmentedHessian = linearFactors_.augmentedHessian(); Matrix actual3AugmentedHessian = isam.getFactorsUnsafe().linearize( diff --git a/tests/testGaussianJunctionTreeB.cpp b/tests/testGaussianJunctionTreeB.cpp index b24b2b901..13fcf5ccb 100644 --- a/tests/testGaussianJunctionTreeB.cpp +++ b/tests/testGaussianJunctionTreeB.cpp @@ -21,12 +21,12 @@ #include #include #include -#include +#include #include -#include +#include #include #include -#include +#include #include #include #include @@ -59,11 +59,11 @@ using symbol_shorthand::L; TEST( GaussianJunctionTreeB, constructor2 ) { // create a graph - Ordering ordering; ordering += X(1),X(3),X(5),X(7),X(2),X(6),X(4); - GaussianFactorGraph fg = createSmoother(7, ordering).first; + OrderingOrdered ordering; ordering += X(1),X(3),X(5),X(7),X(2),X(6),X(4); + GaussianFactorGraphOrdered fg = createSmoother(7, ordering).first; // create an ordering - GaussianJunctionTree actual(fg); + GaussianJunctionTreeOrdered actual(fg); vector frontal1; frontal1 += ordering[X(5)], ordering[X(6)], ordering[X(4)]; vector frontal2; frontal2 += ordering[X(3)], ordering[X(2)]; @@ -76,10 +76,10 @@ TEST( GaussianJunctionTreeB, constructor2 ) EXPECT(assert_equal(frontal1, actual.root()->frontal)); EXPECT(assert_equal(sep1, actual.root()->separator)); LONGS_EQUAL(5, actual.root()->size()); - list::const_iterator child0it = actual.root()->children().begin(); - list::const_iterator child1it = child0it; ++child1it; - GaussianJunctionTree::sharedClique child0 = *child0it; - GaussianJunctionTree::sharedClique child1 = *child1it; + list::const_iterator child0it = actual.root()->children().begin(); + list::const_iterator child1it = child0it; ++child1it; + GaussianJunctionTreeOrdered::sharedClique child0 = *child0it; + GaussianJunctionTreeOrdered::sharedClique child1 = *child1it; EXPECT(assert_equal(frontal2, child0->frontal)); EXPECT(assert_equal(sep2, child0->separator)); LONGS_EQUAL(4, child0->size()); @@ -95,16 +95,16 @@ TEST( GaussianJunctionTreeB, constructor2 ) TEST( GaussianJunctionTreeB, optimizeMultiFrontal ) { // create a graph - GaussianFactorGraph fg; - Ordering ordering; + GaussianFactorGraphOrdered fg; + OrderingOrdered ordering; boost::tie(fg,ordering) = createSmoother(7); // optimize the graph - GaussianJunctionTree tree(fg); - VectorValues actual = tree.optimize(&EliminateQR); + GaussianJunctionTreeOrdered tree(fg); + VectorValuesOrdered actual = tree.optimize(&EliminateQROrdered); // verify - VectorValues expected(vector(7,2)); // expected solution + VectorValuesOrdered expected(vector(7,2)); // expected solution Vector v = Vector_(2, 0., 0.); for (int i=1; i<=7; i++) expected[ordering[X(i)]] = v; @@ -117,15 +117,15 @@ TEST( GaussianJunctionTreeB, optimizeMultiFrontal2) // create a graph example::Graph nlfg = createNonlinearFactorGraph(); Values noisy = createNoisyValues(); - Ordering ordering; ordering += X(1),X(2),L(1); - GaussianFactorGraph fg = *nlfg.linearize(noisy, ordering); + OrderingOrdered ordering; ordering += X(1),X(2),L(1); + GaussianFactorGraphOrdered fg = *nlfg.linearize(noisy, ordering); // optimize the graph - GaussianJunctionTree tree(fg); - VectorValues actual = tree.optimize(&EliminateQR); + GaussianJunctionTreeOrdered tree(fg); + VectorValuesOrdered actual = tree.optimize(&EliminateQROrdered); // verify - VectorValues expected = createCorrectDelta(ordering); // expected solution + VectorValuesOrdered expected = createCorrectDelta(ordering); // expected solution EXPECT(assert_equal(expected,actual)); } @@ -177,15 +177,15 @@ TEST(GaussianJunctionTreeB, slamlike) { ++ i; // Compare solutions - Ordering ordering = *fullgraph.orderingCOLAMD(init); - GaussianFactorGraph linearized = *fullgraph.linearize(init, ordering); + OrderingOrdered ordering = *fullgraph.orderingCOLAMD(init); + GaussianFactorGraphOrdered linearized = *fullgraph.linearize(init, ordering); - GaussianJunctionTree gjt(linearized); - VectorValues deltaactual = gjt.optimize(&EliminateQR); + GaussianJunctionTreeOrdered gjt(linearized); + VectorValuesOrdered deltaactual = gjt.optimize(&EliminateQROrdered); Values actual = init.retract(deltaactual, ordering); - GaussianBayesNet gbn = *GaussianSequentialSolver(linearized).eliminate(); - VectorValues delta = optimize(gbn); + GaussianBayesNetOrdered gbn = *GaussianSequentialSolver(linearized).eliminate(); + VectorValuesOrdered delta = optimize(gbn); Values expected = init.retract(delta, ordering); EXPECT(assert_equal(expected, actual)); @@ -194,7 +194,7 @@ TEST(GaussianJunctionTreeB, slamlike) { /* ************************************************************************* */ TEST(GaussianJunctionTreeB, simpleMarginal) { - typedef BayesTree GaussianBayesTree; + typedef BayesTreeOrdered GaussianBayesTree; // Create a simple graph NonlinearFactorGraph fg; @@ -205,10 +205,10 @@ TEST(GaussianJunctionTreeB, simpleMarginal) { init.insert(X(0), Pose2()); init.insert(X(1), Pose2(1.0, 0.0, 0.0)); - Ordering ordering; + OrderingOrdered ordering; ordering += X(1), X(0); - GaussianFactorGraph gfg = *fg.linearize(init, ordering); + GaussianFactorGraphOrdered gfg = *fg.linearize(init, ordering); // Compute marginals with both sequential and multifrontal Matrix expected = GaussianSequentialSolver(gfg).marginalCovariance(1); @@ -216,15 +216,15 @@ TEST(GaussianJunctionTreeB, simpleMarginal) { Matrix actual1 = GaussianMultifrontalSolver(gfg).marginalCovariance(1); // Compute marginal directly from marginal factor - GaussianFactor::shared_ptr marginalFactor = GaussianMultifrontalSolver(gfg).marginalFactor(1); - JacobianFactor::shared_ptr marginalJacobian = boost::dynamic_pointer_cast(marginalFactor); + GaussianFactorOrdered::shared_ptr marginalFactor = GaussianMultifrontalSolver(gfg).marginalFactor(1); + JacobianFactorOrdered::shared_ptr marginalJacobian = boost::dynamic_pointer_cast(marginalFactor); Matrix actual2 = inverse(marginalJacobian->getA(marginalJacobian->begin()).transpose() * marginalJacobian->getA(marginalJacobian->begin())); // Compute marginal directly from BayesTree GaussianBayesTree gbt; - gbt.insert(GaussianJunctionTree(gfg).eliminate(EliminateCholesky)); - marginalFactor = gbt.marginalFactor(1, EliminateCholesky); - marginalJacobian = boost::dynamic_pointer_cast(marginalFactor); + gbt.insert(GaussianJunctionTreeOrdered(gfg).eliminate(EliminateCholeskyOrdered)); + marginalFactor = gbt.marginalFactor(1, EliminateCholeskyOrdered); + marginalJacobian = boost::dynamic_pointer_cast(marginalFactor); Matrix actual3 = inverse(marginalJacobian->getA(marginalJacobian->begin()).transpose() * marginalJacobian->getA(marginalJacobian->begin())); EXPECT(assert_equal(expected, actual1)); diff --git a/tests/testGraph.cpp b/tests/testGraph.cpp index dc00b3f4a..0f68a03d9 100644 --- a/tests/testGraph.cpp +++ b/tests/testGraph.cpp @@ -36,7 +36,7 @@ using namespace gtsam; // x1 -> x2 // -> x3 -> x4 // -> x5 -TEST ( Ordering, predecessorMap2Keys ) { +TEST ( OrderingOrdered, predecessorMap2Keys ) { PredecessorMap p_map; p_map.insert(1,1); p_map.insert(2,1); diff --git a/tests/testInferenceB.cpp b/tests/testInferenceB.cpp index 0df25d082..64bdd480c 100644 --- a/tests/testInferenceB.cpp +++ b/tests/testInferenceB.cpp @@ -48,13 +48,13 @@ TEST( inference, marginals ) { using namespace example; // create and marginalize a small Bayes net on "x" - GaussianBayesNet cbn = createSmallGaussianBayesNet(); + GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet(); vector xvar; xvar.push_back(0); - GaussianBayesNet actual = *GaussianSequentialSolver( - *GaussianSequentialSolver(GaussianFactorGraph(cbn)).jointFactorGraph(xvar)).eliminate(); + GaussianBayesNetOrdered actual = *GaussianSequentialSolver( + *GaussianSequentialSolver(GaussianFactorGraphOrdered(cbn)).jointFactorGraph(xvar)).eliminate(); // expected is just scalar Gaussian on x - GaussianBayesNet expected = scalarGaussian(0, 4, sqrt(2.0)); + GaussianBayesNetOrdered expected = scalarGaussian(0, 4, sqrt(2.0)); CHECK(assert_equal(expected,actual)); } @@ -78,8 +78,8 @@ TEST( inference, marginals2) init.insert(X(2), Pose2(2.0,0.0,0.0)); init.insert(L(0), Point2(1.0,1.0)); - Ordering ordering(*fg.orderingCOLAMD(init)); - FactorGraph::shared_ptr gfg(fg.linearize(init, ordering)); + OrderingOrdered ordering(*fg.orderingCOLAMD(init)); + FactorGraphOrdered::shared_ptr gfg(fg.linearize(init, ordering)); GaussianMultifrontalSolver solver(*gfg); solver.marginalFactor(ordering[L(0)]); } diff --git a/tests/testIterative.cpp b/tests/testIterative.cpp index 1484052e5..80aa52ca4 100644 --- a/tests/testIterative.cpp +++ b/tests/testIterative.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -41,16 +41,16 @@ static ConjugateGradientParameters parameters; TEST( Iterative, steepestDescent ) { // Create factor graph - Ordering ordering; + OrderingOrdered ordering; ordering += L(1), X(1), X(2); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); // eliminate and solve - VectorValues expected = *GaussianSequentialSolver(fg).optimize(); + VectorValuesOrdered expected = *GaussianSequentialSolver(fg).optimize(); // Do gradient descent - VectorValues zero = VectorValues::Zero(expected); // TODO, how do we do this normally? - VectorValues actual = steepestDescent(fg, zero, parameters); + VectorValuesOrdered zero = VectorValuesOrdered::Zero(expected); // TODO, how do we do this normally? + VectorValuesOrdered actual = steepestDescent(fg, zero, parameters); CHECK(assert_equal(expected,actual,1e-2)); } @@ -58,12 +58,12 @@ TEST( Iterative, steepestDescent ) TEST( Iterative, conjugateGradientDescent ) { // Create factor graph - Ordering ordering; + OrderingOrdered ordering; ordering += L(1), X(1), X(2); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); // eliminate and solve - VectorValues expected = *GaussianSequentialSolver(fg).optimize(); + VectorValuesOrdered expected = *GaussianSequentialSolver(fg).optimize(); // get matrices Matrix A; @@ -82,8 +82,8 @@ TEST( Iterative, conjugateGradientDescent ) CHECK(assert_equal(expectedX,actualX2,1e-9)); // Do conjugate gradient descent on factor graph - VectorValues zero = VectorValues::Zero(expected); - VectorValues actual = conjugateGradientDescent(fg, zero, parameters); + VectorValuesOrdered zero = VectorValuesOrdered::Zero(expected); + VectorValuesOrdered actual = conjugateGradientDescent(fg, zero, parameters); CHECK(assert_equal(expected,actual,1e-2)); } @@ -99,19 +99,19 @@ TEST( Iterative, conjugateGradientDescent_hard_constraint ) graph.add(NonlinearEquality(X(1), pose1)); graph.add(BetweenFactor(X(1),X(2), Pose2(1.,0.,0.), noiseModel::Isotropic::Sigma(3, 1))); - Ordering ordering; + OrderingOrdered ordering; ordering += X(1), X(2); - boost::shared_ptr fg = graph.linearize(config,ordering); + boost::shared_ptr fg = graph.linearize(config,ordering); - VectorValues zeros = VectorValues::Zero(2, 3); + VectorValuesOrdered zeros = VectorValuesOrdered::Zero(2, 3); ConjugateGradientParameters parameters; parameters.setEpsilon_abs(1e-3); parameters.setEpsilon_rel(1e-5); parameters.setMaxIterations(100); - VectorValues actual = conjugateGradientDescent(*fg, zeros, parameters); + VectorValuesOrdered actual = conjugateGradientDescent(*fg, zeros, parameters); - VectorValues expected; + VectorValuesOrdered expected; expected.insert(0, zero(3)); expected.insert(1, Vector_(3,-0.5,0.,0.)); CHECK(assert_equal(expected, actual)); @@ -128,19 +128,19 @@ TEST( Iterative, conjugateGradientDescent_soft_constraint ) graph.add(PriorFactor(X(1), Pose2(0.,0.,0.), noiseModel::Isotropic::Sigma(3, 1e-10))); graph.add(BetweenFactor(X(1),X(2), Pose2(1.,0.,0.), noiseModel::Isotropic::Sigma(3, 1))); - Ordering ordering; + OrderingOrdered ordering; ordering += X(1), X(2); - boost::shared_ptr fg = graph.linearize(config,ordering); + boost::shared_ptr fg = graph.linearize(config,ordering); - VectorValues zeros = VectorValues::Zero(2, 3); + VectorValuesOrdered zeros = VectorValuesOrdered::Zero(2, 3); ConjugateGradientParameters parameters; parameters.setEpsilon_abs(1e-3); parameters.setEpsilon_rel(1e-5); parameters.setMaxIterations(100); - VectorValues actual = conjugateGradientDescent(*fg, zeros, parameters); + VectorValuesOrdered actual = conjugateGradientDescent(*fg, zeros, parameters); - VectorValues expected; + VectorValuesOrdered expected; expected.insert(0, zero(3)); expected.insert(1, Vector_(3,-0.5,0.,0.)); CHECK(assert_equal(expected, actual)); diff --git a/tests/testNonlinearEquality.cpp b/tests/testNonlinearEquality.cpp index f10ce1b35..5322721b2 100644 --- a/tests/testNonlinearEquality.cpp +++ b/tests/testNonlinearEquality.cpp @@ -55,9 +55,9 @@ TEST ( NonlinearEquality, linearization ) { // check linearize SharedDiagonal constraintModel = noiseModel::Constrained::All(3); - JacobianFactor expLF(0, eye(3), zero(3), constraintModel); - GaussianFactor::shared_ptr actualLF = nle->linearize(linearize, *linearize.orderingArbitrary()); - EXPECT(assert_equal(*actualLF, (const GaussianFactor&)expLF)); + JacobianFactorOrdered expLF(0, eye(3), zero(3), constraintModel); + GaussianFactorOrdered::shared_ptr actualLF = nle->linearize(linearize, *linearize.orderingArbitrary()); + EXPECT(assert_equal(*actualLF, (const GaussianFactorOrdered&)expLF)); } /* ********************************************************************** */ @@ -71,7 +71,7 @@ TEST ( NonlinearEquality, linearization_pose ) { // create a nonlinear equality constraint shared_poseNLE nle(new PoseNLE(key, value)); - GaussianFactor::shared_ptr actualLF = nle->linearize(config, *config.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actualLF = nle->linearize(config, *config.orderingArbitrary()); EXPECT(true); } @@ -176,11 +176,11 @@ TEST ( NonlinearEquality, allow_error_pose ) { DOUBLES_EQUAL(500.0, actError, 1e-9); // check linearization - GaussianFactor::shared_ptr actLinFactor = nle.linearize(config, *config.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actLinFactor = nle.linearize(config, *config.orderingArbitrary()); Matrix A1 = eye(3,3); Vector b = expVec; SharedDiagonal model = noiseModel::Constrained::All(3); - GaussianFactor::shared_ptr expLinFactor(new JacobianFactor(0, A1, b, model)); + GaussianFactorOrdered::shared_ptr expLinFactor(new JacobianFactorOrdered(0, A1, b, model)); EXPECT(assert_equal(*expLinFactor, *actLinFactor, 1e-5)); } @@ -201,7 +201,7 @@ TEST ( NonlinearEquality, allow_error_optimize ) { init.insert(key1, initPose); // optimize - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(key1); Values result = LevenbergMarquardtOptimizer(graph, init, ordering).optimize(); @@ -235,7 +235,7 @@ TEST ( NonlinearEquality, allow_error_optimize_with_factors ) { graph.add(prior); // optimize - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(key1); Values actual = LevenbergMarquardtOptimizer(graph, init, ordering).optimize(); @@ -277,21 +277,21 @@ TEST( testNonlinearEqualityConstraint, unary_linearization ) { Point2 pt(1.0, 2.0); Symbol key1('x',1); double mu = 1000.0; - Ordering ordering; + OrderingOrdered ordering; ordering += key; eq2D::UnaryEqualityConstraint constraint(pt, key, mu); Values config1; config1.insert(key, pt); - GaussianFactor::shared_ptr actual1 = constraint.linearize(config1, ordering); - GaussianFactor::shared_ptr expected1(new JacobianFactor(ordering[key], eye(2,2), zero(2), hard_model)); + GaussianFactorOrdered::shared_ptr actual1 = constraint.linearize(config1, ordering); + GaussianFactorOrdered::shared_ptr expected1(new JacobianFactorOrdered(ordering[key], eye(2,2), zero(2), hard_model)); EXPECT(assert_equal(*expected1, *actual1, tol)); Values config2; Point2 ptBad(2.0, 2.0); config2.insert(key, ptBad); - GaussianFactor::shared_ptr actual2 = constraint.linearize(config2, ordering); - GaussianFactor::shared_ptr expected2(new JacobianFactor(ordering[key], eye(2,2), Vector_(2,-1.0,0.0), hard_model)); + GaussianFactorOrdered::shared_ptr actual2 = constraint.linearize(config2, ordering); + GaussianFactorOrdered::shared_ptr expected2(new JacobianFactorOrdered(ordering[key], eye(2,2), Vector_(2,-1.0,0.0), hard_model)); EXPECT(assert_equal(*expected2, *actual2, tol)); } @@ -359,16 +359,16 @@ TEST( testNonlinearEqualityConstraint, odo_linearization ) { Point2 x1(1.0, 2.0), x2(2.0, 3.0), odom(1.0, 1.0); Symbol key1('x',1), key2('x',2); double mu = 1000.0; - Ordering ordering; + OrderingOrdered ordering; ordering += key1, key2; eq2D::OdoEqualityConstraint constraint(odom, key1, key2, mu); Values config1; config1.insert(key1, x1); config1.insert(key2, x2); - GaussianFactor::shared_ptr actual1 = constraint.linearize(config1, ordering); - GaussianFactor::shared_ptr expected1( - new JacobianFactor(ordering[key1], -eye(2,2), ordering[key2], + GaussianFactorOrdered::shared_ptr actual1 = constraint.linearize(config1, ordering); + GaussianFactorOrdered::shared_ptr expected1( + new JacobianFactorOrdered(ordering[key1], -eye(2,2), ordering[key2], eye(2,2), zero(2), hard_model)); EXPECT(assert_equal(*expected1, *actual1, tol)); @@ -377,9 +377,9 @@ TEST( testNonlinearEqualityConstraint, odo_linearization ) { Point2 x2bad(2.0, 2.0); config2.insert(key1, x1bad); config2.insert(key2, x2bad); - GaussianFactor::shared_ptr actual2 = constraint.linearize(config2, ordering); - GaussianFactor::shared_ptr expected2( - new JacobianFactor(ordering[key1], -eye(2,2), ordering[key2], + GaussianFactorOrdered::shared_ptr actual2 = constraint.linearize(config2, ordering); + GaussianFactorOrdered::shared_ptr expected2( + new JacobianFactorOrdered(ordering[key1], -eye(2,2), ordering[key2], eye(2,2), Vector_(2, 1.0, 1.0), hard_model)); EXPECT(assert_equal(*expected2, *actual2, tol)); } diff --git a/tests/testNonlinearFactor.cpp b/tests/testNonlinearFactor.cpp index c490cbc6d..beb08fac3 100644 --- a/tests/testNonlinearFactor.cpp +++ b/tests/testNonlinearFactor.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -112,10 +112,10 @@ TEST( NonlinearFactor, linearize_f1 ) Graph::sharedFactor nlf = nfg[0]; // We linearize at noisy config from SmallExample - GaussianFactor::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); - GaussianFactorGraph lfg = createGaussianFactorGraph(*c.orderingArbitrary()); - GaussianFactor::shared_ptr expected = lfg[0]; + GaussianFactorGraphOrdered lfg = createGaussianFactorGraph(*c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr expected = lfg[0]; CHECK(assert_equal(*expected,*actual)); @@ -134,10 +134,10 @@ TEST( NonlinearFactor, linearize_f2 ) Graph::sharedFactor nlf = nfg[1]; // We linearize at noisy config from SmallExample - GaussianFactor::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); - GaussianFactorGraph lfg = createGaussianFactorGraph(*c.orderingArbitrary()); - GaussianFactor::shared_ptr expected = lfg[1]; + GaussianFactorGraphOrdered lfg = createGaussianFactorGraph(*c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr expected = lfg[1]; CHECK(assert_equal(*expected,*actual)); } @@ -151,10 +151,10 @@ TEST( NonlinearFactor, linearize_f3 ) // We linearize at noisy config from SmallExample Values c = createNoisyValues(); - GaussianFactor::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); - GaussianFactorGraph lfg = createGaussianFactorGraph(*c.orderingArbitrary()); - GaussianFactor::shared_ptr expected = lfg[2]; + GaussianFactorGraphOrdered lfg = createGaussianFactorGraph(*c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr expected = lfg[2]; CHECK(assert_equal(*expected,*actual)); } @@ -168,10 +168,10 @@ TEST( NonlinearFactor, linearize_f4 ) // We linearize at noisy config from SmallExample Values c = createNoisyValues(); - GaussianFactor::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actual = nlf->linearize(c, *c.orderingArbitrary()); - GaussianFactorGraph lfg = createGaussianFactorGraph(*c.orderingArbitrary()); - GaussianFactor::shared_ptr expected = lfg[3]; + GaussianFactorGraphOrdered lfg = createGaussianFactorGraph(*c.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr expected = lfg[3]; CHECK(assert_equal(*expected,*actual)); } @@ -205,13 +205,13 @@ TEST( NonlinearFactor, linearize_constraint1 ) Values config; config.insert(X(1), Point2(1.0, 2.0)); - GaussianFactor::shared_ptr actual = f0->linearize(config, *config.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actual = f0->linearize(config, *config.orderingArbitrary()); // create expected - Ordering ord(*config.orderingArbitrary()); + OrderingOrdered ord(*config.orderingArbitrary()); Vector b = Vector_(2, 0., -3.); - JacobianFactor expected(ord[X(1)], Matrix_(2,2, 5.0, 0.0, 0.0, 1.0), b, constraint); - CHECK(assert_equal((const GaussianFactor&)expected, *actual)); + JacobianFactorOrdered expected(ord[X(1)], Matrix_(2,2, 5.0, 0.0, 0.0, 1.0), b, constraint); + CHECK(assert_equal((const GaussianFactorOrdered&)expected, *actual)); } /* ************************************************************************* */ @@ -226,14 +226,14 @@ TEST( NonlinearFactor, linearize_constraint2 ) Values config; config.insert(X(1), Point2(1.0, 2.0)); config.insert(L(1), Point2(5.0, 4.0)); - GaussianFactor::shared_ptr actual = f0.linearize(config, *config.orderingArbitrary()); + GaussianFactorOrdered::shared_ptr actual = f0.linearize(config, *config.orderingArbitrary()); // create expected - Ordering ord(*config.orderingArbitrary()); + OrderingOrdered ord(*config.orderingArbitrary()); Matrix A = Matrix_(2,2, 5.0, 0.0, 0.0, 1.0); Vector b = Vector_(2, -15., -3.); - JacobianFactor expected(ord[X(1)], -1*A, ord[L(1)], A, b, constraint); - CHECK(assert_equal((const GaussianFactor&)expected, *actual)); + JacobianFactorOrdered expected(ord[X(1)], -1*A, ord[L(1)], A, b, constraint); + CHECK(assert_equal((const GaussianFactorOrdered&)expected, *actual)); } /* ************************************************************************* */ @@ -272,8 +272,8 @@ TEST(NonlinearFactor, NoiseModelFactor4) { tv.insert(X(4), LieVector(1, 4.0)); EXPECT(assert_equal(Vector_(1, 10.0), tf.unwhitenedError(tv))); DOUBLES_EQUAL(25.0/2.0, tf.error(tv), 1e-9); - Ordering ordering; ordering += X(1), X(2), X(3), X(4); - JacobianFactor jf(*boost::dynamic_pointer_cast(tf.linearize(tv, ordering))); + OrderingOrdered ordering; ordering += X(1), X(2), X(3), X(4); + JacobianFactorOrdered jf(*boost::dynamic_pointer_cast(tf.linearize(tv, ordering))); LONGS_EQUAL(jf.keys()[0], 0); LONGS_EQUAL(jf.keys()[1], 1); LONGS_EQUAL(jf.keys()[2], 2); @@ -320,8 +320,8 @@ TEST(NonlinearFactor, NoiseModelFactor5) { tv.insert(X(5), LieVector(1, 5.0)); EXPECT(assert_equal(Vector_(1, 15.0), tf.unwhitenedError(tv))); DOUBLES_EQUAL(56.25/2.0, tf.error(tv), 1e-9); - Ordering ordering; ordering += X(1), X(2), X(3), X(4), X(5); - JacobianFactor jf(*boost::dynamic_pointer_cast(tf.linearize(tv, ordering))); + OrderingOrdered ordering; ordering += X(1), X(2), X(3), X(4), X(5); + JacobianFactorOrdered jf(*boost::dynamic_pointer_cast(tf.linearize(tv, ordering))); LONGS_EQUAL(jf.keys()[0], 0); LONGS_EQUAL(jf.keys()[1], 1); LONGS_EQUAL(jf.keys()[2], 2); @@ -374,8 +374,8 @@ TEST(NonlinearFactor, NoiseModelFactor6) { tv.insert(X(6), LieVector(1, 6.0)); EXPECT(assert_equal(Vector_(1, 21.0), tf.unwhitenedError(tv))); DOUBLES_EQUAL(110.25/2.0, tf.error(tv), 1e-9); - Ordering ordering; ordering += X(1), X(2), X(3), X(4), X(5), X(6); - JacobianFactor jf(*boost::dynamic_pointer_cast(tf.linearize(tv, ordering))); + OrderingOrdered ordering; ordering += X(1), X(2), X(3), X(4), X(5), X(6); + JacobianFactorOrdered jf(*boost::dynamic_pointer_cast(tf.linearize(tv, ordering))); LONGS_EQUAL(jf.keys()[0], 0); LONGS_EQUAL(jf.keys()[1], 1); LONGS_EQUAL(jf.keys()[2], 2); diff --git a/tests/testNonlinearFactorGraph.cpp b/tests/testNonlinearFactorGraph.cpp index 5a35cbd94..3f96e6593 100644 --- a/tests/testNonlinearFactorGraph.cpp +++ b/tests/testNonlinearFactorGraph.cpp @@ -30,7 +30,7 @@ using namespace boost::assign; #include #include #include -#include +#include #include #include @@ -76,20 +76,20 @@ TEST( Graph, keys ) /* ************************************************************************* */ TEST( Graph, GET_ORDERING) { -// Ordering expected; expected += "x1","l1","x2"; // For starting with x1,x2,l1 - Ordering expected; expected += L(1), X(2), X(1); // For starting with l1,x1,x2 +// OrderingOrdered expected; expected += "x1","l1","x2"; // For starting with x1,x2,l1 + OrderingOrdered expected; expected += L(1), X(2), X(1); // For starting with l1,x1,x2 Graph nlfg = createNonlinearFactorGraph(); - SymbolicFactorGraph::shared_ptr symbolic; - Ordering::shared_ptr ordering; + SymbolicFactorGraphOrdered::shared_ptr symbolic; + OrderingOrdered::shared_ptr ordering; boost::tie(symbolic, ordering) = nlfg.symbolic(createNoisyValues()); - Ordering actual = *nlfg.orderingCOLAMD(createNoisyValues()); + OrderingOrdered actual = *nlfg.orderingCOLAMD(createNoisyValues()); EXPECT(assert_equal(expected,actual)); // Constrained ordering - put x2 at the end std::map constraints; constraints[X(2)] = 1; - Ordering actualConstrained = *nlfg.orderingCOLAMDConstrained(createNoisyValues(), constraints); - Ordering expectedConstrained; expectedConstrained += L(1), X(1), X(2); + OrderingOrdered actualConstrained = *nlfg.orderingCOLAMDConstrained(createNoisyValues(), constraints); + OrderingOrdered expectedConstrained; expectedConstrained += L(1), X(1), X(2); EXPECT(assert_equal(expectedConstrained, actualConstrained)); } @@ -110,8 +110,8 @@ TEST( Graph, linearize ) { Graph fg = createNonlinearFactorGraph(); Values initial = createNoisyValues(); - boost::shared_ptr > linearized = fg.linearize(initial, *initial.orderingArbitrary()); - FactorGraph expected = createGaussianFactorGraph(*initial.orderingArbitrary()); + boost::shared_ptr > linearized = fg.linearize(initial, *initial.orderingArbitrary()); + FactorGraphOrdered expected = createGaussianFactorGraph(*initial.orderingArbitrary()); CHECK(assert_equal(expected,*linearized)); // Needs correct linearizations } diff --git a/tests/testNonlinearISAM.cpp b/tests/testNonlinearISAM.cpp index b41fa95ae..7ee6fd438 100644 --- a/tests/testNonlinearISAM.cpp +++ b/tests/testNonlinearISAM.cpp @@ -50,7 +50,7 @@ TEST(testNonlinearISAM, markov_chain ) { // perform a check on changing orderings if (i == 5) { - Ordering ordering = isam.getOrdering(); + OrderingOrdered ordering = isam.getOrdering(); // swap last two elements Key last = ordering.pop_back().first; @@ -59,7 +59,7 @@ TEST(testNonlinearISAM, markov_chain ) { ordering.push_back(secondLast); isam.setOrdering(ordering); - Ordering expected; expected += (0), (1), (2), (4), (3); + OrderingOrdered expected; expected += (0), (1), (2), (4), (3); EXPECT(assert_equal(expected, isam.getOrdering())); } diff --git a/tests/testNonlinearOptimizer.cpp b/tests/testNonlinearOptimizer.cpp index aff07c15b..eda207688 100644 --- a/tests/testNonlinearOptimizer.cpp +++ b/tests/testNonlinearOptimizer.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -89,7 +89,7 @@ TEST( NonlinearOptimizer, optimize ) DOUBLES_EQUAL(199.0,fg.error(c0),1e-3); // optimize parameters - Ordering ord; + OrderingOrdered ord; ord.push_back(X(1)); // Gauss-Newton @@ -182,7 +182,7 @@ TEST( NonlinearOptimizer, Factorization ) graph.add(PriorFactor(X(1), Pose2(0.,0.,0.), noiseModel::Isotropic::Sigma(3, 1e-10))); graph.add(BetweenFactor(X(1),X(2), Pose2(1.,0.,0.), noiseModel::Isotropic::Sigma(3, 1))); - Ordering ordering; + OrderingOrdered ordering; ordering.push_back(X(1)); ordering.push_back(X(2)); @@ -216,7 +216,7 @@ TEST(NonlinearOptimizer, NullFactor) { DOUBLES_EQUAL(199.0,fg.error(c0),1e-3); // optimize parameters - Ordering ord; + OrderingOrdered ord; ord.push_back(X(1)); // Gauss-Newton diff --git a/tests/testSerializationSLAM.cpp b/tests/testSerializationSLAM.cpp index 57a1e5cb3..942500aee 100644 --- a/tests/testSerializationSLAM.cpp +++ b/tests/testSerializationSLAM.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -164,8 +164,8 @@ BOOST_CLASS_EXPORT(gtsam::StereoCamera); /* Create GUIDs for factors */ /* ************************************************************************* */ -BOOST_CLASS_EXPORT_GUID(gtsam::JacobianFactor, "gtsam::JacobianFactor"); -BOOST_CLASS_EXPORT_GUID(gtsam::HessianFactor , "gtsam::HessianFactor"); +BOOST_CLASS_EXPORT_GUID(gtsam::JacobianFactorOrdered, "gtsam::JacobianFactorOrdered"); +BOOST_CLASS_EXPORT_GUID(gtsam::HessianFactorOrdered , "gtsam::HessianFactorOrdered"); BOOST_CLASS_EXPORT_GUID(PriorFactorLieVector, "gtsam::PriorFactorLieVector"); BOOST_CLASS_EXPORT_GUID(PriorFactorLieMatrix, "gtsam::PriorFactorLieMatrix"); @@ -234,8 +234,8 @@ BOOST_CLASS_EXPORT_GUID(GenericStereoFactor3D, "gtsam::GenericStereoFactor3D"); TEST (testSerializationSLAM, smallExample_linear) { using namespace example; - Ordering ordering; ordering += X(1),X(2),L(1); - GaussianFactorGraph fg = createGaussianFactorGraph(ordering); + OrderingOrdered ordering; ordering += X(1),X(2),L(1); + GaussianFactorGraphOrdered fg = createGaussianFactorGraph(ordering); EXPECT(equalsObj(ordering)); EXPECT(equalsXML(ordering)); EXPECT(equalsBinary(ordering)); @@ -244,7 +244,7 @@ TEST (testSerializationSLAM, smallExample_linear) { EXPECT(equalsXML(fg)); EXPECT(equalsBinary(fg)); - GaussianBayesNet cbn = createSmallGaussianBayesNet(); + GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet(); EXPECT(equalsObj(cbn)); EXPECT(equalsXML(cbn)); EXPECT(equalsBinary(cbn)); @@ -253,11 +253,11 @@ TEST (testSerializationSLAM, smallExample_linear) { /* ************************************************************************* */ TEST (testSerializationSLAM, gaussianISAM) { using namespace example; - Ordering ordering; - GaussianFactorGraph smoother; + OrderingOrdered ordering; + GaussianFactorGraphOrdered smoother; boost::tie(smoother, ordering) = createSmoother(7); - BayesTree bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); - GaussianISAM isam(bayesTree); + BayesTreeOrdered bayesTree = *GaussianMultifrontalSolver(smoother).eliminate(); + GaussianISAMOrdered isam(bayesTree); EXPECT(equalsObj(isam)); EXPECT(equalsXML(isam)); diff --git a/tests/testSimulated2DOriented.cpp b/tests/testSimulated2DOriented.cpp index 05d64653d..29b7697fa 100644 --- a/tests/testSimulated2DOriented.cpp +++ b/tests/testSimulated2DOriented.cpp @@ -64,7 +64,7 @@ TEST( simulated2DOriented, constructor ) simulated2DOriented::Values config; config.insert(X(1), Pose2(1., 0., 0.2)); config.insert(X(2), Pose2(2., 0., 0.1)); - boost::shared_ptr lf = factor.linearize(config, *config.orderingArbitrary()); + boost::shared_ptr lf = factor.linearize(config, *config.orderingArbitrary()); } /* ************************************************************************* */ diff --git a/tests/testSubgraphPreconditioner.cpp b/tests/testSubgraphPreconditioner.cpp index 53ba92331..044ddb974 100644 --- a/tests/testSubgraphPreconditioner.cpp +++ b/tests/testSubgraphPreconditioner.cpp @@ -16,10 +16,10 @@ **/ #include -#include +#include #include #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ Symbol key(int x, int y) { /* ************************************************************************* */ TEST( SubgraphPreconditioner, planarOrdering ) { // Check canonical ordering - Ordering expected, ordering = planarOrdering(3); + OrderingOrdered expected, ordering = planarOrdering(3); expected += key(3, 3), key(2, 3), key(1, 3), key(3, 2), key(2, 2), key(1, 2), @@ -54,9 +54,9 @@ TEST( SubgraphPreconditioner, planarOrdering ) { /* ************************************************************************* */ /** unnormalized error */ -static double error(const GaussianFactorGraph& fg, const VectorValues& x) { +static double error(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) { double total_error = 0.; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, fg) + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, fg) total_error += factor->error(x); return total_error; } @@ -65,16 +65,16 @@ static double error(const GaussianFactorGraph& fg, const VectorValues& x) { TEST( SubgraphPreconditioner, planarGraph ) { // Check planar graph construction - GaussianFactorGraph A; - VectorValues xtrue; + GaussianFactorGraphOrdered A; + VectorValuesOrdered xtrue; boost::tie(A, xtrue) = planarGraph(3); LONGS_EQUAL(13,A.size()); LONGS_EQUAL(9,xtrue.size()); DOUBLES_EQUAL(0,error(A,xtrue),1e-9); // check zero error for xtrue // Check that xtrue is optimal - GaussianBayesNet::shared_ptr R1 = GaussianSequentialSolver(A).eliminate(); - VectorValues actual = optimize(*R1); + GaussianBayesNetOrdered::shared_ptr R1 = GaussianSequentialSolver(A).eliminate(); + VectorValuesOrdered actual = optimize(*R1); CHECK(assert_equal(xtrue,actual)); } @@ -82,19 +82,19 @@ TEST( SubgraphPreconditioner, planarGraph ) TEST( SubgraphPreconditioner, splitOffPlanarTree ) { // Build a planar graph - GaussianFactorGraph A; - VectorValues xtrue; + GaussianFactorGraphOrdered A; + VectorValuesOrdered xtrue; boost::tie(A, xtrue) = planarGraph(3); // Get the spanning tree and constraints, and check their sizes - GaussianFactorGraph T, C; + GaussianFactorGraphOrdered T, C; boost::tie(T, C) = splitOffPlanarTree(3, A); LONGS_EQUAL(9,T.size()); LONGS_EQUAL(4,C.size()); // Check that the tree can be solved to give the ground xtrue - GaussianBayesNet::shared_ptr R1 = GaussianSequentialSolver(T).eliminate(); - VectorValues xbar = optimize(*R1); + GaussianBayesNetOrdered::shared_ptr R1 = GaussianSequentialSolver(T).eliminate(); + VectorValuesOrdered xbar = optimize(*R1); CHECK(assert_equal(xtrue,xbar)); } @@ -103,37 +103,37 @@ TEST( SubgraphPreconditioner, splitOffPlanarTree ) TEST( SubgraphPreconditioner, system ) { // Build a planar graph - GaussianFactorGraph Ab; - VectorValues xtrue; + GaussianFactorGraphOrdered Ab; + VectorValuesOrdered xtrue; size_t N = 3; boost::tie(Ab, xtrue) = planarGraph(N); // A*x-b // Get the spanning tree and corresponding ordering - GaussianFactorGraph Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 + GaussianFactorGraphOrdered Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 boost::tie(Ab1_, Ab2_) = splitOffPlanarTree(N, Ab); - SubgraphPreconditioner::sharedFG Ab1(new GaussianFactorGraph(Ab1_)); - SubgraphPreconditioner::sharedFG Ab2(new GaussianFactorGraph(Ab2_)); + SubgraphPreconditioner::sharedFG Ab1(new GaussianFactorGraphOrdered(Ab1_)); + SubgraphPreconditioner::sharedFG Ab2(new GaussianFactorGraphOrdered(Ab2_)); // Eliminate the spanning tree to build a prior SubgraphPreconditioner::sharedBayesNet Rc1 = GaussianSequentialSolver(Ab1_).eliminate(); // R1*x-c1 - VectorValues xbar = optimize(*Rc1); // xbar = inv(R1)*c1 + VectorValuesOrdered xbar = optimize(*Rc1); // xbar = inv(R1)*c1 // Create Subgraph-preconditioned system - VectorValues::shared_ptr xbarShared(new VectorValues(xbar)); // TODO: horrible + VectorValuesOrdered::shared_ptr xbarShared(new VectorValuesOrdered(xbar)); // TODO: horrible SubgraphPreconditioner system(Ab2, Rc1, xbarShared); // Create zero config - VectorValues zeros = VectorValues::Zero(xbar); + VectorValuesOrdered zeros = VectorValuesOrdered::Zero(xbar); // Set up y0 as all zeros - VectorValues y0 = zeros; + VectorValuesOrdered y0 = zeros; // y1 = perturbed y0 - VectorValues y1 = zeros; + VectorValuesOrdered y1 = zeros; y1[1] = Vector_(2, 1.0, -1.0); // Check corresponding x values - VectorValues expected_x1 = xtrue, x1 = system.x(y1); + VectorValuesOrdered expected_x1 = xtrue, x1 = system.x(y1); expected_x1[1] = Vector_(2, 2.01, 2.99); expected_x1[0] = Vector_(2, 3.01, 2.99); CHECK(assert_equal(xtrue, system.x(y0))); @@ -146,8 +146,8 @@ TEST( SubgraphPreconditioner, system ) DOUBLES_EQUAL(3,error(system,y1),1e-9); // Test gradient in x - VectorValues expected_gx0 = zeros; - VectorValues expected_gx1 = zeros; + VectorValuesOrdered expected_gx0 = zeros; + VectorValuesOrdered expected_gx1 = zeros; CHECK(assert_equal(expected_gx0,gradient(Ab,xtrue))); expected_gx1[2] = Vector_(2, -100., 100.); expected_gx1[4] = Vector_(2, -100., 100.); @@ -157,8 +157,8 @@ TEST( SubgraphPreconditioner, system ) CHECK(assert_equal(expected_gx1,gradient(Ab,x1))); // Test gradient in y - VectorValues expected_gy0 = zeros; - VectorValues expected_gy1 = zeros; + VectorValuesOrdered expected_gy0 = zeros; + VectorValuesOrdered expected_gy1 = zeros; expected_gy1[2] = Vector_(2, 2., -2.); expected_gy1[4] = Vector_(2, -2., 2.); expected_gy1[1] = Vector_(2, 3., -3.); @@ -169,7 +169,7 @@ TEST( SubgraphPreconditioner, system ) // Check it numerically for good measure // TODO use boost::bind(&SubgraphPreconditioner::error,&system,_1) - // Vector numerical_g1 = numericalGradient (error, y1, 0.001); + // Vector numerical_g1 = numericalGradient (error, y1, 0.001); // Vector expected_g1 = Vector_(18, 0., 0., 0., 0., 2., -2., 0., 0., -2., 2., // 3., -3., 0., 0., -1., 1., 1., -1.); // CHECK(assert_equal(expected_g1,numerical_g1)); @@ -179,41 +179,41 @@ TEST( SubgraphPreconditioner, system ) TEST( SubgraphPreconditioner, conjugateGradients ) { // Build a planar graph - GaussianFactorGraph Ab; - VectorValues xtrue; + GaussianFactorGraphOrdered Ab; + VectorValuesOrdered xtrue; size_t N = 3; boost::tie(Ab, xtrue) = planarGraph(N); // A*x-b // Get the spanning tree and corresponding ordering - GaussianFactorGraph Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 + GaussianFactorGraphOrdered Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 boost::tie(Ab1_, Ab2_) = splitOffPlanarTree(N, Ab); - SubgraphPreconditioner::sharedFG Ab1(new GaussianFactorGraph(Ab1_)); - SubgraphPreconditioner::sharedFG Ab2(new GaussianFactorGraph(Ab2_)); + SubgraphPreconditioner::sharedFG Ab1(new GaussianFactorGraphOrdered(Ab1_)); + SubgraphPreconditioner::sharedFG Ab2(new GaussianFactorGraphOrdered(Ab2_)); // Eliminate the spanning tree to build a prior - Ordering ordering = planarOrdering(N); + OrderingOrdered ordering = planarOrdering(N); SubgraphPreconditioner::sharedBayesNet Rc1 = GaussianSequentialSolver(Ab1_).eliminate(); // R1*x-c1 - VectorValues xbar = optimize(*Rc1); // xbar = inv(R1)*c1 + VectorValuesOrdered xbar = optimize(*Rc1); // xbar = inv(R1)*c1 // Create Subgraph-preconditioned system - VectorValues::shared_ptr xbarShared(new VectorValues(xbar)); // TODO: horrible + VectorValuesOrdered::shared_ptr xbarShared(new VectorValuesOrdered(xbar)); // TODO: horrible SubgraphPreconditioner system(Ab2, Rc1, xbarShared); // Create zero config y0 and perturbed config y1 - VectorValues y0 = VectorValues::Zero(xbar); + VectorValuesOrdered y0 = VectorValuesOrdered::Zero(xbar); - VectorValues y1 = y0; + VectorValuesOrdered y1 = y0; y1[1] = Vector_(2, 1.0, -1.0); - VectorValues x1 = system.x(y1); + VectorValuesOrdered x1 = system.x(y1); // Solve for the remaining constraints using PCG ConjugateGradientParameters parameters; - VectorValues actual = conjugateGradients(system, y1, parameters); + VectorValuesOrdered actual = conjugateGradients(system, y1, parameters); CHECK(assert_equal(y0,actual)); // Compare with non preconditioned version: - VectorValues actual2 = conjugateGradientDescent(Ab, x1, parameters); + VectorValuesOrdered actual2 = conjugateGradientDescent(Ab, x1, parameters); CHECK(assert_equal(xtrue,actual2,1e-4)); } diff --git a/tests/testSubgraphSolver.cpp b/tests/testSubgraphSolver.cpp index 700f35261..017a70af5 100644 --- a/tests/testSubgraphSolver.cpp +++ b/tests/testSubgraphSolver.cpp @@ -16,13 +16,13 @@ **/ #include -#include +#include #include -#include +#include #include -#include +#include #include -#include +#include #include #include @@ -38,9 +38,9 @@ using namespace example; /* ************************************************************************* */ /** unnormalized error */ -static double error(const GaussianFactorGraph& fg, const VectorValues& x) { +static double error(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) { double total_error = 0.; - BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, fg) + BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, fg) total_error += factor->error(x); return total_error; } @@ -50,8 +50,8 @@ static double error(const GaussianFactorGraph& fg, const VectorValues& x) { TEST( SubgraphSolver, constructor1 ) { // Build a planar graph - GaussianFactorGraph Ab; - VectorValues xtrue; + GaussianFactorGraphOrdered Ab; + VectorValuesOrdered xtrue; size_t N = 3; boost::tie(Ab, xtrue) = planarGraph(N); // A*x-b @@ -59,7 +59,7 @@ TEST( SubgraphSolver, constructor1 ) // and it will split the graph into A1 and A2, where A1 is a spanning tree SubgraphSolverParameters parameters; SubgraphSolver solver(Ab, parameters); - VectorValues optimized = solver.optimize(); // does PCG optimization + VectorValuesOrdered optimized = solver.optimize(); // does PCG optimization DOUBLES_EQUAL(0.0, error(Ab, optimized), 1e-5); } @@ -67,20 +67,20 @@ TEST( SubgraphSolver, constructor1 ) TEST( SubgraphSolver, constructor2 ) { // Build a planar graph - GaussianFactorGraph Ab; - VectorValues xtrue; + GaussianFactorGraphOrdered Ab; + VectorValuesOrdered xtrue; size_t N = 3; boost::tie(Ab, xtrue) = planarGraph(N); // A*x-b // Get the spanning tree and corresponding ordering - GaussianFactorGraph Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 + GaussianFactorGraphOrdered Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 boost::tie(Ab1_, Ab2_) = splitOffPlanarTree(N, Ab); // The second constructor takes two factor graphs, // so the caller can specify the preconditioner (Ab1) and the constraints that are left out (Ab2) SubgraphSolverParameters parameters; SubgraphSolver solver(Ab1_, Ab2_, parameters); - VectorValues optimized = solver.optimize(); + VectorValuesOrdered optimized = solver.optimize(); DOUBLES_EQUAL(0.0, error(Ab, optimized), 1e-5); } @@ -88,24 +88,24 @@ TEST( SubgraphSolver, constructor2 ) TEST( SubgraphSolver, constructor3 ) { // Build a planar graph - GaussianFactorGraph Ab; - VectorValues xtrue; + GaussianFactorGraphOrdered Ab; + VectorValuesOrdered xtrue; size_t N = 3; boost::tie(Ab, xtrue) = planarGraph(N); // A*x-b // Get the spanning tree and corresponding ordering - GaussianFactorGraph Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 + GaussianFactorGraphOrdered Ab1_, Ab2_; // A1*x-b1 and A2*x-b2 boost::tie(Ab1_, Ab2_) = splitOffPlanarTree(N, Ab); // The caller solves |A1*x-b1|^2 == |R1*x-c1|^2 via QR factorization, where R1 is square UT - GaussianBayesNet::shared_ptr Rc1 = // - EliminationTree::Create(Ab1_)->eliminate(&EliminateQR); + GaussianBayesNetOrdered::shared_ptr Rc1 = // + EliminationTreeOrdered::Create(Ab1_)->eliminate(&EliminateQROrdered); // The third constructor allows the caller to pass an already solved preconditioner Rc1_ // as a Bayes net, in addition to the "loop closing constraints" Ab2, as before SubgraphSolverParameters parameters; SubgraphSolver solver(Rc1, Ab2_, parameters); - VectorValues optimized = solver.optimize(); + VectorValuesOrdered optimized = solver.optimize(); DOUBLES_EQUAL(0.0, error(Ab, optimized), 1e-5); } diff --git a/tests/testSummarization.cpp b/tests/testSummarization.cpp index bf7342202..b342507fc 100644 --- a/tests/testSummarization.cpp +++ b/tests/testSummarization.cpp @@ -74,15 +74,15 @@ TEST( testSummarization, example_from_ddf1 ) { { // Summarize to a linear system - GaussianFactorGraph actLinGraph; Ordering actOrdering; + GaussianFactorGraphOrdered actLinGraph; OrderingOrdered actOrdering; SummarizationMode mode = PARTIAL_QR; boost::tie(actLinGraph, actOrdering) = summarize(graph, values, saved_keys, mode); - Ordering expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; + OrderingOrdered expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; EXPECT(assert_equal(expSumOrdering, actOrdering)); // Does not split out subfactors where possible - GaussianFactorGraph expLinGraph; + GaussianFactorGraphOrdered expLinGraph; expLinGraph.add( expSumOrdering[lA3], Matrix_(4,2, @@ -108,16 +108,16 @@ TEST( testSummarization, example_from_ddf1 ) { { // Summarize to a linear system using cholesky - compare to previous version - GaussianFactorGraph actLinGraph; Ordering actOrdering; + GaussianFactorGraphOrdered actLinGraph; OrderingOrdered actOrdering; SummarizationMode mode = PARTIAL_CHOLESKY; boost::tie(actLinGraph, actOrdering) = summarize(graph, values, saved_keys, mode); - Ordering expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; + OrderingOrdered expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; EXPECT(assert_equal(expSumOrdering, actOrdering)); // Does not split out subfactors where possible - GaussianFactorGraph expLinGraph; - expLinGraph.add(HessianFactor(JacobianFactor( + GaussianFactorGraphOrdered expLinGraph; + expLinGraph.add(HessianFactorOrdered(JacobianFactorOrdered( expSumOrdering[lA3], Matrix_(4,2, 0.595867, 0.605092, @@ -142,15 +142,15 @@ TEST( testSummarization, example_from_ddf1 ) { { // Summarize to a linear system with joint factor graph version - GaussianFactorGraph actLinGraph; Ordering actOrdering; + GaussianFactorGraphOrdered actLinGraph; OrderingOrdered actOrdering; SummarizationMode mode = SEQUENTIAL_QR; boost::tie(actLinGraph, actOrdering) = summarize(graph, values, saved_keys, mode); - Ordering expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; + OrderingOrdered expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; EXPECT(assert_equal(expSumOrdering, actOrdering)); // Does not split out subfactors where possible - GaussianFactorGraph expLinGraph; + GaussianFactorGraphOrdered expLinGraph; expLinGraph.add( expSumOrdering[lA3], Matrix_(2,2, @@ -180,15 +180,15 @@ TEST( testSummarization, example_from_ddf1 ) { { // Summarize to a linear system with joint factor graph version - GaussianFactorGraph actLinGraph; Ordering actOrdering; + GaussianFactorGraphOrdered actLinGraph; OrderingOrdered actOrdering; SummarizationMode mode = SEQUENTIAL_CHOLESKY; boost::tie(actLinGraph, actOrdering) = summarize(graph, values, saved_keys, mode); - Ordering expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; + OrderingOrdered expSumOrdering; expSumOrdering += xA0, xA1, xA2, lA3, lA5; EXPECT(assert_equal(expSumOrdering, actOrdering)); // Does not split out subfactors where possible - GaussianFactorGraph expLinGraph; + GaussianFactorGraphOrdered expLinGraph; expLinGraph.add( expSumOrdering[lA3], Matrix_(2,2, @@ -229,10 +229,10 @@ TEST( testSummarization, no_summarize_case ) { values.insert(key, Pose2(0.0, 0.0, 0.1)); SummarizationMode mode = SEQUENTIAL_CHOLESKY; - GaussianFactorGraph actLinGraph; Ordering actOrdering; + GaussianFactorGraphOrdered actLinGraph; OrderingOrdered actOrdering; boost::tie(actLinGraph, actOrdering) = summarize(graph, values, saved_keys, mode); - Ordering expOrdering; expOrdering += key; - GaussianFactorGraph expLinGraph = *graph.linearize(values, expOrdering); + OrderingOrdered expOrdering; expOrdering += key; + GaussianFactorGraphOrdered expLinGraph = *graph.linearize(values, expOrdering); EXPECT(assert_equal(expOrdering, actOrdering)); EXPECT(assert_equal(expLinGraph, actLinGraph)); } diff --git a/tests/testSymbolicBayesNetBObsolete.cpp b/tests/testSymbolicBayesNetBObsolete.cpp index e046d6ba4..152661a40 100644 --- a/tests/testSymbolicBayesNetBObsolete.cpp +++ b/tests/testSymbolicBayesNetBObsolete.cpp @@ -23,9 +23,9 @@ using namespace boost::assign; #include #include -#include -#include -#include +#include +#include +#include #include using namespace std; @@ -36,37 +36,37 @@ using symbol_shorthand::X; using symbol_shorthand::L; /* ************************************************************************* */ -TEST( SymbolicBayesNet, constructor ) +TEST( SymbolicBayesNetOrdered, constructor ) { - Ordering o; o += X(2),L(1),X(1); + OrderingOrdered o; o += X(2),L(1),X(1); // Create manually - IndexConditional::shared_ptr - x2(new IndexConditional(o[X(2)],o[L(1)], o[X(1)])), - l1(new IndexConditional(o[L(1)],o[X(1)])), - x1(new IndexConditional(o[X(1)])); - BayesNet expected; + IndexConditionalOrdered::shared_ptr + x2(new IndexConditionalOrdered(o[X(2)],o[L(1)], o[X(1)])), + l1(new IndexConditionalOrdered(o[L(1)],o[X(1)])), + x1(new IndexConditionalOrdered(o[X(1)])); + BayesNetOrdered expected; expected.push_back(x2); expected.push_back(l1); expected.push_back(x1); // Create from a factor graph - GaussianFactorGraph factorGraph = createGaussianFactorGraph(o); - SymbolicFactorGraph fg(factorGraph); + GaussianFactorGraphOrdered factorGraph = createGaussianFactorGraph(o); + SymbolicFactorGraphOrdered fg(factorGraph); // eliminate it - SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(); + SymbolicBayesNetOrdered actual = *SymbolicSequentialSolver(fg).eliminate(); CHECK(assert_equal(expected, actual)); } /* ************************************************************************* */ -TEST( SymbolicBayesNet, FromGaussian) { - SymbolicBayesNet expected; - expected.push_back(IndexConditional::shared_ptr(new IndexConditional(0, 1))); - expected.push_back(IndexConditional::shared_ptr(new IndexConditional(1))); +TEST( SymbolicBayesNetOrdered, FromGaussian) { + SymbolicBayesNetOrdered expected; + expected.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(0, 1))); + expected.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(1))); - GaussianBayesNet gbn = createSmallGaussianBayesNet(); - SymbolicBayesNet actual(gbn); + GaussianBayesNetOrdered gbn = createSmallGaussianBayesNet(); + SymbolicBayesNetOrdered actual(gbn); EXPECT(assert_equal(expected, actual)); } diff --git a/tests/testSymbolicFactorGraphBObsolete.cpp b/tests/testSymbolicFactorGraphBObsolete.cpp index 5d6b478bf..e4e82ab9a 100644 --- a/tests/testSymbolicFactorGraphBObsolete.cpp +++ b/tests/testSymbolicFactorGraphBObsolete.cpp @@ -16,11 +16,11 @@ */ #include -#include +#include #include -#include -#include -#include +#include +#include +#include #include @@ -34,35 +34,35 @@ using symbol_shorthand::X; using symbol_shorthand::L; /* ************************************************************************* */ -TEST( SymbolicFactorGraph, symbolicFactorGraph ) +TEST( SymbolicFactorGraphOrdered, symbolicFactorGraph ) { - Ordering o; o += X(1),L(1),X(2); + OrderingOrdered o; o += X(1),L(1),X(2); // construct expected symbolic graph - SymbolicFactorGraph expected; + SymbolicFactorGraphOrdered expected; expected.push_factor(o[X(1)]); expected.push_factor(o[X(1)],o[X(2)]); expected.push_factor(o[X(1)],o[L(1)]); expected.push_factor(o[X(2)],o[L(1)]); // construct it from the factor graph - GaussianFactorGraph factorGraph = example::createGaussianFactorGraph(o); - SymbolicFactorGraph actual(factorGraph); + GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(o); + SymbolicFactorGraphOrdered actual(factorGraph); CHECK(assert_equal(expected, actual)); } ///* ************************************************************************* */ -//TEST( SymbolicFactorGraph, findAndRemoveFactors ) +//TEST( SymbolicFactorGraphOrdered, findAndRemoveFactors ) //{ // // construct it from the factor graph graph -// GaussianFactorGraph factorGraph = example::createGaussianFactorGraph(); -// SymbolicFactorGraph actual(factorGraph); +// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(); +// SymbolicFactorGraphOrdered actual(factorGraph); // SymbolicFactor::shared_ptr f1 = actual[0]; // SymbolicFactor::shared_ptr f3 = actual[2]; // actual.findAndRemoveFactors(X(2)); // // // construct expected graph after find_factors_and_remove -// SymbolicFactorGraph expected; +// SymbolicFactorGraphOrdered expected; // SymbolicFactor::shared_ptr null; // expected.push_back(f1); // expected.push_back(null); @@ -72,11 +72,11 @@ TEST( SymbolicFactorGraph, symbolicFactorGraph ) // CHECK(assert_equal(expected, actual)); //} ///* ************************************************************************* */ -//TEST( SymbolicFactorGraph, factors) +//TEST( SymbolicFactorGraphOrdered, factors) //{ // // create a test graph -// GaussianFactorGraph factorGraph = example::createGaussianFactorGraph(); -// SymbolicFactorGraph fg(factorGraph); +// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(); +// SymbolicFactorGraphOrdered fg(factorGraph); // // // ask for all factor indices connected to x1 // list x1_factors = fg.factors(X(1)); @@ -92,11 +92,11 @@ TEST( SymbolicFactorGraph, symbolicFactorGraph ) //} ///* ************************************************************************* */ -//TEST( SymbolicFactorGraph, removeAndCombineFactors ) +//TEST( SymbolicFactorGraphOrdered, removeAndCombineFactors ) //{ // // create a test graph -// GaussianFactorGraph factorGraph = example::createGaussianFactorGraph(); -// SymbolicFactorGraph fg(factorGraph); +// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(); +// SymbolicFactorGraphOrdered fg(factorGraph); // // // combine all factors connected to x1 // SymbolicFactor::shared_ptr actual = removeAndCombineFactors(fg,X(1)); @@ -107,43 +107,43 @@ TEST( SymbolicFactorGraph, symbolicFactorGraph ) //} ///* ************************************************************************* */ -//TEST( SymbolicFactorGraph, eliminateOne ) +//TEST( SymbolicFactorGraphOrdered, eliminateOne ) //{ -// Ordering o; o += X(1),L(1),X(2); +// OrderingOrdered o; o += X(1),L(1),X(2); // // create a test graph -// GaussianFactorGraph factorGraph = example::createGaussianFactorGraph(o); -// SymbolicFactorGraph fg(factorGraph); +// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(o); +// SymbolicFactorGraphOrdered fg(factorGraph); // // // eliminate -// IndexConditional::shared_ptr actual = GaussianSequentialSolver::EliminateUntil(fg, o[X(1)]+1); +// IndexConditionalOrdered::shared_ptr actual = GaussianSequentialSolver::EliminateUntil(fg, o[X(1)]+1); // // // create expected symbolic IndexConditional -// IndexConditional expected(o[X(1)],o[L(1)],o[X(2)]); +// IndexConditionalOrdered expected(o[X(1)],o[L(1)],o[X(2)]); // // CHECK(assert_equal(expected,*actual)); //} /* ************************************************************************* */ -TEST( SymbolicFactorGraph, eliminate ) +TEST( SymbolicFactorGraphOrdered, eliminate ) { - Ordering o; o += X(2),L(1),X(1); + OrderingOrdered o; o += X(2),L(1),X(1); // create expected Chordal bayes Net - IndexConditional::shared_ptr x2(new IndexConditional(o[X(2)], o[L(1)], o[X(1)])); - IndexConditional::shared_ptr l1(new IndexConditional(o[L(1)], o[X(1)])); - IndexConditional::shared_ptr x1(new IndexConditional(o[X(1)])); + IndexConditionalOrdered::shared_ptr x2(new IndexConditionalOrdered(o[X(2)], o[L(1)], o[X(1)])); + IndexConditionalOrdered::shared_ptr l1(new IndexConditionalOrdered(o[L(1)], o[X(1)])); + IndexConditionalOrdered::shared_ptr x1(new IndexConditionalOrdered(o[X(1)])); - SymbolicBayesNet expected; + SymbolicBayesNetOrdered expected; expected.push_back(x2); expected.push_back(l1); expected.push_back(x1); // create a test graph - GaussianFactorGraph factorGraph = example::createGaussianFactorGraph(o); - SymbolicFactorGraph fg(factorGraph); + GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(o); + SymbolicFactorGraphOrdered fg(factorGraph); // eliminate it - SymbolicBayesNet actual = *SymbolicSequentialSolver(fg).eliminate(); + SymbolicBayesNetOrdered actual = *SymbolicSequentialSolver(fg).eliminate(); CHECK(assert_equal(expected,actual)); } diff --git a/tests/timeGaussianFactorGraph.cpp b/tests/timeGaussianFactorGraph.cpp index f7dd8601d..6491e221d 100644 --- a/tests/timeGaussianFactorGraph.cpp +++ b/tests/timeGaussianFactorGraph.cpp @@ -30,8 +30,8 @@ using namespace boost::assign; /* ************************************************************************* */ // Create a Kalman smoother for t=1:T and optimize double timeKalmanSmoother(int T) { - pair smoother_ordering = createSmoother(T); - GaussianFactorGraph& smoother(smoother_ordering.first); + pair smoother_ordering = createSmoother(T); + GaussianFactorGraphOrdered& smoother(smoother_ordering.first); clock_t start = clock(); GaussianSequentialSolver(smoother).optimize(); clock_t end = clock (); @@ -43,8 +43,8 @@ double timeKalmanSmoother(int T) { // Create a planar factor graph and optimize // todo: use COLAMD ordering again (removed when linear baked-in ordering added) double timePlanarSmoother(int N, bool old = true) { - boost::tuple pg = planarGraph(N); - GaussianFactorGraph& fg(pg.get<0>()); + boost::tuple pg = planarGraph(N); + GaussianFactorGraphOrdered& fg(pg.get<0>()); clock_t start = clock(); GaussianSequentialSolver(fg).optimize(); clock_t end = clock (); @@ -56,8 +56,8 @@ double timePlanarSmoother(int N, bool old = true) { // Create a planar factor graph and eliminate // todo: use COLAMD ordering again (removed when linear baked-in ordering added) double timePlanarSmootherEliminate(int N, bool old = true) { - boost::tuple pg = planarGraph(N); - GaussianFactorGraph& fg(pg.get<0>()); + boost::tuple pg = planarGraph(N); + GaussianFactorGraphOrdered& fg(pg.get<0>()); clock_t start = clock(); GaussianSequentialSolver(fg).eliminate(); clock_t end = clock (); @@ -69,23 +69,23 @@ double timePlanarSmootherEliminate(int N, bool old = true) { //// Create a planar factor graph and join factors until matrix formation //// This variation uses the original join factors approach //double timePlanarSmootherJoinAug(int N, size_t reps) { -// GaussianFactorGraph fgBase; -// VectorValues config; +// GaussianFactorGraphOrdered fgBase; +// VectorValuesOrdered config; // boost::tie(fgBase,config) = planarGraph(N); -// Ordering ordering = fgBase.getOrdering(); +// OrderingOrdered ordering = fgBase.getOrdering(); // Symbol key = ordering.front(); // // clock_t start = clock(); // // for (size_t i = 0; ikeys()) // if (k != key) render += k; @@ -102,16 +102,16 @@ double timePlanarSmootherEliminate(int N, bool old = true) { //// Create a planar factor graph and join factors until matrix formation //// This variation uses the single-allocate version to create the matrix //double timePlanarSmootherCombined(int N, size_t reps) { -// GaussianFactorGraph fgBase; -// VectorValues config; +// GaussianFactorGraphOrdered fgBase; +// VectorValuesOrdered config; // boost::tie(fgBase,config) = planarGraph(N); -// Ordering ordering = fgBase.getOrdering(); +// OrderingOrdered ordering = fgBase.getOrdering(); // Symbol key = ordering.front(); // // clock_t start = clock(); // // for (size_t i = 0; i