/home/coin/SVN-release/OS-2.4.0/Bonmin/src/CbcBonmin/Heuristics/BonHeuristicDiveMIP.cpp

Go to the documentation of this file.
00001 // Copyright (C) 2007, International Business Machines Corporation and others. 
00002 // All Rights Reserved.
00003 // This code is published under the Common Public License.
00004 //
00005 // Authors :
00006 // Joao P. Goncalves, International Business Machines Corporation
00007 //
00008 // Date : November 12, 2007
00009 
00010 #include "BonHeuristicDiveMIP.hpp"
00011 #include "CoinHelperFunctions.hpp"
00012 #include "CbcModel.hpp"
00013 #include "BonHeuristicDive.hpp"
00014 #include "BonSubMipSolver.hpp"
00015 #include "BonCbcLpStrategy.hpp"
00016 
00017 #ifdef COIN_HAS_CPX
00018 #include "OsiCpxSolverInterface.hpp"
00019 #endif
00020 
00021 #include "OsiClpSolverInterface.hpp"
00022 
00023 #include "OsiAuxInfo.hpp"
00024 
00025 #include "CoinTime.hpp"
00026 
00027 #include <fstream>
00028 
00029 #include <iomanip>
00030 
00031 #include "CoinHelperFunctions.hpp"
00032 
00033 //#define DEBUG_BON_HEURISTIC_DIVE_MIP
00034 
00035 using namespace std;
00036 
00037 namespace Bonmin
00038 {
00039   HeuristicDiveMIP::HeuristicDiveMIP(BonminSetup * setup)
00040     :
00041     CbcHeuristic(),
00042     setup_(setup),
00043     howOften_(100),
00044     mip_(NULL)
00045   {
00046     Initialize(setup);
00047   }
00048 
00049   void
00050   HeuristicDiveMIP::Initialize(BonminSetup * b){
00051     delete mip_;
00052     mip_ = new SubMipSolver (*b, b->prefix());
00053    
00054   }
00055 
00056   HeuristicDiveMIP::HeuristicDiveMIP(const HeuristicDiveMIP &copy)
00057     :
00058     CbcHeuristic(copy),
00059     setup_(copy.setup_),
00060     howOften_(copy.howOften_),
00061     mip_(new SubMipSolver(*copy.mip_))
00062   {
00063   }
00064 
00065   HeuristicDiveMIP &
00066   HeuristicDiveMIP::operator=(const HeuristicDiveMIP & rhs)
00067   {
00068     if(this != &rhs) {
00069       CbcHeuristic::operator=(rhs);
00070       setup_ = rhs.setup_;
00071       howOften_ = rhs.howOften_;
00072       delete mip_;
00073       if(rhs.mip_)
00074         mip_ = new SubMipSolver(*rhs.mip_);
00075     }
00076     return *this;
00077   }
00078 
00079   HeuristicDiveMIP::~HeuristicDiveMIP(){
00080     delete mip_;
00081   }
00082 
00083   struct MatComp{
00084     const int * iRow;
00085     const int * jCol;
00087     bool operator()(int i,int j){
00088       return (jCol[i] < jCol[j]) || (jCol[i] == jCol[j] && iRow[i] < iRow[j]);
00089     }
00090   };
00091 
00092 
00093   int
00094   HeuristicDiveMIP::solution(double &solutionValue, double *betterSolution)
00095   {
00096     if(model_->getNodeCount() || model_->getCurrentPassNumber() > 1) return 0;
00097     if ((model_->getNodeCount()%howOften_)!=0||model_->getCurrentPassNumber()>1)
00098       return 0;
00099  
00100     int returnCode = 0; // 0 means it didn't find a feasible solution
00101 
00102     OsiTMINLPInterface * nlp = NULL;
00103     if(setup_->getAlgorithm() == B_BB)
00104       nlp = dynamic_cast<OsiTMINLPInterface *>(model_->solver()->clone());
00105     else
00106       nlp = dynamic_cast<OsiTMINLPInterface *>(setup_->nonlinearSolver()->clone());
00107 
00108     TMINLP2TNLP* minlp = nlp->problem();
00109  
00110     // set tolerances
00111     double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
00112     double primalTolerance = 1.0e-6;
00113 
00114     int numberColumns;
00115     int numberRows;
00116     int nnz_jac_g;
00117     int nnz_h_lag;
00118     Ipopt::TNLP::IndexStyleEnum index_style;
00119     minlp->get_nlp_info(numberColumns, numberRows, nnz_jac_g,
00120                         nnz_h_lag, index_style);
00121 
00122     const Bonmin::TMINLP::VariableType* variableType = minlp->var_types();
00123     const double* x_sol = minlp->x_sol();
00124     const double* x_l = minlp->x_l();
00125     const double* x_u = minlp->x_u();
00126     //const double* g_sol = minlp->g_sol();
00127     const double* g_l = minlp->g_l();
00128     const double* g_u = minlp->g_u();
00129 
00130     adjustPrimalTolerance(minlp, primalTolerance);
00131 
00132     assert(isNlpFeasible(minlp, primalTolerance));
00133 
00134     // Get information about the linear and nonlinear part of the instance
00135     TMINLP* tminlp = nlp->model();
00136     Ipopt::TNLP::LinearityType* variableLinearNonLinear = new 
00137       Ipopt::TNLP::LinearityType [numberColumns];
00138     tminlp->get_variables_linearity(numberColumns, variableLinearNonLinear);
00139     vector<int> linearVariable;
00140     vector<int> nonlinearVariable;
00141     for (int iColumn=0;iColumn<numberColumns;iColumn++) {
00142       if (variableLinearNonLinear[iColumn]==Ipopt::TNLP::LINEAR)
00143         linearVariable.push_back(iColumn);
00144       else
00145         nonlinearVariable.push_back(iColumn);
00146     }
00147     size_t numberLinearColumns = linearVariable.size();
00148     size_t numberNonlinearColumns = nonlinearVariable.size();
00149 
00150 
00151     // Get the indicies of the jacobian
00152     // This is also a way of knowing which variables are
00153     // used in each row
00154     int* indexRow = new int[nnz_jac_g];
00155     int* indexCol = new int[nnz_jac_g];
00156     minlp->eval_jac_g(numberColumns, x_sol, false,
00157                       numberRows, nnz_jac_g,
00158                       indexRow, indexCol, 0);
00159 
00160     vector<int> sortedIndex(nnz_jac_g);
00161     CoinIotaN(sortedIndex(), nnz_jac_g, 0);
00162     MatComp c;
00163     c.iRow = indexRow;
00164     c.jCol = indexCol;
00165     std::sort(sortedIndex.begin(), sortedIndex.end(), c);
00166 
00167     int* row = new int[nnz_jac_g];
00168     int* columnStart = new int[numberColumns];
00169     int* columnLength = new int[numberColumns];
00170     CoinZeroN(columnStart, numberColumns);
00171     CoinZeroN(columnLength, numberColumns);
00172     vector<vector<int> > column(numberRows); // stores the index of
00173     // the variables in
00174     // each row
00175     vector<vector<int> > columnInt(numberRows); // stores the index of
00176     // the integer variables in
00177     // each row
00178     std::vector<int> numberColumnsLinear(numberRows, 0); // stores the number
00179     // of the linear variables in
00180     // each row
00181     int indexCorrection = (index_style == Ipopt::TNLP::C_STYLE) ? 0 : 1;
00182     int iniCol = -1;
00183     for(int i=0; i<nnz_jac_g; i++) {
00184       int thisIndexCol = indexCol[sortedIndex[i]]-indexCorrection;
00185       if(indexCol[sortedIndex[i]] != iniCol) {
00186         iniCol = indexCol[sortedIndex[i]];
00187         columnStart[thisIndexCol] = i;
00188         columnLength[thisIndexCol] = 1;
00189       }
00190       else {
00191         columnLength[thisIndexCol]++;
00192       }
00193       row[i] = indexRow[sortedIndex[i]]-indexCorrection;
00194       column[row[i]].push_back(thisIndexCol);
00195       if (variableType[thisIndexCol] != Bonmin::TMINLP::CONTINUOUS)
00196         columnInt[row[i]].push_back(thisIndexCol);
00197       if(variableLinearNonLinear[thisIndexCol] == Ipopt::TNLP::LINEAR)
00198         numberColumnsLinear[row[i]]++;
00199     }
00200 
00201     // Get solution array for heuristic solution
00202     double* newSolution = new double [numberColumns];
00203     memcpy(newSolution,x_sol,numberColumns*sizeof(double));
00204     double* new_g_sol = new double [numberRows];
00205 
00206 
00207     // create a set with the indices of the fractional variables
00208     vector<int> integerNonlinearColumns; // stores the integer variables
00209     int numberFractionalNonlinearVariables = 0;
00210     for (size_t iNLCol=0;iNLCol<numberNonlinearColumns;iNLCol++) {
00211       int iColumn = nonlinearVariable[iNLCol];
00212       if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
00213         integerNonlinearColumns.push_back(iColumn);
00214         double value=newSolution[iColumn];
00215         if (fabs(floor(value+0.5)-value)>integerTolerance) {
00216           numberFractionalNonlinearVariables++;
00217         }
00218       }
00219     }
00220 
00221     setInternalVariables(minlp);
00222 
00223     int iteration = -1;
00224     while(numberFractionalNonlinearVariables) {
00225       iteration++;
00226 
00227       // select a fractional variable to bound
00228       int bestColumn = -1;
00229       int bestRound = -1; // -1 rounds down, +1 rounds up
00230       selectVariableToBranch(minlp, integerNonlinearColumns, newSolution,
00231                              bestColumn, bestRound);
00232 
00233       if(bestColumn >= 0) {
00234         if(bestRound < 0)
00235           minlp->SetVariableUpperBound(bestColumn, floor(newSolution[bestColumn]));
00236         else
00237           minlp->SetVariableLowerBound(bestColumn, ceil(newSolution[bestColumn]));
00238       } else {
00239         break;
00240       }
00241 
00242       nlp->initialSolve();
00243 
00244       if(minlp->optimization_status() != Ipopt::SUCCESS) {
00245         break;
00246       }
00247 
00248       memcpy(newSolution,x_sol,numberColumns*sizeof(double));
00249 
00250       numberFractionalNonlinearVariables = 0;
00251       for(int iIntCol=0; iIntCol<(int)integerNonlinearColumns.size(); iIntCol++) {
00252         int iColumn = integerNonlinearColumns[iIntCol];
00253         double value=newSolution[iColumn];
00254         if (fabs(floor(value+0.5)-value)>integerTolerance)
00255           numberFractionalNonlinearVariables++;
00256       }
00257 
00258       double newSolutionValue;
00259       minlp->eval_f(numberColumns, newSolution, true, newSolutionValue); 
00260     }
00261 
00262 
00263     // now we are going to solve a MIP with the linear part of the problem
00264     int numberFractionalLinearVariables = 0;
00265     for (size_t iLCol=0;iLCol<numberLinearColumns;iLCol++) {
00266       int iColumn = linearVariable[iLCol];
00267       if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
00268         double value=newSolution[iColumn];
00269         if (fabs(floor(value+0.5)-value)>integerTolerance) {
00270           numberFractionalLinearVariables++;
00271         }
00272       }
00273     }
00274 
00275     bool feasible = true;
00276     if(numberFractionalLinearVariables) {
00277       int numberMIPRows = 0;
00278       int* mapRows = new int[numberRows];
00279       for(int iRow=0; iRow<numberRows; iRow++) {
00280         mapRows[iRow] = -1; // this means that there are no linear columns in this row
00281         if(numberColumnsLinear[iRow] > 0) {
00282           mapRows[iRow] = numberMIPRows++;
00283         }
00284       }
00285 
00286       // set all linear variables to zero in order to compute the
00287       // impact of the nonlinear variables in each row
00288       int numberIntegerLinearColumns = 0;
00289       for (size_t iLCol=0;iLCol<numberLinearColumns;iLCol++) {
00290         int iColumn = linearVariable[iLCol];
00291         newSolution[iColumn] = 0.0;
00292         if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS)
00293           numberIntegerLinearColumns++;
00294       }
00295 
00296       double* gradient_f = new double[numberColumns];
00297       minlp->eval_grad_f(numberColumns,newSolution,true,gradient_f);
00298       // create row lower and upper bounds for MILP
00299       minlp->eval_g(numberColumns, newSolution, true,
00300                     numberRows, new_g_sol);
00301       double* row_lb = new double[numberMIPRows];
00302       double* row_ub = new double[numberMIPRows];
00303       for(int iRow=0; iRow<numberRows; iRow++) {
00304         if(mapRows[iRow] > -1) {
00305           assert(mapRows[iRow] < numberMIPRows);
00306           if(g_l[iRow] == (-1.0) * nlp->getInfinity())
00307             row_lb[mapRows[iRow]] = g_l[iRow];
00308           else
00309             row_lb[mapRows[iRow]] = g_l[iRow] - new_g_sol[iRow];
00310           if(g_u[iRow] == nlp->getInfinity())
00311             row_ub[mapRows[iRow]] = g_u[iRow];
00312           else
00313             row_ub[mapRows[iRow]] = g_u[iRow] - new_g_sol[iRow];
00314         }
00315       }
00316 
00317       // get the jacobian so that we know the coefficients of the MILP matrix
00318       double* jac_g = new double [nnz_jac_g];
00319       minlp->eval_jac_g(numberColumns, x_sol, false,
00320                         numberRows, nnz_jac_g,
00321                         0, 0, jac_g);
00322 
00323 
00324       // Define the constraint matrix for MILP
00325       CoinPackedMatrix* matrix = new CoinPackedMatrix(true,0,0);
00326       matrix->setDimensions(numberMIPRows,0);
00327 
00328       // create objective function and columns lower and upper bounds for MILP
00329       // and create columns for matrix in MILP
00330       double* objective = new double[numberLinearColumns];
00331       double* col_lb = new double[numberLinearColumns];
00332       double* col_ub = new double[numberLinearColumns];
00333       int* indexIntegerColumn = new int[numberIntegerLinearColumns];
00334       int numberIndexIntegerColumn = 0;
00335       for (size_t iLCol=0;iLCol<numberLinearColumns;iLCol++) {
00336         int iColumn = linearVariable[iLCol];
00337         objective[iLCol] = gradient_f[iColumn];
00338         col_lb[iLCol] = x_l[iColumn];
00339         col_ub[iLCol] = x_u[iColumn];
00340         CoinPackedVector newRow;
00341         int end = columnStart[iColumn]+columnLength[iColumn];
00342         for (int j=columnStart[iColumn];
00343              j< end;j++) {
00344           int iRow = row[j];
00345           newRow.insert(mapRows[iRow], jac_g[sortedIndex[j]]);
00346         }
00347         matrix->appendCol(newRow);
00348         if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS)
00349           indexIntegerColumn[numberIndexIntegerColumn++] = static_cast<int>(iLCol);
00350       }
00351 
00352       // load the problem to OSI
00353       OsiSolverInterface *si = mip_->solver();
00354       bool delete_si = false;
00355       if(si == NULL){
00356         si = new OsiClpSolverInterface;
00357         mip_->setLpSolver(si);
00358         delete_si = true;
00359       }
00360       CoinMessageHandler * handler = model_->messageHandler()->clone();
00361       si->passInMessageHandler(handler);
00362       si->messageHandler()->setLogLevel(0);
00363 
00364       si->loadProblem(*matrix, col_lb, col_ub, objective, row_lb, row_ub);
00365       si->setInteger(indexIntegerColumn, numberIndexIntegerColumn);
00366       
00367       mip_->optimize(DBL_MAX, 0, 60);
00368 
00369       if(mip_->getLastSolution()) {
00370         const double* solution = mip_->getLastSolution();
00371         assert(si->getNumCols() == static_cast<int>(numberLinearColumns));
00372         for (size_t iLCol=0;iLCol<numberLinearColumns;iLCol++) {
00373           int iColumn = linearVariable[iLCol];
00374           newSolution[iColumn] = solution[iLCol];
00375         }
00376       }
00377       else
00378         feasible = false;
00379 
00380       delete [] mapRows;
00381       delete [] row_lb;
00382       delete [] row_ub;
00383       delete [] jac_g;
00384       delete [] gradient_f;
00385       delete matrix;
00386       delete [] objective;
00387       delete [] col_lb;
00388       delete [] col_ub;
00389       delete [] indexIntegerColumn;
00390       if(delete_si){
00391         delete si;
00392       }
00393       delete handler;
00394     }
00395 
00396 #if 0
00397     bool feasible = true;
00398     for (int iColumn=0;iColumn<numberColumns;iColumn++) {
00399       double value=newSolution[iColumn];
00400       if(value < x_l[iColumn] || value > x_u[iColumn]) {
00401         feasible = false;
00402         break;
00403       }
00404       if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
00405         if (fabs(floor(value+0.5)-value)>integerTolerance) {
00406           feasible = false;
00407           break;
00408         }
00409       }
00410     }
00411     minlp->eval_g(numberColumns, newSolution, true,
00412                   numberRows, new_g_sol);
00413     for(int iRow=0; iRow<numberRows; iRow++) {
00414       if(new_g_sol[iRow]<g_l[iRow]-primalTolerance ||
00415          new_g_sol[iRow]>g_u[iRow]+primalTolerance) {
00416         if(minlp->optimization_status() != SUCCESS) {
00417           feasible = false;
00418           break;
00419         } else {
00420 #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
00421           cout<<"It should be infeasible because: "<<endl;
00422           cout<<"g_l["<<iRow<<"]= "<<g_l[iRow]<<" "
00423               <<"g_sol["<<iRow<<"]= "<<new_g_sol[iRow]<<" "
00424               <<"g_u["<<iRow<<"]= "<<g_u[iRow]<<endl;
00425           cout<<"primalTolerance= "<<primalTolerance<<endl;
00426 #endif
00427           feasible = false;
00428           break;
00429         }
00430       }
00431     }
00432 #else
00433     if(feasible) {
00434       // fix the integer variables and solve the NLP
00435       for (int iColumn=0;iColumn<numberColumns;iColumn++) {
00436         if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
00437           double value=newSolution[iColumn];
00438           if (fabs(floor(value+0.5)-value)>integerTolerance) {
00439 #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
00440             cout<<"It should be infeasible because: "<<endl;
00441             cout<<"variable "<<iColumn<<" is not integer"<<endl;
00442 #endif
00443             feasible = false;
00444             break;
00445           }
00446           else {
00447             value=floor(newSolution[iColumn]+0.5);
00448             minlp->SetVariableUpperBound(iColumn, value);
00449             minlp->SetVariableLowerBound(iColumn, value);
00450           }
00451         }
00452       }
00453       if(feasible) {
00454         nlp->initialSolve();
00455         if(minlp->optimization_status() != Ipopt::SUCCESS) {
00456           feasible = false;
00457         }
00458         memcpy(newSolution,x_sol,numberColumns*sizeof(double));
00459       }
00460     }
00461 #endif
00462 
00463     if(feasible) {
00464       double newSolutionValue;
00465       minlp->eval_f(numberColumns, newSolution, true, newSolutionValue); 
00466       if(newSolutionValue < solutionValue) {
00467         memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
00468         solutionValue = newSolutionValue;
00469         returnCode = 1;
00470       }
00471     }
00472 
00473     delete [] variableLinearNonLinear;
00474     delete [] indexRow;
00475     delete [] indexCol;
00476     delete [] row;
00477     delete [] columnStart;
00478     delete [] columnLength;
00479     delete [] newSolution;
00480     delete [] new_g_sol;
00481     delete nlp;
00482 
00483 #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
00484     std::cout<<"DiveMIP returnCode = "<<returnCode<<std::endl;
00485 #endif
00486 
00487     return returnCode;
00488   }
00489 }

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