197 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
		
		
			
		
	
	
			197 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
| 
								 | 
							
								/* ----------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								 * 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 <iostream>
							 | 
						||
| 
								 | 
							
								#include <boost/utility.hpp> // for noncopyable
							 | 
						||
| 
								 | 
							
								#include <boost/foreach.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/range/iterator_range.hpp>
							 | 
						||
| 
								 | 
							
								#include <boost/serialization/nvp.hpp>
							 | 
						||
| 
								 | 
							
								#include <gtsam/base/types.h>
							 | 
						||
| 
								 | 
							
								#include <gtsam/base/Testable.h>
							 | 
						||
| 
								 | 
							
								#include <gtsam/inference/FactorBase.h>
							 | 
						||
| 
								 | 
							
								#include <gtsam/inference/Permutation.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								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<typename KEY>
							 | 
						||
| 
								 | 
							
								class ConditionalBase: public gtsam::FactorBase<KEY>, boost::noncopyable, public Testable<ConditionalBase<KEY> > {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /** The first nFrontal variables are frontal and the rest are parents. */
							 | 
						||
| 
								 | 
							
								  size_t nrFrontals_;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  typedef KEY Key;
							 | 
						||
| 
								 | 
							
								  typedef ConditionalBase<Key> This;
							 | 
						||
| 
								 | 
							
								  typedef gtsam::FactorBase<Key> Factor;
							 | 
						||
| 
								 | 
							
								  typedef boost::shared_ptr<This> shared_ptr;
							 | 
						||
| 
								 | 
							
								  typedef typename Factor::iterator iterator;
							 | 
						||
| 
								 | 
							
								  typedef typename Factor::const_iterator const_iterator;
							 | 
						||
| 
								 | 
							
								  typedef boost::iterator_range<const_iterator> Frontals;
							 | 
						||
| 
								 | 
							
								  typedef boost::iterator_range<const_iterator> 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<Key>& 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<class DERIVED, typename ITERATOR>
							 | 
						||
| 
								 | 
							
								  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<typename DERIVED, typename ITERATOR>
							 | 
						||
| 
								 | 
							
								  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<class DERIVED>
							 | 
						||
| 
								 | 
							
								  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<iterator> frontals() { return boost::make_iterator_range(beginFrontals(), endFrontals()); }
							 | 
						||
| 
								 | 
							
								  boost::iterator_range<iterator> 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<class ARCHIVE>
							 | 
						||
| 
								 | 
							
									void serialize(ARCHIVE & ar, const unsigned int version) {
							 | 
						||
| 
								 | 
							
								    ar & BOOST_SERIALIZATION_NVP(nrFrontals_);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 |