diff --git a/.cproject b/.cproject index d80047a9d..63e07de34 100644 --- a/.cproject +++ b/.cproject @@ -332,7 +332,7 @@ -f local.mk testCal3_S2.run true -false +true true diff --git a/cpp/ConstrainedLinearFactorGraph.cpp b/cpp/ConstrainedLinearFactorGraph.cpp index 62b7b1254..ccb1b450e 100644 --- a/cpp/ConstrainedLinearFactorGraph.cpp +++ b/cpp/ConstrainedLinearFactorGraph.cpp @@ -107,7 +107,7 @@ ConstrainedConditionalGaussian::shared_ptr ConstrainedLinearFactorGraph::elimina ConstrainedConditionalGaussian::shared_ptr ccg = constraint->eliminate(key); // perform a change of variables on the linear factors in the separator - LinearFactorSet separator = find_factors_and_remove(key); + vector separator = find_factors_and_remove(key); BOOST_FOREACH(LinearFactor::shared_ptr factor, separator) { // store the block matrices map blocks; diff --git a/cpp/ConstrainedNonlinearFactorGraph.h b/cpp/ConstrainedNonlinearFactorGraph.h index 9dde141c1..4c7468057 100644 --- a/cpp/ConstrainedNonlinearFactorGraph.h +++ b/cpp/ConstrainedNonlinearFactorGraph.h @@ -24,7 +24,7 @@ namespace gtsam { * To fix it, we need to think more deeply about this. */ template -class ConstrainedNonlinearFactorGraph: public FactorGraph { +class ConstrainedNonlinearFactorGraph: public FactorGraph { protected: /** collection of equality factors */ std::vector eq_factors; @@ -44,7 +44,7 @@ public: * Copy constructor from regular NLFGs */ ConstrainedNonlinearFactorGraph(const NonlinearFactorGraph& nfg) : - FactorGraph (nfg) { + FactorGraph (nfg) { } typedef typename boost::shared_ptr shared_factor; @@ -78,7 +78,7 @@ public: * Insert a factor into the graph */ void push_back(const shared_factor& f) { - FactorGraph::push_back(f); + FactorGraph::push_back(f); } /** diff --git a/cpp/Factor.h b/cpp/Factor.h index 35aa9e084..b99553641 100644 --- a/cpp/Factor.h +++ b/cpp/Factor.h @@ -59,12 +59,6 @@ namespace gtsam { */ virtual double error(const Config& c) const = 0; - /** - * equality up to tolerance - * tricky to implement, see NonLinearFactor1 for an example - virtual bool equals(const Factor& f, double tol=1e-9) const = 0; - */ - virtual std::string dump() const = 0; /** diff --git a/cpp/FactorGraph-inl.h b/cpp/FactorGraph-inl.h index cf5e4c54a..724296eac 100644 --- a/cpp/FactorGraph-inl.h +++ b/cpp/FactorGraph-inl.h @@ -23,8 +23,8 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ -template -void FactorGraph::print(const string& s) const { +template +void FactorGraph::print(const string& s) const { cout << s << endl; printf("size: %d\n", (int) size()); for (int i = 0; i < factors_.size(); i++) { @@ -35,9 +35,9 @@ void FactorGraph::print(const string& s) const { } /* ************************************************************************* */ -template -bool FactorGraph::equals - (const FactorGraph& fg, double tol) const { +template +bool FactorGraph::equals + (const FactorGraph& fg, double tol) const { /** check whether the two factor graphs have the same number of factors_ */ if (factors_.size() != fg.size()) return false; @@ -53,26 +53,36 @@ bool FactorGraph::equals } /* ************************************************************************* */ -template -void FactorGraph::push_back(shared_factor factor) { - factors_.push_back(factor); // add the actual factor - int i = factors_.size() - 1; // index of factor - list keys = factor->keys(); // get keys for factor - BOOST_FOREACH(string key, keys){ // for each key push i onto list +template +size_t FactorGraph::nrFactors() const { + int size_ = 0; + for (const_iterator factor = factors_.begin(); factor != factors_.end(); factor++) + if (*factor != NULL) size_++; + return size_; +} + +/* ************************************************************************* */ +template +void FactorGraph::push_back(shared_factor factor) { + + factors_.push_back(factor); // add the actual factor + + int i = factors_.size() - 1; // index of factor + list keys = factor->keys(); // get keys for factor + + BOOST_FOREACH(string key, keys){ // for each key push i onto list Indices::iterator it = indices_.find(key); // old list for that key (if exists) - if (it==indices_.end()){ // there's no list yet, so make one - list indices(1, i); - indices_.insert(pair >(key, indices)); // insert new indices into factorMap + if (it==indices_.end()){ // there's no list yet + list indices(1,i); // so make one + indices_.insert(make_pair(key,indices)); // insert new indices into factorMap } - else{ - list *indices_ptr; - indices_ptr = &(it->second); - indices_ptr->push_back(i); + else { + list *indices_ptr = &(it->second); // get the list + indices_ptr->push_back(i); // add the index i to it } } } - /* ************************************************************************* */ /** * Call colamd given a column-major symbolic matrix A @@ -122,12 +132,12 @@ Ordering colamd(int n_col, int n_row, int nrNonZeros, const map } /* ************************************************************************* */ -template -Ordering FactorGraph::getOrdering() const { +template +Ordering FactorGraph::getOrdering() const { // A factor graph is really laid out in row-major format, each factor a row // Below, we compute a symbolic matrix stored in sparse columns. - typedef string Key; // default case with string keys + typedef string Key; // default case with string keys map > columns; // map from keys to a sparse column of non-zero row indices int nrNonZeros = 0; // number of non-zero entries int n_row = factors_.size(); /* colamd arg 1: number of rows in A */ @@ -147,5 +157,29 @@ Ordering FactorGraph::getOrdering() const { return colamd(n_col, n_row, nrNonZeros, columns); } +/* ************************************************************************* */ +/** find all non-NULL factors for a variable, then set factors to NULL */ +/* ************************************************************************* */ +template +vector > +FactorGraph::find_factors_and_remove(const string& key) { + vector > found; + + Indices::iterator it = indices_.find(key); + if (it == indices_.end()) + throw(std::invalid_argument + ("FactorGraph::find_factors_and_remove invalid key: " + key)); + + list *indices_ptr; // pointer to indices list in indices_ map + indices_ptr = &(it->second); + + BOOST_FOREACH(int i, *indices_ptr) { + if(factors_[i] == NULL) continue; // skip NULL factors + found.push_back(factors_[i]); // add to found + factors_[i].reset(); // set factor to NULL. + } + return found; +} + /* ************************************************************************* */ } diff --git a/cpp/FactorGraph.h b/cpp/FactorGraph.h index 78b1c5d43..77b94e6b3 100644 --- a/cpp/FactorGraph.h +++ b/cpp/FactorGraph.h @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include @@ -18,10 +19,6 @@ namespace gtsam { class Ordering; - class VectorConfig; - class LinearFactor; - class LinearFactorGraph; - class Ordering; /** * A factor graph is a bipartite graph with factor nodes connected to variable nodes. @@ -29,9 +26,7 @@ namespace gtsam { * * Templated on the type of factors and configuration. */ - template class FactorGraph - : public Testable > - { + template class FactorGraph: public Testable > { public: typedef typename boost::shared_ptr shared_factor; typedef typename std::vector::iterator iterator; @@ -73,38 +68,27 @@ namespace gtsam { return factors_[i]; } - /** return the numbers of the factors_ in the factor graph */ - inline size_t size() const { - int size_=0; - for (const_iterator factor = factors_.begin(); factor != factors_.end(); factor++) - if(*factor != NULL) - size_++; - return size_; - } + /** return the number of factors and NULLS */ + inline size_t size() const { return factors_.size();} + + /** return the number valid factors */ + size_t nrFactors() const; /** Add a factor */ void push_back(shared_factor factor); - /** unnormalized error */ - double error(const Config& c) const { - double total_error = 0.; - /** iterate over all the factors_ to accumulate the log probabilities */ - for (const_iterator factor = factors_.begin(); factor != factors_.end(); factor++) - total_error += (*factor)->error(c); - - return total_error; - } - - /** Unnormalized probability. O(n) */ - double probPrime(const Config& c) const { - return exp(-0.5 * error(c)); - } - /** * Compute colamd ordering */ Ordering getOrdering() const; + /** + * find all the factors that involve the given node and remove them + * from the factor graph + * @param key the key for the given node + */ + std::vector find_factors_and_remove(const std::string& key); + private: /** Serialization function */ @@ -112,6 +96,7 @@ namespace gtsam { template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(factors_); + ar & BOOST_SERIALIZATION_NVP(indices_); } }; // FactorGraph } // namespace gtsam diff --git a/cpp/LinearFactorGraph.cpp b/cpp/LinearFactorGraph.cpp index 4d4637ba7..63052716b 100644 --- a/cpp/LinearFactorGraph.cpp +++ b/cpp/LinearFactorGraph.cpp @@ -55,34 +55,13 @@ list LinearFactorGraph::factors(const string& key) const { return it->second; } - -/* ************************************************************************* */ -/** find all non-NULL factors for a variable, then set factors to NULL */ -/* ************************************************************************* */ -LinearFactorSet LinearFactorGraph::find_factors_and_remove(const string& key) { - LinearFactorSet found; - - Indices::iterator it = indices_.find(key); - list *indices_ptr; // pointer to indices list in indices_ map - indices_ptr = &(it->second); - - for (list::iterator it = indices_ptr->begin(); it != indices_ptr->end(); it++) { - if(factors_[*it] == NULL){ // skip NULL factors - continue; - } - found.push_back(factors_[*it]); - factors_[*it].reset(); // set factor to NULL. - } - return found; -} - /* ************************************************************************* */ /* find factors and remove them from the factor graph: O(n) */ /* ************************************************************************* */ boost::shared_ptr LinearFactorGraph::combine_factors(const string& key) { - LinearFactorSet found = find_factors_and_remove(key); + vector found = find_factors_and_remove(key); boost::shared_ptr lf(new LinearFactor(found)); return lf; } diff --git a/cpp/LinearFactorGraph.h b/cpp/LinearFactorGraph.h index 586681d3c..1ce89df55 100644 --- a/cpp/LinearFactorGraph.h +++ b/cpp/LinearFactorGraph.h @@ -27,7 +27,7 @@ namespace gtsam { * VectorConfig = A configuration of vectors * Most of the time, linear factor graphs arise by linearizing a non-linear factor graph. */ - class LinearFactorGraph : public FactorGraph { + class LinearFactorGraph : public FactorGraph { public: /** @@ -40,6 +40,21 @@ namespace gtsam { */ LinearFactorGraph(const ChordalBayesNet& CBN); + /** unnormalized error */ + double error(const VectorConfig& c) const { + double total_error = 0.; + // iterate over all the factors_ to accumulate the log probabilities + for (const_iterator factor = factors_.begin(); factor != factors_.end(); factor++) + total_error += (*factor)->error(c); + + return total_error; + } + + /** Unnormalized probability. O(n) */ + double probPrime(const VectorConfig& c) const { + return exp(-0.5 * error(c)); + } + /** * given a chordal bayes net, sets the linear factor graph identical to that CBN * FD: imperative !! @@ -58,13 +73,6 @@ namespace gtsam { */ std::list factors(const std::string& key) const; - /** - * find all the factors that involve the given node and remove them - * from the factor graph - * @param key the key for the given node - */ - LinearFactorSet find_factors_and_remove(const std::string& key); - /** * extract and combine all the factors that involve a given node * NOTE: the combined factor will be depends on a system-dependent diff --git a/cpp/Makefile.am b/cpp/Makefile.am index 7e510494f..3ea06573a 100644 --- a/cpp/Makefile.am +++ b/cpp/Makefile.am @@ -82,12 +82,12 @@ timeLinearFactor: LDFLAGS += -L.libs -lgtsam # graphs sources += LinearFactorGraph.cpp -#sources += BayesChain.cpp SymbolicBayesChain.cpp +sources += SymbolicBayesChain.cpp sources += ChordalBayesNet.cpp sources += ConstrainedNonlinearFactorGraph.cpp ConstrainedLinearFactorGraph.cpp check_PROGRAMS += testFactorgraph testLinearFactorGraph testNonlinearFactorGraph check_PROGRAMS += testChordalBayesNet testNonlinearOptimizer -#check_PROGRAMS += testSymbolicBayesChain testBayesTree +check_PROGRAMS += testSymbolicBayesChain testBayesTree check_PROGRAMS += testConstrainedNonlinearFactorGraph testConstrainedLinearFactorGraph testFactorgraph_SOURCES = testFactorgraph.cpp testLinearFactorGraph_SOURCES = $(example) testLinearFactorGraph.cpp diff --git a/cpp/NonlinearFactorGraph-inl.h b/cpp/NonlinearFactorGraph-inl.h index d91504313..eb9536ab0 100644 --- a/cpp/NonlinearFactorGraph-inl.h +++ b/cpp/NonlinearFactorGraph-inl.h @@ -13,27 +13,42 @@ namespace gtsam { -/* ************************************************************************* */ -template -LinearFactorGraph NonlinearFactorGraph::linearize(const Config& config) const { - // TODO speed up the function either by returning a pointer or by - // returning the linearisation as a second argument and returning - // the reference + /* ************************************************************************* */ + template + double NonlinearFactorGraph::error(const Config& c) const { + double total_error = 0.; + // iterate over all the factors_ to accumulate the log probabilities + typedef typename FactorGraph >::const_iterator + const_iterator; + for (const_iterator factor = this->factors_.begin(); factor + != this->factors_.end(); factor++) + total_error += (*factor)->error(c); - // create an empty linear FG - LinearFactorGraph linearFG; + return total_error; + } + /* ************************************************************************* */ + template + LinearFactorGraph NonlinearFactorGraph::linearize( + const Config& config) const { + // TODO speed up the function either by returning a pointer or by + // returning the linearisation as a second argument and returning + // the reference - typedef typename FactorGraph ,Config>:: const_iterator const_iterator; - // linearize all factors - for (const_iterator factor = this->factors_.begin(); factor - < this->factors_.end(); factor++) { - boost::shared_ptr lf = (*factor)->linearize(config); - linearFG.push_back(lf); + // create an empty linear FG + LinearFactorGraph linearFG; + + typedef typename FactorGraph >::const_iterator + const_iterator; + // linearize all factors + for (const_iterator factor = this->factors_.begin(); factor + < this->factors_.end(); factor++) { + boost::shared_ptr lf = (*factor)->linearize(config); + linearFG.push_back(lf); + } + + return linearFG; } - return linearFG; -} - /* ************************************************************************* */ } diff --git a/cpp/NonlinearFactorGraph.h b/cpp/NonlinearFactorGraph.h index 085c5e828..b6f6f6cb3 100644 --- a/cpp/NonlinearFactorGraph.h +++ b/cpp/NonlinearFactorGraph.h @@ -11,7 +11,7 @@ #pragma once #include "NonlinearFactor.h" -#include "FactorGraph.h" +#include "LinearFactorGraph.h" namespace gtsam { @@ -22,12 +22,20 @@ namespace gtsam { * Linearizing the non-linear factor graph creates a linear factor graph on the * tangent vector space at the linearization point. Because the tangent space is a true * vector space, the config type will be an VectorConfig in that linearized - */ + */ template - class NonlinearFactorGraph: public FactorGraph ,Config> { + class NonlinearFactorGraph: public FactorGraph > { public: + /** unnormalized error */ + double error(const Config& c) const; + + /** Unnormalized probability. O(n) */ + double probPrime(const Config& c) const { + return exp(-0.5 * error(c)); + } + /** * linearize a nonlinear factor graph */ diff --git a/cpp/SymbolicBayesChain-inl.h b/cpp/SymbolicBayesChain-inl.h index 05e693614..b783824e9 100644 --- a/cpp/SymbolicBayesChain-inl.h +++ b/cpp/SymbolicBayesChain-inl.h @@ -14,9 +14,9 @@ using namespace std; namespace gtsam { /* ************************************************************************* */ - template + template SymbolicBayesChain::SymbolicBayesChain( - const FactorGraph& factorGraph, const Ordering& ordering) { + const FactorGraph& factorGraph, const Ordering& ordering) { } /* ************************************************************************* */ diff --git a/cpp/SymbolicBayesChain.cpp b/cpp/SymbolicBayesChain.cpp index 0b7fcb5e1..79c4cbd87 100644 --- a/cpp/SymbolicBayesChain.cpp +++ b/cpp/SymbolicBayesChain.cpp @@ -10,6 +10,7 @@ // trick from some reading group #define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) +#include "BayesChain-inl.h" #include "SymbolicBayesChain.h" using namespace std; diff --git a/cpp/SymbolicBayesChain.h b/cpp/SymbolicBayesChain.h index 21d078dbd..392710284 100644 --- a/cpp/SymbolicBayesChain.h +++ b/cpp/SymbolicBayesChain.h @@ -36,8 +36,8 @@ namespace gtsam { /** * Construct from any factor graph */ - template - SymbolicBayesChain(const FactorGraph& factorGraph, + template + SymbolicBayesChain(const FactorGraph& factorGraph, const Ordering& ordering); /** Destructor */ diff --git a/cpp/testConstrainedLinearFactorGraph.cpp b/cpp/testConstrainedLinearFactorGraph.cpp index 319750eab..fb1f531f1 100644 --- a/cpp/testConstrainedLinearFactorGraph.cpp +++ b/cpp/testConstrainedLinearFactorGraph.cpp @@ -6,6 +6,7 @@ #include #include #include "ConstrainedLinearFactorGraph.h" +#include "FactorGraph-inl.h" #include "LinearFactorGraph.h" #include "smallExample.h" @@ -237,12 +238,12 @@ TEST( ConstrainedLinearFactorGraph, eliminate_multi_constraint ) // eliminate the constraint ConstrainedConditionalGaussian::shared_ptr cg1 = fg.eliminate_constraint("x"); CHECK(cg1->size() == 1); - CHECK(fg.size() == 2); + CHECK(fg.nrFactors() == 1); // eliminate the induced constraint ConstrainedConditionalGaussian::shared_ptr cg2 = fg.eliminate_constraint("y"); - CHECK(fg.size() == 1); CHECK(cg2->size() == 1); + CHECK(fg.nrFactors() == 0); // eliminate the linear factor ConditionalGaussian::shared_ptr cg3 = fg.eliminate_one("z"); @@ -259,7 +260,6 @@ TEST( ConstrainedLinearFactorGraph, eliminate_multi_constraint ) CHECK(assert_equal(act_y, Vector_(2, -0.1, 0.4), 1e-4)); Vector act_x = cg1->solve(actual); CHECK(assert_equal(act_x, Vector_(2, -2.0, 2.0), 1e-4)); - } /* ************************************************************************* */ diff --git a/cpp/testLinearFactorGraph.cpp b/cpp/testLinearFactorGraph.cpp index bea73cc6a..67287b146 100644 --- a/cpp/testLinearFactorGraph.cpp +++ b/cpp/testLinearFactorGraph.cpp @@ -487,7 +487,7 @@ TEST( LinearFactorGraph, find_factors_and_remove ) LinearFactor::shared_ptr f2 = fg[2]; // call the function - LinearFactorSet factors = fg.find_factors_and_remove("x1"); + vector factors = fg.find_factors_and_remove("x1"); // Check the factors CHECK(f0==factors[0]); @@ -495,7 +495,7 @@ TEST( LinearFactorGraph, find_factors_and_remove ) CHECK(f2==factors[2]); // CHECK if the factors are deleted from the factor graph - LONGS_EQUAL(1,fg.size()); + LONGS_EQUAL(1,fg.nrFactors()); } /* ************************************************************************* */ @@ -510,7 +510,7 @@ TEST( LinearFactorGraph, find_factors_and_remove__twice ) LinearFactor::shared_ptr f2 = fg[2]; // call the function - LinearFactorSet factors = fg.find_factors_and_remove("x1"); + vector factors = fg.find_factors_and_remove("x1"); // Check the factors CHECK(f0==factors[0]); @@ -521,7 +521,7 @@ TEST( LinearFactorGraph, find_factors_and_remove__twice ) CHECK(factors.size() == 0); // CHECK if the factors are deleted from the factor graph - LONGS_EQUAL(1,fg.size()); + LONGS_EQUAL(1,fg.nrFactors()); } /* ************************************************************************* */ diff --git a/cpp/testSymbolicBayesChain.cpp b/cpp/testSymbolicBayesChain.cpp index 183eeac69..8527e319d 100644 --- a/cpp/testSymbolicBayesChain.cpp +++ b/cpp/testSymbolicBayesChain.cpp @@ -7,32 +7,121 @@ #include #include "smallExample.h" +#include "FactorGraph-inl.h" #include "BayesChain-inl.h" #include "SymbolicBayesChain-inl.h" +namespace gtsam { + + /** Symbolic Factor */ + class SymbolicFactor: public Testable { + private: + + std::list keys_; + + public: + + SymbolicFactor(std::list keys) : + keys_(keys) { + } + + typedef boost::shared_ptr shared_ptr; + + /** print */ + void print(const std::string& s = "SymbolicFactor") const { + cout << s << " "; + BOOST_FOREACH(string key, keys_) cout << key << " "; + cout << endl; + } + + /** check equality */ + bool equals(const SymbolicFactor& other, double tol = 1e-9) const { + return keys_ == other.keys_; + } + + /** + * Find all variables + * @return The set of all variable keys + */ + std::list keys() const { + return keys_; + } + }; + + /** Symbolic Factor Graph */ + class SymbolicFactorGraph: public FactorGraph { + public: + + SymbolicFactorGraph() {} + + template + SymbolicFactorGraph(const FactorGraph& fg) { + for (size_t i = 0; i < fg.size(); i++) { + boost::shared_ptr f = fg[i]; + std::list keys = f->keys(); + SymbolicFactor::shared_ptr factor(new SymbolicFactor(keys)); + push_back(factor); + } + } + + }; + +} + +using namespace std; using namespace gtsam; +/* ************************************************************************* */ +TEST( SymbolicBayesChain, symbolicFactorGraph ) +{ + // construct expected symbolic graph + SymbolicFactorGraph expected; + + list f1_keys; f1_keys.push_back("x1"); + SymbolicFactor::shared_ptr f1(new SymbolicFactor(f1_keys)); + expected.push_back(f1); + + list f2_keys; f2_keys.push_back("x1"); f2_keys.push_back("x2"); + SymbolicFactor::shared_ptr f2(new SymbolicFactor(f2_keys)); + expected.push_back(f2); + + list f3_keys; f3_keys.push_back("l1"); f3_keys.push_back("x1"); + SymbolicFactor::shared_ptr f3(new SymbolicFactor(f3_keys)); + expected.push_back(f3); + + list f4_keys; f4_keys.push_back("l1"); f4_keys.push_back("x2"); + SymbolicFactor::shared_ptr f4(new SymbolicFactor(f4_keys)); + expected.push_back(f4); + + // construct it from the factor graph graph + LinearFactorGraph factorGraph = createLinearFactorGraph(); + SymbolicFactorGraph actual(factorGraph); + + CHECK(assert_equal(expected, actual)); + + //symbolicGraph.find_factors_and_remove("x"); +} + /* ************************************************************************* */ TEST( SymbolicBayesChain, constructor ) { // Create manually - SymbolicConditional::shared_ptr x2(new SymbolicConditional("x1","l1")); + SymbolicConditional::shared_ptr x2(new SymbolicConditional("x1", "l1")); SymbolicConditional::shared_ptr l1(new SymbolicConditional("x1")); SymbolicConditional::shared_ptr x1(new SymbolicConditional()); map nodes; - nodes.insert(make_pair("x2",x2)); - nodes.insert(make_pair("l1",l1)); - nodes.insert(make_pair("x1",x1)); + nodes.insert(make_pair("x2", x2)); + nodes.insert(make_pair("l1", l1)); + nodes.insert(make_pair("x1", x1)); SymbolicBayesChain expected(nodes); // Create from a factor graph - Ordering ordering; - ordering.push_back("x2"); - ordering.push_back("l1"); - ordering.push_back("x1"); + Ordering ordering; + ordering.push_back("x2"); + ordering.push_back("l1"); + ordering.push_back("x1"); LinearFactorGraph factorGraph = createLinearFactorGraph(); - SymbolicBayesChain actual(factorGraph,ordering); - + SymbolicBayesChain actual(factorGraph, ordering); //CHECK(assert_equal(expected, actual)); }