bool NOX::Solver::TensorBased::implementGlobalStrategy(NOX::Abstract::Group& newGrp, double& in_stepSize, const NOX::Solver::Generic& s) { bool ok; counter.incrementNumLineSearches(); isNewtonDirection = false; NOX::Abstract::Vector& searchDirection = *tensorVecPtr; if ((counter.getNumLineSearches() == 1) || (lsType == Newton)) { isNewtonDirection = true; searchDirection = *newtonVecPtr; } // Do line search and compute new soln. if ((lsType != Dual) || (isNewtonDirection)) ok = performLinesearch(newGrp, in_stepSize, searchDirection, s); else if (lsType == Dual) { double fTensor = 0.0; double fNew = 0.0; double tensorStep = 1.0; bool isTensorDescent = false; const Abstract::Group& oldGrp = s.getPreviousSolutionGroup(); double fprime = slopeObj.computeSlope(searchDirection, oldGrp); // Backtrack along tensor direction if it is descent direction. if (fprime < 0) { ok = performLinesearch(newGrp, in_stepSize, searchDirection, s); assert(ok); fTensor = 0.5 * newGrp.getNormF() * newGrp.getNormF(); tensorStep = in_stepSize; isTensorDescent = true; } // Backtrack along the Newton direction. ok = performLinesearch(newGrp, in_stepSize, *newtonVecPtr, s); fNew = 0.5 * newGrp.getNormF() * newGrp.getNormF(); // If backtracking on the tensor step produced a better step, then use it. if (isTensorDescent && (fTensor <= fNew)) { newGrp.computeX(oldGrp, *tensorVecPtr, tensorStep); newGrp.computeF(); } } return ok; }
bool NOX::LineSearch::Polynomial:: updateGrp(NOX::Abstract::Group& newGrp, const NOX::Abstract::Group& oldGrp, const NOX::Abstract::Vector& dir, double step) const { newGrp.computeX(oldGrp, dir, step); NOX::Abstract::Group::ReturnType status = newGrp.computeF(); if (status != NOX::Abstract::Group::Ok) return false; return true; }
bool NOX::LineSearch::Backtrack:: compute(NOX::Abstract::Group& grp, double& step, const NOX::Abstract::Vector& dir, const NOX::Solver::Generic& s) { const Abstract::Group& oldGrp = s.getPreviousSolutionGroup(); double oldF = meritFunctionPtr->computef(oldGrp); double newF; bool isFailed = false; step = defaultStep; grp.computeX(oldGrp, dir, step); NOX::Abstract::Group::ReturnType rtype; rtype = grp.computeF(); if (rtype != NOX::Abstract::Group::Ok) { utils->err() << "NOX::LineSearch::BackTrack::compute - Unable to compute F" << std::endl; throw "NOX Error"; } newF = meritFunctionPtr->computef(grp); int nIters = 1; if (utils->isPrintType(Utils::InnerIteration)) { utils->out() << "\n" << Utils::fill(72) << "\n" << "-- Backtrack Line Search -- \n"; } NOX::StatusTest::FiniteValue checkNAN; while ( ((newF >= oldF) || (checkNAN.finiteNumberTest(newF) !=0)) && (!isFailed)) { if (utils->isPrintType(Utils::InnerIteration)) { utils->out() << std::setw(3) << nIters << ":"; utils->out() << " step = " << utils->sciformat(step); utils->out() << " old f = " << utils->sciformat(oldF); utils->out() << " new f = " << utils->sciformat(newF); utils->out() << std::endl; } nIters ++; step = step * reductionFactor; if ((step < minStep) || (nIters > maxIters)) { isFailed = true; step = recoveryStep; } grp.computeX(oldGrp, dir, step); rtype = grp.computeF(); if (rtype != NOX::Abstract::Group::Ok) { utils->err() << "NOX::LineSearch::BackTrack::compute - Unable to compute F" << std::endl; throw "NOX Error"; } newF = meritFunctionPtr->computef(grp); } if (utils->isPrintType(Utils::InnerIteration)) { utils->out() << std::setw(3) << nIters << ":"; utils->out() << " step = " << utils->sciformat(step); utils->out() << " old f = " << utils->sciformat(oldF); utils->out() << " new f = " << utils->sciformat(newF); if (isFailed) utils->out() << " (USING RECOVERY STEP!)" << std::endl; else utils->out() << " (STEP ACCEPTED!)" << std::endl; utils->out() << Utils::fill(72) << "\n" << std::endl; } return (!isFailed); }
bool NOX::Solver::TensorBased::performLinesearch(NOX::Abstract::Group& newSoln, double& in_stepSize, const NOX::Abstract::Vector& lsDir, const NOX::Solver::Generic& s) { if (print.isPrintType(NOX::Utils::InnerIteration)) { utilsPtr->out() << "\n" << NOX::Utils::fill(72) << "\n"; utilsPtr->out() << "-- Tensor Line Search ("; if (lsType == Curvilinear) utilsPtr->out() << "Curvilinear"; else if (lsType == Standard) utilsPtr->out() << "Standard"; else if (lsType == FullStep) utilsPtr->out() << "Full Step"; else if (lsType == Dual) utilsPtr->out() << "Dual"; utilsPtr->out() << ") -- " << std::endl; } // Local variables bool isFailed = false; bool isAcceptable = false; bool isFirstPass = true; std::string message = "(STEP ACCEPTED!)"; // Set counters int lsIterations = 1; // Get Old f const Abstract::Group& oldSoln = s.getPreviousSolutionGroup(); double fOld = 0.5 * oldSoln.getNormF() * oldSoln.getNormF(); // Compute first trial point and its function value in_stepSize = defaultStep; newSoln.computeX(oldSoln, lsDir, in_stepSize); newSoln.computeF(); double fNew = 0.5 * newSoln.getNormF() * newSoln.getNormF(); // Stop here if only using the full step if (lsType == FullStep) { print.printStep(lsIterations, in_stepSize, fOld, fNew, message); return (!isFailed); } // Compute directional derivative double fprime; if ((lsType == Curvilinear) && !(isNewtonDirection)) fprime = slopeObj.computeSlope(*newtonVecPtr, oldSoln); else fprime = slopeObj.computeSlope(lsDir, oldSoln); numJvMults++; // computeSlope() has J*v inside of it // Compute the convergence criteria for the line search double threshold = fOld + alpha*in_stepSize*fprime; isAcceptable = (fNew < threshold); // Update counter and temporarily hold direction if a linesearch is needed if (!isAcceptable) { counter.incrementNumNonTrivialLineSearches(); *tmpVecPtr = lsDir; } // Iterate until the trial point is accepted.... while (!isAcceptable) { // Check for linesearch failure if (lsIterations > maxIters) { isFailed = true; message = "(FAILED - Max Iters)"; break; } print.printStep(lsIterations, in_stepSize, fOld, fNew); // Is the full tensor step a descent direction? If not, switch to Newton if (isFirstPass && (!isNewtonDirection) && (fprime >= 0) && (lsType != Curvilinear) ) { *tmpVecPtr = *newtonVecPtr; fprime = slopeObj.computeSlope(*tmpVecPtr, oldSoln); numJvMults++; if (utilsPtr->isPrintType(NOX::Utils::Details)) utilsPtr->out() << " Switching to Newton step. New fprime = " << utilsPtr->sciformat(fprime, 6) << std::endl; } else { in_stepSize = selectLambda(fNew, fOld, fprime, in_stepSize); } isFirstPass = false; // Check for linesearch failure if (in_stepSize < minStep) { isFailed = true; message = "(FAILED - Min Step)"; break; } // Update the number of linesearch iterations counter.incrementNumIterations(); lsIterations ++; // Compute new trial point and its function value if ((lsType == Curvilinear) && !(isNewtonDirection)) { computeCurvilinearStep(*tmpVecPtr, oldSoln, s, in_stepSize); // Note: oldSoln is needed above to get correct preconditioner newSoln.computeX(oldSoln, *tmpVecPtr, 1.0); } else { newSoln.computeX(oldSoln, *tmpVecPtr, in_stepSize); } newSoln.computeF(); fNew = 0.5 * newSoln.getNormF() * newSoln.getNormF(); // Recompute convergence criteria based on new step threshold = fOld + alpha*in_stepSize*fprime; isAcceptable = (fNew < threshold); } if (isFailed) { counter.incrementNumFailedLineSearches(); if (recoveryStepType == Constant) { in_stepSize = recoveryStep; if (in_stepSize == 0.0) { newSoln = oldSoln; newSoln.computeF(); fNew = fOld; } else { // Update the group using recovery step if ((lsType == Curvilinear) && !(isNewtonDirection)) { computeCurvilinearStep(*tmpVecPtr, oldSoln, s, in_stepSize); // Note: oldSoln is needed above to get correct preconditioner newSoln.computeX(oldSoln, *tmpVecPtr, 1.0); } else { newSoln.computeX(oldSoln, *tmpVecPtr, in_stepSize); } //newSoln.computeX(oldSoln, lsDir, in_stepSize); newSoln.computeF(); fNew = 0.5 * newSoln.getNormF() * newSoln.getNormF(); message = "(USING RECOVERY STEP!)"; } } else message = "(USING LAST STEP!)"; } print.printStep(lsIterations, in_stepSize, fOld, fNew, message); counter.setValues(paramsPtr->sublist("Line Search")); return (!isFailed); }