@Override
  public void optimize(Point initial, OptimizationController control) throws OptimizationException {

    if (initial.dim() != 1) {
      throw new IllegalArgumentException(
          "Only single-dimensional optimization supported, dim=" + initial.dim());
    }

    log.info("Starting golden section search for optimization");

    Point guessAC = null;
    Point guessBD = null;

    try {
      boolean guessedAC;

      Point previous = p(0);
      double previousValue = Double.NaN;
      current = previous;
      double currentValue = Double.NaN;

      /*
       * Initialize the points + computation.
       */
      Point a = p(0);
      Point d = p(1.0);
      Point b = section1(a, d);
      Point c = section2(a, d);

      functionExecutor.compute(a);
      functionExecutor.compute(d);
      functionExecutor.compute(b);
      functionExecutor.compute(c);

      // Wait for points a and d, which normally are already precomputed
      functionExecutor.waitFor(a);
      functionExecutor.waitFor(d);

      boolean continueOptimization = true;
      while (continueOptimization) {

        /*
         * Get values at A & D for guessing.
         * These are pre-calculated except during the first step.
         */
        double fa, fd;
        fa = functionExecutor.getValue(a);
        fd = functionExecutor.getValue(d);

        /*
         * Start calculating possible two next points.  The order of evaluation
         * is selected based on the function values at A and D.
         */
        guessAC = section1(a, c);
        guessBD = section2(b, d);
        if (Double.isNaN(fd) || fa < fd) {
          guessedAC = true;
          functionExecutor.compute(guessAC);
          functionExecutor.compute(guessBD);
        } else {
          guessedAC = false;
          functionExecutor.compute(guessBD);
          functionExecutor.compute(guessAC);
        }

        /*
         * Get values at B and C.
         */
        double fb, fc;
        functionExecutor.waitFor(b);
        functionExecutor.waitFor(c);
        fb = functionExecutor.getValue(b);
        fc = functionExecutor.getValue(c);

        double min = MathUtil.min(fa, fb, fc, fd);
        if (Double.isNaN(min)) {
          throw new OptimizationException("Unable to compute initial function values");
        }

        /*
         * Update previous and current values for step control.
         */
        previousValue = currentValue;
        currentValue = min;
        previous = current;
        if (min == fa) {
          current = a;
        } else if (min == fb) {
          current = b;
        } else if (min == fc) {
          current = c;
        } else {
          current = d;
        }

        /*
         * Select next positions.  These are already being calculated in the background
         * as guessAC and guessBD.
         */
        if (min == fa || min == fb) {
          d = c;
          c = b;
          b = guessAC;
          functionExecutor.abort(guessBD);
          guessBD = null;
          log.debug("Selecting A-C region, a=" + a.get(0) + " c=" + c.get(0));
          if (guessedAC) {
            guessSuccess++;
          } else {
            guessFailure++;
          }
        } else {
          a = b;
          b = c;
          c = guessBD;
          functionExecutor.abort(guessAC);
          guessAC = null;
          log.debug("Selecting B-D region, b=" + b.get(0) + " d=" + d.get(0));
          if (!guessedAC) {
            guessSuccess++;
          } else {
            guessFailure++;
          }
        }

        /*
         * Check optimization control.
         */
        continueOptimization =
            control.stepTaken(previous, previousValue, current, currentValue, c.get(0) - a.get(0));

        if (Thread.interrupted()) {
          throw new InterruptedException();
        }
      }

    } catch (InterruptedException e) {
      log.info("Optimization was interrupted with InterruptedException");
    }

    if (guessAC != null) {
      functionExecutor.abort(guessAC);
    }
    if (guessBD != null) {
      functionExecutor.abort(guessBD);
    }

    log.info(
        "Finishing optimization at point " + getOptimumPoint() + " value " + getOptimumValue());
    log.info("Optimization statistics: " + getStatistics());
  }
 private Point section2(Point a, Point b) {
   double va = a.get(0);
   double vb = b.get(0);
   return p(va + ALPHA * (vb - va));
 }