/home/coin/SVN-release/OS-2.4.0/Bcp/examples/MaxCut/CG/MC_cutgen.cpp

Go to the documentation of this file.
00001 // Copyright (C) 2000, International Business Machines
00002 // Corporation and others.  All Rights Reserved.
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   // randomly reorder the edges so that if not all edges are checked then at
00050   // least we shuffle which ones are checked.
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     // first check if it's a tree edge...
00060     if (parentnode[i] == j || parentnode[j] == i)
00061       continue;
00062     // Check if the cycle is likely to be violated
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     // Otherwise build the paths to the root (root does get on the path, too)
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     // find where do they intersect first (they do intersect, maybe just in
00082     // the root). also, if one of them is on the other's path the ii or jj
00083     // will be -1 after this loop ends.
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     // Compute the lhs of the inequality
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     // Great! A sufficiently violated cycle. create the cut
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   // will do minimum spanning tree based cut gen heuristic. The MST is done
00164   // in a graph where the weight of the edges is min(x, 1-x) + a perturbation
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   // Now if we do not yet have enough cuts then go through every edge and
00214   // check whether the cycle it creates is  violated.
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   // now create the heur solution
00221   MC_solution* sol = new MC_solution(nodesign, mc, heurswitchround,
00222                                      do_edge_switch_heur, struct_switch_heur);
00223   return sol;
00224 }

Generated on Thu Sep 22 03:05:50 2011 by  doxygen 1.4.7