class ParabolicMinimumBracketer extends MinimumBracketer {

  @Override
  public double[] getBracketedPoints(final Function1D<Double, Double> f, final double xLower, final double xUpper) {
    checkInputs(f, xLower, xUpper);
    double temp;
    double x1 = xLower;
    double x2 = xUpper;
    double f1 = f.evaluate(x1);
    double f2 = f.evaluate(x2);
    if (f2 > f1) {
      temp = x2;
      x2 = x1;
      x1 = temp;
      temp = f2;
      f2 = f1;
      f1 = temp;
    }
    double x3 = x2 + MAGNIFICATION * (x2 - x1);
    double f3 = f.evaluate(x3);
    if (x1 < x2 && x2 < x3 && f2 < f1 && f2 < f3 || x1 > x2 && x2 > x3 && f2 < f1 && f2 < f3) {
      return new double[] {x1, x2, x3};
    }
    double r, q, u, uLim, fu;
    int count = 0;
    while (count < MAX_ITER) {
      if (f2 < f3) {
        return new double[] {x1, x2, x3};
      }
      count++;
      r = (x2 - x1) * (f2 - f3);
      q = (x2 - x1) * (f2 - f1);
      u = x2 - ((x2 - x3) * q - (x2 - x1) * r) / (2 * Math.copySign(Math.max(Math.abs(q - r), ZERO), q - r));
      uLim = x2 + MAX_MAGNIFICATION * (x3 - x2);
      if ((x2 - u) * (u - x3) > 0) {
        fu = f.evaluate(u);
        if (fu < f3) {
          x1 = x2;
          x2 = u;
          return new double[] {x1, x2, x3};
        } else if (fu > f2) {
          x3 = u;
          return new double[] {x1, x2, x3};
        }
        u = x3 + MAGNIFICATION * (x3 - x2);
        fu = f.evaluate(u);
      } else if ((x3 - u) * (u - uLim) > 0) {
        fu = f.evaluate(u);
        if (fu < f3) {
          temp = u + MAGNIFICATION * (u - x3);
          x2 = x3;
          x3 = u;
          u = temp;
          f2 = f3;
          f3 = fu;
          fu = f.evaluate(u);
        }
      } else if ((u - uLim) * (uLim - x3) >= 0) {
        u = uLim;
        fu = f.evaluate(u);
      } else {
        u = x3 + MAGNIFICATION * (x3 - x2);
        fu = f.evaluate(u);
      }
      x1 = x2;
      x2 = x3;
      x3 = u;
      f1 = f2;
      f2 = f3;
      f3 = fu;
    }
    throw new MathException("Could not bracket a minimum in " + MAX_ITER + " attempts");
  }

}