00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "BonIpoptSolver.hpp"
00012 #include "IpSolveStatistics.hpp"
00013 #include "CoinError.hpp"
00014
00015 #include "BonIpoptInteriorWarmStarter.hpp"
00016 #include "BonIpoptWarmStart.hpp"
00017
00018
00019 extern bool BonminAbortAll;
00020
00021 namespace Bonmin
00022 {
00023
00024 std::string IpoptSolver::solverName_ = "Ipopt";
00025
00027 IpoptSolver::IpoptSolver(bool createEmpty ):
00028 TNLPSolver(),
00029 problemHadZeroDimension_(false),
00030 warmStartStrategy_(1),
00031 enable_warm_start_(false),
00032 optimized_before_(false)
00033 {
00034 if (createEmpty) return;
00035 app_ = new Ipopt::IpoptApplication(GetRawPtr(roptions_), options_, journalist_);
00036 }
00037
00039 IpoptSolver::IpoptSolver(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions,
00040 Ipopt::SmartPtr<Ipopt::OptionsList> options,
00041 Ipopt::SmartPtr<Ipopt::Journalist> journalist,
00042 const std::string & prefix):
00043 TNLPSolver(roptions, options, journalist, prefix),
00044 problemHadZeroDimension_(false),
00045 warmStartStrategy_(1),
00046 enable_warm_start_(false),
00047 optimized_before_(false)
00048 {
00049 roptions_ = roptions;
00050 app_ = new Ipopt::IpoptApplication(GetRawPtr(roptions), options, journalist);
00051 }
00052
00054 IpoptSolver::IpoptSolver(Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions,
00055 Ipopt::SmartPtr<Ipopt::OptionsList> options,
00056 Ipopt::SmartPtr<Ipopt::Journalist> journalist):
00057 TNLPSolver(roptions, options, journalist, "bonmin."),
00058 problemHadZeroDimension_(false),
00059 warmStartStrategy_(1),
00060 enable_warm_start_(false),
00061 optimized_before_(false)
00062 {
00063 roptions_ = roptions;
00064 app_ = new Ipopt::IpoptApplication(GetRawPtr(roptions), options, journalist);
00065 }
00066
00067 IpoptSolver::~IpoptSolver()
00068 {}
00069
00070 IpoptSolver::IpoptSolver(const IpoptSolver &other):
00071 TNLPSolver(other),
00072 optimizationStatus_(other.optimizationStatus_),
00073 problemHadZeroDimension_(other.problemHadZeroDimension_),
00074 warmStartStrategy_(other.warmStartStrategy_),
00075 enable_warm_start_(false),
00076 optimized_before_(false){
00077 app_ = new Ipopt::IpoptApplication(GetRawPtr(roptions_), options_, journalist_);
00078 }
00079
00081 Ipopt::SmartPtr<TNLPSolver>
00082 IpoptSolver::clone()
00083 {
00084 SmartPtr<IpoptSolver> retval = new IpoptSolver(*this);
00085 retval->app_->Initialize("");
00086 retval->default_log_level_ = default_log_level_;
00087 return GetRawPtr(retval);
00088 }
00089
00090
00091 bool
00092 IpoptSolver::Initialize(std::string params_file)
00093 {
00094 Ipopt::ApplicationReturnStatus status =
00095 app_->Initialize(params_file);
00096 if (status != Ipopt::Solve_Succeeded) {
00097 return false;
00098 }
00099 options_->GetEnumValue("warm_start",warmStartStrategy_,prefix());
00100 setMinlpDefaults(options_);
00101 optimized_before_ = false;
00102 return true;
00103 }
00104
00105 bool
00106 IpoptSolver::Initialize(std::istream &is)
00107 {
00108 Ipopt::ApplicationReturnStatus status =
00109 app_->Initialize(is);
00110 if (status != Ipopt::Solve_Succeeded) {
00111 return false;
00112 }
00113 options_->GetEnumValue("warm_start",warmStartStrategy_,prefix());
00114 setMinlpDefaults(app_->Options());
00115 optimized_before_ = false;
00116 return true;
00117 }
00118
00119 TNLPSolver::ReturnStatus
00120 IpoptSolver::OptimizeTNLP(const Ipopt::SmartPtr<Ipopt::TNLP> &tnlp)
00121 {
00122 #if 0
00123 printf("Global Time limit set to %g\n", time_limit_);
00124 double local_time_limit = time_limit_ -
00125 CoinCpuTime() + start_time_;
00126 printf("Time limit set to %g\n", local_time_limit);
00127 if(local_time_limit <= 0.){
00128 optimizationStatus_ = Ipopt::Maximum_CpuTime_Exceeded;
00129 return solverReturnStatus(optimizationStatus_);
00130 }
00131 #endif
00132 TNLPSolver::ReturnStatus ret_status;
00133 if (!zeroDimension(tnlp, ret_status)) {
00134 #if 0
00135 if(time_limit_ < DBL_MAX){
00136 options_->SetNumericValue("max_cpu_time", local_time_limit,
00137 true, true);
00138 }
00139 #endif
00140 if (enable_warm_start_ && optimized_before_) {
00141 optimizationStatus_ = app_->ReOptimizeTNLP(tnlp);
00142 }
00143 else {
00144 optimizationStatus_ = app_->OptimizeTNLP(tnlp);
00145 }
00146 optimized_before_ = true;
00147 problemHadZeroDimension_ = false;
00148 }
00149 else {
00150 problemHadZeroDimension_ = true;
00151 if (ret_status == solvedOptimal)
00152 optimizationStatus_ = Ipopt::Solve_Succeeded;
00153 else if (ret_status == provenInfeasible)
00154 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00155 }
00156
00157 if (BonminAbortAll)
00158 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00159
00160 return solverReturnStatus(optimizationStatus_);
00161 }
00162
00163
00164 TNLPSolver::ReturnStatus
00165 IpoptSolver::ReOptimizeTNLP(const Ipopt::SmartPtr<Ipopt::TNLP> &tnlp)
00166 {
00167 #if 0
00168 printf("Global Time limit set to %g\n", time_limit_);
00169 double local_time_limit = time_limit_ -
00170 CoinCpuTime() + start_time_;
00171 printf("Time limit set to %g\n", local_time_limit);
00172 if(local_time_limit <= 0.){
00173 optimizationStatus_ = Ipopt::Maximum_CpuTime_Exceeded;
00174 return solverReturnStatus(optimizationStatus_);
00175 }
00176 #endif
00177 TNLPSolver::ReturnStatus ret_status;
00178 if (!zeroDimension(tnlp, ret_status)) {
00179 #if 0
00180 if(time_limit_ < DBL_MAX){
00181 options_->SetNumericValue("max_cpu_time",
00182 std::max(0., local_time_limit),
00183 true, true);
00184 }
00185 #endif
00186 if (optimized_before_) {
00187 optimizationStatus_ = app_->ReOptimizeTNLP(tnlp);
00188 }
00189 else {
00190 optimizationStatus_ = app_->OptimizeTNLP(tnlp);
00191 }
00192 problemHadZeroDimension_ = false;
00193 optimized_before_ = true;
00194 }
00195 else {
00196 problemHadZeroDimension_ = true;
00197 if (ret_status == solvedOptimal)
00198 optimizationStatus_ = Ipopt::Solve_Succeeded;
00199 else if (ret_status == provenInfeasible)
00200 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00201 }
00202 if (BonminAbortAll)
00203 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00204 return solverReturnStatus(optimizationStatus_);
00205 }
00206
00208 double
00209 IpoptSolver::CPUTime()
00210 {
00211 if (problemHadZeroDimension_) {
00212 return 0.;
00213 }
00214 else {
00215 const Ipopt::SmartPtr<Ipopt::SolveStatistics> stats = app_->Statistics();
00216 if (IsValid(stats)) {
00217 return stats->TotalCPUTime();
00218 }
00219 else {
00220 printf("TODO: No statistics available from Ipopt in Bonmin::IpoptSolver::CPUTime\n");
00221 return 0.;
00222
00223 }
00224 }
00225 }
00226
00228 int
00229 IpoptSolver::IterationCount()
00230 {
00231 if (problemHadZeroDimension_) {
00232 return 0;
00233 }
00234 else {
00235 const Ipopt::SmartPtr<Ipopt::SolveStatistics> stats = app_->Statistics();
00236 if (IsValid(stats)) {
00237 return stats->IterationCount();
00238 }
00239 else {
00240 printf("TODO: No statistics available from Ipopt in Bonmin::IpoptSolver::IterationCount\n");
00241 return 0;
00242
00243 }
00244
00245 }
00246 }
00247
00248
00249 void
00250 IpoptSolver::setMinlpDefaults(Ipopt::SmartPtr<Ipopt::OptionsList> Options)
00251 {
00252 Options->SetNumericValue("gamma_phi", 1e-8, true, true);
00253 Options->SetNumericValue("gamma_theta", 1e-4, true, true);
00254 Options->SetNumericValue("required_infeasibility_reduction", 0.1, true, true);
00255 Options->SetStringValue("expect_infeasible_problem","yes", true, true);
00256 Options->SetStringValue("mu_strategy", "adaptive", true, true);
00257 Options->SetStringValue("mu_oracle","probing", true, true);
00258 if(!Options->GetIntegerValue("print_level",default_log_level_,""))
00259 default_log_level_ = 1;
00260 Options->SetIntegerValue("print_level",1, true, true);
00261 }
00262
00263
00265
00268 TNLPSolver::ReturnStatus IpoptSolver::solverReturnStatus(Ipopt::ApplicationReturnStatus optimization_status) const
00269 {
00270
00271 switch (optimization_status) {
00272 case Ipopt::Maximum_Iterations_Exceeded:
00273 case Ipopt::User_Requested_Stop:
00274 case Ipopt::Restoration_Failed:
00275 return iterationLimit;
00276 case Ipopt::Error_In_Step_Computation:
00277 case Ipopt::Unrecoverable_Exception:
00278 case Ipopt::Insufficient_Memory:
00279 return computationError;
00280 case Ipopt::Not_Enough_Degrees_Of_Freedom:
00281 return notEnoughFreedom;
00282 case Ipopt::Invalid_Problem_Definition:
00283 return illDefinedProblem;
00284 case Ipopt::Invalid_Option:
00285 case Ipopt::Invalid_Number_Detected:
00286 return illegalOption;
00287 case Ipopt::NonIpopt_Exception_Thrown:
00288 return externalException;
00289 case Ipopt::Internal_Error:
00290 return exception;
00291 case Ipopt::Solve_Succeeded:
00292 case Ipopt::Feasible_Point_Found:
00293 return solvedOptimal;
00294 case Ipopt::Search_Direction_Becomes_Too_Small:
00295 return doesNotConverge;
00296 case Ipopt::Solved_To_Acceptable_Level:
00297 return solvedOptimalTol;
00298 case Ipopt::Infeasible_Problem_Detected:
00299 return provenInfeasible;
00300 case Ipopt::Diverging_Iterates:
00301 return unbounded;
00302 case Ipopt::Maximum_CpuTime_Exceeded:
00303 return timeLimit;
00304 default:
00305 return exception;
00306 }
00307 }
00308
00310 CoinWarmStart *
00311 IpoptSolver::getUsedWarmStart(Ipopt::SmartPtr<TMINLP2TNLP> tnlp) const
00312 {
00313 return new IpoptWarmStart(tnlp->num_variables(),
00314 2*tnlp->num_variables() +
00315 tnlp->num_constraints(),
00316 tnlp->x_init(), tnlp->duals_init());
00317 }
00319 CoinWarmStart*
00320 IpoptSolver::getWarmStart(Ipopt::SmartPtr<TMINLP2TNLP> tnlp) const
00321 {
00322 if (warmStartStrategy_==2) {
00323 Ipopt::SmartPtr<IpoptInteriorWarmStarter> warm_starter =
00324 Ipopt::SmartPtr<IpoptInteriorWarmStarter>(tnlp->GetWarmStarter());
00325 return new IpoptWarmStart(tnlp, warm_starter);
00326 }
00327 else return new IpoptWarmStart(tnlp, NULL);
00328 }
00329
00330
00331 bool
00332 IpoptSolver::setWarmStart(const CoinWarmStart* warmstart,
00333 Ipopt::SmartPtr<TMINLP2TNLP> tnlp)
00334 {
00335 if (!warmstart && warmStartStrategy_)
00336 return 0;
00337 const IpoptWarmStart * ws = dynamic_cast<const IpoptWarmStart*> (warmstart);
00338 if (ws->empty())
00339 {
00340 disableWarmStart();
00341 return 1;
00342 }
00343 if(ws->dualSize() > 0){
00344 tnlp->setDualsInit(ws->dualSize(), ws->dual());
00345 enableWarmStart();
00346 }
00347 else
00348 disableWarmStart();
00349 #ifndef NDEBUG
00350 int numcols = tnlp->num_variables();
00351 int numrows = tnlp->num_constraints();
00352 #endif
00353
00354 assert(numcols == ws->primalSize());
00355 assert(2*numcols + numrows == ws->dualSize());
00356 tnlp->setxInit(ws->primalSize(), ws->primal());
00357
00358 if (IsValid(ws->warm_starter()))
00359 tnlp->SetWarmStarter(ws->warm_starter());
00360
00361 return 1;
00362 }
00363
00364 bool
00365 IpoptSolver::warmStartIsValid(const CoinWarmStart * ws) const{
00366 const IpoptWarmStart* iws = dynamic_cast<const IpoptWarmStart*>(ws);
00367 if (iws && !iws->empty()) {
00368 return true;
00369 }
00370 return false;
00371 }
00372
00373 CoinWarmStart *
00374 IpoptSolver::getEmptyWarmStart() const
00375 {
00376 return new IpoptWarmStart(1);
00377 }
00378
00379 void
00380 IpoptSolver::enableWarmStart()
00381 {
00382 enable_warm_start_ = true;
00383 options_->SetStringValue("warm_start_init_point", "yes");
00384 }
00385
00386 void
00387 IpoptSolver::disableWarmStart()
00388 {
00389 enable_warm_start_ = false;
00390 options_->SetStringValue("warm_start_init_point", "no");
00391 }
00392
00393
00394 void
00395 IpoptSolver::setOutputToDefault()
00396 {
00397 options_->SetIntegerValue("print_level", default_log_level_, true, true);
00398 }
00399
00400
00401 void
00402 IpoptSolver::forceSolverOutput(int log_level)
00403 {
00404 options_->SetIntegerValue("print_level", log_level, true, true);
00405 }
00406
00407
00408
00409
00410
00411
00412 std::string
00413 IpoptSolver::UnsolvedIpoptError::errorNames[17] ={"Solve succeeded",
00414 "Solved to acceptable level",
00415 "Infeasible problem detected",
00416 "Search direction becomes too small",
00417 "Diverging iterates",
00418 "User requested stop",
00419 "Maximum iterations exceeded",
00420 "Restoration failed",
00421 "Error in step computation",
00422 "Not enough degrees of freedom",
00423 "Invalid problem definition",
00424 "Invalid option",
00425 "Invalid number detected",
00426 "Unrecoverable exception",
00427 "NonIpopt exception thrown",
00428 "Insufficient memory",
00429 "Internal error"};
00430
00431 const std::string &
00432 IpoptSolver::UnsolvedIpoptError::errorName() const
00433 {
00434 if (errorNum() >=0)
00435 return errorNames[errorNum()];
00436 if (errorNum() == -1) return errorNames[6];
00437 else if (errorNum() == -2) return errorNames[7];
00438 else if (errorNum() == -3) return errorNames[8];
00439 else if (errorNum() == -10) return errorNames[9];
00440 else if (errorNum() == -11) return errorNames[10];
00441 else if (errorNum() == -12) return errorNames[11];
00442 else if (errorNum() == -13) return errorNames[12];
00443 else if (errorNum() == -100) return errorNames[13];
00444 else if (errorNum() == -101) return errorNames[14];
00445 else if (errorNum() == -102) return errorNames[15];
00446 else if (errorNum() == -199) return errorNames[16];
00447 throw CoinError("UnsolvedError", "UnsolvedError::errorName()","Unrecognized optimization status in ipopt.");
00448 }
00449
00450 std::string IpoptSolver::UnsolvedIpoptError::solverName_ = "Ipopt";
00451
00452 const std::string &
00453 IpoptSolver::UnsolvedIpoptError::solverName() const
00454 {
00455 return solverName_;
00456 }
00457
00458
00459
00460
00461 }