Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
fm_partition.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file fm_partition.cpp
1 /* This software is distributed under the GNU Lesser General Public License */
2 //==========================================================================
3 //
4 // fm_partition.cpp
5 //
6 //==========================================================================
7 // $Id: fm_partition.cpp,v 1.8 2001/11/07 13:58:10 pick Exp $
8 
9 #include <GTL/debug.h>
10 #include <GTL/fm_partition.h>
11 
12 #include <iostream>
13 
14 #include <cstdlib>
15 #include <cassert>
16 #include <cmath>
17 #include <ctime>
18 
19 #ifdef __GTL_MSVCC
20 # ifdef _DEBUG
21 # ifndef SEARCH_MEMORY_LEAKS_ENABLED
22 # error SEARCH NOT ENABLED
23 # endif
24 # define new DEBUG_NEW
25 # undef THIS_FILE
26  static char THIS_FILE[] = __FILE__;
27 # endif // _DEBUG
28 #endif // __GTL_MSVCC
29 
31 
32 
35 
36 
40 
41 
43 {
44  set_vars_executed = false;
46  enable_nodesAB_storing = false;
47 }
48 
49 
51 {
52 }
53 
54 
56  const node_map<int>& node_weight, const edge_map<int>& edge_weight)
57 {
58  this->node_weight = node_weight;
59  this->edge_weight = edge_weight;
60  set_vars_executed = true;
61  provided_initial_part = false;
62  this->fixed.init(G, UNFIXED);
63  provided_fix = false;
64  side.init(G);
65 }
66 
67 
69  const node_map<int>& node_weight, const edge_map<int>& edge_weight,
70  const node_map<side_type>& init_side)
71 {
72  this->node_weight = node_weight;
73  this->edge_weight = edge_weight;
74  this->side = init_side;
75  set_vars_executed = true;
76  provided_initial_part = true;
77  this->fixed.init(G, UNFIXED);
78  provided_fix = false;
79 }
80 
81 
83  const node_map<int>& node_weight, const edge_map<int>& edge_weight,
84  const node_map<fix_type>& fixed)
85 {
86  this->node_weight = node_weight;
87  this->edge_weight = edge_weight;
88  set_vars_executed = true;
89  provided_initial_part = false;
90  this->fixed = fixed;
91  provided_fix = true;
92  side.init(G);
93 }
94 
95 
97  const node_map<int>& node_weight, const edge_map<int>& edge_weight,
98  const node_map<side_type>& init_side,
99  const node_map<fix_type>& fixed)
100 {
101  this->node_weight = node_weight;
102  this->edge_weight = edge_weight;
103  this->side = init_side;
104  set_vars_executed = true;
105  provided_initial_part = true;
106  this->fixed = fixed;
107  provided_fix = true;
108 }
109 
110 
111 void fm_partition::store_cut_edges(const bool set)
112 {
114 }
115 
116 
117 void fm_partition::store_nodesAB(const bool set)
118 {
120 }
121 
122 
124 {
125  if ((!set_vars_executed) || (!G.is_undirected()))
126  {
127  return GTL_ERROR;
128  }
129 
130  graph::edge_iterator edge_it = G.edges_begin();
131  graph::edge_iterator edges_end = G.edges_end();
132  while (edge_it != edges_end)
133  {
134  if (edge_weight[*edge_it] < 0)
135  {
136  return GTL_ERROR;
137  }
138  ++edge_it;
139  }
140  graph::node_iterator node_it = G.nodes_begin();
141  graph::node_iterator nodes_end = G.nodes_end();
142  while (node_it != nodes_end)
143  {
144  if (node_weight[*node_it] < 0)
145  {
146  return GTL_ERROR;
147  }
148  ++node_it;
149  }
150 
151  return GTL_OK;
152 }
153 
154 
156 {
157  init_variables(G);
159  {
160  divide_up(G);
161  }
163  {
165  }
166 
167  hide_self_loops(G);
169 
170  pass_manager(G);
171 
173  {
175  }
177  {
178  compute_nodesAB(G);
179  }
180  G.restore_graph();
181 
182  return GTL_OK;
183 }
184 
185 
187 {
188  return cur_cutsize;
189 }
190 
191 
193 {
194  return no_passes;
195 }
196 
197 
199 {
200  return side[n];
201 }
202 
203 
205 {
206  return side[n];
207 }
208 
209 
211 {
212  int nwA = 0;
213  graph::node_iterator node_it = G.nodes_begin();
214  graph::node_iterator nodes_end = G.nodes_end();
215  while (node_it != nodes_end)
216  {
217  if (side[*node_it] == A)
218  {
219  nwA += node_weight[*node_it];
220  }
221  ++node_it;
222  }
223  return nwA;
224 }
225 
226 
228 {
229  int nwB = 0;
230  graph::node_iterator node_it = G.nodes_begin();
231  graph::node_iterator nodes_end = G.nodes_end();
232  while (node_it != nodes_end)
233  {
234  if (side[*node_it] == B)
235  {
236  nwB += node_weight[*node_it];
237  }
238  ++node_it;
239  }
240  return nwB;
241 }
242 
243 
245 {
246  return cut_edges.begin();
247 }
248 
249 
251 {
252  return cut_edges.end();
253 }
254 
255 
258 {
259  return nodesA.begin();
260 }
261 
262 
265 {
266  return nodesA.end();
267 }
268 
269 
272 {
273  return nodesB.begin();
274 }
275 
276 
279 {
280  return nodesB.end();
281 }
282 
283 
285 {
286  set_vars_executed = false;
287  cut_edges.clear();
288  nodesA.clear();
289  nodesB.clear();
290 }
291 
292 
294 {
295  graph::node_iterator node_it = G.nodes_begin();
296  graph::node_iterator nodes_end = G.nodes_end();
297  while (node_it != nodes_end)
298  {
299  if (fixed[*node_it] == FIXA)
300  {
301  side[*node_it] = A;
302  }
303  else if (fixed[*node_it] == FIXB)
304  {
305  side[*node_it] = B;
306  }
307  ++node_it;
308  }
309 }
310 
311 
313 {
314  graph::edge_iterator temp_it;
315  graph::edge_iterator edge_it = G.edges_begin();
316  graph::edge_iterator edges_end = G.edges_end();
317  while (edge_it != edges_end)
318  {
319  if ((*edge_it).source() == (*edge_it).target())
320  {
321  temp_it = edge_it;
322  ++edge_it;
323  G.hide_edge(*temp_it);
324  }
325  else
326  {
327  ++edge_it;
328  }
329  }
330 }
331 
332 
334 {
335  bool first_edge_found = true;
336  bool first_node_found = true;
337  max_edge_weight = 0;
338  max_node_weight = 0;
339  graph::edge_iterator edge_it = G.edges_begin();
340  graph::edge_iterator edges_end = G.edges_end();
341  while (edge_it != edges_end)
342  {
343  if (first_edge_found)
344  {
345  max_edge_weight = edge_weight[*edge_it];
346  first_edge_found = false;
347  }
348  else if (edge_weight[*edge_it] > max_edge_weight)
349  {
350  max_edge_weight = edge_weight[*edge_it];
351  }
352  ++edge_it;
353  }
354  graph::node_iterator node_it = G.nodes_begin();
355  graph::node_iterator nodes_end = G.nodes_end();
356  total_node_weight = 0;
357  while (node_it != nodes_end)
358  {
359  total_node_weight += node_weight[*node_it];
360  if (first_node_found)
361  {
362  max_node_weight = node_weight[*node_it];
363  first_node_found = false;
364  }
365  else if (node_weight[*node_it] > max_node_weight)
366  {
367  max_node_weight = node_weight[*node_it];
368  }
369  ++node_it;
370  }
371 }
372 
373 
375 {
376  int i = 0; // counter
377  int no_nodes = G.number_of_nodes();
380 
381  graph::node_iterator node_it = G.nodes_begin();
382  graph::node_iterator nodes_end = G.nodes_end();
383  vector<graph::node_iterator> node_vector(G.number_of_nodes());
384  while (node_it != nodes_end)
385  {
386  node_vector[i] = node_it;
387  if (fixed[*node_it] == FIXA)
388  {
389  side[*node_it] = A;
390  node_weight_on_sideA += node_weight[*node_it];
391  }
392  else if (fixed[*node_it] == FIXB)
393  {
394  side[*node_it] = B;
395  node_weight_on_sideB += node_weight[*node_it];
396  }
397  else // fixed[*node_it] == UNFIXED
398  {
399  node_weight_on_sideB += node_weight[*node_it];
400  side[*node_it] = B;
401  }
402  ++i;
403  ++node_it;
404  }
405  shuffle_vector(no_nodes, node_vector);
406 
407  // compute best balance
409  int best_pos = -1;
410  for (i = 0; i < no_nodes; i++)
411  {
412  if (fixed[*node_vector[i]] == UNFIXED)
413  {
414  node_weight_on_sideA += node_weight[*node_vector[i]];
415  node_weight_on_sideB -= node_weight[*node_vector[i]];
416  if (node_weight_on_sideA * node_weight_on_sideB > best_bal)
417  {
419  best_pos = i;
420  }
421  }
422  }
423 
424  // create partition with best balance
425  for (i = 0; i <= best_pos; i++)
426  {
427  if (fixed[*node_vector[i]] == UNFIXED)
428  {
429  side[*node_vector[i]] = A;
430  }
431  }
432 }
433 
434 
435 void fm_partition::shuffle_vector(const int vector_size,
436  vector<graph::node_iterator>& node_vector)
437 {
438  srand((unsigned)time(NULL));
439  rand(); // necessary, otherwise the next rand() returns always 0 ?-)
440  for (int i = 1; i <= vector_size; i++)
441  {
442  int pos_1 = (int)floor((((double)rand() / (double)RAND_MAX) *
443  (double)(vector_size - 1)) + 0.5);
444  int pos_2 = (int)floor((((double)rand() / (double)RAND_MAX) *
445  (double)(vector_size - 1)) + 0.5);
446  graph::node_iterator temp_it;
447  temp_it = node_vector[pos_1];
448  node_vector[pos_1] = node_vector[pos_2];
449  node_vector[pos_2] = temp_it;
450  }
451 }
452 
453 
455 {
456  max_vertex_degree = 0;
457  graph::node_iterator node_it = G.nodes_begin();
458  graph::node_iterator nodes_end = G.nodes_end();
459  while (node_it != nodes_end)
460  {
461  if (max_vertex_degree < (*node_it).degree())
462  {
463  max_vertex_degree = (*node_it).degree();
464  }
465  ++node_it;
466  }
467 }
468 
469 
471 {
472  // final pass which doesn't improve cur_cutsize is not counted
473  no_passes = -1;
474  int best_cutsize = -1; // = -1 to avoid warning
475  node_map<side_type> best_side(G);
476  bool improved_cutsize;
477 
478  do
479  {
481  if (no_passes == -1)
482  {
483  best_cutsize = cur_cutsize;
484  copy_side_node_map(G, best_side, side);
485  }
486  move_manager(G);
487  clean_pass(G);
488  improved_cutsize = false;
489  if (best_cutsize > cur_cutsize)
490  {
491  best_cutsize = cur_cutsize;
492  copy_side_node_map(G, best_side, side);
493  improved_cutsize = true;
494  }
495  ++no_passes;
496  }
497  while (improved_cutsize);
498  cur_cutsize = best_cutsize;
499  copy_side_node_map(G, side, best_side);
500 }
501 
502 
505 {
506  graph::node_iterator node_it = G.nodes_begin();
507  graph::node_iterator nodes_end = G.nodes_end();
508  while (node_it != nodes_end)
509  {
510  dest[*node_it] = source[*node_it];
511  ++node_it;
512  }
513 }
514 
515 
517 {
518  aside.init(G);
519  bside.init(G);
520  unlockedA.init(G);
521  unlockedB.init(G);
522  cur_cutsize = 0;
523  graph::edge_iterator edge_it = G.edges_begin();
524  graph::edge_iterator edges_end = G.edges_end();
525  while (edge_it != edges_end)
526  {
527  if ((side[(*edge_it).source()] == A) &&
528  (side[(*edge_it).target()] == A))
529  {
530  aside[*edge_it] = 2;
531  bside[*edge_it] = 0;
532  unlockedA[*edge_it].push_back((*edge_it).source());
533  unlockedA[*edge_it].push_back((*edge_it).target());
534  }
535  else if ((side[(*edge_it).source()] == B) &&
536  (side[(*edge_it).target()] == B))
537  {
538  aside[*edge_it] = 0;
539  bside[*edge_it] = 2;
540  unlockedB[*edge_it].push_back((*edge_it).source());
541  unlockedB[*edge_it].push_back((*edge_it).target());
542  }
543  else if ((side[(*edge_it).source()] == A) &&
544  (side[(*edge_it).target()] == B))
545  {
546  aside[*edge_it] = 1;
547  bside[*edge_it] = 1;
548  cur_cutsize += edge_weight[*edge_it];
549  unlockedA[*edge_it].push_back((*edge_it).source());
550  unlockedB[*edge_it].push_back((*edge_it).target());
551  }
552  else if ((side[(*edge_it).source()] == B) &&
553  (side[(*edge_it).target()] == A))
554  {
555  aside[*edge_it] = 1;
556  bside[*edge_it] = 1;
557  cur_cutsize += edge_weight[*edge_it];
558  unlockedA[*edge_it].push_back((*edge_it).target());
559  unlockedB[*edge_it].push_back((*edge_it).source());
560  }
561  ++edge_it;
562  }
563 
564  bucketA.resize(2 * max_vertex_degree * max_edge_weight + 1);
565  bucketB.resize(2 * max_vertex_degree * max_edge_weight + 1);
566 
568 }
569 
570 
572 {
575  bucketA_empty = true;
576  bucketB_empty = true;
577  bool first_A_node = true;
578  bool first_B_node = true;
579  int index;
580  // position_in_bucket.init(G);
581  gain_value.init(G);
582 
583  graph::node_iterator node_it = G.nodes_begin();
584  graph::node_iterator nodes_end = G.nodes_end();
585  while (node_it != nodes_end)
586  {
587  if (side[*node_it] == A)
588  {
589  node_weight_on_sideA += node_weight[*node_it];
590  gain_value[*node_it] = inital_gain_of_node_on_sideA(*node_it);
591  if (fixed[*node_it] == UNFIXED)
592  {
593  if (first_A_node)
594  {
595  bucketA_empty = false;
596  max_gainA = gain_value[*node_it];
597  first_A_node = false;
598  }
599  else
600  {
601  if (max_gainA < gain_value[*node_it])
602  {
603  max_gainA = gain_value[*node_it];
604  }
605  }
606  index = range_up(gain_value[*node_it]);
607  position_in_bucket[*node_it] = bucketA[index].insert(
608  bucketA[index].end(), *node_it);
609  }
610  }
611  else // side[*node_it] == B
612  {
613  node_weight_on_sideB += node_weight[*node_it];
614  gain_value[*node_it] = inital_gain_of_node_on_sideB(*node_it);
615  if (fixed[*node_it] == UNFIXED)
616  {
617  if (first_B_node)
618  {
619  bucketB_empty = false;
620  max_gainB = gain_value[*node_it];
621  first_B_node = false;
622  }
623  else
624  {
625  if (max_gainB < gain_value[*node_it])
626  {
627  max_gainB = gain_value[*node_it];
628  }
629  }
630  index = range_up(gain_value[*node_it]);
631  position_in_bucket[*node_it] = bucketB[index].insert(
632  bucketB[index].end(), *node_it);
633  }
634  }
635  ++node_it;
636  }
637 }
638 
639 
641 {
642  int node_gain = 0;
643  node::adj_edges_iterator adj_edge_it = cur_node.adj_edges_begin();
644  node::adj_edges_iterator adj_edges_end = cur_node.adj_edges_end();
645  while (adj_edge_it != adj_edges_end)
646  {
647  if (aside[*adj_edge_it] == 1)
648  {
649  node_gain += edge_weight[*adj_edge_it];
650  }
651  if (bside[*adj_edge_it] == 0)
652  {
653  node_gain -= edge_weight[*adj_edge_it];
654  }
655  ++adj_edge_it;
656  }
657  return node_gain;
658 }
659 
660 
662 {
663  int node_gain = 0;
664  node::adj_edges_iterator adj_edge_it = cur_node.adj_edges_begin();
665  node::adj_edges_iterator adj_edges_end = cur_node.adj_edges_end();
666  while (adj_edge_it != adj_edges_end)
667  {
668  if (bside[*adj_edge_it] == 1)
669  {
670  node_gain += edge_weight[*adj_edge_it];
671  }
672  if (aside[*adj_edge_it] == 0)
673  {
674  node_gain -= edge_weight[*adj_edge_it];
675  }
676  ++adj_edge_it;
677  }
678  return node_gain;
679 }
680 
681 
683 {
684  int step_number = 0;
685  int best_tentative_move = 0;
687  vector<node> tentative_moves(G.number_of_nodes() + 1);
688  vector<int> tentative_cutsize(G.number_of_nodes() + 1);
689  node moved_node;
690  tentative_cutsize[0] = cur_cutsize;
691 
692  while (move_vertex(G, moved_node))
693  {
694  ++step_number;
695  tentative_cutsize[step_number] = cur_cutsize;
696  tentative_moves[step_number] = moved_node;
697  if (tentative_cutsize[best_tentative_move] > cur_cutsize)
698  {
699  best_tentative_move = step_number;
701  }
702  else if (tentative_cutsize[best_tentative_move] == cur_cutsize)
703  {
704  if (node_weight_on_sideA * node_weight_on_sideB > best_bal)
705  {
706  best_tentative_move = step_number;
708  }
709  }
710  }
711 
712  for (int i = 1; i <= best_tentative_move; i++)
713  {
714  if (side[tentative_moves[i]] == A)
715  {
716  side[tentative_moves[i]] = B;
717  }
718  else // side[tentative_moves[i]] == B
719  {
720  side[tentative_moves[i]] = A;
721  }
722  }
723  cur_cutsize = tentative_cutsize[best_tentative_move];
724 }
725 
726 
727 bool fm_partition::move_vertex(const graph& G, node& moved_node)
728 {
729  node cons_nodeA;
730  if (!bucketA_empty)
731  {
732  cons_nodeA = bucketA[range_up(max_gainA)].back();
733  }
734  node cons_nodeB;
735  if (!bucketB_empty)
736  {
737  cons_nodeB = bucketB[range_up(max_gainB)].back();
738  }
739  if ((!bucketA_empty) && (!bucketB_empty) &&
740  (balance_holds(G, cons_nodeA)) && (balance_holds(G, cons_nodeB)))
741  {
742  if (gain_value[cons_nodeA] > gain_value[cons_nodeB])
743  {
744  update_data_structure_A2B(cons_nodeA);
745  moved_node = cons_nodeA;
746  }
747  else if (gain_value[cons_nodeB] > gain_value[cons_nodeA])
748  {
749  update_data_structure_B2A(cons_nodeB);
750  moved_node = cons_nodeB;
751  }
752  else // gain_value[cons_nodeB] == gain_value[cons_nodeA]
753  {
754  int bal_diff_A2B = abs(node_weight_on_sideA - 2 *
755  node_weight[cons_nodeA] - node_weight_on_sideB);
756  int bal_diff_B2A = abs(node_weight_on_sideB - 2 *
757  node_weight[cons_nodeB] - node_weight_on_sideA);
758  if (bal_diff_A2B < bal_diff_B2A)
759  {
760  update_data_structure_A2B(cons_nodeA);
761  moved_node = cons_nodeA;
762  }
763  else if (bal_diff_B2A < bal_diff_A2B)
764  {
765  update_data_structure_B2A(cons_nodeB);
766  moved_node = cons_nodeB;
767  }
768  else // break remaining ties as desired [FidMat82]
769  {
770  update_data_structure_A2B(cons_nodeA);
771  moved_node = cons_nodeA;
772  }
773  }
774  }
775  else if ((!bucketA_empty) && (balance_holds(G, cons_nodeA)))
776  {
777  update_data_structure_A2B(cons_nodeA);
778  moved_node = cons_nodeA;
779  }
780  else if ((!bucketB_empty) && (balance_holds(G, cons_nodeB)))
781  {
782  update_data_structure_B2A(cons_nodeB);
783  moved_node = cons_nodeB;
784  }
785  else
786  {
787  return false; // no more vertices can be moved
788  }
791  return true;
792 }
793 
794 
795 bool fm_partition::balance_holds(const graph& G, const node cur_node)
796 {
797  if (side[cur_node] == A)
798  {
799  if ((double)node_weight_on_sideB + (double)node_weight[cur_node]
800  <= ((double)total_node_weight / 2.0) + (double)max_node_weight)
801  {
802  return true;
803  }
804  }
805  else // side[cur_node] == B
806  {
807  if ((double)node_weight_on_sideA + (double)node_weight[cur_node]
808  <= ((double)total_node_weight / 2.0) + (double)max_node_weight)
809  {
810  return true;
811  }
812  }
813  return false;
814 }
815 
816 
818 {
819  bucketA[range_up(max_gainA)].pop_back();
820  node_weight_on_sideA -= node_weight[cur_node];
821  node_weight_on_sideB += node_weight[cur_node];
822  cur_cutsize -= gain_value[cur_node];
823 
824  // updating gain values
825  node::adj_edges_iterator adj_edge_it = cur_node.adj_edges_begin();
826  node::adj_edges_iterator adj_edges_end = cur_node.adj_edges_end();
827  while (adj_edge_it != adj_edges_end)
828  {
829  // delete cur_node from side A
830  unlockedA[*adj_edge_it].remove(cur_node);
831  --aside[*adj_edge_it];
832  if (aside[*adj_edge_it] == 0)
833  {
834  list<node>::iterator node_it = unlockedB[*adj_edge_it].begin();
835  list<node>::iterator nodes_end = unlockedB[*adj_edge_it].end();
836  while (node_it != nodes_end)
837  {
838  update_bucketB(*node_it, gain_value[*node_it],
839  gain_value[*node_it] - edge_weight[*adj_edge_it]);
840  gain_value[*node_it] -= edge_weight[*adj_edge_it];
841  ++node_it;
842  }
843  }
844  else if (aside[*adj_edge_it] == 1)
845  {
846  list<node>::iterator node_it = unlockedA[*adj_edge_it].begin();
847  list<node>::iterator nodes_end = unlockedA[*adj_edge_it].end();
848  while (node_it != nodes_end)
849  {
850  update_bucketA(*node_it, gain_value[*node_it],
851  gain_value[*node_it] + edge_weight[*adj_edge_it]);
852  gain_value[*node_it] += edge_weight[*adj_edge_it];
853  ++node_it;
854  }
855  }
856  // add cur_node to side B
857  ++bside[*adj_edge_it];
858  if (bside[*adj_edge_it] == 1)
859  {
860  list<node>::iterator node_it = unlockedA[*adj_edge_it].begin();
861  list<node>::iterator nodes_end = unlockedA[*adj_edge_it].end();
862  while (node_it != nodes_end)
863  {
864  update_bucketA(*node_it, gain_value[*node_it],
865  gain_value[*node_it] + edge_weight[*adj_edge_it]);
866  gain_value[*node_it] += edge_weight[*adj_edge_it];
867  ++node_it;
868  }
869  }
870  else if (bside[*adj_edge_it] == 2)
871  {
872  list<node>::iterator node_it = unlockedB[*adj_edge_it].begin();
873  list<node>::iterator nodes_end = unlockedB[*adj_edge_it].end();
874  while (node_it != nodes_end)
875  {
876  update_bucketB(*node_it, gain_value[*node_it],
877  gain_value[*node_it] - edge_weight[*adj_edge_it]);
878  gain_value[*node_it] -= edge_weight[*adj_edge_it];
879  ++node_it;
880  }
881  }
882  ++adj_edge_it;
883  }
884 }
885 
886 
888 {
889  bucketB[range_up(max_gainB)].pop_back();
890  node_weight_on_sideA += node_weight[cur_node];
891  node_weight_on_sideB -= node_weight[cur_node];
892  cur_cutsize -= gain_value[cur_node];
893 
894  // updating gain values
895  node::adj_edges_iterator adj_edge_it = cur_node.adj_edges_begin();
896  node::adj_edges_iterator adj_edges_end = cur_node.adj_edges_end();
897  while (adj_edge_it != adj_edges_end)
898  {
899  // delete cur_node from side B
900  unlockedB[*adj_edge_it].remove(cur_node);
901  bside[*adj_edge_it] -= 1;
902  if (bside[*adj_edge_it] == 0)
903  {
904  list<node>::iterator node_it = unlockedA[*adj_edge_it].begin();
905  list<node>::iterator nodes_end = unlockedA[*adj_edge_it].end();
906  while (node_it != nodes_end)
907  {
908  update_bucketA(*node_it, gain_value[*node_it],
909  gain_value[*node_it] - edge_weight[*adj_edge_it]);
910  gain_value[*node_it] -= edge_weight[*adj_edge_it];
911  ++node_it;
912  }
913  }
914  else if (bside[*adj_edge_it] == 1)
915  {
916  list<node>::iterator node_it = unlockedB[*adj_edge_it].begin();
917  list<node>::iterator nodes_end = unlockedB[*adj_edge_it].end();
918  while (node_it != nodes_end)
919  {
920  update_bucketB(*node_it, gain_value[*node_it],
921  gain_value[*node_it] + edge_weight[*adj_edge_it]);
922  gain_value[*node_it] += edge_weight[*adj_edge_it];
923  ++node_it;
924  }
925  }
926  // add cur_node to side A
927  aside[*adj_edge_it] += 1;
928  if (aside[*adj_edge_it] == 1)
929  {
930  list<node>::iterator node_it = unlockedB[*adj_edge_it].begin();
931  list<node>::iterator nodes_end = unlockedB[*adj_edge_it].end();
932  while (node_it != nodes_end)
933  {
934  update_bucketB(*node_it, gain_value[*node_it],
935  gain_value[*node_it] + edge_weight[*adj_edge_it]);
936  gain_value[*node_it] += edge_weight[*adj_edge_it];
937  ++node_it;
938  }
939  }
940  else if (aside[*adj_edge_it] == 2)
941  {
942  list<node>::iterator node_it = unlockedA[*adj_edge_it].begin();
943  list<node>::iterator nodes_end = unlockedA[*adj_edge_it].end();
944  while (node_it != nodes_end)
945  {
946  update_bucketA(*node_it, gain_value[*node_it],
947  gain_value[*node_it] - edge_weight[*adj_edge_it]);
948  gain_value[*node_it] -= edge_weight[*adj_edge_it];
949  ++node_it;
950  }
951  }
952  ++adj_edge_it;
953  }
954 }
955 
956 
957 void fm_partition::update_bucketA(const node cur_node, const int old_gain,
958  const int new_gain)
959 {
960  if (fixed[cur_node] != UNFIXED)
961  {
962  return; // fixed nodes need no update
963  }
964 
965  bucketA[range_up(old_gain)].erase(position_in_bucket[cur_node]);
966  position_in_bucket[cur_node] = bucketA[range_up(new_gain)].insert(
967  bucketA[range_up(new_gain)].end(), cur_node);
968 
969  if (max_gainA < new_gain)
970  {
971  max_gainA = new_gain;
972  }
973 }
974 
975 
976 void fm_partition::update_bucketB(const node cur_node, const int old_gain,
977  const int new_gain)
978 {
979  if (fixed[cur_node] != UNFIXED)
980  {
981  return; // fixed nodes need no update
982  }
983 
984  bucketB[range_up(old_gain)].erase(position_in_bucket[cur_node]);
985  position_in_bucket[cur_node] = bucketB[range_up(new_gain)].insert(
986  bucketB[range_up(new_gain)].end(), cur_node);
987 
988  if (max_gainB < new_gain)
989  {
990  max_gainB = new_gain;
991  }
992 }
993 
994 
996 {
997  if ((side == A) && (!bucketA_empty))
998  {
999  while (bucketA[range_up(max_gainA)].empty())
1000  {
1001  --max_gainA;
1002  if (range_up(max_gainA) < 0)
1003  {
1004  bucketA_empty = true;
1005  return;
1006  }
1007  }
1008  bucketA_empty = false;
1009  }
1010  if ((side == B) && (!bucketB_empty))
1011  {
1012  while (bucketB[range_up(max_gainB)].empty())
1013  {
1014  --max_gainB;
1015  if (range_up(max_gainB) < 0)
1016  {
1017  bucketB_empty = true;
1018  return;
1019  }
1020  }
1021  bucketB_empty = false;
1022  }
1023 }
1024 
1025 
1026 inline int fm_partition::range_up(const int gain_value) const
1027 {
1028  return gain_value + (max_vertex_degree * max_edge_weight);
1029 }
1030 
1031 
1032 inline int fm_partition::range_down(const int index) const
1033 {
1034  return index - (max_vertex_degree * max_edge_weight);
1035 }
1036 
1037 
1039 {
1040  // clean unlocked* lists
1041  graph::edge_iterator edge_it = G.edges_begin();
1042  graph::edge_iterator edges_end = G.edges_end();
1043  while (edge_it != edges_end)
1044  {
1045  unlockedA[*edge_it].clear();
1046  unlockedB[*edge_it].clear();
1047  ++edge_it;
1048  }
1049 
1050  // clean buckets
1051  for (int i = 0; i <= 2 * max_vertex_degree * max_edge_weight; i++)
1052  {
1053  bucketA[i].clear();
1054  bucketB[i].clear();
1055  }
1056  bucketA.clear();
1057  bucketB.clear();
1058 }
1059 
1060 
1062 {
1063  cut_edges.clear();
1064  graph::edge_iterator edge_it = G.edges_begin();
1065  graph::edge_iterator edges_end = G.edges_end();
1066  while (edge_it != edges_end)
1067  {
1068  if (side[(*edge_it).source()] != side[(*edge_it).target()])
1069  {
1070  cut_edges.push_back(*edge_it);
1071  }
1072  ++edge_it;
1073  }
1074 }
1075 
1076 
1078 {
1079  nodesA.clear();
1080  nodesB.clear();
1081  graph::node_iterator node_it = G.nodes_begin();
1082  graph::node_iterator nodes_end = G.nodes_end();
1083  while (node_it != nodes_end)
1084  {
1085  if (side[*node_it] == A)
1086  {
1087  nodesA.push_back(*node_it);
1088  }
1089  else // side[*node_it] == B
1090  {
1091  nodesB.push_back(*node_it);
1092  }
1093  ++node_it;
1094  }
1095 }
1096 
1097 
1098 #ifdef _DEBUG
1099 void fm_partition::print_bucketA()
1100 {
1102  GTL_debug::os() << endl << "bucketA:" << endl;
1103  for (int i = 0; i <= 2 * max_vertex_degree * max_edge_weight; i++)
1104  {
1105  GTL_debug::os() << range_down(i) << ": ";
1106  list<node>::iterator node_it = bucketA[i].begin();
1107  list<node>::iterator nodes_end = bucketA[i].end();
1108  while (node_it != nodes_end)
1109  {
1110  GTL_debug::os() << *node_it << " ";
1111  ++node_it;
1112  }
1113  GTL_debug::os() << endl;
1114  }
1115  GTL_debug::os() << endl;
1117 }
1118 
1119 
1120 void fm_partition::print_bucketB()
1121 {
1123  GTL_debug::os() << endl << "bucketB:" << endl;
1124  for (int i = 0; i <= 2 * max_vertex_degree * max_edge_weight; i++)
1125  {
1126  GTL_debug::os() << range_down(i) << ": ";
1127  list<node>::iterator node_it = bucketB[i].begin();
1128  list<node>::iterator nodes_end = bucketB[i].end();
1129  while (node_it != nodes_end)
1130  {
1131  GTL_debug::os() << *node_it << " ";
1132  ++node_it;
1133  }
1134  GTL_debug::os() << endl;
1135  }
1136  GTL_debug::os() << endl;
1138 }
1139 #endif // _DEBUG
1140 
1141 
1143 
1144 //--------------------------------------------------------------------------
1145 // end of file
1146 //--------------------------------------------------------------------------