@Override
 public Coupon toDerivative(
     final ZonedDateTime date,
     final DoubleTimeSeries<ZonedDateTime> indexFixingTS,
     final String... yieldCurveNames) {
   Validate.notNull(date, "date");
   Validate.notNull(indexFixingTS, "index fixing time series");
   Validate.notNull(yieldCurveNames, "yield curve names");
   Validate.isTrue(yieldCurveNames.length > 1, "at least two curves required");
   Validate.isTrue(!date.isAfter(getPaymentDate()), "date is after payment date");
   final DayCount actAct = DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
   final String fundingCurveName = yieldCurveNames[0];
   final double paymentTime = actAct.getDayCountFraction(date, getPaymentDate());
   if (date.isAfter(getFixingDate())
       || date.equals(
           getFixingDate())) { // The CMS coupon has already fixed, it is now a fixed coupon.
     final double fixedRate = indexFixingTS.getValue(getFixingDate());
     return new CouponFixed(
         getCurrency(),
         paymentTime,
         fundingCurveName,
         getPaymentYearFraction(),
         getNotional(),
         payOff(fixedRate));
   }
   // CMS is not fixed yet, all the details are required.
   final CouponCMS cmsCoupon =
       (CouponCMS) super.toDerivative(date, indexFixingTS, yieldCurveNames);
   return CapFloorCMS.from(cmsCoupon, _strike, _isCap);
 }
 @Override
 public double[] evaluate(final DoubleTimeSeries<?> x) {
   Validate.notNull(x, "x");
   if (x.isEmpty()) {
     throw new IllegalArgumentException("Time series was empty");
   }
   final int h = x.size() - 1;
   final double[] result = new double[h];
   final double mean = _meanCalculator.evaluate(x);
   double[] x1, x2;
   final int n = x.size();
   double sum;
   final double[] x0 = x.valuesArrayFast();
   for (int i = 0; i < h; i++) {
     x1 = Arrays.copyOfRange(x0, 0, n - i);
     x2 = Arrays.copyOfRange(x0, i, n);
     if (x1.length != x2.length) {
       throw new IllegalArgumentException(
           "Series were not the same length; this should not happen");
     }
     sum = 0;
     for (int j = 0; j < x1.length; j++) {
       sum += (x1[j] - mean) * (x2[j] - mean);
     }
     result[i] = sum / n;
   }
   return result;
 }
 @SuppressWarnings("synthetic-access")
 @Override
 public InstrumentDerivative convert(
     final CapFloorCMSSpreadSecurity security,
     final AnnuityCapFloorCMSSpreadDefinition definition,
     final ZonedDateTime now,
     final String[] curveNames,
     final HistoricalTimeSeriesBundle timeSeries) {
   final ExternalId longId = security.getLongId();
   final ExternalId shortId = security.getShortId();
   final DoubleTimeSeries<ZonedDateTime> indexLongTS =
       getIndexTimeSeries(getIndexIdBundle(longId), now.getZone(), timeSeries);
   final DoubleTimeSeries<ZonedDateTime> indexShortTS =
       getIndexTimeSeries(getIndexIdBundle(shortId), now.getZone(), timeSeries);
   final DoubleTimeSeries<ZonedDateTime> indexSpreadTS =
       indexLongTS.subtract(indexShortTS);
   return definition.toDerivative(now, indexSpreadTS, curveNames);
 }
public class CovarianceMatrixCalculatorTest {
  private static final DoubleTimeSeries<?> TS1 =
      new FastArrayIntDoubleTimeSeries(
          DateTimeNumericEncoding.DATE_EPOCH_DAYS,
          new int[] {1, 2, 3, 4},
          new double[] {-1, 1, -1, 1});
  private static final DoubleTimeSeries<?> TS2 = TS1.multiply(-1);
  private static final CovarianceCalculator COVARIANCE = new HistoricalCovarianceCalculator();
  private static final Function<DoubleTimeSeries<?>, DoubleMatrix2D> CALCULATOR =
      new CovarianceMatrixCalculator(COVARIANCE);
  private static final double EPS = 1e-9;

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

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullTSArray() {
    CALCULATOR.evaluate((DoubleTimeSeries<?>[]) null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testEmptyTSArray() {
    CALCULATOR.evaluate(new DoubleTimeSeries<?>[0]);
  }

  @Test
  public void test() {
    final DoubleMatrix2D matrix = CALCULATOR.evaluate(TS1, TS2);
    assertEquals(matrix.getNumberOfRows(), 2);
    assertEquals(matrix.getNumberOfColumns(), 2);
    assertEquals(matrix.getEntry(0, 0), 4. / 3, EPS);
    assertEquals(matrix.getEntry(1, 0), -4. / 3, EPS);
    assertEquals(matrix.getEntry(0, 1), -4. / 3, EPS);
    assertEquals(matrix.getEntry(1, 1), 4. / 3, EPS);
  }
}