1 /* Copyright (C) 2006-2008 Joris Mooij [joris dot mooij at tuebingen dot mpg dot de]
2 Radboud University Nijmegen, The Netherlands /
3 Max Planck Institute for Biological Cybernetics, Germany
5 This file is part of libDAI.
7 libDAI is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 libDAI is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with libDAI; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <dai/bipgraph.h>
32 void BipartiteGraph::erase1( size_t n1
) {
34 // Erase neighbor entry of node n1
35 _nb1
.erase( _nb1
.begin() + n1
);
36 // Adjust neighbor entries of nodes of type 2
37 for( size_t n2
= 0; n2
< nr2(); n2
++ ) {
38 for( size_t iter
= 0; iter
< nb2(n2
).size(); ) {
39 Neighbor
&m1
= nb2(n2
, iter
);
41 // delete this entry, because it points to the deleted node
42 nb2(n2
).erase( nb2(n2
).begin() + iter
);
43 } else if( m1
.node
> n1
) {
44 // update this entry and the corresponding dual of the neighboring node of type 1
47 nb1( m1
.node
, m1
.dual
).dual
= iter
;
58 void BipartiteGraph::erase2( size_t n2
) {
60 // Erase neighbor entry of node n2
61 _nb2
.erase( _nb2
.begin() + n2
);
62 // Adjust neighbor entries of nodes of type 1
63 for( size_t n1
= 0; n1
< nr1(); n1
++ ) {
64 for( size_t iter
= 0; iter
< nb1(n1
).size(); ) {
65 Neighbor
&m2
= nb1(n1
, iter
);
67 // delete this entry, because it points to the deleted node
68 nb1(n1
).erase( nb1(n1
).begin() + iter
);
69 } else if( m2
.node
> n2
) {
70 // update this entry and the corresponding dual of the neighboring node of type 2
73 nb2( m2
.node
, m2
.dual
).dual
= iter
;
84 std::vector
<size_t> BipartiteGraph::delta1( size_t n1
, bool include
) const {
85 // get all second-order neighbors
86 std::vector
<size_t> result
;
87 foreach( const Neighbor
&n2
, nb1(n1
) )
88 foreach( const Neighbor
&m1
, nb2(n2
) )
89 if( include
|| (m1
!= n1
) )
90 result
.push_back( m1
);
92 std::vector
<size_t>::iterator it
= std::unique( result
.begin(), result
.end() );
93 result
.erase( it
, result
.end() );
98 std::vector
<size_t> BipartiteGraph::delta2( size_t n2
, bool include
) const {
99 // store all second-order neighbors
100 std::vector
<size_t> result
;
101 foreach( const Neighbor
&n1
, nb2(n2
) )
102 foreach( const Neighbor
&m2
, nb1(n1
) )
103 if( include
|| (m2
!= n2
) )
104 result
.push_back( m2
);
106 std::vector
<size_t>::iterator it
= std::unique( result
.begin(), result
.end() );
107 result
.erase( it
, result
.end() );
112 bool BipartiteGraph::isConnected() const {
116 std::vector
<bool> incomponent1( nr1(), false );
117 std::vector
<bool> incomponent2( nr2(), false );
119 incomponent1
[0] = true;
120 bool found_new_nodes
;
122 found_new_nodes
= false;
124 // For all nodes of type 2, check if they are connected with the (growing) component
125 for( size_t n2
= 0; n2
< nr2(); n2
++ )
126 if( !incomponent2
[n2
] ) {
127 foreach( const Neighbor
&n1
, nb2(n2
) ) {
128 if( incomponent1
[n1
] ) {
129 found_new_nodes
= true;
130 incomponent2
[n2
] = true;
136 // For all nodes of type 1, check if they are connected with the (growing) component
137 for( size_t n1
= 0; n1
< nr1(); n1
++ )
138 if( !incomponent1
[n1
] ) {
139 foreach( const Neighbor
&n2
, nb1(n1
) ) {
140 if( incomponent2
[n2
] ) {
141 found_new_nodes
= true;
142 incomponent1
[n1
] = true;
147 } while( found_new_nodes
);
149 // Check if there are remaining nodes (not in the component)
150 bool all_connected
= true;
151 for( size_t n1
= 0; (n1
< nr1()) && all_connected
; n1
++ )
152 if( !incomponent1
[n1
] )
153 all_connected
= false;
154 for( size_t n2
= 0; (n2
< nr2()) && all_connected
; n2
++ )
155 if( !incomponent2
[n2
] )
156 all_connected
= false;
158 return all_connected
;
163 bool BipartiteGraph::isTree() const {
165 vector
<levelType
> levels
;
167 bool foundCycle
= false;
171 if( nr1() == 0 || nr2() == 0 )
176 newLevel
.ind1
.clear();
177 newLevel
.ind2
.clear();
178 if( levels
.size() == 0 ) {
181 newLevel
.ind1
= vector
<size_t>( 1, n1
);
182 // add all neighbors of n1 to ind2
183 newLevel
.ind2
.reserve( nb1(n1
).size() );
184 foreach( const Neighbor
&n2
, nb1(n1
) )
185 newLevel
.ind2
.push_back( n2
);
187 const levelType
&prevLevel
= levels
.back();
188 // build newLevel.ind1
189 foreach( size_t n2
, prevLevel
.ind2
) { // for all n2 in the previous level
190 foreach( const Neighbor
&n1
, nb2(n2
) ) { // for all neighbors n1 of n2
191 if( find( prevLevel
.ind1
.begin(), prevLevel
.ind1
.end(), n1
) == prevLevel
.ind1
.end() ) { // n1 not in previous level
192 if( find( newLevel
.ind1
.begin(), newLevel
.ind1
.end(), n1
) != newLevel
.ind1
.end() )
193 foundCycle
= true; // n1 already in new level: we found a cycle
195 newLevel
.ind1
.push_back( n1
); // add n1 to new level
203 // build newLevel.ind2
204 foreach( size_t n1
, newLevel
.ind1
) { // for all n1 in this level
205 foreach( const Neighbor
&n2
, nb1(n1
) ) { // for all neighbors n2 of n1
206 if( find( prevLevel
.ind2
.begin(), prevLevel
.ind2
.end(), n2
) == prevLevel
.ind2
.end() ) { // n2 not in previous level
207 if( find( newLevel
.ind2
.begin(), newLevel
.ind2
.end(), n2
) != newLevel
.ind2
.end() )
208 foundCycle
= true; // n2 already in new level: we found a cycle
210 newLevel
.ind2
.push_back( n2
); // add n2 to new level
219 levels
.push_back( newLevel
);
220 nr_1
+= newLevel
.ind1
.size();
221 nr_2
+= newLevel
.ind2
.size();
222 } while( ((newLevel
.ind1
.size() != 0) || (newLevel
.ind2
.size() != 0)) && !foundCycle
);
223 if( nr_1
== nr1() && nr_2
== nr2() && !foundCycle
)
231 void BipartiteGraph::printDot( std::ostream
& os
) const {
233 os
<< "graph G {" << endl
;
234 os
<< "node[shape=circle,width=0.4,fixedsize=true];" << endl
;
235 for( size_t n1
= 0; n1
< nr1(); n1
++ )
236 os
<< "\tx" << n1
<< ";" << endl
;
237 os
<< "node[shape=box,width=0.3,height=0.3,fixedsize=true];" << endl
;
238 for( size_t n2
= 0; n2
< nr2(); n2
++ )
239 os
<< "\ty" << n2
<< ";" << endl
;
240 for( size_t n1
= 0; n1
< nr1(); n1
++ )
241 foreach( const Neighbor
&n2
, nb1(n1
) )
242 os
<< "\tx" << n1
<< " -- y" << n2
<< ";" << endl
;
247 void BipartiteGraph::check() const {
250 for( size_t n1
= 0; n1
< N1
; n1
++ ) {
252 foreach( const Neighbor
&n2
, nb1(n1
) ) {
253 assert( n2
.iter
== iter
);
254 assert( n2
.node
< N2
);
255 assert( n2
.dual
< nb2(n2
).size() );
256 assert( nb2(n2
, n2
.dual
) == n1
);
260 for( size_t n2
= 0; n2
< N2
; n2
++ ) {
262 foreach( const Neighbor
&n1
, nb2(n2
) ) {
263 assert( n1
.iter
== iter
);
264 assert( n1
.node
< N1
);
265 assert( n1
.dual
< nb1(n1
).size() );
266 assert( nb1(n1
, n1
.dual
) == n2
);
273 } // end of namespace dai