/** * @file VariableIndex.h * @brief * @author Richard Roberts * @created Sep 12, 2010 */ #pragma once #include #include #include #include #include #include namespace gtsam { class Inference; /** * The VariableIndex can internally use either a vector or a deque to store * variables. For one-shot elimination, using a vector will give the best * performance, and this is the default. For incremental updates, such as in * ISAM and ISAM2, deque storage is used to prevent frequent reallocation. */ struct VariableIndexStorage_vector { template struct type_factory { typedef std::vector type; }; }; struct VariableIndexStorage_deque { template struct type_factory { typedef std::deque type; }; }; /** * The VariableIndex class stores the information necessary to perform * elimination, including an index of factors involving each variable and * the structure of the intermediate joint factors that develop during * elimination. This maps variables to deque's of pair, * which is pairs the factor index with the position of the variable within * the factor. */ struct _mapped_factor_type { size_t factorIndex; size_t variablePosition; _mapped_factor_type(size_t _factorIndex, size_t _variablePosition) : factorIndex(_factorIndex), variablePosition(_variablePosition) {} bool operator==(const _mapped_factor_type& o) const { return factorIndex == o.factorIndex && variablePosition == o.variablePosition; } }; template class VariableIndex { public: typedef _mapped_factor_type mapped_factor_type; typedef boost::shared_ptr shared_ptr; typedef std::deque mapped_type; typedef typename mapped_type::iterator factor_iterator; typedef typename mapped_type::const_iterator const_factor_iterator; protected: typedef typename VariableIndexStorage::template type_factory::type storage_type; storage_type indexUnpermuted_; Permuted index_; size_t nFactors_; size_t nEntries_; // Sum of involved variable counts of each factor public: VariableIndex() : index_(indexUnpermuted_), nFactors_(0), nEntries_(0) {} template VariableIndex(const FactorGraph& factorGraph); varid_t size() const { return index_.size(); } size_t nFactors() const { return nFactors_; } size_t nEntries() const { return nEntries_; } const mapped_type& operator[](varid_t variable) const { checkVar(variable); return index_[variable]; } mapped_type& operator[](varid_t variable) { checkVar(variable); return index_[variable]; } void permute(const Permutation& permutation); // template void augment(const Derived& varIndex); template void augment(const FactorGraph& factorGraph); void rebaseFactors(ptrdiff_t baseIndexChange); template bool equals(const Derived& other, double tol=0.0) const; void print(const std::string& str = "VariableIndex: ") const; protected: VariableIndex(size_t nVars) : indexUnpermuted_(nVars), index_(indexUnpermuted_), nFactors_(0), nEntries_(0) {} void checkVar(varid_t variable) const { assert(variable < index_.size()); } factor_iterator factorsBegin(varid_t variable) { checkVar(variable); return index_[variable].begin(); } const_factor_iterator factorsBegin(varid_t variable) const { checkVar(variable); return index_[variable].begin(); } factor_iterator factorsEnd(varid_t variable) { checkVar(variable); return index_[variable].end(); } const_factor_iterator factorsEnd(varid_t variable) const { checkVar(variable); return index_[variable].end(); } friend class Inference; }; /* ************************************************************************* */ template void VariableIndex::permute(const Permutation& permutation) { #ifndef NDEBUG // Assert that the permutation does not leave behind any non-empty variables, // otherwise the nFactors and nEntries counts would be incorrect. for(varid_t j=0; jindex_.size(); ++j) if(find(permutation.begin(), permutation.end(), j) == permutation.end()) assert(this->operator[](j).empty()); #endif index_.permute(permutation); // storage_type original(this->index_.size()); // this->index_.swap(original); // for(varid_t j=0; jindex_[j].swap(original[permutation[j]]); } /* ************************************************************************* */ template template VariableIndex::VariableIndex(const FactorGraph& factorGraph) : index_(indexUnpermuted_), nFactors_(0), nEntries_(0) { // 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) { // Find highest-numbered variable varid_t maxVar = 0; BOOST_FOREACH(const typename FactorGraph::sharedFactor& factor, factorGraph) { if(factor) { BOOST_FOREACH(const varid_t key, factor->keys()) { if(key > maxVar) maxVar = key; } } } // Allocate index index_.container().resize(maxVar+1); index_.permutation() = Permutation::Identity(maxVar+1); // Build index mapping from variable id to factor index for(size_t fi=0; fikeys()) { index_[key].push_back(mapped_factor_type(fi, fvari)); ++ fvari; ++ nEntries_; } ++ nFactors_; } } } ///* ************************************************************************* */ //template //template //void VariableIndex::augment(const Derived& varIndex) { // nFactors_ = std::max(nFactors_, varIndex.nFactors()); // nEntries_ = nEntries_ + varIndex.nEntries(); // varid_t originalSize = index_.size(); // index_.container().resize(std::max(index_.size(), varIndex.size())); // index_.permutation().resize(index_.container().size()); // for(varid_t var=originalSize; var template void VariableIndex::augment(const FactorGraph& factorGraph) { // 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) { // Find highest-numbered variable varid_t maxVar = 0; BOOST_FOREACH(const typename FactorGraph::sharedFactor& factor, factorGraph) { if(factor) { BOOST_FOREACH(const varid_t key, factor->keys()) { if(key > maxVar) maxVar = key; } } } // Allocate index varid_t originalSize = index_.size(); index_.container().resize(std::max(index_.size(), maxVar+1)); index_.permutation().resize(index_.container().size()); for(varid_t var=originalSize; varkeys()) { index_[key].push_back(mapped_factor_type(orignFactors + fi, fvari)); ++ fvari; ++ nEntries_; } ++ nFactors_; } } } /* ************************************************************************* */ template void VariableIndex::rebaseFactors(ptrdiff_t baseIndexChange) { BOOST_FOREACH(mapped_type& factors, index_.container()) { BOOST_FOREACH(mapped_factor_type& factor, factors) { factor.factorIndex += baseIndexChange; } } } /* ************************************************************************* */ template template bool VariableIndex::equals(const Derived& other, double tol) const { if(this->nEntries_ == other.nEntries_ && this->nFactors_ == other.nFactors_ && this->index_.size() == other.index_.size()) { for(size_t var=0; varindex_.size(); ++var) if(this->index_[var] != other.index_[var]) return false; } else return false; return true; } /* ************************************************************************* */ template void VariableIndex::print(const std::string& str) const { std::cout << str; varid_t var = 0; BOOST_FOREACH(const mapped_type& variable, index_.container()) { Permutation::const_iterator rvar = find(index_.permutation().begin(), index_.permutation().end(), var); assert(rvar != index_.permutation().end()); std::cout << "var " << *rvar << ":"; BOOST_FOREACH(const mapped_factor_type& factor, variable) { std::cout << " " << factor.factorIndex << "-" << factor.variablePosition; } std::cout << "\n"; ++ var; } std::cout << std::flush; } }