Started implementing junction tree construction

release/4.3a0
Richard Roberts 2013-06-06 15:36:21 +00:00
parent 5b1ac91c85
commit b4d282f67e
5 changed files with 125 additions and 118 deletions

View File

@ -28,7 +28,7 @@ namespace gtsam {
template<typename NODE, typename DATA> template<typename NODE, typename DATA>
struct TraversalNode { struct TraversalNode {
bool expanded; bool expanded;
NODE* const treeNode; NODE& const treeNode;
DATA data; DATA data;
TraversalNode(NODE* _treeNode, const DATA& _data) : TraversalNode(NODE* _treeNode, const DATA& _data) :
expanded(false), treeNode(_treeNode), data(_data) {} expanded(false), treeNode(_treeNode), data(_data) {}
@ -38,16 +38,14 @@ namespace gtsam {
template<typename NODE, typename VISITOR, typename DATA, typename STACK> template<typename NODE, typename VISITOR, typename DATA, typename STACK>
struct PreOrderExpand { struct PreOrderExpand {
VISITOR& visitor_; VISITOR& visitor_;
DATA* parentData_; DATA& parentData_;
STACK& stack_; STACK& stack_;
PreOrderExpand(VISITOR& visitor, DATA* parentData, STACK& stack) : PreOrderExpand(VISITOR& visitor, DATA& parentData, STACK& stack) :
visitor_(visitor), parentData_(parentData), stack_(stack) {} visitor_(visitor), parentData_(parentData), stack_(stack) {}
template<typename P> template<typename P>
void operator()(const P& nodePointer) { void operator()(const P& nodePointer) {
// Get raw pointer (in case nodePointer is a shared_ptr)
NODE* rawNodePointer = &(*nodePointer);
// Add node // Add node
stack_.push(TraversalNode<NODE,DATA>(rawNodePointer, visitor_(nodePointer, *parentData_))); stack_.push(TraversalNode<NODE,DATA>(*nodePointer, visitor_(nodePointer, parentData_)));
} }
}; };
@ -82,7 +80,7 @@ namespace gtsam {
// Add roots to stack (use reverse iterators so children are processed in the order they // Add roots to stack (use reverse iterators so children are processed in the order they
// appear) // appear)
(void) std::for_each(forest.roots().rbegin(), forest.roots().rend(), (void) std::for_each(forest.roots().rbegin(), forest.roots().rend(),
Expander(visitorPre, &rootData, stack)); Expander(visitorPre, rootData, stack));
// Traverse // Traverse
while(!stack.empty()) while(!stack.empty())
@ -93,13 +91,13 @@ namespace gtsam {
if(node.expanded) { if(node.expanded) {
// If already expanded, then the data stored in the node is no longer needed, so visit // If already expanded, then the data stored in the node is no longer needed, so visit
// then delete it. // then delete it.
(void) visitorPost(*node.treeNode, node.data); (void) visitorPost(node.treeNode, node.data);
stack.pop(); stack.pop();
} else { } else {
// If not already visited, visit the node and add its children (use reverse iterators so // If not already visited, visit the node and add its children (use reverse iterators so
// children are processed in the order they appear) // children are processed in the order they appear)
(void) std::for_each(node.treeNode->children.rbegin(), node.treeNode->children.rend(), (void) std::for_each(node.treeNode->children.rbegin(), node.treeNode->children.rend(),
Expander(visitorPre, &node.data, stack)); Expander(visitorPre, node.data, stack));
node.expanded = true; node.expanded = true;
} }
} }

View File

@ -37,6 +37,8 @@ namespace gtsam {
const boost::shared_ptr<BayesNetType>& output, const boost::shared_ptr<BayesNetType>& output,
const Eliminate& function, const std::vector<sharedFactor>& childrenResults) const const Eliminate& function, const std::vector<sharedFactor>& childrenResults) const
{ {
// This function eliminates one node (Node::eliminate) - see below eliminate for the whole tree.
assert(childrenResults.size() == children.size()); assert(childrenResults.size() == children.size());
// Gather factors // Gather factors
@ -146,8 +148,7 @@ namespace gtsam {
// Build variable index first // Build variable index first
const VariableIndexUnordered variableIndex(factorGraph); const VariableIndexUnordered variableIndex(factorGraph);
This temp(factorGraph, variableIndex, order); This temp(factorGraph, variableIndex, order);
roots_.swap(temp.roots_); // Swap in the tree, and temp will be deleted this->swap(temp); // Swap in the tree, and temp will be deleted
remainingFactors_.swap(temp.remainingFactors_);
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -295,4 +296,12 @@ namespace gtsam {
return true; return true;
} }
/* ************************************************************************* */
template<class BAYESNET, class GRAPH>
void EliminationTreeUnordered<BAYESNET,GRAPH>::swap(This& other) {
roots_.swap(other.roots_);
remainingFactors_.swap(other.remainingFactors_);
}
} }

View File

@ -65,8 +65,8 @@ namespace gtsam {
Eliminate; ///< Typedef for an eliminate subroutine Eliminate; ///< Typedef for an eliminate subroutine
struct Node { struct Node {
typedef FastList<sharedFactor> Factors; typedef std::vector<sharedFactor> Factors;
typedef FastList<boost::shared_ptr<Node> > Children; typedef std::vector<boost::shared_ptr<Node> > Children;
Key key; ///< key associated with root Key key; ///< key associated with root
Factors factors; ///< factors associated with root Factors factors; ///< factors associated with root
@ -146,6 +146,9 @@ namespace gtsam {
const FastList<sharedNode>& roots() const { return roots_; } const FastList<sharedNode>& roots() const { return roots_; }
/** Swap the data of this tree with another one, this operation is very fast. */
void swap(This& other);
protected: protected:
/// Protected default constructor /// Protected default constructor
EliminationTreeUnordered() {} EliminationTreeUnordered() {}

View File

@ -28,6 +28,71 @@
namespace gtsam { namespace gtsam {
namespace {
/* ************************************************************************* */
template<class BAYESTREE, class GRAPH>
struct ConstructorTraversalData {
const ConstructorTraversalData& parentData;
typename JunctionTreeUnordered<BAYESTREE,GRAPH>::sharedNode myJTNode;
ConstructorTraversalData(const ConstructorTraversalData& _parentData) : parentData(_parentData) {}
};
/* ************************************************************************* */
template<class BAYESTREE, class GRAPH, class ETREE_NODE>
ConstructorTraversalData<BAYESTREE,GRAPH> ConstructorTraversalVisitorPre(
const boost::shared_ptr<ETREE_NODE>& node,
const ConstructorTraversalData<BAYESTREE,GRAPH>& parentData)
{
// On the pre-order pass, before children have been visited, we just set up a traversal data
// structure with its own JT node, and create a child pointer in its parent.
ConstructorTraversalData<BAYESTREE,GRAPH> myData = ConstructorTraversalData<BAYESTREE,GRAPH>(parentData);
myData.myJTNode = boost::make_shared<typename JunctionTreeUnordered<BAYESREE,GRAPH>::Node>();
myData.myJTNode->keys.push_back(node->key);
myData.myJTNode->factors.insert(myData.myJTNode->factors.begin(), node->factors.begin(), node->factors.end());
parentData.myJTNode->children.push_back(myData.myJTNode);
return myData;
}
/* ************************************************************************* */
template<class BAYESTREE, class GRAPH, class ETREE_NODE, class SYMBOLIC_CONDITIONAL>
struct ConstructorTraversalVisitorPost
{
// Store and increment an iterator into the Bayes net during the post-order step
FactorGraphUnordered<SYMBOLIC_CONDITIONAL>::const_iterator symbolicBayesNetIterator;
// Constructor that starts at the beginning of the Bayes net
ConstructorTraversalVisitorPost(const FactorGraphUnordered<SYMBOLIC_CONDITIONAL>& symbolicBayesNet) :
symbolicBayesNetIterator(symbolicBayesNet.begin()) {}
// Post-order visitor function
void operator()(
const boost::shared_ptr<ETREE_NODE>& node,
const ConstructorTraversalData<BAYESTREE,GRAPH>& myData)
{
// In the post-order step, we check if we are in the same clique with our parent. If so, we
// merge our JT nodes.
if()
}
};
}
/* ************************************************************************* */
template<class BAYESTREE, class GRAPH>
template<class ETREE, class SYMBOLIC_CONDITIONAL>
JunctionTreeUnordered(const ETREE& eliminationTree,
const FactorGraphUnordered<SYMBOLIC_CONDITIONAL>& symbolicBayesNet)
{
// Here we rely on the BayesNet having been produced by this elimination tree, such that the
// conditionals are arranged in DFS post-order. We traverse the elimination tree, and inspect
// the symbolic conditional corresponding to each node. The elimination tree node is added to
// the same clique with its parent if it has exactly one more Bayes net conditional parent than
// does its elimination tree parent.
}
/* ************************************************************************* */ /* ************************************************************************* */
template <class FG, class BTCLIQUE> template <class FG, class BTCLIQUE>
void JunctionTree<FG,BTCLIQUE>::construct(const FG& fg, const VariableIndex& variableIndex) { void JunctionTree<FG,BTCLIQUE>::construct(const FG& fg, const VariableIndex& variableIndex) {

View File

@ -21,51 +21,11 @@
#include <gtsam/base/Testable.h> #include <gtsam/base/Testable.h>
#include <gtsam/inference/Key.h> #include <gtsam/inference/Key.h>
#include <gtsam/inference/FactorGraphUnordered.h>
#include <gtsam/inference/EliminationTreeUnordered.h>
namespace gtsam { namespace gtsam {
template<class BAYESTREE, class GRAPH>
class JunctionTreeUnordered {
public:
typedef GRAPH FactorGraphType; ///< The factor graph type
typedef typename GRAPH::FactorType FactorType; ///< The type of factors
typedef JunctionTreeUnordered<BAYESTREE, GRAPH> This; ///< This class
typedef boost::shared_ptr<This> shared_ptr; ///< Shared pointer to this class
typedef typename boost::shared_ptr<FactorType> sharedFactor; ///< Shared pointer to a factor
typedef BAYESTREE BayesTreeType; ///< The BayesNet corresponding to FACTOR
typedef typename BayesTreeType::ConditionalType ConditionalType; ///< The type of conditionals
typedef typename boost::shared_ptr<ConditionalType> sharedConditional; ///< Shared pointer to a conditional
typedef boost::function<std::pair<sharedConditional,sharedFactor>(std::vector<sharedFactor>, std::vector<Key>)>
Eliminate; ///< Typedef for an eliminate subroutine
struct Node {
typedef FastList<sharedFactor> Factors;
typedef FastList<boost::shared_ptr<Node> > Children;
Key key; ///< key associated with root
Factors factors; ///< factors associated with root
Children children; ///< sub-trees
sharedFactor eliminate(const boost::shared_ptr<BayesTreeType>& output,
const Eliminate& function, const std::vector<sharedFactor>& childrenFactors) const;
};
typedef boost::shared_ptr<Node> sharedNode; ///< Shared pointer to Node
private:
/** concept check */
GTSAM_CONCEPT_TESTABLE_TYPE(FactorType);
FastList<sharedNode> roots_;
std::vector<sharedFactor> remainingFactors_;
public:
};
/** /**
* A ClusterTree, i.e., a set of variable clusters with factors, arranged in a tree, with * 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. * the additional property that it represents the clique tree associated with a Bayes net.
@ -87,86 +47,58 @@ namespace gtsam {
* \addtogroup Multifrontal * \addtogroup Multifrontal
* \nosubgrouping * \nosubgrouping
*/ */
template<class FG, class BTCLIQUE=typename BayesTree<typename FG::FactorType::ConditionalType>::Clique> template<class BAYESTREE, class GRAPH>
class JunctionTree: public ClusterTree<FG> { class JunctionTreeUnordered {
public: public:
/// In a junction tree each cluster is associated with a clique typedef GRAPH FactorGraphType; ///< The factor graph type
typedef typename ClusterTree<FG>::Cluster Clique; typedef typename GRAPH::FactorType FactorType; ///< The type of factors
typedef typename Clique::shared_ptr sharedClique; ///< Shared pointer to a clique typedef JunctionTreeUnordered<BAYESTREE, GRAPH> This; ///< This class
typedef boost::shared_ptr<This> shared_ptr; ///< Shared pointer to this class
typedef typename boost::shared_ptr<FactorType> sharedFactor; ///< Shared pointer to a factor
typedef BAYESTREE BayesTreeType; ///< The BayesTree type produced by elimination
typedef typename BayesTreeType::ConditionalType ConditionalType; ///< The type of conditionals
typedef typename boost::shared_ptr<ConditionalType> sharedConditional; ///< Shared pointer to a conditional
typedef boost::function<std::pair<sharedConditional,sharedFactor>(std::vector<sharedFactor>, std::vector<Key>)>
Eliminate; ///< Typedef for an eliminate subroutine
/// The BayesTree type produced by elimination struct Node {
typedef BTCLIQUE BTClique; typedef std::vector<Key> Keys;
typedef std::vector<sharedFactor> Factors;
typedef std::vector<boost::shared_ptr<Node> > Children;
/// Shared pointer to this class Keys keys; ///< Frontal keys of this node
typedef boost::shared_ptr<JunctionTree<FG> > shared_ptr; Factors factors; ///< Factors associated with this node
Children children; ///< sub-trees
/// We will frequently refer to a symbolic Bayes tree, used to find the clique structure sharedFactor eliminate(const boost::shared_ptr<BayesTreeType>& output,
typedef gtsam::BayesTree<IndexConditional> SymbolicBayesTree; const Eliminate& function, const std::vector<sharedFactor>& childrenFactors) const;
};
typedef boost::shared_ptr<Node> sharedNode; ///< Shared pointer to Node
private: private:
/// @name Advanced Interface /** concept check */
/// @{ GTSAM_CONCEPT_TESTABLE_TYPE(FactorType);
/// distribute the factors along the cluster tree FastList<sharedNode> roots_;
sharedClique distributeFactors(const FG& fg, std::vector<sharedFactor> remainingFactors_;
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 VariableIndex& variableIndex);
/// @}
public: public:
/// @name Standard Constructors /// @name Standard Constructors
/// @{ /// @{
/** Default constructor */ /** Build the junction tree from an elimination tree and a symbolic Bayes net. */
JunctionTree() {} template<class ETREE, class SYMBOLIC_CONDITIONAL>
JunctionTreeUnordered(
/** Named constructor to build the junction tree of a factor graph. Note const ETREE& eliminationTree,
* that this has to compute the column structure as a VariableIndex, so if you const FactorGraphUnordered<SYMBOLIC_CONDITIONAL>& symbolicBayesNet);
* 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
*/
JunctionTree(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.
*/
JunctionTree(const FG& fg, const VariableIndex& 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/JunctionTree-inl.h>