@Override
  public LeastSquareResultsWithTransform getFitResult(
      final EuropeanVanillaOption[] options,
      final BlackFunctionData[] data,
      final double[] errors,
      final double[] initialFitParameters,
      final BitSet fixed) {
    testData(options, data, errors, initialFitParameters, fixed, N_PARAMETERS);
    final int n = options.length;
    final double forward = data[0].getForward();
    final double maturity = options[0].getTimeToExpiry();
    for (int i = 1; i < n; i++) {
      Validate.isTrue(
          CompareUtils.closeEquals(options[i].getTimeToExpiry(), maturity),
          "All options must have the same maturity "
              + maturity
              + "; have one with maturity "
              + options[i].getTimeToExpiry());
    }
    final UncoupledParameterTransforms transforms =
        new UncoupledParameterTransforms(
            new DoubleMatrix1D(initialFitParameters), TRANSFORMS, fixed);
    final Function1D<DoubleMatrix1D, Double> function =
        new Function1D<DoubleMatrix1D, Double>() {

          @SuppressWarnings("synthetic-access")
          @Override
          public Double evaluate(final DoubleMatrix1D fp) {
            final DoubleMatrix1D mp = transforms.inverseTransform(fp);
            final double alpha = mp.getEntry(0);
            final double beta = mp.getEntry(1);
            final double nu = mp.getEntry(2);
            final double rho = mp.getEntry(3);
            double chiSqr = 0;
            final SABRFormulaData sabrFormulaData = new SABRFormulaData(alpha, beta, rho, nu);
            for (int i = 0; i < n; i++) {
              chiSqr +=
                  FunctionUtils.square(
                      (data[i].getBlackVolatility()
                              - _formula
                                  .getVolatilityFunction(options[i], forward)
                                  .evaluate(sabrFormulaData))
                          / errors[i]);
            }
            return chiSqr;
          }
        };
    final ScalarMinimizer lineMinimizer = new BrentMinimizer1D();
    final ConjugateDirectionVectorMinimizer minimzer =
        new ConjugateDirectionVectorMinimizer(lineMinimizer, 1e-6, 10000);
    final DoubleMatrix1D fp = transforms.transform(new DoubleMatrix1D(initialFitParameters));
    final DoubleMatrix1D minPos = minimzer.minimize(function, fp);
    final double chiSquare = function.evaluate(minPos);
    final DoubleMatrix1D res = transforms.inverseTransform(minPos);
    return new LeastSquareResultsWithTransform(
        new LeastSquareResults(
            chiSquare, res, new DoubleMatrix2D(new double[N_PARAMETERS][N_PARAMETERS])),
        transforms);
    // return new LeastSquareResults(chiSquare, res, new DoubleMatrix2D(new
    // double[N_PARAMETERS][N_PARAMETERS]));
  }