From f6773411087abde1d884aa014131da96e0bec3b2 Mon Sep 17 00:00:00 2001 From: Frank Dellaert Date: Thu, 12 Nov 2009 04:56:30 +0000 Subject: [PATCH] Moved inference methods to new compilation unit. Added [factor], and [marginalize] now returns a factor graph. --- .cproject | 43 ++++++++++------------ cpp/BayesNet-inl.h | 26 +------------- cpp/BayesNet.h | 9 ----- cpp/BayesTree-inl.h | 67 +++++++++++++++++++++++++++-------- cpp/BayesTree.h | 17 ++++++--- cpp/FactorGraph-inl.h | 55 +++++++--------------------- cpp/FactorGraph.h | 23 ++---------- cpp/LinearFactorGraph.cpp | 23 ++++++++---- cpp/LinearFactorGraph.h | 4 +-- cpp/SymbolicFactorGraph.cpp | 10 ++++-- cpp/SymbolicFactorGraph.h | 4 +-- cpp/testBayesTree.cpp | 23 ++++++------ cpp/testGaussianBayesNet.cpp | 15 +------- cpp/testLinearFactorGraph.cpp | 13 +++++-- 14 files changed, 152 insertions(+), 180 deletions(-) diff --git a/.cproject b/.cproject index 76e521ae2..893526580 100644 --- a/.cproject +++ b/.cproject @@ -300,7 +300,6 @@ make - install true true @@ -308,7 +307,6 @@ make - check true true @@ -324,7 +322,6 @@ make - testSimpleCamera.run true true @@ -340,6 +337,7 @@ make + testVSLAMFactor.run true true @@ -347,7 +345,6 @@ make - testCalibratedCamera.run true true @@ -355,6 +352,7 @@ make + testConditionalGaussian.run true true @@ -362,23 +360,13 @@ make - testPose2.run true true true - -make --f local.mk -testFGConfig.run -true -false -true - make - testRot3.run true true @@ -386,6 +374,7 @@ make + testNonlinearOptimizer.run true true @@ -393,7 +382,6 @@ make - testLinearFactor.run true true @@ -401,7 +389,6 @@ make - testLinearFactorGraph.run true true @@ -409,6 +396,7 @@ make + testNonlinearFactorGraph.run true true @@ -416,7 +404,6 @@ make - testPose3.run true true @@ -424,6 +411,7 @@ make + testVectorConfig.run true true @@ -431,6 +419,7 @@ make + testPoint2.run true true @@ -438,7 +427,6 @@ make - testNonlinearFactor.run true true @@ -446,7 +434,6 @@ make - timeLinearFactor.run true true @@ -454,7 +441,6 @@ make - timeLinearFactorGraph.run true true @@ -462,7 +448,6 @@ make - testGaussianBayesNet.run true true @@ -470,6 +455,7 @@ make + testBayesTree.run true false @@ -477,7 +463,6 @@ make - testSymbolicBayesNet.run true false @@ -485,6 +470,7 @@ make + testSymbolicFactorGraph.run true false @@ -492,7 +478,6 @@ make - testVector.run true true @@ -500,14 +485,22 @@ make - testMatrix.run true true true + +make + +testInference.run +true +true +true + make + install true true @@ -515,6 +508,7 @@ make + clean true true @@ -522,6 +516,7 @@ make + check true true diff --git a/cpp/BayesNet-inl.h b/cpp/BayesNet-inl.h index c90202dc3..cb74f37f4 100644 --- a/cpp/BayesNet-inl.h +++ b/cpp/BayesNet-inl.h @@ -1,6 +1,6 @@ /** * @file BayesNet-inl.h - * @brief Bayes chain template definitions + * @brief Bayes net template definitions * @author Frank Dellaert */ @@ -70,29 +70,5 @@ namespace gtsam { } /* ************************************************************************* */ - template - BayesNet marginals(const BayesNet& bn, const Ordering& keys) { - // Convert to factor graph - FactorGraph factorGraph(bn); - - // Get the keys of all variables and remove all keys we want the marginal for - Ordering ord = bn.ordering(); - BOOST_FOREACH(string key, keys) ord.remove(key); // TODO: O(n*k), faster possible? - - // add marginal keys at end - BOOST_FOREACH(string key, keys) ord.push_back(key); - - // eliminate to get joint - BayesNet joint = _eliminate(factorGraph,ord); - - // remove all integrands, P(K) = \int_I P(I|K) P(K) - size_t nrIntegrands = ord.size()-keys.size(); - for(int i=0;i - BayesNet marginals(const BayesNet& bn, const Ordering& keys); - } /// namespace gtsam diff --git a/cpp/BayesTree-inl.h b/cpp/BayesTree-inl.h index da2a30b02..db35ac75b 100644 --- a/cpp/BayesTree-inl.h +++ b/cpp/BayesTree-inl.h @@ -9,8 +9,7 @@ using namespace boost::assign; #include "BayesTree.h" -#include "FactorGraph-inl.h" -#include "BayesNet-inl.h" +#include "inference-inl.h" namespace gtsam { @@ -106,7 +105,7 @@ namespace gtsam { BOOST_REVERSE_FOREACH(string key, integrands) ordering.push_front(key); // eliminate to get marginal - BayesNet p_S_R = _eliminate(p_Cp_R,ordering); + BayesNet p_S_R = eliminate(p_Cp_R,ordering); // remove all integrands BOOST_FOREACH(string key, integrands) p_S_R.pop_front(); @@ -123,7 +122,7 @@ namespace gtsam { /* ************************************************************************* */ template template - BayesNet + FactorGraph BayesTree::Clique::marginal(shared_ptr R) { // If we are the root, just return this root if (R.get()==this) return *R; @@ -134,7 +133,7 @@ namespace gtsam { p_FSR.push_back(*R); // Find marginal on the keys we are interested in - return marginals(p_FSR,keys()); + return marginalize(p_FSR,keys()); } /* ************************************************************************* */ @@ -142,7 +141,7 @@ namespace gtsam { /* ************************************************************************* */ template template - BayesNet + FactorGraph BayesTree::Clique::joint(shared_ptr C2, shared_ptr R) { // For now, assume neither is the root @@ -160,7 +159,7 @@ namespace gtsam { keys12.unique(); // Calculate the marginal - return marginals(*bn,keys12); + return marginalize(*bn,keys12); } /* ************************************************************************* */ @@ -226,17 +225,35 @@ namespace gtsam { /* ************************************************************************* */ template template - BayesNet + FactorGraph BayesTree::marginal(const string& key) const { // get clique containing key sharedClique clique = (*this)[key]; // calculate or retrieve its marginal - BayesNet cliqueMarginal = clique->marginal(root_); + FactorGraph cliqueMarginal = clique->marginal(root_); - // Get the marginal on the single key - return marginals(cliqueMarginal,Ordering(key)); + // create an ordering where only the requested key is not eliminated + Ordering ord = clique->keys(); + ord.remove(key); + + // partially eliminate, remaining factor graph is requested marginal + eliminate(cliqueMarginal,ord); + return cliqueMarginal; + } + + /* ************************************************************************* */ + template + template + BayesNet + BayesTree::marginalBayesNet(const string& key) const { + + // calculate marginal as a factor graph + FactorGraph fg = this->marginal(key); + + // eliminate further to Bayes net + return eliminate(fg,Ordering(key)); } /* ************************************************************************* */ @@ -244,19 +261,39 @@ namespace gtsam { /* ************************************************************************* */ template template - BayesNet + FactorGraph BayesTree::joint(const std::string& key1, const std::string& key2) const { // get clique C1 and C2 sharedClique C1 = (*this)[key1], C2 = (*this)[key2]; // calculate joint - BayesNet p_C1C2 = C1->joint(C2,root_); + FactorGraph p_C1C2 = C1->joint(C2,root_); - // Get the marginal on the two keys + // create an ordering where both requested keys are not eliminated + Ordering ord = p_C1C2.keys(); + ord.remove(key1); + ord.remove(key2); + + // partially eliminate, remaining factor graph is requested joint + // TODO, make eliminate functional + eliminate(p_C1C2,ord); + return p_C1C2; + } + + /* ************************************************************************* */ + template + template + BayesNet + BayesTree::jointBayesNet(const std::string& key1, const std::string& key2) const { + + // calculate marginal as a factor graph + FactorGraph fg = this->joint(key1,key2); + + // eliminate further to Bayes net Ordering ordering; ordering += key1, key2; - return marginals(p_C1C2,ordering); + return eliminate(fg,ordering); } /* ************************************************************************* */ diff --git a/cpp/BayesTree.h b/cpp/BayesTree.h index d425d64cf..fcd73eda6 100644 --- a/cpp/BayesTree.h +++ b/cpp/BayesTree.h @@ -15,6 +15,7 @@ #include #include "Testable.h" +#include "FactorGraph.h" #include "BayesNet.h" namespace gtsam { @@ -70,11 +71,11 @@ namespace gtsam { /** return the marginal P(C) of the clique */ template - BayesNet marginal(shared_ptr root); + FactorGraph marginal(shared_ptr root); /** return the joint P(C1,C2), where C1==this. TODO: not a method? */ template - BayesNet joint(shared_ptr C2, shared_ptr root); + FactorGraph joint(shared_ptr C2, shared_ptr root); }; typedef boost::shared_ptr sharedClique; @@ -142,11 +143,19 @@ namespace gtsam { /** return marginal on any variable */ template - BayesNet marginal(const std::string& key) const; + FactorGraph marginal(const std::string& key) const; + + /** return marginal on any variable, as a Bayes Net */ + template + BayesNet marginalBayesNet(const std::string& key) const; /** return joint on two variables */ template - BayesNet joint(const std::string& key1, const std::string& key2) const; + FactorGraph joint(const std::string& key1, const std::string& key2) const; + + /** return joint on two variables as a BayesNet */ + template + BayesNet jointBayesNet(const std::string& key1, const std::string& key2) const; }; // BayesTree diff --git a/cpp/FactorGraph-inl.h b/cpp/FactorGraph-inl.h index 86371920c..2b30b983e 100644 --- a/cpp/FactorGraph-inl.h +++ b/cpp/FactorGraph-inl.h @@ -18,6 +18,9 @@ #include "Ordering.h" #include "FactorGraph.h" +// trick from some reading group +#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) + using namespace std; namespace gtsam { @@ -95,6 +98,16 @@ void FactorGraph::push_back(sharedFactor factor) { } } +/* ************************************************************************* */ +template +Ordering FactorGraph::keys() const { + string key; + Ordering keys; + list indices_key; + FOREACH_PAIR(key, indices_key, indices_) keys.push_back(key); + return keys; +} + /* ************************************************************************* */ /** * Call colamd given a column-major symbolic matrix A @@ -213,48 +226,6 @@ removeAndCombineFactors(FactorGraph& factorGraph, const string& key) return new_factor; } -/* ************************************************************************* */ -/* eliminate one node from the factor graph */ -/* ************************************************************************* */ -template -boost::shared_ptr _eliminateOne(FactorGraph& graph, const string& key) { - - // combine the factors of all nodes connected to the variable to be eliminated - // if no factors are connected to key, returns an empty factor - boost::shared_ptr joint_factor = removeAndCombineFactors(graph,key); - - // eliminate that joint factor - boost::shared_ptr factor; - boost::shared_ptr conditional; - boost::tie(conditional, factor) = joint_factor->eliminate(key); - - // add new factor on separator back into the graph - if (!factor->empty()) graph.push_back(factor); - - // return the conditional Gaussian - return conditional; -} - -/* ************************************************************************* */ -// This doubly templated function is generic. There is a LinearFactorGraph -// version that returns a more specific GaussianBayesNet. -// Note, you will need to include this file to instantiate the function. -// TODO: get rid of summy argument -/* ************************************************************************* */ -template -BayesNet -_eliminate(FactorGraph& factorGraph, const Ordering& ordering) -{ - BayesNet bayesNet; // empty - - BOOST_FOREACH(string key, ordering) { - boost::shared_ptr cg = _eliminateOne(factorGraph,key); - bayesNet.push_back(cg); - } - - return bayesNet; -} - /* ************************************************************************* */ template FactorGraph combine(const FactorGraph& fg1, const FactorGraph& fg2) { diff --git a/cpp/FactorGraph.h b/cpp/FactorGraph.h index f1e87f342..1d6ffcc42 100644 --- a/cpp/FactorGraph.h +++ b/cpp/FactorGraph.h @@ -86,6 +86,9 @@ namespace gtsam { /** Add a factor */ void push_back(sharedFactor factor); + /** return keys in some random order */ + Ordering keys() const; + /** * Compute colamd ordering */ @@ -124,27 +127,7 @@ namespace gtsam { template boost::shared_ptr removeAndCombineFactors(FactorGraph& factorGraph, const std::string& key); - /** doubly templated functions */ - /** - * Eliminate a single node yielding a Conditional - * Eliminates the factors from the factor graph through findAndRemoveFactors - * and adds a new factor on the separator to the factor graph - */ - template - boost::shared_ptr _eliminateOne( - FactorGraph& factorGraph, - const std::string& key); - - /** - * eliminate factor graph using the given (not necessarily complete) - * ordering, yielding a chordal Bayes net and (partially eliminated) FG - */ - template - BayesNet - _eliminate(FactorGraph& factorGraph, const Ordering& ordering); - - /** * static function that combines two factor graphs * @param const &fg1 Linear factor graph * @param const &fg2 Linear factor graph diff --git a/cpp/LinearFactorGraph.cpp b/cpp/LinearFactorGraph.cpp index fea4f21d3..e7608702c 100644 --- a/cpp/LinearFactorGraph.cpp +++ b/cpp/LinearFactorGraph.cpp @@ -12,9 +12,10 @@ #include -#include "FactorGraph-inl.h" #include "LinearFactorGraph.h" #include "LinearFactorSet.h" +#include "FactorGraph-inl.h" +#include "inference-inl.h" using namespace std; using namespace gtsam; @@ -40,6 +41,12 @@ set LinearFactorGraph::find_separator(const string& key) const return separator; } +/* ************************************************************************* */ +ConditionalGaussian::shared_ptr +LinearFactorGraph::eliminateOne(const std::string& key) { + return gtsam::eliminateOne(*this, key); +} + /* ************************************************************************* */ GaussianBayesNet LinearFactorGraph::eliminate(const Ordering& ordering) @@ -59,15 +66,19 @@ VectorConfig LinearFactorGraph::optimize(const Ordering& ordering) GaussianBayesNet chordalBayesNet = eliminate(ordering); // calculate new configuration (using backsubstitution) - VectorConfig newConfig = ::optimize(chordalBayesNet); - - return newConfig; + return ::optimize(chordalBayesNet); } /* ************************************************************************* */ boost::shared_ptr -LinearFactorGraph::eliminate_(const Ordering& ordering) { - return boost::shared_ptr(new GaussianBayesNet(eliminate(ordering))); +LinearFactorGraph::eliminate_(const Ordering& ordering) +{ + boost::shared_ptr chordalBayesNet(new GaussianBayesNet); // empty + BOOST_FOREACH(string key, ordering) { + ConditionalGaussian::shared_ptr cg = eliminateOne(key); + chordalBayesNet->push_back(cg); + } + return chordalBayesNet; } /* ************************************************************************* */ diff --git a/cpp/LinearFactorGraph.h b/cpp/LinearFactorGraph.h index 232c600eb..040f1d6de 100644 --- a/cpp/LinearFactorGraph.h +++ b/cpp/LinearFactorGraph.h @@ -66,9 +66,7 @@ namespace gtsam { * Eliminates the factors from the factor graph through findAndRemoveFactors * and adds a new factor on the separator to the factor graph */ - inline ConditionalGaussian::shared_ptr eliminateOne(const std::string& key){ - return _eliminateOne(*this, key); - } + ConditionalGaussian::shared_ptr eliminateOne(const std::string& key); /** * eliminate factor graph in place(!) in the given order, yielding diff --git a/cpp/SymbolicFactorGraph.cpp b/cpp/SymbolicFactorGraph.cpp index 912c90eac..fc01479ef 100644 --- a/cpp/SymbolicFactorGraph.cpp +++ b/cpp/SymbolicFactorGraph.cpp @@ -7,9 +7,9 @@ #include #include "Ordering.h" -#include "FactorGraph-inl.h" #include "SymbolicFactorGraph.h" #include "SymbolicBayesNet.h" +#include "inference-inl.h" using namespace std; @@ -18,6 +18,12 @@ namespace gtsam { // Explicitly instantiate so we don't have to include everywhere template class FactorGraph; + /* ************************************************************************* */ + boost::shared_ptr + SymbolicFactorGraph::eliminateOne(const std::string& key){ + return gtsam::eliminateOne(*this, key); + } + /* ************************************************************************* */ SymbolicBayesNet SymbolicFactorGraph::eliminate(const Ordering& ordering) @@ -26,7 +32,7 @@ namespace gtsam { BOOST_FOREACH(string key, ordering) { SymbolicConditional::shared_ptr conditional = - _eliminateOne(*this,key); + gtsam::eliminateOne(*this,key); bayesNet.push_back(conditional); } return bayesNet; diff --git a/cpp/SymbolicFactorGraph.h b/cpp/SymbolicFactorGraph.h index 034acb803..e0b1e4e80 100644 --- a/cpp/SymbolicFactorGraph.h +++ b/cpp/SymbolicFactorGraph.h @@ -46,9 +46,7 @@ namespace gtsam { * Eliminates the factors from the factor graph through findAndRemoveFactors * and adds a new factor on the separator to the factor graph */ - inline boost::shared_ptr eliminateOne(const std::string& key){ - return _eliminateOne(*this, key); - } + boost::shared_ptr eliminateOne(const std::string& key); /** * eliminate factor graph in place(!) in the given order, yielding diff --git a/cpp/testBayesTree.cpp b/cpp/testBayesTree.cpp index d8438b595..ff70d5c89 100644 --- a/cpp/testBayesTree.cpp +++ b/cpp/testBayesTree.cpp @@ -177,28 +177,28 @@ TEST( BayesTree, balanced_smoother_marginals ) LONGS_EQUAL(7,bayesTree.size()); // Check marginal on x1 - GaussianBayesNet expected1 = simpleGaussian("x1", zero(2), sigmax1); - GaussianBayesNet actual1 = bayesTree.marginal("x1"); + GaussianBayesNet expected1 = simpleGaussian("x1", zero(2), sigmax1); + GaussianBayesNet actual1 = bayesTree.marginalBayesNet("x1"); CHECK(assert_equal(expected1,actual1,1e-4)); // Check marginal on x2 GaussianBayesNet expected2 = simpleGaussian("x2", zero(2), sigmax2); - GaussianBayesNet actual2 = bayesTree.marginal("x2"); + GaussianBayesNet actual2 = bayesTree.marginalBayesNet("x2"); CHECK(assert_equal(expected2,actual2,1e-4)); // Check marginal on x3 GaussianBayesNet expected3 = simpleGaussian("x3", zero(2), sigmax3); - GaussianBayesNet actual3 = bayesTree.marginal("x3"); + GaussianBayesNet actual3 = bayesTree.marginalBayesNet("x3"); CHECK(assert_equal(expected3,actual3,1e-4)); // Check marginal on x4 GaussianBayesNet expected4 = simpleGaussian("x4", zero(2), sigmax4); - GaussianBayesNet actual4 = bayesTree.marginal("x4"); + GaussianBayesNet actual4 = bayesTree.marginalBayesNet("x4"); CHECK(assert_equal(expected4,actual4,1e-4)); // Check marginal on x7 (should be equal to x1) GaussianBayesNet expected7 = simpleGaussian("x7", zero(2), sigmax7); - GaussianBayesNet actual7 = bayesTree.marginal("x7"); + GaussianBayesNet actual7 = bayesTree.marginalBayesNet("x7"); CHECK(assert_equal(expected7,actual7,1e-4)); } @@ -252,7 +252,8 @@ TEST( BayesTree, balanced_smoother_clique_marginals ) ConditionalGaussian::shared_ptr cg(new ConditionalGaussian("x1", zero(2), eye(2), "x2", A12, sigma)); expected.push_front(cg); Gaussian::sharedClique R = bayesTree.root(), C3 = bayesTree["x1"]; - GaussianBayesNet actual = C3->marginal(R); + FactorGraph marginal = C3->marginal(R); + GaussianBayesNet actual = eliminate(marginal,C3->keys()); CHECK(assert_equal(expected,actual,1e-4)); } @@ -276,14 +277,14 @@ TEST( BayesTree, balanced_smoother_joint ) GaussianBayesNet expected1 = simpleGaussian("x7", zero(2), sigmax7); ConditionalGaussian::shared_ptr cg1(new ConditionalGaussian("x1", zero(2), eye(2), "x7", A, sigma)); expected1.push_front(cg1); - GaussianBayesNet actual1 = bayesTree.joint("x1","x7"); + GaussianBayesNet actual1 = bayesTree.jointBayesNet("x1","x7"); CHECK(assert_equal(expected1,actual1,1e-4)); // Check the joint density P(x7,x1) factored as P(x7|x1)P(x1) GaussianBayesNet expected2 = simpleGaussian("x1", zero(2), sigmax1); ConditionalGaussian::shared_ptr cg2(new ConditionalGaussian("x7", zero(2), eye(2), "x1", A, sigma)); expected2.push_front(cg2); - GaussianBayesNet actual2 = bayesTree.joint("x7","x1"); + GaussianBayesNet actual2 = bayesTree.jointBayesNet("x7","x1"); CHECK(assert_equal(expected2,actual2,1e-4)); // Check the joint density P(x1,x4), i.e. with a root variable @@ -292,7 +293,7 @@ TEST( BayesTree, balanced_smoother_joint ) Matrix A14 = (-0.0769231)*eye(2); ConditionalGaussian::shared_ptr cg3(new ConditionalGaussian("x1", zero(2), eye(2), "x4", A14, sigma14)); expected3.push_front(cg3); - GaussianBayesNet actual3 = bayesTree.joint("x1","x4"); + GaussianBayesNet actual3 = bayesTree.jointBayesNet("x1","x4"); CHECK(assert_equal(expected3,actual3,1e-4)); // Check the joint density P(x4,x1), i.e. with a root variable, factored the other way @@ -301,7 +302,7 @@ TEST( BayesTree, balanced_smoother_joint ) Matrix A41 = (-0.055794)*eye(2); ConditionalGaussian::shared_ptr cg4(new ConditionalGaussian("x4", zero(2), eye(2), "x1", A41, sigma41)); expected4.push_front(cg4); - GaussianBayesNet actual4 = bayesTree.joint("x4","x1"); + GaussianBayesNet actual4 = bayesTree.jointBayesNet("x4","x1"); CHECK(assert_equal(expected4,actual4,1e-4)); } diff --git a/cpp/testGaussianBayesNet.cpp b/cpp/testGaussianBayesNet.cpp index 40b5e3ea7..39a2376b8 100644 --- a/cpp/testGaussianBayesNet.cpp +++ b/cpp/testGaussianBayesNet.cpp @@ -20,7 +20,7 @@ using namespace boost::assign; #endif //HAVE_BOOST_SERIALIZATION #include "GaussianBayesNet.h" -#include "BayesNet-inl.h" +#include "BayesNet.h" #include "smallExample.h" #include "Ordering.h" @@ -84,19 +84,6 @@ TEST( GaussianBayesNet, optimize ) CHECK(assert_equal(expected,actual)); } -/* ************************************************************************* */ -TEST( GaussianBayesNet, marginals ) -{ - // create and marginalize a small Bayes net on "x" - GaussianBayesNet cbn = createSmallGaussianBayesNet(); - Ordering keys("x"); - GaussianBayesNet actual = marginals(cbn,keys); - - // expected is just scalar Gaussian on x - GaussianBayesNet expected = scalarGaussian("x",4,sqrt(2)); - CHECK(assert_equal(expected,actual)); -} - /* ************************************************************************* */ #ifdef HAVE_BOOST_SERIALIZATION TEST( GaussianBayesNet, serialize ) diff --git a/cpp/testLinearFactorGraph.cpp b/cpp/testLinearFactorGraph.cpp index 994d5b056..cd1edab48 100644 --- a/cpp/testLinearFactorGraph.cpp +++ b/cpp/testLinearFactorGraph.cpp @@ -19,7 +19,7 @@ using namespace boost::assign; #include "Ordering.h" #include "smallExample.h" #include "GaussianBayesNet.h" -#include // needed for FactorGraph::eliminate +#include "inference-inl.h" // needed for eliminate and marginals using namespace gtsam; @@ -420,7 +420,7 @@ TEST( LinearFactorGraph, CONSTRUCTOR_GaussianBayesNet ) // Base FactorGraph only FactorGraph fg3(CBN); - GaussianBayesNet CBN3 = _eliminate(fg3,ord); + GaussianBayesNet CBN3 = gtsam::eliminate(fg3,ord); CHECK(assert_equal(CBN,CBN3)); } @@ -585,6 +585,15 @@ TEST( LinearFactorGraph, variables ) CHECK(expected==actual); } +/* ************************************************************************* */ +TEST( LinearFactorGraph, keys ) +{ + LinearFactorGraph fg = createLinearFactorGraph(); + Ordering expected; + expected += "l1","x1","x2"; + CHECK(assert_equal(expected,fg.keys())); +} + /* ************************************************************************* */ // Tests ported from ConstrainedLinearFactorGraph /* ************************************************************************* */