@Override
 public void calibrate(final DATA_TYPE data) {
   computeCalibrationPrice(data);
   _calibrationObjective.setMulticurves(data.getMulticurveProvider());
   final int nbInstruments = getBasket().size();
   final RidderSingleRootFinder rootFinder =
       new RidderSingleRootFinder(
           _calibrationObjective.getFunctionValueAccuracy(),
           _calibrationObjective.getVariableAbsoluteAccuracy());
   final BracketRoot bracketer = new BracketRoot();
   for (int loopins = 0; loopins < nbInstruments; loopins++) {
     final InstrumentDerivative instrument = getBasket().get(loopins);
     _calibrationObjective.setInstrument(instrument);
     _calibrationObjective.setPrice(getCalibrationPrices().get(loopins));
     final double[] range =
         bracketer.getBracketedPoints(
             _calibrationObjective,
             _calibrationObjective.getMinimumParameter(),
             _calibrationObjective.getMaximumParameter());
     rootFinder.getRoot(_calibrationObjective, range[0], range[1]);
     if (loopins < nbInstruments - 1) {
       ((SuccessiveRootFinderHullWhiteCalibrationObjective) _calibrationObjective)
           .setNextCalibrationTime(_calibrationTimes.get(loopins));
     }
   }
 }
  /** {@inheritDoc} */
  @Override
  public IsdaCompliantCreditCurve calibrateCreditCurve(
      CdsAnalytic[] cds,
      double[] premiums,
      IsdaCompliantYieldCurve yieldCurve,
      double[] pointsUpfront) {

    ArgChecker.noNulls(cds, "null CDSs");
    ArgChecker.notEmpty(premiums, "empty fractionalSpreads");
    ArgChecker.notEmpty(pointsUpfront, "empty pointsUpfront");
    ArgChecker.notNull(yieldCurve, "null yieldCurve");
    int n = cds.length;
    ArgChecker.isTrue(n == premiums.length, "Number of CDSs does not match number of spreads");
    ArgChecker.isTrue(
        n == pointsUpfront.length, "Number of CDSs does not match number of pointsUpfront");
    double proStart = cds[0].getEffectiveProtectionStart();
    for (int i = 1; i < n; i++) {
      ArgChecker.isTrue(
          proStart == cds[i].getEffectiveProtectionStart(),
          "all CDSs must has same protection start");
      ArgChecker.isTrue(
          cds[i].getProtectionEnd() > cds[i - 1].getProtectionEnd(),
          "protection end must be ascending");
    }

    // use continuous premiums as initial guess
    double[] guess = new double[n];
    double[] t = new double[n];
    for (int i = 0; i < n; i++) {
      t[i] = cds[i].getProtectionEnd();
      guess[i] = (premiums[i] + pointsUpfront[i] / t[i]) / cds[i].getLGD();
    }

    IsdaCompliantCreditCurve creditCurve = new IsdaCompliantCreditCurve(t, guess);
    for (int i = 0; i < n; i++) {
      Pricer pricer = new Pricer(cds[i], yieldCurve, t, premiums[i], pointsUpfront[i]);
      Function1D<Double, Double> func = pricer.getPointFunction(i, creditCurve);

      switch (getArbHanding()) {
        case Ignore:
          {
            try {
              double[] bracket =
                  BRACKER.getBracketedPoints(
                      func,
                      0.8 * guess[i],
                      1.25 * guess[i],
                      Double.NEGATIVE_INFINITY,
                      Double.POSITIVE_INFINITY);
              double zeroRate =
                  bracket[0] > bracket[1]
                      ? ROOTFINDER.getRoot(func, bracket[1], bracket[0])
                      : ROOTFINDER.getRoot(func, bracket[0], bracket[1]); // Negative guess handled
              creditCurve = creditCurve.withRate(zeroRate, i);
            } catch (
                MathException e) { // handling bracketing failure due to small survival probability
              if (Math.abs(func.evaluate(creditCurve.getZeroRateAtIndex(i - 1))) < 1.e-12) {
                creditCurve = creditCurve.withRate(creditCurve.getZeroRateAtIndex(i - 1), i);
              } else {
                throw new MathException(e);
              }
            }
            break;
          }
        case Fail:
          {
            double minValue =
                i == 0 ? 0.0 : creditCurve.getRTAtIndex(i - 1) / creditCurve.getTimeAtIndex(i);
            if (i > 0 && func.evaluate(minValue) > 0.0) { // can never fail on the first spread
              StringBuilder msg = new StringBuilder();
              if (pointsUpfront[i] == 0.0) {
                msg.append("The par spread of " + premiums[i] + " at index " + i);
              } else {
                msg.append(
                    "The premium of "
                        + premiums[i]
                        + "and points up-front of "
                        + pointsUpfront[i]
                        + " at index "
                        + i);
              }
              msg.append(
                  " is an arbitrage; cannot fit a curve with positive forward hazard rate. ");
              throw new IllegalArgumentException(msg.toString());
            }
            guess[i] = Math.max(minValue, guess[i]);
            double[] bracket =
                BRACKER.getBracketedPoints(
                    func, guess[i], 1.2 * guess[i], minValue, Double.POSITIVE_INFINITY);
            double zeroRate = ROOTFINDER.getRoot(func, bracket[0], bracket[1]);
            creditCurve = creditCurve.withRate(zeroRate, i);
            break;
          }
        case ZeroHazardRate:
          {
            double minValue =
                i == 0 ? 0.0 : creditCurve.getRTAtIndex(i - 1) / creditCurve.getTimeAtIndex(i);
            if (i > 0 && func.evaluate(minValue) > 0.0) { // can never fail on the first spread
              creditCurve = creditCurve.withRate(minValue, i);
            } else {
              guess[i] = Math.max(minValue, guess[i]);
              double[] bracket =
                  BRACKER.getBracketedPoints(
                      func, guess[i], 1.2 * guess[i], minValue, Double.POSITIVE_INFINITY);
              double zeroRate = ROOTFINDER.getRoot(func, bracket[0], bracket[1]);
              creditCurve = creditCurve.withRate(zeroRate, i);
            }
            break;
          }
        default:
          throw new IllegalArgumentException("unknow case " + getArbHanding());
      }
    }
    return creditCurve;
  }