00001
00002
00003
00004
00005
00006
00007
00008
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
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 ©)
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;
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
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
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
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
00152
00153
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);
00173
00174
00175 vector<vector<int> > columnInt(numberRows);
00176
00177
00178 std::vector<int> numberColumnsLinear(numberRows, 0);
00179
00180
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
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
00208 vector<int> integerNonlinearColumns;
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
00228 int bestColumn = -1;
00229 int bestRound = -1;
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
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;
00281 if(numberColumnsLinear[iRow] > 0) {
00282 mapRows[iRow] = numberMIPRows++;
00283 }
00284 }
00285
00286
00287
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
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
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
00325 CoinPackedMatrix* matrix = new CoinPackedMatrix(true,0,0);
00326 matrix->setDimensions(numberMIPRows,0);
00327
00328
00329
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
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
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 }