00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "NOX_LineSearch_MoreThuente.H"
00034
00035 #include "NOX_Abstract_Vector.H"
00036 #include "NOX_Abstract_Group.H"
00037 #include "NOX_Solver_Generic.H"
00038 #include "NOX_Parameter_List.H"
00039 #include "NOX_Parameter_MeritFunction.H"
00040 #include "NOX_Parameter_UserNorm.H"
00041 #include "NOX_Utils.H"
00042
00043 NOX::LineSearch::MoreThuente::MoreThuente(const NOX::Utils& u, Parameter::List& params) :
00044 print(u),
00045 paramsPtr(0)
00046 {
00047 reset(params);
00048 }
00049
00050 NOX::LineSearch::MoreThuente::~MoreThuente()
00051 {
00052 }
00053
00054 bool NOX::LineSearch::MoreThuente::reset(Parameter::List& params)
00055 {
00056 paramsPtr = ¶ms;
00057 NOX::Parameter::List& p = params.sublist("More'-Thuente");
00058 ftol = p.getParameter("Sufficient Decrease", 1.0e-4);
00059 gtol = p.getParameter("Curvature Condition", 0.9999);
00060 xtol = p.getParameter("Interval Width", 1.0e-15);
00061 stpmin = p.getParameter("Minimum Step", 1.0e-12);
00062 stpmax = p.getParameter("Maximum Step", 1.0e+6);
00063 maxfev = p.getParameter("Max Iters", 20);
00064 defaultstep = p.getParameter("Default Step", 1.0);
00065 recoverystep = p.getParameter("Recovery Step", defaultstep);
00066
00067
00068 if ((ftol < 0.0) ||
00069 (gtol < 0.0) ||
00070 (xtol < 0.0) ||
00071 (stpmin < 0.0) ||
00072 (stpmax < stpmin) ||
00073 (maxfev <= 0) ||
00074 (defaultstep <= 0))
00075 {
00076 cout << "NOX::LineSearch::MoreThuente::reset - Error in Input Parameter!" << endl;
00077 throw "NOX Error";
00078 }
00079
00080 counter.reset();
00081
00082 string choice = p.getParameter("Sufficient Decrease Condition", "Armijo-Goldstein");
00083 if (choice == "Ared/Pred")
00084 suffDecrCond = AredPred;
00085 else if (choice == "Armijo-Goldstein")
00086 suffDecrCond = ArmijoGoldstein;
00087 else {
00088 cout << "ERROR: NOX::LineSearch::MoreThuente::reset() - the choice of "
00089 << "\"Sufficient Decrease Condition\" is invalid." << endl;
00090 throw "NOX Error";
00091 }
00092
00093 choice = p.getParameter("Recovery Step Type", "Constant");
00094 if (choice == "Constant")
00095 recoveryStepType = Constant;
00096 else if (choice == "Last Computed Step") {
00097 recoveryStepType = LastComputedStep;
00098 }
00099 else {
00100 cout << "NOX::LineSearch::MoreThuente::reset - Invalid "
00101 << "\"Recovery Step Type\"" << endl;
00102 throw "NOX Error";
00103 }
00104
00105 useOptimizedSlopeCalc = p.getParameter("Optimize Slope Calculation", false);
00106
00107
00108 userDefinedNorm = false;
00109 userNormPtr = 0;
00110 if (p.isParameterArbitrary("User Defined Norm")) {
00111 userNormPtr = const_cast<NOX::Parameter::UserNorm*>(dynamic_cast<const NOX::Parameter::UserNorm*>(&(p.getArbitraryParameter("User Defined Norm"))));
00112 if (userNormPtr != 0)
00113 userDefinedNorm = true;
00114 }
00115
00116
00117 userDefinedMeritFunction = false;
00118 meritFuncPtr = 0;
00119 if (p.isParameterArbitrary("Merit Function")) {
00120 meritFuncPtr = const_cast<NOX::Parameter::MeritFunction*>(dynamic_cast<const NOX::Parameter::MeritFunction*>(&(p.getArbitraryParameter("Merit Function"))));
00121 if (meritFuncPtr != 0)
00122 userDefinedMeritFunction = true;
00123 }
00124
00125 return true;
00126 }
00127
00128
00129 bool NOX::LineSearch::MoreThuente::compute(Abstract::Group& grp, double& step,
00130 const Abstract::Vector& dir,
00131 const Solver::Generic& s)
00132 {
00133 counter.incrementNumLineSearches();
00134 const Abstract::Group& oldGrp = s.getPreviousSolutionGroup();
00135 int info = cvsrch(grp, step, oldGrp, dir, s);
00136
00137 if (step != 1.0)
00138 counter.incrementNumNonTrivialLineSearches();
00139
00140 counter.setValues(*paramsPtr);
00141
00142 return (info == 1);
00143 }
00144
00145 int NOX::LineSearch::MoreThuente::cvsrch(Abstract::Group& newgrp, double& stp,
00146 const Abstract::Group& oldgrp, const Abstract::Vector& dir, const Solver::Generic& s)
00147 {
00148 if (print.isPrintProcessAndType(NOX::Utils::InnerIteration))
00149 {
00150 cout << "\n" << NOX::Utils::fill(72) << "\n" << "-- More'-Thuente Line Search -- \n";
00151 }
00152
00153
00154 stp = defaultstep;
00155
00156 int info = 0;
00157 int infoc = 1;
00158
00159
00160
00161 double dginit = 0.0;
00162 if (userDefinedMeritFunction)
00163 dginit = meritFuncPtr->computeSlope(dir, oldgrp);
00164 else {
00165 if (useOptimizedSlopeCalc)
00166 dginit = slope.computeSlopeWithOutJac(dir, oldgrp);
00167 else
00168 dginit = slope.computeSlope(dir, oldgrp);
00169 }
00170
00171 if (dginit >= 0.0)
00172 {
00173 if (print.isPrintProcessAndType(NOX::Utils::Warning))
00174 {
00175 cout << "NOX::LineSearch::MoreThuente::cvsrch - Non-descent direction (dginit = " << dginit << ")" << endl;
00176 }
00177 stp = recoverystep;
00178 newgrp.computeX(oldgrp, dir, stp);
00179 return 7;
00180 }
00181
00182
00183
00184 bool brackt = false;
00185 bool stage1 = true;
00186 int nfev = 0;
00187 double dgtest = ftol * dginit;
00188 double width = stpmax - stpmin;
00189 double width1 = 2 * width;
00190
00191
00192 double finit = 0.0;
00193 if (userDefinedMeritFunction)
00194 finit = meritFuncPtr->computef(oldgrp);
00195 else
00196 finit = 0.5 * oldgrp.getNormF() * oldgrp.getNormF();
00197
00198
00199
00200
00201
00202
00203
00204
00205 double stx = 0.0;
00206 double fx = finit;
00207 double dgx = dginit;
00208 double sty = 0.0;
00209 double fy = finit;
00210 double dgy = dginit;
00211
00212
00213 const NOX::Parameter::List& p = s.getParameterList();
00214 double eta_original = 0.0;
00215 double eta = 0.0;
00216 eta_original = p.sublist("Direction").sublist("Newton").sublist("Linear Solver").getParameter("Tolerance", -1.0);
00217 eta = eta_original;
00218
00219
00220
00221
00222 double stmin, stmax;
00223 double fm, fxm, fym, dgm, dgxm, dgym;
00224
00225 while (1)
00226 {
00227
00228
00229
00230
00231 if (brackt)
00232 {
00233 stmin = min(stx, sty);
00234 stmax = max(stx, sty);
00235 }
00236 else
00237 {
00238 stmin = stx;
00239 stmax = stp + 4 * (stp - stx);
00240 }
00241
00242
00243 stp = max(stp, stpmin);
00244 stp = min(stp, stpmax);
00245
00246
00247
00248
00249 if ((brackt && ((stp <= stmin) || (stp >= stmax))) ||
00250 (nfev >= maxfev - 1) || (infoc == 0) ||
00251 (brackt && (stmax - stmin <= xtol * stmax)))
00252 {
00253 stp = stx;
00254 }
00255
00256
00257
00258
00259 newgrp.computeX(oldgrp, dir, stp);
00260
00261 NOX::Abstract::Group::ReturnType rtype;
00262 rtype = newgrp.computeF();
00263 if (rtype != NOX::Abstract::Group::Ok)
00264 {
00265 cerr << "NOX::LineSearch::MoreThuente::cvrch - Unable to compute F" << endl;
00266 throw "NOX Error";
00267 }
00268
00269 double f = 0.0;
00270 if (userDefinedMeritFunction)
00271 f = meritFuncPtr->computef(newgrp);
00272 else
00273 f = 0.5 * newgrp.getNormF() * newgrp.getNormF();
00274
00275 if (!useOptimizedSlopeCalc) {
00276
00277 rtype = newgrp.computeJacobian();
00278 if (rtype != NOX::Abstract::Group::Ok)
00279 {
00280 cerr << "NOX::LineSearch::MoreThuente::cvrch - Unable to compute Jacobian" << endl;
00281 throw "NOX Error";
00282 }
00283
00284 rtype = newgrp.computeGradient();
00285 if (rtype != NOX::Abstract::Group::Ok)
00286 {
00287 cerr << "NOX::LineSearch::MoreThuente::cvrch - Unable to compute Gradient" << endl;
00288 throw "NOX Error";
00289 }
00290 }
00291
00292 nfev ++;
00293 string message = "";
00294
00295 double dg = 0.0;
00296 if (userDefinedMeritFunction) {
00297 dg = meritFuncPtr->computeSlope(dir, newgrp);
00298 }
00299 else {
00300 if (useOptimizedSlopeCalc)
00301 dg = slope.computeSlopeWithOutJac(dir, newgrp);
00302 else
00303 dg = slope.computeSlope(dir, newgrp);
00304 }
00305
00306
00307 double ftest1 = finit + stp * dgtest;
00308
00309
00310 double ftest2 = 0.0;
00311 if (userDefinedNorm)
00312 ftest2 = userNormPtr->norm(oldgrp.getF()) * (1.0 - ftol * (1.0 - eta));
00313 else
00314 ftest2 = oldgrp.getNormF() * (1.0 - ftol * (1.0 - eta));
00315
00316
00317
00318 if ((brackt && ((stp <= stmin) || (stp >= stmax))) || (infoc == 0))
00319 info = 6;
00320
00321 if ((stp == stpmax) && (f <= ftest1) && (dg <= dgtest))
00322 info = 5;
00323
00324 if ((stp == stpmin) && ((f > ftest1) || (dg >= dgtest)))
00325 info = 4;
00326
00327 if (nfev >= maxfev)
00328 info = 3;
00329
00330 if (brackt && (stmax-stmin <= xtol*stmax))
00331 info = 2;
00332
00333
00334
00335
00336
00337
00338 bool sufficientDecreaseTest = false;
00339 if (suffDecrCond == ArmijoGoldstein)
00340 sufficientDecreaseTest = (f <= ftest1);
00341 else {
00342 double ap_normF = 0.0;
00343 if (userDefinedNorm)
00344 ap_normF = userNormPtr->norm(newgrp.getF());
00345 else
00346 ap_normF = newgrp.getNormF();
00347
00348 sufficientDecreaseTest = (ap_normF <= ftest2);
00349 }
00350
00351 if ((sufficientDecreaseTest) && (fabs(dg) <= gtol*(-dginit)))
00352 info = 1;
00353
00354 if (info != 0)
00355 {
00356 if (info != 1)
00357 {
00358
00359 counter.incrementNumFailedLineSearches();
00360
00361 if (recoveryStepType == Constant)
00362 stp = recoverystep;
00363
00364 newgrp.computeX(oldgrp, dir, stp);
00365
00366 message = "(USING RECOVERY STEP!)";
00367
00368
00369
00370
00371
00372
00373 }
00374 else
00375 {
00376 message = "(STEP ACCEPTED!)";
00377 }
00378
00379 print.printStep(nfev, stp, finit, f, message);
00380
00381
00382 return info;
00383
00384 }
00385
00386 print.printStep(nfev, stp, finit, f, message);
00387
00388
00389 counter.incrementNumIterations();
00390
00391
00392
00393
00394 if (stage1 && (f <= ftest1) && (dg >= min(ftol, gtol) * dginit))
00395 stage1 = false;
00396
00397
00398
00399
00400
00401
00402
00403 if (stage1 && (f <= fx) && (f > ftest1))
00404 {
00405
00406
00407
00408 fm = f - stp * dgtest;
00409 fxm = fx - stx * dgtest;
00410 fym = fy - sty * dgtest;
00411 dgm = dg - dgtest;
00412 dgxm = dgx - dgtest;
00413 dgym = dgy - dgtest;
00414
00415
00416
00417
00418 infoc = cstep(stx,fxm,dgxm,sty,fym,dgym,stp,fm,dgm,
00419 brackt,stmin,stmax);
00420
00421
00422
00423 fx = fxm + stx*dgtest;
00424 fy = fym + sty*dgtest;
00425 dgx = dgxm + dgtest;
00426 dgy = dgym + dgtest;
00427
00428 }
00429
00430 else
00431 {
00432
00433
00434
00435
00436 infoc = cstep(stx,fx,dgx,sty,fy,dgy,stp,f,dg,
00437 brackt,stmin,stmax);
00438
00439 }
00440
00441
00442
00443
00444 if (brackt)
00445 {
00446 if (fabs(sty - stx) >= 0.66 * width1)
00447 stp = stx + 0.5 * (sty - stx);
00448 width1 = width;
00449 width = fabs(sty-stx);
00450 }
00451
00452 }
00453
00454 }
00455
00456
00457 int NOX::LineSearch::MoreThuente::cstep(double& stx, double& fx, double& dx,
00458 double& sty, double& fy, double& dy,
00459 double& stp, double& fp, double& dp,
00460 bool& brackt, double stmin, double stmax)
00461 {
00462 int info = 0;
00463
00464
00465
00466 if ((brackt && ((stp <= min(stx, sty)) || (stp >= max(stx, sty)))) ||
00467 (dx * (stp - stx) >= 0.0) || (stmax < stmin))
00468 return info;
00469
00470
00471
00472 double sgnd = dp * (dx / fabs(dx));
00473
00474
00475
00476
00477
00478
00479 bool bound;
00480 double theta;
00481 double s;
00482 double gamma;
00483 double p,q,r;
00484 double stpc, stpq, stpf;
00485
00486 if (fp > fx)
00487 {
00488 info = 1;
00489 bound = 1;
00490 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
00491 s = absmax(theta, dx, dp);
00492 gamma = s * sqrt(((theta / s) * (theta / s)) - (dx / s) * (dp / s));
00493 if (stp < stx)
00494 gamma = -gamma;
00495
00496 p = (gamma - dx) + theta;
00497 q = ((gamma - dx) + gamma) + dp;
00498 r = p / q;
00499 stpc = stx + r * (stp - stx);
00500 stpq = stx + ((dx / ((fx - fp) / (stp - stx) + dx)) / 2) * (stp - stx);
00501 if (fabs(stpc - stx) < fabs(stpq - stx))
00502 stpf = stpc;
00503 else
00504 stpf = stpc + (stpq - stpc) / 2;
00505
00506 brackt = true;
00507 }
00508
00509
00510
00511
00512
00513
00514 else if (sgnd < 0.0)
00515 {
00516 info = 2;
00517 bound = false;
00518 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
00519 s = absmax(theta,dx,dp);
00520 gamma = s * sqrt(((theta/s) * (theta/s)) - (dx / s) * (dp / s));
00521 if (stp > stx)
00522 gamma = -gamma;
00523 p = (gamma - dp) + theta;
00524 q = ((gamma - dp) + gamma) + dx;
00525 r = p / q;
00526 stpc = stp + r * (stx - stp);
00527 stpq = stp + (dp / (dp - dx)) * (stx - stp);
00528 if (fabs(stpc - stp) > fabs(stpq - stp))
00529 stpf = stpc;
00530 else
00531 stpf = stpq;
00532 brackt = true;
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 else if (fabs(dp) < fabs(dx))
00545 {
00546 info = 3;
00547 bound = true;
00548 theta = 3 * (fx - fp) / (stp - stx) + dx + dp;
00549 s = absmax(theta, dx, dp);
00550
00551
00552
00553
00554 gamma = s * sqrt(max(0,(theta / s) * (theta / s) - (dx / s) * (dp / s)));
00555 if (stp > stx)
00556 gamma = -gamma;
00557
00558 p = (gamma - dp) + theta;
00559 q = (gamma + (dx - dp)) + gamma;
00560 r = p / q;
00561 if ((r < 0.0) && (gamma != 0.0))
00562 stpc = stp + r * (stx - stp);
00563 else if (stp > stx)
00564 stpc = stmax;
00565 else
00566 stpc = stmin;
00567
00568 stpq = stp + (dp/ (dp - dx)) * (stx - stp);
00569 if (brackt)
00570 {
00571 if (fabs(stp - stpc) < fabs(stp - stpq))
00572 stpf = stpc;
00573 else
00574 stpf = stpq;
00575 }
00576 else
00577 {
00578 if (fabs(stp - stpc) > fabs(stp - stpq))
00579 stpf = stpc;
00580 else
00581 stpf = stpq;
00582 }
00583 }
00584
00585
00586
00587
00588
00589
00590 else {
00591 info = 4;
00592 bound = false;
00593 if (brackt)
00594 {
00595 theta = 3 * (fp - fy) / (sty - stp) + dy + dp;
00596 s = absmax(theta, dy, dp);
00597 gamma = s * sqrt(((theta/s)*(theta/s)) - (dy / s) * (dp / s));
00598 if (stp > sty)
00599 gamma = -gamma;
00600 p = (gamma - dp) + theta;
00601 q = ((gamma - dp) + gamma) + dy;
00602 r = p / q;
00603 stpc = stp + r * (sty - stp);
00604 stpf = stpc;
00605 }
00606 else if (stp > stx)
00607 stpf = stmax;
00608 else
00609 stpf = stmin;
00610 }
00611
00612
00613
00614
00615 if (fp > fx)
00616 {
00617 sty = stp;
00618 fy = fp;
00619 dy = dp;
00620 }
00621 else
00622 {
00623 if (sgnd < 0.0)
00624 {
00625 sty = stx;
00626 fy = fx;
00627 dy = dx;
00628 }
00629 stx = stp;
00630 fx = fp;
00631 dx = dp;
00632 }
00633
00634
00635
00636 stpf = min(stmax, stpf);
00637 stpf = max(stmin, stpf);
00638 stp = stpf;
00639 if (brackt && bound)
00640 {
00641 if (sty > stx)
00642 stp = min(stx + 0.66 * (sty - stx), stp);
00643 else
00644 stp = max(stx + 0.66 * (sty - stx), stp);
00645 }
00646
00647 return info;
00648
00649 }
00650
00651 double NOX::LineSearch::MoreThuente::min(double a, double b)
00652 {
00653 return (a < b ? a : b);
00654 }
00655
00656 double NOX::LineSearch::MoreThuente::max(double a, double b)
00657 {
00658 return (a > b ? a : b);
00659 }
00660
00661
00662 double NOX::LineSearch::MoreThuente::absmax(double a, double b, double c)
00663 {
00664 a = fabs(a);
00665 b = fabs(b);
00666 c = fabs(c);
00667
00668 if (a > b)
00669 return (a > c) ? a : c;
00670 else
00671 return (b > c) ? b : c;
00672 }
00673
00674