MC_kruskal.cpp
Go to the documentation of this file.
1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others. All Rights Reserved.
3 #include <cassert>
4 #include <algorithm>
5 #include <numeric>
6 
7 #include "CoinHelperFunctions.hpp"
8 
9 #include "MC_cut.hpp"
10 #include "MC.hpp"
11 
12 //#############################################################################
13 
14 static void
15 MC_label_neighbors(const int this_node, const int* degree,
16  const int* neighbornode, const int* neighboredge,
17  int * parentnode, int * parentedge)
18 {
19  for (int i = degree[this_node]; i < degree[this_node+1]; ++i) {
20  const int child = neighbornode[i];
21  if (parentnode[child] == -2) {
22  parentnode[child] = this_node;
23  parentedge[child] = neighboredge[i];
24  MC_label_neighbors(child, degree, neighbornode, neighboredge,
25  parentnode, parentedge);
26  }
27  }
28 }
29 
30 //#############################################################################
31 
32 void
33 MC_kruskal(const MC_problem& mc, const int* edgeorder, const double* x,
34  int * nodesign, int * edges_in_tree)
35 {
36  //--------------------------------------------------------------------------
37  // Kruskal's algo is used (the version when we add edges starting from the
38  // cheapest and never creating a cycle). Avoiding cycles is ensured by
39  // keeping the components in chains (first each in its own chain), later
40  // an edge is added iff its two endpoints have different chain heads.
41  //
42  // NOTE: the weights on the edges are not needed to find the MST, it's
43  // enough that the edges are ordered in increasing weight.
44  // HOWEVER, to fill out nodesign we need the weights (or it might be a
45  // different vector...).
46  //--------------------------------------------------------------------------
47 
48  // Also, create the nodesign array: mark the tree nodes with +/- 1 according
49  // to the following rule: if the x value of the edge is closer to 0 then the
50  // two nodes are on the same side, if it's closer to 1 then they are on the
51  // opposite sides. This is done by assigning +1 to each node to start with,
52  // and when two chains are merged (the shorted appended to the longer) the
53  // nodesigns of all nodes on the shorter chain are reversed if necessary.
54  // nodesign is assumed to be exactly mc.num_nodes long.
55 
56  const int n = mc.num_nodes;
57  const int m = mc.num_edges;
58  int k;
59 
60  CoinFillN(nodesign, n, 1);
61 
62  // the first/last node on the chain containing the i-th node
63  // first_on_chain is accurate for every i,
64  // last_on_chain is accurate only for chain heads!
65  int * first_on_chain = new int[n];
66  int * last_on_chain = new int[n];
67  // the next node in the same chain, or -1 if there aren't more. ACCURATE
68  int * next_on_chain = new int[n];
69  // size of the chain containing i. Accurate only for chain heads!
70  int * size_of_chain = new int[n];
71 
72  CoinIotaN(first_on_chain, n, 0);
73  CoinIotaN(last_on_chain, n, 0);
74  CoinFillN(next_on_chain, n, -1);
75  CoinFillN(size_of_chain, n, 1);
76 
77  int tree_size = 0;
78 
79  const MC_graph_edge* edges = mc.edges;
80 
81  int label_s = -1; // shorter chain head
82  int label_l = -1; // longer chain head
83  for (k = 0; k < m; ++k) {
84  const int kth_edge = edgeorder[k];
85  const int i = edges[kth_edge].tail;
86  const int j = edges[kth_edge].head;
87  const int label_i = first_on_chain[i];
88  const int label_j = first_on_chain[j];
89  if (label_i == label_j)
90  continue;
91  if (size_of_chain[label_i] > size_of_chain[label_j]) {
92  label_s = label_j;
93  label_l = label_i;
94  } else {
95  label_s = label_i;
96  label_l = label_j;
97  }
98  edges_in_tree[tree_size++] = kth_edge;
99  // relabel those in the chain headed by label_s and if necessary, reverse
100  // the nodesign of all of them
101  for (int l = label_s; l != -1; l = next_on_chain[l]) {
102  first_on_chain[l] = label_l;
103  }
104  if ((x[kth_edge] > .5 && (nodesign[i] == nodesign[j])) ||
105  (x[kth_edge] < .5 && (nodesign[i] != nodesign[j])) ) {
106  for (int l = label_s; l != -1; l = next_on_chain[l]) {
107  nodesign[l] = -nodesign[l];
108  }
109  }
110  next_on_chain[last_on_chain[label_l]] = label_s;
111  last_on_chain[label_l] = last_on_chain[label_s];
112  size_of_chain[label_l] += size_of_chain[label_s];
113  }
114 
115  if (tree_size != n-1) {
116  printf("MC: The MST has less than n-1 edges!\n");
117  abort();
118  }
119 
120  delete[] size_of_chain;
121  delete[] next_on_chain;
122  delete[] last_on_chain;
123  delete[] first_on_chain;
124 }
125 
126 //#############################################################################
127 
128 void
129 MC_kruskal(const MC_problem& mc, const int * edgeorder, const double* x,
130  int * nodesign, int * parentnode, int * parentedge)
131 {
132  const int n = mc.num_nodes;
133 
134  int * edges_in_tree = new int[n-1];
135 
136  MC_kruskal(mc, edgeorder, x, nodesign, edges_in_tree);
137 
138  // Create the rooted tree
139 
140  int * neighbornode = new int[2*n];
141  int * neighboredge = new int[2*n];
142  int * degree = new int[n+1];
143 
144  int k;
145  const int tree_size = n - 1;
146  const MC_graph_edge* edges = mc.edges;
147 
148  CoinFillN(degree, n + 1, 0);
149  for (k = 0; k < tree_size; ++k) {
150  const int l = edges_in_tree[k];
151  ++degree[edges[l].tail];
152  ++degree[edges[l].head];
153  }
154  const int maxdeg_node = std::max_element(degree, degree + n) - degree;
155 
156  std::partial_sum(degree, degree + n, degree);
157  degree[n] = 0;
158  std::rotate(degree, degree + n, degree + (n+1));
159 
160  for (k = 0; k < tree_size; ++k) {
161  const int l = edges_in_tree[k];
162  const int i = edges[l].tail;
163  const int j = edges[l].head;
164  neighbornode[degree[i]] = j;
165  neighbornode[degree[j]] = i;
166  neighboredge[degree[i]++] = l;
167  neighboredge[degree[j]++] = l;
168  }
169  std::rotate(degree, degree + n, degree + (n+1));
170  degree[0] = 0;
171 
172  CoinFillN(parentnode, n, -2);
173  CoinFillN(parentedge, n, -1);
174  parentnode[maxdeg_node] = -1;
175  MC_label_neighbors(maxdeg_node, degree, neighbornode, neighboredge,
176  parentnode, parentedge);
177 
178  delete[] degree;
179  delete[] neighboredge;
180  delete[] neighbornode;
181  delete[] edges_in_tree;
182 }
int num_edges
Definition: MC.hpp:92
int head
Definition: MC.hpp:30
int num_nodes
Definition: MC.hpp:91
MC_graph_edge * edges
Definition: MC.hpp:95
static void MC_label_neighbors(const int this_node, const int *degree, const int *neighbornode, const int *neighboredge, int *parentnode, int *parentedge)
Definition: MC_kruskal.cpp:15
void MC_kruskal(const MC_problem &mc, const int *edgeorder, const double *x, int *nodesign, int *edges_in_tree)
Definition: MC_kruskal.cpp:33
static char * j
Definition: OSdtoa.cpp:3622
int tail
Definition: MC.hpp:29
void fint fint * k
void fint * m
void fint * n
void fint fint fint real fint real * x