gtsam
Loading...
Searching...
No Matches
treeTraversal-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
17#pragma once
18
19#include <gtsam/base/treeTraversal/parallelTraversalTasks.h>
20#include <gtsam/base/treeTraversal/statistics.h>
21
22#include <gtsam/base/FastList.h>
24#include <gtsam/inference/Key.h>
25#include <gtsam/config.h> // for GTSAM_USE_TBB
26
27#include <stack>
28#include <vector>
29#include <string>
30#include <memory>
31#include <functional>
32#include <cassert>
33
34namespace gtsam {
35
37namespace treeTraversal {
38
39/* ************************************************************************* */
40namespace {
41// Internal node used in DFS preorder stack
42template<typename NODE, typename DATA>
43struct TraversalNode {
44 bool expanded;
45 const std::shared_ptr<NODE>& treeNode;
46 DATA& parentData;
47 typename FastList<DATA>::iterator dataPointer;
48 TraversalNode(const std::shared_ptr<NODE>& _treeNode, DATA& _parentData) :
49 expanded(false), treeNode(_treeNode), parentData(_parentData) {
50 }
51};
52
53// Do nothing - default argument for post-visitor for tree traversal
54struct no_op {
55 template<typename NODE, typename DATA>
56 void operator()(const std::shared_ptr<NODE>& node, const DATA& data) {
57 }
58};
59
60}
61
76template<class FOREST, typename DATA, typename VISITOR_PRE,
77 typename VISITOR_POST>
78void DepthFirstForest(FOREST& forest, DATA& rootData, VISITOR_PRE& visitorPre,
79 VISITOR_POST& visitorPost) {
80 // Typedefs
81 typedef typename FOREST::Node Node;
82 typedef std::shared_ptr<Node> sharedNode;
83
84 // Depth first traversal stack
85 typedef TraversalNode<typename FOREST::Node, DATA> TraversalNode;
86 typedef FastList<TraversalNode> Stack;
87 Stack stack;
88 FastList<DATA> dataList; // List to store node data as it is returned from the pre-order visitor
89
90 // Add roots to stack (insert such that they are visited and processed in order
91 {
92 typename Stack::iterator insertLocation = stack.begin();
93 for(const sharedNode& root: forest.roots())
94 stack.insert(insertLocation, TraversalNode(root, rootData));
95 }
96
97 // Traverse
98 while (!stack.empty()) {
99 // Get next node
100 TraversalNode& node = stack.front();
101
102 if (node.expanded) {
103 // If already expanded, then the data stored in the node is no longer needed, so visit
104 // then delete it.
105 (void) visitorPost(node.treeNode, *node.dataPointer);
106 dataList.erase(node.dataPointer);
107 stack.pop_front();
108 } else {
109 // If not already visited, visit the node and add its children (use reverse iterators so
110 // children are processed in the order they appear)
111 node.dataPointer = dataList.insert(dataList.end(),
112 visitorPre(node.treeNode, node.parentData));
113 typename Stack::iterator insertLocation = stack.begin();
114 for(const sharedNode& child: node.treeNode->children)
115 stack.insert(insertLocation, TraversalNode(child, *node.dataPointer));
116 node.expanded = true;
117 }
118 }
119 assert(dataList.empty());
120}
121
122/* ************************************************************************* */
129template<class FOREST, typename VISITOR_POST>
130void PostOrderForest(FOREST& forest, VISITOR_POST& visitorPost) {
131 typedef typename FOREST::Node Node;
132 typedef std::shared_ptr<Node> sharedNode;
133
134 std::function<void(const sharedNode&)> visit =
135 [&](const sharedNode& node) {
136 if (!node) return;
137 for (const sharedNode& child : node->children) visit(child);
138 (void)visitorPost(node);
139 };
140
141 for (const sharedNode& root : forest.roots()) {
142 visit(root);
143 }
144}
145
157template<class FOREST, typename DATA, typename VISITOR_PRE>
158void DepthFirstForest(FOREST& forest, DATA& rootData, VISITOR_PRE& visitorPre) {
159 no_op visitorPost;
160 DepthFirstForest(forest, rootData, visitorPre, visitorPost);
161}
162
179template<class FOREST, typename DATA, typename VISITOR_PRE,
180 typename VISITOR_POST>
181void DepthFirstForestParallel(FOREST& forest, DATA& rootData,
182 VISITOR_PRE& visitorPre, VISITOR_POST& visitorPost,
183 int problemSizeThreshold = 10) {
184
185#if defined(GTSAM_USE_TBB) && !defined(GTSAM_TBB_BOUNDED_MEMORY_GROWTH_FLAG)
186 // Note: Parallel tree traversal (the default) causes a large increase in memory footprint.
187 // In a tested use case, memory grew from approximately 4 GB to 12 GB.
188
189 typedef typename FOREST::Node Node;
190
191 internal::CreateRootTask<Node>(forest.roots(), rootData, visitorPre,
192 visitorPost, problemSizeThreshold);
193#else
194 DepthFirstForest(forest, rootData, visitorPre, visitorPost);
195#endif
196}
197
198/* ************************************************************************* */
208template<class FOREST, typename VISITOR_POST>
209void PostOrderForestParallel(FOREST& forest, VISITOR_POST& visitorPost,
210 int problemSizeThreshold = 10,
211 size_t leafAggregationProblemSize = 0) {
212#if defined(GTSAM_USE_TBB) && !defined(GTSAM_TBB_BOUNDED_MEMORY_GROWTH_FLAG)
213 // Note: Parallel tree traversal (the default) causes a large increase in memory footprint.
214
215 typedef typename FOREST::Node Node;
216 internal::CreateRootPostOrderTask<Node>(forest.roots(), visitorPost,
217 problemSizeThreshold,
218 leafAggregationProblemSize);
219#else
220 (void)leafAggregationProblemSize;
221 PostOrderForest(forest, visitorPost);
222#endif
223}
224
225/* ************************************************************************* */
227namespace {
228template<typename NODE>
229std::shared_ptr<NODE> CloneForestVisitorPre(
230 const std::shared_ptr<NODE>& node,
231 const std::shared_ptr<NODE>& parentPointer) {
232 // Clone the current node and add it to its cloned parent
233 std::shared_ptr<NODE> clone = std::make_shared<NODE>(*node);
234 clone->children.clear();
235 parentPointer->children.push_back(clone);
236 return clone;
237}
238}
239
245template<class FOREST>
247 const FOREST& forest) {
248 typedef typename FOREST::Node Node;
249 std::shared_ptr<Node> rootContainer = std::make_shared<Node>();
250 DepthFirstForest(forest, rootContainer, CloneForestVisitorPre<Node>);
251 return FastVector<std::shared_ptr<Node> >(rootContainer->children.begin(),
252 rootContainer->children.end());
253}
254
255/* ************************************************************************* */
257namespace {
258struct PrintForestVisitorPre {
259 const KeyFormatter& formatter;
260 PrintForestVisitorPre(const KeyFormatter& formatter) :
261 formatter(formatter) {
262 }
263 template<typename NODE> std::string operator()(
264 const std::shared_ptr<NODE>& node, const std::string& parentString) {
265 // Print the current node
266 node->print(parentString + "-", formatter);
267 // Increment the indentation
268 return parentString + "| ";
269 }
270};
271}
272
275template<class FOREST>
276void PrintForest(const FOREST& forest, std::string str,
277 const KeyFormatter& keyFormatter) {
278 PrintForestVisitorPre visitor(keyFormatter);
279 DepthFirstForest(forest, str, visitor);
280}
281} // namespace treeTraversal
282
283} // namespace gtsam
A thin wrapper around std::vector that uses a custom allocator.
A thin wrapper around std::list that uses boost's fast_pool_allocator.
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
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
Internal functions used for traversing trees.
Definition treeTraversal-inst.h:37
void PostOrderForest(FOREST &forest, VISITOR_POST &visitorPost)
Traverse a forest depth-first with post-order visits only.
Definition treeTraversal-inst.h:130
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 DepthFirstForest(FOREST &forest, DATA &rootData, VISITOR_PRE &visitorPre, VISITOR_POST &visitorPost)
Traverse a forest depth-first with pre-order and post-order visits.
Definition treeTraversal-inst.h:78
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
void PostOrderForestParallel(FOREST &forest, VISITOR_POST &visitorPost, int problemSizeThreshold=10, size_t leafAggregationProblemSize=0)
Traverse a forest depth-first with post-order visits only (parallel if TBB).
Definition treeTraversal-inst.h:209
void DepthFirstForestParallel(FOREST &forest, DATA &rootData, VISITOR_PRE &visitorPre, VISITOR_POST &visitorPost, int problemSizeThreshold=10)
Traverse a forest depth-first with pre-order and post-order visits.
Definition treeTraversal-inst.h:181
FastList is a thin wrapper around std::list that uses the boost fast_pool_allocator instead of the de...
Definition FastList.h:43
const FastVector< sharedNode > & roots() const
Return the set of roots (one for a tree, multiple for a forest).
Definition ClusterTree.h:178