MC_cutgen.cpp
Go to the documentation of this file.
1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others. All Rights Reserved.
3 #include <cmath>
4 #include <algorithm>
5 
6 #include "CoinSort.hpp"
7 #include "BCP_vector.hpp"
8 #include "BCP_matrix.hpp"
9 
10 #include "MC_cut.hpp"
11 #include "MC_solution.hpp"
12 #include "MC.hpp"
13 
14 //#############################################################################
15 
16 void
17 MC_cuts_from_mst(const MC_problem& mc, const double* x, const double minviol,
18  const BCP_vec<int>& nodesign,
19  const BCP_vec<int>& parentnode,
20  const BCP_vec<int>& parentedge,
21  const int maxnewcuts,
22  BCP_vec<BCP_cut*>& new_cuts, BCP_vec<BCP_row*>& new_rows)
23 
24 
25 {
26  const int n = mc.num_nodes;
27  const int m = mc.num_edges;
28  const MC_graph_edge* edges = mc.edges;
29 
30  double* coefs = new double[n];
31  int* posedges = new int[n];
32  int* negedges = new int[n];
33  int pos, neg;
34  double sum;
35 
36  BCP_vec<int> nodepathi;
37  BCP_vec<int> nodepathj;
38  BCP_vec<int> edgepathi;
39  BCP_vec<int> edgepathj;
40 
41  nodepathi.reserve(n+1);
42  nodepathj.reserve(n+1);
43  edgepathi.reserve(n);
44  edgepathj.reserve(n);
45 
46 
47  int ii, jj;
48 
49  // randomly reorder the edges so that if not all edges are checked then at
50  // least we shuffle which ones are checked.
51  int* randomorder = new int[m];
52  CoinIotaN(randomorder, m, 0);
53  std::random_shuffle(randomorder, randomorder + m);
54 
55  for (int l = 0; l < m; ++l) {
56  const int k = randomorder[l];
57  const int i = edges[k].tail;
58  const int j = edges[k].head;
59  // first check if it's a tree edge...
60  if (parentnode[i] == j || parentnode[j] == i)
61  continue;
62  // Check if the cycle is likely to be violated
63 #if 0
64  if ((nodesign[i] == nodesign[j] && x[k] < .3) ||
65  (nodesign[i] != nodesign[j] && x[k] > .7))
66  continue;
67 #endif
68  // Otherwise build the paths to the root (root does get on the path, too)
69  nodepathi.clear();
70  nodepathj.clear();
71  edgepathi.clear();
72  edgepathj.clear();
73  for (ii = i; ii != -1; ii = parentnode[ii]) {
74  nodepathi.unchecked_push_back(ii);
75  edgepathi.unchecked_push_back(parentedge[ii]);
76  }
77  for (jj = j; jj != -1; jj = parentnode[jj]) {
78  nodepathj.unchecked_push_back(jj);
79  edgepathj.unchecked_push_back(parentedge[jj]);
80  }
81  // find where do they intersect first (they do intersect, maybe just in
82  // the root). also, if one of them is on the other's path the ii or jj
83  // will be -1 after this loop ends.
84  for (ii = nodepathi.size()-1, jj = nodepathj.size()-1;
85  ii >= 0 && jj >= 0; --ii, --jj) {
86  if (nodepathi[ii] != nodepathj[jj])
87  break;
88  }
89 
90  // Compute the lhs of the inequality
91  sum = 0.0;
92  pos = 0;
93  neg = 0;
94  if (nodesign[i] == nodesign[j]) {
95  sum = x[k];
96  posedges[pos++] = k;
97  } else {
98  sum = -x[k];
99  negedges[neg++] = k;
100  }
101  for ( ; ii >= 0; --ii) {
102  const int p0 = nodepathi[ii];
103  const int p1 = nodepathi[ii+1];
104  const int path_ind = edgepathi[ii];
105  if (nodesign[p0] == nodesign[p1]) {
106  sum -= x[path_ind];
107  negedges[neg++] = path_ind;
108  } else {
109  sum += x[path_ind];
110  posedges[pos++] = path_ind;
111  }
112  }
113  for ( ; jj >= 0; --jj) {
114  const int p0 = nodepathj[jj];
115  const int p1 = nodepathj[jj+1];
116  const int path_ind = edgepathj[jj];
117  if (nodesign[p0] == nodesign[p1]) {
118  sum -= x[path_ind];
119  negedges[neg++] = path_ind;
120  } else {
121  sum += x[path_ind];
122  posedges[pos++] = path_ind;
123  }
124  }
125  if (sum <= pos - 1.0 + minviol)
126  continue;
127 
128  if ((pos % 2) != 1)
129  abort();
130  // Great! A sufficiently violated cycle. create the cut
131  const int len = pos + neg;
132  CoinDisjointCopyN(negedges, neg, posedges + pos);
133  new_cuts.push_back(new MC_cycle_cut(posedges, pos, len));
134  CoinFillN(coefs, pos, 1.0);
135  CoinFillN(coefs + pos, neg, -1.0);
136  CoinSort_2(posedges, posedges + len, coefs);
137  new_rows.push_back(new BCP_row(posedges, posedges + len,
138  coefs, coefs + len, -BCP_DBL_MAX, pos - 1));
139  if (static_cast<int>(new_cuts.size()) >= maxnewcuts)
140  break;
141  }
142 
143  delete[] randomorder;
144  delete[] negedges;
145  delete[] posedges;
146  delete[] coefs;
147 }
148 
149 //#############################################################################
150 
152 MC_mst_cutgen(const MC_problem& mc, const double* x, const double* w,
153  const double alpha, const double beta,
154  const MC_EdgeOrdering edge_ordering,
155  const int heurswitchround,
156  const bool do_edge_switch_heur, const int struct_switch_heur,
157  const double minviol, const int maxnewcuts,
158  BCP_vec<BCP_cut*>& new_cuts, BCP_vec<BCP_row*>& new_rows)
159 {
160  const int n = mc.num_nodes;
161  const int m = mc.num_edges;
162 
163  // will do minimum spanning tree based cut gen heuristic. The MST is done
164  // in a graph where the weight of the edges is min(x, 1-x) + a perturbation
165  BCP_vec<double> weights;
166  BCP_vec<int> edgeorder;
167  weights.reserve(m);
168  edgeorder.reserve(m);
169 
170  int i;
171 
172  switch (edge_ordering) {
174  if (w == NULL || beta == 0.0) {
175  for (i = 0; i < m; ++i)
176  weights.unchecked_push_back( alpha * x[i] );
177  } else {
178  for (i = 0; i < m; ++i)
179  weights.unchecked_push_back(alpha * x[i] - beta * w[i]);
180  }
181  break;
183  if (w == NULL || beta == 0.0) {
184  for (i = 0; i < m; ++i)
185  weights.unchecked_push_back( alpha * (1.0-x[i]) );
186  } else {
187  for (i = 0; i < m; ++i)
188  weights.unchecked_push_back(alpha * (1.0-x[i]) - beta * w[i]);
189  }
190  break;
192  if (w == NULL || beta == 0.0) {
193  for (i = 0; i < m; ++i)
194  weights.unchecked_push_back( alpha * CoinMin(x[i], 1.0-x[i]) );
195  } else {
196  for (i = 0; i < m; ++i)
197  weights.unchecked_push_back(alpha*CoinMin(x[i], 1.0-x[i]) - beta*w[i]);
198  }
199  break;
200  }
201  for (i = 0; i < m; ++i)
202  edgeorder.unchecked_push_back(i);
203 
204  CoinSort_2(weights.begin(), weights.end(), edgeorder.begin());
205 
206  BCP_vec<int> parentnode(n, -1);
207  BCP_vec<int> parentedge(n, -1);
208  BCP_vec<int> nodesign(n, 1);
209 
210  MC_kruskal(mc, edgeorder.begin(), x, nodesign.begin(),
211  parentnode.begin(), parentedge.begin());
212 
213  // Now if we do not yet have enough cuts then go through every edge and
214  // check whether the cycle it creates is violated.
215  if (static_cast<int>(new_cuts.size()) < maxnewcuts)
216  MC_cuts_from_mst(mc, x, minviol,
217  nodesign, parentnode, parentedge,
218  maxnewcuts, new_cuts, new_rows);
219 
220  // now create the heur solution
221  MC_solution* sol = new MC_solution(nodesign, mc, heurswitchround,
222  do_edge_switch_heur, struct_switch_heur);
223  return sol;
224 }
MC_solution * MC_mst_cutgen(const MC_problem &mc, const double *x, const double *w, const double alpha, const double beta, const MC_EdgeOrdering edge_ordering, const int heurswitchround, const bool do_edge_switch_heur, const int struct_switch_heur, const double minviol, const int maxnewcuts, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Definition: MC_cutgen.cpp:152
void MC_cuts_from_mst(const MC_problem &mc, const double *x, const double minviol, const BCP_vec< int > &nodesign, const BCP_vec< int > &parentnode, const BCP_vec< int > &parentedge, const int maxnewcuts, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Definition: MC_cutgen.cpp:17
int num_edges
Definition: MC.hpp:92
pos
position where the operator should be printed when printing the expression
void clear()
Delete every entry.
int head
Definition: MC.hpp:30
int num_nodes
Definition: MC.hpp:91
MC_graph_edge * edges
Definition: MC.hpp:95
iterator begin()
Return an iterator to the beginning of the object.
Definition: BCP_vector.hpp:99
void reserve(const size_t n)
Reallocate the object to make space for n entries.
void MC_kruskal(const MC_problem &mc, const int *edgeorder, const double *x, int *nodesign, int *edges_in_tree)
Definition: MC_kruskal.cpp:33
void push_back(const_reference x)
Append x to the end of the vector.
static char * j
Definition: OSdtoa.cpp:3622
real alpha
int tail
Definition: MC.hpp:29
#define BCP_DBL_MAX
Definition: BCP_math.hpp:6
void fint fint * k
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
iterator end()
Return an iterator to the end of the object.
Definition: BCP_vector.hpp:104
void unchecked_push_back(const_reference x)
Append x to the end of the vector.
void fint * m
void fint fint fint real fint real real real real real real real real * w
void fint * n
MC_EdgeOrdering
Definition: MC_cut.hpp:26
void fint fint fint real fint real * x
This class holds a row in a compressed form.
Definition: BCP_matrix.hpp:152