gtsam
Loading...
Searching...
No Matches
EliminationTree-inst.h
Go to the documentation of this file.
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 <stack>
21#include <queue>
22#include <cassert>
23
24#include <gtsam/base/timing.h>
30
31namespace gtsam {
32
33 /* ************************************************************************* */
34 template<class BAYESNET, class GRAPH>
36 EliminationTree<BAYESNET,GRAPH>::Node::eliminate(
37 const std::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 KeyVector keyAsVector(1); keyAsVector[0] = key;
52 auto eliminationResult = function(gatheredFactors, Ordering(keyAsVector));
53
54 // Add conditional to BayesNet
55 output->push_back(eliminationResult.first);
56
57 // Return result
58 return eliminationResult.second;
59 }
60
61 /* ************************************************************************* */
62 template<class BAYESNET, class GRAPH>
64 const std::string& str, const KeyFormatter& keyFormatter) const
65 {
66 std::cout << str << "(" << keyFormatter(key) << ")\n";
67 for(const sharedFactor& factor: factors) {
68 if(factor)
69 factor->print(str);
70 else
71 std::cout << str << "null factor\n";
72 }
73 }
74
75
76 /* ************************************************************************* */
77 template<class BAYESNET, class GRAPH>
79 const VariableIndex& structure, const Ordering& order)
80 {
81 gttic(EliminationTree_Contructor);
82
83 // Number of factors and variables - NOTE in the case of partial elimination, n here may
84 // be fewer variables than are actually present in the graph.
85 const size_t m = graph.size();
86 const size_t n = order.size();
87
88 static const size_t none = std::numeric_limits<size_t>::max();
89
90 // Allocate result parent vector and vector of last factor columns
92 FastVector<size_t> parents(n, none);
93 FastVector<size_t> prevCol(m, none);
94 FastVector<bool> factorUsed(m, false);
95
96 try {
97 // for column j \in 1 to n do
98 for (size_t j = 0; j < n; j++)
99 {
100 // Retrieve the factors involving this variable and create the current node
101 const FactorIndices& factors = structure.at(order[j]);
102 const sharedNode node = std::make_shared<Node>();
103 node->key = order[j];
104
105 // for row i \in Struct[A*j] do
106 node->children.reserve(factors.size());
107 node->factors.reserve(factors.size());
108 for(const size_t i: factors) {
109 // If we already hit a variable in this factor, make the subtree containing the previous
110 // variable in this factor a child of the current node. This means that the variables
111 // eliminated earlier in the factor depend on the later variables in the factor. If we
112 // haven't yet hit a variable in this factor, we add the factor to the current node.
113 // TODO: Store root shortcuts instead of parents.
114 if (prevCol[i] != none) {
115 size_t k = prevCol[i];
116 // Find root r of the current tree that contains k. Use raw pointers in computing the
117 // parents to avoid changing the reference counts while traversing up the tree.
118 size_t r = k;
119 while (parents[r] != none)
120 r = parents[r];
121 // If the root of the subtree involving this node is actually the current node,
122 // TODO: what does this mean? forest?
123 if (r != j) {
124 // Now that we found the root, hook up parent and child pointers in the nodes.
125 parents[r] = j;
126 node->children.push_back(nodes[r]);
127 }
128 } else {
129 // Add the factor to the current node since we are at the first variable in this factor.
130 node->factors.push_back(graph[i]);
131 factorUsed[i] = true;
132 }
133 prevCol[i] = j;
134 }
135 nodes[j] = node;
136 }
137 } catch(std::invalid_argument& e) {
138 // If this is thrown from structure.at(order[j]) above, it means that it was requested to
139 // eliminate a variable not present in the graph, so throw a more informative error message.
140 (void)e; // Prevent unused variable warning
141 throw std::invalid_argument("EliminationTree: given ordering contains variables that are not involved in the factor graph");
142 } catch(...) {
143 throw;
144 }
145
146 // Find roots
147 assert(parents.empty() || parents.back() == none); // We expect the last-eliminated node to be a root no matter what
148 for(size_t j = 0; j < n; ++j)
149 if(parents[j] == none)
150 roots_.push_back(nodes[j]);
151
152 // Gather remaining factors (exclude null factors)
153 for(size_t i = 0; i < m; ++i)
154 if(!factorUsed[i] && graph[i])
155 remainingFactors_.push_back(graph[i]);
156 }
157
158 /* ************************************************************************* */
159 template<class BAYESNET, class GRAPH>
161 const FactorGraphType& factorGraph, const Ordering& order)
162 {
163 gttic(ET_Create2);
164 // Build variable index first
165 const VariableIndex variableIndex(factorGraph);
166 This temp(factorGraph, variableIndex, order);
167 this->swap(temp); // Swap in the tree, and temp will be deleted
168 }
169
170 /* ************************************************************************* */
171 template<class BAYESNET, class GRAPH>
174 {
175 // Start by duplicating the tree.
177
178 // Assign the remaining factors - these are pointers to factors in the original factor graph and
179 // we do not clone them.
180 remainingFactors_ = other.remainingFactors_;
181
182 return *this;
183 }
184
185 /* ************************************************************************* */
186
192 template<class BAYESNET, class GRAPH>
194 {
195 // For each tree, we first move the root into a queue; then we do a BFS on the tree with the queue;
196
197 for (auto&& root : roots_) {
198 std::queue<sharedNode> bfs_queue;
199
200 // first, steal the root and move it to the queue. This invalidates root
201 bfs_queue.push(std::move(root));
202
203 // for each node iterated, if its reference count is 1, it will be deleted while its children are still in the queue.
204 // so that the recursive deletion will not happen.
205 while (!bfs_queue.empty()) {
206 // move the ownership of the front node from the queue to the current variable, invalidating the sharedClique at the front of the queue
207 auto node = std::move(bfs_queue.front());
208 bfs_queue.pop();
209
210 // add the children of the current node to the queue, so that the queue will also own the children nodes.
211 for (auto&& child : node->children) {
212 bfs_queue.push(std::move(child));
213 } // leaving the scope of current will decrease the reference count of the current node by 1, and if the reference count is 0,
214 // the node will be deleted. Because the children are in the queue, the deletion of the node will not trigger a recursive
215 // deletion of the children.
216 }
217 }
218 }
219
220
221 /* ************************************************************************* */
222 template<class BAYESNET, class GRAPH>
223 std::pair<std::shared_ptr<BAYESNET>, std::shared_ptr<GRAPH> >
225 {
226 gttic(EliminationTree_eliminate);
227 // Allocate result
228 auto result = std::make_shared<BayesNetType>();
229
230 // Run tree elimination algorithm
232
233 // Add remaining factors that were not involved with eliminated variables
234 auto allRemainingFactors = std::make_shared<FactorGraphType>();
235 allRemainingFactors->push_back(remainingFactors_.begin(), remainingFactors_.end());
236 allRemainingFactors->push_back(remainingFactors.begin(), remainingFactors.end());
237
238 // Return result
239 return {result, allRemainingFactors};
240 }
241
242 /* ************************************************************************* */
243 template<class BAYESNET, class GRAPH>
244 void EliminationTree<BAYESNET,GRAPH>::print(const std::string& name, const KeyFormatter& formatter) const
245 {
246 treeTraversal::PrintForest(*this, name, formatter);
247 }
248
249 /* ************************************************************************* */
250 template<class BAYESNET, class GRAPH>
251 bool EliminationTree<BAYESNET,GRAPH>::equals(const This& expected, double tol) const
252 {
253 // Depth-first-traversal stacks
254 std::stack<sharedNode, FastVector<sharedNode> > stack1, stack2;
255
256 // Add roots in sorted order
257 {
259 for(const sharedNode& root: this->roots_) { keys.emplace(root->key, root); }
260 typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
261 for(const Key_Node& key_node: keys) { stack1.push(key_node.second); }
262 }
263 {
265 for(const sharedNode& root: expected.roots_) { keys.emplace(root->key, root); }
266 typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
267 for(const Key_Node& key_node: keys) { stack2.push(key_node.second); }
268 }
269
270 // Traverse, adding children in sorted order
271 while(!stack1.empty() && !stack2.empty()) {
272 // Pop nodes
273 sharedNode node1 = stack1.top();
274 stack1.pop();
275 sharedNode node2 = stack2.top();
276 stack2.pop();
277
278 // Compare nodes
279 if(node1->key != node2->key)
280 return false;
281 if(node1->factors.size() != node2->factors.size()) {
282 return false;
283 } else {
284 for(typename Node::Factors::const_iterator it1 = node1->factors.begin(), it2 = node2->factors.begin();
285 it1 != node1->factors.end(); ++it1, ++it2) // Only check it1 == end because we already returned false for different counts
286 {
287 if(*it1 && *it2) {
288 if(!(*it1)->equals(**it2, tol))
289 return false;
290 } else if((*it1 && !*it2) || (*it2 && !*it1)) {
291 return false;
292 }
293 }
294 }
295
296 // Add children in sorted order
297 {
299 for(const sharedNode& node: node1->children) { keys.emplace(node->key, node); }
300 typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
301 for(const Key_Node& key_node: keys) { stack1.push(key_node.second); }
302 }
303 {
305 for(const sharedNode& node: node2->children) { keys.emplace(node->key, node); }
306 typedef typename FastMap<Key,sharedNode>::value_type Key_Node;
307 for(const Key_Node& key_node: keys) { stack2.push(key_node.second); }
308 }
309 }
310
311 // If either stack is not empty, the number of nodes differed
312 if(!stack1.empty() || !stack2.empty())
313 return false;
314
315 return true;
316 }
317
318 /* ************************************************************************* */
319 template<class BAYESNET, class GRAPH>
321 roots_.swap(other.roots_);
322 remainingFactors_.swap(other.remainingFactors_);
323 }
324
325
326}
Timing utilities.
Variable ordering for the elimination algorithm.
Contains generic inference algorithms that convert between templated graphical models,...
FastVector< typename TREE::sharedFactor > EliminateTree(RESULT &result, const TREE &tree, const typename TREE::Eliminate &function)
Eliminate an elimination tree or a Bayes tree (used internally).
Definition inference-inst.h:74
std::vector< T, typename internal::FastDefaultVectorAllocator< T >::type > FastVector
FastVector is a type alias to a std::vector with a custom memory allocator.
Definition FastVector.h:33
Global functions in a separate testing namespace.
Definition chartTesting.h:28
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition Key.h:91
std::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition Key.h:35
FastVector< FactorIndex > FactorIndices
Define collection types:
Definition Factor.h:37
FastVector< std::shared_ptr< typename FOREST::Node > > CloneForest(const FOREST &forest)
Clone a tree, copy-constructing new nodes (calling std::make_shared) and setting up child pointers fo...
Definition treeTraversal-inst.h:246
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:276
FastMap is a thin wrapper around std::map that uses the boost fast_pool_allocator instead of the defa...
Definition FastMap.h:40
An elimination tree is a data structure used intermediately during elimination.
Definition EliminationTree.h:52
bool equals(const This &other, double tol=1e-9) const
Test whether the tree is equal to another.
Definition EliminationTree-inst.h:251
void print(const std::string &name="EliminationTree: ", const KeyFormatter &formatter=DefaultKeyFormatter) const
Print the tree to cout.
Definition EliminationTree-inst.h:244
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:173
EliminationTree< BAYESNET, GRAPH > This
This class.
Definition EliminationTree.h:54
~EliminationTree()
Destructor Using default destructor causes stack overflow for large trees due to recursive destructio...
Definition EliminationTree-inst.h:193
FastVector< sharedNode > roots_
concept check
Definition EliminationTree.h:86
std::shared_ptr< FactorType > sharedFactor
Shared pointer to a factor.
Definition EliminationTree.h:60
std::shared_ptr< Node > sharedNode
Shared pointer to Node.
Definition EliminationTree.h:80
GRAPH FactorGraphType
The factor graph type.
Definition EliminationTree.h:58
void swap(This &other)
Swap the data of this tree with another one, this operation is very fast.
Definition EliminationTree-inst.h:320
std::pair< std::shared_ptr< BayesNetType >, std::shared_ptr< FactorGraphType > > eliminate(Eliminate function) const
Eliminate the factors to a Bayes net and remaining factor graph.
Definition EliminationTree-inst.h:224
EliminationTree()
Protected default constructor.
Definition EliminationTree.h:164
EliminationTree(const FactorGraphType &factorGraph, const VariableIndex &structure, const Ordering &order)
Build the elimination tree of a factor graph using pre-computed column structure.
Definition EliminationTree-inst.h:78
const FastVector< sharedFactor > & remainingFactors() const
Return the remaining factors that are not pulled into elimination.
Definition EliminationTree.h:157
Key key
key associated with root
Definition EliminationTree.h:70
Children children
sub-trees
Definition EliminationTree.h:72
Factors factors
factors associated with root
Definition EliminationTree.h:71
Definition Ordering.h:33
The VariableIndex class computes and stores the block column structure of a factor graph.
Definition VariableIndex.h:41
const FactorIndices & at(Key variable) const
Access a list of factors by variable.
Definition VariableIndex.cpp:30