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 Ipopt::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 app_->Jnlst()->Printf(Ipopt::J_WARNING, Ipopt::J_STATISTICS, "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 app_->Jnlst()->Printf(Ipopt::J_WARNING, Ipopt::J_STATISTICS, "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 bool set = false;
00253 double dummy_dbl;
00254 int dummy_int;
00255 set = Options->GetNumericValue("gamma_phi", dummy_dbl, "");
00256 if(!set)
00257 Options->SetNumericValue("gamma_phi", 1e-8, true, true);
00258 set = Options->GetNumericValue("gamma_theta", dummy_dbl, "");
00259 if(!set)
00260 Options->SetNumericValue("gamma_theta", 1e-4, true, true);
00261 set = Options->GetNumericValue("required_infeasibility_reduction", dummy_dbl, "");
00262 if(!set)
00263 Options->SetNumericValue("required_infeasibility_reduction", 0.1, true, true);
00264 set = Options->GetEnumValue("expect_infeasible_problem",dummy_int, "");
00265 if(!set)
00266 Options->SetStringValue("expect_infeasible_problem","yes", true, true);
00267 set = Options->GetEnumValue("mu_strategy", dummy_int, "");
00268 if(!set)
00269 Options->SetStringValue("mu_strategy", "adaptive", true, true);
00270 set = Options->GetEnumValue("mu_oracle",dummy_int, "");
00271 if(!set)
00272 Options->SetStringValue("mu_oracle","probing", true, true);
00273 if(!Options->GetIntegerValue("print_level",default_log_level_,"")) {
00274 default_log_level_ = 1;
00275 Options->SetIntegerValue("print_level",1, true, true);
00276 }
00277 }
00278
00279
00281
00284 TNLPSolver::ReturnStatus IpoptSolver::solverReturnStatus(Ipopt::ApplicationReturnStatus optimization_status) const
00285 {
00286
00287 switch (optimization_status) {
00288 case Ipopt::Maximum_Iterations_Exceeded:
00289 case Ipopt::User_Requested_Stop:
00290 case Ipopt::Restoration_Failed:
00291 return iterationLimit;
00292 case Ipopt::Error_In_Step_Computation:
00293 case Ipopt::Unrecoverable_Exception:
00294 case Ipopt::Insufficient_Memory:
00295 return computationError;
00296 case Ipopt::Not_Enough_Degrees_Of_Freedom:
00297 return notEnoughFreedom;
00298 case Ipopt::Invalid_Problem_Definition:
00299 return illDefinedProblem;
00300 case Ipopt::Invalid_Option:
00301 case Ipopt::Invalid_Number_Detected:
00302 return illegalOption;
00303 case Ipopt::NonIpopt_Exception_Thrown:
00304 return externalException;
00305 case Ipopt::Internal_Error:
00306 return exception;
00307 case Ipopt::Solve_Succeeded:
00308 case Ipopt::Feasible_Point_Found:
00309 return solvedOptimal;
00310 case Ipopt::Search_Direction_Becomes_Too_Small:
00311 return doesNotConverge;
00312 case Ipopt::Solved_To_Acceptable_Level:
00313 return solvedOptimalTol;
00314 case Ipopt::Infeasible_Problem_Detected:
00315 return provenInfeasible;
00316 case Ipopt::Diverging_Iterates:
00317 return unbounded;
00318 case Ipopt::Maximum_CpuTime_Exceeded:
00319 return timeLimit;
00320 default:
00321 return exception;
00322 }
00323 }
00324
00326 CoinWarmStart *
00327 IpoptSolver::getUsedWarmStart(Ipopt::SmartPtr<TMINLP2TNLP> tnlp) const
00328 {
00329 if(tnlp->x_init() == NULL || tnlp->duals_init() == NULL)
00330 return NULL;
00331 return new IpoptWarmStart(tnlp->num_variables(),
00332 2*tnlp->num_variables() +
00333 tnlp->num_constraints(),
00334 tnlp->x_init(), tnlp->duals_init());
00335 }
00337 CoinWarmStart*
00338 IpoptSolver::getWarmStart(Ipopt::SmartPtr<TMINLP2TNLP> tnlp) const
00339 {
00340 if (warmStartStrategy_==2) {
00341 Ipopt::SmartPtr<IpoptInteriorWarmStarter> warm_starter =
00342 Ipopt::SmartPtr<IpoptInteriorWarmStarter>(tnlp->GetWarmStarter());
00343 return new IpoptWarmStart(tnlp, warm_starter);
00344 }
00345 else return new IpoptWarmStart(tnlp, NULL);
00346 }
00347
00348
00349 bool
00350 IpoptSolver::setWarmStart(const CoinWarmStart* warmstart,
00351 Ipopt::SmartPtr<TMINLP2TNLP> tnlp)
00352 {
00353 if (!warmstart && warmStartStrategy_)
00354 return 0;
00355 const IpoptWarmStart * ws = dynamic_cast<const IpoptWarmStart*> (warmstart);
00356 if(ws == NULL) return 0;
00357 if (ws->empty())
00358 {
00359 disableWarmStart();
00360 return 1;
00361 }
00362 if(ws->dualSize() > 0){
00363 tnlp->setDualsInit(ws->dualSize(), ws->dual());
00364 enableWarmStart();
00365 }
00366 else
00367 disableWarmStart();
00368 #ifndef NDEBUG
00369 int numcols = tnlp->num_variables();
00370 int numrows = tnlp->num_constraints();
00371 #endif
00372
00373 assert(numcols == ws->primalSize());
00374 assert(2*numcols + numrows == ws->dualSize());
00375 tnlp->setxInit(ws->primalSize(), ws->primal());
00376
00377 if (IsValid(ws->warm_starter()))
00378 tnlp->SetWarmStarter(ws->warm_starter());
00379
00380 return 1;
00381 }
00382
00383 bool
00384 IpoptSolver::warmStartIsValid(const CoinWarmStart * ws) const{
00385 const IpoptWarmStart* iws = dynamic_cast<const IpoptWarmStart*>(ws);
00386 if (iws && !iws->empty()) {
00387 return true;
00388 }
00389 return false;
00390 }
00391
00392 CoinWarmStart *
00393 IpoptSolver::getEmptyWarmStart() const
00394 {
00395 return new IpoptWarmStart(1);
00396 }
00397
00398 void
00399 IpoptSolver::enableWarmStart()
00400 {
00401 enable_warm_start_ = true;
00402 options_->SetStringValue("warm_start_init_point", "yes");
00403 }
00404
00405 void
00406 IpoptSolver::disableWarmStart()
00407 {
00408 enable_warm_start_ = false;
00409 options_->SetStringValue("warm_start_init_point", "no");
00410 }
00411
00412
00413 void
00414 IpoptSolver::setOutputToDefault()
00415 {
00416 options_->SetIntegerValue("print_level", default_log_level_, true, true);
00417 }
00418
00419
00420 void
00421 IpoptSolver::forceSolverOutput(int log_level)
00422 {
00423 options_->SetIntegerValue("print_level", log_level, true, true);
00424 }
00425
00426
00427
00428
00429
00430
00431 std::string
00432 IpoptSolver::UnsolvedIpoptError::errorNames[17] ={"Solve succeeded",
00433 "Solved to acceptable level",
00434 "Infeasible problem detected",
00435 "Search direction becomes too small",
00436 "Diverging iterates",
00437 "User requested stop",
00438 "Maximum iterations exceeded",
00439 "Restoration failed",
00440 "Error in step computation",
00441 "Not enough degrees of freedom",
00442 "Invalid problem definition",
00443 "Invalid option",
00444 "Invalid number detected",
00445 "Unrecoverable exception",
00446 "NonIpopt exception thrown",
00447 "Insufficient memory",
00448 "Internal error"};
00449
00450 const std::string &
00451 IpoptSolver::UnsolvedIpoptError::errorName() const
00452 {
00453 if (errorNum() >=0)
00454 return errorNames[errorNum()];
00455 if (errorNum() == -1) return errorNames[6];
00456 else if (errorNum() == -2) return errorNames[7];
00457 else if (errorNum() == -3) return errorNames[8];
00458 else if (errorNum() == -10) return errorNames[9];
00459 else if (errorNum() == -11) return errorNames[10];
00460 else if (errorNum() == -12) return errorNames[11];
00461 else if (errorNum() == -13) return errorNames[12];
00462 else if (errorNum() == -100) return errorNames[13];
00463 else if (errorNum() == -101) return errorNames[14];
00464 else if (errorNum() == -102) return errorNames[15];
00465 else if (errorNum() == -199) return errorNames[16];
00466 throw CoinError("UnsolvedError", "UnsolvedError::errorName()","Unrecognized optimization status in ipopt.");
00467 }
00468
00469 std::string IpoptSolver::UnsolvedIpoptError::solverName_ = "Ipopt";
00470
00471 const std::string &
00472 IpoptSolver::UnsolvedIpoptError::solverName() const
00473 {
00474 return solverName_;
00475 }
00476
00477
00478
00479
00480 }