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
12 #include <dai/bipgraph.h>
21 void BipartiteGraph::erase1( size_t n1
) {
23 // Erase neighbor entry of node n1
24 _nb1
.erase( _nb1
.begin() + n1
);
25 // Adjust neighbor entries of nodes of type 2
26 for( size_t n2
= 0; n2
< nr2(); n2
++ ) {
27 for( size_t iter
= 0; iter
< nb2(n2
).size(); ) {
28 Neighbor
&m1
= nb2(n2
, iter
);
30 // delete this entry, because it points to the deleted node
31 nb2(n2
).erase( nb2(n2
).begin() + iter
);
32 } else if( m1
.node
> n1
) {
33 // update this entry and the corresponding dual of the neighboring node of type 1
36 nb1( m1
.node
, m1
.dual
).dual
= iter
;
47 void BipartiteGraph::erase2( size_t n2
) {
49 // Erase neighbor entry of node n2
50 _nb2
.erase( _nb2
.begin() + n2
);
51 // Adjust neighbor entries of nodes of type 1
52 for( size_t n1
= 0; n1
< nr1(); n1
++ ) {
53 for( size_t iter
= 0; iter
< nb1(n1
).size(); ) {
54 Neighbor
&m2
= nb1(n1
, iter
);
56 // delete this entry, because it points to the deleted node
57 nb1(n1
).erase( nb1(n1
).begin() + iter
);
58 } else if( m2
.node
> n2
) {
59 // update this entry and the corresponding dual of the neighboring node of type 2
62 nb2( m2
.node
, m2
.dual
).dual
= iter
;
73 std::vector
<size_t> BipartiteGraph::delta1( size_t n1
, bool include
) const {
74 // get all second-order neighbors
75 std::vector
<size_t> result
;
76 foreach( const Neighbor
&n2
, nb1(n1
) )
77 foreach( const Neighbor
&m1
, nb2(n2
) )
78 if( include
|| (m1
!= n1
) )
79 result
.push_back( m1
);
81 std::vector
<size_t>::iterator it
= std::unique( result
.begin(), result
.end() );
82 result
.erase( it
, result
.end() );
87 std::vector
<size_t> BipartiteGraph::delta2( size_t n2
, bool include
) const {
88 // store all second-order neighbors
89 std::vector
<size_t> result
;
90 foreach( const Neighbor
&n1
, nb2(n2
) )
91 foreach( const Neighbor
&m2
, nb1(n1
) )
92 if( include
|| (m2
!= n2
) )
93 result
.push_back( m2
);
95 std::vector
<size_t>::iterator it
= std::unique( result
.begin(), result
.end() );
96 result
.erase( it
, result
.end() );
101 bool BipartiteGraph::isConnected() const {
102 // TODO: use BGL, like:
103 // std::vector<int> component( num_vertices( g ) );
104 // int num_comp = connected_components( g, make_iterator_property_map(component.begin(), get(vertex_index, g)) );
108 std::vector
<bool> incomponent1( nr1(), false );
109 std::vector
<bool> incomponent2( nr2(), false );
111 incomponent1
[0] = true;
112 bool found_new_nodes
;
114 found_new_nodes
= false;
116 // For all nodes of type 2, check if they are connected with the (growing) component
117 for( size_t n2
= 0; n2
< nr2(); n2
++ )
118 if( !incomponent2
[n2
] ) {
119 foreach( const Neighbor
&n1
, nb2(n2
) ) {
120 if( incomponent1
[n1
] ) {
121 found_new_nodes
= true;
122 incomponent2
[n2
] = true;
128 // For all nodes of type 1, check if they are connected with the (growing) component
129 for( size_t n1
= 0; n1
< nr1(); n1
++ )
130 if( !incomponent1
[n1
] ) {
131 foreach( const Neighbor
&n2
, nb1(n1
) ) {
132 if( incomponent2
[n2
] ) {
133 found_new_nodes
= true;
134 incomponent1
[n1
] = true;
139 } while( found_new_nodes
);
141 // Check if there are remaining nodes (not in the component)
142 bool all_connected
= true;
143 for( size_t n1
= 0; (n1
< nr1()) && all_connected
; n1
++ )
144 if( !incomponent1
[n1
] )
145 all_connected
= false;
146 for( size_t n2
= 0; (n2
< nr2()) && all_connected
; n2
++ )
147 if( !incomponent2
[n2
] )
148 all_connected
= false;
150 return all_connected
;
155 bool BipartiteGraph::isTree() const {
157 vector
<levelType
> levels
;
159 bool foundCycle
= false;
163 if( nr1() == 0 || nr2() == 0 )
168 newLevel
.ind1
.clear();
169 newLevel
.ind2
.clear();
170 if( levels
.size() == 0 ) {
173 newLevel
.ind1
= vector
<size_t>( 1, n1
);
174 // add all neighbors of n1 to ind2
175 newLevel
.ind2
.reserve( nb1(n1
).size() );
176 foreach( const Neighbor
&n2
, nb1(n1
) )
177 newLevel
.ind2
.push_back( n2
);
179 const levelType
&prevLevel
= levels
.back();
180 // build newLevel.ind1
181 foreach( size_t n2
, prevLevel
.ind2
) { // for all n2 in the previous level
182 foreach( const Neighbor
&n1
, nb2(n2
) ) { // for all neighbors n1 of n2
183 if( find( prevLevel
.ind1
.begin(), prevLevel
.ind1
.end(), n1
) == prevLevel
.ind1
.end() ) { // n1 not in previous level
184 if( find( newLevel
.ind1
.begin(), newLevel
.ind1
.end(), n1
) != newLevel
.ind1
.end() )
185 foundCycle
= true; // n1 already in new level: we found a cycle
187 newLevel
.ind1
.push_back( n1
); // add n1 to new level
195 // build newLevel.ind2
196 foreach( size_t n1
, newLevel
.ind1
) { // for all n1 in this level
197 foreach( const Neighbor
&n2
, nb1(n1
) ) { // for all neighbors n2 of n1
198 if( find( prevLevel
.ind2
.begin(), prevLevel
.ind2
.end(), n2
) == prevLevel
.ind2
.end() ) { // n2 not in previous level
199 if( find( newLevel
.ind2
.begin(), newLevel
.ind2
.end(), n2
) != newLevel
.ind2
.end() )
200 foundCycle
= true; // n2 already in new level: we found a cycle
202 newLevel
.ind2
.push_back( n2
); // add n2 to new level
211 levels
.push_back( newLevel
);
212 nr_1
+= newLevel
.ind1
.size();
213 nr_2
+= newLevel
.ind2
.size();
214 } while( ((newLevel
.ind1
.size() != 0) || (newLevel
.ind2
.size() != 0)) && !foundCycle
);
215 if( nr_1
== nr1() && nr_2
== nr2() && !foundCycle
)
223 void BipartiteGraph::printDot( std::ostream
& os
) const {
225 os
<< "graph G {" << endl
;
226 os
<< "node[shape=circle,width=0.4,fixedsize=true];" << endl
;
227 for( size_t n1
= 0; n1
< nr1(); n1
++ )
228 os
<< "\tx" << n1
<< ";" << endl
;
229 os
<< "node[shape=box,width=0.3,height=0.3,fixedsize=true];" << endl
;
230 for( size_t n2
= 0; n2
< nr2(); n2
++ )
231 os
<< "\ty" << n2
<< ";" << endl
;
232 for( size_t n1
= 0; n1
< nr1(); n1
++ )
233 foreach( const Neighbor
&n2
, nb1(n1
) )
234 os
<< "\tx" << n1
<< " -- y" << n2
<< ";" << endl
;
239 void BipartiteGraph::check() const {
242 for( size_t n1
= 0; n1
< N1
; n1
++ ) {
244 foreach( const Neighbor
&n2
, nb1(n1
) ) {
245 assert( n2
.iter
== iter
);
246 assert( n2
.node
< N2
);
247 assert( n2
.dual
< nb2(n2
).size() );
248 assert( nb2(n2
, n2
.dual
) == n1
);
252 for( size_t n2
= 0; n2
< N2
; n2
++ ) {
254 foreach( const Neighbor
&n1
, nb2(n2
) ) {
255 assert( n1
.iter
== iter
);
256 assert( n1
.node
< N1
);
257 assert( n1
.dual
< nb1(n1
).size() );
258 assert( nb1(n1
, n1
.dual
) == n2
);
265 } // end of namespace dai