Removed obsolete Ordered classes and unit tests that have already been converted
parent
682eddf3ef
commit
be0b27a003
|
|
@ -1,192 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 BayesNet-inl.h
|
||||
* @brief Bayes net template definitions
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <boost/assign/std/vector.hpp> // for +=
|
||||
using boost::assign::operator+=;
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
void BayesNetOrdered<CONDITIONAL>::print(const std::string& s,
|
||||
const IndexFormatter& formatter) const {
|
||||
std::cout << s;
|
||||
BOOST_REVERSE_FOREACH(sharedConditional conditional, conditionals_)
|
||||
conditional->print("Conditional", formatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
bool BayesNetOrdered<CONDITIONAL>::equals(const BayesNetOrdered& cbn, double tol) const {
|
||||
if (size() != cbn.size())
|
||||
return false;
|
||||
return std::equal(conditionals_.begin(), conditionals_.end(),
|
||||
cbn.conditionals_.begin(), equals_star<CONDITIONAL>(tol));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
void BayesNetOrdered<CONDITIONAL>::printStats(const std::string& s) const {
|
||||
|
||||
const size_t n = conditionals_.size();
|
||||
size_t max_size = 0;
|
||||
size_t total = 0;
|
||||
BOOST_REVERSE_FOREACH(sharedConditional conditional, conditionals_) {
|
||||
max_size = std::max(max_size, conditional->size());
|
||||
total += conditional->size();
|
||||
}
|
||||
std::cout << s
|
||||
<< "maximum conditional size = " << max_size << std::endl
|
||||
<< "average conditional size = " << total / n << std::endl
|
||||
<< "density = " << 100.0 * total / (double) (n*(n+1)/2) << " %" << std::endl;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
void BayesNetOrdered<CONDITIONAL>::saveGraph(const std::string &s,
|
||||
const IndexFormatter& indexFormatter) const {
|
||||
std::ofstream of(s.c_str());
|
||||
of << "digraph G{\n";
|
||||
|
||||
BOOST_REVERSE_FOREACH(typename CONDITIONAL::shared_ptr conditional, conditionals_) {
|
||||
typename CONDITIONAL::Frontals frontals = conditional->frontals();
|
||||
Index me = frontals.front();
|
||||
typename CONDITIONAL::Parents parents = conditional->parents();
|
||||
BOOST_FOREACH(Index p, parents)
|
||||
of << p << "->" << me << std::endl;
|
||||
}
|
||||
|
||||
of << "}";
|
||||
of.close();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
typename BayesNetOrdered<CONDITIONAL>::const_iterator BayesNetOrdered<CONDITIONAL>::find(
|
||||
Index key) const {
|
||||
for (const_iterator it = begin(); it != end(); ++it)
|
||||
if (std::find((*it)->beginFrontals(), (*it)->endFrontals(), key)
|
||||
!= (*it)->endFrontals())
|
||||
return it;
|
||||
return end();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
typename BayesNetOrdered<CONDITIONAL>::iterator BayesNetOrdered<CONDITIONAL>::find(
|
||||
Index key) {
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
if (std::find((*it)->beginFrontals(), (*it)->endFrontals(), key)
|
||||
!= (*it)->endFrontals())
|
||||
return it;
|
||||
return end();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
void BayesNetOrdered<CONDITIONAL>::permuteWithInverse(
|
||||
const Permutation& inversePermutation) {
|
||||
BOOST_FOREACH(sharedConditional conditional, conditionals_) {
|
||||
conditional->permuteWithInverse(inversePermutation);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
void BayesNetOrdered<CONDITIONAL>::push_back(const BayesNetOrdered<CONDITIONAL>& bn) {
|
||||
BOOST_FOREACH(sharedConditional conditional,bn.conditionals_)
|
||||
push_back(conditional);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
void BayesNetOrdered<CONDITIONAL>::push_front(const BayesNetOrdered<CONDITIONAL>& bn) {
|
||||
BOOST_FOREACH(sharedConditional conditional,bn.conditionals_)
|
||||
push_front(conditional);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
void BayesNetOrdered<CONDITIONAL>::popLeaf(iterator conditional) {
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
BOOST_FOREACH(typename CONDITIONAL::shared_ptr checkConditional, conditionals_) {
|
||||
BOOST_FOREACH(Index key, (*conditional)->frontals()) {
|
||||
if(std::find(checkConditional->beginParents(), checkConditional->endParents(), key) != checkConditional->endParents())
|
||||
throw std::invalid_argument(
|
||||
"Debug mode exception: in BayesNet::popLeaf, the requested conditional is not a leaf.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
conditionals_.erase(conditional);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
FastList<Index> BayesNetOrdered<CONDITIONAL>::ordering() const {
|
||||
FastList<Index> ord;
|
||||
BOOST_FOREACH(sharedConditional conditional,conditionals_)
|
||||
ord.insert(ord.begin(), conditional->beginFrontals(),
|
||||
conditional->endFrontals());
|
||||
return ord;
|
||||
}
|
||||
|
||||
// /* ************************************************************************* */
|
||||
// template<class CONDITIONAL>
|
||||
// void BayesNet<CONDITIONAL>::saveGraph(const std::string &s) const {
|
||||
// ofstream of(s.c_str());
|
||||
// of<< "digraph G{\n";
|
||||
// BOOST_FOREACH(const_sharedConditional conditional,conditionals_) {
|
||||
// Index child = conditional->key();
|
||||
// BOOST_FOREACH(Index parent, conditional->parents()) {
|
||||
// of << parent << "->" << child << endl;
|
||||
// }
|
||||
// }
|
||||
// of<<"}";
|
||||
// of.close();
|
||||
// }
|
||||
//
|
||||
/* ************************************************************************* */
|
||||
|
||||
template<class CONDITIONAL>
|
||||
typename BayesNetOrdered<CONDITIONAL>::sharedConditional BayesNetOrdered<CONDITIONAL>::operator[](
|
||||
Index key) const {
|
||||
BOOST_FOREACH(typename CONDITIONAL::shared_ptr conditional, conditionals_) {
|
||||
typename CONDITIONAL::const_iterator it = std::find(
|
||||
conditional->beginFrontals(), conditional->endFrontals(), key);
|
||||
if (it != conditional->endFrontals()) {
|
||||
return conditional;
|
||||
}
|
||||
}
|
||||
throw(std::invalid_argument(
|
||||
(boost::format("BayesNet::operator['%1%']: not found") % key).str()));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 BayesNet.h
|
||||
* @brief Bayes network
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/assign/list_inserter.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/base/FastList.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* A BayesNet is a list of conditionals, stored in elimination order, i.e.
|
||||
* leaves first, parents last. GaussianBayesNet and SymbolicBayesNet are
|
||||
* defined as typedefs of this class, using GaussianConditional and
|
||||
* IndexConditional as the CONDITIONAL template argument.
|
||||
*
|
||||
* todo: Symbolic using Index is a misnomer.
|
||||
* todo: how to handle Bayes nets with an optimize function? Currently using global functions.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class CONDITIONAL>
|
||||
class BayesNetOrdered {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename boost::shared_ptr<BayesNetOrdered<CONDITIONAL> > shared_ptr;
|
||||
|
||||
/** We store shared pointers to Conditional densities */
|
||||
typedef typename CONDITIONAL::KeyType KeyType;
|
||||
typedef typename boost::shared_ptr<CONDITIONAL> sharedConditional;
|
||||
typedef typename boost::shared_ptr<const CONDITIONAL> const_sharedConditional;
|
||||
typedef typename std::list<sharedConditional> Conditionals;
|
||||
|
||||
typedef typename Conditionals::iterator iterator;
|
||||
typedef typename Conditionals::reverse_iterator reverse_iterator;
|
||||
typedef typename Conditionals::const_iterator const_iterator;
|
||||
typedef typename Conditionals::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Conditional densities are stored in reverse topological sort order (i.e., leaves first,
|
||||
* parents last), which corresponds to the elimination ordering if so obtained,
|
||||
* and is consistent with the column (block) ordering of an upper triangular matrix.
|
||||
*/
|
||||
Conditionals conditionals_;
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Default constructor as an empty BayesNet */
|
||||
BayesNetOrdered() {};
|
||||
|
||||
/** convert from a derived type */
|
||||
template<class DERIVEDCONDITIONAL>
|
||||
BayesNetOrdered(const BayesNetOrdered<DERIVEDCONDITIONAL>& bn) {
|
||||
conditionals_.assign(bn.begin(), bn.end());
|
||||
}
|
||||
|
||||
/** BayesNet with 1 conditional */
|
||||
explicit BayesNetOrdered(const sharedConditional& conditional) { push_back(conditional); }
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** print */
|
||||
void print(const std::string& s = "",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** check equality */
|
||||
bool equals(const BayesNetOrdered& other, double tol = 1e-9) const;
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** size is the number of nodes */
|
||||
size_t size() const {
|
||||
return conditionals_.size();
|
||||
}
|
||||
|
||||
/** @return true if there are no conditionals/nodes */
|
||||
bool empty() const {
|
||||
return conditionals_.empty();
|
||||
}
|
||||
|
||||
/** print statistics */
|
||||
void printStats(const std::string& s = "") const;
|
||||
|
||||
/** save dot graph */
|
||||
void saveGraph(const std::string &s, const IndexFormatter& indexFormatter =
|
||||
DefaultIndexFormatter) const;
|
||||
|
||||
/** return keys in reverse topological sort order, i.e., elimination order */
|
||||
FastList<Index> ordering() const;
|
||||
|
||||
/** SLOW O(n) random access to Conditional by key */
|
||||
sharedConditional operator[](Index key) const;
|
||||
|
||||
/** return last node in ordering */
|
||||
boost::shared_ptr<const CONDITIONAL> front() const { return conditionals_.front(); }
|
||||
|
||||
/** return last node in ordering */
|
||||
boost::shared_ptr<const CONDITIONAL> back() const { return conditionals_.back(); }
|
||||
|
||||
/** return iterators. FD: breaks encapsulation? */
|
||||
const_iterator begin() const {return conditionals_.begin();} ///<TODO: comment
|
||||
const_iterator end() const {return conditionals_.end();} ///<TODO: comment
|
||||
const_reverse_iterator rbegin() const {return conditionals_.rbegin();} ///<TODO: comment
|
||||
const_reverse_iterator rend() const {return conditionals_.rend();} ///<TODO: comment
|
||||
|
||||
/** Find an iterator pointing to the conditional where the specified key
|
||||
* appears as a frontal variable, or end() if no conditional contains this
|
||||
* key. Running time is approximately \f$ O(n) \f$ in the number of
|
||||
* conditionals in the BayesNet.
|
||||
* @param key The index to find in the frontal variables of a conditional.
|
||||
*/
|
||||
const_iterator find(Index key) const;
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Remove any leaf conditional. The conditional to remove is specified by
|
||||
* iterator. To find the iterator pointing to the conditional containing a
|
||||
* particular key, use find(), which has \f$ O(n) \f$ complexity. The
|
||||
* popLeaf function by itself has \f$ O(1) \f$ complexity.
|
||||
*
|
||||
* If gtsam is compiled with GTSAM_EXTRA_CONSISTENCY_CHECKS defined, this
|
||||
* function will check that the node is indeed a leaf, but otherwise will
|
||||
* not check, because the check has \f$ O(n^2) \f$ complexity.
|
||||
*
|
||||
* Example 1:
|
||||
\code
|
||||
// Remove a leaf node with a known conditional
|
||||
GaussianBayesNet gbn = ...
|
||||
GaussianBayesNet::iterator leafConditional = ...
|
||||
gbn.popLeaf(leafConditional);
|
||||
\endcode
|
||||
* Example 2:
|
||||
\code
|
||||
// Remove the leaf node containing variable index 14
|
||||
GaussianBayesNet gbn = ...
|
||||
gbn.popLeaf(gbn.find(14));
|
||||
\endcode
|
||||
* @param conditional The iterator pointing to the leaf conditional to remove
|
||||
*/
|
||||
void popLeaf(iterator conditional);
|
||||
|
||||
/** return last node in ordering */
|
||||
sharedConditional& front() { return conditionals_.front(); }
|
||||
|
||||
/** return last node in ordering */
|
||||
sharedConditional& back() { return conditionals_.back(); }
|
||||
|
||||
/** Find an iterator pointing to the conditional where the specified key
|
||||
* appears as a frontal variable, or end() if no conditional contains this
|
||||
* key. Running time is approximately \f$ O(n) \f$ in the number of
|
||||
* conditionals in the BayesNet.
|
||||
* @param key The index to find in the frontal variables of a conditional.
|
||||
*/
|
||||
iterator find(Index key);
|
||||
|
||||
/** push_back: use reverse topological sort (i.e. parents last / elimination order) */
|
||||
inline void push_back(const sharedConditional& conditional) {
|
||||
conditionals_.push_back(conditional);
|
||||
}
|
||||
|
||||
/** push_front: use topological sort (i.e. parents first / reverse elimination order) */
|
||||
inline void push_front(const sharedConditional& conditional) {
|
||||
conditionals_.push_front(conditional);
|
||||
}
|
||||
|
||||
/// push_back an entire Bayes net
|
||||
void push_back(const BayesNetOrdered<CONDITIONAL>& bn);
|
||||
|
||||
/// push_front an entire Bayes net
|
||||
void push_front(const BayesNetOrdered<CONDITIONAL>& bn);
|
||||
|
||||
/** += syntax for push_back, e.g. bayesNet += c1, c2, c3
|
||||
* @param conditional The conditional to add to the back of the BayesNet
|
||||
*/
|
||||
boost::assign::list_inserter<boost::assign_detail::call_push_back<BayesNetOrdered<CONDITIONAL> >, sharedConditional>
|
||||
operator+=(const sharedConditional& conditional) {
|
||||
return boost::assign::make_list_inserter(boost::assign_detail::call_push_back<BayesNetOrdered<CONDITIONAL> >(*this))(conditional); }
|
||||
|
||||
/**
|
||||
* pop_front: remove node at the bottom, used in marginalization
|
||||
* For example P(ABC)=P(A|BC)P(B|C)P(C) becomes P(BC)=P(B|C)P(C)
|
||||
*/
|
||||
void pop_front() {conditionals_.pop_front();}
|
||||
|
||||
/** Permute the variables in the BayesNet */
|
||||
void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
iterator begin() {return conditionals_.begin();} ///<TODO: comment
|
||||
iterator end() {return conditionals_.end();} ///<TODO: comment
|
||||
reverse_iterator rbegin() {return conditionals_.rbegin();} ///<TODO: comment
|
||||
reverse_iterator rend() {return conditionals_.rend();} ///<TODO: comment
|
||||
|
||||
/** saves the bayes to a text file in GraphViz format */
|
||||
// void saveGraph(const std::string& s) const;
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_NVP(conditionals_);
|
||||
}
|
||||
|
||||
/// @}
|
||||
}; // BayesNet
|
||||
|
||||
} // namespace gtsam
|
||||
|
||||
#include <gtsam/inference/BayesNetOrdered-inl.h>
|
||||
|
|
@ -1,301 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 BayesTreeCliqueBase-inl.h
|
||||
* @brief Base class for cliques of a BayesTree
|
||||
* @author Richard Roberts and Frank Dellaert
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/GenericSequentialSolver.h>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
void BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::assertInvariants() const {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
std::vector<Index> BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::separator_setminus_B(
|
||||
derived_ptr B) const {
|
||||
sharedConditional p_F_S = this->conditional();
|
||||
std::vector<Index> &indicesB = B->conditional()->keys();
|
||||
std::vector<Index> S_setminus_B;
|
||||
std::set_difference(p_F_S->beginParents(), p_F_S->endParents(), //
|
||||
indicesB.begin(), indicesB.end(), back_inserter(S_setminus_B));
|
||||
return S_setminus_B;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
std::vector<Index> BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::shortcut_indices(
|
||||
derived_ptr B, const FactorGraphOrdered<FactorType>& p_Cp_B) const
|
||||
{
|
||||
gttic(shortcut_indices);
|
||||
std::set<Index> allKeys = p_Cp_B.keys();
|
||||
std::vector<Index> &indicesB = B->conditional()->keys();
|
||||
std::vector<Index> S_setminus_B = separator_setminus_B(B); // TODO, get as argument?
|
||||
std::vector<Index> keep;
|
||||
// keep = S\B intersect allKeys
|
||||
std::set_intersection(S_setminus_B.begin(), S_setminus_B.end(), //
|
||||
allKeys.begin(), allKeys.end(), back_inserter(keep));
|
||||
// keep += B intersect allKeys
|
||||
std::set_intersection(indicesB.begin(), indicesB.end(), //
|
||||
allKeys.begin(), allKeys.end(), back_inserter(keep));
|
||||
// BOOST_FOREACH(Index j, keep) std::cout << j << " "; std::cout << std::endl;
|
||||
return keep;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::BayesTreeCliqueBaseOrdered(
|
||||
const sharedConditional& conditional) :
|
||||
conditional_(conditional) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::BayesTreeCliqueBaseOrdered(
|
||||
const std::pair<sharedConditional,
|
||||
boost::shared_ptr<typename ConditionalType::FactorType> >& result) :
|
||||
conditional_(result.first) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
void BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::print(const std::string& s,
|
||||
const IndexFormatter& indexFormatter) const {
|
||||
conditional_->print(s, indexFormatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
size_t BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::treeSize() const {
|
||||
size_t size = 1;
|
||||
BOOST_FOREACH(const derived_ptr& child, children_)
|
||||
size += child->treeSize();
|
||||
return size;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
size_t BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::numCachedSeparatorMarginals() const {
|
||||
if (!cachedSeparatorMarginal_)
|
||||
return 0;
|
||||
|
||||
size_t subtree_count = 1;
|
||||
BOOST_FOREACH(const derived_ptr& child, children_)
|
||||
subtree_count += child->numCachedSeparatorMarginals();
|
||||
|
||||
return subtree_count;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
void BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::printTree(
|
||||
const std::string& indent, const IndexFormatter& indexFormatter) const {
|
||||
asDerived(this)->print(indent, indexFormatter);
|
||||
BOOST_FOREACH(const derived_ptr& child, children_)
|
||||
child->printTree(indent + " ", indexFormatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
void BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::permuteWithInverse(
|
||||
const Permutation& inversePermutation) {
|
||||
conditional_->permuteWithInverse(inversePermutation);
|
||||
BOOST_FOREACH(const derived_ptr& child, children_) {
|
||||
child->permuteWithInverse(inversePermutation);
|
||||
}
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
bool BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::reduceSeparatorWithInverse(
|
||||
const internal::Reduction& inverseReduction)
|
||||
{
|
||||
bool changed = conditional_->reduceSeparatorWithInverse(inverseReduction);
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
if(!changed) {
|
||||
BOOST_FOREACH(const derived_ptr& child, children_) {
|
||||
assert(child->reduceSeparatorWithInverse(inverseReduction) == false); }
|
||||
}
|
||||
#endif
|
||||
if(changed) {
|
||||
BOOST_FOREACH(const derived_ptr& child, children_) {
|
||||
(void) child->reduceSeparatorWithInverse(inverseReduction); }
|
||||
}
|
||||
assertInvariants();
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// The shortcut density is a conditional P(S|R) of the separator of this
|
||||
// clique on the root. We can compute it recursively from the parent shortcut
|
||||
// P(Sp|R) as \int P(Fp|Sp) P(Sp|R), where Fp are the frontal nodes in p
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
BayesNetOrdered<CONDITIONAL> BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::shortcut(
|
||||
derived_ptr B, Eliminate function) const
|
||||
{
|
||||
gttic(BayesTreeCliqueBase_shortcut);
|
||||
|
||||
// We only calculate the shortcut when this clique is not B
|
||||
// and when the S\B is not empty
|
||||
std::vector<Index> S_setminus_B = separator_setminus_B(B);
|
||||
if (B.get() != this && !S_setminus_B.empty()) {
|
||||
|
||||
// Obtain P(Cp||B) = P(Fp|Sp) * P(Sp||B) as a factor graph
|
||||
derived_ptr parent(parent_.lock());
|
||||
gttoc(BayesTreeCliqueBase_shortcut);
|
||||
FactorGraphOrdered<FactorType> p_Cp_B(parent->shortcut(B, function)); // P(Sp||B)
|
||||
gttic(BayesTreeCliqueBase_shortcut);
|
||||
p_Cp_B.push_back(parent->conditional()->toFactor()); // P(Fp|Sp)
|
||||
|
||||
// Determine the variables we want to keepSet, S union B
|
||||
std::vector<Index> keep = shortcut_indices(B, p_Cp_B);
|
||||
|
||||
// Reduce the variable indices to start at zero
|
||||
gttic(Reduce);
|
||||
const Permutation reduction = internal::createReducingPermutation(p_Cp_B.keys());
|
||||
internal::Reduction inverseReduction = internal::Reduction::CreateAsInverse(reduction);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, p_Cp_B) {
|
||||
if(factor) factor->reduceWithInverse(inverseReduction); }
|
||||
inverseReduction.applyInverse(keep);
|
||||
gttoc(Reduce);
|
||||
|
||||
// Create solver that will marginalize for us
|
||||
GenericSequentialSolver<FactorType> solver(p_Cp_B);
|
||||
|
||||
// Finally, we only want to have S\B variables in the Bayes net, so
|
||||
size_t nrFrontals = S_setminus_B.size();
|
||||
BayesNetOrdered<CONDITIONAL> result = *solver.conditionalBayesNet(keep, nrFrontals, function);
|
||||
|
||||
// Undo the reduction
|
||||
gttic(Undo_Reduce);
|
||||
BOOST_FOREACH(const typename boost::shared_ptr<FactorType>& factor, p_Cp_B) {
|
||||
if (factor) factor->permuteWithInverse(reduction); }
|
||||
result.permuteWithInverse(reduction);
|
||||
gttoc(Undo_Reduce);
|
||||
|
||||
assertInvariants();
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return BayesNetOrdered<CONDITIONAL>();
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// separator marginal, uses separator marginal of parent recursively
|
||||
// P(C) = P(F|S) P(S)
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
FactorGraphOrdered<typename BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::FactorType> BayesTreeCliqueBaseOrdered<
|
||||
DERIVED, CONDITIONAL>::separatorMarginal(derived_ptr R, Eliminate function) const
|
||||
{
|
||||
gttic(BayesTreeCliqueBase_separatorMarginal);
|
||||
// Check if the Separator marginal was already calculated
|
||||
if (!cachedSeparatorMarginal_) {
|
||||
gttic(BayesTreeCliqueBase_separatorMarginal_cachemiss);
|
||||
// If this is the root, there is no separator
|
||||
if (R.get() == this) {
|
||||
// we are root, return empty
|
||||
FactorGraphOrdered<FactorType> empty;
|
||||
cachedSeparatorMarginal_ = empty;
|
||||
} else {
|
||||
// Obtain P(S) = \int P(Cp) = \int P(Fp|Sp) P(Sp)
|
||||
// initialize P(Cp) with the parent separator marginal
|
||||
derived_ptr parent(parent_.lock());
|
||||
gttoc(BayesTreeCliqueBase_separatorMarginal_cachemiss); // Flatten recursion in timing outline
|
||||
gttoc(BayesTreeCliqueBase_separatorMarginal);
|
||||
FactorGraphOrdered<FactorType> p_Cp(parent->separatorMarginal(R, function)); // P(Sp)
|
||||
gttic(BayesTreeCliqueBase_separatorMarginal);
|
||||
gttic(BayesTreeCliqueBase_separatorMarginal_cachemiss);
|
||||
// now add the parent conditional
|
||||
p_Cp.push_back(parent->conditional()->toFactor()); // P(Fp|Sp)
|
||||
|
||||
// Reduce the variable indices to start at zero
|
||||
gttic(Reduce);
|
||||
const Permutation reduction = internal::createReducingPermutation(p_Cp.keys());
|
||||
internal::Reduction inverseReduction = internal::Reduction::CreateAsInverse(reduction);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, p_Cp) {
|
||||
if(factor) factor->reduceWithInverse(inverseReduction); }
|
||||
|
||||
// The variables we want to keepSet are exactly the ones in S
|
||||
sharedConditional p_F_S = this->conditional();
|
||||
std::vector<Index> indicesS(p_F_S->beginParents(), p_F_S->endParents());
|
||||
inverseReduction.applyInverse(indicesS);
|
||||
gttoc(Reduce);
|
||||
|
||||
// Create solver that will marginalize for us
|
||||
GenericSequentialSolver<FactorType> solver(p_Cp);
|
||||
|
||||
cachedSeparatorMarginal_ = *(solver.jointBayesNet(indicesS, function));
|
||||
|
||||
// Undo the reduction
|
||||
gttic(Undo_Reduce);
|
||||
BOOST_FOREACH(const typename boost::shared_ptr<FactorType>& factor, p_Cp) {
|
||||
if (factor) factor->permuteWithInverse(reduction); }
|
||||
BOOST_FOREACH(const typename boost::shared_ptr<FactorType>& factor, *cachedSeparatorMarginal_) {
|
||||
if (factor) factor->permuteWithInverse(reduction); }
|
||||
gttoc(Undo_Reduce);
|
||||
}
|
||||
} else {
|
||||
gttic(BayesTreeCliqueBase_separatorMarginal_cachehit);
|
||||
}
|
||||
|
||||
// return the shortcut P(S||B)
|
||||
return *cachedSeparatorMarginal_; // return the cached version
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// marginal2, uses separator marginal of parent recursively
|
||||
// P(C) = P(F|S) P(S)
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
FactorGraphOrdered<typename BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::FactorType> BayesTreeCliqueBaseOrdered<
|
||||
DERIVED, CONDITIONAL>::marginal2(derived_ptr R, Eliminate function) const
|
||||
{
|
||||
gttic(BayesTreeCliqueBase_marginal2);
|
||||
// initialize with separator marginal P(S)
|
||||
FactorGraphOrdered<FactorType> p_C(this->separatorMarginal(R, function));
|
||||
// add the conditional P(F|S)
|
||||
p_C.push_back(this->conditional()->toFactor());
|
||||
return p_C;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
void BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>::deleteCachedShortcuts() {
|
||||
|
||||
// When a shortcut is requested, all of the shortcuts between it and the
|
||||
// root are also generated. So, if this clique's cached shortcut is set,
|
||||
// recursively call over all child cliques. Otherwise, it is unnecessary.
|
||||
if (cachedSeparatorMarginal_) {
|
||||
BOOST_FOREACH(derived_ptr& child, children_) {
|
||||
child->deleteCachedShortcuts();
|
||||
}
|
||||
|
||||
//Delete CachedShortcut for this clique
|
||||
cachedSeparatorMarginal_ = boost::none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,273 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 BayesTreeCliqueBase.h
|
||||
* @brief Base class for cliques of a BayesTree
|
||||
* @author Richard Roberts and Frank Dellaert
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
template<class CONDITIONAL, class CLIQUE> class BayesTreeOrdered;
|
||||
}
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* This is the base class for BayesTree cliques. The default and standard
|
||||
* derived type is BayesTreeClique, but some algorithms, like iSAM2, use a
|
||||
* different clique type in order to store extra data along with the clique.
|
||||
*
|
||||
* This class is templated on the derived class (i.e. the curiously recursive
|
||||
* template pattern). The advantage of this over using virtual classes is
|
||||
* that it avoids the need for casting to get the derived type. This is
|
||||
* possible because all cliques in a BayesTree are the same type - if they
|
||||
* were not then we'd need a virtual class.
|
||||
*
|
||||
* @tparam DERIVED The derived clique type.
|
||||
* @tparam CONDITIONAL The conditional type.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
struct BayesTreeCliqueBaseOrdered {
|
||||
|
||||
public:
|
||||
typedef BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL> This;
|
||||
typedef DERIVED DerivedType;
|
||||
typedef CONDITIONAL ConditionalType;
|
||||
typedef boost::shared_ptr<ConditionalType> sharedConditional;
|
||||
typedef boost::shared_ptr<This> shared_ptr;
|
||||
typedef boost::weak_ptr<This> weak_ptr;
|
||||
typedef boost::shared_ptr<DerivedType> derived_ptr;
|
||||
typedef boost::weak_ptr<DerivedType> derived_weak_ptr;
|
||||
typedef typename ConditionalType::FactorType FactorType;
|
||||
typedef typename FactorGraphOrdered<FactorType>::Eliminate Eliminate;
|
||||
|
||||
protected:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Default constructor */
|
||||
BayesTreeCliqueBaseOrdered() {}
|
||||
|
||||
/** Construct from a conditional, leaving parent and child pointers uninitialized */
|
||||
BayesTreeCliqueBaseOrdered(const sharedConditional& conditional);
|
||||
|
||||
/** Construct from an elimination result, which is a pair<CONDITIONAL,FACTOR> */
|
||||
BayesTreeCliqueBaseOrdered(
|
||||
const std::pair<sharedConditional,
|
||||
boost::shared_ptr<typename ConditionalType::FactorType> >& result);
|
||||
|
||||
/// @}
|
||||
|
||||
/// This stores the Cached separator margnal P(S)
|
||||
mutable boost::optional<FactorGraphOrdered<FactorType> > cachedSeparatorMarginal_;
|
||||
|
||||
public:
|
||||
sharedConditional conditional_;
|
||||
derived_weak_ptr parent_;
|
||||
FastList<derived_ptr> children_;
|
||||
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** check equality */
|
||||
bool equals(const This& other, double tol = 1e-9) const {
|
||||
return (!conditional_ && !other.conditional())
|
||||
|| conditional_->equals(*other.conditional(), tol);
|
||||
}
|
||||
|
||||
/** print this node */
|
||||
void print(const std::string& s = "", const IndexFormatter& indexFormatter =
|
||||
DefaultIndexFormatter) const;
|
||||
|
||||
/** print this node and entire subtree below it */
|
||||
void printTree(const std::string& indent = "",
|
||||
const IndexFormatter& indexFormatter = DefaultIndexFormatter) const;
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** Access the conditional */
|
||||
const sharedConditional& conditional() const {
|
||||
return conditional_;
|
||||
}
|
||||
|
||||
/** is this the root of a Bayes tree ? */
|
||||
inline bool isRoot() const {
|
||||
return parent_.expired();
|
||||
}
|
||||
|
||||
/** The size of subtree rooted at this clique, i.e., nr of Cliques */
|
||||
size_t treeSize() const;
|
||||
|
||||
/** Collect number of cliques with cached separator marginals */
|
||||
size_t numCachedSeparatorMarginals() const;
|
||||
|
||||
/** The arrow operator accesses the conditional */
|
||||
const ConditionalType* operator->() const {
|
||||
return conditional_.get();
|
||||
}
|
||||
|
||||
/** return the const reference of children */
|
||||
const std::list<derived_ptr>& children() const {
|
||||
return children_;
|
||||
}
|
||||
|
||||
/** return a shared_ptr to the parent clique */
|
||||
derived_ptr parent() const {
|
||||
return parent_.lock();
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/** The arrow operator accesses the conditional */
|
||||
ConditionalType* operator->() {
|
||||
return conditional_.get();
|
||||
}
|
||||
|
||||
/** return the reference of children non-const version*/
|
||||
FastList<derived_ptr>& children() {
|
||||
return children_;
|
||||
}
|
||||
|
||||
/** Construct shared_ptr from a conditional, leaving parent and child pointers uninitialized */
|
||||
static derived_ptr Create(const sharedConditional& conditional) {
|
||||
return boost::make_shared<DerivedType>(conditional);
|
||||
}
|
||||
|
||||
/** Construct shared_ptr from a FactorGraph<FACTOR>::EliminationResult. In this class
|
||||
* the conditional part is kept and the factor part is ignored, but in derived clique
|
||||
* types, such as ISAM2Clique, the factor part is kept as a cached factor.
|
||||
* @param result An elimination result, which is a pair<CONDITIONAL,FACTOR>
|
||||
*/
|
||||
static derived_ptr Create(const std::pair<sharedConditional,
|
||||
boost::shared_ptr<typename ConditionalType::FactorType> >& result) {
|
||||
return boost::make_shared<DerivedType>(result);
|
||||
}
|
||||
|
||||
/** Returns a new clique containing a copy of the conditional but without
|
||||
* the parent and child clique pointers.
|
||||
*/
|
||||
derived_ptr clone() const {
|
||||
return Create(sharedConditional(new ConditionalType(*conditional_)));
|
||||
}
|
||||
|
||||
/** Permute the variables in the whole subtree rooted at this clique */
|
||||
void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
/** Permute variables when they only appear in the separators. In this
|
||||
* case the running intersection property will be used to prevent always
|
||||
* traversing the whole tree. Returns whether any separator variables in
|
||||
* this subtree were reordered.
|
||||
*/
|
||||
bool reduceSeparatorWithInverse(const internal::Reduction& inverseReduction);
|
||||
|
||||
/** return the conditional P(S|Root) on the separator given the root */
|
||||
BayesNetOrdered<ConditionalType> shortcut(derived_ptr root, Eliminate function) const;
|
||||
|
||||
/** return the marginal P(S) on the separator */
|
||||
FactorGraphOrdered<FactorType> separatorMarginal(derived_ptr root, Eliminate function) const;
|
||||
|
||||
/** return the marginal P(C) of the clique, using marginal caching */
|
||||
FactorGraphOrdered<FactorType> marginal2(derived_ptr root, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* This deletes the cached shortcuts of all cliques (subtree) below this clique.
|
||||
* This is performed when the bayes tree is modified.
|
||||
*/
|
||||
void deleteCachedShortcuts();
|
||||
|
||||
const boost::optional<FactorGraphOrdered<FactorType> >& cachedSeparatorMarginal() const {
|
||||
return cachedSeparatorMarginal_; }
|
||||
|
||||
friend class BayesTreeOrdered<ConditionalType, DerivedType> ;
|
||||
|
||||
protected:
|
||||
|
||||
/// assert invariants that have to hold in a clique
|
||||
void assertInvariants() const;
|
||||
|
||||
/// Calculate set \f$ S \setminus B \f$ for shortcut calculations
|
||||
std::vector<Index> separator_setminus_B(derived_ptr B) const;
|
||||
|
||||
/// Calculate set \f$ S_p \cap B \f$ for shortcut calculations
|
||||
std::vector<Index> parent_separator_intersection_B(derived_ptr B) const;
|
||||
|
||||
/**
|
||||
* Determine variable indices to keep in recursive separator shortcut calculation
|
||||
* The factor graph p_Cp_B has keys from the parent clique Cp and from B.
|
||||
* But we only keep the variables not in S union B.
|
||||
*/
|
||||
std::vector<Index> shortcut_indices(derived_ptr B,
|
||||
const FactorGraphOrdered<FactorType>& p_Cp_B) const;
|
||||
|
||||
/** Non-recursive delete cached shortcuts and marginals - internal only. */
|
||||
void deleteCachedShortcutsNonRecursive() { cachedSeparatorMarginal_ = boost::none; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Cliques cannot be copied except by the clone() method, which does not
|
||||
* copy the parent and child pointers.
|
||||
*/
|
||||
BayesTreeCliqueBaseOrdered(const This& other) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/** Cliques cannot be copied except by the clone() method, which does not
|
||||
* copy the parent and child pointers.
|
||||
*/
|
||||
This& operator=(const This& other) {
|
||||
assert(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_NVP(conditional_);
|
||||
ar & BOOST_SERIALIZATION_NVP(parent_);
|
||||
ar & BOOST_SERIALIZATION_NVP(children_);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
// \struct Clique
|
||||
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
const DERIVED* asDerived(
|
||||
const BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>* base) {
|
||||
return static_cast<const DERIVED*>(base);
|
||||
}
|
||||
|
||||
template<class DERIVED, class CONDITIONAL>
|
||||
DERIVED* asDerived(BayesTreeCliqueBaseOrdered<DERIVED, CONDITIONAL>* base) {
|
||||
return static_cast<DERIVED*>(base);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,804 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 BayesTree-inl.h
|
||||
* @brief Bayes Tree is a tree of cliques of a Bayes Chain
|
||||
* @author Frank Dellaert
|
||||
* @author Michael Kaess
|
||||
* @author Viorela Ila
|
||||
* @author Richard Roberts
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/FastList.h>
|
||||
#include <gtsam/base/FastSet.h>
|
||||
#include <gtsam/base/FastVector.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
#include <gtsam/inference/inferenceOrdered.h>
|
||||
#include <gtsam/inference/GenericSequentialSolver.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using boost::assign::operator+=;
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::CliqueData
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>::getCliqueData() const {
|
||||
CliqueData data;
|
||||
getCliqueData(data, root_);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::getCliqueData(CliqueData& data, sharedClique clique) const {
|
||||
data.conditionalSizes.push_back((*clique)->nrFrontals());
|
||||
data.separatorSizes.push_back((*clique)->nrParents());
|
||||
BOOST_FOREACH(sharedClique c, clique->children_) {
|
||||
getCliqueData(data, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
size_t BayesTreeOrdered<CONDITIONAL,CLIQUE>::numCachedSeparatorMarginals() const {
|
||||
return (root_) ? root_->numCachedSeparatorMarginals() : 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::saveGraph(const std::string &s, const IndexFormatter& indexFormatter) const {
|
||||
if (!root_.get()) throw std::invalid_argument("the root of Bayes tree has not been initialized!");
|
||||
std::ofstream of(s.c_str());
|
||||
of<< "digraph G{\n";
|
||||
saveGraph(of, root_, indexFormatter);
|
||||
of<<"}";
|
||||
of.close();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::saveGraph(std::ostream &s, sharedClique clique, const IndexFormatter& indexFormatter, int parentnum) const {
|
||||
static int num = 0;
|
||||
bool first = true;
|
||||
std::stringstream out;
|
||||
out << num;
|
||||
std::string parent = out.str();
|
||||
parent += "[label=\"";
|
||||
|
||||
BOOST_FOREACH(Index index, clique->conditional_->frontals()) {
|
||||
if(!first) parent += ","; first = false;
|
||||
parent += indexFormatter(index);
|
||||
}
|
||||
|
||||
if( clique != root_){
|
||||
parent += " : ";
|
||||
s << parentnum << "->" << num << "\n";
|
||||
}
|
||||
|
||||
first = true;
|
||||
BOOST_FOREACH(Index sep, clique->conditional_->parents()) {
|
||||
if(!first) parent += ","; first = false;
|
||||
parent += indexFormatter(sep);
|
||||
}
|
||||
parent += "\"];\n";
|
||||
s << parent;
|
||||
parentnum = num;
|
||||
|
||||
BOOST_FOREACH(sharedClique c, clique->children_) {
|
||||
num++;
|
||||
saveGraph(s, c, indexFormatter, parentnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::CliqueStats::print(const std::string& s) const {
|
||||
std::cout << s
|
||||
<<"avg Conditional Size: " << avgConditionalSize << std::endl
|
||||
<< "max Conditional Size: " << maxConditionalSize << std::endl
|
||||
<< "avg Separator Size: " << avgSeparatorSize << std::endl
|
||||
<< "max Separator Size: " << maxSeparatorSize << std::endl;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::CliqueStats
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>::CliqueData::getStats() const {
|
||||
CliqueStats stats;
|
||||
|
||||
double sum = 0.0;
|
||||
size_t max = 0;
|
||||
BOOST_FOREACH(size_t s, conditionalSizes) {
|
||||
sum += (double)s;
|
||||
if(s > max) max = s;
|
||||
}
|
||||
stats.avgConditionalSize = sum / (double)conditionalSizes.size();
|
||||
stats.maxConditionalSize = max;
|
||||
|
||||
sum = 0.0;
|
||||
max = 1;
|
||||
BOOST_FOREACH(size_t s, separatorSizes) {
|
||||
sum += (double)s;
|
||||
if(s > max) max = s;
|
||||
}
|
||||
stats.avgSeparatorSize = sum / (double)separatorSizes.size();
|
||||
stats.maxSeparatorSize = max;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::Cliques::print(const std::string& s, const IndexFormatter& indexFormatter) const {
|
||||
std::cout << s << ":\n";
|
||||
BOOST_FOREACH(sharedClique clique, *this)
|
||||
clique->printTree("", indexFormatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
bool BayesTreeOrdered<CONDITIONAL,CLIQUE>::Cliques::equals(const Cliques& other, double tol) const {
|
||||
return other == *this;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>::addClique(const sharedConditional& conditional, const sharedClique& parent_clique) {
|
||||
sharedClique new_clique(new Clique(conditional));
|
||||
addClique(new_clique, parent_clique);
|
||||
return new_clique;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::addClique(const sharedClique& clique, const sharedClique& parent_clique) {
|
||||
nodes_.resize(std::max((*clique)->lastFrontalKey()+1, nodes_.size()));
|
||||
BOOST_FOREACH(Index j, (*clique)->frontals())
|
||||
nodes_[j] = clique;
|
||||
if (parent_clique != NULL) {
|
||||
clique->parent_ = parent_clique;
|
||||
parent_clique->children_.push_back(clique);
|
||||
} else {
|
||||
assert(!root_);
|
||||
root_ = clique;
|
||||
}
|
||||
clique->assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique BayesTreeOrdered<CONDITIONAL,CLIQUE>::addClique(
|
||||
const sharedConditional& conditional, std::list<sharedClique>& child_cliques) {
|
||||
sharedClique new_clique(new Clique(conditional));
|
||||
nodes_.resize(std::max(conditional->lastFrontalKey()+1, nodes_.size()));
|
||||
BOOST_FOREACH(Index j, conditional->frontals())
|
||||
nodes_[j] = new_clique;
|
||||
new_clique->children_ = child_cliques;
|
||||
BOOST_FOREACH(sharedClique& child, child_cliques)
|
||||
child->parent_ = new_clique;
|
||||
new_clique->assertInvariants();
|
||||
return new_clique;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::permuteWithInverse(const Permutation& inversePermutation) {
|
||||
// recursively permute the cliques and internal conditionals
|
||||
if (root_)
|
||||
root_->permuteWithInverse(inversePermutation);
|
||||
|
||||
// need to know what the largest key is to get the right number of cliques
|
||||
Index maxIndex = *std::max_element(inversePermutation.begin(), inversePermutation.end());
|
||||
|
||||
// Update the nodes structure
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::Nodes newNodes(maxIndex+1);
|
||||
// inversePermutation.applyToCollection(newNodes, nodes_); // Uses the forward, rather than inverse permutation
|
||||
for(size_t i = 0; i < nodes_.size(); ++i)
|
||||
newNodes[inversePermutation[i]] = nodes_[i];
|
||||
|
||||
nodes_ = newNodes;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
inline void BayesTreeOrdered<CONDITIONAL,CLIQUE>::addToCliqueFront(BayesTreeOrdered<CONDITIONAL,CLIQUE>& bayesTree, const sharedConditional& conditional, const sharedClique& clique) {
|
||||
static const bool debug = false;
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
// Debug check to make sure the conditional variable is ordered lower than
|
||||
// its parents and that all of its parents are present either in this
|
||||
// clique or its separator.
|
||||
BOOST_FOREACH(Index parent, conditional->parents()) {
|
||||
assert(parent > conditional->lastFrontalKey());
|
||||
const Clique& cliquer(*clique);
|
||||
assert(find(cliquer->begin(), cliquer->end(), parent) != cliquer->end());
|
||||
}
|
||||
#endif
|
||||
if(debug) conditional->print("Adding conditional ");
|
||||
if(debug) clique->print("To clique ");
|
||||
Index j = conditional->lastFrontalKey();
|
||||
bayesTree.nodes_.resize(std::max(j+1, bayesTree.nodes_.size()));
|
||||
bayesTree.nodes_[j] = clique;
|
||||
FastVector<Index> newIndices((*clique)->size() + 1);
|
||||
newIndices[0] = j;
|
||||
std::copy((*clique)->begin(), (*clique)->end(), newIndices.begin()+1);
|
||||
clique->conditional_ = CONDITIONAL::FromKeys(newIndices, (*clique)->nrFrontals() + 1);
|
||||
if(debug) clique->print("Expanded clique is ");
|
||||
clique->assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::removeClique(sharedClique clique) {
|
||||
|
||||
if (clique->isRoot())
|
||||
root_.reset();
|
||||
else { // detach clique from parent
|
||||
sharedClique parent = clique->parent_.lock();
|
||||
typename FastList<typename CLIQUE::shared_ptr>::iterator child = std::find(parent->children().begin(), parent->children().end(), clique);
|
||||
assert(child != parent->children().end());
|
||||
parent->children().erase(child);
|
||||
}
|
||||
|
||||
// orphan my children
|
||||
BOOST_FOREACH(sharedClique child, clique->children_)
|
||||
child->parent_ = typename Clique::weak_ptr();
|
||||
|
||||
BOOST_FOREACH(Index j, clique->conditional()->frontals()) {
|
||||
nodes_[j].reset();
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::recursiveTreeBuild(const boost::shared_ptr<BayesTreeClique<IndexConditionalOrdered> >& symbolic,
|
||||
const std::vector<boost::shared_ptr<CONDITIONAL> >& conditionals,
|
||||
const typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique& parent) {
|
||||
|
||||
// Helper function to build a non-symbolic tree (e.g. Gaussian) using a
|
||||
// symbolic tree, used in the BT(BN) constructor.
|
||||
|
||||
// Build the current clique
|
||||
FastList<typename CONDITIONAL::shared_ptr> cliqueConditionals;
|
||||
BOOST_FOREACH(Index j, symbolic->conditional()->frontals()) {
|
||||
cliqueConditionals.push_back(conditionals[j]); }
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique thisClique(new CLIQUE(CONDITIONAL::Combine(cliqueConditionals.begin(), cliqueConditionals.end())));
|
||||
|
||||
// Add the new clique with the current parent
|
||||
this->addClique(thisClique, parent);
|
||||
|
||||
// Build the children, whose parent is the new clique
|
||||
BOOST_FOREACH(const BayesTreeOrdered<IndexConditionalOrdered>::sharedClique& child, symbolic->children()) {
|
||||
this->recursiveTreeBuild(child, conditionals, thisClique); }
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>::BayesTreeOrdered(const BayesNetOrdered<CONDITIONAL>& bayesNet) {
|
||||
// First generate symbolic BT to determine clique structure
|
||||
BayesTreeOrdered<IndexConditionalOrdered> sbt(bayesNet);
|
||||
|
||||
// Build index of variables to conditionals
|
||||
std::vector<boost::shared_ptr<CONDITIONAL> > conditionals(sbt.root()->conditional()->frontals().back() + 1);
|
||||
BOOST_FOREACH(const boost::shared_ptr<CONDITIONAL>& c, bayesNet) {
|
||||
if(c->nrFrontals() != 1)
|
||||
throw std::invalid_argument("BayesTree constructor from BayesNet only supports single frontal variable conditionals");
|
||||
if(c->firstFrontalKey() >= conditionals.size())
|
||||
throw std::invalid_argument("An inconsistent BayesNet was passed into the BayesTree constructor!");
|
||||
if(conditionals[c->firstFrontalKey()])
|
||||
throw std::invalid_argument("An inconsistent BayesNet with duplicate frontal variables was passed into the BayesTree constructor!");
|
||||
|
||||
conditionals[c->firstFrontalKey()] = c;
|
||||
}
|
||||
|
||||
// Build the new tree
|
||||
this->recursiveTreeBuild(sbt.root(), conditionals, sharedClique());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<>
|
||||
inline BayesTreeOrdered<IndexConditionalOrdered>::BayesTreeOrdered(const BayesNetOrdered<IndexConditionalOrdered>& bayesNet) {
|
||||
BayesNetOrdered<IndexConditionalOrdered>::const_reverse_iterator rit;
|
||||
for ( rit=bayesNet.rbegin(); rit != bayesNet.rend(); ++rit )
|
||||
insert(*this, *rit);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>::BayesTreeOrdered(const BayesNetOrdered<CONDITIONAL>& bayesNet, std::list<BayesTreeOrdered<CONDITIONAL,CLIQUE> > subtrees) {
|
||||
if (bayesNet.size() == 0)
|
||||
throw std::invalid_argument("BayesTree::insert: empty bayes net!");
|
||||
|
||||
// get the roots of child subtrees and merge their nodes_
|
||||
std::list<sharedClique> childRoots;
|
||||
typedef BayesTreeOrdered<CONDITIONAL,CLIQUE> Tree;
|
||||
BOOST_FOREACH(const Tree& subtree, subtrees) {
|
||||
nodes_.assign(subtree.nodes_.begin(), subtree.nodes_.end());
|
||||
childRoots.push_back(subtree.root());
|
||||
}
|
||||
|
||||
// create a new clique and add all the conditionals to the clique
|
||||
sharedClique new_clique;
|
||||
typename BayesNetOrdered<CONDITIONAL>::sharedConditional conditional;
|
||||
BOOST_REVERSE_FOREACH(conditional, bayesNet) {
|
||||
if (!new_clique.get())
|
||||
new_clique = addClique(conditional,childRoots);
|
||||
else
|
||||
addToCliqueFront(*this, conditional, new_clique);
|
||||
}
|
||||
|
||||
root_ = new_clique;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>::BayesTreeOrdered(const This& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>& BayesTreeOrdered<CONDITIONAL,CLIQUE>::operator=(const This& other) {
|
||||
this->clear();
|
||||
other.cloneTo(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::print(const std::string& s, const IndexFormatter& indexFormatter) const {
|
||||
if (root_.use_count() == 0) {
|
||||
std::cout << "WARNING: BayesTree.print encountered a forest..." << std::endl;
|
||||
return;
|
||||
}
|
||||
std::cout << s << ": clique size == " << size() << ", node size == " << nodes_.size() << std::endl;
|
||||
if (nodes_.empty()) return;
|
||||
root_->printTree("", indexFormatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// binary predicate to test equality of a pair for use in equals
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
bool check_sharedCliques(
|
||||
const typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique& v1,
|
||||
const typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique& v2
|
||||
) {
|
||||
return (!v1 && !v2) || (v1 && v2 && v1->equals(*v2));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
bool BayesTreeOrdered<CONDITIONAL,CLIQUE>::equals(const BayesTreeOrdered<CONDITIONAL,CLIQUE>& other,
|
||||
double tol) const {
|
||||
return size()==other.size() &&
|
||||
std::equal(nodes_.begin(), nodes_.end(), other.nodes_.begin(), &check_sharedCliques<CONDITIONAL,CLIQUE>);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
template<class CONTAINER>
|
||||
inline Index BayesTreeOrdered<CONDITIONAL,CLIQUE>::findParentClique(const CONTAINER& parents) const {
|
||||
typename CONTAINER::const_iterator lowestOrderedParent = min_element(parents.begin(), parents.end());
|
||||
assert(lowestOrderedParent != parents.end());
|
||||
return *lowestOrderedParent;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::insert(BayesTreeOrdered<CONDITIONAL,CLIQUE>& bayesTree, const sharedConditional& conditional)
|
||||
{
|
||||
static const bool debug = false;
|
||||
|
||||
// get indices and parents
|
||||
const typename CONDITIONAL::Parents& parents = conditional->parents();
|
||||
|
||||
if(debug) conditional->print("Adding conditional ");
|
||||
|
||||
// if no parents, start a new root clique
|
||||
if (parents.empty()) {
|
||||
if(debug) std::cout << "No parents so making root" << std::endl;
|
||||
bayesTree.root_ = bayesTree.addClique(conditional);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, find the parent clique by using the index data structure
|
||||
// to find the lowest-ordered parent
|
||||
Index parentRepresentative = bayesTree.findParentClique(parents);
|
||||
if(debug) std::cout << "First-eliminated parent is " << parentRepresentative << ", have " << bayesTree.nodes_.size() << " nodes." << std::endl;
|
||||
sharedClique parent_clique = bayesTree[parentRepresentative];
|
||||
if(debug) parent_clique->print("Parent clique is ");
|
||||
|
||||
// if the parents and parent clique have the same size, add to parent clique
|
||||
if ((*parent_clique)->size() == size_t(parents.size())) {
|
||||
if(debug) std::cout << "Adding to parent clique" << std::endl;
|
||||
addToCliqueFront(bayesTree, conditional, parent_clique);
|
||||
} else {
|
||||
if(debug) std::cout << "Starting new clique" << std::endl;
|
||||
// otherwise, start a new clique and add it to the tree
|
||||
bayesTree.addClique(conditional,parent_clique);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
//TODO: remove this function after removing TSAM.cpp
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique BayesTreeOrdered<CONDITIONAL,CLIQUE>::insert(
|
||||
const sharedConditional& clique, std::list<sharedClique>& children, bool isRootClique) {
|
||||
|
||||
if (clique->nrFrontals() == 0)
|
||||
throw std::invalid_argument("BayesTree::insert: empty clique!");
|
||||
|
||||
// create a new clique and add all the conditionals to the clique
|
||||
sharedClique new_clique = addClique(clique, children);
|
||||
if (isRootClique) root_ = new_clique;
|
||||
|
||||
return new_clique;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::fillNodesIndex(const sharedClique& subtree) {
|
||||
// Add each frontal variable of this root node
|
||||
BOOST_FOREACH(const Index& j, subtree->conditional()->frontals()) { nodes_[j] = subtree; }
|
||||
// Fill index for each child
|
||||
typedef typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique sharedClique;
|
||||
BOOST_FOREACH(const sharedClique& child, subtree->children_) {
|
||||
fillNodesIndex(child); }
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::insert(const sharedClique& subtree) {
|
||||
if(subtree) {
|
||||
// Find the parent clique of the new subtree. By the running intersection
|
||||
// property, those separator variables in the subtree that are ordered
|
||||
// lower than the highest frontal variable of the subtree root will all
|
||||
// appear in the separator of the subtree root.
|
||||
if(subtree->conditional()->parents().empty()) {
|
||||
assert(!root_);
|
||||
root_ = subtree;
|
||||
} else {
|
||||
Index parentRepresentative = findParentClique(subtree->conditional()->parents());
|
||||
sharedClique parent = (*this)[parentRepresentative];
|
||||
parent->children_ += subtree;
|
||||
subtree->parent_ = parent; // set new parent!
|
||||
}
|
||||
|
||||
// Now fill in the nodes index
|
||||
if(nodes_.size() == 0 ||
|
||||
*std::max_element(subtree->conditional()->beginFrontals(), subtree->conditional()->endFrontals()) > (nodes_.size() - 1)) {
|
||||
nodes_.resize(subtree->conditional()->lastFrontalKey() + 1);
|
||||
}
|
||||
fillNodesIndex(subtree);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// First finds clique marginal then marginalizes that
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename CONDITIONAL::FactorType::shared_ptr BayesTreeOrdered<CONDITIONAL,CLIQUE>::marginalFactor(
|
||||
Index j, Eliminate function) const
|
||||
{
|
||||
gttic(BayesTree_marginalFactor);
|
||||
|
||||
// get clique containing Index j
|
||||
sharedClique clique = (*this)[j];
|
||||
|
||||
// calculate or retrieve its marginal P(C) = P(F,S)
|
||||
#ifdef OLD_SHORTCUT_MARGINALS
|
||||
FactorGraphOrdered<FactorType> cliqueMarginal = clique->marginal(root_,function);
|
||||
#else
|
||||
FactorGraphOrdered<FactorType> cliqueMarginal = clique->marginal2(root_,function);
|
||||
#endif
|
||||
|
||||
// Reduce the variable indices to start at zero
|
||||
gttic(Reduce);
|
||||
const Permutation reduction = internal::createReducingPermutation(cliqueMarginal.keys());
|
||||
internal::Reduction inverseReduction = internal::Reduction::CreateAsInverse(reduction);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, cliqueMarginal) {
|
||||
if(factor) factor->reduceWithInverse(inverseReduction); }
|
||||
gttoc(Reduce);
|
||||
|
||||
// now, marginalize out everything that is not variable j
|
||||
GenericSequentialSolver<FactorType> solver(cliqueMarginal);
|
||||
boost::shared_ptr<FactorType> result = solver.marginalFactor(inverseReduction[j], function);
|
||||
|
||||
// Undo the reduction
|
||||
gttic(Undo_Reduce);
|
||||
result->permuteWithInverse(reduction);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, cliqueMarginal) {
|
||||
if(factor) factor->permuteWithInverse(reduction); }
|
||||
gttoc(Undo_Reduce);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesNetOrdered<CONDITIONAL>::shared_ptr BayesTreeOrdered<CONDITIONAL,CLIQUE>::marginalBayesNet(
|
||||
Index j, Eliminate function) const
|
||||
{
|
||||
gttic(BayesTree_marginalBayesNet);
|
||||
|
||||
// calculate marginal as a factor graph
|
||||
FactorGraphOrdered<FactorType> fg;
|
||||
fg.push_back(this->marginalFactor(j,function));
|
||||
|
||||
// Reduce the variable indices to start at zero
|
||||
gttic(Reduce);
|
||||
const Permutation reduction = internal::createReducingPermutation(fg.keys());
|
||||
internal::Reduction inverseReduction = internal::Reduction::CreateAsInverse(reduction);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, fg) {
|
||||
if(factor) factor->reduceWithInverse(inverseReduction); }
|
||||
gttoc(Reduce);
|
||||
|
||||
// eliminate factor graph marginal to a Bayes net
|
||||
boost::shared_ptr<BayesNetOrdered<CONDITIONAL> > bn = GenericSequentialSolver<FactorType>(fg).eliminate(function);
|
||||
|
||||
// Undo the reduction
|
||||
gttic(Undo_Reduce);
|
||||
bn->permuteWithInverse(reduction);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, fg) {
|
||||
if(factor) factor->permuteWithInverse(reduction); }
|
||||
gttoc(Undo_Reduce);
|
||||
return bn;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Find two cliques, their joint, then marginalizes
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename FactorGraphOrdered<typename CONDITIONAL::FactorType>::shared_ptr
|
||||
BayesTreeOrdered<CONDITIONAL,CLIQUE>::joint(Index j1, Index j2, Eliminate function) const {
|
||||
gttic(BayesTree_joint);
|
||||
|
||||
// get clique C1 and C2
|
||||
sharedClique C1 = (*this)[j1], C2 = (*this)[j2];
|
||||
|
||||
gttic(Lowest_common_ancestor);
|
||||
// Find lowest common ancestor clique
|
||||
sharedClique B; {
|
||||
// Build two paths to the root
|
||||
FastList<sharedClique> path1, path2; {
|
||||
sharedClique p = C1;
|
||||
while(p) {
|
||||
path1.push_front(p);
|
||||
p = p->parent();
|
||||
}
|
||||
} {
|
||||
sharedClique p = C2;
|
||||
while(p) {
|
||||
path2.push_front(p);
|
||||
p = p->parent();
|
||||
}
|
||||
}
|
||||
// Find the path intersection
|
||||
B = this->root();
|
||||
typename FastList<sharedClique>::const_iterator p1 = path1.begin(), p2 = path2.begin();
|
||||
while(p1 != path1.end() && p2 != path2.end() && *p1 == *p2) {
|
||||
B = *p1;
|
||||
++p1;
|
||||
++p2;
|
||||
}
|
||||
}
|
||||
gttoc(Lowest_common_ancestor);
|
||||
|
||||
// Compute marginal on lowest common ancestor clique
|
||||
gttic(LCA_marginal);
|
||||
FactorGraphOrdered<FactorType> p_B = B->marginal2(this->root(), function);
|
||||
gttoc(LCA_marginal);
|
||||
|
||||
// Compute shortcuts of the requested cliques given the lowest common ancestor
|
||||
gttic(Clique_shortcuts);
|
||||
BayesNetOrdered<CONDITIONAL> p_C1_Bred = C1->shortcut(B, function);
|
||||
BayesNetOrdered<CONDITIONAL> p_C2_Bred = C2->shortcut(B, function);
|
||||
gttoc(Clique_shortcuts);
|
||||
|
||||
// Factor the shortcuts to be conditioned on the full root
|
||||
// Get the set of variables to eliminate, which is C1\B.
|
||||
gttic(Full_root_factoring);
|
||||
sharedConditional p_C1_B; {
|
||||
std::vector<Index> C1_minus_B; {
|
||||
FastSet<Index> C1_minus_B_set(C1->conditional()->beginParents(), C1->conditional()->endParents());
|
||||
BOOST_FOREACH(const Index j, *B->conditional()) {
|
||||
C1_minus_B_set.erase(j); }
|
||||
C1_minus_B.assign(C1_minus_B_set.begin(), C1_minus_B_set.end());
|
||||
}
|
||||
// Factor into C1\B | B.
|
||||
FactorGraphOrdered<FactorType> temp_remaining;
|
||||
boost::tie(p_C1_B, temp_remaining) = FactorGraphOrdered<FactorType>(p_C1_Bred).eliminate(C1_minus_B, function);
|
||||
}
|
||||
sharedConditional p_C2_B; {
|
||||
std::vector<Index> C2_minus_B; {
|
||||
FastSet<Index> C2_minus_B_set(C2->conditional()->beginParents(), C2->conditional()->endParents());
|
||||
BOOST_FOREACH(const Index j, *B->conditional()) {
|
||||
C2_minus_B_set.erase(j); }
|
||||
C2_minus_B.assign(C2_minus_B_set.begin(), C2_minus_B_set.end());
|
||||
}
|
||||
// Factor into C2\B | B.
|
||||
FactorGraphOrdered<FactorType> temp_remaining;
|
||||
boost::tie(p_C2_B, temp_remaining) = FactorGraphOrdered<FactorType>(p_C2_Bred).eliminate(C2_minus_B, function);
|
||||
}
|
||||
gttoc(Full_root_factoring);
|
||||
|
||||
gttic(Variable_joint);
|
||||
// Build joint on all involved variables
|
||||
FactorGraphOrdered<FactorType> p_BC1C2;
|
||||
p_BC1C2.push_back(p_B);
|
||||
p_BC1C2.push_back(p_C1_B->toFactor());
|
||||
p_BC1C2.push_back(p_C2_B->toFactor());
|
||||
if(C1 != B)
|
||||
p_BC1C2.push_back(C1->conditional()->toFactor());
|
||||
if(C2 != B)
|
||||
p_BC1C2.push_back(C2->conditional()->toFactor());
|
||||
|
||||
// Reduce the variable indices to start at zero
|
||||
gttic(Reduce);
|
||||
const Permutation reduction = internal::createReducingPermutation(p_BC1C2.keys());
|
||||
internal::Reduction inverseReduction = internal::Reduction::CreateAsInverse(reduction);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, p_BC1C2) {
|
||||
if(factor) factor->reduceWithInverse(inverseReduction); }
|
||||
std::vector<Index> js; js.push_back(inverseReduction[j1]); js.push_back(inverseReduction[j2]);
|
||||
gttoc(Reduce);
|
||||
|
||||
// now, marginalize out everything that is not variable j
|
||||
GenericSequentialSolver<FactorType> solver(p_BC1C2);
|
||||
boost::shared_ptr<FactorGraphOrdered<FactorType> > result = solver.jointFactorGraph(js, function);
|
||||
|
||||
// Undo the reduction
|
||||
gttic(Undo_Reduce);
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, *result) {
|
||||
if(factor) factor->permuteWithInverse(reduction); }
|
||||
BOOST_FOREACH(const boost::shared_ptr<FactorType>& factor, p_BC1C2) {
|
||||
if(factor) factor->permuteWithInverse(reduction); }
|
||||
gttoc(Undo_Reduce);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesNetOrdered<CONDITIONAL>::shared_ptr BayesTreeOrdered<CONDITIONAL,CLIQUE>::jointBayesNet(
|
||||
Index j1, Index j2, Eliminate function) const {
|
||||
|
||||
// eliminate factor graph marginal to a Bayes net
|
||||
return GenericSequentialSolver<FactorType> (
|
||||
*this->joint(j1, j2, function)).eliminate(function);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::clear() {
|
||||
// Remove all nodes and clear the root pointer
|
||||
nodes_.clear();
|
||||
root_.reset();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::removePath(sharedClique clique,
|
||||
BayesNetOrdered<CONDITIONAL>& bn, typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::Cliques& orphans) {
|
||||
|
||||
// base case is NULL, if so we do nothing and return empties above
|
||||
if (clique!=NULL) {
|
||||
|
||||
// remove the clique from orphans in case it has been added earlier
|
||||
orphans.remove(clique);
|
||||
|
||||
// remove me
|
||||
this->removeClique(clique);
|
||||
|
||||
// remove path above me
|
||||
this->removePath(typename Clique::shared_ptr(clique->parent_.lock()), bn, orphans);
|
||||
|
||||
// add children to list of orphans (splice also removed them from clique->children_)
|
||||
orphans.splice(orphans.begin(), clique->children_);
|
||||
|
||||
bn.push_back(clique->conditional());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
template<class CONTAINER>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::removeTop(const CONTAINER& keys,
|
||||
BayesNetOrdered<CONDITIONAL>& bn, typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::Cliques& orphans) {
|
||||
|
||||
// process each key of the new factor
|
||||
BOOST_FOREACH(const Index& j, keys) {
|
||||
|
||||
// get the clique
|
||||
if(j < nodes_.size()) {
|
||||
const sharedClique& clique(nodes_[j]);
|
||||
if(clique) {
|
||||
// remove path from clique to root
|
||||
this->removePath(clique, bn, orphans);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete cachedShortcuts for each orphan subtree
|
||||
//TODO: Consider Improving
|
||||
BOOST_FOREACH(sharedClique& orphan, orphans)
|
||||
orphan->deleteCachedShortcuts();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::Cliques BayesTreeOrdered<CONDITIONAL,CLIQUE>::removeSubtree(
|
||||
const sharedClique& subtree)
|
||||
{
|
||||
// Result clique list
|
||||
Cliques cliques;
|
||||
cliques.push_back(subtree);
|
||||
|
||||
// Remove the first clique from its parents
|
||||
if(!subtree->isRoot())
|
||||
subtree->parent()->children().remove(subtree);
|
||||
else
|
||||
root_.reset();
|
||||
|
||||
// Add all subtree cliques and erase the children and parent of each
|
||||
for(typename Cliques::iterator clique = cliques.begin(); clique != cliques.end(); ++clique)
|
||||
{
|
||||
// Add children
|
||||
BOOST_FOREACH(const sharedClique& child, (*clique)->children()) {
|
||||
cliques.push_back(child); }
|
||||
|
||||
// Delete cached shortcuts
|
||||
(*clique)->deleteCachedShortcutsNonRecursive();
|
||||
|
||||
// Remove this node from the nodes index
|
||||
BOOST_FOREACH(Index j, (*clique)->conditional()->frontals()) {
|
||||
nodes_[j].reset(); }
|
||||
|
||||
// Erase the parent and children pointers
|
||||
(*clique)->parent_.reset();
|
||||
(*clique)->children_.clear();
|
||||
}
|
||||
|
||||
return cliques;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::cloneTo(This& newTree) const {
|
||||
if(root())
|
||||
cloneTo(newTree, root(), sharedClique());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void BayesTreeOrdered<CONDITIONAL,CLIQUE>::cloneTo(
|
||||
This& newTree, const sharedClique& subtree, const sharedClique& parent) const {
|
||||
sharedClique newClique(subtree->clone());
|
||||
newTree.addClique(newClique, parent);
|
||||
BOOST_FOREACH(const sharedClique& childClique, subtree->children()) {
|
||||
cloneTo(newTree, childClique, newClique);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,418 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 BayesTree.h
|
||||
* @brief Bayes Tree is a tree of cliques of a Bayes Chain
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <deque>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/base/FastList.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
#include <gtsam/inference/BayesTreeCliqueBaseOrdered.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/linear/VectorValuesOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declaration of BayesTreeClique which is defined below BayesTree in this file
|
||||
template<class CONDITIONAL> struct BayesTreeClique;
|
||||
|
||||
/**
|
||||
* Bayes tree
|
||||
* @tparam CONDITIONAL The type of the conditional densities, i.e. the type of node in the underlying Bayes chain,
|
||||
* which could be a ConditionalProbabilityTable, a GaussianConditional, or a SymbolicConditional.
|
||||
* @tparam CLIQUE The type of the clique data structure, defaults to BayesTreeClique, normally do not change this
|
||||
* as it is only used when developing special versions of BayesTree, e.g. for ISAM2.
|
||||
*
|
||||
* \addtogroup Multifrontal
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class CONDITIONAL, class CLIQUE=BayesTreeClique<CONDITIONAL> >
|
||||
class BayesTreeOrdered {
|
||||
|
||||
public:
|
||||
|
||||
typedef BayesTreeOrdered<CONDITIONAL, CLIQUE> This;
|
||||
typedef boost::shared_ptr<BayesTreeOrdered<CONDITIONAL, CLIQUE> > shared_ptr;
|
||||
typedef boost::shared_ptr<CONDITIONAL> sharedConditional;
|
||||
typedef boost::shared_ptr<BayesNetOrdered<CONDITIONAL> > sharedBayesNet;
|
||||
typedef CONDITIONAL ConditionalType;
|
||||
typedef typename CONDITIONAL::FactorType FactorType;
|
||||
typedef typename FactorGraphOrdered<FactorType>::Eliminate Eliminate;
|
||||
|
||||
typedef CLIQUE Clique; ///< The clique type, normally BayesTreeClique
|
||||
|
||||
// typedef for shared pointers to cliques
|
||||
typedef boost::shared_ptr<Clique> sharedClique;
|
||||
|
||||
// A convenience class for a list of shared cliques
|
||||
struct Cliques : public FastList<sharedClique> {
|
||||
void print(const std::string& s = "Cliques",
|
||||
const IndexFormatter& indexFormatter = DefaultIndexFormatter) const;
|
||||
bool equals(const Cliques& other, double tol = 1e-9) const;
|
||||
};
|
||||
|
||||
/** clique statistics */
|
||||
struct CliqueStats {
|
||||
double avgConditionalSize;
|
||||
std::size_t maxConditionalSize;
|
||||
double avgSeparatorSize;
|
||||
std::size_t maxSeparatorSize;
|
||||
void print(const std::string& s = "") const ;
|
||||
};
|
||||
|
||||
/** store all the sizes */
|
||||
struct CliqueData {
|
||||
std::vector<std::size_t> conditionalSizes;
|
||||
std::vector<std::size_t> separatorSizes;
|
||||
CliqueStats getStats() const;
|
||||
};
|
||||
|
||||
/** Map from indices to Clique */
|
||||
typedef std::vector<sharedClique> Nodes;
|
||||
|
||||
protected:
|
||||
|
||||
/** Map from indices to Clique */
|
||||
Nodes nodes_;
|
||||
|
||||
/** Root clique */
|
||||
sharedClique root_;
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Create an empty Bayes Tree */
|
||||
BayesTreeOrdered() {}
|
||||
|
||||
/** Create a Bayes Tree from a Bayes Net (requires CONDITIONAL is IndexConditional *or* CONDITIONAL::Combine) */
|
||||
explicit BayesTreeOrdered(const BayesNetOrdered<CONDITIONAL>& bayesNet);
|
||||
|
||||
/** Copy constructor */
|
||||
BayesTreeOrdered(const This& other);
|
||||
|
||||
/** Assignment operator */
|
||||
This& operator=(const This& other);
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Constructors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Create a Bayes Tree from a Bayes Net and some subtrees. The Bayes net corresponds to the
|
||||
* new root clique and the subtrees are connected to the root clique.
|
||||
*/
|
||||
BayesTreeOrdered(const BayesNetOrdered<CONDITIONAL>& bayesNet, std::list<BayesTreeOrdered<CONDITIONAL,CLIQUE> > subtrees);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~BayesTreeOrdered() {}
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** check equality */
|
||||
bool equals(const BayesTreeOrdered<CONDITIONAL,CLIQUE>& other, double tol = 1e-9) const;
|
||||
|
||||
/** print */
|
||||
void print(const std::string& s = "",
|
||||
const IndexFormatter& indexFormatter = DefaultIndexFormatter ) const;
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Find parent clique of a conditional. It will look at all parents and
|
||||
* return the one with the lowest index in the ordering.
|
||||
*/
|
||||
template<class CONTAINER>
|
||||
Index findParentClique(const CONTAINER& parents) const;
|
||||
|
||||
/** number of cliques */
|
||||
inline size_t size() const {
|
||||
if(root_)
|
||||
return root_->treeSize();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** number of nodes */
|
||||
inline size_t nrNodes() const { return nodes_.size(); }
|
||||
|
||||
/** Check if there are any cliques in the tree */
|
||||
inline bool empty() const {
|
||||
return nodes_.empty();
|
||||
}
|
||||
|
||||
/** return nodes */
|
||||
const Nodes& nodes() const { return nodes_; }
|
||||
|
||||
/** return root clique */
|
||||
const sharedClique& root() const { return root_; }
|
||||
|
||||
/** find the clique that contains the variable with Index j */
|
||||
inline sharedClique operator[](Index j) const {
|
||||
return nodes_.at(j);
|
||||
}
|
||||
|
||||
/** alternate syntax for matlab: find the clique that contains the variable with Index j */
|
||||
inline sharedClique clique(Index j) const {
|
||||
return nodes_.at(j);
|
||||
}
|
||||
|
||||
/** Gather data on all cliques */
|
||||
CliqueData getCliqueData() const;
|
||||
|
||||
/** Collect number of cliques with cached separator marginals */
|
||||
size_t numCachedSeparatorMarginals() const;
|
||||
|
||||
/** return marginal on any variable */
|
||||
typename FactorType::shared_ptr marginalFactor(Index j, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* return marginal on any variable, as a Bayes Net
|
||||
* NOTE: this function calls marginal, and then eliminates it into a Bayes Net
|
||||
* This is more expensive than the above function
|
||||
*/
|
||||
typename BayesNetOrdered<CONDITIONAL>::shared_ptr marginalBayesNet(Index j, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* return joint on two variables
|
||||
* Limitation: can only calculate joint if cliques are disjoint or one of them is root
|
||||
*/
|
||||
typename FactorGraphOrdered<FactorType>::shared_ptr joint(Index j1, Index j2, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* return joint on two variables as a BayesNet
|
||||
* Limitation: can only calculate joint if cliques are disjoint or one of them is root
|
||||
*/
|
||||
typename BayesNetOrdered<CONDITIONAL>::shared_ptr jointBayesNet(Index j1, Index j2, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* Read only with side effects
|
||||
*/
|
||||
|
||||
/** saves the Tree to a text file in GraphViz format */
|
||||
void saveGraph(const std::string& s, const IndexFormatter& indexFormatter = DefaultIndexFormatter ) const;
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/** Access the root clique (non-const version) */
|
||||
sharedClique& root() { return root_; }
|
||||
|
||||
/** Access the nodes (non-cost version) */
|
||||
Nodes& nodes() { return nodes_; }
|
||||
|
||||
/** Remove all nodes */
|
||||
void clear();
|
||||
|
||||
/** Clear all shortcut caches - use before timing on marginal calculation to avoid residual cache data */
|
||||
void deleteCachedShortcuts() {
|
||||
root_->deleteCachedShortcuts();
|
||||
}
|
||||
|
||||
/** Apply a permutation to the full tree - also updates the nodes structure */
|
||||
void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
/**
|
||||
* Remove path from clique to root and return that path as factors
|
||||
* plus a list of orphaned subtree roots. Used in removeTop below.
|
||||
*/
|
||||
void removePath(sharedClique clique, BayesNetOrdered<CONDITIONAL>& bn, Cliques& orphans);
|
||||
|
||||
/**
|
||||
* Given a list of indices, turn "contaminated" part of the tree back into a factor graph.
|
||||
* Factors and orphans are added to the in/out arguments.
|
||||
*/
|
||||
template<class CONTAINER>
|
||||
void removeTop(const CONTAINER& indices, BayesNetOrdered<CONDITIONAL>& bn, Cliques& orphans);
|
||||
|
||||
/**
|
||||
* Remove the requested subtree. */
|
||||
Cliques removeSubtree(const sharedClique& subtree);
|
||||
|
||||
/**
|
||||
* Hang a new subtree off of the existing tree. This finds the appropriate
|
||||
* parent clique for the subtree (which may be the root), and updates the
|
||||
* nodes index with the new cliques in the subtree. None of the frontal
|
||||
* variables in the subtree may appear in the separators of the existing
|
||||
* BayesTree.
|
||||
*/
|
||||
void insert(const sharedClique& subtree);
|
||||
|
||||
/** Insert a new conditional
|
||||
* This function only applies for Symbolic case with IndexCondtional,
|
||||
* We make it static so that it won't be compiled in GaussianConditional case.
|
||||
* */
|
||||
static void insert(BayesTreeOrdered<CONDITIONAL,CLIQUE>& bayesTree, const sharedConditional& conditional);
|
||||
|
||||
/**
|
||||
* Insert a new clique corresponding to the given Bayes net.
|
||||
* It is the caller's responsibility to decide whether the given Bayes net is a valid clique,
|
||||
* i.e. all the variables (frontal and separator) are connected
|
||||
*/
|
||||
sharedClique insert(const sharedConditional& clique,
|
||||
std::list<sharedClique>& children, bool isRootClique = false);
|
||||
|
||||
/**
|
||||
* Create a clone of this object as a shared pointer
|
||||
* Necessary for inheritance in matlab interface
|
||||
*/
|
||||
virtual shared_ptr clone() const {
|
||||
return shared_ptr(new This(*this));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/** private helper method for saving the Tree to a text file in GraphViz format */
|
||||
void saveGraph(std::ostream &s, sharedClique clique, const IndexFormatter& indexFormatter,
|
||||
int parentnum = 0) const;
|
||||
|
||||
/** Gather data on a single clique */
|
||||
void getCliqueData(CliqueData& stats, sharedClique clique) const;
|
||||
|
||||
/** remove a clique: warning, can result in a forest */
|
||||
void removeClique(sharedClique clique);
|
||||
|
||||
/** add a clique (top down) */
|
||||
sharedClique addClique(const sharedConditional& conditional, const sharedClique& parent_clique = sharedClique());
|
||||
|
||||
/** add a clique (top down) */
|
||||
void addClique(const sharedClique& clique, const sharedClique& parent_clique = sharedClique());
|
||||
|
||||
/** add a clique (bottom up) */
|
||||
sharedClique addClique(const sharedConditional& conditional, std::list<sharedClique>& child_cliques);
|
||||
|
||||
/**
|
||||
* Add a conditional to the front of a clique, i.e. a conditional whose
|
||||
* parents are already in the clique or its separators. This function does
|
||||
* not check for this condition, it just updates the data structures.
|
||||
*/
|
||||
static void addToCliqueFront(BayesTreeOrdered<CONDITIONAL,CLIQUE>& bayesTree,
|
||||
const sharedConditional& conditional, const sharedClique& clique);
|
||||
|
||||
/** Fill the nodes index for a subtree */
|
||||
void fillNodesIndex(const sharedClique& subtree);
|
||||
|
||||
/** Helper function to build a non-symbolic tree (e.g. Gaussian) using a
|
||||
* symbolic tree, used in the BT(BN) constructor.
|
||||
*/
|
||||
void recursiveTreeBuild(const boost::shared_ptr<BayesTreeClique<IndexConditionalOrdered> >& symbolic,
|
||||
const std::vector<boost::shared_ptr<CONDITIONAL> >& conditionals,
|
||||
const typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique& parent);
|
||||
|
||||
private:
|
||||
|
||||
/** deep copy to another tree */
|
||||
void cloneTo(This& newTree) const;
|
||||
|
||||
/** deep copy to another tree */
|
||||
void cloneTo(This& newTree, const sharedClique& subtree, const sharedClique& parent) const;
|
||||
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_NVP(nodes_);
|
||||
ar & BOOST_SERIALIZATION_NVP(root_);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
}; // BayesTree
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
void _BayesTree_dim_adder(
|
||||
std::vector<size_t>& dims,
|
||||
const typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique& clique) {
|
||||
|
||||
if(clique) {
|
||||
// Add dims from this clique
|
||||
for(typename CONDITIONAL::const_iterator it = (*clique)->beginFrontals(); it != (*clique)->endFrontals(); ++it)
|
||||
dims[*it] = (*clique)->dim(it);
|
||||
|
||||
// Traverse children
|
||||
typedef typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique sharedClique;
|
||||
BOOST_FOREACH(const sharedClique& child, clique->children()) {
|
||||
_BayesTree_dim_adder<CONDITIONAL,CLIQUE>(dims, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL,class CLIQUE>
|
||||
boost::shared_ptr<VectorValuesOrdered> allocateVectorValues(const BayesTreeOrdered<CONDITIONAL,CLIQUE>& bt) {
|
||||
std::vector<size_t> dimensions(bt.nodes().size(), 0);
|
||||
_BayesTree_dim_adder<CONDITIONAL,CLIQUE>(dimensions, bt.root());
|
||||
return boost::shared_ptr<VectorValuesOrdered>(new VectorValuesOrdered(dimensions));
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* A Clique in the tree is an incomplete Bayes net: the variables
|
||||
* in the Bayes net are the frontal nodes, and the variables conditioned
|
||||
* on are the separator. We also have pointers up and down the tree.
|
||||
*
|
||||
* Since our Conditional class already handles multiple frontal variables,
|
||||
* this Clique contains exactly 1 conditional.
|
||||
*
|
||||
* This is the default clique type in a BayesTree, but some algorithms, like
|
||||
* iSAM2 (see ISAM2Clique), use a different clique type in order to store
|
||||
* extra data along with the clique.
|
||||
*/
|
||||
template<class CONDITIONAL>
|
||||
struct BayesTreeClique : public BayesTreeCliqueBaseOrdered<BayesTreeClique<CONDITIONAL>, CONDITIONAL> {
|
||||
public:
|
||||
typedef CONDITIONAL ConditionalType;
|
||||
typedef BayesTreeClique<CONDITIONAL> This;
|
||||
typedef BayesTreeCliqueBaseOrdered<This, CONDITIONAL> Base;
|
||||
typedef boost::shared_ptr<This> shared_ptr;
|
||||
typedef boost::weak_ptr<This> weak_ptr;
|
||||
BayesTreeClique() {}
|
||||
BayesTreeClique(const typename ConditionalType::shared_ptr& conditional) : Base(conditional) {}
|
||||
BayesTreeClique(const std::pair<typename ConditionalType::shared_ptr, typename ConditionalType::FactorType::shared_ptr>& result) : Base(result) {}
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
|
||||
}
|
||||
};
|
||||
|
||||
} /// namespace gtsam
|
||||
|
||||
#include <gtsam/inference/BayesTreeOrdered-inl.h>
|
||||
#include <gtsam/inference/BayesTreeCliqueBaseOrdered-inl.h>
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 ClusterTree-inl.h
|
||||
* @date July 13, 2010
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
* @brief: Collects factorgraph fragments defined on variable clusters, arranged in a tree
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <gtsam/inference/ClusterTreeOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* *
|
||||
* Cluster
|
||||
* ************************************************************************* */
|
||||
template<class FG>
|
||||
template<class Iterator>
|
||||
ClusterTreeOrdered<FG>::Cluster::Cluster(const FG& fg, Index key, Iterator firstSeparator, Iterator lastSeparator) :
|
||||
FG(fg), frontal(1, key), separator(firstSeparator, lastSeparator) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
template<typename FRONTALIT, typename SEPARATORIT>
|
||||
ClusterTreeOrdered<FG>::Cluster::Cluster(
|
||||
const FG& fg, FRONTALIT firstFrontal, FRONTALIT lastFrontal, SEPARATORIT firstSeparator, SEPARATORIT lastSeparator) :
|
||||
FG(fg), frontal(firstFrontal, lastFrontal), separator(firstSeparator, lastSeparator) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
template<typename FRONTALIT, typename SEPARATORIT>
|
||||
ClusterTreeOrdered<FG>::Cluster::Cluster(
|
||||
FRONTALIT firstFrontal, FRONTALIT lastFrontal, SEPARATORIT firstSeparator, SEPARATORIT lastSeparator) :
|
||||
frontal(firstFrontal, lastFrontal), separator(firstSeparator, lastSeparator) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
void ClusterTreeOrdered<FG>::Cluster::addChild(typename ClusterTreeOrdered<FG>::Cluster::shared_ptr child) {
|
||||
children_.push_back(child);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
bool ClusterTreeOrdered<FG>::Cluster::equals(const Cluster& other) const {
|
||||
if (frontal != other.frontal) return false;
|
||||
if (separator != other.separator) return false;
|
||||
if (children_.size() != other.children_.size()) return false;
|
||||
|
||||
typename std::list<shared_ptr>::const_iterator it1 = children_.begin();
|
||||
typename std::list<shared_ptr>::const_iterator it2 = other.children_.begin();
|
||||
for (; it1 != children_.end(); it1++, it2++)
|
||||
if (!(*it1)->equals(**it2)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
void ClusterTreeOrdered<FG>::Cluster::print(const std::string& indent,
|
||||
const IndexFormatter& formatter) const {
|
||||
std::cout << indent;
|
||||
BOOST_FOREACH(const Index key, frontal)
|
||||
std::cout << formatter(key) << " ";
|
||||
std::cout << ": ";
|
||||
BOOST_FOREACH(const Index key, separator)
|
||||
std::cout << key << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
void ClusterTreeOrdered<FG>::Cluster::printTree(const std::string& indent,
|
||||
const IndexFormatter& formatter) const {
|
||||
print(indent, formatter);
|
||||
BOOST_FOREACH(const shared_ptr& child, children_)
|
||||
child->printTree(indent + " ", formatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* *
|
||||
* ClusterTree
|
||||
* ************************************************************************* */
|
||||
template<class FG>
|
||||
void ClusterTreeOrdered<FG>::print(const std::string& str,
|
||||
const IndexFormatter& formatter) const {
|
||||
std::cout << str << std::endl;
|
||||
if (root_) root_->printTree("", formatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
bool ClusterTreeOrdered<FG>::equals(const ClusterTreeOrdered<FG>& other, double tol) const {
|
||||
if (!root_ && !other.root_) return true;
|
||||
if (!root_ || !other.root_) return false;
|
||||
return root_->equals(*other.root_);
|
||||
}
|
||||
|
||||
} //namespace gtsam
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 ClusterTree.h
|
||||
* @date July 13, 2010
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
* @brief: Collects factorgraph fragments defined on variable clusters, arranged in a tree
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* A cluster-tree is associated with a factor graph and is defined as in Koller-Friedman:
|
||||
* each node k represents a subset \f$ C_k \sub X \f$, and the tree is family preserving, in that
|
||||
* each factor \f$ f_i \f$ is associated with a single cluster and \f$ scope(f_i) \sub C_k \f$.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template <class FG>
|
||||
class ClusterTreeOrdered {
|
||||
public:
|
||||
// Access to factor types
|
||||
typedef typename FG::KeyType KeyType;
|
||||
|
||||
protected:
|
||||
|
||||
// the class for subgraphs that also include the pointers to the parents and two children
|
||||
class Cluster : public FG {
|
||||
public:
|
||||
typedef typename boost::shared_ptr<Cluster> shared_ptr;
|
||||
typedef typename boost::weak_ptr<Cluster> weak_ptr;
|
||||
|
||||
const std::vector<Index> frontal; // the frontal variables
|
||||
const std::vector<Index> separator; // the separator variables
|
||||
|
||||
protected:
|
||||
|
||||
weak_ptr parent_; // the parent cluster
|
||||
std::list<shared_ptr> children_; // the child clusters
|
||||
const typename FG::sharedFactor eliminated_; // the eliminated factor to pass on to the parent
|
||||
|
||||
public:
|
||||
|
||||
/// Construct empty clique
|
||||
Cluster() {}
|
||||
|
||||
/** Create a node with a single frontal variable */
|
||||
template<typename Iterator>
|
||||
Cluster(const FG& fg, Index key, Iterator firstSeparator, Iterator lastSeparator);
|
||||
|
||||
/** Create a node with several frontal variables */
|
||||
template<typename FRONTALIT, typename SEPARATORIT>
|
||||
Cluster(const FG& fg, FRONTALIT firstFrontal, FRONTALIT lastFrontal, SEPARATORIT firstSeparator, SEPARATORIT lastSeparator);
|
||||
|
||||
/** Create a node with several frontal variables */
|
||||
template<typename FRONTALIT, typename SEPARATORIT>
|
||||
Cluster(FRONTALIT firstFrontal, FRONTALIT lastFrontal, SEPARATORIT firstSeparator, SEPARATORIT lastSeparator);
|
||||
|
||||
/// print
|
||||
void print(const std::string& indent, const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/// print the enire tree
|
||||
void printTree(const std::string& indent, const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/// check equality
|
||||
bool equals(const Cluster& other) const;
|
||||
|
||||
/// get a reference to the children
|
||||
const std::list<shared_ptr>& children() const { return children_; }
|
||||
|
||||
/// add a child
|
||||
void addChild(shared_ptr child);
|
||||
|
||||
/// get or set the parent
|
||||
weak_ptr& parent() { return parent_; }
|
||||
|
||||
};
|
||||
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/// typedef for shared pointers to clusters
|
||||
typedef typename Cluster::shared_ptr sharedCluster;
|
||||
|
||||
/// Root cluster
|
||||
sharedCluster root_;
|
||||
|
||||
public:
|
||||
|
||||
/// @}
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/// constructor of empty tree
|
||||
ClusterTreeOrdered() {}
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/// return the root cluster
|
||||
sharedCluster root() const { return root_; }
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/// print the object
|
||||
void print(const std::string& str="", const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** check equality */
|
||||
bool equals(const ClusterTreeOrdered<FG>& other, double tol = 1e-9) const;
|
||||
|
||||
/// @}
|
||||
|
||||
}; // ClusterTree
|
||||
|
||||
} // namespace gtsam
|
||||
|
||||
#include <gtsam/inference/ClusterTreeOrdered-inl.h>
|
||||
|
|
@ -1,266 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 <gtsam/inference/FactorOrdered.h>
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* Base class for conditional densities, templated on KEY type. This class
|
||||
* provides storage for the keys involved in a conditional, and iterators and
|
||||
* access to the frontal and separator keys.
|
||||
*
|
||||
* Derived classes *must* redefine the Factor and shared_ptr typedefs to refer
|
||||
* to the associated factor type and shared_ptr type of the derived class. See
|
||||
* IndexConditional and GaussianConditional for examples.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<typename KEY>
|
||||
class ConditionalOrdered: public gtsam::FactorOrdered<KEY> {
|
||||
|
||||
private:
|
||||
|
||||
/** Create keys by adding key in front */
|
||||
template<typename ITERATOR>
|
||||
static std::vector<KEY> MakeKeys(KEY key, ITERATOR firstParent,
|
||||
ITERATOR lastParent) {
|
||||
std::vector<KeyType> keys((lastParent - firstParent) + 1);
|
||||
std::copy(firstParent, lastParent, keys.begin() + 1);
|
||||
keys[0] = key;
|
||||
return keys;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/** The first nFrontal variables are frontal and the rest are parents. */
|
||||
size_t nrFrontals_;
|
||||
|
||||
// Calls the base class assertInvariants, which checks for unique keys
|
||||
void assertInvariants() const {
|
||||
FactorOrdered<KEY>::assertInvariants();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef KEY KeyType;
|
||||
typedef ConditionalOrdered<KeyType> This;
|
||||
typedef FactorOrdered<KeyType> Base;
|
||||
|
||||
/**
|
||||
* Typedef to the factor type that produces this conditional and that this
|
||||
* conditional can be converted to using a factor constructor. Derived
|
||||
* classes must redefine this.
|
||||
*/
|
||||
typedef gtsam::FactorOrdered<KeyType> FactorType;
|
||||
|
||||
/** A shared_ptr to this class. Derived classes must redefine this. */
|
||||
typedef boost::shared_ptr<This> shared_ptr;
|
||||
|
||||
/** Iterator over keys */
|
||||
typedef typename FactorType::iterator iterator;
|
||||
|
||||
/** Const iterator over keys */
|
||||
typedef typename FactorType::const_iterator const_iterator;
|
||||
|
||||
/** View of the frontal keys (call frontals()) */
|
||||
typedef boost::iterator_range<const_iterator> Frontals;
|
||||
|
||||
/** View of the separator keys (call parents()) */
|
||||
typedef boost::iterator_range<const_iterator> Parents;
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Empty Constructor to make serialization possible */
|
||||
ConditionalOrdered() :
|
||||
nrFrontals_(0) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** No parents */
|
||||
ConditionalOrdered(KeyType key) :
|
||||
FactorType(key), nrFrontals_(1) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Single parent */
|
||||
ConditionalOrdered(KeyType key, KeyType parent) :
|
||||
FactorType(key, parent), nrFrontals_(1) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Two parents */
|
||||
ConditionalOrdered(KeyType key, KeyType parent1, KeyType parent2) :
|
||||
FactorType(key, parent1, parent2), nrFrontals_(1) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Three parents */
|
||||
ConditionalOrdered(KeyType key, KeyType parent1, KeyType parent2, KeyType parent3) :
|
||||
FactorType(key, parent1, parent2, parent3), nrFrontals_(1) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Constructors
|
||||
/// @{
|
||||
|
||||
/** Constructor from a frontal variable and a vector of parents */
|
||||
ConditionalOrdered(KeyType key, const std::vector<KeyType>& parents) :
|
||||
FactorType(MakeKeys(key, parents.begin(), parents.end())), nrFrontals_(
|
||||
1) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Constructor from keys and nr of frontal variables */
|
||||
ConditionalOrdered(const std::vector<Index>& keys, size_t nrFrontals) :
|
||||
FactorType(keys), nrFrontals_(nrFrontals) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Constructor from keys and nr of frontal variables */
|
||||
ConditionalOrdered(const std::list<Index>& keys, size_t nrFrontals) :
|
||||
FactorType(keys.begin(),keys.end()), nrFrontals_(nrFrontals) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** print with optional formatter */
|
||||
void print(const std::string& s = "Conditional",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** check equality */
|
||||
template<class DERIVED>
|
||||
bool equals(const DERIVED& c, double tol = 1e-9) const {
|
||||
return nrFrontals_ == c.nrFrontals_ && FactorType::equals(c, tol);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** return the number of frontals */
|
||||
size_t nrFrontals() const {
|
||||
return nrFrontals_;
|
||||
}
|
||||
|
||||
/** return the number of parents */
|
||||
size_t nrParents() const {
|
||||
return FactorType::size() - nrFrontals_;
|
||||
}
|
||||
|
||||
/** Special accessor when there is only one frontal variable. */
|
||||
KeyType firstFrontalKey() const {
|
||||
assert(nrFrontals_>0);
|
||||
return FactorType::front();
|
||||
}
|
||||
KeyType lastFrontalKey() const {
|
||||
assert(nrFrontals_>0);
|
||||
return *(endFrontals() - 1);
|
||||
}
|
||||
|
||||
/** 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());
|
||||
}
|
||||
|
||||
/** Iterators over frontal and parent variables. */
|
||||
const_iterator beginFrontals() const {
|
||||
return FactorType::begin();
|
||||
} ///<TODO: comment
|
||||
const_iterator endFrontals() const {
|
||||
return FactorType::begin() + nrFrontals_;
|
||||
} ///<TODO: comment
|
||||
const_iterator beginParents() const {
|
||||
return FactorType::begin() + nrFrontals_;
|
||||
} ///<TODO: comment
|
||||
const_iterator endParents() const {
|
||||
return FactorType::end();
|
||||
} ///<TODO: comment
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/** Mutable iterators and accessors */
|
||||
iterator beginFrontals() {
|
||||
return FactorType::begin();
|
||||
} ///<TODO: comment
|
||||
iterator endFrontals() {
|
||||
return FactorType::begin() + nrFrontals_;
|
||||
} ///<TODO: comment
|
||||
iterator beginParents() {
|
||||
return FactorType::begin() + nrFrontals_;
|
||||
} ///<TODO: comment
|
||||
iterator endParents() {
|
||||
return FactorType::end();
|
||||
} ///<TODO: comment
|
||||
|
||||
///TODO: comment
|
||||
boost::iterator_range<iterator> frontals() {
|
||||
return boost::make_iterator_range(beginFrontals(), endFrontals());
|
||||
}
|
||||
|
||||
///TODO: comment
|
||||
boost::iterator_range<iterator> parents() {
|
||||
return boost::make_iterator_range(beginParents(), endParents());
|
||||
}
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
|
||||
ar & BOOST_SERIALIZATION_NVP(nrFrontals_);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
void ConditionalOrdered<KEY>::print(const std::string& s,
|
||||
const IndexFormatter& formatter) const {
|
||||
std::cout << s << " P(";
|
||||
BOOST_FOREACH(KeyType key, frontals())
|
||||
std::cout << " " << formatter(key);
|
||||
if (nrParents() > 0)
|
||||
std::cout << " |";
|
||||
BOOST_FOREACH(KeyType parent, parents())
|
||||
std::cout << " " << formatter(parent);
|
||||
std::cout << ")" << std::endl;
|
||||
}
|
||||
|
||||
} // gtsam
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 EliminationTree-inl.h
|
||||
* @author Frank Dellaert
|
||||
* @date Oct 13, 2010
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/base/FastSet.h>
|
||||
#include <gtsam/inference/EliminationTreeOrdered.h>
|
||||
#include <gtsam/inference/VariableSlots.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename EliminationTreeOrdered<FACTOR>::sharedFactor EliminationTreeOrdered<FACTOR>::eliminate_(
|
||||
Eliminate function, Conditionals& conditionals) const {
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
if(debug) std::cout << "ETree: eliminating " << this->key_ << std::endl;
|
||||
|
||||
if(this->key_ < conditionals.size()) { // If it is requested to eliminate the current variable
|
||||
// Create the list of factors to be eliminated, initially empty, and reserve space
|
||||
FactorGraphOrdered<FACTOR> factors;
|
||||
factors.reserve(this->factors_.size() + this->subTrees_.size());
|
||||
|
||||
// Add all factors associated with the current node
|
||||
factors.push_back(this->factors_.begin(), this->factors_.end());
|
||||
|
||||
// for all subtrees, eliminate into Bayes net and a separator factor, added to [factors]
|
||||
BOOST_FOREACH(const shared_ptr& child, subTrees_)
|
||||
factors.push_back(child->eliminate_(function, conditionals)); // TODO: spawn thread
|
||||
// TODO: wait for completion of all threads
|
||||
|
||||
// Combine all factors (from this node and from subtrees) into a joint factor
|
||||
typename FactorGraphOrdered<FACTOR>::EliminationResult
|
||||
eliminated(function(factors, 1));
|
||||
conditionals[this->key_] = eliminated.first;
|
||||
|
||||
if(debug) std::cout << "Eliminated " << this->key_ << " to get:\n";
|
||||
if(debug) eliminated.first->print("Conditional: ");
|
||||
if(debug) eliminated.second->print("Factor: ");
|
||||
|
||||
return eliminated.second;
|
||||
} else {
|
||||
// Eliminate each child but discard the result.
|
||||
BOOST_FOREACH(const shared_ptr& child, subTrees_) {
|
||||
(void)child->eliminate_(function, conditionals);
|
||||
}
|
||||
return sharedFactor(); // Return a NULL factor
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
std::vector<Index> EliminationTreeOrdered<FACTOR>::ComputeParents(const VariableIndexOrdered& structure) {
|
||||
|
||||
// Number of factors and variables
|
||||
const size_t m = structure.nFactors();
|
||||
const size_t n = structure.size();
|
||||
|
||||
static const Index none = std::numeric_limits<Index>::max();
|
||||
|
||||
// Allocate result parent vector and vector of last factor columns
|
||||
std::vector<Index> parents(n, none);
|
||||
std::vector<Index> prevCol(m, none);
|
||||
|
||||
// for column j \in 1 to n do
|
||||
for (Index j = 0; j < n; j++) {
|
||||
// for row i \in Struct[A*j] do
|
||||
BOOST_FOREACH(const size_t i, structure[j]) {
|
||||
if (prevCol[i] != none) {
|
||||
Index k = prevCol[i];
|
||||
// find root r of the current tree that contains k
|
||||
Index r = k;
|
||||
while (parents[r] != none)
|
||||
r = parents[r];
|
||||
if (r != j) parents[r] = j;
|
||||
}
|
||||
prevCol[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
template<class DERIVEDFACTOR>
|
||||
typename EliminationTreeOrdered<FACTOR>::shared_ptr EliminationTreeOrdered<FACTOR>::Create(
|
||||
const FactorGraphOrdered<DERIVEDFACTOR>& factorGraph,
|
||||
const VariableIndexOrdered& structure) {
|
||||
|
||||
static const bool debug = false;
|
||||
gttic(ET_Create1);
|
||||
|
||||
gttic(ET_ComputeParents);
|
||||
// Compute the tree structure
|
||||
std::vector<Index> parents(ComputeParents(structure));
|
||||
gttoc(ET_ComputeParents);
|
||||
|
||||
// Number of variables
|
||||
const size_t n = structure.size();
|
||||
|
||||
static const Index none = std::numeric_limits<Index>::max();
|
||||
|
||||
// Create tree structure
|
||||
gttic(assemble_tree);
|
||||
std::vector<shared_ptr> trees(n);
|
||||
for (Index k = 1; k <= n; k++) {
|
||||
Index j = n - k; // Start at the last variable and loop down to 0
|
||||
trees[j].reset(new EliminationTreeOrdered(j)); // Create a new node on this variable
|
||||
if (parents[j] != none) // If this node has a parent, add it to the parent's children
|
||||
trees[parents[j]]->add(trees[j]);
|
||||
else if(!structure[j].empty() && j != n - 1) // If a node other than the last has no parents, this is a forest
|
||||
throw DisconnectedGraphException();
|
||||
}
|
||||
gttoc(assemble_tree);
|
||||
|
||||
// Hang factors in right places
|
||||
gttic(hang_factors);
|
||||
BOOST_FOREACH(const typename boost::shared_ptr<DERIVEDFACTOR>& factor, factorGraph) {
|
||||
if(factor && factor->size() > 0) {
|
||||
Index j = *std::min_element(factor->begin(), factor->end());
|
||||
if(j < structure.size())
|
||||
trees[j]->add(factor);
|
||||
}
|
||||
}
|
||||
gttoc(hang_factors);
|
||||
|
||||
if(debug)
|
||||
trees.back()->print("ETree: ");
|
||||
|
||||
// Check that this is not null
|
||||
assert(trees.back().get());
|
||||
return trees.back();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
template<class DERIVEDFACTOR>
|
||||
typename EliminationTreeOrdered<FACTOR>::shared_ptr
|
||||
EliminationTreeOrdered<FACTOR>::Create(const FactorGraphOrdered<DERIVEDFACTOR>& factorGraph) {
|
||||
|
||||
gttic(ET_Create2);
|
||||
// Build variable index
|
||||
const VariableIndexOrdered variableIndex(factorGraph);
|
||||
|
||||
// Build elimination tree
|
||||
return Create(factorGraph, variableIndex);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTORGRAPH>
|
||||
void EliminationTreeOrdered<FACTORGRAPH>::print(const std::string& name,
|
||||
const IndexFormatter& formatter) const {
|
||||
std::cout << name << " (" << formatter(key_) << ")" << std::endl;
|
||||
BOOST_FOREACH(const sharedFactor& factor, factors_) {
|
||||
factor->print(name + " ", formatter); }
|
||||
BOOST_FOREACH(const shared_ptr& child, subTrees_) {
|
||||
child->print(name + " ", formatter); }
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTORGRAPH>
|
||||
bool EliminationTreeOrdered<FACTORGRAPH>::equals(const EliminationTreeOrdered<FACTORGRAPH>& expected, double tol) const {
|
||||
if(this->key_ == expected.key_ && this->factors_ == expected.factors_
|
||||
&& this->subTrees_.size() == expected.subTrees_.size()) {
|
||||
typename SubTrees::const_iterator this_subtree = this->subTrees_.begin();
|
||||
typename SubTrees::const_iterator expected_subtree = expected.subTrees_.begin();
|
||||
while(this_subtree != this->subTrees_.end())
|
||||
if( ! (*(this_subtree++))->equals(**(expected_subtree++), tol))
|
||||
return false;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename EliminationTreeOrdered<FACTOR>::BayesNet::shared_ptr
|
||||
EliminationTreeOrdered<FACTOR>::eliminatePartial(typename EliminationTreeOrdered<FACTOR>::Eliminate function, size_t nrToEliminate) const {
|
||||
|
||||
// call recursive routine
|
||||
gttic(ET_recursive_eliminate);
|
||||
if(nrToEliminate > this->key_ + 1)
|
||||
throw std::invalid_argument("Requested that EliminationTree::eliminatePartial eliminate more variables than exist");
|
||||
Conditionals conditionals(nrToEliminate); // reserve a vector of conditional shared pointers
|
||||
(void)eliminate_(function, conditionals); // modify in place
|
||||
gttoc(ET_recursive_eliminate);
|
||||
|
||||
// Add conditionals to BayesNet
|
||||
gttic(assemble_BayesNet);
|
||||
typename BayesNet::shared_ptr bayesNet(new BayesNet);
|
||||
BOOST_FOREACH(const typename BayesNet::sharedConditional& conditional, conditionals) {
|
||||
if(conditional)
|
||||
bayesNet->push_back(conditional);
|
||||
}
|
||||
gttoc(assemble_BayesNet);
|
||||
|
||||
return bayesNet;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename EliminationTreeOrdered<FACTOR>::BayesNet::shared_ptr
|
||||
EliminationTreeOrdered<FACTOR>::eliminate(Eliminate function) const {
|
||||
size_t nrConditionals = this->key_ + 1; // root key has highest index
|
||||
return eliminatePartial(function, nrConditionals);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 EliminationTree.h
|
||||
* @author Frank Dellaert
|
||||
* @date Oct 13, 2010
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <gtsam/base/FastSet.h>
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/inference/VariableIndexOrdered.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
|
||||
class EliminationTreeOrderedTester; // for unit tests, see testEliminationTree
|
||||
namespace gtsam { template<class CONDITIONAL> class BayesNetOrdered; }
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* An elimination tree is a data structure used intermediately during
|
||||
* elimination. In future versions it will be used to save work between
|
||||
* multiple eliminations.
|
||||
*
|
||||
* When a variable is eliminated, a new factor is created by combining that
|
||||
* variable's neighboring factors. The new combined factor involves the combined
|
||||
* factors' involved variables. When the lowest-ordered one of those variables
|
||||
* is eliminated, it consumes that combined factor. In the elimination tree,
|
||||
* that lowest-ordered variable is the parent of the variable that was eliminated to
|
||||
* produce the combined factor. This yields a tree in general, and not a chain
|
||||
* because of the implicit sparse structure of the resulting Bayes net.
|
||||
*
|
||||
* This structure is examined even more closely in a JunctionTree, which
|
||||
* additionally identifies cliques in the chordal Bayes net.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class FACTOR>
|
||||
class EliminationTreeOrdered {
|
||||
|
||||
public:
|
||||
|
||||
typedef EliminationTreeOrdered<FACTOR> This; ///< This class
|
||||
typedef boost::shared_ptr<This> shared_ptr; ///< Shared pointer to this class
|
||||
typedef typename boost::shared_ptr<FACTOR> sharedFactor; ///< Shared pointer to a factor
|
||||
typedef gtsam::BayesNetOrdered<typename FACTOR::ConditionalType> BayesNet; ///< The BayesNet corresponding to FACTOR
|
||||
typedef FACTOR Factor;
|
||||
typedef typename FACTOR::KeyType KeyType;
|
||||
|
||||
/** Typedef for an eliminate subroutine */
|
||||
typedef typename FactorGraphOrdered<FACTOR>::Eliminate Eliminate;
|
||||
|
||||
private:
|
||||
|
||||
/** concept check */
|
||||
GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR)
|
||||
|
||||
typedef FastList<sharedFactor> Factors;
|
||||
typedef FastList<shared_ptr> SubTrees;
|
||||
typedef std::vector<typename FACTOR::ConditionalType::shared_ptr> Conditionals;
|
||||
|
||||
Index key_; ///< index associated with root // FIXME: doesn't this require that "Index" is the type of keys in the generic factor?
|
||||
Factors factors_; ///< factors associated with root
|
||||
SubTrees subTrees_; ///< sub-trees
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Named constructor to build the elimination tree of a factor graph using
|
||||
* pre-computed column structure.
|
||||
* @param factorGraph The factor graph for which to build the elimination tree
|
||||
* @param structure The set of factors involving each variable. If this is not
|
||||
* precomputed, you can call the Create(const FactorGraph<DERIVEDFACTOR>&)
|
||||
* named constructor instead.
|
||||
* @return The elimination tree
|
||||
*/
|
||||
template<class DERIVEDFACTOR>
|
||||
static shared_ptr Create(const FactorGraphOrdered<DERIVEDFACTOR>& factorGraph, const VariableIndexOrdered& structure);
|
||||
|
||||
/** Named constructor to build the elimination tree of a factor graph. Note
|
||||
* that this has to compute the column structure as a VariableIndex, so if you
|
||||
* already have this precomputed, use the Create(const FactorGraph<DERIVEDFACTOR>&, const VariableIndex&)
|
||||
* named constructor instead.
|
||||
* @param factorGraph The factor graph for which to build the elimination tree
|
||||
*/
|
||||
template<class DERIVEDFACTOR>
|
||||
static shared_ptr Create(const FactorGraphOrdered<DERIVEDFACTOR>& factorGraph);
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** Eliminate the factors to a Bayes Net
|
||||
* @param function The function to use to eliminate, see the namespace functions
|
||||
* in GaussianFactorGraph.h
|
||||
* @return The BayesNet resulting from elimination
|
||||
*/
|
||||
typename BayesNet::shared_ptr eliminate(Eliminate function) const;
|
||||
|
||||
/** Eliminate the factors to a Bayes Net and return the remaining factor
|
||||
* @param function The function to use to eliminate, see the namespace functions
|
||||
* in GaussianFactorGraph.h
|
||||
* @return The BayesNet resulting from elimination and the remaining factor
|
||||
*/
|
||||
typename BayesNet::shared_ptr eliminatePartial(Eliminate function, size_t nrToEliminate) const;
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** Print the tree to cout */
|
||||
void print(const std::string& name = "EliminationTree: ",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** Test whether the tree is equal to another */
|
||||
bool equals(const EliminationTreeOrdered& other, double tol = 1e-9) const;
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
||||
/** default constructor, private, as you should use Create below */
|
||||
EliminationTreeOrdered(Index key = 0) : key_(key) {}
|
||||
|
||||
/**
|
||||
* Static internal function to build a vector of parent pointers using the
|
||||
* algorithm of Gilbert et al., 2001, BIT.
|
||||
*/
|
||||
static std::vector<Index> ComputeParents(const VariableIndexOrdered& structure);
|
||||
|
||||
/** add a factor, for Create use only */
|
||||
void add(const sharedFactor& factor) { factors_.push_back(factor); }
|
||||
|
||||
/** add a subtree, for Create use only */
|
||||
void add(const shared_ptr& child) { subTrees_.push_back(child); }
|
||||
|
||||
/**
|
||||
* Recursive routine that eliminates the factors arranged in an elimination tree
|
||||
* @param Conditionals is a vector of shared pointers that will be modified in place
|
||||
*/
|
||||
sharedFactor eliminate_(Eliminate function, Conditionals& conditionals) const;
|
||||
|
||||
/// Allow access to constructor and add methods for testing purposes
|
||||
friend class ::EliminationTreeOrderedTester;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An exception thrown when attempting to eliminate a disconnected factor
|
||||
* graph, which is not currently possible in gtsam. If you need to work with
|
||||
* disconnected graphs, a workaround is to create zero-information factors to
|
||||
* bridge the disconnects. To do this, create any factor type (e.g.
|
||||
* BetweenFactor or RangeFactor) with the noise model
|
||||
* <tt>sharedPrecision(dim, 0.0)</tt>, where \c dim is the appropriate
|
||||
* dimensionality for that factor.
|
||||
*/
|
||||
struct DisconnectedGraphException : public std::exception {
|
||||
DisconnectedGraphException() {}
|
||||
virtual ~DisconnectedGraphException() throw() {}
|
||||
|
||||
/// Returns the string "Attempting to eliminate a disconnected graph - this is not currently possible in gtsam."
|
||||
virtual const char* what() const throw() {
|
||||
return
|
||||
"Attempting to eliminate a disconnected graph - this is not currently possible in\n"
|
||||
"GTSAM. You may add \"empty\" BetweenFactor's to join disconnected graphs, these\n"
|
||||
"will affect the symbolic structure and solving complexity of the graph but not\n"
|
||||
"the solution. To do this, create BetweenFactor's with zero-precision noise\n"
|
||||
"models, i.e. noiseModel::Isotropic::Precision(n, 0.0);\n"; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <gtsam/inference/EliminationTreeOrdered-inl.h>
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 FactorGraph-inl.h
|
||||
* This is a template definition file, include it where needed (only!)
|
||||
* so that the appropriate code is generated and link errors avoided.
|
||||
* @brief Factor Graph Base Class
|
||||
* @author Carlos Nieto
|
||||
* @author Frank Dellaert
|
||||
* @author Alireza Fathi
|
||||
* @author Michael Kaess
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/FastSet.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
#include <gtsam/inference/VariableIndexOrdered.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
template<class CONDITIONAL>
|
||||
FactorGraphOrdered<FACTOR>::FactorGraphOrdered(const BayesNetOrdered<CONDITIONAL>& bayesNet) {
|
||||
factors_.reserve(bayesNet.size());
|
||||
BOOST_FOREACH(const typename CONDITIONAL::shared_ptr& cond, bayesNet) {
|
||||
this->push_back(cond->toFactor());
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
void FactorGraphOrdered<FACTOR>::print(const std::string& s,
|
||||
const IndexFormatter& formatter) const {
|
||||
std::cout << s << std::endl;
|
||||
std::cout << "size: " << size() << std::endl;
|
||||
for (size_t i = 0; i < factors_.size(); i++) {
|
||||
std::stringstream ss;
|
||||
ss << "factor " << i << ": ";
|
||||
if (factors_[i] != NULL) factors_[i]->print(ss.str(), formatter);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
bool FactorGraphOrdered<FACTOR>::equals(const This& fg, double tol) const {
|
||||
/** check whether the two factor graphs have the same number of factors_ */
|
||||
if (factors_.size() != fg.size()) return false;
|
||||
|
||||
/** check whether the factors_ are the same */
|
||||
for (size_t i = 0; i < factors_.size(); i++) {
|
||||
// TODO: Doesn't this force order of factor insertion?
|
||||
sharedFactor f1 = factors_[i], f2 = fg.factors_[i];
|
||||
if (f1 == NULL && f2 == NULL) continue;
|
||||
if (f1 == NULL || f2 == NULL) return false;
|
||||
if (!f1->equals(*f2, tol)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
size_t FactorGraphOrdered<FACTOR>::nrFactors() const {
|
||||
size_t size_ = 0;
|
||||
BOOST_FOREACH(const sharedFactor& factor, factors_)
|
||||
if (factor) size_++;
|
||||
return size_;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
std::set<typename FACTOR::KeyType> FactorGraphOrdered<FACTOR>::keys() const {
|
||||
std::set<KeyType> allKeys;
|
||||
BOOST_FOREACH(const sharedFactor& factor, factors_)
|
||||
if (factor) {
|
||||
BOOST_FOREACH(Index j, factor->keys())
|
||||
allKeys.insert(j);
|
||||
}
|
||||
return allKeys;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
std::pair<typename FactorGraphOrdered<FACTOR>::sharedConditional, FactorGraphOrdered<FACTOR> >
|
||||
FactorGraphOrdered<FACTOR>::eliminateFrontals(size_t nFrontals, const Eliminate& eliminate) const
|
||||
{
|
||||
// Build variable index
|
||||
VariableIndexOrdered variableIndex(*this);
|
||||
|
||||
// Find first variable
|
||||
Index firstIndex = 0;
|
||||
while(firstIndex < variableIndex.size() && variableIndex[firstIndex].empty())
|
||||
++ firstIndex;
|
||||
|
||||
// Check that number of variables is in bounds
|
||||
if(firstIndex + nFrontals > variableIndex.size())
|
||||
throw std::invalid_argument("Requested to eliminate more frontal variables than exist in the factor graph.");
|
||||
|
||||
// Get set of involved factors
|
||||
FastSet<size_t> involvedFactorIs;
|
||||
for(Index j = firstIndex; j < firstIndex + nFrontals; ++j) {
|
||||
BOOST_FOREACH(size_t i, variableIndex[j]) {
|
||||
involvedFactorIs.insert(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Separate factors into involved and remaining
|
||||
FactorGraphOrdered<FactorType> involvedFactors;
|
||||
FactorGraphOrdered<FactorType> remainingFactors;
|
||||
FastSet<size_t>::const_iterator involvedFactorIsIt = involvedFactorIs.begin();
|
||||
for(size_t i = 0; i < this->size(); ++i) {
|
||||
if(involvedFactorIsIt != involvedFactorIs.end() && *involvedFactorIsIt == i) {
|
||||
// If the current factor is involved, add it to involved and increment involved iterator
|
||||
involvedFactors.push_back((*this)[i]);
|
||||
++ involvedFactorIsIt;
|
||||
} else {
|
||||
// If not involved, add to remaining
|
||||
remainingFactors.push_back((*this)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Do dense elimination on the involved factors
|
||||
typename FactorGraphOrdered<FactorType>::EliminationResult eliminationResult =
|
||||
eliminate(involvedFactors, nFrontals);
|
||||
|
||||
// Add the remaining factor back into the factor graph
|
||||
remainingFactors.push_back(eliminationResult.second);
|
||||
|
||||
// Return the eliminated factor and remaining factor graph
|
||||
return std::make_pair(eliminationResult.first, remainingFactors);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
std::pair<typename FactorGraphOrdered<FACTOR>::sharedConditional, FactorGraphOrdered<FACTOR> >
|
||||
FactorGraphOrdered<FACTOR>::eliminate(const std::vector<KeyType>& variables, const Eliminate& eliminateFcn,
|
||||
boost::optional<const VariableIndexOrdered&> variableIndex_) const
|
||||
{
|
||||
const VariableIndexOrdered& variableIndex =
|
||||
variableIndex_ ? *variableIndex_ : VariableIndexOrdered(*this);
|
||||
|
||||
// First find the involved factors
|
||||
FactorGraphOrdered<FACTOR> involvedFactors;
|
||||
Index highestInvolvedVariable = 0; // Largest index of the variables in the involved factors
|
||||
|
||||
// First get the indices of the involved factors, but uniquely in a set
|
||||
FastSet<size_t> involvedFactorIndices;
|
||||
BOOST_FOREACH(Index variable, variables) {
|
||||
involvedFactorIndices.insert(variableIndex[variable].begin(), variableIndex[variable].end()); }
|
||||
|
||||
// Add the factors themselves to involvedFactors and update largest index
|
||||
involvedFactors.reserve(involvedFactorIndices.size());
|
||||
BOOST_FOREACH(size_t factorIndex, involvedFactorIndices) {
|
||||
const sharedFactor factor = this->at(factorIndex);
|
||||
involvedFactors.push_back(factor); // Add involved factor
|
||||
highestInvolvedVariable = std::max( // Updated largest index
|
||||
highestInvolvedVariable,
|
||||
*std::max_element(factor->begin(), factor->end()));
|
||||
}
|
||||
|
||||
sharedConditional conditional;
|
||||
sharedFactor remainingFactor;
|
||||
if(involvedFactors.size() > 0) {
|
||||
// Now permute the variables to be eliminated to the front of the ordering
|
||||
Permutation toFront = Permutation::PullToFront(variables, highestInvolvedVariable+1);
|
||||
Permutation toFrontInverse = *toFront.inverse();
|
||||
BOOST_FOREACH(const sharedFactor& factor, involvedFactors) {
|
||||
factor->permuteWithInverse(toFrontInverse); }
|
||||
|
||||
// Eliminate into conditional and remaining factor
|
||||
EliminationResult eliminated = eliminateFcn(involvedFactors, variables.size());
|
||||
conditional = eliminated.first;
|
||||
remainingFactor = eliminated.second;
|
||||
|
||||
// Undo the permutation
|
||||
BOOST_FOREACH(const sharedFactor& factor, involvedFactors) {
|
||||
factor->permuteWithInverse(toFront); }
|
||||
conditional->permuteWithInverse(toFront);
|
||||
remainingFactor->permuteWithInverse(toFront);
|
||||
} else {
|
||||
// Eliminate 0 variables
|
||||
EliminationResult eliminated = eliminateFcn(involvedFactors, 0);
|
||||
conditional = eliminated.first;
|
||||
remainingFactor = eliminated.second;
|
||||
}
|
||||
|
||||
// Build the remaining graph, without the removed factors
|
||||
FactorGraphOrdered<FACTOR> remainingGraph;
|
||||
remainingGraph.reserve(this->size() - involvedFactors.size() + 1);
|
||||
FastSet<size_t>::const_iterator involvedFactorIndexIt = involvedFactorIndices.begin();
|
||||
for(size_t i = 0; i < this->size(); ++i) {
|
||||
if(involvedFactorIndexIt != involvedFactorIndices.end() && *involvedFactorIndexIt == i)
|
||||
++ involvedFactorIndexIt;
|
||||
else
|
||||
remainingGraph.push_back(this->at(i));
|
||||
}
|
||||
|
||||
// Add the remaining factor if it is not empty.
|
||||
if(remainingFactor->size() != 0)
|
||||
remainingGraph.push_back(remainingFactor);
|
||||
|
||||
return std::make_pair(conditional, remainingGraph);
|
||||
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
void FactorGraphOrdered<FACTOR>::replace(size_t index, sharedFactor factor) {
|
||||
if (index >= factors_.size()) throw std::invalid_argument(boost::str(
|
||||
boost::format("Factor graph does not contain a factor with index %d.")
|
||||
% index));
|
||||
// Replace the factor
|
||||
factors_[index] = factor;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTORGRAPH>
|
||||
FACTORGRAPH combine(const FACTORGRAPH& fg1, const FACTORGRAPH& fg2) {
|
||||
// create new linear factor graph equal to the first one
|
||||
FACTORGRAPH fg = fg1;
|
||||
|
||||
// add the second factors_ in the graph
|
||||
fg.push_back(fg2);
|
||||
|
||||
return fg;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class DERIVEDFACTOR, class KEY>
|
||||
typename DERIVEDFACTOR::shared_ptr Combine(const FactorGraphOrdered<DERIVEDFACTOR>& factors,
|
||||
const FastMap<KEY, std::vector<KEY> >& variableSlots) {
|
||||
|
||||
typedef const std::pair<const KEY, std::vector<KEY> > KeySlotPair;
|
||||
// Local functional for getting keys out of key-value pairs
|
||||
struct Local { static KEY FirstOf(const KeySlotPair& pr) { return pr.first; } };
|
||||
|
||||
return typename DERIVEDFACTOR::shared_ptr(new DERIVEDFACTOR(
|
||||
boost::make_transform_iterator(variableSlots.begin(), &Local::FirstOf),
|
||||
boost::make_transform_iterator(variableSlots.end(), &Local::FirstOf)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Recursive function to add factors in cliques to vector of factors_io
|
||||
template<class FACTOR, class CONDITIONAL, class CLIQUE>
|
||||
void _FactorGraph_BayesTree_adder(
|
||||
std::vector<typename boost::shared_ptr<FACTOR> >& factors_io,
|
||||
const typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique& clique) {
|
||||
|
||||
if(clique) {
|
||||
// Add factor from this clique
|
||||
factors_io.push_back((*clique)->toFactor());
|
||||
|
||||
// Traverse children
|
||||
typedef typename BayesTreeOrdered<CONDITIONAL,CLIQUE>::sharedClique sharedClique;
|
||||
BOOST_FOREACH(const sharedClique& child, clique->children())
|
||||
_FactorGraph_BayesTree_adder<FACTOR,CONDITIONAL,CLIQUE>(factors_io, child);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
FactorGraphOrdered<FACTOR>::FactorGraphOrdered(const BayesTreeOrdered<CONDITIONAL,CLIQUE>& bayesTree) {
|
||||
factors_.reserve(bayesTree.size());
|
||||
_FactorGraph_BayesTree_adder<FACTOR,CONDITIONAL,CLIQUE>(factors_, bayesTree.root());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,273 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 FactorGraph.h
|
||||
* @brief Factor Graph Base Class
|
||||
* @author Carlos Nieto
|
||||
* @author Christian Potthast
|
||||
* @author Michael Kaess
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/base/FastMap.h>
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <set>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declarations
|
||||
template<class CONDITIONAL, class CLIQUE> class BayesTreeOrdered;
|
||||
class VariableIndexOrdered;
|
||||
|
||||
/**
|
||||
* A factor graph is a bipartite graph with factor nodes connected to variable nodes.
|
||||
* In this class, however, only factor nodes are kept around.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class FACTOR>
|
||||
class FactorGraphOrdered {
|
||||
|
||||
public:
|
||||
|
||||
typedef FACTOR FactorType; ///< factor type
|
||||
typedef typename FACTOR::KeyType KeyType; ///< type of Keys we use to index variables with
|
||||
typedef boost::shared_ptr<FACTOR> sharedFactor; ///< Shared pointer to a factor
|
||||
typedef boost::shared_ptr<typename FACTOR::ConditionalType> sharedConditional; ///< Shared pointer to a conditional
|
||||
|
||||
typedef FactorGraphOrdered<FACTOR> This; ///< Typedef for this class
|
||||
typedef boost::shared_ptr<This> shared_ptr; ///< Shared pointer for this class
|
||||
typedef typename std::vector<sharedFactor>::iterator iterator;
|
||||
typedef typename std::vector<sharedFactor>::const_iterator const_iterator;
|
||||
|
||||
/** typedef for elimination result */
|
||||
typedef std::pair<sharedConditional, sharedFactor> EliminationResult;
|
||||
|
||||
/** typedef for an eliminate subroutine */
|
||||
typedef boost::function<EliminationResult(const This&, size_t)> Eliminate;
|
||||
|
||||
protected:
|
||||
|
||||
/** concept check, makes sure FACTOR defines print and equals */
|
||||
GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR)
|
||||
|
||||
/** Collection of factors */
|
||||
std::vector<sharedFactor> factors_;
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructor
|
||||
/// @{
|
||||
|
||||
/** Default constructor */
|
||||
FactorGraphOrdered() {}
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Constructors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* @brief Constructor from a Bayes net
|
||||
* @param bayesNet the Bayes net to convert, type CONDITIONAL must yield compatible factor
|
||||
* @return a factor graph with all the conditionals, as factors
|
||||
*/
|
||||
template<class CONDITIONAL>
|
||||
FactorGraphOrdered(const BayesNetOrdered<CONDITIONAL>& bayesNet);
|
||||
|
||||
/** convert from Bayes tree */
|
||||
template<class CONDITIONAL, class CLIQUE>
|
||||
FactorGraphOrdered(const BayesTreeOrdered<CONDITIONAL, CLIQUE>& bayesTree);
|
||||
|
||||
/** convert from a derived type */
|
||||
template<class DERIVEDFACTOR>
|
||||
FactorGraphOrdered(const FactorGraphOrdered<DERIVEDFACTOR>& factors) {
|
||||
factors_.assign(factors.begin(), factors.end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Adding Factors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Reserve space for the specified number of factors if you know in
|
||||
* advance how many there will be (works like std::vector::reserve).
|
||||
*/
|
||||
void reserve(size_t size) { factors_.reserve(size); }
|
||||
|
||||
/** Add a factor */
|
||||
template<class DERIVEDFACTOR>
|
||||
void push_back(const boost::shared_ptr<DERIVEDFACTOR>& factor) {
|
||||
factors_.push_back(boost::shared_ptr<FACTOR>(factor));
|
||||
}
|
||||
|
||||
/** push back many factors */
|
||||
void push_back(const This& factors) {
|
||||
factors_.insert(end(), factors.begin(), factors.end());
|
||||
}
|
||||
|
||||
/** push back many factors with an iterator */
|
||||
template<typename ITERATOR>
|
||||
void push_back(ITERATOR firstFactor, ITERATOR lastFactor) {
|
||||
factors_.insert(end(), firstFactor, lastFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add a vector of derived factors
|
||||
* @param factors to add
|
||||
*/
|
||||
template<typename DERIVEDFACTOR>
|
||||
void push_back(const std::vector<typename boost::shared_ptr<DERIVEDFACTOR> >& factors) {
|
||||
factors_.insert(end(), factors.begin(), factors.end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** print out graph */
|
||||
void print(const std::string& s = "FactorGraph",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** Check equality */
|
||||
bool equals(const This& fg, double tol = 1e-9) const;
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** return the number of factors and NULLS */
|
||||
size_t size() const { return factors_.size();}
|
||||
|
||||
/** Simple check for an empty graph - faster than comparing size() to zero */
|
||||
bool empty() const { return factors_.empty(); }
|
||||
|
||||
/** const cast to the underlying vector of factors */
|
||||
operator const std::vector<sharedFactor>&() const { return factors_; }
|
||||
|
||||
/** Get a specific factor by index */
|
||||
const sharedFactor at(size_t i) const { assert(i<factors_.size()); return factors_[i]; }
|
||||
sharedFactor& at(size_t i) { assert(i<factors_.size()); return factors_[i]; }
|
||||
const sharedFactor operator[](size_t i) const { return at(i); }
|
||||
sharedFactor& operator[](size_t i) { return at(i); }
|
||||
|
||||
/** Checks whether a valid factor exists at the given index */
|
||||
inline bool exists(size_t i) const { return i<factors_.size() && factors_[i]; }
|
||||
|
||||
/** STL begin, so we can use BOOST_FOREACH */
|
||||
const_iterator begin() const { return factors_.begin();}
|
||||
|
||||
/** STL end, so we can use BOOST_FOREACH */
|
||||
const_iterator end() const { return factors_.end(); }
|
||||
|
||||
/** Get the first factor */
|
||||
sharedFactor front() const { return factors_.front(); }
|
||||
|
||||
/** Get the last factor */
|
||||
sharedFactor back() const { return factors_.back(); }
|
||||
|
||||
/** Eliminate the first \c n frontal variables, returning the resulting
|
||||
* conditional and remaining factor graph - this is very inefficient for
|
||||
* eliminating all variables, to do that use EliminationTree or
|
||||
* JunctionTree.
|
||||
*/
|
||||
std::pair<sharedConditional, FactorGraphOrdered<FactorType> > eliminateFrontals(size_t nFrontals, const Eliminate& eliminate) const;
|
||||
|
||||
/** Factor the factor graph into a conditional and a remaining factor graph.
|
||||
* Given the factor graph \f$ f(X) \f$, and \c variables to factorize out
|
||||
* \f$ V \f$, this function factorizes into \f$ f(X) = f(V;Y)f(Y) \f$, where
|
||||
* \f$ Y := X\V \f$ are the remaining variables. If \f$ f(X) = p(X) \f$ is
|
||||
* a probability density or likelihood, the factorization produces a
|
||||
* conditional probability density and a marginal \f$ p(X) = p(V|Y)p(Y) \f$.
|
||||
*
|
||||
* For efficiency, this function treats the variables to eliminate
|
||||
* \c variables as fully-connected, so produces a dense (fully-connected)
|
||||
* conditional on all of the variables in \c variables, instead of a sparse
|
||||
* BayesNet. If the variables are not fully-connected, it is more efficient
|
||||
* to sequentially factorize multiple times.
|
||||
*/
|
||||
std::pair<sharedConditional, FactorGraphOrdered<FactorType> > eliminate(
|
||||
const std::vector<KeyType>& variables, const Eliminate& eliminateFcn,
|
||||
boost::optional<const VariableIndexOrdered&> variableIndex = boost::none) const;
|
||||
|
||||
/** Eliminate a single variable, by calling FactorGraph::eliminate. */
|
||||
std::pair<sharedConditional, FactorGraphOrdered<FactorType> > eliminateOne(
|
||||
KeyType variable, const Eliminate& eliminateFcn,
|
||||
boost::optional<const VariableIndexOrdered&> variableIndex = boost::none) const {
|
||||
std::vector<size_t> variables(1, variable);
|
||||
return eliminate(variables, eliminateFcn, variableIndex);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Modifying Factor Graphs (imperative, discouraged)
|
||||
/// @{
|
||||
|
||||
/** non-const STL-style begin() */
|
||||
iterator begin() { return factors_.begin();}
|
||||
|
||||
/** non-const STL-style end() */
|
||||
iterator end() { return factors_.end(); }
|
||||
|
||||
/** resize the factor graph. TODO: effects? */
|
||||
void resize(size_t size) { factors_.resize(size); }
|
||||
|
||||
/** delete factor without re-arranging indexes by inserting a NULL pointer */
|
||||
inline void remove(size_t i) { factors_[i].reset();}
|
||||
|
||||
/** replace a factor by index */
|
||||
void replace(size_t index, sharedFactor factor);
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/** return the number valid factors */
|
||||
size_t nrFactors() const;
|
||||
|
||||
/** Potentially very slow function to return all keys involved */
|
||||
std::set<KeyType> keys() const;
|
||||
|
||||
private:
|
||||
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_NVP(factors_);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
}; // FactorGraph
|
||||
|
||||
/** Create a combined joint factor (new style for EliminationTree). */
|
||||
template<class DERIVEDFACTOR, class KEY>
|
||||
typename DERIVEDFACTOR::shared_ptr Combine(const FactorGraphOrdered<DERIVEDFACTOR>& factors,
|
||||
const FastMap<KEY, std::vector<KEY> >& variableSlots);
|
||||
|
||||
/**
|
||||
* static function that combines two factor graphs
|
||||
* @param fg1 Linear factor graph
|
||||
* @param fg2 Linear factor graph
|
||||
* @return a new combined factor graph
|
||||
*/
|
||||
template<class FACTORGRAPH>
|
||||
FACTORGRAPH combine(const FACTORGRAPH& fg1, const FACTORGRAPH& fg2);
|
||||
|
||||
} // namespace gtsam
|
||||
|
||||
#include <gtsam/inference/FactorGraphOrdered-inl.h>
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 Factor-inl.h
|
||||
* @author Richard Roberts
|
||||
* @date Sep 1, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/FactorOrdered.h>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
FactorOrdered<KEY>::FactorOrdered(const FactorOrdered<KEY>& f) :
|
||||
keys_(f.keys_) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
FactorOrdered<KEY>::FactorOrdered(const ConditionalType& c) :
|
||||
keys_(c.keys()) {
|
||||
// assert(c.nrFrontals() == 1);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
void FactorOrdered<KEY>::assertInvariants() const {
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
// Check that keys are all unique
|
||||
std::multiset<KeyType> nonunique(keys_.begin(), keys_.end());
|
||||
std::set<KeyType> unique(keys_.begin(), keys_.end());
|
||||
bool correct = (nonunique.size() == unique.size())
|
||||
&& std::equal(nonunique.begin(), nonunique.end(), unique.begin());
|
||||
if (!correct) throw std::logic_error(
|
||||
"Factor::assertInvariants: Factor contains duplicate keys");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
void FactorOrdered<KEY>::print(const std::string& s,
|
||||
const IndexFormatter& formatter) const {
|
||||
printKeys(s,formatter);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
void FactorOrdered<KEY>::printKeys(const std::string& s, const IndexFormatter& formatter) const {
|
||||
std::cout << s << " ";
|
||||
BOOST_FOREACH(KEY key, keys_) std::cout << " " << formatter(key);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
bool FactorOrdered<KEY>::equals(const This& other, double tol) const {
|
||||
return keys_ == other.keys_;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
#ifdef TRACK_ELIMINATE
|
||||
template<typename KEY>
|
||||
template<class COND>
|
||||
typename COND::shared_ptr FactorOrdered<KEY>::eliminateFirst() {
|
||||
assert(!keys_.empty());
|
||||
assertInvariants();
|
||||
KEY eliminated = keys_.front();
|
||||
keys_.erase(keys_.begin());
|
||||
assertInvariants();
|
||||
return typename COND::shared_ptr(new COND(eliminated, keys_));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename KEY>
|
||||
template<class COND>
|
||||
typename BayesNetOrdered<COND>::shared_ptr FactorOrdered<KEY>::eliminate(size_t nrFrontals) {
|
||||
assert(keys_.size() >= nrFrontals);
|
||||
assertInvariants();
|
||||
typename BayesNetOrdered<COND>::shared_ptr fragment(new BayesNetOrdered<COND> ());
|
||||
const_iterator it = this->begin();
|
||||
for (KEY n = 0; n < nrFrontals; ++n, ++it)
|
||||
fragment->push_back(COND::FromRange(it, const_iterator(this->end()), 1));
|
||||
if (nrFrontals > 0) keys_.assign(fragment->back()->beginParents(),
|
||||
fragment->back()->endParents());
|
||||
assertInvariants();
|
||||
return fragment;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 Factor.h
|
||||
* @brief The base class for all factors
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
* @author Richard Roberts
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/function/function1.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/base/FastMap.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
template<class KEY> class ConditionalOrdered;
|
||||
|
||||
/**
|
||||
* This is the base class for all factor types. It is templated on a KEY type,
|
||||
* which will be the type used to label variables. Key types currently in use
|
||||
* in gtsam are Index with symbolic (IndexFactor, SymbolicFactorGraph) and
|
||||
* Gaussian factors (GaussianFactor, JacobianFactor, HessianFactor, GaussianFactorGraph),
|
||||
* and Key with nonlinear factors (NonlinearFactor, NonlinearFactorGraph).
|
||||
* though currently only IndexFactor and IndexConditional derive from this
|
||||
* class, using Index keys. This class does not store any data other than its
|
||||
* keys. Derived classes store data such as matrices and probability tables.
|
||||
*
|
||||
* Note that derived classes *must* redefine the ConditionalType and shared_ptr
|
||||
* typedefs to refer to the associated conditional and shared_ptr types of the
|
||||
* derived class. See IndexFactor, JacobianFactor, etc. for examples.
|
||||
*
|
||||
* This class is \b not virtual for performance reasons - derived symbolic classes,
|
||||
* IndexFactor and IndexConditional, need to be created and destroyed quickly
|
||||
* during symbolic elimination. GaussianFactor and NonlinearFactor are virtual.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<typename KEY>
|
||||
class FactorOrdered {
|
||||
|
||||
public:
|
||||
|
||||
typedef KEY KeyType; ///< The KEY template parameter
|
||||
typedef FactorOrdered<KeyType> This; ///< This class
|
||||
|
||||
/**
|
||||
* Typedef to the conditional type obtained by eliminating this factor,
|
||||
* derived classes must redefine this.
|
||||
*/
|
||||
typedef ConditionalOrdered<KeyType> ConditionalType;
|
||||
|
||||
/// A shared_ptr to this class, derived classes must redefine this.
|
||||
typedef boost::shared_ptr<FactorOrdered> shared_ptr;
|
||||
|
||||
/// Iterator over keys
|
||||
typedef typename std::vector<KeyType>::iterator iterator;
|
||||
|
||||
/// Const iterator over keys
|
||||
typedef typename std::vector<KeyType>::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
|
||||
/// The keys involved in this factor
|
||||
std::vector<KeyType> keys_;
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Copy constructor */
|
||||
FactorOrdered(const This& f);
|
||||
|
||||
/** Construct from conditional, calls ConditionalType::toFactor() */
|
||||
FactorOrdered(const ConditionalType& c);
|
||||
|
||||
/** Default constructor for I/O */
|
||||
FactorOrdered() {}
|
||||
|
||||
/** Construct unary factor */
|
||||
FactorOrdered(KeyType key) : keys_(1) {
|
||||
keys_[0] = key; assertInvariants(); }
|
||||
|
||||
/** Construct binary factor */
|
||||
FactorOrdered(KeyType key1, KeyType key2) : keys_(2) {
|
||||
keys_[0] = key1; keys_[1] = key2; assertInvariants(); }
|
||||
|
||||
/** Construct ternary factor */
|
||||
FactorOrdered(KeyType key1, KeyType key2, KeyType key3) : keys_(3) {
|
||||
keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; assertInvariants(); }
|
||||
|
||||
/** Construct 4-way factor */
|
||||
FactorOrdered(KeyType key1, KeyType key2, KeyType key3, KeyType key4) : keys_(4) {
|
||||
keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; assertInvariants(); }
|
||||
|
||||
/** Construct 5-way factor */
|
||||
FactorOrdered(KeyType key1, KeyType key2, KeyType key3, KeyType key4, KeyType key5) : keys_(5) {
|
||||
keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; keys_[4] = key5; assertInvariants(); }
|
||||
|
||||
/** Construct 6-way factor */
|
||||
FactorOrdered(KeyType key1, KeyType key2, KeyType key3, KeyType key4, KeyType key5, KeyType key6) : keys_(6) {
|
||||
keys_[0] = key1; keys_[1] = key2; keys_[2] = key3; keys_[3] = key4; keys_[4] = key5; keys_[5] = key6; assertInvariants(); }
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Constructors
|
||||
/// @{
|
||||
|
||||
/** Construct n-way factor */
|
||||
FactorOrdered(const std::set<KeyType>& keys) {
|
||||
BOOST_FOREACH(const KeyType& key, keys) keys_.push_back(key);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct n-way factor */
|
||||
FactorOrdered(const std::vector<KeyType>& keys) : keys_(keys) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Constructor from a collection of keys */
|
||||
template<class KEYITERATOR> FactorOrdered(KEYITERATOR beginKey, KEYITERATOR endKey) :
|
||||
keys_(beginKey, endKey) { assertInvariants(); }
|
||||
|
||||
/// @}
|
||||
|
||||
#ifdef TRACK_ELIMINATE
|
||||
/**
|
||||
* eliminate the first variable involved in this factor
|
||||
* @return a conditional on the eliminated variable
|
||||
*/
|
||||
template<class CONDITIONAL>
|
||||
typename CONDITIONAL::shared_ptr eliminateFirst();
|
||||
|
||||
/**
|
||||
* eliminate the first nrFrontals frontal variables.
|
||||
*/
|
||||
template<class CONDITIONAL>
|
||||
typename BayesNetOrdered<CONDITIONAL>::shared_ptr eliminate(size_t nrFrontals = 1);
|
||||
#endif
|
||||
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/// First key
|
||||
KeyType front() const { return keys_.front(); }
|
||||
|
||||
/// Last key
|
||||
KeyType back() const { return keys_.back(); }
|
||||
|
||||
/// find
|
||||
const_iterator find(KeyType key) const { return std::find(begin(), end(), key); }
|
||||
|
||||
/// Access the factor's involved variable keys
|
||||
const std::vector<KeyType>& keys() const { return keys_; }
|
||||
|
||||
/** iterators */
|
||||
const_iterator begin() const { return keys_.begin(); } ///TODO: comment
|
||||
const_iterator end() const { return keys_.end(); } ///TODO: comment
|
||||
|
||||
/**
|
||||
* @return the number of variables involved in this factor
|
||||
*/
|
||||
size_t size() const { return keys_.size(); }
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/// print
|
||||
void print(const std::string& s = "Factor",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/// print only keys
|
||||
void printKeys(const std::string& s = "Factor",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/// check equality
|
||||
bool equals(const This& other, double tol = 1e-9) const;
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* @return keys involved in this factor
|
||||
*/
|
||||
std::vector<KeyType>& keys() { return keys_; }
|
||||
|
||||
/** mutable iterators */
|
||||
iterator begin() { return keys_.begin(); } ///TODO: comment
|
||||
iterator end() { return keys_.end(); } ///TODO: comment
|
||||
|
||||
protected:
|
||||
friend class JacobianFactorOrdered;
|
||||
friend class HessianFactorOrdered;
|
||||
|
||||
/// Internal consistency check that is run frequently when in debug mode.
|
||||
/// If NDEBUG is defined, this is empty and optimized out.
|
||||
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(keys_);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <gtsam/inference/FactorOrdered-inl.h>
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GenericMultifrontalSolver-inl.h
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/FactorOrdered-inl.h>
|
||||
#include <gtsam/inference/JunctionTreeOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered-inl.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class F, class JT>
|
||||
GenericMultifrontalSolver<F, JT>::GenericMultifrontalSolver(
|
||||
const FactorGraphOrdered<F>& graph) :
|
||||
structure_(new VariableIndexOrdered(graph)), junctionTree_(
|
||||
new JT(graph, *structure_)) {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class F, class JT>
|
||||
GenericMultifrontalSolver<F, JT>::GenericMultifrontalSolver(
|
||||
const sharedGraph& graph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex) :
|
||||
structure_(variableIndex), junctionTree_(new JT(*graph, *structure_)) {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class F, class JT>
|
||||
void GenericMultifrontalSolver<F, JT>::print(const std::string& s) const {
|
||||
this->structure_->print(s + " structure:\n");
|
||||
this->junctionTree_->print(s + " jtree:");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class F, class JT>
|
||||
bool GenericMultifrontalSolver<F, JT>::equals(
|
||||
const GenericMultifrontalSolver& expected, double tol) const {
|
||||
if (!this->structure_->equals(*expected.structure_, tol)) return false;
|
||||
if (!this->junctionTree_->equals(*expected.junctionTree_, tol)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class F, class JT>
|
||||
void GenericMultifrontalSolver<F, JT>::replaceFactors(const sharedGraph& graph) {
|
||||
junctionTree_.reset(new JT(*graph, *structure_));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR, class JUNCTIONTREE>
|
||||
typename BayesTreeOrdered<typename FACTOR::ConditionalType>::shared_ptr
|
||||
GenericMultifrontalSolver<FACTOR, JUNCTIONTREE>::eliminate(Eliminate function) const {
|
||||
|
||||
// eliminate junction tree, returns pointer to root
|
||||
typename BayesTreeOrdered<typename FACTOR::ConditionalType>::sharedClique
|
||||
root = junctionTree_->eliminate(function);
|
||||
|
||||
// create an empty Bayes tree and insert root clique
|
||||
typename BayesTreeOrdered<typename FACTOR::ConditionalType>::shared_ptr
|
||||
bayesTree(new BayesTreeOrdered<typename FACTOR::ConditionalType>);
|
||||
bayesTree->insert(root);
|
||||
|
||||
// return the Bayes tree
|
||||
return bayesTree;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class F, class JT>
|
||||
typename FactorGraphOrdered<F>::shared_ptr GenericMultifrontalSolver<F, JT>::jointFactorGraph(
|
||||
const std::vector<Index>& js, Eliminate function) const {
|
||||
|
||||
// FIXME: joint for arbitrary sets of variables not present
|
||||
// TODO: develop and implement theory for shortcuts of more than two variables
|
||||
|
||||
if (js.size() != 2) throw std::domain_error(
|
||||
"*MultifrontalSolver::joint(js) currently can only compute joint marginals\n"
|
||||
"for exactly two variables. You can call marginal to compute the\n"
|
||||
"marginal for one variable. *SequentialSolver::joint(js) can compute the\n"
|
||||
"joint marginal over any number of variables, so use that if necessary.\n");
|
||||
|
||||
return eliminate(function)->joint(js[0], js[1], function);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class F, class JT>
|
||||
typename boost::shared_ptr<F> GenericMultifrontalSolver<F, JT>::marginalFactor(
|
||||
Index j, Eliminate function) const {
|
||||
return eliminate(function)->marginalFactor(j, function);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GenericMultifrontalSolver.h
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <gtsam/inference/JunctionTreeOrdered.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* A Generic Multifrontal Solver class
|
||||
*
|
||||
* A solver is given a factor graph at construction, and implements
|
||||
* a strategy to solve it (in this case, eliminate into a Bayes tree).
|
||||
* This generic one will create a Bayes tree when eliminate() is called.
|
||||
*
|
||||
* Takes two template arguments:
|
||||
* FACTOR the factor type, e.g., GaussianFactor, DiscreteFactor
|
||||
* JUNCTIONTREE annoyingly, you also have to supply a compatible JT type
|
||||
* i.e., one templated on a factor graph with the same factors
|
||||
* TODO: figure why this is so and possibly fix it
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class FACTOR, class JUNCTIONTREE>
|
||||
class GenericMultifrontalSolver {
|
||||
|
||||
protected:
|
||||
|
||||
/// Column structure of the factor graph
|
||||
VariableIndexOrdered::shared_ptr structure_;
|
||||
|
||||
/// Junction tree that performs elimination.
|
||||
typename JUNCTIONTREE::shared_ptr junctionTree_;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename FactorGraphOrdered<FACTOR>::shared_ptr sharedGraph;
|
||||
typedef typename FactorGraphOrdered<FACTOR>::Eliminate Eliminate;
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Construct the solver for a factor graph. This builds the junction
|
||||
* tree, which does the symbolic elimination, identifies the cliques,
|
||||
* and distributes all the factors to the right cliques.
|
||||
*/
|
||||
GenericMultifrontalSolver(const FactorGraphOrdered<FACTOR>& factorGraph);
|
||||
|
||||
/**
|
||||
* Construct the solver with a shared pointer to a factor graph and to a
|
||||
* VariableIndex. The solver will store these pointers, so this constructor
|
||||
* is the fastest.
|
||||
*/
|
||||
GenericMultifrontalSolver(const sharedGraph& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex);
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** Print to cout */
|
||||
void print(const std::string& name = "GenericMultifrontalSolver: ") const;
|
||||
|
||||
/** Test whether is equal to another */
|
||||
bool equals(const GenericMultifrontalSolver& other, double tol = 1e-9) const;
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Replace the factor graph with a new one having the same structure. The
|
||||
* This function can be used if the numerical part of the factors changes,
|
||||
* such as during relinearization or adjusting of noise models.
|
||||
*/
|
||||
void replaceFactors(const sharedGraph& factorGraph);
|
||||
|
||||
/**
|
||||
* Eliminate the factor graph sequentially. Uses a column elimination tree
|
||||
* to recursively eliminate.
|
||||
*/
|
||||
typename BayesTreeOrdered<typename FACTOR::ConditionalType>::shared_ptr
|
||||
eliminate(Eliminate function) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. This function returns the result as a factor
|
||||
* graph.
|
||||
*/
|
||||
typename FactorGraphOrdered<FACTOR>::shared_ptr jointFactorGraph(
|
||||
const std::vector<Index>& js, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as a factor.
|
||||
*/
|
||||
typename boost::shared_ptr<FACTOR> marginalFactor(Index j,
|
||||
Eliminate function) const;
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
} // gtsam
|
||||
|
||||
#include <gtsam/inference/GenericMultifrontalSolver-inl.h>
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GenericSequentialSolver-inl.h
|
||||
* @brief Implementation for generic sequential solver
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/FactorOrdered.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
#include <gtsam/inference/EliminationTreeOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
#include <gtsam/inference/inferenceOrdered.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
GenericSequentialSolver<FACTOR>::GenericSequentialSolver(const FactorGraphOrdered<FACTOR>& factorGraph) {
|
||||
gttic(GenericSequentialSolver_constructor1);
|
||||
assert(factorGraph.size());
|
||||
factors_.reset(new FactorGraphOrdered<FACTOR>(factorGraph));
|
||||
structure_.reset(new VariableIndexOrdered(factorGraph));
|
||||
eliminationTree_ = EliminationTreeOrdered<FACTOR>::Create(*factors_, *structure_);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
GenericSequentialSolver<FACTOR>::GenericSequentialSolver(
|
||||
const sharedFactorGraph& factorGraph,
|
||||
const boost::shared_ptr<VariableIndexOrdered>& variableIndex)
|
||||
{
|
||||
gttic(GenericSequentialSolver_constructor2);
|
||||
factors_ = factorGraph;
|
||||
structure_ = variableIndex;
|
||||
eliminationTree_ = EliminationTreeOrdered<FACTOR>::Create(*factors_, *structure_);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
void GenericSequentialSolver<FACTOR>::print(const std::string& s) const {
|
||||
this->factors_->print(s + " factors:");
|
||||
this->structure_->print(s + " structure:\n");
|
||||
this->eliminationTree_->print(s + " etree:");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
bool GenericSequentialSolver<FACTOR>::equals(
|
||||
const GenericSequentialSolver& expected, double tol) const {
|
||||
if (!this->factors_->equals(*expected.factors_, tol))
|
||||
return false;
|
||||
if (!this->structure_->equals(*expected.structure_, tol))
|
||||
return false;
|
||||
if (!this->eliminationTree_->equals(*expected.eliminationTree_, tol))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
void GenericSequentialSolver<FACTOR>::replaceFactors(
|
||||
const sharedFactorGraph& factorGraph) {
|
||||
// Reset this shared pointer first to deallocate if possible - for big
|
||||
// problems there may not be enough memory to store two copies.
|
||||
eliminationTree_.reset();
|
||||
factors_ = factorGraph;
|
||||
eliminationTree_ = EliminationTreeOrdered<FACTOR>::Create(*factors_, *structure_);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename GenericSequentialSolver<FACTOR>::sharedBayesNet //
|
||||
GenericSequentialSolver<FACTOR>::eliminate(Eliminate function) const {
|
||||
return eliminationTree_->eliminate(function);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename GenericSequentialSolver<FACTOR>::sharedBayesNet //
|
||||
GenericSequentialSolver<FACTOR>::eliminate(const Permutation& permutation,
|
||||
Eliminate function, boost::optional<size_t> nrToEliminate) const
|
||||
{
|
||||
gttic(GenericSequentialSolver_eliminate);
|
||||
// Create inverse permutation
|
||||
Permutation::shared_ptr permutationInverse(permutation.inverse());
|
||||
|
||||
// Permute the factors - NOTE that this permutes the original factors, not
|
||||
// copies. Other parts of the code may hold shared_ptr's to these factors so
|
||||
// we must undo the permutation before returning.
|
||||
BOOST_FOREACH(const typename boost::shared_ptr<FACTOR>& factor, *factors_)
|
||||
if (factor)
|
||||
factor->permuteWithInverse(*permutationInverse);
|
||||
|
||||
// Eliminate using elimination tree provided
|
||||
typename EliminationTreeOrdered<FACTOR>::shared_ptr etree = EliminationTreeOrdered<FACTOR>::Create(*factors_);
|
||||
sharedBayesNet bayesNet;
|
||||
if(nrToEliminate)
|
||||
bayesNet = etree->eliminatePartial(function, *nrToEliminate);
|
||||
else
|
||||
bayesNet = etree->eliminate(function);
|
||||
|
||||
// Undo the permutation on the original factors and on the structure.
|
||||
BOOST_FOREACH(const typename boost::shared_ptr<FACTOR>& factor, *factors_)
|
||||
if (factor)
|
||||
factor->permuteWithInverse(permutation);
|
||||
|
||||
// Undo the permutation on the conditionals
|
||||
BOOST_FOREACH(const boost::shared_ptr<Conditional>& c, *bayesNet)
|
||||
c->permuteWithInverse(permutation);
|
||||
|
||||
return bayesNet;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename GenericSequentialSolver<FACTOR>::sharedBayesNet //
|
||||
GenericSequentialSolver<FACTOR>::conditionalBayesNet(
|
||||
const std::vector<Index>& js, size_t nrFrontals,
|
||||
Eliminate function) const
|
||||
{
|
||||
gttic(GenericSequentialSolver_conditionalBayesNet);
|
||||
// Compute a COLAMD permutation with the marginal variables constrained to the end.
|
||||
// TODO in case of nrFrontals, the order of js has to be respected here !
|
||||
Permutation::shared_ptr permutation(
|
||||
inference::PermutationCOLAMD(*structure_, js, true));
|
||||
|
||||
// Eliminate only variables J \cup F from P(J,F,S) to get P(F|S)
|
||||
size_t nrVariables = structure_->size();
|
||||
size_t nrMarginalized = nrVariables - js.size();
|
||||
size_t nrToEliminate = nrMarginalized + nrFrontals;
|
||||
sharedBayesNet bayesNet = eliminate(*permutation, function, nrToEliminate);
|
||||
// Get rid of conditionals on variables that we want to marginalize out
|
||||
for (size_t i = 0; i < nrMarginalized; i++)
|
||||
bayesNet->pop_front();
|
||||
|
||||
return bayesNet;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename GenericSequentialSolver<FACTOR>::sharedBayesNet //
|
||||
GenericSequentialSolver<FACTOR>::jointBayesNet(const std::vector<Index>& js,
|
||||
Eliminate function) const
|
||||
{
|
||||
gttic(GenericSequentialSolver_jointBayesNet);
|
||||
// Compute a COLAMD permutation with the marginal variables constrained to the end.
|
||||
Permutation::shared_ptr permutation(
|
||||
inference::PermutationCOLAMD(*structure_, js));
|
||||
|
||||
// Eliminate all variables
|
||||
sharedBayesNet bayesNet = eliminate(*permutation, function);
|
||||
|
||||
// Get rid of conditionals on variables that we want to marginalize out
|
||||
size_t nrMarginalized = bayesNet->size() - js.size();
|
||||
for (size_t i = 0; i < nrMarginalized; i++)
|
||||
bayesNet->pop_front();
|
||||
|
||||
return bayesNet;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename FactorGraphOrdered<FACTOR>::shared_ptr //
|
||||
GenericSequentialSolver<FACTOR>::jointFactorGraph(
|
||||
const std::vector<Index>& js, Eliminate function) const
|
||||
{
|
||||
gttic(GenericSequentialSolver_jointFactorGraph);
|
||||
// Eliminate all variables
|
||||
typename BayesNetOrdered<Conditional>::shared_ptr bayesNet = jointBayesNet(js, function);
|
||||
|
||||
return boost::make_shared<FactorGraphOrdered<FACTOR> >(*bayesNet);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FACTOR>
|
||||
typename boost::shared_ptr<FACTOR> //
|
||||
GenericSequentialSolver<FACTOR>::marginalFactor(Index j, Eliminate function) const {
|
||||
gttic(GenericSequentialSolver_marginalFactor);
|
||||
// Create a container for the one variable index
|
||||
std::vector<Index> js(1);
|
||||
js[0] = j;
|
||||
|
||||
// Call joint and return the only factor in the factor graph it returns
|
||||
// TODO: just call jointBayesNet and grab last conditional, then toFactor....
|
||||
return (*this->jointFactorGraph(js, function))[0];
|
||||
}
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GenericSequentialSolver.h
|
||||
* @brief generic sequential elimination
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/base/Testable.h>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace gtsam {
|
||||
class VariableIndexOrdered;
|
||||
class Permutation;
|
||||
}
|
||||
namespace gtsam {
|
||||
template<class FACTOR> class EliminationTreeOrdered;
|
||||
}
|
||||
namespace gtsam {
|
||||
template<class FACTOR> class FactorGraphOrdered;
|
||||
}
|
||||
namespace gtsam {
|
||||
template<class CONDITIONAL> class BayesNetOrdered;
|
||||
}
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* This solver implements sequential variable elimination for factor graphs.
|
||||
* Underlying this is a column elimination tree, see Gilbert 2001 BIT.
|
||||
*
|
||||
* The elimination ordering is "baked in" to the variable indices at this
|
||||
* stage, i.e. elimination proceeds in order from '0'.
|
||||
*
|
||||
* This is not the most efficient algorithm we provide, most efficient is the
|
||||
* MultifrontalSolver, which examines and uses the clique structure.
|
||||
* However, sequential variable elimination is easier to understand so this is a good
|
||||
* starting point to learn about these algorithms and our implementation.
|
||||
* Additionally, the first step of MFQR is symbolic sequential elimination.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class FACTOR>
|
||||
class GenericSequentialSolver {
|
||||
|
||||
protected:
|
||||
|
||||
typedef boost::shared_ptr<FactorGraphOrdered<FACTOR> > sharedFactorGraph;
|
||||
typedef typename FACTOR::ConditionalType Conditional;
|
||||
typedef typename boost::shared_ptr<Conditional> sharedConditional;
|
||||
typedef typename boost::shared_ptr<BayesNetOrdered<Conditional> > sharedBayesNet;
|
||||
typedef std::pair<boost::shared_ptr<Conditional>, boost::shared_ptr<FACTOR> > EliminationResult;
|
||||
typedef boost::function<
|
||||
EliminationResult(const FactorGraphOrdered<FACTOR>&, size_t)> Eliminate;
|
||||
|
||||
/** Store the original factors for computing marginals
|
||||
* TODO Frank says: really? Marginals should be computed from result.
|
||||
*/
|
||||
sharedFactorGraph factors_;
|
||||
|
||||
/** Store column structure of the factor graph. Why? */
|
||||
boost::shared_ptr<VariableIndexOrdered> structure_;
|
||||
|
||||
/** Elimination tree that performs elimination */
|
||||
boost::shared_ptr<EliminationTreeOrdered<FACTOR> > eliminationTree_;
|
||||
|
||||
/** concept checks */
|
||||
GTSAM_CONCEPT_TESTABLE_TYPE(FACTOR)
|
||||
// GTSAM_CONCEPT_TESTABLE_TYPE(EliminationTreeOrdered)
|
||||
|
||||
/**
|
||||
* Eliminate in a different order, given a permutation
|
||||
*/
|
||||
sharedBayesNet eliminate(const Permutation& permutation, Eliminate function,
|
||||
boost::optional<size_t> nrToEliminate = boost::none ///< If given a number of variables to eliminate, will only eliminate that many
|
||||
) const;
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Construct the solver for a factor graph. This builds the elimination
|
||||
* tree, which already does some of the work of elimination.
|
||||
*/
|
||||
GenericSequentialSolver(const FactorGraphOrdered<FACTOR>& factorGraph);
|
||||
|
||||
/**
|
||||
* Construct the solver with a shared pointer to a factor graph and to a
|
||||
* VariableIndex. The solver will store these pointers, so this constructor
|
||||
* is the fastest.
|
||||
*/
|
||||
GenericSequentialSolver(const sharedFactorGraph& factorGraph,
|
||||
const boost::shared_ptr<VariableIndexOrdered>& variableIndex);
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** Print to cout */
|
||||
void print(const std::string& name = "GenericSequentialSolver: ") const;
|
||||
|
||||
/** Test whether is equal to another */
|
||||
bool equals(const GenericSequentialSolver& other, double tol = 1e-9) const;
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Replace the factor graph with a new one having the same structure. The
|
||||
* This function can be used if the numerical part of the factors changes,
|
||||
* such as during relinearization or adjusting of noise models.
|
||||
*/
|
||||
void replaceFactors(const sharedFactorGraph& factorGraph);
|
||||
|
||||
/**
|
||||
* Eliminate the factor graph sequentially. Uses a column elimination tree
|
||||
* to recursively eliminate.
|
||||
*/
|
||||
sharedBayesNet eliminate(Eliminate function) const;
|
||||
|
||||
/**
|
||||
* Compute a conditional density P(F|S) while marginalizing out variables J
|
||||
* P(F|S) is obtained by P(J,F,S)=P(J|F,S)P(F|S)P(S) and dropping P(S)
|
||||
* Returns the result as a Bayes net.
|
||||
*/
|
||||
sharedBayesNet
|
||||
conditionalBayesNet(const std::vector<Index>& js, size_t nrFrontals,
|
||||
Eliminate function) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. Returns the result as a Bayes net
|
||||
*/
|
||||
sharedBayesNet
|
||||
jointBayesNet(const std::vector<Index>& js, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. Returns the result as a factor graph.
|
||||
*/
|
||||
typename FactorGraphOrdered<FACTOR>::shared_ptr
|
||||
jointFactorGraph(const std::vector<Index>& js, Eliminate function) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal Gaussian density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as a factor.
|
||||
*/
|
||||
typename boost::shared_ptr<FACTOR>
|
||||
marginalFactor(Index j, Eliminate function) const;
|
||||
|
||||
/// @}
|
||||
|
||||
}
|
||||
;
|
||||
// GenericSequentialSolver
|
||||
|
||||
}// namespace gtsam
|
||||
|
||||
#include <gtsam/inference/GenericSequentialSolver-inl.h>
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 ISAM-inl.h
|
||||
* @brief Incremental update functionality (iSAM) for BayesTree.
|
||||
* @author Michael Kaess
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
|
||||
#include <gtsam/inference/ConditionalOrdered.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
#include <gtsam/inference/GenericMultifrontalSolver.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
ISAMOrdered<CONDITIONAL>::ISAMOrdered() : BayesTreeOrdered<CONDITIONAL>() {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
template<class FG> void ISAMOrdered<CONDITIONAL>::update_internal(
|
||||
const FG& newFactors, Cliques& orphans, typename FG::Eliminate function) {
|
||||
|
||||
// Remove the contaminated part of the Bayes tree
|
||||
// Throw exception if disconnected
|
||||
BayesNetOrdered<CONDITIONAL> bn;
|
||||
if (!this->empty()) {
|
||||
this->removeTop(newFactors.keys(), bn, orphans);
|
||||
if (bn.empty())
|
||||
throw std::runtime_error(
|
||||
"ISAM::update_internal(): no variables in common between existing Bayes tree and incoming factors!");
|
||||
}
|
||||
FG factors(bn);
|
||||
|
||||
// add the factors themselves
|
||||
factors.push_back(newFactors);
|
||||
|
||||
// eliminate into a Bayes net
|
||||
GenericMultifrontalSolver<typename CONDITIONAL::FactorType, JunctionTreeOrdered<FG> > solver(factors);
|
||||
boost::shared_ptr<BayesTreeOrdered<CONDITIONAL> > bayesTree;
|
||||
bayesTree = solver.eliminate(function);
|
||||
this->root_ = bayesTree->root();
|
||||
this->nodes_ = bayesTree->nodes();
|
||||
|
||||
// add orphans to the bottom of the new tree
|
||||
BOOST_FOREACH(sharedClique orphan, orphans)
|
||||
this->insert(orphan);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONDITIONAL>
|
||||
template<class FG>
|
||||
void ISAMOrdered<CONDITIONAL>::update(const FG& newFactors,
|
||||
typename FG::Eliminate function) {
|
||||
Cliques orphans;
|
||||
this->update_internal(newFactors, orphans, function);
|
||||
}
|
||||
|
||||
}
|
||||
/// namespace gtsam
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 ISAM.h
|
||||
* @brief Incremental update functionality (iSAM) for BayesTree.
|
||||
* @author Michael Kaess
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* A Bayes tree with an update methods that implements the iSAM algorithm.
|
||||
* Given a set of new factors, it re-eliminates the invalidated part of the tree.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class CONDITIONAL>
|
||||
class ISAMOrdered: public BayesTreeOrdered<CONDITIONAL> {
|
||||
|
||||
private:
|
||||
|
||||
typedef BayesTreeOrdered<CONDITIONAL> Base;
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Create an empty Bayes Tree */
|
||||
ISAMOrdered();
|
||||
|
||||
/** Copy constructor */
|
||||
ISAMOrdered(const Base& bayesTree) :
|
||||
Base(bayesTree) {
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* update the Bayes tree with a set of new factors, typically derived from measurements
|
||||
* @param newFactors is a factor graph that contains the new factors
|
||||
* @param function an elimination routine
|
||||
*/
|
||||
template<class FG>
|
||||
void update(const FG& newFactors, typename FG::Eliminate function);
|
||||
|
||||
typedef typename BayesTreeOrdered<CONDITIONAL>::sharedClique sharedClique; ///<TODO: comment
|
||||
typedef typename BayesTreeOrdered<CONDITIONAL>::Cliques Cliques; ///<TODO: comment
|
||||
|
||||
/** update_internal provides access to list of orphans for drawing purposes */
|
||||
template<class FG>
|
||||
void update_internal(const FG& newFactors, Cliques& orphans,
|
||||
typename FG::Eliminate function);
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
}/// namespace gtsam
|
||||
|
||||
#include <gtsam/inference/ISAMOrdered-inl.h>
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 IndexConditional.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 17, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/base/FastSet.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::lambda;
|
||||
|
||||
/* ************************************************************************* */
|
||||
void IndexConditionalOrdered::assertInvariants() const {
|
||||
// Checks for uniqueness of keys
|
||||
Base::assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool IndexConditionalOrdered::reduceSeparatorWithInverse(const internal::Reduction& inverseReduction) {
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
BOOST_FOREACH(KeyType key, frontals()) { assert(inverseReduction.find(key) == inverseReduction.end()); }
|
||||
#endif
|
||||
bool parentChanged = false;
|
||||
BOOST_FOREACH(KeyType& parent, parents()) {
|
||||
internal::Reduction::const_iterator it = inverseReduction.find(parent);
|
||||
if(it != inverseReduction.end()) {
|
||||
parentChanged = true;
|
||||
parent = it->second;
|
||||
}
|
||||
}
|
||||
assertInvariants();
|
||||
return parentChanged;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void IndexConditionalOrdered::permuteWithInverse(const Permutation& inversePermutation) {
|
||||
BOOST_FOREACH(Index& key, keys())
|
||||
key = inversePermutation[key];
|
||||
assertInvariants();
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 IndexConditional.h
|
||||
* @author Richard Roberts
|
||||
* @date Oct 17, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/inference/ConditionalOrdered.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* IndexConditional serves two purposes. It is the base class for
|
||||
* GaussianConditional, and also functions as a symbolic conditional with
|
||||
* Index keys, produced by symbolic elimination of IndexFactor.
|
||||
*
|
||||
* It derives from Conditional with a key type of Index, which is an
|
||||
* unsigned integer.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
class IndexConditionalOrdered : public ConditionalOrdered<Index> {
|
||||
|
||||
protected:
|
||||
|
||||
// Checks that frontal indices are sorted and lower than parent indices
|
||||
GTSAM_EXPORT void assertInvariants() const;
|
||||
|
||||
public:
|
||||
|
||||
typedef IndexConditionalOrdered This;
|
||||
typedef ConditionalOrdered<Index> Base;
|
||||
typedef IndexFactorOrdered FactorType;
|
||||
typedef boost::shared_ptr<IndexConditionalOrdered> shared_ptr;
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Empty Constructor to make serialization possible */
|
||||
IndexConditionalOrdered() { assertInvariants(); }
|
||||
|
||||
/** No parents */
|
||||
IndexConditionalOrdered(Index j) : Base(j) { assertInvariants(); }
|
||||
|
||||
/** Single parent */
|
||||
IndexConditionalOrdered(Index j, Index parent) : Base(j, parent) { assertInvariants(); }
|
||||
|
||||
/** Two parents */
|
||||
IndexConditionalOrdered(Index j, Index parent1, Index parent2) : Base(j, parent1, parent2) { assertInvariants(); }
|
||||
|
||||
/** Three parents */
|
||||
IndexConditionalOrdered(Index j, Index parent1, Index parent2, Index parent3) : Base(j, parent1, parent2, parent3) { assertInvariants(); }
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Constructors
|
||||
/// @{
|
||||
|
||||
/** Constructor from a frontal variable and a vector of parents */
|
||||
IndexConditionalOrdered(Index j, const std::vector<Index>& parents) : Base(j, parents) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Constructor from keys and nr of frontal variables */
|
||||
IndexConditionalOrdered(const std::vector<Index>& keys, size_t nrFrontals) :
|
||||
Base(keys, nrFrontals) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Constructor from keys and nr of frontal variables */
|
||||
IndexConditionalOrdered(const std::list<Index>& keys, size_t nrFrontals) :
|
||||
Base(keys, nrFrontals) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** Named constructor directly returning a shared pointer */
|
||||
template<class KEYS>
|
||||
static shared_ptr FromKeys(const KEYS& keys, size_t nrFrontals) {
|
||||
shared_ptr conditional(new IndexConditionalOrdered());
|
||||
conditional->keys_.assign(keys.begin(), keys.end());
|
||||
conditional->nrFrontals_ = nrFrontals;
|
||||
return conditional;
|
||||
}
|
||||
|
||||
/** Convert to a factor */
|
||||
IndexFactorOrdered::shared_ptr toFactor() const {
|
||||
return IndexFactorOrdered::shared_ptr(new IndexFactorOrdered(*this));
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
GTSAM_EXPORT bool reduceSeparatorWithInverse(const internal::Reduction& inverseReduction);
|
||||
|
||||
/**
|
||||
* Permutes the Conditional, but for efficiency requires the permutation
|
||||
* to already be inverted.
|
||||
*/
|
||||
GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 IndexFactor.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 17, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
#include <gtsam/inference/FactorOrdered.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
void IndexFactorOrdered::assertInvariants() const {
|
||||
Base::assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
IndexFactorOrdered::IndexFactorOrdered(const IndexConditionalOrdered& c) :
|
||||
Base(c) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
#ifdef TRACK_ELIMINATE
|
||||
boost::shared_ptr<IndexConditionalOrdered> IndexFactorOrdered::eliminateFirst() {
|
||||
boost::shared_ptr<IndexConditionalOrdered> result(Base::eliminateFirst<
|
||||
IndexConditionalOrdered>());
|
||||
assertInvariants();
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
boost::shared_ptr<BayesNetOrdered<IndexConditionalOrdered> > IndexFactorOrdered::eliminate(
|
||||
size_t nrFrontals) {
|
||||
boost::shared_ptr<BayesNetOrdered<IndexConditionalOrdered> > result(Base::eliminate<
|
||||
IndexConditionalOrdered>(nrFrontals));
|
||||
assertInvariants();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ************************************************************************* */
|
||||
void IndexFactorOrdered::permuteWithInverse(const Permutation& inversePermutation) {
|
||||
BOOST_FOREACH(Index& key, keys())
|
||||
key = inversePermutation[key];
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void IndexFactorOrdered::reduceWithInverse(const internal::Reduction& inverseReduction) {
|
||||
BOOST_FOREACH(Index& key, keys())
|
||||
key = inverseReduction[key];
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
} // gtsam
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 IndexFactor.h
|
||||
* @author Richard Roberts
|
||||
* @date Oct 17, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/FactorOrdered.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declaration of IndexConditional
|
||||
class IndexConditionalOrdered;
|
||||
|
||||
/**
|
||||
* IndexFactor serves two purposes. It is the base class for all linear
|
||||
* factors (GaussianFactor, JacobianFactor, HessianFactor), and also
|
||||
* functions as a symbolic factor with Index keys, used to do symbolic
|
||||
* elimination by JunctionTree.
|
||||
*
|
||||
* It derives from Factor with a key type of Index, an unsigned integer.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
class IndexFactorOrdered: public FactorOrdered<Index> {
|
||||
|
||||
protected:
|
||||
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/// Internal function for checking class invariants (unique keys for this factor)
|
||||
GTSAM_EXPORT void assertInvariants() const;
|
||||
|
||||
/// @}
|
||||
|
||||
public:
|
||||
|
||||
typedef IndexFactorOrdered This;
|
||||
typedef FactorOrdered<Index> Base;
|
||||
|
||||
/** Elimination produces an IndexConditional */
|
||||
typedef IndexConditionalOrdered ConditionalType;
|
||||
|
||||
/** Overriding the shared_ptr typedef */
|
||||
typedef boost::shared_ptr<IndexFactorOrdered> shared_ptr;
|
||||
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** Copy constructor */
|
||||
IndexFactorOrdered(const This& f) :
|
||||
Base(f) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct from derived type */
|
||||
GTSAM_EXPORT IndexFactorOrdered(const IndexConditionalOrdered& c);
|
||||
|
||||
/** Default constructor for I/O */
|
||||
IndexFactorOrdered() {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct unary factor */
|
||||
IndexFactorOrdered(Index j) :
|
||||
Base(j) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct binary factor */
|
||||
IndexFactorOrdered(Index j1, Index j2) :
|
||||
Base(j1, j2) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct ternary factor */
|
||||
IndexFactorOrdered(Index j1, Index j2, Index j3) :
|
||||
Base(j1, j2, j3) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct 4-way factor */
|
||||
IndexFactorOrdered(Index j1, Index j2, Index j3, Index j4) :
|
||||
Base(j1, j2, j3, j4) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct 5-way factor */
|
||||
IndexFactorOrdered(Index j1, Index j2, Index j3, Index j4, Index j5) :
|
||||
Base(j1, j2, j3, j4, j5) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct 6-way factor */
|
||||
IndexFactorOrdered(Index j1, Index j2, Index j3, Index j4, Index j5, Index j6) :
|
||||
Base(j1, j2, j3, j4, j5, j6) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Constructors
|
||||
/// @{
|
||||
|
||||
/** Construct n-way factor */
|
||||
IndexFactorOrdered(const std::set<Index>& js) :
|
||||
Base(js) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Construct n-way factor */
|
||||
IndexFactorOrdered(const std::vector<Index>& js) :
|
||||
Base(js) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/** Constructor from a collection of keys */
|
||||
template<class KeyIterator> IndexFactorOrdered(KeyIterator beginKey,
|
||||
KeyIterator endKey) :
|
||||
Base(beginKey, endKey) {
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
#ifdef TRACK_ELIMINATE
|
||||
/**
|
||||
* eliminate the first variable involved in this factor
|
||||
* @return a conditional on the eliminated variable
|
||||
*/
|
||||
GTSAM_EXPORT boost::shared_ptr<ConditionalType> eliminateFirst();
|
||||
|
||||
/** eliminate the first nrFrontals frontal variables.*/
|
||||
GTSAM_EXPORT boost::shared_ptr<BayesNetOrdered<ConditionalType> > eliminate(size_t nrFrontals =
|
||||
1);
|
||||
#endif
|
||||
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Permutes the factor, but for efficiency requires the permutation
|
||||
* to already be inverted.
|
||||
*/
|
||||
GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
/**
|
||||
* Apply a reduction, which is a remapping of variable indices.
|
||||
*/
|
||||
GTSAM_EXPORT void reduceWithInverse(const internal::Reduction& inverseReduction);
|
||||
|
||||
virtual ~IndexFactorOrdered() {
|
||||
}
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
}; // IndexFactor
|
||||
|
||||
}
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 JunctionTree-inl.h
|
||||
* @date Feb 4, 2010
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
* @brief The junction tree, template bodies
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/VariableSlots.h>
|
||||
#include <gtsam/inference/EliminationTreeOrdered.h>
|
||||
#include <gtsam/base/timing.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template <class FG, class BTCLIQUE>
|
||||
void JunctionTreeOrdered<FG,BTCLIQUE>::construct(const FG& fg, const VariableIndexOrdered& variableIndex) {
|
||||
gttic(JT_construct);
|
||||
gttic(JT_symbolic_ET);
|
||||
const typename EliminationTreeOrdered<IndexFactorOrdered>::shared_ptr symETree =
|
||||
EliminationTreeOrdered<IndexFactorOrdered>::Create(fg, variableIndex);
|
||||
assert(symETree.get());
|
||||
gttoc(JT_symbolic_ET);
|
||||
gttic(JT_symbolic_eliminate);
|
||||
SymbolicBayesNetOrdered::shared_ptr sbn = symETree->eliminate(&EliminateSymbolic);
|
||||
assert(sbn.get());
|
||||
gttoc(JT_symbolic_eliminate);
|
||||
gttic(symbolic_BayesTree);
|
||||
SymbolicBayesTree sbt(*sbn);
|
||||
gttoc(symbolic_BayesTree);
|
||||
|
||||
// distribute factors
|
||||
gttic(distributeFactors);
|
||||
this->root_ = distributeFactors(fg, sbt.root());
|
||||
gttoc(distributeFactors);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template <class FG, class BTCLIQUE>
|
||||
JunctionTreeOrdered<FG,BTCLIQUE>::JunctionTreeOrdered(const FG& fg) {
|
||||
gttic(VariableIndexOrdered);
|
||||
VariableIndexOrdered varIndex(fg);
|
||||
gttoc(VariableIndexOrdered);
|
||||
construct(fg, varIndex);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template <class FG, class BTCLIQUE>
|
||||
JunctionTreeOrdered<FG,BTCLIQUE>::JunctionTreeOrdered(const FG& fg, const VariableIndexOrdered& variableIndex) {
|
||||
construct(fg, variableIndex);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG, class BTCLIQUE>
|
||||
typename JunctionTreeOrdered<FG,BTCLIQUE>::sharedClique JunctionTreeOrdered<FG,BTCLIQUE>::distributeFactors(
|
||||
const FG& fg, const SymbolicBayesTree::sharedClique& bayesClique) {
|
||||
|
||||
// Build "target" index. This is an index for each variable of the factors
|
||||
// that involve this variable as their *lowest-ordered* variable. For each
|
||||
// factor, it is the lowest-ordered variable of that factor that pulls the
|
||||
// factor into elimination, after which all of the information in the
|
||||
// factor is contained in the eliminated factors that are passed up the
|
||||
// tree as elimination continues.
|
||||
|
||||
// Two stages - first build an array of the lowest-ordered variable in each
|
||||
// factor and find the last variable to be eliminated.
|
||||
std::vector<Index> lowestOrdered(fg.size(), std::numeric_limits<Index>::max());
|
||||
Index maxVar = 0;
|
||||
for(size_t i=0; i<fg.size(); ++i)
|
||||
if(fg[i]) {
|
||||
typename FG::FactorType::const_iterator min = std::min_element(fg[i]->begin(), fg[i]->end());
|
||||
if(min != fg[i]->end()) {
|
||||
lowestOrdered[i] = *min;
|
||||
maxVar = std::max(maxVar, *min);
|
||||
}
|
||||
}
|
||||
|
||||
// Now add each factor to the list corresponding to its lowest-ordered
|
||||
// variable.
|
||||
std::vector<FastList<size_t> > targets(maxVar+1);
|
||||
for(size_t i=0; i<lowestOrdered.size(); ++i)
|
||||
if(lowestOrdered[i] != std::numeric_limits<Index>::max())
|
||||
targets[lowestOrdered[i]].push_back(i);
|
||||
|
||||
// Now call the recursive distributeFactors
|
||||
return distributeFactors(fg, targets, bayesClique);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG, class BTCLIQUE>
|
||||
typename JunctionTreeOrdered<FG,BTCLIQUE>::sharedClique JunctionTreeOrdered<FG,BTCLIQUE>::distributeFactors(const FG& fg,
|
||||
const std::vector<FastList<size_t> >& targets,
|
||||
const SymbolicBayesTree::sharedClique& bayesClique) {
|
||||
|
||||
if(bayesClique) {
|
||||
// create a new clique in the junction tree
|
||||
sharedClique clique(new Clique((*bayesClique)->beginFrontals(), (*bayesClique)->endFrontals(),
|
||||
(*bayesClique)->beginParents(), (*bayesClique)->endParents()));
|
||||
|
||||
// count the factors for this cluster to pre-allocate space
|
||||
{
|
||||
size_t nFactors = 0;
|
||||
BOOST_FOREACH(const Index frontal, clique->frontal) {
|
||||
// There may be less variables in "targets" than there really are if
|
||||
// some of the highest-numbered variables do not pull in any factors.
|
||||
if(frontal < targets.size())
|
||||
nFactors += targets[frontal].size(); }
|
||||
clique->reserve(nFactors);
|
||||
}
|
||||
// add the factors to this cluster
|
||||
BOOST_FOREACH(const Index frontal, clique->frontal) {
|
||||
if(frontal < targets.size()) {
|
||||
BOOST_FOREACH(const size_t factorI, targets[frontal]) {
|
||||
clique->push_back(fg[factorI]); } } }
|
||||
|
||||
// recursively call the children
|
||||
BOOST_FOREACH(const typename SymbolicBayesTree::sharedClique bayesChild, bayesClique->children()) {
|
||||
sharedClique child = distributeFactors(fg, targets, bayesChild);
|
||||
clique->addChild(child);
|
||||
child->parent() = clique;
|
||||
}
|
||||
return clique;
|
||||
} else
|
||||
return sharedClique();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG, class BTCLIQUE>
|
||||
std::pair<typename JunctionTreeOrdered<FG,BTCLIQUE>::BTClique::shared_ptr,
|
||||
typename FG::sharedFactor> JunctionTreeOrdered<FG,BTCLIQUE>::eliminateOneClique(
|
||||
typename FG::Eliminate function,
|
||||
const boost::shared_ptr<const Clique>& current) const {
|
||||
|
||||
FG fg; // factor graph will be assembled from local factors and marginalized children
|
||||
fg.reserve(current->size() + current->children().size());
|
||||
fg.push_back(*current); // add the local factors
|
||||
|
||||
// receive the factors from the child and its clique point
|
||||
std::list<typename BTClique::shared_ptr> children;
|
||||
BOOST_FOREACH(const boost::shared_ptr<const Clique>& child, current->children()) {
|
||||
std::pair<typename BTClique::shared_ptr, typename FG::sharedFactor> tree_factor(
|
||||
eliminateOneClique(function, child));
|
||||
children.push_back(tree_factor.first);
|
||||
fg.push_back(tree_factor.second);
|
||||
}
|
||||
|
||||
// eliminate the combined factors
|
||||
// warning: fg is being eliminated in-place and will contain marginal afterwards
|
||||
|
||||
// Now that we know which factors and variables, and where variables
|
||||
// come from and go to, create and eliminate the new joint factor.
|
||||
gttic(CombineAndEliminate);
|
||||
typename FG::EliminationResult eliminated(function(fg,
|
||||
current->frontal.size()));
|
||||
gttoc(CombineAndEliminate);
|
||||
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
assert(std::equal(eliminated.second->begin(), eliminated.second->end(), current->separator.begin()));
|
||||
#endif
|
||||
|
||||
gttic(Update_tree);
|
||||
// create a new clique corresponding the combined factors
|
||||
typename BTClique::shared_ptr new_clique(BTClique::Create(eliminated));
|
||||
new_clique->children_ = children;
|
||||
|
||||
BOOST_FOREACH(typename BTClique::shared_ptr& childRoot, children) {
|
||||
childRoot->parent_ = new_clique;
|
||||
}
|
||||
gttoc(Update_tree);
|
||||
|
||||
return std::make_pair(new_clique, eliminated.second);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG, class BTCLIQUE>
|
||||
typename BTCLIQUE::shared_ptr JunctionTreeOrdered<FG,BTCLIQUE>::eliminate(
|
||||
typename FG::Eliminate function) const
|
||||
{
|
||||
if (this->root()) {
|
||||
gttic(JT_eliminate);
|
||||
std::pair<typename BTClique::shared_ptr, typename FG::sharedFactor> ret =
|
||||
this->eliminateOneClique(function, this->root());
|
||||
if (ret.second->size() != 0) throw std::runtime_error(
|
||||
"JuntionTree::eliminate: elimination failed because of factors left over!");
|
||||
gttoc(JT_eliminate);
|
||||
return ret.first;
|
||||
} else
|
||||
return typename BTClique::shared_ptr();
|
||||
}
|
||||
|
||||
} //namespace gtsam
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 JunctionTree.h
|
||||
* @date Feb 4, 2010
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
* @brief: The junction tree
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <gtsam/base/FastList.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
#include <gtsam/inference/ClusterTreeOrdered.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/inference/VariableIndexOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* A ClusterTree, i.e., a set of variable clusters with factors, arranged in a tree, with
|
||||
* the additional property that it represents the clique tree associated with a Bayes net.
|
||||
*
|
||||
* In GTSAM a junction tree is an intermediate data structure in multifrontal
|
||||
* variable elimination. Each node is a cluster of factors, along with a
|
||||
* clique of variables that are eliminated all at once. In detail, every node k represents
|
||||
* a clique (maximal fully connected subset) of an associated chordal graph, such as a
|
||||
* chordal Bayes net resulting from elimination.
|
||||
*
|
||||
* The difference with the BayesTree is that a JunctionTree stores factors, whereas a
|
||||
* BayesTree stores conditionals, that are the product of eliminating the factors in the
|
||||
* corresponding JunctionTree cliques.
|
||||
*
|
||||
* The tree structure and elimination method are exactly analagous to the EliminationTree,
|
||||
* except that in the JunctionTree, at each node multiple variables are eliminated at a time.
|
||||
*
|
||||
*
|
||||
* \addtogroup Multifrontal
|
||||
* \nosubgrouping
|
||||
*/
|
||||
template<class FG, class BTCLIQUE=typename BayesTreeOrdered<typename FG::FactorType::ConditionalType>::Clique>
|
||||
class JunctionTreeOrdered: public ClusterTreeOrdered<FG> {
|
||||
|
||||
public:
|
||||
|
||||
/// In a junction tree each cluster is associated with a clique
|
||||
typedef typename ClusterTreeOrdered<FG>::Cluster Clique;
|
||||
typedef typename Clique::shared_ptr sharedClique; ///< Shared pointer to a clique
|
||||
|
||||
/// The BayesTree type produced by elimination
|
||||
typedef BTCLIQUE BTClique;
|
||||
|
||||
/// Shared pointer to this class
|
||||
typedef boost::shared_ptr<JunctionTreeOrdered<FG> > shared_ptr;
|
||||
|
||||
/// We will frequently refer to a symbolic Bayes tree, used to find the clique structure
|
||||
typedef gtsam::BayesTreeOrdered<IndexConditionalOrdered> SymbolicBayesTree;
|
||||
|
||||
private:
|
||||
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/// distribute the factors along the cluster tree
|
||||
sharedClique distributeFactors(const FG& fg,
|
||||
const SymbolicBayesTree::sharedClique& clique);
|
||||
|
||||
/// distribute the factors along the cluster tree
|
||||
sharedClique distributeFactors(const FG& fg, const std::vector<FastList<size_t> >& targets,
|
||||
const SymbolicBayesTree::sharedClique& clique);
|
||||
|
||||
/// recursive elimination function
|
||||
std::pair<typename BTClique::shared_ptr, typename FG::sharedFactor>
|
||||
eliminateOneClique(typename FG::Eliminate function,
|
||||
const boost::shared_ptr<const Clique>& clique) const;
|
||||
|
||||
/// internal constructor
|
||||
void construct(const FG& fg, const VariableIndexOrdered& variableIndex);
|
||||
|
||||
/// @}
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Default constructor */
|
||||
JunctionTreeOrdered() {}
|
||||
|
||||
/** Named constructor to build the junction tree of a factor graph. Note
|
||||
* that this has to compute the column structure as a VariableIndex, so if you
|
||||
* already have this precomputed, use the JunctionTree(const FG&, const VariableIndex&)
|
||||
* constructor instead.
|
||||
* @param factorGraph The factor graph for which to build the elimination tree
|
||||
*/
|
||||
JunctionTreeOrdered(const FG& factorGraph);
|
||||
|
||||
/** Construct from a factor graph and pre-computed variable index.
|
||||
* @param fg The factor graph for which to build the junction tree
|
||||
* @param structure The set of factors involving each variable. If this is not
|
||||
* precomputed, you can call the JunctionTree(const FG&)
|
||||
* constructor instead.
|
||||
*/
|
||||
JunctionTreeOrdered(const FG& fg, const VariableIndexOrdered& variableIndex);
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** Eliminate the factors in the subgraphs to produce a BayesTree.
|
||||
* @param function The function used to eliminate, see the namespace functions
|
||||
* in GaussianFactorGraph.h
|
||||
* @return The BayesTree resulting from elimination
|
||||
*/
|
||||
typename BTClique::shared_ptr eliminate(typename FG::Eliminate function) const;
|
||||
|
||||
/// @}
|
||||
|
||||
}; // JunctionTree
|
||||
|
||||
} // namespace gtsam
|
||||
|
||||
#include <gtsam/inference/JunctionTreeOrdered-inl.h>
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 Permutation.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 9, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation Permutation::Identity(Index nVars) {
|
||||
Permutation ret(nVars);
|
||||
for(Index i=0; i<nVars; ++i)
|
||||
ret[i] = i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation Permutation::PullToFront(const vector<Index>& toFront, size_t size, bool filterDuplicates) {
|
||||
|
||||
Permutation ret(size);
|
||||
|
||||
// Mask of which variables have been pulled, used to reorder
|
||||
vector<bool> pulled(size, false);
|
||||
|
||||
// Put the pulled variables at the front of the permutation and set up the
|
||||
// pulled flags.
|
||||
size_t toFrontUniqueSize = 0;
|
||||
for(Index j=0; j<toFront.size(); ++j) {
|
||||
if(!pulled[toFront[j]]) {
|
||||
ret[j] = toFront[j];
|
||||
pulled[toFront[j]] = true;
|
||||
++ toFrontUniqueSize;
|
||||
} else if(!filterDuplicates) {
|
||||
stringstream ss;
|
||||
ss << "Duplicate variable given as input to Permutation::PullToFront:\n";
|
||||
ss << " toFront:";
|
||||
BOOST_FOREACH(Index i, toFront) { ss << " " << i; }
|
||||
ss << ", size = " << size << endl;
|
||||
throw invalid_argument(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the rest of the variables
|
||||
Index nextVar = toFrontUniqueSize;
|
||||
for(Index j=0; j<size; ++j)
|
||||
if(!pulled[j])
|
||||
ret[nextVar++] = j;
|
||||
assert(nextVar == size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation Permutation::PushToBack(const std::vector<Index>& toBack, size_t size, bool filterDuplicates) {
|
||||
|
||||
Permutation ret(size);
|
||||
|
||||
// Mask of which variables have been pushed, used to reorder
|
||||
vector<bool> pushed(size, false);
|
||||
|
||||
// Put the pushed variables at the back of the permutation and set up the
|
||||
// pushed flags;
|
||||
Index nextVar = size;
|
||||
size_t toBackUniqueSize = 0;
|
||||
if(toBack.size() > 0) {
|
||||
Index j = toBack.size();
|
||||
do {
|
||||
-- j;
|
||||
if(!pushed[toBack[j]]) {
|
||||
ret[--nextVar] = toBack[j];
|
||||
pushed[toBack[j]] = true;
|
||||
++ toBackUniqueSize;
|
||||
} else if(!filterDuplicates) {
|
||||
stringstream ss;
|
||||
ss << "Duplicate variable given as input to Permutation::PushToBack:\n";
|
||||
ss << " toBack:";
|
||||
BOOST_FOREACH(Index i, toBack) { ss << " " << i; }
|
||||
ss << ", size = " << size << endl;
|
||||
throw invalid_argument(ss.str());
|
||||
}
|
||||
} while(j > 0);
|
||||
}
|
||||
assert(nextVar == size - toBackUniqueSize);
|
||||
|
||||
// Fill in the rest of the variables
|
||||
nextVar = 0;
|
||||
for(Index j=0; j<size; ++j)
|
||||
if(!pushed[j])
|
||||
ret[nextVar++] = j;
|
||||
assert(nextVar == size - toBackUniqueSize);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation::shared_ptr Permutation::permute(const Permutation& permutation) const {
|
||||
const size_t nVars = permutation.size();
|
||||
Permutation::shared_ptr result(new Permutation(nVars));
|
||||
for(size_t j=0; j<nVars; ++j) {
|
||||
assert(permutation[j] < rangeIndices_.size());
|
||||
(*result)[j] = operator[](permutation[j]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation::shared_ptr Permutation::inverse() const {
|
||||
Permutation::shared_ptr result(new Permutation(this->size()));
|
||||
for(Index i=0; i<this->size(); ++i) {
|
||||
assert((*this)[i] < this->size());
|
||||
(*result)[(*this)[i]] = i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void Permutation::print(const std::string& str) const {
|
||||
std::cout << str << " ";
|
||||
BOOST_FOREACH(Index s, rangeIndices_) { std::cout << s << " "; }
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
/* ************************************************************************* */
|
||||
Reduction Reduction::CreateAsInverse(const Permutation& p) {
|
||||
Reduction result;
|
||||
for(Index j = 0; j < p.size(); ++j)
|
||||
result.insert(std::make_pair(p[j], j));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Reduction Reduction::CreateFromPartialPermutation(const Permutation& selector, const Permutation& p) {
|
||||
if(selector.size() != p.size())
|
||||
throw invalid_argument("internal::Reduction::CreateFromPartialPermutation called with selector and permutation of different sizes");
|
||||
Reduction result;
|
||||
for(size_t dstSlot = 0; dstSlot < p.size(); ++dstSlot)
|
||||
result.insert(make_pair(selector[dstSlot], selector[p[dstSlot]]));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void Reduction::applyInverse(std::vector<Index>& js) const {
|
||||
BOOST_FOREACH(Index& j, js) {
|
||||
j = this->find(j)->second;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation Reduction::inverse() const {
|
||||
Index maxIndex = 0;
|
||||
BOOST_FOREACH(const value_type& target_source, *this) {
|
||||
if(target_source.second > maxIndex)
|
||||
maxIndex = target_source.second;
|
||||
}
|
||||
Permutation result(maxIndex + 1);
|
||||
BOOST_FOREACH(const value_type& target_source, *this) {
|
||||
result[target_source.second] = target_source.first;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
const Index& Reduction::operator[](const Index& j) {
|
||||
iterator it = this->find(j);
|
||||
if(it == this->end())
|
||||
return j;
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
const Index& Reduction::operator[](const Index& j) const {
|
||||
const_iterator it = this->find(j);
|
||||
if(it == this->end())
|
||||
return j;
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void Reduction::print(const std::string& s) const {
|
||||
cout << s << " reduction:" << endl;
|
||||
BOOST_FOREACH(const value_type& p, *this)
|
||||
cout << " " << p.first << " : " << p.second << endl;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool Reduction::equals(const Reduction& other, double tol) const {
|
||||
return (const Base&)(*this) == (const Base&)other;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation createReducingPermutation(const std::set<Index>& indices) {
|
||||
Permutation p(indices.size());
|
||||
Index newJ = 0;
|
||||
BOOST_FOREACH(Index j, indices) {
|
||||
p[newJ] = j;
|
||||
++ newJ;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
} // \namespace internal
|
||||
|
||||
/* ************************************************************************* */
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,215 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 Permutation.h
|
||||
* @author Richard Roberts
|
||||
* @date Sep 12, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/base/FastMap.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* A permutation reorders variables, for example to reduce fill-in during
|
||||
* elimination. To save computation, the permutation can be applied to
|
||||
* the necessary data structures only once, then multiple computations
|
||||
* performed on the permuted problem. For example, in an iterative
|
||||
* non-linear setting, a permutation can be created from the symbolic graph
|
||||
* structure and applied to the ordering of nonlinear variables once, so
|
||||
* that linearized factor graphs are already correctly ordered and need
|
||||
* not be permuted.
|
||||
*
|
||||
* Consistent with their mathematical definition, permutations are functions
|
||||
* that accept the destination index and return the source index. For example,
|
||||
* to permute data structure A into a new data structure B using permutation P,
|
||||
* the mapping is B[i] = A[P[i]]. This is the behavior implemented by
|
||||
* B = A.permute(P).
|
||||
*
|
||||
* For some data structures in GTSAM, for efficiency it is necessary to have
|
||||
* the inverse of the desired permutation. In this case, the data structure
|
||||
* will implement permuteWithInverse(P) instead of permute(P). You may already
|
||||
* have the inverse permutation by construction, or may instead compute it with
|
||||
* Pinv = P.inverse().
|
||||
*
|
||||
* Permutations can be composed and inverted
|
||||
* in order to create new indexing for a structure.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
class GTSAM_EXPORT Permutation {
|
||||
protected:
|
||||
std::vector<Index> rangeIndices_;
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<Permutation> shared_ptr;
|
||||
typedef std::vector<Index>::const_iterator const_iterator;
|
||||
typedef std::vector<Index>::iterator iterator;
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Create an empty permutation. This cannot do anything, but you can later
|
||||
* assign to it.
|
||||
*/
|
||||
Permutation() {}
|
||||
|
||||
/**
|
||||
* Create an uninitialized permutation. You must assign all values using the
|
||||
* square bracket [] operator or they will be undefined!
|
||||
*/
|
||||
Permutation(Index nVars) : rangeIndices_(nVars) {}
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** Print */
|
||||
void print(const std::string& str = "Permutation: ") const;
|
||||
|
||||
/** Check equality */
|
||||
bool equals(const Permutation& rhs, double tol=0.0) const { return rangeIndices_ == rhs.rangeIndices_; }
|
||||
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Return the source index of the supplied destination index.
|
||||
*/
|
||||
Index operator[](Index variable) const { check(variable); return rangeIndices_[variable]; }
|
||||
|
||||
/**
|
||||
* Return the source index of the supplied destination index. This version allows modification.
|
||||
*/
|
||||
Index& operator[](Index variable) { check(variable); return rangeIndices_[variable]; }
|
||||
|
||||
/**
|
||||
* Return the source index of the supplied destination index. Synonym for operator[](Index).
|
||||
*/
|
||||
Index at(Index variable) const { return operator[](variable); }
|
||||
|
||||
/**
|
||||
* Return the source index of the supplied destination index. This version allows modification. Synonym for operator[](Index).
|
||||
*/
|
||||
Index& at(Index variable) { return operator[](variable); }
|
||||
|
||||
/**
|
||||
* The number of variables in the range of this permutation, i.e. the
|
||||
* destination space.
|
||||
*/
|
||||
Index size() const { return rangeIndices_.size(); }
|
||||
|
||||
/** Whether the permutation contains any entries */
|
||||
bool empty() const { return rangeIndices_.empty(); }
|
||||
|
||||
/**
|
||||
* Resize the permutation. You must fill in the new entries if new new size
|
||||
* is larger than the old one. If the new size is smaller, entries from the
|
||||
* end are discarded.
|
||||
*/
|
||||
void resize(size_t newSize) { rangeIndices_.resize(newSize); }
|
||||
|
||||
/**
|
||||
* Return an identity permutation.
|
||||
*/
|
||||
static Permutation Identity(Index nVars);
|
||||
|
||||
/**
|
||||
* Create a permutation that pulls the given variables to the front while
|
||||
* pushing the rest to the back.
|
||||
*/
|
||||
static Permutation PullToFront(const std::vector<Index>& toFront, size_t size, bool filterDuplicates = false);
|
||||
|
||||
/**
|
||||
* Create a permutation that pushes the given variables to the back while
|
||||
* pulling the rest to the front.
|
||||
*/
|
||||
static Permutation PushToBack(const std::vector<Index>& toBack, size_t size, bool filterDuplicates = false);
|
||||
|
||||
|
||||
/**
|
||||
* Permute the permutation, p1.permute(p2)[i] is equivalent to p1[p2[i]].
|
||||
*/
|
||||
Permutation::shared_ptr permute(const Permutation& permutation) const;
|
||||
|
||||
/**
|
||||
* Return the inverse permutation. This is only possible if this is a non-
|
||||
* reducing permutation, that is, (*this)[i] < this->size() for all
|
||||
* i < size(). If NDEBUG is not defined, this conditional will be checked.
|
||||
*/
|
||||
Permutation::shared_ptr inverse() const;
|
||||
|
||||
const_iterator begin() const { return rangeIndices_.begin(); } ///< Iterate through the indices
|
||||
const_iterator end() const { return rangeIndices_.end(); } ///< Iterate through the indices
|
||||
|
||||
/** Apply the permutation to a collection, which must have operator[] defined.
|
||||
* Note that permutable gtsam data structures typically have their own
|
||||
* permute function to apply a permutation. Permutation::applyToCollection is
|
||||
* a generic function, e.g. for STL classes.
|
||||
* @param input The input collection.
|
||||
* @param output The preallocated output collection, which is assigned output[i] = input[permutation[i]]
|
||||
*/
|
||||
template<typename INPUT_COLLECTION, typename OUTPUT_COLLECTION>
|
||||
void applyToCollection(OUTPUT_COLLECTION& output, const INPUT_COLLECTION& input) const {
|
||||
for(size_t i = 0; i < output.size(); ++i) output[i] = input[(*this)[i]]; }
|
||||
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
iterator begin() { return rangeIndices_.begin(); } ///< Iterate through the indices
|
||||
iterator end() { return rangeIndices_.end(); } ///< Iterate through the indices
|
||||
|
||||
protected:
|
||||
void check(Index variable) const { assert(variable < rangeIndices_.size()); }
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
|
||||
namespace internal {
|
||||
/**
|
||||
* An internal class used for storing and applying a permutation from a map
|
||||
*/
|
||||
class Reduction : public gtsam::FastMap<Index,Index> {
|
||||
public:
|
||||
typedef gtsam::FastMap<Index,Index> Base;
|
||||
|
||||
GTSAM_EXPORT static Reduction CreateAsInverse(const Permutation& p);
|
||||
GTSAM_EXPORT static Reduction CreateFromPartialPermutation(const Permutation& selector, const Permutation& p);
|
||||
GTSAM_EXPORT void applyInverse(std::vector<Index>& js) const;
|
||||
GTSAM_EXPORT Permutation inverse() const;
|
||||
GTSAM_EXPORT const Index& operator[](const Index& j);
|
||||
GTSAM_EXPORT const Index& operator[](const Index& j) const;
|
||||
|
||||
GTSAM_EXPORT void print(const std::string& s="") const;
|
||||
GTSAM_EXPORT bool equals(const Reduction& other, double tol = 1e-9) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduce the variable indices so that those in the set are mapped to start at zero
|
||||
*/
|
||||
GTSAM_EXPORT Permutation createReducingPermutation(const std::set<Index>& indices);
|
||||
} // \namespace internal
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 SymbolicFactorGraph.cpp
|
||||
* @date Oct 29, 2009
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
#include <gtsam/inference/EliminationTreeOrdered.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* ************************************************************************* */
|
||||
SymbolicFactorGraphOrdered::SymbolicFactorGraphOrdered(const SymbolicBayesNetOrdered& bayesNet) :
|
||||
FactorGraphOrdered<IndexFactorOrdered>(bayesNet) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
SymbolicFactorGraphOrdered::SymbolicFactorGraphOrdered(const SymbolicBayesTreeOrdered& bayesTree) :
|
||||
FactorGraphOrdered<IndexFactorOrdered>(bayesTree) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void SymbolicFactorGraphOrdered::push_factor(Index key) {
|
||||
push_back(boost::make_shared<IndexFactorOrdered>(key));
|
||||
}
|
||||
|
||||
/** Push back binary factor */
|
||||
void SymbolicFactorGraphOrdered::push_factor(Index key1, Index key2) {
|
||||
push_back(boost::make_shared<IndexFactorOrdered>(key1,key2));
|
||||
}
|
||||
|
||||
/** Push back ternary factor */
|
||||
void SymbolicFactorGraphOrdered::push_factor(Index key1, Index key2, Index key3) {
|
||||
push_back(boost::make_shared<IndexFactorOrdered>(key1,key2,key3));
|
||||
}
|
||||
|
||||
/** Push back 4-way factor */
|
||||
void SymbolicFactorGraphOrdered::push_factor(Index key1, Index key2, Index key3, Index key4) {
|
||||
push_back(boost::make_shared<IndexFactorOrdered>(key1,key2,key3,key4));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
FastSet<Index>
|
||||
SymbolicFactorGraphOrdered::keys() const {
|
||||
FastSet<Index> keys;
|
||||
BOOST_FOREACH(const sharedFactor& factor, *this) {
|
||||
if(factor) keys.insert(factor->begin(), factor->end()); }
|
||||
return keys;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
std::pair<SymbolicFactorGraphOrdered::sharedConditional, SymbolicFactorGraphOrdered>
|
||||
SymbolicFactorGraphOrdered::eliminateFrontals(size_t nFrontals) const
|
||||
{
|
||||
return FactorGraphOrdered<IndexFactorOrdered>::eliminateFrontals(nFrontals, EliminateSymbolic);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
std::pair<SymbolicFactorGraphOrdered::sharedConditional, SymbolicFactorGraphOrdered>
|
||||
SymbolicFactorGraphOrdered::eliminate(const std::vector<Index>& variables) const
|
||||
{
|
||||
return FactorGraphOrdered<IndexFactorOrdered>::eliminate(variables, EliminateSymbolic);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
std::pair<SymbolicFactorGraphOrdered::sharedConditional, SymbolicFactorGraphOrdered>
|
||||
SymbolicFactorGraphOrdered::eliminateOne(Index variable) const
|
||||
{
|
||||
return FactorGraphOrdered<IndexFactorOrdered>::eliminateOne(variable, EliminateSymbolic);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void SymbolicFactorGraphOrdered::permuteWithInverse(
|
||||
const Permutation& inversePermutation) {
|
||||
BOOST_FOREACH(const sharedFactor& factor, factors_) {
|
||||
if(factor)
|
||||
factor->permuteWithInverse(inversePermutation);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void SymbolicFactorGraphOrdered::reduceWithInverse(
|
||||
const internal::Reduction& inverseReduction) {
|
||||
BOOST_FOREACH(const sharedFactor& factor, factors_) {
|
||||
if(factor)
|
||||
factor->reduceWithInverse(inverseReduction);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
IndexFactorOrdered::shared_ptr CombineSymbolic(
|
||||
const FactorGraphOrdered<IndexFactorOrdered>& factors, const FastMap<Index,
|
||||
vector<Index> >& variableSlots) {
|
||||
IndexFactorOrdered::shared_ptr combined(Combine<IndexFactorOrdered, Index> (factors, variableSlots));
|
||||
// combined->assertInvariants();
|
||||
return combined;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
pair<IndexConditionalOrdered::shared_ptr, IndexFactorOrdered::shared_ptr> //
|
||||
EliminateSymbolic(const FactorGraphOrdered<IndexFactorOrdered>& factors, size_t nrFrontals) {
|
||||
|
||||
FastSet<Index> keys;
|
||||
BOOST_FOREACH(const IndexFactorOrdered::shared_ptr& factor, factors)
|
||||
BOOST_FOREACH(Index var, *factor)
|
||||
keys.insert(var);
|
||||
|
||||
if (keys.size() < nrFrontals) throw invalid_argument(
|
||||
"EliminateSymbolic requested to eliminate more variables than exist in graph.");
|
||||
|
||||
vector<Index> newKeys(keys.begin(), keys.end());
|
||||
return make_pair(boost::make_shared<IndexConditionalOrdered>(newKeys, nrFrontals),
|
||||
boost::make_shared<IndexFactorOrdered>(newKeys.begin() + nrFrontals, newKeys.end()));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 SymbolicFactorGraph.h
|
||||
* @date Oct 29, 2009
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
|
||||
namespace gtsam { template<class FACTOR> class EliminationTreeOrdered; }
|
||||
namespace gtsam { template<class CONDITIONAL> class BayesNetOrdered; }
|
||||
namespace gtsam { template<class CONDITIONAL, class CLIQUE> class BayesTreeOrdered; }
|
||||
namespace gtsam { class IndexConditionalOrdered; }
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
typedef EliminationTreeOrdered<IndexFactorOrdered> SymbolicEliminationTreeOrdered;
|
||||
typedef BayesNetOrdered<IndexConditionalOrdered> SymbolicBayesNetOrdered;
|
||||
typedef BayesTreeOrdered<IndexConditionalOrdered> SymbolicBayesTreeOrdered;
|
||||
|
||||
/** Symbolic IndexFactor Graph
|
||||
* \nosubgrouping
|
||||
*/
|
||||
class SymbolicFactorGraphOrdered: public FactorGraphOrdered<IndexFactorOrdered> {
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Construct empty factor graph */
|
||||
SymbolicFactorGraphOrdered() {
|
||||
}
|
||||
|
||||
/** Construct from a BayesNet */
|
||||
GTSAM_EXPORT SymbolicFactorGraphOrdered(const SymbolicBayesNetOrdered& bayesNet);
|
||||
|
||||
/** Construct from a BayesTree */
|
||||
GTSAM_EXPORT SymbolicFactorGraphOrdered(const SymbolicBayesTreeOrdered& bayesTree);
|
||||
|
||||
/**
|
||||
* Construct from a factor graph of any type
|
||||
*/
|
||||
template<class FACTOR>
|
||||
SymbolicFactorGraphOrdered(const FactorGraphOrdered<FACTOR>& fg);
|
||||
|
||||
/** Eliminate the first \c n frontal variables, returning the resulting
|
||||
* conditional and remaining factor graph - this is very inefficient for
|
||||
* eliminating all variables, to do that use EliminationTree or
|
||||
* JunctionTree. Note that this version simply calls
|
||||
* FactorGraph<IndexFactor>::eliminateFrontals with EliminateSymbolic
|
||||
* as the eliminate function argument.
|
||||
*/
|
||||
GTSAM_EXPORT std::pair<sharedConditional, SymbolicFactorGraphOrdered> eliminateFrontals(size_t nFrontals) const;
|
||||
|
||||
/** Factor the factor graph into a conditional and a remaining factor graph.
|
||||
* Given the factor graph \f$ f(X) \f$, and \c variables to factorize out
|
||||
* \f$ V \f$, this function factorizes into \f$ f(X) = f(V;Y)f(Y) \f$, where
|
||||
* \f$ Y := X\V \f$ are the remaining variables. If \f$ f(X) = p(X) \f$ is
|
||||
* a probability density or likelihood, the factorization produces a
|
||||
* conditional probability density and a marginal \f$ p(X) = p(V|Y)p(Y) \f$.
|
||||
*
|
||||
* For efficiency, this function treats the variables to eliminate
|
||||
* \c variables as fully-connected, so produces a dense (fully-connected)
|
||||
* conditional on all of the variables in \c variables, instead of a sparse
|
||||
* BayesNet. If the variables are not fully-connected, it is more efficient
|
||||
* to sequentially factorize multiple times.
|
||||
* Note that this version simply calls
|
||||
* FactorGraph<GaussianFactor>::eliminate with EliminateSymbolic as the eliminate
|
||||
* function argument.
|
||||
*/
|
||||
GTSAM_EXPORT std::pair<sharedConditional, SymbolicFactorGraphOrdered> eliminate(const std::vector<Index>& variables) const;
|
||||
|
||||
/** Eliminate a single variable, by calling SymbolicFactorGraph::eliminate. */
|
||||
GTSAM_EXPORT std::pair<sharedConditional, SymbolicFactorGraphOrdered> eliminateOne(Index variable) const;
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Return the set of variables involved in the factors (computes a set
|
||||
* union).
|
||||
*/
|
||||
GTSAM_EXPORT FastSet<Index> keys() const;
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/** Push back unary factor */
|
||||
GTSAM_EXPORT void push_factor(Index key);
|
||||
|
||||
/** Push back binary factor */
|
||||
GTSAM_EXPORT void push_factor(Index key1, Index key2);
|
||||
|
||||
/** Push back ternary factor */
|
||||
GTSAM_EXPORT void push_factor(Index key1, Index key2, Index key3);
|
||||
|
||||
/** Push back 4-way factor */
|
||||
GTSAM_EXPORT void push_factor(Index key1, Index key2, Index key3, Index key4);
|
||||
|
||||
/** Permute the variables in the factors */
|
||||
GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
/** Apply a reduction, which is a remapping of variable indices. */
|
||||
GTSAM_EXPORT void reduceWithInverse(const internal::Reduction& inverseReduction);
|
||||
|
||||
};
|
||||
|
||||
/** Create a combined joint factor (new style for EliminationTree). */
|
||||
GTSAM_EXPORT IndexFactorOrdered::shared_ptr CombineSymbolic(const FactorGraphOrdered<IndexFactorOrdered>& factors,
|
||||
const FastMap<Index, std::vector<Index> >& variableSlots);
|
||||
|
||||
/**
|
||||
* CombineAndEliminate provides symbolic elimination.
|
||||
* Combine and eliminate can also be called separately, but for this and
|
||||
* derived classes calling them separately generally does extra work.
|
||||
*/
|
||||
GTSAM_EXPORT std::pair<boost::shared_ptr<IndexConditionalOrdered>, boost::shared_ptr<IndexFactorOrdered> >
|
||||
EliminateSymbolic(const FactorGraphOrdered<IndexFactorOrdered>&, size_t nrFrontals = 1);
|
||||
|
||||
/// @}
|
||||
|
||||
/** Template function implementation */
|
||||
template<class FACTOR>
|
||||
SymbolicFactorGraphOrdered::SymbolicFactorGraphOrdered(const FactorGraphOrdered<FACTOR>& fg) {
|
||||
for (size_t i = 0; i < fg.size(); i++) {
|
||||
if (fg[i]) {
|
||||
IndexFactorOrdered::shared_ptr factor(new IndexFactorOrdered(*fg[i]));
|
||||
push_back(factor);
|
||||
} else
|
||||
push_back(IndexFactorOrdered::shared_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 SymbolicMultifrontalSolver.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 22, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/SymbolicMultifrontalSolverOrdered.h>
|
||||
#include <gtsam/inference/JunctionTreeOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
//template class GenericMultifrontalSolver<IndexFactor, JunctionTree<FactorGraph<IndexFactor> > >;
|
||||
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 SymbolicMultifrontalSolver.h
|
||||
* @author Richard Roberts
|
||||
* @date Oct 22, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/GenericMultifrontalSolver.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
class SymbolicMultifrontalSolver : GenericMultifrontalSolver<IndexFactorOrdered, JunctionTreeOrdered<FactorGraphOrdered<IndexFactorOrdered> > > {
|
||||
|
||||
protected:
|
||||
typedef GenericMultifrontalSolver<IndexFactorOrdered, JunctionTreeOrdered<FactorGraphOrdered<IndexFactorOrdered> > > Base;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct the solver for a factor graph. This builds the junction
|
||||
* tree, which does the symbolic elimination, identifies the cliques,
|
||||
* and distributes all the factors to the right cliques.
|
||||
*/
|
||||
SymbolicMultifrontalSolver(const SymbolicFactorGraphOrdered& factorGraph) : Base(factorGraph) {};
|
||||
|
||||
/**
|
||||
* Construct the solver with a shared pointer to a factor graph and to a
|
||||
* VariableIndex. The solver will store these pointers, so this constructor
|
||||
* is the fastest.
|
||||
*/
|
||||
SymbolicMultifrontalSolver(const SymbolicFactorGraphOrdered::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex) : Base(factorGraph, variableIndex) {};
|
||||
|
||||
/** Print to cout */
|
||||
void print(const std::string& name = "SymbolicMultifrontalSolver: ") const { Base::print(name); };
|
||||
|
||||
/** Test whether is equal to another */
|
||||
bool equals(const SymbolicMultifrontalSolver& other, double tol = 1e-9) const { return Base::equals(other, tol); };
|
||||
|
||||
/**
|
||||
* Eliminate the factor graph sequentially. Uses a column elimination tree
|
||||
* to recursively eliminate.
|
||||
*/
|
||||
SymbolicBayesTreeOrdered::shared_ptr eliminate() const { return Base::eliminate(&EliminateSymbolic); };
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. Returns the result as a factor graph.
|
||||
*/
|
||||
SymbolicFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector<Index>& js) const { return Base::jointFactorGraph(js, &EliminateSymbolic); };
|
||||
|
||||
/**
|
||||
* Compute the marginal Gaussian density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as a factor.
|
||||
*/
|
||||
IndexFactorOrdered::shared_ptr marginalFactor(Index j) const { return Base::marginalFactor(j, &EliminateSymbolic); };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 SymbolicSequentialSolver.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
#include <gtsam/inference/GenericSequentialSolver-inl.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// An explicit instantiation to be compiled into the library
|
||||
//template class GenericSequentialSolver<IndexFactor>;
|
||||
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 SymbolicSequentialSolver.h
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/GenericSequentialSolver.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
class SymbolicSequentialSolver : GenericSequentialSolver<IndexFactorOrdered> {
|
||||
|
||||
protected:
|
||||
typedef GenericSequentialSolver<IndexFactorOrdered> Base;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct the solver for a factor graph. This builds the junction
|
||||
* tree, which does the symbolic elimination, identifies the cliques,
|
||||
* and distributes all the factors to the right cliques.
|
||||
*/
|
||||
SymbolicSequentialSolver(const SymbolicFactorGraphOrdered& factorGraph) : Base(factorGraph) {};
|
||||
|
||||
/**
|
||||
* Construct the solver with a shared pointer to a factor graph and to a
|
||||
* VariableIndex. The solver will store these pointers, so this constructor
|
||||
* is the fastest.
|
||||
*/
|
||||
SymbolicSequentialSolver(const SymbolicFactorGraphOrdered::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex) : Base(factorGraph, variableIndex) {};
|
||||
|
||||
/** Print to cout */
|
||||
void print(const std::string& name = "SymbolicSequentialSolver: ") const { Base::print(name); };
|
||||
|
||||
/** Test whether is equal to another */
|
||||
bool equals(const SymbolicSequentialSolver& other, double tol = 1e-9) const { return Base::equals(other, tol); };
|
||||
|
||||
/**
|
||||
* Eliminate the factor graph sequentially. Uses a column elimination tree
|
||||
* to recursively eliminate.
|
||||
*/
|
||||
SymbolicBayesNetOrdered::shared_ptr eliminate() const
|
||||
{ return Base::eliminate(&EliminateSymbolic); };
|
||||
|
||||
/**
|
||||
* Compute a conditional density P(F|S) while marginalizing out variables J
|
||||
* P(F|S) is obtained by P(J,F,S)=P(J|F,S)P(F|S)P(S) and dropping P(S)
|
||||
* Returns the result as a Bayes net.
|
||||
*/
|
||||
SymbolicBayesNetOrdered::shared_ptr conditionalBayesNet(const std::vector<Index>& js, size_t nrFrontals) const
|
||||
{ return Base::conditionalBayesNet(js, nrFrontals, &EliminateSymbolic); };
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. Returns the result as a Bayes net.
|
||||
*/
|
||||
SymbolicBayesNetOrdered::shared_ptr jointBayesNet(const std::vector<Index>& js) const
|
||||
{ return Base::jointBayesNet(js, &EliminateSymbolic); };
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. Returns the result as a factor graph.
|
||||
*/
|
||||
SymbolicFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector<Index>& js) const
|
||||
{ return Base::jointFactorGraph(js, &EliminateSymbolic); };
|
||||
|
||||
/**
|
||||
* Compute the marginal Gaussian density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as a factor.
|
||||
*/
|
||||
IndexFactorOrdered::shared_ptr marginalFactor(Index j) const { return Base::marginalFactor(j, &EliminateSymbolic); };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 VariableIndex.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 22, 2010
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <gtsam/inference/VariableIndexOrdered.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool VariableIndexOrdered::equals(const VariableIndexOrdered& other, double tol) const {
|
||||
if(this->nEntries_ == other.nEntries_ && this->nFactors_ == other.nFactors_) {
|
||||
for(size_t var=0; var < max(this->index_.size(), other.index_.size()); ++var)
|
||||
if(var >= this->index_.size() || var >= other.index_.size()) {
|
||||
if(!((var >= this->index_.size() && other.index_[var].empty()) ||
|
||||
(var >= other.index_.size() && this->index_[var].empty())))
|
||||
return false;
|
||||
} else if(this->index_[var] != other.index_[var])
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VariableIndexOrdered::print(const string& str) const {
|
||||
cout << str;
|
||||
cout << "nEntries = " << nEntries() << ", nFactors = " << nFactors() << "\n";
|
||||
for(Index var = 0; var < size(); ++var) {
|
||||
cout << "var " << var << ":";
|
||||
BOOST_FOREACH(const size_t factor, index_[var])
|
||||
cout << " " << factor;
|
||||
cout << "\n";
|
||||
}
|
||||
cout << flush;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VariableIndexOrdered::outputMetisFormat(ostream& os) const {
|
||||
os << size() << " " << nFactors() << "\n";
|
||||
// run over variables, which will be hyper-edges.
|
||||
BOOST_FOREACH(const Factors& variable, index_) {
|
||||
// every variable is a hyper-edge covering its factors
|
||||
BOOST_FOREACH(const size_t factor, variable)
|
||||
os << (factor+1) << " "; // base 1
|
||||
os << "\n";
|
||||
}
|
||||
os << flush;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VariableIndexOrdered::permuteInPlace(const Permutation& permutation) {
|
||||
// Create new index and move references to data into it in permuted order
|
||||
vector<VariableIndexOrdered::Factors> newIndex(this->size());
|
||||
for(Index i = 0; i < newIndex.size(); ++i)
|
||||
newIndex[i].swap(this->index_[permutation[i]]);
|
||||
|
||||
// Move reference to entire index into the VariableIndex
|
||||
index_.swap(newIndex);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VariableIndexOrdered::permuteInPlace(const Permutation& selector, const Permutation& permutation) {
|
||||
if(selector.size() != permutation.size())
|
||||
throw invalid_argument("VariableIndex::permuteInPlace (partial permutation version) called with selector and permutation of different sizes.");
|
||||
// Create new index the size of the permuted entries
|
||||
vector<VariableIndexOrdered::Factors> newIndex(selector.size());
|
||||
// Permute the affected entries into the new index
|
||||
for(size_t dstSlot = 0; dstSlot < selector.size(); ++dstSlot)
|
||||
newIndex[dstSlot].swap(this->index_[selector[permutation[dstSlot]]]);
|
||||
// Put the affected entries back in the new order
|
||||
for(size_t slot = 0; slot < selector.size(); ++slot)
|
||||
this->index_[selector[slot]].swap(newIndex[slot]);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VariableIndexOrdered::removeUnusedAtEnd(size_t nToRemove) {
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
for(size_t i = this->size() - nToRemove; i < this->size(); ++i)
|
||||
if(!(*this)[i].empty())
|
||||
throw std::invalid_argument("Attempting to remove non-empty variables with VariableIndex::removeUnusedAtEnd()");
|
||||
#endif
|
||||
|
||||
index_.resize(this->size() - nToRemove);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 VariableIndex.h
|
||||
* @author Richard Roberts
|
||||
* @date Sep 12, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <stdexcept>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <gtsam/base/FastList.h>
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/base/timing.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
class Permutation;
|
||||
|
||||
/**
|
||||
* The VariableIndex class computes and stores the block column structure of a
|
||||
* factor graph. The factor graph stores a collection of factors, each of
|
||||
* which involves a set of variables. In contrast, the VariableIndex is built
|
||||
* from a factor graph prior to elimination, and stores the list of factors
|
||||
* that involve each variable. This information is stored as a deque of
|
||||
* lists of factor indices.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
class GTSAM_EXPORT VariableIndexOrdered {
|
||||
public:
|
||||
|
||||
typedef boost::shared_ptr<VariableIndexOrdered> shared_ptr;
|
||||
typedef FastList<size_t> Factors;
|
||||
typedef Factors::iterator Factor_iterator;
|
||||
typedef Factors::const_iterator Factor_const_iterator;
|
||||
|
||||
protected:
|
||||
std::vector<Factors> index_;
|
||||
size_t nFactors_; // Number of factors in the original factor graph.
|
||||
size_t nEntries_; // Sum of involved variable counts of each factor.
|
||||
|
||||
public:
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/** Default constructor, creates an empty VariableIndex */
|
||||
VariableIndexOrdered() : nFactors_(0), nEntries_(0) {}
|
||||
|
||||
/**
|
||||
* Create a VariableIndex that computes and stores the block column structure
|
||||
* of a factor graph. This constructor is used when the number of variables
|
||||
* is known beforehand.
|
||||
*/
|
||||
template<class FG> VariableIndexOrdered(const FG& factorGraph, Index nVariables);
|
||||
|
||||
/**
|
||||
* Create a VariableIndex that computes and stores the block column structure
|
||||
* of a factor graph.
|
||||
*/
|
||||
template<class FG> VariableIndexOrdered(const FG& factorGraph);
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* The number of variable entries. This is one greater than the variable
|
||||
* with the highest index.
|
||||
*/
|
||||
Index size() const { return index_.size(); }
|
||||
|
||||
/** The number of factors in the original factor graph */
|
||||
size_t nFactors() const { return nFactors_; }
|
||||
|
||||
/** The number of nonzero blocks, i.e. the number of variable-factor entries */
|
||||
size_t nEntries() const { return nEntries_; }
|
||||
|
||||
/** Access a list of factors by variable */
|
||||
const Factors& operator[](Index variable) const { checkVar(variable); return index_[variable]; }
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
/// @{
|
||||
|
||||
/** Test for equality (for unit tests and debug assertions). */
|
||||
bool equals(const VariableIndexOrdered& other, double tol=0.0) const;
|
||||
|
||||
/** Print the variable index (for unit tests and debugging). */
|
||||
void print(const std::string& str = "VariableIndex: ") const;
|
||||
|
||||
/**
|
||||
* Output dual hypergraph to Metis file format for use with hmetis
|
||||
* In the dual graph, variables are hyperedges, factors are nodes.
|
||||
*/
|
||||
void outputMetisFormat(std::ostream& os) const;
|
||||
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Augment the variable index with new factors. This can be used when
|
||||
* solving problems incrementally.
|
||||
*/
|
||||
template<class FG> void augment(const FG& factors);
|
||||
|
||||
/**
|
||||
* Remove entries corresponding to the specified factors.
|
||||
* NOTE: We intentionally do not decrement nFactors_ because the factor
|
||||
* indices need to remain consistent. Removing factors from a factor graph
|
||||
* does not shift the indices of other factors. Also, we keep nFactors_
|
||||
* one greater than the highest-numbered factor referenced in a VariableIndex.
|
||||
*
|
||||
* @param indices The indices of the factors to remove, which must match \c factors
|
||||
* @param factors The factors being removed, which must symbolically correspond
|
||||
* exactly to the factors with the specified \c indices that were added.
|
||||
*/
|
||||
template<typename CONTAINER, class FG> void remove(const CONTAINER& indices, const FG& factors);
|
||||
|
||||
/// Permute the variables in the VariableIndex according to the given permutation
|
||||
void permuteInPlace(const Permutation& permutation);
|
||||
|
||||
/// Permute the variables in the VariableIndex according to the given partial permutation
|
||||
void permuteInPlace(const Permutation& selector, const Permutation& permutation);
|
||||
|
||||
/** Remove unused empty variables at the end of the ordering (in debug mode
|
||||
* verifies they are empty).
|
||||
* @param nToRemove The number of unused variables at the end to remove
|
||||
*/
|
||||
void removeUnusedAtEnd(size_t nToRemove);
|
||||
|
||||
protected:
|
||||
Factor_iterator factorsBegin(Index variable) { checkVar(variable); return index_[variable].begin(); }
|
||||
Factor_iterator factorsEnd(Index variable) { checkVar(variable); return index_[variable].end(); }
|
||||
|
||||
Factor_const_iterator factorsBegin(Index variable) const { checkVar(variable); return index_[variable].begin(); }
|
||||
Factor_const_iterator factorsEnd(Index variable) const { checkVar(variable); return index_[variable].end(); }
|
||||
|
||||
/// Internal constructor to allocate a VariableIndex of the requested size
|
||||
VariableIndexOrdered(size_t nVars) : index_(nVars), nFactors_(0), nEntries_(0) {}
|
||||
|
||||
/// Internal check of the validity of a variable
|
||||
void checkVar(Index variable) const { assert(variable < index_.size()); }
|
||||
|
||||
/// Internal function to populate the variable index from a factor graph
|
||||
template<class FG> void fill(const FG& factorGraph);
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_NVP(index_);
|
||||
ar & BOOST_SERIALIZATION_NVP(nFactors_);
|
||||
ar & BOOST_SERIALIZATION_NVP(nEntries_);
|
||||
}
|
||||
};
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
void VariableIndexOrdered::fill(const FG& factorGraph) {
|
||||
gttic(VariableIndex_fill);
|
||||
// Build index mapping from variable id to factor index
|
||||
for(size_t fi=0; fi<factorGraph.size(); ++fi) {
|
||||
if(factorGraph[fi]) {
|
||||
BOOST_FOREACH(const Index key, factorGraph[fi]->keys()) {
|
||||
if(key < index_.size()) {
|
||||
index_[key].push_back(fi);
|
||||
++ nEntries_;
|
||||
}
|
||||
}
|
||||
}
|
||||
++ nFactors_; // Increment factor count even if factors are null, to keep indices consistent
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
VariableIndexOrdered::VariableIndexOrdered(const FG& factorGraph) :
|
||||
nFactors_(0), nEntries_(0)
|
||||
{
|
||||
gttic(VariableIndex_constructor);
|
||||
// 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) {
|
||||
gttic(VariableIndex_constructor_find_highest);
|
||||
// Find highest-numbered variable
|
||||
Index maxVar = 0;
|
||||
BOOST_FOREACH(const typename FG::sharedFactor& factor, factorGraph) {
|
||||
if(factor) {
|
||||
BOOST_FOREACH(const Index key, factor->keys()) {
|
||||
if(key > maxVar)
|
||||
maxVar = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
gttoc(VariableIndex_constructor_find_highest);
|
||||
|
||||
// Allocate array
|
||||
gttic(VariableIndex_constructor_allocate);
|
||||
index_.resize(maxVar+1);
|
||||
gttoc(VariableIndex_constructor_allocate);
|
||||
|
||||
fill(factorGraph);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
VariableIndexOrdered::VariableIndexOrdered(const FG& factorGraph, Index nVariables) :
|
||||
nFactors_(0), nEntries_(0)
|
||||
{
|
||||
gttic(VariableIndex_constructor_allocate);
|
||||
index_.resize(nVariables);
|
||||
gttoc(VariableIndex_constructor_allocate);
|
||||
fill(factorGraph);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class FG>
|
||||
void VariableIndexOrdered::augment(const FG& factors) {
|
||||
gttic(VariableIndex_augment);
|
||||
// If the factor graph is empty, return an empty index because inside this
|
||||
// if block we assume at least one factor.
|
||||
if(factors.size() > 0) {
|
||||
// Find highest-numbered variable
|
||||
Index maxVar = 0;
|
||||
BOOST_FOREACH(const typename FG::sharedFactor& factor, factors) {
|
||||
if(factor) {
|
||||
BOOST_FOREACH(const Index key, factor->keys()) {
|
||||
if(key > maxVar)
|
||||
maxVar = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate index
|
||||
index_.resize(std::max(index_.size(), maxVar+1));
|
||||
|
||||
// Augment index mapping from variable id to factor index
|
||||
size_t orignFactors = nFactors_;
|
||||
for(size_t fi=0; fi<factors.size(); ++fi) {
|
||||
if(factors[fi]) {
|
||||
BOOST_FOREACH(const Index key, factors[fi]->keys()) {
|
||||
index_[key].push_back(orignFactors + fi);
|
||||
++ nEntries_;
|
||||
}
|
||||
}
|
||||
++ nFactors_; // Increment factor count even if factors are null, to keep indices consistent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename CONTAINER, class FG>
|
||||
void VariableIndexOrdered::remove(const CONTAINER& indices, const FG& factors) {
|
||||
gttic(VariableIndex_remove);
|
||||
// NOTE: We intentionally do not decrement nFactors_ because the factor
|
||||
// indices need to remain consistent. Removing factors from a factor graph
|
||||
// does not shift the indices of other factors. Also, we keep nFactors_
|
||||
// one greater than the highest-numbered factor referenced in a VariableIndex.
|
||||
for(size_t fi=0; fi<factors.size(); ++fi)
|
||||
if(factors[fi]) {
|
||||
for(size_t ji = 0; ji < factors[fi]->keys().size(); ++ji) {
|
||||
Factors& factorEntries = index_[factors[fi]->keys()[ji]];
|
||||
Factors::iterator entry = std::find(factorEntries.begin(), factorEntries.end(), indices[fi]);
|
||||
if(entry == factorEntries.end())
|
||||
throw std::invalid_argument("Internal error, indices and factors passed into VariableIndex::remove are not consistent with the existing variable index");
|
||||
factorEntries.erase(entry);
|
||||
-- nEntries_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 inference-inl.h
|
||||
* @brief
|
||||
* @author Richard Roberts
|
||||
* @date Mar 3, 2012
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// Only for Eclipse parser, inference-inl.h (this file) is included at the bottom of inference.h
|
||||
#include <gtsam/inference/inferenceOrdered.h>
|
||||
|
||||
#include <gtsam/base/FastSet.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
namespace inference {
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename CONSTRAINED>
|
||||
Permutation::shared_ptr PermutationCOLAMD(
|
||||
const VariableIndexOrdered& variableIndex, const CONSTRAINED& constrainLast, bool forceOrder) {
|
||||
gttic(PermutationCOLAMD_constrained);
|
||||
|
||||
size_t n = variableIndex.size();
|
||||
std::vector<int> cmember(n, 0);
|
||||
|
||||
// If at least some variables are not constrained to be last, constrain the
|
||||
// ones that should be constrained.
|
||||
if(constrainLast.size() < n) {
|
||||
BOOST_FOREACH(Index var, constrainLast) {
|
||||
assert(var < n);
|
||||
cmember[var] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Permutation::shared_ptr permutation = PermutationCOLAMD_(variableIndex, cmember);
|
||||
if (forceOrder) {
|
||||
Index j=n;
|
||||
BOOST_REVERSE_FOREACH(Index c, constrainLast)
|
||||
permutation->operator[](--j) = c;
|
||||
}
|
||||
return permutation;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename CONSTRAINED_MAP>
|
||||
Permutation::shared_ptr PermutationCOLAMDGrouped(
|
||||
const VariableIndexOrdered& variableIndex, const CONSTRAINED_MAP& constraints) {
|
||||
gttic(PermutationCOLAMD_grouped);
|
||||
size_t n = variableIndex.size();
|
||||
std::vector<int> cmember(n, 0);
|
||||
|
||||
typedef typename CONSTRAINED_MAP::value_type constraint_pair;
|
||||
BOOST_FOREACH(const constraint_pair& p, constraints) {
|
||||
assert(p.first < n);
|
||||
// FIXME: check that no groups are skipped
|
||||
cmember[p.first] = p.second;
|
||||
}
|
||||
|
||||
return PermutationCOLAMD_(variableIndex, cmember);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
inline Permutation::shared_ptr PermutationCOLAMD(const VariableIndexOrdered& variableIndex) {
|
||||
gttic(PermutationCOLAMD_unconstrained);
|
||||
size_t n = variableIndex.size();
|
||||
std::vector<int> cmember(n, 0);
|
||||
return PermutationCOLAMD_(variableIndex, cmember);
|
||||
}
|
||||
|
||||
} // namespace inference
|
||||
} // namespace gtsam
|
||||
|
||||
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 inference.cpp
|
||||
* @brief inference definitions
|
||||
* @author Frank Dellaert
|
||||
* @author Richard Roberts
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/inferenceOrdered.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <ccolamd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
namespace inference {
|
||||
|
||||
/* ************************************************************************* */
|
||||
Permutation::shared_ptr PermutationCOLAMD_(const VariableIndexOrdered& variableIndex, std::vector<int>& cmember) {
|
||||
gttic(PermutationCOLAMD_internal);
|
||||
|
||||
gttic(Prepare);
|
||||
size_t nEntries = variableIndex.nEntries(), nFactors = variableIndex.nFactors(), nVars = variableIndex.size();
|
||||
// Convert to compressed column major format colamd wants it in (== MATLAB format!)
|
||||
size_t Alen = ccolamd_recommended((int)nEntries, (int)nFactors, (int)nVars); /* colamd arg 3: size of the array A */
|
||||
vector<int> A = vector<int>(Alen); /* colamd arg 4: row indices of A, of size Alen */
|
||||
vector<int> p = vector<int>(nVars + 1); /* colamd arg 5: column pointers of A, of size n_col+1 */
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
p[0] = 0;
|
||||
int count = 0;
|
||||
for(Index var = 0; var < variableIndex.size(); ++var) {
|
||||
const VariableIndexOrdered::Factors& column(variableIndex[var]);
|
||||
size_t lastFactorId = numeric_limits<size_t>::max();
|
||||
BOOST_FOREACH(size_t factorIndex, column) {
|
||||
if(lastFactorId != numeric_limits<size_t>::max())
|
||||
assert(factorIndex > lastFactorId);
|
||||
A[count++] = (int)factorIndex; // copy sparse column
|
||||
if(debug) cout << "A[" << count-1 << "] = " << factorIndex << endl;
|
||||
}
|
||||
p[var+1] = count; // column j (base 1) goes from A[j-1] to A[j]-1
|
||||
}
|
||||
|
||||
assert((size_t)count == variableIndex.nEntries());
|
||||
|
||||
if(debug)
|
||||
for(size_t i=0; i<nVars+1; ++i)
|
||||
cout << "p[" << i << "] = " << p[i] << endl;
|
||||
|
||||
//double* knobs = NULL; /* colamd arg 6: parameters (uses defaults if NULL) */
|
||||
double knobs[CCOLAMD_KNOBS];
|
||||
ccolamd_set_defaults(knobs);
|
||||
knobs[CCOLAMD_DENSE_ROW]=-1;
|
||||
knobs[CCOLAMD_DENSE_COL]=-1;
|
||||
|
||||
int stats[CCOLAMD_STATS]; /* colamd arg 7: colamd output statistics and error codes */
|
||||
|
||||
gttoc(Prepare);
|
||||
|
||||
// call colamd, result will be in p
|
||||
/* returns (1) if successful, (0) otherwise*/
|
||||
if(nVars > 0) {
|
||||
gttic(ccolamd);
|
||||
int rv = ccolamd((int)nFactors, (int)nVars, (int)Alen, &A[0], &p[0], knobs, stats, &cmember[0]);
|
||||
if(rv != 1)
|
||||
throw runtime_error((boost::format("ccolamd failed with return value %1%")%rv).str());
|
||||
}
|
||||
|
||||
// ccolamd_report(stats);
|
||||
|
||||
gttic(Create_permutation);
|
||||
// Convert elimination ordering in p to an ordering
|
||||
Permutation::shared_ptr permutation(new Permutation(nVars));
|
||||
for (Index j = 0; j < nVars; j++) {
|
||||
// if(p[j] == -1)
|
||||
// permutation->operator[](j) = j;
|
||||
// else
|
||||
permutation->operator[](j) = p[j];
|
||||
if(debug) cout << "COLAMD: " << j << "->" << p[j] << endl;
|
||||
}
|
||||
if(debug) cout << "COLAMD: p[" << nVars << "] = " << p[nVars] << endl;
|
||||
gttoc(Create_permutation);
|
||||
|
||||
return permutation;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
} // \namespace inference
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 inference.h
|
||||
* @brief Contains *generic* inference algorithms that convert between templated
|
||||
* graphical models, i.e., factor graphs, Bayes nets, and Bayes trees
|
||||
* @author Frank Dellaert
|
||||
* @author Richard Roberts
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/VariableIndexOrdered.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
namespace inference {
|
||||
|
||||
/**
|
||||
* Compute a permutation (variable ordering) using colamd
|
||||
*/
|
||||
GTSAM_EXPORT Permutation::shared_ptr PermutationCOLAMD(
|
||||
const VariableIndexOrdered& variableIndex);
|
||||
|
||||
/**
|
||||
* Compute a permutation (variable ordering) using constrained colamd to move
|
||||
* a set of variables to the end of the ordering
|
||||
* @param variableIndex is the variable index lookup from a graph
|
||||
* @param constrainlast is a vector of keys that should be constrained
|
||||
* @tparam constrainLast is a std::vector (or similar structure)
|
||||
* @param forceOrder if true, will not allow re-ordering of constrained variables
|
||||
*/
|
||||
template<typename CONSTRAINED>
|
||||
Permutation::shared_ptr PermutationCOLAMD(
|
||||
const VariableIndexOrdered& variableIndex, const CONSTRAINED& constrainLast, bool forceOrder=false);
|
||||
|
||||
/**
|
||||
* Compute a permutation of variable ordering using constrained colamd to
|
||||
* move variables to the end in groups (0 = unconstrained, higher numbers at
|
||||
* the end).
|
||||
* @param variableIndex is the variable index lookup from a graph
|
||||
* @param constraintMap is a map from variable index -> group number for constrained variables
|
||||
* @tparam CONSTRAINED_MAP is an associative structure (like std::map), from size_t->int
|
||||
*/
|
||||
template<typename CONSTRAINED_MAP>
|
||||
Permutation::shared_ptr PermutationCOLAMDGrouped(
|
||||
const VariableIndexOrdered& variableIndex, const CONSTRAINED_MAP& constraints);
|
||||
|
||||
/**
|
||||
* Compute a CCOLAMD permutation using the constraint groups in cmember.
|
||||
* The format for cmember is a part of ccolamd.
|
||||
*
|
||||
* @param variableIndex is the variable structure from a graph
|
||||
* @param cmember is the constraint group list for each variable, where
|
||||
* 0 is the default, unconstrained group, and higher numbers move further to
|
||||
* the back of the list
|
||||
*
|
||||
* AGC: does cmember change?
|
||||
*/
|
||||
GTSAM_EXPORT Permutation::shared_ptr PermutationCOLAMD_(
|
||||
const VariableIndexOrdered& variableIndex, std::vector<int>& cmember);
|
||||
|
||||
} // \namespace inference
|
||||
|
||||
} // \namespace gtsam
|
||||
|
||||
#include <gtsam/inference/inferenceOrdered-inl.h>
|
||||
|
|
@ -1,563 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testBayesTree.cpp
|
||||
* @brief Unit tests for Bayes Tree
|
||||
* @author Frank Dellaert
|
||||
* @author Michael Kaess
|
||||
* @author Viorela Ila
|
||||
*/
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/assign/std/set.hpp>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
///* ************************************************************************* */
|
||||
//// SLAM example from RSS sqrtSAM paper
|
||||
static const Index _x3_=0, _x2_=1;
|
||||
//static const Index _x1_=2, _l2_=3, _l1_=4; // unused
|
||||
//IndexConditionalOrdered::shared_ptr
|
||||
// x3(new IndexConditionalOrdered(_x3_)),
|
||||
// x2(new IndexConditionalOrdered(_x2_,_x3_)),
|
||||
// x1(new IndexConditionalOrdered(_x1_,_x2_,_x3_)),
|
||||
// l1(new IndexConditionalOrdered(_l1_,_x1_,_x2_)),
|
||||
// l2(new IndexConditionalOrdered(_l2_,_x1_,_x3_));
|
||||
//
|
||||
//// Bayes Tree for sqrtSAM example
|
||||
//SymbolicBayesTreeOrdered createSlamSymbolicBayesTree(){
|
||||
// // Create using insert
|
||||
//// Ordering slamOrdering; slamOrdering += _x3_, _x2_, _x1_, _l2_, _l1_;
|
||||
// SymbolicBayesTreeOrdered bayesTree_slam;
|
||||
// bayesTree_slam.insert(x3);
|
||||
// bayesTree_slam.insert(x2);
|
||||
// bayesTree_slam.insert(x1);
|
||||
// bayesTree_slam.insert(l2);
|
||||
// bayesTree_slam.insert(l1);
|
||||
// return bayesTree_slam;
|
||||
//}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Conditionals for ASIA example from the tutorial with A and D evidence
|
||||
static const Index _X_=0, _T_=1, _S_=2, _E_=3, _L_=4, _B_=5;
|
||||
static IndexConditionalOrdered::shared_ptr
|
||||
B(new IndexConditionalOrdered(_B_)),
|
||||
L(new IndexConditionalOrdered(_L_, _B_)),
|
||||
E(new IndexConditionalOrdered(_E_, _L_, _B_)),
|
||||
S(new IndexConditionalOrdered(_S_, _L_, _B_)),
|
||||
T(new IndexConditionalOrdered(_T_, _E_, _L_)),
|
||||
X(new IndexConditionalOrdered(_X_, _E_));
|
||||
|
||||
// Cliques
|
||||
static IndexConditionalOrdered::shared_ptr
|
||||
ELB(IndexConditionalOrdered::FromKeys(cref_list_of<3>(_E_)(_L_)(_B_), 3));
|
||||
|
||||
// Bayes Tree for Asia example
|
||||
static SymbolicBayesTreeOrdered createAsiaSymbolicBayesTree() {
|
||||
SymbolicBayesTreeOrdered bayesTree;
|
||||
// Ordering asiaOrdering; asiaOrdering += _X_, _T_, _S_, _E_, _L_, _B_;
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, B);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, L);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, E);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, S);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, T);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, X);
|
||||
return bayesTree;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, constructor )
|
||||
{
|
||||
// Create using insert
|
||||
SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree();
|
||||
|
||||
bayesTree.print("bayesTree (ordered): ");
|
||||
|
||||
// Check Size
|
||||
LONGS_EQUAL(4,bayesTree.size());
|
||||
EXPECT(!bayesTree.empty());
|
||||
|
||||
// Check root
|
||||
boost::shared_ptr<IndexConditionalOrdered> actual_root = bayesTree.root()->conditional();
|
||||
CHECK(assert_equal(*ELB,*actual_root));
|
||||
|
||||
// Create from symbolic Bayes chain in which we want to discover cliques
|
||||
BayesNetOrdered<IndexConditionalOrdered> ASIA;
|
||||
ASIA.push_back(X);
|
||||
ASIA.push_back(T);
|
||||
ASIA.push_back(S);
|
||||
ASIA.push_back(E);
|
||||
ASIA.push_back(L);
|
||||
ASIA.push_back(B);
|
||||
SymbolicBayesTreeOrdered bayesTree2(ASIA);
|
||||
|
||||
// Check whether the same
|
||||
CHECK(assert_equal(bayesTree,bayesTree2));
|
||||
|
||||
// CHECK findParentClique, should *not depend on order of parents*
|
||||
// Ordering ordering; ordering += _X_, _T_, _S_, _E_, _L_, _B_;
|
||||
// IndexTable<Symbol> index(ordering);
|
||||
|
||||
list<Index> parents1; parents1 += _E_, _L_;
|
||||
CHECK(assert_equal(_E_, bayesTree.findParentClique(parents1)));
|
||||
|
||||
list<Index> parents2; parents2 += _L_, _E_;
|
||||
CHECK(assert_equal(_E_, bayesTree.findParentClique(parents2)));
|
||||
|
||||
list<Index> parents3; parents3 += _L_, _B_;
|
||||
CHECK(assert_equal(_L_, bayesTree.findParentClique(parents3)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(BayesTreeOrdered, clear)
|
||||
{
|
||||
// SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree();
|
||||
// bayesTree.clear();
|
||||
//
|
||||
// SymbolicBayesTreeOrdered expected;
|
||||
//
|
||||
// // Check whether cleared BayesTreeOrdered is equal to a new BayesTreeOrdered
|
||||
// CHECK(assert_equal(expected, bayesTree));
|
||||
}
|
||||
|
||||
/* ************************************************************************* *
|
||||
Bayes Tree for testing conversion to a forest of orphans needed for incremental.
|
||||
A,B
|
||||
C|A E|B
|
||||
D|C F|E
|
||||
*/
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, removePath )
|
||||
{
|
||||
const Index _A_=5, _B_=4, _C_=3, _D_=2, _E_=1, _F_=0;
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
A(new IndexConditionalOrdered(_A_)),
|
||||
B(new IndexConditionalOrdered(_B_, _A_)),
|
||||
C(new IndexConditionalOrdered(_C_, _A_)),
|
||||
D(new IndexConditionalOrdered(_D_, _C_)),
|
||||
E(new IndexConditionalOrdered(_E_, _B_)),
|
||||
F(new IndexConditionalOrdered(_F_, _E_));
|
||||
SymbolicBayesTreeOrdered bayesTree;
|
||||
EXPECT(bayesTree.empty());
|
||||
// Ordering ord; ord += _A_,_B_,_C_,_D_,_E_,_F_;
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, A);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, B);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, C);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, D);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, E);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, F);
|
||||
|
||||
// remove C, expected outcome: factor graph with ABC,
|
||||
// Bayes Tree now contains two orphan trees: D|C and E|B,F|E
|
||||
SymbolicFactorGraphOrdered expected;
|
||||
expected.push_factor(_B_,_A_);
|
||||
// expected.push_factor(_A_);
|
||||
expected.push_factor(_C_,_A_);
|
||||
SymbolicBayesTreeOrdered::Cliques expectedOrphans;
|
||||
expectedOrphans += bayesTree[_D_], bayesTree[_E_];
|
||||
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans;
|
||||
bayesTree.removePath(bayesTree[_C_], bn, orphans);
|
||||
SymbolicFactorGraphOrdered factors(bn);
|
||||
CHECK(assert_equal((SymbolicFactorGraphOrdered)expected, factors));
|
||||
CHECK(assert_equal(expectedOrphans, orphans));
|
||||
|
||||
// remove E: factor graph with EB; E|B removed from second orphan tree
|
||||
SymbolicFactorGraphOrdered expected2;
|
||||
expected2.push_factor(_E_,_B_);
|
||||
SymbolicBayesTreeOrdered::Cliques expectedOrphans2;
|
||||
expectedOrphans2 += bayesTree[_F_];
|
||||
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn2;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans2;
|
||||
bayesTree.removePath(bayesTree[_E_], bn2, orphans2);
|
||||
SymbolicFactorGraphOrdered factors2(bn2);
|
||||
CHECK(assert_equal((SymbolicFactorGraphOrdered)expected2, factors2));
|
||||
CHECK(assert_equal(expectedOrphans2, orphans2));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, removePath2 )
|
||||
{
|
||||
SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree();
|
||||
|
||||
// Call remove-path with clique B
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans;
|
||||
bayesTree.removePath(bayesTree[_B_], bn, orphans);
|
||||
SymbolicFactorGraphOrdered factors(bn);
|
||||
|
||||
// Check expected outcome
|
||||
SymbolicFactorGraphOrdered expected;
|
||||
expected.push_factor(_E_,_L_,_B_);
|
||||
// expected.push_factor(_L_,_B_);
|
||||
// expected.push_factor(_B_);
|
||||
CHECK(assert_equal(expected, factors));
|
||||
SymbolicBayesTreeOrdered::Cliques expectedOrphans;
|
||||
expectedOrphans += bayesTree[_S_], bayesTree[_T_], bayesTree[_X_];
|
||||
CHECK(assert_equal(expectedOrphans, orphans));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, removePath3 )
|
||||
{
|
||||
SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree();
|
||||
|
||||
// Call remove-path with clique S
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans;
|
||||
bayesTree.removePath(bayesTree[_S_], bn, orphans);
|
||||
SymbolicFactorGraphOrdered factors(bn);
|
||||
|
||||
// Check expected outcome
|
||||
SymbolicFactorGraphOrdered expected;
|
||||
expected.push_factor(_E_,_L_,_B_);
|
||||
// expected.push_factor(_L_,_B_);
|
||||
// expected.push_factor(_B_);
|
||||
expected.push_factor(_S_,_L_,_B_);
|
||||
CHECK(assert_equal(expected, factors));
|
||||
SymbolicBayesTreeOrdered::Cliques expectedOrphans;
|
||||
expectedOrphans += bayesTree[_T_], bayesTree[_X_];
|
||||
CHECK(assert_equal(expectedOrphans, orphans));
|
||||
}
|
||||
|
||||
void getAllCliques(const SymbolicBayesTreeOrdered::sharedClique& subtree, SymbolicBayesTreeOrdered::Cliques& cliques) {
|
||||
// Check if subtree exists
|
||||
if (subtree) {
|
||||
cliques.push_back(subtree);
|
||||
// Recursive call over all child cliques
|
||||
BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& childClique, subtree->children()) {
|
||||
getAllCliques(childClique,cliques);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, shortcutCheck )
|
||||
{
|
||||
const Index _A_=6, _B_=5, _C_=4, _D_=3, _E_=2, _F_=1, _G_=0;
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
A(new IndexConditionalOrdered(_A_)),
|
||||
B(new IndexConditionalOrdered(_B_, _A_)),
|
||||
C(new IndexConditionalOrdered(_C_, _A_)),
|
||||
D(new IndexConditionalOrdered(_D_, _C_)),
|
||||
E(new IndexConditionalOrdered(_E_, _B_)),
|
||||
F(new IndexConditionalOrdered(_F_, _E_)),
|
||||
G(new IndexConditionalOrdered(_G_, _F_));
|
||||
SymbolicBayesTreeOrdered bayesTree;
|
||||
// Ordering ord; ord += _A_,_B_,_C_,_D_,_E_,_F_;
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, A);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, B);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, C);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, D);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, E);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, F);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, G);
|
||||
|
||||
//bayesTree.print("BayesTreeOrdered");
|
||||
//bayesTree.saveGraph("BT1.dot");
|
||||
|
||||
SymbolicBayesTreeOrdered::sharedClique rootClique= bayesTree.root();
|
||||
//rootClique->printTree();
|
||||
SymbolicBayesTreeOrdered::Cliques allCliques;
|
||||
getAllCliques(rootClique,allCliques);
|
||||
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn;
|
||||
BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& clique, allCliques) {
|
||||
//clique->print("Clique#");
|
||||
bn = clique->shortcut(rootClique, &EliminateSymbolic);
|
||||
//bn.print("Shortcut:\n");
|
||||
//cout << endl;
|
||||
}
|
||||
|
||||
// Check if all the cached shortcuts are cleared
|
||||
rootClique->deleteCachedShortcuts();
|
||||
BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& clique, allCliques) {
|
||||
bool notCleared = clique->cachedSeparatorMarginal();
|
||||
CHECK( notCleared == false);
|
||||
}
|
||||
EXPECT_LONGS_EQUAL(0, rootClique->numCachedSeparatorMarginals());
|
||||
|
||||
// BOOST_FOREACH(SymbolicBayesTreeOrdered::sharedClique& clique, allCliques) {
|
||||
// clique->print("Clique#");
|
||||
// if(clique->cachedShortcut()){
|
||||
// bn = clique->cachedShortcut().get();
|
||||
// bn.print("Shortcut:\n");
|
||||
// }
|
||||
// else
|
||||
// cout << "Not Initialized" << endl;
|
||||
// cout << endl;
|
||||
// }
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, removeTop )
|
||||
{
|
||||
SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree();
|
||||
|
||||
// create a new factor to be inserted
|
||||
boost::shared_ptr<IndexFactorOrdered> newFactor(new IndexFactorOrdered(_S_,_B_));
|
||||
|
||||
// Remove the contaminated part of the Bayes tree
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans;
|
||||
list<Index> keys; keys += _B_,_S_;
|
||||
bayesTree.removeTop(keys, bn, orphans);
|
||||
SymbolicFactorGraphOrdered factors(bn);
|
||||
|
||||
// Check expected outcome
|
||||
SymbolicFactorGraphOrdered expected;
|
||||
expected.push_factor(_E_,_L_,_B_);
|
||||
// expected.push_factor(_L_,_B_);
|
||||
// expected.push_factor(_B_);
|
||||
expected.push_factor(_S_,_L_,_B_);
|
||||
CHECK(assert_equal(expected, factors));
|
||||
SymbolicBayesTreeOrdered::Cliques expectedOrphans;
|
||||
expectedOrphans += bayesTree[_T_], bayesTree[_X_];
|
||||
CHECK(assert_equal(expectedOrphans, orphans));
|
||||
|
||||
// Try removeTop again with a factor that should not change a thing
|
||||
boost::shared_ptr<IndexFactorOrdered> newFactor2(new IndexFactorOrdered(_B_));
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn2;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans2;
|
||||
keys.clear(); keys += _B_;
|
||||
bayesTree.removeTop(keys, bn2, orphans2);
|
||||
SymbolicFactorGraphOrdered factors2(bn2);
|
||||
SymbolicFactorGraphOrdered expected2;
|
||||
CHECK(assert_equal(expected2, factors2));
|
||||
SymbolicBayesTreeOrdered::Cliques expectedOrphans2;
|
||||
CHECK(assert_equal(expectedOrphans2, orphans2));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, removeTop2 )
|
||||
{
|
||||
SymbolicBayesTreeOrdered bayesTree = createAsiaSymbolicBayesTree();
|
||||
|
||||
// create two factors to be inserted
|
||||
SymbolicFactorGraphOrdered newFactors;
|
||||
newFactors.push_factor(_B_);
|
||||
newFactors.push_factor(_S_);
|
||||
|
||||
// Remove the contaminated part of the Bayes tree
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans;
|
||||
list<Index> keys; keys += _B_,_S_;
|
||||
bayesTree.removeTop(keys, bn, orphans);
|
||||
SymbolicFactorGraphOrdered factors(bn);
|
||||
|
||||
// Check expected outcome
|
||||
SymbolicFactorGraphOrdered expected;
|
||||
expected.push_factor(_E_,_L_,_B_);
|
||||
// expected.push_factor(_L_,_B_);
|
||||
// expected.push_factor(_B_);
|
||||
expected.push_factor(_S_,_L_,_B_);
|
||||
CHECK(assert_equal(expected, factors));
|
||||
SymbolicBayesTreeOrdered::Cliques expectedOrphans;
|
||||
expectedOrphans += bayesTree[_T_], bayesTree[_X_];
|
||||
CHECK(assert_equal(expectedOrphans, orphans));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, removeTop3 )
|
||||
{
|
||||
const Index _x4_=5, _l5_=6;
|
||||
// simple test case that failed after COLAMD was fixed/activated
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
X(new IndexConditionalOrdered(_l5_)),
|
||||
A(new IndexConditionalOrdered(_x4_, _l5_)),
|
||||
B(new IndexConditionalOrdered(_x2_, _x4_)),
|
||||
C(new IndexConditionalOrdered(_x3_, _x2_));
|
||||
|
||||
// Ordering newOrdering;
|
||||
// newOrdering += _x3_, _x2_, _x1_, _l2_, _l1_, _x4_, _l5_;
|
||||
SymbolicBayesTreeOrdered bayesTree;
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, X);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, A);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, B);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTree, C);
|
||||
|
||||
// remove all
|
||||
list<Index> keys;
|
||||
keys += _l5_, _x2_, _x3_, _x4_;
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn;
|
||||
SymbolicBayesTreeOrdered::Cliques orphans;
|
||||
bayesTree.removeTop(keys, bn, orphans);
|
||||
SymbolicFactorGraphOrdered factors(bn);
|
||||
|
||||
CHECK(orphans.size() == 0);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( BayesTreeOrdered, permute )
|
||||
{
|
||||
// creates a permutation and ensures that the nodes listing is updated
|
||||
|
||||
// initial keys - more than just 6 variables - for a system with 9 variables
|
||||
const Index _A0_=8, _B0_=7, _C0_=6, _D0_=5, _E0_=4, _F0_=0;
|
||||
|
||||
// reduced keys - back to just 6 variables
|
||||
const Index _A_=5, _B_=4, _C_=3, _D_=2, _E_=1, _F_=0;
|
||||
|
||||
// Create and verify the permutation
|
||||
std::set<Index> indices; indices += _A0_, _B0_, _C0_, _D0_, _E0_, _F0_;
|
||||
Permutation actReducingPermutation = gtsam::internal::createReducingPermutation(indices);
|
||||
Permutation expReducingPermutation(6);
|
||||
expReducingPermutation[_A_] = _A0_;
|
||||
expReducingPermutation[_B_] = _B0_;
|
||||
expReducingPermutation[_C_] = _C0_;
|
||||
expReducingPermutation[_D_] = _D0_;
|
||||
expReducingPermutation[_E_] = _E0_;
|
||||
expReducingPermutation[_F_] = _F0_;
|
||||
EXPECT(assert_equal(expReducingPermutation, actReducingPermutation));
|
||||
|
||||
// Invert the permutation
|
||||
gtsam::internal::Reduction inv_reduction = gtsam::internal::Reduction::CreateAsInverse(expReducingPermutation);
|
||||
|
||||
// Build a bayes tree around reduced keys as if just eliminated from subset of factors/variables
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
A(new IndexConditionalOrdered(_A_)),
|
||||
B(new IndexConditionalOrdered(_B_, _A_)),
|
||||
C(new IndexConditionalOrdered(_C_, _A_)),
|
||||
D(new IndexConditionalOrdered(_D_, _C_)),
|
||||
E(new IndexConditionalOrdered(_E_, _B_)),
|
||||
F(new IndexConditionalOrdered(_F_, _E_));
|
||||
SymbolicBayesTreeOrdered bayesTreeReduced;
|
||||
SymbolicBayesTreeOrdered::insert(bayesTreeReduced, A);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTreeReduced, B);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTreeReduced, C);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTreeReduced, D);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTreeReduced, E);
|
||||
SymbolicBayesTreeOrdered::insert(bayesTreeReduced, F);
|
||||
|
||||
// bayesTreeReduced.print("Reduced bayes tree");
|
||||
// P( 4 5)
|
||||
// P( 3 | 5)
|
||||
// P( 2 | 3)
|
||||
// P( 1 | 4)
|
||||
// P( 0 | 1)
|
||||
|
||||
// Apply the permutation - should add placeholders for variables not present in nodes
|
||||
SymbolicBayesTreeOrdered actBayesTree = *bayesTreeReduced.clone();
|
||||
actBayesTree.permuteWithInverse(expReducingPermutation);
|
||||
|
||||
// actBayesTree.print("Full bayes tree");
|
||||
// P( 7 8)
|
||||
// P( 6 | 8)
|
||||
// P( 5 | 6)
|
||||
// P( 4 | 7)
|
||||
// P( 0 | 4)
|
||||
|
||||
// check keys in cliques
|
||||
std::vector<Index> expRootIndices; expRootIndices += _B0_, _A0_;
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
expRoot(new IndexConditionalOrdered(expRootIndices, 2)), // root
|
||||
A0(new IndexConditionalOrdered(_A0_)),
|
||||
B0(new IndexConditionalOrdered(_B0_, _A0_)),
|
||||
C0(new IndexConditionalOrdered(_C0_, _A0_)), // leaf level 1
|
||||
D0(new IndexConditionalOrdered(_D0_, _C0_)), // leaf level 2
|
||||
E0(new IndexConditionalOrdered(_E0_, _B0_)), // leaf level 2
|
||||
F0(new IndexConditionalOrdered(_F0_, _E0_)); // leaf level 3
|
||||
|
||||
CHECK(actBayesTree.root());
|
||||
EXPECT(assert_equal(*expRoot, *actBayesTree.root()->conditional()));
|
||||
EXPECT(assert_equal(*C0, *actBayesTree.root()->children().front()->conditional()));
|
||||
EXPECT(assert_equal(*D0, *actBayesTree.root()->children().front()->children().front()->conditional()));
|
||||
EXPECT(assert_equal(*E0, *actBayesTree.root()->children().back()->conditional()));
|
||||
EXPECT(assert_equal(*F0, *actBayesTree.root()->children().back()->children().front()->conditional()));
|
||||
|
||||
// check nodes structure
|
||||
LONGS_EQUAL(9, actBayesTree.nodes().size());
|
||||
|
||||
SymbolicBayesTreeOrdered expFullTree;
|
||||
SymbolicBayesTreeOrdered::insert(expFullTree, A0);
|
||||
SymbolicBayesTreeOrdered::insert(expFullTree, B0);
|
||||
SymbolicBayesTreeOrdered::insert(expFullTree, C0);
|
||||
SymbolicBayesTreeOrdered::insert(expFullTree, D0);
|
||||
SymbolicBayesTreeOrdered::insert(expFullTree, E0);
|
||||
SymbolicBayesTreeOrdered::insert(expFullTree, F0);
|
||||
|
||||
EXPECT(assert_equal(expFullTree, actBayesTree));
|
||||
}
|
||||
|
||||
///* ************************************************************************* */
|
||||
///**
|
||||
// * x2 - x3 - x4 - x5
|
||||
// * | / \ |
|
||||
// * x1 / \ x6
|
||||
// */
|
||||
//TEST( BayesTreeOrdered, insert )
|
||||
//{
|
||||
// // construct bayes tree by split the graph along the separator x3 - x4
|
||||
// const Index _x1_=0, _x2_=1, _x6_=2, _x5_=3, _x3_=4, _x4_=5;
|
||||
// SymbolicFactorGraphOrdered fg1, fg2, fg3;
|
||||
// fg1.push_factor(_x3_, _x4_);
|
||||
// fg2.push_factor(_x1_, _x2_);
|
||||
// fg2.push_factor(_x2_, _x3_);
|
||||
// fg2.push_factor(_x1_, _x3_);
|
||||
// fg3.push_factor(_x5_, _x4_);
|
||||
// fg3.push_factor(_x6_, _x5_);
|
||||
// fg3.push_factor(_x6_, _x4_);
|
||||
//
|
||||
//// Ordering ordering1; ordering1 += _x3_, _x4_;
|
||||
//// Ordering ordering2; ordering2 += _x1_, _x2_;
|
||||
//// Ordering ordering3; ordering3 += _x6_, _x5_;
|
||||
//
|
||||
// BayesNetOrdered<IndexConditionalOrdered> bn1, bn2, bn3;
|
||||
// bn1 = *SymbolicSequentialSolver::EliminateUntil(fg1, _x4_+1);
|
||||
// bn2 = *SymbolicSequentialSolver::EliminateUntil(fg2, _x2_+1);
|
||||
// bn3 = *SymbolicSequentialSolver::EliminateUntil(fg3, _x5_+1);
|
||||
//
|
||||
// // insert child cliques
|
||||
// SymbolicBayesTreeOrdered actual;
|
||||
// list<SymbolicBayesTreeOrdered::sharedClique> children;
|
||||
// SymbolicBayesTreeOrdered::sharedClique r1 = actual.insert(bn2, children);
|
||||
// SymbolicBayesTreeOrdered::sharedClique r2 = actual.insert(bn3, children);
|
||||
//
|
||||
// // insert root clique
|
||||
// children.push_back(r1);
|
||||
// children.push_back(r2);
|
||||
// actual.insert(bn1, children, true);
|
||||
//
|
||||
// // traditional way
|
||||
// SymbolicFactorGraphOrdered fg;
|
||||
// fg.push_factor(_x3_, _x4_);
|
||||
// fg.push_factor(_x1_, _x2_);
|
||||
// fg.push_factor(_x2_, _x3_);
|
||||
// fg.push_factor(_x1_, _x3_);
|
||||
// fg.push_factor(_x5_, _x4_);
|
||||
// fg.push_factor(_x6_, _x5_);
|
||||
// fg.push_factor(_x6_, _x4_);
|
||||
//
|
||||
//// Ordering ordering; ordering += _x1_, _x2_, _x6_, _x5_, _x3_, _x4_;
|
||||
// BayesNetOrdered<IndexConditionalOrdered> bn(*SymbolicSequentialSolver(fg).eliminate());
|
||||
// SymbolicBayesTreeOrdered expected(bn);
|
||||
// CHECK(assert_equal(expected, actual));
|
||||
//
|
||||
//}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testClusterTree.cpp
|
||||
* @brief Unit tests for Bayes Tree
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/ClusterTreeOrdered.h>
|
||||
|
||||
using namespace gtsam;
|
||||
|
||||
// explicit instantiation and typedef
|
||||
namespace gtsam { template class ClusterTreeOrdered<SymbolicFactorGraphOrdered>; }
|
||||
typedef ClusterTreeOrdered<SymbolicFactorGraphOrdered> SymbolicClusterTree;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(ClusterTreeOrdered, constructor) {
|
||||
SymbolicClusterTree tree;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testConditional.cpp
|
||||
* @brief Unit tests for IndexConditional class
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
#include <boost/assign/std/vector.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, empty )
|
||||
{
|
||||
IndexConditionalOrdered c0;
|
||||
LONGS_EQUAL(0,c0.nrFrontals())
|
||||
LONGS_EQUAL(0,c0.nrParents())
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, noParents )
|
||||
{
|
||||
IndexConditionalOrdered c0(0);
|
||||
LONGS_EQUAL(1,c0.nrFrontals())
|
||||
LONGS_EQUAL(0,c0.nrParents())
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, oneParents )
|
||||
{
|
||||
IndexConditionalOrdered c0(0,1);
|
||||
LONGS_EQUAL(1,c0.nrFrontals())
|
||||
LONGS_EQUAL(1,c0.nrParents())
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, twoParents )
|
||||
{
|
||||
IndexConditionalOrdered c0(0,1,2);
|
||||
LONGS_EQUAL(1,c0.nrFrontals())
|
||||
LONGS_EQUAL(2,c0.nrParents())
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, threeParents )
|
||||
{
|
||||
IndexConditionalOrdered c0(0,1,2,3);
|
||||
LONGS_EQUAL(1,c0.nrFrontals())
|
||||
LONGS_EQUAL(3,c0.nrParents())
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, fourParents )
|
||||
{
|
||||
vector<Index> parents;
|
||||
parents += 1,2,3,4;
|
||||
IndexConditionalOrdered c0(0,parents);
|
||||
LONGS_EQUAL(1,c0.nrFrontals())
|
||||
LONGS_EQUAL(4,c0.nrParents())
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, FromRange )
|
||||
{
|
||||
vector<Index> keys;
|
||||
keys += 1,2,3,4,5;
|
||||
IndexConditionalOrdered::shared_ptr c0(new IndexConditionalOrdered(keys,2));
|
||||
LONGS_EQUAL(2,c0->nrFrontals())
|
||||
LONGS_EQUAL(3,c0->nrParents())
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( IndexConditionalOrdered, equals )
|
||||
{
|
||||
IndexConditionalOrdered c0(0, 1, 2), c1(0, 1, 2), c2(1, 2, 3), c3(3,4);
|
||||
CHECK(c0.equals(c1));
|
||||
CHECK(c1.equals(c0));
|
||||
CHECK(!c0.equals(c2));
|
||||
CHECK(!c2.equals(c0));
|
||||
CHECK(!c0.equals(c3));
|
||||
CHECK(!c3.equals(c0));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testEliminationTree.cpp
|
||||
* @brief
|
||||
* @author Richard Roberts
|
||||
* @date Oct 14, 2010
|
||||
*/
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
|
||||
#include <gtsam/inference/EliminationTreeOrdered-inl.h>
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
|
||||
using namespace gtsam;
|
||||
using namespace std;
|
||||
|
||||
class EliminationTreeOrderedTester {
|
||||
public:
|
||||
// build hardcoded tree
|
||||
static SymbolicEliminationTreeOrdered::shared_ptr buildHardcodedTree(const SymbolicFactorGraphOrdered& fg) {
|
||||
|
||||
SymbolicEliminationTreeOrdered::shared_ptr leaf0(new SymbolicEliminationTreeOrdered);
|
||||
leaf0->add(fg[0]);
|
||||
leaf0->add(fg[1]);
|
||||
|
||||
SymbolicEliminationTreeOrdered::shared_ptr node1(new SymbolicEliminationTreeOrdered(1));
|
||||
node1->add(fg[2]);
|
||||
node1->add(leaf0);
|
||||
|
||||
SymbolicEliminationTreeOrdered::shared_ptr node2(new SymbolicEliminationTreeOrdered(2));
|
||||
node2->add(fg[3]);
|
||||
node2->add(node1);
|
||||
|
||||
SymbolicEliminationTreeOrdered::shared_ptr leaf3(new SymbolicEliminationTreeOrdered(3));
|
||||
leaf3->add(fg[4]);
|
||||
|
||||
SymbolicEliminationTreeOrdered::shared_ptr etree(new SymbolicEliminationTreeOrdered(4));
|
||||
etree->add(leaf3);
|
||||
etree->add(node2);
|
||||
|
||||
return etree;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(EliminationTreeOrdered, Create)
|
||||
{
|
||||
// create example factor graph
|
||||
SymbolicFactorGraphOrdered fg;
|
||||
fg.push_factor(0, 1);
|
||||
fg.push_factor(0, 2);
|
||||
fg.push_factor(1, 4);
|
||||
fg.push_factor(2, 4);
|
||||
fg.push_factor(3, 4);
|
||||
|
||||
SymbolicEliminationTreeOrdered::shared_ptr expected = EliminationTreeOrderedTester::buildHardcodedTree(fg);
|
||||
|
||||
// Build from factor graph
|
||||
SymbolicEliminationTreeOrdered::shared_ptr actual = SymbolicEliminationTreeOrdered::Create(fg);
|
||||
|
||||
CHECK(assert_equal(*expected,*actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Test to drive elimination tree development
|
||||
// graph: f(0,1) f(0,2) f(1,4) f(2,4) f(3,4)
|
||||
/* ************************************************************************* */
|
||||
|
||||
TEST(EliminationTreeOrdered, eliminate )
|
||||
{
|
||||
// create expected Chordal bayes Net
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(3,4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(2,4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(1,2,4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(0,1,2));
|
||||
|
||||
// Create factor graph
|
||||
SymbolicFactorGraphOrdered fg;
|
||||
fg.push_factor(0, 1);
|
||||
fg.push_factor(0, 2);
|
||||
fg.push_factor(1, 4);
|
||||
fg.push_factor(2, 4);
|
||||
fg.push_factor(3, 4);
|
||||
|
||||
// eliminate
|
||||
SymbolicBayesNetOrdered actual = *SymbolicSequentialSolver(fg).eliminate();
|
||||
|
||||
CHECK(assert_equal(expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(EliminationTreeOrdered, disconnected_graph) {
|
||||
SymbolicFactorGraphOrdered fg;
|
||||
fg.push_factor(0, 1);
|
||||
fg.push_factor(0, 2);
|
||||
fg.push_factor(1, 2);
|
||||
fg.push_factor(3, 4);
|
||||
|
||||
CHECK_EXCEPTION(SymbolicEliminationTreeOrdered::Create(fg), DisconnectedGraphException);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testFactorgraph.cpp
|
||||
* @brief Unit tests for IndexFactor Graphs
|
||||
* @author Christian Potthast
|
||||
**/
|
||||
|
||||
/*STL/C++*/
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/assign/std/set.hpp> // for operator +=
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(FactorGraphOrdered, eliminateFrontals) {
|
||||
|
||||
SymbolicFactorGraphOrdered sfgOrig;
|
||||
sfgOrig.push_factor(0,1);
|
||||
sfgOrig.push_factor(0,2);
|
||||
sfgOrig.push_factor(1,3);
|
||||
sfgOrig.push_factor(1,4);
|
||||
sfgOrig.push_factor(2,3);
|
||||
sfgOrig.push_factor(4,5);
|
||||
|
||||
IndexConditionalOrdered::shared_ptr actualCond;
|
||||
SymbolicFactorGraphOrdered actualSfg;
|
||||
boost::tie(actualCond, actualSfg) = sfgOrig.eliminateFrontals(2);
|
||||
|
||||
vector<Index> condIndices;
|
||||
condIndices += 0,1,2,3,4;
|
||||
IndexConditionalOrdered expectedCond(condIndices, 2);
|
||||
|
||||
SymbolicFactorGraphOrdered expectedSfg;
|
||||
expectedSfg.push_factor(2,3);
|
||||
expectedSfg.push_factor(4,5);
|
||||
expectedSfg.push_factor(2,3,4);
|
||||
|
||||
EXPECT(assert_equal(expectedSfg, actualSfg));
|
||||
EXPECT(assert_equal(expectedCond, *actualCond));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testISAM.cpp
|
||||
* @brief Unit tests for ISAM
|
||||
* @author Michael Kaess
|
||||
*/
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/ISAMOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
typedef ISAMOrdered<IndexConditionalOrdered> SymbolicISAM;
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Some numbers that should be consistent among all smoother tests
|
||||
|
||||
//static double sigmax1 = 0.786153, sigmax2 = 0.687131 ,sigmax3 = 0.671512,
|
||||
//sigmax4 = 0.669534, sigmax5 = sigmax3,, sigmax7 = sigmax1, sigmax6 = sigmax2;
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
//// SLAM example from RSS sqrtSAM paper
|
||||
//SymbolicConditional::shared_ptr x3(new SymbolicConditional("x3")),
|
||||
// x2(new SymbolicConditional("x2","x3")),
|
||||
// x1(new SymbolicConditional("x1","x2","x3")),
|
||||
// l1(new SymbolicConditional("l1","x1","x2")),
|
||||
// l2(new SymbolicConditional("l2","x1","x3"));
|
||||
//
|
||||
//// ISAM for sqrtSAM example
|
||||
//SymbolicISAM createSlamSymbolicISAM(){
|
||||
// // Create using insert
|
||||
// SymbolicISAM bayesTree_slam;
|
||||
// bayesTree_slam.insert(x3);
|
||||
// bayesTree_slam.insert(x2);
|
||||
// bayesTree_slam.insert(x1);
|
||||
// bayesTree_slam.insert(l2);
|
||||
// bayesTree_slam.insert(l1);
|
||||
// return bayesTree_slam;
|
||||
//}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
//// Conditionals for ASIA example from the tutorial with A and D evidence
|
||||
//SymbolicConditional::shared_ptr
|
||||
// B(new SymbolicConditional("B")),
|
||||
// L(new SymbolicConditional("L", "B")),
|
||||
// E(new SymbolicConditional("E", "B", "L")),
|
||||
// S(new SymbolicConditional("S", "L", "B")),
|
||||
// T(new SymbolicConditional("T", "E", "L")),
|
||||
// X(new SymbolicConditional("X", "E"));
|
||||
//
|
||||
//// ISAM for Asia example
|
||||
//SymbolicISAM createAsiaSymbolicISAM() {
|
||||
// SymbolicISAM bayesTree;
|
||||
// bayesTree.insert(B);
|
||||
// bayesTree.insert(L);
|
||||
// bayesTree.insert(E);
|
||||
// bayesTree.insert(S);
|
||||
// bayesTree.insert(T);
|
||||
// bayesTree.insert(X);
|
||||
// return bayesTree;
|
||||
//}
|
||||
//
|
||||
///* ************************************************************************* */
|
||||
//TEST( ISAM, iSAM )
|
||||
//{
|
||||
// SymbolicISAM bayesTree = createAsiaSymbolicISAM();
|
||||
//
|
||||
// // Now we modify the Bayes tree by inserting a new factor over B and S
|
||||
//
|
||||
// // New conditionals in modified top of the tree
|
||||
// SymbolicConditional::shared_ptr
|
||||
// S_(new SymbolicConditional("S")),
|
||||
// B_(new SymbolicConditional("B", "S")),
|
||||
// L_(new SymbolicConditional("L", "B", "S"));
|
||||
//
|
||||
// // Create expected Bayes tree
|
||||
// SymbolicISAM expected;
|
||||
// expected.insert(S_);
|
||||
// expected.insert(B_);
|
||||
// expected.insert(L_);
|
||||
// expected.insert(E);
|
||||
// expected.insert(T);
|
||||
// expected.insert(X);
|
||||
//
|
||||
// // create new factors to be inserted
|
||||
// SymbolicFactorGraph factorGraph;
|
||||
// factorGraph.push_factor("B","S");
|
||||
// factorGraph.push_factor("B");
|
||||
//
|
||||
// // do incremental inference
|
||||
// bayesTree.update(factorGraph);
|
||||
//
|
||||
// // Check whether the same
|
||||
// CHECK(assert_equal(expected,bayesTree));
|
||||
//}
|
||||
//
|
||||
///* ************************************************************************* */
|
||||
//TEST( ISAM, iSAM_slam )
|
||||
//{
|
||||
// // Create using insert
|
||||
// SymbolicISAM bayesTree_slam = createSlamSymbolicISAM();
|
||||
//
|
||||
// //New conditionals for the expected Bayes tree
|
||||
// SymbolicConditional::shared_ptr
|
||||
// l1_(new SymbolicConditional("l1","x1","x2","x3"));
|
||||
//
|
||||
// // Create expected Bayes tree
|
||||
// SymbolicISAM expected_slam;
|
||||
// expected_slam.insert(x3);
|
||||
// expected_slam.insert(x2);
|
||||
// expected_slam.insert(x1);
|
||||
// expected_slam.insert(l1_);
|
||||
// expected_slam.insert(l2);
|
||||
//
|
||||
//
|
||||
// // create new factors to be inserted
|
||||
// SymbolicFactorGraph factorGraph_slam;
|
||||
// factorGraph_slam.push_factor("x3","l1");
|
||||
// factorGraph_slam.push_factor("x3");
|
||||
//
|
||||
// // do incremental inference
|
||||
// bayesTree_slam.update(factorGraph_slam);
|
||||
//
|
||||
// // Check whether the same
|
||||
// CHECK(assert_equal(expected_slam,bayesTree_slam));
|
||||
//}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testJunctionTree.cpp
|
||||
* @brief Unit tests for Junction Tree
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
#include <boost/assign/std/vector.hpp> // for operator +=
|
||||
#include <boost/assign/std/set.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/JunctionTreeOrdered.h>
|
||||
#include <gtsam/inference/ClusterTreeOrdered.h>
|
||||
#include <gtsam/inference/JunctionTreeOrdered.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
|
||||
using namespace gtsam;
|
||||
using namespace std;
|
||||
|
||||
typedef JunctionTreeOrdered<SymbolicFactorGraphOrdered> SymbolicJunctionTree;
|
||||
|
||||
/* ************************************************************************* *
|
||||
* x1 - x2 - x3 - x4
|
||||
* x3 x4
|
||||
* x2 x1 : x3
|
||||
****************************************************************************/
|
||||
TEST( JunctionTreeOrdered, constructor )
|
||||
{
|
||||
const Index x2=0, x1=1, x3=2, x4=3;
|
||||
SymbolicFactorGraphOrdered fg;
|
||||
fg.push_factor(x2,x1);
|
||||
fg.push_factor(x2,x3);
|
||||
fg.push_factor(x3,x4);
|
||||
|
||||
SymbolicJunctionTree actual(fg);
|
||||
|
||||
vector<Index> frontal1; frontal1 += x3, x4;
|
||||
vector<Index> frontal2; frontal2 += x2, x1;
|
||||
vector<Index> sep1;
|
||||
vector<Index> sep2; sep2 += x3;
|
||||
CHECK(assert_equal(frontal1, actual.root()->frontal));
|
||||
CHECK(assert_equal(sep1, actual.root()->separator));
|
||||
LONGS_EQUAL(1, actual.root()->size());
|
||||
CHECK(assert_equal(frontal2, actual.root()->children().front()->frontal));
|
||||
CHECK(assert_equal(sep2, actual.root()->children().front()->separator));
|
||||
LONGS_EQUAL(2, actual.root()->children().front()->size());
|
||||
CHECK(assert_equal(*fg[2], *(*actual.root())[0]));
|
||||
CHECK(assert_equal(*fg[0], *(*actual.root()->children().front())[0]));
|
||||
CHECK(assert_equal(*fg[1], *(*actual.root()->children().front())[1]));
|
||||
}
|
||||
|
||||
/* ************************************************************************* *
|
||||
* x1 - x2 - x3 - x4
|
||||
* x3 x4
|
||||
* x2 x1 : x3
|
||||
****************************************************************************/
|
||||
TEST( JunctionTreeOrdered, eliminate)
|
||||
{
|
||||
const Index x2=0, x1=1, x3=2, x4=3;
|
||||
SymbolicFactorGraphOrdered fg;
|
||||
fg.push_factor(x2,x1);
|
||||
fg.push_factor(x2,x3);
|
||||
fg.push_factor(x3,x4);
|
||||
|
||||
SymbolicJunctionTree jt(fg);
|
||||
SymbolicBayesTreeOrdered::sharedClique actual = jt.eliminate(&EliminateSymbolic);
|
||||
|
||||
BayesNetOrdered<IndexConditionalOrdered> bn(*SymbolicSequentialSolver(fg).eliminate());
|
||||
SymbolicBayesTreeOrdered expected(bn);
|
||||
|
||||
// cout << "BT from JT:\n";
|
||||
// actual->printTree("");
|
||||
|
||||
CHECK(assert_equal(*expected.root(), *actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testPermutation.cpp
|
||||
* @date Sep 22, 2011
|
||||
* @author richard
|
||||
*/
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace gtsam;
|
||||
using namespace std;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(Permutation, Identity) {
|
||||
Permutation expected(5);
|
||||
expected[0] = 0;
|
||||
expected[1] = 1;
|
||||
expected[2] = 2;
|
||||
expected[3] = 3;
|
||||
expected[4] = 4;
|
||||
|
||||
Permutation actual = Permutation::Identity(5);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(Permutation, PullToFront) {
|
||||
Permutation expected(5);
|
||||
expected[0] = 4;
|
||||
expected[1] = 0;
|
||||
expected[2] = 2;
|
||||
expected[3] = 1;
|
||||
expected[4] = 3;
|
||||
|
||||
std::vector<Index> toFront;
|
||||
toFront.push_back(4);
|
||||
toFront.push_back(0);
|
||||
toFront.push_back(2);
|
||||
Permutation actual = Permutation::PullToFront(toFront, 5);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(Permutation, PushToBack) {
|
||||
Permutation expected(5);
|
||||
expected[0] = 1;
|
||||
expected[1] = 3;
|
||||
expected[2] = 4;
|
||||
expected[3] = 0;
|
||||
expected[4] = 2;
|
||||
|
||||
std::vector<Index> toBack;
|
||||
toBack.push_back(4);
|
||||
toBack.push_back(0);
|
||||
toBack.push_back(2);
|
||||
Permutation actual = Permutation::PushToBack(toBack, 5);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(Permutation, compose) {
|
||||
Permutation p1(5);
|
||||
p1[0] = 1;
|
||||
p1[1] = 2;
|
||||
p1[2] = 3;
|
||||
p1[3] = 4;
|
||||
p1[4] = 0;
|
||||
|
||||
Permutation p2(5);
|
||||
p2[0] = 1;
|
||||
p2[1] = 2;
|
||||
p2[2] = 4;
|
||||
p2[3] = 3;
|
||||
p2[4] = 0;
|
||||
|
||||
Permutation expected(5);
|
||||
expected[0] = 2;
|
||||
expected[1] = 3;
|
||||
expected[2] = 0;
|
||||
expected[3] = 4;
|
||||
expected[4] = 1;
|
||||
|
||||
Permutation actual = *p1.permute(p2);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
LONGS_EQUAL(p1[p2[0]], actual[0]);
|
||||
LONGS_EQUAL(p1[p2[1]], actual[1]);
|
||||
LONGS_EQUAL(p1[p2[2]], actual[2]);
|
||||
LONGS_EQUAL(p1[p2[3]], actual[3]);
|
||||
LONGS_EQUAL(p1[p2[4]], actual[4]);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(Reduction, CreateFromPartialPermutation) {
|
||||
Permutation selector(3);
|
||||
selector[0] = 2;
|
||||
selector[1] = 4;
|
||||
selector[2] = 6;
|
||||
Permutation p(3);
|
||||
p[0] = 2;
|
||||
p[1] = 0;
|
||||
p[2] = 1;
|
||||
|
||||
internal::Reduction expected;
|
||||
expected.insert(make_pair(2,6));
|
||||
expected.insert(make_pair(4,2));
|
||||
expected.insert(make_pair(6,4));
|
||||
|
||||
internal::Reduction actual = internal::Reduction::CreateFromPartialPermutation(selector, p);
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
||||
|
||||
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testSymbolicBayesNet.cpp
|
||||
* @brief Unit tests for a symbolic Bayes chain
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <boost/assign/list_inserter.hpp> // for 'insert()'
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
static const Index _L_ = 0;
|
||||
static const Index _A_ = 1;
|
||||
static const Index _B_ = 2;
|
||||
static const Index _C_ = 3;
|
||||
static const Index _D_ = 4;
|
||||
static const Index _E_ = 5;
|
||||
|
||||
static IndexConditionalOrdered::shared_ptr
|
||||
B(new IndexConditionalOrdered(_B_)),
|
||||
L(new IndexConditionalOrdered(_L_, _B_));
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicBayesNetOrdered, equals )
|
||||
{
|
||||
BayesNetOrdered<IndexConditionalOrdered> f1;
|
||||
f1.push_back(B);
|
||||
f1.push_back(L);
|
||||
BayesNetOrdered<IndexConditionalOrdered> f2;
|
||||
f2.push_back(L);
|
||||
f2.push_back(B);
|
||||
CHECK(f1.equals(f1));
|
||||
CHECK(!f1.equals(f2));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicBayesNetOrdered, pop_front )
|
||||
{
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
A(new IndexConditionalOrdered(_A_,_B_,_C_)),
|
||||
B(new IndexConditionalOrdered(_B_,_C_)),
|
||||
C(new IndexConditionalOrdered(_C_));
|
||||
|
||||
// Expected after pop_front
|
||||
BayesNetOrdered<IndexConditionalOrdered> expected;
|
||||
expected.push_back(B);
|
||||
expected.push_back(C);
|
||||
|
||||
// Actual
|
||||
BayesNetOrdered<IndexConditionalOrdered> actual;
|
||||
actual.push_back(A);
|
||||
actual.push_back(B);
|
||||
actual.push_back(C);
|
||||
actual.pop_front();
|
||||
|
||||
CHECK(assert_equal(expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicBayesNetOrdered, combine )
|
||||
{
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
A(new IndexConditionalOrdered(_A_,_B_,_C_)),
|
||||
B(new IndexConditionalOrdered(_B_,_C_)),
|
||||
C(new IndexConditionalOrdered(_C_));
|
||||
|
||||
// p(A|BC)
|
||||
BayesNetOrdered<IndexConditionalOrdered> p_ABC;
|
||||
p_ABC.push_back(A);
|
||||
|
||||
// P(BC)=P(B|C)P(C)
|
||||
BayesNetOrdered<IndexConditionalOrdered> p_BC;
|
||||
p_BC.push_back(B);
|
||||
p_BC.push_back(C);
|
||||
|
||||
// P(ABC) = P(A|BC) P(BC)
|
||||
p_ABC.push_back(p_BC);
|
||||
|
||||
BayesNetOrdered<IndexConditionalOrdered> expected;
|
||||
expected.push_back(A);
|
||||
expected.push_back(B);
|
||||
expected.push_back(C);
|
||||
|
||||
CHECK(assert_equal(expected,p_ABC));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(SymbolicBayesNetOrdered, find) {
|
||||
SymbolicBayesNetOrdered bn;
|
||||
bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_A_, _B_));
|
||||
std::vector<Index> keys;
|
||||
keys.push_back(_B_);
|
||||
keys.push_back(_C_);
|
||||
keys.push_back(_D_);
|
||||
bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(keys,2));
|
||||
bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_D_));
|
||||
|
||||
SymbolicBayesNetOrdered::iterator expected = bn.begin(); ++ expected;
|
||||
SymbolicBayesNetOrdered::iterator actual = bn.find(_C_);
|
||||
EXPECT(assert_equal(**expected, **actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST_UNSAFE(SymbolicBayesNetOrdered, popLeaf) {
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
A(new IndexConditionalOrdered(_A_,_E_)),
|
||||
B(new IndexConditionalOrdered(_B_,_E_)),
|
||||
C(new IndexConditionalOrdered(_C_,_D_)),
|
||||
D(new IndexConditionalOrdered(_D_,_E_)),
|
||||
E(new IndexConditionalOrdered(_E_));
|
||||
|
||||
// BayesNet after popping A
|
||||
SymbolicBayesNetOrdered expected1;
|
||||
expected1 += B, C, D, E;
|
||||
|
||||
// BayesNet after popping C
|
||||
SymbolicBayesNetOrdered expected2;
|
||||
expected2 += A, B, D, E;
|
||||
|
||||
// BayesNet after popping C and D
|
||||
SymbolicBayesNetOrdered expected3;
|
||||
expected3 += A, B, E;
|
||||
|
||||
// BayesNet after popping C and A
|
||||
SymbolicBayesNetOrdered expected4;
|
||||
expected4 += B, D, E;
|
||||
|
||||
|
||||
// BayesNet after popping A
|
||||
SymbolicBayesNetOrdered actual1;
|
||||
actual1 += A, B, C, D, E;
|
||||
actual1.popLeaf(actual1.find(_A_));
|
||||
|
||||
// BayesNet after popping C
|
||||
SymbolicBayesNetOrdered actual2;
|
||||
actual2 += A, B, C, D, E;
|
||||
actual2.popLeaf(actual2.find(_C_));
|
||||
|
||||
// BayesNet after popping C and D
|
||||
SymbolicBayesNetOrdered actual3;
|
||||
actual3 += A, B, C, D, E;
|
||||
actual3.popLeaf(actual3.find(_C_));
|
||||
actual3.popLeaf(actual3.find(_D_));
|
||||
|
||||
// BayesNet after popping C and A
|
||||
SymbolicBayesNetOrdered actual4;
|
||||
actual4 += A, B, C, D, E;
|
||||
actual4.popLeaf(actual4.find(_C_));
|
||||
actual4.popLeaf(actual4.find(_A_));
|
||||
|
||||
EXPECT(assert_equal(expected1, actual1));
|
||||
EXPECT(assert_equal(expected2, actual2));
|
||||
EXPECT(assert_equal(expected3, actual3));
|
||||
EXPECT(assert_equal(expected4, actual4));
|
||||
|
||||
// Try to remove a non-leaf node (this test is not working in non-debug mode)
|
||||
//#undef NDEBUG_SAVED
|
||||
//#ifdef NDEBUG
|
||||
//#define NDEBUG_SAVED
|
||||
//#endif
|
||||
//
|
||||
//#undef NDEBUG
|
||||
// SymbolicBayesNetOrdered actual5;
|
||||
// actual5 += A, B, C, D, E;
|
||||
// CHECK_EXCEPTION(actual5.popLeaf(actual5.find(_D_)), std::invalid_argument);
|
||||
//
|
||||
//#ifdef NDEBUG_SAVED
|
||||
//#define NDEBUG
|
||||
//#endif
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(SymbolicBayesNetOrdered, saveGraph) {
|
||||
SymbolicBayesNetOrdered bn;
|
||||
bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_A_, _B_));
|
||||
std::vector<Index> keys;
|
||||
keys.push_back(_B_);
|
||||
keys.push_back(_C_);
|
||||
keys.push_back(_D_);
|
||||
bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(keys,2));
|
||||
bn += IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(_D_));
|
||||
|
||||
bn.saveGraph("SymbolicBayesNet.dot");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,323 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testSymbolicBayesTree.cpp
|
||||
* @date sept 15, 2012
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
static bool debug = false;
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
TEST_UNSAFE( SymbolicBayesTreeOrdered, thinTree ) {
|
||||
|
||||
// create a thin-tree Bayesnet, a la Jean-Guillaume
|
||||
SymbolicBayesNetOrdered bayesNet;
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(14));
|
||||
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(13, 14));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(12, 14));
|
||||
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(11, 13, 14));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(10, 13, 14));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(9, 12, 14));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(8, 12, 14));
|
||||
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(7, 11, 13));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(6, 11, 13));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(5, 10, 13));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(4, 10, 13));
|
||||
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(3, 9, 12));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(2, 9, 12));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(1, 8, 12));
|
||||
bayesNet.push_front(boost::make_shared<IndexConditionalOrdered>(0, 8, 12));
|
||||
|
||||
if (debug) {
|
||||
GTSAM_PRINT(bayesNet);
|
||||
bayesNet.saveGraph("/tmp/symbolicBayesNet.dot");
|
||||
}
|
||||
|
||||
// create a BayesTree out of a Bayes net
|
||||
SymbolicBayesTreeOrdered bayesTree(bayesNet);
|
||||
if (debug) {
|
||||
GTSAM_PRINT(bayesTree);
|
||||
bayesTree.saveGraph("/tmp/symbolicBayesTree.dot");
|
||||
}
|
||||
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr R = bayesTree.root();
|
||||
|
||||
{
|
||||
// check shortcut P(S9||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[9];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
{
|
||||
// check shortcut P(S8||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[8];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(12, 14));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
{
|
||||
// check shortcut P(S4||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[4];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(10, 13, 14));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
{
|
||||
// check shortcut P(S2||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[2];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(12, 14));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(9, 12, 14));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
{
|
||||
// check shortcut P(S0||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[0];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(12, 14));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(8, 12, 14));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
SymbolicBayesNetOrdered::shared_ptr actualJoint;
|
||||
|
||||
// Check joint P(8,2)
|
||||
if (false) { // TODO, not disjoint
|
||||
actualJoint = bayesTree.jointBayesNet(8, 2, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(8));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(2, 8));
|
||||
EXPECT(assert_equal(expected, *actualJoint));
|
||||
}
|
||||
|
||||
// Check joint P(1,2)
|
||||
if (false) { // TODO, not disjoint
|
||||
actualJoint = bayesTree.jointBayesNet(1, 2, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(2));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(1, 2));
|
||||
EXPECT(assert_equal(expected, *actualJoint));
|
||||
}
|
||||
|
||||
// Check joint P(2,6)
|
||||
if (true) {
|
||||
actualJoint = bayesTree.jointBayesNet(2, 6, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(6));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(2, 6));
|
||||
EXPECT(assert_equal(expected, *actualJoint));
|
||||
}
|
||||
|
||||
// Check joint P(4,6)
|
||||
if (false) { // TODO, not disjoint
|
||||
actualJoint = bayesTree.jointBayesNet(4, 6, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(6));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(4, 6));
|
||||
EXPECT(assert_equal(expected, *actualJoint));
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* *
|
||||
Bayes tree for smoother with "natural" ordering:
|
||||
C1 5 6
|
||||
C2 4 : 5
|
||||
C3 3 : 4
|
||||
C4 2 : 3
|
||||
C5 1 : 2
|
||||
C6 0 : 1
|
||||
**************************************************************************** */
|
||||
|
||||
TEST_UNSAFE( SymbolicBayesTreeOrdered, linear_smoother_shortcuts ) {
|
||||
// Create smoother with 7 nodes
|
||||
SymbolicFactorGraphOrdered smoother;
|
||||
smoother.push_factor(0);
|
||||
smoother.push_factor(0, 1);
|
||||
smoother.push_factor(1, 2);
|
||||
smoother.push_factor(2, 3);
|
||||
smoother.push_factor(3, 4);
|
||||
smoother.push_factor(4, 5);
|
||||
smoother.push_factor(5, 6);
|
||||
|
||||
BayesNetOrdered<IndexConditionalOrdered> bayesNet =
|
||||
*SymbolicSequentialSolver(smoother).eliminate();
|
||||
|
||||
if (debug) {
|
||||
GTSAM_PRINT(bayesNet);
|
||||
bayesNet.saveGraph("/tmp/symbolicBayesNet.dot");
|
||||
}
|
||||
|
||||
// create a BayesTree out of a Bayes net
|
||||
SymbolicBayesTreeOrdered bayesTree(bayesNet);
|
||||
if (debug) {
|
||||
GTSAM_PRINT(bayesTree);
|
||||
bayesTree.saveGraph("/tmp/symbolicBayesTree.dot");
|
||||
}
|
||||
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr R = bayesTree.root();
|
||||
|
||||
{
|
||||
// check shortcut P(S2||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[4]; // 4 is frontal in C2
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
{
|
||||
// check shortcut P(S3||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[3]; // 3 is frontal in C3
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(4, 5));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
{
|
||||
// check shortcut P(S4||R) to root
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bayesTree[2]; // 2 is frontal in C4
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(3, 5));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// from testSymbolicJunctionTree, which failed at one point
|
||||
TEST(SymbolicBayesTreeOrdered, complicatedMarginal) {
|
||||
|
||||
// Create the conditionals to go in the BayesTree
|
||||
list<Index> L;
|
||||
L = list_of(1)(2)(5);
|
||||
IndexConditionalOrdered::shared_ptr R_1_2(new IndexConditionalOrdered(L, 2));
|
||||
L = list_of(3)(4)(6);
|
||||
IndexConditionalOrdered::shared_ptr R_3_4(new IndexConditionalOrdered(L, 2));
|
||||
L = list_of(5)(6)(7)(8);
|
||||
IndexConditionalOrdered::shared_ptr R_5_6(new IndexConditionalOrdered(L, 2));
|
||||
L = list_of(7)(8)(11);
|
||||
IndexConditionalOrdered::shared_ptr R_7_8(new IndexConditionalOrdered(L, 2));
|
||||
L = list_of(9)(10)(11)(12);
|
||||
IndexConditionalOrdered::shared_ptr R_9_10(new IndexConditionalOrdered(L, 2));
|
||||
L = list_of(11)(12);
|
||||
IndexConditionalOrdered::shared_ptr R_11_12(new IndexConditionalOrdered(L, 2));
|
||||
|
||||
// Symbolic Bayes Tree
|
||||
typedef SymbolicBayesTreeOrdered::Clique Clique;
|
||||
typedef SymbolicBayesTreeOrdered::sharedClique sharedClique;
|
||||
|
||||
// Create Bayes Tree
|
||||
SymbolicBayesTreeOrdered bt;
|
||||
bt.insert(sharedClique(new Clique(R_11_12)));
|
||||
bt.insert(sharedClique(new Clique(R_9_10)));
|
||||
bt.insert(sharedClique(new Clique(R_7_8)));
|
||||
bt.insert(sharedClique(new Clique(R_5_6)));
|
||||
bt.insert(sharedClique(new Clique(R_3_4)));
|
||||
bt.insert(sharedClique(new Clique(R_1_2)));
|
||||
if (debug) {
|
||||
GTSAM_PRINT(bt);
|
||||
bt.saveGraph("/tmp/symbolicBayesTree.dot");
|
||||
}
|
||||
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr R = bt.root();
|
||||
SymbolicBayesNetOrdered empty;
|
||||
|
||||
// Shortcut on 9
|
||||
{
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[9];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
EXPECT(assert_equal(empty, shortcut));
|
||||
}
|
||||
|
||||
// Shortcut on 7
|
||||
{
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[7];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
EXPECT(assert_equal(empty, shortcut));
|
||||
}
|
||||
|
||||
// Shortcut on 5
|
||||
{
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[5];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(8, 11));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(7, 8, 11));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
// Shortcut on 3
|
||||
{
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[3];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(6, 11));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
// Shortcut on 1
|
||||
{
|
||||
SymbolicBayesTreeOrdered::Clique::shared_ptr c = bt[1];
|
||||
SymbolicBayesNetOrdered shortcut = c->shortcut(R, EliminateSymbolic);
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(5, 11));
|
||||
EXPECT(assert_equal(expected, shortcut));
|
||||
}
|
||||
|
||||
// Marginal on 5
|
||||
{
|
||||
IndexFactorOrdered::shared_ptr actual = bt.marginalFactor(5, EliminateSymbolic);
|
||||
EXPECT(assert_equal(IndexFactorOrdered(5), *actual, 1e-1));
|
||||
}
|
||||
|
||||
// Shortcut on 6
|
||||
{
|
||||
IndexFactorOrdered::shared_ptr actual = bt.marginalFactor(6, EliminateSymbolic);
|
||||
EXPECT(assert_equal(IndexFactorOrdered(6), *actual, 1e-1));
|
||||
}
|
||||
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testSymbolicFactorGraph.cpp
|
||||
* @brief Unit tests for a symbolic IndexFactor Graph
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered-inl.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
static const Index vx2 = 0;
|
||||
static const Index vx1 = 1;
|
||||
static const Index vl1 = 2;
|
||||
|
||||
///* ************************************************************************* */
|
||||
//TEST( SymbolicFactorGraphOrdered, EliminateOne )
|
||||
//{
|
||||
// // create a test graph
|
||||
// SymbolicFactorGraphOrdered fg;
|
||||
// fg.push_factor(vx2, vx1);
|
||||
//
|
||||
// SymbolicSequentialSolver::EliminateUntil(fg, vx2+1);
|
||||
// SymbolicFactorGraphOrdered expected;
|
||||
// expected.push_back(boost::shared_ptr<IndexFactor>());
|
||||
// expected.push_factor(vx1);
|
||||
//
|
||||
// CHECK(assert_equal(expected, fg));
|
||||
//}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicFactorGraphOrdered, constructFromBayesNet )
|
||||
{
|
||||
// create expected factor graph
|
||||
SymbolicFactorGraphOrdered expected;
|
||||
expected.push_factor(vx2, vx1, vl1);
|
||||
expected.push_factor(vx1, vl1);
|
||||
expected.push_factor(vx1);
|
||||
|
||||
// create Bayes Net
|
||||
IndexConditionalOrdered::shared_ptr x2(new IndexConditionalOrdered(vx2, vx1, vl1));
|
||||
IndexConditionalOrdered::shared_ptr l1(new IndexConditionalOrdered(vx1, vl1));
|
||||
IndexConditionalOrdered::shared_ptr x1(new IndexConditionalOrdered(vx1));
|
||||
|
||||
BayesNetOrdered<IndexConditionalOrdered> bayesNet;
|
||||
bayesNet.push_back(x2);
|
||||
bayesNet.push_back(l1);
|
||||
bayesNet.push_back(x1);
|
||||
|
||||
// create actual factor graph from a Bayes Net
|
||||
SymbolicFactorGraphOrdered actual(bayesNet);
|
||||
|
||||
CHECK(assert_equal((SymbolicFactorGraphOrdered)expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicFactorGraphOrdered, push_back )
|
||||
{
|
||||
// Create two factor graphs and expected combined graph
|
||||
SymbolicFactorGraphOrdered fg1, fg2, expected;
|
||||
|
||||
fg1.push_factor(vx1);
|
||||
fg1.push_factor(vx2, vx1);
|
||||
|
||||
fg2.push_factor(vx1, vl1);
|
||||
fg2.push_factor(vx2, vl1);
|
||||
|
||||
expected.push_factor(vx1);
|
||||
expected.push_factor(vx2, vx1);
|
||||
expected.push_factor(vx1, vl1);
|
||||
expected.push_factor(vx2, vl1);
|
||||
|
||||
// combine
|
||||
SymbolicFactorGraphOrdered actual = combine(fg1, fg2);
|
||||
CHECK(assert_equal(expected, actual));
|
||||
|
||||
// combine using push_back
|
||||
fg1.push_back(fg2);
|
||||
CHECK(assert_equal(expected, fg1));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testSymbolicFactor.cpp
|
||||
* @brief Unit tests for a symbolic IndexFactor
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
using namespace boost::assign;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(SymbolicFactor, constructor) {
|
||||
|
||||
// Frontals sorted, parents not sorted
|
||||
vector<Index> keys1; keys1 += 3, 4, 5, 9, 7, 8;
|
||||
(void)IndexConditionalOrdered(keys1, 3);
|
||||
|
||||
// // Frontals not sorted
|
||||
// vector<Index> keys2; keys2 += 3, 5, 4, 9, 7, 8;
|
||||
// (void)IndexConditionalOrdered::FromRange(keys2.begin(), keys2.end(), 3);
|
||||
|
||||
// // Frontals not before parents
|
||||
// vector<Index> keys3; keys3 += 3, 4, 5, 1, 7, 8;
|
||||
// (void)IndexConditionalOrdered::FromRange(keys3.begin(), keys3.end(), 3);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
#ifdef TRACK_ELIMINATE
|
||||
TEST(SymbolicFactor, eliminate) {
|
||||
vector<Index> keys; keys += 2, 3, 4, 6, 7, 9, 10, 11;
|
||||
IndexFactorOrdered actual(keys.begin(), keys.end());
|
||||
BayesNetOrdered<IndexConditionalOrdered> fragment = *actual.eliminate(3);
|
||||
|
||||
IndexFactorOrdered expected(keys.begin()+3, keys.end());
|
||||
IndexConditionalOrdered::shared_ptr expected0 = IndexConditionalOrdered::FromRange(keys.begin(), keys.end(), 1);
|
||||
IndexConditionalOrdered::shared_ptr expected1 = IndexConditionalOrdered::FromRange(keys.begin()+1, keys.end(), 1);
|
||||
IndexConditionalOrdered::shared_ptr expected2 = IndexConditionalOrdered::FromRange(keys.begin()+2, keys.end(), 1);
|
||||
|
||||
CHECK(assert_equal(fragment.size(), size_t(3)));
|
||||
CHECK(assert_equal(expected, actual));
|
||||
BayesNetOrdered<IndexConditionalOrdered>::const_iterator fragmentCond = fragment.begin();
|
||||
CHECK(assert_equal(**fragmentCond++, *expected0));
|
||||
CHECK(assert_equal(**fragmentCond++, *expected1));
|
||||
CHECK(assert_equal(**fragmentCond++, *expected2));
|
||||
}
|
||||
#endif
|
||||
/* ************************************************************************* */
|
||||
TEST(SymbolicFactor, EliminateSymbolic) {
|
||||
SymbolicFactorGraphOrdered factors;
|
||||
factors.push_factor(2,4,6);
|
||||
factors.push_factor(1,2,5);
|
||||
factors.push_factor(0,3);
|
||||
|
||||
IndexFactorOrdered expectedFactor(4,5,6);
|
||||
std::vector<Index> keys; keys += 0,1,2,3,4,5,6;
|
||||
IndexConditionalOrdered::shared_ptr expectedConditional(new IndexConditionalOrdered(keys, 4));
|
||||
|
||||
IndexFactorOrdered::shared_ptr actualFactor;
|
||||
IndexConditionalOrdered::shared_ptr actualConditional;
|
||||
boost::tie(actualConditional, actualFactor) = EliminateSymbolic(factors, 4);
|
||||
|
||||
CHECK(assert_equal(*expectedConditional, *actualConditional));
|
||||
CHECK(assert_equal(expectedFactor, *actualFactor));
|
||||
|
||||
// BayesNetOrdered<IndexConditionalOrdered> expected_bn;
|
||||
// vector<Index> parents;
|
||||
//
|
||||
// parents.clear(); parents += 1,2,3,4,5,6;
|
||||
// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(0, parents)));
|
||||
//
|
||||
// parents.clear(); parents += 2,3,4,5,6;
|
||||
// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(1, parents)));
|
||||
//
|
||||
// parents.clear(); parents += 3,4,5,6;
|
||||
// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(2, parents)));
|
||||
//
|
||||
// parents.clear(); parents += 4,5,6;
|
||||
// expected_bn.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(3, parents)));
|
||||
//
|
||||
// BayesNetOrdered<IndexConditionalOrdered>::shared_ptr actual_bn;
|
||||
// IndexFactor::shared_ptr actual_factor;
|
||||
// boost::tie(actual_bn, actual_factor) = EliminateSymbolic(factors, 4);
|
||||
//
|
||||
// CHECK(assert_equal(expected_bn, *actual_bn));
|
||||
// CHECK(assert_equal(expected_factor, *actual_factor));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testSymbolicSequentialSolver.cpp
|
||||
* @brief Unit tests for a symbolic sequential solver routines
|
||||
* @author Frank Dellaert
|
||||
* @date Sept 16, 2012
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
TEST( SymbolicSequentialSolver, SymbolicSequentialSolver ) {
|
||||
// create factor graph
|
||||
SymbolicFactorGraphOrdered g;
|
||||
g.push_factor(2, 1, 0);
|
||||
g.push_factor(2, 0);
|
||||
g.push_factor(2);
|
||||
// test solver is Testable
|
||||
SymbolicSequentialSolver solver(g);
|
||||
// GTSAM_PRINT(solver);
|
||||
EXPECT(assert_equal(solver,solver));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
TEST( SymbolicSequentialSolver, inference ) {
|
||||
// Create factor graph
|
||||
SymbolicFactorGraphOrdered fg;
|
||||
fg.push_factor(0, 1);
|
||||
fg.push_factor(0, 2);
|
||||
fg.push_factor(1, 4);
|
||||
fg.push_factor(2, 4);
|
||||
fg.push_factor(3, 4);
|
||||
|
||||
// eliminate
|
||||
SymbolicSequentialSolver solver(fg);
|
||||
SymbolicBayesNetOrdered::shared_ptr actual = solver.eliminate();
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(3, 4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(2, 4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(1, 2, 4));
|
||||
expected.push_front(boost::make_shared<IndexConditionalOrdered>(0, 1, 2));
|
||||
EXPECT(assert_equal(expected,*actual));
|
||||
|
||||
{
|
||||
// jointBayesNet
|
||||
vector<Index> js;
|
||||
js.push_back(0);
|
||||
js.push_back(4);
|
||||
js.push_back(3);
|
||||
SymbolicBayesNetOrdered::shared_ptr actualBN = solver.jointBayesNet(js);
|
||||
SymbolicBayesNetOrdered expectedBN;
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(3));
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(4, 3));
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(0, 4));
|
||||
EXPECT( assert_equal(expectedBN,*actualBN));
|
||||
|
||||
// jointFactorGraph
|
||||
SymbolicFactorGraphOrdered::shared_ptr actualFG = solver.jointFactorGraph(js);
|
||||
SymbolicFactorGraphOrdered expectedFG;
|
||||
expectedFG.push_factor(0, 4);
|
||||
expectedFG.push_factor(4, 3);
|
||||
expectedFG.push_factor(3);
|
||||
EXPECT( assert_equal(expectedFG,(SymbolicFactorGraphOrdered)(*actualFG)));
|
||||
}
|
||||
|
||||
{
|
||||
// jointBayesNet
|
||||
vector<Index> js;
|
||||
js.push_back(0);
|
||||
js.push_back(2);
|
||||
js.push_back(3);
|
||||
SymbolicBayesNetOrdered::shared_ptr actualBN = solver.jointBayesNet(js);
|
||||
SymbolicBayesNetOrdered expectedBN;
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(2));
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(3, 2));
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(0, 3, 2));
|
||||
EXPECT( assert_equal(expectedBN,*actualBN));
|
||||
|
||||
// jointFactorGraph
|
||||
SymbolicFactorGraphOrdered::shared_ptr actualFG = solver.jointFactorGraph(js);
|
||||
SymbolicFactorGraphOrdered expectedFG;
|
||||
expectedFG.push_factor(0, 3, 2);
|
||||
expectedFG.push_factor(3, 2);
|
||||
expectedFG.push_factor(2);
|
||||
EXPECT( assert_equal(expectedFG,(SymbolicFactorGraphOrdered)(*actualFG)));
|
||||
}
|
||||
|
||||
{
|
||||
// conditionalBayesNet
|
||||
vector<Index> js;
|
||||
js.push_back(0);
|
||||
js.push_back(2);
|
||||
js.push_back(3);
|
||||
size_t nrFrontals = 2;
|
||||
SymbolicBayesNetOrdered::shared_ptr actualBN = //
|
||||
solver.conditionalBayesNet(js, nrFrontals);
|
||||
SymbolicBayesNetOrdered expectedBN;
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(2, 3));
|
||||
expectedBN.push_front(boost::make_shared<IndexConditionalOrdered>(0, 2, 3));
|
||||
EXPECT( assert_equal(expectedBN,*actualBN));
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testVariableIndex.cpp
|
||||
* @brief
|
||||
* @author Richard Roberts
|
||||
* @date Sep 26, 2010
|
||||
*/
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
|
||||
#include <gtsam/inference/VariableIndexOrdered.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VariableIndexOrdered, augment) {
|
||||
|
||||
SymbolicFactorGraphOrdered fg1, fg2;
|
||||
fg1.push_factor(0, 1);
|
||||
fg1.push_factor(0, 2);
|
||||
fg1.push_factor(5, 9);
|
||||
fg1.push_factor(2, 3);
|
||||
fg2.push_factor(1, 3);
|
||||
fg2.push_factor(2, 4);
|
||||
fg2.push_factor(3, 5);
|
||||
fg2.push_factor(5, 6);
|
||||
|
||||
SymbolicFactorGraphOrdered fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2);
|
||||
|
||||
VariableIndexOrdered expected(fgCombined);
|
||||
VariableIndexOrdered actual(fg1);
|
||||
actual.augment(fg2);
|
||||
|
||||
LONGS_EQUAL(16, actual.nEntries());
|
||||
LONGS_EQUAL(8, actual.nFactors());
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VariableIndexOrdered, remove) {
|
||||
|
||||
SymbolicFactorGraphOrdered fg1, fg2;
|
||||
fg1.push_factor(0, 1);
|
||||
fg1.push_factor(0, 2);
|
||||
fg1.push_factor(5, 9);
|
||||
fg1.push_factor(2, 3);
|
||||
fg2.push_factor(1, 3);
|
||||
fg2.push_factor(2, 4);
|
||||
fg2.push_factor(3, 5);
|
||||
fg2.push_factor(5, 6);
|
||||
|
||||
SymbolicFactorGraphOrdered fgCombined; fgCombined.push_back(fg1); fgCombined.push_back(fg2);
|
||||
|
||||
// Create a factor graph containing only the factors from fg2 and with null
|
||||
// factors in the place of those of fg1, so that the factor indices are correct.
|
||||
SymbolicFactorGraphOrdered fg2removed(fgCombined);
|
||||
fg2removed.remove(0); fg2removed.remove(1); fg2removed.remove(2); fg2removed.remove(3);
|
||||
|
||||
// The expected VariableIndex has the same factor indices as fgCombined but
|
||||
// with entries from fg1 removed, and still has all 10 variables.
|
||||
VariableIndexOrdered expected(fg2removed, 10);
|
||||
VariableIndexOrdered actual(fgCombined);
|
||||
vector<size_t> indices;
|
||||
indices.push_back(0); indices.push_back(1); indices.push_back(2); indices.push_back(3);
|
||||
actual.remove(indices, fg1);
|
||||
|
||||
CHECK(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VariableIndexOrdered, deep_copy) {
|
||||
|
||||
SymbolicFactorGraphOrdered fg1, fg2;
|
||||
fg1.push_factor(0, 1);
|
||||
fg1.push_factor(0, 2);
|
||||
fg1.push_factor(5, 9);
|
||||
fg1.push_factor(2, 3);
|
||||
fg2.push_factor(1, 3);
|
||||
fg2.push_factor(2, 4);
|
||||
fg2.push_factor(3, 5);
|
||||
fg2.push_factor(5, 6);
|
||||
|
||||
// Create original graph and VariableIndex
|
||||
SymbolicFactorGraphOrdered fgOriginal; fgOriginal.push_back(fg1); fgOriginal.push_back(fg2);
|
||||
VariableIndexOrdered original(fgOriginal);
|
||||
VariableIndexOrdered expectedOriginal(fgOriginal);
|
||||
|
||||
// Create a factor graph containing only the factors from fg2 and with null
|
||||
// factors in the place of those of fg1, so that the factor indices are correct.
|
||||
SymbolicFactorGraphOrdered fg2removed(fgOriginal);
|
||||
fg2removed.remove(0); fg2removed.remove(1); fg2removed.remove(2); fg2removed.remove(3);
|
||||
VariableIndexOrdered expectedRemoved(fg2removed);
|
||||
|
||||
// Create a clone and modify the clone - the original should not change
|
||||
VariableIndexOrdered clone(original);
|
||||
vector<size_t> indices;
|
||||
indices.push_back(0); indices.push_back(1); indices.push_back(2); indices.push_back(3);
|
||||
clone.remove(indices, fg1);
|
||||
|
||||
// When modifying the clone, the original should have stayed the same
|
||||
EXPECT(assert_equal(expectedOriginal, original));
|
||||
EXPECT(assert_equal(expectedRemoved, clone));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,255 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianBayesNet.cpp
|
||||
* @brief Chordal Bayes Net, the result of eliminating a factor graph
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <gtsam/linear/GaussianBayesNetOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
#include <gtsam/linear/VectorValuesOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered-inl.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
// trick from some reading group
|
||||
#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL)
|
||||
#define REVERSE_FOREACH_PAIR( KEY, VAL, COL) BOOST_REVERSE_FOREACH (boost::tie(KEY,VAL),COL)
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Explicitly instantiate so we don't have to include everywhere
|
||||
template class BayesNetOrdered<GaussianConditionalOrdered>;
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianBayesNetOrdered scalarGaussian(Index key, double mu, double sigma) {
|
||||
GaussianBayesNetOrdered bn;
|
||||
GaussianConditionalOrdered::shared_ptr
|
||||
conditional(new GaussianConditionalOrdered(key, Vector_(1,mu)/sigma, eye(1)/sigma, ones(1)));
|
||||
bn.push_back(conditional);
|
||||
return bn;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianBayesNetOrdered simpleGaussian(Index key, const Vector& mu, double sigma) {
|
||||
GaussianBayesNetOrdered bn;
|
||||
size_t n = mu.size();
|
||||
GaussianConditionalOrdered::shared_ptr
|
||||
conditional(new GaussianConditionalOrdered(key, mu/sigma, eye(n)/sigma, ones(n)));
|
||||
bn.push_back(conditional);
|
||||
return bn;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R,
|
||||
Index name1, Matrix S, Vector sigmas) {
|
||||
GaussianConditionalOrdered::shared_ptr cg(new GaussianConditionalOrdered(key, d, R, name1, S, sigmas));
|
||||
bn.push_front(cg);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R,
|
||||
Index name1, Matrix S, Index name2, Matrix T, Vector sigmas) {
|
||||
GaussianConditionalOrdered::shared_ptr cg(new GaussianConditionalOrdered(key, d, R, name1, S, name2, T, sigmas));
|
||||
bn.push_front(cg);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
boost::shared_ptr<VectorValuesOrdered> allocateVectorValues(const GaussianBayesNetOrdered& bn) {
|
||||
vector<size_t> dimensions(bn.size());
|
||||
Index var = 0;
|
||||
BOOST_FOREACH(const boost::shared_ptr<const GaussianConditionalOrdered> conditional, bn) {
|
||||
dimensions[var++] = conditional->dim();
|
||||
}
|
||||
return boost::shared_ptr<VectorValuesOrdered>(new VectorValuesOrdered(dimensions));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered optimize(const GaussianBayesNetOrdered& bn) {
|
||||
VectorValuesOrdered x = *allocateVectorValues(bn);
|
||||
optimizeInPlace(bn, x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// (R*x)./sigmas = y by solving x=inv(R)*(y.*sigmas)
|
||||
void optimizeInPlace(const GaussianBayesNetOrdered& bn, VectorValuesOrdered& x) {
|
||||
/** solve each node in turn in topological sort order (parents first)*/
|
||||
BOOST_REVERSE_FOREACH(const boost::shared_ptr<const GaussianConditionalOrdered> cg, bn) {
|
||||
// i^th part of R*x=y, x=inv(R)*y
|
||||
// (Rii*xi + R_i*x(i+1:))./si = yi <-> xi = inv(Rii)*(yi.*si - R_i*x(i+1:))
|
||||
cg->solveInPlace(x);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered backSubstitute(const GaussianBayesNetOrdered& bn, const VectorValuesOrdered& input) {
|
||||
VectorValuesOrdered output = input;
|
||||
BOOST_REVERSE_FOREACH(const boost::shared_ptr<const GaussianConditionalOrdered> cg, bn) {
|
||||
const Index key = *(cg->beginFrontals());
|
||||
Vector xS = internal::extractVectorValuesSlices(output, cg->beginParents(), cg->endParents());
|
||||
xS = input[key] - cg->get_S() * xS;
|
||||
output[key] = cg->get_R().triangularView<Eigen::Upper>().solve(xS);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const boost::shared_ptr<const GaussianConditionalOrdered> cg, bn) {
|
||||
cg->scaleFrontalsBySigma(output);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
// gy=inv(L)*gx by solving L*gy=gx.
|
||||
// gy=inv(R'*inv(Sigma))*gx
|
||||
// gz'*R'=gx', gy = gz.*sigmas
|
||||
VectorValuesOrdered backSubstituteTranspose(const GaussianBayesNetOrdered& bn,
|
||||
const VectorValuesOrdered& gx) {
|
||||
|
||||
// Initialize gy from gx
|
||||
// TODO: used to insert zeros if gx did not have an entry for a variable in bn
|
||||
VectorValuesOrdered gy = gx;
|
||||
|
||||
// we loop from first-eliminated to last-eliminated
|
||||
// i^th part of L*gy=gx is done block-column by block-column of L
|
||||
BOOST_FOREACH(const boost::shared_ptr<const GaussianConditionalOrdered> cg, bn)
|
||||
cg->solveTransposeInPlace(gy);
|
||||
|
||||
// Scale gy
|
||||
BOOST_FOREACH(GaussianConditionalOrdered::shared_ptr cg, bn)
|
||||
cg->scaleFrontalsBySigma(gy);
|
||||
|
||||
return gy;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered optimizeGradientSearch(const GaussianBayesNetOrdered& Rd) {
|
||||
gttic(Allocate_VectorValues);
|
||||
VectorValuesOrdered grad = *allocateVectorValues(Rd);
|
||||
gttoc(Allocate_VectorValues);
|
||||
|
||||
optimizeGradientSearchInPlace(Rd, grad);
|
||||
|
||||
return grad;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void optimizeGradientSearchInPlace(const GaussianBayesNetOrdered& Rd, VectorValuesOrdered& grad) {
|
||||
gttic(Compute_Gradient);
|
||||
// Compute gradient (call gradientAtZero function, which is defined for various linear systems)
|
||||
gradientAtZero(Rd, grad);
|
||||
double gradientSqNorm = grad.dot(grad);
|
||||
gttoc(Compute_Gradient);
|
||||
|
||||
gttic(Compute_Rg);
|
||||
// Compute R * g
|
||||
FactorGraphOrdered<JacobianFactorOrdered> Rd_jfg(Rd);
|
||||
Errors Rg = Rd_jfg * grad;
|
||||
gttoc(Compute_Rg);
|
||||
|
||||
gttic(Compute_minimizing_step_size);
|
||||
// Compute minimizing step size
|
||||
double step = -gradientSqNorm / dot(Rg, Rg);
|
||||
gttoc(Compute_minimizing_step_size);
|
||||
|
||||
gttic(Compute_point);
|
||||
// Compute steepest descent point
|
||||
scal(step, grad);
|
||||
gttoc(Compute_point);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
pair<Matrix,Vector> matrix(const GaussianBayesNetOrdered& bn) {
|
||||
|
||||
// add the dimensions of all variables to get matrix dimension
|
||||
// and at the same time create a mapping from keys to indices
|
||||
size_t N=0; map<Index,size_t> mapping;
|
||||
BOOST_FOREACH(GaussianConditionalOrdered::shared_ptr cg,bn) {
|
||||
GaussianConditionalOrdered::const_iterator it = cg->beginFrontals();
|
||||
for (; it != cg->endFrontals(); ++it) {
|
||||
mapping.insert(make_pair(*it,N));
|
||||
N += cg->dim(it);
|
||||
}
|
||||
}
|
||||
|
||||
// create matrix and copy in values
|
||||
Matrix R = zeros(N,N);
|
||||
Vector d(N);
|
||||
Index key; size_t I;
|
||||
FOREACH_PAIR(key,I,mapping) {
|
||||
// find corresponding conditional
|
||||
boost::shared_ptr<const GaussianConditionalOrdered> cg = bn[key];
|
||||
|
||||
// get sigmas
|
||||
Vector sigmas = cg->get_sigmas();
|
||||
|
||||
// get RHS and copy to d
|
||||
GaussianConditionalOrdered::const_d_type d_ = cg->get_d();
|
||||
const size_t n = d_.size();
|
||||
for (size_t i=0;i<n;i++)
|
||||
d(I+i) = d_(i)/sigmas(i);
|
||||
|
||||
// get leading R matrix and copy to R
|
||||
GaussianConditionalOrdered::const_r_type R_ = cg->get_R();
|
||||
for (size_t i=0;i<n;i++)
|
||||
for(size_t j=0;j<n;j++)
|
||||
R(I+i,I+j) = R_(i,j)/sigmas(i);
|
||||
|
||||
// loop over S matrices and copy them into R
|
||||
GaussianConditionalOrdered::const_iterator keyS = cg->beginParents();
|
||||
for (; keyS!=cg->endParents(); keyS++) {
|
||||
Matrix S = cg->get_S(keyS); // get S matrix
|
||||
const size_t m = S.rows(), n = S.cols(); // find S size
|
||||
const size_t J = mapping[*keyS]; // find column index
|
||||
for (size_t i=0;i<m;i++)
|
||||
for(size_t j=0;j<n;j++)
|
||||
R(I+i,J+j) = S(i,j)/sigmas(i);
|
||||
} // keyS
|
||||
|
||||
} // keyI
|
||||
|
||||
return make_pair(R,d);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
double determinant(const GaussianBayesNetOrdered& bayesNet) {
|
||||
double logDet = 0.0;
|
||||
|
||||
BOOST_FOREACH(boost::shared_ptr<const GaussianConditionalOrdered> cg, bayesNet){
|
||||
logDet += cg->get_R().diagonal().unaryExpr(ptr_fun<double,double>(log)).sum();
|
||||
}
|
||||
|
||||
return exp(logDet);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered gradient(const GaussianBayesNetOrdered& bayesNet, const VectorValuesOrdered& x0) {
|
||||
return gradient(GaussianFactorGraphOrdered(bayesNet), x0);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void gradientAtZero(const GaussianBayesNetOrdered& bayesNet, VectorValuesOrdered& g) {
|
||||
gradientAtZero(GaussianFactorGraphOrdered(bayesNet), g);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianBayesNet.h
|
||||
* @brief Chordal Bayes Net, the result of eliminating a factor graph
|
||||
* @brief GaussianBayesNet
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/** A Bayes net made from linear-Gaussian densities */
|
||||
typedef BayesNetOrdered<GaussianConditionalOrdered> GaussianBayesNetOrdered;
|
||||
|
||||
/** Create a scalar Gaussian */
|
||||
GTSAM_EXPORT GaussianBayesNetOrdered scalarGaussian(Index key, double mu=0.0, double sigma=1.0);
|
||||
|
||||
/** Create a simple Gaussian on a single multivariate variable */
|
||||
GTSAM_EXPORT GaussianBayesNetOrdered simpleGaussian(Index key, const Vector& mu, double sigma=1.0);
|
||||
|
||||
/**
|
||||
* Add a conditional node with one parent
|
||||
* |Rx+Sy-d|
|
||||
*/
|
||||
GTSAM_EXPORT void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R,
|
||||
Index name1, Matrix S, Vector sigmas);
|
||||
|
||||
/**
|
||||
* Add a conditional node with two parents
|
||||
* |Rx+Sy+Tz-d|
|
||||
*/
|
||||
GTSAM_EXPORT void push_front(GaussianBayesNetOrdered& bn, Index key, Vector d, Matrix R,
|
||||
Index name1, Matrix S, Index name2, Matrix T, Vector sigmas);
|
||||
|
||||
/**
|
||||
* Allocate a VectorValues for the variables in a BayesNet
|
||||
*/
|
||||
GTSAM_EXPORT boost::shared_ptr<VectorValuesOrdered> allocateVectorValues(const GaussianBayesNetOrdered& bn);
|
||||
|
||||
/**
|
||||
* Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by
|
||||
* back-substitution.
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered optimize(const GaussianBayesNetOrdered& bn);
|
||||
|
||||
/**
|
||||
* Solve the GaussianBayesNet, i.e. return \f$ x = R^{-1}*d \f$, computed by
|
||||
* back-substitution, writes the solution \f$ x \f$ into a pre-allocated
|
||||
* VectorValues. You can use allocateVectorValues(const GaussianBayesNet&)
|
||||
* allocate it. See also optimize(const GaussianBayesNet&), which does not
|
||||
* require pre-allocation.
|
||||
*/
|
||||
GTSAM_EXPORT void optimizeInPlace(const GaussianBayesNetOrdered& bn, VectorValuesOrdered& x);
|
||||
|
||||
/**
|
||||
* Optimize along the gradient direction, with a closed-form computation to
|
||||
* perform the line search. The gradient is computed about \f$ \delta x=0 \f$.
|
||||
*
|
||||
* This function returns \f$ \delta x \f$ that minimizes a reparametrized
|
||||
* problem. The error function of a GaussianBayesNet is
|
||||
*
|
||||
* \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f]
|
||||
*
|
||||
* with gradient and Hessian
|
||||
*
|
||||
* \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f]
|
||||
*
|
||||
* This function performs the line search in the direction of the
|
||||
* gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size
|
||||
* \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$:
|
||||
*
|
||||
* \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f]
|
||||
*
|
||||
* Optimizing by setting the derivative to zero yields
|
||||
* \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function
|
||||
* evaluates the denominator without computing the Hessian \f$ G \f$, returning
|
||||
*
|
||||
* \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f]
|
||||
*
|
||||
* @param bn The GaussianBayesNet on which to perform this computation
|
||||
* @return The resulting \f$ \delta x \f$ as described above
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered optimizeGradientSearch(const GaussianBayesNetOrdered& bn);
|
||||
|
||||
/** In-place version of optimizeGradientSearch(const GaussianBayesNet&) requiring pre-allocated VectorValues \c grad
|
||||
*
|
||||
* @param bn The GaussianBayesNet on which to perform this computation
|
||||
* @param [out] grad The resulting \f$ \delta x \f$ as described in optimizeGradientSearch(const GaussianBayesNet&)
|
||||
* */
|
||||
GTSAM_EXPORT void optimizeGradientSearchInPlace(const GaussianBayesNetOrdered& bn, VectorValuesOrdered& grad);
|
||||
|
||||
/**
|
||||
* Backsubstitute
|
||||
* gy=inv(R*inv(Sigma))*gx
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered backSubstitute(const GaussianBayesNetOrdered& bn, const VectorValuesOrdered& gx);
|
||||
|
||||
/**
|
||||
* Transpose Backsubstitute
|
||||
* gy=inv(L)*gx by solving L*gy=gx.
|
||||
* gy=inv(R'*inv(Sigma))*gx
|
||||
* gz'*R'=gx', gy = gz.*sigmas
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered backSubstituteTranspose(const GaussianBayesNetOrdered& bn, const VectorValuesOrdered& gx);
|
||||
|
||||
/**
|
||||
* Return (dense) upper-triangular matrix representation
|
||||
*/
|
||||
GTSAM_EXPORT std::pair<Matrix, Vector> matrix(const GaussianBayesNetOrdered&);
|
||||
|
||||
/**
|
||||
* Computes the determinant of a GassianBayesNet
|
||||
* A GaussianBayesNet is an upper triangular matrix and for an upper triangular matrix
|
||||
* determinant is the product of the diagonal elements. Instead of actually multiplying
|
||||
* we add the logarithms of the diagonal elements and take the exponent at the end
|
||||
* because this is more numerically stable.
|
||||
* @param bayesNet The input GaussianBayesNet
|
||||
* @return The determinant
|
||||
*/
|
||||
GTSAM_EXPORT double determinant(const GaussianBayesNetOrdered& bayesNet);
|
||||
|
||||
/**
|
||||
* Compute the gradient of the energy function,
|
||||
* \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$,
|
||||
* centered around \f$ x = x_0 \f$.
|
||||
* The gradient is \f$ R^T(Rx-d) \f$.
|
||||
* @param bayesNet The Gaussian Bayes net $(R,d)$
|
||||
* @param x0 The center about which to compute the gradient
|
||||
* @return The gradient as a VectorValues
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered gradient(const GaussianBayesNetOrdered& bayesNet, const VectorValuesOrdered& x0);
|
||||
|
||||
/**
|
||||
* Compute the gradient of the energy function,
|
||||
* \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$,
|
||||
* centered around zero.
|
||||
* The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&).
|
||||
* @param bayesNet The Gaussian Bayes net $(R,d)$
|
||||
* @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues
|
||||
* @return The gradient as a VectorValues
|
||||
*/
|
||||
GTSAM_EXPORT void gradientAtZero(const GaussianBayesNetOrdered& bayesNet, VectorValuesOrdered& g);
|
||||
|
||||
} /// namespace gtsam
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianBayesTree.cpp
|
||||
* @brief Gaussian Bayes Tree, the result of eliminating a GaussianJunctionTree
|
||||
* @brief GaussianBayesTree
|
||||
* @author Frank Dellaert
|
||||
* @author Richard Roberts
|
||||
*/
|
||||
|
||||
#include <gtsam/linear/GaussianBayesTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered optimize(const GaussianBayesTreeOrdered& bayesTree) {
|
||||
VectorValuesOrdered result = *allocateVectorValues(bayesTree);
|
||||
optimizeInPlace(bayesTree, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void optimizeInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& result) {
|
||||
internal::optimizeInPlace<GaussianBayesTreeOrdered>(bayesTree.root(), result);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered optimizeGradientSearch(const GaussianBayesTreeOrdered& bayesTree) {
|
||||
gttic(Allocate_VectorValues);
|
||||
VectorValuesOrdered grad = *allocateVectorValues(bayesTree);
|
||||
gttoc(Allocate_VectorValues);
|
||||
|
||||
optimizeGradientSearchInPlace(bayesTree, grad);
|
||||
|
||||
return grad;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void optimizeGradientSearchInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& grad) {
|
||||
gttic(Compute_Gradient);
|
||||
// Compute gradient (call gradientAtZero function, which is defined for various linear systems)
|
||||
gradientAtZero(bayesTree, grad);
|
||||
double gradientSqNorm = grad.dot(grad);
|
||||
gttoc(Compute_Gradient);
|
||||
|
||||
gttic(Compute_Rg);
|
||||
// Compute R * g
|
||||
FactorGraphOrdered<JacobianFactorOrdered> Rd_jfg(bayesTree);
|
||||
Errors Rg = Rd_jfg * grad;
|
||||
gttoc(Compute_Rg);
|
||||
|
||||
gttic(Compute_minimizing_step_size);
|
||||
// Compute minimizing step size
|
||||
double step = -gradientSqNorm / dot(Rg, Rg);
|
||||
gttoc(Compute_minimizing_step_size);
|
||||
|
||||
gttic(Compute_point);
|
||||
// Compute steepest descent point
|
||||
scal(step, grad);
|
||||
gttoc(Compute_point);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered gradient(const GaussianBayesTreeOrdered& bayesTree, const VectorValuesOrdered& x0) {
|
||||
return gradient(FactorGraphOrdered<JacobianFactorOrdered>(bayesTree), x0);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void gradientAtZero(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& g) {
|
||||
gradientAtZero(FactorGraphOrdered<JacobianFactorOrdered>(bayesTree), g);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
double determinant(const GaussianBayesTreeOrdered& bayesTree) {
|
||||
if (!bayesTree.root())
|
||||
return 0.0;
|
||||
|
||||
return exp(internal::logDeterminant<GaussianBayesTreeOrdered>(bayesTree.root()));
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // \namespace gtsam
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianBayesTree.h
|
||||
* @brief Gaussian Bayes Tree, the result of eliminating a GaussianJunctionTree
|
||||
* @brief GaussianBayesTree
|
||||
* @author Frank Dellaert
|
||||
* @author Richard Roberts
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/// A Bayes Tree representing a Gaussian density
|
||||
GTSAM_EXPORT typedef BayesTreeOrdered<GaussianConditionalOrdered> GaussianBayesTreeOrdered;
|
||||
|
||||
/// optimize the BayesTree, starting from the root
|
||||
GTSAM_EXPORT VectorValuesOrdered optimize(const GaussianBayesTreeOrdered& bayesTree);
|
||||
|
||||
/// recursively optimize this conditional and all subtrees
|
||||
GTSAM_EXPORT void optimizeInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& result);
|
||||
|
||||
namespace internal {
|
||||
template<class BAYESTREE>
|
||||
void optimizeInPlace(const typename BAYESTREE::sharedClique& clique, VectorValuesOrdered& result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize along the gradient direction, with a closed-form computation to
|
||||
* perform the line search. The gradient is computed about \f$ \delta x=0 \f$.
|
||||
*
|
||||
* This function returns \f$ \delta x \f$ that minimizes a reparametrized
|
||||
* problem. The error function of a GaussianBayesNet is
|
||||
*
|
||||
* \f[ f(\delta x) = \frac{1}{2} |R \delta x - d|^2 = \frac{1}{2}d^T d - d^T R \delta x + \frac{1}{2} \delta x^T R^T R \delta x \f]
|
||||
*
|
||||
* with gradient and Hessian
|
||||
*
|
||||
* \f[ g(\delta x) = R^T(R\delta x - d), \qquad G(\delta x) = R^T R. \f]
|
||||
*
|
||||
* This function performs the line search in the direction of the
|
||||
* gradient evaluated at \f$ g = g(\delta x = 0) \f$ with step size
|
||||
* \f$ \alpha \f$ that minimizes \f$ f(\delta x = \alpha g) \f$:
|
||||
*
|
||||
* \f[ f(\alpha) = \frac{1}{2} d^T d + g^T \delta x + \frac{1}{2} \alpha^2 g^T G g \f]
|
||||
*
|
||||
* Optimizing by setting the derivative to zero yields
|
||||
* \f$ \hat \alpha = (-g^T g) / (g^T G g) \f$. For efficiency, this function
|
||||
* evaluates the denominator without computing the Hessian \f$ G \f$, returning
|
||||
*
|
||||
* \f[ \delta x = \hat\alpha g = \frac{-g^T g}{(R g)^T(R g)} \f]
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered optimizeGradientSearch(const GaussianBayesTreeOrdered& bayesTree);
|
||||
|
||||
/** In-place version of optimizeGradientSearch requiring pre-allocated VectorValues \c x */
|
||||
GTSAM_EXPORT void optimizeGradientSearchInPlace(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& grad);
|
||||
|
||||
/**
|
||||
* Compute the gradient of the energy function,
|
||||
* \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$,
|
||||
* centered around \f$ x = x_0 \f$.
|
||||
* The gradient is \f$ R^T(Rx-d) \f$.
|
||||
* @param bayesTree The Gaussian Bayes Tree $(R,d)$
|
||||
* @param x0 The center about which to compute the gradient
|
||||
* @return The gradient as a VectorValues
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered gradient(const GaussianBayesTreeOrdered& bayesTree, const VectorValuesOrdered& x0);
|
||||
|
||||
/**
|
||||
* Compute the gradient of the energy function,
|
||||
* \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} R x - d \right\Vert^2 \f$,
|
||||
* centered around zero.
|
||||
* The gradient about zero is \f$ -R^T d \f$. See also gradient(const GaussianBayesNet&, const VectorValues&).
|
||||
* @param bayesTree The Gaussian Bayes Tree $(R,d)$
|
||||
* @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues
|
||||
* @return The gradient as a VectorValues
|
||||
*/
|
||||
GTSAM_EXPORT void gradientAtZero(const GaussianBayesTreeOrdered& bayesTree, VectorValuesOrdered& g);
|
||||
|
||||
/**
|
||||
* Computes the determinant of a GassianBayesTree
|
||||
* A GassianBayesTree is an upper triangular matrix and for an upper triangular matrix
|
||||
* determinant is the product of the diagonal elements. Instead of actually multiplying
|
||||
* we add the logarithms of the diagonal elements and take the exponent at the end
|
||||
* because this is more numerically stable.
|
||||
* @param bayesTree The input GassianBayesTree
|
||||
* @return The determinant
|
||||
*/
|
||||
GTSAM_EXPORT double determinant(const GaussianBayesTreeOrdered& bayesTree);
|
||||
|
||||
|
||||
namespace internal {
|
||||
template<class BAYESTREE>
|
||||
double logDeterminant(const typename BAYESTREE::sharedClique& clique);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <gtsam/linear/GaussianBayesTreeOrdered-inl.h>
|
||||
|
||||
|
|
@ -1,238 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianConditional.cpp
|
||||
* @brief Conditional Gaussian Base class
|
||||
* @author Christian Potthast
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <boost/format.hpp>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/lambda/bind.hpp>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <gtsam/linear/linearExceptions.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorOrdered.h>
|
||||
#include <gtsam/linear/JacobianFactorOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered() : rsd_(matrix_) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(Index key) : IndexConditionalOrdered(key), rsd_(matrix_) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(Index key,const Vector& d, const Matrix& R, const Vector& sigmas) :
|
||||
IndexConditionalOrdered(key), rsd_(matrix_), sigmas_(sigmas) {
|
||||
assert(R.rows() <= R.cols());
|
||||
size_t dims[] = { R.cols(), 1 };
|
||||
rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+2, d.size()));
|
||||
rsd_(0) = R.triangularView<Eigen::Upper>();
|
||||
get_d_() = d;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R,
|
||||
Index name1, const Matrix& S, const Vector& sigmas) :
|
||||
IndexConditionalOrdered(key,name1), rsd_(matrix_), sigmas_(sigmas) {
|
||||
assert(R.rows() <= R.cols());
|
||||
size_t dims[] = { R.cols(), S.cols(), 1 };
|
||||
rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+3, d.size()));
|
||||
rsd_(0) = R.triangularView<Eigen::Upper>();
|
||||
rsd_(1) = S;
|
||||
get_d_() = d;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R,
|
||||
Index name1, const Matrix& S, Index name2, const Matrix& T, const Vector& sigmas) :
|
||||
IndexConditionalOrdered(key,name1,name2), rsd_(matrix_), sigmas_(sigmas) {
|
||||
assert(R.rows() <= R.cols());
|
||||
size_t dims[] = { R.cols(), S.cols(), T.cols(), 1 };
|
||||
rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+4, d.size()));
|
||||
rsd_(0) = R.triangularView<Eigen::Upper>();
|
||||
rsd_(1) = S;
|
||||
rsd_(2) = T;
|
||||
get_d_() = d;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(Index key, const Vector& d,
|
||||
const Matrix& R, const list<pair<Index, Matrix> >& parents, const Vector& sigmas) :
|
||||
IndexConditionalOrdered(key, GetKeys(parents.size(), parents.begin(), parents.end())), rsd_(matrix_), sigmas_(sigmas) {
|
||||
assert(R.rows() <= R.cols());
|
||||
size_t* dims = (size_t*)alloca(sizeof(size_t)*(1+parents.size()+1)); // FIXME: alloca is bad, just ask Google.
|
||||
dims[0] = R.cols();
|
||||
size_t j=1;
|
||||
std::list<std::pair<Index, Matrix> >::const_iterator parent=parents.begin();
|
||||
for(; parent!=parents.end(); ++parent,++j)
|
||||
dims[j] = parent->second.cols();
|
||||
dims[j] = 1;
|
||||
rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+1+parents.size()+1, d.size()));
|
||||
rsd_(0) = R.triangularView<Eigen::Upper>();
|
||||
j = 1;
|
||||
for(std::list<std::pair<Index, Matrix> >::const_iterator parent=parents.begin(); parent!=parents.end(); ++parent) {
|
||||
rsd_(j).noalias() = parent->second;
|
||||
++ j;
|
||||
}
|
||||
get_d_() = d;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(const std::list<std::pair<Index, Matrix> >& terms,
|
||||
const size_t nrFrontals, const Vector& d, const Vector& sigmas) :
|
||||
IndexConditionalOrdered(GetKeys(terms.size(), terms.begin(), terms.end()), nrFrontals),
|
||||
rsd_(matrix_), sigmas_(sigmas) {
|
||||
size_t* dims = (size_t*)alloca(sizeof(size_t)*(terms.size()+1)); // FIXME: alloca is bad, just ask Google.
|
||||
size_t j=0;
|
||||
typedef pair<Index, Matrix> Index_Matrix;
|
||||
BOOST_FOREACH(const Index_Matrix& term, terms) {
|
||||
dims[j] = term.second.cols();
|
||||
++ j;
|
||||
}
|
||||
dims[j] = 1;
|
||||
rsd_.copyStructureFrom(rsd_type(matrix_, dims, dims+terms.size()+1, d.size()));
|
||||
j=0;
|
||||
BOOST_FOREACH(const Index_Matrix& term, terms) {
|
||||
rsd_(j) = term.second;
|
||||
++ j;
|
||||
}
|
||||
get_d_() = d;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(const GaussianConditionalOrdered& rhs) :
|
||||
rsd_(matrix_) {
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered& GaussianConditionalOrdered::operator=(const GaussianConditionalOrdered& rhs) {
|
||||
if(this != &rhs) {
|
||||
this->Base::operator=(rhs); // Copy keys
|
||||
rsd_.assignNoalias(rhs.rsd_); // Copy matrix and block configuration
|
||||
sigmas_ = rhs.sigmas_; // Copy sigmas
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianConditionalOrdered::print(const string &s, const IndexFormatter& formatter) const
|
||||
{
|
||||
cout << s << ": density on ";
|
||||
for(const_iterator it = beginFrontals(); it != endFrontals(); ++it) {
|
||||
cout << (boost::format("[%1%]")%(formatter(*it))).str() << " ";
|
||||
}
|
||||
cout << endl;
|
||||
gtsam::print(Matrix(get_R()),"R");
|
||||
for(const_iterator it = beginParents() ; it != endParents() ; ++it ) {
|
||||
gtsam::print(Matrix(get_S(it)), (boost::format("A[%1%]")%(formatter(*it))).str());
|
||||
}
|
||||
gtsam::print(Vector(get_d()),"d");
|
||||
gtsam::print(sigmas_,"sigmas");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool GaussianConditionalOrdered::equals(const GaussianConditionalOrdered &c, double tol) const {
|
||||
// check if the size of the parents_ map is the same
|
||||
if (parents().size() != c.parents().size())
|
||||
return false;
|
||||
|
||||
// check if R_ and d_ are linear independent
|
||||
for (size_t i=0; i<rsd_.rows(); i++) {
|
||||
list<Vector> rows1; rows1.push_back(Vector(get_R().row(i)));
|
||||
list<Vector> rows2; rows2.push_back(Vector(c.get_R().row(i)));
|
||||
|
||||
// check if the matrices are the same
|
||||
// iterate over the parents_ map
|
||||
for (const_iterator it = beginParents(); it != endParents(); ++it) {
|
||||
const_iterator it2 = c.beginParents() + (it-beginParents());
|
||||
if(*it != *(it2))
|
||||
return false;
|
||||
rows1.push_back(row(get_S(it), i));
|
||||
rows2.push_back(row(c.get_S(it2), i));
|
||||
}
|
||||
|
||||
Vector row1 = concatVectors(rows1);
|
||||
Vector row2 = concatVectors(rows2);
|
||||
if (!linear_dependent(row1, row2, tol))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if sigmas are equal
|
||||
if (!(equal_with_abs_tol(sigmas_, c.sigmas_, tol))) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::shared_ptr GaussianConditionalOrdered::toFactor() const {
|
||||
return JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(*this));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianConditionalOrdered::solveInPlace(VectorValuesOrdered& x) const {
|
||||
static const bool debug = false;
|
||||
if(debug) this->print("Solving conditional in place");
|
||||
Vector xS = internal::extractVectorValuesSlices(x, this->beginParents(), this->endParents());
|
||||
xS = this->get_d() - this->get_S() * xS;
|
||||
Vector soln = this->get_R().triangularView<Eigen::Upper>().solve(xS);
|
||||
|
||||
// Check for indeterminant solution
|
||||
if(soln.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite<double>), boost::lambda::_1)).any())
|
||||
throw IndeterminantLinearSystemException(this->keys().front());
|
||||
|
||||
if(debug) {
|
||||
gtsam::print(Matrix(this->get_R()), "Calling backSubstituteUpper on ");
|
||||
gtsam::print(soln, "full back-substitution solution: ");
|
||||
}
|
||||
internal::writeVectorValuesSlices(soln, x, this->beginFrontals(), this->endFrontals());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianConditionalOrdered::solveTransposeInPlace(VectorValuesOrdered& gy) const {
|
||||
Vector frontalVec = internal::extractVectorValuesSlices(gy, beginFrontals(), endFrontals());
|
||||
frontalVec = gtsam::backSubstituteUpper(frontalVec,Matrix(get_R()));
|
||||
|
||||
// Check for indeterminant solution
|
||||
if(frontalVec.unaryExpr(!boost::lambda::bind(ptr_fun(isfinite<double>), boost::lambda::_1)).any())
|
||||
throw IndeterminantLinearSystemException(this->keys().front());
|
||||
|
||||
GaussianConditionalOrdered::const_iterator it;
|
||||
for (it = beginParents(); it!= endParents(); it++) {
|
||||
const Index i = *it;
|
||||
transposeMultiplyAdd(-1.0,get_S(it),frontalVec,gy[i]);
|
||||
}
|
||||
internal::writeVectorValuesSlices(frontalVec, gy, beginFrontals(), endFrontals());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianConditionalOrdered::scaleFrontalsBySigma(VectorValuesOrdered& gy) const {
|
||||
Vector frontalVec = internal::extractVectorValuesSlices(gy, beginFrontals(), endFrontals());
|
||||
frontalVec = emul(frontalVec, get_sigmas());
|
||||
internal::writeVectorValuesSlices(frontalVec, gy, beginFrontals(), endFrontals());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,300 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianConditional.h
|
||||
* @brief Conditional Gaussian Base class
|
||||
* @author Christian Potthast
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include <gtsam/global_includes.h>
|
||||
#include <gtsam/base/blockMatrices.h>
|
||||
#include <gtsam/inference/IndexConditionalOrdered.h>
|
||||
#include <gtsam/linear/VectorValuesOrdered.h>
|
||||
|
||||
// Forward declaration to friend unit tests
|
||||
class JacobianFactorOrderedeliminate2Test;
|
||||
class GaussianConditionalOrderedconstructorTest;
|
||||
class GaussianFactorGraphOrderedeliminationTest;
|
||||
class GaussianJunctionTreeOrderedcomplicatedMarginalTest;
|
||||
class GaussianConditionalOrderedinformationTest;
|
||||
class GaussianConditionalOrderedisGaussianFactorTest;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declarations
|
||||
class GaussianFactorOrdered;
|
||||
class JacobianFactorOrdered;
|
||||
|
||||
/**
|
||||
* A conditional Gaussian functions as the node in a Bayes network
|
||||
* It has a set of parents y,z, etc. and implements a probability density on x.
|
||||
* The negative log-probability is given by \f$ \frac{1}{2} |Rx - (d - Sy - Tz - ...)|^2 \f$
|
||||
*/
|
||||
class GTSAM_EXPORT GaussianConditionalOrdered : public IndexConditionalOrdered {
|
||||
|
||||
public:
|
||||
typedef GaussianFactorOrdered FactorType;
|
||||
typedef boost::shared_ptr<GaussianConditionalOrdered> shared_ptr;
|
||||
|
||||
/** Store the conditional matrix as upper-triangular column-major */
|
||||
typedef Matrix RdMatrix;
|
||||
typedef VerticalBlockView<RdMatrix> rsd_type;
|
||||
|
||||
typedef rsd_type::Block r_type;
|
||||
typedef rsd_type::constBlock const_r_type;
|
||||
typedef rsd_type::Column d_type;
|
||||
typedef rsd_type::constColumn const_d_type;
|
||||
|
||||
protected:
|
||||
|
||||
/** Store the conditional as one big upper-triangular wide matrix, arranged
|
||||
* as \f$ [ R S1 S2 ... d ] \f$. Access these blocks using a VerticalBlockView.
|
||||
* */
|
||||
RdMatrix matrix_;
|
||||
rsd_type rsd_;
|
||||
|
||||
/** vector of standard deviations */
|
||||
Vector sigmas_;
|
||||
|
||||
/** typedef to base class */
|
||||
typedef IndexConditionalOrdered Base;
|
||||
|
||||
public:
|
||||
|
||||
/** default constructor needed for serialization */
|
||||
GaussianConditionalOrdered();
|
||||
|
||||
/** constructor */
|
||||
explicit GaussianConditionalOrdered(Index key);
|
||||
|
||||
/** constructor with no parents
|
||||
* |Rx-d|
|
||||
*/
|
||||
GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R, const Vector& sigmas);
|
||||
|
||||
/** constructor with only one parent
|
||||
* |Rx+Sy-d|
|
||||
*/
|
||||
GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R,
|
||||
Index name1, const Matrix& S, const Vector& sigmas);
|
||||
|
||||
/** constructor with two parents
|
||||
* |Rx+Sy+Tz-d|
|
||||
*/
|
||||
GaussianConditionalOrdered(Index key, const Vector& d, const Matrix& R,
|
||||
Index name1, const Matrix& S, Index name2, const Matrix& T, const Vector& sigmas);
|
||||
|
||||
/**
|
||||
* constructor with number of arbitrary parents (only used in unit tests,
|
||||
* std::list is not efficient)
|
||||
* \f$ |Rx+sum(Ai*xi)-d| \f$
|
||||
*/
|
||||
GaussianConditionalOrdered(Index key, const Vector& d,
|
||||
const Matrix& R, const std::list<std::pair<Index, Matrix> >& parents, const Vector& sigmas);
|
||||
|
||||
/**
|
||||
* Constructor with arbitrary number of frontals and parents (only used in unit tests,
|
||||
* std::list is not efficient)
|
||||
*/
|
||||
GaussianConditionalOrdered(const std::list<std::pair<Index, Matrix> >& terms,
|
||||
size_t nrFrontals, const Vector& d, const Vector& sigmas);
|
||||
|
||||
/**
|
||||
* Constructor when matrices are already stored in a combined matrix, allows
|
||||
* for multiple frontal variables.
|
||||
*/
|
||||
template<typename ITERATOR, class MATRIX>
|
||||
GaussianConditionalOrdered(ITERATOR firstKey, ITERATOR lastKey, size_t nrFrontals,
|
||||
const VerticalBlockView<MATRIX>& matrices, const Vector& sigmas);
|
||||
|
||||
/** Copy constructor */
|
||||
GaussianConditionalOrdered(const GaussianConditionalOrdered& rhs);
|
||||
|
||||
/** Combine several GaussianConditional into a single dense GC. The
|
||||
* conditionals enumerated by \c first and \c last must be in increasing
|
||||
* order, meaning that the parents of any conditional may not include a
|
||||
* conditional coming before it.
|
||||
* @param firstConditional Iterator to the first conditional to combine, must dereference to a shared_ptr<GaussianConditional>.
|
||||
* @param lastConditional Iterator to after the last conditional to combine, must dereference to a shared_ptr<GaussianConditional>. */
|
||||
template<typename ITERATOR>
|
||||
static shared_ptr Combine(ITERATOR firstConditional, ITERATOR lastConditional);
|
||||
|
||||
/** Assignment operator */
|
||||
GaussianConditionalOrdered& operator=(const GaussianConditionalOrdered& rhs);
|
||||
|
||||
/** print */
|
||||
void print(const std::string& = "GaussianConditional",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** equals function */
|
||||
bool equals(const GaussianConditionalOrdered &cg, double tol = 1e-9) const;
|
||||
|
||||
/** dimension of multivariate variable (same as rows()) */
|
||||
size_t dim() const { return rsd_.rows(); }
|
||||
|
||||
/** dimension of multivariate variable (same as dim()) */
|
||||
size_t rows() const { return dim(); }
|
||||
|
||||
/** Compute the augmented information matrix as
|
||||
* \f$ [ R S d ]^T [ R S d ] \f$
|
||||
*/
|
||||
Matrix augmentedInformation() const {
|
||||
return rsd_.full().transpose() * rsd_.full().transpose();
|
||||
}
|
||||
|
||||
/** Compute the information matrix */
|
||||
Matrix information() const {
|
||||
return get_R().transpose() * get_R();
|
||||
}
|
||||
|
||||
/** Return a view of the upper-triangular R block of the conditional */
|
||||
rsd_type::constBlock get_R() const { return rsd_.range(0, nrFrontals()); }
|
||||
|
||||
/** Return a view of the r.h.s. d vector */
|
||||
const_d_type get_d() const { return rsd_.column(nrFrontals()+nrParents(), 0); }
|
||||
|
||||
/** get the dimension of a variable */
|
||||
size_t dim(const_iterator variable) const { return rsd_(variable - this->begin()).cols(); }
|
||||
|
||||
/** Get a view of the parent block corresponding to the variable pointed to by the given key iterator */
|
||||
rsd_type::constBlock get_S(const_iterator variable) const { return rsd_(variable - this->begin()); }
|
||||
/** Get a view of the parent block corresponding to the variable pointed to by the given key iterator (non-const version) */
|
||||
rsd_type::constBlock get_S() const { return rsd_.range(nrFrontals(), size()); }
|
||||
/** Get the Vector of sigmas */
|
||||
const Vector& get_sigmas() const {return sigmas_;}
|
||||
|
||||
protected:
|
||||
|
||||
const RdMatrix& matrix() const { return matrix_; }
|
||||
const rsd_type& rsd() const { return rsd_; }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Copy to a Factor (this creates a JacobianFactor and returns it as its
|
||||
* base class GaussianFactor.
|
||||
*/
|
||||
boost::shared_ptr<JacobianFactorOrdered> toFactor() const;
|
||||
|
||||
/**
|
||||
* Solves a conditional Gaussian and writes the solution into the entries of
|
||||
* \c x for each frontal variable of the conditional. The parents are
|
||||
* assumed to have already been solved in and their values are read from \c x.
|
||||
* This function works for multiple frontal variables.
|
||||
*
|
||||
* Given the Gaussian conditional with log likelihood \f$ |R x_f - (d - S x_s)|^2,
|
||||
* where \f$ f \f$ are the frontal variables and \f$ s \f$ are the separator
|
||||
* variables of this conditional, this solve function computes
|
||||
* \f$ x_f = R^{-1} (d - S x_s) \f$ using back-substitution.
|
||||
*
|
||||
* @param x VectorValues structure with solved parents \f$ x_s \f$, and into which the
|
||||
* solution \f$ x_f \f$ will be written.
|
||||
*/
|
||||
void solveInPlace(VectorValuesOrdered& x) const;
|
||||
|
||||
// functions for transpose backsubstitution
|
||||
|
||||
/**
|
||||
* Performs backsubstition in place on values
|
||||
*/
|
||||
void solveTransposeInPlace(VectorValuesOrdered& gy) const;
|
||||
void scaleFrontalsBySigma(VectorValuesOrdered& gy) const;
|
||||
|
||||
protected:
|
||||
rsd_type::Column get_d_() { return rsd_.column(nrFrontals()+nrParents(), 0); }
|
||||
rsd_type::Block get_R_() { return rsd_.range(0, nrFrontals()); }
|
||||
rsd_type::Block get_S_(iterator variable) { return rsd_(variable - this->begin()); }
|
||||
|
||||
private:
|
||||
|
||||
// Friends
|
||||
friend class JacobianFactorOrdered;
|
||||
friend class ::JacobianFactorOrderedeliminate2Test;
|
||||
friend class ::GaussianConditionalOrderedconstructorTest;
|
||||
friend class ::GaussianFactorGraphOrderedeliminationTest;
|
||||
friend class ::GaussianJunctionTreeOrderedcomplicatedMarginalTest;
|
||||
friend class ::GaussianConditionalOrderedinformationTest;
|
||||
friend class ::GaussianConditionalOrderedisGaussianFactorTest;
|
||||
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(IndexConditionalOrdered);
|
||||
ar & BOOST_SERIALIZATION_NVP(matrix_);
|
||||
ar & BOOST_SERIALIZATION_NVP(rsd_);
|
||||
ar & BOOST_SERIALIZATION_NVP(sigmas_);
|
||||
}
|
||||
}; // GaussianConditional
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename ITERATOR, class MATRIX>
|
||||
GaussianConditionalOrdered::GaussianConditionalOrdered(ITERATOR firstKey, ITERATOR lastKey,
|
||||
size_t nrFrontals, const VerticalBlockView<MATRIX>& matrices,
|
||||
const Vector& sigmas) :
|
||||
IndexConditionalOrdered(std::vector<Index>(firstKey, lastKey), nrFrontals), rsd_(
|
||||
matrix_), sigmas_(sigmas) {
|
||||
rsd_.assignNoalias(matrices);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<typename ITERATOR>
|
||||
GaussianConditionalOrdered::shared_ptr GaussianConditionalOrdered::Combine(ITERATOR firstConditional, ITERATOR lastConditional) {
|
||||
|
||||
// TODO: check for being a clique
|
||||
|
||||
// Get dimensions from first conditional
|
||||
std::vector<size_t> dims; dims.reserve((*firstConditional)->size() + 1);
|
||||
for(const_iterator j = (*firstConditional)->begin(); j != (*firstConditional)->end(); ++j)
|
||||
dims.push_back((*firstConditional)->dim(j));
|
||||
dims.push_back(1);
|
||||
|
||||
// We assume the conditionals form clique, so the first n variables will be
|
||||
// frontal variables in the new conditional.
|
||||
size_t nFrontals = 0;
|
||||
size_t nRows = 0;
|
||||
for(ITERATOR c = firstConditional; c != lastConditional; ++c) {
|
||||
nRows += dims[nFrontals];
|
||||
++ nFrontals;
|
||||
}
|
||||
|
||||
// Allocate combined conditional, has same keys as firstConditional
|
||||
Matrix tempCombined;
|
||||
VerticalBlockView<Matrix> tempBlockView(tempCombined, dims.begin(), dims.end(), 0);
|
||||
GaussianConditionalOrdered::shared_ptr combinedConditional(new GaussianConditionalOrdered((*firstConditional)->begin(), (*firstConditional)->end(), nFrontals, tempBlockView, zero(nRows)));
|
||||
|
||||
// Resize to correct number of rows
|
||||
combinedConditional->matrix_.resize(nRows, combinedConditional->matrix_.cols());
|
||||
combinedConditional->rsd_.rowEnd() = combinedConditional->matrix_.rows();
|
||||
|
||||
// Copy matrix and sigmas
|
||||
const size_t totalDims = combinedConditional->matrix_.cols();
|
||||
size_t currentSlot = 0;
|
||||
for(ITERATOR c = firstConditional; c != lastConditional; ++c) {
|
||||
const size_t startRow = combinedConditional->rsd_.offset(currentSlot); // Start row is same as start column
|
||||
combinedConditional->rsd_.range(0, currentSlot).block(startRow, 0, dims[currentSlot], combinedConditional->rsd_.offset(currentSlot)).operator=(
|
||||
Matrix::Zero(dims[currentSlot], combinedConditional->rsd_.offset(currentSlot)));
|
||||
combinedConditional->rsd_.range(currentSlot, dims.size()).block(startRow, 0, dims[currentSlot], totalDims - startRow).operator=(
|
||||
(*c)->matrix_);
|
||||
combinedConditional->sigmas_.segment(startRow, dims[currentSlot]) = (*c)->sigmas_;
|
||||
++ currentSlot;
|
||||
}
|
||||
|
||||
return combinedConditional;
|
||||
}
|
||||
|
||||
} // gtsam
|
||||
|
|
@ -1,590 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianFactorGraph.cpp
|
||||
* @brief Linear Factor Graph where all factors are Gaussians
|
||||
* @author Kai Ni
|
||||
* @author Christian Potthast
|
||||
* @author Richard Roberts
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/base/cholesky.h>
|
||||
#include <gtsam/base/FastVector.h>
|
||||
#include <gtsam/linear/HessianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
#include <gtsam/inference/VariableSlots.h>
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/base/cholesky.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::GaussianFactorGraphOrdered(const GaussianBayesNetOrdered& CBN) : Base(CBN) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::Keys GaussianFactorGraphOrdered::keys() const {
|
||||
FastSet<Index> keys;
|
||||
BOOST_FOREACH(const sharedFactor& factor, *this)
|
||||
if (factor) keys.insert(factor->begin(), factor->end());
|
||||
return keys;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianFactorGraphOrdered::permuteWithInverse(
|
||||
const Permutation& inversePermutation) {
|
||||
BOOST_FOREACH(const sharedFactor& factor, factors_) {
|
||||
if(factor)
|
||||
factor->permuteWithInverse(inversePermutation);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianFactorGraphOrdered::reduceWithInverse(
|
||||
const internal::Reduction& inverseReduction) {
|
||||
BOOST_FOREACH(const sharedFactor& factor, factors_) {
|
||||
if(factor)
|
||||
factor->reduceWithInverse(inverseReduction);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianFactorGraphOrdered::combine(const GaussianFactorGraphOrdered &lfg) {
|
||||
for (const_iterator factor = lfg.factors_.begin(); factor
|
||||
!= lfg.factors_.end(); factor++) {
|
||||
push_back(*factor);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered GaussianFactorGraphOrdered::combine2(
|
||||
const GaussianFactorGraphOrdered& lfg1, const GaussianFactorGraphOrdered& lfg2) {
|
||||
|
||||
// create new linear factor graph equal to the first one
|
||||
GaussianFactorGraphOrdered fg = lfg1;
|
||||
|
||||
// add the second factors_ in the graph
|
||||
for (const_iterator factor = lfg2.factors_.begin(); factor
|
||||
!= lfg2.factors_.end(); factor++) {
|
||||
fg.push_back(*factor);
|
||||
}
|
||||
return fg;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
std::vector<boost::tuple<size_t, size_t, double> > GaussianFactorGraphOrdered::sparseJacobian() const {
|
||||
// First find dimensions of each variable
|
||||
FastVector<size_t> dims;
|
||||
BOOST_FOREACH(const sharedFactor& factor, *this) {
|
||||
for(GaussianFactorOrdered::const_iterator pos = factor->begin(); pos != factor->end(); ++pos) {
|
||||
if(dims.size() <= *pos)
|
||||
dims.resize(*pos + 1, 0);
|
||||
dims[*pos] = factor->getDim(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute first scalar column of each variable
|
||||
vector<size_t> columnIndices(dims.size()+1, 0);
|
||||
for(size_t j=1; j<dims.size()+1; ++j)
|
||||
columnIndices[j] = columnIndices[j-1] + dims[j-1];
|
||||
|
||||
// Iterate over all factors, adding sparse scalar entries
|
||||
typedef boost::tuple<size_t, size_t, double> triplet;
|
||||
FastVector<triplet> entries;
|
||||
size_t row = 0;
|
||||
BOOST_FOREACH(const sharedFactor& factor, *this) {
|
||||
// Convert to JacobianFactor if necessary
|
||||
JacobianFactorOrdered::shared_ptr jacobianFactor(
|
||||
boost::dynamic_pointer_cast<JacobianFactorOrdered>(factor));
|
||||
if (!jacobianFactor) {
|
||||
HessianFactorOrdered::shared_ptr hessian(boost::dynamic_pointer_cast<HessianFactorOrdered>(factor));
|
||||
if (hessian)
|
||||
jacobianFactor.reset(new JacobianFactorOrdered(*hessian));
|
||||
else
|
||||
throw invalid_argument(
|
||||
"GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor.");
|
||||
}
|
||||
|
||||
// Whiten the factor and add entries for it
|
||||
// iterate over all variables in the factor
|
||||
const JacobianFactorOrdered whitened(jacobianFactor->whiten());
|
||||
for(JacobianFactorOrdered::const_iterator pos=whitened.begin(); pos<whitened.end(); ++pos) {
|
||||
JacobianFactorOrdered::constABlock whitenedA = whitened.getA(pos);
|
||||
// find first column index for this key
|
||||
size_t column_start = columnIndices[*pos];
|
||||
for (size_t i = 0; i < (size_t) whitenedA.rows(); i++)
|
||||
for (size_t j = 0; j < (size_t) whitenedA.cols(); j++) {
|
||||
double s = whitenedA(i,j);
|
||||
if (std::abs(s) > 1e-12) entries.push_back(
|
||||
boost::make_tuple(row+i, column_start+j, s));
|
||||
}
|
||||
}
|
||||
|
||||
JacobianFactorOrdered::constBVector whitenedb(whitened.getb());
|
||||
size_t bcolumn = columnIndices.back();
|
||||
for (size_t i = 0; i < (size_t) whitenedb.size(); i++)
|
||||
entries.push_back(boost::make_tuple(row+i, bcolumn, whitenedb(i)));
|
||||
|
||||
// Increment row index
|
||||
row += jacobianFactor->rows();
|
||||
}
|
||||
return vector<triplet>(entries.begin(), entries.end());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix GaussianFactorGraphOrdered::sparseJacobian_() const {
|
||||
|
||||
// call sparseJacobian
|
||||
typedef boost::tuple<size_t, size_t, double> triplet;
|
||||
std::vector<triplet> result = sparseJacobian();
|
||||
|
||||
// translate to base 1 matrix
|
||||
size_t nzmax = result.size();
|
||||
Matrix IJS(3,nzmax);
|
||||
for (size_t k = 0; k < result.size(); k++) {
|
||||
const triplet& entry = result[k];
|
||||
IJS(0,k) = double(entry.get<0>() + 1);
|
||||
IJS(1,k) = double(entry.get<1>() + 1);
|
||||
IJS(2,k) = entry.get<2>();
|
||||
}
|
||||
return IJS;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix GaussianFactorGraphOrdered::augmentedJacobian() const {
|
||||
// Convert to Jacobians
|
||||
FactorGraphOrdered<JacobianFactorOrdered> jfg;
|
||||
jfg.reserve(this->size());
|
||||
BOOST_FOREACH(const sharedFactor& factor, *this) {
|
||||
if(boost::shared_ptr<JacobianFactorOrdered> jf =
|
||||
boost::dynamic_pointer_cast<JacobianFactorOrdered>(factor))
|
||||
jfg.push_back(jf);
|
||||
else
|
||||
jfg.push_back(boost::make_shared<JacobianFactorOrdered>(*factor));
|
||||
}
|
||||
// combine all factors
|
||||
JacobianFactorOrdered combined(*CombineJacobians(jfg, VariableSlots(*this)));
|
||||
return combined.matrix_augmented();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
std::pair<Matrix,Vector> GaussianFactorGraphOrdered::jacobian() const {
|
||||
Matrix augmented = augmentedJacobian();
|
||||
return make_pair(
|
||||
augmented.leftCols(augmented.cols()-1),
|
||||
augmented.col(augmented.cols()-1));
|
||||
}
|
||||
|
||||
// Helper functions for Combine
|
||||
static boost::tuple<vector<size_t>, size_t, size_t> countDims(const FactorGraphOrdered<JacobianFactorOrdered>& factors, const VariableSlots& variableSlots) {
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
vector<size_t> varDims(variableSlots.size(), numeric_limits<size_t>::max());
|
||||
#else
|
||||
vector<size_t> varDims(variableSlots.size());
|
||||
#endif
|
||||
size_t m = 0;
|
||||
size_t n = 0;
|
||||
{
|
||||
Index jointVarpos = 0;
|
||||
BOOST_FOREACH(const VariableSlots::value_type& slots, variableSlots) {
|
||||
|
||||
assert(slots.second.size() == factors.size());
|
||||
|
||||
Index sourceFactorI = 0;
|
||||
BOOST_FOREACH(const Index sourceVarpos, slots.second) {
|
||||
if(sourceVarpos < numeric_limits<Index>::max()) {
|
||||
const JacobianFactorOrdered& sourceFactor = *factors[sourceFactorI];
|
||||
size_t vardim = sourceFactor.getDim(sourceFactor.begin() + sourceVarpos);
|
||||
#ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS
|
||||
if(varDims[jointVarpos] == numeric_limits<size_t>::max()) {
|
||||
varDims[jointVarpos] = vardim;
|
||||
n += vardim;
|
||||
} else
|
||||
assert(varDims[jointVarpos] == vardim);
|
||||
#else
|
||||
varDims[jointVarpos] = vardim;
|
||||
n += vardim;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
++ sourceFactorI;
|
||||
}
|
||||
++ jointVarpos;
|
||||
}
|
||||
BOOST_FOREACH(const JacobianFactorOrdered::shared_ptr& factor, factors) {
|
||||
m += factor->rows();
|
||||
}
|
||||
}
|
||||
return boost::make_tuple(varDims, m, n);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::shared_ptr CombineJacobians(
|
||||
const FactorGraphOrdered<JacobianFactorOrdered>& factors,
|
||||
const VariableSlots& variableSlots) {
|
||||
|
||||
const bool debug = ISDEBUG("CombineJacobians");
|
||||
if (debug) factors.print("Combining factors: ");
|
||||
if (debug) variableSlots.print();
|
||||
|
||||
if (debug) cout << "Determine dimensions" << endl;
|
||||
gttic(countDims);
|
||||
vector<size_t> varDims;
|
||||
size_t m, n;
|
||||
boost::tie(varDims, m, n) = countDims(factors, variableSlots);
|
||||
if (debug) {
|
||||
cout << "Dims: " << m << " x " << n << "\n";
|
||||
BOOST_FOREACH(const size_t dim, varDims) cout << dim << " ";
|
||||
cout << endl;
|
||||
}
|
||||
gttoc(countDims);
|
||||
|
||||
if (debug) cout << "Allocate new factor" << endl;
|
||||
gttic(allocate);
|
||||
JacobianFactorOrdered::shared_ptr combined(new JacobianFactorOrdered());
|
||||
combined->allocate(variableSlots, varDims, m);
|
||||
Vector sigmas(m);
|
||||
gttoc(allocate);
|
||||
|
||||
if (debug) cout << "Copy blocks" << endl;
|
||||
gttic(copy_blocks);
|
||||
// Loop over slots in combined factor
|
||||
Index combinedSlot = 0;
|
||||
BOOST_FOREACH(const VariableSlots::value_type& varslot, variableSlots) {
|
||||
JacobianFactorOrdered::ABlock destSlot(combined->getA(combined->begin()+combinedSlot));
|
||||
// Loop over source factors
|
||||
size_t nextRow = 0;
|
||||
for(size_t factorI = 0; factorI < factors.size(); ++factorI) {
|
||||
// Slot in source factor
|
||||
const Index sourceSlot = varslot.second[factorI];
|
||||
const size_t sourceRows = factors[factorI]->rows();
|
||||
JacobianFactorOrdered::ABlock::RowsBlockXpr destBlock(destSlot.middleRows(nextRow, sourceRows));
|
||||
// Copy if exists in source factor, otherwise set zero
|
||||
if(sourceSlot != numeric_limits<Index>::max())
|
||||
destBlock = factors[factorI]->getA(factors[factorI]->begin()+sourceSlot);
|
||||
else
|
||||
destBlock.setZero();
|
||||
nextRow += sourceRows;
|
||||
}
|
||||
++combinedSlot;
|
||||
}
|
||||
gttoc(copy_blocks);
|
||||
|
||||
if (debug) cout << "Copy rhs (b) and sigma" << endl;
|
||||
gttic(copy_vectors);
|
||||
bool anyConstrained = false;
|
||||
// Loop over source factors
|
||||
size_t nextRow = 0;
|
||||
for(size_t factorI = 0; factorI < factors.size(); ++factorI) {
|
||||
const size_t sourceRows = factors[factorI]->rows();
|
||||
combined->getb().segment(nextRow, sourceRows) = factors[factorI]->getb();
|
||||
sigmas.segment(nextRow, sourceRows) = factors[factorI]->get_model()->sigmas();
|
||||
if (factors[factorI]->isConstrained()) anyConstrained = true;
|
||||
nextRow += sourceRows;
|
||||
}
|
||||
gttoc(copy_vectors);
|
||||
|
||||
if (debug) cout << "Create noise model from sigmas" << endl;
|
||||
gttic(noise_model);
|
||||
combined->setModel(anyConstrained, sigmas);
|
||||
gttoc(noise_model);
|
||||
|
||||
if (debug) cout << "Assert Invariants" << endl;
|
||||
combined->assertInvariants();
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::EliminationResult EliminateJacobians(const FactorGraphOrdered<
|
||||
JacobianFactorOrdered>& factors, size_t nrFrontals) {
|
||||
gttic(Combine);
|
||||
JacobianFactorOrdered::shared_ptr jointFactor =
|
||||
CombineJacobians(factors, VariableSlots(factors));
|
||||
gttoc(Combine);
|
||||
gttic(eliminate);
|
||||
GaussianConditionalOrdered::shared_ptr gbn = jointFactor->eliminate(nrFrontals);
|
||||
gttoc(eliminate);
|
||||
return make_pair(gbn, jointFactor);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix GaussianFactorGraphOrdered::augmentedHessian() const {
|
||||
// combine all factors and get upper-triangular part of Hessian
|
||||
HessianFactorOrdered combined(*this);
|
||||
Matrix result = combined.info();
|
||||
// Fill in lower-triangular part of Hessian
|
||||
result.triangularView<Eigen::StrictlyLower>() = result.transpose();
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
std::pair<Matrix,Vector> GaussianFactorGraphOrdered::hessian() const {
|
||||
Matrix augmented = augmentedHessian();
|
||||
return make_pair(
|
||||
augmented.topLeftCorner(augmented.rows()-1, augmented.rows()-1),
|
||||
augmented.col(augmented.rows()-1).head(augmented.rows()-1));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::EliminationResult EliminateCholeskyOrdered(const FactorGraphOrdered<
|
||||
GaussianFactorOrdered>& factors, size_t nrFrontals) {
|
||||
|
||||
const bool debug = ISDEBUG("EliminateCholesky");
|
||||
|
||||
// Form Ab' * Ab
|
||||
gttic(combine);
|
||||
HessianFactorOrdered::shared_ptr combinedFactor(new HessianFactorOrdered(factors));
|
||||
gttoc(combine);
|
||||
|
||||
// Do Cholesky, note that after this, the lower triangle still contains
|
||||
// some untouched non-zeros that should be zero. We zero them while
|
||||
// extracting submatrices next.
|
||||
gttic(partial_Cholesky);
|
||||
combinedFactor->partialCholesky(nrFrontals);
|
||||
|
||||
gttoc(partial_Cholesky);
|
||||
|
||||
// Extract conditional and fill in details of the remaining factor
|
||||
gttic(split);
|
||||
GaussianConditionalOrdered::shared_ptr conditional =
|
||||
combinedFactor->splitEliminatedFactor(nrFrontals);
|
||||
if (debug) {
|
||||
conditional->print("Extracted conditional: ");
|
||||
combinedFactor->print("Eliminated factor (L piece): ");
|
||||
}
|
||||
gttoc(split);
|
||||
|
||||
combinedFactor->assertInvariants();
|
||||
return make_pair(conditional, combinedFactor);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
static FactorGraphOrdered<JacobianFactorOrdered> convertToJacobians(const FactorGraphOrdered<
|
||||
GaussianFactorOrdered>& factors) {
|
||||
|
||||
typedef JacobianFactorOrdered J;
|
||||
typedef HessianFactorOrdered H;
|
||||
|
||||
const bool debug = ISDEBUG("convertToJacobians");
|
||||
|
||||
FactorGraphOrdered<J> jacobians;
|
||||
jacobians.reserve(factors.size());
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factors)
|
||||
if (factor) {
|
||||
J::shared_ptr jacobian(boost::dynamic_pointer_cast<J>(factor));
|
||||
if (jacobian) {
|
||||
jacobians.push_back(jacobian);
|
||||
if (debug) jacobian->print("Existing JacobianFactor: ");
|
||||
} else {
|
||||
H::shared_ptr hessian(boost::dynamic_pointer_cast<H>(factor));
|
||||
if (!hessian) throw std::invalid_argument(
|
||||
"convertToJacobians: factor is neither a JacobianFactor nor a HessianFactor.");
|
||||
J::shared_ptr converted(new J(*hessian));
|
||||
if (debug) {
|
||||
cout << "Converted HessianFactor to JacobianFactor:\n";
|
||||
hessian->print("HessianFactor: ");
|
||||
converted->print("JacobianFactor: ");
|
||||
if (!assert_equal(*hessian, HessianFactorOrdered(*converted), 1e-3)) throw runtime_error(
|
||||
"convertToJacobians: Conversion between Jacobian and Hessian incorrect");
|
||||
}
|
||||
jacobians.push_back(converted);
|
||||
}
|
||||
}
|
||||
return jacobians;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::EliminationResult EliminateQROrdered(const FactorGraphOrdered<
|
||||
GaussianFactorOrdered>& factors, size_t nrFrontals) {
|
||||
|
||||
const bool debug = ISDEBUG("EliminateQR");
|
||||
|
||||
// Convert all factors to the appropriate type and call the type-specific EliminateGaussian.
|
||||
if (debug) cout << "Using QR" << endl;
|
||||
|
||||
gttic(convert_to_Jacobian);
|
||||
FactorGraphOrdered<JacobianFactorOrdered> jacobians = convertToJacobians(factors);
|
||||
gttoc(convert_to_Jacobian);
|
||||
|
||||
gttic(Jacobian_EliminateGaussian);
|
||||
GaussianConditionalOrdered::shared_ptr conditional;
|
||||
GaussianFactorOrdered::shared_ptr factor;
|
||||
boost::tie(conditional, factor) = EliminateJacobians(jacobians, nrFrontals);
|
||||
gttoc(Jacobian_EliminateGaussian);
|
||||
|
||||
return make_pair(conditional, factor);
|
||||
} // \EliminateQR
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool hasConstraints(const FactorGraphOrdered<GaussianFactorOrdered>& factors) {
|
||||
typedef JacobianFactorOrdered J;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factors) {
|
||||
J::shared_ptr jacobian(boost::dynamic_pointer_cast<J>(factor));
|
||||
if (jacobian && jacobian->get_model()->isConstrained()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::EliminationResult EliminatePreferCholeskyOrdered(
|
||||
const FactorGraphOrdered<GaussianFactorOrdered>& factors, size_t nrFrontals) {
|
||||
|
||||
// If any JacobianFactors have constrained noise models, we have to convert
|
||||
// all factors to JacobianFactors. Otherwise, we can convert all factors
|
||||
// to HessianFactors. This is because QR can handle constrained noise
|
||||
// models but Cholesky cannot.
|
||||
if (hasConstraints(factors))
|
||||
return EliminateQROrdered(factors, nrFrontals);
|
||||
else {
|
||||
GaussianFactorGraphOrdered::EliminationResult ret;
|
||||
gttic(EliminateCholeskyOrdered);
|
||||
ret = EliminateCholeskyOrdered(factors, nrFrontals);
|
||||
gttoc(EliminateCholeskyOrdered);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // \EliminatePreferCholesky
|
||||
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
static JacobianFactorOrdered::shared_ptr convertToJacobianFactorPtr(const GaussianFactorOrdered::shared_ptr &gf) {
|
||||
JacobianFactorOrdered::shared_ptr result = boost::dynamic_pointer_cast<JacobianFactorOrdered>(gf);
|
||||
if( !result ) {
|
||||
result = boost::make_shared<JacobianFactorOrdered>(*gf); // Convert any non-Jacobian factors to Jacobians (e.g. Hessian -> Jacobian with Cholesky)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Errors operator*(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) {
|
||||
Errors e;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
e.push_back((*Ai)*x);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, Errors& e) {
|
||||
multiplyInPlace(fg,x,e.begin());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, const Errors::iterator& e) {
|
||||
Errors::iterator ei = e;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
*ei = (*Ai)*x;
|
||||
ei++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// x += alpha*A'*e
|
||||
void transposeMultiplyAdd(const GaussianFactorGraphOrdered& fg, double alpha, const Errors& e, VectorValuesOrdered& x) {
|
||||
// For each factor add the gradient contribution
|
||||
Errors::const_iterator ei = e.begin();
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
Ai->transposeMultiplyAdd(alpha,*(ei++),x);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered gradient(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x0) {
|
||||
// It is crucial for performance to make a zero-valued clone of x
|
||||
VectorValuesOrdered g = VectorValuesOrdered::Zero(x0);
|
||||
Errors e;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
e.push_back(Ai->error_vector(x0));
|
||||
}
|
||||
transposeMultiplyAdd(fg, 1.0, e, g);
|
||||
return g;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void gradientAtZero(const GaussianFactorGraphOrdered& fg, VectorValuesOrdered& g) {
|
||||
// Zero-out the gradient
|
||||
g.setZero();
|
||||
Errors e;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
e.push_back(-Ai->getb());
|
||||
}
|
||||
transposeMultiplyAdd(fg, 1.0, e, g);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void residual(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r) {
|
||||
Index i = 0 ;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
r[i] = Ai->getb();
|
||||
i++;
|
||||
}
|
||||
VectorValuesOrdered Ax = VectorValuesOrdered::SameStructure(r);
|
||||
multiply(fg,x,Ax);
|
||||
axpy(-1.0,Ax,r);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void multiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r) {
|
||||
r.setZero();
|
||||
Index i = 0;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
Vector &y = r[i];
|
||||
for(JacobianFactorOrdered::const_iterator j = Ai->begin(); j != Ai->end(); ++j) {
|
||||
y += Ai->getA(j) * x[*j];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void transposeMultiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &r, VectorValuesOrdered &x) {
|
||||
x.setZero();
|
||||
Index i = 0;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
for(JacobianFactorOrdered::const_iterator j = Ai->begin(); j != Ai->end(); ++j) {
|
||||
x[*j] += Ai->getA(j).transpose() * r[i];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
boost::shared_ptr<Errors> gaussianErrors_(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) {
|
||||
boost::shared_ptr<Errors> e(new Errors);
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& Ai_G, fg) {
|
||||
JacobianFactorOrdered::shared_ptr Ai = convertToJacobianFactorPtr(Ai_G);
|
||||
e->push_back(Ai->error_vector(x));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,388 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianFactorGraph.h
|
||||
* @brief Linear Factor Graph where all factors are Gaussians
|
||||
* @author Kai Ni
|
||||
* @author Christian Potthast
|
||||
* @author Alireza Fathi
|
||||
* @author Richard Roberts
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <gtsam/base/FastSet.h>
|
||||
#include <gtsam/linear/Errors.h>
|
||||
#include <gtsam/linear/HessianFactorOrdered.h>
|
||||
#include <gtsam/linear/JacobianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianBayesNetOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declaration to use as default argument, documented declaration below.
|
||||
GTSAM_EXPORT FactorGraphOrdered<GaussianFactorOrdered>::EliminationResult
|
||||
EliminateQROrdered(const FactorGraphOrdered<GaussianFactorOrdered>& factors, size_t nrFrontals);
|
||||
|
||||
/**
|
||||
* A Linear Factor Graph is a factor graph where all factors are Gaussian, i.e.
|
||||
* Factor == GaussianFactor
|
||||
* VectorValues = A values structure of vectors
|
||||
* Most of the time, linear factor graphs arise by linearizing a non-linear factor graph.
|
||||
*/
|
||||
class GaussianFactorGraphOrdered : public FactorGraphOrdered<GaussianFactorOrdered> {
|
||||
public:
|
||||
|
||||
typedef boost::shared_ptr<GaussianFactorGraphOrdered> shared_ptr;
|
||||
typedef FactorGraphOrdered<GaussianFactorOrdered> Base;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
GaussianFactorGraphOrdered() {}
|
||||
|
||||
/**
|
||||
* Constructor that receives a Chordal Bayes Net and returns a GaussianFactorGraph
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorGraphOrdered(const GaussianBayesNetOrdered& CBN);
|
||||
|
||||
/**
|
||||
* Constructor that receives a BayesTree and returns a GaussianFactorGraph
|
||||
*/
|
||||
template<class CLIQUE>
|
||||
GaussianFactorGraphOrdered(const BayesTreeOrdered<GaussianConditionalOrdered,CLIQUE>& gbt) : Base(gbt) {}
|
||||
|
||||
/** Constructor from a factor graph of GaussianFactor or a derived type */
|
||||
template<class DERIVEDFACTOR>
|
||||
GaussianFactorGraphOrdered(const FactorGraphOrdered<DERIVEDFACTOR>& fg) {
|
||||
push_back(fg);
|
||||
}
|
||||
|
||||
/** Add a factor by value - makes a copy */
|
||||
void add(const GaussianFactorOrdered& factor) {
|
||||
factors_.push_back(factor.clone());
|
||||
}
|
||||
|
||||
/** Add a factor by pointer - stores pointer without copying the factor */
|
||||
void add(const sharedFactor& factor) {
|
||||
factors_.push_back(factor);
|
||||
}
|
||||
|
||||
/** Add a null factor */
|
||||
void add(const Vector& b) {
|
||||
add(JacobianFactorOrdered(b));
|
||||
}
|
||||
|
||||
/** Add a unary factor */
|
||||
void add(Index key1, const Matrix& A1,
|
||||
const Vector& b, const SharedDiagonal& model) {
|
||||
add(JacobianFactorOrdered(key1,A1,b,model));
|
||||
}
|
||||
|
||||
/** Add a binary factor */
|
||||
void add(Index key1, const Matrix& A1,
|
||||
Index key2, const Matrix& A2,
|
||||
const Vector& b, const SharedDiagonal& model) {
|
||||
add(JacobianFactorOrdered(key1,A1,key2,A2,b,model));
|
||||
}
|
||||
|
||||
/** Add a ternary factor */
|
||||
void add(Index key1, const Matrix& A1,
|
||||
Index key2, const Matrix& A2,
|
||||
Index key3, const Matrix& A3,
|
||||
const Vector& b, const SharedDiagonal& model) {
|
||||
add(JacobianFactorOrdered(key1,A1,key2,A2,key3,A3,b,model));
|
||||
}
|
||||
|
||||
/** Add an n-ary factor */
|
||||
void add(const std::vector<std::pair<Index, Matrix> > &terms,
|
||||
const Vector &b, const SharedDiagonal& model) {
|
||||
add(JacobianFactorOrdered(terms,b,model));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of variables involved in the factors (computes a set
|
||||
* union).
|
||||
*/
|
||||
typedef FastSet<Index> Keys;
|
||||
GTSAM_EXPORT Keys keys() const;
|
||||
|
||||
|
||||
/** Eliminate the first \c n frontal variables, returning the resulting
|
||||
* conditional and remaining factor graph - this is very inefficient for
|
||||
* eliminating all variables, to do that use EliminationTree or
|
||||
* JunctionTree. Note that this version simply calls
|
||||
* FactorGraph<GaussianFactor>::eliminateFrontals with EliminateQR as the
|
||||
* eliminate function argument.
|
||||
*/
|
||||
std::pair<sharedConditional, GaussianFactorGraphOrdered> eliminateFrontals(size_t nFrontals, const Eliminate& function = EliminateQROrdered) const {
|
||||
return Base::eliminateFrontals(nFrontals, function); }
|
||||
|
||||
/** Factor the factor graph into a conditional and a remaining factor graph.
|
||||
* Given the factor graph \f$ f(X) \f$, and \c variables to factorize out
|
||||
* \f$ V \f$, this function factorizes into \f$ f(X) = f(V;Y)f(Y) \f$, where
|
||||
* \f$ Y := X\V \f$ are the remaining variables. If \f$ f(X) = p(X) \f$ is
|
||||
* a probability density or likelihood, the factorization produces a
|
||||
* conditional probability density and a marginal \f$ p(X) = p(V|Y)p(Y) \f$.
|
||||
*
|
||||
* For efficiency, this function treats the variables to eliminate
|
||||
* \c variables as fully-connected, so produces a dense (fully-connected)
|
||||
* conditional on all of the variables in \c variables, instead of a sparse
|
||||
* BayesNet. If the variables are not fully-connected, it is more efficient
|
||||
* to sequentially factorize multiple times.
|
||||
* Note that this version simply calls
|
||||
* FactorGraph<GaussianFactor>::eliminate with EliminateQR as the eliminate
|
||||
* function argument.
|
||||
*/
|
||||
std::pair<sharedConditional, GaussianFactorGraphOrdered> eliminate(const std::vector<Index>& variables, const Eliminate& function = EliminateQROrdered) const {
|
||||
return Base::eliminate(variables, function); }
|
||||
|
||||
/** Eliminate a single variable, by calling GaussianFactorGraph::eliminate. */
|
||||
std::pair<sharedConditional, GaussianFactorGraphOrdered> eliminateOne(Index variable, const Eliminate& function = EliminateQROrdered) const {
|
||||
return Base::eliminateOne(variable, function); }
|
||||
|
||||
/** Permute the variables in the factors */
|
||||
GTSAM_EXPORT void permuteWithInverse(const Permutation& inversePermutation);
|
||||
|
||||
/** Apply a reduction, which is a remapping of variable indices. */
|
||||
GTSAM_EXPORT void reduceWithInverse(const internal::Reduction& inverseReduction);
|
||||
|
||||
/** unnormalized error */
|
||||
double error(const VectorValuesOrdered& x) const {
|
||||
double total_error = 0.;
|
||||
BOOST_FOREACH(const sharedFactor& factor, *this)
|
||||
total_error += factor->error(x);
|
||||
return total_error;
|
||||
}
|
||||
|
||||
/** Unnormalized probability. O(n) */
|
||||
double probPrime(const VectorValuesOrdered& c) const {
|
||||
return exp(-0.5 * error(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function that combines two factor graphs.
|
||||
* @param lfg1 Linear factor graph
|
||||
* @param lfg2 Linear factor graph
|
||||
* @return a new combined factor graph
|
||||
*/
|
||||
GTSAM_EXPORT static GaussianFactorGraphOrdered combine2(const GaussianFactorGraphOrdered& lfg1,
|
||||
const GaussianFactorGraphOrdered& lfg2);
|
||||
|
||||
/**
|
||||
* combine two factor graphs
|
||||
* @param *lfg Linear factor graph
|
||||
*/
|
||||
GTSAM_EXPORT void combine(const GaussianFactorGraphOrdered &lfg);
|
||||
|
||||
/**
|
||||
* Return vector of i, j, and s to generate an m-by-n sparse Jacobian matrix,
|
||||
* where i(k) and j(k) are the base 0 row and column indices, s(k) a double.
|
||||
* The standard deviations are baked into A and b
|
||||
*/
|
||||
GTSAM_EXPORT std::vector<boost::tuple<size_t, size_t, double> > sparseJacobian() const;
|
||||
|
||||
/**
|
||||
* Matrix version of sparseJacobian: generates a 3*m matrix with [i,j,s] entries
|
||||
* such that S(i(k),j(k)) = s(k), which can be given to MATLAB's sparse.
|
||||
* The standard deviations are baked into A and b
|
||||
*/
|
||||
GTSAM_EXPORT Matrix sparseJacobian_() const;
|
||||
|
||||
/**
|
||||
* Return a dense \f$ [ \;A\;b\; ] \in \mathbb{R}^{m \times n+1} \f$
|
||||
* Jacobian matrix, augmented with b with the noise models baked
|
||||
* into A and b. The negative log-likelihood is
|
||||
* \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also
|
||||
* GaussianFactorGraph::jacobian and GaussianFactorGraph::sparseJacobian.
|
||||
*/
|
||||
GTSAM_EXPORT Matrix augmentedJacobian() const;
|
||||
|
||||
/**
|
||||
* Return the dense Jacobian \f$ A \f$ and right-hand-side \f$ b \f$,
|
||||
* with the noise models baked into A and b. The negative log-likelihood
|
||||
* is \f$ \frac{1}{2} \Vert Ax-b \Vert^2 \f$. See also
|
||||
* GaussianFactorGraph::augmentedJacobian and
|
||||
* GaussianFactorGraph::sparseJacobian.
|
||||
*/
|
||||
GTSAM_EXPORT std::pair<Matrix,Vector> jacobian() const;
|
||||
|
||||
/**
|
||||
* Return a dense \f$ \Lambda \in \mathbb{R}^{n+1 \times n+1} \f$ Hessian
|
||||
* matrix, augmented with the information vector \f$ \eta \f$. The
|
||||
* augmented Hessian is
|
||||
\f[ \left[ \begin{array}{ccc}
|
||||
\Lambda & \eta \\
|
||||
\eta^T & c
|
||||
\end{array} \right] \f]
|
||||
and the negative log-likelihood is
|
||||
\f$ \frac{1}{2} x^T \Lambda x + \eta^T x + c \f$.
|
||||
*/
|
||||
GTSAM_EXPORT Matrix augmentedHessian() const;
|
||||
|
||||
/**
|
||||
* Return the dense Hessian \f$ \Lambda \f$ and information vector
|
||||
* \f$ \eta \f$, with the noise models baked in. The negative log-likelihood
|
||||
* is \frac{1}{2} x^T \Lambda x + \eta^T x + c. See also
|
||||
* GaussianFactorGraph::augmentedHessian.
|
||||
*/
|
||||
GTSAM_EXPORT std::pair<Matrix,Vector> hessian() const;
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Combine and eliminate several factors.
|
||||
* \addtogroup LinearSolving
|
||||
*/
|
||||
GTSAM_EXPORT JacobianFactorOrdered::shared_ptr CombineJacobians(
|
||||
const FactorGraphOrdered<JacobianFactorOrdered>& factors,
|
||||
const VariableSlots& variableSlots);
|
||||
|
||||
/**
|
||||
* Evaluates whether linear factors have any constrained noise models
|
||||
* @return true if any factor is constrained.
|
||||
*/
|
||||
GTSAM_EXPORT bool hasConstraints(const FactorGraphOrdered<GaussianFactorOrdered>& factors);
|
||||
|
||||
/**
|
||||
* Densely combine and partially eliminate JacobianFactors to produce a
|
||||
* single conditional with nrFrontals frontal variables and a remaining
|
||||
* factor.
|
||||
* Variables are eliminated in the natural order of the variable indices of in the factors.
|
||||
* @param factors Factors to combine and eliminate
|
||||
* @param nrFrontals Number of frontal variables to eliminate.
|
||||
* @return The conditional and remaining factor
|
||||
|
||||
* \addtogroup LinearSolving
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminateJacobians(const FactorGraphOrdered<
|
||||
JacobianFactorOrdered>& factors, size_t nrFrontals = 1);
|
||||
|
||||
/**
|
||||
* Densely partially eliminate with QR factorization. HessianFactors are
|
||||
* first factored with Cholesky decomposition to produce JacobianFactors,
|
||||
* by calling the conversion constructor JacobianFactor(const HessianFactor&).
|
||||
* Variables are eliminated in the natural order of the variable indices of in
|
||||
* the factors.
|
||||
* @param factors Factors to combine and eliminate
|
||||
* @param nrFrontals Number of frontal variables to eliminate.
|
||||
* @return The conditional and remaining factor
|
||||
|
||||
* \addtogroup LinearSolving
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminateQROrdered(const FactorGraphOrdered<
|
||||
GaussianFactorOrdered>& factors, size_t nrFrontals = 1);
|
||||
|
||||
/**
|
||||
* Densely partially eliminate with Cholesky factorization. JacobianFactors
|
||||
* are left-multiplied with their transpose to form the Hessian using the
|
||||
* conversion constructor HessianFactor(const JacobianFactor&).
|
||||
*
|
||||
* If any factors contain constrained noise models (any sigmas equal to
|
||||
* zero), QR factorization will be performed instead, because our current
|
||||
* implementation cannot handle constrained noise models in Cholesky
|
||||
* factorization. EliminateCholesky(), on the other hand, will fail if any
|
||||
* factors contain constrained noise models.
|
||||
*
|
||||
* Variables are eliminated in the natural order of the variable indices of in
|
||||
* the factors.
|
||||
* @param factors Factors to combine and eliminate
|
||||
* @param nrFrontals Number of frontal variables to eliminate.
|
||||
* @return The conditional and remaining factor
|
||||
|
||||
* \addtogroup LinearSolving
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminatePreferCholeskyOrdered(const FactorGraphOrdered<
|
||||
GaussianFactorOrdered>& factors, size_t nrFrontals = 1);
|
||||
|
||||
/**
|
||||
* Densely partially eliminate with Cholesky factorization. JacobianFactors
|
||||
* are left-multiplied with their transpose to form the Hessian using the
|
||||
* conversion constructor HessianFactor(const JacobianFactor&).
|
||||
*
|
||||
* If any factors contain constrained noise models, this function will fail
|
||||
* because our current implementation cannot handle constrained noise models
|
||||
* in Cholesky factorization. The function EliminatePreferCholesky()
|
||||
* automatically does QR instead when this is the case.
|
||||
*
|
||||
* Variables are eliminated in the natural order of the variable indices of in
|
||||
* the factors.
|
||||
* @param factors Factors to combine and eliminate
|
||||
* @param nrFrontals Number of frontal variables to eliminate.
|
||||
* @return The conditional and remaining factor
|
||||
|
||||
* \addtogroup LinearSolving
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorGraphOrdered::EliminationResult EliminateCholeskyOrdered(const FactorGraphOrdered<
|
||||
GaussianFactorOrdered>& factors, size_t nrFrontals = 1);
|
||||
|
||||
/****** Linear Algebra Opeations ******/
|
||||
|
||||
/** return A*x */
|
||||
GTSAM_EXPORT Errors operator*(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x);
|
||||
|
||||
/** In-place version e <- A*x that overwrites e. */
|
||||
GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, Errors& e);
|
||||
|
||||
/** In-place version e <- A*x that takes an iterator. */
|
||||
GTSAM_EXPORT void multiplyInPlace(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x, const Errors::iterator& e);
|
||||
|
||||
/** x += alpha*A'*e */
|
||||
GTSAM_EXPORT void transposeMultiplyAdd(const GaussianFactorGraphOrdered& fg, double alpha, const Errors& e, VectorValuesOrdered& x);
|
||||
|
||||
/**
|
||||
* Compute the gradient of the energy function,
|
||||
* \f$ \nabla_{x=x_0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$,
|
||||
* centered around \f$ x = x_0 \f$.
|
||||
* The gradient is \f$ A^T(Ax-b) \f$.
|
||||
* @param fg The Jacobian factor graph $(A,b)$
|
||||
* @param x0 The center about which to compute the gradient
|
||||
* @return The gradient as a VectorValues
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered gradient(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x0);
|
||||
|
||||
/**
|
||||
* Compute the gradient of the energy function,
|
||||
* \f$ \nabla_{x=0} \left\Vert \Sigma^{-1} A x - b \right\Vert^2 \f$,
|
||||
* centered around zero.
|
||||
* The gradient is \f$ A^T(Ax-b) \f$.
|
||||
* @param fg The Jacobian factor graph $(A,b)$
|
||||
* @param [output] g A VectorValues to store the gradient, which must be preallocated, see allocateVectorValues
|
||||
* @return The gradient as a VectorValues
|
||||
*/
|
||||
GTSAM_EXPORT void gradientAtZero(const GaussianFactorGraphOrdered& fg, VectorValuesOrdered& g);
|
||||
|
||||
/* matrix-vector operations */
|
||||
GTSAM_EXPORT void residual(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r);
|
||||
GTSAM_EXPORT void multiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &x, VectorValuesOrdered &r);
|
||||
GTSAM_EXPORT void transposeMultiply(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered &r, VectorValuesOrdered &x);
|
||||
|
||||
/** shared pointer version
|
||||
* \todo Make this a member function - affects SubgraphPreconditioner */
|
||||
GTSAM_EXPORT boost::shared_ptr<Errors> gaussianErrors_(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x);
|
||||
|
||||
/** return A*x-b
|
||||
* \todo Make this a member function - affects SubgraphPreconditioner */
|
||||
inline Errors gaussianErrors(const GaussianFactorGraphOrdered& fg, const VectorValuesOrdered& x) {
|
||||
return *gaussianErrors_(fg, x); }
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianFactor.cpp
|
||||
* @brief Linear Factor....A Gaussian
|
||||
* @brief linearFactor
|
||||
* @author Richard Roberts, Christian Potthast
|
||||
*/
|
||||
|
||||
#include <gtsam/linear/GaussianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorOrdered::GaussianFactorOrdered(const GaussianConditionalOrdered& c) :
|
||||
IndexFactorOrdered(c) {}
|
||||
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianFactor.h
|
||||
* @brief A factor with a quadratic error function - a Gaussian
|
||||
* @brief GaussianFactor
|
||||
* @author Richard Roberts, Christian Potthast
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/inference/IndexFactorOrdered.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declarations
|
||||
class VectorValuesOrdered;
|
||||
class Permutation;
|
||||
class GaussianConditionalOrdered;
|
||||
template<class C> class BayesNetOrdered;
|
||||
|
||||
/**
|
||||
* An abstract virtual base class for JacobianFactor and HessianFactor.
|
||||
* A GaussianFactor has a quadratic error function.
|
||||
* GaussianFactor is non-mutable (all methods const!).
|
||||
* The factor value is exp(-0.5*||Ax-b||^2)
|
||||
*/
|
||||
class GTSAM_EXPORT GaussianFactorOrdered: public IndexFactorOrdered {
|
||||
|
||||
protected:
|
||||
|
||||
/** Copy constructor */
|
||||
GaussianFactorOrdered(const This& f) : IndexFactorOrdered(f) {}
|
||||
|
||||
/** Construct from derived type */
|
||||
GaussianFactorOrdered(const GaussianConditionalOrdered& c);
|
||||
|
||||
/** Constructor from a collection of keys */
|
||||
template<class KeyIterator> GaussianFactorOrdered(KeyIterator beginKey, KeyIterator endKey) :
|
||||
Base(beginKey, endKey) {}
|
||||
|
||||
/** Default constructor for I/O */
|
||||
GaussianFactorOrdered() {}
|
||||
|
||||
/** Construct unary factor */
|
||||
GaussianFactorOrdered(Index j) : IndexFactorOrdered(j) {}
|
||||
|
||||
/** Construct binary factor */
|
||||
GaussianFactorOrdered(Index j1, Index j2) : IndexFactorOrdered(j1, j2) {}
|
||||
|
||||
/** Construct ternary factor */
|
||||
GaussianFactorOrdered(Index j1, Index j2, Index j3) : IndexFactorOrdered(j1, j2, j3) {}
|
||||
|
||||
/** Construct 4-way factor */
|
||||
GaussianFactorOrdered(Index j1, Index j2, Index j3, Index j4) : IndexFactorOrdered(j1, j2, j3, j4) {}
|
||||
|
||||
/** Construct n-way factor */
|
||||
GaussianFactorOrdered(const std::set<Index>& js) : IndexFactorOrdered(js) {}
|
||||
|
||||
/** Construct n-way factor */
|
||||
GaussianFactorOrdered(const std::vector<Index>& js) : IndexFactorOrdered(js) {}
|
||||
|
||||
public:
|
||||
|
||||
typedef GaussianConditionalOrdered ConditionalType;
|
||||
typedef boost::shared_ptr<GaussianFactorOrdered> shared_ptr;
|
||||
|
||||
// Implementing Testable interface
|
||||
virtual void print(const std::string& s = "",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const = 0;
|
||||
|
||||
virtual bool equals(const GaussianFactorOrdered& lf, double tol = 1e-9) const = 0;
|
||||
|
||||
virtual double error(const VectorValuesOrdered& c) const = 0; /** 0.5*(A*x-b)'*D*(A*x-b) */
|
||||
|
||||
/** Return the dimension of the variable pointed to by the given key iterator */
|
||||
virtual size_t getDim(const_iterator variable) const = 0;
|
||||
|
||||
/** Return the augmented information matrix represented by this GaussianFactor.
|
||||
* The augmented information matrix contains the information matrix with an
|
||||
* additional column holding the information vector, and an additional row
|
||||
* holding the transpose of the information vector. The lower-right entry
|
||||
* contains the constant error term (when \f$ \delta x = 0 \f$). The
|
||||
* augmented information matrix is described in more detail in HessianFactor,
|
||||
* which in fact stores an augmented information matrix.
|
||||
*/
|
||||
virtual Matrix augmentedInformation() const = 0;
|
||||
|
||||
/** Return the non-augmented information matrix represented by this
|
||||
* GaussianFactor.
|
||||
*/
|
||||
virtual Matrix information() const = 0;
|
||||
|
||||
/** Clone a factor (make a deep copy) */
|
||||
virtual GaussianFactorOrdered::shared_ptr clone() const = 0;
|
||||
|
||||
/**
|
||||
* Permutes the GaussianFactor, but for efficiency requires the permutation
|
||||
* to already be inverted. This acts just as a change-of-name for each
|
||||
* variable. The order of the variables within the factor is not changed.
|
||||
*/
|
||||
virtual void permuteWithInverse(const Permutation& inversePermutation) {
|
||||
IndexFactorOrdered::permuteWithInverse(inversePermutation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a reduction, which is a remapping of variable indices.
|
||||
*/
|
||||
virtual void reduceWithInverse(const internal::Reduction& inverseReduction) {
|
||||
IndexFactorOrdered::reduceWithInverse(inverseReduction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the corresponding anti-factor to negate information
|
||||
* stored stored in this factor.
|
||||
* @return a HessianFactor with negated Hessian matrices
|
||||
*/
|
||||
virtual GaussianFactorOrdered::shared_ptr negate() const = 0;
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(IndexFactorOrdered);
|
||||
}
|
||||
|
||||
}; // GaussianFactor
|
||||
|
||||
/** make keys from list, vector, or map of matrices */
|
||||
template<typename ITERATOR>
|
||||
static std::vector<Index> GetKeys(size_t n, ITERATOR begin, ITERATOR end) {
|
||||
std::vector<Index> keys;
|
||||
keys.reserve(n);
|
||||
for (ITERATOR it=begin;it!=end;++it) keys.push_back(it->first);
|
||||
return keys;
|
||||
}
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianISAM.cpp
|
||||
* @brief Linear ISAM only
|
||||
* @author Michael Kaess
|
||||
*/
|
||||
|
||||
#include <gtsam/linear/GaussianISAMOrdered.h>
|
||||
#include <gtsam/linear/GaussianBayesTreeOrdered.h>
|
||||
|
||||
#include <gtsam/inference/ISAMOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Explicitly instantiate so we don't have to include everywhere
|
||||
template class ISAMOrdered<GaussianConditionalOrdered>;
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorOrdered::shared_ptr GaussianISAMOrdered::marginalFactor(Index j) const {
|
||||
return Super::marginalFactor(j, &EliminateQROrdered);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
BayesNetOrdered<GaussianConditionalOrdered>::shared_ptr GaussianISAMOrdered::marginalBayesNet(Index j) const {
|
||||
return Super::marginalBayesNet(j, &EliminateQROrdered);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix GaussianISAMOrdered::marginalCovariance(Index j) const {
|
||||
GaussianConditionalOrdered::shared_ptr conditional = marginalBayesNet(j)->front();
|
||||
return conditional->information().inverse();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
BayesNetOrdered<GaussianConditionalOrdered>::shared_ptr GaussianISAMOrdered::jointBayesNet(
|
||||
Index key1, Index key2) const {
|
||||
return Super::jointBayesNet(key1, key2, &EliminateQROrdered);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered optimize(const GaussianISAMOrdered& isam) {
|
||||
VectorValuesOrdered result(isam.dims_);
|
||||
// Call optimize for BayesTree
|
||||
optimizeInPlace((const BayesTreeOrdered<GaussianConditionalOrdered>&)isam, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
BayesNetOrdered<GaussianConditionalOrdered> GaussianISAMOrdered::shortcut(sharedClique clique, sharedClique root) {
|
||||
return clique->shortcut(root,&EliminateQROrdered);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianISAM.h
|
||||
* @brief Linear ISAM only
|
||||
* @author Michael Kaess
|
||||
*/
|
||||
|
||||
// \callgraph
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <gtsam/inference/ISAMOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
#include <gtsam/linear/GaussianJunctionTreeOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
class GaussianISAMOrdered : public ISAMOrdered<GaussianConditionalOrdered> {
|
||||
|
||||
typedef ISAMOrdered<GaussianConditionalOrdered> Super;
|
||||
std::vector<size_t> dims_;
|
||||
|
||||
public:
|
||||
|
||||
typedef std::vector<size_t> Dims;
|
||||
|
||||
/** Create an empty Bayes Tree */
|
||||
GaussianISAMOrdered() : Super() {}
|
||||
|
||||
/** Create a Bayes Tree from a Bayes Net */
|
||||
// GaussianISAM(const GaussianBayesNet& bayesNet) : Super(bayesNet) {}
|
||||
GaussianISAMOrdered(const BayesTreeOrdered<GaussianConditionalOrdered>& bayesTree) : Super(bayesTree) {
|
||||
GaussianJunctionTreeOrdered::countDims(bayesTree, dims_);
|
||||
}
|
||||
|
||||
/** Override update_internal to also keep track of variable dimensions. */
|
||||
template<class FACTORGRAPH>
|
||||
void update_internal(const FACTORGRAPH& newFactors, Cliques& orphans) {
|
||||
Super::update_internal(newFactors, orphans, &EliminateQROrdered); // TODO: why does this force QR?
|
||||
update_dimensions(newFactors);
|
||||
}
|
||||
|
||||
template<class FACTORGRAPH>
|
||||
void update(const FACTORGRAPH& newFactors) {
|
||||
Cliques orphans;
|
||||
this->update_internal(newFactors, orphans);
|
||||
}
|
||||
|
||||
template<class FACTORGRAPH>
|
||||
inline void update_dimensions(const FACTORGRAPH& newFactors) {
|
||||
BOOST_FOREACH(const typename FACTORGRAPH::sharedFactor& factor, newFactors) {
|
||||
for(typename FACTORGRAPH::FactorType::const_iterator key = factor->begin(); key != factor->end(); ++key) {
|
||||
if(*key >= dims_.size())
|
||||
dims_.resize(*key + 1);
|
||||
if(dims_[*key] == 0)
|
||||
dims_[*key] = factor->getDim(key);
|
||||
else
|
||||
assert(dims_[*key] == factor->getDim(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Super::clear();
|
||||
dims_.clear();
|
||||
}
|
||||
|
||||
// access
|
||||
const Dims& dims() const { return dims_; } ///< Const access to dimensions structure
|
||||
Dims& dims() { return dims_; } ///< non-const access to dimensions structure (advanced interface)
|
||||
|
||||
GTSAM_EXPORT friend VectorValuesOrdered optimize(const GaussianISAMOrdered&);
|
||||
|
||||
/** return marginal on any variable as a factor, Bayes net, or mean/cov */
|
||||
GTSAM_EXPORT GaussianFactorOrdered::shared_ptr marginalFactor(Index j) const;
|
||||
GTSAM_EXPORT BayesNetOrdered<GaussianConditionalOrdered>::shared_ptr marginalBayesNet(Index key) const;
|
||||
GTSAM_EXPORT Matrix marginalCovariance(Index key) const;
|
||||
|
||||
/** return joint between two variables, as a Bayes net */
|
||||
GTSAM_EXPORT BayesNetOrdered<GaussianConditionalOrdered>::shared_ptr jointBayesNet(Index key1, Index key2) const;
|
||||
|
||||
/** return the conditional P(S|Root) on the separator given the root */
|
||||
GTSAM_EXPORT static BayesNetOrdered<GaussianConditionalOrdered> shortcut(sharedClique clique, sharedClique root);
|
||||
|
||||
}; // \class GaussianISAM
|
||||
|
||||
// optimize the BayesTree, starting from the root
|
||||
GTSAM_EXPORT VectorValuesOrdered optimize(const GaussianISAMOrdered& isam);
|
||||
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianJunctionTree.cpp
|
||||
* @date Jul 12, 2010
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
* @brief: the Gaussian junction tree
|
||||
*/
|
||||
|
||||
#include <gtsam/inference/ClusterTreeOrdered.h>
|
||||
#include <gtsam/inference/JunctionTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianJunctionTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianBayesTreeOrdered.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// explicit template instantiation
|
||||
template class JunctionTreeOrdered<GaussianFactorGraphOrdered>;
|
||||
template class ClusterTreeOrdered<GaussianFactorGraphOrdered>;
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered GaussianJunctionTreeOrdered::optimize(Eliminate function) const {
|
||||
gttic(GJT_eliminate);
|
||||
// eliminate from leaves to the root
|
||||
BTClique::shared_ptr rootClique(this->eliminate(function));
|
||||
gttoc(GJT_eliminate);
|
||||
|
||||
// Allocate solution vector and copy RHS
|
||||
gttic(allocate_VectorValues);
|
||||
vector<size_t> dims(rootClique->conditional()->back()+1, 0);
|
||||
countDims(rootClique, dims);
|
||||
VectorValuesOrdered result(dims);
|
||||
gttoc(allocate_VectorValues);
|
||||
|
||||
// back-substitution
|
||||
gttic(backsubstitute);
|
||||
internal::optimizeInPlace<GaussianBayesTreeOrdered>(rootClique, result);
|
||||
gttoc(backsubstitute);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
} //namespace gtsam
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianJunctionTree.h
|
||||
* @date Jul 12, 2010
|
||||
* @author Kai Ni
|
||||
* @author Frank Dellaert
|
||||
* @brief: the Gaussian junction tree
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <gtsam/inference/JunctionTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianBayesTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* A JunctionTree where all the factors are of type GaussianFactor.
|
||||
*
|
||||
* In GTSAM, typically, a GaussianJunctionTree is created directly from a GaussianFactorGraph,
|
||||
* after which you call optimize() to solve for the mean, or JunctionTree::eliminate() to
|
||||
* create a BayesTree<GaussianConditional>. In both cases, you need to provide a basic
|
||||
* GaussianFactorGraph::Eliminate function that will be used to
|
||||
*
|
||||
* \addtogroup Multifrontal
|
||||
*/
|
||||
class GaussianJunctionTreeOrdered: public JunctionTreeOrdered<GaussianFactorGraphOrdered> {
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<GaussianJunctionTreeOrdered> shared_ptr;
|
||||
typedef JunctionTreeOrdered<GaussianFactorGraphOrdered> Base;
|
||||
typedef Base::sharedClique sharedClique;
|
||||
typedef GaussianFactorGraphOrdered::Eliminate Eliminate;
|
||||
|
||||
public :
|
||||
|
||||
/** Default constructor */
|
||||
GaussianJunctionTreeOrdered() : Base() {}
|
||||
|
||||
/** Constructor from a factor graph. Builds a VariableIndex. */
|
||||
GaussianJunctionTreeOrdered(const GaussianFactorGraphOrdered& fg) : Base(fg) {}
|
||||
|
||||
/** Construct from a factor graph and a pre-computed variable index. */
|
||||
GaussianJunctionTreeOrdered(const GaussianFactorGraphOrdered& fg, const VariableIndexOrdered& variableIndex)
|
||||
: Base(fg, variableIndex) {}
|
||||
|
||||
/**
|
||||
* optimize the linear graph
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered optimize(Eliminate function) const;
|
||||
|
||||
// convenient function to return dimensions of all variables in the BayesTree<GaussianConditional>
|
||||
template<class DIM_CONTAINER, class CLIQUE>
|
||||
static void countDims(const BayesTreeOrdered<GaussianConditionalOrdered,CLIQUE>& bayesTree, DIM_CONTAINER& dims) {
|
||||
dims = DIM_CONTAINER(bayesTree.root()->conditional()->back()+1, 0);
|
||||
countDims(bayesTree.root(), dims);
|
||||
}
|
||||
|
||||
private:
|
||||
template<class DIM_CONTAINER, class CLIQUE>
|
||||
static void countDims(const boost::shared_ptr<CLIQUE>& clique, DIM_CONTAINER& dims) {
|
||||
GaussianConditionalOrdered::const_iterator it = clique->conditional()->beginFrontals();
|
||||
for (; it != clique->conditional()->endFrontals(); ++it) {
|
||||
assert(dims.at(*it) == 0);
|
||||
dims.at(*it) = clique->conditional()->dim(it);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const typename CLIQUE::shared_ptr& child, clique->children()) {
|
||||
countDims(child, dims);
|
||||
}
|
||||
}
|
||||
|
||||
}; // GaussianJunctionTree
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianMultifrontalSolver.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/linear/GaussianMultifrontalSolver.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraphOrdered<GaussianFactorOrdered>& factorGraph, bool useQR) :
|
||||
Base(factorGraph), useQR_(useQR) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianMultifrontalSolver::GaussianMultifrontalSolver(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) :
|
||||
Base(factorGraph, variableIndex), useQR_(useQR) {}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianMultifrontalSolver::shared_ptr
|
||||
GaussianMultifrontalSolver::Create(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) {
|
||||
return shared_ptr(new GaussianMultifrontalSolver(factorGraph, variableIndex, useQR));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianMultifrontalSolver::replaceFactors(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph) {
|
||||
Base::replaceFactors(factorGraph);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianBayesTreeOrdered::shared_ptr GaussianMultifrontalSolver::eliminate() const {
|
||||
if (useQR_)
|
||||
return Base::eliminate(&EliminateQROrdered);
|
||||
else
|
||||
return Base::eliminate(&EliminatePreferCholeskyOrdered);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered::shared_ptr GaussianMultifrontalSolver::optimize() const {
|
||||
gttic(GaussianMultifrontalSolver_optimize);
|
||||
VectorValuesOrdered::shared_ptr values;
|
||||
if (useQR_)
|
||||
values = VectorValuesOrdered::shared_ptr(new VectorValuesOrdered(junctionTree_->optimize(&EliminateQROrdered)));
|
||||
else
|
||||
values= VectorValuesOrdered::shared_ptr(new VectorValuesOrdered(junctionTree_->optimize(&EliminatePreferCholeskyOrdered)));
|
||||
return values;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::shared_ptr GaussianMultifrontalSolver::jointFactorGraph(const std::vector<Index>& js) const {
|
||||
if (useQR_)
|
||||
return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered(*Base::jointFactorGraph(js,&EliminateQROrdered)));
|
||||
else
|
||||
return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered(*Base::jointFactorGraph(js,&EliminatePreferCholeskyOrdered)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorOrdered::shared_ptr GaussianMultifrontalSolver::marginalFactor(Index j) const {
|
||||
if (useQR_)
|
||||
return Base::marginalFactor(j,&EliminateQROrdered);
|
||||
else
|
||||
return Base::marginalFactor(j,&EliminatePreferCholeskyOrdered);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix GaussianMultifrontalSolver::marginalCovariance(Index j) const {
|
||||
FactorGraphOrdered<GaussianFactorOrdered> fg;
|
||||
GaussianConditionalOrdered::shared_ptr conditional;
|
||||
if (useQR_) {
|
||||
fg.push_back(Base::marginalFactor(j,&EliminateQROrdered));
|
||||
conditional = EliminateQROrdered(fg,1).first;
|
||||
} else {
|
||||
fg.push_back(Base::marginalFactor(j,&EliminatePreferCholeskyOrdered));
|
||||
conditional = EliminatePreferCholeskyOrdered(fg,1).first;
|
||||
}
|
||||
return conditional->information().inverse();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianMultifrontalSolver.h
|
||||
* @author Richard Roberts
|
||||
* @date Oct 21, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/GenericMultifrontalSolver.h>
|
||||
#include <gtsam/linear/GaussianBayesTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianJunctionTreeOrdered.h>
|
||||
#include <gtsam/linear/VectorValuesOrdered.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/**
|
||||
* This solver uses multifrontal elimination to solve a GaussianFactorGraph,
|
||||
* i.e. a sparse linear system. Underlying this is a junction tree, which is
|
||||
* eliminated into a Bayes tree.
|
||||
*
|
||||
* The elimination ordering is "baked in" to the variable indices at this
|
||||
* stage, i.e. elimination proceeds in order from '0'. A fill-reducing
|
||||
* ordering is computed symbolically from the NonlinearFactorGraph, on the
|
||||
* nonlinear side of gtsam. (It is actually also possible to permute an
|
||||
* existing GaussianFactorGraph into a COLAMD ordering instead, this is done
|
||||
* when computing marginals).
|
||||
*
|
||||
* The JunctionTree recursively produces a BayesTree<GaussianConditional>,
|
||||
* on which this class calls optimize(...) to perform back-substitution.
|
||||
*/
|
||||
class GaussianMultifrontalSolver : GenericMultifrontalSolver<GaussianFactorOrdered, GaussianJunctionTreeOrdered> {
|
||||
|
||||
protected:
|
||||
|
||||
typedef GenericMultifrontalSolver<GaussianFactorOrdered, GaussianJunctionTreeOrdered> Base;
|
||||
typedef boost::shared_ptr<const GaussianMultifrontalSolver> shared_ptr;
|
||||
|
||||
/** flag to determine whether to use Cholesky or QR */
|
||||
bool useQR_;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct the solver for a factor graph. This builds the junction
|
||||
* tree, which already does some of the work of elimination.
|
||||
*/
|
||||
GTSAM_EXPORT GaussianMultifrontalSolver(const FactorGraphOrdered<GaussianFactorOrdered>& factorGraph, bool useQR = false);
|
||||
|
||||
/**
|
||||
* Construct the solver with a shared pointer to a factor graph and to a
|
||||
* VariableIndex. The solver will store these pointers, so this constructor
|
||||
* is the fastest.
|
||||
*/
|
||||
GTSAM_EXPORT GaussianMultifrontalSolver(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false);
|
||||
|
||||
/**
|
||||
* Named constructor to return a shared_ptr. This builds the elimination
|
||||
* tree, which already does some of the symbolic work of elimination.
|
||||
*/
|
||||
GTSAM_EXPORT static shared_ptr Create(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false);
|
||||
|
||||
/**
|
||||
* Return a new solver that solves the given factor graph, which must have
|
||||
* the *same structure* as the one this solver solves. For some solvers this
|
||||
* is more efficient than constructing the solver from scratch. This can be
|
||||
* used in cases where the numerical values of the linear problem change,
|
||||
* e.g. during iterative nonlinear optimization.
|
||||
*/
|
||||
GTSAM_EXPORT void replaceFactors(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph);
|
||||
|
||||
/**
|
||||
* Eliminate the factor graph sequentially. Uses a column elimination tree
|
||||
* to recursively eliminate.
|
||||
*/
|
||||
GTSAM_EXPORT GaussianBayesTreeOrdered::shared_ptr eliminate() const;
|
||||
|
||||
/**
|
||||
* Compute the least-squares solution of the GaussianFactorGraph. This
|
||||
* eliminates to create a BayesNet and then back-substitutes this BayesNet to
|
||||
* obtain the solution.
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered::shared_ptr optimize() const;
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. This function returns the result as a factor
|
||||
* graph.
|
||||
*
|
||||
* NOTE: This function is limited to computing a joint on 2 variables
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector<Index>& js) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal Gaussian density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as an upper-
|
||||
* triangular R factor and right-hand-side, i.e. a GaussianConditional with
|
||||
* R*x = d. To get a mean and covariance matrix, use marginalStandard(...)
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorOrdered::shared_ptr marginalFactor(Index j) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal Gaussian density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as a mean
|
||||
* vector and covariance matrix. Compared to marginalCanonical, which
|
||||
* returns a GaussianConditional, this function back-substitutes the R factor
|
||||
* to obtain the mean, then computes \f$ \Sigma = (R^T * R)^{-1} \f$.
|
||||
*/
|
||||
GTSAM_EXPORT Matrix marginalCovariance(Index j) const;
|
||||
|
||||
/** @return true if using QR */
|
||||
inline bool usingQR() const { return useQR_; }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianSequentialSolver.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Oct 19, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/linear/GaussianSequentialSolver.h>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianSequentialSolver::GaussianSequentialSolver(
|
||||
const FactorGraphOrdered<GaussianFactorOrdered>& factorGraph, bool useQR) :
|
||||
Base(factorGraph), useQR_(useQR) {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianSequentialSolver::GaussianSequentialSolver(
|
||||
const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) :
|
||||
Base(factorGraph, variableIndex), useQR_(useQR) {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianSequentialSolver::shared_ptr GaussianSequentialSolver::Create(
|
||||
const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR) {
|
||||
return shared_ptr(
|
||||
new GaussianSequentialSolver(factorGraph, variableIndex, useQR));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void GaussianSequentialSolver::replaceFactors(
|
||||
const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph) {
|
||||
Base::replaceFactors(factorGraph);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianBayesNetOrdered::shared_ptr GaussianSequentialSolver::eliminate() const {
|
||||
if (useQR_)
|
||||
return Base::eliminate(&EliminateQROrdered);
|
||||
else
|
||||
return Base::eliminate(&EliminatePreferCholeskyOrdered);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered::shared_ptr GaussianSequentialSolver::optimize() const {
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
if(debug) this->factors_->print("GaussianSequentialSolver, eliminating ");
|
||||
if(debug) this->eliminationTree_->print("GaussianSequentialSolver, elimination tree ");
|
||||
|
||||
gttic(eliminate);
|
||||
// Eliminate using the elimination tree
|
||||
GaussianBayesNetOrdered::shared_ptr bayesNet(this->eliminate());
|
||||
gttoc(eliminate);
|
||||
|
||||
if(debug) bayesNet->print("GaussianSequentialSolver, Bayes net ");
|
||||
|
||||
// Allocate the solution vector if it is not already allocated
|
||||
// VectorValuesOrdered::shared_ptr solution = allocateVectorValues(*bayesNet);
|
||||
|
||||
gttic(optimize);
|
||||
// Back-substitute
|
||||
VectorValuesOrdered::shared_ptr solution(
|
||||
new VectorValuesOrdered(gtsam::optimize(*bayesNet)));
|
||||
gttoc(optimize);
|
||||
|
||||
if(debug) solution->print("GaussianSequentialSolver, solution ");
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorOrdered::shared_ptr GaussianSequentialSolver::marginalFactor(Index j) const {
|
||||
if (useQR_)
|
||||
return Base::marginalFactor(j,&EliminateQROrdered);
|
||||
else
|
||||
return Base::marginalFactor(j,&EliminatePreferCholeskyOrdered);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix GaussianSequentialSolver::marginalCovariance(Index j) const {
|
||||
FactorGraphOrdered<GaussianFactorOrdered> fg;
|
||||
GaussianConditionalOrdered::shared_ptr conditional;
|
||||
if (useQR_) {
|
||||
fg.push_back(Base::marginalFactor(j, &EliminateQROrdered));
|
||||
conditional = EliminateQROrdered(fg, 1).first;
|
||||
} else {
|
||||
fg.push_back(Base::marginalFactor(j, &EliminatePreferCholeskyOrdered));
|
||||
conditional = EliminatePreferCholeskyOrdered(fg, 1).first;
|
||||
}
|
||||
return conditional->information().inverse();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorGraphOrdered::shared_ptr
|
||||
GaussianSequentialSolver::jointFactorGraph(const std::vector<Index>& js) const {
|
||||
if (useQR_)
|
||||
return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered(
|
||||
*Base::jointFactorGraph(js, &EliminateQROrdered)));
|
||||
else
|
||||
return GaussianFactorGraphOrdered::shared_ptr(new GaussianFactorGraphOrdered(
|
||||
*Base::jointFactorGraph(js, &EliminatePreferCholeskyOrdered)));
|
||||
}
|
||||
|
||||
} /// namespace gtsam
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 GaussianSequentialSolver.h
|
||||
* @brief Solves a GaussianFactorGraph (i.e. a sparse linear system) using sequential variable elimination.
|
||||
* @author Richard Roberts
|
||||
* @date Oct 19, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/inference/GenericSequentialSolver.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
#include <gtsam/linear/VectorValuesOrdered.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/** This solver uses sequential variable elimination to solve a
|
||||
* GaussianFactorGraph, i.e. a sparse linear system. Underlying this is a
|
||||
* column elimination tree (inference/EliminationTree), see Gilbert 2001 BIT.
|
||||
*
|
||||
* The elimination ordering is "baked in" to the variable indices at this
|
||||
* stage, i.e. elimination proceeds in order from '0'. A fill-reducing
|
||||
* ordering is computed symbolically from the NonlinearFactorGraph, on the
|
||||
* nonlinear side of gtsam. (To be precise, it is possible to permute an
|
||||
* existing GaussianFactorGraph into a COLAMD ordering instead, this is done
|
||||
* when computing marginals).
|
||||
*
|
||||
* This is not the most efficient algorithm we provide, most efficient is the
|
||||
* MultifrontalSolver, which performs Multi-frontal QR factorization. However,
|
||||
* sequential variable elimination is easier to understand so this is a good
|
||||
* starting point to learn about these algorithms and our implementation.
|
||||
* Additionally, the first step of MFQR is symbolic sequential elimination.
|
||||
*
|
||||
* The EliminationTree recursively produces a BayesNet<GaussianConditional>,
|
||||
* typedef'ed in linear/GaussianBayesNet, on which this class calls
|
||||
* optimize(...) to perform back-substitution.
|
||||
*/
|
||||
class GaussianSequentialSolver : GenericSequentialSolver<GaussianFactorOrdered> {
|
||||
|
||||
protected:
|
||||
|
||||
typedef GenericSequentialSolver<GaussianFactorOrdered> Base;
|
||||
typedef boost::shared_ptr<const GaussianSequentialSolver> shared_ptr;
|
||||
|
||||
/** flag to determine whether to use Cholesky or QR */
|
||||
bool useQR_;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct the solver for a factor graph. This builds the elimination
|
||||
* tree, which already does some of the work of elimination.
|
||||
*/
|
||||
GTSAM_EXPORT GaussianSequentialSolver(const FactorGraphOrdered<GaussianFactorOrdered>& factorGraph, bool useQR = false);
|
||||
|
||||
/**
|
||||
* Construct the solver with a shared pointer to a factor graph and to a
|
||||
* VariableIndex. The solver will store these pointers, so this constructor
|
||||
* is the fastest.
|
||||
*/
|
||||
GTSAM_EXPORT GaussianSequentialSolver(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false);
|
||||
|
||||
/**
|
||||
* Named constructor to return a shared_ptr. This builds the elimination
|
||||
* tree, which already does some of the symbolic work of elimination.
|
||||
*/
|
||||
GTSAM_EXPORT static shared_ptr Create(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph,
|
||||
const VariableIndexOrdered::shared_ptr& variableIndex, bool useQR = false);
|
||||
|
||||
/**
|
||||
* Return a new solver that solves the given factor graph, which must have
|
||||
* the *same structure* as the one this solver solves. For some solvers this
|
||||
* is more efficient than constructing the solver from scratch. This can be
|
||||
* used in cases where the numerical values of the linear problem change,
|
||||
* e.g. during iterative nonlinear optimization.
|
||||
*/
|
||||
GTSAM_EXPORT void replaceFactors(const FactorGraphOrdered<GaussianFactorOrdered>::shared_ptr& factorGraph);
|
||||
|
||||
/**
|
||||
* Eliminate the factor graph sequentially. Uses a column elimination tree
|
||||
* to recursively eliminate.
|
||||
*/
|
||||
GTSAM_EXPORT GaussianBayesNetOrdered::shared_ptr eliminate() const;
|
||||
|
||||
/**
|
||||
* Compute the least-squares solution of the GaussianFactorGraph. This
|
||||
* eliminates to create a BayesNet and then back-substitutes this BayesNet to
|
||||
* obtain the solution.
|
||||
*/
|
||||
GTSAM_EXPORT VectorValuesOrdered::shared_ptr optimize() const;
|
||||
|
||||
/**
|
||||
* Compute the marginal Gaussian density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as an upper-
|
||||
* triangular R factor and right-hand-side, i.e. a GaussianConditional with
|
||||
* R*x = d. To get a mean and covariance matrix, use marginalStandard(...)
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorOrdered::shared_ptr marginalFactor(Index j) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal Gaussian density over a variable, by integrating out
|
||||
* all of the other variables. This function returns the result as a mean
|
||||
* vector and covariance matrix. Compared to marginalCanonical, which
|
||||
* returns a GaussianConditional, this function back-substitutes the R factor
|
||||
* to obtain the mean, then computes \f$ \Sigma = (R^T * R)^{-1} \f$.
|
||||
*/
|
||||
GTSAM_EXPORT Matrix marginalCovariance(Index j) const;
|
||||
|
||||
/**
|
||||
* Compute the marginal joint over a set of variables, by integrating out
|
||||
* all of the other variables. This function returns the result as an upper-
|
||||
* triangular R factor and right-hand-side, i.e. a GaussianBayesNet with
|
||||
* R*x = d. To get a mean and covariance matrix, use jointStandard(...)
|
||||
*/
|
||||
GTSAM_EXPORT GaussianFactorGraphOrdered::shared_ptr jointFactorGraph(const std::vector<Index>& js) const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,560 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 HessianFactor.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Dec 8, 2010
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
#include <boost/bind.hpp>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/base/FastMap.h>
|
||||
#include <gtsam/base/cholesky.h>
|
||||
#include <gtsam/linear/linearExceptions.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/HessianFactorOrdered.h>
|
||||
#include <gtsam/linear/JacobianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
#include <gtsam/linear/GaussianBayesNetOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
string SlotEntryOrdered::toString() const {
|
||||
ostringstream oss;
|
||||
oss << "SlotEntryOrdered: slot=" << slot << ", dim=" << dimension;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
ScatterOrdered::ScatterOrdered(const FactorGraphOrdered<GaussianFactorOrdered>& gfg) {
|
||||
// First do the set union.
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, gfg) {
|
||||
if(factor) {
|
||||
for(GaussianFactorOrdered::const_iterator variable = factor->begin(); variable != factor->end(); ++variable) {
|
||||
this->insert(make_pair(*variable, SlotEntryOrdered(0, factor->getDim(variable))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next fill in the slot indices (we can only get these after doing the set
|
||||
// union.
|
||||
size_t slot = 0;
|
||||
BOOST_FOREACH(value_type& var_slot, *this) {
|
||||
var_slot.second.slot = (slot ++);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void HessianFactorOrdered::assertInvariants() const {
|
||||
GaussianFactorOrdered::assertInvariants(); // The base class checks for unique keys
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(const HessianFactorOrdered& gf) :
|
||||
GaussianFactorOrdered(gf), info_(matrix_) {
|
||||
info_.assignNoalias(gf.info_);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered() : info_(matrix_) {
|
||||
// The empty HessianFactor has only a constant error term of zero
|
||||
FastVector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
info_.resize(dims.begin(), dims.end(), false);
|
||||
info_(0,0)(0,0) = 0.0;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(Index j, const Matrix& G, const Vector& g, double f) :
|
||||
GaussianFactorOrdered(j), info_(matrix_) {
|
||||
if(G.rows() != G.cols() || G.rows() != g.size())
|
||||
throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor");
|
||||
size_t dims[] = { G.rows(), 1 };
|
||||
InfoMatrix fullMatrix(G.rows() + 1, G.rows() + 1);
|
||||
BlockInfo infoMatrix(fullMatrix, dims, dims+2);
|
||||
infoMatrix(0,0) = G;
|
||||
infoMatrix.column(0,1,0) = g;
|
||||
infoMatrix(1,1)(0,0) = f;
|
||||
infoMatrix.swap(info_);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// error is 0.5*(x-mu)'*inv(Sigma)*(x-mu) = 0.5*(x'*G*x - 2*x'*G*mu + mu'*G*mu)
|
||||
// where G = inv(Sigma), g = G*mu, f = mu'*G*mu = mu'*g
|
||||
HessianFactorOrdered::HessianFactorOrdered(Index j, const Vector& mu, const Matrix& Sigma) :
|
||||
GaussianFactorOrdered(j), info_(matrix_) {
|
||||
if (Sigma.rows() != Sigma.cols() || Sigma.rows() != mu.size()) throw invalid_argument(
|
||||
"Inconsistent matrix and/or vector dimensions in HessianFactor constructor");
|
||||
Matrix G = inverse(Sigma);
|
||||
Vector g = G * mu;
|
||||
double f = dot(mu, g);
|
||||
size_t dims[] = { G.rows(), 1 };
|
||||
InfoMatrix fullMatrix(G.rows() + 1, G.rows() + 1);
|
||||
BlockInfo infoMatrix(fullMatrix, dims, dims + 2);
|
||||
infoMatrix(0, 0) = G;
|
||||
infoMatrix.column(0, 1, 0) = g;
|
||||
infoMatrix(1, 1)(0, 0) = f;
|
||||
infoMatrix.swap(info_);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(Index j1, Index j2,
|
||||
const Matrix& G11, const Matrix& G12, const Vector& g1,
|
||||
const Matrix& G22, const Vector& g2, double f) :
|
||||
GaussianFactorOrdered(j1, j2), info_(matrix_) {
|
||||
if(G11.rows() != G11.cols() || G11.rows() != G12.rows() || G11.rows() != g1.size() ||
|
||||
G22.cols() != G12.cols() || G22.cols() != g2.size())
|
||||
throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor");
|
||||
size_t dims[] = { G11.rows(), G22.rows(), 1 };
|
||||
InfoMatrix fullMatrix(G11.rows() + G22.rows() + 1, G11.rows() + G22.rows() + 1);
|
||||
BlockInfo infoMatrix(fullMatrix, dims, dims+3);
|
||||
infoMatrix(0,0) = G11;
|
||||
infoMatrix(0,1) = G12;
|
||||
infoMatrix.column(0,2,0) = g1;
|
||||
infoMatrix(1,1) = G22;
|
||||
infoMatrix.column(1,2,0) = g2;
|
||||
infoMatrix(2,2)(0,0) = f;
|
||||
infoMatrix.swap(info_);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(Index j1, Index j2, Index j3,
|
||||
const Matrix& G11, const Matrix& G12, const Matrix& G13, const Vector& g1,
|
||||
const Matrix& G22, const Matrix& G23, const Vector& g2,
|
||||
const Matrix& G33, const Vector& g3, double f) :
|
||||
GaussianFactorOrdered(j1, j2, j3), info_(matrix_) {
|
||||
if(G11.rows() != G11.cols() || G11.rows() != G12.rows() || G11.rows() != G13.rows() || G11.rows() != g1.size() ||
|
||||
G22.cols() != G12.cols() || G33.cols() != G13.cols() || G22.cols() != g2.size() || G33.cols() != g3.size())
|
||||
throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor");
|
||||
size_t dims[] = { G11.rows(), G22.rows(), G33.rows(), 1 };
|
||||
InfoMatrix fullMatrix(G11.rows() + G22.rows() + G33.rows() + 1, G11.rows() + G22.rows() + G33.rows() + 1);
|
||||
BlockInfo infoMatrix(fullMatrix, dims, dims+4);
|
||||
infoMatrix(0,0) = G11;
|
||||
infoMatrix(0,1) = G12;
|
||||
infoMatrix(0,2) = G13;
|
||||
infoMatrix.column(0,3,0) = g1;
|
||||
infoMatrix(1,1) = G22;
|
||||
infoMatrix(1,2) = G23;
|
||||
infoMatrix.column(1,3,0) = g2;
|
||||
infoMatrix(2,2) = G33;
|
||||
infoMatrix.column(2,3,0) = g3;
|
||||
infoMatrix(3,3)(0,0) = f;
|
||||
infoMatrix.swap(info_);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(const std::vector<Index>& js, const std::vector<Matrix>& Gs,
|
||||
const std::vector<Vector>& gs, double f) : GaussianFactorOrdered(js), info_(matrix_) {
|
||||
|
||||
// Get the number of variables
|
||||
size_t variable_count = js.size();
|
||||
|
||||
// Verify the provided number of entries in the vectors are consistent
|
||||
if(gs.size() != variable_count || Gs.size() != (variable_count*(variable_count+1))/2)
|
||||
throw invalid_argument("Inconsistent number of entries between js, Gs, and gs in HessianFactor constructor.\nThe number of keys provided \
|
||||
in js must match the number of linear vector pieces in gs. The number of upper-diagonal blocks in Gs must be n*(n+1)/2");
|
||||
|
||||
// Verify the dimensions of each provided matrix are consistent
|
||||
// Note: equations for calculating the indices derived from the "sum of an arithmetic sequence" formula
|
||||
for(size_t i = 0; i < variable_count; ++i){
|
||||
int block_size = gs[i].size();
|
||||
// Check rows
|
||||
for(size_t j = 0; j < variable_count-i; ++j){
|
||||
size_t index = i*(2*variable_count - i + 1)/2 + j;
|
||||
if(Gs[index].rows() != block_size){
|
||||
throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor");
|
||||
}
|
||||
}
|
||||
// Check cols
|
||||
for(size_t j = 0; j <= i; ++j){
|
||||
size_t index = j*(2*variable_count - j + 1)/2 + (i-j);
|
||||
if(Gs[index].cols() != block_size){
|
||||
throw invalid_argument("Inconsistent matrix and/or vector dimensions in HessianFactor constructor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the dims vector
|
||||
size_t* dims = (size_t*)alloca(sizeof(size_t)*(variable_count+1)); // FIXME: alloca is bad, just ask Google.
|
||||
size_t total_size = 0;
|
||||
for(unsigned int i = 0; i < variable_count; ++i){
|
||||
dims[i] = gs[i].size();
|
||||
total_size += gs[i].size();
|
||||
}
|
||||
dims[variable_count] = 1;
|
||||
total_size += 1;
|
||||
|
||||
// Fill in the internal matrix with the supplied blocks
|
||||
InfoMatrix fullMatrix(total_size, total_size);
|
||||
BlockInfo infoMatrix(fullMatrix, dims, dims+variable_count+1);
|
||||
size_t index = 0;
|
||||
for(size_t i = 0; i < variable_count; ++i){
|
||||
for(size_t j = i; j < variable_count; ++j){
|
||||
infoMatrix(i,j) = Gs[index++];
|
||||
}
|
||||
infoMatrix.column(i,variable_count,0) = gs[i];
|
||||
}
|
||||
infoMatrix(variable_count,variable_count)(0,0) = f;
|
||||
|
||||
// update the BlockView variable
|
||||
infoMatrix.swap(info_);
|
||||
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(const GaussianConditionalOrdered& cg) : GaussianFactorOrdered(cg), info_(matrix_) {
|
||||
JacobianFactorOrdered jf(cg);
|
||||
info_.copyStructureFrom(jf.Ab_);
|
||||
matrix_.noalias() = jf.matrix_.transpose() * jf.matrix_;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(const GaussianFactorOrdered& gf) : info_(matrix_) {
|
||||
// Copy the variable indices
|
||||
(GaussianFactorOrdered&)(*this) = gf;
|
||||
// Copy the matrix data depending on what type of factor we're copying from
|
||||
if(dynamic_cast<const JacobianFactorOrdered*>(&gf)) {
|
||||
const JacobianFactorOrdered& jf(static_cast<const JacobianFactorOrdered&>(gf));
|
||||
if(jf.model_->isConstrained())
|
||||
throw invalid_argument("Cannot construct HessianFactor from JacobianFactor with constrained noise model");
|
||||
else {
|
||||
Vector invsigmas = jf.model_->invsigmas().cwiseProduct(jf.model_->invsigmas());
|
||||
info_.copyStructureFrom(jf.Ab_);
|
||||
BlockInfo::constBlock A = jf.Ab_.full();
|
||||
matrix_.noalias() = A.transpose() * invsigmas.asDiagonal() * A;
|
||||
}
|
||||
} else if(dynamic_cast<const HessianFactorOrdered*>(&gf)) {
|
||||
const HessianFactorOrdered& hf(static_cast<const HessianFactorOrdered&>(gf));
|
||||
info_.assignNoalias(hf.info_);
|
||||
} else
|
||||
throw std::invalid_argument("In HessianFactor(const GaussianFactor& gf), gf is neither a JacobianFactor nor a HessianFactor");
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered::HessianFactorOrdered(const FactorGraphOrdered<GaussianFactorOrdered>& factors) : info_(matrix_)
|
||||
{
|
||||
ScatterOrdered scatter(factors);
|
||||
|
||||
// Pull out keys and dimensions
|
||||
gttic(keys);
|
||||
vector<size_t> dimensions(scatter.size() + 1);
|
||||
BOOST_FOREACH(const ScatterOrdered::value_type& var_slot, scatter) {
|
||||
dimensions[var_slot.second.slot] = var_slot.second.dimension;
|
||||
}
|
||||
// This is for the r.h.s. vector
|
||||
dimensions.back() = 1;
|
||||
gttoc(keys);
|
||||
|
||||
const bool debug = ISDEBUG("EliminateCholesky");
|
||||
// Form Ab' * Ab
|
||||
gttic(allocate);
|
||||
info_.resize(dimensions.begin(), dimensions.end(), false);
|
||||
// Fill in keys
|
||||
keys_.resize(scatter.size());
|
||||
std::transform(scatter.begin(), scatter.end(), keys_.begin(), boost::bind(&ScatterOrdered::value_type::first, ::_1));
|
||||
gttoc(allocate);
|
||||
gttic(zero);
|
||||
matrix_.noalias() = Matrix::Zero(matrix_.rows(),matrix_.cols());
|
||||
gttoc(zero);
|
||||
gttic(update);
|
||||
if (debug) cout << "Combining " << factors.size() << " factors" << endl;
|
||||
BOOST_FOREACH(const GaussianFactorOrdered::shared_ptr& factor, factors)
|
||||
{
|
||||
if(factor) {
|
||||
if(shared_ptr hessian = boost::dynamic_pointer_cast<HessianFactorOrdered>(factor))
|
||||
updateATA(*hessian, scatter);
|
||||
else if(JacobianFactorOrdered::shared_ptr jacobianFactor = boost::dynamic_pointer_cast<JacobianFactorOrdered>(factor))
|
||||
updateATA(*jacobianFactor, scatter);
|
||||
else
|
||||
throw invalid_argument("GaussianFactor is neither Hessian nor Jacobian");
|
||||
}
|
||||
}
|
||||
gttoc(update);
|
||||
|
||||
if (debug) gtsam::print(matrix_, "Ab' * Ab: ");
|
||||
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
HessianFactorOrdered& HessianFactorOrdered::operator=(const HessianFactorOrdered& rhs) {
|
||||
this->Base::operator=(rhs); // Copy keys
|
||||
info_.assignNoalias(rhs.info_); // Copy matrix and block structure
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void HessianFactorOrdered::print(const std::string& s, const IndexFormatter& formatter) const {
|
||||
cout << s << "\n";
|
||||
cout << " keys: ";
|
||||
for(const_iterator key=this->begin(); key!=this->end(); ++key)
|
||||
cout << formatter(*key) << "(" << this->getDim(key) << ") ";
|
||||
cout << "\n";
|
||||
gtsam::print(Matrix(info_.range(0,info_.nBlocks(), 0,info_.nBlocks()).selfadjointView<Eigen::Upper>()), "Ab^T * Ab: ");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool HessianFactorOrdered::equals(const GaussianFactorOrdered& lf, double tol) const {
|
||||
if(!dynamic_cast<const HessianFactorOrdered*>(&lf))
|
||||
return false;
|
||||
else {
|
||||
Matrix thisMatrix = this->info_.full().selfadjointView<Eigen::Upper>();
|
||||
thisMatrix(thisMatrix.rows()-1, thisMatrix.cols()-1) = 0.0;
|
||||
Matrix rhsMatrix = static_cast<const HessianFactorOrdered&>(lf).info_.full().selfadjointView<Eigen::Upper>();
|
||||
rhsMatrix(rhsMatrix.rows()-1, rhsMatrix.cols()-1) = 0.0;
|
||||
return equal_with_abs_tol(thisMatrix, rhsMatrix, tol);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix HessianFactorOrdered::augmentedInformation() const {
|
||||
return info_.full().selfadjointView<Eigen::Upper>();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix HessianFactorOrdered::information() const {
|
||||
return info_.range(0, this->size(), 0, this->size()).selfadjointView<Eigen::Upper>();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
double HessianFactorOrdered::error(const VectorValuesOrdered& c) const {
|
||||
// error 0.5*(f - 2*x'*g + x'*G*x)
|
||||
const double f = constantTerm();
|
||||
double xtg = 0, xGx = 0;
|
||||
// extract the relevant subset of the VectorValues
|
||||
// NOTE may not be as efficient
|
||||
const Vector x = c.vector(this->keys());
|
||||
xtg = x.dot(linearTerm());
|
||||
xGx = x.transpose() * info_.range(0, this->size(), 0, this->size()).selfadjointView<Eigen::Upper>() * x;
|
||||
return 0.5 * (f - 2.0 * xtg + xGx);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void HessianFactorOrdered::updateATA(const HessianFactorOrdered& update, const ScatterOrdered& scatter) {
|
||||
|
||||
// This function updates 'combined' with the information in 'update'.
|
||||
// 'scatter' maps variables in the update factor to slots in the combined
|
||||
// factor.
|
||||
|
||||
const bool debug = ISDEBUG("updateATA");
|
||||
|
||||
// First build an array of slots
|
||||
gttic(slots);
|
||||
size_t* slots = (size_t*)alloca(sizeof(size_t)*update.size()); // FIXME: alloca is bad, just ask Google.
|
||||
size_t slot = 0;
|
||||
BOOST_FOREACH(Index j, update) {
|
||||
slots[slot] = scatter.find(j)->second.slot;
|
||||
++ slot;
|
||||
}
|
||||
gttoc(slots);
|
||||
|
||||
if(debug) {
|
||||
this->print("Updating this: ");
|
||||
update.print("with (Hessian): ");
|
||||
}
|
||||
|
||||
// Apply updates to the upper triangle
|
||||
gttic(update);
|
||||
for(size_t j2=0; j2<update.info_.nBlocks(); ++j2) {
|
||||
size_t slot2 = (j2 == update.size()) ? this->info_.nBlocks()-1 : slots[j2];
|
||||
for(size_t j1=0; j1<=j2; ++j1) {
|
||||
size_t slot1 = (j1 == update.size()) ? this->info_.nBlocks()-1 : slots[j1];
|
||||
if(slot2 > slot1) {
|
||||
if(debug)
|
||||
cout << "Updating (" << slot1 << "," << slot2 << ") from (" << j1 << "," << j2 << ")" << endl;
|
||||
matrix_.block(info_.offset(slot1), info_.offset(slot2), info_(slot1,slot2).rows(), info_(slot1,slot2).cols()).noalias() +=
|
||||
update.matrix_.block(update.info_.offset(j1), update.info_.offset(j2), update.info_(j1,j2).rows(), update.info_(j1,j2).cols());
|
||||
} else if(slot1 > slot2) {
|
||||
if(debug)
|
||||
cout << "Updating (" << slot2 << "," << slot1 << ") from (" << j1 << "," << j2 << ")" << endl;
|
||||
matrix_.block(info_.offset(slot2), info_.offset(slot1), info_(slot2,slot1).rows(), info_(slot2,slot1).cols()).noalias() +=
|
||||
update.matrix_.block(update.info_.offset(j1), update.info_.offset(j2), update.info_(j1,j2).rows(), update.info_(j1,j2).cols()).transpose();
|
||||
} else {
|
||||
if(debug)
|
||||
cout << "Updating (" << slot1 << "," << slot2 << ") from (" << j1 << "," << j2 << ")" << endl;
|
||||
matrix_.block(info_.offset(slot1), info_.offset(slot2), info_(slot1,slot2).rows(), info_(slot1,slot2).cols()).triangularView<Eigen::Upper>() +=
|
||||
update.matrix_.block(update.info_.offset(j1), update.info_.offset(j2), update.info_(j1,j2).rows(), update.info_(j1,j2).cols());
|
||||
}
|
||||
if(debug) cout << "Updating block " << slot1 << "," << slot2 << " from block " << j1 << "," << j2 << "\n";
|
||||
if(debug) this->print();
|
||||
}
|
||||
}
|
||||
gttoc(update);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void HessianFactorOrdered::updateATA(const JacobianFactorOrdered& update, const ScatterOrdered& scatter) {
|
||||
|
||||
// This function updates 'combined' with the information in 'update'.
|
||||
// 'scatter' maps variables in the update factor to slots in the combined
|
||||
// factor.
|
||||
|
||||
const bool debug = ISDEBUG("updateATA");
|
||||
|
||||
// First build an array of slots
|
||||
gttic(slots);
|
||||
size_t* slots = (size_t*)alloca(sizeof(size_t)*update.size()); // FIXME: alloca is bad, just ask Google.
|
||||
size_t slot = 0;
|
||||
BOOST_FOREACH(Index j, update) {
|
||||
slots[slot] = scatter.find(j)->second.slot;
|
||||
++ slot;
|
||||
}
|
||||
gttoc(slots);
|
||||
|
||||
gttic(form_ATA);
|
||||
if(update.model_->isConstrained())
|
||||
throw invalid_argument("Cannot update HessianFactor from JacobianFactor with constrained noise model");
|
||||
|
||||
if(debug) {
|
||||
this->print("Updating this: ");
|
||||
update.print("with (Jacobian): ");
|
||||
}
|
||||
|
||||
typedef Eigen::Block<const JacobianFactorOrdered::AbMatrix> BlockUpdateMatrix;
|
||||
BlockUpdateMatrix updateA(update.matrix_.block(
|
||||
update.Ab_.rowStart(),update.Ab_.offset(0), update.Ab_.full().rows(), update.Ab_.full().cols()));
|
||||
if (debug) cout << "updateA: \n" << updateA << endl;
|
||||
|
||||
Matrix updateInform;
|
||||
if(boost::dynamic_pointer_cast<noiseModel::Unit>(update.model_)) {
|
||||
updateInform.noalias() = updateA.transpose() * updateA;
|
||||
} else {
|
||||
noiseModel::Diagonal::shared_ptr diagonal(boost::dynamic_pointer_cast<noiseModel::Diagonal>(update.model_));
|
||||
if(diagonal) {
|
||||
Vector invsigmas2 = update.model_->invsigmas().cwiseProduct(update.model_->invsigmas());
|
||||
updateInform.noalias() = updateA.transpose() * invsigmas2.asDiagonal() * updateA;
|
||||
} else
|
||||
throw invalid_argument("In HessianFactor::updateATA, JacobianFactor noise model is neither Unit nor Diagonal");
|
||||
}
|
||||
if (debug) cout << "updateInform: \n" << updateInform << endl;
|
||||
gttoc(form_ATA);
|
||||
|
||||
// Apply updates to the upper triangle
|
||||
gttic(update);
|
||||
for(size_t j2=0; j2<update.Ab_.nBlocks(); ++j2) {
|
||||
size_t slot2 = (j2 == update.size()) ? this->info_.nBlocks()-1 : slots[j2];
|
||||
for(size_t j1=0; j1<=j2; ++j1) {
|
||||
size_t slot1 = (j1 == update.size()) ? this->info_.nBlocks()-1 : slots[j1];
|
||||
size_t off0 = update.Ab_.offset(0);
|
||||
if(slot2 > slot1) {
|
||||
if(debug)
|
||||
cout << "Updating (" << slot1 << "," << slot2 << ") from (" << j1 << "," << j2 << ")" << endl;
|
||||
matrix_.block(info_.offset(slot1), info_.offset(slot2), info_(slot1,slot2).rows(), info_(slot1,slot2).cols()).noalias() +=
|
||||
updateInform.block(update.Ab_.offset(j1)-off0, update.Ab_.offset(j2)-off0, update.Ab_(j1).cols(), update.Ab_(j2).cols());
|
||||
} else if(slot1 > slot2) {
|
||||
if(debug)
|
||||
cout << "Updating (" << slot2 << "," << slot1 << ") from (" << j1 << "," << j2 << ")" << endl;
|
||||
matrix_.block(info_.offset(slot2), info_.offset(slot1), info_(slot2,slot1).rows(), info_(slot2,slot1).cols()).noalias() +=
|
||||
updateInform.block(update.Ab_.offset(j1)-off0, update.Ab_.offset(j2)-off0, update.Ab_(j1).cols(), update.Ab_(j2).cols()).transpose();
|
||||
} else {
|
||||
if(debug)
|
||||
cout << "Updating (" << slot1 << "," << slot2 << ") from (" << j1 << "," << j2 << ")" << endl;
|
||||
matrix_.block(info_.offset(slot1), info_.offset(slot2), info_(slot1,slot2).rows(), info_(slot1,slot2).cols()).triangularView<Eigen::Upper>() +=
|
||||
updateInform.block(update.Ab_.offset(j1)-off0, update.Ab_.offset(j2)-off0, update.Ab_(j1).cols(), update.Ab_(j2).cols());
|
||||
}
|
||||
if(debug) cout << "Updating block " << slot1 << "," << slot2 << " from block " << j1 << "," << j2 << "\n";
|
||||
if(debug) this->print();
|
||||
}
|
||||
}
|
||||
gttoc(update);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void HessianFactorOrdered::partialCholesky(size_t nrFrontals) {
|
||||
if(!choleskyPartial(matrix_, info_.offset(nrFrontals)))
|
||||
throw IndeterminantLinearSystemException(this->keys().front());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::shared_ptr HessianFactorOrdered::splitEliminatedFactor(size_t nrFrontals) {
|
||||
|
||||
static const bool debug = false;
|
||||
|
||||
// Extract conditionals
|
||||
gttic(extract_conditionals);
|
||||
GaussianConditionalOrdered::shared_ptr conditional(new GaussianConditionalOrdered());
|
||||
typedef VerticalBlockView<Matrix> BlockAb;
|
||||
BlockAb Ab(matrix_, info_);
|
||||
|
||||
size_t varDim = info_.offset(nrFrontals);
|
||||
Ab.rowEnd() = Ab.rowStart() + varDim;
|
||||
|
||||
// Create one big conditionals with many frontal variables.
|
||||
gttic(construct_cond);
|
||||
Vector sigmas = Vector::Ones(varDim);
|
||||
conditional = boost::make_shared<ConditionalType>(keys_.begin(), keys_.end(), nrFrontals, Ab, sigmas);
|
||||
gttoc(construct_cond);
|
||||
if(debug) conditional->print("Extracted conditional: ");
|
||||
|
||||
gttoc(extract_conditionals);
|
||||
|
||||
// Take lower-right block of Ab_ to get the new factor
|
||||
gttic(remaining_factor);
|
||||
info_.blockStart() = nrFrontals;
|
||||
// Assign the keys
|
||||
vector<Index> remainingKeys(keys_.size() - nrFrontals);
|
||||
remainingKeys.assign(keys_.begin() + nrFrontals, keys_.end());
|
||||
keys_.swap(remainingKeys);
|
||||
gttoc(remaining_factor);
|
||||
|
||||
return conditional;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorOrdered::shared_ptr HessianFactorOrdered::negate() const {
|
||||
// Copy Hessian Blocks from Hessian factor and invert
|
||||
std::vector<Index> js;
|
||||
std::vector<Matrix> Gs;
|
||||
std::vector<Vector> gs;
|
||||
double f;
|
||||
js.insert(js.end(), begin(), end());
|
||||
for(size_t i = 0; i < js.size(); ++i){
|
||||
for(size_t j = i; j < js.size(); ++j){
|
||||
Gs.push_back( -info(begin()+i, begin()+j) );
|
||||
}
|
||||
gs.push_back( -linearTerm(begin()+i) );
|
||||
}
|
||||
f = -constantTerm();
|
||||
|
||||
// Create the Anti-Hessian Factor from the negated blocks
|
||||
return HessianFactorOrdered::shared_ptr(new HessianFactorOrdered(js, Gs, gs, f));
|
||||
}
|
||||
|
||||
} // gtsam
|
||||
|
|
@ -1,377 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 HessianFactor.h
|
||||
* @brief Contains the HessianFactor class, a general quadratic factor
|
||||
* @author Richard Roberts
|
||||
* @date Dec 8, 2010
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/blockMatrices.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorOrdered.h>
|
||||
|
||||
// Forward declarations for friend unit tests
|
||||
class HessianFactorOrderedConversionConstructorTest;
|
||||
class HessianFactorOrderedConstructor1Test;
|
||||
class HessianFactorOrderedConstructor1bTest;
|
||||
class HessianFactorOrderedcombineTest;
|
||||
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declarations
|
||||
class JacobianFactorOrdered;
|
||||
class GaussianConditionalOrdered;
|
||||
template<class C> class BayesNetOrdered;
|
||||
|
||||
// Definition of ScatterOrdered, which is an intermediate data structure used when
|
||||
// building a HessianFactor incrementally, to get the keys in the right
|
||||
// order.
|
||||
// The "scatter" is a map from global variable indices to slot indices in the
|
||||
// union of involved variables. We also include the dimensionality of the
|
||||
// variable.
|
||||
struct GTSAM_EXPORT SlotEntryOrdered {
|
||||
size_t slot;
|
||||
size_t dimension;
|
||||
SlotEntryOrdered(size_t _slot, size_t _dimension)
|
||||
: slot(_slot), dimension(_dimension) {}
|
||||
std::string toString() const;
|
||||
};
|
||||
class ScatterOrdered : public FastMap<Index, SlotEntryOrdered> {
|
||||
public:
|
||||
ScatterOrdered() {}
|
||||
ScatterOrdered(const FactorGraphOrdered<GaussianFactorOrdered>& gfg);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A Gaussian factor using the canonical parameters (information form)
|
||||
*
|
||||
* HessianFactor implements a general quadratic factor of the form
|
||||
* \f[ E(x) = 0.5 x^T G x - x^T g + 0.5 f \f]
|
||||
* that stores the matrix \f$ G \f$, the vector \f$ g \f$, and the constant term \f$ f \f$.
|
||||
*
|
||||
* When \f$ G \f$ is positive semidefinite, this factor represents a Gaussian,
|
||||
* in which case \f$ G \f$ is the information matrix \f$ \Lambda \f$,
|
||||
* \f$ g \f$ is the information vector \f$ \eta \f$, and \f$ f \f$ is the residual
|
||||
* sum-square-error at the mean, when \f$ x = \mu \f$.
|
||||
*
|
||||
* Indeed, the negative log-likelihood of a Gaussian is (up to a constant)
|
||||
* @f$ E(x) = 0.5(x-\mu)^T P^{-1} (x-\mu) @f$
|
||||
* with @f$ \mu @f$ the mean and @f$ P @f$ the covariance matrix. Expanding the product we get
|
||||
* @f[
|
||||
* E(x) = 0.5 x^T P^{-1} x - x^T P^{-1} \mu + 0.5 \mu^T P^{-1} \mu
|
||||
* @f]
|
||||
* We define the Information matrix (or Hessian) @f$ \Lambda = P^{-1} @f$
|
||||
* and the information vector @f$ \eta = P^{-1} \mu = \Lambda \mu @f$
|
||||
* to arrive at the canonical form of the Gaussian:
|
||||
* @f[
|
||||
* E(x) = 0.5 x^T \Lambda x - x^T \eta + 0.5 \mu^T \Lambda \mu
|
||||
* @f]
|
||||
*
|
||||
* This factor is one of the factors that can be in a GaussianFactorGraph.
|
||||
* It may be returned from NonlinearFactor::linearize(), but is also
|
||||
* used internally to store the Hessian during Cholesky elimination.
|
||||
*
|
||||
* This can represent a quadratic factor with characteristics that cannot be
|
||||
* represented using a JacobianFactor (which has the form
|
||||
* \f$ E(x) = \Vert Ax - b \Vert^2 \f$ and stores the Jacobian \f$ A \f$
|
||||
* and error vector \f$ b \f$, i.e. is a sum-of-squares factor). For example,
|
||||
* a HessianFactor need not be positive semidefinite, it can be indefinite or
|
||||
* even negative semidefinite.
|
||||
*
|
||||
* If a HessianFactor is indefinite or negative semi-definite, then in order
|
||||
* for solving the linear system to be possible,
|
||||
* the Hessian of the full system must be positive definite (i.e. when all
|
||||
* small Hessians are combined, the result must be positive definite). If
|
||||
* this is not the case, an error will occur during elimination.
|
||||
*
|
||||
* This class stores G, g, and f as an augmented matrix HessianFactor::matrix_.
|
||||
* The upper-left n x n blocks of HessianFactor::matrix_ store the upper-right
|
||||
* triangle of G, the upper-right-most column of length n of HessianFactor::matrix_
|
||||
* stores g, and the lower-right entry of HessianFactor::matrix_ stores f, i.e.
|
||||
* \code
|
||||
HessianFactor::matrix_ = [ G11 G12 G13 ... g1
|
||||
0 G22 G23 ... g2
|
||||
0 0 G33 ... g3
|
||||
: : : :
|
||||
0 0 0 ... f ]
|
||||
\endcode
|
||||
Blocks can be accessed as follows:
|
||||
\code
|
||||
G11 = info(begin(), begin());
|
||||
G12 = info(begin(), begin()+1);
|
||||
G23 = info(begin()+1, begin()+2);
|
||||
g2 = linearTerm(begin()+1);
|
||||
f = constantTerm();
|
||||
.......
|
||||
\endcode
|
||||
*/
|
||||
class GTSAM_EXPORT HessianFactorOrdered : public GaussianFactorOrdered {
|
||||
protected:
|
||||
typedef Matrix InfoMatrix; ///< The full augmented Hessian
|
||||
typedef SymmetricBlockView<InfoMatrix> BlockInfo; ///< A blockwise view of the Hessian
|
||||
typedef GaussianFactorOrdered Base; ///< Typedef to base class
|
||||
|
||||
InfoMatrix matrix_; ///< The full augmented information matrix, s.t. the quadratic error is 0.5*[x -1]'*H*[x -1]
|
||||
BlockInfo info_; ///< The block view of the full information matrix.
|
||||
|
||||
public:
|
||||
|
||||
typedef boost::shared_ptr<HessianFactorOrdered> shared_ptr; ///< A shared_ptr to this
|
||||
typedef BlockInfo::Block Block; ///< A block from the Hessian matrix
|
||||
typedef BlockInfo::constBlock constBlock; ///< A block from the Hessian matrix (const version)
|
||||
typedef BlockInfo::Column Column; ///< A column containing the linear term h
|
||||
typedef BlockInfo::constColumn constColumn; ///< A column containing the linear term h (const version)
|
||||
|
||||
/** Copy constructor */
|
||||
HessianFactorOrdered(const HessianFactorOrdered& gf);
|
||||
|
||||
/** default constructor for I/O */
|
||||
HessianFactorOrdered();
|
||||
|
||||
/** Construct a unary factor. G is the quadratic term (Hessian matrix), g
|
||||
* the linear term (a vector), and f the constant term. The quadratic
|
||||
* error is:
|
||||
* 0.5*(f - 2*x'*g + x'*G*x)
|
||||
*/
|
||||
HessianFactorOrdered(Index j, const Matrix& G, const Vector& g, double f);
|
||||
|
||||
/** Construct a unary factor, given a mean and covariance matrix.
|
||||
* error is 0.5*(x-mu)'*inv(Sigma)*(x-mu)
|
||||
*/
|
||||
HessianFactorOrdered(Index j, const Vector& mu, const Matrix& Sigma);
|
||||
|
||||
/** Construct a binary factor. Gxx are the upper-triangle blocks of the
|
||||
* quadratic term (the Hessian matrix), gx the pieces of the linear vector
|
||||
* term, and f the constant term.
|
||||
* JacobianFactor error is \f[ 0.5* (Ax-b)' M (Ax-b) = 0.5*x'A'MAx - x'A'Mb + 0.5*b'Mb \f]
|
||||
* HessianFactor error is \f[ 0.5*(x'Gx - 2x'g + f) = 0.5*x'Gx - x'*g + 0.5*f \f]
|
||||
* So, with \f$ A = [A1 A2] \f$ and \f$ G=A*'M*A = [A1';A2']*M*[A1 A2] \f$ we have
|
||||
\code
|
||||
n1*n1 G11 = A1'*M*A1
|
||||
n1*n2 G12 = A1'*M*A2
|
||||
n2*n2 G22 = A2'*M*A2
|
||||
n1*1 g1 = A1'*M*b
|
||||
n2*1 g2 = A2'*M*b
|
||||
1*1 f = b'*M*b
|
||||
\endcode
|
||||
*/
|
||||
HessianFactorOrdered(Index j1, Index j2,
|
||||
const Matrix& G11, const Matrix& G12, const Vector& g1,
|
||||
const Matrix& G22, const Vector& g2, double f);
|
||||
|
||||
/** Construct a ternary factor. Gxx are the upper-triangle blocks of the
|
||||
* quadratic term (the Hessian matrix), gx the pieces of the linear vector
|
||||
* term, and f the constant term.
|
||||
*/
|
||||
HessianFactorOrdered(Index j1, Index j2, Index j3,
|
||||
const Matrix& G11, const Matrix& G12, const Matrix& G13, const Vector& g1,
|
||||
const Matrix& G22, const Matrix& G23, const Vector& g2,
|
||||
const Matrix& G33, const Vector& g3, double f);
|
||||
|
||||
/** Construct an n-way factor. Gs contains the upper-triangle blocks of the
|
||||
* quadratic term (the Hessian matrix) provided in row-order, gs the pieces
|
||||
* of the linear vector term, and f the constant term.
|
||||
*/
|
||||
HessianFactorOrdered(const std::vector<Index>& js, const std::vector<Matrix>& Gs,
|
||||
const std::vector<Vector>& gs, double f);
|
||||
|
||||
/** Construct from Conditional Gaussian */
|
||||
explicit HessianFactorOrdered(const GaussianConditionalOrdered& cg);
|
||||
|
||||
/** Convert from a JacobianFactor (computes A^T * A) or HessianFactor */
|
||||
explicit HessianFactorOrdered(const GaussianFactorOrdered& factor);
|
||||
|
||||
/** Combine a set of factors into a single dense HessianFactor */
|
||||
HessianFactorOrdered(const FactorGraphOrdered<GaussianFactorOrdered>& factors);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HessianFactorOrdered() {}
|
||||
|
||||
/** Aassignment operator */
|
||||
HessianFactorOrdered& operator=(const HessianFactorOrdered& rhs);
|
||||
|
||||
/** Clone this JacobianFactor */
|
||||
virtual GaussianFactorOrdered::shared_ptr clone() const {
|
||||
return boost::static_pointer_cast<GaussianFactorOrdered>(
|
||||
shared_ptr(new HessianFactorOrdered(*this)));
|
||||
}
|
||||
|
||||
/** Print the factor for debugging and testing (implementing Testable) */
|
||||
virtual void print(const std::string& s = "",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** Compare to another factor for testing (implementing Testable) */
|
||||
virtual bool equals(const GaussianFactorOrdered& lf, double tol = 1e-9) const;
|
||||
|
||||
/** Evaluate the factor error f(x), see above. */
|
||||
virtual double error(const VectorValuesOrdered& c) const; /** 0.5*[x -1]'*H*[x -1] (also see constructor documentation) */
|
||||
|
||||
/** Return the dimension of the variable pointed to by the given key iterator
|
||||
* todo: Remove this in favor of keeping track of dimensions with variables?
|
||||
* @param variable An iterator pointing to the slot in this factor. You can
|
||||
* use, for example, begin() + 2 to get the 3rd variable in this factor.
|
||||
*/
|
||||
virtual size_t getDim(const_iterator variable) const { return info_(variable-this->begin(), 0).rows(); }
|
||||
|
||||
/** Return the number of columns and rows of the Hessian matrix */
|
||||
size_t rows() const { return info_.rows(); }
|
||||
|
||||
/**
|
||||
* Construct the corresponding anti-factor to negate information
|
||||
* stored stored in this factor.
|
||||
* @return a HessianFactor with negated Hessian matrices
|
||||
*/
|
||||
virtual GaussianFactorOrdered::shared_ptr negate() const;
|
||||
|
||||
/** Return a view of the block at (j1,j2) of the <em>upper-triangular part</em> of the
|
||||
* information matrix \f$ H \f$, no data is copied. See HessianFactor class documentation
|
||||
* above to explain that only the upper-triangular part of the information matrix is stored
|
||||
* and returned by this function.
|
||||
* @param j1 Which block row to get, as an iterator pointing to the slot in this factor. You can
|
||||
* use, for example, begin() + 2 to get the 3rd variable in this factor.
|
||||
* @param j2 Which block column to get, as an iterator pointing to the slot in this factor. You can
|
||||
* use, for example, begin() + 2 to get the 3rd variable in this factor.
|
||||
* @return A view of the requested block, not a copy.
|
||||
*/
|
||||
constBlock info(const_iterator j1, const_iterator j2) const { return info_(j1-begin(), j2-begin()); }
|
||||
|
||||
/** Return a view of the block at (j1,j2) of the <em>upper-triangular part</em> of the
|
||||
* information matrix \f$ H \f$, no data is copied. See HessianFactor class documentation
|
||||
* above to explain that only the upper-triangular part of the information matrix is stored
|
||||
* and returned by this function.
|
||||
* @param j1 Which block row to get, as an iterator pointing to the slot in this factor. You can
|
||||
* use, for example, begin() + 2 to get the 3rd variable in this factor.
|
||||
* @param j2 Which block column to get, as an iterator pointing to the slot in this factor. You can
|
||||
* use, for example, begin() + 2 to get the 3rd variable in this factor.
|
||||
* @return A view of the requested block, not a copy.
|
||||
*/
|
||||
Block info(iterator j1, iterator j2) { return info_(j1-begin(), j2-begin()); }
|
||||
|
||||
/** Return the <em>upper-triangular part</em> of the full *augmented* information matrix,
|
||||
* as described above. See HessianFactor class documentation above to explain that only the
|
||||
* upper-triangular part of the information matrix is stored and returned by this function.
|
||||
*/
|
||||
constBlock info() const { return info_.full(); }
|
||||
|
||||
/** Return the <em>upper-triangular part</em> of the full *augmented* information matrix,
|
||||
* as described above. See HessianFactor class documentation above to explain that only the
|
||||
* upper-triangular part of the information matrix is stored and returned by this function.
|
||||
*/
|
||||
Block info() { return info_.full(); }
|
||||
|
||||
/** Return the constant term \f$ f \f$ as described above
|
||||
* @return The constant term \f$ f \f$
|
||||
*/
|
||||
double constantTerm() const { return info_(this->size(), this->size())(0,0); }
|
||||
|
||||
/** Return the constant term \f$ f \f$ as described above
|
||||
* @return The constant term \f$ f \f$
|
||||
*/
|
||||
double& constantTerm() { return info_(this->size(), this->size())(0,0); }
|
||||
|
||||
/** Return the part of linear term \f$ g \f$ as described above corresponding to the requested variable.
|
||||
* @param j Which block row to get, as an iterator pointing to the slot in this factor. You can
|
||||
* use, for example, begin() + 2 to get the 3rd variable in this factor.
|
||||
* @return The linear term \f$ g \f$ */
|
||||
constColumn linearTerm(const_iterator j) const { return info_.column(j-begin(), size(), 0); }
|
||||
|
||||
/** Return the part of linear term \f$ g \f$ as described above corresponding to the requested variable.
|
||||
* @param j Which block row to get, as an iterator pointing to the slot in this factor. You can
|
||||
* use, for example, begin() + 2 to get the 3rd variable in this factor.
|
||||
* @return The linear term \f$ g \f$ */
|
||||
Column linearTerm(iterator j) { return info_.column(j-begin(), size(), 0); }
|
||||
|
||||
/** Return the complete linear term \f$ g \f$ as described above.
|
||||
* @return The linear term \f$ g \f$ */
|
||||
constColumn linearTerm() const { return info_.rangeColumn(0, this->size(), this->size(), 0); }
|
||||
|
||||
/** Return the complete linear term \f$ g \f$ as described above.
|
||||
* @return The linear term \f$ g \f$ */
|
||||
Column linearTerm() { return info_.rangeColumn(0, this->size(), this->size(), 0); }
|
||||
|
||||
/** Return the augmented information matrix represented by this GaussianFactor.
|
||||
* The augmented information matrix contains the information matrix with an
|
||||
* additional column holding the information vector, and an additional row
|
||||
* holding the transpose of the information vector. The lower-right entry
|
||||
* contains the constant error term (when \f$ \delta x = 0 \f$). The
|
||||
* augmented information matrix is described in more detail in HessianFactor,
|
||||
* which in fact stores an augmented information matrix.
|
||||
*
|
||||
* For HessianFactor, this is the same as info() except that this function
|
||||
* returns a complete symmetric matrix whereas info() returns a matrix where
|
||||
* only the upper triangle is valid, but should be interpreted as symmetric.
|
||||
* This is because info() returns only a reference to the internal
|
||||
* representation of the augmented information matrix, which stores only the
|
||||
* upper triangle.
|
||||
*/
|
||||
virtual Matrix augmentedInformation() const;
|
||||
|
||||
/** Return the non-augmented information matrix represented by this
|
||||
* GaussianFactor.
|
||||
*/
|
||||
virtual Matrix information() const;
|
||||
|
||||
// Friend unit test classes
|
||||
friend class ::HessianFactorOrderedConversionConstructorTest;
|
||||
friend class ::HessianFactorOrderedConstructor1Test;
|
||||
friend class ::HessianFactorOrderedConstructor1bTest;
|
||||
friend class ::HessianFactorOrderedcombineTest;
|
||||
|
||||
// Friend JacobianFactor for conversion
|
||||
friend class JacobianFactorOrdered;
|
||||
|
||||
// used in eliminateCholesky:
|
||||
|
||||
/**
|
||||
* Do Cholesky. Note that after this, the lower triangle still contains
|
||||
* some untouched non-zeros that should be zero. We zero them while
|
||||
* extracting submatrices in splitEliminatedFactor. Frank says :-(
|
||||
*/
|
||||
void partialCholesky(size_t nrFrontals);
|
||||
|
||||
/** split partially eliminated factor */
|
||||
boost::shared_ptr<GaussianConditionalOrdered> splitEliminatedFactor(size_t nrFrontals);
|
||||
|
||||
/** Update the factor by adding the information from the JacobianFactor
|
||||
* (used internally during elimination).
|
||||
* @param update The JacobianFactor containing the new information to add
|
||||
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
||||
*/
|
||||
void updateATA(const JacobianFactorOrdered& update, const ScatterOrdered& scatter);
|
||||
|
||||
/** Update the factor by adding the information from the HessianFactor
|
||||
* (used internally during elimination).
|
||||
* @param update The HessianFactor containing the new information to add
|
||||
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
||||
*/
|
||||
void updateATA(const HessianFactorOrdered& update, const ScatterOrdered& scatter);
|
||||
|
||||
/** assert invariants */
|
||||
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_BASE_OBJECT_NVP(GaussianFactorOrdered);
|
||||
ar & BOOST_SERIALIZATION_NVP(info_);
|
||||
ar & BOOST_SERIALIZATION_NVP(matrix_);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,533 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 JacobianFactor.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Dec 8, 2010
|
||||
*/
|
||||
|
||||
#include <gtsam/linear/linearExceptions.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/JacobianFactorOrdered.h>
|
||||
#include <gtsam/linear/HessianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/VariableSlots.h>
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/base/timing.h>
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/base/FastMap.h>
|
||||
#include <gtsam/base/cholesky.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
#include <boost/bind.hpp>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
void JacobianFactorOrdered::assertInvariants() const {
|
||||
#ifndef NDEBUG
|
||||
GaussianFactorOrdered::assertInvariants(); // The base class checks for unique keys
|
||||
assert((size() == 0 && Ab_.rows() == 0 && Ab_.nBlocks() == 0) || size()+1 == Ab_.nBlocks());
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const JacobianFactorOrdered& gf) :
|
||||
GaussianFactorOrdered(gf), model_(gf.model_), Ab_(matrix_) {
|
||||
Ab_.assignNoalias(gf.Ab_);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const GaussianFactorOrdered& gf) : Ab_(matrix_) {
|
||||
// Copy the matrix data depending on what type of factor we're copying from
|
||||
if(const JacobianFactorOrdered* rhs = dynamic_cast<const JacobianFactorOrdered*>(&gf))
|
||||
*this = JacobianFactorOrdered(*rhs);
|
||||
else if(const HessianFactorOrdered* rhs = dynamic_cast<const HessianFactorOrdered*>(&gf))
|
||||
*this = JacobianFactorOrdered(*rhs);
|
||||
else
|
||||
throw std::invalid_argument("In JacobianFactor(const GaussianFactor& rhs), rhs is neither a JacobianFactor nor a HessianFactor");
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered() : Ab_(matrix_) { assertInvariants(); }
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const Vector& b_in) : Ab_(matrix_) {
|
||||
size_t dims[] = { 1 };
|
||||
Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+1, b_in.size()));
|
||||
getb() = b_in;
|
||||
model_ = noiseModel::Unit::Create(this->rows());
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(Index i1, const Matrix& A1,
|
||||
const Vector& b, const SharedDiagonal& model) :
|
||||
GaussianFactorOrdered(i1), model_(model), Ab_(matrix_) {
|
||||
|
||||
if(model->dim() != (size_t) b.size())
|
||||
throw InvalidNoiseModel(b.size(), model->dim());
|
||||
|
||||
size_t dims[] = { A1.cols(), 1};
|
||||
Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+2, b.size()));
|
||||
Ab_(0) = A1;
|
||||
getb() = b;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(Index i1, const Matrix& A1, Index i2, const Matrix& A2,
|
||||
const Vector& b, const SharedDiagonal& model) :
|
||||
GaussianFactorOrdered(i1,i2), model_(model), Ab_(matrix_) {
|
||||
|
||||
if(model->dim() != (size_t) b.size())
|
||||
throw InvalidNoiseModel(b.size(), model->dim());
|
||||
|
||||
size_t dims[] = { A1.cols(), A2.cols(), 1};
|
||||
Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+3, b.size()));
|
||||
Ab_(0) = A1;
|
||||
Ab_(1) = A2;
|
||||
getb() = b;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(Index i1, const Matrix& A1, Index i2, const Matrix& A2,
|
||||
Index i3, const Matrix& A3, const Vector& b, const SharedDiagonal& model) :
|
||||
GaussianFactorOrdered(i1,i2,i3), model_(model), Ab_(matrix_) {
|
||||
|
||||
if(model->dim() != (size_t) b.size())
|
||||
throw InvalidNoiseModel(b.size(), model->dim());
|
||||
|
||||
size_t dims[] = { A1.cols(), A2.cols(), A3.cols(), 1};
|
||||
Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+4, b.size()));
|
||||
Ab_(0) = A1;
|
||||
Ab_(1) = A2;
|
||||
Ab_(2) = A3;
|
||||
getb() = b;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const std::vector<std::pair<Index, Matrix> > &terms,
|
||||
const Vector &b, const SharedDiagonal& model) :
|
||||
GaussianFactorOrdered(GetKeys(terms.size(), terms.begin(), terms.end())),
|
||||
model_(model), Ab_(matrix_)
|
||||
{
|
||||
// get number of measurements and variables involved in this factor
|
||||
size_t m = b.size(), n = terms.size();
|
||||
|
||||
if(model->dim() != (size_t) m)
|
||||
throw InvalidNoiseModel(b.size(), model->dim());
|
||||
|
||||
// Get the dimensions of each variable and copy to "dims" array, add 1 for RHS
|
||||
size_t* dims = (size_t*)alloca(sizeof(size_t)*(n+1)); // FIXME: alloca is bad, just ask Google.
|
||||
for(size_t j=0; j<n; ++j)
|
||||
dims[j] = terms[j].second.cols();
|
||||
dims[n] = 1;
|
||||
|
||||
// Frank is mystified why this is done this way, rather than just creating Ab_
|
||||
Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+terms.size()+1, b.size()));
|
||||
|
||||
// Now copy the Jacobian matrices from the terms matrix
|
||||
for(size_t j=0; j<n; ++j) {
|
||||
assert(terms[j].second.rows()==m);
|
||||
Ab_(j) = terms[j].second;
|
||||
}
|
||||
getb() = b;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const std::list<std::pair<Index, Matrix> > &terms,
|
||||
const Vector &b, const SharedDiagonal& model) :
|
||||
GaussianFactorOrdered(GetKeys(terms.size(), terms.begin(), terms.end())),
|
||||
model_(model), Ab_(matrix_)
|
||||
{
|
||||
|
||||
if(model->dim() != (size_t) b.size())
|
||||
throw InvalidNoiseModel(b.size(), model->dim());
|
||||
|
||||
size_t* dims=(size_t*)alloca(sizeof(size_t)*(terms.size()+1)); // FIXME: alloca is bad, just ask Google.
|
||||
size_t j=0;
|
||||
std::list<std::pair<Index, Matrix> >::const_iterator term=terms.begin();
|
||||
for(; term!=terms.end(); ++term,++j)
|
||||
dims[j] = term->second.cols();
|
||||
dims[j] = 1;
|
||||
Ab_.copyStructureFrom(BlockAb(matrix_, dims, dims+terms.size()+1, b.size()));
|
||||
j = 0;
|
||||
for(term=terms.begin(); term!=terms.end(); ++term,++j)
|
||||
Ab_(j) = term->second;
|
||||
getb() = b;
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const GaussianConditionalOrdered& cg) :
|
||||
GaussianFactorOrdered(cg),
|
||||
model_(noiseModel::Diagonal::Sigmas(cg.get_sigmas(), true)),
|
||||
Ab_(matrix_) {
|
||||
Ab_.assignNoalias(cg.rsd_);
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const HessianFactorOrdered& factor) : Ab_(matrix_) {
|
||||
keys_ = factor.keys_;
|
||||
Ab_.assignNoalias(factor.info_);
|
||||
|
||||
// Do Cholesky to get a Jacobian
|
||||
size_t maxrank;
|
||||
bool success;
|
||||
boost::tie(maxrank, success) = choleskyCareful(matrix_);
|
||||
|
||||
// Check for indefinite system
|
||||
if(!success)
|
||||
throw IndeterminantLinearSystemException(factor.keys().front());
|
||||
|
||||
// Zero out lower triangle
|
||||
matrix_.topRows(maxrank).triangularView<Eigen::StrictlyLower>() =
|
||||
Matrix::Zero(maxrank, matrix_.cols());
|
||||
// FIXME: replace with triangular system
|
||||
Ab_.rowEnd() = maxrank;
|
||||
model_ = noiseModel::Unit::Create(maxrank);
|
||||
|
||||
assertInvariants();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered::JacobianFactorOrdered(const GaussianFactorGraphOrdered& gfg) : Ab_(matrix_) {
|
||||
// Cast or convert to Jacobians
|
||||
FactorGraphOrdered<JacobianFactorOrdered> jacobians;
|
||||
BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, gfg) {
|
||||
if(factor) {
|
||||
if(JacobianFactorOrdered::shared_ptr jf = boost::dynamic_pointer_cast<JacobianFactorOrdered>(factor))
|
||||
jacobians.push_back(jf);
|
||||
else
|
||||
jacobians.push_back(boost::make_shared<JacobianFactorOrdered>(*factor));
|
||||
}
|
||||
}
|
||||
|
||||
*this = *CombineJacobians(jacobians, VariableSlots(jacobians));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered& JacobianFactorOrdered::operator=(const JacobianFactorOrdered& rhs) {
|
||||
this->Base::operator=(rhs); // Copy keys
|
||||
model_ = rhs.model_; // Copy noise model
|
||||
Ab_.assignNoalias(rhs.Ab_); // Copy matrix and block structure
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void JacobianFactorOrdered::print(const string& s, const IndexFormatter& formatter) const {
|
||||
cout << s << "\n";
|
||||
if (empty()) {
|
||||
cout << " empty, keys: ";
|
||||
BOOST_FOREACH(const Index& key, keys()) { cout << formatter(key) << " "; }
|
||||
cout << endl;
|
||||
} else {
|
||||
for(const_iterator key=begin(); key!=end(); ++key)
|
||||
cout << boost::format("A[%1%]=\n")%formatter(*key) << getA(key) << endl;
|
||||
cout << "b=" << getb() << endl;
|
||||
model_->print("model");
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Check if two linear factors are equal
|
||||
bool JacobianFactorOrdered::equals(const GaussianFactorOrdered& f_, double tol) const {
|
||||
if(!dynamic_cast<const JacobianFactorOrdered*>(&f_))
|
||||
return false;
|
||||
else {
|
||||
const JacobianFactorOrdered& f(static_cast<const JacobianFactorOrdered&>(f_));
|
||||
if (empty()) return (f.empty());
|
||||
if(keys()!=f.keys() /*|| !model_->equals(lf->model_, tol)*/)
|
||||
return false;
|
||||
|
||||
if (!(Ab_.rows() == f.Ab_.rows() && Ab_.cols() == f.Ab_.cols()))
|
||||
return false;
|
||||
|
||||
constABlock Ab1(Ab_.range(0, Ab_.nBlocks()));
|
||||
constABlock Ab2(f.Ab_.range(0, f.Ab_.nBlocks()));
|
||||
for(size_t row=0; row< (size_t) Ab1.rows(); ++row)
|
||||
if(!equal_with_abs_tol(Ab1.row(row), Ab2.row(row), tol) &&
|
||||
!equal_with_abs_tol(-Ab1.row(row), Ab2.row(row), tol))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Vector JacobianFactorOrdered::unweighted_error(const VectorValuesOrdered& c) const {
|
||||
Vector e = -getb();
|
||||
if (empty()) return e;
|
||||
for(size_t pos=0; pos<size(); ++pos)
|
||||
e += Ab_(pos) * c[keys_[pos]];
|
||||
return e;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Vector JacobianFactorOrdered::error_vector(const VectorValuesOrdered& c) const {
|
||||
if (empty()) return model_->whiten(-getb());
|
||||
return model_->whiten(unweighted_error(c));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
double JacobianFactorOrdered::error(const VectorValuesOrdered& c) const {
|
||||
if (empty()) return 0;
|
||||
Vector weighted = error_vector(c);
|
||||
return 0.5 * weighted.dot(weighted);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix JacobianFactorOrdered::augmentedInformation() const {
|
||||
Matrix AbWhitened = Ab_.full();
|
||||
model_->WhitenInPlace(AbWhitened);
|
||||
return AbWhitened.transpose() * AbWhitened;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix JacobianFactorOrdered::information() const {
|
||||
Matrix AWhitened = this->getA();
|
||||
model_->WhitenInPlace(AWhitened);
|
||||
return AWhitened.transpose() * AWhitened;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Vector JacobianFactorOrdered::operator*(const VectorValuesOrdered& x) const {
|
||||
Vector Ax = zero(Ab_.rows());
|
||||
if (empty()) return Ax;
|
||||
|
||||
// Just iterate over all A matrices and multiply in correct config part
|
||||
for(size_t pos=0; pos<size(); ++pos)
|
||||
Ax += Ab_(pos) * x[keys_[pos]];
|
||||
|
||||
return model_->whiten(Ax);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void JacobianFactorOrdered::transposeMultiplyAdd(double alpha, const Vector& e,
|
||||
VectorValuesOrdered& x) const {
|
||||
Vector E = alpha * model_->whiten(e);
|
||||
// Just iterate over all A matrices and insert Ai^e into VectorValues
|
||||
for(size_t pos=0; pos<size(); ++pos)
|
||||
gtsam::transposeMultiplyAdd(1.0, Ab_(pos), E, x[keys_[pos]]);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
pair<Matrix,Vector> JacobianFactorOrdered::matrix(bool weight) const {
|
||||
Matrix A(Ab_.range(0, size()));
|
||||
Vector b(getb());
|
||||
// divide in sigma so error is indeed 0.5*|Ax-b|
|
||||
if (weight) model_->WhitenSystem(A,b);
|
||||
return make_pair(A, b);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix JacobianFactorOrdered::matrix_augmented(bool weight) const {
|
||||
if (weight) { Matrix Ab(Ab_.range(0,Ab_.nBlocks())); model_->WhitenInPlace(Ab); return Ab; }
|
||||
else return Ab_.range(0, Ab_.nBlocks());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
std::vector<boost::tuple<size_t, size_t, double> >
|
||||
JacobianFactorOrdered::sparse(const std::vector<size_t>& columnIndices) const {
|
||||
|
||||
std::vector<boost::tuple<size_t, size_t, double> > entries;
|
||||
|
||||
// iterate over all variables in the factor
|
||||
for(const_iterator var=begin(); var<end(); ++var) {
|
||||
Matrix whitenedA(model_->Whiten(getA(var)));
|
||||
// find first column index for this key
|
||||
size_t column_start = columnIndices[*var];
|
||||
for (size_t i = 0; i < (size_t) whitenedA.rows(); i++)
|
||||
for (size_t j = 0; j < (size_t) whitenedA.cols(); j++) {
|
||||
double s = whitenedA(i,j);
|
||||
if (std::abs(s) > 1e-12) entries.push_back(
|
||||
boost::make_tuple(i, column_start + j, s));
|
||||
}
|
||||
}
|
||||
|
||||
Vector whitenedb(model_->whiten(getb()));
|
||||
size_t bcolumn = columnIndices.back();
|
||||
for (size_t i = 0; i < (size_t) whitenedb.size(); i++)
|
||||
entries.push_back(boost::make_tuple(i, bcolumn, whitenedb(i)));
|
||||
|
||||
// return the result
|
||||
return entries;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
JacobianFactorOrdered JacobianFactorOrdered::whiten() const {
|
||||
JacobianFactorOrdered result(*this);
|
||||
result.model_->WhitenInPlace(result.matrix_);
|
||||
result.model_ = noiseModel::Unit::Create(result.model_->dim());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianFactorOrdered::shared_ptr JacobianFactorOrdered::negate() const {
|
||||
HessianFactorOrdered hessian(*this);
|
||||
return hessian.negate();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::shared_ptr JacobianFactorOrdered::eliminateFirst() {
|
||||
return this->eliminate(1);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::shared_ptr JacobianFactorOrdered::splitConditional(size_t nrFrontals) {
|
||||
assert(Ab_.rowStart() == 0 && Ab_.rowEnd() == (size_t) matrix_.rows() && Ab_.firstBlock() == 0);
|
||||
assert(size() >= nrFrontals);
|
||||
assertInvariants();
|
||||
|
||||
const bool debug = ISDEBUG("JacobianFactor::splitConditional");
|
||||
|
||||
if(debug) cout << "Eliminating " << nrFrontals << " frontal variables" << endl;
|
||||
if(debug) this->print("Splitting JacobianFactor: ");
|
||||
|
||||
size_t frontalDim = Ab_.range(0,nrFrontals).cols();
|
||||
|
||||
// Check for singular factor
|
||||
if(model_->dim() < frontalDim)
|
||||
throw IndeterminantLinearSystemException(this->keys().front());
|
||||
|
||||
// Extract conditional
|
||||
gttic(cond_Rd);
|
||||
|
||||
// Restrict the matrix to be in the first nrFrontals variables
|
||||
Ab_.rowEnd() = Ab_.rowStart() + frontalDim;
|
||||
const Eigen::VectorBlock<const Vector> sigmas = model_->sigmas().segment(Ab_.rowStart(), Ab_.rowEnd()-Ab_.rowStart());
|
||||
GaussianConditionalOrdered::shared_ptr conditional(new GaussianConditionalOrdered(begin(), end(), nrFrontals, Ab_, sigmas));
|
||||
if(debug) conditional->print("Extracted conditional: ");
|
||||
Ab_.rowStart() += frontalDim;
|
||||
Ab_.firstBlock() += nrFrontals;
|
||||
gttoc(cond_Rd);
|
||||
|
||||
if(debug) conditional->print("Extracted conditional: ");
|
||||
|
||||
gttic(remaining_factor);
|
||||
// Take lower-right block of Ab to get the new factor
|
||||
Ab_.rowEnd() = model_->dim();
|
||||
keys_.erase(begin(), begin() + nrFrontals);
|
||||
// Set sigmas with the right model
|
||||
if (model_->isConstrained())
|
||||
model_ = noiseModel::Constrained::MixedSigmas(sub(model_->sigmas(), frontalDim, model_->dim()));
|
||||
else
|
||||
model_ = noiseModel::Diagonal::Sigmas(sub(model_->sigmas(), frontalDim, model_->dim()));
|
||||
if(debug) this->print("Eliminated factor: ");
|
||||
assert(Ab_.rows() <= Ab_.cols()-1);
|
||||
gttoc(remaining_factor);
|
||||
|
||||
if(debug) print("Eliminated factor: ");
|
||||
|
||||
assertInvariants();
|
||||
|
||||
return conditional;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
GaussianConditionalOrdered::shared_ptr JacobianFactorOrdered::eliminate(size_t nrFrontals) {
|
||||
|
||||
assert(Ab_.rowStart() == 0 && Ab_.rowEnd() == (size_t) matrix_.rows() && Ab_.firstBlock() == 0);
|
||||
assert(size() >= nrFrontals);
|
||||
assertInvariants();
|
||||
|
||||
const bool debug = ISDEBUG("JacobianFactor::eliminate");
|
||||
|
||||
if(debug) cout << "Eliminating " << nrFrontals << " frontal variables" << endl;
|
||||
if(debug) this->print("Eliminating JacobianFactor: ");
|
||||
if(debug) gtsam::print(matrix_, "Augmented Ab: ");
|
||||
|
||||
size_t frontalDim = Ab_.range(0,nrFrontals).cols();
|
||||
|
||||
if(debug) cout << "frontalDim = " << frontalDim << endl;
|
||||
|
||||
// Use in-place QR dense Ab appropriate to NoiseModel
|
||||
gttic(QR);
|
||||
SharedDiagonal noiseModel = model_->QR(matrix_);
|
||||
// In the new unordered code, empty noise model indicates unit noise model, and I already
|
||||
// modified QR to return an empty noise model. This just creates a unit noise model in that
|
||||
// case because this old code does not handle empty noise models.
|
||||
if(!noiseModel)
|
||||
noiseModel = noiseModel::Unit::Create(std::min(matrix_.rows(), matrix_.cols() - 1));
|
||||
gttoc(QR);
|
||||
|
||||
// Zero the lower-left triangle. todo: not all of these entries actually
|
||||
// need to be zeroed if we are careful to start copying rows after the last
|
||||
// structural zero.
|
||||
if(matrix_.rows() > 0)
|
||||
for(size_t j=0; j<(size_t) matrix_.cols(); ++j)
|
||||
for(size_t i=j+1; i<noiseModel->dim(); ++i)
|
||||
matrix_(i,j) = 0.0;
|
||||
|
||||
if(debug) gtsam::print(matrix_, "QR result: ");
|
||||
if(debug) noiseModel->print("QR result noise model: ");
|
||||
|
||||
// Start of next part
|
||||
model_ = noiseModel;
|
||||
return splitConditional(nrFrontals);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void JacobianFactorOrdered::allocate(const VariableSlots& variableSlots, vector<
|
||||
size_t>& varDims, size_t m) {
|
||||
keys_.resize(variableSlots.size());
|
||||
std::transform(variableSlots.begin(), variableSlots.end(), begin(),
|
||||
boost::bind(&VariableSlots::const_iterator::value_type::first, _1));
|
||||
varDims.push_back(1);
|
||||
Ab_.copyStructureFrom(BlockAb(matrix_, varDims.begin(), varDims.end(), m));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void JacobianFactorOrdered::setModel(bool anyConstrained, const Vector& sigmas) {
|
||||
if((size_t) sigmas.size() != this->rows())
|
||||
throw InvalidNoiseModel(this->rows(), sigmas.size());
|
||||
if (anyConstrained)
|
||||
model_ = noiseModel::Constrained::MixedSigmas(sigmas);
|
||||
else
|
||||
model_ = noiseModel::Diagonal::Sigmas(sigmas);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
const char* JacobianFactorOrdered::InvalidNoiseModel::what() const throw() {
|
||||
if(description_.empty())
|
||||
description_ = (boost::format(
|
||||
"A JacobianFactor was attempted to be constructed or modified to use a\n"
|
||||
"noise model of incompatible dimension. The JacobianFactor has\n"
|
||||
"dimensionality (i.e. length of error vector) %d but the provided noise\n"
|
||||
"model has dimensionality %d.") % factorDims % noiseModelDims).str();
|
||||
return description_.c_str();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,335 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 JacobianFactor.h
|
||||
* @author Richard Roberts
|
||||
* @date Dec 8, 2010
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/linear/GaussianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/Errors.h>
|
||||
#include <gtsam/linear/NoiseModel.h>
|
||||
#include <gtsam/inference/FactorGraphOrdered.h>
|
||||
#include <gtsam/base/blockMatrices.h>
|
||||
#include <gtsam/global_includes.h>
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
// Forward declarations of friend unit tests
|
||||
class JacobianFactorOrderedCombine2Test;
|
||||
class JacobianFactorOrderedeliminateFrontalsTest;
|
||||
class JacobianFactorOrderedconstructor2Test;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declarations
|
||||
class HessianFactorOrdered;
|
||||
class VariableSlots;
|
||||
template<class C> class BayesNetOrdered;
|
||||
class GaussianFactorGraphOrdered;
|
||||
|
||||
/**
|
||||
* A Gaussian factor in the squared-error form.
|
||||
*
|
||||
* JacobianFactor implements a
|
||||
* Gaussian, which has quadratic negative log-likelihood
|
||||
* \f[ E(x) = \frac{1}{2} (Ax-b)^T \Sigma^{-1} (Ax-b) \f]
|
||||
* where \f$ \Sigma \f$ is a \a diagonal covariance matrix. The
|
||||
* matrix \f$ A \f$, r.h.s. vector \f$ b \f$, and diagonal noise model
|
||||
* \f$ \Sigma \f$ are stored in this class.
|
||||
*
|
||||
* This factor represents the sum-of-squares error of a \a linear
|
||||
* measurement function, and is created upon linearization of a NoiseModelFactor,
|
||||
* which in turn is a sum-of-squares factor with a nonlinear measurement function.
|
||||
*
|
||||
* Here is an example of how this factor represents a sum-of-squares error:
|
||||
*
|
||||
* Letting \f$ h(x) \f$ be a \a linear measurement prediction function, \f$ z \f$ be
|
||||
* the actual observed measurement, the residual is
|
||||
* \f[ f(x) = h(x) - z . \f]
|
||||
* If we expect noise with diagonal covariance matrix \f$ \Sigma \f$ on this
|
||||
* measurement, then the negative log-likelihood of the Gaussian induced by this
|
||||
* measurement model is
|
||||
* \f[ E(x) = \frac{1}{2} (h(x) - z)^T \Sigma^{-1} (h(x) - z) . \f]
|
||||
* Because \f$ h(x) \f$ is linear, we can write it as
|
||||
* \f[ h(x) = Ax + e \f]
|
||||
* and thus we have
|
||||
* \f[ E(x) = \frac{1}{2} (Ax-b)^T \Sigma^{-1} (Ax-b) \f]
|
||||
* where \f$ b = z - e \f$.
|
||||
*
|
||||
* This factor can involve an arbitrary number of variables, and in the
|
||||
* above example \f$ x \f$ would almost always be only be a subset of the variables
|
||||
* in the entire factor graph. There are special constructors for 1-, 2-, and 3-
|
||||
* way JacobianFactors, and additional constructors for creating n-way JacobianFactors.
|
||||
* The Jacobian matrix \f$ A \f$ is passed to these constructors in blocks,
|
||||
* for example, for a 2-way factor, the constructor would accept \f$ A1 \f$ and \f$ A2 \f$,
|
||||
* as well as the variable indices \f$ j1 \f$ and \f$ j2 \f$
|
||||
* and the negative log-likelihood represented by this factor would be
|
||||
* \f[ E(x) = \frac{1}{2} (A_1 x_{j1} + A_2 x_{j2} - b)^T \Sigma^{-1} (A_1 x_{j1} + A_2 x_{j2} - b) . \f]
|
||||
*/
|
||||
class GTSAM_EXPORT JacobianFactorOrdered : public GaussianFactorOrdered {
|
||||
protected:
|
||||
typedef Matrix AbMatrix;
|
||||
typedef VerticalBlockView<AbMatrix> BlockAb;
|
||||
|
||||
noiseModel::Diagonal::shared_ptr model_; // Gaussian noise model with diagonal covariance matrix
|
||||
AbMatrix matrix_; // the full matrix corresponding to the factor
|
||||
BlockAb Ab_; // the block view of the full matrix
|
||||
typedef GaussianFactorOrdered Base; // typedef to base
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<JacobianFactorOrdered> shared_ptr;
|
||||
typedef BlockAb::Block ABlock;
|
||||
typedef BlockAb::constBlock constABlock;
|
||||
typedef BlockAb::Column BVector;
|
||||
typedef BlockAb::constColumn constBVector;
|
||||
|
||||
/** Copy constructor */
|
||||
JacobianFactorOrdered(const JacobianFactorOrdered& gf);
|
||||
|
||||
/** Convert from other GaussianFactor */
|
||||
JacobianFactorOrdered(const GaussianFactorOrdered& gf);
|
||||
|
||||
/** default constructor for I/O */
|
||||
JacobianFactorOrdered();
|
||||
|
||||
/** Construct Null factor */
|
||||
JacobianFactorOrdered(const Vector& b_in);
|
||||
|
||||
/** Construct unary factor */
|
||||
JacobianFactorOrdered(Index i1, const Matrix& A1,
|
||||
const Vector& b, const SharedDiagonal& model);
|
||||
|
||||
/** Construct binary factor */
|
||||
JacobianFactorOrdered(Index i1, const Matrix& A1,
|
||||
Index i2, const Matrix& A2,
|
||||
const Vector& b, const SharedDiagonal& model);
|
||||
|
||||
/** Construct ternary factor */
|
||||
JacobianFactorOrdered(Index i1, const Matrix& A1, Index i2,
|
||||
const Matrix& A2, Index i3, const Matrix& A3,
|
||||
const Vector& b, const SharedDiagonal& model);
|
||||
|
||||
/** Construct an n-ary factor */
|
||||
JacobianFactorOrdered(const std::vector<std::pair<Index, Matrix> > &terms,
|
||||
const Vector &b, const SharedDiagonal& model);
|
||||
|
||||
JacobianFactorOrdered(const std::list<std::pair<Index, Matrix> > &terms,
|
||||
const Vector &b, const SharedDiagonal& model);
|
||||
|
||||
/** Construct from Conditional Gaussian */
|
||||
JacobianFactorOrdered(const GaussianConditionalOrdered& cg);
|
||||
|
||||
/** Convert from a HessianFactor (does Cholesky) */
|
||||
JacobianFactorOrdered(const HessianFactorOrdered& factor);
|
||||
|
||||
/** Build a dense joint factor from all the factors in a factor graph. */
|
||||
JacobianFactorOrdered(const GaussianFactorGraphOrdered& gfg);
|
||||
|
||||
/** Virtual destructor */
|
||||
virtual ~JacobianFactorOrdered() {}
|
||||
|
||||
/** Aassignment operator */
|
||||
JacobianFactorOrdered& operator=(const JacobianFactorOrdered& rhs);
|
||||
|
||||
/** Clone this JacobianFactor */
|
||||
virtual GaussianFactorOrdered::shared_ptr clone() const {
|
||||
return boost::static_pointer_cast<GaussianFactorOrdered>(
|
||||
shared_ptr(new JacobianFactorOrdered(*this)));
|
||||
}
|
||||
|
||||
// Implementing Testable interface
|
||||
virtual void print(const std::string& s = "",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
virtual bool equals(const GaussianFactorOrdered& lf, double tol = 1e-9) const;
|
||||
|
||||
Vector unweighted_error(const VectorValuesOrdered& c) const; /** (A*x-b) */
|
||||
Vector error_vector(const VectorValuesOrdered& c) const; /** (A*x-b)/sigma */
|
||||
virtual double error(const VectorValuesOrdered& c) const; /** 0.5*(A*x-b)'*D*(A*x-b) */
|
||||
|
||||
/** Return the augmented information matrix represented by this GaussianFactor.
|
||||
* The augmented information matrix contains the information matrix with an
|
||||
* additional column holding the information vector, and an additional row
|
||||
* holding the transpose of the information vector. The lower-right entry
|
||||
* contains the constant error term (when \f$ \delta x = 0 \f$). The
|
||||
* augmented information matrix is described in more detail in HessianFactor,
|
||||
* which in fact stores an augmented information matrix.
|
||||
*/
|
||||
virtual Matrix augmentedInformation() const;
|
||||
|
||||
/** Return the non-augmented information matrix represented by this
|
||||
* GaussianFactor.
|
||||
*/
|
||||
virtual Matrix information() const;
|
||||
|
||||
/**
|
||||
* Construct the corresponding anti-factor to negate information
|
||||
* stored stored in this factor.
|
||||
* @return a HessianFactor with negated Hessian matrices
|
||||
*/
|
||||
virtual GaussianFactorOrdered::shared_ptr negate() const;
|
||||
|
||||
/** Check if the factor contains no information, i.e. zero rows. This does
|
||||
* not necessarily mean that the factor involves no variables (to check for
|
||||
* involving no variables use keys().empty()).
|
||||
*/
|
||||
bool empty() const { return Ab_.rows() == 0;}
|
||||
|
||||
/** is noise model constrained ? */
|
||||
bool isConstrained() const { return model_->isConstrained();}
|
||||
|
||||
/** Return the dimension of the variable pointed to by the given key iterator
|
||||
* todo: Remove this in favor of keeping track of dimensions with variables?
|
||||
*/
|
||||
virtual size_t getDim(const_iterator variable) const { return Ab_(variable - begin()).cols(); }
|
||||
|
||||
/**
|
||||
* return the number of rows in the corresponding linear system
|
||||
*/
|
||||
size_t rows() const { return Ab_.rows(); }
|
||||
|
||||
/**
|
||||
* return the number of rows in the corresponding linear system
|
||||
*/
|
||||
size_t numberOfRows() const { return rows(); }
|
||||
|
||||
/**
|
||||
* return the number of columns in the corresponding linear system
|
||||
*/
|
||||
size_t cols() const { return Ab_.cols(); }
|
||||
|
||||
/** get a copy of model */
|
||||
const SharedDiagonal& get_model() const { return model_; }
|
||||
|
||||
/** get a copy of model (non-const version) */
|
||||
SharedDiagonal& get_model() { return model_; }
|
||||
|
||||
/** Get a view of the r.h.s. vector b */
|
||||
const constBVector getb() const { return Ab_.column(size(), 0); }
|
||||
|
||||
/** Get a view of the A matrix for the variable pointed to by the given key iterator */
|
||||
constABlock getA(const_iterator variable) const { return Ab_(variable - begin()); }
|
||||
|
||||
/** Get a view of the A matrix */
|
||||
constABlock getA() const { return Ab_.range(0, size()); }
|
||||
|
||||
/** Get a view of the r.h.s. vector b (non-const version) */
|
||||
BVector getb() { return Ab_.column(size(), 0); }
|
||||
|
||||
/** Get a view of the A matrix for the variable pointed to by the given key iterator (non-const version) */
|
||||
ABlock getA(iterator variable) { return Ab_(variable - begin()); }
|
||||
|
||||
/** Get a view of the A matrix */
|
||||
ABlock getA() { return Ab_.range(0, size()); }
|
||||
|
||||
/** Return A*x */
|
||||
Vector operator*(const VectorValuesOrdered& x) const;
|
||||
|
||||
/** x += A'*e */
|
||||
void transposeMultiplyAdd(double alpha, const Vector& e, VectorValuesOrdered& x) const;
|
||||
|
||||
/**
|
||||
* Return (dense) matrix associated with factor
|
||||
* @param ordering of variables needed for matrix column order
|
||||
* @param set weight to true to bake in the weights
|
||||
*/
|
||||
std::pair<Matrix, Vector> matrix(bool weight = true) const;
|
||||
|
||||
/**
|
||||
* Return (dense) matrix associated with factor
|
||||
* The returned system is an augmented matrix: [A b]
|
||||
* @param set weight to use whitening to bake in weights
|
||||
*/
|
||||
Matrix matrix_augmented(bool weight = true) const;
|
||||
|
||||
/**
|
||||
* Return vector of i, j, and s to generate an m-by-n sparse matrix
|
||||
* such that S(i(k),j(k)) = s(k), which can be given to MATLAB's sparse.
|
||||
* As above, the standard deviations are baked into A and b
|
||||
* @param columnIndices First column index for each variable.
|
||||
*/
|
||||
std::vector<boost::tuple<size_t, size_t, double> >
|
||||
sparse(const std::vector<size_t>& columnIndices) const;
|
||||
|
||||
/**
|
||||
* Return a whitened version of the factor, i.e. with unit diagonal noise
|
||||
* model. */
|
||||
JacobianFactorOrdered whiten() const;
|
||||
|
||||
/** Eliminate the first variable, modifying the factor in place to contain the remaining marginal. */
|
||||
boost::shared_ptr<GaussianConditionalOrdered> eliminateFirst();
|
||||
|
||||
/** Eliminate the requested number of frontal variables, modifying the factor in place to contain the remaining marginal. */
|
||||
boost::shared_ptr<GaussianConditionalOrdered> eliminate(size_t nrFrontals = 1);
|
||||
|
||||
/**
|
||||
* splits a pre-factorized factor into a conditional, and changes the current
|
||||
* factor to be the remaining component. Performs same operation as eliminate(),
|
||||
* but without running QR.
|
||||
*/
|
||||
boost::shared_ptr<GaussianConditionalOrdered> splitConditional(size_t nrFrontals = 1);
|
||||
|
||||
// following methods all used in CombineJacobians:
|
||||
// Many imperative, perhaps all need to be combined in constructor
|
||||
|
||||
/** allocate space */
|
||||
void allocate(const VariableSlots& variableSlots,
|
||||
std::vector<size_t>& varDims, size_t m);
|
||||
|
||||
/** set noiseModel correctly */
|
||||
void setModel(bool anyConstrained, const Vector& sigmas);
|
||||
|
||||
/** Assert invariants after elimination */
|
||||
void assertInvariants() const;
|
||||
|
||||
/** An exception indicating that the noise model dimension passed into the
|
||||
* JacobianFactor has a different dimensionality than the factor. */
|
||||
class InvalidNoiseModel : public std::exception {
|
||||
public:
|
||||
const size_t factorDims; ///< The dimensionality of the factor
|
||||
const size_t noiseModelDims; ///< The dimensionality of the noise model
|
||||
|
||||
InvalidNoiseModel(size_t factorDims, size_t noiseModelDims) :
|
||||
factorDims(factorDims), noiseModelDims(noiseModelDims) {}
|
||||
virtual ~InvalidNoiseModel() throw() {}
|
||||
|
||||
virtual const char* what() const throw();
|
||||
|
||||
private:
|
||||
mutable std::string description_;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// Friend HessianFactor to facilitate conversion constructors
|
||||
friend class HessianFactorOrdered;
|
||||
|
||||
// Friend unit tests (see also forward declarations above)
|
||||
friend class ::JacobianFactorOrderedCombine2Test;
|
||||
friend class ::JacobianFactorOrderedeliminateFrontalsTest;
|
||||
friend class ::JacobianFactorOrderedconstructor2Test;
|
||||
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(GaussianFactorOrdered);
|
||||
ar & BOOST_SERIALIZATION_NVP(Ab_);
|
||||
ar & BOOST_SERIALIZATION_NVP(model_);
|
||||
ar & BOOST_SERIALIZATION_NVP(matrix_);
|
||||
}
|
||||
}; // JacobianFactor
|
||||
|
||||
} // gtsam
|
||||
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 VectorValues.cpp
|
||||
* @brief Implementations for VectorValues
|
||||
* @author Richard Roberts
|
||||
* @author Alex Cunningham
|
||||
*/
|
||||
|
||||
#include <gtsam/base/FastVector.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
#include <gtsam/linear/VectorValuesOrdered.h>
|
||||
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered VectorValuesOrdered::Zero(const VectorValuesOrdered& x) {
|
||||
VectorValuesOrdered result;
|
||||
result.values_.resize(x.size());
|
||||
for(size_t j=0; j<x.size(); ++j)
|
||||
result.values_[j] = Vector::Zero(x.values_[j].size());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
vector<size_t> VectorValuesOrdered::dims() const {
|
||||
std::vector<size_t> result(this->size());
|
||||
for(Index j = 0; j < this->size(); ++j)
|
||||
result[j] = this->dim(j);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::insert(Index j, const Vector& value) {
|
||||
// Make sure j does not already exist
|
||||
if(exists(j))
|
||||
throw invalid_argument("VectorValues: requested variable index to insert already exists.");
|
||||
|
||||
// If this adds variables at the end, insert zero-length entries up to j
|
||||
if(j >= size())
|
||||
values_.resize(j+1);
|
||||
|
||||
// Assign value
|
||||
values_[j] = value;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::print(const std::string& str, const IndexFormatter& formatter) const {
|
||||
std::cout << str << ": " << size() << " elements\n";
|
||||
for (Index var = 0; var < size(); ++var)
|
||||
std::cout << " " << formatter(var) << ": " << (*this)[var].transpose() << "\n";
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool VectorValuesOrdered::equals(const VectorValuesOrdered& x, double tol) const {
|
||||
if(this->size() != x.size())
|
||||
return false;
|
||||
for(Index j=0; j < size(); ++j)
|
||||
if(!equal_with_abs_tol(values_[j], x.values_[j], tol))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::resize(Index nVars, size_t varDim) {
|
||||
values_.resize(nVars);
|
||||
for(Index j = 0; j < nVars; ++j)
|
||||
values_[j] = Vector(varDim);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::resizeLike(const VectorValuesOrdered& other) {
|
||||
values_.resize(other.size());
|
||||
for(Index j = 0; j < other.size(); ++j)
|
||||
values_[j].resize(other.values_[j].size());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered VectorValuesOrdered::SameStructure(const VectorValuesOrdered& other) {
|
||||
VectorValuesOrdered ret;
|
||||
ret.resizeLike(other);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered VectorValuesOrdered::Zero(Index nVars, size_t varDim) {
|
||||
VectorValuesOrdered ret(nVars, varDim);
|
||||
ret.setZero();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::setZero() {
|
||||
BOOST_FOREACH(Vector& v, *this) {
|
||||
v.setZero();
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
const Vector VectorValuesOrdered::asVector() const {
|
||||
return internal::extractVectorValuesSlices(*this,
|
||||
boost::make_counting_iterator(size_t(0)), boost::make_counting_iterator(this->size()), true);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
const Vector VectorValuesOrdered::vector(const std::vector<Index>& indices) const {
|
||||
return internal::extractVectorValuesSlices(*this, indices.begin(), indices.end());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool VectorValuesOrdered::hasSameStructure(const VectorValuesOrdered& other) const {
|
||||
if(this->size() != other.size())
|
||||
return false;
|
||||
for(size_t j = 0; j < size(); ++j)
|
||||
// Directly accessing maps instead of using VV::dim in case some values are empty
|
||||
if(this->values_[j].rows() != other.values_[j].rows())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::permuteInPlace(const Permutation& permutation) {
|
||||
// Allocate new values
|
||||
Values newValues(this->size());
|
||||
|
||||
// Swap values from this VectorValues to the permuted VectorValues
|
||||
for(size_t i = 0; i < this->size(); ++i)
|
||||
newValues[i].swap(this->at(permutation[i]));
|
||||
|
||||
// Swap the values into this VectorValues
|
||||
values_.swap(newValues);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::permuteInPlace(const Permutation& selector, const Permutation& permutation) {
|
||||
if(selector.size() != permutation.size())
|
||||
throw invalid_argument("VariableIndex::permuteInPlace (partial permutation version) called with selector and permutation of different sizes.");
|
||||
// Create new index the size of the permuted entries
|
||||
Values reorderedEntries(selector.size());
|
||||
// Permute the affected entries into the new index
|
||||
for(size_t dstSlot = 0; dstSlot < selector.size(); ++dstSlot)
|
||||
reorderedEntries[dstSlot].swap(values_[selector[permutation[dstSlot]]]);
|
||||
// Put the affected entries back in the new order
|
||||
for(size_t slot = 0; slot < selector.size(); ++slot)
|
||||
values_[selector[slot]].swap(reorderedEntries[slot]);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::swap(VectorValuesOrdered& other) {
|
||||
this->values_.swap(other.values_);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
double VectorValuesOrdered::dot(const VectorValuesOrdered& v) const {
|
||||
double result = 0.0;
|
||||
if(this->size() != v.size())
|
||||
throw invalid_argument("VectorValues::dot called with different vector sizes");
|
||||
for(Index j = 0; j < this->size(); ++j)
|
||||
// Directly accessing maps instead of using VV::dim in case some values are empty
|
||||
if(this->values_[j].size() == v.values_[j].size())
|
||||
result += this->values_[j].dot(v.values_[j]);
|
||||
else
|
||||
throw invalid_argument("VectorValues::dot called with different vector sizes");
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
double VectorValuesOrdered::norm() const {
|
||||
return std::sqrt(this->squaredNorm());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
double VectorValuesOrdered::squaredNorm() const {
|
||||
double sumSquares = 0.0;
|
||||
for(Index j = 0; j < this->size(); ++j)
|
||||
// Directly accessing maps instead of using VV::dim in case some values are empty
|
||||
sumSquares += this->values_[j].squaredNorm();
|
||||
return sumSquares;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered VectorValuesOrdered::operator+(const VectorValuesOrdered& c) const {
|
||||
VectorValuesOrdered result = SameStructure(*this);
|
||||
if(this->size() != c.size())
|
||||
throw invalid_argument("VectorValues::operator+ called with different vector sizes");
|
||||
for(Index j = 0; j < this->size(); ++j)
|
||||
// Directly accessing maps instead of using VV::dim in case some values are empty
|
||||
if(this->values_[j].size() == c.values_[j].size())
|
||||
result.values_[j] = this->values_[j] + c.values_[j];
|
||||
else
|
||||
throw invalid_argument("VectorValues::operator- called with different vector sizes");
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
VectorValuesOrdered VectorValuesOrdered::operator-(const VectorValuesOrdered& c) const {
|
||||
VectorValuesOrdered result = SameStructure(*this);
|
||||
if(this->size() != c.size())
|
||||
throw invalid_argument("VectorValues::operator- called with different vector sizes");
|
||||
for(Index j = 0; j < this->size(); ++j)
|
||||
// Directly accessing maps instead of using VV::dim in case some values are empty
|
||||
if(this->values_[j].size() == c.values_[j].size())
|
||||
result.values_[j] = this->values_[j] - c.values_[j];
|
||||
else
|
||||
throw invalid_argument("VectorValues::operator- called with different vector sizes");
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void VectorValuesOrdered::operator+=(const VectorValuesOrdered& c) {
|
||||
if(this->size() != c.size())
|
||||
throw invalid_argument("VectorValues::operator+= called with different vector sizes");
|
||||
for(Index j = 0; j < this->size(); ++j)
|
||||
// Directly accessing maps instead of using VV::dim in case some values are empty
|
||||
if(this->values_[j].size() == c.values_[j].size())
|
||||
this->values_[j] += c.values_[j];
|
||||
else
|
||||
throw invalid_argument("VectorValues::operator+= called with different vector sizes");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,468 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 VectorValues.h
|
||||
* @brief Factor Graph Values
|
||||
* @author Richard Roberts
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtsam/base/Vector.h>
|
||||
#include <gtsam/global_includes.h>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
// Forward declarations
|
||||
class Permutation;
|
||||
|
||||
/**
|
||||
* This class represents a collection of vector-valued variables associated
|
||||
* each with a unique integer index. It is typically used to store the variables
|
||||
* of a GaussianFactorGraph. Optimizing a GaussianFactorGraph or GaussianBayesNet
|
||||
* returns this class.
|
||||
*
|
||||
* For basic usage, such as receiving a linear solution from gtsam solving functions,
|
||||
* or creating this class in unit tests and examples where speed is not important,
|
||||
* you can use a simple interface:
|
||||
* - The default constructor VectorValues() to create this class
|
||||
* - insert(Index, const Vector&) to add vector variables
|
||||
* - operator[](Index) for read and write access to stored variables
|
||||
* - \ref exists (Index) to check if a variable is present
|
||||
* - Other facilities like iterators, size(), dim(), etc.
|
||||
*
|
||||
* Indices can be non-consecutive and inserted out-of-order, but you should not
|
||||
* use indices that are larger than a reasonable array size because the indices
|
||||
* correspond to positions in an internal array.
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
VectorValues values;
|
||||
values.insert(3, Vector_(3, 1.0, 2.0, 3.0));
|
||||
values.insert(4, Vector_(2, 4.0, 5.0));
|
||||
values.insert(0, Vector_(4, 6.0, 7.0, 8.0, 9.0));
|
||||
|
||||
// Prints [ 3.0 4.0 ]
|
||||
gtsam::print(values[1]);
|
||||
|
||||
// Prints [ 8.0 9.0 ]
|
||||
values[1] = Vector_(2, 8.0, 9.0);
|
||||
gtsam::print(values[1]);
|
||||
\endcode
|
||||
*
|
||||
* <h2>Advanced Interface and Performance Information</h2>
|
||||
*
|
||||
* Internally, all vector values are stored as part of one large vector. In
|
||||
* gtsam this vector is always pre-allocated for efficiency, using the
|
||||
* advanced interface described below. Accessing and modifying already-allocated
|
||||
* values is \f$ O(1) \f$. Using the insert() function of the standard interface
|
||||
* is slow because it requires re-allocating the internal vector.
|
||||
*
|
||||
* For advanced usage, or where speed is important:
|
||||
* - Allocate space ahead of time using a pre-allocating constructor
|
||||
* (\ref AdvancedConstructors "Advanced Constructors"), Zero(),
|
||||
* SameStructure(), resize(), or append(). Do not use
|
||||
* insert(Index, const Vector&), which always has to re-allocate the
|
||||
* internal vector.
|
||||
* - The vector() function permits access to the underlying Vector, for
|
||||
* doing mathematical or other operations that require all values.
|
||||
* - operator[]() returns a SubVector view of the underlying Vector,
|
||||
* without copying any data.
|
||||
*
|
||||
* Access is through the variable index j, and returns a SubVector,
|
||||
* which is a view on the underlying data structure.
|
||||
*
|
||||
* This class is additionally used in gradient descent and dog leg to store the gradient.
|
||||
* \nosubgrouping
|
||||
*/
|
||||
class GTSAM_EXPORT VectorValuesOrdered {
|
||||
protected:
|
||||
typedef std::vector<Vector> Values; ///< Typedef for the collection of Vectors making up a VectorValues
|
||||
Values values_; ///< Collection of Vectors making up this VectorValues
|
||||
|
||||
public:
|
||||
typedef Values::iterator iterator; ///< Iterator over vector values
|
||||
typedef Values::const_iterator const_iterator; ///< Const iterator over vector values
|
||||
typedef Values::reverse_iterator reverse_iterator; ///< Reverse iterator over vector values
|
||||
typedef Values::const_reverse_iterator const_reverse_iterator; ///< Const reverse iterator over vector values
|
||||
typedef boost::shared_ptr<VectorValuesOrdered> shared_ptr; ///< shared_ptr to this class
|
||||
|
||||
/// @name Standard Constructors
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Default constructor creates an empty VectorValues.
|
||||
*/
|
||||
VectorValuesOrdered() {}
|
||||
|
||||
/** Named constructor to create a VectorValues of the same structure of the
|
||||
* specified one, but filled with zeros.
|
||||
* @return
|
||||
*/
|
||||
static VectorValuesOrdered Zero(const VectorValuesOrdered& model);
|
||||
|
||||
/// @}
|
||||
/// @name Standard Interface
|
||||
/// @{
|
||||
|
||||
/** Number of variables stored, always 1 more than the highest variable index,
|
||||
* even if some variables with lower indices are not present. */
|
||||
Index size() const { return values_.size(); }
|
||||
|
||||
/** Return the dimension of variable \c j. */
|
||||
size_t dim(Index j) const { checkExists(j); return (*this)[j].rows(); }
|
||||
|
||||
/** Return the dimension of each vector in this container */
|
||||
std::vector<size_t> dims() const;
|
||||
|
||||
/** Check whether a variable with index \c j exists. */
|
||||
bool exists(Index j) const { return j < size() && values_[j].rows() > 0; }
|
||||
|
||||
/** Read/write access to the vector value with index \c j, throws std::out_of_range if \c j does not exist, identical to operator[](Index). */
|
||||
Vector& at(Index j) { checkExists(j); return values_[j]; }
|
||||
|
||||
/** Access the vector value with index \c j (const version), throws std::out_of_range if \c j does not exist, identical to operator[](Index). */
|
||||
const Vector& at(Index j) const { checkExists(j); return values_[j]; }
|
||||
|
||||
/** Read/write access to the vector value with index \c j, throws std::out_of_range if \c j does not exist, identical to at(Index). */
|
||||
Vector& operator[](Index j) { return at(j); }
|
||||
|
||||
/** Access the vector value with index \c j (const version), throws std::out_of_range if \c j does not exist, identical to at(Index). */
|
||||
const Vector& operator[](Index j) const { return at(j); }
|
||||
|
||||
/** Insert a vector \c value with index \c j.
|
||||
* Causes reallocation, but can insert values in any order.
|
||||
* Throws an invalid_argument exception if the index \c j is already used.
|
||||
* @param value The vector to be inserted.
|
||||
* @param j The index with which the value will be associated.
|
||||
*/
|
||||
void insert(Index j, const Vector& value);
|
||||
|
||||
iterator begin() { return values_.begin(); } ///< Iterator over variables
|
||||
const_iterator begin() const { return values_.begin(); } ///< Iterator over variables
|
||||
iterator end() { return values_.end(); } ///< Iterator over variables
|
||||
const_iterator end() const { return values_.end(); } ///< Iterator over variables
|
||||
reverse_iterator rbegin() { return values_.rbegin(); } ///< Reverse iterator over variables
|
||||
const_reverse_iterator rbegin() const { return values_.rbegin(); } ///< Reverse iterator over variables
|
||||
reverse_iterator rend() { return values_.rend(); } ///< Reverse iterator over variables
|
||||
const_reverse_iterator rend() const { return values_.rend(); } ///< Reverse iterator over variables
|
||||
|
||||
/** print required by Testable for unit testing */
|
||||
void print(const std::string& str = "VectorValues: ",
|
||||
const IndexFormatter& formatter = DefaultIndexFormatter) const;
|
||||
|
||||
/** equals required by Testable for unit testing */
|
||||
bool equals(const VectorValuesOrdered& x, double tol = 1e-9) const;
|
||||
|
||||
/// @{
|
||||
/// \anchor AdvancedConstructors
|
||||
/// @name Advanced Constructors
|
||||
/// @}
|
||||
|
||||
/** Construct from a container of variable dimensions (in variable order), without initializing any values. */
|
||||
template<class CONTAINER>
|
||||
explicit VectorValuesOrdered(const CONTAINER& dimensions) { this->append(dimensions); }
|
||||
|
||||
/** Construct to hold nVars vectors of varDim dimension each. */
|
||||
VectorValuesOrdered(Index nVars, size_t varDim) { this->resize(nVars, varDim); }
|
||||
|
||||
/** Named constructor to create a VectorValues that matches the structure of
|
||||
* the specified VectorValues, but do not initialize the new values. */
|
||||
static VectorValuesOrdered SameStructure(const VectorValuesOrdered& other);
|
||||
|
||||
/** Named constructor to create a VectorValues from a container of variable
|
||||
* dimensions that is filled with zeros.
|
||||
* @param dimensions A container of the dimension of each variable to create.
|
||||
*/
|
||||
template<class CONTAINER>
|
||||
static VectorValuesOrdered Zero(const CONTAINER& dimensions);
|
||||
|
||||
/** Named constructor to create a VectorValues filled with zeros that has
|
||||
* \c nVars variables, each of dimension \c varDim
|
||||
* @param nVars The number of variables to create
|
||||
* @param varDim The dimension of each variable
|
||||
* @return The new VectorValues
|
||||
*/
|
||||
static VectorValuesOrdered Zero(Index nVars, size_t varDim);
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Interface
|
||||
/// @{
|
||||
|
||||
/** Resize this VectorValues to have identical structure to other, leaving
|
||||
* this VectorValues with uninitialized values.
|
||||
* @param other The VectorValues whose structure to copy
|
||||
*/
|
||||
void resizeLike(const VectorValuesOrdered& other);
|
||||
|
||||
/** Resize the VectorValues to hold \c nVars variables, each of dimension
|
||||
* \c varDim. Any individual vectors that do not change size will keep
|
||||
* their values, but any new or resized vectors will be uninitialized.
|
||||
* @param nVars The number of variables to create
|
||||
* @param varDim The dimension of each variable
|
||||
*/
|
||||
void resize(Index nVars, size_t varDim);
|
||||
|
||||
/** Resize the VectorValues to contain variables of the dimensions stored
|
||||
* in \c dimensions. Any individual vectors that do not change size will keep
|
||||
* their values, but any new or resized vectors will be uninitialized.
|
||||
* @param dimensions A container of the dimension of each variable to create.
|
||||
*/
|
||||
template<class CONTAINER>
|
||||
void resize(const CONTAINER& dimensions);
|
||||
|
||||
/** Append to the VectorValues to additionally contain variables of the
|
||||
* dimensions stored in \c dimensions. The new variables are uninitialized,
|
||||
* but this function is used to pre-allocate space for performance. This
|
||||
* function preserves the original data, so all previously-existing variables
|
||||
* are left unchanged.
|
||||
* @param dimensions A container of the dimension of each variable to create.
|
||||
*/
|
||||
template<class CONTAINER>
|
||||
void append(const CONTAINER& dimensions);
|
||||
|
||||
/** Removes the last subvector from the VectorValues */
|
||||
void pop_back() { values_.pop_back(); };
|
||||
|
||||
/** Set all entries to zero, does not modify the size. */
|
||||
void setZero();
|
||||
|
||||
/** Retrieve the entire solution as a single vector */
|
||||
const Vector asVector() const;
|
||||
|
||||
/** Access a vector that is a subset of relevant indices */
|
||||
const Vector vector(const std::vector<Index>& indices) const;
|
||||
|
||||
/** Check whether this VectorValues has the same structure, meaning has the
|
||||
* same number of variables and that all variables are of the same dimension,
|
||||
* as another VectorValues
|
||||
* @param other The other VectorValues with which to compare structure
|
||||
* @return \c true if the structure is the same, \c false if not.
|
||||
*/
|
||||
bool hasSameStructure(const VectorValuesOrdered& other) const;
|
||||
|
||||
/**
|
||||
* Permute the variables in the VariableIndex according to the given partial permutation
|
||||
*/
|
||||
void permuteInPlace(const Permutation& selector, const Permutation& permutation);
|
||||
|
||||
/**
|
||||
* Permute the entries of this VectorValues in place
|
||||
*/
|
||||
void permuteInPlace(const Permutation& permutation);
|
||||
|
||||
/**
|
||||
* Swap the data in this VectorValues with another.
|
||||
*/
|
||||
void swap(VectorValuesOrdered& other);
|
||||
|
||||
/// @}
|
||||
/// @name Linear algebra operations
|
||||
/// @{
|
||||
|
||||
/** Dot product with another VectorValues, interpreting both as vectors of
|
||||
* their concatenated values. */
|
||||
double dot(const VectorValuesOrdered& v) const;
|
||||
|
||||
/** Vector L2 norm */
|
||||
double norm() const;
|
||||
|
||||
/** Squared vector L2 norm */
|
||||
double squaredNorm() const;
|
||||
|
||||
/**
|
||||
* + operator does element-wise addition. Both VectorValues must have the
|
||||
* same structure (checked when NDEBUG is not defined).
|
||||
*/
|
||||
VectorValuesOrdered operator+(const VectorValuesOrdered& c) const;
|
||||
|
||||
/**
|
||||
* + operator does element-wise subtraction. Both VectorValues must have the
|
||||
* same structure (checked when NDEBUG is not defined).
|
||||
*/
|
||||
VectorValuesOrdered operator-(const VectorValuesOrdered& c) const;
|
||||
|
||||
/**
|
||||
* += operator does element-wise addition. Both VectorValues must have the
|
||||
* same structure (checked when NDEBUG is not defined).
|
||||
*/
|
||||
void operator+=(const VectorValuesOrdered& c);
|
||||
|
||||
/// @}
|
||||
|
||||
/// @}
|
||||
/// @name Matlab syntactic sugar for linear algebra operations
|
||||
/// @{
|
||||
|
||||
inline VectorValuesOrdered add(const VectorValuesOrdered& c) const { return *this + c; }
|
||||
inline VectorValuesOrdered scale(const double a, const VectorValuesOrdered& c) const { return a * (*this); }
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// Throw an exception if j does not exist
|
||||
void checkExists(Index j) const {
|
||||
if(!exists(j)) {
|
||||
const std::string msg =
|
||||
(boost::format("VectorValues: requested variable index j=%1% is not in this VectorValues.") % j).str();
|
||||
throw std::out_of_range(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* scale a vector by a scalar
|
||||
*/
|
||||
friend VectorValuesOrdered operator*(const double a, const VectorValuesOrdered &v) {
|
||||
VectorValuesOrdered result = VectorValuesOrdered::SameStructure(v);
|
||||
for(Index j = 0; j < v.size(); ++j)
|
||||
result.values_[j] = a * v.values_[j];
|
||||
return result;
|
||||
}
|
||||
|
||||
/// TODO: linear algebra interface seems to have been added for SPCG.
|
||||
friend void scal(double alpha, VectorValuesOrdered& x) {
|
||||
for(Index j = 0; j < x.size(); ++j)
|
||||
x.values_[j] *= alpha;
|
||||
}
|
||||
/// TODO: linear algebra interface seems to have been added for SPCG.
|
||||
friend void axpy(double alpha, const VectorValuesOrdered& x, VectorValuesOrdered& y) {
|
||||
if(x.size() != y.size())
|
||||
throw std::invalid_argument("axpy(VectorValues) called with different vector sizes");
|
||||
for(Index j = 0; j < x.size(); ++j)
|
||||
if(x.values_[j].size() == y.values_[j].size())
|
||||
y.values_[j] += alpha * x.values_[j];
|
||||
else
|
||||
throw std::invalid_argument("axpy(VectorValues) called with different vector sizes");
|
||||
}
|
||||
/// TODO: linear algebra interface seems to have been added for SPCG.
|
||||
friend void sqrt(VectorValuesOrdered &x) {
|
||||
for(Index j = 0; j < x.size(); ++j)
|
||||
x.values_[j] = x.values_[j].cwiseSqrt();
|
||||
}
|
||||
|
||||
/// TODO: linear algebra interface seems to have been added for SPCG.
|
||||
friend void ediv(const VectorValuesOrdered& numerator, const VectorValuesOrdered& denominator, VectorValuesOrdered &result) {
|
||||
if(numerator.size() != denominator.size() || numerator.size() != result.size())
|
||||
throw std::invalid_argument("ediv(VectorValues) called with different vector sizes");
|
||||
for(Index j = 0; j < numerator.size(); ++j)
|
||||
if(numerator.values_[j].size() == denominator.values_[j].size() && numerator.values_[j].size() == result.values_[j].size())
|
||||
result.values_[j] = numerator.values_[j].cwiseQuotient(denominator.values_[j]);
|
||||
else
|
||||
throw std::invalid_argument("ediv(VectorValues) called with different vector sizes");
|
||||
}
|
||||
|
||||
/// TODO: linear algebra interface seems to have been added for SPCG.
|
||||
friend void edivInPlace(VectorValuesOrdered& x, const VectorValuesOrdered& y) {
|
||||
if(x.size() != y.size())
|
||||
throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes");
|
||||
for(Index j = 0; j < x.size(); ++j)
|
||||
if(x.values_[j].size() == y.values_[j].size())
|
||||
x.values_[j].array() /= y.values_[j].array();
|
||||
else
|
||||
throw std::invalid_argument("edivInPlace(VectorValues) called with different vector sizes");
|
||||
}
|
||||
|
||||
private:
|
||||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class ARCHIVE>
|
||||
void serialize(ARCHIVE & ar, const unsigned int version) {
|
||||
ar & BOOST_SERIALIZATION_NVP(values_);
|
||||
}
|
||||
}; // VectorValues definition
|
||||
|
||||
// Implementations of template and inline functions
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONTAINER>
|
||||
void VectorValuesOrdered::resize(const CONTAINER& dimensions) {
|
||||
values_.clear();
|
||||
append(dimensions);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONTAINER>
|
||||
void VectorValuesOrdered::append(const CONTAINER& dimensions) {
|
||||
size_t i = size();
|
||||
values_.resize(size() + dimensions.size());
|
||||
BOOST_FOREACH(size_t dim, dimensions) {
|
||||
values_[i] = Vector(dim);
|
||||
++ i;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
template<class CONTAINER>
|
||||
VectorValuesOrdered VectorValuesOrdered::Zero(const CONTAINER& dimensions) {
|
||||
VectorValuesOrdered ret;
|
||||
ret.values_.resize(dimensions.size());
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(size_t dim, dimensions) {
|
||||
ret.values_[i] = Vector::Zero(dim);
|
||||
++ i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
/* ************************************************************************* */
|
||||
// Helper function, extracts vectors with variable indices
|
||||
// in the first and last iterators, and concatenates them in that order into the
|
||||
// output.
|
||||
template<typename ITERATOR>
|
||||
const Vector extractVectorValuesSlices(const VectorValuesOrdered& values, ITERATOR first, ITERATOR last, bool allowNonexistant = false) {
|
||||
// Find total dimensionality
|
||||
size_t dim = 0;
|
||||
for(ITERATOR j = first; j != last; ++j)
|
||||
// If allowNonexistant is true, skip nonexistent indices (otherwise dim will throw an error on nonexistent)
|
||||
if(!allowNonexistant || values.exists(*j))
|
||||
dim += values.dim(*j);
|
||||
|
||||
// Copy vectors
|
||||
Vector ret(dim);
|
||||
size_t varStart = 0;
|
||||
for(ITERATOR j = first; j != last; ++j) {
|
||||
// If allowNonexistant is true, skip nonexistent indices (otherwise dim will throw an error on nonexistent)
|
||||
if(!allowNonexistant || values.exists(*j)) {
|
||||
ret.segment(varStart, values.dim(*j)) = values[*j];
|
||||
varStart += values.dim(*j);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Helper function, writes to the variables in values
|
||||
// with indices iterated over by first and last, interpreting vector as the
|
||||
// concatenated vectors to write.
|
||||
template<class VECTOR, typename ITERATOR>
|
||||
void writeVectorValuesSlices(const VECTOR& vector, VectorValuesOrdered& values, ITERATOR first, ITERATOR last) {
|
||||
// Copy vectors
|
||||
size_t varStart = 0;
|
||||
for(ITERATOR j = first; j != last; ++j) {
|
||||
values[*j] = vector.segment(varStart, values[*j].rows());
|
||||
varStart += values[*j].rows();
|
||||
}
|
||||
assert(varStart == vector.rows());
|
||||
}
|
||||
}
|
||||
|
||||
} // \namespace gtsam
|
||||
|
|
@ -1,354 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testGaussianConditional.cpp
|
||||
* @brief Unit tests for Conditional gaussian
|
||||
* @author Christian Potthast
|
||||
**/
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/linear/JacobianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/GaussianBayesNetOrdered.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <boost/assign/std/list.hpp>
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
|
||||
using namespace gtsam;
|
||||
using namespace std;
|
||||
using namespace boost::assign;
|
||||
|
||||
static const double tol = 1e-5;
|
||||
static const Index _x_=0, _x1_=1, _l1_=2;
|
||||
|
||||
Matrix R = Matrix_(2,2,
|
||||
-12.1244, -5.1962,
|
||||
0., 4.6904);
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianConditionalOrdered, constructor)
|
||||
{
|
||||
Matrix S1 = Matrix_(2,2,
|
||||
-5.2786, -8.6603,
|
||||
5.0254, 5.5432);
|
||||
Matrix S2 = Matrix_(2,2,
|
||||
-10.5573, -5.9385,
|
||||
5.5737, 3.0153);
|
||||
Matrix S3 = Matrix_(2,2,
|
||||
-11.3820, -7.2581,
|
||||
-3.0153, -3.5635);
|
||||
|
||||
Vector d = Vector_(2, 1.0, 2.0);
|
||||
Vector s = Vector_(2, 3.0, 4.0);
|
||||
|
||||
list<pair<Index, Matrix> > terms;
|
||||
terms +=
|
||||
make_pair(3, S1),
|
||||
make_pair(5, S2),
|
||||
make_pair(7, S3);
|
||||
|
||||
GaussianConditionalOrdered actual(1, d, R, terms, s);
|
||||
|
||||
GaussianConditionalOrdered::const_iterator it = actual.beginFrontals();
|
||||
EXPECT(assert_equal(Index(1), *it));
|
||||
EXPECT(assert_equal(R, actual.get_R()));
|
||||
++ it;
|
||||
EXPECT(it == actual.endFrontals());
|
||||
|
||||
it = actual.beginParents();
|
||||
EXPECT(assert_equal(Index(3), *it));
|
||||
EXPECT(assert_equal(S1, actual.get_S(it)));
|
||||
|
||||
++ it;
|
||||
EXPECT(assert_equal(Index(5), *it));
|
||||
EXPECT(assert_equal(S2, actual.get_S(it)));
|
||||
|
||||
++ it;
|
||||
EXPECT(assert_equal(Index(7), *it));
|
||||
EXPECT(assert_equal(S3, actual.get_S(it)));
|
||||
|
||||
++it;
|
||||
EXPECT(it == actual.endParents());
|
||||
|
||||
EXPECT(assert_equal(d, actual.get_d()));
|
||||
EXPECT(assert_equal(s, actual.get_sigmas()));
|
||||
|
||||
// test copy constructor
|
||||
GaussianConditionalOrdered copied(actual);
|
||||
EXPECT(assert_equal(d, copied.get_d()));
|
||||
EXPECT(assert_equal(s, copied.get_sigmas()));
|
||||
EXPECT(assert_equal(R, copied.get_R()));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
GaussianConditionalOrdered construct() {
|
||||
Vector d = Vector_(2, 1.0, 2.0);
|
||||
Vector s = Vector_(2, 3.0, 4.0);
|
||||
GaussianConditionalOrdered::shared_ptr shared(new GaussianConditionalOrdered(1, d, R, s));
|
||||
return *shared;
|
||||
}
|
||||
|
||||
TEST(GaussianConditionalOrdered, return_value)
|
||||
{
|
||||
Vector d = Vector_(2, 1.0, 2.0);
|
||||
Vector s = Vector_(2, 3.0, 4.0);
|
||||
GaussianConditionalOrdered copied = construct();
|
||||
EXPECT(assert_equal(d, copied.get_d()));
|
||||
EXPECT(assert_equal(s, copied.get_sigmas()));
|
||||
EXPECT(assert_equal(R, copied.get_R()));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianConditionalOrdered, equals )
|
||||
{
|
||||
// create a conditional gaussian node
|
||||
Matrix A1(2,2);
|
||||
A1(0,0) = 1 ; A1(1,0) = 2;
|
||||
A1(0,1) = 3 ; A1(1,1) = 4;
|
||||
|
||||
Matrix A2(2,2);
|
||||
A2(0,0) = 6 ; A2(1,0) = 0.2;
|
||||
A2(0,1) = 8 ; A2(1,1) = 0.4;
|
||||
|
||||
Matrix R(2,2);
|
||||
R(0,0) = 0.1 ; R(1,0) = 0.3;
|
||||
R(0,1) = 0.0 ; R(1,1) = 0.34;
|
||||
|
||||
Vector tau(2);
|
||||
tau(0) = 1.0;
|
||||
tau(1) = 0.34;
|
||||
|
||||
Vector d(2);
|
||||
d(0) = 0.2; d(1) = 0.5;
|
||||
|
||||
GaussianConditionalOrdered
|
||||
expected(_x_,d, R, _x1_, A1, _l1_, A2, tau),
|
||||
actual(_x_,d, R, _x1_, A1, _l1_, A2, tau);
|
||||
|
||||
EXPECT( expected.equals(actual) );
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianConditionalOrdered, solve )
|
||||
{
|
||||
//expected solution
|
||||
Vector expectedX(2);
|
||||
expectedX(0) = 20-3-11 ; expectedX(1) = 40-7-15;
|
||||
|
||||
// create a conditional Gaussian node
|
||||
Matrix R = Matrix_(2,2, 1., 0.,
|
||||
0., 1.);
|
||||
|
||||
Matrix A1 = Matrix_(2,2, 1., 2.,
|
||||
3., 4.);
|
||||
|
||||
Matrix A2 = Matrix_(2,2, 5., 6.,
|
||||
7., 8.);
|
||||
|
||||
Vector d(2);
|
||||
d(0) = 20.0; d(1) = 40.0;
|
||||
|
||||
Vector tau = ones(2);
|
||||
|
||||
GaussianConditionalOrdered cg(_x_, d, R, _x1_, A1, _l1_, A2, tau);
|
||||
|
||||
Vector sx1(2);
|
||||
sx1(0) = 1.0; sx1(1) = 1.0;
|
||||
|
||||
Vector sl1(2);
|
||||
sl1(0) = 1.0; sl1(1) = 1.0;
|
||||
|
||||
VectorValuesOrdered solution(vector<size_t>(3, 2));
|
||||
solution[_x_] = d;
|
||||
solution[_x1_] = sx1; // parents
|
||||
solution[_l1_] = sl1;
|
||||
|
||||
VectorValuesOrdered expected(vector<size_t>(3, 2));
|
||||
expected[_x_] = expectedX;
|
||||
expected[_x1_] = sx1;
|
||||
expected[_l1_] = sl1;
|
||||
cg.solveInPlace(solution);
|
||||
|
||||
EXPECT(assert_equal(expected, solution, 0.0001));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianConditionalOrdered, solve_simple )
|
||||
{
|
||||
Matrix full_matrix = Matrix_(4, 7,
|
||||
1.0, 0.0, 2.0, 0.0, 3.0, 0.0, 0.1,
|
||||
0.0, 1.0, 0.0, 2.0, 0.0, 3.0, 0.2,
|
||||
0.0, 0.0, 3.0, 0.0, 4.0, 0.0, 0.3,
|
||||
0.0, 0.0, 0.0, 3.0, 0.0, 4.0, 0.4);
|
||||
|
||||
// solve system as a non-multifrontal version first
|
||||
// 2 variables, frontal has dim=4
|
||||
vector<size_t> dims; dims += 4, 2, 1;
|
||||
GaussianConditionalOrdered::rsd_type matrices(full_matrix, dims.begin(), dims.end());
|
||||
Vector sigmas = ones(4);
|
||||
vector<size_t> cgdims; cgdims += _x_, _x1_;
|
||||
GaussianConditionalOrdered cg(cgdims.begin(), cgdims.end(), 1, matrices, sigmas);
|
||||
|
||||
// partial solution
|
||||
Vector sx1 = Vector_(2, 9.0, 10.0);
|
||||
|
||||
// elimination order; _x_, _x1_
|
||||
vector<size_t> vdim; vdim += 4, 2;
|
||||
VectorValuesOrdered actual(vdim);
|
||||
actual[_x1_] = sx1; // parent
|
||||
|
||||
VectorValuesOrdered expected(vdim);
|
||||
expected[_x1_] = sx1;
|
||||
expected[_x_] = Vector_(4, -3.1,-3.4,-11.9,-13.2);
|
||||
|
||||
// verify indices/size
|
||||
EXPECT_LONGS_EQUAL(2, cg.size());
|
||||
EXPECT_LONGS_EQUAL(4, cg.dim());
|
||||
|
||||
// solve and verify
|
||||
cg.solveInPlace(actual);
|
||||
EXPECT(assert_equal(expected, actual, tol));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianConditionalOrdered, solve_multifrontal )
|
||||
{
|
||||
// create full system, 3 variables, 2 frontals, all 2 dim
|
||||
Matrix full_matrix = Matrix_(4, 7,
|
||||
1.0, 0.0, 2.0, 0.0, 3.0, 0.0, 0.1,
|
||||
0.0, 1.0, 0.0, 2.0, 0.0, 3.0, 0.2,
|
||||
0.0, 0.0, 3.0, 0.0, 4.0, 0.0, 0.3,
|
||||
0.0, 0.0, 0.0, 3.0, 0.0, 4.0, 0.4);
|
||||
|
||||
// 3 variables, all dim=2
|
||||
vector<size_t> dims; dims += 2, 2, 2, 1;
|
||||
GaussianConditionalOrdered::rsd_type matrices(full_matrix, dims.begin(), dims.end());
|
||||
Vector sigmas = ones(4);
|
||||
vector<size_t> cgdims; cgdims += _x_, _x1_, _l1_;
|
||||
GaussianConditionalOrdered cg(cgdims.begin(), cgdims.end(), 2, matrices, sigmas);
|
||||
|
||||
EXPECT(assert_equal(Vector_(4, 0.1, 0.2, 0.3, 0.4), cg.get_d()));
|
||||
|
||||
// partial solution
|
||||
Vector sl1 = Vector_(2, 9.0, 10.0);
|
||||
|
||||
// elimination order; _x_, _x1_, _l1_
|
||||
VectorValuesOrdered actual(vector<size_t>(3, 2));
|
||||
actual[_l1_] = sl1; // parent
|
||||
|
||||
VectorValuesOrdered expected(vector<size_t>(3, 2));
|
||||
expected[_x_] = Vector_(2, -3.1,-3.4);
|
||||
expected[_x1_] = Vector_(2, -11.9,-13.2);
|
||||
expected[_l1_] = sl1;
|
||||
|
||||
// verify indices/size
|
||||
EXPECT_LONGS_EQUAL(3, cg.size());
|
||||
EXPECT_LONGS_EQUAL(4, cg.dim());
|
||||
|
||||
// solve and verify
|
||||
cg.solveInPlace(actual);
|
||||
EXPECT(assert_equal(expected, actual, tol));
|
||||
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianConditionalOrdered, solveTranspose ) {
|
||||
static const Index _y_=1;
|
||||
/** create small Chordal Bayes Net x <- y
|
||||
* x y d
|
||||
* 1 1 9
|
||||
* 1 5
|
||||
*/
|
||||
Matrix R11 = Matrix_(1, 1, 1.0), S12 = Matrix_(1, 1, 1.0);
|
||||
Matrix R22 = Matrix_(1, 1, 1.0);
|
||||
Vector d1(1), d2(1);
|
||||
d1(0) = 9;
|
||||
d2(0) = 5;
|
||||
Vector tau(1);
|
||||
tau(0) = 1.0;
|
||||
|
||||
// define nodes and specify in reverse topological sort (i.e. parents last)
|
||||
GaussianConditionalOrdered::shared_ptr Px_y(new GaussianConditionalOrdered(_x_, d1, R11, _y_, S12, tau));
|
||||
GaussianConditionalOrdered::shared_ptr Py(new GaussianConditionalOrdered(_y_, d2, R22, tau));
|
||||
GaussianBayesNetOrdered cbn;
|
||||
cbn.push_back(Px_y);
|
||||
cbn.push_back(Py);
|
||||
|
||||
// x=R'*y, y=inv(R')*x
|
||||
// 2 = 1 2
|
||||
// 5 1 1 3
|
||||
|
||||
VectorValuesOrdered y(vector<size_t>(2,1)), x(vector<size_t>(2,1));
|
||||
x[_x_] = Vector_(1,2.);
|
||||
x[_y_] = Vector_(1,5.);
|
||||
y[_x_] = Vector_(1,2.);
|
||||
y[_y_] = Vector_(1,3.);
|
||||
|
||||
// test functional version
|
||||
VectorValuesOrdered actual = backSubstituteTranspose(cbn,x);
|
||||
CHECK(assert_equal(y,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianConditionalOrdered, information ) {
|
||||
|
||||
// Create R matrix
|
||||
Matrix R = (Matrix(4,4) <<
|
||||
1, 2, 3, 4,
|
||||
0, 5, 6, 7,
|
||||
0, 0, 8, 9,
|
||||
0, 0, 0, 10).finished();
|
||||
|
||||
// Create conditional
|
||||
GaussianConditionalOrdered conditional(0, Vector::Zero(4), R, Vector::Constant(4, 1.0));
|
||||
|
||||
// Expected information matrix (using permuted R)
|
||||
Matrix IExpected = R.transpose() * R;
|
||||
|
||||
// Actual information matrix (conditional should permute R)
|
||||
Matrix IActual = conditional.information();
|
||||
EXPECT(assert_equal(IExpected, IActual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianConditionalOrdered, isGaussianFactor ) {
|
||||
|
||||
// Create R matrix
|
||||
Matrix R = (Matrix(4,4) <<
|
||||
1, 2, 3, 4,
|
||||
0, 5, 6, 7,
|
||||
0, 0, 8, 9,
|
||||
0, 0, 0, 10).finished();
|
||||
|
||||
// Create a conditional
|
||||
GaussianConditionalOrdered conditional(0, Vector::Zero(4), R, Vector::Constant(4, 1.0));
|
||||
|
||||
// Expected information matrix computed by conditional
|
||||
Matrix IExpected = conditional.information();
|
||||
|
||||
// Expected information matrix computed by a factor
|
||||
JacobianFactorOrdered jf = *conditional.toFactor();
|
||||
Matrix IActual = jf.getA(jf.begin()).transpose() * jf.getA(jf.begin());
|
||||
|
||||
EXPECT(assert_equal(IExpected, IActual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,537 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testGaussianFactor.cpp
|
||||
* @brief Unit tests for Linear Factor
|
||||
* @author Christian Potthast
|
||||
* @author Frank Dellaert
|
||||
**/
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/inference/VariableSlots.h>
|
||||
#include <gtsam/inference/VariableIndexOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
#include <gtsam/linear/GaussianSequentialSolver.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
using namespace boost;
|
||||
|
||||
static SharedDiagonal
|
||||
sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1), sigma_02 = noiseModel::Isotropic::Sigma(2,0.2),
|
||||
constraintModel = noiseModel::Constrained::All(2);
|
||||
|
||||
static GaussianFactorGraphOrdered createSimpleGaussianFactorGraph() {
|
||||
GaussianFactorGraphOrdered fg;
|
||||
SharedDiagonal unit2 = noiseModel::Unit::Create(2);
|
||||
// linearized prior on x1: c[_x1_]+x1=0 i.e. x1=-c[_x1_]
|
||||
fg.add(2, 10*eye(2), -1.0*ones(2), unit2);
|
||||
// odometry between x1 and x2: x2-x1=[0.2;-0.1]
|
||||
fg.add(2, -10*eye(2), 0, 10*eye(2), Vector_(2, 2.0, -1.0), unit2);
|
||||
// measurement between x1 and l1: l1-x1=[0.0;0.2]
|
||||
fg.add(2, -5*eye(2), 1, 5*eye(2), Vector_(2, 0.0, 1.0), unit2);
|
||||
// measurement between x2 and l1: l1-x2=[-0.2;0.3]
|
||||
fg.add(0, -5*eye(2), 1, 5*eye(2), Vector_(2, -1.0, 1.5), unit2);
|
||||
return fg;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorGraphOrdered, initialization) {
|
||||
// Create empty graph
|
||||
GaussianFactorGraphOrdered fg;
|
||||
SharedDiagonal unit2 = noiseModel::Unit::Create(2);
|
||||
|
||||
fg.add(0, 10*eye(2), -1.0*ones(2), unit2);
|
||||
fg.add(0, -10*eye(2),1, 10*eye(2), Vector_(2, 2.0, -1.0), unit2);
|
||||
fg.add(0, -5*eye(2), 2, 5*eye(2), Vector_(2, 0.0, 1.0), unit2);
|
||||
fg.add(1, -5*eye(2), 2, 5*eye(2), Vector_(2, -1.0, 1.5), unit2);
|
||||
|
||||
EXPECT_LONGS_EQUAL(4, fg.size());
|
||||
JacobianFactorOrdered factor = *boost::dynamic_pointer_cast<JacobianFactorOrdered>(fg[0]);
|
||||
|
||||
// Test sparse, which takes a vector and returns a matrix, used in MATLAB
|
||||
// Note that this the augmented vector and the RHS is in column 7
|
||||
Matrix expectedIJS = Matrix_(3,22,
|
||||
1., 2., 1., 2., 3., 4., 3., 4., 3., 4., 5., 6., 5., 6., 5., 6., 7., 8., 7., 8., 7., 8.,
|
||||
1., 2., 7., 7., 1., 2., 3., 4., 7., 7., 1., 2., 5., 6., 7., 7., 3., 4., 5., 6., 7., 7.,
|
||||
10., 10., -1., -1., -10., -10., 10., 10., 2., -1., -5., -5., 5., 5., 0., 1., -5., -5., 5., 5., -1., 1.5
|
||||
);
|
||||
Matrix actualIJS = fg.sparseJacobian_();
|
||||
EQUALITY(expectedIJS, actualIJS);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorGraphOrdered, CombineJacobians)
|
||||
{
|
||||
Matrix A01 = Matrix_(3,3,
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
|
||||
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
|
||||
|
||||
Matrix A10 = Matrix_(3,3,
|
||||
2.0, 0.0, 0.0,
|
||||
0.0, 2.0, 0.0,
|
||||
0.0, 0.0, 2.0);
|
||||
Matrix A11 = Matrix_(3,3,
|
||||
-2.0, 0.0, 0.0,
|
||||
0.0, -2.0, 0.0,
|
||||
0.0, 0.0, -2.0);
|
||||
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
|
||||
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
|
||||
|
||||
Matrix A21 = Matrix_(3,3,
|
||||
3.0, 0.0, 0.0,
|
||||
0.0, 3.0, 0.0,
|
||||
0.0, 0.0, 3.0);
|
||||
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
|
||||
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
|
||||
|
||||
GaussianFactorGraphOrdered gfg;
|
||||
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true));
|
||||
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
|
||||
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
|
||||
|
||||
// Convert to Jacobians (inefficient copy of all factors instead of selectively converting only Hessians)
|
||||
FactorGraphOrdered<JacobianFactorOrdered> jacobians;
|
||||
BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, gfg) {
|
||||
jacobians.push_back(boost::make_shared<JacobianFactorOrdered>(*factor));
|
||||
}
|
||||
|
||||
// Combine Jacobians into a single dense factor
|
||||
JacobianFactorOrdered actual = *CombineJacobians(jacobians, VariableSlots(gfg));
|
||||
|
||||
Matrix zero3x3 = zeros(3,3);
|
||||
Matrix A0 = gtsam::stack(3, &zero3x3, &A10, &zero3x3);
|
||||
Matrix A1 = gtsam::stack(3, &A01, &A11, &A21);
|
||||
Vector b = gtsam::concatVectors(3, &b0, &b1, &b2);
|
||||
Vector sigmas = gtsam::concatVectors(3, &s0, &s1, &s2);
|
||||
|
||||
JacobianFactorOrdered expected(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorOrdered, CombineAndEliminate)
|
||||
{
|
||||
Matrix A01 = Matrix_(3,3,
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
|
||||
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
|
||||
|
||||
Matrix A10 = Matrix_(3,3,
|
||||
2.0, 0.0, 0.0,
|
||||
0.0, 2.0, 0.0,
|
||||
0.0, 0.0, 2.0);
|
||||
Matrix A11 = Matrix_(3,3,
|
||||
-2.0, 0.0, 0.0,
|
||||
0.0, -2.0, 0.0,
|
||||
0.0, 0.0, -2.0);
|
||||
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
|
||||
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
|
||||
|
||||
Matrix A21 = Matrix_(3,3,
|
||||
3.0, 0.0, 0.0,
|
||||
0.0, 3.0, 0.0,
|
||||
0.0, 0.0, 3.0);
|
||||
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
|
||||
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
|
||||
|
||||
GaussianFactorGraphOrdered gfg;
|
||||
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true));
|
||||
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
|
||||
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
|
||||
|
||||
Matrix zero3x3 = zeros(3,3);
|
||||
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3);
|
||||
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21);
|
||||
Vector b = gtsam::concatVectors(3, &b1, &b0, &b2);
|
||||
Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2);
|
||||
|
||||
JacobianFactorOrdered expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
|
||||
GaussianConditionalOrdered::shared_ptr expectedBN = expectedFactor.eliminate(1);
|
||||
|
||||
GaussianConditionalOrdered::shared_ptr actualBN;
|
||||
GaussianFactorOrdered::shared_ptr actualFactor;
|
||||
boost::tie(actualBN, actualFactor) = EliminateQROrdered(gfg, 1);
|
||||
JacobianFactorOrdered::shared_ptr actualJacobian = boost::dynamic_pointer_cast<
|
||||
JacobianFactorOrdered>(actualFactor);
|
||||
|
||||
EXPECT(assert_equal(*expectedBN, *actualBN));
|
||||
EXPECT(assert_equal(expectedFactor, *actualJacobian));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorOrdered, eliminateFrontals)
|
||||
{
|
||||
// Augmented Ab test case for whole factor graph
|
||||
Matrix Ab = Matrix_(14,11,
|
||||
4., 0., 1., 4., 1., 0., 3., 6., 8., 8., 1.,
|
||||
9., 2., 0., 1., 6., 3., 9., 6., 6., 9., 4.,
|
||||
5., 3., 7., 9., 5., 5., 9., 1., 3., 7., 0.,
|
||||
5., 6., 5., 7., 9., 4., 0., 1., 1., 3., 5.,
|
||||
0., 0., 4., 5., 6., 6., 7., 9., 4., 5., 4.,
|
||||
0., 0., 9., 4., 8., 6., 2., 1., 4., 1., 6.,
|
||||
0., 0., 6., 0., 4., 2., 4., 0., 1., 9., 6.,
|
||||
0., 0., 6., 6., 4., 4., 5., 5., 5., 8., 6.,
|
||||
0., 0., 0., 0., 8., 0., 9., 8., 2., 8., 0.,
|
||||
0., 0., 0., 0., 0., 9., 4., 6., 3., 2., 0.,
|
||||
0., 0., 0., 0., 1., 1., 9., 1., 5., 5., 3.,
|
||||
0., 0., 0., 0., 1., 1., 3., 3., 2., 0., 5.,
|
||||
0., 0., 0., 0., 0., 0., 0., 0., 2., 4., 6.,
|
||||
0., 0., 0., 0., 0., 0., 0., 0., 6., 3., 4.);
|
||||
|
||||
// Create first factor (from pieces of Ab)
|
||||
list<pair<Index, Matrix> > terms1;
|
||||
|
||||
terms1 +=
|
||||
make_pair( 3, Matrix(Ab.block(0, 0, 4, 2))),
|
||||
make_pair( 5, Matrix(Ab.block(0, 2, 4, 2))),
|
||||
make_pair( 7, Matrix(Ab.block(0, 4, 4, 2))),
|
||||
make_pair( 9, Matrix(Ab.block(0, 6, 4, 2))),
|
||||
make_pair(11, Matrix(Ab.block(0, 8, 4, 2)));
|
||||
Vector b1 = Ab.col(10).segment(0, 4);
|
||||
JacobianFactorOrdered::shared_ptr factor1(new JacobianFactorOrdered(terms1, b1, noiseModel::Isotropic::Sigma(4, 0.5)));
|
||||
|
||||
// Create second factor
|
||||
list<pair<Index, Matrix> > terms2;
|
||||
terms2 +=
|
||||
make_pair(5, Matrix(Ab.block(4, 2, 4, 2))),
|
||||
make_pair(7, Matrix(Ab.block(4, 4, 4, 2))),
|
||||
make_pair(9, Matrix(Ab.block(4, 6, 4, 2))),
|
||||
make_pair(11,Matrix(Ab.block(4, 8, 4, 2)));
|
||||
Vector b2 = Ab.col(10).segment(4, 4);
|
||||
JacobianFactorOrdered::shared_ptr factor2(new JacobianFactorOrdered(terms2, b2, noiseModel::Isotropic::Sigma(4, 0.5)));
|
||||
|
||||
// Create third factor
|
||||
list<pair<Index, Matrix> > terms3;
|
||||
terms3 +=
|
||||
make_pair(7, Matrix(Ab.block(8, 4, 4, 2))),
|
||||
make_pair(9, Matrix(Ab.block(8, 6, 4, 2))),
|
||||
make_pair(11,Matrix(Ab.block(8, 8, 4, 2)));
|
||||
Vector b3 = Ab.col(10).segment(8, 4);
|
||||
JacobianFactorOrdered::shared_ptr factor3(new JacobianFactorOrdered(terms3, b3, noiseModel::Isotropic::Sigma(4, 0.5)));
|
||||
|
||||
// Create fourth factor
|
||||
list<pair<Index, Matrix> > terms4;
|
||||
terms4 +=
|
||||
make_pair(11, Matrix(Ab.block(12, 8, 2, 2)));
|
||||
Vector b4 = Ab.col(10).segment(12, 2);
|
||||
JacobianFactorOrdered::shared_ptr factor4(new JacobianFactorOrdered(terms4, b4, noiseModel::Isotropic::Sigma(2, 0.5)));
|
||||
|
||||
// Create factor graph
|
||||
GaussianFactorGraphOrdered factors;
|
||||
factors.push_back(factor1);
|
||||
factors.push_back(factor2);
|
||||
factors.push_back(factor3);
|
||||
factors.push_back(factor4);
|
||||
|
||||
// extract the dense matrix for the graph
|
||||
Matrix actualDense = factors.augmentedJacobian();
|
||||
EXPECT(assert_equal(2.0 * Ab, actualDense));
|
||||
|
||||
// Convert to Jacobians, inefficient copy of all factors instead of selectively converting only Hessians
|
||||
FactorGraphOrdered<JacobianFactorOrdered> jacobians;
|
||||
BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, factors) {
|
||||
jacobians.push_back(boost::make_shared<JacobianFactorOrdered>(*factor));
|
||||
}
|
||||
|
||||
// Create combined factor
|
||||
JacobianFactorOrdered combined(*CombineJacobians(jacobians, VariableSlots(factors)));
|
||||
|
||||
// Copies factors as they will be eliminated in place
|
||||
JacobianFactorOrdered actualFactor_QR = combined;
|
||||
JacobianFactorOrdered actualFactor_Chol = combined;
|
||||
|
||||
// Expected augmented matrix, both GaussianConditional (first 6 rows) and remaining factor (next 4 rows)
|
||||
Matrix R = 2.0*Matrix_(11,11,
|
||||
-12.1244, -5.1962, -5.2786, -8.6603, -10.5573, -5.9385, -11.3820, -7.2581, -8.7427, -13.4440, -5.3611,
|
||||
0., 4.6904, 5.0254, 5.5432, 5.5737, 3.0153, -3.0153, -3.5635, -3.9290, -2.7412, 2.1625,
|
||||
0., 0., -13.8160, -8.7166, -10.2245, -8.8666, -8.7632, -5.2544, -6.9192, -10.5537, -9.3250,
|
||||
0., 0., 0., 6.5033, -1.1453, 1.3179, 2.5768, 5.5503, 3.6524, 1.3491, -2.5676,
|
||||
0., 0., 0., 0., -9.6242, -2.1148, -9.3509, -10.5846, -3.5366, -6.8561, -3.2277,
|
||||
0., 0., 0., 0., 0., 9.7887, 4.3551, 5.7572, 2.7876, 0.1611, 1.1769,
|
||||
0., 0., 0., 0., 0., 0., -11.1139, -0.6521, -2.1943, -7.5529, -0.9081,
|
||||
0., 0., 0., 0., 0., 0., 0., -4.6479, -1.9367, -6.5170, -3.7685,
|
||||
0., 0., 0., 0., 0., 0., 0., 0., 8.2503, 3.3757, 6.8476,
|
||||
0., 0., 0., 0., 0., 0., 0., 0., 0., -5.7095, -0.0090,
|
||||
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., -7.1635);
|
||||
|
||||
// Expected conditional on first variable from first 2 rows of R
|
||||
Matrix R1 = sub(R, 0,2, 0,2);
|
||||
list<pair<Index, Matrix> > cterms1;
|
||||
cterms1 +=
|
||||
make_pair(5, sub(R, 0,2, 2,4 )),
|
||||
make_pair(7, sub(R, 0,2, 4,6 )),
|
||||
make_pair(9, sub(R, 0,2, 6,8 )),
|
||||
make_pair(11,sub(R, 0,2, 8,10));
|
||||
Vector d1 = R.col(10).segment(0,2);
|
||||
GaussianConditionalOrdered::shared_ptr cond1(new GaussianConditionalOrdered(3, d1, R1, cterms1, ones(2)));
|
||||
|
||||
// Expected conditional on second variable from next 2 rows of R
|
||||
Matrix R2 = sub(R, 2,4, 2,4);
|
||||
list<pair<Index, Matrix> > cterms2;
|
||||
cterms2 +=
|
||||
make_pair(7, sub(R, 2,4, 4,6)),
|
||||
make_pair(9, sub(R, 2,4, 6,8)),
|
||||
make_pair(11,sub(R, 2,4, 8,10));
|
||||
Vector d2 = R.col(10).segment(2,2);
|
||||
GaussianConditionalOrdered::shared_ptr cond2(new GaussianConditionalOrdered(5, d2, R2, cterms2, ones(2)));
|
||||
|
||||
// Expected conditional on third variable from next 2 rows of R
|
||||
Matrix R3 = sub(R, 4,6, 4,6);
|
||||
list<pair<Index, Matrix> > cterms3;
|
||||
cterms3 +=
|
||||
make_pair(9, sub(R, 4,6, 6,8)),
|
||||
make_pair(11, sub(R, 4,6, 8,10));
|
||||
Vector d3 = R.col(10).segment(4,2);
|
||||
GaussianConditionalOrdered::shared_ptr cond3(new GaussianConditionalOrdered(7, d3, R3, cterms3, ones(2)));
|
||||
|
||||
// Create expected Bayes net fragment from three conditionals above
|
||||
// GaussianBayesNetOrdered expectedFragment;
|
||||
// expectedFragment.push_back(cond1);
|
||||
// expectedFragment.push_back(cond2);
|
||||
// expectedFragment.push_back(cond3);
|
||||
Index ikeys[] = {3,5,7,9,11};
|
||||
std::vector<Index> keys(ikeys, ikeys + sizeof(ikeys)/sizeof(Index));
|
||||
size_t dims[] = { 2,2,2,2,2,1 };
|
||||
size_t height = 11;
|
||||
VerticalBlockView<Matrix> Rblock(R, dims, dims+6, height);
|
||||
GaussianConditionalOrdered::shared_ptr expectedFragment( new GaussianConditionalOrdered(keys.begin(), keys.end(), 3,
|
||||
Rblock, ones(6)) );
|
||||
|
||||
// Get expected matrices for remaining factor
|
||||
Matrix Ae1 = sub(R, 6,10, 6,8);
|
||||
Matrix Ae2 = sub(R, 6,10, 8,10);
|
||||
Vector be = R.col(10).segment(6, 4);
|
||||
|
||||
// Eliminate (3 frontal variables, 6 scalar columns) using QR !!!!
|
||||
GaussianConditionalOrdered::shared_ptr actualFragment_QR = actualFactor_QR.eliminate(3);
|
||||
|
||||
EXPECT(assert_equal(*expectedFragment, *actualFragment_QR, 0.001));
|
||||
EXPECT(assert_equal(size_t(2), actualFactor_QR.keys().size()));
|
||||
EXPECT(assert_equal(Index(9), actualFactor_QR.keys()[0]));
|
||||
EXPECT(assert_equal(Index(11), actualFactor_QR.keys()[1]));
|
||||
EXPECT(assert_equal(Ae1, actualFactor_QR.getA(actualFactor_QR.begin()), 0.001));
|
||||
EXPECT(assert_equal(Ae2, actualFactor_QR.getA(actualFactor_QR.begin()+1), 0.001));
|
||||
EXPECT(assert_equal(be, actualFactor_QR.getb(), 0.001));
|
||||
EXPECT(assert_equal(ones(4), actualFactor_QR.get_model()->sigmas(), 0.001));
|
||||
|
||||
// Eliminate (3 frontal variables, 6 scalar columns) using Cholesky !!!!
|
||||
#ifdef BROKEN
|
||||
GaussianBayesNetOrdered actualFragment_Chol = *actualFactor_Chol.eliminate(3, JacobianFactorOrdered::SOLVE_CHOLESKY);
|
||||
EXPECT(assert_equal(expectedFragment, actualFragment_Chol, 0.001));
|
||||
EXPECT(assert_equal(size_t(2), actualFactor_Chol.keys().size()));
|
||||
EXPECT(assert_equal(Index(9), actualFactor_Chol.keys()[0]));
|
||||
EXPECT(assert_equal(Index(11), actualFactor_Chol.keys()[1]));
|
||||
EXPECT(assert_equal(Ae1, actualFactor_Chol.getA(actualFactor_Chol.begin()), 0.001)); ////
|
||||
EXPECT(linear_dependent(Ae2, actualFactor_Chol.getA(actualFactor_Chol.begin()+1), 0.001));
|
||||
EXPECT(assert_equal(be, actualFactor_Chol.getb(), 0.001)); ////
|
||||
EXPECT(assert_equal(ones(4), actualFactor_Chol.get_sigmas(), 0.001));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorOrdered, permuteWithInverse)
|
||||
{
|
||||
Matrix A1 = Matrix_(2,2,
|
||||
1.0, 2.0,
|
||||
3.0, 4.0);
|
||||
Matrix A2 = Matrix_(2,1,
|
||||
5.0,
|
||||
6.0);
|
||||
Matrix A3 = Matrix_(2,3,
|
||||
7.0, 8.0, 9.0,
|
||||
10.0, 11.0, 12.0);
|
||||
Vector b = Vector_(2, 13.0, 14.0);
|
||||
|
||||
Permutation inversePermutation(6);
|
||||
inversePermutation[0] = 5;
|
||||
inversePermutation[1] = 4;
|
||||
inversePermutation[2] = 3;
|
||||
inversePermutation[3] = 2;
|
||||
inversePermutation[4] = 1;
|
||||
inversePermutation[5] = 0;
|
||||
|
||||
JacobianFactorOrdered actual(1, A1, 3, A2, 5, A3, b, noiseModel::Isotropic::Sigma(2, 1.0));
|
||||
GaussianFactorGraphOrdered actualFG; actualFG.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(actual)));
|
||||
VariableIndexOrdered actualIndex(actualFG);
|
||||
actual.permuteWithInverse(inversePermutation);
|
||||
// actualIndex.permute(*inversePermutation.inverse());
|
||||
|
||||
JacobianFactorOrdered expected(4, A1, 2, A2, 0, A3, b, noiseModel::Isotropic::Sigma(2, 1.0));
|
||||
GaussianFactorGraphOrdered expectedFG; expectedFG.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(expected)));
|
||||
// GaussianVariableIndex expectedIndex(expectedFG);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorGraphOrdered, sparseJacobian) {
|
||||
// Create factor graph:
|
||||
// x1 x2 x3 x4 x5 b
|
||||
// 1 2 3 0 0 4
|
||||
// 5 6 7 0 0 8
|
||||
// 9 10 0 11 12 13
|
||||
// 0 0 0 14 15 16
|
||||
|
||||
// Expected - NOTE that we transpose this!
|
||||
Matrix expected = Matrix_(16,3,
|
||||
1., 1., 2.,
|
||||
1., 2., 4.,
|
||||
1., 3., 6.,
|
||||
2., 1.,10.,
|
||||
2., 2.,12.,
|
||||
2., 3.,14.,
|
||||
1., 6., 8.,
|
||||
2., 6.,16.,
|
||||
3., 1.,18.,
|
||||
3., 2.,20.,
|
||||
3., 4.,22.,
|
||||
3., 5.,24.,
|
||||
4., 4.,28.,
|
||||
4., 5.,30.,
|
||||
3., 6.,26.,
|
||||
4., 6.,32.).transpose();
|
||||
|
||||
GaussianFactorGraphOrdered gfg;
|
||||
SharedDiagonal model = noiseModel::Isotropic::Sigma(2, 0.5);
|
||||
gfg.add(0, Matrix_(2,3, 1., 2., 3., 5., 6., 7.), Vector_(2, 4., 8.), model);
|
||||
gfg.add(0, Matrix_(2,3, 9.,10., 0., 0., 0., 0.), 1, Matrix_(2,2, 11., 12., 14., 15.), Vector_(2, 13.,16.), model);
|
||||
|
||||
Matrix actual = gfg.sparseJacobian_();
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorGraphOrdered, matrices) {
|
||||
// Create factor graph:
|
||||
// x1 x2 x3 x4 x5 b
|
||||
// 1 2 3 0 0 4
|
||||
// 5 6 7 0 0 8
|
||||
// 9 10 0 11 12 13
|
||||
// 0 0 0 14 15 16
|
||||
|
||||
GaussianFactorGraphOrdered gfg;
|
||||
SharedDiagonal model = noiseModel::Unit::Create(2);
|
||||
gfg.add(0, Matrix_(2,3, 1., 2., 3., 5., 6., 7.), Vector_(2, 4., 8.), model);
|
||||
gfg.add(0, Matrix_(2,3, 9.,10., 0., 0., 0., 0.), 1, Matrix_(2,2, 11., 12., 14., 15.), Vector_(2, 13.,16.), model);
|
||||
|
||||
Matrix jacobian(4,6);
|
||||
jacobian <<
|
||||
1, 2, 3, 0, 0, 4,
|
||||
5, 6, 7, 0, 0, 8,
|
||||
9,10, 0,11,12,13,
|
||||
0, 0, 0,14,15,16;
|
||||
|
||||
Matrix expectedJacobian = jacobian;
|
||||
Matrix expectedHessian = jacobian.transpose() * jacobian;
|
||||
Matrix expectedA = jacobian.leftCols(jacobian.cols()-1);
|
||||
Vector expectedb = jacobian.col(jacobian.cols()-1);
|
||||
Matrix expectedL = expectedA.transpose() * expectedA;
|
||||
Vector expectedeta = expectedA.transpose() * expectedb;
|
||||
|
||||
Matrix actualJacobian = gfg.augmentedJacobian();
|
||||
Matrix actualHessian = gfg.augmentedHessian();
|
||||
Matrix actualA; Vector actualb; boost::tie(actualA,actualb) = gfg.jacobian();
|
||||
Matrix actualL; Vector actualeta; boost::tie(actualL,actualeta) = gfg.hessian();
|
||||
|
||||
EXPECT(assert_equal(expectedJacobian, actualJacobian));
|
||||
EXPECT(assert_equal(expectedHessian, actualHessian));
|
||||
EXPECT(assert_equal(expectedA, actualA));
|
||||
EXPECT(assert_equal(expectedb, actualb));
|
||||
EXPECT(assert_equal(expectedL, actualL));
|
||||
EXPECT(assert_equal(expectedeta, actualeta));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorGraphOrdered, gradient )
|
||||
{
|
||||
GaussianFactorGraphOrdered fg = createSimpleGaussianFactorGraph();
|
||||
|
||||
// Construct expected gradient
|
||||
VectorValuesOrdered expected;
|
||||
|
||||
// 2*f(x) = 100*(x1+c[X(1)])^2 + 100*(x2-x1-[0.2;-0.1])^2 + 25*(l1-x1-[0.0;0.2])^2 + 25*(l1-x2-[-0.2;0.3])^2
|
||||
// worked out: df/dx1 = 100*[0.1;0.1] + 100*[0.2;-0.1]) + 25*[0.0;0.2] = [10+20;10-10+5] = [30;5]
|
||||
expected.insert(1,Vector_(2, 5.0,-12.5));
|
||||
expected.insert(2,Vector_(2, 30.0, 5.0));
|
||||
expected.insert(0,Vector_(2,-25.0, 17.5));
|
||||
|
||||
// Check the gradient at delta=0
|
||||
VectorValuesOrdered zero = VectorValuesOrdered::Zero(expected);
|
||||
VectorValuesOrdered actual = gradient(fg, zero);
|
||||
EXPECT(assert_equal(expected,actual));
|
||||
|
||||
// Check the gradient at the solution (should be zero)
|
||||
VectorValuesOrdered solution = *GaussianSequentialSolver(fg).optimize();
|
||||
VectorValuesOrdered actual2 = gradient(fg, solution);
|
||||
EXPECT(assert_equal(VectorValuesOrdered::Zero(solution), actual2));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorGraphOrdered, transposeMultiplication )
|
||||
{
|
||||
GaussianFactorGraphOrdered A = createSimpleGaussianFactorGraph();
|
||||
|
||||
VectorValuesOrdered e;
|
||||
e.insert(0, Vector_(2, 0.0, 0.0));
|
||||
e.insert(1, Vector_(2,15.0, 0.0));
|
||||
e.insert(2, Vector_(2, 0.0,-5.0));
|
||||
e.insert(3, Vector_(2,-7.5,-5.0));
|
||||
|
||||
VectorValuesOrdered expected;
|
||||
expected.insert(1, Vector_(2, -37.5,-50.0));
|
||||
expected.insert(2, Vector_(2,-150.0, 25.0));
|
||||
expected.insert(0, Vector_(2, 187.5, 25.0));
|
||||
|
||||
VectorValuesOrdered actual = VectorValuesOrdered::SameStructure(expected);
|
||||
transposeMultiply(A, e, actual);
|
||||
EXPECT(assert_equal(expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianFactorGraphOrdered, eliminate_empty )
|
||||
{
|
||||
// eliminate an empty factor
|
||||
GaussianFactorGraphOrdered gfg;
|
||||
gfg.push_back(boost::make_shared<JacobianFactorOrdered>());
|
||||
GaussianConditionalOrdered::shared_ptr actualCG;
|
||||
GaussianFactorGraphOrdered remainingGFG;
|
||||
boost::tie(actualCG, remainingGFG) = gfg.eliminateOne(0);
|
||||
|
||||
// expected Conditional Gaussian is just a parent-less node with P(x)=1
|
||||
GaussianConditionalOrdered expectedCG(0, Vector(), Matrix(), Vector());
|
||||
|
||||
// expected remaining graph should be the same as the original, still empty :-)
|
||||
GaussianFactorGraphOrdered expectedLF = gfg;
|
||||
|
||||
// check if the result matches
|
||||
EXPECT(actualCG->equals(expectedCG));
|
||||
EXPECT(remainingGFG.equals(expectedLF));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,309 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testGaussianJunctionTree.cpp
|
||||
* @date Jul 8, 2010
|
||||
* @author Kai Ni
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
#include <boost/assign/std/set.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/geometry/Rot2.h>
|
||||
#include <gtsam/linear/GaussianJunctionTreeOrdered.h>
|
||||
#include <gtsam/linear/GaussianSequentialSolver.h>
|
||||
#include <gtsam/linear/GaussianMultifrontalSolver.h>
|
||||
#include <gtsam/inference/BayesTreeOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
static const Index x2=0, x1=1, x3=2, x4=3;
|
||||
|
||||
static GaussianFactorGraphOrdered createChain() {
|
||||
|
||||
typedef GaussianFactorGraphOrdered::sharedFactor Factor;
|
||||
SharedDiagonal model = noiseModel::Isotropic::Sigma(1, 0.5);
|
||||
Factor factor1(new JacobianFactorOrdered(x2, Matrix_(1,1,1.), x1, Matrix_(1,1,1.), Vector_(1,1.), model));
|
||||
Factor factor2(new JacobianFactorOrdered(x2, Matrix_(1,1,1.), x3, Matrix_(1,1,1.), Vector_(1,1.), model));
|
||||
Factor factor3(new JacobianFactorOrdered(x3, Matrix_(1,1,1.), x4, Matrix_(1,1,1.), Vector_(1,1.), model));
|
||||
Factor factor4(new JacobianFactorOrdered(x4, Matrix_(1,1,1.), Vector_(1,1.), model));
|
||||
|
||||
GaussianFactorGraphOrdered fg;
|
||||
fg.push_back(factor1);
|
||||
fg.push_back(factor2);
|
||||
fg.push_back(factor3);
|
||||
fg.push_back(factor4);
|
||||
|
||||
return fg;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
/**
|
||||
* x1 - x2 - x3 - x4
|
||||
* x3 x4
|
||||
* x2 x1 : x3
|
||||
*
|
||||
* x2 x1 x3 x4 b
|
||||
* 1 1 1
|
||||
* 1 1 1
|
||||
* 1 1 1
|
||||
* 1 1
|
||||
*
|
||||
* 1 0 0 1
|
||||
*/
|
||||
TEST( GaussianJunctionTreeOrdered, eliminate )
|
||||
{
|
||||
GaussianFactorGraphOrdered fg = createChain();
|
||||
GaussianJunctionTreeOrdered junctionTree(fg);
|
||||
BayesTreeOrdered<GaussianConditionalOrdered>::sharedClique rootClique = junctionTree.eliminate(&EliminateQROrdered);
|
||||
|
||||
typedef BayesTreeOrdered<GaussianConditionalOrdered>::sharedConditional sharedConditional;
|
||||
Matrix two = Matrix_(1,1,2.);
|
||||
Matrix one = Matrix_(1,1,1.);
|
||||
|
||||
BayesTreeOrdered<GaussianConditionalOrdered> bayesTree_expected;
|
||||
Index keys_root[] = {x3,x4};
|
||||
Matrix rsd_root = Matrix_(2,3, 2., 2., 2., 0., 2., 2.);
|
||||
size_t dim_root[] = {1, 1, 1};
|
||||
sharedConditional root_expected(new GaussianConditionalOrdered(keys_root, keys_root+2, 2,
|
||||
VerticalBlockView<Matrix>(rsd_root, dim_root, dim_root+3, 2), ones(2)));
|
||||
BayesTreeOrdered<GaussianConditionalOrdered>::sharedClique rootClique_expected(new BayesTreeOrdered<GaussianConditionalOrdered>::Clique(root_expected));
|
||||
|
||||
Index keys_child[] = {x2,x1,x3};
|
||||
Matrix rsd_child = Matrix_(2,4, 2., 1., 1., 2., 0., -1., 1., 0.);
|
||||
size_t dim_child[] = {1, 1, 1, 1};
|
||||
sharedConditional child_expected(new GaussianConditionalOrdered(keys_child, keys_child+3, 2,
|
||||
VerticalBlockView<Matrix>(rsd_child, dim_child, dim_child+4, 2), ones(2)));
|
||||
BayesTreeOrdered<GaussianConditionalOrdered>::sharedClique childClique_expected(new BayesTreeOrdered<GaussianConditionalOrdered>::Clique(child_expected));
|
||||
|
||||
bayesTree_expected.insert(rootClique_expected);
|
||||
bayesTree_expected.insert(childClique_expected);
|
||||
|
||||
// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x4, Vector_(1,2.), two, Vector_(1,1.))));
|
||||
// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x3, Vector_(1,2.), two, x4, two, Vector_(1,1.))));
|
||||
// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x1, Vector_(1,0.), one*(-1), x3, one, Vector_(1,1.))));
|
||||
// bayesTree_expected.insert(sharedConditional(new GaussianConditionalOrdered(x2, Vector_(1,2.), two, x1, one, x3, one, Vector_(1,1.))));
|
||||
CHECK(assert_equal(*bayesTree_expected.root(), *rootClique));
|
||||
EXPECT(assert_equal(*(bayesTree_expected.root()->children().front()), *(rootClique->children().front())));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianJunctionTreeOrdered, GBNConstructor )
|
||||
{
|
||||
GaussianFactorGraphOrdered fg = createChain();
|
||||
GaussianJunctionTreeOrdered jt(fg);
|
||||
BayesTreeOrdered<GaussianConditionalOrdered>::sharedClique root = jt.eliminate(&EliminateQROrdered);
|
||||
BayesTreeOrdered<GaussianConditionalOrdered> expected;
|
||||
expected.insert(root);
|
||||
|
||||
GaussianBayesNetOrdered bn(*GaussianSequentialSolver(fg).eliminate());
|
||||
BayesTreeOrdered<GaussianConditionalOrdered> actual(bn);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianJunctionTreeOrdered, optimizeMultiFrontal )
|
||||
{
|
||||
GaussianFactorGraphOrdered fg = createChain();
|
||||
GaussianJunctionTreeOrdered tree(fg);
|
||||
|
||||
VectorValuesOrdered actual = tree.optimize(&EliminateQROrdered);
|
||||
VectorValuesOrdered expected(vector<size_t>(4,1));
|
||||
expected[x1] = Vector_(1, 0.);
|
||||
expected[x2] = Vector_(1, 1.);
|
||||
expected[x3] = Vector_(1, 0.);
|
||||
expected[x4] = Vector_(1, 1.);
|
||||
EXPECT(assert_equal(expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(GaussianJunctionTreeOrdered, complicatedMarginal) {
|
||||
|
||||
// Create the conditionals to go in the BayesTree
|
||||
GaussianConditionalOrdered::shared_ptr R_1_2(new GaussianConditionalOrdered(
|
||||
pair_list_of
|
||||
(1, (Matrix(3,1) <<
|
||||
0.2630,
|
||||
0,
|
||||
0).finished())
|
||||
(2, (Matrix(3,2) <<
|
||||
0.7482, 0.2290,
|
||||
0.4505, 0.9133,
|
||||
0, 0.1524).finished())
|
||||
(5, (Matrix(3,1) <<
|
||||
0.8258,
|
||||
0.5383,
|
||||
0.9961).finished()),
|
||||
2, (Vector(3) << 0.0782, 0.4427, 0.1067).finished(), ones(3)));
|
||||
GaussianConditionalOrdered::shared_ptr R_3_4(new GaussianConditionalOrdered(
|
||||
pair_list_of
|
||||
(3, (Matrix(3,1) <<
|
||||
0.0540,
|
||||
0,
|
||||
0).finished())
|
||||
(4, (Matrix(3,2) <<
|
||||
0.9340, 0.4694,
|
||||
0.1299, 0.0119,
|
||||
0, 0.3371).finished())
|
||||
(6, (Matrix(3,2) <<
|
||||
0.1622, 0.5285,
|
||||
0.7943, 0.1656,
|
||||
0.3112, 0.6020).finished()),
|
||||
2, (Vector(3) << 0.9619, 0.0046, 0.7749).finished(), ones(3)));
|
||||
// GaussianConditionalOrdered::shared_ptr R_5_6(new GaussianConditionalOrdered(
|
||||
// pair_list_of
|
||||
// (5, (Matrix(3,1) <<
|
||||
// 0.2435,
|
||||
// 0,
|
||||
// 0).finished())
|
||||
// (6, (Matrix(3,2) <<
|
||||
// 0.4733, 0.1966,
|
||||
// 0.9022, 0.0979,
|
||||
// 0.0, 0.2312).finished()) // Attempted to recreate without permutation
|
||||
// (7, (Matrix(3,1) <<
|
||||
// 0.5853,
|
||||
// 1.0589,
|
||||
// 0.1487).finished())
|
||||
// (8, (Matrix(3,2) <<
|
||||
// 0.2858, 0.3804,
|
||||
// 0.9893, 0.2912,
|
||||
// 0.4035, 0.4933).finished()),
|
||||
// 2, (Vector(3) << 0.8173, 0.4164, 0.7671).finished(), ones(3)));
|
||||
GaussianConditionalOrdered::shared_ptr R_5_6(new GaussianConditionalOrdered(
|
||||
pair_list_of
|
||||
(5, (Matrix(3,1) <<
|
||||
0.2435,
|
||||
0,
|
||||
0).finished())
|
||||
(6, (Matrix(3,2) <<
|
||||
0.4733, 0.1966,
|
||||
0.3517, 0.2511,
|
||||
0.8308, 0.0).finished()) // NOTE the non-upper-triangular form
|
||||
// here since this test was written when we had column permutations
|
||||
// from LDL. The code still works currently (does not enfore
|
||||
// upper-triangularity in this case) but this test will need to be
|
||||
// redone if this stops working in the future
|
||||
(7, (Matrix(3,1) <<
|
||||
0.5853,
|
||||
0.5497,
|
||||
0.9172).finished())
|
||||
(8, (Matrix(3,2) <<
|
||||
0.2858, 0.3804,
|
||||
0.7572, 0.5678,
|
||||
0.7537, 0.0759).finished()),
|
||||
2, (Vector(3) << 0.8173, 0.8687, 0.0844).finished(), ones(3)));
|
||||
GaussianConditionalOrdered::shared_ptr R_7_8(new GaussianConditionalOrdered(
|
||||
pair_list_of
|
||||
(7, (Matrix(3,1) <<
|
||||
0.2551,
|
||||
0,
|
||||
0).finished())
|
||||
(8, (Matrix(3,2) <<
|
||||
0.8909, 0.1386,
|
||||
0.9593, 0.1493,
|
||||
0, 0.2575).finished())
|
||||
(11, (Matrix(3,1) <<
|
||||
0.8407,
|
||||
0.2543,
|
||||
0.8143).finished()),
|
||||
2, (Vector(3) << 0.3998, 0.2599, 0.8001).finished(), ones(3)));
|
||||
GaussianConditionalOrdered::shared_ptr R_9_10(new GaussianConditionalOrdered(
|
||||
pair_list_of
|
||||
(9, (Matrix(3,1) <<
|
||||
0.7952,
|
||||
0,
|
||||
0).finished())
|
||||
(10, (Matrix(3,2) <<
|
||||
0.4456, 0.7547,
|
||||
0.6463, 0.2760,
|
||||
0, 0.6797).finished())
|
||||
(11, (Matrix(3,1) <<
|
||||
0.6551,
|
||||
0.1626,
|
||||
0.1190).finished())
|
||||
(12, (Matrix(3,2) <<
|
||||
0.4984, 0.5853,
|
||||
0.9597, 0.2238,
|
||||
0.3404, 0.7513).finished()),
|
||||
2, (Vector(3) << 0.4314, 0.9106, 0.1818).finished(), ones(3)));
|
||||
GaussianConditionalOrdered::shared_ptr R_11_12(new GaussianConditionalOrdered(
|
||||
pair_list_of
|
||||
(11, (Matrix(3,1) <<
|
||||
0.0971,
|
||||
0,
|
||||
0).finished())
|
||||
(12, (Matrix(3,2) <<
|
||||
0.3171, 0.4387,
|
||||
0.9502, 0.3816,
|
||||
0, 0.7655).finished()),
|
||||
2, (Vector(3) << 0.2638, 0.1455, 0.1361).finished(), ones(3)));
|
||||
|
||||
// Gaussian Bayes Tree
|
||||
typedef BayesTreeOrdered<GaussianConditionalOrdered> GaussianBayesTree;
|
||||
typedef GaussianBayesTree::Clique Clique;
|
||||
typedef GaussianBayesTree::sharedClique sharedClique;
|
||||
|
||||
// Create Bayes Tree
|
||||
GaussianBayesTree bt;
|
||||
bt.insert(sharedClique(new Clique(R_11_12)));
|
||||
bt.insert(sharedClique(new Clique(R_9_10)));
|
||||
bt.insert(sharedClique(new Clique(R_7_8)));
|
||||
bt.insert(sharedClique(new Clique(R_5_6)));
|
||||
bt.insert(sharedClique(new Clique(R_3_4)));
|
||||
bt.insert(sharedClique(new Clique(R_1_2)));
|
||||
|
||||
// Marginal on 5
|
||||
Matrix expectedCov = (Matrix(1,1) << 236.5166).finished();
|
||||
JacobianFactorOrdered::shared_ptr actualJacobianChol= boost::dynamic_pointer_cast<JacobianFactorOrdered>(
|
||||
bt.marginalFactor(5, EliminateCholeskyOrdered));
|
||||
JacobianFactorOrdered::shared_ptr actualJacobianQR = boost::dynamic_pointer_cast<JacobianFactorOrdered>(
|
||||
bt.marginalFactor(5, EliminateQROrdered));
|
||||
CHECK(assert_equal(*actualJacobianChol, *actualJacobianQR)); // Check that Chol and QR obtained marginals are the same
|
||||
LONGS_EQUAL(1, actualJacobianChol->rows());
|
||||
LONGS_EQUAL(1, actualJacobianChol->size());
|
||||
LONGS_EQUAL(5, actualJacobianChol->keys()[0]);
|
||||
Matrix actualA = actualJacobianChol->getA(actualJacobianChol->begin());
|
||||
Matrix actualCov = inverse(actualA.transpose() * actualA);
|
||||
EXPECT(assert_equal(expectedCov, actualCov, 1e-1));
|
||||
|
||||
// Marginal on 6
|
||||
// expectedCov = (Matrix(2,2) <<
|
||||
// 8471.2, 2886.2,
|
||||
// 2886.2, 1015.8).finished();
|
||||
expectedCov = (Matrix(2,2) <<
|
||||
1015.8, 2886.2,
|
||||
2886.2, 8471.2).finished();
|
||||
actualJacobianChol = boost::dynamic_pointer_cast<JacobianFactorOrdered>(
|
||||
bt.marginalFactor(6, EliminateCholeskyOrdered));
|
||||
actualJacobianQR = boost::dynamic_pointer_cast<JacobianFactorOrdered>(
|
||||
bt.marginalFactor(6, EliminateQROrdered));
|
||||
CHECK(assert_equal(*actualJacobianChol, *actualJacobianQR)); // Check that Chol and QR obtained marginals are the same
|
||||
LONGS_EQUAL(2, actualJacobianChol->rows());
|
||||
LONGS_EQUAL(1, actualJacobianChol->size());
|
||||
LONGS_EQUAL(6, actualJacobianChol->keys()[0]);
|
||||
actualA = actualJacobianChol->getA(actualJacobianChol->begin());
|
||||
actualCov = inverse(actualA.transpose() * actualA);
|
||||
EXPECT(assert_equal(expectedCov, actualCov, 1e1));
|
||||
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,635 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testCholeskyFactor.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Dec 15, 2010
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/assign/std/map.hpp>
|
||||
|
||||
#include <gtsam/base/debug.h>
|
||||
#include <gtsam/linear/HessianFactorOrdered.h>
|
||||
#include <gtsam/linear/JacobianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::assign;
|
||||
using namespace gtsam;
|
||||
|
||||
const double tol = 1e-5;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, emptyConstructor) {
|
||||
HessianFactorOrdered f;
|
||||
DOUBLES_EQUAL(0.0, f.constantTerm(), 1e-9); // Constant term should be zero
|
||||
EXPECT(assert_equal(Vector(), f.linearTerm())); // Linear term should be empty
|
||||
EXPECT(assert_equal(zeros(1,1), f.info())); // Full matrix should be 1-by-1 zero matrix
|
||||
DOUBLES_EQUAL(0.0, f.error(VectorValuesOrdered()), 1e-9); // Should have zero error
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, ConversionConstructor) {
|
||||
|
||||
HessianFactorOrdered expected;
|
||||
expected.keys_.push_back(0);
|
||||
expected.keys_.push_back(1);
|
||||
size_t dims[] = { 2, 4, 1 };
|
||||
expected.info_.resize(dims, dims+3, false);
|
||||
expected.matrix_ = Matrix_(7,7,
|
||||
125.0000, 0.0, -25.0000, 0.0, -100.0000, 0.0, 25.0000,
|
||||
0.0, 125.0000, 0.0, -25.0000, 0.0, -100.0000, -17.5000,
|
||||
-25.0000, 0.0, 25.0000, 0.0, 0.0, 0.0, -5.0000,
|
||||
0.0, -25.0000, 0.0, 25.0000, 0.0, 0.0, 7.5000,
|
||||
-100.0000, 0.0, 0.0, 0.0, 100.0000, 0.0, -20.0000,
|
||||
0.0, -100.0000, 0.0, 0.0, 0.0, 100.0000, 10.0000,
|
||||
25.0000, -17.5000, -5.0000, 7.5000, -20.0000, 10.0000, 8.2500);
|
||||
|
||||
// sigmas
|
||||
double sigma1 = 0.2;
|
||||
double sigma2 = 0.1;
|
||||
Vector sigmas = Vector_(4, sigma1, sigma1, sigma2, sigma2);
|
||||
|
||||
// the combined linear factor
|
||||
Matrix Ax2 = Matrix_(4,2,
|
||||
// x2
|
||||
-1., 0.,
|
||||
+0.,-1.,
|
||||
1., 0.,
|
||||
+0.,1.
|
||||
);
|
||||
|
||||
Matrix Al1x1 = Matrix_(4,4,
|
||||
// l1 x1
|
||||
1., 0., 0.00, 0., // f4
|
||||
0., 1., 0.00, 0., // f4
|
||||
0., 0., -1., 0., // f2
|
||||
0., 0., 0.00,-1. // f2
|
||||
);
|
||||
|
||||
// the RHS
|
||||
Vector b2(4);
|
||||
b2(0) = -0.2;
|
||||
b2(1) = 0.3;
|
||||
b2(2) = 0.2;
|
||||
b2(3) = -0.1;
|
||||
|
||||
vector<pair<Index, Matrix> > meas;
|
||||
meas.push_back(make_pair(0, Ax2));
|
||||
meas.push_back(make_pair(1, Al1x1));
|
||||
JacobianFactorOrdered combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas));
|
||||
|
||||
HessianFactorOrdered actual(combined);
|
||||
|
||||
VectorValuesOrdered values(std::vector<size_t>(dims, dims+2));
|
||||
values[0] = Vector_(2, 1.0, 2.0);
|
||||
values[1] = Vector_(4, 3.0, 4.0, 5.0, 6.0);
|
||||
|
||||
EXPECT_LONGS_EQUAL(2, actual.size());
|
||||
|
||||
EXPECT(assert_equal(expected, actual, 1e-9));
|
||||
|
||||
// error terms
|
||||
EXPECT_DOUBLES_EQUAL(combined.error(values), actual.error(values), 1e-9);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, Constructor1)
|
||||
{
|
||||
Matrix G = Matrix_(2,2, 3.0, 5.0, 0.0, 6.0);
|
||||
Vector g = Vector_(2, -8.0, -9.0);
|
||||
double f = 10.0;
|
||||
|
||||
Vector dxv = Vector_(2, 1.5, 2.5);
|
||||
|
||||
vector<size_t> dims;
|
||||
dims.push_back(2);
|
||||
VectorValuesOrdered dx(dims);
|
||||
|
||||
dx[0] = dxv;
|
||||
|
||||
HessianFactorOrdered factor(0, G, g, f);
|
||||
|
||||
// extract underlying parts
|
||||
Matrix info_matrix = factor.info_.range(0, 1, 0, 1);
|
||||
EXPECT(assert_equal(Matrix(G), info_matrix));
|
||||
EXPECT_DOUBLES_EQUAL(f, factor.constantTerm(), 1e-10);
|
||||
EXPECT(assert_equal(g, Vector(factor.linearTerm()), 1e-10));
|
||||
EXPECT_LONGS_EQUAL(1, factor.size());
|
||||
|
||||
// error 0.5*(f - 2*x'*g + x'*G*x)
|
||||
double expected = 80.375;
|
||||
double actual = factor.error(dx);
|
||||
double expected_manual = 0.5 * (f - 2.0 * dxv.dot(g) + dxv.transpose() * G.selfadjointView<Eigen::Upper>() * dxv);
|
||||
EXPECT_DOUBLES_EQUAL(expected, expected_manual, 1e-10);
|
||||
DOUBLES_EQUAL(expected, actual, 1e-10);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, Constructor1b)
|
||||
{
|
||||
Vector mu = Vector_(2,1.0,2.0);
|
||||
Matrix Sigma = eye(2,2);
|
||||
|
||||
HessianFactorOrdered factor(0, mu, Sigma);
|
||||
|
||||
Matrix G = eye(2,2);
|
||||
Vector g = G*mu;
|
||||
double f = dot(g,mu);
|
||||
|
||||
// Check
|
||||
Matrix info_matrix = factor.info_.range(0, 1, 0, 1);
|
||||
EXPECT(assert_equal(Matrix(G), info_matrix));
|
||||
EXPECT_DOUBLES_EQUAL(f, factor.constantTerm(), 1e-10);
|
||||
EXPECT(assert_equal(g, Vector(factor.linearTerm()), 1e-10));
|
||||
EXPECT_LONGS_EQUAL(1, factor.size());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, Constructor2)
|
||||
{
|
||||
Matrix G11 = Matrix_(1,1, 1.0);
|
||||
Matrix G12 = Matrix_(1,2, 2.0, 4.0);
|
||||
Matrix G22 = Matrix_(2,2, 3.0, 5.0, 0.0, 6.0);
|
||||
Vector g1 = Vector_(1, -7.0);
|
||||
Vector g2 = Vector_(2, -8.0, -9.0);
|
||||
double f = 10.0;
|
||||
|
||||
Vector dx0 = Vector_(1, 0.5);
|
||||
Vector dx1 = Vector_(2, 1.5, 2.5);
|
||||
|
||||
vector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
dims.push_back(2);
|
||||
VectorValuesOrdered dx(dims);
|
||||
|
||||
dx[0] = dx0;
|
||||
dx[1] = dx1;
|
||||
|
||||
HessianFactorOrdered factor(0, 1, G11, G12, g1, G22, g2, f);
|
||||
|
||||
double expected = 90.5;
|
||||
double actual = factor.error(dx);
|
||||
|
||||
DOUBLES_EQUAL(expected, actual, 1e-10);
|
||||
LONGS_EQUAL(4, factor.rows());
|
||||
DOUBLES_EQUAL(10.0, factor.constantTerm(), 1e-10);
|
||||
|
||||
Vector linearExpected(3); linearExpected << g1, g2;
|
||||
EXPECT(assert_equal(linearExpected, factor.linearTerm()));
|
||||
|
||||
EXPECT(assert_equal(G11, factor.info(factor.begin(), factor.begin())));
|
||||
EXPECT(assert_equal(G12, factor.info(factor.begin(), factor.begin()+1)));
|
||||
EXPECT(assert_equal(G22, factor.info(factor.begin()+1, factor.begin()+1)));
|
||||
|
||||
// Check case when vector values is larger than factor
|
||||
dims.push_back(2);
|
||||
VectorValuesOrdered dxLarge(dims);
|
||||
dxLarge[0] = dx0;
|
||||
dxLarge[1] = dx1;
|
||||
dxLarge[2] = Vector_(2, 0.1, 0.2);
|
||||
EXPECT_DOUBLES_EQUAL(expected, factor.error(dxLarge), 1e-10);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, Constructor3)
|
||||
{
|
||||
Matrix G11 = Matrix_(1,1, 1.0);
|
||||
Matrix G12 = Matrix_(1,2, 2.0, 4.0);
|
||||
Matrix G13 = Matrix_(1,3, 3.0, 6.0, 9.0);
|
||||
|
||||
Matrix G22 = Matrix_(2,2, 3.0, 5.0, 0.0, 6.0);
|
||||
Matrix G23 = Matrix_(2,3, 4.0, 6.0, 8.0, 1.0, 2.0, 4.0);
|
||||
|
||||
Matrix G33 = Matrix_(3,3, 1.0, 2.0, 3.0, 0.0, 5.0, 6.0, 0.0, 0.0, 9.0);
|
||||
|
||||
Vector g1 = Vector_(1, -7.0);
|
||||
Vector g2 = Vector_(2, -8.0, -9.0);
|
||||
Vector g3 = Vector_(3, 1.0, 2.0, 3.0);
|
||||
|
||||
double f = 10.0;
|
||||
|
||||
Vector dx0 = Vector_(1, 0.5);
|
||||
Vector dx1 = Vector_(2, 1.5, 2.5);
|
||||
Vector dx2 = Vector_(3, 1.5, 2.5, 3.5);
|
||||
|
||||
vector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
dims.push_back(2);
|
||||
dims.push_back(3);
|
||||
VectorValuesOrdered dx(dims);
|
||||
|
||||
dx[0] = dx0;
|
||||
dx[1] = dx1;
|
||||
dx[2] = dx2;
|
||||
|
||||
HessianFactorOrdered factor(0, 1, 2, G11, G12, G13, g1, G22, G23, g2, G33, g3, f);
|
||||
|
||||
double expected = 371.3750;
|
||||
double actual = factor.error(dx);
|
||||
|
||||
DOUBLES_EQUAL(expected, actual, 1e-10);
|
||||
LONGS_EQUAL(7, factor.rows());
|
||||
DOUBLES_EQUAL(10.0, factor.constantTerm(), 1e-10);
|
||||
|
||||
Vector linearExpected(6); linearExpected << g1, g2, g3;
|
||||
EXPECT(assert_equal(linearExpected, factor.linearTerm()));
|
||||
|
||||
EXPECT(assert_equal(G11, factor.info(factor.begin()+0, factor.begin()+0)));
|
||||
EXPECT(assert_equal(G12, factor.info(factor.begin()+0, factor.begin()+1)));
|
||||
EXPECT(assert_equal(G13, factor.info(factor.begin()+0, factor.begin()+2)));
|
||||
EXPECT(assert_equal(G22, factor.info(factor.begin()+1, factor.begin()+1)));
|
||||
EXPECT(assert_equal(G23, factor.info(factor.begin()+1, factor.begin()+2)));
|
||||
EXPECT(assert_equal(G33, factor.info(factor.begin()+2, factor.begin()+2)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, ConstructorNWay)
|
||||
{
|
||||
Matrix G11 = Matrix_(1,1, 1.0);
|
||||
Matrix G12 = Matrix_(1,2, 2.0, 4.0);
|
||||
Matrix G13 = Matrix_(1,3, 3.0, 6.0, 9.0);
|
||||
|
||||
Matrix G22 = Matrix_(2,2, 3.0, 5.0, 0.0, 6.0);
|
||||
Matrix G23 = Matrix_(2,3, 4.0, 6.0, 8.0, 1.0, 2.0, 4.0);
|
||||
|
||||
Matrix G33 = Matrix_(3,3, 1.0, 2.0, 3.0, 0.0, 5.0, 6.0, 0.0, 0.0, 9.0);
|
||||
|
||||
Vector g1 = Vector_(1, -7.0);
|
||||
Vector g2 = Vector_(2, -8.0, -9.0);
|
||||
Vector g3 = Vector_(3, 1.0, 2.0, 3.0);
|
||||
|
||||
double f = 10.0;
|
||||
|
||||
Vector dx0 = Vector_(1, 0.5);
|
||||
Vector dx1 = Vector_(2, 1.5, 2.5);
|
||||
Vector dx2 = Vector_(3, 1.5, 2.5, 3.5);
|
||||
|
||||
vector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
dims.push_back(2);
|
||||
dims.push_back(3);
|
||||
VectorValuesOrdered dx(dims);
|
||||
|
||||
dx[0] = dx0;
|
||||
dx[1] = dx1;
|
||||
dx[2] = dx2;
|
||||
|
||||
|
||||
std::vector<Index> js;
|
||||
js.push_back(0); js.push_back(1); js.push_back(2);
|
||||
std::vector<Matrix> Gs;
|
||||
Gs.push_back(G11); Gs.push_back(G12); Gs.push_back(G13); Gs.push_back(G22); Gs.push_back(G23); Gs.push_back(G33);
|
||||
std::vector<Vector> gs;
|
||||
gs.push_back(g1); gs.push_back(g2); gs.push_back(g3);
|
||||
HessianFactorOrdered factor(js, Gs, gs, f);
|
||||
|
||||
double expected = 371.3750;
|
||||
double actual = factor.error(dx);
|
||||
|
||||
DOUBLES_EQUAL(expected, actual, 1e-10);
|
||||
LONGS_EQUAL(7, factor.rows());
|
||||
DOUBLES_EQUAL(10.0, factor.constantTerm(), 1e-10);
|
||||
|
||||
Vector linearExpected(6); linearExpected << g1, g2, g3;
|
||||
EXPECT(assert_equal(linearExpected, factor.linearTerm()));
|
||||
|
||||
EXPECT(assert_equal(G11, factor.info(factor.begin()+0, factor.begin()+0)));
|
||||
EXPECT(assert_equal(G12, factor.info(factor.begin()+0, factor.begin()+1)));
|
||||
EXPECT(assert_equal(G13, factor.info(factor.begin()+0, factor.begin()+2)));
|
||||
EXPECT(assert_equal(G22, factor.info(factor.begin()+1, factor.begin()+1)));
|
||||
EXPECT(assert_equal(G23, factor.info(factor.begin()+1, factor.begin()+2)));
|
||||
EXPECT(assert_equal(G33, factor.info(factor.begin()+2, factor.begin()+2)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST_UNSAFE(HessianFactorOrdered, CopyConstructor_and_assignment)
|
||||
{
|
||||
Matrix G11 = Matrix_(1,1, 1.0);
|
||||
Matrix G12 = Matrix_(1,2, 2.0, 4.0);
|
||||
Matrix G22 = Matrix_(2,2, 3.0, 5.0, 0.0, 6.0);
|
||||
Vector g1 = Vector_(1, -7.0);
|
||||
Vector g2 = Vector_(2, -8.0, -9.0);
|
||||
double f = 10.0;
|
||||
|
||||
Vector dx0 = Vector_(1, 0.5);
|
||||
Vector dx1 = Vector_(2, 1.5, 2.5);
|
||||
|
||||
vector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
dims.push_back(2);
|
||||
VectorValuesOrdered dx(dims);
|
||||
|
||||
dx[0] = dx0;
|
||||
dx[1] = dx1;
|
||||
|
||||
HessianFactorOrdered originalFactor(0, 1, G11, G12, g1, G22, g2, f);
|
||||
|
||||
// Make a copy
|
||||
HessianFactorOrdered copy1(originalFactor);
|
||||
|
||||
double expected = 90.5;
|
||||
double actual = copy1.error(dx);
|
||||
|
||||
DOUBLES_EQUAL(expected, actual, 1e-10);
|
||||
LONGS_EQUAL(4, copy1.rows());
|
||||
DOUBLES_EQUAL(10.0, copy1.constantTerm(), 1e-10);
|
||||
|
||||
Vector linearExpected(3); linearExpected << g1, g2;
|
||||
EXPECT(assert_equal(linearExpected, copy1.linearTerm()));
|
||||
|
||||
EXPECT(assert_equal(G11, copy1.info(copy1.begin(), copy1.begin())));
|
||||
EXPECT(assert_equal(G12, copy1.info(copy1.begin(), copy1.begin()+1)));
|
||||
EXPECT(assert_equal(G22, copy1.info(copy1.begin()+1, copy1.begin()+1)));
|
||||
|
||||
// Make a copy using the assignment operator
|
||||
HessianFactorOrdered copy2;
|
||||
copy2 = HessianFactorOrdered(originalFactor); // Make a temporary to make sure copying does not shared references
|
||||
|
||||
actual = copy2.error(dx);
|
||||
DOUBLES_EQUAL(expected, actual, 1e-10);
|
||||
LONGS_EQUAL(4, copy2.rows());
|
||||
DOUBLES_EQUAL(10.0, copy2.constantTerm(), 1e-10);
|
||||
|
||||
EXPECT(assert_equal(linearExpected, copy2.linearTerm()));
|
||||
|
||||
EXPECT(assert_equal(G11, copy2.info(copy2.begin(), copy2.begin())));
|
||||
EXPECT(assert_equal(G12, copy2.info(copy2.begin(), copy2.begin()+1)));
|
||||
EXPECT(assert_equal(G22, copy2.info(copy2.begin()+1, copy2.begin()+1)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST_UNSAFE(HessianFactorOrdered, CombineAndEliminate)
|
||||
{
|
||||
Matrix A01 = Matrix_(3,3,
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
Vector b0 = Vector_(3, 1.5, 1.5, 1.5);
|
||||
Vector s0 = Vector_(3, 1.6, 1.6, 1.6);
|
||||
|
||||
Matrix A10 = Matrix_(3,3,
|
||||
2.0, 0.0, 0.0,
|
||||
0.0, 2.0, 0.0,
|
||||
0.0, 0.0, 2.0);
|
||||
Matrix A11 = Matrix_(3,3,
|
||||
-2.0, 0.0, 0.0,
|
||||
0.0, -2.0, 0.0,
|
||||
0.0, 0.0, -2.0);
|
||||
Vector b1 = Vector_(3, 2.5, 2.5, 2.5);
|
||||
Vector s1 = Vector_(3, 2.6, 2.6, 2.6);
|
||||
|
||||
Matrix A21 = Matrix_(3,3,
|
||||
3.0, 0.0, 0.0,
|
||||
0.0, 3.0, 0.0,
|
||||
0.0, 0.0, 3.0);
|
||||
Vector b2 = Vector_(3, 3.5, 3.5, 3.5);
|
||||
Vector s2 = Vector_(3, 3.6, 3.6, 3.6);
|
||||
|
||||
GaussianFactorGraphOrdered gfg;
|
||||
gfg.add(1, A01, b0, noiseModel::Diagonal::Sigmas(s0, true));
|
||||
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
|
||||
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
|
||||
|
||||
Matrix zero3x3 = zeros(3,3);
|
||||
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3);
|
||||
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21);
|
||||
Vector b = gtsam::concatVectors(3, &b1, &b0, &b2);
|
||||
Vector sigmas = gtsam::concatVectors(3, &s1, &s0, &s2);
|
||||
|
||||
// create a full, uneliminated version of the factor
|
||||
JacobianFactorOrdered expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
|
||||
|
||||
// perform elimination
|
||||
GaussianConditionalOrdered::shared_ptr expectedBN = expectedFactor.eliminate(1);
|
||||
|
||||
// create expected Hessian after elimination
|
||||
HessianFactorOrdered expectedCholeskyFactor(expectedFactor);
|
||||
|
||||
// Convert all factors to hessians
|
||||
FactorGraphOrdered<HessianFactorOrdered> hessians;
|
||||
BOOST_FOREACH(const GaussianFactorGraphOrdered::sharedFactor& factor, gfg) {
|
||||
if(boost::shared_ptr<HessianFactorOrdered> hf = boost::dynamic_pointer_cast<HessianFactorOrdered>(factor))
|
||||
hessians.push_back(hf);
|
||||
else if(boost::shared_ptr<JacobianFactorOrdered> jf = boost::dynamic_pointer_cast<JacobianFactorOrdered>(factor))
|
||||
hessians.push_back(boost::make_shared<HessianFactorOrdered>(*jf));
|
||||
else
|
||||
CHECK(false);
|
||||
}
|
||||
|
||||
// Eliminate
|
||||
GaussianFactorGraphOrdered::EliminationResult actualCholesky = EliminateCholeskyOrdered(gfg, 1);
|
||||
HessianFactorOrdered::shared_ptr actualFactor = boost::dynamic_pointer_cast<HessianFactorOrdered>(actualCholesky.second);
|
||||
|
||||
EXPECT(assert_equal(*expectedBN, *actualCholesky.first, 1e-6));
|
||||
EXPECT(assert_equal(expectedCholeskyFactor, *actualFactor, 1e-6));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, eliminate2 )
|
||||
{
|
||||
// sigmas
|
||||
double sigma1 = 0.2;
|
||||
double sigma2 = 0.1;
|
||||
Vector sigmas = Vector_(4, sigma1, sigma1, sigma2, sigma2);
|
||||
|
||||
// the combined linear factor
|
||||
Matrix Ax2 = Matrix_(4,2,
|
||||
// x2
|
||||
-1., 0.,
|
||||
+0.,-1.,
|
||||
1., 0.,
|
||||
+0.,1.
|
||||
);
|
||||
|
||||
Matrix Al1x1 = Matrix_(4,4,
|
||||
// l1 x1
|
||||
1., 0., 0.00, 0., // f4
|
||||
0., 1., 0.00, 0., // f4
|
||||
0., 0., -1., 0., // f2
|
||||
0., 0., 0.00,-1. // f2
|
||||
);
|
||||
|
||||
// the RHS
|
||||
Vector b2(4);
|
||||
b2(0) = -0.2;
|
||||
b2(1) = 0.3;
|
||||
b2(2) = 0.2;
|
||||
b2(3) = -0.1;
|
||||
|
||||
vector<pair<Index, Matrix> > meas;
|
||||
meas.push_back(make_pair(0, Ax2));
|
||||
meas.push_back(make_pair(1, Al1x1));
|
||||
JacobianFactorOrdered combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas));
|
||||
|
||||
// eliminate the combined factor
|
||||
HessianFactorOrdered::shared_ptr combinedLF_Chol(new HessianFactorOrdered(combined));
|
||||
FactorGraphOrdered<HessianFactorOrdered> combinedLFG_Chol;
|
||||
combinedLFG_Chol.push_back(combinedLF_Chol);
|
||||
|
||||
GaussianFactorGraphOrdered::EliminationResult actual_Chol = EliminateCholeskyOrdered(
|
||||
combinedLFG_Chol, 1);
|
||||
HessianFactorOrdered::shared_ptr actualFactor = boost::dynamic_pointer_cast<
|
||||
HessianFactorOrdered>(actual_Chol.second);
|
||||
|
||||
// create expected Conditional Gaussian
|
||||
double oldSigma = 0.0894427; // from when R was made unit
|
||||
Matrix R11 = Matrix_(2,2,
|
||||
1.00, 0.00,
|
||||
0.00, 1.00
|
||||
)/oldSigma;
|
||||
Matrix S12 = Matrix_(2,4,
|
||||
-0.20, 0.00,-0.80, 0.00,
|
||||
+0.00,-0.20,+0.00,-0.80
|
||||
)/oldSigma;
|
||||
Vector d = Vector_(2,0.2,-0.14)/oldSigma;
|
||||
GaussianConditionalOrdered expectedCG(0,d,R11,1,S12,ones(2));
|
||||
EXPECT(assert_equal(expectedCG,*actual_Chol.first,1e-4));
|
||||
|
||||
// the expected linear factor
|
||||
double sigma = 0.2236;
|
||||
Matrix Bl1x1 = Matrix_(2,4,
|
||||
// l1 x1
|
||||
1.00, 0.00, -1.00, 0.00,
|
||||
0.00, 1.00, +0.00, -1.00
|
||||
)/sigma;
|
||||
Vector b1 = Vector_(2,0.0,0.894427);
|
||||
JacobianFactorOrdered expectedLF(1, Bl1x1, b1, noiseModel::Isotropic::Sigma(2,1.0));
|
||||
EXPECT(assert_equal(HessianFactorOrdered(expectedLF), *actualFactor, 1.5e-3));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, eliminateUnsorted) {
|
||||
|
||||
JacobianFactorOrdered::shared_ptr factor1(
|
||||
new JacobianFactorOrdered(0,
|
||||
Matrix_(3,3,
|
||||
44.7214, 0.0, 0.0,
|
||||
0.0, 44.7214, 0.0,
|
||||
0.0, 0.0, 44.7214),
|
||||
1,
|
||||
Matrix_(3,3,
|
||||
-0.179168, -44.721, 0.717294,
|
||||
44.721, -0.179168, -44.9138,
|
||||
0.0, 0.0, -44.7214),
|
||||
Vector_(3, 1.98916e-17, -4.96503e-15, -7.75792e-17),
|
||||
noiseModel::Unit::Create(3)));
|
||||
HessianFactorOrdered::shared_ptr unsorted_factor2(
|
||||
new HessianFactorOrdered(JacobianFactorOrdered(0,
|
||||
Matrix_(6,3,
|
||||
25.8367, 0.1211, 0.0593,
|
||||
0.0, 23.4099, 30.8733,
|
||||
0.0, 0.0, 25.8729,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0),
|
||||
1,
|
||||
Matrix_(6,3,
|
||||
25.7429, -1.6897, 0.4587,
|
||||
1.6400, 23.3095, -8.4816,
|
||||
0.0034, 0.0509, -25.7855,
|
||||
0.9997, -0.0002, 0.0824,
|
||||
0.0, 0.9973, 0.9517,
|
||||
0.0, 0.0, 0.9973),
|
||||
Vector_(6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
noiseModel::Unit::Create(6))));
|
||||
Permutation permutation(2);
|
||||
permutation[0] = 1;
|
||||
permutation[1] = 0;
|
||||
unsorted_factor2->permuteWithInverse(permutation);
|
||||
|
||||
HessianFactorOrdered::shared_ptr sorted_factor2(
|
||||
new HessianFactorOrdered(JacobianFactorOrdered(0,
|
||||
Matrix_(6,3,
|
||||
25.7429, -1.6897, 0.4587,
|
||||
1.6400, 23.3095, -8.4816,
|
||||
0.0034, 0.0509, -25.7855,
|
||||
0.9997, -0.0002, 0.0824,
|
||||
0.0, 0.9973, 0.9517,
|
||||
0.0, 0.0, 0.9973),
|
||||
1,
|
||||
Matrix_(6,3,
|
||||
25.8367, 0.1211, 0.0593,
|
||||
0.0, 23.4099, 30.8733,
|
||||
0.0, 0.0, 25.8729,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0),
|
||||
Vector_(6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
noiseModel::Unit::Create(6))));
|
||||
|
||||
GaussianFactorGraphOrdered sortedGraph;
|
||||
// sortedGraph.push_back(factor1);
|
||||
sortedGraph.push_back(sorted_factor2);
|
||||
|
||||
GaussianFactorGraphOrdered unsortedGraph;
|
||||
// unsortedGraph.push_back(factor1);
|
||||
unsortedGraph.push_back(unsorted_factor2);
|
||||
|
||||
GaussianConditionalOrdered::shared_ptr expected_bn;
|
||||
GaussianFactorOrdered::shared_ptr expected_factor;
|
||||
boost::tie(expected_bn, expected_factor) =
|
||||
EliminatePreferCholeskyOrdered(sortedGraph, 1);
|
||||
|
||||
GaussianConditionalOrdered::shared_ptr actual_bn;
|
||||
GaussianFactorOrdered::shared_ptr actual_factor;
|
||||
boost::tie(actual_bn, actual_factor) =
|
||||
EliminatePreferCholeskyOrdered(unsortedGraph, 1);
|
||||
|
||||
EXPECT(assert_equal(*expected_bn, *actual_bn, 1e-10));
|
||||
EXPECT(assert_equal(*expected_factor, *actual_factor, 1e-10));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(HessianFactorOrdered, combine) {
|
||||
|
||||
// update the information matrix with a single jacobian factor
|
||||
Matrix A0 = Matrix_(2, 2,
|
||||
11.1803399, 0.0,
|
||||
0.0, 11.1803399);
|
||||
Matrix A1 = Matrix_(2, 2,
|
||||
-2.23606798, 0.0,
|
||||
0.0, -2.23606798);
|
||||
Matrix A2 = Matrix_(2, 2,
|
||||
-8.94427191, 0.0,
|
||||
0.0, -8.94427191);
|
||||
Vector b = Vector_(2, 2.23606798,-1.56524758);
|
||||
SharedDiagonal model = noiseModel::Diagonal::Sigmas(ones(2));
|
||||
GaussianFactorOrdered::shared_ptr f(new JacobianFactorOrdered(0, A0, 1, A1, 2, A2, b, model));
|
||||
FactorGraphOrdered<GaussianFactorOrdered> factors;
|
||||
factors.push_back(f);
|
||||
|
||||
// Form Ab' * Ab
|
||||
HessianFactorOrdered actual(factors);
|
||||
|
||||
Matrix expected = Matrix_(7, 7,
|
||||
125.0000, 0.0, -25.0000, 0.0, -100.0000, 0.0, 25.0000,
|
||||
0.0, 125.0000, 0.0, -25.0000, 0.0, -100.0000, -17.5000,
|
||||
-25.0000, 0.0, 5.0000, 0.0, 20.0000, 0.0, -5.0000,
|
||||
0.0, -25.0000, 0.0, 5.0000, 0.0, 20.0000, 3.5000,
|
||||
-100.0000, 0.0, 20.0000, 0.0, 80.0000, 0.0, -20.0000,
|
||||
0.0, -100.0000, 0.0, 20.0000, 0.0, 80.0000, 14.0000,
|
||||
25.0000, -17.5000, -5.0000, 3.5000, -20.0000, 14.0000, 7.4500);
|
||||
EXPECT(assert_equal(Matrix(expected.triangularView<Eigen::Upper>()),
|
||||
Matrix(actual.matrix_.triangularView<Eigen::Upper>()), tol));
|
||||
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,468 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testJacobianFactor.cpp
|
||||
* @brief Unit tests for Linear Factor
|
||||
* @author Christian Potthast
|
||||
* @author Frank Dellaert
|
||||
**/
|
||||
|
||||
#include <gtsam/base/TestableAssertions.h>
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/linear/JacobianFactorOrdered.h>
|
||||
#include <gtsam/linear/HessianFactorOrdered.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/linear/GaussianFactorGraphOrdered.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
static const Index _x0_=0, _x1_=1, _x2_=2, _x_=5, _y_=6, _l11_=8;
|
||||
|
||||
static SharedDiagonal constraintModel = noiseModel::Constrained::All(2);
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, constructor)
|
||||
{
|
||||
Vector b = Vector_(3, 1., 2., 3.);
|
||||
SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector_(3,1.,1.,1.));
|
||||
std::list<std::pair<Index, Matrix> > terms;
|
||||
terms.push_back(make_pair(_x0_, eye(3)));
|
||||
terms.push_back(make_pair(_x1_, 2.*eye(3)));
|
||||
JacobianFactorOrdered actual(terms, b, noise);
|
||||
JacobianFactorOrdered expected(_x0_, eye(3), _x1_, 2.*eye(3), b, noise);
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, constructor2)
|
||||
{
|
||||
Vector b = Vector_(3, 1., 2., 3.);
|
||||
SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector_(3,1.,1.,1.));
|
||||
std::list<std::pair<Index, Matrix> > terms;
|
||||
terms.push_back(make_pair(_x0_, eye(3)));
|
||||
terms.push_back(make_pair(_x1_, 2.*eye(3)));
|
||||
const JacobianFactorOrdered actual(terms, b, noise);
|
||||
|
||||
JacobianFactorOrdered::const_iterator key0 = actual.begin();
|
||||
JacobianFactorOrdered::const_iterator key1 = key0 + 1;
|
||||
EXPECT(assert_equal(*key0, _x0_));
|
||||
EXPECT(assert_equal(*key1, _x1_));
|
||||
EXPECT(!actual.empty());
|
||||
EXPECT_LONGS_EQUAL(3, actual.Ab_.nBlocks());
|
||||
|
||||
Matrix actualA0 = actual.getA(key0);
|
||||
Matrix actualA1 = actual.getA(key1);
|
||||
Vector actualb = actual.getb();
|
||||
|
||||
EXPECT(assert_equal(eye(3), actualA0));
|
||||
EXPECT(assert_equal(2.*eye(3), actualA1));
|
||||
EXPECT(assert_equal(b, actualb));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
JacobianFactorOrdered construct() {
|
||||
Matrix A = Matrix_(2,2, 1.,2.,3.,4.);
|
||||
Vector b = Vector_(2, 1.0, 2.0);
|
||||
SharedDiagonal s = noiseModel::Diagonal::Sigmas(Vector_(2, 3.0, 4.0));
|
||||
JacobianFactorOrdered::shared_ptr shared(
|
||||
new JacobianFactorOrdered(0, A, b, s));
|
||||
return *shared;
|
||||
}
|
||||
|
||||
TEST(JacobianFactorOrdered, return_value)
|
||||
{
|
||||
Matrix A = Matrix_(2,2, 1.,2.,3.,4.);
|
||||
Vector b = Vector_(2, 1.0, 2.0);
|
||||
SharedDiagonal s = noiseModel::Diagonal::Sigmas(Vector_(2, 3.0, 4.0));
|
||||
JacobianFactorOrdered copied = construct();
|
||||
EXPECT(assert_equal(b, copied.getb()));
|
||||
EXPECT(assert_equal(*s, *copied.get_model()));
|
||||
EXPECT(assert_equal(A, copied.getA(copied.begin())));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JabobianFactor, Hessian_conversion) {
|
||||
HessianFactorOrdered hessian(0, (Matrix(4,4) <<
|
||||
1.57, 2.695, -1.1, -2.35,
|
||||
2.695, 11.3125, -0.65, -10.225,
|
||||
-1.1, -0.65, 1, 0.5,
|
||||
-2.35, -10.225, 0.5, 9.25).finished(),
|
||||
(Vector(4) << -7.885, -28.5175, 2.75, 25.675).finished(),
|
||||
73.1725);
|
||||
|
||||
JacobianFactorOrdered expected(0, (Matrix(2,4) <<
|
||||
1.2530, 2.1508, -0.8779, -1.8755,
|
||||
0, 2.5858, 0.4789, -2.3943).finished(),
|
||||
(Vector(2) << -6.2929, -5.7941).finished(),
|
||||
noiseModel::Unit::Create(2));
|
||||
|
||||
JacobianFactorOrdered actual(hessian);
|
||||
|
||||
EXPECT(assert_equal(expected, actual, 1e-3));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( JacobianFactorOrdered, constructor_combined){
|
||||
double sigma1 = 0.0957;
|
||||
Matrix A11(2,2);
|
||||
A11(0,0) = 1; A11(0,1) = 0;
|
||||
A11(1,0) = 0; A11(1,1) = 1;
|
||||
Vector b(2);
|
||||
b(0) = 2; b(1) = -1;
|
||||
JacobianFactorOrdered::shared_ptr f1(new JacobianFactorOrdered(0, A11, b*sigma1, noiseModel::Isotropic::Sigma(2,sigma1)));
|
||||
|
||||
double sigma2 = 0.5;
|
||||
A11(0,0) = 1; A11(0,1) = 0;
|
||||
A11(1,0) = 0; A11(1,1) = -1;
|
||||
b(0) = 4 ; b(1) = -5;
|
||||
JacobianFactorOrdered::shared_ptr f2(new JacobianFactorOrdered(0, A11, b*sigma2, noiseModel::Isotropic::Sigma(2,sigma2)));
|
||||
|
||||
double sigma3 = 0.25;
|
||||
A11(0,0) = 1; A11(0,1) = 0;
|
||||
A11(1,0) = 0; A11(1,1) = -1;
|
||||
b(0) = 3 ; b(1) = -88;
|
||||
JacobianFactorOrdered::shared_ptr f3(new JacobianFactorOrdered(0, A11, b*sigma3, noiseModel::Isotropic::Sigma(2,sigma3)));
|
||||
|
||||
// TODO: find a real sigma value for this example
|
||||
double sigma4 = 0.1;
|
||||
A11(0,0) = 6; A11(0,1) = 0;
|
||||
A11(1,0) = 0; A11(1,1) = 7;
|
||||
b(0) = 5 ; b(1) = -6;
|
||||
JacobianFactorOrdered::shared_ptr f4(new JacobianFactorOrdered(0, A11*sigma4, b*sigma4, noiseModel::Isotropic::Sigma(2,sigma4)));
|
||||
|
||||
GaussianFactorGraphOrdered lfg;
|
||||
lfg.push_back(f1);
|
||||
lfg.push_back(f2);
|
||||
lfg.push_back(f3);
|
||||
lfg.push_back(f4);
|
||||
JacobianFactorOrdered combined(lfg);
|
||||
|
||||
Vector sigmas = Vector_(8, sigma1, sigma1, sigma2, sigma2, sigma3, sigma3, sigma4, sigma4);
|
||||
Matrix A22(8,2);
|
||||
A22(0,0) = 1; A22(0,1) = 0;
|
||||
A22(1,0) = 0; A22(1,1) = 1;
|
||||
A22(2,0) = 1; A22(2,1) = 0;
|
||||
A22(3,0) = 0; A22(3,1) = -1;
|
||||
A22(4,0) = 1; A22(4,1) = 0;
|
||||
A22(5,0) = 0; A22(5,1) = -1;
|
||||
A22(6,0) = 0.6; A22(6,1) = 0;
|
||||
A22(7,0) = 0; A22(7,1) = 0.7;
|
||||
Vector exb(8);
|
||||
exb(0) = 2*sigma1 ; exb(1) = -1*sigma1; exb(2) = 4*sigma2 ; exb(3) = -5*sigma2;
|
||||
exb(4) = 3*sigma3 ; exb(5) = -88*sigma3; exb(6) = 5*sigma4 ; exb(7) = -6*sigma4;
|
||||
|
||||
vector<pair<Index, Matrix> > meas;
|
||||
meas.push_back(make_pair(0, A22));
|
||||
JacobianFactorOrdered expected(meas, exb, noiseModel::Diagonal::Sigmas(sigmas));
|
||||
EXPECT(assert_equal(expected,combined));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, linearFactorN){
|
||||
Matrix I = eye(2);
|
||||
GaussianFactorGraphOrdered f;
|
||||
SharedDiagonal model = noiseModel::Isotropic::Sigma(2,1.0);
|
||||
f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(0, I, Vector_(2, 10.0, 5.0), model)));
|
||||
f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(0, -10 * I, 1, 10 * I, Vector_(2, 1.0, -2.0), model)));
|
||||
f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(1, -10 * I, 2, 10 * I, Vector_(2, 1.5, -1.5), model)));
|
||||
f.push_back(JacobianFactorOrdered::shared_ptr(new JacobianFactorOrdered(2, -10 * I, 3, 10 * I, Vector_(2, 2.0, -1.0), model)));
|
||||
|
||||
JacobianFactorOrdered combinedFactor(f);
|
||||
|
||||
vector<pair<Index, Matrix> > combinedMeasurement;
|
||||
combinedMeasurement.push_back(make_pair(0, Matrix_(8,2,
|
||||
1.0, 0.0,
|
||||
0.0, 1.0,
|
||||
-10.0, 0.0,
|
||||
0.0,-10.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0)));
|
||||
combinedMeasurement.push_back(make_pair(1, Matrix_(8,2,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
10.0, 0.0,
|
||||
0.0, 10.0,
|
||||
-10.0, 0.0,
|
||||
0.0,-10.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0)));
|
||||
combinedMeasurement.push_back(make_pair(2, Matrix_(8,2,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
10.0, 0.0,
|
||||
0.0, 10.0,
|
||||
-10.0, 0.0,
|
||||
0.0,-10.0)));
|
||||
combinedMeasurement.push_back(make_pair(3, Matrix_(8,2,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
10.0, 0.0,
|
||||
0.0,10.0)));
|
||||
Vector b = Vector_(8,
|
||||
10.0, 5.0, 1.0, -2.0, 1.5, -1.5, 2.0, -1.0);
|
||||
|
||||
Vector sigmas = repeat(8,1.0);
|
||||
JacobianFactorOrdered expected(combinedMeasurement, b, noiseModel::Diagonal::Sigmas(sigmas));
|
||||
EXPECT(assert_equal(expected,combinedFactor));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, error) {
|
||||
Vector b = Vector_(3, 1., 2., 3.);
|
||||
SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector_(3,2.,2.,2.));
|
||||
std::list<std::pair<Index, Matrix> > terms;
|
||||
terms.push_back(make_pair(_x0_, eye(3)));
|
||||
terms.push_back(make_pair(_x1_, 2.*eye(3)));
|
||||
const JacobianFactorOrdered jf(terms, b, noise);
|
||||
|
||||
VectorValuesOrdered values(2, 3);
|
||||
values[0] = Vector_(3, 1.,2.,3.);
|
||||
values[1] = Vector_(3, 4.,5.,6.);
|
||||
|
||||
Vector expected_unwhitened = Vector_(3, 8., 10., 12.);
|
||||
Vector actual_unwhitened = jf.unweighted_error(values);
|
||||
EXPECT(assert_equal(expected_unwhitened, actual_unwhitened));
|
||||
|
||||
Vector expected_whitened = Vector_(3, 4., 5., 6.);
|
||||
Vector actual_whitened = jf.error_vector(values);
|
||||
EXPECT(assert_equal(expected_whitened, actual_whitened));
|
||||
|
||||
// check behavior when there are more values than in this factor
|
||||
VectorValuesOrdered largeValues(3, 3);
|
||||
largeValues[0] = Vector_(3, 1.,2.,3.);
|
||||
largeValues[1] = Vector_(3, 4.,5.,6.);
|
||||
largeValues[2] = Vector_(3, 7.,8.,9.);
|
||||
|
||||
EXPECT(assert_equal(expected_unwhitened, jf.unweighted_error(largeValues)));
|
||||
EXPECT(assert_equal(expected_whitened, jf.error_vector(largeValues)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, operators )
|
||||
{
|
||||
SharedDiagonal sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1);
|
||||
|
||||
Matrix I = eye(2);
|
||||
Vector b = Vector_(2,0.2,-0.1);
|
||||
JacobianFactorOrdered lf(_x1_, -I, _x2_, I, b, sigma0_1);
|
||||
|
||||
VectorValuesOrdered c;
|
||||
c.insert(_x1_, Vector_(2,10.,20.));
|
||||
c.insert(_x2_, Vector_(2,30.,60.));
|
||||
|
||||
// test A*x
|
||||
Vector expectedE = Vector_(2,200.,400.), e = lf*c;
|
||||
EXPECT(assert_equal(expectedE,e));
|
||||
|
||||
// test A^e
|
||||
VectorValuesOrdered expectedX;
|
||||
expectedX.insert(_x1_, Vector_(2,-2000.,-4000.));
|
||||
expectedX.insert(_x2_, Vector_(2, 2000., 4000.));
|
||||
VectorValuesOrdered actualX = VectorValuesOrdered::Zero(expectedX);
|
||||
lf.transposeMultiplyAdd(1.0, e, actualX);
|
||||
EXPECT(assert_equal(expectedX, actualX));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, eliminate2 )
|
||||
{
|
||||
// sigmas
|
||||
double sigma1 = 0.2;
|
||||
double sigma2 = 0.1;
|
||||
Vector sigmas = Vector_(4, sigma1, sigma1, sigma2, sigma2);
|
||||
|
||||
// the combined linear factor
|
||||
Matrix Ax2 = Matrix_(4,2,
|
||||
// x2
|
||||
-1., 0.,
|
||||
+0.,-1.,
|
||||
1., 0.,
|
||||
+0.,1.
|
||||
);
|
||||
|
||||
Matrix Al1x1 = Matrix_(4,4,
|
||||
// l1 x1
|
||||
1., 0., 0.00, 0., // f4
|
||||
0., 1., 0.00, 0., // f4
|
||||
0., 0., -1., 0., // f2
|
||||
0., 0., 0.00,-1. // f2
|
||||
);
|
||||
|
||||
// the RHS
|
||||
Vector b2(4);
|
||||
b2(0) = -0.2;
|
||||
b2(1) = 0.3;
|
||||
b2(2) = 0.2;
|
||||
b2(3) = -0.1;
|
||||
|
||||
vector<pair<Index, Matrix> > meas;
|
||||
meas.push_back(make_pair(_x2_, Ax2));
|
||||
meas.push_back(make_pair(_l11_, Al1x1));
|
||||
JacobianFactorOrdered combined(meas, b2, noiseModel::Diagonal::Sigmas(sigmas));
|
||||
|
||||
// eliminate the combined factor
|
||||
GaussianConditionalOrdered::shared_ptr actualCG_QR;
|
||||
JacobianFactorOrdered::shared_ptr actualLF_QR(new JacobianFactorOrdered(combined));
|
||||
actualCG_QR = actualLF_QR->eliminateFirst();
|
||||
|
||||
// create expected Conditional Gaussian
|
||||
double oldSigma = 0.0894427; // from when R was made unit
|
||||
Matrix R11 = Matrix_(2,2,
|
||||
1.00, 0.00,
|
||||
0.00, 1.00
|
||||
)/oldSigma;
|
||||
Matrix S12 = Matrix_(2,4,
|
||||
-0.20, 0.00,-0.80, 0.00,
|
||||
+0.00,-0.20,+0.00,-0.80
|
||||
)/oldSigma;
|
||||
Vector d = Vector_(2,0.2,-0.14)/oldSigma;
|
||||
GaussianConditionalOrdered expectedCG(_x2_,d,R11,_l11_,S12,ones(2));
|
||||
|
||||
EXPECT_LONGS_EQUAL(0, actualCG_QR->rsd().firstBlock());
|
||||
EXPECT_LONGS_EQUAL(0, actualCG_QR->rsd().rowStart());
|
||||
EXPECT_LONGS_EQUAL(2, actualCG_QR->rsd().rowEnd());
|
||||
EXPECT_LONGS_EQUAL(3, actualCG_QR->rsd().nBlocks());
|
||||
EXPECT(assert_equal(expectedCG,*actualCG_QR,1e-4));
|
||||
|
||||
// the expected linear factor
|
||||
double sigma = 0.2236;
|
||||
Matrix Bl1x1 = Matrix_(2,4,
|
||||
// l1 x1
|
||||
1.00, 0.00, -1.00, 0.00,
|
||||
0.00, 1.00, +0.00, -1.00
|
||||
)/sigma;
|
||||
Vector b1 = Vector_(2,0.0,0.894427);
|
||||
JacobianFactorOrdered expectedLF(_l11_, Bl1x1, b1, noiseModel::Isotropic::Sigma(2,1.0));
|
||||
EXPECT(assert_equal(expectedLF,*actualLF_QR,1e-3));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, default_error )
|
||||
{
|
||||
JacobianFactorOrdered f;
|
||||
vector<size_t> dims;
|
||||
VectorValuesOrdered c(dims);
|
||||
double actual = f.error(c);
|
||||
EXPECT(actual==0.0);
|
||||
}
|
||||
|
||||
//* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, empty )
|
||||
{
|
||||
// create an empty factor
|
||||
JacobianFactorOrdered f;
|
||||
EXPECT(f.empty()==true);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// small aux. function to print out lists of anything
|
||||
template<class T>
|
||||
void print(const list<T>& i) {
|
||||
copy(i.begin(), i.end(), ostream_iterator<T> (cout, ","));
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(JacobianFactorOrdered, CONSTRUCTOR_GaussianConditional )
|
||||
{
|
||||
Matrix R11 = eye(2);
|
||||
Matrix S12 = Matrix_(2,2,
|
||||
-0.200001, 0.00,
|
||||
+0.00,-0.200001
|
||||
);
|
||||
Vector d(2); d(0) = 2.23607; d(1) = -1.56525;
|
||||
Vector sigmas =repeat(2,0.29907);
|
||||
GaussianConditionalOrdered::shared_ptr CG(new GaussianConditionalOrdered(_x2_,d,R11,_l11_,S12,sigmas));
|
||||
|
||||
// Call the constructor we are testing !
|
||||
JacobianFactorOrdered actualLF(*CG);
|
||||
|
||||
JacobianFactorOrdered expectedLF(_x2_,R11,_l11_,S12,d, noiseModel::Diagonal::Sigmas(sigmas));
|
||||
EXPECT(assert_equal(expectedLF,actualLF,1e-5));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST ( JacobianFactorOrdered, constraint_eliminate1 )
|
||||
{
|
||||
// construct a linear constraint
|
||||
Vector v(2); v(0)=1.2; v(1)=3.4;
|
||||
Index key = _x0_;
|
||||
JacobianFactorOrdered lc(key, eye(2), v, constraintModel);
|
||||
|
||||
// eliminate it
|
||||
GaussianConditionalOrdered::shared_ptr actualCG;
|
||||
JacobianFactorOrdered::shared_ptr actualLF(new JacobianFactorOrdered(lc));
|
||||
actualCG = actualLF->eliminateFirst();
|
||||
|
||||
// verify linear factor
|
||||
EXPECT(actualLF->size() == 0);
|
||||
|
||||
// verify conditional Gaussian
|
||||
Vector sigmas = Vector_(2, 0.0, 0.0);
|
||||
GaussianConditionalOrdered expCG(_x0_, v, eye(2), sigmas);
|
||||
EXPECT(assert_equal(expCG, *actualCG));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST ( JacobianFactorOrdered, constraint_eliminate2 )
|
||||
{
|
||||
// Construct a linear constraint
|
||||
// RHS
|
||||
Vector b(2); b(0)=3.0; b(1)=4.0;
|
||||
|
||||
// A1 - invertible
|
||||
Matrix A1(2,2);
|
||||
A1(0,0) = 1.0 ; A1(0,1) = 2.0;
|
||||
A1(1,0) = 2.0 ; A1(1,1) = 1.0;
|
||||
|
||||
// A2 - not invertible
|
||||
Matrix A2(2,2);
|
||||
A2(0,0) = 1.0 ; A2(0,1) = 2.0;
|
||||
A2(1,0) = 2.0 ; A2(1,1) = 4.0;
|
||||
|
||||
JacobianFactorOrdered lc(_x_, A1, _y_, A2, b, constraintModel);
|
||||
|
||||
// eliminate x and verify results
|
||||
GaussianConditionalOrdered::shared_ptr actualCG;
|
||||
JacobianFactorOrdered::shared_ptr actualLF(new JacobianFactorOrdered(lc));
|
||||
actualCG = actualLF->eliminateFirst();
|
||||
|
||||
// LF should be null
|
||||
JacobianFactorOrdered expectedLF;
|
||||
EXPECT(assert_equal(*actualLF, expectedLF));
|
||||
|
||||
// verify CG
|
||||
Matrix R = Matrix_(2, 2,
|
||||
1.0, 2.0,
|
||||
0.0, 1.0);
|
||||
Matrix S = Matrix_(2,2,
|
||||
1.0, 2.0,
|
||||
0.0, 0.0);
|
||||
Vector d = Vector_(2, 3.0, 0.6666);
|
||||
GaussianConditionalOrdered expectedCG(_x_, d, R, _y_, S, zero(2));
|
||||
EXPECT(assert_equal(expectedCG, *actualCG, 1e-4));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,456 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testVectorValues.cpp
|
||||
* @author Richard Roberts
|
||||
* @date Sep 16, 2010
|
||||
*/
|
||||
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/linear/VectorValuesOrdered.h>
|
||||
#include <gtsam/inference/PermutationOrdered.h>
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::assign;
|
||||
using namespace gtsam;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, insert) {
|
||||
|
||||
// insert, with out-of-order indices
|
||||
VectorValuesOrdered actual;
|
||||
actual.insert(0, Vector_(1, 1.0));
|
||||
actual.insert(1, Vector_(2, 2.0, 3.0));
|
||||
actual.insert(5, Vector_(2, 6.0, 7.0));
|
||||
actual.insert(2, Vector_(2, 4.0, 5.0));
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(6, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
LONGS_EQUAL(2, actual.dim(5));
|
||||
|
||||
// Logic
|
||||
EXPECT(actual.exists(0));
|
||||
EXPECT(actual.exists(1));
|
||||
EXPECT(actual.exists(2));
|
||||
EXPECT(!actual.exists(3));
|
||||
EXPECT(!actual.exists(4));
|
||||
EXPECT(actual.exists(5));
|
||||
EXPECT(!actual.exists(6));
|
||||
|
||||
// Check values
|
||||
EXPECT(assert_equal(Vector_(1, 1.0), actual[0]));
|
||||
EXPECT(assert_equal(Vector_(2, 2.0, 3.0), actual[1]));
|
||||
EXPECT(assert_equal(Vector_(2, 4.0, 5.0), actual[2]));
|
||||
EXPECT(assert_equal(Vector_(2, 6.0, 7.0), actual[5]));
|
||||
EXPECT(assert_equal(Vector_(7, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0), actual.asVector()));
|
||||
|
||||
// Check exceptions
|
||||
CHECK_EXCEPTION(actual.insert(1, Vector()), invalid_argument);
|
||||
CHECK_EXCEPTION(actual.dim(3), out_of_range);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, dimsConstructor) {
|
||||
vector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
dims.push_back(2);
|
||||
dims.push_back(2);
|
||||
|
||||
VectorValuesOrdered actual(dims);
|
||||
actual[0] = Vector_(1, 1.0);
|
||||
actual[1] = Vector_(2, 2.0, 3.0);
|
||||
actual[2] = Vector_(2, 4.0, 5.0);
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(3, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
|
||||
// Check values
|
||||
EXPECT(assert_equal(Vector_(1, 1.0), actual[0]));
|
||||
EXPECT(assert_equal(Vector_(2, 2.0, 3.0), actual[1]));
|
||||
EXPECT(assert_equal(Vector_(2, 4.0, 5.0), actual[2]));
|
||||
EXPECT(assert_equal(Vector_(5, 1.0, 2.0, 3.0, 4.0, 5.0), actual.asVector()));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, copyConstructor) {
|
||||
|
||||
// insert, with out-of-order indices
|
||||
VectorValuesOrdered original;
|
||||
original.insert(0, Vector_(1, 1.0));
|
||||
original.insert(1, Vector_(2, 2.0, 3.0));
|
||||
original.insert(5, Vector_(2, 6.0, 7.0));
|
||||
original.insert(2, Vector_(2, 4.0, 5.0));
|
||||
|
||||
VectorValuesOrdered actual(original);
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(6, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
LONGS_EQUAL(2, actual.dim(5));
|
||||
|
||||
// Logic
|
||||
EXPECT(actual.exists(0));
|
||||
EXPECT(actual.exists(1));
|
||||
EXPECT(actual.exists(2));
|
||||
EXPECT(!actual.exists(3));
|
||||
EXPECT(!actual.exists(4));
|
||||
EXPECT(actual.exists(5));
|
||||
EXPECT(!actual.exists(6));
|
||||
|
||||
// Check values
|
||||
EXPECT(assert_equal(Vector_(1, 1.0), actual[0]));
|
||||
EXPECT(assert_equal(Vector_(2, 2.0, 3.0), actual[1]));
|
||||
EXPECT(assert_equal(Vector_(2, 4.0, 5.0), actual[2]));
|
||||
EXPECT(assert_equal(Vector_(2, 6.0, 7.0), actual[5]));
|
||||
EXPECT(assert_equal(Vector_(7, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0), actual.asVector()));
|
||||
|
||||
// Check exceptions
|
||||
CHECK_EXCEPTION(actual.insert(1, Vector()), invalid_argument);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, assignment) {
|
||||
|
||||
VectorValuesOrdered actual;
|
||||
|
||||
{
|
||||
// insert, with out-of-order indices
|
||||
VectorValuesOrdered original;
|
||||
original.insert(0, Vector_(1, 1.0));
|
||||
original.insert(1, Vector_(2, 2.0, 3.0));
|
||||
original.insert(5, Vector_(2, 6.0, 7.0));
|
||||
original.insert(2, Vector_(2, 4.0, 5.0));
|
||||
actual = original;
|
||||
}
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(6, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
LONGS_EQUAL(2, actual.dim(5));
|
||||
|
||||
// Logic
|
||||
EXPECT(actual.exists(0));
|
||||
EXPECT(actual.exists(1));
|
||||
EXPECT(actual.exists(2));
|
||||
EXPECT(!actual.exists(3));
|
||||
EXPECT(!actual.exists(4));
|
||||
EXPECT(actual.exists(5));
|
||||
EXPECT(!actual.exists(6));
|
||||
|
||||
// Check values
|
||||
EXPECT(assert_equal(Vector_(1, 1.0), actual[0]));
|
||||
EXPECT(assert_equal(Vector_(2, 2.0, 3.0), actual[1]));
|
||||
EXPECT(assert_equal(Vector_(2, 4.0, 5.0), actual[2]));
|
||||
EXPECT(assert_equal(Vector_(2, 6.0, 7.0), actual[5]));
|
||||
EXPECT(assert_equal(Vector_(7, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0), actual.asVector()));
|
||||
|
||||
// Check exceptions
|
||||
CHECK_EXCEPTION(actual.insert(1, Vector()), invalid_argument);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, SameStructure) {
|
||||
// insert, with out-of-order indices
|
||||
VectorValuesOrdered original;
|
||||
original.insert(0, Vector_(1, 1.0));
|
||||
original.insert(1, Vector_(2, 2.0, 3.0));
|
||||
original.insert(5, Vector_(2, 6.0, 7.0));
|
||||
original.insert(2, Vector_(2, 4.0, 5.0));
|
||||
|
||||
VectorValuesOrdered actual(VectorValuesOrdered::SameStructure(original));
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(6, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
LONGS_EQUAL(2, actual.dim(5));
|
||||
|
||||
// Logic
|
||||
EXPECT(actual.exists(0));
|
||||
EXPECT(actual.exists(1));
|
||||
EXPECT(actual.exists(2));
|
||||
EXPECT(!actual.exists(3));
|
||||
EXPECT(!actual.exists(4));
|
||||
EXPECT(actual.exists(5));
|
||||
EXPECT(!actual.exists(6));
|
||||
|
||||
// Check exceptions
|
||||
CHECK_EXCEPTION(actual.insert(1, Vector()), invalid_argument);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, Zero_fromModel) {
|
||||
// insert, with out-of-order indices
|
||||
VectorValuesOrdered original;
|
||||
original.insert(0, Vector_(1, 1.0));
|
||||
original.insert(1, Vector_(2, 2.0, 3.0));
|
||||
original.insert(5, Vector_(2, 6.0, 7.0));
|
||||
original.insert(2, Vector_(2, 4.0, 5.0));
|
||||
|
||||
VectorValuesOrdered actual(VectorValuesOrdered::Zero(original));
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(6, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
LONGS_EQUAL(2, actual.dim(5));
|
||||
|
||||
// Values
|
||||
EXPECT(assert_equal(Vector::Zero(1), actual[0]));
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[1]));
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[5]));
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[2]));
|
||||
|
||||
// Logic
|
||||
EXPECT(actual.exists(0));
|
||||
EXPECT(actual.exists(1));
|
||||
EXPECT(actual.exists(2));
|
||||
EXPECT(!actual.exists(3));
|
||||
EXPECT(!actual.exists(4));
|
||||
EXPECT(actual.exists(5));
|
||||
EXPECT(!actual.exists(6));
|
||||
|
||||
// Check exceptions
|
||||
CHECK_EXCEPTION(actual.insert(1, Vector()), invalid_argument);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, Zero_fromDims) {
|
||||
vector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
dims.push_back(2);
|
||||
dims.push_back(2);
|
||||
|
||||
VectorValuesOrdered actual(VectorValuesOrdered::Zero(dims));
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(3, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
|
||||
// Values
|
||||
EXPECT(assert_equal(Vector::Zero(1), actual[0]));
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[1]));
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[2]));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, Zero_fromUniform) {
|
||||
VectorValuesOrdered actual(VectorValuesOrdered::Zero(3, 2));
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(3, actual.size());
|
||||
LONGS_EQUAL(2, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
|
||||
// Values
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[0]));
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[1]));
|
||||
EXPECT(assert_equal(Vector::Zero(2), actual[2]));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, resizeLike) {
|
||||
// insert, with out-of-order indices
|
||||
VectorValuesOrdered original;
|
||||
original.insert(0, Vector_(1, 1.0));
|
||||
original.insert(1, Vector_(2, 2.0, 3.0));
|
||||
original.insert(5, Vector_(2, 6.0, 7.0));
|
||||
original.insert(2, Vector_(2, 4.0, 5.0));
|
||||
|
||||
VectorValuesOrdered actual(10, 3);
|
||||
actual.resizeLike(original);
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(6, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
LONGS_EQUAL(2, actual.dim(5));
|
||||
|
||||
// Logic
|
||||
EXPECT(actual.exists(0));
|
||||
EXPECT(actual.exists(1));
|
||||
EXPECT(actual.exists(2));
|
||||
EXPECT(!actual.exists(3));
|
||||
EXPECT(!actual.exists(4));
|
||||
EXPECT(actual.exists(5));
|
||||
EXPECT(!actual.exists(6));
|
||||
|
||||
// Check exceptions
|
||||
CHECK_EXCEPTION(actual.insert(1, Vector()), invalid_argument);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, resize_fromUniform) {
|
||||
VectorValuesOrdered actual(4, 10);
|
||||
actual.resize(3, 2);
|
||||
|
||||
actual[0] = Vector_(2, 1.0, 2.0);
|
||||
actual[1] = Vector_(2, 2.0, 3.0);
|
||||
actual[2] = Vector_(2, 4.0, 5.0);
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(3, actual.size());
|
||||
LONGS_EQUAL(2, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
|
||||
// Check values
|
||||
EXPECT(assert_equal(Vector_(2, 1.0, 2.0), actual[0]));
|
||||
EXPECT(assert_equal(Vector_(2, 2.0, 3.0), actual[1]));
|
||||
EXPECT(assert_equal(Vector_(2, 4.0, 5.0), actual[2]));
|
||||
EXPECT(assert_equal(Vector_(6, 1.0, 2.0, 2.0, 3.0, 4.0, 5.0), actual.asVector()));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, resize_fromDims) {
|
||||
vector<size_t> dims;
|
||||
dims.push_back(1);
|
||||
dims.push_back(2);
|
||||
dims.push_back(2);
|
||||
|
||||
VectorValuesOrdered actual(4, 10);
|
||||
actual.resize(dims);
|
||||
actual[0] = Vector_(1, 1.0);
|
||||
actual[1] = Vector_(2, 2.0, 3.0);
|
||||
actual[2] = Vector_(2, 4.0, 5.0);
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(3, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
|
||||
// Check values
|
||||
EXPECT(assert_equal(Vector_(1, 1.0), actual[0]));
|
||||
EXPECT(assert_equal(Vector_(2, 2.0, 3.0), actual[1]));
|
||||
EXPECT(assert_equal(Vector_(2, 4.0, 5.0), actual[2]));
|
||||
EXPECT(assert_equal(Vector_(5, 1.0, 2.0, 3.0, 4.0, 5.0), actual.asVector()));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, append) {
|
||||
// insert
|
||||
VectorValuesOrdered actual;
|
||||
actual.insert(0, Vector_(1, 1.0));
|
||||
actual.insert(1, Vector_(2, 2.0, 3.0));
|
||||
actual.insert(2, Vector_(2, 4.0, 5.0));
|
||||
|
||||
// append
|
||||
vector<size_t> dims(2);
|
||||
dims[0] = 3;
|
||||
dims[1] = 5;
|
||||
actual.append(dims);
|
||||
|
||||
// Check dimensions
|
||||
LONGS_EQUAL(5, actual.size());
|
||||
LONGS_EQUAL(1, actual.dim(0));
|
||||
LONGS_EQUAL(2, actual.dim(1));
|
||||
LONGS_EQUAL(2, actual.dim(2));
|
||||
LONGS_EQUAL(3, actual.dim(3));
|
||||
LONGS_EQUAL(5, actual.dim(4));
|
||||
|
||||
// Logic
|
||||
EXPECT(actual.exists(0));
|
||||
EXPECT(actual.exists(1));
|
||||
EXPECT(actual.exists(2));
|
||||
EXPECT(actual.exists(3));
|
||||
EXPECT(actual.exists(4));
|
||||
EXPECT(!actual.exists(5));
|
||||
|
||||
// Check values
|
||||
EXPECT(assert_equal(Vector_(1, 1.0), actual[0]));
|
||||
EXPECT(assert_equal(Vector_(2, 2.0, 3.0), actual[1]));
|
||||
EXPECT(assert_equal(Vector_(2, 4.0, 5.0), actual[2]));
|
||||
|
||||
// Check exceptions
|
||||
CHECK_EXCEPTION(actual.insert(3, Vector()), invalid_argument);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, hasSameStructure) {
|
||||
VectorValuesOrdered v1(2, 3);
|
||||
VectorValuesOrdered v2(3, 2);
|
||||
VectorValuesOrdered v3(4, 2);
|
||||
VectorValuesOrdered v4(4, 2);
|
||||
|
||||
EXPECT(!v1.hasSameStructure(v2));
|
||||
EXPECT(!v2.hasSameStructure(v3));
|
||||
EXPECT(v3.hasSameStructure(v4));
|
||||
EXPECT(VectorValuesOrdered().hasSameStructure(VectorValuesOrdered()));
|
||||
EXPECT(!v1.hasSameStructure(VectorValuesOrdered()));
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, permute) {
|
||||
|
||||
VectorValuesOrdered original;
|
||||
original.insert(0, Vector_(1, 1.0));
|
||||
original.insert(1, Vector_(2, 2.0, 3.0));
|
||||
original.insert(2, Vector_(2, 4.0, 5.0));
|
||||
original.insert(3, Vector_(2, 6.0, 7.0));
|
||||
|
||||
VectorValuesOrdered expected;
|
||||
expected.insert(0, Vector_(2, 4.0, 5.0)); // from 2
|
||||
expected.insert(1, Vector_(1, 1.0)); // from 0
|
||||
expected.insert(2, Vector_(2, 6.0, 7.0)); // from 3
|
||||
expected.insert(3, Vector_(2, 2.0, 3.0)); // from 1
|
||||
|
||||
Permutation permutation(4);
|
||||
permutation[0] = 2;
|
||||
permutation[1] = 0;
|
||||
permutation[2] = 3;
|
||||
permutation[3] = 1;
|
||||
|
||||
VectorValuesOrdered actual = original;
|
||||
actual.permuteInPlace(permutation);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(VectorValuesOrdered, subvector) {
|
||||
VectorValuesOrdered init;
|
||||
init.insert(0, Vector_(1, 1.0));
|
||||
init.insert(1, Vector_(2, 2.0, 3.0));
|
||||
init.insert(2, Vector_(2, 4.0, 5.0));
|
||||
init.insert(3, Vector_(2, 6.0, 7.0));
|
||||
|
||||
std::vector<gtsam::Index> indices;
|
||||
indices += 0, 2, 3;
|
||||
Vector expSubVector = Vector_(5, 1.0, 4.0, 5.0, 6.0, 7.0);
|
||||
EXPECT(assert_equal(expSubVector, init.vector(indices)));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testGaussianBayesNet.cpp
|
||||
* @brief Unit tests for GaussianBayesNet
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
// STL/C++
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <gtsam/inference/BayesNetOrdered.h>
|
||||
#include <gtsam/linear/GaussianBayesNetOrdered.h>
|
||||
#include <gtsam/linear/GaussianSequentialSolver.h>
|
||||
#include <tests/smallExample.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
using namespace example;
|
||||
|
||||
static const Index _x_=0, _y_=1, _z_=2;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianBayesNetOrdered, constructor )
|
||||
{
|
||||
// small Bayes Net x <- y
|
||||
// x y d
|
||||
// 1 1 9
|
||||
// 1 5
|
||||
Matrix R11 = Matrix_(1,1,1.0), S12 = Matrix_(1,1,1.0);
|
||||
Matrix R22 = Matrix_(1,1,1.0);
|
||||
Vector d1(1), d2(1);
|
||||
d1(0) = 9; d2(0) = 5;
|
||||
Vector sigmas(1);
|
||||
sigmas(0) = 1.;
|
||||
|
||||
// define nodes and specify in reverse topological sort (i.e. parents last)
|
||||
GaussianConditionalOrdered x(_x_,d1,R11,_y_,S12, sigmas), y(_y_,d2,R22, sigmas);
|
||||
|
||||
// check small example which uses constructor
|
||||
GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet();
|
||||
EXPECT( x.equals(*cbn[_x_]) );
|
||||
EXPECT( y.equals(*cbn[_y_]) );
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianBayesNetOrdered, matrix )
|
||||
{
|
||||
// Create a test graph
|
||||
GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet();
|
||||
|
||||
Matrix R; Vector d;
|
||||
boost::tie(R,d) = matrix(cbn); // find matrix and RHS
|
||||
|
||||
Matrix R1 = Matrix_(2,2,
|
||||
1.0, 1.0,
|
||||
0.0, 1.0
|
||||
);
|
||||
Vector d1 = Vector_(2, 9.0, 5.0);
|
||||
|
||||
EXPECT(assert_equal(R,R1));
|
||||
EXPECT(assert_equal(d,d1));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianBayesNetOrdered, optimize )
|
||||
{
|
||||
GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet();
|
||||
VectorValuesOrdered actual = optimize(cbn);
|
||||
|
||||
VectorValuesOrdered expected(vector<size_t>(2,1));
|
||||
expected[_x_] = Vector_(1,4.);
|
||||
expected[_y_] = Vector_(1,5.);
|
||||
|
||||
EXPECT(assert_equal(expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianBayesNetOrdered, optimize2 )
|
||||
{
|
||||
|
||||
// Create empty graph
|
||||
GaussianFactorGraphOrdered fg;
|
||||
SharedDiagonal noise = noiseModel::Unit::Create(1);
|
||||
|
||||
fg.add(_y_, eye(1), 2*ones(1), noise);
|
||||
|
||||
fg.add(_x_, eye(1),_y_, -eye(1), -ones(1), noise);
|
||||
|
||||
fg.add(_y_, eye(1),_z_, -eye(1), -ones(1), noise);
|
||||
|
||||
fg.add(_x_, -eye(1), _z_, eye(1), 2*ones(1), noise);
|
||||
|
||||
VectorValuesOrdered actual = *GaussianSequentialSolver(fg).optimize();
|
||||
|
||||
VectorValuesOrdered expected(vector<size_t>(3,1));
|
||||
expected[_x_] = Vector_(1,1.);
|
||||
expected[_y_] = Vector_(1,2.);
|
||||
expected[_z_] = Vector_(1,3.);
|
||||
|
||||
EXPECT(assert_equal(expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianBayesNetOrdered, optimize3 )
|
||||
{
|
||||
// y=R*x, x=inv(R)*y
|
||||
// 9 = 1 1 4
|
||||
// 5 1 5
|
||||
// NOTE: we are supplying a new RHS here
|
||||
GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet();
|
||||
|
||||
VectorValuesOrdered expected(vector<size_t>(2,1)), x(vector<size_t>(2,1));
|
||||
expected[_x_] = Vector_(1, 4.);
|
||||
expected[_y_] = Vector_(1, 5.);
|
||||
|
||||
// test functional version
|
||||
VectorValuesOrdered actual = optimize(cbn);
|
||||
EXPECT(assert_equal(expected,actual));
|
||||
|
||||
// test imperative version
|
||||
optimizeInPlace(cbn,x);
|
||||
EXPECT(assert_equal(expected,x));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianBayesNetOrdered, backSubstituteTranspose )
|
||||
{
|
||||
// x=R'*y, y=inv(R')*x
|
||||
// 2 = 1 2
|
||||
// 5 1 1 3
|
||||
GaussianBayesNetOrdered cbn = createSmallGaussianBayesNet();
|
||||
|
||||
VectorValuesOrdered y(vector<size_t>(2,1)), x(vector<size_t>(2,1));
|
||||
x[_x_] = Vector_(1,2.);
|
||||
x[_y_] = Vector_(1,5.);
|
||||
y[_x_] = Vector_(1,2.);
|
||||
y[_y_] = Vector_(1,3.);
|
||||
|
||||
// test functional version
|
||||
VectorValuesOrdered actual = backSubstituteTranspose(cbn,x);
|
||||
EXPECT(assert_equal(y,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// Tests computing Determinant
|
||||
TEST( GaussianBayesNetOrdered, DeterminantTest )
|
||||
{
|
||||
GaussianBayesNetOrdered cbn;
|
||||
cbn += boost::shared_ptr<GaussianConditionalOrdered>(new GaussianConditionalOrdered(
|
||||
0, Vector_( 2, 3.0, 4.0 ), Matrix_(2, 2, 1.0, 3.0, 0.0, 4.0 ),
|
||||
1, Matrix_(2, 2, 2.0, 1.0, 2.0, 3.0),
|
||||
ones(2)));
|
||||
|
||||
cbn += boost::shared_ptr<GaussianConditionalOrdered>(new GaussianConditionalOrdered(
|
||||
1, Vector_( 2, 5.0, 6.0 ), Matrix_(2, 2, 1.0, 1.0, 0.0, 3.0 ),
|
||||
2, Matrix_(2, 2, 1.0, 0.0, 5.0, 2.0),
|
||||
ones(2)));
|
||||
|
||||
cbn += boost::shared_ptr<GaussianConditionalOrdered>(new GaussianConditionalOrdered(
|
||||
3, Vector_( 2, 7.0, 8.0 ), Matrix_(2, 2, 1.0, 1.0, 0.0, 5.0 ),
|
||||
ones(2)));
|
||||
|
||||
double expectedDeterminant = 60;
|
||||
double actualDeterminant = determinant(cbn);
|
||||
|
||||
EXPECT_DOUBLES_EQUAL( expectedDeterminant, actualDeterminant, 1e-9);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testGaussianFactor.cpp
|
||||
* @brief Unit tests for Linear Factor
|
||||
* @author Christian Potthast
|
||||
* @author Frank Dellaert
|
||||
**/
|
||||
|
||||
#include <tests/smallExample.h>
|
||||
#include <gtsam/nonlinear/Symbol.h>
|
||||
#include <gtsam/nonlinear/OrderingOrdered.h>
|
||||
#include <gtsam/linear/GaussianConditionalOrdered.h>
|
||||
#include <gtsam/base/Matrix.h>
|
||||
#include <gtsam/base/Testable.h>
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
#include <boost/assign/std/set.hpp>
|
||||
#include <boost/assign/std/map.hpp> // for insert
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
// Convenience for named keys
|
||||
using symbol_shorthand::X;
|
||||
using symbol_shorthand::L;
|
||||
|
||||
static SharedDiagonal
|
||||
sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1), sigma_02 = noiseModel::Isotropic::Sigma(2,0.2),
|
||||
constraintModel = noiseModel::Constrained::All(2);
|
||||
|
||||
//const Key kx1 = X(1), kx2 = X(2), kl1 = L(1); // FIXME: throws exception
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorOrdered, linearFactor )
|
||||
{
|
||||
const Key kx1 = X(1), kx2 = X(2), kl1 = L(1);
|
||||
OrderingOrdered ordering; ordering += kx1,kx2,kl1;
|
||||
|
||||
Matrix I = eye(2);
|
||||
Vector b = Vector_(2, 2.0, -1.0);
|
||||
JacobianFactorOrdered expected(ordering[kx1], -10*I,ordering[kx2], 10*I, b, noiseModel::Unit::Create(2));
|
||||
|
||||
// create a small linear factor graph
|
||||
GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering);
|
||||
|
||||
// get the factor kf2 from the factor graph
|
||||
JacobianFactorOrdered::shared_ptr lf =
|
||||
boost::dynamic_pointer_cast<JacobianFactorOrdered>(fg[1]);
|
||||
|
||||
// check if the two factors are the same
|
||||
EXPECT(assert_equal(expected,*lf));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorOrdered, getDim )
|
||||
{
|
||||
const Key kx1 = X(1), kx2 = X(2), kl1 = L(1);
|
||||
// get a factor
|
||||
OrderingOrdered ordering; ordering += kx1,kx2,kl1;
|
||||
GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering);
|
||||
GaussianFactorOrdered::shared_ptr factor = fg[0];
|
||||
|
||||
// get the size of a variable
|
||||
size_t actual = factor->getDim(factor->find(ordering[kx1]));
|
||||
|
||||
// verify
|
||||
size_t expected = 2;
|
||||
EXPECT_LONGS_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorOrdered, error )
|
||||
{
|
||||
const Key kx1 = X(1), kx2 = X(2), kl1 = L(1);
|
||||
// create a small linear factor graph
|
||||
OrderingOrdered ordering; ordering += kx1,kx2,kl1;
|
||||
GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering);
|
||||
|
||||
// get the first factor from the factor graph
|
||||
GaussianFactorOrdered::shared_ptr lf = fg[0];
|
||||
|
||||
// check the error of the first factor with noisy config
|
||||
VectorValuesOrdered cfg = example::createZeroDelta(ordering);
|
||||
|
||||
// calculate the error from the factor kf1
|
||||
// note the error is the same as in testNonlinearFactor
|
||||
double actual = lf->error(cfg);
|
||||
DOUBLES_EQUAL( 1.0, actual, 0.00000001 );
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorOrdered, matrix )
|
||||
{
|
||||
const Key kx1 = X(1), kx2 = X(2), kl1 = L(1);
|
||||
// create a small linear factor graph
|
||||
OrderingOrdered ordering; ordering += kx1,kx2,kl1;
|
||||
GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering);
|
||||
|
||||
// get the factor kf2 from the factor graph
|
||||
//GaussianFactorOrdered::shared_ptr lf = fg[1]; // NOTE: using the older version
|
||||
Vector b2 = Vector_(2, 0.2, -0.1);
|
||||
Matrix I = eye(2);
|
||||
// render with a given ordering
|
||||
OrderingOrdered ord;
|
||||
ord += kx1,kx2;
|
||||
JacobianFactorOrdered::shared_ptr lf(new JacobianFactorOrdered(ord[kx1], -I, ord[kx2], I, b2, sigma0_1));
|
||||
|
||||
// Test whitened version
|
||||
Matrix A_act1; Vector b_act1;
|
||||
boost::tie(A_act1,b_act1) = lf->matrix(true);
|
||||
|
||||
Matrix A1 = Matrix_(2,4,
|
||||
-10.0, 0.0, 10.0, 0.0,
|
||||
000.0,-10.0, 0.0, 10.0 );
|
||||
Vector b1 = Vector_(2, 2.0, -1.0);
|
||||
|
||||
EQUALITY(A_act1,A1);
|
||||
EQUALITY(b_act1,b1);
|
||||
|
||||
// Test unwhitened version
|
||||
Matrix A_act2; Vector b_act2;
|
||||
boost::tie(A_act2,b_act2) = lf->matrix(false);
|
||||
|
||||
|
||||
Matrix A2 = Matrix_(2,4,
|
||||
-1.0, 0.0, 1.0, 0.0,
|
||||
000.0,-1.0, 0.0, 1.0 );
|
||||
//Vector b2 = Vector_(2, 2.0, -1.0);
|
||||
|
||||
EQUALITY(A_act2,A2);
|
||||
EQUALITY(b_act2,b2);
|
||||
|
||||
// Ensure that whitening is consistent
|
||||
boost::shared_ptr<noiseModel::Gaussian> model = lf->get_model();
|
||||
model->WhitenSystem(A_act2, b_act2);
|
||||
EQUALITY(A_act1, A_act2);
|
||||
EQUALITY(b_act1, b_act2);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorOrdered, matrix_aug )
|
||||
{
|
||||
const Key kx1 = X(1), kx2 = X(2), kl1 = L(1);
|
||||
// create a small linear factor graph
|
||||
OrderingOrdered ordering; ordering += kx1,kx2,kl1;
|
||||
GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering);
|
||||
|
||||
// get the factor kf2 from the factor graph
|
||||
//GaussianFactorOrdered::shared_ptr lf = fg[1];
|
||||
Vector b2 = Vector_(2, 0.2, -0.1);
|
||||
Matrix I = eye(2);
|
||||
// render with a given ordering
|
||||
OrderingOrdered ord;
|
||||
ord += kx1,kx2;
|
||||
JacobianFactorOrdered::shared_ptr lf(new JacobianFactorOrdered(ord[kx1], -I, ord[kx2], I, b2, sigma0_1));
|
||||
|
||||
|
||||
// Test unwhitened version
|
||||
Matrix Ab_act1;
|
||||
Ab_act1 = lf->matrix_augmented(false);
|
||||
|
||||
Matrix Ab1 = Matrix_(2,5,
|
||||
-1.0, 0.0, 1.0, 0.0, 0.2,
|
||||
00.0,- 1.0, 0.0, 1.0, -0.1 );
|
||||
|
||||
EQUALITY(Ab_act1,Ab1);
|
||||
|
||||
// Test whitened version
|
||||
Matrix Ab_act2;
|
||||
Ab_act2 = lf->matrix_augmented(true);
|
||||
|
||||
Matrix Ab2 = Matrix_(2,5,
|
||||
-10.0, 0.0, 10.0, 0.0, 2.0,
|
||||
00.0, -10.0, 0.0, 10.0, -1.0 );
|
||||
|
||||
EQUALITY(Ab_act2,Ab2);
|
||||
|
||||
// Ensure that whitening is consistent
|
||||
boost::shared_ptr<noiseModel::Gaussian> model = lf->get_model();
|
||||
model->WhitenInPlace(Ab_act1);
|
||||
EQUALITY(Ab_act1, Ab_act2);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
// small aux. function to print out lists of anything
|
||||
template<class T>
|
||||
void print(const list<T>& i) {
|
||||
copy(i.begin(), i.end(), ostream_iterator<T> (cout, ","));
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( GaussianFactorOrdered, size )
|
||||
{
|
||||
// create a linear factor graph
|
||||
const Key kx1 = X(1), kx2 = X(2), kl1 = L(1);
|
||||
OrderingOrdered ordering; ordering += kx1,kx2,kl1;
|
||||
GaussianFactorGraphOrdered fg = example::createGaussianFactorGraph(ordering);
|
||||
|
||||
// get some factors from the graph
|
||||
boost::shared_ptr<GaussianFactorOrdered> factor1 = fg[0];
|
||||
boost::shared_ptr<GaussianFactorOrdered> factor2 = fg[1];
|
||||
boost::shared_ptr<GaussianFactorOrdered> factor3 = fg[2];
|
||||
|
||||
EXPECT_LONGS_EQUAL(1, factor1->size());
|
||||
EXPECT_LONGS_EQUAL(2, factor2->size());
|
||||
EXPECT_LONGS_EQUAL(2, factor3->size());
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testSymbolicBayesNetB.cpp
|
||||
* @brief Unit tests for a symbolic Bayes chain
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <boost/assign/list_inserter.hpp> // for 'insert()'
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <gtsam/base/Testable.h>
|
||||
#include <tests/smallExample.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
#include <gtsam/nonlinear/OrderingOrdered.h>
|
||||
#include <gtsam/nonlinear/Symbol.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
using namespace example;
|
||||
|
||||
using symbol_shorthand::X;
|
||||
using symbol_shorthand::L;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicBayesNetOrdered, constructor )
|
||||
{
|
||||
OrderingOrdered o; o += X(2),L(1),X(1);
|
||||
// Create manually
|
||||
IndexConditionalOrdered::shared_ptr
|
||||
x2(new IndexConditionalOrdered(o[X(2)],o[L(1)], o[X(1)])),
|
||||
l1(new IndexConditionalOrdered(o[L(1)],o[X(1)])),
|
||||
x1(new IndexConditionalOrdered(o[X(1)]));
|
||||
BayesNetOrdered<IndexConditionalOrdered> expected;
|
||||
expected.push_back(x2);
|
||||
expected.push_back(l1);
|
||||
expected.push_back(x1);
|
||||
|
||||
// Create from a factor graph
|
||||
GaussianFactorGraphOrdered factorGraph = createGaussianFactorGraph(o);
|
||||
SymbolicFactorGraphOrdered fg(factorGraph);
|
||||
|
||||
// eliminate it
|
||||
SymbolicBayesNetOrdered actual = *SymbolicSequentialSolver(fg).eliminate();
|
||||
|
||||
CHECK(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicBayesNetOrdered, FromGaussian) {
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(0, 1)));
|
||||
expected.push_back(IndexConditionalOrdered::shared_ptr(new IndexConditionalOrdered(1)));
|
||||
|
||||
GaussianBayesNetOrdered gbn = createSmallGaussianBayesNet();
|
||||
SymbolicBayesNetOrdered actual(gbn);
|
||||
|
||||
EXPECT(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* 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 testSymbolicFactorGraphB.cpp
|
||||
* @brief Unit tests for a symbolic Factor Graph
|
||||
* @author Frank Dellaert
|
||||
*/
|
||||
|
||||
#include <tests/smallExample.h>
|
||||
#include <gtsam/nonlinear/OrderingOrdered.h>
|
||||
#include <gtsam/nonlinear/Symbol.h>
|
||||
#include <gtsam/inference/SymbolicFactorGraphOrdered.h>
|
||||
#include <gtsam/inference/BayesNetOrdered-inl.h>
|
||||
#include <gtsam/inference/SymbolicSequentialSolverOrdered.h>
|
||||
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
|
||||
#include <boost/assign/std/list.hpp> // for operator +=
|
||||
using namespace boost::assign;
|
||||
|
||||
using namespace std;
|
||||
using namespace gtsam;
|
||||
|
||||
using symbol_shorthand::X;
|
||||
using symbol_shorthand::L;
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicFactorGraphOrdered, symbolicFactorGraph )
|
||||
{
|
||||
OrderingOrdered o; o += X(1),L(1),X(2);
|
||||
// construct expected symbolic graph
|
||||
SymbolicFactorGraphOrdered expected;
|
||||
expected.push_factor(o[X(1)]);
|
||||
expected.push_factor(o[X(1)],o[X(2)]);
|
||||
expected.push_factor(o[X(1)],o[L(1)]);
|
||||
expected.push_factor(o[X(2)],o[L(1)]);
|
||||
|
||||
// construct it from the factor graph
|
||||
GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(o);
|
||||
SymbolicFactorGraphOrdered actual(factorGraph);
|
||||
|
||||
CHECK(assert_equal(expected, actual));
|
||||
}
|
||||
|
||||
///* ************************************************************************* */
|
||||
//TEST( SymbolicFactorGraphOrdered, findAndRemoveFactors )
|
||||
//{
|
||||
// // construct it from the factor graph graph
|
||||
// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph();
|
||||
// SymbolicFactorGraphOrdered actual(factorGraph);
|
||||
// SymbolicFactor::shared_ptr f1 = actual[0];
|
||||
// SymbolicFactor::shared_ptr f3 = actual[2];
|
||||
// actual.findAndRemoveFactors(X(2));
|
||||
//
|
||||
// // construct expected graph after find_factors_and_remove
|
||||
// SymbolicFactorGraphOrdered expected;
|
||||
// SymbolicFactor::shared_ptr null;
|
||||
// expected.push_back(f1);
|
||||
// expected.push_back(null);
|
||||
// expected.push_back(f3);
|
||||
// expected.push_back(null);
|
||||
//
|
||||
// CHECK(assert_equal(expected, actual));
|
||||
//}
|
||||
///* ************************************************************************* */
|
||||
//TEST( SymbolicFactorGraphOrdered, factors)
|
||||
//{
|
||||
// // create a test graph
|
||||
// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph();
|
||||
// SymbolicFactorGraphOrdered fg(factorGraph);
|
||||
//
|
||||
// // ask for all factor indices connected to x1
|
||||
// list<size_t> x1_factors = fg.factors(X(1));
|
||||
// int x1_indices[] = { 0, 1, 2 };
|
||||
// list<size_t> x1_expected(x1_indices, x1_indices + 3);
|
||||
// CHECK(x1_factors==x1_expected);
|
||||
//
|
||||
// // ask for all factor indices connected to x2
|
||||
// list<size_t> x2_factors = fg.factors(X(2));
|
||||
// int x2_indices[] = { 1, 3 };
|
||||
// list<size_t> x2_expected(x2_indices, x2_indices + 2);
|
||||
// CHECK(x2_factors==x2_expected);
|
||||
//}
|
||||
|
||||
///* ************************************************************************* */
|
||||
//TEST( SymbolicFactorGraphOrdered, removeAndCombineFactors )
|
||||
//{
|
||||
// // create a test graph
|
||||
// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph();
|
||||
// SymbolicFactorGraphOrdered fg(factorGraph);
|
||||
//
|
||||
// // combine all factors connected to x1
|
||||
// SymbolicFactor::shared_ptr actual = removeAndCombineFactors(fg,X(1));
|
||||
//
|
||||
// // check result
|
||||
// SymbolicFactor expected(L(1),X(1),X(2));
|
||||
// CHECK(assert_equal(expected,*actual));
|
||||
//}
|
||||
|
||||
///* ************************************************************************* */
|
||||
//TEST( SymbolicFactorGraphOrdered, eliminateOne )
|
||||
//{
|
||||
// OrderingOrdered o; o += X(1),L(1),X(2);
|
||||
// // create a test graph
|
||||
// GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(o);
|
||||
// SymbolicFactorGraphOrdered fg(factorGraph);
|
||||
//
|
||||
// // eliminate
|
||||
// IndexConditionalOrdered::shared_ptr actual = GaussianSequentialSolver::EliminateUntil(fg, o[X(1)]+1);
|
||||
//
|
||||
// // create expected symbolic IndexConditional
|
||||
// IndexConditionalOrdered expected(o[X(1)],o[L(1)],o[X(2)]);
|
||||
//
|
||||
// CHECK(assert_equal(expected,*actual));
|
||||
//}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST( SymbolicFactorGraphOrdered, eliminate )
|
||||
{
|
||||
OrderingOrdered o; o += X(2),L(1),X(1);
|
||||
|
||||
// create expected Chordal bayes Net
|
||||
IndexConditionalOrdered::shared_ptr x2(new IndexConditionalOrdered(o[X(2)], o[L(1)], o[X(1)]));
|
||||
IndexConditionalOrdered::shared_ptr l1(new IndexConditionalOrdered(o[L(1)], o[X(1)]));
|
||||
IndexConditionalOrdered::shared_ptr x1(new IndexConditionalOrdered(o[X(1)]));
|
||||
|
||||
SymbolicBayesNetOrdered expected;
|
||||
expected.push_back(x2);
|
||||
expected.push_back(l1);
|
||||
expected.push_back(x1);
|
||||
|
||||
// create a test graph
|
||||
GaussianFactorGraphOrdered factorGraph = example::createGaussianFactorGraph(o);
|
||||
SymbolicFactorGraphOrdered fg(factorGraph);
|
||||
|
||||
// eliminate it
|
||||
SymbolicBayesNetOrdered actual = *SymbolicSequentialSolver(fg).eliminate();
|
||||
|
||||
CHECK(assert_equal(expected,actual));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() {
|
||||
TestResult tr;
|
||||
return TestRegistry::runAllTests(tr);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
Loading…
Reference in New Issue