/**
  * @param function
  * @param lineSearcher
  * @param guess
  * @param direction
  * @return
  */
 protected double[] doLineSearch(
     DifferentiableFunction function,
     BacktrackingLineSearcher lineSearcher,
     double[] guess,
     double[] direction) {
   return lineSearcher.minimize(function, guess, direction);
 }
  public double[] minimize(DifferentiableFunction function, double[] initial, double tolerance) {
    boolean printProgress = true;
    BacktrackingLineSearcher lineSearcher = new BacktrackingLineSearcher();
    double[] guess = DoubleArrays.clone(initial);

    // this grows linearly as the iterations go on (if stepSizeGrowthAmount
    // > 0.0)
    // but gets scaled back geometrically by lineSearcher
    double stepSize = initialStepSize;
    for (int iteration = 0; iteration < maxIterations; iteration++) {

      if (stepSizeGrowthAmount == 0.0) stepSize = initialStepSize;
      else {
        stepSize *= stepSizeGrowthAmount;
      }
      double[] subgradient = function.derivativeAt(guess);
      double value = function.valueAt(guess);
      double[] direction = subgradient;
      DoubleArrays.scale(direction, -1.0);
      if (iteration == 0) lineSearcher.stepSizeMultiplier = initialStepSizeMultiplier;
      else lineSearcher.stepSizeMultiplier = stepSizeMultiplier;
      lineSearcher.initialStepSize = stepSize;
      double[] nextGuess = doLineSearch(function, lineSearcher, guess, direction);
      stepSize = lineSearcher.getFinalStepSize();
      double[] nextDerivative = function.derivativeAt(nextGuess);
      double nextValue = function.valueAt(nextGuess);
      if (printProgress) {
        Logger.i().logs("[Subgradient] Iteration %d: %.6f", iteration, nextValue);
      }

      if (iteration >= minIterations && converged(value, nextValue, tolerance)) {
        return nextGuess;
      }
      guess = nextGuess;
      value = nextValue;
      subgradient = nextDerivative;
    }
    return guess;
  }