MC_shortest_path_cycle.cpp
Go to the documentation of this file.
1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others. All Rights Reserved.
3 
4 #include <queue>
5 #include <vector>
6 
7 #include "CoinSort.hpp"
8 
9 #include "MC.hpp"
10 #include "MC_cut.hpp"
11 
12 #include "BCP_matrix.hpp"
13 
14 //#############################################################################
15 
16 void
17 MC_create_shortest_path_cut(const int n, const int sp_tree_root,
18  const MC_graph_edge* edges,
19  const MC_path_node* bp_nodes,
20  BCP_vec<BCP_cut*>& new_cuts,
21  BCP_vec<BCP_row*>& new_rows,
22  int * itmp, double * dtmp)
23 {
24  int pos = 0, neg = 0;
25  int* posedges = itmp;
26  int* negedges = itmp + n;
27 
28  int i = sp_tree_root + n;
29  int parent;
30  do {
31  parent = bp_nodes[i].parent;
32  if ((parent < n && i < n) || (parent >= n && i >= n)) {
33  // side edge thus not in F
34  negedges[neg++] = bp_nodes[i].edge_to_parent;
35  } else {
36  // crossing edge thus in F
37  posedges[pos++] = bp_nodes[i].edge_to_parent;
38  }
39  i = parent;
40  } while (parent != sp_tree_root);
41 
42  if ((pos % 2) != 1)
43  abort();
44  const int len = pos + neg;
45  CoinDisjointCopyN(negedges, neg, posedges + pos);
46  new_cuts.push_back(new MC_cycle_cut(posedges, pos, len));
47  CoinFillN(dtmp, pos, 1.0);
48  CoinFillN(dtmp + pos, neg, -1.0);
49  CoinSort_2(posedges, posedges + len, dtmp);
50  new_rows.push_back(new BCP_row(posedges, posedges + len,
51  dtmp, dtmp + len, -BCP_DBL_MAX, pos - 1.0));
52 }
53 
54 //#############################################################################
55 
56 int
57 MC_find_components(const int nodenum, const MC_path_node* bp_nodes,
58  int * component)
59 {
60  int* node_stack = new int[nodenum];
61  int stack_size = 0;
62  int comp_num = 0;
63  int i, j;
64  for (i = 0; i < nodenum; ++i) {
65  if (component[i] >= 0) // it's already encountered
66  continue;
67  node_stack[stack_size++] = i;
68  ++comp_num;
69  while (stack_size > 0) {
70  const int node = node_stack[--stack_size];
71  component[node] = i;
72  const MC_path_adj_entry* neighbors = bp_nodes[node].adj_list;
73  for (j = bp_nodes[node].degree - 1; j >= 0; --j) {
74  const int other = neighbors[j].neighbor;
75  if (component[other] == -1) {
76  component[other] = i;
77  node_stack[stack_size++] = other;
78  }
79  }
80  }
81  }
82  delete[] node_stack;
83  return comp_num;
84 }
85 
86 //#############################################################################
87 
88 void
90  const bool generate_all_cuts,
91  const double minviol,
92  BCP_vec<BCP_cut*>& new_cuts,
93  BCP_vec<BCP_row*>& new_rows)
94 {
95  const double minviol1 = 1.0 - minviol;
96 
97  const int n = mc.num_nodes;
98  const int m = mc.num_edges;
99  double* dtmp = new double[n];
100  int* itmp = new int[4 * n + m];
101  // the first 2n entries will be used in MC_generate_shortest_path_cycles as
102  // temporaries
103  int* component = itmp + (2 * n);
104  int* edges_to_create = itmp + (4 * n);
105  const MC_graph_edge* edges = mc.edges;
106 
107  MC_path_node* bp_nodes = new MC_path_node[2 * n];
108  MC_path_adj_entry* bp_all_adj_list = new MC_path_adj_entry[8 * m];
109 
110  int i, j;
111 
112  for (i = 0; i < n; ++i)
113  bp_nodes[i].degree = 0;
114 
115  // Build the bipartite graph
116  for (i = 0; i < m; ++i) {
117  const double xi = x[i];
118  const int t = edges[i].tail;
119  const int h = edges[i].head;
120  edges_to_create[i] = 0;
121  if (xi >= minviol) {
122  // the length of the crossing edges is < 1 - minviol, so there can be a
123  // violated cycle through them, so they exist
124  edges_to_create[i] |= 1;
125  ++bp_nodes[t].degree;
126  ++bp_nodes[h].degree;
127  }
128  if (xi < minviol1) {
129  // the length of the side edges is < 1 - minviol, so there can be a
130  // violated cycle through them, so they exist
131  edges_to_create[i] |= 2;
132  ++bp_nodes[t].degree;
133  ++bp_nodes[h].degree;
134  }
135  }
136 
137  int total_degree = 0;
138  for (i = 0; i < n; ++i) {
139  bp_nodes[i].adj_list = bp_all_adj_list + total_degree;
140  total_degree += bp_nodes[i].degree;
141  bp_nodes[i + n].adj_list = bp_all_adj_list + total_degree;
142  total_degree += bp_nodes[i].degree;
143  }
144 
145  for (i = 0; i < n; ++i)
146  bp_nodes[i].degree = 0;
147 
148  for (i = 0; i < m; ++i) {
149  const double xi = CoinMax(x[i], 0.0);
150  const double xi1 = CoinMax(1 - xi, 0.0);
151  const int t = edges[i].tail;
152  const int h = edges[i].head;
153  const int nt = n + t;
154  const int nh = n + h;
155  if ((edges_to_create[i] & 1) != 0) { // create the crossing edges
156  const int degt = bp_nodes[t].degree;
157  const int degh = bp_nodes[h].degree;
158  MC_path_adj_entry& t_entry = bp_nodes[t].adj_list[degt];
159  MC_path_adj_entry& h_entry = bp_nodes[h].adj_list[degh];
160  MC_path_adj_entry& nt_entry = bp_nodes[nt].adj_list[degt];
161  MC_path_adj_entry& nh_entry = bp_nodes[nh].adj_list[degh];
162 
163  t_entry.neighbor = nh;
164  h_entry.neighbor = nt;
165  nt_entry.neighbor = h;
166  nh_entry.neighbor = t;
167 
168  t_entry.orig_edge = i;
169  h_entry.orig_edge = i;
170  nt_entry.orig_edge = i;
171  nh_entry.orig_edge = i;
172 
173  t_entry.cost = xi1;
174  h_entry.cost = xi1;
175  nt_entry.cost = xi1;
176  nh_entry.cost = xi1;
177 
178  ++bp_nodes[t].degree;
179  ++bp_nodes[h].degree;
180  }
181  if ((edges_to_create[i] & 2) != 0) { // create the side edges
182  const int degt = bp_nodes[t].degree;
183  const int degh = bp_nodes[h].degree;
184  MC_path_adj_entry& t_entry = bp_nodes[t].adj_list[degt];
185  MC_path_adj_entry& h_entry = bp_nodes[h].adj_list[degh];
186  MC_path_adj_entry& nt_entry = bp_nodes[nt].adj_list[degt];
187  MC_path_adj_entry& nh_entry = bp_nodes[nh].adj_list[degh];
188 
189  t_entry.neighbor = h;
190  h_entry.neighbor = t;
191  nt_entry.neighbor = nh;
192  nh_entry.neighbor = nt;
193 
194  t_entry.orig_edge = i;
195  h_entry.orig_edge = i;
196  nt_entry.orig_edge = i;
197  nh_entry.orig_edge = i;
198 
199  t_entry.cost = xi;
200  h_entry.cost = xi;
201  nt_entry.cost = xi;
202  nh_entry.cost = xi;
203 
204  ++bp_nodes[t].degree;
205  ++bp_nodes[h].degree;
206  }
207  }
208  for (i = 0; i < n; ++i)
209  bp_nodes[n+i].degree = bp_nodes[i].degree;
210 
211  // Create a priority queue that will hold the shortest path tree
212  std::priority_queue<MC_path_node*,
213  std::vector<MC_path_node*>,
214  MC_path_node_ptr_compare> pqueue;
215 
216  CoinFillN(component, 2 * n, -1);
217 
218  const int comp_num = MC_find_components(2*n, bp_nodes, component);
219  printf("MC: sp based exact: there are %i components in the graph\n",
220  comp_num);
221 
222  /* Check the nodes where we already have a sufficiently violated cycle
223  through the node. If such a node and it's pair is in the same component
224  then set the component id of one to be -1 so we skip the shortest path
225  computation for them. */
226  double viol;
227  int skip = 0;
228  for (i = new_cuts.size() - 1; i >= 0; --i) {
229  const MC_cycle_cut* cut = dynamic_cast<const MC_cycle_cut*>(new_cuts[i]);
230  if (! cut)
231  continue;
232  viol = - (cut->pos_edges - 1);
233  for (j = 0; j < cut->pos_edges; ++j) {
234  viol += x[cut->edges[j]];
235  }
236  for ( ; j < cut->cycle_len; ++j) {
237  viol -= x[cut->edges[j]];
238  }
239  if (viol <= minviol)
240  continue;
241  for (j = 0; j < cut->cycle_len; ++j) {
242  const int t = edges[cut->edges[j]].tail;
243  const int h = edges[cut->edges[j]].head;
244  if (component[t] == component[n + t]) {
245  ++skip;
246  component[t] = -2;
247  }
248  if (component[h] == component[n + h]) {
249  ++skip;
250  component[h] = -2;
251  }
252  }
253  }
254  printf("MC: sp based exact: skipping %i sp computations\n", skip);
255  printf(" because of already found cycles\n");
256 
257  int split_num = 0;
258  for (i = 0; i < n; ++i) {
259  if (component[i] != component[n + i]) {
260  ++split_num;
261  continue;
262  }
263  // do the shortest path
264  double limit = minviol1;
265 
266  // set the original distance of everything to 1.0 (that's larger than the
267  // longest edge, and we will anyway terminate every path that's longer
268  // than limit). Note that a node can be in the priority queue more than
269  // once, but it's going to be processed only once. All this is necessary
270  // because the std priority queue installation cannot "relocate" a node
271  // when it's value changes.
272  for (j = 2*n - 1; j >= 0; --j) {
273  bp_nodes[j].distance = 1.0;
274  bp_nodes[j].processed = false;
275  }
276  bp_nodes[i].distance = 0.0;
277 
278  pqueue.push(bp_nodes + i);
279 
280  while (! pqueue.empty()) {
281  MC_path_node* this_node_nonconst = pqueue.top();
282  const MC_path_node* this_node = this_node_nonconst;
283  pqueue.pop();
284  if (this_node->processed)
285  continue;
286  const int this_node_index = this_node - bp_nodes;
287  if (this_node_index == n+i) {
288  // got the shortest path to the pair, need not go further
289  if (! generate_all_cuts) {
290  // wee needed only the best cut for each node, here it is
291  MC_create_shortest_path_cut(n, this_node_index, edges, bp_nodes,
292  new_cuts, new_rows, itmp, dtmp);
293  }
294  break;
295  }
296  this_node_nonconst->processed = true;
297  const double this_dist = this_node->distance;
298  const MC_path_adj_entry* this_alist = this_node->adj_list;
299  for (j = this_node->degree - 1; j >= 0; --j) {
300  const double neighborcost = this_dist + this_alist[j].cost;
301  if (neighborcost >= limit)
302  continue;
303  const int neighbor = this_alist[j].neighbor;
304  if (bp_nodes[neighbor].distance > neighborcost) {
305  MC_path_node* neighbor_node = bp_nodes + neighbor;
306  pqueue.push(neighbor_node);
307  neighbor_node->distance = neighborcost;
308  neighbor_node->parent = this_node_index;
309  neighbor_node->edge_to_parent = this_alist[j].orig_edge;
310  if (neighbor == n+i) {
311  // found a new violated cycle...
312  limit = neighborcost;
313  if (generate_all_cuts) {
314  MC_create_shortest_path_cut(n, i, edges, bp_nodes,
315  new_cuts, new_rows, itmp, dtmp);
316  }
317  }
318  }
319  }
320  }
321  }
322 
323  printf("MC: sp based exact: computed %i sp out of %i\n", n - split_num, n);
324 
325  delete[] bp_all_adj_list;
326  delete[] bp_nodes;
327  delete[] itmp;
328  delete[] dtmp;
329 }
int orig_edge
Definition: MC.hpp:150
int num_edges
Definition: MC.hpp:92
pos
position where the operator should be printed when printing the expression
void MC_create_shortest_path_cut(const int n, const int sp_tree_root, const MC_graph_edge *edges, const MC_path_node *bp_nodes, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows, int *itmp, double *dtmp)
int num_nodes
Definition: MC.hpp:91
int degree
Definition: MC.hpp:160
MC_graph_edge * edges
Definition: MC.hpp:95
void MC_generate_shortest_path_cycles(const MC_problem &mc, const double *x, const bool generate_all_cuts, const double minviol, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
int * edges
Definition: MC_cut.hpp:50
void push_back(const_reference x)
Append x to the end of the vector.
static char * j
Definition: OSdtoa.cpp:3622
int neighbor
Definition: MC.hpp:149
bool processed
Definition: MC.hpp:159
#define BCP_DBL_MAX
Definition: BCP_math.hpp:6
int cycle_len
Definition: MC_cut.hpp:48
double cost
Definition: MC.hpp:151
int edge_to_parent
Definition: MC.hpp:164
Definition: MC.hpp:147
int parent
Definition: MC.hpp:162
double distance
Definition: MC.hpp:166
int MC_find_components(const int nodenum, const MC_path_node *bp_nodes, int *component)
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
int pos_edges
Definition: MC_cut.hpp:49
fint nt
MC_path_adj_entry * adj_list
Definition: MC.hpp:167
void fint * m
double distance(const double *p1, const double *p2, int size, double k=2.)
compute Euclidean distance between two points (most likely LP solutions) l_2 norm by default...
static char * t
Definition: OSdtoa.cpp:3645
void fint * n
void fint fint fint real fint real * x
This class holds a row in a compressed form.
Definition: BCP_matrix.hpp:152