1 /* This file is part of libDAI - http://www.libdai.org/
2 *
4 * 2, or (at your option) any later version. libDAI is distributed without any
5 * warranty. See the file COPYING for more details.
6 *
7 * Copyright (C) 2006-2010 Joris Mooij [joris dot mooij at libdai dot org]
9 */
12 /// \file
13 /// \brief Defines the GraphAL class, which represents an undirected graph as an adjacency list
16 #ifndef __defined_libdai_graph_h
17 #define __defined_libdai_graph_h
20 #include <ostream>
21 #include <vector>
22 #include <algorithm>
23 #include <dai/util.h>
24 #include <dai/exceptions.h>
25 #include <dai/smallset.h>
28 namespace dai {
31 /// Describes the neighbor relationship of two nodes in a graph.
32 /** Most graphs that libDAI deals with are sparse. Therefore,
33 * a fast and memory-efficient way of representing the structure
34 * of a sparse graph is needed. A frequently used operation that
35 * also needs to be fast is switching between viewing node \a a as a
36 * neighbor of node \a b, and node \a b as a neighbor of node \a a.
37 * The Neighbor struct solves both of these problems.
38 *
39 * Most sparse graphs in libDAI are represented by storing for each
40 * node in the graph the set of its neighbors. In practice, this set
41 * of neighbors is stored using the Neighbors type, which is simply a
43 * the label of the neighboring node (the \c node member) and
44 * additional information which allows to access a node as a neighbor
45 * of its neighbor (the \c dual member). For convenience, each Neighbor
46 * structure also stores its index in the Neighbors vector that it is
47 * part of (the \c iter member).
48 *
49 * By convention, variable identifiers naming indices into a vector
50 * of neighbors are prefixed with an underscore ("_"). The neighbor list
51 * which they point into is then understood from the context.
52 *
53 * Let us denote the \a _j 'th neighbor of node \a i by <tt>nb(i,_j)</tt>,
54 * which is of the Neighbor type. Here, \a i is the "absolute" index of
55 * node \a i, but \a _j is understood as a "relative" index, giving node
56 * \a j 's entry in the Neighbors <tt>nb(i)</tt> of node \a i. The absolute
57 * index of \a _j, which would be denoted \a j, can be recovered from the
58 * \c node member, <tt>nb(i,_j).node</tt>. The \c iter member
59 * <tt>nb(i,_j).iter</tt> gives the relative index \a _j, and the \c dual
60 * member <tt>nb(i,_j).dual</tt> gives the "dual" relative index, i.e.,
61 * the index of \a i in \a j 's neighbor list.
62 *
63 * Iteration over edges can be easily accomplished:
64 * \code
65 * for( size_t i = 0; i < nrNodes(); ++i ) {
66 * size_t _j = 0;
67 * foreach( const Neighbor &j, nb(i) ) {
68 * assert( j == nb(i,j.iter) );
69 * assert( nb(j.node,j.dual).node == i );
70 * assert( _j = j.iter );
71 * _j++;
72 * }
73 * }
74 * \endcode
75 */
76 struct Neighbor {
77 /// Corresponds to the index of this Neighbor entry in the vector of neighbors
78 size_t iter;
79 /// Contains the absolute index of the neighboring node
80 size_t node;
81 /// Contains the "dual" index (i.e., the index of this node in the Neighbors vector of the neighboring node)
82 size_t dual;
84 /// Default constructor
85 Neighbor() {}
86 /// Constructor that allows setting the values of the member variables
87 Neighbor( size_t iter, size_t node, size_t dual ) : iter(iter), node(node), dual(dual) {}
89 /// Cast to \c size_t returns \c node member
90 operator size_t () const { return node; }
91 };
94 /// Describes the set of neighbors of some node in a graph
95 typedef std::vector<Neighbor> Neighbors;
98 /// Represents an edge in a graph: an Edge(\a i,\a j) corresponds to the edge between node \a i and node \a j.
99 /** \note If the edge is interpreted as a directed edge, then it points from \a i to \a j.
100 * \note If the edge is part of a bipartite graph, \a i is understood to correspond to a node of type 1, and
101 * \a j to a node of type 2.
102 */
103 typedef std::pair<size_t,size_t> Edge;
106 /// Represents the neighborhood structure of nodes in an undirected graph.
107 /** A graph has nodes connected by edges. Nodes are indexed by an unsigned integer.
108 * If there are nrNodes() nodes, they are numbered 0,1,2,...,nrNodes()-1. An edge
109 * between node \a n1 and node \a n2 is represented by a Edge(\a n1,\a n2).
110 *
111 * GraphAL is implemented as a sparse adjacency list, i.e., it stores for each node a list of
112 * its neighboring nodes. The list of neighboring nodes is implemented as a vector of Neighbor
113 * structures (accessible by the nb() method). Thus, each node has an associated variable of
114 * type GraphAL::Neighbors, which is a vector of Neighbor structures, describing its
115 * neighboring nodes.
116 */
117 class GraphAL {
118 public:
119 /// Describes the neighbor relationship of two nodes in a GraphAL.
121 */
122 typedef dai::Neighbor Neighbor;
124 /// Describes the neighbors of some node.
126 */
127 typedef dai::Neighbors Neighbors;
129 /// Represents an edge: an Edge(\a n1,\a n2) corresponds to the edge between node \a n1 and node \a n2.
131 */
132 typedef dai::Edge Edge;
134 private:
135 /// Contains for each node a vector of its neighbors
136 std::vector<Neighbors> _nb;
138 public:
139 /// \name Constructors and destructors
140 //@{
141 /// Default constructor (creates an empty graph).
142 GraphAL() : _nb() {}
144 /// Constructs GraphAL with \a nr nodes and no edges.
145 GraphAL( size_t nr ) : _nb( nr ) {}
147 /// Constructs GraphAL from a range of edges.
148 /** \tparam EdgeInputIterator Iterator that iterates over instances of Edge.
149 * \param nr The number of nodes.
150 * \param begin Points to the first edge.
151 * \param end Points just beyond the last edge.
152 * \param check Whether to only add an edge if it does not exist already.
153 */
154 template<typename EdgeInputIterator>
155 GraphAL( size_t nr, EdgeInputIterator begin, EdgeInputIterator end, bool check=true ) : _nb() {
156 construct( nr, begin, end, check );
157 }
158 //@}
160 /// \name Accessors and mutators
161 //@{
162 /// Returns constant reference to the \a _n2 'th neighbor of node \a n1
163 const Neighbor & nb( size_t n1, size_t _n2 ) const {
164 DAI_DEBASSERT( n1 < _nb.size() );
165 DAI_DEBASSERT( _n2 < _nb[n1].size() );
166 return _nb[n1][_n2];
167 }
168 /// Returns reference to the \a _n2 'th neighbor of node \a n1
169 Neighbor & nb( size_t n1, size_t _n2 ) {
170 DAI_DEBASSERT( n1 < _nb.size() );
171 DAI_DEBASSERT( _n2 < _nb[n1].size() );
172 return _nb[n1][_n2];
173 }
175 /// Returns constant reference to all neighbors of node \a n
176 const Neighbors & nb( size_t n ) const {
177 DAI_DEBASSERT( n < _nb.size() );
178 return _nb[n];
179 }
180 /// Returns reference to all neighbors of node \a n
181 Neighbors & nb( size_t n ) {
182 DAI_DEBASSERT( n < _nb.size() );
183 return _nb[n];
184 }
185 //@}
187 /// \name Adding nodes and edges
188 //@{
189 /// (Re)constructs GraphAL from a range of edges.
190 /** \tparam EdgeInputIterator Iterator that iterates over instances of Edge.
191 * \param nr The number of nodes.
192 * \param begin Points to the first edge.
193 * \param end Points just beyond the last edge.
194 * \param check Whether to only add an edge if it does not exist already.
195 */
196 template<typename EdgeInputIterator>
197 void construct( size_t nr, EdgeInputIterator begin, EdgeInputIterator end, bool check=true );
199 /// Adds a node without neighbors and returns the index of the added node.
200 size_t addNode() { _nb.push_back( Neighbors() ); return _nb.size() - 1; }
202 /// Adds a node, with neighbors specified by a range of nodes.
203 /** \tparam NodeInputIterator Iterator that iterates over instances of \c size_t.
204 * \param begin Points to the first index of the nodes that should become neighbors of the added node.
205 * \param end Points just beyond the last index of the nodes that should become neighbors of the added node.
206 * \param sizeHint For improved efficiency, the size of the range may be specified by \a sizeHint.
207 * \returns Index of the added node.
208 */
209 template <typename NodeInputIterator>
210 size_t addNode( NodeInputIterator begin, NodeInputIterator end, size_t sizeHint = 0 ) {
211 Neighbors nbsnew;
212 nbsnew.reserve( sizeHint );
213 size_t iter = 0;
214 for( NodeInputIterator it = begin; it != end; ++it ) {
215 DAI_ASSERT( *it < nrNodes() );
216 Neighbor nb1new( iter, *it, nb(*it).size() );
217 Neighbor nb2new( nb(*it).size(), nrNodes(), iter++ );
218 nbsnew.push_back( nb1new );
219 nb( *it ).push_back( nb2new );
220 }
221 _nb.push_back( nbsnew );
222 return _nb.size() - 1;
223 }
225 /// Adds an edge between node \a n1 and node \a n2.
226 /** If \a check == \c true, only adds the edge if it does not exist already.
227 */
228 GraphAL& addEdge( size_t n1, size_t n2, bool check = true );
229 //@}
231 /// \name Erasing nodes and edges
232 //@{
233 /// Removes node \a n and all incident edges; indices of other nodes are changed accordingly.
234 void eraseNode( size_t n );
236 /// Removes edge between node \a n1 and node \a n2.
237 void eraseEdge( size_t n1, size_t n2 );
238 //@}
240 /// \name Queries
241 //@{
242 /// Returns number of nodes
243 size_t nrNodes() const { return _nb.size(); }
245 /// Calculates the number of edges, time complexity: O(nrNodes())
246 size_t nrEdges() const {
247 size_t sum = 0;
248 for( size_t i = 0; i < nrNodes(); i++ )
249 sum += nb(i).size();
250 return sum / 2;
251 }
253 /// Returns true if the graph contains an edge between nodes \a n1 and \a n2
254 /** \note The time complexity is linear in the number of neighbors of \a n1 or \a n2
255 */
256 bool hasEdge( size_t n1, size_t n2 ) const {
257 if( nb(n1).size() < nb(n2).size() ) {
258 for( size_t _n2 = 0; _n2 < nb(n1).size(); _n2++ )
259 if( nb( n1, _n2 ) == n2 )
260 return true;
261 } else {
262 for( size_t _n1 = 0; _n1 < nb(n2).size(); _n1++ )
263 if( nb( n2, _n1 ) == n1 )
264 return true;
265 }
266 return false;
267 }
269 /// Returns the index of a given node \a n2 amongst the neighbors of \a n1
270 /** \note The time complexity is linear in the number of neighbors of \a n1
271 * \throw OBJECT_NOT_FOUND if \a n2 is not a neighbor of \a n1
272 */
273 size_t findNb( size_t n1, size_t n2 ) {
274 for( size_t _n2 = 0; _n2 < nb(n1).size(); _n2++ )
275 if( nb( n1, _n2 ) == n2 )
276 return _n2;
277 DAI_THROW(OBJECT_NOT_FOUND);
278 return nb(n1).size();
279 }
281 /// Returns neighbors of node \a n as a SmallSet<size_t>.
282 SmallSet<size_t> nbSet( size_t n ) const;
284 /// Returns true if the graph is connected
285 bool isConnected() const;
287 /// Returns true if the graph is a tree, i.e., if it is singly connected and connected.
288 bool isTree() const;
290 /// Asserts internal consistency
291 void checkConsistency() const;
293 /// Comparison operator which returns true if two graphs are identical
294 /** \note Two graphs are called identical if they have the same number
295 * of nodes and the same edges (i.e., \a x has an edge between nodes
296 * \a n1 and \a n2 if and only if \c *this has an edge between nodes \a n1 and \a n2).
297 */
298 bool operator==( const GraphAL& x ) const {
299 if( nrNodes() != x.nrNodes() )
300 return false;
301 for( size_t n1 = 0; n1 < nrNodes(); n1++ ) {
302 if( nb(n1).size() != x.nb(n1).size() )
303 return false;
304 foreach( const Neighbor &n2, nb(n1) )
305 if( !x.hasEdge( n1, n2 ) )
306 return false;
307 foreach( const Neighbor &n2, x.nb(n1) )
308 if( !hasEdge( n1, n2 ) )
309 return false;
310 }
311 return true;
312 }
313 //@}
315 /// \name Input and output
316 //@{
317 /// Writes this GraphAL to an output stream in GraphViz .dot syntax
318 void printDot( std::ostream& os ) const;
320 /// Writes this GraphAL to an output stream
321 friend std::ostream& operator<<( std::ostream& os, const GraphAL& g ) {
322 g.printDot( os );
323 return os;
324 }
325 //@}
326 };
329 template<typename EdgeInputIterator>
330 void GraphAL::construct( size_t nr, EdgeInputIterator begin, EdgeInputIterator end, bool check ) {
331 _nb.clear();
332 _nb.resize( nr );
334 for( EdgeInputIterator e = begin; e != end; e++ )
335 addEdge( e->first, e->second, check );
336 }
339 /// Creates a fully-connected graph with \a N nodes
340 GraphAL createGraphFull( size_t N );
341 /// Creates a two-dimensional rectangular grid of \a N1 by \a N2 nodes, which can be \a periodic
342 GraphAL createGraphGrid( size_t N1, size_t N2, bool periodic );
343 /// Creates a three-dimensional rectangular grid of \a N1 by \a N2 by \a N3 nodes, which can be \a periodic
344 GraphAL createGraphGrid3D( size_t N1, size_t N2, size_t N3, bool periodic );
345 /// Creates a graph consisting of a single loop of \a N nodes
346 GraphAL createGraphLoop( size_t N );
347 /// Creates a random tree-structured graph of \a N nodes
348 GraphAL createGraphTree( size_t N );
349 /// Creates a random regular graph of \a N nodes with uniform connectivity \a d
350 /** Algorithm 1 in [\ref StW99].
351 * Draws a random graph of size \a N and uniform degree \a d
352 * from an almost uniform probability distribution over these graphs
353 * (which becomes uniform in the limit that \a d is small and \a N goes
354 * to infinity).
355 */
356 GraphAL createGraphRegular( size_t N, size_t d );
359 } // end of namespace dai
362 #endif