aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
cliqueGraph.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief Basic class for all graphs of cliques (join trees, etc)
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 #ifndef GUM_CLIQUE_GRAPH_H
28 #define GUM_CLIQUE_GRAPH_H
29 
30 #include <iostream>
31 
32 #include <agrum/agrum.h>
33 
34 #include <agrum/tools/graphs/undiGraph.h>
35 
36 namespace gum {
37  /* ===========================================================================
38  */
39  /* === GRAPHS OF CLIQUES ===
40  */
41  /* ===========================================================================
42  */
43  /** @class CliqueGraph
44  * @brief Basic graph of cliques
45  *
46  * \ingroup graph_group
47  *
48  *
49  * A CliqueGraph is an undirected graph the nodes of which are Cliques, i.e.,
50  * sets of NodeIds. Cliques are linked by Edges. These edges contain
51  *separators
52  * that are actually the intersection of the two Cliques at the extermities of
53  * the edge. */
54  /* ===========================================================================
55  */
56 
57  class CliqueGraph: public UndiGraph {
58  public:
59  // ############################################################################
60  /// @name Constructors / Destructors
61  // ############################################################################
62  /// @{
63 
64  /// basic constructor: creates an empty clique graph
65  /** @param nodes_size the size of the hash table used to store all the nodes
66  * @param nodes_resize_policy the resizing policy of this hash table
67  * @param edges_size the size of the hash table used to store all the edges
68  * @param edges_resize_policy the resizing policy of this hash table */
69 
70  explicit CliqueGraph(Size nodes_size = HashTableConst::default_size,
71  bool nodes_resize_policy = true,
72  Size edges_size = HashTableConst::default_size,
73  bool edges_resize_policy = true);
74 
75  /// copy constructor
76  /** @param from the CliqueGraph that will be copied into \e this */
77 
78  CliqueGraph(const CliqueGraph& from);
79 
80  /// destructor
81 
82  virtual ~CliqueGraph();
83 
84  /// @}
85 
86  // ############################################################################
87  /// @name Accessors/Modifiers
88  // ############################################################################
89  /// @{
90 
91  /// inserts a new edge between two cliques
92  /**
93  * @param first the id of one extremity of the new edge to be inserted
94  * @param second the id of the other extremity of the new edge to be
95  * inserted
96  * @warning if the edge already exists, nothing is done. In particular, no
97  * exception is raised.
98  * @throw InvalidNode if first and/or second do not belong to the
99  * graph nodes */
100  virtual void addEdge(const NodeId first, const NodeId second);
101 
102  /// removes an edge (and its separator) from the clique graph
103  /** @param edge the edge to be removed
104  * @warning if the edge does not exist, nothing is done. In particular, no
105  * exception is thrown. */
106 
107  virtual void eraseEdge(const Edge& edge);
108 
109  /// removes all edges and their separators
110 
111  virtual void clearEdges();
112 
113  /// adds a new clique to the graph
114  /** @return the id chosen for the new clique */
115  NodeId addNode(const NodeSet& clique);
116 
117  /// adds a new clique to the graph
118  /** @return the id chosen for the new clique */
119  virtual NodeId addNode();
120 
121  /// try to add a new clique to the graph
122  /** @throws DuplicateElement exception is thrown if the id of the clique
123  * already exists within the clique graph */
124  virtual void addNode(const NodeId id, const NodeSet& clique);
125 
126  /// try to add a new clique to the graph
127  /** @throws DuplicateElement exception is thrown if the id of the clique
128  * already exists within the clique graph */
129  virtual void addNode(const NodeId id);
130 
131  /// removes a given clique from the clique graph
132  /** If the CliqueGraph does not contain the node, then nothing is done. In
133  * particular, no exception is raised. */
134 
135  virtual void eraseNode(const NodeId node);
136 
137  /** @brief removes all the cliques and separators from the graph (as well as
138  * their adjacent edges) */
139 
140  virtual void clear();
141 
142  /// returns the set of nodes included into a given clique
143  /** @throw NotFound exception is raised if the clique does not belong to
144  * the clique graph */
145 
146  const NodeSet& clique(const NodeId idClique) const;
147 
148  /** @brief returns the id of a clique containing the node the id of which is
149  * in argument
150  * @warning note that this method is time consuming as the clique graph does
151  * not contain a priori information about which clique could contain idNode.
152  * As a consequence, it searches the cliques until it finds one that
153  * actually
154  * contains idNode.
155  * @throws NotFound exception is thrown if no clique contains idNode */
156 
157  NodeId container(const NodeId idNode) const;
158 
159  /** @brief changes the set of nodes included into a given clique and returns
160  * the new set
161  * @throws NotFound exception is thrown if idClique is not a clique of
162  * the clique graph */
163 
164  virtual void setClique(const NodeId idClique, const NodeSet& new_clique);
165 
166  /** @brief changes the set of nodes included into a given clique and returns
167  * the new set
168  *
169  * @throws NotFound exception is thrown if clique_id does not exist
170  * @throw DuplicateElement exception is thrown if clique_id set already
171  * contains the node */
172 
173  virtual void addToClique(const NodeId clique_id, const NodeId node_id);
174 
175  /// remove a node from a clique
176  /** If node_id cannot be found in the clique set, then the function does
177  * nothing. In particular, it does not throw any exception.
178  * @throws NotFound exception is thrown if clique_id does not exist */
179 
180  virtual void eraseFromClique(const NodeId clique_id, const NodeId node_id);
181 
182  /// returns the separator included in a given edge
183  /** @throw NotFound exception is thrown if the edge does not belong to the
184  * clique graph */
185 
186  const NodeSet& separator(const Edge& edge) const;
187 
188  /// returns the separator included in an edge specified by its extremities
189  /** @throw NotFound exception is thrown if the edge does not belong to the
190  * clique graph */
191 
192  const NodeSet& separator(const NodeId clique1, const NodeId clique) const;
193 
194  /// returns a path from a clique containing node1 to a clique containing
195  /// node2
196  /** @throws NotFound such path cannot be found */
197 
198  std::vector< NodeId > containerPath(const NodeId node1,
199  const NodeId node2) const;
200 
201  /// indicates whether the running intersection property holds
202  /** The function works properly even if the graph contains cycles. */
203 
204  bool hasRunningIntersection() const;
205 
206  /// indicates whether the graph is a join tree
207 
208  bool isJoinTree() const;
209 
210  /// friendly displays the content of the CliqueGraph
211 
212  virtual std::string toString() const;
213 
214  /// friendly displays the content of the CliqueGraph in DOT format
215 
216  virtual std::string toDot() const;
217 
218  /// @}
219 
220  // ############################################################################
221  /// @name Operators
222  // ############################################################################
223  /// @{
224 
225  /// copy operator
226 
227  CliqueGraph& operator=(const CliqueGraph& from);
228 
229  /// checks whether two clique graphs are different
230 
231  bool operator!=(const CliqueGraph& from) const;
232 
233  /// checks whether two clique graphs are equal
234 
235  bool operator==(const CliqueGraph& from) const;
236 
237  /// @}
238 
239  private:
240  /// the set of nodes contained into the cliques
241  NodeProperty< NodeSet > cliques__;
242 
243  /// the set of nodes contained into the separators
244  EdgeProperty< NodeSet > separators__;
245 
246  /// function used to update the separators when a clique is modified
247 
248  void updateSeparators__(const NodeId clique1);
249 
250  /// structure used for the computation of the running intersection property
251 
252  struct RunningIntersect__ {
253  /** @brief structure indicating for each clique whether it has been
254  * examined by a DFS (Depth First Search) */
255  NodeSet visited_cliques;
256 
257  /// structure indicating the nodes that belong to other connected
258  /// components
259  /** These nodes must not be found in the current connected component if
260  * the
261  * running intersection holds */
262  NodeSet nodes_other_components;
263 
264  /// the nodes that are currently forbidden by separators in the DFS
265  NodeSet nodes_DFS_forbidden;
266 
267  /// set of the nodes examined during the current DFS
268  NodeSet nodes_DFS_seen;
269 
270  /** @brief for each clique, the list of its nodes that require accessing
271  *the
272  * clique through a chain
273  *
274  * At the beginning, all nodes in a clique require a chain to be accessed.
275  * In a DFS, when a chain reaches a clique, we remove from
276  * \c cliques_DFS_chain the nodes that are not forbidden by the DFS,
277  * i.e., the nodes that are reachable by the chain starting from the root
278  *of
279  * the DFS. These are the nodes that belong to the separators. Hence,
280  *after
281  * completing all the DFS, there remain in \c cliques_DFS_chain only the
282  * nodes that are accessible by no chain but that are found in several
283  *parts
284  * of the clique graph. In such a case, this is a violation of the running
285  * intersection property. Hence, for the latter to hold, after completion
286  *of
287  * all the DFS, \c cliques_DFS_chain must contain only empty sets. */
288  NodeProperty< NodeSet > cliques_DFS_chain;
289  };
290 
291  /// function used for the computation of the running intersection property
292 
293  bool runningIntersectionDFS__(const NodeId clique,
294  const NodeId from,
295  RunningIntersect__& infos_DFS) const;
296  };
297 
298  /** @brief a junction tree is a clique graph satisfying the running
299  * intersection
300  * property and such that no clique is included into another one. */
301  typedef CliqueGraph JunctionTree;
302 
303  /** @brief a join tree is a clique graph satisfying the running intersection
304  * property (but some cliques may be included into others) */
305  typedef CliqueGraph JoinTree;
306 
307  /// for friendly displaying the content of clique graphs
308 
309  std::ostream& operator<<(std::ostream&, const CliqueGraph&);
310 
311 } /* namespace gum */
312 
313 #ifndef GUM_NO_INLINE
314 # include <agrum/tools/graphs/cliqueGraph_inl.h>
315 #endif // GUM_NOINLINE
316 
317 #endif /* GUM_CLIQUE_GRAPH_H */