00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "BonMilpRounding.hpp"
00011 #include "CoinHelperFunctions.hpp"
00012 #include "CbcModel.hpp"
00013 #include "BonSubMipSolver.hpp"
00014
00015 #include "CoinTime.hpp"
00016
00017 #include <fstream>
00018
00019 #include <iomanip>
00020
00021 #include "CoinHelperFunctions.hpp"
00022 #include "OsiClpSolverInterface.hpp"
00023
00024
00025
00026 using namespace std;
00027
00028 namespace Bonmin
00029 {
00030 MilpRounding::MilpRounding(BonminSetup * setup)
00031 :
00032 CbcHeuristic(),
00033 setup_(setup),
00034 howOften_(20),
00035 mip_(NULL)
00036 {
00037 Initialize(setup);
00038 }
00039
00040 void
00041 MilpRounding::Initialize(BonminSetup * b){
00042 delete mip_;
00043 mip_ = new SubMipSolver (*b, b->prefix());
00044
00045 }
00046
00047 MilpRounding::MilpRounding(const MilpRounding ©)
00048 :
00049 CbcHeuristic(copy),
00050 setup_(copy.setup_),
00051 howOften_(copy.howOften_),
00052 mip_(new SubMipSolver(*copy.mip_))
00053 {
00054 }
00055
00056 MilpRounding &
00057 MilpRounding::operator=(const MilpRounding & rhs)
00058 {
00059 if(this != &rhs) {
00060 CbcHeuristic::operator=(rhs);
00061 setup_ = rhs.setup_;
00062 howOften_ = rhs.howOften_;
00063 delete mip_;
00064 if(rhs.mip_)
00065 mip_ = new SubMipSolver(*rhs.mip_);
00066 }
00067 return *this;
00068 }
00069
00070 MilpRounding::~MilpRounding(){
00071 delete mip_;
00072 }
00073
00074 struct MatComp{
00075 const int * iRow;
00076 const int * jCol;
00078 bool operator()(int i,int j){
00079 return (jCol[i] < jCol[j]) || (jCol[i] == jCol[j] && iRow[i] < iRow[j]);
00080 }
00081 };
00082
00083
00084 int
00085 MilpRounding::solution(double &solutionValue, double *betterSolution)
00086 {
00087 if(model_->getCurrentPassNumber() > 1) return 0;
00088 if ((model_->getNodeCount()%howOften_)!=0||model_->getCurrentPassNumber()>1)
00089 return 0;
00090
00091 int returnCode = 0;
00092
00093 OsiTMINLPInterface * nlp = NULL;
00094 if(setup_->getAlgorithm() == B_BB)
00095 nlp = dynamic_cast<OsiTMINLPInterface *>(model_->solver()->clone());
00096 else
00097 nlp = dynamic_cast<OsiTMINLPInterface *>(setup_->nonlinearSolver()->clone());
00098
00099 TMINLP2TNLP* minlp = nlp->problem();
00100
00101
00102 double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
00103
00104
00105 int n;
00106 int m;
00107 int nnz_jac_g;
00108 int nnz_h_lag;
00109 Ipopt::TNLP::IndexStyleEnum index_style;
00110 minlp->get_nlp_info(n, m, nnz_jac_g,
00111 nnz_h_lag, index_style);
00112
00113 const Bonmin::TMINLP::VariableType* variableType = minlp->var_types();
00114 const double* x_sol = minlp->x_sol();
00115 const double* g_l = minlp->g_l();
00116 const double* g_u = minlp->g_u();
00117
00118 const double * colsol = model_->solver()->getColSolution();
00119
00120
00121
00122 TMINLP* tminlp = nlp->model();
00123 vector<Ipopt::TNLP::LinearityType> c_lin(m);
00124 tminlp->get_constraints_linearity(m, c_lin());
00125 vector<int> c_idx(m);
00126 int n_lin = 0;
00127 for (int i=0;i<m;i++) {
00128 if (c_lin[i]==Ipopt::TNLP::LINEAR)
00129 c_idx[i] = n_lin++;
00130 else
00131 c_idx[i] = -1;
00132 }
00133
00134
00135
00136 vector<int> indexRow(nnz_jac_g);
00137 vector<int> indexCol(nnz_jac_g);
00138 minlp->eval_jac_g(n, x_sol, false,
00139 m, nnz_jac_g,
00140 indexRow(), indexCol(), 0);
00141
00142
00143 vector<double> jac_g(nnz_jac_g);
00144 minlp->eval_jac_g(n, x_sol, false,
00145 m, nnz_jac_g,
00146 NULL, NULL, jac_g());
00147
00148
00149 vector<int> sortedIndex(nnz_jac_g);
00150 CoinIotaN(sortedIndex(), nnz_jac_g, 0);
00151 MatComp c;
00152 c.iRow = indexRow();
00153 c.jCol = indexCol();
00154 std::sort(sortedIndex.begin(), sortedIndex.end(), c);
00155
00156 vector<int> row (nnz_jac_g);
00157 vector<double> value (nnz_jac_g);
00158 vector<int> columnStart(n,0);
00159 vector<int> columnLength(n,0);
00160 int indexCorrection = (index_style == Ipopt::TNLP::C_STYLE) ? 0 : 1;
00161 int iniCol = -1;
00162 int nnz = 0;
00163 for(int i=0; i<nnz_jac_g; i++) {
00164 int thisIndexCol = indexCol[sortedIndex[i]]-indexCorrection;
00165 int thisIndexRow = c_idx[indexRow[sortedIndex[i]] - indexCorrection];
00166 if(thisIndexCol != iniCol) {
00167 iniCol = thisIndexCol;
00168 columnStart[thisIndexCol] = nnz;
00169 columnLength[thisIndexCol] = 0;
00170 }
00171 if(thisIndexRow == -1) continue;
00172 columnLength[thisIndexCol]++;
00173 row[nnz] = thisIndexRow;
00174 value[nnz] = jac_g[i];
00175 nnz++;
00176 }
00177
00178
00179 vector<double> newRowLower(n_lin);
00180 vector<double> newRowUpper(n_lin);
00181 for(int i = 0 ; i < m ; i++){
00182 if(c_idx[i] == -1) continue;
00183 newRowLower[c_idx[i]] = g_l[i];
00184 newRowUpper[c_idx[i]] = g_u[i];
00185 }
00186
00187
00188 vector<double> newSolution(n);
00189 std::copy(x_sol, x_sol + n, newSolution.begin());
00190
00191
00192 CoinPackedMatrix matrix(true,n_lin,n, nnz, value(), row(), columnStart(), columnLength());
00193
00194
00195
00196
00197 double beta = 1;
00198 vector<double> objective(n);
00199 vector<int> idxIntegers;
00200 idxIntegers.reserve(n);
00201 for(int i = 0 ; i < n ; i++){
00202 if(variableType[i] != Bonmin::TMINLP::CONTINUOUS){
00203 idxIntegers.push_back(i);
00204 objective[i] = beta*(1 - 2*colsol[i]);
00205 }
00206 }
00207
00208 #if 0
00209
00210 const double * duals = nlp->getRowPrice() + 2 *n;
00211 vector<double> grad(n, 0);
00212 vector<int> indices(n, 0);
00213 tminlp->eval_grad_f(n, x_sol, false, grad());
00214 for(int i = 0 ; i < m ; i++){
00215 if(c_lin[i] == Ipopt::TNLP::LINEAR) continue;
00216 int nnz;
00217 tminlp->eval_grad_gi(n, x_sol, false, i, nnz, indices(), NULL);
00218 tminlp->eval_grad_gi(n, x_sol, false, i, nnz, NULL, grad());
00219 for(int k = 0 ; k < nnz ; k++){
00220 objective[indices[k]] += alpha *duals[i] * grad[k];
00221 }
00222 }
00223 for(int i = 0 ; i < n ; i++){
00224 if(variableType[i] != Bonmin::TMINLP::CONTINUOUS)
00225 objective[i] += alpha * grad[i];
00226
00227 else objective[i] = 0;
00228 }
00229 std::copy(objective.begin(), objective.end(), std::ostream_iterator<double>(std::cout, " "));
00230 std::cout<<std::endl;
00231 #endif
00232
00233
00234 OsiSolverInterface *si = mip_->solver();
00235 assert(si != NULL);
00236 CoinMessageHandler * handler = model_->messageHandler()->clone();
00237 si->passInMessageHandler(handler);
00238 si->messageHandler()->setLogLevel(1);
00239
00240 si->loadProblem(matrix, model_->solver()->getColLower(), model_->solver()->getColUpper(), objective(),
00241 newRowLower(), newRowUpper());
00242 si->setInteger(idxIntegers(), static_cast<int>(idxIntegers.size()));
00243 si->applyCuts(noGoods);
00244
00245 bool hasFractionnal = true;
00246 while(hasFractionnal){
00247 mip_->optimize(DBL_MAX, 0, 60);
00248 hasFractionnal = false;
00249 #if 0
00250 bool feasible = false;
00251 if(mip_->getLastSolution()) {
00252 const double* solution = mip_->getLastSolution();
00253 std::copy(solution, solution + n, newSolution.begin());
00254 feasible = true;
00255
00256 }
00257
00258 if(feasible) {
00259
00260
00261 CoinPackedVector v;
00262 double lb = 1;
00263 for (int iColumn=0;iColumn<n;iColumn++) {
00264 if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
00265 double value=newSolution[iColumn];
00266 if (fabs(floor(value+0.5)-value)>integerTolerance) {
00267 #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
00268 cout<<"It should be infeasible because: "<<endl;
00269 cout<<"variable "<<iColumn<<" is not integer"<<endl;
00270 #endif
00271 feasible = false;
00272 break;
00273 }
00274 else {
00275 value=floor(newSolution[iColumn]+0.5);
00276 if(value > 0.5){
00277 v.insert(iColumn, -1);
00278 lb -= value;
00279 }
00280 minlp->SetVariableUpperBound(iColumn, value);
00281 minlp->SetVariableLowerBound(iColumn, value);
00282 }
00283 }
00284 }
00285 }
00286 #endif
00287 }
00288 bool feasible = false;
00289 if(mip_->getLastSolution()) {
00290 const double* solution = mip_->getLastSolution();
00291 std::copy(solution, solution + n, newSolution.begin());
00292 feasible = true;
00293
00294 delete handler;
00295 }
00296
00297
00298 if(feasible) {
00299
00300
00301 CoinPackedVector v;
00302 double lb = 1;
00303 for (int iColumn=0;iColumn<n;iColumn++) {
00304 if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) {
00305 double value=newSolution[iColumn];
00306 if (fabs(floor(value+0.5)-value)>integerTolerance) {
00307 #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
00308 cout<<"It should be infeasible because: "<<endl;
00309 cout<<"variable "<<iColumn<<" is not integer"<<endl;
00310 #endif
00311 feasible = false;
00312 break;
00313 }
00314 else {
00315 value=floor(newSolution[iColumn]+0.5);
00316 if(value > 0.5){
00317 v.insert(iColumn, -1);
00318 lb -= value;
00319 }
00320 minlp->SetVariableUpperBound(iColumn, value);
00321 minlp->SetVariableLowerBound(iColumn, value);
00322 }
00323 }
00324 }
00325 OsiRowCut c;
00326 c.setRow(v);
00327 c.setLb(lb);
00328 c.setUb(DBL_MAX);
00329 noGoods.insert(c);
00330 if(feasible) {
00331 nlp->initialSolve();
00332 if(minlp->optimization_status() != Ipopt::SUCCESS) {
00333 feasible = false;
00334 }
00335 std::copy(x_sol,x_sol+n, newSolution.begin());
00336 }
00337 }
00338 if(feasible) {
00339 double newSolutionValue;
00340 minlp->eval_f(n, newSolution(), true, newSolutionValue);
00341 if(newSolutionValue < solutionValue) {
00342 std::copy(newSolution.begin(), newSolution.end(), betterSolution);
00343 solutionValue = newSolutionValue;
00344 returnCode = 1;
00345 }
00346 }
00347
00348 delete nlp;
00349
00350 #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP
00351 std::cout<<"DiveMIP returnCode = "<<returnCode<<std::endl;
00352 #endif
00353
00354 return returnCode;
00355 }
00356 void
00357 MilpRounding::registerOptions(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions){
00358 roptions->SetRegisteringCategory("Undocumented Heuristics", RegisteredOptions::UndocumentedCategory);
00359 roptions->AddStringOption2(
00360 "MILP_rounding_heuristic",
00361 "if yes runs the heuristic",
00362 "no",
00363 "no", "don't run it",
00364 "yes", "runs the heuristic",
00365 "");
00366 }
00367 }