Made EliminationTree generic, with Symbolic and Gaussian unit tests
parent
fc66445be8
commit
130d9d2797
|
@ -71,7 +71,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
/* 4.2.1 Alternatively, you can go through the process step by step
|
/* 4.2.1 Alternatively, you can go through the process step by step
|
||||||
* Choose an ordering */
|
* Choose an ordering */
|
||||||
Ordering::shared_ptr ordering = graph->orderingCOLAMD(*initialEstimate).first;
|
Ordering::shared_ptr ordering = graph->orderingCOLAMD(*initialEstimate);
|
||||||
|
|
||||||
/* 4.2.2 set up solver and optimize */
|
/* 4.2.2 set up solver and optimize */
|
||||||
Optimizer::shared_solver solver(new Optimizer::solver(ordering));
|
Optimizer::shared_solver solver(new Optimizer::solver(ordering));
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
/**
|
||||||
|
* @file EliminationTree.cpp
|
||||||
|
* @brief
|
||||||
|
* @author Frank Dellaert
|
||||||
|
* @created Oct 13, 2010
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtsam/inference/EliminationTree.h>
|
||||||
|
#include <gtsam/inference/VariableSlots-inl.h>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/lambda/lambda.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace gtsam {
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
template<class FACTORGRAPH>
|
||||||
|
typename EliminationTree<FACTORGRAPH>::EliminationResult
|
||||||
|
EliminationTree<FACTORGRAPH>::eliminate_() const {
|
||||||
|
|
||||||
|
typename FACTORGRAPH::bayesnet_type bayesNet;
|
||||||
|
|
||||||
|
set<Index, std::less<Index>, boost::fast_pool_allocator<Index> > separator;
|
||||||
|
|
||||||
|
// Create the list of factors to be eliminated
|
||||||
|
FACTORGRAPH factors;
|
||||||
|
factors.reserve(this->factors_.size() + this->subTrees_.size());
|
||||||
|
|
||||||
|
// add all factors associated with root
|
||||||
|
factors.push_back(this->factors_.begin(), this->factors_.end());
|
||||||
|
|
||||||
|
// for all children, eliminate into Bayes net and add the eliminated factors
|
||||||
|
BOOST_FOREACH(const shared_ptr& child, subTrees_) {
|
||||||
|
EliminationResult result = child->eliminate_();
|
||||||
|
bayesNet.push_back(result.first);
|
||||||
|
factors.push_back(result.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eliminate the joint factor and add the conditional to the bayes net
|
||||||
|
typename FACTORGRAPH::sharedFactor jointFactor(FACTORGRAPH::factor_type::Combine(factors, VariableSlots(factors)));
|
||||||
|
bayesNet.push_back(jointFactor->eliminateFirst());
|
||||||
|
|
||||||
|
return EliminationResult(bayesNet, jointFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
template<class FACTORGRAPH>
|
||||||
|
vector<Index> EliminationTree<FACTORGRAPH>::ComputeParents(const VariableIndex<>& structure) {
|
||||||
|
|
||||||
|
// Number of factors and variables
|
||||||
|
const size_t m = structure.nFactors();
|
||||||
|
const size_t n = structure.size();
|
||||||
|
|
||||||
|
static const Index none = numeric_limits<Index>::max();
|
||||||
|
|
||||||
|
// Allocate result parent vector and vector of last factor columns
|
||||||
|
vector<Index> parents(n, none);
|
||||||
|
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(typename VariableIndex<>::mapped_factor_type i_pos, structure[j]) {
|
||||||
|
const size_t i = i_pos.factorIndex;
|
||||||
|
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 FACTORGRAPH>
|
||||||
|
typename EliminationTree<FACTORGRAPH>::shared_ptr
|
||||||
|
EliminationTree<FACTORGRAPH>::Create(const FACTORGRAPH& factorGraph) {
|
||||||
|
|
||||||
|
// Create column structure
|
||||||
|
VariableIndex<> varIndex(factorGraph);
|
||||||
|
|
||||||
|
// Compute the tree structure
|
||||||
|
vector<Index> parents(ComputeParents(varIndex));
|
||||||
|
|
||||||
|
// Number of variables
|
||||||
|
const size_t n = varIndex.size();
|
||||||
|
|
||||||
|
static const Index none = numeric_limits<Index>::max();
|
||||||
|
|
||||||
|
// Create tree structure
|
||||||
|
vector<shared_ptr> trees(n);
|
||||||
|
for (Index k = 1; k <= n; k++) {
|
||||||
|
Index j = n - k;
|
||||||
|
trees[j].reset(new EliminationTree(j));
|
||||||
|
if (parents[j] != none)
|
||||||
|
trees[parents[j]]->add(trees[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hang factors in right places
|
||||||
|
BOOST_FOREACH(const sharedFactor& factor, factorGraph) {
|
||||||
|
Index j = factor->front();
|
||||||
|
trees[j]->add(factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert that all other nodes have parents, i.e. that this is not a forest.
|
||||||
|
#ifndef NDEBUG
|
||||||
|
for(typename vector<shared_ptr>::const_iterator tree=trees.begin(); tree!=trees.end()-1; ++tree)
|
||||||
|
assert((*tree) != shared_ptr());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return trees.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
template<class FACTORGRAPH>
|
||||||
|
void EliminationTree<FACTORGRAPH>::print(const std::string& name) const {
|
||||||
|
cout << name << " (" << key_ << ")" << endl;
|
||||||
|
BOOST_FOREACH(const sharedFactor& factor, factors_) {
|
||||||
|
factor->print(name + " "); }
|
||||||
|
BOOST_FOREACH(const shared_ptr& child, subTrees_) {
|
||||||
|
child->print(name + " "); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
template<class FACTORGRAPH>
|
||||||
|
bool EliminationTree<FACTORGRAPH>::equals(const EliminationTree<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 FACTORGRAPH>
|
||||||
|
typename FACTORGRAPH::bayesnet_type::shared_ptr EliminationTree<FACTORGRAPH>::eliminate() const {
|
||||||
|
|
||||||
|
// call recursive routine
|
||||||
|
EliminationResult result = eliminate_();
|
||||||
|
return typename FACTORGRAPH::bayesnet_type::shared_ptr(new typename FACTORGRAPH::bayesnet_type(result.first));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
* @file EliminationTree.h
|
||||||
|
* @brief
|
||||||
|
* @author Frank Dellaert
|
||||||
|
* @created Oct 13, 2010
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <boost/pool/pool_alloc.hpp>
|
||||||
|
|
||||||
|
#include <gtsam/inference/VariableIndex.h>
|
||||||
|
|
||||||
|
class EliminationTreeTester; // for unit tests, see testEliminationTree
|
||||||
|
|
||||||
|
namespace gtsam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An elimination tree is a tree of factors
|
||||||
|
*/
|
||||||
|
template<class FACTORGRAPH>
|
||||||
|
class EliminationTree: public Testable<EliminationTree<FACTORGRAPH> > {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<typename FACTORGRAPH::factor_type> sharedFactor;
|
||||||
|
typedef boost::shared_ptr<EliminationTree<FACTORGRAPH> > shared_ptr;
|
||||||
|
typedef FACTORGRAPH FactorGraph;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::list<sharedFactor, boost::fast_pool_allocator<sharedFactor> > Factors;
|
||||||
|
typedef std::list<shared_ptr, boost::fast_pool_allocator<shared_ptr> > SubTrees;
|
||||||
|
|
||||||
|
Index key_; /** index associated with root */
|
||||||
|
Factors factors_; /** factors associated with root */
|
||||||
|
SubTrees subTrees_; /** sub-trees */
|
||||||
|
|
||||||
|
typedef std::pair<typename FACTORGRAPH::bayesnet_type, typename FACTORGRAPH::sharedFactor> EliminationResult;
|
||||||
|
|
||||||
|
/** default constructor, private, as you should use Create below */
|
||||||
|
EliminationTree(Index key = 0) : key_(key) {}
|
||||||
|
|
||||||
|
/** 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); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 VariableIndex<>& structure);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive routine that eliminates the factors arranged in an elimination tree
|
||||||
|
*/
|
||||||
|
EliminationResult eliminate_() const;
|
||||||
|
|
||||||
|
// Allow access to constructor and add methods for testing purposes
|
||||||
|
friend class ::EliminationTreeTester;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Named constructor to build the elimination tree of a factor graph */
|
||||||
|
static shared_ptr Create(const FACTORGRAPH& factorGraph);
|
||||||
|
|
||||||
|
/** Print the tree to cout */
|
||||||
|
void print(const std::string& name = "EliminationTree: ") const;
|
||||||
|
|
||||||
|
/** Test whether the tree is equal to another */
|
||||||
|
bool equals(const EliminationTree& other, double tol = 1e-9) const;
|
||||||
|
|
||||||
|
/** Eliminate the factors to a Bayes Net */
|
||||||
|
typename FACTORGRAPH::bayesnet_type::shared_ptr eliminate() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -85,6 +85,10 @@ namespace gtsam {
|
||||||
/** push back many factors */
|
/** push back many factors */
|
||||||
void push_back(const FactorGraph<Factor>& factors);
|
void push_back(const FactorGraph<Factor>& factors);
|
||||||
|
|
||||||
|
/** push back many factors with an iterator */
|
||||||
|
template<typename Iterator>
|
||||||
|
void push_back(Iterator firstFactor, Iterator lastFactor);
|
||||||
|
|
||||||
/** ------------------ Querying Factor Graphs ---------------------------- */
|
/** ------------------ Querying Factor Graphs ---------------------------- */
|
||||||
|
|
||||||
/** print out graph */
|
/** print out graph */
|
||||||
|
@ -249,6 +253,14 @@ namespace gtsam {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
template<class Factor>
|
||||||
|
template<typename Iterator>
|
||||||
|
void FactorGraph<Factor>::push_back(Iterator firstFactor, Iterator lastFactor) {
|
||||||
|
Iterator factor = firstFactor;
|
||||||
|
while(factor != lastFactor)
|
||||||
|
this->push_back(*(factor++));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gtsam
|
} // namespace gtsam
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ headers += VariableIndex.h
|
||||||
headers += FactorGraph.h FactorGraph-inl.h
|
headers += FactorGraph.h FactorGraph-inl.h
|
||||||
headers += ClusterTree.h ClusterTree-inl.h
|
headers += ClusterTree.h ClusterTree-inl.h
|
||||||
headers += JunctionTree.h JunctionTree-inl.h
|
headers += JunctionTree.h JunctionTree-inl.h
|
||||||
#headers += EliminationTree.h EliminationTree-inl.h
|
headers += EliminationTree.h EliminationTree-inl.h
|
||||||
headers += BayesNet.h BayesNet-inl.h
|
headers += BayesNet.h BayesNet-inl.h
|
||||||
headers += BayesTree.h BayesTree-inl.h
|
headers += BayesTree.h BayesTree-inl.h
|
||||||
headers += ISAM.h ISAM-inl.h
|
headers += ISAM.h ISAM-inl.h
|
||||||
|
@ -38,7 +38,7 @@ check_PROGRAMS += tests/testFactorGraph
|
||||||
check_PROGRAMS += tests/testFactorGraph
|
check_PROGRAMS += tests/testFactorGraph
|
||||||
check_PROGRAMS += tests/testBayesTree
|
check_PROGRAMS += tests/testBayesTree
|
||||||
check_PROGRAMS += tests/testISAM
|
check_PROGRAMS += tests/testISAM
|
||||||
#check_PROGRAMS += tests/testEliminationTree
|
check_PROGRAMS += tests/testEliminationTree
|
||||||
check_PROGRAMS += tests/testClusterTree
|
check_PROGRAMS += tests/testClusterTree
|
||||||
check_PROGRAMS += tests/testJunctionTree
|
check_PROGRAMS += tests/testJunctionTree
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <gtsam/inference/BayesNet-inl.h>
|
#include <gtsam/inference/BayesNet-inl.h>
|
||||||
#include <gtsam/inference/Factor-inl.h>
|
#include <gtsam/inference/Factor-inl.h>
|
||||||
#include <gtsam/inference/inference-inl.h>
|
#include <gtsam/inference/inference-inl.h>
|
||||||
|
#include <gtsam/inference/EliminationTree-inl.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ namespace gtsam {
|
||||||
// Explicitly instantiate so we don't have to include everywhere
|
// Explicitly instantiate so we don't have to include everywhere
|
||||||
template class FactorGraph<Factor>;
|
template class FactorGraph<Factor>;
|
||||||
template class BayesNet<Conditional>;
|
template class BayesNet<Conditional>;
|
||||||
|
template class EliminationTree<SymbolicFactorGraph>;
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
SymbolicFactorGraph::SymbolicFactorGraph(const BayesNet<Conditional>& bayesNet) :
|
SymbolicFactorGraph::SymbolicFactorGraph(const BayesNet<Conditional>& bayesNet) :
|
||||||
|
|
|
@ -80,7 +80,6 @@ public:
|
||||||
const mapped_type& operator[](Index variable) const { checkVar(variable); return index_[variable]; }
|
const mapped_type& operator[](Index variable) const { checkVar(variable); return index_[variable]; }
|
||||||
mapped_type& operator[](Index variable) { checkVar(variable); return index_[variable]; }
|
mapped_type& operator[](Index variable) { checkVar(variable); return index_[variable]; }
|
||||||
void permute(const Permutation& permutation);
|
void permute(const Permutation& permutation);
|
||||||
// template<class Derived> void augment(const Derived& varIndex);
|
|
||||||
template<class FactorGraph> void augment(const FactorGraph& factorGraph);
|
template<class FactorGraph> void augment(const FactorGraph& factorGraph);
|
||||||
void rebaseFactors(ptrdiff_t baseIndexChange);
|
void rebaseFactors(ptrdiff_t baseIndexChange);
|
||||||
|
|
||||||
|
@ -154,21 +153,6 @@ VariableIndex<Storage>::VariableIndex(const FactorGraph& factorGraph) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///* ************************************************************************* */
|
|
||||||
//template<class Storage>
|
|
||||||
//template<class Derived>
|
|
||||||
//void VariableIndex<Storage>::augment(const Derived& varIndex) {
|
|
||||||
// nFactors_ = std::max(nFactors_, varIndex.nFactors());
|
|
||||||
// nEntries_ = nEntries_ + varIndex.nEntries();
|
|
||||||
// Index originalSize = index_.size();
|
|
||||||
// index_.container().resize(std::max(index_.size(), varIndex.size()));
|
|
||||||
// index_.permutation().resize(index_.container().size());
|
|
||||||
// for(Index var=originalSize; var<index_.permutation().size(); ++var)
|
|
||||||
// index_.permutation()[var] = var;
|
|
||||||
// for(Index var=0; var<varIndex.size(); ++var)
|
|
||||||
// index_[var].insert(index_[var].begin(), varIndex[var].begin(), varIndex[var].end());
|
|
||||||
//}
|
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
template<class Storage>
|
template<class Storage>
|
||||||
template<class FactorGraph>
|
template<class FactorGraph>
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/**
|
||||||
|
* @file testEliminationTree.cpp
|
||||||
|
* @brief
|
||||||
|
* @author Richard Roberts
|
||||||
|
* @created Oct 14, 2010
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtsam/CppUnitLite/TestHarness.h>
|
||||||
|
#include <gtsam/base/TestableAssertions.h>
|
||||||
|
|
||||||
|
#include <gtsam/inference/EliminationTree.h>
|
||||||
|
#include <gtsam/inference/SymbolicFactorGraph.h>
|
||||||
|
|
||||||
|
using namespace gtsam;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef EliminationTree<SymbolicFactorGraph> SymbolicEliminationTree;
|
||||||
|
|
||||||
|
struct EliminationTreeTester {
|
||||||
|
// build hardcoded tree
|
||||||
|
static SymbolicEliminationTree::shared_ptr buildHardcodedTree(const SymbolicFactorGraph& fg) {
|
||||||
|
|
||||||
|
SymbolicEliminationTree::shared_ptr leaf0(new SymbolicEliminationTree);
|
||||||
|
leaf0->add(fg[0]);
|
||||||
|
leaf0->add(fg[1]);
|
||||||
|
|
||||||
|
SymbolicEliminationTree::shared_ptr node1(new SymbolicEliminationTree(1));
|
||||||
|
node1->add(fg[2]);
|
||||||
|
node1->add(leaf0);
|
||||||
|
|
||||||
|
SymbolicEliminationTree::shared_ptr node2(new SymbolicEliminationTree(2));
|
||||||
|
node2->add(fg[3]);
|
||||||
|
node2->add(node1);
|
||||||
|
|
||||||
|
SymbolicEliminationTree::shared_ptr leaf3(new SymbolicEliminationTree(3));
|
||||||
|
leaf3->add(fg[4]);
|
||||||
|
|
||||||
|
SymbolicEliminationTree::shared_ptr etree(new SymbolicEliminationTree(4));
|
||||||
|
etree->add(leaf3);
|
||||||
|
etree->add(node2);
|
||||||
|
|
||||||
|
return etree;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(EliminationTree, Create)
|
||||||
|
{
|
||||||
|
// create example factor graph
|
||||||
|
SymbolicFactorGraph 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);
|
||||||
|
|
||||||
|
SymbolicEliminationTree::shared_ptr expected = EliminationTreeTester::buildHardcodedTree(fg);
|
||||||
|
|
||||||
|
// Build from factor graph
|
||||||
|
SymbolicEliminationTree::shared_ptr actual = SymbolicEliminationTree::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(EliminationTree, eliminate )
|
||||||
|
{
|
||||||
|
// create expected Chordal bayes Net
|
||||||
|
Conditional::shared_ptr c0(new Conditional(0, 1, 2));
|
||||||
|
Conditional::shared_ptr c1(new Conditional(1, 2, 4));
|
||||||
|
Conditional::shared_ptr c2(new Conditional(2, 4));
|
||||||
|
Conditional::shared_ptr c3(new Conditional(3, 4));
|
||||||
|
Conditional::shared_ptr c4(new Conditional(4));
|
||||||
|
|
||||||
|
SymbolicBayesNet expected;
|
||||||
|
expected.push_back(c3);
|
||||||
|
expected.push_back(c0);
|
||||||
|
expected.push_back(c1);
|
||||||
|
expected.push_back(c2);
|
||||||
|
expected.push_back(c4);
|
||||||
|
|
||||||
|
// Create factor graph
|
||||||
|
SymbolicFactorGraph 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
|
||||||
|
SymbolicBayesNet actual = *SymbolicEliminationTree::Create(fg)->eliminate();
|
||||||
|
|
||||||
|
CHECK(assert_equal(expected,actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
int main() {
|
||||||
|
TestResult tr;
|
||||||
|
return TestRegistry::runAllTests(tr);
|
||||||
|
}
|
||||||
|
/* ************************************************************************* */
|
|
@ -102,297 +102,296 @@ TEST( SymbolicFactorGraph, push_back )
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
||||||
/**
|
///**
|
||||||
* An elimination tree is a tree of factors
|
// * An elimination tree is a tree of factors
|
||||||
*/
|
// */
|
||||||
class ETree: public Testable<ETree> {
|
//class ETree: public Testable<ETree> {
|
||||||
|
//
|
||||||
|
//public:
|
||||||
|
//
|
||||||
|
// typedef boost::shared_ptr<Factor> sharedFactor;
|
||||||
|
// typedef boost::shared_ptr<ETree> shared_ptr;
|
||||||
|
//
|
||||||
|
//private:
|
||||||
|
//
|
||||||
|
// Index key_; /** index associated with root */
|
||||||
|
// list<sharedFactor> factors_; /** factors associated with root */
|
||||||
|
// list<shared_ptr> subTrees_; /** sub-trees */
|
||||||
|
//
|
||||||
|
// typedef pair<SymbolicBayesNet, Factor> Result;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Recursive routine that eliminates the factors arranged in an elimination tree
|
||||||
|
// */
|
||||||
|
// Result eliminate_() const {
|
||||||
|
//
|
||||||
|
// SymbolicBayesNet bn;
|
||||||
|
//
|
||||||
|
// set<Index> separator;
|
||||||
|
//
|
||||||
|
// // loop over all factors associated with root
|
||||||
|
// // and set-union their keys to a separator
|
||||||
|
// BOOST_FOREACH(const sharedFactor& factor, factors_)
|
||||||
|
// BOOST_FOREACH(Index key, *factor) {
|
||||||
|
// if (key != key_) separator.insert(key); }
|
||||||
|
//
|
||||||
|
// // for all children, eliminate into Bayes net
|
||||||
|
// BOOST_FOREACH(const shared_ptr& child, subTrees_) {
|
||||||
|
// Result result = child->eliminate_();
|
||||||
|
// bn.push_back(result.first);
|
||||||
|
// BOOST_FOREACH(Index key, result.second)
|
||||||
|
// if (key != key_) separator.insert(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Make the conditional from the key and separator, and insert it in Bayes net
|
||||||
|
// vector<Index> parents;
|
||||||
|
// std::copy(separator.begin(), separator.end(), back_inserter(parents));
|
||||||
|
// Conditional::shared_ptr conditional(new Conditional(key_, parents));
|
||||||
|
// bn.push_back(conditional);
|
||||||
|
//
|
||||||
|
// // now create the new factor from separator to return to caller
|
||||||
|
// Factor newFactor(separator.begin(), separator.end());
|
||||||
|
// return Result(bn, newFactor);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//public:
|
||||||
|
//
|
||||||
|
// /** default constructor */
|
||||||
|
// ETree(Index key = 0) :
|
||||||
|
// key_(key) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /** add a factor */
|
||||||
|
// void add(const sharedFactor& factor) {
|
||||||
|
// factors_.push_back(factor);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /** add a subtree */
|
||||||
|
// void add(const shared_ptr& child) {
|
||||||
|
// subTrees_.push_back(child);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// void print(const std::string& name) const {
|
||||||
|
// cout << name << " (" << key_ << ")" << endl;
|
||||||
|
// BOOST_FOREACH(const sharedFactor& factor, factors_)
|
||||||
|
// factor->print(name + " ");
|
||||||
|
// BOOST_FOREACH(const shared_ptr& child, subTrees_)
|
||||||
|
// child->print(name + " ");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// bool equals(const ETree& expected, double tol) const {
|
||||||
|
// // todo
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Eliminate the factors to a Bayes Net
|
||||||
|
// */
|
||||||
|
// SymbolicBayesNet eliminate() const {
|
||||||
|
//
|
||||||
|
// // call recursive routine
|
||||||
|
// Result result = eliminate_();
|
||||||
|
// return result.first;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//// build hardcoded tree
|
||||||
|
//ETree::shared_ptr buildHardcodedTree(const SymbolicFactorGraph& fg) {
|
||||||
|
//
|
||||||
|
// ETree::shared_ptr leaf0(new ETree);
|
||||||
|
// leaf0->add(fg[0]);
|
||||||
|
// leaf0->add(fg[1]);
|
||||||
|
//
|
||||||
|
// ETree::shared_ptr node1(new ETree(1));
|
||||||
|
// node1->add(fg[2]);
|
||||||
|
// node1->add(leaf0);
|
||||||
|
//
|
||||||
|
// ETree::shared_ptr node2(new ETree(2));
|
||||||
|
// node2->add(fg[3]);
|
||||||
|
// node2->add(node1);
|
||||||
|
//
|
||||||
|
// ETree::shared_ptr leaf3(new ETree(3));
|
||||||
|
// leaf3->add(fg[4]);
|
||||||
|
//
|
||||||
|
// ETree::shared_ptr etree(new ETree(4));
|
||||||
|
// etree->add(leaf3);
|
||||||
|
// etree->add(node2);
|
||||||
|
//
|
||||||
|
// return etree;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//typedef size_t RowIndex;
|
||||||
|
//typedef vector<list<RowIndex> > StructA;
|
||||||
|
//typedef vector<boost::optional<Index> > optionalIndices;
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Gilbert01bit algorithm in Figure 2.2
|
||||||
|
// */
|
||||||
|
//optionalIndices buildETree(const StructA& structA) {
|
||||||
|
//
|
||||||
|
// // todo: get n
|
||||||
|
// size_t n = 5;
|
||||||
|
// optionalIndices parent(n);
|
||||||
|
//
|
||||||
|
// // todo: get m
|
||||||
|
// size_t m = 5;
|
||||||
|
// optionalIndices prev_col(m);
|
||||||
|
//
|
||||||
|
// // 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(RowIndex i, structA[j]) {
|
||||||
|
// if (prev_col[i]) {
|
||||||
|
// Index k = *(prev_col[i]);
|
||||||
|
// // find root r of the current tree that contains k
|
||||||
|
// Index r = k;
|
||||||
|
// while (parent[r])
|
||||||
|
// r = *parent[r];
|
||||||
|
// if (r != j) parent[r].reset(j);
|
||||||
|
// }
|
||||||
|
// prev_col[i].reset(j);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return parent;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * TODO: Build StructA from factor graph
|
||||||
|
// */
|
||||||
|
//StructA createStructA(const SymbolicFactorGraph& fg) {
|
||||||
|
//
|
||||||
|
// StructA structA;
|
||||||
|
//
|
||||||
|
// // hardcode for now
|
||||||
|
// list<RowIndex> list0;
|
||||||
|
// list0 += 0, 1;
|
||||||
|
// structA.push_back(list0);
|
||||||
|
// list<RowIndex> list1;
|
||||||
|
// list1 += 0, 2;
|
||||||
|
// structA.push_back(list1);
|
||||||
|
// list<RowIndex> list2;
|
||||||
|
// list2 += 1, 3;
|
||||||
|
// structA.push_back(list2);
|
||||||
|
// list<RowIndex> list3;
|
||||||
|
// list3 += 4;
|
||||||
|
// structA.push_back(list3);
|
||||||
|
// list<RowIndex> list4;
|
||||||
|
// list4 += 2, 3, 4;
|
||||||
|
// structA.push_back(list4);
|
||||||
|
//
|
||||||
|
// return structA;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Build ETree from factor graph and parent indices
|
||||||
|
// */
|
||||||
|
//ETree::shared_ptr buildETree(const SymbolicFactorGraph& fg, const optionalIndices& parent) {
|
||||||
|
//
|
||||||
|
// // todo: get n
|
||||||
|
// size_t n = 5;
|
||||||
|
//
|
||||||
|
// // Create tree structure
|
||||||
|
// vector<ETree::shared_ptr> trees(n);
|
||||||
|
// for (Index k = 1; k <= n; k++) {
|
||||||
|
// Index j = n - k;
|
||||||
|
// trees[j].reset(new ETree(j));
|
||||||
|
// if (parent[j]) trees[*parent[j]]->add(trees[j]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Hang factors in right places
|
||||||
|
// BOOST_FOREACH(const ETree::sharedFactor& factor, fg)
|
||||||
|
// {
|
||||||
|
// Index j = factor->front();
|
||||||
|
// trees[j]->add(factor);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return trees[n - 1];
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///* ************************************************************************* */
|
||||||
|
//// Test of elimination tree creation
|
||||||
|
//// graph: f(0,1) f(0,2) f(1,4) f(2,4) f(3,4)
|
||||||
|
///* ************************************************************************* */
|
||||||
|
///**
|
||||||
|
// * Build ETree from factor graph
|
||||||
|
// */
|
||||||
|
//ETree::shared_ptr buildETree(const SymbolicFactorGraph& fg) {
|
||||||
|
//
|
||||||
|
// // create vector of factor indices
|
||||||
|
// StructA structA = createStructA(fg);
|
||||||
|
//
|
||||||
|
// // call Gilbert01bit algorithm
|
||||||
|
// optionalIndices parent = buildETree(structA);
|
||||||
|
//
|
||||||
|
// // Build ETree from factor graph and parent indices
|
||||||
|
// return buildETree(fg, parent);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//TEST( ETree, buildETree )
|
||||||
|
//{
|
||||||
|
// // create example factor graph
|
||||||
|
// SymbolicFactorGraph 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);
|
||||||
|
//
|
||||||
|
// ETree::shared_ptr expected = buildHardcodedTree(fg);
|
||||||
|
//
|
||||||
|
// // Build from factor graph
|
||||||
|
// ETree::shared_ptr actual = buildETree(fg);
|
||||||
|
//
|
||||||
|
// // todo: 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)
|
||||||
|
///* ************************************************************************* */
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Eliminate factor graph
|
||||||
|
// */
|
||||||
|
//SymbolicBayesNet eliminate(const SymbolicFactorGraph& fg) {
|
||||||
|
//
|
||||||
|
// // build etree
|
||||||
|
// ETree::shared_ptr etree = buildETree(fg);
|
||||||
|
//
|
||||||
|
// return etree->eliminate();
|
||||||
|
//}
|
||||||
|
|
||||||
public:
|
//TEST( SymbolicFactorGraph, eliminate )
|
||||||
|
//{
|
||||||
typedef boost::shared_ptr<Factor> sharedFactor;
|
// // create expected Chordal bayes Net
|
||||||
typedef boost::shared_ptr<ETree> shared_ptr;
|
// Conditional::shared_ptr c0(new Conditional(0, 1, 2));
|
||||||
|
// Conditional::shared_ptr c1(new Conditional(1, 2, 4));
|
||||||
private:
|
// Conditional::shared_ptr c2(new Conditional(2, 4));
|
||||||
|
// Conditional::shared_ptr c3(new Conditional(3, 4));
|
||||||
Index key_; /** index associated with root */
|
// Conditional::shared_ptr c4(new Conditional(4));
|
||||||
list<sharedFactor> factors_; /** factors associated with root */
|
//
|
||||||
list<shared_ptr> subTrees_; /** sub-trees */
|
// SymbolicBayesNet expected;
|
||||||
|
// expected.push_back(c3);
|
||||||
typedef pair<SymbolicBayesNet, Factor> Result;
|
// expected.push_back(c0);
|
||||||
|
// expected.push_back(c1);
|
||||||
/**
|
// expected.push_back(c2);
|
||||||
* Recursive routine that eliminates the factors arranged in an elimination tree
|
// expected.push_back(c4);
|
||||||
*/
|
//
|
||||||
Result eliminate_() const {
|
// // Create factor graph
|
||||||
|
// SymbolicFactorGraph fg;
|
||||||
SymbolicBayesNet bn;
|
// fg.push_factor(0, 1);
|
||||||
|
// fg.push_factor(0, 2);
|
||||||
set<Index> separator;
|
// fg.push_factor(1, 4);
|
||||||
|
// fg.push_factor(2, 4);
|
||||||
// loop over all factors associated with root
|
// fg.push_factor(3, 4);
|
||||||
// and set-union their keys to a separator
|
//
|
||||||
BOOST_FOREACH(const sharedFactor& factor, factors_)
|
// // eliminate
|
||||||
BOOST_FOREACH(Index key, *factor)
|
// SymbolicBayesNet actual = eliminate(fg);
|
||||||
if (key != key_) separator.insert(key);
|
//
|
||||||
|
// CHECK(assert_equal(expected,actual));
|
||||||
// for all children, eliminate into Bayes net
|
//}
|
||||||
BOOST_FOREACH(const shared_ptr& child, subTrees_)
|
|
||||||
{
|
|
||||||
Result result = child->eliminate_();
|
|
||||||
bn.push_back(result.first);
|
|
||||||
BOOST_FOREACH(Index key, result.second)
|
|
||||||
if (key != key_) separator.insert(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the conditional from the key and separator, and insert it in Bayes net
|
|
||||||
vector<Index> parents;
|
|
||||||
std::copy(separator.begin(), separator.end(), back_inserter(parents));
|
|
||||||
Conditional::shared_ptr conditional(new Conditional(key_, parents));
|
|
||||||
bn.push_back(conditional);
|
|
||||||
|
|
||||||
// now create the new factor from separator to return to caller
|
|
||||||
Factor newFactor(separator.begin(), separator.end());
|
|
||||||
return Result(bn, newFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** default constructor */
|
|
||||||
ETree(Index key = 0) :
|
|
||||||
key_(key) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** add a factor */
|
|
||||||
void add(const sharedFactor& factor) {
|
|
||||||
factors_.push_back(factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** add a subtree */
|
|
||||||
void add(const shared_ptr& child) {
|
|
||||||
subTrees_.push_back(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print(const std::string& name) const {
|
|
||||||
cout << name << " (" << key_ << ")" << endl;
|
|
||||||
BOOST_FOREACH(const sharedFactor& factor, factors_)
|
|
||||||
factor->print(name + " ");
|
|
||||||
BOOST_FOREACH(const shared_ptr& child, subTrees_)
|
|
||||||
child->print(name + " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool equals(const ETree& expected, double tol) const {
|
|
||||||
// todo
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Eliminate the factors to a Bayes Net
|
|
||||||
*/
|
|
||||||
SymbolicBayesNet eliminate() const {
|
|
||||||
|
|
||||||
// call recursive routine
|
|
||||||
Result result = eliminate_();
|
|
||||||
return result.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// build hardcoded tree
|
|
||||||
ETree::shared_ptr buildHardcodedTree(const SymbolicFactorGraph& fg) {
|
|
||||||
|
|
||||||
ETree::shared_ptr leaf0(new ETree);
|
|
||||||
leaf0->add(fg[0]);
|
|
||||||
leaf0->add(fg[1]);
|
|
||||||
|
|
||||||
ETree::shared_ptr node1(new ETree(1));
|
|
||||||
node1->add(fg[2]);
|
|
||||||
node1->add(leaf0);
|
|
||||||
|
|
||||||
ETree::shared_ptr node2(new ETree(2));
|
|
||||||
node2->add(fg[3]);
|
|
||||||
node2->add(node1);
|
|
||||||
|
|
||||||
ETree::shared_ptr leaf3(new ETree(3));
|
|
||||||
leaf3->add(fg[4]);
|
|
||||||
|
|
||||||
ETree::shared_ptr etree(new ETree(4));
|
|
||||||
etree->add(leaf3);
|
|
||||||
etree->add(node2);
|
|
||||||
|
|
||||||
return etree;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef size_t RowIndex;
|
|
||||||
typedef vector<list<RowIndex> > StructA;
|
|
||||||
typedef vector<boost::optional<Index> > optionalIndices;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gilbert01bit algorithm in Figure 2.2
|
|
||||||
*/
|
|
||||||
optionalIndices buildETree(const StructA& structA) {
|
|
||||||
|
|
||||||
// todo: get n
|
|
||||||
size_t n = 5;
|
|
||||||
optionalIndices parent(n);
|
|
||||||
|
|
||||||
// todo: get m
|
|
||||||
size_t m = 5;
|
|
||||||
optionalIndices prev_col(m);
|
|
||||||
|
|
||||||
// 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(RowIndex i, structA[j]) {
|
|
||||||
if (prev_col[i]) {
|
|
||||||
Index k = *(prev_col[i]);
|
|
||||||
// find root r of the current tree that contains k
|
|
||||||
Index r = k;
|
|
||||||
while (parent[r])
|
|
||||||
r = *parent[r];
|
|
||||||
if (r != j) parent[r].reset(j);
|
|
||||||
}
|
|
||||||
prev_col[i].reset(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Build StructA from factor graph
|
|
||||||
*/
|
|
||||||
StructA createStructA(const SymbolicFactorGraph& fg) {
|
|
||||||
|
|
||||||
StructA structA;
|
|
||||||
|
|
||||||
// hardcode for now
|
|
||||||
list<RowIndex> list0;
|
|
||||||
list0 += 0, 1;
|
|
||||||
structA.push_back(list0);
|
|
||||||
list<RowIndex> list1;
|
|
||||||
list1 += 0, 2;
|
|
||||||
structA.push_back(list1);
|
|
||||||
list<RowIndex> list2;
|
|
||||||
list2 += 1, 3;
|
|
||||||
structA.push_back(list2);
|
|
||||||
list<RowIndex> list3;
|
|
||||||
list3 += 4;
|
|
||||||
structA.push_back(list3);
|
|
||||||
list<RowIndex> list4;
|
|
||||||
list4 += 2, 3, 4;
|
|
||||||
structA.push_back(list4);
|
|
||||||
|
|
||||||
return structA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build ETree from factor graph and parent indices
|
|
||||||
*/
|
|
||||||
ETree::shared_ptr buildETree(const SymbolicFactorGraph& fg, const optionalIndices& parent) {
|
|
||||||
|
|
||||||
// todo: get n
|
|
||||||
size_t n = 5;
|
|
||||||
|
|
||||||
// Create tree structure
|
|
||||||
vector<ETree::shared_ptr> trees(n);
|
|
||||||
for (Index k = 1; k <= n; k++) {
|
|
||||||
Index j = n - k;
|
|
||||||
trees[j].reset(new ETree(j));
|
|
||||||
if (parent[j]) trees[*parent[j]]->add(trees[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hang factors in right places
|
|
||||||
BOOST_FOREACH(const ETree::sharedFactor& factor, fg)
|
|
||||||
{
|
|
||||||
Index j = factor->front();
|
|
||||||
trees[j]->add(factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
return trees[n - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************************************************* */
|
|
||||||
// Test of elimination tree creation
|
|
||||||
// graph: f(0,1) f(0,2) f(1,4) f(2,4) f(3,4)
|
|
||||||
/* ************************************************************************* */
|
|
||||||
/**
|
|
||||||
* Build ETree from factor graph
|
|
||||||
*/
|
|
||||||
ETree::shared_ptr buildETree(const SymbolicFactorGraph& fg) {
|
|
||||||
|
|
||||||
// create vector of factor indices
|
|
||||||
StructA structA = createStructA(fg);
|
|
||||||
|
|
||||||
// call Gilbert01bit algorithm
|
|
||||||
optionalIndices parent = buildETree(structA);
|
|
||||||
|
|
||||||
// Build ETree from factor graph and parent indices
|
|
||||||
return buildETree(fg, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST( ETree, buildETree )
|
|
||||||
{
|
|
||||||
// create example factor graph
|
|
||||||
SymbolicFactorGraph 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);
|
|
||||||
|
|
||||||
ETree::shared_ptr expected = buildHardcodedTree(fg);
|
|
||||||
|
|
||||||
// Build from factor graph
|
|
||||||
ETree::shared_ptr actual = buildETree(fg);
|
|
||||||
|
|
||||||
// todo: 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)
|
|
||||||
/* ************************************************************************* */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Eliminate factor graph
|
|
||||||
*/
|
|
||||||
SymbolicBayesNet eliminate(const SymbolicFactorGraph& fg) {
|
|
||||||
|
|
||||||
// build etree
|
|
||||||
ETree::shared_ptr etree = buildETree(fg);
|
|
||||||
|
|
||||||
return etree->eliminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST( SymbolicFactorGraph, eliminate )
|
|
||||||
{
|
|
||||||
// create expected Chordal bayes Net
|
|
||||||
Conditional::shared_ptr c0(new Conditional(0, 1, 2));
|
|
||||||
Conditional::shared_ptr c1(new Conditional(1, 2, 4));
|
|
||||||
Conditional::shared_ptr c2(new Conditional(2, 4));
|
|
||||||
Conditional::shared_ptr c3(new Conditional(3, 4));
|
|
||||||
Conditional::shared_ptr c4(new Conditional(4));
|
|
||||||
|
|
||||||
SymbolicBayesNet expected;
|
|
||||||
expected.push_back(c3);
|
|
||||||
expected.push_back(c0);
|
|
||||||
expected.push_back(c1);
|
|
||||||
expected.push_back(c2);
|
|
||||||
expected.push_back(c4);
|
|
||||||
|
|
||||||
// Create factor graph
|
|
||||||
SymbolicFactorGraph 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
|
|
||||||
SymbolicBayesNet actual = eliminate(fg);
|
|
||||||
|
|
||||||
CHECK(assert_equal(expected,actual));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
int main() {
|
int main() {
|
||||||
|
|
|
@ -715,24 +715,24 @@ TEST(GaussianFactor, permuteWithInverse)
|
||||||
GaussianFactorGraph actualFG; actualFG.push_back(GaussianFactor::shared_ptr(new GaussianFactor(actual)));
|
GaussianFactorGraph actualFG; actualFG.push_back(GaussianFactor::shared_ptr(new GaussianFactor(actual)));
|
||||||
GaussianVariableIndex<> actualIndex(actualFG);
|
GaussianVariableIndex<> actualIndex(actualFG);
|
||||||
actual.permuteWithInverse(inversePermutation);
|
actual.permuteWithInverse(inversePermutation);
|
||||||
actualIndex.permute(*inversePermutation.inverse());
|
// actualIndex.permute(*inversePermutation.inverse());
|
||||||
|
|
||||||
GaussianFactor expected(0, A3, 2, A2, 4, A1, b, sharedSigma(2, 1.0));
|
GaussianFactor expected(0, A3, 2, A2, 4, A1, b, sharedSigma(2, 1.0));
|
||||||
GaussianFactorGraph expectedFG; expectedFG.push_back(GaussianFactor::shared_ptr(new GaussianFactor(expected)));
|
GaussianFactorGraph expectedFG; expectedFG.push_back(GaussianFactor::shared_ptr(new GaussianFactor(expected)));
|
||||||
GaussianVariableIndex<> expectedIndex(expectedFG);
|
// GaussianVariableIndex<> expectedIndex(expectedFG);
|
||||||
|
|
||||||
CHECK(assert_equal(expected, actual));
|
CHECK(assert_equal(expected, actual));
|
||||||
|
|
||||||
// todo: fix this!!! VariableIndex should not hold slots
|
// // todo: fix this!!! VariableIndex should not hold slots
|
||||||
for(Index j=0; j<actualIndex.size(); ++j) {
|
// for(Index j=0; j<actualIndex.size(); ++j) {
|
||||||
BOOST_FOREACH( GaussianVariableIndex<>::mapped_factor_type& factor_pos, actualIndex[j]) {
|
// BOOST_FOREACH( GaussianVariableIndex<>::mapped_factor_type& factor_pos, actualIndex[j]) {
|
||||||
factor_pos.variablePosition = numeric_limits<Index>::max(); }
|
// factor_pos.variablePosition = numeric_limits<Index>::max(); }
|
||||||
}
|
// }
|
||||||
for(Index j=0; j<expectedIndex.size(); ++j) {
|
// for(Index j=0; j<expectedIndex.size(); ++j) {
|
||||||
BOOST_FOREACH( GaussianVariableIndex<>::mapped_factor_type& factor_pos, expectedIndex[j]) {
|
// BOOST_FOREACH( GaussianVariableIndex<>::mapped_factor_type& factor_pos, expectedIndex[j]) {
|
||||||
factor_pos.variablePosition = numeric_limits<Index>::max(); }
|
// factor_pos.variablePosition = numeric_limits<Index>::max(); }
|
||||||
}
|
// }
|
||||||
CHECK(assert_equal(expectedIndex, actualIndex));
|
// CHECK(assert_equal(expectedIndex, actualIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
///* ************************************************************************* */
|
///* ************************************************************************* */
|
||||||
|
|
|
@ -60,8 +60,7 @@ void NonlinearFactorGraph<Values>::print(const std::string& str) const {
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
template<class Values>
|
template<class Values>
|
||||||
pair<Ordering::shared_ptr, GaussianVariableIndex<>::shared_ptr>
|
Ordering::shared_ptr NonlinearFactorGraph<Values>::orderingCOLAMD(const Values& config) const {
|
||||||
NonlinearFactorGraph<Values>::orderingCOLAMD(const Values& config) const {
|
|
||||||
|
|
||||||
// Create symbolic graph and initial (iterator) ordering
|
// Create symbolic graph and initial (iterator) ordering
|
||||||
FactorGraph<Factor>::shared_ptr symbolic;
|
FactorGraph<Factor>::shared_ptr symbolic;
|
||||||
|
@ -76,14 +75,12 @@ void NonlinearFactorGraph<Values>::print(const std::string& str) const {
|
||||||
|
|
||||||
// Permute the Ordering and VariableIndex with the COLAMD ordering
|
// Permute the Ordering and VariableIndex with the COLAMD ordering
|
||||||
ordering->permuteWithInverse(*colamdPerm->inverse());
|
ordering->permuteWithInverse(*colamdPerm->inverse());
|
||||||
variableIndex.permute(*colamdPerm);
|
// variableIndex.permute(*colamdPerm);
|
||||||
|
// SL-FIX: fix permutation
|
||||||
// Build a variable dimensions array to upgrade to a GaussianVariableIndex
|
|
||||||
GaussianVariableIndex<>::shared_ptr gaussianVarIndex(new GaussianVariableIndex<>(variableIndex, config.dims(*ordering)));
|
|
||||||
|
|
||||||
// Return the Ordering and VariableIndex to be re-used during linearization
|
// Return the Ordering and VariableIndex to be re-used during linearization
|
||||||
// and elimination
|
// and elimination
|
||||||
return make_pair(ordering, gaussianVarIndex);
|
return ordering;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
|
@ -84,8 +84,7 @@ namespace gtsam {
|
||||||
* ordering and a VariableIndex, which can later be re-used to save
|
* ordering and a VariableIndex, which can later be re-used to save
|
||||||
* computation.
|
* computation.
|
||||||
*/
|
*/
|
||||||
std::pair<Ordering::shared_ptr, GaussianVariableIndex<>::shared_ptr>
|
Ordering::shared_ptr orderingCOLAMD(const Values& config) const;
|
||||||
orderingCOLAMD(const Values& config) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* linearize a nonlinear factor graph
|
* linearize a nonlinear factor graph
|
||||||
|
|
|
@ -230,9 +230,7 @@ namespace gtsam {
|
||||||
verbosityLevel verbosity = SILENT) {
|
verbosityLevel verbosity = SILENT) {
|
||||||
|
|
||||||
// Use a variable ordering from COLAMD
|
// Use a variable ordering from COLAMD
|
||||||
Ordering::shared_ptr ordering;
|
Ordering::shared_ptr ordering = graph->orderingCOLAMD(*config);
|
||||||
GaussianVariableIndex<>::shared_ptr variableIndex;
|
|
||||||
boost::tie(ordering, variableIndex) = graph->orderingCOLAMD(*config);
|
|
||||||
|
|
||||||
double relativeThreshold = 1e-5, absoluteThreshold = 1e-5;
|
double relativeThreshold = 1e-5, absoluteThreshold = 1e-5;
|
||||||
|
|
||||||
|
@ -264,9 +262,7 @@ namespace gtsam {
|
||||||
*/
|
*/
|
||||||
static shared_values optimizeGN(shared_graph graph, shared_values config,
|
static shared_values optimizeGN(shared_graph graph, shared_values config,
|
||||||
verbosityLevel verbosity = SILENT) {
|
verbosityLevel verbosity = SILENT) {
|
||||||
Ordering::shared_ptr ordering;
|
Ordering::shared_ptr ordering = graph->orderingCOLAMD(*config);
|
||||||
GaussianVariableIndex<>::shared_ptr variableIndex;
|
|
||||||
boost::tie(ordering, variableIndex) = graph->orderingCOLAMD(*config);
|
|
||||||
double relativeThreshold = 1e-5, absoluteThreshold = 1e-5;
|
double relativeThreshold = 1e-5, absoluteThreshold = 1e-5;
|
||||||
|
|
||||||
// initial optimization state is the same in both cases tested
|
// initial optimization state is the same in both cases tested
|
||||||
|
|
|
@ -175,9 +175,7 @@ TEST( Graph, CHECK_ORDERING)
|
||||||
initialEstimate->insert(3, landmark3);
|
initialEstimate->insert(3, landmark3);
|
||||||
initialEstimate->insert(4, landmark4);
|
initialEstimate->insert(4, landmark4);
|
||||||
|
|
||||||
Ordering::shared_ptr ordering;
|
Ordering::shared_ptr ordering = graph->orderingCOLAMD(*initialEstimate);
|
||||||
GaussianVariableIndex<>::shared_ptr varindex;
|
|
||||||
boost::tie(ordering,varindex) = graph->orderingCOLAMD(*initialEstimate);
|
|
||||||
|
|
||||||
// Create an optimizer and check its error
|
// Create an optimizer and check its error
|
||||||
// We expect the initial to be zero because config is the ground truth
|
// We expect the initial to be zero because config is the ground truth
|
||||||
|
|
|
@ -37,7 +37,7 @@ using namespace boost::assign;
|
||||||
#include <gtsam/inference/SymbolicFactorGraph.h>
|
#include <gtsam/inference/SymbolicFactorGraph.h>
|
||||||
//#include <gtsam/inference/BayesTree-inl.h>
|
//#include <gtsam/inference/BayesTree-inl.h>
|
||||||
#include <gtsam/inference/inference-inl.h>
|
#include <gtsam/inference/inference-inl.h>
|
||||||
|
#include <gtsam/inference/EliminationTree-inl.h>
|
||||||
|
|
||||||
using namespace gtsam;
|
using namespace gtsam;
|
||||||
using namespace example;
|
using namespace example;
|
||||||
|
@ -313,6 +313,9 @@ TEST( GaussianFactorGraph, eliminateAll )
|
||||||
GaussianFactorGraph fg1 = createGaussianFactorGraph(ordering);
|
GaussianFactorGraph fg1 = createGaussianFactorGraph(ordering);
|
||||||
GaussianBayesNet actual = *Inference::Eliminate(fg1);
|
GaussianBayesNet actual = *Inference::Eliminate(fg1);
|
||||||
CHECK(assert_equal(expected,actual,tol));
|
CHECK(assert_equal(expected,actual,tol));
|
||||||
|
|
||||||
|
GaussianBayesNet actualET = *EliminationTree<GaussianFactorGraph>::Create(fg1)->eliminate();
|
||||||
|
CHECK(assert_equal(expected,actualET,tol));
|
||||||
}
|
}
|
||||||
|
|
||||||
///* ************************************************************************* */
|
///* ************************************************************************* */
|
||||||
|
@ -488,11 +491,13 @@ TEST( GaussianFactorGraph, optimize )
|
||||||
|
|
||||||
// optimize the graph
|
// optimize the graph
|
||||||
VectorValues actual = optimize(*Inference::Eliminate(fg));
|
VectorValues actual = optimize(*Inference::Eliminate(fg));
|
||||||
|
VectorValues actualET = optimize(*EliminationTree<GaussianFactorGraph>::Create(fg)->eliminate());
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
VectorValues expected = createCorrectDelta(ord);
|
VectorValues expected = createCorrectDelta(ord);
|
||||||
|
|
||||||
CHECK(assert_equal(expected,actual));
|
CHECK(assert_equal(expected,actual));
|
||||||
|
CHECK(assert_equal(expected,actualET));
|
||||||
}
|
}
|
||||||
|
|
||||||
///* ************************************************************************* */
|
///* ************************************************************************* */
|
||||||
|
@ -781,10 +786,12 @@ TEST( GaussianFactorGraph, constrained_simple )
|
||||||
|
|
||||||
// eliminate and solve
|
// eliminate and solve
|
||||||
VectorValues actual = optimize(*Inference::Eliminate(fg));
|
VectorValues actual = optimize(*Inference::Eliminate(fg));
|
||||||
|
VectorValues actualET = optimize(*EliminationTree<GaussianFactorGraph>::Create(fg)->eliminate());
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
VectorValues expected = createSimpleConstraintValues();
|
VectorValues expected = createSimpleConstraintValues();
|
||||||
CHECK(assert_equal(expected, actual));
|
CHECK(assert_equal(expected, actual));
|
||||||
|
CHECK(assert_equal(expected, actualET));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
|
@ -169,7 +169,7 @@ TEST(GaussianJunctionTree, slamlike) {
|
||||||
++ i;
|
++ i;
|
||||||
|
|
||||||
// Compare solutions
|
// Compare solutions
|
||||||
Ordering ordering = *fullgraph.orderingCOLAMD(init).first;
|
Ordering ordering = *fullgraph.orderingCOLAMD(init);
|
||||||
GaussianFactorGraph linearized = *fullgraph.linearize(init, ordering);
|
GaussianFactorGraph linearized = *fullgraph.linearize(init, ordering);
|
||||||
|
|
||||||
GaussianJunctionTree gjt(linearized);
|
GaussianJunctionTree gjt(linearized);
|
||||||
|
|
|
@ -62,7 +62,7 @@ TEST( Graph, GET_ORDERING)
|
||||||
{
|
{
|
||||||
Ordering expected; expected += "x1","l1","x2";
|
Ordering expected; expected += "x1","l1","x2";
|
||||||
Graph nlfg = createNonlinearFactorGraph();
|
Graph nlfg = createNonlinearFactorGraph();
|
||||||
Ordering actual = *nlfg.orderingCOLAMD(createNoisyValues()).first;
|
Ordering actual = *nlfg.orderingCOLAMD(createNoisyValues());
|
||||||
CHECK(assert_equal(expected,actual));
|
CHECK(assert_equal(expected,actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
|
||||||
pair<shared_ptr<Pose2Graph>, shared_ptr<Pose2Values> > data = load2D(dataset(datasetname));
|
pair<shared_ptr<Pose2Graph>, shared_ptr<Pose2Values> > data = load2D(dataset(datasetname));
|
||||||
|
|
||||||
tic("Z 1 order");
|
tic("Z 1 order");
|
||||||
Ordering::shared_ptr ordering(data.first->orderingCOLAMD(*data.second).first);
|
Ordering::shared_ptr ordering(data.first->orderingCOLAMD(*data.second));
|
||||||
toc("Z 1 order");
|
toc("Z 1 order");
|
||||||
|
|
||||||
tic("Z 2 linearize");
|
tic("Z 2 linearize");
|
||||||
|
|
Loading…
Reference in New Issue