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