private double[] implicitMultiply(double[] initialInverseHessianDiagonal, double[] derivative) {
    double[] rho = new double[historySize()];
    double[] alpha = new double[historySize()];
    double[] right = DoubleArrays.clone(derivative);
    // loop last backward
    for (int i = historySize()-1; i >= 0; i--) {
      double[] inputDifference = getInputDifference(i);
      double[] derivativeDifference = getDerivativeDifference(i);
      rho[i] = DoubleArrays.innerProduct(inputDifference, derivativeDifference);
      if (rho[i] == 0.0)
        throw new RuntimeException("LBFGSMinimizer.implicitMultiply: Curvature problem.");
      alpha[i] = DoubleArrays.innerProduct(inputDifference, right) / rho[i];
      right = DoubleArrays.addMultiples(right, 1.0, derivativeDifference, -1.0*alpha[i]);
    }
    double[] left = DoubleArrays.pointwiseMultiply(initialInverseHessianDiagonal, right);
    for (int i = 0; i < historySize(); i++) {
      double[] inputDifference = getInputDifference(i);
      double[] derivativeDifference = getDerivativeDifference(i);
      double beta = DoubleArrays.innerProduct(derivativeDifference, left) / rho[i];
      left = DoubleArrays.addMultiples(left, 1.0, inputDifference, alpha[i] - beta);
    }
    return left;
  }