public void test_volatility_sensitivity() {
   double eps = 1.0e-6;
   int nData = TIME.size();
   for (int i = 0; i < NB_TEST; i++) {
     SwaptionSensitivity point =
         SwaptionSensitivity.of(
             CONVENTION,
             TEST_OPTION_EXPIRY[i],
             TENOR.get(i),
             TEST_STRIKE,
             TEST_FORWARD,
             GBP,
             TEST_SENSITIVITY[i]);
     SurfaceCurrencyParameterSensitivity sensi =
         PROVIDER_WITH_PARAM.surfaceCurrencyParameterSensitivity(point);
     Map<DoublesPair, Double> map = new HashMap<DoublesPair, Double>();
     for (int j = 0; j < nData; ++j) {
       DoubleArray volDataUp = VOL.subArray(0, nData).with(j, VOL.get(j) + eps);
       DoubleArray volDataDw = VOL.subArray(0, nData).with(j, VOL.get(j) - eps);
       InterpolatedNodalSurface paramUp =
           InterpolatedNodalSurface.of(
               METADATA_WITH_PARAM, TIME, TENOR, volDataUp, INTERPOLATOR_2D);
       InterpolatedNodalSurface paramDw =
           InterpolatedNodalSurface.of(
               METADATA_WITH_PARAM, TIME, TENOR, volDataDw, INTERPOLATOR_2D);
       BlackVolatilityExpiryTenorSwaptionProvider provUp =
           BlackVolatilityExpiryTenorSwaptionProvider.of(
               paramUp, CONVENTION, ACT_365F, VALUATION_DATE_TIME);
       BlackVolatilityExpiryTenorSwaptionProvider provDw =
           BlackVolatilityExpiryTenorSwaptionProvider.of(
               paramDw, CONVENTION, ACT_365F, VALUATION_DATE_TIME);
       double volUp =
           provUp.getVolatility(TEST_OPTION_EXPIRY[i], TEST_TENOR[i], TEST_STRIKE, TEST_FORWARD);
       double volDw =
           provDw.getVolatility(TEST_OPTION_EXPIRY[i], TEST_TENOR[i], TEST_STRIKE, TEST_FORWARD);
       double fd = 0.5 * (volUp - volDw) / eps;
       map.put(DoublesPair.of(TIME.get(j), TENOR.get(j)), fd);
     }
     SurfaceCurrencyParameterSensitivity sensiFromNoMetadata =
         PROVIDER.surfaceCurrencyParameterSensitivity(point);
     List<SurfaceParameterMetadata> list = sensi.getMetadata().getParameterMetadata().get();
     DoubleArray computed = sensi.getSensitivity();
     assertEquals(computed.size(), nData);
     for (int j = 0; j < list.size(); ++j) {
       SwaptionSurfaceExpiryTenorNodeMetadata metadata =
           (SwaptionSurfaceExpiryTenorNodeMetadata) list.get(i);
       double expected = map.get(DoublesPair.of(metadata.getYearFraction(), metadata.getTenor()));
       assertEquals(computed.get(i), expected, eps);
       assertTrue(
           sensiFromNoMetadata.getMetadata().getParameterMetadata().get().contains(metadata));
     }
   }
 }
  @Override
  public MulticurveSensitivity visitSwapFuturesPriceDeliverableSecurity(
      final SwapFuturesPriceDeliverableSecurity futures,
      final ParameterProviderInterface multicurve) {
    ArgChecker.notNull(futures, "futures");
    ArgChecker.notNull(multicurve, "multi-curve provider");
    double dfInv =
        1.0
            / multicurve
                .getMulticurveProvider()
                .getDiscountFactor(futures.getCurrency(), futures.getDeliveryTime());
    MulticurveSensitivity pvcs =
        futures
            .getUnderlyingSwap()
            .accept(PVCSDC, multicurve.getMulticurveProvider())
            .getSensitivity(futures.getCurrency())
            .multipliedBy(dfInv);

    final PresentValueDiscountingCalculator pvCalc =
        PresentValueDiscountingCalculator.getInstance();
    double pv =
        futures
            .getUnderlyingSwap()
            .accept(pvCalc, multicurve.getMulticurveProvider())
            .getAmount(futures.getCurrency())
            .getAmount();
    final Map<String, List<DoublesPair>> resultMap = new HashMap<>();
    final List<DoublesPair> listDf = new ArrayList<>();
    listDf.add(DoublesPair.of(futures.getDeliveryTime(), futures.getDeliveryTime() * pv * dfInv));
    resultMap.put(multicurve.getMulticurveProvider().getName(futures.getCurrency()), listDf);
    MulticurveSensitivity result = MulticurveSensitivity.ofYieldDiscounting(resultMap);
    return result.plus(pvcs);
  }
 /**
  * Returns the volatility for given expiry, tenor, strike and forward rate.
  *
  * @param expiryTime time to expiry
  * @param tenor tenor
  * @param strike the strike
  * @param forward the forward
  * @return the volatility
  */
 public double getVolatility(double expiryTime, double tenor, double strike, double forward) {
   DoublesPair expiryTenor = DoublesPair.of(expiryTime, tenor);
   SabrFormulaData data =
       SabrFormulaData.of(
           getAlpha(expiryTenor), getBeta(expiryTenor), getRho(expiryTenor), getNu(expiryTenor));
   double shift = getShift(expiryTenor);
   return sabrFunctionProvider.getVolatility(forward + shift, strike + shift, expiryTime, data);
 }
 @Test
 public void testCleanSameCurvesWithRelativeTolerance1() {
   final double eps = 1e-3;
   final double eps2 = 5e-4;
   final InterestRateCurveSensitivity sensitivity1 =
       new InterestRateCurveSensitivity(SENSITIVITY_11);
   final List<DoublesPair> fuzzyList =
       Arrays.asList(
           new DoublesPair[] {
             DoublesPair.of(1d, -10d - 10 * eps2),
             DoublesPair.of(2d, 30d),
             DoublesPair.of(3d, -30d + 30 * eps2),
             DoublesPair.of(4d, 10d)
           });
   List<DoublesPair> expectedList =
       Arrays.asList(new DoublesPair[] {DoublesPair.of(2d, 50d), DoublesPair.of(4d, 50d)});
   Map<String, List<DoublesPair>> expectedMap = new HashMap<>();
   expectedMap.put(CURVE_NAME_1, expectedList);
   final Map<String, List<DoublesPair>> fuzzyMap = new HashMap<>();
   fuzzyMap.put(CURVE_NAME_1, fuzzyList);
   final InterestRateCurveSensitivity fuzzySensitivity =
       new InterestRateCurveSensitivity(fuzzyMap);
   InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(expectedMap);
   final InterestRateCurveSensitivity actualUncleaned = sensitivity1.plus(fuzzySensitivity);
   InterestRateCurveSensitivity actual = actualUncleaned.cleaned(eps, eps / 10);
   assertFalse(actualUncleaned == actual);
   assertFalse(actualUncleaned.getSensitivities() == actual.getSensitivities());
   assertEquals(expected, actual);
   expectedList =
       Arrays.asList(
           new DoublesPair[] {
             DoublesPair.of(1d, -10d * eps2),
             DoublesPair.of(2d, 50d),
             DoublesPair.of(3d, 30d * eps2),
             DoublesPair.of(4d, 50d)
           });
   expectedMap = new HashMap<>();
   expectedMap.put(CURVE_NAME_1, expectedList);
   expected = new InterestRateCurveSensitivity(expectedMap);
   actual = actualUncleaned.cleaned(eps / 100, eps / 10);
   assertEquals(expected.getSensitivities().size(), actual.getSensitivities().size());
   assertIRCSEquals(expected, actual);
 }
 private SurfaceMetadata updateSurfaceMetadata(Set<DoublesPair> pairs) {
   SurfaceMetadata surfaceMetadata = surface.getMetadata();
   List<SurfaceParameterMetadata> sortedMetaList = new ArrayList<SurfaceParameterMetadata>();
   if (surfaceMetadata.getParameterMetadata().isPresent()) {
     List<SurfaceParameterMetadata> metaList =
         new ArrayList<SurfaceParameterMetadata>(surfaceMetadata.getParameterMetadata().get());
     for (DoublesPair pair : pairs) {
       metadataLoop:
       for (SurfaceParameterMetadata parameterMetadata : metaList) {
         ArgChecker.isTrue(
             parameterMetadata instanceof GenericVolatilitySurfaceYearFractionMetadata,
             "Surface parameter metadata must be instance of GenericVolatilitySurfaceYearFractionMetadata");
         GenericVolatilitySurfaceYearFractionMetadata casted =
             (GenericVolatilitySurfaceYearFractionMetadata) parameterMetadata;
         if (pair.getFirst() == casted.getYearFraction()
             && pair.getSecond() == casted.getStrike().getValue()) {
           sortedMetaList.add(casted);
           metaList.remove(parameterMetadata);
           break metadataLoop;
         }
       }
     }
     ArgChecker.isTrue(
         metaList.size() == 0,
         "Mismatch between surface parameter metadata list and doubles pair list");
   } else {
     for (DoublesPair pair : pairs) {
       GenericVolatilitySurfaceYearFractionMetadata parameterMetadata =
           GenericVolatilitySurfaceYearFractionMetadata.of(
               pair.getFirst(), SimpleStrike.of(pair.getSecond()));
       sortedMetaList.add(parameterMetadata);
     }
   }
   return surfaceMetadata.withParameterMetadata(sortedMetaList);
 }
 @Test
 public void testCompareDifferentValues() {
   AssertSensitivityObjects.assertEquals(
       "", new InterestRateCurveSensitivity(), new InterestRateCurveSensitivity(), EPS);
   final TreeMap<String, List<DoublesPair>> sortedMap = new TreeMap<>(SENSITIVITY_11);
   final InterestRateCurveSensitivity sensitivity1 = new InterestRateCurveSensitivity(sortedMap);
   final InterestRateCurveSensitivity sensitivity2 =
       new InterestRateCurveSensitivity(SENSITIVITY_12);
   AssertSensitivityObjects.assertDoesNotEqual("", sensitivity1, sensitivity2, EPS);
   final Map<String, List<DoublesPair>> map = Maps.newTreeMap();
   final double eps = 1e-4;
   for (final Map.Entry<String, List<DoublesPair>> entry : sortedMap.entrySet()) {
     final List<DoublesPair> list = new ArrayList<>();
     for (final DoublesPair pair : entry.getValue()) {
       list.add(DoublesPair.of(pair.getFirst(), pair.getSecond() + 0.01 * eps));
     }
     map.put(entry.getKey(), list);
   }
   final InterestRateCurveSensitivity sensitivity3 = new InterestRateCurveSensitivity(map);
   AssertSensitivityObjects.assertEquals("", sensitivity1, sensitivity3, eps);
   AssertSensitivityObjects.assertDoesNotEqual("", sensitivity1, sensitivity3, EPS);
 }
 @Test
 public void testCleanSameCurves() {
   final InterestRateCurveSensitivity sensitivity1 =
       new InterestRateCurveSensitivity(SENSITIVITY_11);
   final InterestRateCurveSensitivity sensitivity2 =
       new InterestRateCurveSensitivity(SENSITIVITY_12);
   final List<DoublesPair> list =
       Arrays.asList(
           new DoublesPair[] {
             DoublesPair.of(1d, 50d),
             DoublesPair.of(2d, 50d),
             DoublesPair.of(3d, 50d),
             DoublesPair.of(4d, 50d)
           });
   final Map<String, List<DoublesPair>> map = new HashMap<>();
   map.put(CURVE_NAME_1, list);
   final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
   final InterestRateCurveSensitivity actualUncleaned = sensitivity1.plus(sensitivity2);
   final InterestRateCurveSensitivity actual = actualUncleaned.cleaned();
   assertFalse(actualUncleaned == actual);
   assertFalse(actualUncleaned.getSensitivities() == actual.getSensitivities());
   assertEquals(expected, actual);
 }
  @Test
  public void sensitivityTest() {
    final VolatilitySurfaceProvider vsPro =
        new BasisSplineVolatilitySurfaceProvider(0.0, 0.15, 10, 3, 0.0, 10.0, 7, 2);

    final DoubleMatrix1D w = new DoubleMatrix1D(vsPro.getNumModelParameters());
    for (int i = 0; i < w.getNumberOfElements(); i++) {
      w.getData()[i] = RANDOM.nextDouble();
    }

    final VolatilitySurface volSurf = vsPro.getVolSurface(w);
    final Surface<Double, Double, DoubleMatrix1D> senseSurf =
        vsPro.getParameterSensitivitySurface(w);
    final Surface<Double, Double, Pair<Double, DoubleMatrix1D>> volAndSenseSurf =
        vsPro.getVolAndParameterSensitivitySurface(w);

    final int nSamples = 20;
    final DoublesPair[] points = new DoublesPair[nSamples];
    for (int i = 0; i < nSamples; i++) {
      final double t = 10.0 * RANDOM.nextDouble();
      final double k = 0.15 * RANDOM.nextDouble();
      points[i] = DoublesPair.of(t, k);

      final double vol = volSurf.getVolatility(points[i]);
      final DoubleMatrix1D sense = senseSurf.getZValue(points[i].toPair());
      final Pair<Double, DoubleMatrix1D> volAndSense =
          volAndSenseSurf.getZValue(points[i].toPair());
      assertEquals(vol, volAndSense.getFirst(), 1e-15);
      AssertMatrix.assertEqualsVectors(sense, volAndSense.getSecond(), 1e-15);
    }

    // create a DiscreteVolatilityFunctionProvider in order to compute the Jacobian for a (random)
    // set the points
    final DiscreteVolatilityFunctionProvider dvfp =
        new DiscreteVolatilityFunctionProviderFromVolSurface(vsPro);
    final DiscreteVolatilityFunction func = dvfp.from(points);
    final DoubleMatrix2D jac = func.calculateJacobian(w);
    final DoubleMatrix2D jacFD = func.calculateJacobianViaFD(w);
    AssertMatrix.assertEqualsMatrix(jacFD, jac, 1e-10);
  }
  private void assertIRCSEquals(
      final InterestRateCurveSensitivity expected, final InterestRateCurveSensitivity actual) {
    final Iterator<Map.Entry<String, List<DoublesPair>>> expectedIterator =
        new TreeMap<>(expected.getSensitivities()).entrySet().iterator();
    final Iterator<Map.Entry<String, List<DoublesPair>>> actualIterator =
        new TreeMap<>(actual.getSensitivities()).entrySet().iterator();
    do {
      final Map.Entry<String, List<DoublesPair>> expectedEntry = expectedIterator.next();
      final Map.Entry<String, List<DoublesPair>> actualEntry = actualIterator.next();
      assertEquals(expectedEntry.getKey(), actualEntry.getKey());
      assertEquals(expectedEntry.getValue().size(), actualEntry.getValue().size());
      for (int i = 0; i < expectedEntry.getValue().size(); i++) {
        final DoublesPair expectedPair = expectedEntry.getValue().get(i);
        final DoublesPair actualPair = actualEntry.getValue().get(i);
        assertEquals(expectedPair.getFirst(), actualPair.getFirst(), EPS);
        assertEquals(expectedPair.getSecond(), actualPair.getSecond(), EPS);
      }

    } while (expectedIterator.hasNext() && actualIterator.hasNext());
  }
