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 nr1()
33 * nodes of type 1 and nr2() nodes of type 2, the nodes of type 1 are numbered
34 * 0,1,2,...,nr1()-1 and the nodes of type 2 are numbered 0,1,2,...,nr2()-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.
46 class BipartiteGraph
{
48 /// Describes the neighbor relationship of two nodes in a BipartiteGraph.
49 /** Sometimes we want to do an action, such as sending a
50 * message, for all edges in a graph. However, most graphs
51 * will be sparse, so we need some way of storing a set of
52 * the neighbors of a node, which is both fast and
53 * memory-efficient. We also need to be able to go between
54 * viewing node \a a as a neighbor of node \a b, and node \a b
55 * as a neighbor of node \a a. The Neighbor struct solves
56 * both of these problems. Each node has a list of neighbors,
57 * stored as a std::vector<\link Neighbor \endlink>, and
58 * extra information is included in the Neighbor struct which
59 * allows us to access a node as a neighbor of its neighbor
60 * (the \c dual member).
62 * By convention, variable identifiers naming indices into a
63 * vector of neighbors are prefixed with an underscore ("_").
64 * The neighbor list which they point into is then understood
65 * from context. For example:
68 * void BP::calcNewMessage( size_t i, size_t _I )
71 * Here, \a i is the "absolute" index of node i, but \a _I is
72 * understood as a "relative" index, giving node \a I 's entry in
73 * <tt>nb1(i)</tt>. The corresponding Neighbor structure can be
74 * accessed as <tt>nb1(i,_I)</tt> or <tt>nb1(i)[_I]</tt>. The
75 * absolute index of \a _I, which would be called \a I, can be
76 * recovered from the \c node member: <tt>nb1(i,_I).node</tt>.
77 * The \c iter member gives the relative index \a _I, and the
78 * \c dual member gives the "dual" relative index, i.e., the
79 * index of \a i in \a I 's neighbor list.
82 * Neighbor n = nb1(i,_I);
85 * nb2(n.node,n.dual).node == i
88 * In a FactorGraph, the nodes of type 1 represent variables, and
89 * the nodes of type 2 represent factors. For convenience, nb1() is
90 * called FactorGraph::nbV(), and nb2() is called FactorGraph::nbF().
92 * There is no easy way to transform a pair of absolute node
93 * indices \a i and \a I into a Neighbor structure relative
94 * to one of the nodes. Such a feature has never yet been
95 * found to be necessary. Iteration over edges can always be
96 * accomplished using the Neighbor lists, and by writing
97 * functions that accept relative indices:
99 * for( size_t i = 0; i < nrVars(); ++i )
100 * foreach( const Neighbor &I, nbV(i) )
101 * calcNewMessage( i, I.iter );
105 /// Corresponds to the index of this Neighbor entry in the vector of neighbors
107 /// Contains the number of the neighboring node
109 /// Contains the "dual" iter
112 /// Default constructor
114 /// Constructor that sets the Neighbor members according to the parameters
115 Neighbor( size_t iter
, size_t node
, size_t dual
) : iter(iter
), node(node
), dual(dual
) {}
117 /// Cast to \c size_t returns \c node member
118 operator size_t () const { return node
; }
121 /// Describes the neighbors of some node.
122 typedef std::vector
<Neighbor
> Neighbors
;
124 /// 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.
125 typedef std::pair
<size_t,size_t> Edge
;
128 /// Contains for each node of type 1 a vector of its neighbors
129 std::vector
<Neighbors
> _nb1
;
131 /// Contains for each node of type 2 a vector of its neighbors
132 std::vector
<Neighbors
> _nb2
;
134 /// Used internally by isTree()
136 /// Indices of nodes of type 1
137 std::vector
<size_t> ind1
;
138 /// Indices of nodes of type 2
139 std::vector
<size_t> ind2
;
143 /// \name Backwards compatibility layer (to be removed soon)
145 /// Enable backwards compatibility layer?
146 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
149 /// Call indexEdges() first to initialize these members
150 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
152 std::vector
<Edge
> _edges
;
153 /// Call indexEdges() first to initialize these members
154 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
156 hash_map
<Edge
,size_t> _vv2e
;
160 /// \name Constructors and destructors
162 /// Default constructor (creates an empty bipartite graph)
163 BipartiteGraph() : _nb1(), _nb2(), _edge_indexed(false) {}
165 /// Constructs BipartiteGraph from a range of edges.
166 /** \tparam EdgeInputIterator Iterator that iterates over instances of BipartiteGraph::Edge.
167 * \param nr1 The number of nodes of type 1.
168 * \param nr2 The number of nodes of type 2.
169 * \param begin Points to the first edge.
170 * \param end Points just beyond the last edge.
172 template<typename EdgeInputIterator
>
173 BipartiteGraph( size_t nr1
, size_t nr2
, EdgeInputIterator begin
, EdgeInputIterator end
) : _nb1( nr1
), _nb2( nr2
), _edge_indexed(false) {
174 construct( nr1
, nr2
, begin
, end
);
178 /// \name Accessors and mutators
180 /// Returns constant reference to the \a _i2 'th neighbor of node \a i1 of type 1
181 const Neighbor
& nb1( size_t i1
, size_t _i2
) const {
182 DAI_DEBASSERT( i1
< _nb1
.size() );
183 DAI_DEBASSERT( _i2
< _nb1
[i1
].size() );
184 return _nb1
[i1
][_i2
];
186 /// Returns reference to the \a _i2 'th neighbor of node \a i1 of type 1
187 Neighbor
& nb1( size_t i1
, size_t _i2
) {
188 DAI_DEBASSERT( i1
< _nb1
.size() );
189 DAI_DEBASSERT( _i2
< _nb1
[i1
].size() );
190 return _nb1
[i1
][_i2
];
193 /// Returns constant reference to the \a _i1 'th neighbor of node \a i2 of type 2
194 const Neighbor
& nb2( size_t i2
, size_t _i1
) const {
195 DAI_DEBASSERT( i2
< _nb2
.size() );
196 DAI_DEBASSERT( _i1
< _nb2
[i2
].size() );
197 return _nb2
[i2
][_i1
];
199 /// Returns reference to the \a _i1 'th neighbor of node \a i2 of type 2
200 Neighbor
& nb2( size_t i2
, size_t _i1
) {
201 DAI_DEBASSERT( i2
< _nb2
.size() );
202 DAI_DEBASSERT( _i1
< _nb2
[i2
].size() );
203 return _nb2
[i2
][_i1
];
206 /// Returns constant reference to all neighbors of node \a i1 of type 1
207 const Neighbors
& nb1( size_t i1
) const {
208 DAI_DEBASSERT( i1
< _nb1
.size() );
211 /// Returns reference to all neighbors of node \a i1 of type 1
212 Neighbors
& nb1( size_t i1
) {
213 DAI_DEBASSERT( i1
< _nb1
.size() );
217 /// Returns constant reference to all neighbors of node \a i2 of type 2
218 const Neighbors
& nb2( size_t i2
) const {
219 DAI_DEBASSERT( i2
< _nb2
.size() );
222 /// Returns reference to all neighbors of node \a i2 of type 2
223 Neighbors
& nb2( size_t i2
) {
224 DAI_DEBASSERT( i2
< _nb2
.size() );
229 /// \name Adding nodes and edges
231 /// (Re)constructs BipartiteGraph from a range of edges.
232 /** \tparam EdgeInputIterator Iterator that iterates over instances of BipartiteGraph::Edge.
233 * \param nr1 The number of nodes of type 1.
234 * \param nr2 The number of nodes of type 2.
235 * \param begin Points to the first edge.
236 * \param end Points just beyond the last edge.
238 template<typename EdgeInputIterator
>
239 void construct( size_t nr1
, size_t nr2
, EdgeInputIterator begin
, EdgeInputIterator end
);
241 /// Adds a node of type 1 without neighbors and returns the index of the added node.
242 size_t add1() { _nb1
.push_back( Neighbors() ); return _nb1
.size() - 1; }
244 /// Adds a node of type 2 without neighbors and returns the index of the added node.
245 size_t add2() { _nb2
.push_back( Neighbors() ); return _nb2
.size() - 1; }
247 /// Adds a node of type 1, with neighbors specified by a range of nodes of type 2.
248 /** \tparam NodeInputIterator Iterator that iterates over instances of \c size_t.
249 * \param begin Points to the first index of the nodes of type 2 that should become neighbors of the added node.
250 * \param end Points just beyond the last index of the nodes of type 2 that should become neighbors of the added node.
251 * \param sizeHint For improved efficiency, the size of the range may be specified by \a sizeHint.
252 * \returns Index of the added node.
254 template <typename NodeInputIterator
>
255 size_t add1( NodeInputIterator begin
, NodeInputIterator end
, size_t sizeHint
= 0 ) {
257 nbs1new
.reserve( sizeHint
);
259 for( NodeInputIterator it
= begin
; it
!= end
; ++it
) {
260 DAI_ASSERT( *it
< nr2() );
261 Neighbor
nb1new( iter
, *it
, nb2(*it
).size() );
262 Neighbor
nb2new( nb2(*it
).size(), nr1(), iter
++ );
263 nbs1new
.push_back( nb1new
);
264 nb2( *it
).push_back( nb2new
);
266 _nb1
.push_back( nbs1new
);
267 return _nb1
.size() - 1;
270 /// Adds a node of type 2, with neighbors specified by a range of nodes of type 1.
271 /** \tparam NodeInputIterator Iterator that iterates over instances of \c size_t.
272 * \param begin Points to the first index of the nodes of type 1 that should become neighbors of the added node.
273 * \param end Points just beyond the last index of the nodes of type 1 that should become neighbors of the added node.
274 * \param sizeHint For improved efficiency, the size of the range may be specified by \a sizeHint.
275 * \returns Index of the added node.
277 template <typename NodeInputIterator
>
278 size_t add2( NodeInputIterator begin
, NodeInputIterator end
, size_t sizeHint
= 0 ) {
280 nbs2new
.reserve( sizeHint
);
282 for( NodeInputIterator it
= begin
; it
!= end
; ++it
) {
283 DAI_ASSERT( *it
< nr1() );
284 Neighbor
nb2new( iter
, *it
, nb1(*it
).size() );
285 Neighbor
nb1new( nb1(*it
).size(), nr2(), iter
++ );
286 nbs2new
.push_back( nb2new
);
287 nb1( *it
).push_back( nb1new
);
289 _nb2
.push_back( nbs2new
);
290 return _nb2
.size() - 1;
293 /// Adds an edge between node \a n1 of type 1 and node \a n2 of type 2.
294 /** If \a check == \c true, only adds the edge if it does not exist already.
296 void addEdge( size_t n1
, size_t n2
, bool check
= true );
299 /// \name Erasing nodes and edges
301 /// Removes node \a n1 of type 1 and all incident edges; indices of other nodes are changed accordingly.
302 void erase1( size_t n1
);
304 /// Removes node \a n2 of type 2 and all incident edges; indices of other nodes are changed accordingly.
305 void erase2( size_t n2
);
307 /// Removes edge between node \a n1 of type 1 and node \a n2 of type 2.
308 void eraseEdge( size_t n1
, size_t n2
);
313 /// Returns number of nodes of type 1
314 size_t nr1() const { return _nb1
.size(); }
315 /// Returns number of nodes of type 2
316 size_t nr2() const { return _nb2
.size(); }
318 /// Calculates the number of edges, time complexity: O(nr1())
319 size_t nrEdges() const {
321 for( size_t i1
= 0; i1
< nr1(); i1
++ )
322 sum
+= nb1(i1
).size();
326 /// Calculates second-order neighbors (i.e., neighbors of neighbors) of node \a n1 of type 1.
327 /** If \a include == \c true, includes \a n1 itself, otherwise excludes \a n1.
329 std::vector
<size_t> delta1( size_t n1
, bool include
= false ) const;
331 /// Calculates second-order neighbors (i.e., neighbors of neighbors) of node \a n2 of type 2.
332 /** If \a include == \c true, includes \a n2 itself, otherwise excludes \a n2.
334 std::vector
<size_t> delta2( size_t n2
, bool include
= false ) const;
336 /// Returns true if the graph is connected
337 /** \todo Should be optimized by invoking boost::graph library
339 bool isConnected() const;
341 /// Returns true if the graph is a tree, i.e., if it is singly connected and connected.
344 /// Checks internal consistency
345 void checkConsistency() const;
348 /// \name Input and output
350 /// Writes this BipartiteGraph to an output stream in GraphViz .dot syntax
351 void printDot( std::ostream
& os
) const;
355 /// \name Backwards compatibility layer (to be removed soon)
357 /// Prepare backwards compatibility layer for indexed edges
358 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
361 std::cerr
<< "Warning: this BipartiteGraph edge interface is obsolete!" << std::endl
;
365 foreach(const Neighbors
&nb1s
, _nb1
) {
366 foreach(const Neighbor
&n2
, nb1s
) {
372 sort(_edges
.begin(), _edges
.end()); // unnecessary?
375 foreach(const Edge
& e
, _edges
) {
379 _edge_indexed
= true;
382 /// Returns edge with index \a e
383 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
385 const Edge
& edge(size_t e
) const {
386 DAI_ASSERT(_edge_indexed
);
390 /// Returns all edges
391 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
393 const std::vector
<Edge
>& edges() const {
397 /// Converts a pair of node indices to an edge index
398 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
400 size_t VV2E(size_t n1
, size_t n2
) const {
401 DAI_ASSERT(_edge_indexed
);
403 hash_map
<Edge
,size_t>::const_iterator i
= _vv2e
.find(e
);
404 DAI_ASSERT(i
!= _vv2e
.end());
408 /// Returns number of edges
409 /** \deprecated Please use the BipartiteGraph::Neighbor interface instead
411 size_t nr_edges() const {
412 DAI_ASSERT(_edge_indexed
);
413 return _edges
.size();
419 template<typename EdgeInputIterator
>
420 void BipartiteGraph::construct( size_t nr1
, size_t nr2
, EdgeInputIterator begin
, EdgeInputIterator end
) {
426 for( EdgeInputIterator e
= begin
; e
!= end
; e
++ ) {
428 addEdge( e
->first
, e
->second
, true );
430 addEdge( e
->first
, e
->second
, false );
436 } // end of namespace dai
439 /** \example example_bipgraph.cpp
440 * This example deals with the following bipartite graph:
444 * subgraph cluster_type1 {
445 * node[shape=circle,width=0.4,fixedsize=true,style=filled];
450 * subgraph cluster_type2 {
451 * node[shape=polygon,regular=true,sides=4,width=0.4,fixedsize=true,style=filled];
462 * It has three nodes of type 1 (drawn as circles) and two nodes of type 2 (drawn as rectangles).
463 * 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).
464 * The example code shows how to construct a BipartiteGraph object representing this bipartite graph and
465 * how to iterate over nodes and their neighbors.
468 * \verbinclude examples/example_bipgraph.out