aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
graphElements.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 some utils for topology : NodeId, Edge, Arc and consorts ...
24  *
25  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
26  *
27  * This file provides two classes, namely Edge and Arc
28  * which represent respectively undirected and directed edges. The
29  * "directed/undirected" term may be misleading although in practice this
30  * will probably result in how these edges will be drawn. In fact, a more
31  * appropriate term would be "symmetric/asymmetric edges": an Arc is an edge in
32  * which the extremities have different status whereas in an Edge the role of
33  *the
34  * extremities is symmetric. For instance, in an arrow, one node is near the
35  *head
36  * and the other one is farther, hence these nodes have different status and
37  * swapping the nodes results in reversing the direction of the arrow. Thus, the
38  * nodes in an arrow can be thought of as asymmetric and the arrow's graphical
39  * representation contains a pointed extremity so as to account for this
40  *asymmetry.
41  * Conversely, in a Markov Random Field, an edge between two nodes, x and y,
42  * means that x and y are probabilistically dependent of one another. This being
43  *a
44  * symmetrical relation, there is no difference between edge (x,y) and edge
45  *(y,x).
46  * Thus, it can be represented by an Edge and, graphically, by an undirected
47  *edge.
48  *
49  * @par Usage example:
50  * @code
51  * // creation of an edge between nodes whose IDs are 3 and 4
52  * Edge edge1 (3,4);
53  *
54  *
55  * // copy the edge into another edge
56  * Edge edge2 (edge1), edge3 = edge4;
57  *
58  * // compare two edges
59  * if (Edge(3,4) == Edge(4,3)) cerr << "ok, this is symmetric" << endl;
60  * if (Edge(3,4) != Edge(5,4)) cerr << "different edges" << endl;
61  *
62  * // get the extremities of the edge
63  * cerr << edge1.first() << " = 3 and " << edge1.second() << " = 4\n";
64  * cerr << "edge1 = (3," << edge1.other (3) << ")" << endl;
65  *
66  * // display the edge in a console
67  * cerr << edge1 << endl;
68  *
69  * // creation of an arc (directed edge) from 3 to 4
70  * Arc arc1 (3,4);
71  * *
72  * // compare two arcs
73  * if (Arc(3,4) != Arc(4,3)) cerr << "ok, this is asymmetric" << endl;
74  *
75  * // get the extremities of the edge
76  * cerr << arc1.tail() << " = 3 and " << arc1.head() << " = 4\n";
77  * cerr << "arc1 = (3 -> " << edge1.other (3) << ")" << endl;
78  *
79  * // display an arc in a console
80  * cerr << arc1 << endl;
81  * @endcode
82  */
83 #ifndef GUM_GRAPH_ELEMENTS_H
84 #define GUM_GRAPH_ELEMENTS_H
85 
86 #include <iostream>
87 
88 #include <agrum/agrum.h>
89 
90 #include <agrum/tools/core/set.h>
91 
92 namespace gum {
93 
94  /** \ingroup graph_group
95  * Type for node ids
96  */
97  typedef Size NodeId;
98 
99  /* ===========================================================================
100  */
101  /* ===========================================================================
102  */
103  /* === GENERIC UNDIRECTED EDGES ===
104  */
105  /* ===========================================================================
106  */
107  /* ===========================================================================
108  */
109  /** @class Edge
110  * @brief The base class for all undirected edges.
111  * \ingroup graph_group
112  *
113  * This class is used as a basis for manipulating any undirected edge in any
114  * graph. By undirected edge, we mean a symmetric edge, i.e., an edge in which
115  * the order of the nodes is unimportant. For instance, in Markov Random
116  * fields, an edge between two nodes, x and y, means that x and y are
117  * probabilistically dependent of one another. This being a symmetrical
118  *relation,
119  * there is no difference between edge (x,y) and edge (y,x). Thus, it can be
120  * represented by an undirected edge and, in aGrUM, by an Edge.
121  * @par Usage example:
122  * @code
123  * // creation of an edge between nodes whose IDs are 3 and 4
124  * Edge edge1 (3,4);
125  * *
126  * // copy the edge into another edge
127  * Edge edge2 (edge1), edge3 = edge4;
128  *
129  * // compare two edges
130  * if (Edge(3,4) == Edge(4,3)) cerr << "ok, this is symmetric" << endl;
131  * if (Edge(3,4) != Edge(5,4)) cerr << "different edges" << endl;
132  *
133  * // get the extremities of the edge
134  * cerr << edge1.first() << " = 3 and " << edge1.second() << " = 4\n";
135  * cerr << "edge1 = (3," << edge1.other (3) << ")" << endl;
136  *
137  * // display the edge in a console
138  * cerr << edge1 << endl;
139  * @endcode
140  */
141  /* ===========================================================================
142  */
143 
144  class Edge {
145  public:
146  // ############################################################################
147  /// @name Constructors / Destructors
148  // ############################################################################
149  /// @{
150 
151  /// constructs a new edge (aN1,aN2)
152  /** @param aN1 the ID of the first extremal node
153  * @param aN2 the ID of the second extremal node */
154  Edge(NodeId aN1, NodeId aN2);
155 
156  /// copy constructor
157  Edge(const Edge& src);
158 
159  /// destructor
160  ~Edge();
161 
162  ///@}
163 
164  // ############################################################################
165  /// @name Accessors
166  // ############################################################################
167  /// @{
168 
169  /// returns an extremal node of an edge given the ID of the other one
170  NodeId other(NodeId id) const;
171 
172  /// returns one extremal node ID (whichever one it is is unspecified)
173  NodeId first() const;
174 
175  /// returns the node ID of the other extremal node ID
176  NodeId second() const;
177 
178  ///@}
179 
180  // ############################################################################
181  /// @name Operators
182  // ############################################################################
183  /// @{
184 
185  /// copy operator
186  Edge& operator=(const Edge& src);
187 
188  /// checks whether two undirected edges are equal
189  /** Two Edge are equal if they have the same extremal nodes, whetever their
190  * order. For instance (3,4) == (4,3). */
191  bool operator==(const Edge& src) const;
192 
193  /// checks whether two undirected edges are different
194  /** Two Edge are different if at least one extremal node of an edge is not
195  * an extremal node of the other edge. For instance, (4,5) != (5,6). */
196  bool operator!=(const Edge& src) const;
197 
198  /// @}
199 
200  private:
201  /// the extremal nodes of the edge (their order is unimportant)
202  NodeId n1, n2;
203  };
204 
205  /* ===========================================================================
206  */
207  /* ===========================================================================
208  */
209  /* === GENERIC DIRECTED EDGES ===
210  */
211  /* ===========================================================================
212  */
213  /* ===========================================================================
214  */
215  /** @class Arc
216  * @brief The base class for all directed edges
217  * \ingroup graph_group
218  *
219  * This class is used as a basis for manipulating all directed edges (i.e.,
220  *edges
221  * in which the order of the nodes is meaningful). For instance, in an arrow,
222  *one
223  * node is near the head and the other one is farther, hence these nodes have
224  * different status and swapping the nodes results in reversing the direction
225  *of
226  * the arrow. Thus, the nodes in an arrow can be thought of as asymmetric and
227  *the
228  * arrow's graphical representation contains a pointed extremity so as to
229  *account
230  * for this asymmetry. In aGrUM, the latter is taken into account by Arc.
231  * @par Usage example:
232  * @code
233  * // creation of an arc (directed edge) from 3 to 4
234  * Arc arc1 (3,4);
235  * *
236  * // compare two arcs
237  * if (Arc(3,4) != Arc(4,3)) cerr << "ok, this is asymmetric" << endl;
238  *
239  * // get the extremities of the edge
240  * cerr << arc1.tail() << " = 3 and " << arc1.head() << " = 4\n";
241  * cerr << "arc1 = (3 -> " << edge1.other (3) << ")" << endl;
242  *
243  * // display an arc in a console
244  * cerr << arc1 << endl;
245  * @endcode
246  */
247  /* ===========================================================================
248  */
249 
250  class Arc {
251  public:
252  // ############################################################################
253  /// @name Constructors / Destructors
254  // ############################################################################
255  /// @{
256 
257  /// basic constructor. Creates tail -> head.
258  /** @warning the order in which the nodes are passed is important */
259  Arc(NodeId tail, NodeId head);
260 
261  /// copy constructor
262  Arc(const Arc& src);
263 
264  /// destructor
265  ~Arc();
266 
267  /// @}
268 
269  // ############################################################################
270  /// @name Accessors
271  // ############################################################################
272  /// @{
273 
274  /// returns the tail of the arc
275  NodeId tail() const;
276 
277  /// returns the head of the arc
278  NodeId head() const;
279 
280  /// returns an extremal node of an edge given the ID of the other one
281  NodeId other(NodeId id) const;
282 
283  /// returns one extremal node ID (whichever one it is is unspecified)
284  NodeId first() const;
285 
286  /// returns the node ID of the other extremal node ID
287  NodeId second() const;
288 
289  /// @}
290 
291  // ############################################################################
292  /// @name Operators
293  // ############################################################################
294  /// @{
295 
296  /// copy operator
297  Arc& operator=(const Arc& src);
298 
299  /// checks whether two arcs are equal
300  /** Two arcs are considered equal if they have the same head and tail
301  * (by same we mean they have the same ID). */
302  bool operator==(const Arc& src) const;
303 
304  /// check if two arcs are different
305  /** Two arcs are considered different if they have different head and/or
306  * tail
307  * (by different we mean they have different ID). */
308  bool operator!=(const Arc& src) const;
309 
310  /// @}
311 
312  private:
313  /// the extremal nodes of the edge (their order is unimportant)
314  NodeId n1, n2;
315 
316  /// modifies the tail of the arc
317  void _setTail_(NodeId id);
318 
319  /// modifies the head of the arc
320  void _setHead_(NodeId id);
321 
322  /// reverses the direction of the arc
323  void operator-();
324  };
325 
326  ////////////////////////////////////////////////////////////////
327  // we need to provide hash functions for some Edge and Arc
328 
329 #ifndef DOXYGEN_SHOULD_SKIP_THIS
330 
331  template <>
332  class HashFunc< Edge >: public HashFuncBase< Edge > {
333  public:
334  /**
335  * @brief Returns the value of a key as a Size.
336  * @param key The value to return as a Size.
337  * @return Returns the value of a key as a Size.
338  */
339  static Size castToSize(const Edge& key);
340 
341  /**
342  * @brief Computes the hashed value of a key.
343  * @param key The key to compute the hashed value.
344  * @return Returns the hashed value of a key.
345  */
346  virtual Size operator()(const Edge& key) const override final;
347  };
348 
349 
350  template <>
351  class HashFunc< Arc >: public HashFuncBase< Arc > {
352  public:
353  /**
354  * @brief Returns the value of a key as a Size.
355  * @param key The value to return as a Size.
356  * @return Returns the value of a key as a Size.
357  */
358  static Size castToSize(const Arc& key);
359 
360  /**
361  * @brief Computes the hashed value of a key.
362  * @param key The key to compute the hashed value.
363  * @return Returns the hashed value of a key.
364  */
365  virtual Size operator()(const Arc& key) const override final;
366  };
367 
368 #endif // DOXYGEN_SHOULD_SKIP_THIS
369 
370  /** \ingroup graph_group
371  * @{
372  * Some typdefs and define for shortcuts ...
373  */
374  typedef Set< NodeId > NodeSet;
375  typedef Set< Edge > EdgeSet;
376  typedef Set< Arc > ArcSet;
377 
378  typedef ArcSet::const_iterator ArcSetIterator;
379  typedef EdgeSet::const_iterator EdgeSetIterator;
380  typedef NodeSet::const_iterator NodeSetIterator;
381  /** @} */
382 
383  /** \ingroup graph_group
384  * @{
385  * @brief Property on graph elements
386  **/
387  template < class VAL >
388  using NodeProperty = HashTable< NodeId, VAL >;
389  template < class VAL >
390  using EdgeProperty = HashTable< Edge, VAL >;
391  template < class VAL >
392  using ArcProperty = HashTable< Arc, VAL >;
393 
394  /// @}
395 
396  /// to friendly display an edge
397  std::ostream& operator<<(std::ostream& stream, const Edge& edge);
398 
399  /// to friendly display an arc
400  std::ostream& operator<<(std::ostream& stream, const Arc& arc);
401 
402 } /* namespace gum */
403 
404 #ifndef GUM_NO_EXTERN_TEMPLATE_CLASS
405 extern template class gum::HashFunc< gum::NodeSet >;
406 #endif
407 
408 #ifndef GUM_NO_INLINE
409 # include <agrum/tools/graphs/graphElements_inl.h>
410 #endif /* GUM_NO_INLINE */
411 
412 #endif // GUM_GRAPHELEMENTS_H