/home/coin/SVN-release/OS-2.4.1/Bcp/examples/MCF-1/LP/MCF1_lp.cpp

Go to the documentation of this file.
00001 #include "CoinHelperFunctions.hpp"
00002 #include "OsiClpSolverInterface.hpp"
00003 #include "BCP_lp.hpp"
00004 #include "MCF1_lp.hpp"
00005 
00006 //#############################################################################
00007 
00008 OsiSolverInterface* MCF1_lp::initialize_solver_interface()
00009 {
00010   return new OsiClpSolverInterface;
00011 }
00012 
00013 //#############################################################################
00014 
00015 void
00016 MCF1_adjust_bounds(const BCP_vec<BCP_var*>& vars,
00017                    std::vector<MCF1_branch_decision>* history,
00018                    BCP_vec<int>& var_changed_pos,
00019                    BCP_vec<double>& var_new_bd)
00020 {
00021   for (int i = vars.size()-1; i >= 0; --i) {
00022     MCF1_var* v = dynamic_cast<MCF1_var*>(vars[i]);
00023     if (!v) continue;
00024     const int vsize = v->flow.getNumElements();
00025     const int* vind = v->flow.getIndices();
00026     const double* vval = v->flow.getElements();
00027 
00028     bool violated = false;
00029     const std::vector<MCF1_branch_decision>& hist = history[v->commodity];
00030     for (int j = hist.size()-1; !violated && j >= 0; --j) {
00031       const MCF1_branch_decision& h = hist[j];
00032       double f = 0.0;
00033       for (int k = 0; k < vsize; ++k) {
00034         if (vind[k] == h.arc_index) {
00035           f = vval[k];
00036           break;
00037         }
00038       }
00039       violated = (f < h.lb || f > h.ub);
00040     }
00041     if (violated) {
00042       var_changed_pos.push_back(i);
00043       var_new_bd.push_back(0.0); // the new lower bound on the var
00044       var_new_bd.push_back(0.0); // the new upper bound on the var
00045     }
00046   }
00047 }
00048 
00049 /*---------------------------------------------------------------------------*/
00050 
00051 void
00052 MCF1_adjust_bounds(const BCP_vec<BCP_var*>& vars,
00053                    const int commodity,
00054                    const MCF1_branch_decision& decision,
00055                    BCP_vec<int>& var_changed_pos,
00056                    BCP_vec<double>& var_new_bd)
00057 {
00058   for (int i = vars.size()-1; i >= 0; --i) {
00059     MCF1_var* v = dynamic_cast<MCF1_var*>(vars[i]);
00060     if (!v)
00061       continue;
00062     if (v->commodity != commodity)
00063       continue;
00064     const int vsize = v->flow.getNumElements();
00065     const int* vind = v->flow.getIndices();
00066     const double* vval = v->flow.getElements();
00067 
00068     double f = 0.0;
00069     for (int k = 0; k < vsize; ++k) {
00070       if (vind[k] == decision.arc_index) {
00071         f = vval[k];
00072         break;
00073       }
00074     }
00075     if (f < decision.lb || f > decision.ub) {
00076       var_changed_pos.push_back(i);
00077       var_new_bd.push_back(0.0); // the new lower bound on the var
00078       var_new_bd.push_back(0.0); // the new upper bound on the var
00079     }
00080   }
00081 }
00082 
00083 /*---------------------------------------------------------------------------*/
00084 
00085 void MCF1_lp::
00086 initialize_new_search_tree_node(const BCP_vec<BCP_var*>& vars,
00087                                 const BCP_vec<BCP_cut*>& cuts,
00088                                 const BCP_vec<BCP_obj_status>& var_status,
00089                                 const BCP_vec<BCP_obj_status>& cut_status,
00090                                 BCP_vec<int>& var_changed_pos,
00091                                 BCP_vec<double>& var_new_bd,
00092                                 BCP_vec<int>& cut_changed_pos,
00093                                 BCP_vec<double>& cut_new_bd)
00094 {
00095   // Go through all the variables, select the MCF1_branching_var's and save
00096   // the upper/lower bounds to be applied in the subproblems
00097   int i;
00098   for (i = data.numcommodities-1; i >= 0; --i) {
00099     branch_history[i].clear();
00100   }
00101   for (i = vars.size()-1; i >= 0; --i) {
00102     MCF1_branching_var* v = dynamic_cast<MCF1_branching_var*>(vars[i]);
00103     if (v) {
00104       if (v->ub() == 0.0) {
00105         // the upper bound of the branching var in this child is set
00106         // to 0, so we are in child 0v->lb_child0
00107         branch_history[v->commodity].
00108           push_back(MCF1_branch_decision(v->arc_index,
00109                                          v->lb_child0,
00110                                          v->ub_child0));
00111       } else {
00112         branch_history[v->commodity].
00113           push_back(MCF1_branch_decision(v->arc_index,
00114                                          v->lb_child1,
00115                                          v->ub_child1));
00116       }
00117     }
00118   }
00119 
00120   MCF1_adjust_bounds(vars, branch_history, var_changed_pos, var_new_bd);
00121 
00122   // clear out our local pool
00123   purge_ptr_vector(gen_vars);
00124 }
00125 
00126 /*---------------------------------------------------------------------------*/
00127 
00128 BCP_solution* MCF1_lp::
00129 test_feasibility(const BCP_lp_result& lpres,
00130                  const BCP_vec<BCP_var*>& vars,
00131                  const BCP_vec<BCP_cut*>& cuts)
00132 {
00133 #if 0
00134   static int cnt = 0;
00135   char name[100];
00136   sprintf(name, "currlp-%i", cnt++);
00137   // sprintf(name, "currlp");
00138   getLpProblemPointer()->lp_solver->writeMps(name, "mps");
00139   printf("Current LP written in file %s.mps\n", name);
00140   getLpProblemPointer()->lp_solver->writeLp(name, "lp");
00141   printf("Current LP written in file %s.lp\n", name);
00142 #endif
00143 
00144   // Feasibility testing: we need to test whether the convex combination of
00145   // the current columns (according to \lambda, the current primal solution)
00146   // is integer feasible for the original problem. The only thing that can
00147   // be violated is integrality.
00148   
00149   int i, j;
00150   for (i = data.numcommodities-1; i >= 0; --i) {
00151     flows[i].clear();
00152   }
00153 
00154   const double* x = lpres.x();
00155   for (i = vars.size()-1; i >= 0; --i) {
00156     MCF1_var* v = dynamic_cast<MCF1_var*>(vars[i]);
00157     if (!v) continue;
00158     std::map<int,double>& f = flows[v->commodity];
00159     const int vsize = v->flow.getNumElements();
00160     const int* vind = v->flow.getIndices();
00161     const double* vval = v->flow.getElements();
00162     for (j = 0; j < vsize; ++j) {
00163       f[vind[j]] += vval[j]*x[i];
00164     }
00165   }
00166   for (i = data.numcommodities-1; i >= 0; --i) {
00167     std::map<int,double>& f = flows[i];
00168     for (std::map<int,double>::iterator fi=f.begin(); fi != f.end(); ++fi) {
00169       const double frac = fabs(fi->second - floor(fi->second) - 0.5);
00170       if (frac < 0.5-1e-6)
00171         return NULL;
00172     }
00173   }
00174 
00175   // Found an integer solution
00176   BCP_solution_generic* gsol = new BCP_solution_generic;
00177   for (i = data.numcommodities-1; i >= 0; --i) {
00178     std::map<int,double>& f = flows[i];
00179     CoinPackedVector flow(false);
00180     double weight = 0;
00181     for (std::map<int,double>::iterator fi=f.begin();
00182          fi != f.end();
00183          ++fi) {
00184       const double val = floor(fi->second + 0.5);
00185       if (val > 0) {
00186         flow.insert(fi->first, val);
00187         weight += val * data.arcs[fi->first].weight;
00188       }
00189     }
00190     gsol->add_entry(new MCF1_var(i, flow, weight), 1.0);
00191   }
00192   return gsol;
00193 }
00194 
00195 /*---------------------------------------------------------------------------*/
00196 
00197 double MCF1_lp::
00198 compute_lower_bound(const double old_lower_bound,
00199                     const BCP_lp_result& lpres,
00200                     const BCP_vec<BCP_var*>& vars,
00201                     const BCP_vec<BCP_cut*>& cuts)
00202 {
00203   // To compute a true lower bound we need to generate variables first (if
00204   // we can). These are saved so that we can return them in
00205   // generate_vars_in_lp.
00206 
00207   // generate variables:  for each commodity generate a flow.
00208 
00209   const int numarcs = data.numarcs;
00210   double* cost = new double[numarcs];
00211   const double* pi = lpres.pi();
00212   const double* nu = pi + numarcs;
00213 
00214   int i, j;
00215 
00216   for (i = numarcs-1; i >= 0; --i) {
00217     cost[i] = data.arcs[i].weight - pi[i];
00218   }
00219   cg_lp->setObjective(cost);
00220 
00221   // This will hold generated variables
00222   int* ind = new int[numarcs];
00223   double* val = new double[numarcs];
00224   int cnt = 0;
00225 
00226   for (i = data.numcommodities-1; i >= 0; --i) {
00227     const MCF1_data::commodity& comm = data.commodities[i];
00228     cg_lp->setRowBounds(comm.source, -comm.demand, -comm.demand);
00229     cg_lp->setRowBounds(comm.sink, comm.demand, comm.demand);
00230     const std::vector<MCF1_branch_decision>& hist = branch_history[i];
00231     for (j = hist.size() - 1; j >= 0; --j) {
00232       const MCF1_branch_decision& h = hist[j];
00233       cg_lp->setColBounds(h.arc_index, h.lb, h.ub);
00234     }
00235     cg_lp->initialSolve();
00236     if (cg_lp->isProvenOptimal() && cg_lp->getObjValue() < nu[i] - 1e-8) {
00237       // we have generated a column. Create a var out of it. Round the
00238       // double values while we are here, after all, they should be
00239       // integer. there can only be some tiny roundoff error by the LP
00240       // solver
00241       const double* x = cg_lp->getColSolution();
00242       cnt = 0;
00243       double obj = 0.0;
00244       for (int j = 0; j < numarcs; ++j) {
00245         const double xval = floor(x[j] + 0.5);
00246         if (xval != 0.0) {
00247           ind[cnt] = j;
00248           val[cnt] = xval;
00249           ++cnt;
00250           obj += data.arcs[j].weight * xval;
00251         }
00252       }
00253       gen_vars.push_back(new MCF1_var(i, CoinPackedVector(cnt, ind, val,
00254                                                           false), obj));
00255     }
00256     for (j = hist.size() - 1; j >= 0; --j) {
00257       const int ind = hist[j].arc_index;
00258       cg_lp->setColBounds(ind, data.arcs[ind].lb, data.arcs[ind].ub);
00259     }
00260     cg_lp->setRowBounds(comm.source, 0, 0);
00261     cg_lp->setRowBounds(comm.sink, 0, 0);
00262   }
00263   delete[] val;
00264   delete[] ind;
00265   delete[] cost;
00266 
00267   // Excercise: do the same in a random order and apply dual discounting
00268   // Not yet implemented.
00269 
00270   // Now get a true lower bound
00271   double true_lower_bound = 0.0;
00272   generated_vars = (gen_vars.size() > 0);
00273 
00274   if (generated_vars) {
00275     true_lower_bound = old_lower_bound;
00276   } else {
00277     true_lower_bound = lpres.objval();
00278   }
00279 
00280   // Excercise: Get a better true lower bound
00281   // Hint: lpres.objval() + The sum of the reduced costs of the
00282   // variables with the most negative reduced cost in each subproblem
00283   // yield a true lower bound
00284   // Not yet implemented.
00285 
00286   return true_lower_bound;
00287 }
00288 
00289 /*---------------------------------------------------------------------------*/
00290 
00291 void MCF1_lp::
00292 generate_vars_in_lp(const BCP_lp_result& lpres,
00293                     const BCP_vec<BCP_var*>& vars,
00294                     const BCP_vec<BCP_cut*>& cuts,
00295                     const bool before_fathom,
00296                     BCP_vec<BCP_var*>& new_vars,
00297                     BCP_vec<BCP_col*>& new_cols)
00298 {
00299   new_vars.append(gen_vars);
00300   gen_vars.clear();
00301 }
00302 
00303 /*---------------------------------------------------------------------------*/
00304 
00305 void MCF1_lp::
00306 vars_to_cols(const BCP_vec<BCP_cut*>& cuts,
00307              BCP_vec<BCP_var*>& vars,
00308              BCP_vec<BCP_col*>& cols,
00309              const BCP_lp_result& lpres,
00310              BCP_object_origin origin, bool allow_multiple)
00311 {
00312   static const CoinPackedVector emptyVector(false);
00313   const int numvars = vars.size();
00314   for (int i = 0; i < numvars; ++i) {
00315     const MCF1_var* v =
00316       dynamic_cast<const MCF1_var*>(vars[i]);
00317     if (v) {
00318       // Since we do not generate cuts, we can just disregard the "cuts"
00319       // argument, since the column corresponding to the var is exactly
00320       // the flow (plus the entry in the appropriate convexity
00321       // constraint)
00322       BCP_col* col = new BCP_col(v->flow, v->weight, 0.0, 1.0);
00323       col->insert(data.numarcs + v->commodity, 1.0);
00324       cols.push_back(col);
00325       // Excercise: if we had generated cuts, then the coefficients for
00326       // those rows would be appended to the end of each column
00327       continue;
00328     }
00329     const MCF1_branching_var* bv =
00330       dynamic_cast<const MCF1_branching_var*>(vars[i]);
00331     if (bv) {
00332       cols.push_back(new BCP_col(emptyVector, 0.0, bv->lb(), bv->ub()));
00333     }
00334   }
00335 }
00336 
00337 /*---------------------------------------------------------------------------*/
00338 
00339 BCP_branching_decision MCF1_lp::
00340 select_branching_candidates(const BCP_lp_result& lpres,
00341                             const BCP_vec<BCP_var*>& vars,
00342                             const BCP_vec<BCP_cut*>& cuts,
00343                             const BCP_lp_var_pool& local_var_pool,
00344                             const BCP_lp_cut_pool& local_cut_pool,
00345                             BCP_vec<BCP_lp_branching_object*>& cands,
00346                             bool force_branch)
00347 {
00348   if (generated_vars > 0) {
00349     return BCP_DoNotBranch;
00350   }
00351 
00352   if (lpres.objval() > upper_bound() - 1e-6) {
00353     return BCP_DoNotBranch_Fathomed;
00354   }
00355 
00356   int i, j;
00357 
00358   const int dummyStart = par.entry(MCF1_par::AddDummySourceSinkArcs) ?
00359     data.numarcs - data.numcommodities : data.numarcs;
00360                 
00361   // find a few fractional original variables and do strong branching on them
00362   for (i = data.numcommodities-1; i >= 0; --i) {
00363     std::map<int,double>& f = flows[i];
00364     int most_frac_ind = -1;
00365     double most_frac_val = 0.5-1e-6;
00366     double frac_val = 0.0;
00367     for (std::map<int,double>::iterator fi=f.begin(); fi != f.end(); ++fi){
00368       if (fi->first >= dummyStart)
00369         continue;
00370       const double frac = fabs(fi->second - floor(fi->second) - 0.5);
00371       if (frac < most_frac_val) {
00372         most_frac_ind = fi->first;
00373         most_frac_val = frac;
00374         frac_val = fi->second;
00375       }
00376     }
00377     if (most_frac_ind >= 0) {
00378       BCP_vec<BCP_var*> new_vars;
00379       BCP_vec<int> fvp;
00380       BCP_vec<double> fvb;
00381       int lb = data.arcs[most_frac_ind].lb;
00382       int ub = data.arcs[most_frac_ind].ub;
00383       for (j = branch_history[i].size() - 1; j >= 0; --j) {
00384         // To correctly set lb/ub we need to check whether we have
00385         // already branched on this arc
00386         const MCF1_branch_decision& h = branch_history[i][j];
00387         if (h.arc_index == most_frac_ind) {
00388           lb = CoinMax(lb, h.lb);
00389           ub = CoinMin(ub, h.ub);
00390         }
00391       }
00392       const int mid = static_cast<int>(floor(frac_val));
00393       new_vars.push_back(new MCF1_branching_var(i, most_frac_ind,
00394                                                 lb, mid, mid+1, ub));
00395       // Look at the consequences of of this branch
00396       BCP_vec<int> child0_pos, child1_pos;
00397       BCP_vec<double> child0_bd, child1_bd;
00398 
00399       MCF1_branch_decision child0(most_frac_ind, lb, mid);
00400       MCF1_adjust_bounds(vars, i, child0, child0_pos, child0_bd);
00401 
00402       MCF1_branch_decision child1(most_frac_ind, mid+1, ub);
00403       MCF1_adjust_bounds(vars, i, child1, child1_pos, child1_bd);
00404 
00405       // Now put together the changes
00406       fvp.push_back(-1);
00407       fvp.append(child0_pos);
00408       fvp.append(child1_pos);
00409       fvb.push_back(0.0);
00410       fvb.push_back(0.0);
00411       fvb.append(child0_bd);
00412       for (j = child1_pos.size() - 1; j >= 0; --j) {
00413         fvb.push_back(0.0);
00414         fvb.push_back(1.0);
00415       }
00416       fvb.push_back(1.0);
00417       fvb.push_back(1.0);
00418       for (j = child0_pos.size() - 1; j >= 0; --j) {
00419         fvb.push_back(0.0);
00420         fvb.push_back(1.0);
00421       }
00422       fvb.append(child1_bd);
00423       cands.push_back(new BCP_lp_branching_object(2, // num of children
00424                                                   &new_vars,
00425                                                   NULL, // no new cuts
00426                                                   &fvp,NULL,&fvb,NULL,
00427                                                   NULL,NULL,NULL,NULL));
00428     }
00429   }
00430   return BCP_DoBranch;
00431 }
00432 
00433 /*===========================================================================*/
00434 
00435 void MCF1_lp::
00436 unpack_module_data(BCP_buffer& buf)
00437 {
00438   par.unpack(buf);
00439   data.unpack(buf);
00440 
00441   // This is the place where we can preallocate some data structures
00442   branch_history = new std::vector<MCF1_branch_decision>[data.numcommodities];
00443   flows = new std::map<int,double>[data.numcommodities];
00444 
00445   // Create the LP that will be used to generate columns
00446   cg_lp = new OsiClpSolverInterface();
00447 
00448   const int numCols = data.numarcs;
00449   const int numRows = data.numnodes;
00450   const int numNz = 2*numCols;
00451 
00452   double *clb = new double[numCols];
00453   double *cub = new double[numCols];
00454   double *obj = new double[numCols];
00455   double *rlb = new double[numRows];
00456   double *rub = new double[numRows];
00457   CoinBigIndex *start = new int[numCols+1];
00458   int *index = new int[numNz];
00459   double *value = new double[numNz];
00460 
00461   // all these will be properly set for the search tree node in the
00462   // initialize_new_search_tree_node method
00463   CoinZeroN(obj, numCols);
00464   CoinZeroN(clb, numCols);
00465   for (int i = numCols - 1; i >= 0; --i) {
00466     cub[i] = data.arcs[i].ub;
00467   }
00468   // and these will be properly set for the subproblem in the
00469   // generate_vars_in_lp method
00470   CoinZeroN(rlb, numRows);
00471   CoinZeroN(rub, numRows);
00472 
00473   for (int i = 0; i < data.numarcs; ++i) {
00474     start[i] = 2*i;
00475     index[2*i] = data.arcs[i].tail;
00476     index[2*i+1] = data.arcs[i].head;
00477     value[2*i] = -1;
00478     value[2*i+1] = 1;
00479   }
00480   start[numCols] = 2*numCols;
00481 
00482   cg_lp->loadProblem(numCols, numRows, start, index, value,
00483                      clb, cub, obj, rlb, rub);
00484 
00485   delete[] value;
00486   delete[] index;
00487   delete[] start;
00488   delete[] rub;
00489   delete[] rlb;
00490   delete[] obj;
00491   delete[] cub;
00492   delete[] clb;
00493 }                       

Generated on Thu Nov 10 03:05:37 2011 by  doxygen 1.4.7