class CrossGammaMultiCurveCalculator {

  public DoubleMatrix2D calculateCrossGammaCrossCurve(final InstrumentDerivative instrument, final MulticurveProviderDiscount multicurve) {
    ArgumentChecker.notNull(instrument, "instrument");
    ArgumentChecker.notNull(multicurve, "multi-curve provider");
    Set<String> names = multicurve.getAllNames();
    int nbCurve = names.size();
    String[] namesArray = names.toArray(new String[nbCurve]);
    Currency ccy = checkUniqueCurrency(multicurve);
    InterpolatedDoublesCurve[] interpolatedCurves = interpolatedCurves(multicurve, nbCurve, namesArray);
    // Curves description
    double[][] y = new double[nbCurve][];
    double[][] x = new double[nbCurve][];
    int[] nbNodeByCurve = new int[nbCurve];
    int nbNodeTotal = 0;
    for (int loopcurve = 0; loopcurve < nbCurve; loopcurve++) {
      y[loopcurve] = interpolatedCurves[loopcurve].getYDataAsPrimitive();
      x[loopcurve] = interpolatedCurves[loopcurve].getXDataAsPrimitive();
      nbNodeByCurve[loopcurve] = x[loopcurve].length;
      nbNodeTotal += nbNodeByCurve[loopcurve];
    }
    // Initial sensitivity
    MultipleCurrencyParameterSensitivity ps0 = _psc.calculateSensitivity(instrument, multicurve);
    double[][] ps0Array = sensitivitiesAsArrayOfMatrix(nbCurve, namesArray, ccy, nbNodeByCurve, ps0);
    // Bump and recompute for each curve and each point
    double[][] gammaArray = new double[nbNodeTotal][nbNodeTotal];
    int loopnodetotal = 0;
    for (int loopcurve = 0; loopcurve < nbCurve; loopcurve++) {
      MultipleCurrencyParameterSensitivity[] psShift = new MultipleCurrencyParameterSensitivity[nbNodeByCurve[loopcurve]];
      for (int loopnode = 0; loopnode < nbNodeByCurve[loopcurve]; loopnode++) {
        final double[] yieldBumped = y[loopcurve].clone();
        yieldBumped[loopnode] += _shift;
        MulticurveProviderDiscount multicurveBumped = bumpedProvider(multicurve, namesArray[loopcurve],
            interpolatedCurves[loopcurve].getInterpolator(), x[loopcurve], yieldBumped);
        psShift[loopnode] = _psc.calculateSensitivity(instrument, multicurveBumped);
        int loopnodetotal2 = 0;
        for (int loopcurve2 = 0; loopcurve2 < nbCurve; loopcurve2++) {
          DoubleMatrix1D sensiCurve = psShift[loopnode].getSensitivity(namesArray[loopcurve2], ccy);
          double[] psShiftArray = new double[nbNodeByCurve[loopcurve2]];
          if (sensiCurve != null) {
            psShiftArray = sensiCurve.getData();
          }
          for (int loopnode2 = 0; loopnode2 < nbNodeByCurve[loopcurve2]; loopnode2++) {
            gammaArray[loopnodetotal][loopnodetotal2] = (psShiftArray[loopnode2] - ps0Array[loopcurve2][loopnode2]) / _shift;
            loopnodetotal2++;
          }
        }
        loopnodetotal++;
      }
    }
    return new DoubleMatrix2D(gammaArray);
  }

  public  CrossGammaMultiCurveCalculator(final double shift,
      final InstrumentDerivativeVisitor<ParameterProviderInterface, MultipleCurrencyMulticurveSensitivity> curveSensitivityCalculator);
  public  CrossGammaMultiCurveCalculator(final InstrumentDerivativeVisitor<ParameterProviderInterface, MultipleCurrencyMulticurveSensitivity> curveSensitivityCalculator);

}