/**
   * Check if the optimization algorithm has converged considering the last two points. This method
   * may be called several time from the same algorithm iteration with different points. This can be
   * detected by checking the iteration number at each call if needed. Each time this method is
   * called, the previous and current point correspond to points with the same role at each
   * iteration, so they can be compared. As an example, simplex-based algorithms call this method
   * for all points of the simplex, not only for the best or worst ones.
   *
   * @param iteration Index of current iteration
   * @param previous Best point in the previous iteration.
   * @param current Best point in the current iteration.
   * @return {@code true} if the algorithm has converged.
   */
  @Override
  public boolean converged(
      final int iteration, final PointValuePair previous, final PointValuePair current) {
    if (maxIterationCount != ITERATION_CHECK_DISABLED && iteration >= maxIterationCount) {
      return true;
    }

    final double p = previous.getValue();
    final double c = current.getValue();
    final double difference = FastMath.abs(p - c);
    final double size = FastMath.max(FastMath.abs(p), FastMath.abs(c));
    return difference <= size * getRelativeThreshold() || difference <= getAbsoluteThreshold();
  }
  public double estimateParameters() {

    Sinv = new LUDecomposition(R).getSolver().getInverse();

    WLSObjectiveFunction objectiveFunction = new WLSObjectiveFunction();

    optimizer =
        new NonLinearConjugateGradientOptimizer(
            NonLinearConjugateGradientOptimizer.Formula.POLAK_RIBIERE,
            new SimpleValueChecker(1e-8, 1e-8));

    solution =
        optimizer.optimize(
            new MaxEval(1000),
            objectiveFunction.getObjectiveFunction(),
            objectiveFunction.getObjectiveFunctionGradient(),
            GoalType.MINIMIZE,
            new InitialGuess(getStartValues()),
            new SimpleBounds(getLowerBounds(), getUpperBounds()));

    computeFactorLoadings(solution.getPoint());
    return solution.getValue();
  }