Sandia Home

Nonlinear Solver Project: NOX_LineSearch_MoreThuente.C Source File

NOX_LineSearch_MoreThuente.C

00001 // $Id: NOX_LineSearch_MoreThuente.C,v 1.13 2003/11/25 16:30:10 tgkolda Exp $ 
00002 // $Source: /space/CVS/Trilinos/packages/nox/src/NOX_LineSearch_MoreThuente.C,v $ 
00003 
00004 //@HEADER
00005 // ************************************************************************
00006 // 
00007 //            NOX: An Object-Oriented Nonlinear Solver Package
00008 //                 Copyright (2002) Sandia Corporation
00009 // 
00010 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00011 // license for use of this work by or on behalf of the U.S. Government.
00012 // 
00013 // This library is free software; you can redistribute it and/or modify
00014 // it under the terms of the GNU Lesser General Public License as
00015 // published by the Free Software Foundation; either version 2.1 of the
00016 // License, or (at your option) any later version.
00017 //  
00018 // This library is distributed in the hope that it will be useful, but
00019 // WITHOUT ANY WARRANTY; without even the implied warranty of
00020 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 // Lesser General Public License for more details.
00022 //                                                                                 
00023 // You should have received a copy of the GNU Lesser General Public
00024 // License along with this library; if not, write to the Free Software
00025 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00026 // USA                                                                                
00027 // Questions? Contact Tammy Kolda (tgkolda@sandia.gov) or Roger Pawlowski
00028 // (rppawlo@sandia.gov), Sandia National Laboratories.
00029 // 
00030 // ************************************************************************
00031 //@HEADER
00032 
00033 #include "NOX_LineSearch_MoreThuente.H" // class definition
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 = &params;
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   // Check the input parameters for errors.
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   // Check for a user supplied norm
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   // Check for a user supplied merit function
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   // Set default step
00154   stp = defaultstep;
00155 
00156   int info = 0;                 // return code
00157   int infoc = 1;                // return code for subroutine cstep
00158 
00159   // Compute the initial gradient in the search direction and check
00160   // that s is a descent direction.
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   // Initialize local variables.
00183 
00184   bool brackt = false;          // has the soln been bracketed?
00185   bool stage1 = true;           // are we in stage 1?
00186   int nfev = 0;                 // number of function evaluations
00187   double dgtest = ftol * dginit; // f for curvature condition
00188   double width = stpmax - stpmin; // interval width
00189   double width1 = 2 * width;    // ???
00190 
00191   // initial function value
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   // The variables stx, fx, dgx contain the values of the step,
00199   // function, and directional derivative at the best step.  The
00200   // variables sty, fy, dgy contain the value of the step, function,
00201   // and derivative at the other endpoint of the interval of
00202   // uncertainty.  The variables stp, f, dg contain the values of the
00203   // step, function, and derivative at the current step.
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   // Get the linear solve tolerance for adjustable forcing term
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   // Start of iteration.
00221 
00222   double stmin, stmax;
00223   double fm, fxm, fym, dgm, dgxm, dgym;
00224 
00225   while (1) 
00226   {
00227 
00228     // Set the minimum and maximum steps to correspond to the present
00229     // interval of uncertainty.
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     // Force the step to be within the bounds stpmax and stpmin.
00243     stp = max(stp, stpmin);
00244     stp = min(stp, stpmax);
00245 
00246     // If an unusual termination is to occur then let stp be the
00247     // lowest point obtained so far.
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     // Evaluate the function and gradient at stp
00257     // and compute the directional derivative.
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     // Armijo-Goldstein sufficient decrease
00307     double ftest1 = finit + stp * dgtest;
00308 
00309     // Ared/Pred suffiecient decrease (could use a user defined norm)
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     // Test for convergence.
00317 
00318     if ((brackt && ((stp <= stmin) || (stp >= stmax))) || (infoc == 0)) 
00319       info = 6;                 // Rounding errors
00320 
00321     if ((stp == stpmax) && (f <= ftest1) && (dg <= dgtest))
00322       info = 5;                 // stp=stpmax
00323 
00324     if ((stp == stpmin) && ((f > ftest1) || (dg >= dgtest))) 
00325       info = 4;                 // stp=stpmin
00326 
00327     if (nfev >= maxfev) 
00328       info = 3;                 // max'd out on fevals
00329 
00330     if (brackt && (stmax-stmin <= xtol*stmax)) 
00331       info = 2;                 // bracketed soln
00332 
00333 
00334     //cout << "f=" << f << " ftest1=" << ftest1 << " fabs(dg)=" << fabs(dg) 
00335     //   << " gtol*(-dginit)=" << gtol*(-dginit) << endl;
00336 
00337     // RPP sufficient decrease test can be different
00338     bool sufficientDecreaseTest = false;
00339     if (suffDecrCond == ArmijoGoldstein)
00340       sufficientDecreaseTest = (f <= ftest1);  // Armijo-Golstein
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); // Ared/Pred
00349     }
00350 
00351     if ((sufficientDecreaseTest) && (fabs(dg) <= gtol*(-dginit))) 
00352       info = 1;                 // Success!!!!
00353 
00354     if (info != 0)              // Line search is done
00355     {
00356       if (info != 1)            // Line search failed 
00357       {
00358         // RPP add
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         if (print.isPrintProcessAndType(Utils::Details))
00370           message += "[Failure info flag = " + info + "]";
00371         */
00372             
00373       }
00374       else                      // Line search succeeded
00375       {
00376         message = "(STEP ACCEPTED!)";
00377       }
00378       
00379       print.printStep(nfev, stp, finit, f, message);
00380 
00381       // Returning the line search flag
00382       return info;
00383 
00384     } // info != 0
00385     
00386     print.printStep(nfev, stp, finit, f, message);
00387 
00388     // RPP add
00389     counter.incrementNumIterations();
00390 
00391     // In the first stage we seek a step for which the modified
00392     // function has a nonpositive value and nonnegative derivative.
00393 
00394     if (stage1 && (f <= ftest1) && (dg >= min(ftol, gtol) * dginit)) 
00395       stage1 = false;
00396 
00397     // A modified function is used to predict the step only if we have
00398     // not obtained a step for which the modified function has a
00399     // nonpositive function value and nonnegative derivative, and if a
00400     // lower function value has been obtained but the decrease is not
00401     // sufficient.
00402 
00403     if (stage1 && (f <= fx) && (f > ftest1)) 
00404     {
00405 
00406       // Define the modified function and derivative values.
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       // Call cstep to update the interval of uncertainty 
00416       // and to compute the new step.
00417 
00418       infoc = cstep(stx,fxm,dgxm,sty,fym,dgym,stp,fm,dgm, 
00419                     brackt,stmin,stmax);
00420 
00421       // Reset the function and gradient values for f.
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       // Call cstep to update the interval of uncertainty 
00434       // and to compute the new step.
00435 
00436       infoc = cstep(stx,fx,dgx,sty,fy,dgy,stp,f,dg,
00437                     brackt,stmin,stmax);
00438 
00439     }
00440 
00441     // Force a sufficient decrease in the size of the
00442     // interval of uncertainty.
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   } // while-loop
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   // Check the input parameters for errors.
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   // Determine if the derivatives have opposite sign.
00471 
00472   double sgnd = dp * (dx / fabs(dx));
00473 
00474   // First case. A higher function value.  The minimum is
00475   // bracketed. If the cubic step is closer to stx than the quadratic
00476   // step, the cubic step is taken, else the average of the cubic and
00477   // quadratic steps is taken.
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   // Second case. A lower function value and derivatives of opposite
00510   // sign. The minimum is bracketed. If the cubic step is closer to
00511   // stx than the quadratic (secant) step, the cubic step is taken,
00512   // else the quadratic step is taken.
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   // Third case. A lower function value, derivatives of the same sign,
00536   // and the magnitude of the derivative decreases.  The cubic step is
00537   // only used if the cubic tends to infinity in the direction of the
00538   // step or if the minimum of the cubic is beyond stp. Otherwise the
00539   // cubic step is defined to be either stmin or stmax. The
00540   // quadratic (secant) step is also computed and if the minimum is
00541   // bracketed then the the step closest to stx is taken, else the
00542   // step farthest away is taken.
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     // The case gamma = 0 only arises if the cubic does not tend
00552     // to infinity in the direction of the step.
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   // Fourth case. A lower function value, derivatives of the same
00586   // sign, and the magnitude of the derivative does not decrease. If
00587   // the minimum is not bracketed, the step is either stmin or
00588   // stmax, else the cubic step is taken.
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   // Update the interval of uncertainty. This update does not depend
00613   // on the new step or the case analysis above.
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   // Compute the new step and safeguard it.
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 

Generated on Thu Mar 3 01:00:51 2005 for Nonlinear Solver Project by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2002


© Sandia Corporation | Software.Sandia.Gov | Site Contact | Privacy and Security