00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "BonOACutGenerator2.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 = "OA decomposition";
00028
00029
00031 OACutGenerator2::OACutGenerator2(BabSetupBase & b):
00032 OaDecompositionBase(b, true, false)
00033 {
00034 std::string bonmin="bonmin.";
00035 std::string prefix = (b.prefix() == bonmin) ? "" : b.prefix();
00036 prefix += "oa_decomposition.";
00037 subMip_ = new SubMipSolver(b, prefix);
00038 double oaTime;
00039 b.options()->GetNumericValue("time_limit",oaTime,prefix);
00040 parameter().maxLocalSearch_ = INT_MAX;
00041 b.options()->GetIntegerValue("solution_limit", parameter().maxSols_,prefix);
00042 parameter().maxLocalSearchTime_ =
00043 std::min(b.getDoubleParameter(BabSetupBase::MaxTime), oaTime);
00044 if(parameter().maxSols_ > b.getIntParameter(BabSetupBase::MaxSolutions))
00045 parameter().maxSols_ = b.getIntParameter(BabSetupBase::MaxSolutions);
00046 }
00047 OACutGenerator2::~OACutGenerator2()
00048 {
00049 delete subMip_;
00050 }
00051
00053 bool
00054 OACutGenerator2::doLocalSearch(BabInfo * babInfo) const
00055 {
00056 return (nLocalSearch_<parameters_.maxLocalSearch_ &&
00057 numSols_ < parameters_.maxSols_ &&
00058 CoinCpuTime() - timeBegin_ < parameters_.maxLocalSearchTime_);
00059 }
00061 double
00062 OACutGenerator2::performOa(OsiCuts &cs,
00063 solverManip &lpManip,
00064 BabInfo * babInfo,
00065 double & cutoff, const CglTreeInfo & info) const
00066 {
00067
00068 double lastPeriodicLog = CoinCpuTime();
00069
00070
00071 double gap_tol = this->parameter().gap_tol_;
00072
00073 bool isInteger = false;
00074
00075 subMip_->setLpSolver(lpManip.si());
00076 OsiSolverInterface * lp = subMip_->solver();
00077 lp->resolve();
00078 OsiBranchingInformation branch_info(lp, false);
00079 bool milpOptimal = 1;
00080
00081
00082 double milpBound = -COIN_DBL_MAX;
00083 bool milpFeasible = 1;
00084 bool feasible = 1;
00085
00086 subMip_->solve(cutoff, parameters_.subMilpLogLevel_,
00087 (parameters_.maxLocalSearchTime_ + timeBegin_ - CoinCpuTime()));
00088 milpBound = std::max(milpBound, subMip_->lowBound());
00089 milpOptimal = subMip_->optimal();
00090
00091 feasible = milpBound < cutoff;
00092 milpFeasible = feasible;
00093 isInteger = (subMip_->getLastSolution() != NULL);
00094 nLocalSearch_++;
00095
00096 if (milpOptimal)
00097 handler_->message(SOLVED_LOCAL_SEARCH, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00098 else
00099 {
00100 handler_->message(LOCAL_SEARCH_ABORT, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00101 }
00102
00103 int nodeCount = subMip_->nodeCount();
00104
00105 int numberPasses = 0;
00106
00107 #ifdef OA_DEBUG
00108 bool foundSolution = 0;
00109 #endif
00110 double * nlpSol = NULL;
00111 double ub = cutoff;
00112 double gap = 1;
00113 while (isInteger && feasible) {
00114 numberPasses++;
00115
00116 double time = CoinCpuTime();
00117 if (time - lastPeriodicLog > parameters_.logFrequency_) {
00118 handler_->message(PERIODIC_MSG,messages_)
00119 <<time - timeBegin_<<cutoff
00120 <<milpBound
00121 <<CoinMessageEol;
00122 lastPeriodicLog = CoinCpuTime();
00123 }
00124
00125
00126
00127 int numberCutsBefore = cs.sizeRowCuts();
00128
00129
00130 const double * colsol =
00131 subMip_->getLastSolution();
00132 branch_info.solution_ = colsol;
00133
00134 fixIntegers(*nlp_,branch_info, parameters_.cbcIntegerTolerance_,objects_, nObjects_);
00135
00136 nlp_->resolve(txt_id);
00137 if (post_nlp_solve(babInfo, cutoff)) {
00138
00139
00140 ub = std::min(nlp_->getObjValue(), ub);
00141 cutoff = ub > 0 ? ub *(1 - parameters_.cbcCutoffIncrement_) : ub*(1 + parameters_.cbcCutoffIncrement_);
00142 assert(cutoff < ub);
00143
00144 lp->setDblParam(OsiDualObjectiveLimit, cutoff);
00145 numSols_++;
00146 }
00147
00148 nlpSol = const_cast<double *>(nlp_->getColSolution());
00149
00150
00151 const double * toCut = (parameter().addOnlyViolated_)?
00152 colsol:NULL;
00153 nlp_->getOuterApproximation(cs, nlpSol, 1, toCut,
00154 parameter().global_);
00155
00156 int numberCuts = cs.sizeRowCuts() - numberCutsBefore;
00157 assert(numberCuts);
00158 installCuts(*lp, cs, numberCuts);
00159
00160 lp->resolve();
00161
00162 double objvalue = lp->getObjValue();
00163
00164 feasible = (lp->isProvenOptimal() &&
00165 !lp->isDualObjectiveLimitReached() && (objvalue<cutoff)) ;
00166
00167 bool changed = !feasible;
00168 branch_info.solution_ = lp->getColSolution();
00169 if (!changed)
00170 changed = isDifferentOnIntegers(*nlp_, objects_, nObjects_,
00171 0.1,
00172 nlp_->getColSolution(), lp->getColSolution());
00173 if (changed) {
00174
00175 isInteger = integerFeasible(*lp, branch_info, parameters_.cbcIntegerTolerance_,
00176 objects_, nObjects_);
00177 }
00178 else {
00179 isInteger = 0;
00180
00181 milpBound = 1e200;
00182 }
00183 #ifdef OA_DEBUG
00184 printf("Obj value after cuts %g %d rows\n",lp->getObjValue(),
00185 numberCuts) ;
00186 #endif
00187
00188 if (CoinCpuTime() - timeBegin_ > parameters_.maxLocalSearchTime_)
00189 break;
00190
00191 if(ub!=0)
00192 gap = (ub - milpBound)/fabs(ub);
00193 else
00194 gap = -milpBound/(1e-10);
00195 if (gap < gap_tol){
00196 milpBound = 1e50;
00197 feasible = 0;
00198 handler_->message(OASUCCESS, messages_)<<"OA finished due to gap tolerance"<<CoinCpuTime() - timeBegin_
00199 <<ub<<CoinMessageEol;
00200 }
00201
00202 if (feasible &&
00203 nLocalSearch_ < parameters_.maxLocalSearch_ &&
00204 numSols_ < parameters_.maxSols_) {
00205
00206 if(ub!=0)
00207 gap = (ub - milpBound)/fabs(ub);
00208 else
00209 gap = -milpBound/(1e-10);
00210 if (gap < gap_tol){
00211 milpBound = 1e50;
00212 feasible = 0;
00213 handler_->message(OASUCCESS, messages_)<<"OA finished due to gap tolerance"<<CoinCpuTime() - timeBegin_
00214 <<ub<<CoinMessageEol;
00215 }
00216 nLocalSearch_++;
00217
00218 assert(cutoff < ub);
00219 subMip_->solve(cutoff, parameters_.subMilpLogLevel_,
00220 parameters_.maxLocalSearchTime_ + timeBegin_ - CoinCpuTime()
00221 );
00222
00223 milpBound = std::max(milpBound, subMip_->lowBound());
00224
00225 if (subMip_->optimal())
00226 handler_->message(SOLVED_LOCAL_SEARCH, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00227 else
00228 handler_->message(LOCAL_SEARCH_ABORT, messages_)<<subMip_->nodeCount()<<subMip_->iterationCount()<<CoinMessageEol;
00229
00230 nodeCount += subMip_->nodeCount();
00231
00232 colsol = const_cast<double *> (subMip_->getLastSolution());
00233 isInteger = (colsol != 0);
00234
00235 feasible = (milpBound < cutoff);
00236
00237 if (feasible && isInteger) {
00238 bool changed = false;
00239 changed = isDifferentOnIntegers(*nlp_, objects_, nObjects_,
00240 0.1,
00241 nlp_->getColSolution(), colsol);
00242
00243 if (!changed) {
00244 feasible = 0;
00245 milpBound = 1e50;
00246 }
00247 milpFeasible = feasible;
00248 }
00249 if (subMip_->optimal())
00250 milpOptimal = 1;
00251 else {
00252 milpOptimal = 0;
00253 }
00254 if (milpBound < cutoff)
00255 handler_->message(UPDATE_LB, messages_)<<milpBound<<CoinCpuTime() - timeBegin_<<CoinMessageEol;
00256 else {
00257 milpBound = 1e50;
00258 feasible = 0;
00259 handler_->message(OASUCCESS, messages_)<<"OA"<<CoinCpuTime() - timeBegin_
00260 <<ub<<CoinMessageEol;
00261 }
00262 }
00263
00264 }
00265
00266
00267 handler_->message(OA_STATS, messages_)<<numberPasses<<nodeCount
00268 <<CoinMessageEol;
00269 #ifdef OA_DEBUG
00270 debug_.printEndOfProcedureDebugMessage(cs, foundSolution, cutoff, milpBound, isInteger, feasible, std::cout);
00271 #endif
00272 return milpBound;
00273 }
00274
00276 void
00277 OACutGenerator2::registerOptions(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions)
00278 {
00279 roptions->SetRegisteringCategory("Options for OA decomposition", RegisteredOptions::BonminCategory);
00280 roptions->AddStringOption2("oa_decomposition", "If yes do initial OA decomposition",
00281 "no",
00282 "no","",
00283 "yes","",
00284 "");
00285 roptions->setOptionExtraInfo("oa_decomposition",19);
00286
00287 roptions->AddBoundedIntegerOption("oa_log_level",
00288 "specify OA iterations log level.",
00289 0,2,1,
00290 "Set the level of output of OA decomposition solver : "
00291 "0 - none, 1 - normal, 2 - verbose"
00292 );
00293 roptions->setOptionExtraInfo("oa_log_level", 25);
00294
00295 roptions->AddLowerBoundedNumberOption("oa_log_frequency",
00296 "display an update on lower and upper bounds in OA every n seconds",
00297 0.,1.,100.,
00298 "");
00299 roptions->setOptionExtraInfo("oa_log_frequency", 25);
00300 }
00301 }
00302