/** Class to test the PresentValueSensitivity class. */
@Test
public class InterestRateCurveSensitivityTest {

  private static final List<DoublesPair> SENSITIVITY_DATA_1 =
      Arrays.asList(
          new DoublesPair[] {
            DoublesPair.of(1d, 10d),
            DoublesPair.of(2d, 20d),
            DoublesPair.of(3d, 30d),
            DoublesPair.of(4d, 40d)
          });
  private static final List<DoublesPair> SENSITIVITY_DATA_2 =
      Arrays.asList(
          new DoublesPair[] {
            DoublesPair.of(1d, 40d),
            DoublesPair.of(2d, 30d),
            DoublesPair.of(3d, 20d),
            DoublesPair.of(4d, 10d)
          });
  private static final List<DoublesPair> SENSITIVITY_DATA_3 =
      Arrays.asList(
          new DoublesPair[] {
            DoublesPair.of(11d, 40d),
            DoublesPair.of(12d, 30d),
            DoublesPair.of(13d, 20d),
            DoublesPair.of(14d, 10d)
          });
  private static final String CURVE_NAME_1 = "A";
  private static final String CURVE_NAME_2 = "B";
  private static final String CURVE_NAME_3 = "C";
  private static final Map<String, List<DoublesPair>> SENSITIVITY_11 = new HashMap<>();
  private static final Map<String, List<DoublesPair>> SENSITIVITY_12 = new HashMap<>();
  private static final Map<String, List<DoublesPair>> SENSITIVITY_22 = new HashMap<>();
  private static final Map<String, List<DoublesPair>> SENSITIVITY_33 = new HashMap<>();
  private static final double EPS = 1e-12;

