/** * @file BayesTree * @brief Bayes Tree is a tree of cliques of a Bayes Chain * @author Frank Dellaert */ // \callgraph #pragma once #include #include //#include //#include #include #include #include #include #include #include namespace gtsam { /** * Bayes tree * Templated on the Conditional class, the type of node in the underlying Bayes chain. * This could be a ConditionalProbabilityTable, a GaussianConditional, or a SymbolicConditional */ template class BayesTree: public Testable > { public: typedef boost::shared_ptr sharedConditional; typedef boost::shared_ptr > sharedBayesNet; /** A Clique in the tree is an incomplete Bayes net: the variables * in the Bayes net are the frontal nodes, and the variables conditioned * on is the separator. We also have pointers up and down the tree. */ struct Clique: public BayesNet { typedef typename boost::shared_ptr shared_ptr; typedef typename boost::weak_ptr weak_ptr; weak_ptr parent_; std::list children_; std::list separator_; /** separator keys */ typename Conditional::FactorType::shared_ptr cachedFactor_; friend class BayesTree; //* Constructor */ Clique(); Clique(const sharedConditional& conditional); Clique(const BayesNet& bayesNet); /** return keys in frontal:separator order */ std::vector keys() const; /** print this node */ void print(const std::string& s = "") const; /** The size *includes* the separator */ size_t size() const { return this->conditionals_.size() + separator_.size(); } /** is this the root of a Bayes tree ? */ inline bool isRoot() const { return parent_.expired();} /** return the const reference of children */ std::list& children() { return children_; } const std::list& children() const { return children_; } /** Reference the cached factor */ typename Conditional::FactorType::shared_ptr& cachedFactor() { return cachedFactor_; } /** The size of subtree rooted at this clique, i.e., nr of Cliques */ size_t treeSize() const; /** print this node and entire subtree below it */ void printTree(const std::string& indent="") const; /** Permute the variables in the whole subtree rooted at this clique */ void permuteWithInverse(const Permutation& inversePermutation); /** Permute variables when they only appear in the separators. In this * case the running intersection property will be used to prevent always * traversing the whole tree. Returns whether any separator variables in * this subtree were reordered. */ bool permuteSeparatorWithInverse(const Permutation& inversePermutation); /** return the conditional P(S|Root) on the separator given the root */ // TODO: create a cached version template BayesNet shortcut(shared_ptr root); /** return the marginal P(C) of the clique */ template FactorGraph marginal(shared_ptr root); // /** return the joint P(C1,C2), where C1==this. TODO: not a method? */ // template // std::pair,Ordering> joint(shared_ptr C2, shared_ptr root); }; // typedef for shared pointers to cliques typedef boost::shared_ptr sharedClique; // A convenience class for a list of shared cliques struct Cliques : public std::list, public Testable { void print(const std::string& s = "Cliques") const; bool equals(const Cliques& other, double tol = 1e-9) const; }; /** clique statistics */ struct CliqueStats { double avgConditionalSize; std::size_t maxConditionalSize; double avgSeparatorSize; std::size_t maxSeparatorSize; }; /** store all the sizes */ struct CliqueData { std::vector conditionalSizes; std::vector separatorSizes; CliqueStats getStats() const; }; protected: /** Map from keys to Clique */ typedef std::deque Nodes; Nodes nodes_; /** private helper method for saving the Tree to a text file in GraphViz format */ void saveGraph(std::ostream &s, sharedClique clique, int parentnum = 0) const; /** Gather data on a single clique */ void getCliqueData(CliqueData& stats, sharedClique clique) const; protected: /** Root clique */ sharedClique root_; /** remove a clique: warning, can result in a forest */ void removeClique(sharedClique clique); /** add a clique (top down) */ sharedClique addClique(const sharedConditional& conditional, sharedClique parent_clique = sharedClique()); /** add a clique (bottom up) */ sharedClique addClique(const sharedConditional& conditional, std::list& child_cliques); /** Add a conditional to the front of a clique, i.e. a conditional whose * parents are already in the clique or its separators. This function does * not check for this condition, it just updates the data structures. */ void addToCliqueFront(const sharedConditional& conditional, const sharedClique& clique); /** Fill the nodes index for a subtree */ void fillNodesIndex(const sharedClique& subtree); public: /** Create an empty Bayes Tree */ BayesTree(); /** Create a Bayes Tree from a Bayes Net */ BayesTree(const BayesNet& bayesNet); /** * Create a Bayes Tree from a Bayes Net and some subtrees. The Bayes net corresponds to the * new root clique and the subtrees are connected to the root clique. */ BayesTree(const BayesNet& bayesNet, std::list > subtrees); /** Destructor */ virtual ~BayesTree() { } /** * Constructing Bayes trees */ /** Insert a new conditional */ void insert(const sharedConditional& conditional); /** Insert a new clique corresponding to the given Bayes net. * It is the caller's responsibility to decide whether the given Bayes net is a valid clique, * i.e. all the variables (frontal and separator) are connected */ sharedClique insert(const BayesNet& bayesNet, std::list& children, bool isRootClique = false); /** * Hang a new subtree off of the existing tree. This finds the appropriate * parent clique for the subtree (which may be the root), and updates the * nodes index with the new cliques in the subtree. None of the frontal * variables in the subtree may appear in the separators of the existing * BayesTree. */ void insert(const sharedClique& subtree); /** * Querying Bayes trees */ /** check equality */ bool equals(const BayesTree& other, double tol = 1e-9) const; /** * Find parent clique of a conditional. It will look at all parents and * return the one with the lowest index in the ordering. */ template Index findParentClique(const Container& parents) const; /** number of cliques */ inline size_t size() const { if(root_) return root_->treeSize(); else return 0; } /** return root clique */ const sharedClique& root() const { return root_; } sharedClique& root() { return root_; } /** find the clique to which key belongs */ sharedClique operator[](Index key) const { return nodes_.at(key); } /** Gather data on all cliques */ CliqueData getCliqueData() const; /** return marginal on any variable */ template FactorGraph marginal(Index key) const; /** return marginal on any variable, as a Bayes Net */ template BayesNet marginalBayesNet(Index key) const; // /** return joint on two variables */ // template // FactorGraph joint(Index key1, Index key2) const; // // /** return joint on two variables as a BayesNet */ // template // BayesNet jointBayesNet(Index key1, Index key2) const; /** * Read only with side effects */ /** print */ void print(const std::string& s = "") const; /** saves the Tree to a text file in GraphViz format */ void saveGraph(const std::string& s) const; /** * Altering Bayes trees */ /** Remove all nodes */ void clear(); /** * Remove path from clique to root and return that path as factors * plus a list of orphaned subtree roots. Used in removeTop below. */ void removePath(sharedClique clique, BayesNet& bn, Cliques& orphans); /** * Given a list of keys, turn "contaminated" part of the tree back into a factor graph. * Factors and orphans are added to the in/out arguments. */ template void removeTop(const Container& keys, BayesNet& bn, Cliques& orphans); }; // BayesTree } /// namespace gtsam