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);
}