00001
00002
00003 #include <cmath>
00004 #include <algorithm>
00005
00006 #include "CoinSort.hpp"
00007 #include "BCP_vector.hpp"
00008 #include "BCP_matrix.hpp"
00009
00010 #include "MC_cut.hpp"
00011 #include "MC_solution.hpp"
00012 #include "MC.hpp"
00013
00014
00015
00016 void
00017 MC_cuts_from_mst(const MC_problem& mc, const double* x, const double minviol,
00018 const BCP_vec<int>& nodesign,
00019 const BCP_vec<int>& parentnode,
00020 const BCP_vec<int>& parentedge,
00021 const int maxnewcuts,
00022 BCP_vec<BCP_cut*>& new_cuts, BCP_vec<BCP_row*>& new_rows)
00023
00024
00025 {
00026 const int n = mc.num_nodes;
00027 const int m = mc.num_edges;
00028 const MC_graph_edge* edges = mc.edges;
00029
00030 double* coefs = new double[n];
00031 int* posedges = new int[n];
00032 int* negedges = new int[n];
00033 int pos, neg;
00034 double sum;
00035
00036 BCP_vec<int> nodepathi;
00037 BCP_vec<int> nodepathj;
00038 BCP_vec<int> edgepathi;
00039 BCP_vec<int> edgepathj;
00040
00041 nodepathi.reserve(n+1);
00042 nodepathj.reserve(n+1);
00043 edgepathi.reserve(n);
00044 edgepathj.reserve(n);
00045
00046
00047 int ii, jj;
00048
00049
00050
00051 int* randomorder = new int[m];
00052 CoinIotaN(randomorder, m, 0);
00053 std::random_shuffle(randomorder, randomorder + m);
00054
00055 for (int l = 0; l < m; ++l) {
00056 const int k = randomorder[l];
00057 const int i = edges[k].tail;
00058 const int j = edges[k].head;
00059
00060 if (parentnode[i] == j || parentnode[j] == i)
00061 continue;
00062
00063 #if 0
00064 if ((nodesign[i] == nodesign[j] && x[k] < .3) ||
00065 (nodesign[i] != nodesign[j] && x[k] > .7))
00066 continue;
00067 #endif
00068
00069 nodepathi.clear();
00070 nodepathj.clear();
00071 edgepathi.clear();
00072 edgepathj.clear();
00073 for (ii = i; ii != -1; ii = parentnode[ii]) {
00074 nodepathi.unchecked_push_back(ii);
00075 edgepathi.unchecked_push_back(parentedge[ii]);
00076 }
00077 for (jj = j; jj != -1; jj = parentnode[jj]) {
00078 nodepathj.unchecked_push_back(jj);
00079 edgepathj.unchecked_push_back(parentedge[jj]);
00080 }
00081
00082
00083
00084 for (ii = nodepathi.size()-1, jj = nodepathj.size()-1;
00085 ii >= 0 && jj >= 0; --ii, --jj) {
00086 if (nodepathi[ii] != nodepathj[jj])
00087 break;
00088 }
00089
00090
00091 sum = 0.0;
00092 pos = 0;
00093 neg = 0;
00094 if (nodesign[i] == nodesign[j]) {
00095 sum = x[k];
00096 posedges[pos++] = k;
00097 } else {
00098 sum = -x[k];
00099 negedges[neg++] = k;
00100 }
00101 for ( ; ii >= 0; --ii) {
00102 const int p0 = nodepathi[ii];
00103 const int p1 = nodepathi[ii+1];
00104 const int path_ind = edgepathi[ii];
00105 if (nodesign[p0] == nodesign[p1]) {
00106 sum -= x[path_ind];
00107 negedges[neg++] = path_ind;
00108 } else {
00109 sum += x[path_ind];
00110 posedges[pos++] = path_ind;
00111 }
00112 }
00113 for ( ; jj >= 0; --jj) {
00114 const int p0 = nodepathj[jj];
00115 const int p1 = nodepathj[jj+1];
00116 const int path_ind = edgepathj[jj];
00117 if (nodesign[p0] == nodesign[p1]) {
00118 sum -= x[path_ind];
00119 negedges[neg++] = path_ind;
00120 } else {
00121 sum += x[path_ind];
00122 posedges[pos++] = path_ind;
00123 }
00124 }
00125 if (sum <= pos - 1.0 + minviol)
00126 continue;
00127
00128 if ((pos % 2) != 1)
00129 abort();
00130
00131 const int len = pos + neg;
00132 CoinDisjointCopyN(negedges, neg, posedges + pos);
00133 new_cuts.push_back(new MC_cycle_cut(posedges, pos, len));
00134 CoinFillN(coefs, pos, 1.0);
00135 CoinFillN(coefs + pos, neg, -1.0);
00136 CoinSort_2(posedges, posedges + len, coefs);
00137 new_rows.push_back(new BCP_row(posedges, posedges + len,
00138 coefs, coefs + len, -BCP_DBL_MAX, pos - 1));
00139 if (static_cast<int>(new_cuts.size()) >= maxnewcuts)
00140 break;
00141 }
00142
00143 delete[] randomorder;
00144 delete[] negedges;
00145 delete[] posedges;
00146 delete[] coefs;
00147 }
00148
00149
00150
00151 MC_solution*
00152 MC_mst_cutgen(const MC_problem& mc, const double* x, const double* w,
00153 const double alpha, const double beta,
00154 const MC_EdgeOrdering edge_ordering,
00155 const int heurswitchround,
00156 const bool do_edge_switch_heur, const int struct_switch_heur,
00157 const double minviol, const int maxnewcuts,
00158 BCP_vec<BCP_cut*>& new_cuts, BCP_vec<BCP_row*>& new_rows)
00159 {
00160 const int n = mc.num_nodes;
00161 const int m = mc.num_edges;
00162
00163
00164
00165 BCP_vec<double> weights;
00166 BCP_vec<int> edgeorder;
00167 weights.reserve(m);
00168 edgeorder.reserve(m);
00169
00170 int i;
00171
00172 switch (edge_ordering) {
00173 case MC_MstEdgeOrderingPreferZero:
00174 if (w == NULL || beta == 0.0) {
00175 for (i = 0; i < m; ++i)
00176 weights.unchecked_push_back( alpha * x[i] );
00177 } else {
00178 for (i = 0; i < m; ++i)
00179 weights.unchecked_push_back(alpha * x[i] - beta * w[i]);
00180 }
00181 break;
00182 case MC_MstEdgeOrderingPreferOne:
00183 if (w == NULL || beta == 0.0) {
00184 for (i = 0; i < m; ++i)
00185 weights.unchecked_push_back( alpha * (1.0-x[i]) );
00186 } else {
00187 for (i = 0; i < m; ++i)
00188 weights.unchecked_push_back(alpha * (1.0-x[i]) - beta * w[i]);
00189 }
00190 break;
00191 case MC_MstEdgeOrderingPreferExtreme:
00192 if (w == NULL || beta == 0.0) {
00193 for (i = 0; i < m; ++i)
00194 weights.unchecked_push_back( alpha * CoinMin(x[i], 1.0-x[i]) );
00195 } else {
00196 for (i = 0; i < m; ++i)
00197 weights.unchecked_push_back(alpha*CoinMin(x[i], 1.0-x[i]) - beta*w[i]);
00198 }
00199 break;
00200 }
00201 for (i = 0; i < m; ++i)
00202 edgeorder.unchecked_push_back(i);
00203
00204 CoinSort_2(weights.begin(), weights.end(), edgeorder.begin());
00205
00206 BCP_vec<int> parentnode(n, -1);
00207 BCP_vec<int> parentedge(n, -1);
00208 BCP_vec<int> nodesign(n, 1);
00209
00210 MC_kruskal(mc, edgeorder.begin(), x, nodesign.begin(),
00211 parentnode.begin(), parentedge.begin());
00212
00213
00214
00215 if (static_cast<int>(new_cuts.size()) < maxnewcuts)
00216 MC_cuts_from_mst(mc, x, minviol,
00217 nodesign, parentnode, parentedge,
00218 maxnewcuts, new_cuts, new_rows);
00219
00220
00221 MC_solution* sol = new MC_solution(nodesign, mc, heurswitchround,
00222 do_edge_switch_heur, struct_switch_heur);
00223 return sol;
00224 }