  static {
    SENSITIVITY_11.put(CURVE_NAME_1, SENSITIVITY_DATA_1);
    SENSITIVITY_22.put(CURVE_NAME_2, SENSITIVITY_DATA_2);
    SENSITIVITY_12.put(CURVE_NAME_1, SENSITIVITY_DATA_2);
    SENSITIVITY_33.put(CURVE_NAME_3, SENSITIVITY_DATA_3);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullSensitivity1() {
    new InterestRateCurveSensitivity(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullSensitivity2() {
    InterestRateCurveSensitivity.of(CURVE_NAME_1, null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCurveName() {
    InterestRateCurveSensitivity.of(null, SENSITIVITY_DATA_1);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullSensitivities() {
    InterestRateCurveSensitivity.of("Name", null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testPlusNullName() {
    new InterestRateCurveSensitivity().plus(null, SENSITIVITY_DATA_1);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testPlusNullList() {
    new InterestRateCurveSensitivity().plus(CURVE_NAME_1, null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testPlusNullSensitivity() {
    new InterestRateCurveSensitivity().plus(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testCleanNegativeAbsoluteTolerance() {
    new InterestRateCurveSensitivity(SENSITIVITY_11).cleaned(EPS, -EPS);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testCleanNegativeRelativeTolerance() {
    new InterestRateCurveSensitivity(SENSITIVITY_11).cleaned(-EPS, EPS);
  }

  @Test
  public void testObject() {
    final Map<String, List<DoublesPair>> map = Maps.newHashMap(SENSITIVITY_11);
    InterestRateCurveSensitivity sensitivities = new InterestRateCurveSensitivity(map);
    map.put("DUMMY", SENSITIVITY_DATA_3);
    assertFalse(sensitivities.getSensitivities().equals(map));
    sensitivities = new InterestRateCurveSensitivity(SENSITIVITY_11);
    assertEquals(SENSITIVITY_11.keySet(), sensitivities.getCurves());
    assertEquals(SENSITIVITY_11, sensitivities.getSensitivities());
    InterestRateCurveSensitivity other = new InterestRateCurveSensitivity(SENSITIVITY_11);
    assertEquals(sensitivities.hashCode(), other.hashCode());
    assertEquals(sensitivities, other);
    other = InterestRateCurveSensitivity.of(CURVE_NAME_1, SENSITIVITY_DATA_1);
    assertEquals(sensitivities, other);
    assertFalse(
        SENSITIVITY_11 == new InterestRateCurveSensitivity(SENSITIVITY_11).getSensitivities());
    assertFalse(sensitivities.equals(new InterestRateCurveSensitivity(SENSITIVITY_12)));
    other = new InterestRateCurveSensitivity();
    assertTrue(other.getCurves().isEmpty());
    assertTrue(other.getSensitivities().isEmpty());
    other = new InterestRateCurveSensitivity(SENSITIVITY_11);
    assertEquals(sensitivities, other);
  }

  @Test
  public void testPlusDifferentCurves() {
    // Simple add
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_22);
    final Map<String, List<DoublesPair>> map = new HashMap<>();
    map.put(CURVE_NAME_1, SENSITIVITY_DATA_1);
    map.put(CURVE_NAME_2, SENSITIVITY_DATA_2);
    final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
    InterestRateCurveSensitivity actual = sensitivity1.plus(sensitivity2);
    assertFalse(sensitivity1 == actual);
    assertFalse(sensitivity2 == actual);
    assertEquals(expected, actual);
    actual = sensitivity1.plus(CURVE_NAME_2, SENSITIVITY_DATA_2);
    assertEquals(expected, actual);
  }

  @Test
  public void testPlusSameCurves() {
    // Add on the same curve
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    final List<DoublesPair> data = new ArrayList<>();
    data.addAll(SENSITIVITY_DATA_1);
    data.addAll(SENSITIVITY_DATA_2);
    final Map<String, List<DoublesPair>> map = new HashMap<>();
    map.put(CURVE_NAME_1, data);
    final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
    InterestRateCurveSensitivity actual = sensitivity1.plus(sensitivity2);
    assertFalse(sensitivity1 == actual);
    assertFalse(sensitivity2 == actual);
    assertEquals(expected, actual);
    actual = sensitivity1.plus(CURVE_NAME_1, SENSITIVITY_DATA_2);
    assertEquals(expected, actual);
  }

  @Test
  public void testPlusMultiCurve() {
    // Add multi-curve
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    final InterestRateCurveSensitivity sensitivity3 =
        new InterestRateCurveSensitivity(SENSITIVITY_22);
    final InterestRateCurveSensitivity sensitivity4 =
        new InterestRateCurveSensitivity(SENSITIVITY_33);
    final List<DoublesPair> list = new ArrayList<>();
    list.addAll(SENSITIVITY_DATA_1);
    list.addAll(SENSITIVITY_DATA_2);
    final Map<String, List<DoublesPair>> map = new HashMap<>();
    map.put(CURVE_NAME_1, list);
    map.put(CURVE_NAME_2, SENSITIVITY_DATA_2);
    map.put(CURVE_NAME_3, SENSITIVITY_DATA_3);
    final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
    InterestRateCurveSensitivity actual =
        sensitivity1.plus(sensitivity2).plus(sensitivity3).plus(sensitivity4);
    assertEquals(expected, actual);
    actual =
        sensitivity1
            .plus(CURVE_NAME_1, SENSITIVITY_DATA_2)
            .plus(CURVE_NAME_2, SENSITIVITY_DATA_2)
            .plus(CURVE_NAME_3, SENSITIVITY_DATA_3);
    assertEquals(expected, actual);
  }

  @Test
  public void testMultiply() {
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    final InterestRateCurveSensitivity sensitivity3 =
        new InterestRateCurveSensitivity(SENSITIVITY_22);
    final InterestRateCurveSensitivity sensitivity4 =
        new InterestRateCurveSensitivity(SENSITIVITY_33);
    final double factor = Math.random() - 1;
    final List<DoublesPair> list1 = new ArrayList<>();
    final List<DoublesPair> list2 = new ArrayList<>();
    final List<DoublesPair> list3 = new ArrayList<>();
    for (final DoublesPair pair : SENSITIVITY_DATA_1) {
      list1.add(DoublesPair.of(pair.getFirst(), pair.getSecond() * factor));
    }
    for (final DoublesPair pair : SENSITIVITY_DATA_2) {
      final DoublesPair scaledPair = DoublesPair.of(pair.getFirst(), pair.getSecond() * factor);
      list1.add(scaledPair);
      list2.add(scaledPair);
    }
    for (final DoublesPair pair : SENSITIVITY_DATA_3) {
      list3.add(DoublesPair.of(pair.getFirst(), pair.getSecond() * factor));
    }
    final Map<String, List<DoublesPair>> map = new HashMap<>();
    map.put(CURVE_NAME_1, list1);
    map.put(CURVE_NAME_2, list2);
    map.put(CURVE_NAME_3, list3);
    final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
    final InterestRateCurveSensitivity actualUnscaled =
        sensitivity1.plus(sensitivity2).plus(sensitivity3).plus(sensitivity4);
    InterestRateCurveSensitivity actual = actualUnscaled.multipliedBy(factor);
    assertFalse(actualUnscaled == actual);
    assertFalse(actualUnscaled.getSensitivities() == actual.getSensitivities());
    assertEquals(expected, actual);
    actual =
        sensitivity1
            .multipliedBy(factor)
            .plus(sensitivity2.multipliedBy(factor))
            .plus(sensitivity3.multipliedBy(factor))
            .plus(sensitivity4.multipliedBy(factor));
    assertEquals(expected, actual);
  }

  @Test
  public void testCleanSameCurves() {
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    final List<DoublesPair> list =
        Arrays.asList(
            new DoublesPair[] {
              DoublesPair.of(1d, 50d),
              DoublesPair.of(2d, 50d),
              DoublesPair.of(3d, 50d),
              DoublesPair.of(4d, 50d)
            });
    final Map<String, List<DoublesPair>> map = new HashMap<>();
    map.put(CURVE_NAME_1, list);
    final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
    final InterestRateCurveSensitivity actualUncleaned = sensitivity1.plus(sensitivity2);
    final InterestRateCurveSensitivity actual = actualUncleaned.cleaned();
    assertFalse(actualUncleaned == actual);
    assertFalse(actualUncleaned.getSensitivities() == actual.getSensitivities());
    assertEquals(expected, actual);
  }

  @Test
  public void testCleanDifferentCurves() {
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_22);
    final Map<String, List<DoublesPair>> map = new HashMap<>();
    map.put(CURVE_NAME_1, SENSITIVITY_DATA_1);
    map.put(CURVE_NAME_2, SENSITIVITY_DATA_2);
    final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
    final InterestRateCurveSensitivity actualUncleaned = sensitivity1.plus(sensitivity2);
    final InterestRateCurveSensitivity actual = actualUncleaned.cleaned();
    assertFalse(actualUncleaned == actual);
    assertFalse(actualUncleaned.getSensitivities() == actual.getSensitivities());
    assertEquals(expected, actual);
    assertEquals(actualUncleaned, actual);
  }

  @Test
  public void testCleanSameCurvesWithAbsoluteTolerance1() {
    final double eps = 1e-3;
    final double eps2 = 5e-4;
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final List<DoublesPair> fuzzyList =
        Arrays.asList(
            new DoublesPair[] {
              DoublesPair.of(1d, -10 - eps2),
              DoublesPair.of(2d, 30d),
              DoublesPair.of(3d, -30d + eps2),
              DoublesPair.of(4d, 10d)
            });
    List<DoublesPair> expectedList =
        Arrays.asList(new DoublesPair[] {DoublesPair.of(2d, 50d), DoublesPair.of(4d, 50d)});
    Map<String, List<DoublesPair>> expectedMap = new HashMap<>();
    expectedMap.put(CURVE_NAME_1, expectedList);
    final Map<String, List<DoublesPair>> fuzzyMap = new HashMap<>();
    fuzzyMap.put(CURVE_NAME_1, fuzzyList);
    final InterestRateCurveSensitivity fuzzySensitivity =
        new InterestRateCurveSensitivity(fuzzyMap);
    InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(expectedMap);
    final InterestRateCurveSensitivity actualUncleaned = sensitivity1.plus(fuzzySensitivity);
    InterestRateCurveSensitivity actual = actualUncleaned.cleaned(eps / 10, eps);
    assertFalse(actualUncleaned == actual);
    assertFalse(actualUncleaned.getSensitivities() == actual.getSensitivities());
    assertEquals(expected, actual);
    expectedList =
        Arrays.asList(
            new DoublesPair[] {
              DoublesPair.of(1d, -eps2),
              DoublesPair.of(2d, 50d),
              DoublesPair.of(3d, eps2),
              DoublesPair.of(4d, 50d)
            });
    expectedMap = new HashMap<>();
    expectedMap.put(CURVE_NAME_1, expectedList);
    expected = new InterestRateCurveSensitivity(expectedMap);
    actual = actualUncleaned.cleaned(eps / 1000, eps / 100);
    assertEquals(expected.getSensitivities().size(), actual.getSensitivities().size());
    assertIRCSEquals(expected, actual);
  }

  @Test
  public void testCleanSameCurvesWithRelativeTolerance1() {
    final double eps = 1e-3;
    final double eps2 = 5e-4;
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final List<DoublesPair> fuzzyList =
        Arrays.asList(
            new DoublesPair[] {
              DoublesPair.of(1d, -10d - 10 * eps2),
              DoublesPair.of(2d, 30d),
              DoublesPair.of(3d, -30d + 30 * eps2),
              DoublesPair.of(4d, 10d)
            });
    List<DoublesPair> expectedList =
        Arrays.asList(new DoublesPair[] {DoublesPair.of(2d, 50d), DoublesPair.of(4d, 50d)});
    Map<String, List<DoublesPair>> expectedMap = new HashMap<>();
    expectedMap.put(CURVE_NAME_1, expectedList);
    final Map<String, List<DoublesPair>> fuzzyMap = new HashMap<>();
    fuzzyMap.put(CURVE_NAME_1, fuzzyList);
    final InterestRateCurveSensitivity fuzzySensitivity =
        new InterestRateCurveSensitivity(fuzzyMap);
    InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(expectedMap);
    final InterestRateCurveSensitivity actualUncleaned = sensitivity1.plus(fuzzySensitivity);
    InterestRateCurveSensitivity actual = actualUncleaned.cleaned(eps, eps / 10);
    assertFalse(actualUncleaned == actual);
    assertFalse(actualUncleaned.getSensitivities() == actual.getSensitivities());
    assertEquals(expected, actual);
    expectedList =
        Arrays.asList(
            new DoublesPair[] {
              DoublesPair.of(1d, -10d * eps2),
              DoublesPair.of(2d, 50d),
              DoublesPair.of(3d, 30d * eps2),
              DoublesPair.of(4d, 50d)
            });
    expectedMap = new HashMap<>();
    expectedMap.put(CURVE_NAME_1, expectedList);
    expected = new InterestRateCurveSensitivity(expectedMap);
    actual = actualUncleaned.cleaned(eps / 100, eps / 10);
    assertEquals(expected.getSensitivities().size(), actual.getSensitivities().size());
    assertIRCSEquals(expected, actual);
  }

  @Test
  public void testTotalSensitivityByCurve() {
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    final InterestRateCurveSensitivity sensitivity3 =
        new InterestRateCurveSensitivity(SENSITIVITY_22);
    final InterestRateCurveSensitivity sensitivity4 =
        new InterestRateCurveSensitivity(SENSITIVITY_33);
    final Map<String, Double> actual =
        sensitivity1
            .plus(sensitivity2)
            .plus(sensitivity3)
            .plus(sensitivity4)
            .totalSensitivityByCurve();
    final Map<String, Double> expected = new HashMap<>();
    expected.put(CURVE_NAME_1, 200.);
    expected.put(CURVE_NAME_2, 100.);
    expected.put(CURVE_NAME_3, 100.);
    assertEquals(expected, actual);
  }

  @Test
  public void testTotalSensitivity() {
    final InterestRateCurveSensitivity sensitivity1 =
        new InterestRateCurveSensitivity(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    final InterestRateCurveSensitivity sensitivity3 =
        new InterestRateCurveSensitivity(SENSITIVITY_22);
    final InterestRateCurveSensitivity sensitivity4 =
        new InterestRateCurveSensitivity(SENSITIVITY_33);
    final double actual =
        sensitivity1.plus(sensitivity2).plus(sensitivity3).plus(sensitivity4).totalSensitivity();
    final double expected = 400;
    assertEquals(expected, actual);
  }

  @Test
  public void testCompareDifferentTimes() {
    AssertSensitivityObjects.assertEquals(
        "", new InterestRateCurveSensitivity(), new InterestRateCurveSensitivity(), EPS);
    final TreeMap<String, List<DoublesPair>> sortedMap = new TreeMap<>(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity1 = new InterestRateCurveSensitivity(sortedMap);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    AssertSensitivityObjects.assertDoesNotEqual("", sensitivity1, sensitivity2, EPS);
    final Map<String, List<DoublesPair>> map = Maps.newTreeMap();
    final double eps = 1e-4;
    for (final Map.Entry<String, List<DoublesPair>> entry : sortedMap.entrySet()) {
      final List<DoublesPair> list = new ArrayList<>();
      for (final DoublesPair pair : entry.getValue()) {
        list.add(DoublesPair.of(pair.getFirst() + 0.01 * eps, pair.getSecond()));
      }
      map.put(entry.getKey(), list);
    }
    final InterestRateCurveSensitivity sensitivity3 = new InterestRateCurveSensitivity(map);
    AssertSensitivityObjects.assertEquals("", sensitivity1, sensitivity3, eps);
    AssertSensitivityObjects.assertDoesNotEqual("", sensitivity1, sensitivity3, EPS);
  }

  @Test
  public void testCompareDifferentValues() {
    AssertSensitivityObjects.assertEquals(
        "", new InterestRateCurveSensitivity(), new InterestRateCurveSensitivity(), EPS);
    final TreeMap<String, List<DoublesPair>> sortedMap = new TreeMap<>(SENSITIVITY_11);
    final InterestRateCurveSensitivity sensitivity1 = new InterestRateCurveSensitivity(sortedMap);
    final InterestRateCurveSensitivity sensitivity2 =
        new InterestRateCurveSensitivity(SENSITIVITY_12);
    AssertSensitivityObjects.assertDoesNotEqual("", sensitivity1, sensitivity2, EPS);
    final Map<String, List<DoublesPair>> map = Maps.newTreeMap();
    final double eps = 1e-4;
    for (final Map.Entry<String, List<DoublesPair>> entry : sortedMap.entrySet()) {
      final List<DoublesPair> list = new ArrayList<>();
      for (final DoublesPair pair : entry.getValue()) {
        list.add(DoublesPair.of(pair.getFirst(), pair.getSecond() + 0.01 * eps));
      }
      map.put(entry.getKey(), list);
    }
    final InterestRateCurveSensitivity sensitivity3 = new InterestRateCurveSensitivity(map);
    AssertSensitivityObjects.assertEquals("", sensitivity1, sensitivity3, eps);
    AssertSensitivityObjects.assertDoesNotEqual("", sensitivity1, sensitivity3, EPS);
  }

  private void assertIRCSEquals(
      final InterestRateCurveSensitivity expected, final InterestRateCurveSensitivity actual) {
    final Iterator<Map.Entry<String, List<DoublesPair>>> expectedIterator =
        new TreeMap<>(expected.getSensitivities()).entrySet().iterator();
    final Iterator<Map.Entry<String, List<DoublesPair>>> actualIterator =
        new TreeMap<>(actual.getSensitivities()).entrySet().iterator();
    do {
      final Map.Entry<String, List<DoublesPair>> expectedEntry = expectedIterator.next();
      final Map.Entry<String, List<DoublesPair>> actualEntry = actualIterator.next();
      assertEquals(expectedEntry.getKey(), actualEntry.getKey());
      assertEquals(expectedEntry.getValue().size(), actualEntry.getValue().size());
      for (int i = 0; i < expectedEntry.getValue().size(); i++) {
        final DoublesPair expectedPair = expectedEntry.getValue().get(i);
        final DoublesPair actualPair = actualEntry.getValue().get(i);
        assertEquals(expectedPair.getFirst(), actualPair.getFirst(), EPS);
        assertEquals(expectedPair.getSecond(), actualPair.getSecond(), EPS);
      }

    } while (expectedIterator.hasNext() && actualIterator.hasNext());
  }
}
 @Test
 public void testMultiply() {
   final InterestRateCurveSensitivity sensitivity1 =
       new InterestRateCurveSensitivity(SENSITIVITY_11);
   final InterestRateCurveSensitivity sensitivity2 =
       new InterestRateCurveSensitivity(SENSITIVITY_12);
   final InterestRateCurveSensitivity sensitivity3 =
       new InterestRateCurveSensitivity(SENSITIVITY_22);
   final InterestRateCurveSensitivity sensitivity4 =
       new InterestRateCurveSensitivity(SENSITIVITY_33);
   final double factor = Math.random() - 1;
   final List<DoublesPair> list1 = new ArrayList<>();
   final List<DoublesPair> list2 = new ArrayList<>();
   final List<DoublesPair> list3 = new ArrayList<>();
   for (final DoublesPair pair : SENSITIVITY_DATA_1) {
     list1.add(DoublesPair.of(pair.getFirst(), pair.getSecond() * factor));
   }
   for (final DoublesPair pair : SENSITIVITY_DATA_2) {
     final DoublesPair scaledPair = DoublesPair.of(pair.getFirst(), pair.getSecond() * factor);
     list1.add(scaledPair);
     list2.add(scaledPair);
   }
   for (final DoublesPair pair : SENSITIVITY_DATA_3) {
     list3.add(DoublesPair.of(pair.getFirst(), pair.getSecond() * factor));
   }
   final Map<String, List<DoublesPair>> map = new HashMap<>();
   map.put(CURVE_NAME_1, list1);
   map.put(CURVE_NAME_2, list2);
   map.put(CURVE_NAME_3, list3);
   final InterestRateCurveSensitivity expected = new InterestRateCurveSensitivity(map);
   final InterestRateCurveSensitivity actualUnscaled =
       sensitivity1.plus(sensitivity2).plus(sensitivity3).plus(sensitivity4);
   InterestRateCurveSensitivity actual = actualUnscaled.multipliedBy(factor);
   assertFalse(actualUnscaled == actual);
   assertFalse(actualUnscaled.getSensitivities() == actual.getSensitivities());
   assertEquals(expected, actual);
   actual =
       sensitivity1
           .multipliedBy(factor)
           .plus(sensitivity2.multipliedBy(factor))
           .plus(sensitivity3.multipliedBy(factor))
           .plus(sensitivity4.multipliedBy(factor));
   assertEquals(expected, actual);
 }
 /** Tests the coupon present value SABR parameters sensitivity vs finite difference. */
 public void presentValueSABRSensitivityCoupon() {
   final double pv =
       METHOD_EXTRAPOLATION_CPN
           .presentValue(CMS_COUPON, SABR_MULTICURVES)
           .getAmount(EUR)
           .getAmount();
   final PresentValueSABRSensitivityDataBundle pvsCpn =
       METHOD_EXTRAPOLATION_CPN.presentValueSABRSensitivity(CMS_COUPON, SABR_MULTICURVES);
   // SABR sensitivity vs finite difference
   final double shift = 0.0001;
   final double shiftAlpha = 0.00001;
   final double maturity =
       CMS_COUPON
               .getUnderlyingSwap()
               .getFixedLeg()
               .getNthPayment(
                   CMS_COUPON.getUnderlyingSwap().getFixedLeg().getNumberOfPayments() - 1)
               .getPaymentTime()
           - CMS_COUPON.getSettlementTime();
   final DoublesPair expectedExpiryTenor = DoublesPair.of(CMS_COUPON.getFixingTime(), maturity);
   // Alpha sensitivity vs finite difference computation
   final SABRInterestRateParameters sabrParameterAlphaBumped =
       SABRDataSets.createSABR1AlphaBumped(shiftAlpha);
   final SABRSwaptionProviderDiscount sabrBundleAlphaBumped =
       new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterAlphaBumped, EUR1YEURIBOR6M);
   final double pvLongPayerAlphaBumped =
       METHOD_EXTRAPOLATION_CPN
           .presentValue(CMS_COUPON, sabrBundleAlphaBumped)
           .getAmount(EUR)
           .getAmount();
   final double expectedAlphaSensi = (pvLongPayerAlphaBumped - pv) / shiftAlpha;
   assertEquals("Number of alpha sensitivity", pvsCpn.getAlpha().getMap().keySet().size(), 1);
   assertEquals(
       "Alpha sensitivity expiry/tenor",
       pvsCpn.getAlpha().getMap().keySet().contains(expectedExpiryTenor),
       true);
   assertEquals(
       "Alpha sensitivity value",
       expectedAlphaSensi,
       pvsCpn.getAlpha().getMap().get(expectedExpiryTenor),
       TOLERANCE_PV_DELTA);
   // Rho sensitivity vs finite difference computation
   final SABRInterestRateParameters sabrParameterRhoBumped = SABRDataSets.createSABR1RhoBumped();
   final SABRSwaptionProviderDiscount sabrBundleRhoBumped =
       new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterRhoBumped, EUR1YEURIBOR6M);
   final double pvLongPayerRhoBumped =
       METHOD_EXTRAPOLATION_CPN
           .presentValue(CMS_COUPON, sabrBundleRhoBumped)
           .getAmount(EUR)
           .getAmount();
   final double expectedRhoSensi = (pvLongPayerRhoBumped - pv) / shift;
   assertEquals("Number of rho sensitivity", pvsCpn.getRho().getMap().keySet().size(), 1);
   assertEquals(
       "Rho sensitivity expiry/tenor",
       pvsCpn.getRho().getMap().keySet().contains(expectedExpiryTenor),
       true);
   assertEquals(
       "Rho sensitivity value",
       expectedRhoSensi,
       pvsCpn.getRho().getMap().get(expectedExpiryTenor),
       TOLERANCE_PV_DELTA);
   // Nu sensitivity vs finite difference computation
   final SABRInterestRateParameters sabrParameterNuBumped = SABRDataSets.createSABR1NuBumped();
   final SABRSwaptionProviderDiscount sabrBundleNuBumped =
       new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterNuBumped, EUR1YEURIBOR6M);
   final double pvLongPayerNuBumped =
       METHOD_EXTRAPOLATION_CPN
           .presentValue(CMS_COUPON, sabrBundleNuBumped)
           .getAmount(EUR)
           .getAmount();
   final double expectedNuSensi = (pvLongPayerNuBumped - pv) / shift;
   assertEquals("Number of nu sensitivity", pvsCpn.getNu().getMap().keySet().size(), 1);
   assertTrue(
       "Nu sensitivity expiry/tenor",
       pvsCpn.getNu().getMap().keySet().contains(expectedExpiryTenor));
   assertEquals(
       "Nu sensitivity value",
       expectedNuSensi,
       pvsCpn.getNu().getMap().get(expectedExpiryTenor),
       TOLERANCE_PV_DELTA);
 }