aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
cliqueGraph.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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, const NodeId node2) const;
199 
200  /// indicates whether the running intersection property holds
201  /** The function works properly even if the graph contains cycles. */
202 
203  bool hasRunningIntersection() const;
204 
205  /// indicates whether the graph is a join tree
206 
207  bool isJoinTree() const;
208 
209  /// friendly displays the content of the CliqueGraph
210 
211  virtual std::string toString() const;
212 
213  /// friendly displays the content of the CliqueGraph in DOT format
214 
215  virtual std::string toDot() const;
216 
217  /// @}
218 
219  // ############################################################################
220  /// @name Operators
221  // ############################################################################
222  /// @{
223 
224  /// copy operator
225 
226  CliqueGraph& operator=(const CliqueGraph& from);
227 
228  /// checks whether two clique graphs are different
229 
230  bool operator!=(const CliqueGraph& from) const;
231 
232  /// checks whether two clique graphs are equal
233 
234  bool operator==(const CliqueGraph& from) const;
235 
236  /// @}
237 
238  private:
239  /// the set of nodes contained into the cliques
240  NodeProperty< NodeSet > _cliques_;
241 
242  /// the set of nodes contained into the separators
243  EdgeProperty< NodeSet > _separators_;
244 
245  /// function used to update the separators when a clique is modified
246 
247  void _updateSeparators_(const NodeId clique1);
248 
249  /// structure used for the computation of the running intersection property
250 
251  struct _RunningIntersect_ {
252  /** @brief structure indicating for each clique whether it has been
253  * examined by a DFS (Depth First Search) */
254  NodeSet visited_cliques;
255 
256  /// structure indicating the nodes that belong to other connected
257  /// components
258  /** These nodes must not be found in the current connected component if
259  * the
260  * running intersection holds */
261  NodeSet nodes_other_components;
262 
263  /// the nodes that are currently forbidden by separators in the DFS
264  NodeSet nodes_DFS_forbidden;
265 
266  /// set of the nodes examined during the current DFS
267  NodeSet nodes_DFS_seen;
268 
269  /** @brief for each clique, the list of its nodes that require accessing
270  *the
271  * clique through a chain
272  *
273  * At the beginning, all nodes in a clique require a chain to be accessed.
274  * In a DFS, when a chain reaches a clique, we remove from
275  * \c cliques_DFS_chain the nodes that are not forbidden by the DFS,
276  * i.e., the nodes that are reachable by the chain starting from the root
277  *of
278  * the DFS. These are the nodes that belong to the separators. Hence,
279  *after
280  * completing all the DFS, there remain in \c cliques_DFS_chain only the
281  * nodes that are accessible by no chain but that are found in several
282  *parts
283  * of the clique graph. In such a case, this is a violation of the running
284  * intersection property. Hence, for the latter to hold, after completion
285  *of
286  * all the DFS, \c cliques_DFS_chain must contain only empty sets. */
287  NodeProperty< NodeSet > cliques_DFS_chain;
288  };
289 
290  /// function used for the computation of the running intersection property
291 
292  bool _runningIntersectionDFS_(const NodeId clique,
293  const NodeId from,
294  _RunningIntersect_& infos_DFS) const;
295  };
296 
297  /** @brief a junction tree is a clique graph satisfying the running
298  * intersection
299  * property and such that no clique is included into another one. */
300  typedef CliqueGraph JunctionTree;
301 
302  /** @brief a join tree is a clique graph satisfying the running intersection
303  * property (but some cliques may be included into others) */
304  typedef CliqueGraph JoinTree;
305 
306  /// for friendly displaying the content of clique graphs
307 
308  std::ostream& operator<<(std::ostream&, const CliqueGraph&);
309 
310 } /* namespace gum */
311 
312 #ifndef GUM_NO_INLINE
313 # include <agrum/tools/graphs/cliqueGraph_inl.h>
314 #endif // GUM_NOINLINE
315 
316 #endif /* GUM_CLIQUE_GRAPH_H */