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