Main Page | Class Hierarchy | File List

AAP_lp.cpp

00001 // $Id: AAP_lp.cpp,v 1.3 2003/12/03 01:52:30 magh Exp $
00002 
00003 /* ------------------------------------------------------------------------
00004  Author: Matthew Galati (magh@lehigh.edu)
00005 
00006  (c) Copyright 2003 Lehigh University. All Rights Reserved.
00007 
00008  This software is licensed under the Common Public License. Please see 
00009  accompanying file for terms.    
00010 ---------------------------------------------------------------------------*/
00011 
00012 #ifdef COIN_USE_CPX
00013 #include "OsiCpxSolverInterface.hpp"
00014 #include "cplex.h"
00015 typedef OsiCpxSolverInterface OsiXxxSolverInterface;
00016 #endif
00017 #ifdef COIN_USE_CLP
00018 #include "OsiClpSolverInterface.hpp"
00019 typedef OsiClpSolverInterface OsiXxxSolverInterface;
00020 #endif
00021 #ifdef COIN_USE_OSL
00022 #include "OsiOslSolverInterface.hpp"
00023 typedef OsiOslSolverInterface OsiXxxSolverInterface;
00024 #endif
00025 
00026 #include "BCP_lp.hpp"
00027 #include "BCP_lp_node.hpp"
00028 #include "AAP_lp.hpp"
00029 #include "AAP_var.hpp"
00030 #include "AAP_user_data.hpp"
00031 
00032 /*--------------------------------------------------------------------------*/
00033 void AAP_lp::unpack_module_data(BCP_buffer& buf) {
00034   //Unpack the information passed from the TM process
00035   lp_par.unpack(buf); //parameter list for LP
00036   aap = new AAP(buf); //the AAP instance
00037 }
00038 
00039 /*--------------------------------------------------------------------------*/
00040 void AAP_lp::pack_var_algo(const BCP_var_algo* var, BCP_buffer& buf){
00041   //Pack an algorithmic variable (AAP_var is derived from BCP_var_algo)
00042   {
00043     const AAP_var * mvar = dynamic_cast<const AAP_var*>(var);
00044     if(mvar){
00045       mvar->pack(buf);
00046       return;
00047     }
00048   }
00049   throw BCP_fatal_error("AAP_lp::pack_var_algo() : unknown cut type!\n");
00050 }
00051 
00052 /*--------------------------------------------------------------------------*/
00053 BCP_var_algo* AAP_lp::unpack_var_algo(BCP_buffer& buf){
00054   //Unpack an algorithmic variable (AAP_var is derived from BCP_var_algo)
00055   return new AAP_var(buf);
00056 }
00057 
00058 /*--------------------------------------------------------------------------*/
00059 void AAP_lp::pack_user_data(const BCP_user_data* ud, BCP_buffer& buf){
00060   //Pack user data
00061   {
00062     const AAP_user_data * data = dynamic_cast<const AAP_user_data*>(ud);
00063     if(data){
00064       data->pack(buf);
00065       return;
00066     }
00067   }
00068   throw BCP_fatal_error("AAP_tm::pack_user_data() : cast failed!\n");
00069 }
00070 
00071 /*--------------------------------------------------------------------------*/
00072 BCP_user_data* AAP_lp::unpack_user_data(BCP_buffer& buf){
00073   return new AAP_user_data(buf);
00074 }
00075 
00076 /*--------------------------------------------------------------------------*/
00077 OsiSolverInterface* AAP_lp::initialize_solver_interface(){
00078   //Initialize the OSI Xxx solver interface
00079   OsiXxxSolverInterface * si = new OsiXxxSolverInterface();
00080 
00081 #ifdef COIN_USE_CPX
00082   //Using cplex, we need to shut off the presolver to make sure get a dual 
00083   //ray in the case of primal infeasibility.
00084   CPXsetintparam(si->getEnvironmentPtr(),CPX_PARAM_PREIND, 0);
00085 #endif
00086 
00087   return si;
00088 }
00089 
00090 /*--------------------------------------------------------------------------*/
00091 void AAP_lp::display_lp_solution(const BCP_lp_result& lpres,
00092                                  const BCP_vec<BCP_var*>& vars,
00093                                  const BCP_vec<BCP_cut*>& cuts,
00094                                  const bool final_lp_solution){
00095 
00096 #ifdef DBG_PRINT 
00097   //Display the current LP solution
00098   cout << "UB: " << upper_bound() << " LB: " 
00099        << getLpProblemPointer()->node->true_lower_bound << endl;
00100 
00101   const int varnum = vars.size();
00102   for (int c = 0; c < varnum; ++c) {   
00103     if(lpres.x()[c] > tolerance){
00104       const AAP_var* mvar = dynamic_cast<const AAP_var*>(vars[c]);
00105       if(mvar){
00106         cout << "Column " << c << " : " << lpres.x()[c] << endl; 
00107         mvar->print(aap->getDimension());
00108       }
00109     }
00110   }
00111 #endif
00112 
00113 }
00114 
00115 /*--------------------------------------------------------------------------*/
00116 double AAP_lp::compute_lower_bound(const double old_lower_bound,
00117                                    const BCP_lp_result& lpres,
00118                                    const BCP_vec<BCP_var*>& vars,
00119                                    const BCP_vec<BCP_cut*>& cuts){
00120 
00121   // In order to get the bound we are solving the subproblem over the 
00122   // set of reduced costs. So, if we find any columns with negative 
00123   // reduced cost, we should save them for generate_vars_in_lp.  
00124 
00125   // Only try to generate_vars here if we have good duals 
00126   if(lpres.termcode() & BCP_ProvenPrimalInf)
00127     return -DBL_MAX;
00128 
00129   bool new_var = generate_vars(lpres.pi(), false);
00130 
00131   if(new_var){
00132     return old_lower_bound;
00133     //return max(old_lower_bound, lpres.objval() + most_reduced_cost);
00134   }
00135   else{
00136     const int tc = lpres.termcode();
00137     if (tc & BCP_ProvenOptimal)
00138       return lpres.objval();
00139     else return old_lower_bound;
00140   }
00141 }
00142 
00143 /*--------------------------------------------------------------------------*/
00144 void AAP_lp::generate_vars_in_lp(const BCP_lp_result& lpres,
00145                                  const BCP_vec<BCP_var*>& vars,
00146                                  const BCP_vec<BCP_cut*>& cuts,
00147                                  const bool before_fathom,
00148                                  BCP_vec<BCP_var*>& new_vars,
00149                                  BCP_vec<BCP_col*>& new_cols){
00150 
00151   /*
00152     Generate variables with negative reduced cost to be added 
00153     to the LP by solving an assignment problem. This work has
00154     already been done in compute_lower_bound and was saved in 
00155     generated_vars.
00156 
00157     The reduced cost of an assignment point is:
00158     rc_s = sum{ijk in H} s_ijk c_ijk                                    [c_s]
00159     - sum{i in I} sum{jk in J x K} s_ijk uhat_i       [dual of I constraints]
00160     - 1 * alpha                                [dual of convexity constraint]
00161   */
00162     
00163   new_vars.reserve(new_vars.size() + generated_vars.size());
00164   for (unsigned int i = 0; i < generated_vars.size(); ++i)
00165     new_vars.push_back(generated_vars[i]);
00166   generated_vars.clear();
00167 }
00168 
00169 /*--------------------------------------------------------------------------*/
00170 void AAP_lp::restore_feasibility(const BCP_lp_result& lpres,
00171                                  const std::vector<double*> dual_rays,
00172                                  const BCP_vec<BCP_var*>& vars,
00173                                  const BCP_vec<BCP_cut*>& cuts,
00174                                  BCP_vec<BCP_var*>& vars_to_add,
00175                                  BCP_vec<BCP_col*>& cols_to_add){
00176 
00177   // Generate a variable that breaks the certificate of infeasibility 
00178   // using the dual ray as the cost vector and solving an assignment problem. 
00179 
00180   for(unsigned int r = 0; r < dual_rays.size(); r++){
00181     generate_vars(dual_rays[r], true);
00182     vars_to_add.reserve(vars_to_add.size() + generated_vars.size());
00183     for (unsigned int i = 0; i < generated_vars.size(); ++i)
00184       vars_to_add.push_back(generated_vars[i]);
00185     
00186     generated_vars.clear();
00187   }
00188 }
00189 
00190 /*--------------------------------------------------------------------------*/
00191 void AAP_lp::construct_cost(const double * pi, const bool from_restore,
00192                             double * ap_costv, map<int,int> & jk_mini){
00193   
00194   /*
00195     Assignment Problem objective:
00196     min {jk in J x K} c'_jk x_jk    
00197     
00198     c_'jk = min{i in I} c_ijk - uhat_i OR
00199     c_'jk = min{i in I} ray_i
00200   */
00201   
00202 #ifdef DBG_PRINT
00203   const AAP_user_data * datatmp 
00204     = dynamic_cast<const AAP_user_data*>(get_user_data());
00205   cout << "ONES: ";
00206   for(unsigned int i = 0; i < datatmp->ones.size(); i++)
00207     cout << datatmp->ones[i] << " ";
00208   cout << endl;
00209   cout << "ZEROS: ";
00210   for(unsigned int i = 0; i < datatmp->zeros.size(); i++)
00211     cout << datatmp->zeros[i] << " ";
00212   cout << endl;
00213 #endif
00214 
00215   const int dimension = aap->getDimension();
00216   
00217   int index, index0, i, j, k, mult;
00218 
00219   //Construct the full cost vector across all ijk
00220   double * rc = new double[aap->n_cols()];
00221   if(from_restore){
00222     CoinFillN(rc, aap->n_cols(), 0.0);
00223     mult = 1;
00224   }
00225   else{
00226     CoinDisjointCopyN(aap->getAssignCost(), aap->n_cols(), rc);
00227     mult = -1;
00228   }
00229 
00230   int c = 0;
00231   for(i = 0; i < dimension; i++){
00232     for(j = 0; j < dimension; j++){
00233       for(k = 0; k < dimension; k++){
00234         rc[c] += (mult * pi[i]);
00235         c++;
00236       }
00237     }
00238   }
00239 
00240   //Enforce branching rules using a bigM cost
00241   const AAP_user_data * data 
00242     = dynamic_cast<const AAP_user_data*>(get_user_data());
00243 
00244   //For x_ijk = 1, for all s in F' such that s_ijk != 1, set lambda_s = 0
00245   for(index = 0; index < (int)data->ones.size(); index++)
00246     rc[data->ones[index]] += -bigM;
00247 
00248   //For x_ijk = 0, for all s in F' such that s_ijk != 1, set lambda_s = 0
00249   for(index = 0; index < (int)data->zeros.size(); index++)
00250     rc[data->zeros[index]] += bigM;
00251 
00252 
00253   //Now construct the cost vector for the AP problem
00254   //(j,k) -> (i*,j,k) for i* arg min{i in I} rc_ijk
00255   c = 0;
00256   for(j = 0; j < dimension; j++){
00257     for(k = 0; k < dimension; k++){
00258       index0 = index3(0,j,k,dimension);
00259       pair<int,double> mini = make_pair(index0,rc[index0]);
00260       for(i = 1; i < dimension; i++){
00261         index = index3(i,j,k,dimension);
00262         if(rc[index] < mini.second)
00263           mini = make_pair(index, rc[index]);
00264       }
00265       jk_mini.insert(make_pair(c, mini.first));
00266       ap_costv[c] = mini.second;
00267       c++;
00268     }
00269   } 
00270 
00271   delete [] rc;
00272 }
00273 
00274 /*--------------------------------------------------------------------------*/
00275 bool AAP_lp::generate_vars(const double * pi, const bool from_restore){
00276 
00277   const int dimension = aap->getDimension();
00278 
00279   double objective_value;
00280   double * solution  = new double[dimension * dimension];
00281   double * ap_costv  = new double[dimension * dimension];//BCP will delete
00282   map<int,int> jk_mini;
00283 
00284   construct_cost(pi, from_restore, ap_costv, jk_mini);
00285   
00286   int return_code = solve_assignment_problem(ap_costv, solution, 
00287                                              objective_value); 
00288   
00289   if(return_code){
00290     delete [] solution;
00291     return false;
00292   }
00293 
00294   double most_reduced_cost;
00295   const AAP_user_data * data 
00296     = dynamic_cast<const AAP_user_data*>(get_user_data());
00297   const int n_ones = data->ones.size();
00298 
00299   if(from_restore)
00300     most_reduced_cost = objective_value + pi[dimension] + (n_ones * bigM);
00301   else
00302     most_reduced_cost = objective_value - pi[dimension] + (n_ones * bigM);
00303   
00304   if(most_reduced_cost >= -tolerance){
00305     delete [] solution;
00306     return false;
00307   }
00308 
00309   //If the column has negative reduced cost, then transform the AP point 
00310   //back into AAP indices and create an AAP_var.
00311   double ap_cost = 0.0;
00312   vector<int> ap; ap.reserve(dimension);
00313   int index_aap, j, k, c = 0;
00314   for(j = 0; j < dimension; j++){
00315     for(k = 0; k < dimension; k++){
00316       if(solution[c] > tolerance){
00317         index_aap = jk_mini[c];
00318         ap.push_back(index_aap);
00319         ap_cost += aap->getAssignCost()[index_aap];
00320       }
00321       c++;
00322     }
00323   }
00324   AAP_var * new_var = new AAP_var(ap, ap_cost);
00325   generated_vars.push_back(new_var);
00326   delete [] solution;
00327   return true;
00328 }
00329 
00330 /*--------------------------------------------------------------------------*/
00331 int AAP_lp::solve_assignment_problem(double * ap_costv,
00332                                      double * solution,
00333                                      double & objective_value){
00334   /*
00335     Construct the Assignment Problem as an OSI instance
00336 
00337     Assignment Problem - relaxation of I:
00338     min {jk in J x K} c'_jk x_jk
00339     sum {k in K}            x_jk = 1, forall j in J
00340     sum {j in J}            x_jk = 1, forall k in K
00341     x_jk in {0,1}, for all jk in J x K
00342 
00343     c_'jk = min{i in I} c_ijk - uhat_i OR
00344     c_'jk = min{i in I} ray_i
00345   */
00346 
00347   OsiXxxSolverInterface * siAP = new OsiXxxSolverInterface();
00348   
00349   const int dimension = aap->getDimension();
00350   const int n_cols    = dimension * dimension;
00351   const int n_rows    = 2 * dimension;
00352   
00353   int i, j, k, index;
00354   double * col_lb    = new double[n_cols];
00355   double * col_ub    = new double[n_cols];
00356   double * row_lb_ub = new double[n_rows];
00357   CoinFillN(col_lb, n_cols, 0.0);
00358   CoinFillN(col_ub, n_cols, 1.0);
00359   CoinFillN(row_lb_ub, n_rows, 1.0);  
00360 
00361 
00362   //Adjust for branching:
00363   const AAP_user_data * data 
00364     = dynamic_cast<const AAP_user_data*>(get_user_data());
00365 
00366   //This should have been already taken care of using bigM, but using 
00367   //bounds should be used to help the LP solver.
00368 
00369   //For x_ijk = 1, for all s in F' such that s_ijk != 1, set lambda_s = 0
00370   for(index = 0; index < (int)data->ones.size(); index++){
00371     ijk(data->ones[index], dimension, i, j, k);
00372     col_lb[index2(j,k,dimension)] = 1.0;
00373   }
00374 
00375 
00376   CoinPackedMatrix * M =  new CoinPackedMatrix(false,0,0);
00377   M->setDimensions(0, n_cols);
00378   
00379   //sum {k in K}            x_jk = 1, forall j in J
00380   for(j = 0; j < dimension; j++){
00381     CoinPackedVector row;
00382     for(k = 0; k < dimension; k++){
00383       index = index2(j,k,dimension);
00384       row.insert(index, 1.0);
00385     }
00386     M->appendRow(row);
00387   }
00388 
00389   //sum {j in J}            x_jk = 1, forall k in K
00390   for(k = 0; k < dimension; k++){
00391     CoinPackedVector row;
00392     for(j = 0; j < dimension; j++){
00393       index = index2(j,k,dimension);
00394       row.insert(index, 1.0);
00395     }
00396     M->appendRow(row);
00397   }
00398 
00399   //Note on OSI usage:
00400   //assignProblem assumes ownership of the arguments (and deletes memory)
00401   //loadProblem makes a copy of the arguments
00402   siAP->assignProblem(M, col_lb, col_ub, ap_costv, row_lb_ub, row_lb_ub);
00403 
00404   //AP is Totally Unimodular, so LP is sufficient for integral solutions
00405   siAP->initialSolve();
00406 
00407   int return_code = 0;
00408   if(siAP->isProvenOptimal()){
00409     objective_value = siAP->getObjValue();
00410     CoinDisjointCopyN(siAP->getColSolution(), n_cols, solution);
00411   }
00412   else
00413     return_code = 1;
00414 
00415   delete siAP;
00416 
00417   return return_code;
00418 }
00419 
00420 /*--------------------------------------------------------------------------*/
00421 void AAP_lp::vars_to_cols(const BCP_vec<BCP_cut*>& cuts,
00422                           BCP_vec<BCP_var*>& vars,       
00423                           BCP_vec<BCP_col*>& cols,
00424                           const BCP_lp_result& lpres,
00425                           BCP_object_origin origin, bool allow_multiple){
00426 
00427   /*
00428     Expand the variable (AP point) into a column in the LP:
00429     min {s in F'}                c_s lambda_s             
00430     sum {s in F', jk in J x K} s_ijk lambda_s = 1, forall i in I (5)
00431     sum {s in F'}                    lambda_s = 1                (6)
00432   */
00433   const int varnum = vars.size();
00434   if (varnum == 0)
00435     return; 
00436 
00437   cols.reserve(varnum);
00438   for (int c = 0; c < varnum; ++c) {   
00439     const AAP_var* mvar = dynamic_cast<const AAP_var*>(vars[c]);
00440     if(mvar){
00441 
00442       CoinPackedVector col;
00443 
00444       //coefficient = number of i's in AP point (can be > 1)
00445       vector<int> coeff(aap->getDimension(), 0);
00446       for(unsigned int p = 0; p < mvar->ap.size(); p++)
00447         coeff[ijk_i(mvar->ap[p], aap->getDimension())]++;
00448   
00449       for(int i = 0; i < aap->getDimension(); i++)
00450         if(coeff[i] > 0) 
00451           col.insert(i, static_cast<double>(coeff[i])); //const           (5)
00452       col.insert(aap->getDimension(), 1.0);             //convexity const (6)
00453 
00454       cols.unchecked_push_back(new BCP_col(col, mvar->cost, 
00455                                            vars[c]->lb(), vars[c]->ub()));
00456     }
00457   }
00458 }

Generated on Wed Dec 3 01:30:51 2003 for AAP_BP by doxygen 1.3.5