MC_solution.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 <cfloat>
5 #include <cstdio>
6 #include <fstream>
7 
8 #include "CoinHelperFunctions.hpp"
9 
10 #include "BCP_math.hpp"
11 #include "BCP_string.hpp"
12 #include "BCP_buffer.hpp"
13 #include "BCP_vector.hpp"
14 
15 #include "MC.hpp"
16 #include "MC_solution.hpp"
17 
18 #define MC_PRINT_ITER_COUNT 0
19 
20 #define MC_TEST_COST_AFTER_EVERY_SWITCH 0
21 
22 //#############################################################################
23 
26  buf.pack(cost).pack(sig);
27  return buf;
28 }
29 
30 //#############################################################################
31 
34  buf.unpack(cost).unpack(sig);
35  return buf;
36 }
37 
38 //#############################################################################
39 
42  cost = sol.cost;
43  sig = sol.sig;
44  return *this;
45 }
46 
47 //#############################################################################
48 
49 double
50 MC_solution::compute_cost(const int m, const MC_graph_edge* edges)
51 {
52  cost = 0.0;
53  for (int i = 0; i < m; ++i) {
54  const MC_graph_edge& edge = edges[i];
55  if (sig[edge.tail] != sig[edge.head]) {
56  cost += edge.cost;
57  }
58  }
59  return cost;
60 }
61 
62 //#############################################################################
63 
64 static inline double
65 MC_switch_cost(const MC_adjacency_entry* adj_list, const int degree,
66  const int* sig, const int this_sig)
67 {
68  double sum = 0;
69  for (int j = degree - 1; j >= 0; --j) {
70 #if 1
71  // Because of pipelined processors, this is probably much faster...
72  sum += sig[adj_list[j].neighbor] * this_sig * adj_list[j].cost;
73 #else
74  if (sig[adj_list[j].neighbor] == this_sig) {
75  sum += adj_list[j].cost;
76  } else {
77  sum -= adj_list[j].cost;
78  }
79 #endif
80  }
81  return sum;
82 }
83 
84 //#############################################################################
85 
86 double
88 {
89  const int n = mc.num_nodes;
90  bool flag = true;
91  int i, iter;
92  double newcost = cost;
93  for (iter = 0; iter < maxiter && flag; ++iter) {
94  flag = false;
95  for (i = 0; i < n; ++i) {
96  const double sum = MC_switch_cost(mc.nodes[i].adj_list,
97  mc.nodes[i].degree,
98  sig.begin(), sig[i]);
99  if (sum < 0) {
100  sig[i] *= -1;
101  newcost += sum;
102  flag = true;
103 #if MC_TEST_COST_AFTER_EVERY_SWITCH
104  compute_cost(mc.num_edges, mc.edges);
105  if (cost != newcost)
106  abort();
107 #endif
108  }
109  }
110  }
111 #if MC_PRINT_ITER_COUNT
112  printf("MC_solution: switch_improve: %i.\n", iter);
113 #endif
114 
115  compute_cost(mc.num_edges, mc.edges);
116  if (cost != newcost)
117  abort();
118 
119  return cost;
120 }
121 
122 
123 //#############################################################################
124 // This routine must be invoked after switch_improve(), since to speed things
125 // up we assume that no single node switch can help, i.e., MC_switch_cost() is
126 // non-negative for all nodes.
127 
128 double
130 {
131  const int m = mc.num_edges;
132  bool flag = true;
133  int k, iter;
134  double newcost = cost;
135  const MC_graph_edge* edges = mc.edges;
136 
137  for (iter = 0; iter < maxiter && flag; ++iter) {
138  flag = false;
139  for (k = 0; k < m; ++k) {
140  const int i = edges[k].tail;
141  const int j = edges[k].head;
142  const double costk = 2 * sig[i] * sig[j] * edges[k].cost;
143  // we assume that no single node switch can help at this point ==>
144  // The MC_switch_cost values will be non-negative ==> costk > 0 is a
145  // necessary condition to find improvement.
146  if (costk <= 0.0)
147  continue;
148  const double sum =
150  sig.begin(), sig[i]) +
152  sig.begin(), sig[j]) -
153  costk;
154  if (sum < 0) {
155  sig[i] *= -1;
156  sig[j] *= -1;
157  newcost += sum;
158  flag = true;
159 #if MC_TEST_COST_AFTER_EVERY_SWITCH
160  compute_cost(mc.num_edges, mc.edges);
161  if (cost != newcost)
162  abort();
163 #endif
164  }
165  }
166  }
167 #if MC_PRINT_ITER_COUNT
168  printf("MC_solution: edge_switch_improve: %i.\n", iter);
169 #endif
170 
171  compute_cost(mc.num_edges, mc.edges);
172  if (cost != newcost)
173  abort();
174 
175  return cost;
176 }
177 
178 //#############################################################################
179 // This routine must be invoked after switch_improve(), since to speed things
180 // up we assume that no single node switch can help, i.e., MC_switch_cost() is
181 // non-negative for all nodes.
182 
183 double
185  const int maxiter)
186 {
187  const int m = mc.num_edges;
188  const int grid_edge_num = m - mc.num_nodes + 1;
189  bool flag = true;
190  int k, iter;
191  double newcost = cost;
192  const MC_graph_edge* edges = mc.edges;
193 
194  const int plus_node = mc.num_nodes - 1;
195  const MC_adjacency_entry* plus_node_adj_list = mc.nodes[plus_node].adj_list;
196 
197  for (iter = 0; iter < maxiter && flag; ++iter) {
198  flag = false;
199  // First try to switch edges not going to the extra node
200  for (k = 0; k < grid_edge_num; ++k) {
201  const int i = edges[k].tail;
202  const int j = edges[k].head;
203  const double costk = 2 * sig[i] * sig[j] * edges[k].cost;
204  // we assume that no single node switch can help at this point ==>
205  // The MC_switch_cost values will be non-negative ==> costk > 0 is a
206  // necessary condition to find improvement.
207  if (costk <= 0.0)
208  continue;
209  const double sum =
211  sig.begin(), sig[i]) +
213  sig.begin(), sig[j]) -
214  costk;
215  if (sum < 0) {
216  sig[i] *= -1;
217  sig[j] *= -1;
218  newcost += sum;
219  flag = true;
220 #if MC_TEST_COST_AFTER_EVERY_SWITCH
221  compute_cost(mc.num_edges, mc.edges);
222  if (cost != newcost)
223  abort();
224 #endif
225  }
226  }
227 
228  // Now try to switch edges going to the extra node
229  double switch_cost_of_plus_node =
230  MC_switch_cost(plus_node_adj_list, mc.nodes[plus_node].degree,
231  sig.begin(), sig[plus_node]);
232  for ( ; k < m; ++k) {
233  const int i = edges[k].tail;
234  const double costk = 2 * sig[i] * sig[plus_node] * edges[k].cost;
235  // we assume that no single node switch can help at this point ==>
236  // The MC_switch_cost values will be non-negative ==> costk > 0 is a
237  // necessary condition to find improvement.
238  if (costk <= 0.0)
239  continue;
240  const double sum =
242  sig.begin(), sig[i]) +
243  switch_cost_of_plus_node -
244  costk;
245  if (sum < 0) {
246  sig[i] *= -1;
247  sig[plus_node] *= -1;
248  switch_cost_of_plus_node = - switch_cost_of_plus_node + costk;
249  newcost += sum;
250  flag = true;
251 #if MC_TEST_COST_AFTER_EVERY_SWITCH
252  compute_cost(mc.num_edges, mc.edges);
253  if (cost != newcost)
254  abort();
255 #endif
256  }
257  }
258  }
259 #if MC_PRINT_ITER_COUNT
260  printf("MC_solution: edge_switch_improve: %i.\n", iter);
261 #endif
262 
263  compute_cost(mc.num_edges, mc.edges);
264  if (cost != newcost)
265  abort();
266 
267  return cost;
268 }
269 
270 //#############################################################################
271 
272 double
274  const int struct_ind, const int maxiter)
275 {
276  if (mc.num_switch_structures[struct_ind] == 0)
277  return cost;
278 
279  const int s = mc.num_switch_structures[struct_ind];
280  const MC_switch_structure* sw_structs = mc.switch_structures[struct_ind];
281  bool flag = true;
282  int i, k, iter;
283  double sum;
284  double newcost = cost;
285  const MC_graph_edge* edges = mc.edges;
286 
287  for (iter = 0; iter < maxiter && flag; ++iter) {
288  flag = false;
289  for (k = 0; k < s; ++k) {
290  const MC_switch_structure& sw_struct = sw_structs[k];
291  const int * nb = sw_struct.neighbors;
292  sum = 0.0;
293  for (i = sw_struct.num_neighbors - 1; i >= 0; --i) {
294  const MC_graph_edge& e = edges[nb[i]];
295  sum += sig[e.tail] * sig[e.head] * e.cost;
296  }
297  if (sum < 0) {
298  const int * nodes = sw_struct.nodes;
299  for (i = sw_struct.num_nodes - 1; i >= 0; --i) {
300  sig[nodes[i]] *= -1;
301  }
302  newcost += sum;
303  flag = true;
304 #if MC_TEST_COST_AFTER_EVERY_SWITCH
305  compute_cost(mc.num_edges, mc.edges);
306  if (cost != newcost)
307  abort();
308 #endif
309  }
310  }
311  }
312 #if MC_PRINT_ITER_COUNT
313  printf("MC_solution: sw_struct_improve: %i.\n", iter);
314 #endif
315 
316  compute_cost(mc.num_edges, mc.edges);
317  if (cost != newcost)
318  abort();
319 
320  return cost;
321 }
322 
323 //#############################################################################
324 
325 double
327 {
328  const int n = mc.num_nodes;
329  int i, start, end, iter = 0;
330  double sum;
331  double best_sum;
332 
333  start = 0;
334  for (iter = 0; iter < 1000 * maxiter; ++iter) {
335  best_sum = 0.0;
336  sum = 0.0;
337 
338  // Find the first node that does improve
339  for (i = start; i < n; ++i) {
340  sum = MC_switch_cost(mc.nodes[i].adj_list, mc.nodes[i].degree,
341  sig.begin(), sig[i]);
342  if (sum < 0.0)
343  break;
344  }
345  if (sum == 0.0) {
346  for (i = 0; i < start; ++i) {
347  sum = MC_switch_cost(mc.nodes[i].adj_list, mc.nodes[i].degree,
348  sig.begin(), sig[i]);
349  if (sum < 0.0)
350  break;
351  }
352  }
353 
354  if (sum >= 0.0) // No individual node can be switched
355  break;
356 
357  sig[i] *= -1;
358  start = i;
359  best_sum = sum;
360  end = i;
361 
362  // Do the Lin-Kerninghan thingy
363  for (i = start+1; i < n; ++i) {
364  sum += MC_switch_cost(mc.nodes[i].adj_list, mc.nodes[i].degree,
365  sig.begin(), sig[i]);
366  if (sum >= 0)
367  break;
368  sig[i] *= -1;
369  if (sum < best_sum) {
370  best_sum = sum;
371  end = i;
372  }
373  }
374  if (sum < 0) {
375  for (i = 0; i < start; ++i) {
376  sum += MC_switch_cost(mc.nodes[i].adj_list, mc.nodes[i].degree,
377  sig.begin(), sig[i]);
378  if (sum >= 0)
379  break;
380  sig[i] *= -1;
381  if (sum < best_sum) {
382  best_sum = sum;
383  end = i;
384  }
385  }
386  }
387 
388  // Now best_sum must be < 0 and we got to switch the [start,end] part
389  // only, i.e., we got to reverse the switching of (end,i).
390  // Note that i cannot be start since when everything is switched then sum
391  // is 0.0.
392  if (end > i) {
393  for (--i; i >= 0; --i)
394  sig[i] *= -1;
395  i = n;
396  }
397  for (--i; i > end; --i)
398  sig[i] *= -1;
399 
400  const double newcost = cost + best_sum;
401  compute_cost(mc.num_edges, mc.edges);
402  if (cost != newcost)
403  abort();
404 
405  start = (end + 1) %n;
406  }
407 #if MC_PRINT_ITER_COUNT
408  printf("MC_solution: lk_switch_improve: %i.\n", iter);
409 #endif
410 
411  return cost;
412 }
413 
414 //#############################################################################
415 
416 void
417 MC_solution::display(const BCP_string& fname) const
418 {
419  const int num_nodes = sig.size();
420  int objval = static_cast<int>(objective_value());
421 
422  printf("MC_solution:\n");
423  printf("%i\n", objval);
424  for (int i = 0; i < num_nodes; ++i) {
425  printf("%2i\n", sig[i]);
426  }
427  printf("\n");
428 
429  if (fname.length() != 0) {
430  std::ofstream ofile(fname.c_str());
431  ofile << "MC_solution:\n";
432  ofile << objval << "\n";
433  for (int i = 0; i < num_nodes; ++i) {
434  ofile << sig[i] << "\n";
435  }
436  }
437 }
438 
439 //#############################################################################
440 
442  const MC_problem& mc,
443  const int heurswitchround,
444  const bool do_edge_switch_heur,
445  const int struct_switch_heur) :
446  sig(sign)
447 {
448  const int m = mc.num_edges;
449  const MC_graph_edge* edges = mc.edges;
450  const int num_struct_type = mc.num_structure_type;
451 
452  const double percentage[3] = {0.05, 0.01, 0.002};
453 
454  BCP_vec<int> bestsig;
455  double bestcost = BCP_DBL_MAX;
456 
457  int i;
458  bool do_plain_switch = true;
459  bool do_edge_switch = true;
460  bool* do_structure_switch = new bool[num_struct_type];
461  bool do_switch = true;
462 
463  printf("MC: Heur Sol Improvement: ");
464  for (int k = 0; k < 1; ++k) {
465  compute_cost(m, edges);
466 
467  BCP_vec<double> obj;
468  BCP_vec<char> type;
469 
470  obj.push_back(objective_value());
471  type.push_back('o');
472 
473  do_plain_switch = true;
474  do_edge_switch = true;
475  CoinFillN(do_structure_switch, num_struct_type, true);
476  do_switch = true;
477 
478  while (do_switch) {
479  if (do_plain_switch) {
480  switch_improve(mc, heurswitchround);
481  if (obj.back() > objective_value()) {
482  obj.push_back(objective_value());
483  type.push_back('P');
484  // improved, got to do the others, too
485  do_edge_switch = true;
486  CoinFillN(do_structure_switch, num_struct_type, true);
487  }
488  do_plain_switch = false;
489  }
490  if (do_edge_switch) {
491  if (do_edge_switch_heur) {
492  if (!mc.ising_triangles)
493  edge_switch_improve(mc, heurswitchround);
494  else
495  ising_with_external_edge_switch_improve(mc, heurswitchround);
496  if (obj.back() > objective_value()) {
497  obj.push_back(objective_value());
498  type.push_back('E');
499  // improved, got to do the others, too
500  do_plain_switch = true;
501  CoinFillN(do_structure_switch, num_struct_type, true);
502  }
503  }
504  do_edge_switch = false;
505  }
506  for (i = 0; i < num_struct_type; ++i) {
507  if (do_structure_switch[i]) {
508  if ((struct_switch_heur & (1 << i)) != 0) {
509  structure_switch_improve(mc, i, heurswitchround);
510  if (obj.back() > objective_value()) {
511  obj.push_back(objective_value());
512  type.push_back('0'+i);
513  // improved, got to do the others, too
514  do_plain_switch = true;
515  do_edge_switch = true;
516  CoinFillN(do_structure_switch, num_struct_type, true);
517  }
518  }
519  }
520  do_structure_switch[i] = false;
521  }
522 
523  do_switch = do_plain_switch || do_edge_switch;
524  for (i = 0; i < num_struct_type; ++i)
525  do_switch |= do_structure_switch[i];
526  }
527  printf(" %.0f", obj[0]);
528  const int rounds = obj.size();
529  for (i = 1; i < rounds; ++i) {
530  printf(" / %c %.0f", type[i], obj[i]);
531  }
532  printf("\n");
533 
534  if (cost < bestcost) {
535  bestsig = sig;
536  bestcost = cost;
537  }
538 
539  for (i = sig.size() - 1; i >= 0; --i) {
540  if (CoinDrand48() < percentage[k])
541  sig[i] = -sig[i];
542  }
543  }
544 
545  sig = bestsig;
546  cost = bestcost;
547 
548  delete[] do_structure_switch;
549 }
double structure_switch_improve(const MC_problem &mc, const int struct_ind, const int maxiter)
double cost
Definition: MC.hpp:31
BCP_buffer & pack(const T &value)
Pack a single object of type T.
Definition: BCP_buffer.hpp:177
int num_edges
Definition: MC.hpp:92
BCP_buffer & unpack(T &value)
Unpack a single object of type T.
Definition: BCP_buffer.hpp:186
int head
Definition: MC.hpp:30
int neighbor
Definition: MC.hpp:12
int num_nodes
Definition: MC.hpp:91
MC_graph_edge * edges
Definition: MC.hpp:95
const char * c_str() const
Definition: BCP_string.hpp:19
iterator begin()
Return an iterator to the beginning of the object.
Definition: BCP_vector.hpp:99
double edge_switch_improve(const MC_problem &mc, const int maxiter)
int * ising_triangles
Definition: MC.hpp:107
reference back()
Return a reference to the last entry.
Definition: BCP_vector.hpp:133
This class is a very simple impelementation of a constant length string.
Definition: BCP_string.hpp:13
void push_back(const_reference x)
Append x to the end of the vector.
static char * j
Definition: OSdtoa.cpp:3622
MC_solution & operator=(const MC_solution &sol)
Definition: MC_solution.cpp:41
int tail
Definition: MC.hpp:29
MC_switch_structure ** switch_structures
Definition: MC.hpp:111
#define BCP_DBL_MAX
Definition: BCP_math.hpp:6
double compute_cost(const int m, const MC_graph_edge *edges)
Definition: MC_solution.cpp:50
void fint fint fint real fint real real real real real real real real real * e
int degree
Definition: MC.hpp:21
fint end
int length() const
Definition: BCP_string.hpp:16
MC_graph_node * nodes
Definition: MC.hpp:96
void fint fint * k
void fint fint fint fint fint fint fint fint fint fint real real real real real real real real * s
virtual double objective_value() const
The method returning the objective value of the solution.
Definition: MC_solution.hpp:27
Definition: MC.hpp:10
int num_neighbors
Definition: MC.hpp:43
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
double switch_improve(const MC_problem &mc, const int maxiter)
Definition: MC_solution.cpp:87
BCP_buffer & unpack(BCP_buffer &buf)
Definition: MC_solution.cpp:33
fint nb
This class describes the message buffer used for all processes of BCP.
Definition: BCP_buffer.hpp:39
int num_structure_type
Definition: MC.hpp:109
double ising_with_external_edge_switch_improve(const MC_problem &mc, const int maxiter)
MC_adjacency_entry * adj_list
Definition: MC.hpp:22
int * num_switch_structures
Definition: MC.hpp:110
static double MC_switch_cost(const MC_adjacency_entry *adj_list, const int degree, const int *sig, const int this_sig)
Definition: MC_solution.cpp:65
double lk_switch_improve(const MC_problem &mc, const int maxiter)
void fint * m
void fint fint fint fint fint fint fint fint fint fint real real real real real real real real real fint real fint real char real fint fint * maxiter
BCP_vec< int > sig
Definition: MC_solution.hpp:17
void fint * n
void display(const BCP_string &fname) const
double cost
Definition: MC.hpp:14
BCP_buffer & pack(BCP_buffer &buf) const
Definition: MC_solution.cpp:25
int * neighbors
Definition: MC.hpp:45