gtsam
Loading...
Searching...
No Matches
BayesTree-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
20
21#pragma once
22
26#include <gtsam/base/timing.h>
27
28#include <fstream>
29#include <queue>
30#include <cassert>
31#include <unordered_set>
32
33namespace gtsam {
34
35 /* ************************************************************************* */
36 template<class CLIQUE>
39 for (const sharedClique& root : roots_) getCliqueData(root, &stats);
40 return stats;
41 }
42
43 /* ************************************************************************* */
44 template <class CLIQUE>
46 BayesTreeCliqueData* stats) const {
47 const auto conditional = clique->conditional();
48 stats->conditionalSizes.push_back(conditional->nrFrontals());
49 stats->separatorSizes.push_back(conditional->nrParents());
50 for (sharedClique c : clique->children) {
51 getCliqueData(c, stats);
52 }
53 }
54
55 /* ************************************************************************* */
56 template<class CLIQUE>
58 size_t count = 0;
59 for(const sharedClique& root: roots_)
60 count += root->numCachedSeparatorMarginals();
61 return count;
62 }
63
64 /* ************************************************************************* */
65 template <class CLIQUE>
66 void BayesTree<CLIQUE>::dot(std::ostream& os,
67 const KeyFormatter& keyFormatter) const {
68 if (roots_.empty())
69 throw std::invalid_argument(
70 "the root of Bayes tree has not been initialized!");
71 os << "digraph G{\n";
72 for (const sharedClique& root : roots_) {
73 size_t key = root->conditional()->firstFrontalKey();
74 dot(os, root, keyFormatter, key);
75 }
76 os << "}";
77 std::flush(os);
78 }
79
80 /* ************************************************************************* */
81 template <class CLIQUE>
82 std::string BayesTree<CLIQUE>::dot(const KeyFormatter& keyFormatter) const {
83 std::stringstream ss;
84 dot(ss, keyFormatter);
85 return ss.str();
86 }
87
88 /* ************************************************************************* */
89 template <class CLIQUE>
90 void BayesTree<CLIQUE>::saveGraph(const std::string& filename,
91 const KeyFormatter& keyFormatter) const {
92 std::ofstream of(filename.c_str());
93 dot(of, keyFormatter);
94 of.close();
95 }
96
97 /* ************************************************************************* */
98 template <class CLIQUE>
100 const KeyFormatter& keyFormatter,
101 size_t parentnum) const {
102 size_t num = clique->conditional()->firstFrontalKey();
103 bool first = true;
104 std::stringstream out;
105 out << num;
106 std::string parent = out.str();
107 parent += "[label=\"";
108
109 for (Key key : clique->conditional_->frontals()) {
110 if (!first) parent += ", ";
111 first = false;
112 parent += keyFormatter(key);
113 }
114
115 if (clique->parent()) {
116 parent += " : ";
117 s << parentnum << "->" << num << "\n";
118 }
119
120 first = true;
121 for (Key parentKey : clique->conditional_->parents()) {
122 if (!first) parent += ", ";
123 first = false;
124 parent += keyFormatter(parentKey);
125 }
126 parent += "\"];\n";
127 s << parent;
128
129 for (sharedClique c : clique->children) {
130 dot(s, c, keyFormatter, num);
131 }
132 }
133
134 /* ************************************************************************* */
135 template<class CLIQUE>
136 size_t BayesTree<CLIQUE>::size() const {
137 size_t size = 0;
138 for(const sharedClique& clique: roots_)
139 size += clique->treeSize();
140 return size;
141 }
142
143 /* ************************************************************************* */
144 template<class CLIQUE>
146 for(Key j: clique->conditional()->frontals())
147 nodes_[j] = clique;
148 if (parent_clique != nullptr) {
149 clique->parent_ = parent_clique;
150 parent_clique->children.push_back(clique);
151 } else {
152 roots_.push_back(clique);
153 }
154 }
155
156 /* ************************************************************************* */
157 namespace {
158 template <class FACTOR, class CLIQUE>
159 struct _pushCliqueFunctor {
160 _pushCliqueFunctor(FactorGraph<FACTOR>* graph_) : graph(graph_) {}
161 FactorGraph<FACTOR>* graph;
162 int operator()(const std::shared_ptr<CLIQUE>& clique, int dummy) {
163 graph->push_back(clique->conditional_);
164 return 0;
165 }
166 };
167 } // namespace
168
169 /* ************************************************************************* */
170 template <class CLIQUE>
172 FactorGraph<FactorType>* graph) const {
173 // Traverse the BayesTree and add all conditionals to this graph
174 int data = 0; // Unused
175 _pushCliqueFunctor<FactorType, CLIQUE> functor(graph);
176 treeTraversal::DepthFirstForest(*this, data, functor);
177 }
178
179 /* ************************************************************************* */
180 template<class CLIQUE>
181 BayesTree<CLIQUE>::BayesTree(const This& other) {
182 *this = other;
183 }
184
185 /* ************************************************************************* */
186
192 template<class CLIQUE>
194 /* Because tree nodes are hold by both root_ and nodes_, we need to clear nodes_ manually first and
195 * reduce the reference count of each node by 1. Otherwise, the nodes will not be properly deleted
196 * during the BFS process.
197 */
198 nodes_.clear();
199 for (auto&& root: roots_) {
200 std::queue<sharedClique> bfs_queue;
201
202 // first, steal the root and move it to the queue. This invalidates root
203 bfs_queue.push(std::move(root));
204
205 // do a BFS on the tree, for each node, add its children to the queue, and then delete it from the queue
206 // So if the reference count of the node is 1, it will be deleted, and because its children are in the queue,
207 // the deletion of the node will not trigger a recursive deletion of the children.
208 while (!bfs_queue.empty()) {
209 // move the ownership of the front node from the queue to the current variable, invalidating the sharedClique at the front of the queue
210 auto current = std::move(bfs_queue.front());
211 bfs_queue.pop();
212
213 // add the children of the current node to the queue, so that the queue will also own the children nodes.
214 for (auto child: current->children) {
215 bfs_queue.push(std::move(child));
216 } // leaving the scope of current will decrease the reference count of the current node by 1, and if the reference count is 0,
217 // the node will be deleted. Because the children are in the queue, the deletion of the node will not trigger a recursive
218 // deletion of the children.
219 }
220 }
221 }
222
223 /* ************************************************************************* */
224 namespace {
225 template<typename NODE>
226 std::shared_ptr<NODE>
227 BayesTreeCloneForestVisitorPre(const std::shared_ptr<NODE>& node, const std::shared_ptr<NODE>& parentPointer)
228 {
229 // Clone the current node and add it to its cloned parent
230 std::shared_ptr<NODE> clone = std::make_shared<NODE>(*node);
231 clone->children.clear();
232 clone->parent_ = parentPointer;
233 parentPointer->children.push_back(clone);
234 return clone;
235 }
236 }
237
238 /* ************************************************************************* */
239 template<class CLIQUE>
241 this->clear();
242 std::shared_ptr<Clique> rootContainer = std::make_shared<Clique>();
243 treeTraversal::DepthFirstForest(other, rootContainer, BayesTreeCloneForestVisitorPre<Clique>);
244 for(const sharedClique& root: rootContainer->children) {
245 root->parent_ = typename Clique::weak_ptr(); // Reset the parent since it's set to the dummy clique
246 insertRoot(root);
247 }
248 return *this;
249 }
250
251 /* ************************************************************************* */
252 template<class CLIQUE>
253 void BayesTree<CLIQUE>::print(const std::string& s, const KeyFormatter& keyFormatter) const {
254 std::cout << s << ": cliques: " << size() << ", variables: " << nodes_.size() << std::endl;
255 treeTraversal::PrintForest(*this, s, keyFormatter);
256 }
257
258 /* ************************************************************************* */
259 // binary predicate to test equality of a pair for use in equals
260 template<class CLIQUE>
261 bool check_sharedCliques(
262 const std::pair<Key, typename BayesTree<CLIQUE>::sharedClique>& v1,
263 const std::pair<Key, typename BayesTree<CLIQUE>::sharedClique>& v2
264 ) {
265 return v1.first == v2.first &&
266 ((!v1.second && !v2.second) || (v1.second && v2.second && v1.second->equals(*v2.second)));
267 }
268
269 /* ************************************************************************* */
270 template<class CLIQUE>
271 bool BayesTree<CLIQUE>::equals(const BayesTree<CLIQUE>& other, double tol) const {
272 // Compare number of cliques first.
273 if (size() != other.size())
274 return false;
275
276 // Compare number of variables (nodes index size).
277 if (nodes_.size() != other.nodes_.size())
278 return false;
279
280 // Compare cliques by key so equality does not depend on the
281 // iteration order of the underlying ConcurrentMap.
282 for (const auto& kv : nodes_) {
283 const Key key = kv.first;
284 const sharedClique& clique = kv.second;
285
286 auto it = other.nodes_.find(key);
287 if (it == other.nodes_.end())
288 return false;
289
290 const sharedClique& otherClique = it->second;
291
292 if (!clique && !otherClique)
293 continue;
294 if (!clique || !otherClique)
295 return false;
296 if (!clique->equals(*otherClique, tol))
297 return false;
298 }
299
300 return true;
301 }
302
303 /* ************************************************************************* */
304 template<class CLIQUE>
305 template<class CONTAINER>
306 Key BayesTree<CLIQUE>::findParentClique(const CONTAINER& parents) const {
307 typename CONTAINER::const_iterator lowestOrderedParent = min_element(parents.begin(), parents.end());
308 assert(lowestOrderedParent != parents.end());
309 return *lowestOrderedParent;
310 }
311
312 /* ************************************************************************* */
313 template<class CLIQUE>
315 // Add each frontal variable of this root node
316 for(const Key& j: subtree->conditional()->frontals()) {
317 bool inserted = nodes_.insert({j, subtree}).second;
318 assert(inserted); (void)inserted;
319 }
320 // Fill index for each child
322 for(const sharedClique& child: subtree->children) {
323 fillNodesIndex(child); }
324 }
325
326 /* ************************************************************************* */
327 template<class CLIQUE>
329 roots_.push_back(subtree); // Add to roots
330 fillNodesIndex(subtree); // Populate nodes index
331 }
332
333 /* ************************************************************************* */
334 // First finds clique marginal then marginalizes that
335 /* ************************************************************************* */
336 template<class CLIQUE>
337 typename BayesTree<CLIQUE>::sharedConditional
338 BayesTree<CLIQUE>::marginalFactor(Key j, const Eliminate& function) const
339 {
340 gttic(BayesTree_marginalFactor);
341
342 // get clique containing Key j
343 sharedClique clique = this->clique(j);
344
345 // calculate or retrieve its marginal P(C) = P(F,S)
346 FactorGraphType cliqueMarginal = clique->marginal2(function);
347
348 // Now, marginalize out everything that is not variable j
349 BayesNetType marginalBN =
350 *cliqueMarginal.marginalMultifrontalBayesNet(Ordering{j}, function);
351
352 // The Bayes net should contain only one conditional for variable j, so return it
353 return marginalBN.front();
354 }
355
356 /* ************************************************************************* */
357 // Find two cliques, their joint, then marginalizes
358 /* ************************************************************************* */
359 template<class CLIQUE>
360 typename BayesTree<CLIQUE>::sharedFactorGraph
361 BayesTree<CLIQUE>::joint(Key j1, Key j2, const Eliminate& function) const
362 {
363 gttic(BayesTree_joint);
364 return std::make_shared<FactorGraphType>(*jointBayesNet(j1, j2, function));
365 }
366
367 /* ************************************************************************* */
368 template <class CLIQUE>
369 typename BayesTree<CLIQUE>::sharedFactorGraph BayesTree<CLIQUE>::joint(
370 const KeyVector& keys, const Eliminate& function) const {
371 gttic(BayesTree_joint);
372 return std::make_shared<FactorGraphType>(*jointBayesNet(keys, function));
373 }
374
375 /* ************************************************************************* */
376 // Find the lowest common ancestor of two cliques
377 // TODO(Varun): consider implementing this as a Range Minimum Query
378 template <class CLIQUE>
379 static std::shared_ptr<CLIQUE> findLowestCommonAncestor(
380 const std::shared_ptr<CLIQUE>& C1, const std::shared_ptr<CLIQUE>& C2) {
381 // Collect all ancestors of C1
382 std::unordered_set<std::shared_ptr<CLIQUE>> ancestors;
383 for (auto p = C1; p; p = p->parent()) {
384 ancestors.insert(p);
385 }
386
387 // Find the first common ancestor in C2's lineage
388 std::shared_ptr<CLIQUE> B;
389 for (auto p = C2; p; p = p->parent()) {
390 if (ancestors.count(p)) {
391 return p; // Return the common ancestor when found
392 }
393 }
394
395 return nullptr; // Return nullptr if no common ancestor is found
396 }
397
398 /* ************************************************************************* */
399 template <class CLIQUE>
400 static std::shared_ptr<CLIQUE> findLowestCommonAncestor(
401 const std::vector<std::shared_ptr<CLIQUE>>& cliques) {
402 if (cliques.empty()) {
403 return nullptr;
404 }
405
406 std::shared_ptr<CLIQUE> lca = cliques.front();
407 for (size_t i = 1; i < cliques.size() && lca; ++i) {
408 lca = findLowestCommonAncestor(lca, cliques[i]);
409 }
410 return lca;
411 }
412
413 /* ************************************************************************* */
414 // Given the clique P(F:S) and the ancestor clique B
415 // Return the Bayes tree P(S\B | S \cap B), where \cap is intersection
416 template <class CLIQUE>
417 static auto factorInto(
418 const std::shared_ptr<CLIQUE>& p_F_S, const std::shared_ptr<CLIQUE>& B,
419 const typename CLIQUE::FactorGraphType::Eliminate& eliminate) {
420 gttic(Full_root_factoring);
421
422 // Get the shortcut P(S|B)
423 auto p_S_B = p_F_S->shortcut(B, eliminate);
424
425 // Compute S\B
426 KeyVector S_setminus_B = p_F_S->separator_setminus_B(B);
427
428 // Factor P(S|B) into P(S\B|S \cap B) and P(S \cap B)
429 auto [bayesTree, fg] =
430 typename CLIQUE::FactorGraphType(p_S_B).eliminatePartialMultifrontal(
431 Ordering(S_setminus_B), eliminate);
432 return bayesTree;
433 }
434
435 /* ************************************************************************* */
437 template <class CLIQUE>
438 static KeyVector uniqueKeys(const KeyVector& keys) {
439 KeyVector unique;
440 unique.reserve(keys.size());
441 KeySet seen;
442 for (Key key : keys) {
443 if (seen.insert(key).second) {
444 unique.push_back(key);
445 }
446 }
447 return unique;
448 }
449
450 /* ************************************************************************* */
451 template <class CLIQUE>
452 static std::vector<std::shared_ptr<CLIQUE>> uniqueCliquesFromKeys(
453 const BayesTree<CLIQUE>& tree, const KeyVector& keys) {
454 std::vector<std::shared_ptr<CLIQUE>> queryCliques;
455 queryCliques.reserve(keys.size());
456 std::unordered_set<std::shared_ptr<CLIQUE>> seen;
457
458 for (Key key : keys) {
459 auto clique = tree.clique(key);
460 if (seen.insert(clique).second) {
461 queryCliques.push_back(clique);
462 }
463 }
464 return queryCliques;
465 }
466
467 /* ************************************************************************* */
468 template <class CLIQUE>
469 static std::shared_ptr<CLIQUE> rootClique(
470 const std::shared_ptr<CLIQUE>& clique) {
471 auto current = clique;
472 while (current && current->parent()) {
473 current = current->parent();
474 }
475 return current;
476 }
477
478 /* ************************************************************************* */
479 template <class CLIQUE>
480 static std::unordered_set<std::shared_ptr<CLIQUE>> collectSupportCliques(
481 const std::vector<std::shared_ptr<CLIQUE>>& queryCliques,
482 const std::shared_ptr<CLIQUE>& root) {
483 std::unordered_set<std::shared_ptr<CLIQUE>> support;
484 if (!root) {
485 return support;
486 }
487
488 support.insert(root);
489 for (const auto& clique : queryCliques) {
490 for (auto current = clique; current && current != root;
491 current = current->parent()) {
492 support.insert(current);
493 }
494 }
495 return support;
496 }
497
498 /* ************************************************************************* */
499 template <class CLIQUE>
500 static std::unordered_map<std::shared_ptr<CLIQUE>, size_t>
501 countSupportChildren(
502 const std::unordered_set<std::shared_ptr<CLIQUE>>& support,
503 const std::shared_ptr<CLIQUE>& root) {
504 std::unordered_map<std::shared_ptr<CLIQUE>, size_t> supportChildren;
505 for (const auto& clique : support) {
506 supportChildren[clique] = 0;
507 }
508
509 for (const auto& clique : support) {
510 if (clique == root) {
511 continue;
512 }
513 auto parent = clique->parent();
514 if (parent && support.count(parent)) {
515 ++supportChildren[parent];
516 }
517 }
518 return supportChildren;
519 }
520
521 /* ************************************************************************* */
522 template <class CLIQUE>
523 static std::unordered_set<std::shared_ptr<CLIQUE>> collectEssentialCliques(
524 const std::vector<std::shared_ptr<CLIQUE>>& queryCliques,
525 const std::unordered_set<std::shared_ptr<CLIQUE>>& support,
526 const std::unordered_map<std::shared_ptr<CLIQUE>, size_t>& supportChildren,
527 const std::shared_ptr<CLIQUE>& root) {
528 std::unordered_set<std::shared_ptr<CLIQUE>> essential;
529 if (root) {
530 essential.insert(root);
531 }
532
533 std::unordered_set<std::shared_ptr<CLIQUE>> querySet(queryCliques.begin(),
534 queryCliques.end());
535 for (const auto& clique : support) {
536 const auto childCount = supportChildren.find(clique);
537 const size_t numSupportChildren =
538 childCount == supportChildren.end() ? 0 : childCount->second;
539 if (querySet.count(clique) || numSupportChildren > 1) {
540 essential.insert(clique);
541 }
542 }
543 return essential;
544 }
545
546 /* ************************************************************************* */
547 template <class CLIQUE>
548 static std::shared_ptr<CLIQUE> descendToNextEssentialClique(
549 const std::shared_ptr<CLIQUE>& child,
550 const std::unordered_set<std::shared_ptr<CLIQUE>>& support,
551 const std::unordered_set<std::shared_ptr<CLIQUE>>& essential) {
552 auto current = child;
553 while (current && !essential.count(current)) {
554 std::shared_ptr<CLIQUE> next;
555 for (const auto& grandChild : current->children) {
556 if (support.count(grandChild)) {
557 next = grandChild;
558 break;
559 }
560 }
561 current = next;
562 }
563 return current;
564 }
565
566 /* ************************************************************************* */
567 template <class CLIQUE>
568 static void appendCompressedSupport(
569 const std::shared_ptr<CLIQUE>& ancestor,
570 const std::unordered_set<std::shared_ptr<CLIQUE>>& support,
571 const std::unordered_set<std::shared_ptr<CLIQUE>>& essential,
572 typename CLIQUE::FactorGraphType* factorGraph,
573 const typename CLIQUE::FactorGraphType::Eliminate& eliminate) {
574 for (const auto& child : ancestor->children) {
575 if (!support.count(child)) {
576 continue;
577 }
578
579 auto nextEssential =
580 descendToNextEssentialClique(child, support, essential);
581 if (!nextEssential) {
582 continue;
583 }
584
585 factorGraph->push_back(*factorInto(nextEssential, ancestor, eliminate));
586 factorGraph->push_back(nextEssential->conditional());
587 appendCompressedSupport(nextEssential, support, essential, factorGraph,
588 eliminate);
589 }
590 }
591
592 /* ************************************************************************* */
593 template <class CLIQUE>
594 typename BayesTree<CLIQUE>::sharedBayesNet BayesTree<CLIQUE>::jointBayesNet(
595 Key j1, Key j2, const Eliminate& eliminate) const {
596 gttic(BayesTree_jointBayesNet);
597 // get clique C1 and C2
598 sharedClique C1 = (*this)[j1], C2 = (*this)[j2];
599
600 // Find the lowest common ancestor clique
601 auto B = findLowestCommonAncestor(C1, C2);
602
603 // Build joint on all involved variables
604 FactorGraphType p_BC1C2;
605
606 if (B) {
607 // Compute marginal on lowest common ancestor clique
608 FactorGraphType p_B = B->marginal2(eliminate);
609
610 // Factor the shortcuts to be conditioned on lowest common ancestor
611 auto p_C1_B = factorInto(C1, B, eliminate);
612 auto p_C2_B = factorInto(C2, B, eliminate);
613
614 p_BC1C2.push_back(p_B);
615 p_BC1C2.push_back(*p_C1_B);
616 p_BC1C2.push_back(*p_C2_B);
617 if (C1 != B) p_BC1C2.push_back(C1->conditional());
618 if (C2 != B) p_BC1C2.push_back(C2->conditional());
619 } else {
620 // The nodes have no common ancestor, they're in different trees, so
621 // they're joint is just the product of their marginals.
622 p_BC1C2.push_back(C1->marginal2(eliminate));
623 p_BC1C2.push_back(C2->marginal2(eliminate));
624 }
625
626 // now, marginalize out everything that is not variable j1 or j2
627 return p_BC1C2.marginalMultifrontalBayesNet(Ordering{j1, j2}, eliminate);
628 }
629
630 /* ************************************************************************* */
631 template <class CLIQUE>
632 typename BayesTree<CLIQUE>::sharedBayesNet BayesTree<CLIQUE>::jointBayesNet(
633 const KeyVector& keys, const Eliminate& eliminate) const {
634 gttic(BayesTree_jointBayesNet);
635
636 const KeyVector queryKeys = uniqueKeys<CLIQUE>(keys);
637 if (queryKeys.empty()) {
638 return std::make_shared<BayesNetType>();
639 }
640 if (queryKeys.size() == 1) {
641 auto bayesNet = std::make_shared<BayesNetType>();
642 bayesNet->push_back(marginalFactor(queryKeys.front(), eliminate));
643 return bayesNet;
644 }
645 if (queryKeys.size() == 2) {
646 return jointBayesNet(queryKeys[0], queryKeys[1], eliminate);
647 }
648
649 const auto queryCliques = uniqueCliquesFromKeys(*this, queryKeys);
650 std::unordered_map<std::shared_ptr<CLIQUE>, KeyVector> keysByRoot;
651 for (Key key : queryKeys) {
652 keysByRoot[rootClique(this->clique(key))].push_back(key);
653 }
654 if (keysByRoot.size() > 1) {
655 FactorGraphType disjointJoint;
656 for (const auto& [rootClique, groupKeys] : keysByRoot) {
657 (void)rootClique;
658 disjointJoint.push_back(*jointBayesNet(groupKeys, eliminate));
659 }
660 return disjointJoint.marginalMultifrontalBayesNet(Ordering(queryKeys),
661 eliminate);
662 }
663
664 const auto root = findLowestCommonAncestor(queryCliques);
665 if (!root) {
666 return std::make_shared<BayesNetType>();
667 }
668
669 const auto support = collectSupportCliques(queryCliques, root);
670 const auto supportChildren = countSupportChildren(support, root);
671 const auto essential =
672 collectEssentialCliques(queryCliques, support, supportChildren, root);
673
674 FactorGraphType reducedJoint;
675 reducedJoint.push_back(root->marginal2(eliminate));
676 appendCompressedSupport(root, support, essential, &reducedJoint, eliminate);
677
678 return reducedJoint.marginalMultifrontalBayesNet(Ordering(queryKeys),
679 eliminate);
680 }
681
682 /* ************************************************************************* */
683 template<class CLIQUE>
685 // Remove all nodes and clear the root pointer
686 nodes_.clear();
687 roots_.clear();
688 }
689
690 /* ************************************************************************* */
691 template<class CLIQUE>
693 for(const sharedClique& root: roots_) {
694 root->deleteCachedShortcuts();
695 }
696 }
697
698 /* ************************************************************************* */
699 template<class CLIQUE>
701 {
702 if (clique->isRoot()) {
703 typename Roots::iterator root = std::find(roots_.begin(), roots_.end(), clique);
704 if(root != roots_.end())
705 roots_.erase(root);
706 } else { // detach clique from parent
707 sharedClique parent = clique->parent_.lock();
708 typename Roots::iterator child = std::find(parent->children.begin(), parent->children.end(), clique);
709 assert(child != parent->children.end());
710 parent->children.erase(child);
711 }
712
713 // orphan my children
714 for(sharedClique child: clique->children)
715 child->parent_ = typename Clique::weak_ptr();
716
717 for(Key j: clique->conditional()->frontals()) {
718 nodes_.unsafe_erase(j);
719 }
720 }
721
722 /* ************************************************************************* */
723 template <class CLIQUE>
725 Cliques* orphans) {
726 // base case is nullptr, if so we do nothing and return empties above
727 if (clique) {
728 // remove the clique from orphans in case it has been added earlier
729 orphans->remove(clique);
730
731 // remove me
732 this->removeClique(clique);
733
734 // remove path above me
735 this->removePath(typename Clique::shared_ptr(clique->parent_.lock()), bn,
736 orphans);
737
738 // add children to list of orphans (splice also removed them from
739 // clique->children_)
740 orphans->insert(orphans->begin(), clique->children.begin(),
741 clique->children.end());
742 clique->children.clear();
743
744 bn->push_back(clique->conditional_);
745 }
746 }
747
748 /* *************************************************************************
749 */
750 template <class CLIQUE>
751 void BayesTree<CLIQUE>::removeTop(const KeyVector& keys, BayesNetType* bn,
752 Cliques* orphans) {
753 gttic(removetop);
754 // process each key of the new factor
755 for (const Key& j : keys) {
756 // get the clique
757 // TODO(frank): Nodes will be searched again in removeClique
758 typename Nodes::const_iterator node = nodes_.find(j);
759 if (node != nodes_.end()) {
760 // remove path from clique to root
761 this->removePath(node->second, bn, orphans);
762 }
763 }
764
765 // Delete cachedShortcuts for each orphan subtree
766 // TODO(frank): Consider Improving
767 for (sharedClique& orphan : *orphans) orphan->deleteCachedShortcuts();
768 }
769
770 /* ************************************************************************* */
771 template<class CLIQUE>
773 const sharedClique& subtree)
774 {
775 // Result clique list
776 Cliques cliques;
777 cliques.push_back(subtree);
778
779 // Remove the first clique from its parents
780 if(!subtree->isRoot())
781 subtree->parent()->children.erase(std::find(
782 subtree->parent()->children.begin(), subtree->parent()->children.end(), subtree));
783 else
784 roots_.erase(std::find(roots_.begin(), roots_.end(), subtree));
785
786 // Add all subtree cliques and erase the children and parent of each
787 for(typename Cliques::iterator clique = cliques.begin(); clique != cliques.end(); ++clique)
788 {
789 // Add children
790 for(const sharedClique& child: (*clique)->children) {
791 cliques.push_back(child); }
792
793 // Delete cached shortcuts
794 (*clique)->deleteCachedShortcutsNonRecursive();
795
796 // Remove this node from the nodes index
797 for(Key j: (*clique)->conditional()->frontals()) {
798 nodes_.unsafe_erase(j); }
799
800 // Erase the parent and children pointers
801 (*clique)->parent_.reset();
802 (*clique)->children.clear();
803 }
804
805 return cliques;
806 }
807
808 /* *********************************************************************** */
809 template <class CLIQUE>
811 gtsam::KeySet& traversedKeys, const sharedClique& clique) const {
812 // base case is nullptr, if so we do nothing and return empties above
813 if (clique) {
814 // traverse me
815 traversedKeys.insert(clique->conditional()->frontals().begin(),
816 clique->conditional()->frontals().end());
817 // traverse path above me
818 this->collectAffectedPathKeys(traversedKeys, clique->parent_.lock());
819 }
820 }
821
822 /* *********************************************************************** */
823 template <class CLIQUE>
825 const gtsam::KeyVector& keys) const {
826 gtsam::KeySet traversedKeys;
827 // process each key of the new factor
828 for (const gtsam::Key& j : keys) {
829 typename Nodes::const_iterator node = nodes_.find(j);
830 if (node != nodes_.end()) {
831 // traverse path from clique to root
832 this->collectAffectedPathKeys(traversedKeys, node->second);
833 }
834 }
835 return traversedKeys;
836 }
837}
Timing utilities.
Bayes Tree is a tree of cliques of a Bayes Chain.
Variable ordering for the elimination algorithm.
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
double dot(const V1 &a, const V2 &b)
Dot product.
Definition Vector.h:191
std::uint64_t Key
Integer nonlinear key type.
Definition types.h:43
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
A factor graph is a bipartite graph with factor nodes connected to variable nodes.
Definition FactorGraph.h:58
store all the sizes
Definition BayesTree.h:58
Bayes tree.
Definition BayesTree.h:77
std::shared_ptr< Clique > sharedClique
Shared pointer to a clique.
Definition BayesTree.h:84
Nodes nodes_
Map from indices to Clique.
Definition BayesTree.h:110
void removeClique(sharedClique clique)
remove a clique: warning, can result in a forest
Definition BayesTree-inst.h:700
sharedFactorGraph joint(Key j1, Key j2, const Eliminate &function=EliminationTraitsType::DefaultEliminate) const
return joint on two variables Limitation: can only calculate joint if cliques are disjoint or one of ...
Definition BayesTree-inst.h:361
void fillNodesIndex(const sharedClique &subtree)
Fill the nodes index for a subtree.
Definition BayesTree-inst.h:314
void dot(std::ostream &os, const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
Output to graphviz format, stream version.
Definition BayesTree-inst.h:66
void addFactorsToGraph(FactorGraph< FactorType > *graph) const
Add all cliques in this BayesTree to the specified factor graph.
Definition BayesTree-inst.h:171
bool equals(const This &other, double tol=1e-9) const
check equality
Definition BayesTree-inst.h:271
This & operator=(const This &other)
Assignment operator.
Definition BayesTree-inst.h:240
BayesTree()
Create an empty Bayes Tree.
Definition BayesTree.h:119
void clear()
Remove all nodes.
Definition BayesTree-inst.h:684
void collectAffectedPathKeys(gtsam::KeySet &traversedKeys, const sharedClique &clique) const
Helper for collectAffectedKeys that recursively aggregates affected keys from a path from 'clique' to...
Definition BayesTree-inst.h:810
Roots roots_
Root cliques.
Definition BayesTree.h:113
void addClique(const sharedClique &clique, const sharedClique &parent_clique=sharedClique())
add a clique (top down)
Definition BayesTree-inst.h:145
sharedBayesNet jointBayesNet(Key j1, Key j2, const Eliminate &function=EliminationTraitsType::DefaultEliminate) const
return joint on two variables as a BayesNet Limitation: can only calculate joint if cliques are disjo...
Definition BayesTree-inst.h:594
Key findParentClique(const CONTAINER &parents) const
Find parent clique of a conditional.
Definition BayesTree-inst.h:306
size_t size() const
number of cliques
Definition BayesTree-inst.h:136
void deleteCachedShortcuts()
Clear all shortcut caches - use before timing on marginal calculation to avoid residual cache data.
Definition BayesTree-inst.h:692
void removePath(sharedClique clique, BayesNetType *bn, Cliques *orphans)
Remove path from clique to root and return that path as factors plus a list of orphaned subtree roots...
Definition BayesTree-inst.h:724
FastList< sharedClique > Cliques
A convenience class for a list of shared cliques.
Definition BayesTree.h:99
sharedConditional marginalFactor(Key j, const Eliminate &function=EliminationTraitsType::DefaultEliminate) const
Return marginal on any variable.
Definition BayesTree-inst.h:338
const sharedClique & clique(Key j) const
alternate syntax for matlab: find the clique that contains the variable with Key j
Definition BayesTree.h:166
~BayesTree()
Destructor.
Definition BayesTree-inst.h:193
size_t numCachedSeparatorMarginals() const
Collect number of cliques with cached separator marginals.
Definition BayesTree-inst.h:57
BayesTreeCliqueData getCliqueData() const
Gather data on all cliques.
Definition BayesTree-inst.h:37
Cliques removeSubtree(const sharedClique &subtree)
Remove the requested subtree.
Definition BayesTree-inst.h:772
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print
Definition BayesTree-inst.h:253
void insertRoot(const sharedClique &subtree)
Insert a new subtree with known parent clique.
Definition BayesTree-inst.h:328
void saveGraph(const std::string &filename, const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
output to file with graphviz format.
Definition BayesTree-inst.h:90
void removeTop(const KeyVector &keys, BayesNetType *bn, Cliques *orphans)
Given a list of indices, turn "contaminated" part of the tree back into a factor graph.
Definition BayesTree-inst.h:751
gtsam::KeySet collectAffectedKeys(const gtsam::KeyVector &keys) const
Returns the set of keys from the tree that are affected by a update to 'keys'.
Definition BayesTree-inst.h:824
Definition Ordering.h:33