00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "BonFpForMinlp.hpp"
00011 #include "BonminConfig.h"
00012
00013 #include "OsiClpSolverInterface.hpp"
00014
00015 #include "CbcModel.hpp"
00016 #include "BonCbcLpStrategy.hpp"
00017 #ifdef COIN_HAS_CPX
00018 #include "OsiCpxSolverInterface.hpp"
00019 #endif
00020 #include "OsiAuxInfo.hpp"
00021 #include "BonSolverHelp.hpp"
00022
00023 #include <climits>
00024
00025 namespace Bonmin
00026 {
00027 static const char * txt_id = "FP for MINLP";
00029 MinlpFeasPump::MinlpFeasPump(BabSetupBase & b):
00030 OaDecompositionBase(b, true, false),
00031 subMip_(NULL)
00032 {
00033 std::string bonmin="bonmin.";
00034 std::string prefix = (b.prefix() == bonmin) ? "" : b.prefix();
00035 prefix += "pump_for_minlp.";
00036 subMip_ = new SubMipSolver(b, prefix);
00037 double oaTime;
00038 b.options()->GetNumericValue("time_limit",oaTime,prefix);
00039 parameter().maxLocalSearch_ = INT_MAX;
00040 b.options()->GetIntegerValue("solution_limit", parameter().maxSols_,prefix);
00041 parameter().maxLocalSearchTime_ =
00042 std::min(b.getDoubleParameter(BabSetupBase::MaxTime), oaTime);
00043 if(parameter().maxSols_ > b.getIntParameter(BabSetupBase::MaxSolutions))
00044 parameter().maxSols_ = b.getIntParameter(BabSetupBase::MaxSolutions);
00045 b.options()->GetEnumValue("fp_pass_infeasible", passBound_, prefix);
00046 }
00047
00048 MinlpFeasPump::~MinlpFeasPump()
00049 {
00050 delete subMip_;
00051 }
00052
00054 bool
00055 MinlpFeasPump::doLocalSearch(BabInfo * babInfo) const
00056 {
00057 return (nLocalSearch_<parameters_.maxLocalSearch_ &&
00058 CoinCpuTime() - timeBegin_ < parameters_.maxLocalSearchTime_ &&
00059 numSols_ < parameters_.maxSols_);
00060 }
00062 double
00063 MinlpFeasPump::performOa(OsiCuts &cs,
00064 solverManip &lpManip,
00065 BabInfo * babInfo,
00066 double & cutoff,const CglTreeInfo &info) const
00067 {
00068
00069
00070
00071
00072 const int numcols = nlp_->getNumCols();
00073 vector<double> savedColLower(nlp_->getNumCols());
00074 CoinCopyN(nlp_->getColLower(), nlp_->getNumCols(), savedColLower());
00075 vector<double> savedColUpper(nlp_->getNumCols());
00076 CoinCopyN(nlp_->getColUpper(), nlp_->getNumCols(), savedColUpper());
00077
00078
00079 subMip_->setLpSolver(lpManip.si());
00080 OsiSolverInterface * lp = subMip_->solver();
00081
00082 assert(lp);
00083 vector<int> indices;
00084 for(int i = 0; i < numcols ; i++) {
00085 lp->setObjCoeff(i,0);
00086 if(!lp->isInteger(i)) {
00087 }
00088 else { indices.push_back(i);}
00089 }
00090
00091
00092 const double * colsol = NULL;
00093 lp->resolve();
00094 OsiBranchingInformation branch_info(lp, false);
00095 branch_info.lower_ = savedColLower();
00096 branch_info.upper_ = savedColUpper();
00097 if(lp->getNumCols() == nlp_->getNumCols())
00098 nlp_->addObjectiveFunction(*lp, nlp_->getColSolution());
00099 lp->setObjCoeff(numcols,0);
00100
00101 bool milpOptimal = false;
00102 nlp_->resolve(txt_id);
00103 set_fp_objective(*lp, nlp_->getColSolution());
00104 lp->initialSolve();
00105 lp->setColUpper(numcols, cutoff);
00106 subMip_->solve(DBL_MAX, parameters_.subMilpLogLevel_,
00107
00108 (parameters_.maxLocalSearchTime_ + timeBegin_ - CoinCpuTime()) );
00109
00110 milpOptimal = subMip_ -> optimal();
00111 colsol = subMip_->getLastSolution();
00112 nLocalSearch_++;
00113 if(milpOptimal)
00114 handler_->message(SOLVED_LOCAL_SEARCH, messages_)
00115 <<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00116 else
00117 handler_->message(LOCAL_SEARCH_ABORT, messages_)
00118 <<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00119 int numberPasses = 0;
00120
00121 #ifdef OA_DEBUG
00122 bool foundSolution = 0;
00123 #endif
00124 double * nlpSol = NULL;
00125 int major_iteration = 0;
00126 double ub = cutoff;
00127 while (colsol) {
00128 numberPasses++;
00129
00130
00131 int numberCutsBefore = cs.sizeRowCuts();
00132
00133
00134 branch_info.solution_ = colsol;
00135
00136 vector<double> x_bar(indices.size());
00137 for(unsigned int i = 0 ; i < indices.size() ; i++){
00138 assert(fabs(colsol[indices[i]] - floor(colsol[indices[i]] + 0.5)) < 1e-5);
00139 x_bar[i] = colsol[indices[i]];
00140 }
00141
00142 double dist = nlp_->solveFeasibilityProblem(indices.size(), x_bar(), indices(), 1, 0, 2);
00143
00144 handler_->message(FP_DISTANCE, messages_)
00145 <<dist<<CoinMessageEol;
00146
00147 if(dist < 1e-05){
00148 fixIntegers(*nlp_,branch_info, parameters_.cbcIntegerTolerance_, objects_, nObjects_);
00149
00150 nlp_->resolve(txt_id);
00151 if(!nlp_->isProvenOptimal()){
00152 relaxIntegers(*nlp_,branch_info, parameters_.cbcIntegerTolerance_, objects_, nObjects_);
00153 nlp_->resolve(txt_id);
00154 }
00155 bool restart = false;
00156 if (post_nlp_solve(babInfo, cutoff)) {
00157 restart = true;
00158
00159
00160 ub = std::min(ub, nlp_->getObjValue());
00161 cutoff = ub * (1 - parameters_.cbcCutoffIncrement_);
00162
00163 numSols_++;
00164 }
00165 else{
00166
00167
00168
00169 }
00170 nlpSol = const_cast<double *>(nlp_->getColSolution());
00171 nlp_->getOuterApproximation(cs, nlpSol, 1, NULL,
00172 parameter().global_);
00173
00174 nlp_->setColLower(savedColLower());
00175 nlp_->setColUpper(savedColUpper());
00176 if(restart){
00177 major_iteration++;
00178 handler_->message(FP_MAJOR_ITERATION, messages_)
00179 <<major_iteration<<cutoff<<CoinMessageEol;
00180 nlp_->resolve(txt_id);
00181 }
00182
00183
00184 }
00185 else {
00186 nlpSol = const_cast<double *>(nlp_->getColSolution());
00187 nlp_->getOuterApproximation(cs, nlpSol, 1, NULL,
00188 parameter().global_);
00189 }
00190
00191
00192 #if 0
00193 handler_->message(FP_MINOR_ITERATION, messages_)
00194 <<nLocalSearch_<<cutoff<<CoinMessageEol;
00195 #endif
00196
00197 int numberCuts = cs.sizeRowCuts() - numberCutsBefore;
00198 assert(numberCuts);
00199 installCuts(*lp, cs, numberCuts);
00200 numberCutsBefore = cs.sizeRowCuts();
00201
00202
00203 if (CoinCpuTime() - timeBegin_ > parameters_.maxLocalSearchTime_){
00204 colsol = NULL;
00205 break;
00206 }
00207
00208 if (nLocalSearch_ < parameters_.maxLocalSearch_ &&
00209 numSols_ < parameters_.maxSols_) {
00210
00211 nLocalSearch_++;
00212 set_fp_objective(*lp, nlp_->getColSolution());
00213
00214 lp->setColUpper(numcols, cutoff);
00215
00216 subMip_->solve(DBL_MAX, parameters_.subMilpLogLevel_,
00217
00218 parameters_.maxLocalSearchTime_ + timeBegin_ - CoinCpuTime());
00219 milpOptimal = subMip_ -> optimal();
00220 colsol = subMip_->getLastSolution();
00221 if(milpOptimal)
00222 handler_->message(SOLVED_LOCAL_SEARCH, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00223 else
00224 handler_->message(LOCAL_SEARCH_ABORT, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00225 if(colsol)
00226 handler_->message(FP_MILP_VAL, messages_)
00227 <<colsol[nlp_->getNumCols()]<<CoinMessageEol;
00228
00229 }
00230 else {
00231 colsol = NULL;
00232 }
00233 }
00234
00235 if(!passBound_ || colsol || ! milpOptimal)
00236 return -DBL_MAX;
00237 else{
00238 handler_->message(OASUCCESS, messages_)<<"FP"<<CoinCpuTime() - timeBegin_
00239 <<ub<<CoinMessageEol;
00240 return DBL_MAX;
00241 }
00242 }
00243
00245 void
00246 MinlpFeasPump::registerOptions(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions)
00247 {
00248 roptions->SetRegisteringCategory("Options for feasibility pump", RegisteredOptions::BonminCategory);
00249
00250 roptions->AddStringOption2("fp_pass_infeasible", "Say whether feasibility pump should claim to converge or not",
00251 "no",
00252 "no", "When master MILP is infeasible just bail out (don't stop all algorithm). This is the option for using in B-Hyb.",
00253 "yes", "Claim convergence, numerically dangerous.","");
00254 roptions->AddBoundedIntegerOption("fp_log_level",
00255 "specify FP iterations log level.",
00256 0,2,1,
00257 "Set the level of output of OA decomposition solver : "
00258 "0 - none, 1 - normal, 2 - verbose"
00259 );
00260 roptions->setOptionExtraInfo("fp_log_level",3);
00261
00262 roptions->AddLowerBoundedNumberOption("fp_log_frequency",
00263 "display an update on lower and upper bounds in FP every n seconds",
00264 0.,1.,100.,
00265 "");
00266 roptions->setOptionExtraInfo("fp_log_frequency",3);
00267 }
00268
00270 void
00271 MinlpFeasPump::set_fp_objective(OsiSolverInterface &si, const double * colsol) const{
00272 if (objects_) {
00273 for (int i = 0 ; i < nObjects_ ; i++) {
00274 OsiObject * obj = objects_[i];
00275 int colnum = obj->columnNumber();
00276 if (colnum >= 0) {
00277 double round = floor(colsol[colnum] + 0.5);
00278 double coeff = (colsol[colnum] - round ) < 0;
00279 si.setObjCoeff(colnum, 1 - 2 * coeff);
00280 }
00281 else {
00282 throw CoinError("OaDecompositionBase::solverManip",
00283 "setFpObjective",
00284 "Can not use FP on problem with SOS constraints");
00285 }
00286 }
00287 }
00288 else {
00289 int numcols = nlp_->getNumCols();
00290 for (int i = 0; i < numcols ; i++) {
00291 if (nlp_->isInteger(i)){
00292 double round = floor(colsol[i] + 0.5);
00293 double coeff = (colsol[i] - round ) < 0;
00294 si.setObjCoeff(i, 1 - 2*coeff);
00295 }
00296 }
00297 }
00298 si.initialSolve();
00299 }
00300
00301 }