31#include <unordered_set>
36 template<
class CLIQUE>
44 template <
class CLIQUE>
47 const auto conditional =
clique->conditional();
48 stats->conditionalSizes.push_back(conditional->nrFrontals());
49 stats->separatorSizes.push_back(conditional->nrParents());
56 template<
class CLIQUE>
60 count += root->numCachedSeparatorMarginals();
65 template <
class CLIQUE>
69 throw std::invalid_argument(
70 "the root of Bayes tree has not been initialized!");
73 size_t key = root->conditional()->firstFrontalKey();
74 dot(os, root, keyFormatter, key);
81 template <
class CLIQUE>
84 dot(ss, keyFormatter);
89 template <
class CLIQUE>
92 std::ofstream of(filename.c_str());
93 dot(of, keyFormatter);
98 template <
class CLIQUE>
101 size_t parentnum)
const {
102 size_t num =
clique->conditional()->firstFrontalKey();
104 std::stringstream out;
106 std::string parent = out.str();
107 parent +=
"[label=\"";
109 for (
Key key :
clique->conditional_->frontals()) {
110 if (!first) parent +=
", ";
112 parent += keyFormatter(key);
117 s << parentnum <<
"->" << num <<
"\n";
121 for (
Key parentKey :
clique->conditional_->parents()) {
122 if (!first) parent +=
", ";
124 parent += keyFormatter(parentKey);
130 dot(s, c, keyFormatter, num);
135 template<
class CLIQUE>
144 template<
class CLIQUE>
146 for(
Key j:
clique->conditional()->frontals())
148 if (parent_clique !=
nullptr) {
149 clique->parent_ = parent_clique;
150 parent_clique->children.push_back(
clique);
158 template <
class FACTOR,
class CLIQUE>
159 struct _pushCliqueFunctor {
161 FactorGraph<FACTOR>* graph;
162 int operator()(
const std::shared_ptr<CLIQUE>& clique,
int dummy) {
163 graph->push_back(clique->conditional_);
170 template <
class CLIQUE>
175 _pushCliqueFunctor<FactorType, CLIQUE> functor(graph);
180 template<
class CLIQUE>
192 template<
class CLIQUE>
199 for (
auto&& root:
roots_) {
200 std::queue<sharedClique> bfs_queue;
203 bfs_queue.push(std::move(root));
208 while (!bfs_queue.empty()) {
210 auto current = std::move(bfs_queue.front());
214 for (
auto child: current->children) {
215 bfs_queue.push(std::move(child));
225 template<
typename NODE>
226 std::shared_ptr<NODE>
227 BayesTreeCloneForestVisitorPre(
const std::shared_ptr<NODE>& node,
const std::shared_ptr<NODE>& parentPointer)
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);
239 template<
class CLIQUE>
242 std::shared_ptr<Clique> rootContainer = std::make_shared<Clique>();
244 for(
const sharedClique& root: rootContainer->children) {
245 root->parent_ =
typename Clique::weak_ptr();
252 template<
class CLIQUE>
254 std::cout << s <<
": cliques: " <<
size() <<
", variables: " <<
nodes_.size() << std::endl;
260 template<
class CLIQUE>
261 bool check_sharedCliques(
265 return v1.first == v2.first &&
266 ((!v1.second && !v2.second) || (v1.second && v2.second && v1.second->equals(*v2.second)));
270 template<
class CLIQUE>
282 for (
const auto& kv :
nodes_) {
283 const Key key = kv.first;
286 auto it = other.
nodes_.find(key);
287 if (it == other.
nodes_.end())
292 if (!
clique && !otherClique)
294 if (!
clique || !otherClique)
296 if (!
clique->equals(*otherClique, tol))
304 template<
class CLIQUE>
305 template<
class CONTAINER>
307 typename CONTAINER::const_iterator lowestOrderedParent = min_element(parents.begin(), parents.end());
308 assert(lowestOrderedParent != parents.end());
309 return *lowestOrderedParent;
313 template<
class CLIQUE>
316 for(
const Key& j: subtree->conditional()->frontals()) {
317 bool inserted =
nodes_.insert({j, subtree}).second;
318 assert(inserted); (void)inserted;
327 template<
class CLIQUE>
329 roots_.push_back(subtree);
336 template<
class CLIQUE>
337 typename BayesTree<CLIQUE>::sharedConditional
340 gttic(BayesTree_marginalFactor);
346 FactorGraphType cliqueMarginal =
clique->marginal2(function);
349 BayesNetType marginalBN =
350 *cliqueMarginal.marginalMultifrontalBayesNet(
Ordering{j}, function);
353 return marginalBN.front();
359 template<
class CLIQUE>
360 typename BayesTree<CLIQUE>::sharedFactorGraph
363 gttic(BayesTree_joint);
364 return std::make_shared<FactorGraphType>(*
jointBayesNet(j1, j2, function));
368 template <
class CLIQUE>
370 const KeyVector& keys,
const Eliminate& function)
const {
371 gttic(BayesTree_joint);
372 return std::make_shared<FactorGraphType>(*
jointBayesNet(keys, function));
378 template <
class CLIQUE>
379 static std::shared_ptr<CLIQUE> findLowestCommonAncestor(
380 const std::shared_ptr<CLIQUE>& C1,
const std::shared_ptr<CLIQUE>& C2) {
382 std::unordered_set<std::shared_ptr<CLIQUE>> ancestors;
383 for (
auto p = C1; p; p = p->parent()) {
388 std::shared_ptr<CLIQUE> B;
389 for (
auto p = C2; p; p = p->parent()) {
390 if (ancestors.count(p)) {
399 template <
class CLIQUE>
400 static std::shared_ptr<CLIQUE> findLowestCommonAncestor(
401 const std::vector<std::shared_ptr<CLIQUE>>& cliques) {
402 if (cliques.empty()) {
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]);
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);
423 auto p_S_B = p_F_S->shortcut(B, eliminate);
426 KeyVector S_setminus_B = p_F_S->separator_setminus_B(B);
429 auto [bayesTree, fg] =
430 typename CLIQUE::FactorGraphType(p_S_B).eliminatePartialMultifrontal(
437 template <
class CLIQUE>
440 unique.reserve(keys.size());
442 for (
Key key : keys) {
443 if (seen.insert(key).second) {
444 unique.push_back(key);
451 template <
class CLIQUE>
452 static std::vector<std::shared_ptr<CLIQUE>> uniqueCliquesFromKeys(
454 std::vector<std::shared_ptr<CLIQUE>> queryCliques;
455 queryCliques.reserve(keys.size());
456 std::unordered_set<std::shared_ptr<CLIQUE>> seen;
458 for (
Key key : keys) {
459 auto clique = tree.clique(key);
460 if (seen.insert(clique).second) {
461 queryCliques.push_back(clique);
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();
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;
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);
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;
509 for (
const auto& clique : support) {
510 if (clique == root) {
513 auto parent = clique->parent();
514 if (parent && support.count(parent)) {
515 ++supportChildren[parent];
518 return supportChildren;
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;
530 essential.insert(root);
533 std::unordered_set<std::shared_ptr<CLIQUE>> querySet(queryCliques.begin(),
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);
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)) {
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)) {
580 descendToNextEssentialClique(child, support, essential);
581 if (!nextEssential) {
585 factorGraph->push_back(*factorInto(nextEssential, ancestor, eliminate));
586 factorGraph->push_back(nextEssential->conditional());
587 appendCompressedSupport(nextEssential, support, essential, factorGraph,
593 template <
class CLIQUE>
595 Key j1,
Key j2,
const Eliminate& eliminate)
const {
596 gttic(BayesTree_jointBayesNet);
601 auto B = findLowestCommonAncestor(C1, C2);
604 FactorGraphType p_BC1C2;
608 FactorGraphType p_B = B->marginal2(eliminate);
611 auto p_C1_B = factorInto(C1, B, eliminate);
612 auto p_C2_B = factorInto(C2, B, eliminate);
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());
622 p_BC1C2.push_back(C1->marginal2(eliminate));
623 p_BC1C2.push_back(C2->marginal2(eliminate));
627 return p_BC1C2.marginalMultifrontalBayesNet(
Ordering{j1, j2}, eliminate);
631 template <
class CLIQUE>
633 const KeyVector& keys,
const Eliminate& eliminate)
const {
634 gttic(BayesTree_jointBayesNet);
636 const KeyVector queryKeys = uniqueKeys<CLIQUE>(keys);
637 if (queryKeys.empty()) {
638 return std::make_shared<BayesNetType>();
640 if (queryKeys.size() == 1) {
641 auto bayesNet = std::make_shared<BayesNetType>();
642 bayesNet->push_back(
marginalFactor(queryKeys.front(), eliminate));
645 if (queryKeys.size() == 2) {
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);
654 if (keysByRoot.size() > 1) {
655 FactorGraphType disjointJoint;
656 for (
const auto& [rootClique, groupKeys] : keysByRoot) {
658 disjointJoint.push_back(*
jointBayesNet(groupKeys, eliminate));
660 return disjointJoint.marginalMultifrontalBayesNet(
Ordering(queryKeys),
664 const auto root = findLowestCommonAncestor(queryCliques);
666 return std::make_shared<BayesNetType>();
669 const auto support = collectSupportCliques(queryCliques, root);
670 const auto supportChildren = countSupportChildren(support, root);
671 const auto essential =
672 collectEssentialCliques(queryCliques, support, supportChildren, root);
674 FactorGraphType reducedJoint;
675 reducedJoint.push_back(root->marginal2(eliminate));
676 appendCompressedSupport(root, support, essential, &reducedJoint, eliminate);
678 return reducedJoint.marginalMultifrontalBayesNet(
Ordering(queryKeys),
683 template<
class CLIQUE>
691 template<
class CLIQUE>
694 root->deleteCachedShortcuts();
699 template<
class CLIQUE>
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);
715 child->parent_ =
typename Clique::weak_ptr();
717 for(
Key j:
clique->conditional()->frontals()) {
723 template <
class CLIQUE>
740 orphans->insert(orphans->begin(),
clique->children.begin(),
744 bn->push_back(
clique->conditional_);
750 template <
class CLIQUE>
755 for (
const Key& j : keys) {
758 typename Nodes::const_iterator node =
nodes_.find(j);
759 if (node !=
nodes_.end()) {
767 for (
sharedClique& orphan : *orphans) orphan->deleteCachedShortcuts();
771 template<
class CLIQUE>
777 cliques.push_back(subtree);
780 if(!subtree->isRoot())
781 subtree->parent()->children.erase(std::find(
782 subtree->parent()->children.begin(), subtree->parent()->children.end(), subtree));
787 for(
typename Cliques::iterator
clique = cliques.begin();
clique != cliques.end(); ++
clique)
791 cliques.push_back(child); }
794 (*clique)->deleteCachedShortcutsNonRecursive();
797 for(
Key j: (*clique)->conditional()->frontals()) {
801 (*clique)->parent_.reset();
802 (*clique)->children.clear();
809 template <
class CLIQUE>
815 traversedKeys.insert(
clique->conditional()->frontals().begin(),
816 clique->conditional()->frontals().end());
823 template <
class CLIQUE>
826 gtsam::KeySet traversedKeys;
829 typename Nodes::const_iterator node =
nodes_.find(j);
830 if (node !=
nodes_.end()) {
835 return traversedKeys;
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