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