/* ---------------------------------------------------------------------------- * 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 // for noncopyable #include #include #include #include #include #include #include namespace gtsam { /** * Base class for conditional densities * * We make it noncopyable so we enforce the fact that factors are * kept in pointer containers. To be safe, you should make them * immutable, i.e., practicing functional programming. */ template class ConditionalBase: public gtsam::FactorBase, boost::noncopyable, public Testable > { protected: /** The first nFrontal variables are frontal and the rest are parents. */ size_t nrFrontals_; public: typedef KEY Key; typedef ConditionalBase This; typedef gtsam::FactorBase Factor; typedef boost::shared_ptr shared_ptr; typedef typename Factor::iterator iterator; typedef typename Factor::const_iterator const_iterator; typedef boost::iterator_range Frontals; typedef boost::iterator_range Parents; /** Empty Constructor to make serialization possible */ ConditionalBase() : nrFrontals_(0) {} /** No parents */ ConditionalBase(Key key) : Factor(key), nrFrontals_(1) {} /** Single parent */ ConditionalBase(Key key, Key parent) : Factor(key, parent), nrFrontals_(1) {} /** Two parents */ ConditionalBase(Key key, Key parent1, Key parent2) : Factor(key, parent1, parent2), nrFrontals_(1) {} /** Three parents */ ConditionalBase(Key key, Key parent1, Key parent2, Key parent3) : Factor(key, parent1, parent2, parent3), nrFrontals_(1) {} /** Constructor from a frontal variable and a vector of parents */ ConditionalBase(Key key, const std::vector& parents) : nrFrontals_(1) { Factor::keys_.resize(1 + parents.size()); *(beginFrontals()) = key; std::copy(parents.begin(), parents.end(), beginParents()); } /** Constructor from a frontal variable and an iterator range of parents */ template static typename DERIVED::shared_ptr FromRange(Key key, ITERATOR firstParent, ITERATOR lastParent) { typename DERIVED::shared_ptr conditional(new DERIVED); conditional->nrFrontals_ = 1; conditional->keys_.push_back(key); std::copy(firstParent, lastParent, back_inserter(conditional->keys_)); return conditional; } /** Named constructor from any number of frontal variables and parents */ template static typename DERIVED::shared_ptr FromRange(ITERATOR firstKey, ITERATOR lastKey, size_t nrFrontals) { typename DERIVED::shared_ptr conditional(new DERIVED); conditional->nrFrontals_ = nrFrontals; std::copy(firstKey, lastKey, back_inserter(conditional->keys_)); return conditional; } /** check equality */ template bool equals(const DERIVED& c, double tol = 1e-9) const { return nrFrontals_ == c.nrFrontals_ && Factor::equals(c, tol); } /** return the number of frontals */ size_t nrFrontals() const { return nrFrontals_; } /** return the number of parents */ size_t nrParents() const { return Factor::keys_.size() - nrFrontals_; } /** Special accessor when there is only one frontal variable. */ Key key() const { assert(nrFrontals_==1); return Factor::keys_[0]; } /** Iterators over frontal and parent variables. */ const_iterator beginFrontals() const { return Factor::keys_.begin(); } const_iterator endFrontals() const { return Factor::keys_.begin()+nrFrontals_; } const_iterator beginParents() const { return Factor::keys_.begin()+nrFrontals_; } const_iterator endParents() const { return Factor::keys_.end(); } /** Mutable iterators and accessors */ iterator beginFrontals() { return Factor::keys_.begin(); } iterator endFrontals() { return Factor::keys_.begin()+nrFrontals_; } iterator beginParents() { return Factor::keys_.begin()+nrFrontals_; } iterator endParents() { return Factor::keys_.end(); } boost::iterator_range frontals() { return boost::make_iterator_range(beginFrontals(), endFrontals()); } boost::iterator_range parents() { return boost::make_iterator_range(beginParents(), endParents()); } /** 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()); } /** print */ void print(const std::string& s = "Conditional") const { std::cout << s << " P("; BOOST_FOREACH(Key key, frontals()) std::cout << " " << key; if (nrParents()>0) std::cout << " |"; BOOST_FOREACH(Key parent, parents()) std::cout << " " << parent; std::cout << ")" << std::endl; } /** Permute the variables when only separator variables need to be permuted. * Returns true if any reordered variables appeared in the separator and * false if not. */ bool permuteSeparatorWithInverse(const Permutation& inversePermutation) { #ifndef NDEBUG BOOST_FOREACH(Key key, frontals()) { assert(key == inversePermutation[key]); } #endif bool parentChanged = false; BOOST_FOREACH(Key& parent, parents()) { Key newParent = inversePermutation[parent]; if(parent != newParent) { parentChanged = true; parent = newParent; } } return parentChanged; } /** * Permutes the Conditional, but for efficiency requires the permutation * to already be inverted. */ void permuteWithInverse(const Permutation& inversePermutation) { // The permutation may not move the separators into the frontals #ifndef NDEBUG BOOST_FOREACH(const Key frontal, this->frontals()) { BOOST_FOREACH(const Key separator, this->parents()) { assert(inversePermutation[frontal] < inversePermutation[separator]); } } #endif Factor::permuteWithInverse(inversePermutation); } protected: /** Debugging invariant that the keys should be in order, including that the * conditioned variable is numbered lower than the parents. */ void assertInvariants() const; private: /** Serialization function */ friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(nrFrontals_); } }; }