@Test
 /** Test the present value. */
 public void presentValueExplicit() {
   final MultipleCurrencyAmount pv = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final double timeToExpiry = SWAPTION_LONG_PAYER.getTimeToExpiry();
   final AnnuityPaymentFixed cfe =
       CFEC.visitSwap(SWAPTION_LONG_PAYER.getUnderlyingSwap(), MULTICURVES);
   final int numberOfPayments = cfe.getNumberOfPayments();
   final double alpha[] = new double[numberOfPayments];
   final double disccf[] = new double[numberOfPayments];
   for (int loopcf = 0; loopcf < numberOfPayments; loopcf++) {
     alpha[loopcf] =
         MODEL.alpha(
             HW_PARAMETERS,
             0.0,
             timeToExpiry,
             timeToExpiry,
             cfe.getNthPayment(loopcf).getPaymentTime());
     disccf[loopcf] =
         MULTICURVES.getDiscountFactor(EUR, cfe.getNthPayment(loopcf).getPaymentTime())
             * cfe.getNthPayment(loopcf).getAmount();
   }
   final double kappa = MODEL.kappa(disccf, alpha);
   double pvExpected = 0.0;
   for (int loopcf = 0; loopcf < numberOfPayments; loopcf++) {
     pvExpected += disccf[loopcf] * NORMAL.getCDF(-kappa - alpha[loopcf]);
   }
   assertEquals(
       "Swaption physical - Hull-White - present value", pvExpected, pv.getAmount(EUR), 1E-2);
   final MultipleCurrencyAmount pv2 =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, cfe, HW_MULTICURVES);
   assertEquals("Swaption physical - Hull-White - present value", pv, pv2);
 }
 @Test
 /** Tests long/short parity. */
 public void longShortParityExplicit() {
   final MultipleCurrencyAmount pvLong =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvShort =
       METHOD_HW.presentValue(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - present value - long/short parity",
       pvLong.getAmount(EUR),
       -pvShort.getAmount(EUR),
       TOLERANCE_PV);
 }
 @Test
 /** Tests payer/receiver/swap parity. */
 public void payerReceiverParityExplicit() {
   final MultipleCurrencyAmount pvReceiverLong =
       METHOD_HW.presentValue(SWAPTION_LONG_RECEIVER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvPayerShort =
       METHOD_HW.presentValue(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvSwap = SWAP_RECEIVER.accept(PVDC, MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - present value - payer/receiver/swap parity",
       pvReceiverLong.getAmount(EUR) + pvPayerShort.getAmount(EUR),
       pvSwap.getAmount(EUR),
       TOLERANCE_PV);
 }
 @Test
 /** Tests the method against the present value calculator. */
 public void presentValueMethodVsCalculator() {
   final MultipleCurrencyAmount pvMethod =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvCalculator = SWAPTION_LONG_PAYER.accept(PVHWC, HW_MULTICURVES);
   assertEquals(
       "SwaptionPhysicalFixedIborSABRMethod: present value : method and calculator",
       pvMethod,
       pvCalculator);
 }
 @Test
 /** Compare explicit formula with approximated formula. */
 public void presentValueApproximation() {
   final BlackImpliedVolatilityFormula implied = new BlackImpliedVolatilityFormula();
   final double forward =
       SWAPTION_LONG_PAYER
           .getUnderlyingSwap()
           .accept(ParRateDiscountingCalculator.getInstance(), MULTICURVES);
   final double pvbp =
       METHOD_SWAP.presentValueBasisPoint(SWAPTION_LONG_PAYER.getUnderlyingSwap(), MULTICURVES);
   final MultipleCurrencyAmount pvPayerLongExplicit =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvPayerLongApproximation =
       METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final BlackFunctionData data = new BlackFunctionData(forward, pvbp, 0.20);
   final double volExplicit =
       implied.getImpliedVolatility(data, SWAPTION_LONG_PAYER, pvPayerLongExplicit.getAmount(EUR));
   final double volApprox =
       implied.getImpliedVolatility(
           data, SWAPTION_LONG_PAYER, pvPayerLongApproximation.getAmount(EUR));
   assertEquals(
       "Swaption physical - Hull-White - present value - explicit/approximation",
       pvPayerLongExplicit.getAmount(EUR),
       pvPayerLongApproximation.getAmount(EUR),
       5.0E+2);
   assertEquals(
       "Swaption physical - Hull-White - present value - explicit/approximation",
       volExplicit,
       volApprox,
       2.5E-4); // 0.025%
   final MultipleCurrencyAmount pvReceiverLongExplicit =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvReceiverLongApproximation =
       METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - present value - explicit/numerical integration",
       pvReceiverLongExplicit.getAmount(EUR),
       pvReceiverLongApproximation.getAmount(EUR),
       5.0E+2);
 }
 @Test
 /** Compare explicit formula with numerical integration. */
 public void presentValueNumericalIntegration() {
   final MultipleCurrencyAmount pvPayerLongExplicit =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvPayerLongIntegration =
       METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - present value - explicit/numerical integration",
       pvPayerLongExplicit.getAmount(EUR),
       pvPayerLongIntegration.getAmount(EUR),
       TOLERANCE_PV);
   final MultipleCurrencyAmount pvPayerShortExplicit =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvPayerShortIntegration =
       METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - present value - explicit/numerical integration",
       pvPayerShortExplicit.getAmount(EUR),
       pvPayerShortIntegration.getAmount(EUR),
       TOLERANCE_PV);
   final MultipleCurrencyAmount pvReceiverLongExplicit =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvReceiverLongIntegration =
       METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - present value - explicit/numerical integration",
       pvReceiverLongExplicit.getAmount(EUR),
       pvReceiverLongIntegration.getAmount(EUR),
       TOLERANCE_PV);
   final MultipleCurrencyAmount pvReceiverShortExplicit =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvReceiverShortIntegration =
       METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - present value - explicit/numerical integration",
       pvReceiverShortExplicit.getAmount(EUR),
       pvReceiverShortIntegration.getAmount(EUR),
       TOLERANCE_PV);
 }
 @Test
 /** Tests the Hull-White parameters sensitivity for the explicit formula. */
 public void presentValueHullWhiteSensitivityExplicit() {
   final double[] hwSensitivity =
       METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final int nbVolatility = HW_PARAMETERS.getVolatility().length;
   final double shiftVol = 1.0E-6;
   final double[] volatilityBumped = new double[nbVolatility];
   System.arraycopy(HW_PARAMETERS.getVolatility(), 0, volatilityBumped, 0, nbVolatility);
   final double[] volatilityTime = new double[nbVolatility - 1];
   System.arraycopy(HW_PARAMETERS.getVolatilityTime(), 1, volatilityTime, 0, nbVolatility - 1);
   final double[] pvBumpedPlus = new double[nbVolatility];
   final double[] pvBumpedMinus = new double[nbVolatility];
   final HullWhiteOneFactorPiecewiseConstantParameters parametersBumped =
       new HullWhiteOneFactorPiecewiseConstantParameters(
           HW_PARAMETERS.getMeanReversion(), volatilityBumped, volatilityTime);
   final HullWhiteOneFactorProviderDiscount bundleBumped =
       new HullWhiteOneFactorProviderDiscount(MULTICURVES, parametersBumped, EUR);
   for (int loopvol = 0; loopvol < nbVolatility; loopvol++) {
     volatilityBumped[loopvol] += shiftVol;
     parametersBumped.setVolatility(volatilityBumped);
     pvBumpedPlus[loopvol] =
         METHOD_HW.presentValue(SWAPTION_LONG_PAYER, bundleBumped).getAmount(EUR);
     volatilityBumped[loopvol] -= 2 * shiftVol;
     parametersBumped.setVolatility(volatilityBumped);
     pvBumpedMinus[loopvol] =
         METHOD_HW.presentValue(SWAPTION_LONG_PAYER, bundleBumped).getAmount(EUR);
     assertEquals(
         "Swaption - Hull-White sensitivity adjoint: derivative "
             + loopvol
             + " - difference:"
             + ((pvBumpedPlus[loopvol] - pvBumpedMinus[loopvol]) / (2 * shiftVol)
                 - hwSensitivity[loopvol]),
         (pvBumpedPlus[loopvol] - pvBumpedMinus[loopvol]) / (2 * shiftVol),
         hwSensitivity[loopvol],
         TOLERANCE_PV_DELTA);
     volatilityBumped[loopvol] = HW_PARAMETERS.getVolatility()[loopvol];
   }
 }
 @Test
 /** Approximation analysis. */
 public void presentValueApproximationAnalysis() {
   final NormalImpliedVolatilityFormula implied = new NormalImpliedVolatilityFormula();
   final int nbStrike = 20;
   final double[] pvExplicit = new double[nbStrike + 1];
   final double[] pvApproximation = new double[nbStrike + 1];
   final double[] strike = new double[nbStrike + 1];
   final double[] volExplicit = new double[nbStrike + 1];
   final double[] volApprox = new double[nbStrike + 1];
   final double strikeRange = 0.010;
   final SwapFixedCoupon<Coupon> swap = SWAP_PAYER_DEFINITION.toDerivative(REFERENCE_DATE);
   final double forward = swap.accept(PRDC, MULTICURVES);
   final double pvbp = METHOD_SWAP.presentValueBasisPoint(swap, MULTICURVES);
   for (int loopstrike = 0; loopstrike <= nbStrike; loopstrike++) {
     strike[loopstrike] =
         forward
             - strikeRange
             + 3
                 * strikeRange
                 * loopstrike
                 / nbStrike; // From forward-strikeRange to forward+2*strikeRange
     final SwapFixedIborDefinition swapDefinition =
         SwapFixedIborDefinition.from(
             SETTLEMENT_DATE,
             SWAP_TENOR,
             EUR1YEURIBOR6M,
             NOTIONAL,
             strike[loopstrike],
             FIXED_IS_PAYER);
     final SwaptionPhysicalFixedIborDefinition swaptionDefinition =
         SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, swapDefinition, IS_LONG);
     final SwaptionPhysicalFixedIbor swaption = swaptionDefinition.toDerivative(REFERENCE_DATE);
     pvExplicit[loopstrike] = METHOD_HW.presentValue(swaption, HW_MULTICURVES).getAmount(EUR);
     pvApproximation[loopstrike] =
         METHOD_HW_APPROXIMATION.presentValue(swaption, HW_MULTICURVES).getAmount(EUR);
     final NormalFunctionData data = new NormalFunctionData(forward, pvbp, 0.01);
     volExplicit[loopstrike] =
         implied.getImpliedVolatility(data, swaption, pvExplicit[loopstrike]);
     volApprox[loopstrike] =
         implied.getImpliedVolatility(data, swaption, pvApproximation[loopstrike]);
     assertEquals(
         "Swaption physical - Hull-White - implied volatility - explicit/approximation",
         volExplicit[loopstrike],
         volApprox[loopstrike],
         1.0E-3); // 0.10%
   }
 }
 @Test(enabled = true)
 /** Compare explicit formula with Monte-Carlo and long/short and payer/receiver parities. */
 public void presentValueMonteCarlo() {
   HullWhiteMonteCarloMethod methodMC;
   methodMC =
       new HullWhiteMonteCarloMethod(
           new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH);
   // Seed fixed to the DEFAULT_SEED for testing purposes.
   final MultipleCurrencyAmount pvPayerLongExplicit =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final MultipleCurrencyAmount pvPayerLongMC =
       methodMC.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - Monte Carlo",
       pvPayerLongExplicit.getAmount(EUR),
       pvPayerLongMC.getAmount(EUR),
       1.0E+4);
   final double pvMCPreviousRun = 4221400.891;
   assertEquals(
       "Swaption physical - Hull-White - Monte Carlo",
       pvMCPreviousRun,
       pvPayerLongMC.getAmount(EUR),
       TOLERANCE_PV);
   methodMC =
       new HullWhiteMonteCarloMethod(
           new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH);
   final MultipleCurrencyAmount pvPayerShortMC =
       methodMC.presentValue(SWAPTION_SHORT_PAYER, EUR, HW_MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - Monte Carlo",
       -pvPayerLongMC.getAmount(EUR),
       pvPayerShortMC.getAmount(EUR),
       TOLERANCE_PV);
   final MultipleCurrencyAmount pvReceiverLongMC =
       methodMC.presentValue(SWAPTION_LONG_RECEIVER, EUR, HW_MULTICURVES);
   final MultipleCurrencyAmount pvSwap = SWAP_RECEIVER.accept(PVDC, MULTICURVES);
   assertEquals(
       "Swaption physical - Hull-White - Monte Carlo - payer/receiver/swap parity",
       pvReceiverLongMC.getAmount(EUR) + pvPayerShortMC.getAmount(EUR),
       pvSwap.getAmount(EUR),
       1.0E+5);
 }
  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performance() {
    long startTime, endTime;
    final int nbTest = 1000;
    MultipleCurrencyAmount pvPayerLongExplicit = MultipleCurrencyAmount.of(EUR, 0.0);
    MultipleCurrencyAmount pvPayerLongIntegration = MultipleCurrencyAmount.of(EUR, 0.0);
    MultipleCurrencyAmount pvPayerLongApproximation = MultipleCurrencyAmount.of(EUR, 0.0);
    @SuppressWarnings("unused")
    MultipleCurrencyAmount pvPayerLongMC = MultipleCurrencyAmount.of(EUR, 0.0);
    double[] pvhws =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    MultipleCurrencyMulticurveSensitivity pvcs =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongExplicit = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " pv swaption Hull-White explicit method: " + (endTime - startTime) + " ms");
    // Performance note: HW price: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 380 ms for
    // 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " HW sensitivity swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW sensitivity (3): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon:
    // 430 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " curve sensitivity swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: curve sensitivity (40): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 855 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
      pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " price/delta/vega swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: present value/delta/vega: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 1730 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongIntegration =
          METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White numerical integration method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW numerical integration: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 1700 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongApproximation =
          METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " swaption Hull-White approximation method: " + (endTime - startTime) + " ms");
    // Performance note: HW approximation: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 250
    // ms for 10000 swaptions.

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongMC = METHOD_HW_MONTECARLO.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White Monte Carlo method ("
            + NB_PATH
            + " paths): "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW approximation: 18-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 9200
    // ms for 1000 swaptions (12500 paths).

    final double difference =
        pvPayerLongExplicit.getAmount(EUR) - pvPayerLongIntegration.getAmount(EUR);
    final double difference2 =
        pvPayerLongExplicit.getAmount(EUR) - pvPayerLongApproximation.getAmount(EUR);
    //      double difference3 = pvPayerLongExplicit.getAmount(CUR) - pvPayerLongMC.getAmount(CUR);
    System.out.println("Difference explicit-integration: " + difference);
    System.out.println("Difference explicit-approximation: " + difference2);
    //      System.out.println("Difference explicit-Monte Carlo: " + difference3);
    System.out.println("Curve sensitivity: " + pvcs.toString());
    System.out.println("HW sensitivity: " + Arrays.toString(pvhws));
  }