1 /* Copyright (C) 2006-2008 Joris Mooij [j dot mooij at science dot ru dot nl]
2 Radboud University Nijmegen, The Netherlands
4 This file is part of libDAI.
6 libDAI is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libDAI 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 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libDAI; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <dai/bipgraph.h>
31 void BipartiteGraph::erase1( size_t n1
) {
33 // Erase neighbor entry of node n1
34 _nb1
.erase( _nb1
.begin() + n1
);
35 // Adjust neighbor entries of nodes of type 2
36 for( size_t n2
= 0; n2
< nr2(); n2
++ ) {
37 for( size_t iter
= 0; iter
< nb2(n2
).size(); ) {
38 Neighbor
&m1
= nb2(n2
, iter
);
40 // delete this entry, because it points to the deleted node
41 nb2(n2
).erase( nb2(n2
).begin() + iter
);
42 } else if( m1
.node
> n1
) {
43 // update this entry and the corresponding dual of the neighboring node of type 1
46 nb1( m1
.node
, m1
.dual
).dual
= iter
;
57 void BipartiteGraph::erase2( size_t n2
) {
59 // Erase neighbor entry of node n2
60 _nb2
.erase( _nb2
.begin() + n2
);
61 // Adjust neighbor entries of nodes of type 1
62 for( size_t n1
= 0; n1
< nr1(); n1
++ ) {
63 for( size_t iter
= 0; iter
< nb1(n1
).size(); ) {
64 Neighbor
&m2
= nb1(n1
, iter
);
66 // delete this entry, because it points to the deleted node
67 nb1(n1
).erase( nb1(n1
).begin() + iter
);
68 } else if( m2
.node
> n2
) {
69 // update this entry and the corresponding dual of the neighboring node of type 2
72 nb2( m2
.node
, m2
.dual
).dual
= iter
;
83 std::vector
<size_t> BipartiteGraph::delta1( size_t n1
, bool include
) const {
84 // get all second-order neighbors
85 std::vector
<size_t> result
;
86 foreach( const Neighbor
&n2
, nb1(n1
) )
87 foreach( const Neighbor
&m1
, nb2(n2
) )
88 if( include
|| (m1
!= n1
) )
89 result
.push_back( m1
);
91 std::vector
<size_t>::iterator it
= std::unique( result
.begin(), result
.end() );
92 result
.erase( it
, result
.end() );
97 std::vector
<size_t> BipartiteGraph::delta2( size_t n2
, bool include
) const {
98 // store all second-order neighbors
99 std::vector
<size_t> result
;
100 foreach( const Neighbor
&n1
, nb2(n2
) )
101 foreach( const Neighbor
&m2
, nb1(n1
) )
102 if( include
|| (m2
!= n2
) )
103 result
.push_back( m2
);
105 std::vector
<size_t>::iterator it
= std::unique( result
.begin(), result
.end() );
106 result
.erase( it
, result
.end() );
111 bool BipartiteGraph::isConnected() const {
115 std::vector
<bool> incomponent1( nr1(), false );
116 std::vector
<bool> incomponent2( nr2(), false );
118 incomponent1
[0] = true;
119 bool found_new_nodes
;
121 found_new_nodes
= false;
123 // For all nodes of type 2, check if they are connected with the (growing) component
124 for( size_t n2
= 0; n2
< nr2(); n2
++ )
125 if( !incomponent2
[n2
] ) {
126 foreach( const Neighbor
&n1
, nb2(n2
) ) {
127 if( incomponent1
[n1
] ) {
128 found_new_nodes
= true;
129 incomponent2
[n2
] = true;
135 // For all nodes of type 1, check if they are connected with the (growing) component
136 for( size_t n1
= 0; n1
< nr1(); n1
++ )
137 if( !incomponent1
[n1
] ) {
138 foreach( const Neighbor
&n2
, nb1(n1
) ) {
139 if( incomponent2
[n2
] ) {
140 found_new_nodes
= true;
141 incomponent1
[n1
] = true;
146 } while( found_new_nodes
);
148 // Check if there are remaining nodes (not in the component)
149 bool all_connected
= true;
150 for( size_t n1
= 0; (n1
< nr1()) && all_connected
; n1
++ )
151 if( !incomponent1
[n1
] )
152 all_connected
= false;
153 for( size_t n2
= 0; (n2
< nr2()) && all_connected
; n2
++ )
154 if( !incomponent2
[n2
] )
155 all_connected
= false;
157 return all_connected
;
162 bool BipartiteGraph::isTree() const {
164 vector
<levelType
> levels
;
166 bool foundCycle
= false;
170 if( nr1() == 0 || nr2() == 0 )
175 newLevel
.ind1
.clear();
176 newLevel
.ind2
.clear();
177 if( levels
.size() == 0 ) {
180 newLevel
.ind1
= vector
<size_t>( 1, n1
);
181 // add all neighbors of n1 to ind2
182 newLevel
.ind2
.reserve( nb1(n1
).size() );
183 foreach( const Neighbor
&n2
, nb1(n1
) )
184 newLevel
.ind2
.push_back( n2
);
186 const levelType
&prevLevel
= levels
.back();
187 // build newLevel.ind1
188 foreach( size_t n2
, prevLevel
.ind2
) { // for all n2 in the previous level
189 foreach( const Neighbor
&n1
, nb2(n2
) ) { // for all neighbors n1 of n2
190 if( find( prevLevel
.ind1
.begin(), prevLevel
.ind1
.end(), n1
) == prevLevel
.ind1
.end() ) { // n1 not in previous level
191 if( find( newLevel
.ind1
.begin(), newLevel
.ind1
.end(), n1
) != newLevel
.ind1
.end() )
192 foundCycle
= true; // n1 already in new level: we found a cycle
194 newLevel
.ind1
.push_back( n1
); // add n1 to new level
202 // build newLevel.ind2
203 foreach( size_t n1
, newLevel
.ind1
) { // for all n1 in this level
204 foreach( const Neighbor
&n2
, nb1(n1
) ) { // for all neighbors n2 of n1
205 if( find( prevLevel
.ind2
.begin(), prevLevel
.ind2
.end(), n2
) == prevLevel
.ind2
.end() ) { // n2 not in previous level
206 if( find( newLevel
.ind2
.begin(), newLevel
.ind2
.end(), n2
) != newLevel
.ind2
.end() )
207 foundCycle
= true; // n2 already in new level: we found a cycle
209 newLevel
.ind2
.push_back( n2
); // add n2 to new level
218 levels
.push_back( newLevel
);
219 nr_1
+= newLevel
.ind1
.size();
220 nr_2
+= newLevel
.ind2
.size();
221 } while( ((newLevel
.ind1
.size() != 0) || (newLevel
.ind2
.size() != 0)) && !foundCycle
);
222 if( nr_1
== nr1() && nr_2
== nr2() && !foundCycle
)
230 void BipartiteGraph::display( std::ostream
& os
) const {
232 os
<< "graph G {" << endl
;
233 os
<< "node[shape=circle,width=0.4,fixedsize=true];" << endl
;
234 for( size_t n1
= 0; n1
< nr1(); n1
++ )
235 os
<< "\tx" << n1
<< ";" << endl
;
236 os
<< "node[shape=box,width=0.3,height=0.3,fixedsize=true];" << endl
;
237 for( size_t n2
= 0; n2
< nr2(); n2
++ )
238 os
<< "\ty" << n2
<< ";" << endl
;
239 for( size_t n1
= 0; n1
< nr1(); n1
++ )
240 foreach( const Neighbor
&n2
, nb1(n1
) )
241 os
<< "\tx" << n1
<< " -- y" << n2
<< ";" << endl
;
246 void BipartiteGraph::check() const {
249 for( size_t n1
= 0; n1
< N1
; n1
++ ) {
251 foreach( const Neighbor
&n2
, nb1(n1
) ) {
252 assert( n2
.iter
== iter
);
253 assert( n2
.node
< N2
);
254 assert( n2
.dual
< nb2(n2
).size() );
255 assert( nb2(n2
, n2
.dual
) == n1
);
259 for( size_t n2
= 0; n2
< N2
; n2
++ ) {
261 foreach( const Neighbor
&n1
, nb2(n2
) ) {
262 assert( n1
.iter
== iter
);
263 assert( n1
.node
< N1
);
264 assert( n1
.dual
< nb1(n1
).size() );
265 assert( nb1(n1
, n1
.dual
) == n2
);
272 } // end of namespace dai