gtsam  4.0.0
gtsam
EliminationTree-inst.h
1 /* ----------------------------------------------------------------------------
2 
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8 * See LICENSE for the license information
9 
10 * -------------------------------------------------------------------------- */
11 
18 #pragma once
19 
20 #include <boost/make_shared.hpp>
21 #include <boost/bind.hpp>
22 #include <stack>
23 
24 #include <gtsam/base/timing.h>
30 
31 namespace gtsam {
32 
33  /* ************************************************************************* */
34  template<class BAYESNET, class GRAPH>
36  EliminationTree<BAYESNET,GRAPH>::Node::eliminate(
37  const boost::shared_ptr<BayesNetType>& output,
38  const Eliminate& function, const FastVector<sharedFactor>& childrenResults) const
39  {
40  // This function eliminates one node (Node::eliminate) - see below eliminate for the whole tree.
41 
42  assert(childrenResults.size() == children.size());
43 
44  // Gather factors
45  FactorGraphType gatheredFactors;
46  gatheredFactors.reserve(factors.size() + children.size());
47  gatheredFactors.push_back(factors.begin(), factors.end());
48  gatheredFactors.push_back(childrenResults.begin(), childrenResults.end());
49 
50  // Do dense elimination step
51  FastVector<Key> keyAsVector(1); keyAsVector[0] = key;
52  std::pair<boost::shared_ptr<ConditionalType>, boost::shared_ptr<FactorType> > eliminationResult =
53  function(gatheredFactors, Ordering(keyAsVector));
54 
55  // Add conditional to BayesNet
56  output->push_back(eliminationResult.first);
57 
58  // Return result
59  return eliminationResult.second;
60  }
61 
62  /* ************************************************************************* */
63  template<class BAYESNET, class GRAPH>
64  void EliminationTree<BAYESNET,GRAPH>::Node::print(
65  const std::string& str, const KeyFormatter& keyFormatter) const
66  {
67  std::cout << str << "(" << keyFormatter(key) << ")\n";
68  for(const sharedFactor& factor: factors) {
69  if(factor)
70  factor->print(str);
71  else
72  std::cout << str << "null factor\n";
73  }
74  }
75 
76 
77  /* ************************************************************************* */
78  template<class BAYESNET, class GRAPH>
80  const VariableIndex& structure, const Ordering& order)
81  {
82  gttic(EliminationTree_Contructor);
83 
84  // Number of factors and variables - NOTE in the case of partial elimination, n here may
85  // be fewer variables than are actually present in the graph.
86  const size_t m = graph.size();
87  const size_t n = order.size();
88 
89  static const size_t none = std::numeric_limits<size_t>::max();
90 
91  // Allocate result parent vector and vector of last factor columns
92  FastVector<sharedNode> nodes(n);
93  FastVector<size_t> parents(n, none);
94  FastVector<size_t> prevCol(m, none);
95  FastVector<bool> factorUsed(m, false);
96 
97  try {
98  // for column j \in 1 to n do
99  for (size_t j = 0; j < n; j++)
100  {
101  // Retrieve the factors involving this variable and create the current node
102  const VariableIndex::Factors& factors = structure[order[j]];
103  const sharedNode node = boost::make_shared<Node>();
104  node->key = order[j];
105 
106  // for row i \in Struct[A*j] do
107  node->children.reserve(factors.size());
108  node->factors.reserve(factors.size());
109  for(const size_t i: factors) {
110  // If we already hit a variable in this factor, make the subtree containing the previous
111  // variable in this factor a child of the current node. This means that the variables
112  // eliminated earlier in the factor depend on the later variables in the factor. If we
113  // haven't yet hit a variable in this factor, we add the factor to the current node.
114  // TODO: Store root shortcuts instead of parents.
115  if (prevCol[i] != none) {
116  size_t k = prevCol[i];
117  // Find root r of the current tree that contains k. Use raw pointers in computing the
118  // parents to avoid changing the reference counts while traversing up the tree.
119  size_t r = k;
120  while (parents[r] != none)
121  r = parents[r];
122  // If the root of the subtree involving this node is actually the current node,
123  // TODO: what does this mean? forest?
124  if (r != j) {
125  // Now that we found the root, hook up parent and child pointers in the nodes.
126  parents[r] = j;
127  node->children.push_back(nodes[r]);
128  }
129  } else {
130  // Add the factor to the current node since we are at the first variable in this factor.
131  node->factors.push_back(graph[i]);
132  factorUsed[i] = true;
133  }
134  prevCol[i] = j;
135  }
136  nodes[j] = node;
137  }
138  } catch(std::invalid_argument& e) {
139  // If this is thrown from structure[order[j]] above, it means that it was requested to
140  // eliminate a variable not present in the graph, so throw a more informative error message.
141  (void)e; // Prevent unused variable warning
142  throw std::invalid_argument("EliminationTree: given ordering contains variables that are not involved in the factor graph");
143  } catch(...) {
144  throw;
145  }
146 
147  // Find roots
148  assert(parents.empty() || parents.back() == none); // We expect the last-eliminated node to be a root no matter what
149  for(size_t j = 0; j < n; ++j)
150  if(parents[j] == none)
151  roots_.push_back(nodes[j]);
152 
153  // Gather remaining factors (exclude null factors)
154  for(size_t i = 0; i < m; ++i)
155  if(!factorUsed[i] && graph[i])
156  remainingFactors_.push_back(graph[i]);
157  }
158 
159  /* ************************************************************************* */
160  template<class BAYESNET, class GRAPH>
162  const FactorGraphType& factorGraph, const Ordering& order)
163  {
164  gttic(ET_Create2);
165  // Build variable index first
166  const VariableIndex variableIndex(factorGraph);
167  This temp(factorGraph, variableIndex, order);
168  this->swap(temp); // Swap in the tree, and temp will be deleted
169  }
170 
171  /* ************************************************************************* */
172  template<class BAYESNET, class GRAPH>
175  {
176  // Start by duplicating the tree.
177  roots_ = treeTraversal::CloneForest(other);
178 
179  // Assign the remaining factors - these are pointers to factors in the original factor graph and
180  // we do not clone them.
181  remainingFactors_ = other.remainingFactors_;
182 
183  return *this;
184  }
185 
186  /* ************************************************************************* */
187  template<class BAYESNET, class GRAPH>
188  std::pair<boost::shared_ptr<BAYESNET>, boost::shared_ptr<GRAPH> >
190  {
191  gttic(EliminationTree_eliminate);
192  // Allocate result
193  boost::shared_ptr<BayesNetType> result = boost::make_shared<BayesNetType>();
194 
195  // Run tree elimination algorithm
196  FastVector<sharedFactor> remainingFactors = inference::EliminateTree(result, *this, function);
197 
198  // Add remaining factors that were not involved with eliminated variables
199  boost::shared_ptr<FactorGraphType> allRemainingFactors = boost::make_shared<FactorGraphType>();
200  allRemainingFactors->push_back(remainingFactors_.begin(), remainingFactors_.end());
201  allRemainingFactors->push_back(remainingFactors.begin(), remainingFactors.end());
202 
203  // Return result
204  return std::make_pair(result, allRemainingFactors);
205  }
206 
207  /* ************************************************************************* */
208  template<class BAYESNET, class GRAPH>
209  void EliminationTree<BAYESNET,GRAPH>::print(const std::string& name, const KeyFormatter& formatter) const
210  {
211  treeTraversal::PrintForest(*this, name, formatter);
212  }
213 
214  /* ************************************************************************* */
215  template<class BAYESNET, class GRAPH>
216  bool EliminationTree<BAYESNET,GRAPH>::equals(const This& expected, double tol) const
217  {
218  // Depth-first-traversal stacks
219  std::stack<sharedNode, FastVector<sharedNode> > stack1, stack2;
220 
221  // Add roots in sorted order
222  {
224  for(const sharedNode& root: this->roots_) { keys.insert(std::make_pair(root->key, root)); }
225  typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
226  for(const Key_Node& key_node: keys) { stack1.push(key_node.second); }
227  }
228  {
230  for(const sharedNode& root: expected.roots_) { keys.insert(std::make_pair(root->key, root)); }
231  typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
232  for(const Key_Node& key_node: keys) { stack2.push(key_node.second); }
233  }
234 
235  // Traverse, adding children in sorted order
236  while(!stack1.empty() && !stack2.empty()) {
237  // Pop nodes
238  sharedNode node1 = stack1.top();
239  stack1.pop();
240  sharedNode node2 = stack2.top();
241  stack2.pop();
242 
243  // Compare nodes
244  if(node1->key != node2->key)
245  return false;
246  if(node1->factors.size() != node2->factors.size()) {
247  return false;
248  } else {
249  for(typename Node::Factors::const_iterator it1 = node1->factors.begin(), it2 = node2->factors.begin();
250  it1 != node1->factors.end(); ++it1, ++it2) // Only check it1 == end because we already returned false for different counts
251  {
252  if(*it1 && *it2) {
253  if(!(*it1)->equals(**it2, tol))
254  return false;
255  } else if((*it1 && !*it2) || (*it2 && !*it1)) {
256  return false;
257  }
258  }
259  }
260 
261  // Add children in sorted order
262  {
264  for(const sharedNode& node: node1->children) { keys.insert(std::make_pair(node->key, node)); }
265  typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
266  for(const Key_Node& key_node: keys) { stack1.push(key_node.second); }
267  }
268  {
270  for(const sharedNode& node: node2->children) { keys.insert(std::make_pair(node->key, node)); }
271  typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
272  for(const Key_Node& key_node: keys) { stack2.push(key_node.second); }
273  }
274  }
275 
276  // If either stack is not empty, the number of nodes differed
277  if(!stack1.empty() || !stack2.empty())
278  return false;
279 
280  return true;
281  }
282 
283  /* ************************************************************************* */
284  template<class BAYESNET, class GRAPH>
286  roots_.swap(other.roots_);
287  remainingFactors_.swap(other.remainingFactors_);
288  }
289 
290 
291 }
This & operator=(const This &other)
Assignment operator - makes a deep copy of the tree structure, but only pointers to factors are copie...
Definition: EliminationTree-inst.h:174
Children children
sub-trees
Definition: EliminationTree.h:72
Contains generic inference algorithms that convert between templated graphical models, i.e., factor graphs, Bayes nets, and Bayes trees.
const FastVector< sharedFactor > & remainingFactors() const
Return the remaining factors that are not pulled into elimination.
Definition: EliminationTree.h:154
The VariableIndex class computes and stores the block column structure of a factor graph...
Definition: VariableIndex.h:42
Key key
key associated with root
Definition: EliminationTree.h:70
EliminationTree()
Protected default constructor.
Definition: EliminationTree.h:161
GRAPH FactorGraphType
The factor graph type.
Definition: EliminationTree.h:58
Factors factors
factors associated with root
Definition: EliminationTree.h:71
Definition: Ordering.h:33
std::pair< boost::shared_ptr< BayesNetType >, boost::shared_ptr< FactorGraphType > > eliminate(Eliminate function) const
Eliminate the factors to a Bayes net and remaining factor graph.
Definition: EliminationTree-inst.h:189
An elimination tree is a data structure used intermediately during elimination.
Definition: EliminationTree.h:51
void PrintForest(const FOREST &forest, std::string str, const KeyFormatter &keyFormatter)
Print a tree, prefixing each line with str, and formatting keys using keyFormatter.
Definition: treeTraversal-inst.h:220
bool equals(const This &other, double tol=1e-9) const
Test whether the tree is equal to another.
Definition: EliminationTree-inst.h:216
void print(const std::string &name="EliminationTree: ", const KeyFormatter &formatter=DefaultKeyFormatter) const
Print the tree to cout.
Definition: EliminationTree-inst.h:209
void swap(This &other)
Swap the data of this tree with another one, this operation is very fast.
Definition: EliminationTree-inst.h:285
Timing utilities.
boost::shared_ptr< Node > sharedNode
Shared pointer to Node.
Definition: EliminationTree.h:80
boost::shared_ptr< FactorType > sharedFactor
Shared pointer to a factor.
Definition: EliminationTree.h:60
Global functions in a separate testing namespace.
Definition: chartTesting.h:28
boost::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition: Key.h:33
Definition: FastMap.h:37
FastVector< boost::shared_ptr< typename FOREST::Node > > CloneForest(const FOREST &forest)
Clone a tree, copy-constructing new nodes (calling boost::make_shared) and setting up child pointers ...
Definition: treeTraversal-inst.h:190