From a28ebc5461a6781e0b37d796ee68468a386b0452 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sun, 21 Jun 2015 22:41:12 -0700 Subject: [PATCH] Switched to vector --- gtsam/linear/HessianFactor.cpp | 13 +++--- gtsam/linear/Scatter.cpp | 74 +++++++++++++++++++--------------- gtsam/linear/Scatter.h | 20 ++++----- 3 files changed, 61 insertions(+), 46 deletions(-) diff --git a/gtsam/linear/HessianFactor.cpp b/gtsam/linear/HessianFactor.cpp index f3e54cffb..2b275b60f 100644 --- a/gtsam/linear/HessianFactor.cpp +++ b/gtsam/linear/HessianFactor.cpp @@ -237,11 +237,14 @@ HessianFactor::HessianFactor(const GaussianFactorGraph& factors, // Allocate and copy keys gttic(allocate); // Allocate with dimensions for each variable plus 1 at the end for the information vector - keys_.resize(scatter->size()); - FastVector dims(scatter->size() + 1); - BOOST_FOREACH(const Scatter::value_type& key_slotentry, *scatter) { - keys_[key_slotentry.second.slot] = key_slotentry.first; - dims[key_slotentry.second.slot] = key_slotentry.second.dimension; + const size_t n = scatter->size(); + keys_.resize(n); + FastVector dims(n + 1); + DenseIndex slot = 0; + BOOST_FOREACH(const SlotEntry& slotentry, *scatter) { + keys_[slot] = slotentry.key; + dims[slot] = slotentry.dimension; + ++slot; } dims.back() = 1; info_ = SymmetricBlockMatrix(dims); diff --git a/gtsam/linear/Scatter.cpp b/gtsam/linear/Scatter.cpp index 942b42160..dde83712a 100644 --- a/gtsam/linear/Scatter.cpp +++ b/gtsam/linear/Scatter.cpp @@ -21,6 +21,7 @@ #include #include +#include using namespace std; @@ -29,53 +30,62 @@ namespace gtsam { /* ************************************************************************* */ string SlotEntry::toString() const { ostringstream oss; - oss << "SlotEntry: slot=" << slot << ", dim=" << dimension; + oss << "SlotEntry: key=" << key << ", dim=" << dimension; return oss.str(); } /* ************************************************************************* */ Scatter::Scatter(const GaussianFactorGraph& gfg, - boost::optional ordering) { + boost::optional ordering) { gttic(Scatter_Constructor); - static const DenseIndex none = std::numeric_limits::max(); - - // 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) { - // TODO: Fix this hack to cope with zero-row Jacobians that come from - // BayesTreeOrphanWrappers - const JacobianFactor* asJacobian = - dynamic_cast(factor.get()); - if (!asJacobian || asJacobian->cols() > 1) - insert( - make_pair(*variable, SlotEntry(none, factor->getDim(variable)))); - } - } - } // If we have an ordering, pre-fill the ordered variables first - size_t slot = 0; if (ordering) { BOOST_FOREACH (Key key, *ordering) { - const_iterator entry = find(key); - if (entry == end()) - throw std::invalid_argument( - "The ordering provided to the HessianFactor Scatter constructor\n" - "contained extra variables that did not appear in the factors to " - "combine."); - at(key).slot = (slot++); + push_back(SlotEntry(key, 0)); } } - // Next fill in the slot indices (we can only get these after doing the set - // union. - BOOST_FOREACH (value_type& var_slot, *this) { - if (var_slot.second.slot == none) var_slot.second.slot = (slot++); + iterator first = end(); // remember position + + // Now, find dimensions of variables and/or extend + BOOST_FOREACH (const GaussianFactor::shared_ptr& factor, gfg) { + if (!factor) continue; + + // TODO: Fix this hack to cope with zero-row Jacobians that come from BayesTreeOrphanWrappers + const JacobianFactor* asJacobian = dynamic_cast(factor.get()); + if (asJacobian && asJacobian->cols() <= 1) continue; + + // loop over variables + for (GaussianFactor::const_iterator variable = factor->begin(); + variable != factor->end(); ++variable) { + const Key key = *variable; + iterator it = find(key); // theoretically expensive, yet cache friendly + if (it!=end()) + it->dimension = factor->getDim(variable); + else + push_back(SlotEntry(key, factor->getDim(variable))); + } } + + // Filter out keys with zero dimensions (if ordering had more keys) + erase(std::remove_if(begin(), end(), SlotEntry::Zero), end()); + + // To keep the same behavior as before, sort the keys after the ordering + if (first != end()) std::sort(begin(), end()); +} + +/* ************************************************************************* */ +FastVector::iterator Scatter::find(Key key) { + iterator it = begin(); + while(it != end()) { + if (it->key == key) + return it; + ++it; + } + return it; // end() } /* ************************************************************************* */ -} // gtsam +} // gtsam diff --git a/gtsam/linear/Scatter.h b/gtsam/linear/Scatter.h index 7a37ba1e0..39bfa6b8d 100644 --- a/gtsam/linear/Scatter.h +++ b/gtsam/linear/Scatter.h @@ -32,30 +32,32 @@ class Ordering; /// One SlotEntry stores the slot index for a variable, as well its dim. struct GTSAM_EXPORT SlotEntry { - DenseIndex slot; + Key key; size_t dimension; - SlotEntry(DenseIndex _slot, size_t _dimension) - : slot(_slot), dimension(_dimension) {} + SlotEntry(Key _key, size_t _dimension) : key(_key), dimension(_dimension) {} std::string toString() const; + friend bool operator<(const SlotEntry& p, const SlotEntry& q) { + return p.key < q.key; + } + static bool Zero(const SlotEntry& p) { return p.dimension==0;} }; /** * Scatter is an intermediate data structure used when building a HessianFactor - * incrementally, to get the keys in the right order. The "scatter" is a map + * incrementally, to get the keys in the right order. In spirit, it is a map * from global variable indices to slot indices in the union of involved * variables. We also include the dimensionality of the variable. */ -class Scatter : public FastMap { +class Scatter : public FastVector { public: /// Constructor Scatter(const GaussianFactorGraph& gfg, boost::optional ordering = boost::none); - /// Get the slot corresponding to the given key - DenseIndex slot(Key key) const { return at(key).slot; } + private: - /// Get the dimension corresponding to the given key - DenseIndex dim(Key key) const { return at(key).dimension; } + /// Find the SlotEntry with the right key (linear time worst case) + iterator find(Key key); }; } // \ namespace gtsam