1 /* This file is part of libDAI - http://www.libdai.org/
3 * libDAI is licensed under the terms of the GNU General Public License version
4 * 2, or (at your option) any later version. libDAI is distributed without any
5 * warranty. See the file COPYING for more details.
7 * Copyright (C) 2006-2009 Joris Mooij [joris dot mooij at libdai dot org]
8 * Copyright (C) 2006-2007 Radboud University Nijmegen, The Netherlands
13 /// \brief Defines the BipartiteGraph class, which represents a bipartite graph
16 #ifndef __defined_libdai_bipgraph_h
17 #define __defined_libdai_bipgraph_h
24 #include <dai/exceptions.h>
30 /// Represents the neighborhood structure of nodes in an undirected, bipartite graph.
31 /** A bipartite graph has two types of nodes: type 1 and type 2. Edges can occur only between
32 * nodes of different type. Nodes are indexed by an unsigned integer. If there are nrNodes1()
33 * nodes of type 1 and nrNodes2() nodes of type 2, the nodes of type 1 are numbered
34 * 0,1,2,...,nrNodes1()-1 and the nodes of type 2 are numbered 0,1,2,...,nrNodes2()-1. An edge
35 * between node \a n1 of type 1 and node \a n2 of type 2 is represented by a BipartiteGraph::Edge(\a n1,\a n2).
37 * A BipartiteGraph is implemented as a sparse adjacency list, i.e., it stores for each node a list of
38 * its neighboring nodes. More precisely: it stores for each node of type 1 a vector of Neighbor structures
39 * (accessible by the nb1() method) describing the neighboring nodes of type 2; similarly, for each node
40 * of type 2 it stores a vector of Neighbor structures (accessibly by the nb2() method) describing the
41 * neighboring nodes of type 1.
42 * Thus, each node has an associated variable of type BipartiteGraph::Neighbors, which is a vector of
43 * Neighbor structures, describing its neighboring nodes of the other type.
44 * \idea Cache second-order neighborhoods in BipartiteGraph.
45 * \todo Check whether BGL isConnected improves performance.
47 class BipartiteGraph
{
49 /// Describes the neighbor relationship of two nodes in a BipartiteGraph.
50 /** Sometimes we want to do an action, such as sending a
51 * message, for all edges in a graph. However, most graphs
52 * will be sparse, so we need some way of storing a set of
53 * the neighbors of a node, which is both fast and
54 * memory-efficient. We also need to be able to go between
55 * viewing node \a a as a neighbor of node \a b, and node \a b
56 * as a neighbor of node \a a. The Neighbor struct solves
57 * both of these problems. Each node has a list of neighbors,
58 * stored as a std::vector<\link Neighbor \endlink>, and
59 * extra information is included in the Neighbor struct which
60 * allows us to access a node as a neighbor of its neighbor
61 * (the \c dual member).
63 * By convention, variable identifiers naming indices into a
64 * vector of neighbors are prefixed with an underscore ("_").
65 * The neighbor list which they point into is then understood
66 * from context. For example:
69 * void BP::calcNewMessage( size_t i, size_t _I )
72 * Here, \a i is the "absolute" index of node i, but \a _I is
73 * understood as a "relative" index, giving node \a I 's entry in
74 * <tt>nb1(i)</tt>. The corresponding Neighbor structure can be
75 * accessed as <tt>nb1(i,_I)</tt> or <tt>nb1(i)[_I]</tt>. The
76 * absolute index of \a _I, which would be called \a I, can be
77 * recovered from the \c node member: <tt>nb1(i,_I).node</tt>.
78 * The \c iter member gives the relative index \a _I, and the
79 * \c dual member gives the "dual" relative index, i.e., the
80 * index of \a i in \a I 's neighbor list.
83 * Neighbor n = nb1(i,_I);
86 * nb2(n.node,n.dual).node == i
89 * In a FactorGraph, the nodes of type 1 represent variables, and
90 * the nodes of type 2 represent factors. For convenience, nb1() is
91 * called FactorGraph::nbV(), and nb2() is called FactorGraph::nbF().
93 * There is no easy way to transform a pair of absolute node
94 * indices \a i and \a I into a Neighbor structure relative
95 * to one of the nodes. Such a feature has never yet been
96 * found to be necessary. Iteration over edges can always be
97 * accomplished using the Neighbor lists, and by writing
98 * functions that accept relative indices:
100 * for( size_t i = 0; i < nrVars(); ++i )
101 * foreach( const Neighbor &I, nbV(i) )
102 * calcNewMessage( i, I.iter );
106 /// Corresponds to the index of this Neighbor entry in the vector of neighbors
108 /// Contains the number of the neighboring node
110 /// Contains the "dual" iter
113 /// Default constructor
115 /// Constructor that sets the Neighbor members according to the parameters
116 Neighbor( size_t iter
, size_t node
, size_t dual
) : iter(iter
), node(node
), dual(dual
) {}
118 /// Cast to \c size_t returns \c node member
119 operator size_t () const { return node
; }
122 /// Describes the neighbors of some node.
123 typedef std::vector
<Neighbor
> Neighbors
;
125 /// Represents an edge: an Edge(\a n1,\a n2) corresponds to the edge between node \a n1 of type 1 and node \a n2 of type 2.
126 typedef std::pair
<size_t,size_t> Edge
;
129 /// Contains for each node of type 1 a vector of its neighbors
130 std::vector
<Neighbors
> _nb1
;
132 /// Contains for each node of type 2 a vector of its neighbors
133 std::vector
<Neighbors
> _nb2
;
135 /// Used internally by isTree()
137 /// Indices of nodes of type 1
138 std::vector
<size_t> ind1
;
139 /// Indices of nodes of type 2
140 std::vector
<size_t> ind2
;
144 /// \name Constructors and destructors
146 /// Default constructor (creates an empty bipartite graph)
147 BipartiteGraph() : _nb1(), _nb2() {}
149 /// Constructs BipartiteGraph from a range of edges.
150 /** \tparam EdgeInputIterator Iterator that iterates over instances of BipartiteGraph::Edge.
151 * \param nrNodes1 The number of nodes of type 1.
152 * \param nrNodes2 The number of nodes of type 2.
153 * \param begin Points to the first edge.
154 * \param end Points just beyond the last edge.
156 template<typename EdgeInputIterator
>
157 BipartiteGraph( size_t nrNodes1
, size_t nrNodes2
, EdgeInputIterator begin
, EdgeInputIterator end
) : _nb1(), _nb2() {
158 construct( nrNodes1
, nrNodes2
, begin
, end
);
162 /// \name Accessors and mutators
164 /// Returns constant reference to the \a _i2 'th neighbor of node \a i1 of type 1
165 const Neighbor
& nb1( size_t i1
, size_t _i2
) const {
166 DAI_DEBASSERT( i1
< _nb1
.size() );
167 DAI_DEBASSERT( _i2
< _nb1
[i1
].size() );
168 return _nb1
[i1
][_i2
];
170 /// Returns reference to the \a _i2 'th neighbor of node \a i1 of type 1
171 Neighbor
& nb1( size_t i1
, size_t _i2
) {
172 DAI_DEBASSERT( i1
< _nb1
.size() );
173 DAI_DEBASSERT( _i2
< _nb1
[i1
].size() );
174 return _nb1
[i1
][_i2
];
177 /// Returns constant reference to the \a _i1 'th neighbor of node \a i2 of type 2
178 const Neighbor
& nb2( size_t i2
, size_t _i1
) const {
179 DAI_DEBASSERT( i2
< _nb2
.size() );
180 DAI_DEBASSERT( _i1
< _nb2
[i2
].size() );
181 return _nb2
[i2
][_i1
];
183 /// Returns reference to the \a _i1 'th neighbor of node \a i2 of type 2
184 Neighbor
& nb2( size_t i2
, size_t _i1
) {
185 DAI_DEBASSERT( i2
< _nb2
.size() );
186 DAI_DEBASSERT( _i1
< _nb2
[i2
].size() );
187 return _nb2
[i2
][_i1
];
190 /// Returns constant reference to all neighbors of node \a i1 of type 1
191 const Neighbors
& nb1( size_t i1
) const {
192 DAI_DEBASSERT( i1
< _nb1
.size() );
195 /// Returns reference to all neighbors of node \a i1 of type 1
196 Neighbors
& nb1( size_t i1
) {
197 DAI_DEBASSERT( i1
< _nb1
.size() );
201 /// Returns constant reference to all neighbors of node \a i2 of type 2
202 const Neighbors
& nb2( size_t i2
) const {
203 DAI_DEBASSERT( i2
< _nb2
.size() );
206 /// Returns reference to all neighbors of node \a i2 of type 2
207 Neighbors
& nb2( size_t i2
) {
208 DAI_DEBASSERT( i2
< _nb2
.size() );
213 /// \name Adding nodes and edges
215 /// (Re)constructs BipartiteGraph from a range of edges.
216 /** \tparam EdgeInputIterator Iterator that iterates over instances of BipartiteGraph::Edge.
217 * \param nrNodes1 The number of nodes of type 1.
218 * \param nrNodes2 The number of nodes of type 2.
219 * \param begin Points to the first edge.
220 * \param end Points just beyond the last edge.
222 template<typename EdgeInputIterator
>
223 void construct( size_t nrNodes1
, size_t nrNodes2
, EdgeInputIterator begin
, EdgeInputIterator end
);
225 /// Adds a node of type 1 without neighbors and returns the index of the added node.
226 size_t addNode1() { _nb1
.push_back( Neighbors() ); return _nb1
.size() - 1; }
228 /// Adds a node of type 2 without neighbors and returns the index of the added node.
229 size_t addNode2() { _nb2
.push_back( Neighbors() ); return _nb2
.size() - 1; }
232 /// Adds a node of type 1 without neighbors and returns the index of the added node.
233 /** \deprecated Please use dai::BipartiteGraph::addNode1() instead.
235 size_t add1() { return addNode1(); }
237 /// Adds a node of type 2 without neighbors and returns the index of the added node.
238 /** \deprecated Please use dai::BipartiteGraph::addNode2() instead.
240 size_t add2() { return addNode2(); }
242 /// Adds a node of type 1, with neighbors specified by a range of nodes of type 2.
243 /** \tparam NodeInputIterator Iterator that iterates over instances of \c size_t.
244 * \param begin Points to the first index of the nodes of type 2 that should become neighbors of the added node.
245 * \param end Points just beyond the last index of the nodes of type 2 that should become neighbors of the added node.
246 * \param sizeHint For improved efficiency, the size of the range may be specified by \a sizeHint.
247 * \returns Index of the added node.
249 template <typename NodeInputIterator
>
250 size_t addNode1( NodeInputIterator begin
, NodeInputIterator end
, size_t sizeHint
= 0 ) {
252 nbs1new
.reserve( sizeHint
);
254 for( NodeInputIterator it
= begin
; it
!= end
; ++it
) {
255 DAI_ASSERT( *it
< nrNodes2() );
256 Neighbor
nb1new( iter
, *it
, nb2(*it
).size() );
257 Neighbor
nb2new( nb2(*it
).size(), nrNodes1(), iter
++ );
258 nbs1new
.push_back( nb1new
);
259 nb2( *it
).push_back( nb2new
);
261 _nb1
.push_back( nbs1new
);
262 return _nb1
.size() - 1;
265 /// Adds a node of type 2, with neighbors specified by a range of nodes of type 1.
266 /** \tparam NodeInputIterator Iterator that iterates over instances of \c size_t.
267 * \param begin Points to the first index of the nodes of type 1 that should become neighbors of the added node.
268 * \param end Points just beyond the last index of the nodes of type 1 that should become neighbors of the added node.
269 * \param sizeHint For improved efficiency, the size of the range may be specified by \a sizeHint.
270 * \returns Index of the added node.
272 template <typename NodeInputIterator
>
273 size_t addNode2( NodeInputIterator begin
, NodeInputIterator end
, size_t sizeHint
= 0 ) {
275 nbs2new
.reserve( sizeHint
);
277 for( NodeInputIterator it
= begin
; it
!= end
; ++it
) {
278 DAI_ASSERT( *it
< nrNodes1() );
279 Neighbor
nb2new( iter
, *it
, nb1(*it
).size() );
280 Neighbor
nb1new( nb1(*it
).size(), nrNodes2(), iter
++ );
281 nbs2new
.push_back( nb2new
);
282 nb1( *it
).push_back( nb1new
);
284 _nb2
.push_back( nbs2new
);
285 return _nb2
.size() - 1;
288 /// Adds a node of type 1, with neighbors specified by a range of nodes of type 2.
289 /** \deprecated Please use dai::BipartiteGraph::addNode1( NodeInputIterator, NodeInputIterator, size_t) instead.
291 template <typename NodeInputIterator
>
292 size_t add1( NodeInputIterator begin
, NodeInputIterator end
, size_t sizeHint
= 0 ) {
293 return addNode1( begin
, end
, sizeHint
);
296 /// Adds a node of type 2, with neighbors specified by a range of nodes of type 1.
297 /** \deprecated Please use dai::BipartiteGraph::addNode2( NodeInputIterator, NodeInputIterator, size_t) instead.
299 template <typename NodeInputIterator
>
300 size_t add2( NodeInputIterator begin
, NodeInputIterator end
, size_t sizeHint
= 0 ) {
301 return addNode2( begin
, end
, sizeHint
);
304 /// Adds an edge between node \a n1 of type 1 and node \a n2 of type 2.
305 /** If \a check == \c true, only adds the edge if it does not exist already.
307 void addEdge( size_t n1
, size_t n2
, bool check
= true );
310 /// \name Erasing nodes and edges
312 /// Removes node \a n1 of type 1 and all incident edges; indices of other nodes are changed accordingly.
313 void eraseNode1( size_t n1
);
315 /// Removes node \a n2 of type 2 and all incident edges; indices of other nodes are changed accordingly.
316 void eraseNode2( size_t n2
);
318 /// Removes node \a n1 of type 1 and all incident edges; indices of other nodes are changed accordingly.
319 /** \deprecated Please use dai::BipartiteGraph::eraseNode1(size_t) instead.
321 void erase1( size_t n1
) { eraseNode1( n1
); }
323 /// Removes node \a n2 of type 2 and all incident edges; indices of other nodes are changed accordingly.
324 /** \deprecated Please use dai::BipartiteGraph::eraseNode2(size_t) instead.
326 void erase2( size_t n2
) { eraseNode2( n2
); }
328 /// Removes edge between node \a n1 of type 1 and node \a n2 of type 2.
329 void eraseEdge( size_t n1
, size_t n2
);
334 /// Returns number of nodes of type 1
335 size_t nrNodes1() const { return _nb1
.size(); }
336 /// Returns number of nodes of type 2
337 size_t nrNodes2() const { return _nb2
.size(); }
339 /// Returns number of nodes of type 1
340 /** \deprecated Please use dai::BipartiteGraph::nrNodes1() instead.
342 size_t nr1() const { return nrNodes1(); }
344 /// Returns number of nodes of type 2
345 /** \deprecated Please use dai::BipartiteGraph::nrNodes2() instead.
347 size_t nr2() const { return nrNodes2(); }
349 /// Calculates the number of edges, time complexity: O(nrNodes1())
350 size_t nrEdges() const {
352 for( size_t i1
= 0; i1
< nrNodes1(); i1
++ )
353 sum
+= nb1(i1
).size();
357 /// Calculates second-order neighbors (i.e., neighbors of neighbors) of node \a n1 of type 1.
358 /** If \a include == \c true, includes \a n1 itself, otherwise excludes \a n1.
360 std::vector
<size_t> delta1( size_t n1
, bool include
= false ) const;
362 /// Calculates second-order neighbors (i.e., neighbors of neighbors) of node \a n2 of type 2.
363 /** If \a include == \c true, includes \a n2 itself, otherwise excludes \a n2.
365 std::vector
<size_t> delta2( size_t n2
, bool include
= false ) const;
367 /// Returns true if the graph is connected
368 bool isConnected() const;
370 /// Returns true if the graph is a tree, i.e., if it is singly connected and connected.
373 /// Checks internal consistency
374 void checkConsistency() const;
377 /// \name Input and output
379 /// Writes this BipartiteGraph to an output stream in GraphViz .dot syntax
380 void printDot( std::ostream
& os
) const;
385 template<typename EdgeInputIterator
>
386 void BipartiteGraph::construct( size_t nrNodes1
, size_t nrNodes2
, EdgeInputIterator begin
, EdgeInputIterator end
) {
388 _nb1
.resize( nrNodes1
);
390 _nb2
.resize( nrNodes2
);
392 for( EdgeInputIterator e
= begin
; e
!= end
; e
++ ) {
394 addEdge( e
->first
, e
->second
, true );
396 addEdge( e
->first
, e
->second
, false );
402 } // end of namespace dai
405 /** \example example_bipgraph.cpp
406 * This example deals with the following bipartite graph:
410 * subgraph cluster_type1 {
411 * node[shape=circle,width=0.4,fixedsize=true,style=filled];
416 * subgraph cluster_type2 {
417 * node[shape=polygon,regular=true,sides=4,width=0.4,fixedsize=true,style=filled];
428 * It has three nodes of type 1 (drawn as circles) and two nodes of type 2 (drawn as rectangles).
429 * Node 0 of type 1 has only one neighbor (node 0 of type 2), but node 0 of type 2 has three neighbors (nodes 0,1,2 of type 1).
430 * The example code shows how to construct a BipartiteGraph object representing this bipartite graph and
431 * how to iterate over nodes and their neighbors.
434 * \verbinclude examples/example_bipgraph.out