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 TNLPSolver(roptions, options, journalist),
00043 problemHadZeroDimension_(false),
00044 warmStartStrategy_(1),
00045 enable_warm_start_(false),
00046 optimized_before_(false)
00047 {
00048 roptions_ = roptions;
00049 app_ = new Ipopt::IpoptApplication(GetRawPtr(roptions), options, journalist);
00050 }
00051
00052 IpoptSolver::~IpoptSolver()
00053 {}
00054
00056 Ipopt::SmartPtr<TNLPSolver>
00057 IpoptSolver::clone()
00058 {
00059 SmartPtr<IpoptSolver> retval = new IpoptSolver(GetRawPtr(roptions_), new Ipopt::OptionsList(), journalist_);
00060 *retval->options_ = *options_;
00061 retval->warmStartStrategy_ = warmStartStrategy_;
00062 retval->problemHadZeroDimension_ = problemHadZeroDimension_;
00063 retval->optimizationStatus_ = optimizationStatus_;
00064
00065 enable_warm_start_ = false;
00066 optimized_before_ = false;
00067 return GetRawPtr(retval);
00068 }
00069
00070
00071 bool
00072 IpoptSolver::Initialize(std::string params_file)
00073 {
00074 Ipopt::ApplicationReturnStatus status =
00075 app_->Initialize(params_file);
00076 if (status != Ipopt::Solve_Succeeded) {
00077 return false;
00078 }
00079 options_->GetEnumValue("warm_start",warmStartStrategy_,"bonmin.");
00080 setMinlpDefaults(options_);
00081 optimized_before_ = false;
00082 return true;
00083 }
00084
00085 bool
00086 IpoptSolver::Initialize(std::istream &is)
00087 {
00088 Ipopt::ApplicationReturnStatus status =
00089 app_->Initialize(is);
00090 if (status != Ipopt::Solve_Succeeded) {
00091 return false;
00092 }
00093 options_->GetEnumValue("warm_start",warmStartStrategy_,"bonmin.");
00094 setMinlpDefaults(app_->Options());
00095 optimized_before_ = false;
00096 return true;
00097 }
00098
00099 TNLPSolver::ReturnStatus
00100 IpoptSolver::OptimizeTNLP(const Ipopt::SmartPtr<Ipopt::TNLP> &tnlp)
00101 {
00102 TNLPSolver::ReturnStatus ret_status;
00103 if (!zeroDimension(tnlp, ret_status)) {
00104 if (enable_warm_start_ && optimized_before_) {
00105 optimizationStatus_ = app_->ReOptimizeTNLP(tnlp);
00106 }
00107 else {
00108 optimizationStatus_ = app_->OptimizeTNLP(tnlp);
00109 }
00110 optimized_before_ = true;
00111 problemHadZeroDimension_ = false;
00112 }
00113 else {
00114 problemHadZeroDimension_ = true;
00115 if (ret_status == solvedOptimal)
00116 optimizationStatus_ = Ipopt::Solve_Succeeded;
00117 else if (ret_status == provenInfeasible)
00118 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00119 }
00120
00121 if (BonminAbortAll)
00122 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00123
00124 return solverReturnStatus(optimizationStatus_);
00125 }
00126
00127
00128 TNLPSolver::ReturnStatus
00129 IpoptSolver::ReOptimizeTNLP(const Ipopt::SmartPtr<Ipopt::TNLP> &tnlp)
00130 {
00131 TNLPSolver::ReturnStatus ret_status;
00132 if (!zeroDimension(tnlp, ret_status)) {
00133 if (optimized_before_) {
00134 optimizationStatus_ = app_->ReOptimizeTNLP(tnlp);
00135 }
00136 else {
00137 optimizationStatus_ = app_->OptimizeTNLP(tnlp);
00138 }
00139 problemHadZeroDimension_ = false;
00140 optimized_before_ = true;
00141 }
00142 else {
00143 problemHadZeroDimension_ = true;
00144 if (ret_status == solvedOptimal)
00145 optimizationStatus_ = Ipopt::Solve_Succeeded;
00146 else if (ret_status == provenInfeasible)
00147 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00148 }
00149 if (BonminAbortAll)
00150 optimizationStatus_ = Ipopt::Infeasible_Problem_Detected;
00151 return solverReturnStatus(optimizationStatus_);
00152 }
00153
00155 double
00156 IpoptSolver::CPUTime()
00157 {
00158 if (problemHadZeroDimension_) {
00159 return 0.;
00160 }
00161 else {
00162 const Ipopt::SmartPtr<Ipopt::SolveStatistics> stats = app_->Statistics();
00163 if (IsValid(stats)) {
00164 return stats->TotalCPUTime();
00165 }
00166 else {
00167 printf("TODO: No statistics available from Ipopt in Bonmin::IpoptSolver::CPUTime\n");
00168 return 0.;
00169
00170 }
00171 }
00172 }
00173
00175 int
00176 IpoptSolver::IterationCount()
00177 {
00178 if (problemHadZeroDimension_) {
00179 return 0;
00180 }
00181 else {
00182 const Ipopt::SmartPtr<Ipopt::SolveStatistics> stats = app_->Statistics();
00183 if (IsValid(stats)) {
00184 return stats->IterationCount();
00185 }
00186 else {
00187 printf("TODO: No statistics available from Ipopt in Bonmin::IpoptSolver::IterationCount\n");
00188 return 0;
00189
00190 }
00191
00192 }
00193 }
00194
00195
00196 void
00197 IpoptSolver::setMinlpDefaults(Ipopt::SmartPtr<Ipopt::OptionsList> Options)
00198 {
00199 Options->SetNumericValue("gamma_phi", 1e-8, true, true);
00200 Options->SetNumericValue("gamma_theta", 1e-4, true, true);
00201 Options->SetNumericValue("required_infeasibility_reduction", 0.1, true, true);
00202 Options->SetStringValue("expect_infeasible_problem","yes", true, true);
00203 Options->SetStringValue("mu_strategy", "adaptive", true, true);
00204 Options->SetStringValue("mu_oracle","probing", true, true);
00205 Options->SetIntegerValue("print_level",1, true, true);
00206 }
00207
00208
00210
00213 TNLPSolver::ReturnStatus IpoptSolver::solverReturnStatus(Ipopt::ApplicationReturnStatus optimization_status) const
00214 {
00215
00216 switch (optimization_status) {
00217 case Ipopt::Maximum_Iterations_Exceeded:
00218 case Ipopt::User_Requested_Stop:
00219 case Ipopt::Restoration_Failed:
00220 return iterationLimit;
00221 case Ipopt::Error_In_Step_Computation:
00222 case Ipopt::Unrecoverable_Exception:
00223 case Ipopt::Insufficient_Memory:
00224 return computationError;
00225 case Ipopt::Not_Enough_Degrees_Of_Freedom:
00226 return notEnoughFreedom;
00227 case Ipopt::Invalid_Problem_Definition:
00228 return illDefinedProblem;
00229 case Ipopt::Invalid_Option:
00230 case Ipopt::Invalid_Number_Detected:
00231 return illegalOption;
00232 case Ipopt::NonIpopt_Exception_Thrown:
00233 return externalException;
00234 case Ipopt::Internal_Error:
00235 return exception;
00236 case Ipopt::Solve_Succeeded:
00237 case Ipopt::Feasible_Point_Found:
00238 return solvedOptimal;
00239 case Ipopt::Search_Direction_Becomes_Too_Small:
00240 return doesNotConverge;
00241 case Ipopt::Solved_To_Acceptable_Level:
00242 return solvedOptimalTol;
00243 case Ipopt::Infeasible_Problem_Detected:
00244 return provenInfeasible;
00245 case Ipopt::Diverging_Iterates:
00246 return unbounded;
00247 default:
00248 return exception;
00249 }
00250 }
00251
00253 CoinWarmStart *
00254 IpoptSolver::getUsedWarmStart(Ipopt::SmartPtr<TMINLP2TNLP> tnlp) const
00255 {
00256 return new IpoptWarmStart(tnlp->num_variables(),
00257 2*tnlp->num_variables() +
00258 tnlp->num_constraints(),
00259 tnlp->x_init(), tnlp->duals_init());
00260 }
00262 CoinWarmStart*
00263 IpoptSolver::getWarmStart(Ipopt::SmartPtr<TMINLP2TNLP> tnlp) const
00264 {
00265 if (warmStartStrategy_==2) {
00266 Ipopt::SmartPtr<IpoptInteriorWarmStarter> warm_starter =
00267 Ipopt::SmartPtr<IpoptInteriorWarmStarter>(tnlp->GetWarmStarter());
00268 return new IpoptWarmStart(tnlp, warm_starter);
00269 }
00270 else return new IpoptWarmStart(tnlp, NULL);
00271 }
00272
00273
00274 bool
00275 IpoptSolver::setWarmStart(const CoinWarmStart* warmstart,
00276 Ipopt::SmartPtr<TMINLP2TNLP> tnlp)
00277 {
00278 if (!warmstart && warmStartStrategy_)
00279 return 0;
00280 const IpoptWarmStart * ws = dynamic_cast<const IpoptWarmStart*> (warmstart);
00281 if (ws->empty())
00282 {
00283 disableWarmStart();
00284 return 1;
00285 }
00286 if(ws->dualSize() > 0){
00287 tnlp->setDualsInit(ws->dualSize(), ws->dual());
00288 enableWarmStart();
00289 }
00290 else
00291 disableWarmStart();
00292 #ifndef NDEBUG
00293 int numcols = tnlp->num_variables();
00294 int numrows = tnlp->num_constraints();
00295 #endif
00296
00297 assert(numcols == ws->primalSize());
00298 assert(2*numcols + numrows == ws->dualSize());
00299 tnlp->setxInit(ws->primalSize(), ws->primal());
00300
00301 if (IsValid(ws->warm_starter()))
00302 tnlp->SetWarmStarter(ws->warm_starter());
00303
00304 return 1;
00305 }
00306
00307 bool
00308 IpoptSolver::warmStartIsValid(const CoinWarmStart * ws) const{
00309 const IpoptWarmStart* iws = dynamic_cast<const IpoptWarmStart*>(ws);
00310 if (iws && !iws->empty()) {
00311 return true;
00312 }
00313 return false;
00314 }
00315
00316 CoinWarmStart *
00317 IpoptSolver::getEmptyWarmStart() const
00318 {
00319 return new IpoptWarmStart(1);
00320 }
00321
00322 void
00323 IpoptSolver::enableWarmStart()
00324 {
00325 enable_warm_start_ = true;
00326 options_->SetStringValue("warm_start_init_point", "yes");
00327 }
00328
00329 void
00330 IpoptSolver::disableWarmStart()
00331 {
00332 enable_warm_start_ = false;
00333 options_->SetStringValue("warm_start_init_point", "no");
00334 }
00335
00336
00337 void
00338 IpoptSolver::turnOffOutput()
00339 {}
00340
00341
00342 void
00343 IpoptSolver::turnOnOutput()
00344 {}
00345
00346
00347
00348
00349
00350
00351 std::string
00352 IpoptSolver::UnsolvedIpoptError::errorNames[17] ={"Solve succeeded",
00353 "Solved to acceptable level",
00354 "Infeasible problem detected",
00355 "Search direction becomes too small",
00356 "Diverging iterates",
00357 "User requested stop",
00358 "Maximum iterations exceeded",
00359 "Restoration failed",
00360 "Error in step computation",
00361 "Not enough degrees of freedom",
00362 "Invalid problem definition",
00363 "Invalid option",
00364 "Invalid number detected",
00365 "Unrecoverable exception",
00366 "NonIpopt exception thrown",
00367 "Insufficient memory",
00368 "Internal error"};
00369
00370 const std::string &
00371 IpoptSolver::UnsolvedIpoptError::errorName() const
00372 {
00373 if (errorNum() >=0)
00374 return errorNames[errorNum()];
00375 if (errorNum() == -1) return errorNames[6];
00376 else if (errorNum() == -2) return errorNames[7];
00377 else if (errorNum() == -3) return errorNames[8];
00378 else if (errorNum() == -10) return errorNames[9];
00379 else if (errorNum() == -11) return errorNames[10];
00380 else if (errorNum() == -12) return errorNames[11];
00381 else if (errorNum() == -13) return errorNames[12];
00382 else if (errorNum() == -100) return errorNames[13];
00383 else if (errorNum() == -101) return errorNames[14];
00384 else if (errorNum() == -102) return errorNames[15];
00385 else if (errorNum() == -199) return errorNames[16];
00386 throw CoinError("UnsolvedError", "UnsolvedError::errorName()","Unrecognized optimization status in ipopt.");
00387 }
00388
00389 std::string IpoptSolver::UnsolvedIpoptError::solverName_ = "Ipopt";
00390
00391 const std::string &
00392 IpoptSolver::UnsolvedIpoptError::solverName() const
00393 {
00394 return solverName_;
00395 }
00396
00397
00398
00399
00400 }